summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRobert Speicher <rspeicher@gmail.com>2015-04-22 16:40:25 -0400
committerRobert Speicher <rspeicher@gmail.com>2015-04-30 16:35:25 -0400
commit382a0aa6efd6141ff184a1a91ab586218c340fec (patch)
treec56640f0ab25ab17e69cef2942391c30bec3a89a /lib
parent286c9e68860aed365ecad0baa9e5466f9153bbc2 (diff)
downloadgitlab-ce-382a0aa6efd6141ff184a1a91ab586218c340fec.tar.gz
Add Gitlab::Markdown::TableOfContentsFilter
Removes header and table of contents processing from Redcarpet renderer.
Diffstat (limited to 'lib')
-rw-r--r--lib/gitlab/markdown.rb5
-rw-r--r--lib/gitlab/markdown/table_of_contents_filter.rb62
-rw-r--r--lib/redcarpet/render/gitlab_html.rb10
3 files changed, 67 insertions, 10 deletions
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index 44779d7fdd8..ffb7e16aed2 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -38,6 +38,7 @@ module Gitlab
autoload :LabelReferenceFilter, 'gitlab/markdown/label_reference_filter'
autoload :MergeRequestReferenceFilter, 'gitlab/markdown/merge_request_reference_filter'
autoload :SnippetReferenceFilter, 'gitlab/markdown/snippet_reference_filter'
+ autoload :TableOfContentsFilter, 'gitlab/markdown/table_of_contents_filter'
autoload :UserReferenceFilter, 'gitlab/markdown/user_reference_filter'
# Public: Parse the provided text with GitLab-Flavored Markdown
@@ -81,6 +82,9 @@ module Gitlab
asset_root: Gitlab.config.gitlab.url,
asset_host: Gitlab::Application.config.asset_host,
+ # TableOfContentsFilter
+ no_header_anchors: options[:no_header_anchors],
+
# ReferenceFilter
current_user: current_user,
only_path: options[:reference_only_path],
@@ -117,6 +121,7 @@ module Gitlab
HTML::Pipeline::SanitizationFilter,
Gitlab::Markdown::EmojiFilter,
+ Gitlab::Markdown::TableOfContentsFilter,
Gitlab::Markdown::UserReferenceFilter,
Gitlab::Markdown::IssueReferenceFilter,
diff --git a/lib/gitlab/markdown/table_of_contents_filter.rb b/lib/gitlab/markdown/table_of_contents_filter.rb
new file mode 100644
index 00000000000..c97612dafb8
--- /dev/null
+++ b/lib/gitlab/markdown/table_of_contents_filter.rb
@@ -0,0 +1,62 @@
+require 'html/pipeline/filter'
+
+module Gitlab
+ module Markdown
+ # HTML filter that adds an anchor child element to all Headers in a
+ # document, so that they can be linked to.
+ #
+ # Generates the Table of Contents with links to each header. See Results.
+ #
+ # Based on HTML::Pipeline::TableOfContentsFilter.
+ #
+ # Context options:
+ # :no_header_anchors - Skips all processing done by this filter.
+ #
+ # Results:
+ # :toc - String containing Table of Contents data as a `ul` element with
+ # `li` child elements.
+ class TableOfContentsFilter < HTML::Pipeline::Filter
+ PUNCTUATION_REGEXP = /[^\p{Word}\- ]/u
+
+ def call
+ return doc if context[:no_header_anchors]
+
+ result[:toc] = ""
+
+ headers = Hash.new(0)
+
+ doc.css('h1, h2, h3, h4, h5, h6').each do |node|
+ text = node.text
+
+ id = text.downcase
+ id.gsub!(PUNCTUATION_REGEXP, '') # remove punctuation
+ id.gsub!(' ', '-') # replace spaces with dash
+ id.squeeze!(' -') # replace multiple spaces or dashes with one
+
+ uniq = (headers[id] > 0) ? "-#{headers[id]}" : ''
+ headers[id] += 1
+
+ if header_content = node.children.first
+ href = "#{id}#{uniq}"
+ push_toc(href, text)
+ header_content.add_previous_sibling(anchor_tag(href))
+ end
+ end
+
+ result[:toc] = %Q{<ul class="section-nav">\n#{result[:toc]}</ul>} unless result[:toc].empty?
+
+ doc
+ end
+
+ private
+
+ def anchor_tag(href)
+ %Q{<a id="#{href}" class="anchor" href="##{href}" aria-hidden="true"></a>}
+ end
+
+ def push_toc(href, text)
+ result[:toc] << %Q{<li><a href="##{href}">#{text}</a></li>\n}
+ end
+ end
+ end
+end
diff --git a/lib/redcarpet/render/gitlab_html.rb b/lib/redcarpet/render/gitlab_html.rb
index 10efff2ae9f..dc5fbe3c8e1 100644
--- a/lib/redcarpet/render/gitlab_html.rb
+++ b/lib/redcarpet/render/gitlab_html.rb
@@ -50,16 +50,6 @@ class Redcarpet::Render::GitlabHTML < Redcarpet::Render::HTML
h.link_to_gfm(content, link, title: title)
end
- def header(text, level)
- if @options[:no_header_anchors]
- "<h#{level}>#{text}</h#{level}>"
- else
- id = ActionController::Base.helpers.strip_tags(h.gfm(text)).downcase() \
- .gsub(/[^a-z0-9_-]/, '-').gsub(/-+/, '-').gsub(/^-/, '').gsub(/-$/, '')
- "<h#{level} id=\"#{id}\">#{text}<a href=\"\##{id}\"></a></h#{level}>"
- end
- end
-
def postprocess(full_document)
full_document.gsub!("ftp://smb:", "smb://")