diff options
author | Brett Walker <bwalker@gitlab.com> | 2018-08-16 20:42:07 -0500 |
---|---|---|
committer | Brett Walker <bwalker@gitlab.com> | 2018-08-20 08:00:47 -0500 |
commit | 036a52ac691e57f82ad5ad8e24d868bd13719558 (patch) | |
tree | df44e086721bbd64d0139ceb64a98470a6a75a08 | |
parent | 3c80adf5c8486315fa84ac237177c38b9ae625c9 (diff) | |
download | gitlab-ce-036a52ac691e57f82ad5ad8e24d868bd13719558.tar.gz |
add SpacedLinkFilter for wiki links with spaces
-rw-r--r-- | lib/banzai/filter/spaced_link_filter.rb | 72 | ||||
-rw-r--r-- | lib/banzai/pipeline/wiki_pipeline.rb | 1 |
2 files changed, 73 insertions, 0 deletions
diff --git a/lib/banzai/filter/spaced_link_filter.rb b/lib/banzai/filter/spaced_link_filter.rb new file mode 100644 index 00000000000..1d21b8174ab --- /dev/null +++ b/lib/banzai/filter/spaced_link_filter.rb @@ -0,0 +1,72 @@ +require 'uri' + +module Banzai + module Filter + # HTML Filter for markdown links with spaces in the URLs + # + # Based on Banzai::Filter::AutolinkFilter + # + # CommonMark does not allow spaces in the url portion of a link. + # For example, `[example](page slug)` is not valid. However, + # in our wikis, we support (via RedCarpet) this type of link, allowing + # wiki pages to be easily linked bby their title. This filter adds that functionality. + # The intent is for this to only be used in Wikis - in general, we want + # to adhere to CommonMark's spec. + # + class SpacedLinkFilter < HTML::Pipeline::Filter + include ActionView::Helpers::TagHelper + + # Pattern to match a standard markdown link + # + # Rubular: http://rubular.com/r/z9EAHxYmKI + LINK_PATTERN = /\[([^\]]+)\]\(([^)"]+)(?: \"([^\"]+)\")?\)/ + + # Text matching LINK_PATTERN inside these elements will not be linked + IGNORE_PARENTS = %w(a code kbd pre script style).to_set + + # The XPath query to use for finding text nodes to parse. + TEXT_QUERY = %Q(descendant-or-self::text()[ + not(#{IGNORE_PARENTS.map { |p| "ancestor::#{p}" }.join(' or ')}) + and contains(., ']\(') + ]).freeze + + def call + return doc if context[:markdown_engine] == :redcarpet + + doc.xpath(TEXT_QUERY).each do |node| + content = node.to_html + + next unless content.match(LINK_PATTERN) + + html = spaced_link_filter(content) + + next if html == content + + node.replace(html) + end + + doc + end + + private + + def spaced_link_match(link) + match = LINK_PATTERN.match(link) + if match && match[1] && match[2] + # escape the spaces in the url so that it's a valid markdown link, + # then run it through the markdown processor again, let it do it's magic + new_link = "[#{match[1]}](#{match[2].gsub(' ', '%20')})" + Banzai::Filter::MarkdownFilter.new(new_link, context).call + else + link + end + end + + def spaced_link_filter(text) + Gitlab::StringRegexMarker.new(CGI.unescapeHTML(text), text.html_safe).mark(LINK_PATTERN) do |link, left:, right:| + spaced_link_match(link) + end + end + end + end +end diff --git a/lib/banzai/pipeline/wiki_pipeline.rb b/lib/banzai/pipeline/wiki_pipeline.rb index c37b8e71cb0..737ff0cc818 100644 --- a/lib/banzai/pipeline/wiki_pipeline.rb +++ b/lib/banzai/pipeline/wiki_pipeline.rb @@ -5,6 +5,7 @@ module Banzai @filters ||= begin super.insert_after(Filter::TableOfContentsFilter, Filter::GollumTagsFilter) .insert_before(Filter::TaskListFilter, Filter::WikiLinkFilter) + .insert_before(Filter::WikiLinkFilter, Filter::SpacedLinkFilter) end end end |