From: Jean-Philippe Lang Date: Sat, 6 Nov 2010 17:47:27 +0000 (+0000) Subject: Extract headings and TOC parsing from the textile formatter. X-Git-Tag: 1.1.0~199 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=024ff96ee27aa7e61ceec25a351f6800461d5cf3;p=redmine.git Extract headings and TOC parsing from the textile formatter. Fixes #2038 and #3707 and will allow to support TOC with other text formatters. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4376 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index bf4e2d5ba..0e4b0a8c3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2010 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -451,7 +451,7 @@ module ApplicationHelper text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } parse_non_pre_blocks(text) do |text| - [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name| send method_name, text, project, obj, attr, only_path, options end end @@ -673,6 +673,38 @@ module ApplicationHelper leading + (link || "#{prefix}#{sep}#{identifier}") end end + + TOC_RE = /

\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) + HEADING_RE = /]+)?>(.+?)<\/h(1|2|3)>/i unless const_defined?(:HEADING_RE) + + # Headings and TOC + # Adds ids and links to headings and renders the TOC if needed unless options[:headings] is set to false + def parse_headings(text, project, obj, attr, only_path, options) + headings = [] + text.gsub!(HEADING_RE) do + level, attrs, content = $1, $2, $3 + item = strip_tags(content).strip + anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + headings << [level, anchor, item] + "#{content}" + end unless options[:headings] == false + + text.gsub!(TOC_RE) do + if headings.empty? + '' + else + div_class = 'toc' + div_class << ' right' if $1 == '>' + div_class << ' left' if $1 == '<' + out = "

' + out + end + end + end # Same as Rails' simple_format helper without using paragraphs def simple_format_without_paragraph(text) diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index 6f8d09d60..63cd2ab8e 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -112,7 +112,7 @@ module Redmine @included_wiki_pages ||= [] raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) @included_wiki_pages << page.title - out = textilizable(page.content, :text, :attachments => page.attachments) + out = textilizable(page.content, :text, :attachments => page.attachments, :headings => false) @included_wiki_pages.pop out end diff --git a/lib/redmine/wiki_formatting/textile/formatter.rb b/lib/redmine/wiki_formatting/textile/formatter.rb index 6794f82c7..88d52a6c2 100644 --- a/lib/redmine/wiki_formatting/textile/formatter.rb +++ b/lib/redmine/wiki_formatting/textile/formatter.rb @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2010 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -24,7 +24,7 @@ module Redmine include ActionView::Helpers::TagHelper # auto_link rule after textile rules so that it doesn't break !image_url! tags - RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_toc] + RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] def initialize(*args) super @@ -61,51 +61,6 @@ module Redmine end end - # Patch to add 'table of content' support to RedCloth - def textile_p_withtoc(tag, atts, cite, content) - # removes wiki links from the item - toc_item = content.gsub(/(\[\[([^\]\|]*)(\|([^\]]*))?\]\])/) { $4 || $2 } - # sanitizes titles from links - # see redcloth3.rb, same as "#{pre}#{text}#{post}" - toc_item.gsub!(LINK_RE) { [$2, $4, $9].join } - # sanitizes image links from titles - toc_item.gsub!(IMAGE_RE) { [$5].join } - # removes styles - # eg. %{color:red}Triggers% => Triggers - toc_item.gsub! %r[%\{[^\}]*\}([^%]+)%], '\\1' - - # replaces non word caracters by dashes - anchor = toc_item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') - - unless anchor.blank? - if tag =~ /^h(\d)$/ - @toc << [$1.to_i, anchor, toc_item] - end - atts << " id=\"#{anchor}\"" - content = content + "" - end - textile_p(tag, atts, cite, content) - end - - alias :textile_h1 :textile_p_withtoc - alias :textile_h2 :textile_p_withtoc - alias :textile_h3 :textile_p_withtoc - - def inline_toc(text) - text.gsub!(/

\{\{([<>]?)toc\}\}<\/p>/i) do - div_class = 'toc' - div_class << ' right' if $1 == '>' - div_class << ' left' if $1 == '<' - out = "

' - out - end - end - AUTO_LINK_RE = %r{ ( # leading text <\w+.*?>| # leading HTML tag, or diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index 52bb13298..be4c79582 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2009 Jean-Philippe Lang +# Copyright (C) 2006-2010 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -422,6 +422,8 @@ Nullam commodo metus accumsan nulla. Curabitur lobortis dui id dolor. h2. Subtitle with [[Wiki|another Wiki]] link h2. Subtitle with %{color:red}red text% + +h2. Subtitle with *some* _modifiers_ h1. Another title @@ -436,11 +438,31 @@ RAW '
  • Subtitle with a Wiki link
  • ' + '
  • Subtitle with another Wiki link
  • ' + '
  • Subtitle with red text
  • ' + + '
  • Subtitle with some modifiers
  • ' + '
  • Another title
  • ' + '
  • An Internet link inside subtitle
  • ' + '
  • Project Name
  • ' + '' + @project = Project.find(1) + assert textilizable(raw).gsub("\n", "").include?(expected) + end + + def test_table_of_content_should_contain_included_page_headings + raw = <<-RAW +{{toc}} + +h1. Included + +{{include(Child_1)}} +RAW + + expected = '' + + @project = Project.find(1) assert textilizable(raw).gsub("\n", "").include?(expected) end diff --git a/test/unit/lib/redmine/wiki_formatting/macros_test.rb b/test/unit/lib/redmine/wiki_formatting/macros_test.rb index a75289551..da062d68b 100644 --- a/test/unit/lib/redmine/wiki_formatting/macros_test.rb +++ b/test/unit/lib/redmine/wiki_formatting/macros_test.rb @@ -20,6 +20,9 @@ require File.dirname(__FILE__) + '/../../../../test_helper' class Redmine::WikiFormatting::MacrosTest < HelperTestCase include ApplicationHelper include ActionView::Helpers::TextHelper + include ActionView::Helpers::SanitizeHelper + extend ActionView::Helpers::SanitizeHelper::ClassMethods + fixtures :projects, :roles, :enabled_modules, :users, :repositories, :changesets, :trackers, :issue_statuses, :issues,