Commit 2860cfaa authored by Nick Thomas's avatar Nick Thomas 💃

Merge branch 'issue-64645-asciidoctor-footnote-links' into 'master'

Preserve footnote link ids

Closes #64645

See merge request gitlab-org/gitlab-ce!30790
parents f6399f1d 34c6f272
---
title: "Preserve footnote link ids in Asciidoctor"
merge_request: 30790
author: Guillaume Grossetie
type: added
\ No newline at end of file
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment