diff options
Diffstat (limited to 'lib/banzai/filter')
-rw-r--r-- | lib/banzai/filter/references/reference_cache.rb | 57 | ||||
-rw-r--r-- | lib/banzai/filter/table_of_contents_tag_filter.rb | 44 |
2 files changed, 74 insertions, 27 deletions
diff --git a/lib/banzai/filter/references/reference_cache.rb b/lib/banzai/filter/references/reference_cache.rb index 24b8b4984cd..816ce973cad 100644 --- a/lib/banzai/filter/references/reference_cache.rb +++ b/lib/banzai/filter/references/reference_cache.rb @@ -28,20 +28,11 @@ module Banzai @references_per_parent[parent_type] ||= begin refs = Hash.new { |hash, key| hash[key] = Set.new } - nodes.each do |node| - prepare_node_for_scan(node).scan(regex) do - parent_path = if parent_type == :project - full_project_path($~[:namespace], $~[:project]) - else - full_group_path($~[:group]) - end - - ident = filter.identifier($~) - refs[parent_path] << ident if ident - end + if Feature.enabled?(:milestone_reference_pattern, default_enabled: :yaml) + doc_search(refs) + else + node_search(nodes, refs) end - - refs end end @@ -172,6 +163,39 @@ module Banzai delegate :project, :group, :parent, :parent_type, to: :filter + # Deprecated: https://gitlab.com/gitlab-org/gitlab/-/issues/336268 + def node_search(nodes, refs) + nodes.each do |node| + prepare_node_for_scan(node).scan(regex) do + parent_path = if parent_type == :project + full_project_path($~[:namespace], $~[:project]) + else + full_group_path($~[:group]) + end + + ident = filter.identifier($~) + refs[parent_path] << ident if ident + end + end + + refs + end + + def doc_search(refs) + prepare_doc_for_scan(filter.doc).to_enum(:scan, regex).each do + parent_path = if parent_type == :project + full_project_path($~[:namespace], $~[:project]) + else + full_group_path($~[:group]) + end + + ident = filter.identifier($~) + refs[parent_path] << ident if ident + end + + refs + end + def regex strong_memoize(:regex) do [ @@ -185,6 +209,13 @@ module Banzai Gitlab::SafeRequestStore["banzai_#{parent_type}_refs".to_sym] ||= {} end + def prepare_doc_for_scan(doc) + html = doc.to_html + + filter.requires_unescaping? ? unescape_html_entities(html) : html + end + + # Deprecated: https://gitlab.com/gitlab-org/gitlab/-/issues/336268 def prepare_node_for_scan(node) html = node.to_html diff --git a/lib/banzai/filter/table_of_contents_tag_filter.rb b/lib/banzai/filter/table_of_contents_tag_filter.rb index 13d0a6a4cc7..4e80b543e2d 100644 --- a/lib/banzai/filter/table_of_contents_tag_filter.rb +++ b/lib/banzai/filter/table_of_contents_tag_filter.rb @@ -2,26 +2,31 @@ module Banzai module Filter - # Using `[[_TOC_]]`, inserts a Table of Contents list. - # This syntax is based on the Gollum syntax. This way we have - # some consistency between with wiki and normal markdown. - # If there ever emerges a markdown standard, we can implement - # that here. + # Using `[[_TOC_]]` or `[TOC]` (both case insensitive), inserts a Table of Contents list. # + # `[[_TOC_]]` is based on the Gollum syntax. This way we have + # some consistency between with wiki and normal markdown. # The support for this has been removed from GollumTagsFilter # + # `[toc]` is a generally accepted form, used by Typora for example. + # # Based on Banzai::Filter::GollumTagsFilter class TableOfContentsTagFilter < HTML::Pipeline::Filter - TEXT_QUERY = %q(descendant-or-self::text()[ancestor::p and contains(., 'TOC')]) + TEXT_QUERY = %q(descendant-or-self::text()[ancestor::p and contains(translate(., 'TOC', 'toc'), 'toc')]) def call return doc if context[:no_header_anchors] doc.xpath(TEXT_QUERY).each do |node| - # A Gollum ToC tag is `[[_TOC_]]`, but due to MarkdownFilter running - # before this one, it will be converted into `[[<em>TOC</em>]]`, so it - # needs special-case handling - process_toc_tag(node) if toc_tag?(node) + if toc_tag?(node) + # Support [TOC] / [toc] tags, which don't have a wrapping <em>-tag + process_toc_tag(node) + elsif toc_tag_em?(node) + # Support Gollum like ToC tag (`[[_TOC_]]` / `[[_toc_]]`), which will be converted + # into `[[<em>TOC</em>]]` by the markdown filter, so it + # needs special-case handling + process_toc_tag_em(node) + end end doc @@ -31,14 +36,25 @@ module Banzai # Replace an entire `[[<em>TOC</em>]]` node with the result generated by # TableOfContentsFilter + def process_toc_tag_em(node) + process_toc_tag(node.parent) + end + + # Replace an entire `[TOC]` node with the result generated by + # TableOfContentsFilter def process_toc_tag(node) - node.parent.parent.replace(result[:toc].presence || '') + # we still need to go one step up to also replace the surrounding <p></p> + node.parent.replace(result[:toc].presence || '') end - def toc_tag?(node) - node.content == 'TOC' && + def toc_tag_em?(node) + node.content.casecmp?('toc') && node.parent.name == 'em' && - node.parent.parent.text == '[[TOC]]' + node.parent.parent.text.casecmp?('[[toc]]') + end + + def toc_tag?(node) + node.parent.text.casecmp?('[toc]') end end end |