diff options
author | Robert Speicher <rspeicher@gmail.com> | 2015-04-22 16:40:25 -0400 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2015-04-30 16:35:25 -0400 |
commit | 382a0aa6efd6141ff184a1a91ab586218c340fec (patch) | |
tree | c56640f0ab25ab17e69cef2942391c30bec3a89a /lib | |
parent | 286c9e68860aed365ecad0baa9e5466f9153bbc2 (diff) | |
download | gitlab-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.rb | 5 | ||||
-rw-r--r-- | lib/gitlab/markdown/table_of_contents_filter.rb | 62 | ||||
-rw-r--r-- | lib/redcarpet/render/gitlab_html.rb | 10 |
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://") |