summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Grossetie <ggrossetie@gmail.com>2019-07-10 10:30:10 +0200
committerGuillaume Grossetie <ggrossetie@gmail.com>2019-07-17 08:40:50 +0200
commit34c6f2723c3bc44aba1d9d886522fdfe8db6a9f6 (patch)
tree77511b4b3fb511c843ff49098f811bb8bcdba966
parent1e99c1b0a7b4e80be5a0be40aebb7f4cad0077de (diff)
downloadgitlab-ce-34c6f2723c3bc44aba1d9d886522fdfe8db6a9f6.tar.gz
Preserve footnote link ids
-rw-r--r--changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml5
-rw-r--r--lib/banzai/filter/ascii_doc_sanitization_filter.rb33
-rw-r--r--spec/lib/gitlab/asciidoc_spec.rb50
3 files changed, 83 insertions, 5 deletions
diff --git a/changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml b/changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml
new file mode 100644
index 00000000000..5427a035478
--- /dev/null
+++ b/changelogs/unreleased/64645-asciidoctor-preserve-footnote-link-ids.yml
@@ -0,0 +1,5 @@
+---
+title: "Preserve footnote link ids in Asciidoctor"
+merge_request: 30790
+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 d8d63075752..9105e86ad04 100644
--- a/lib/banzai/filter/ascii_doc_sanitization_filter.rb
+++ b/lib/banzai/filter/ascii_doc_sanitization_filter.rb
@@ -8,12 +8,18 @@ module Banzai
class AsciiDocSanitizationFilter < Banzai::Filter::BaseSanitizationFilter
# Section anchor link pattern
SECTION_LINK_REF_PATTERN = /\A#{Gitlab::Asciidoc::DEFAULT_ADOC_ATTRS['idprefix']}(:?[[:alnum:]]|-|_)+\z/.freeze
+ SECTION_HEADINGS = %w(h2 h3 h4 h5 h6).freeze
+
+ # Footnote link patterns
+ FOOTNOTE_LINK_ID_PATTERNS = {
+ a: /\A_footnoteref_\d+\z/,
+ div: /\A_footnotedef_\d+\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
CHECKLIST_CLASSES = %w(fa fa-check-square-o fa-square-o).freeze
-
LIST_CLASSES = %w(checklist none no-bullet unnumbered unstyled).freeze
ELEMENT_CLASSES_WHITELIST = {
@@ -26,8 +32,6 @@ module Banzai
a: ['anchor'].freeze
}.freeze
- ALLOWED_HEADERS = %w(h2 h3 h4 h5 h6).freeze
-
def customize_whitelist(whitelist)
# Allow marks
whitelist[:elements].push('mark')
@@ -44,20 +48,39 @@ module Banzai
whitelist[:transformers].push(self.class.remove_element_classes)
# Allow `id` in heading elements for section anchors
- ALLOWED_HEADERS.each do |header|
+ SECTION_HEADINGS.each do |header|
whitelist[:attributes][header] = %w(id)
end
whitelist[:transformers].push(self.class.remove_non_heading_ids)
+ # Allow `id` in footnote elements
+ FOOTNOTE_LINK_ID_PATTERNS.keys.each do |element|
+ whitelist[:attributes][element.to_s].push('id')
+ end
+ whitelist[:transformers].push(self.class.remove_non_footnote_ids)
+
whitelist
end
class << self
+ def remove_non_footnote_ids
+ lambda do |env|
+ node = env[:node]
+
+ return unless (pattern = FOOTNOTE_LINK_ID_PATTERNS[node.name.to_sym])
+ return unless node.has_attribute?('id')
+
+ return if node['id'] =~ pattern
+
+ node.remove_attribute('id')
+ end
+ end
+
def remove_non_heading_ids
lambda do |env|
node = env[:node]
- return unless ALLOWED_HEADERS.any?(node.name)
+ return unless SECTION_HEADINGS.any?(node.name)
return unless node.has_attribute?('id')
return if node['id'] =~ SECTION_LINK_REF_PATTERN
diff --git a/spec/lib/gitlab/asciidoc_spec.rb b/spec/lib/gitlab/asciidoc_spec.rb
index 5293732ead1..cbd4a509a55 100644
--- a/spec/lib/gitlab/asciidoc_spec.rb
+++ b/spec/lib/gitlab/asciidoc_spec.rb
@@ -110,6 +110,56 @@ module Gitlab
expect(render(input, context)).to include(output.strip)
end
+
+ it 'removes non footnote def ids' do
+ input = <<~ADOC
+ ++++
+ <div id="def">Footnote definition</div>
+ ++++
+ ADOC
+
+ output = <<~HTML
+ <div>Footnote definition</div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+
+ it 'removes non footnote ref ids' do
+ input = <<~ADOC
+ ++++
+ <a id="ref">Footnote reference</a>
+ ++++
+ ADOC
+
+ output = <<~HTML
+ <a>Footnote reference</a>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
+ end
+
+ context 'with footnotes' do
+ it 'preserves ids and links' do
+ input = <<~ADOC
+ This paragraph has a footnote.footnote:[This is the text of the footnote.]
+ ADOC
+
+ output = <<~HTML
+ <div>
+ <p>This paragraph has a footnote.<sup>[<a id="_footnoteref_1" href="#_footnotedef_1" title="View footnote.">1</a>]</sup></p>
+ </div>
+ <div>
+ <hr>
+ <div id="_footnotedef_1">
+ <a href="#_footnoteref_1">1</a>. This is the text of the footnote.
+ </div>
+ </div>
+ HTML
+
+ expect(render(input, context)).to include(output.strip)
+ end
end
context 'with section anchors' do