diff options
author | Bob Van Landuyt <bob@gitlab.com> | 2019-07-16 11:53:47 +0000 |
---|---|---|
committer | Bob Van Landuyt <bob@gitlab.com> | 2019-07-16 11:53:47 +0000 |
commit | 1e99c1b0a7b4e80be5a0be40aebb7f4cad0077de (patch) | |
tree | dced6bc8df79afa503160cabc518c9b35e9fb4ea | |
parent | 4a63ae48465ad1ba2403158077acd02d63a9b4ff (diff) | |
parent | 0cba81c0ecc71f411153b1f2a2952c07125217f9 (diff) | |
download | gitlab-ce-1e99c1b0a7b4e80be5a0be40aebb7f4cad0077de.tar.gz |
Merge branch 'issue-64070-asciidoctor-section-anchors' into 'master'
Enable section anchors
Closes #64070
See merge request gitlab-org/gitlab-ce!30666
-rw-r--r-- | changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml | 5 | ||||
-rw-r--r-- | lib/banzai/filter/ascii_doc_sanitization_filter.rb | 30 | ||||
-rw-r--r-- | lib/gitlab/asciidoc.rb | 1 | ||||
-rw-r--r-- | spec/lib/gitlab/asciidoc_spec.rb | 69 |
4 files changed, 103 insertions, 2 deletions
diff --git a/changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml b/changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml new file mode 100644 index 00000000000..51c1537a159 --- /dev/null +++ b/changelogs/unreleased/64070-asciidoctor-enable-section-anchors.yml @@ -0,0 +1,5 @@ +--- +title: "Enable section anchors in Asciidoctor" +merge_request: 30666 +author: Guillaume Grossetie +type: added
\ No newline at end of file diff --git a/lib/banzai/filter/ascii_doc_sanitization_filter.rb b/lib/banzai/filter/ascii_doc_sanitization_filter.rb index a78bb60103c..d8d63075752 100644 --- a/lib/banzai/filter/ascii_doc_sanitization_filter.rb +++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb @@ -6,6 +6,9 @@ module Banzai # # Extends Banzai::Filter::BaseSanitizationFilter with specific rules. class AsciiDocSanitizationFilter < Banzai::Filter::BaseSanitizationFilter + # Section anchor link pattern + SECTION_LINK_REF_PATTERN = /\A#{Gitlab::Asciidoc::DEFAULT_ADOC_ATTRS['idprefix']}(:?[[:alnum:]]|-|_)+\z/.freeze + # Classes used by Asciidoctor to style components ADMONITION_CLASSES = %w(fa icon-note icon-tip icon-warning icon-caution icon-important).freeze CALLOUT_CLASSES = ['conum'].freeze @@ -19,14 +22,17 @@ module Banzai td: ['icon'].freeze, i: ADMONITION_CLASSES + CALLOUT_CLASSES + CHECKLIST_CLASSES, ul: LIST_CLASSES, - ol: LIST_CLASSES + ol: LIST_CLASSES, + a: ['anchor'].freeze }.freeze + ALLOWED_HEADERS = %w(h2 h3 h4 h5 h6).freeze + def customize_whitelist(whitelist) # Allow marks whitelist[:elements].push('mark') - # Allow any classes in `span`, `i`, `div`, `td`, `ul` and `ol` elements + # Allow any classes in `span`, `i`, `div`, `td`, `ul`, `ol` and `a` elements # but then remove any unknown classes whitelist[:attributes]['span'] = %w(class) whitelist[:attributes]['div'].push('class') @@ -34,12 +40,32 @@ module Banzai whitelist[:attributes]['i'] = %w(class) whitelist[:attributes]['ul'] = %w(class) whitelist[:attributes]['ol'] = %w(class) + whitelist[:attributes]['a'].push('class') whitelist[:transformers].push(self.class.remove_element_classes) + # Allow `id` in heading elements for section anchors + ALLOWED_HEADERS.each do |header| + whitelist[:attributes][header] = %w(id) + end + whitelist[:transformers].push(self.class.remove_non_heading_ids) + whitelist end class << self + def remove_non_heading_ids + lambda do |env| + node = env[:node] + + return unless ALLOWED_HEADERS.any?(node.name) + return unless node.has_attribute?('id') + + return if node['id'] =~ SECTION_LINK_REF_PATTERN + + node.remove_attribute('id') + end + end + def remove_element_classes lambda do |env| node = env[:node] diff --git a/lib/gitlab/asciidoc.rb b/lib/gitlab/asciidoc.rb index 00c87cce7b6..da65caa6c9c 100644 --- a/lib/gitlab/asciidoc.rb +++ b/lib/gitlab/asciidoc.rb @@ -13,6 +13,7 @@ module Gitlab MAX_INCLUDE_DEPTH = 5 DEFAULT_ADOC_ATTRS = { 'showtitle' => true, + 'sectanchors' => true, 'idprefix' => 'user-content-', 'idseparator' => '-', 'env' => 'gitlab', diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb index ff002acbd35..5293732ead1 100644 --- a/spec/lib/gitlab/asciidoc_spec.rb +++ b/spec/lib/gitlab/asciidoc_spec.rb @@ -96,6 +96,75 @@ module Gitlab end end + context 'with passthrough' do + it 'removes non heading ids' do + input = <<~ADOC + ++++ + <h2 id="foo">Title</h2> + ++++ + ADOC + + output = <<~HTML + <h2>Title</h2> + HTML + + expect(render(input, context)).to include(output.strip) + end + end + + context 'with section anchors' do + it 'preserves ids and links' do + input = <<~ADOC + = Title + + == First section + + This is the first section. + + == Second section + + This is the second section. + + == Thunder ⚡ ! + + This is the third section. + ADOC + + output = <<~HTML + <h1>Title</h1> + <div> + <h2 id="user-content-first-section"> + <a class="anchor" href="#user-content-first-section"></a>First section</h2> + <div> + <div> + <p>This is the first section.</p> + </div> + </div> + </div> + <div> + <h2 id="user-content-second-section"> + <a class="anchor" href="#user-content-second-section"></a>Second section</h2> + <div> + <div> + <p>This is the second section.</p> + </div> + </div> + </div> + <div> + <h2 id="user-content-thunder"> + <a class="anchor" href="#user-content-thunder"></a>Thunder ⚡ !</h2> + <div> + <div> + <p>This is the third section.</p> + </div> + </div> + </div> + HTML + + expect(render(input, context)).to include(output.strip) + end + end + context 'with checklist' do it 'preserves classes' do input = <<~ADOC |