]> source.dussan.org Git - redmine.git/commitdiff
Extract headings and TOC parsing from the textile formatter.
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 6 Nov 2010 17:47:27 +0000 (17:47 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sat, 6 Nov 2010 17:47:27 +0000 (17:47 +0000)
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

app/helpers/application_helper.rb
lib/redmine/wiki_formatting/macros.rb
lib/redmine/wiki_formatting/textile/formatter.rb
test/unit/helpers/application_helper_test.rb
test/unit/lib/redmine/wiki_formatting/macros_test.rb

index bf4e2d5ba924c9541e5f8bf45f4c03b4aacc33b0..0e4b0a8c3657204bcdd3564d175eb4e043d15e51 100644 (file)
@@ -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 = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
+  HEADING_RE = /<h(1|2|3)( [^>]+)?>(.+?)<\/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]
+      "<h#{level} #{attrs} id=\"#{anchor}\">#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>"
+    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 = "<ul class=\"#{div_class}\">"
+        headings.each do |level, anchor, item|
+          out << "<li class=\"heading#{level}\"><a href=\"##{anchor}\">#{item}</a></li>\n"
+        end
+        out << '</ul>'
+        out
+      end
+    end
+  end
 
   # Same as Rails' simple_format helper without using paragraphs
   def simple_format_without_paragraph(text)
index 6f8d09d609dd3f547e637b435da564a529d7ca48..63cd2ab8e3aa99fa86f5ea4f979d6a13e261e39d 100644 (file)
@@ -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
index 6794f82c79e4fb41ccc53b03727f889091cdd9dd..88d52a6c2673231b155026ac82c16543cf4be2a5 100644 (file)
@@ -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 + "<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a>"
-          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!(/<p>\{\{([<>]?)toc\}\}<\/p>/i) do
-            div_class = 'toc'
-            div_class << ' right' if $1 == '>'
-            div_class << ' left' if $1 == '<'
-            out = "<ul class=\"#{div_class}\">"
-            @toc.each do |heading|
-              level, anchor, toc_item = heading
-              out << "<li class=\"heading#{level}\"><a href=\"##{anchor}\">#{toc_item}</a></li>\n"
-            end
-            out << '</ul>'
-            out
-          end
-        end
-        
         AUTO_LINK_RE = %r{
                         (                          # leading text
                           <\w+.*?>|                # leading HTML tag, or
index 52bb13298149a27b9c8cf3d3d55306c3557c403e..be4c795827478def7f4d7d556db638f9766dc632 100644 (file)
@@ -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
                '<li class="heading2"><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' + 
                '<li class="heading2"><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' + 
                '<li class="heading2"><a href="#Subtitle-with-red-text">Subtitle with red text</a></li>' +
+               '<li class="heading2"><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' +
                '<li class="heading1"><a href="#Another-title">Another title</a></li>' +
                '<li class="heading2"><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' +
                '<li class="heading2"><a href="#Project-Name">Project Name</a></li>' +
                '</ul>'
 
+    @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 = '<ul class="toc">' +
+               '<li class="heading1"><a href="#Included">Included</a></li>' +
+               '<li class="heading1"><a href="#Child-page-1">Child page 1</a></li>' + 
+               '</ul>'
+
+    @project = Project.find(1)
     assert textilizable(raw).gsub("\n", "").include?(expected)
   end
   
index a75289551c1b0817390081370f90cab33e8fade8..da062d68b1170b6367a72b60d0be0189eadeda65 100644 (file)
@@ -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,