From af6d884f2acadedab9e76f52557a15055f0ef7d6 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 10 Mar 2016 12:46:26 -0500 Subject: Replace `[[_TOC_]]` tag anywhere TableOfContentsFilter is used --- lib/banzai/filter/gollum_tags_filter.rb | 33 ++------------ lib/banzai/filter/table_of_contents_filter.rb | 37 ++++++++++++--- spec/lib/banzai/filter/gollum_tags_filter_spec.rb | 15 ------ .../banzai/filter/table_of_contents_filter_spec.rb | 16 +++++++ spec/lib/banzai/pipeline/full_pipeline_spec.rb | 53 ++++++++++++++++++++++ spec/lib/banzai/pipeline/wiki_pipeline_spec.rb | 53 ---------------------- 6 files changed, 105 insertions(+), 102 deletions(-) create mode 100644 spec/lib/banzai/pipeline/full_pipeline_spec.rb delete mode 100644 spec/lib/banzai/pipeline/wiki_pipeline_spec.rb diff --git a/lib/banzai/filter/gollum_tags_filter.rb b/lib/banzai/filter/gollum_tags_filter.rb index f31f921903b..e18f64e08a4 100644 --- a/lib/banzai/filter/gollum_tags_filter.rb +++ b/lib/banzai/filter/gollum_tags_filter.rb @@ -26,10 +26,6 @@ module Banzai # * [[http://example.com/images/logo.png]] # * [[http://example.com/images/logo.png|alt=Logo]] # - # - Insert a Table of Contents list: - # - # * [[_TOC_]] - # # Based on Gollum::Filter::Tags # # Context options: @@ -61,21 +57,14 @@ module Banzai def call search_text_nodes(doc).each do |node| - # A Gollum ToC tag is `[[_TOC_]]`, but due to MarkdownFilter running - # before this one, it will be converted into `[[TOC]]`, so it - # needs special-case handling - if toc_tag?(node) - process_toc_tag(node) - else - content = node.content + content = node.content - next unless content =~ TAGS_PATTERN + next unless content =~ TAGS_PATTERN - html = process_tag($1) + html = process_tag($1) - if html && html != node.content - node.replace(html) - end + if html && html != node.content + node.replace(html) end end @@ -84,12 +73,6 @@ module Banzai private - # Replace an entire `[[TOC]]` node with the result generated by - # TableOfContentsFilter - def process_toc_tag(node) - node.parent.parent.replace(result[:toc].presence || '') - end - # Process a single tag into its final HTML form. # # tag - The String tag contents (the stuff inside the double brackets). @@ -125,12 +108,6 @@ module Banzai end end - def toc_tag?(node) - node.content == 'TOC' && - node.parent.name == 'em' && - node.parent.parent.text == '[[TOC]]' - end - def image?(path) path =~ ALLOWED_IMAGE_EXTENSIONS end diff --git a/lib/banzai/filter/table_of_contents_filter.rb b/lib/banzai/filter/table_of_contents_filter.rb index 4056dcd6d64..7dce0aa1b42 100644 --- a/lib/banzai/filter/table_of_contents_filter.rb +++ b/lib/banzai/filter/table_of_contents_filter.rb @@ -23,6 +23,16 @@ module Banzai result[:toc] = "" + add_header_anchors + result[:toc] = %Q{} unless result[:toc].empty? + replace_toc_tag + + doc + end + + private + + def add_header_anchors headers = Hash.new(0) doc.css('h1, h2, h3, h4, h5, h6').each do |node| @@ -42,14 +52,8 @@ module Banzai header_content.add_previous_sibling(anchor_tag(href)) end end - - result[:toc] = %Q{} unless result[:toc].empty? - - doc end - private - def anchor_tag(href) %Q{} end @@ -57,6 +61,27 @@ module Banzai def push_toc(href, text) result[:toc] << %Q{
  • #{text}
  • \n} end + + def replace_toc_tag + search_text_nodes(doc).each do |node| + if toc_tag?(node) + process_toc_tag(node) + end + end + end + + # A Gollum-compatible ToC tag is `[[_TOC_]]`, but due to MarkdownFilter + # running before this one, it will be converted into `[[TOC]]` + def toc_tag?(node) + node.content == 'TOC' && + node.parent.name == 'em' && + node.parent.parent.text == '[[TOC]]' + end + + # Replace an entire `[[TOC]]` node with our result + def process_toc_tag(node) + node.parent.parent.replace(result[:toc].presence || '') + end end end end diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb index 5e23c5c319a..38baa819957 100644 --- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb +++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb @@ -86,19 +86,4 @@ describe Banzai::Filter::GollumTagsFilter, lib: true do expect(doc.at_css('a')['href']).to eq 'wiki-slug' end end - - context 'table of contents' do - it 'replaces [[TOC]] with ToC result' do - doc = described_class.call("

    [[TOC]]

    ", { project_wiki: project_wiki }, { toc: "FOO" }) - - expect(doc.to_html).to eq("FOO") - end - - it 'handles an empty ToC result' do - input = "

    [[TOC]]

    " - doc = described_class.call(input, project_wiki: project_wiki) - - expect(doc.to_html).to eq '' - end - end end diff --git a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb index 6a5d003e87f..219a0581d13 100644 --- a/spec/lib/banzai/filter/table_of_contents_filter_spec.rb +++ b/spec/lib/banzai/filter/table_of_contents_filter_spec.rb @@ -70,6 +70,22 @@ describe Banzai::Filter::TableOfContentsFilter, lib: true do end end + describe 'TOC tag' do + it 'replaces [[TOC]] with ToC result' do + doc = described_class.call("

    [[TOC]]

    Foo

    ") + + expect(doc.to_html).not_to include('TOC') + expect(doc.to_html).to include('Foo') + end + + it 'handles an empty ToC result' do + input = "

    [[TOC]]

    " + doc = described_class.call(input) + + expect(doc.to_html).to eq '' + end + end + describe 'result' do def result(html) HTML::Pipeline.new([described_class]).call(html) diff --git a/spec/lib/banzai/pipeline/full_pipeline_spec.rb b/spec/lib/banzai/pipeline/full_pipeline_spec.rb new file mode 100644 index 00000000000..36e5978b70b --- /dev/null +++ b/spec/lib/banzai/pipeline/full_pipeline_spec.rb @@ -0,0 +1,53 @@ +require 'rails_helper' + +describe Banzai::Pipeline::FullPipeline do + describe 'TableOfContents' do + it 'replaces the tag with the TableOfContentsFilter result' do + markdown = <<-MD.strip_heredoc + [[_TOC_]] + + ## Header + + Foo + MD + + result = described_class.call(markdown, project: spy, project_wiki: double) + + aggregate_failures do + expect(result[:output].text).not_to include '[[' + expect(result[:output].text).not_to include 'TOC' + expect(result[:output].to_html).to include(result[:toc]) + end + end + + it 'is case-sensitive' do + markdown = <<-MD.strip_heredoc + [[_toc_]] + + # Header 1 + + Foo + MD + + output = described_class.to_html(markdown, project: spy, project_wiki: double) + + expect(output).to include('[[toc]]') + end + + it 'handles an empty pipeline result' do + # No Markdown headers in this doc, so `result[:toc]` will be empty + markdown = <<-MD.strip_heredoc + [[_TOC_]] + + Foo + MD + + output = described_class.to_html(markdown, project: spy, project_wiki: double) + + aggregate_failures do + expect(output).not_to include('