@@ -1,5 +1,5 | |||||
1 |
# |
|
1 | # Redmine - project management software | |
2 |
# Copyright (C) 2006-200 |
|
2 | # Copyright (C) 2006-2010 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # modify it under the terms of the GNU General Public License | |
@@ -451,7 +451,7 module ApplicationHelper | |||||
451 | text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } |
|
451 | text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } | |
452 |
|
452 | |||
453 | parse_non_pre_blocks(text) do |text| |
|
453 | parse_non_pre_blocks(text) do |text| | |
454 | [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| |
|
454 | [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name| | |
455 | send method_name, text, project, obj, attr, only_path, options |
|
455 | send method_name, text, project, obj, attr, only_path, options | |
456 | end |
|
456 | end | |
457 | end |
|
457 | end | |
@@ -673,6 +673,38 module ApplicationHelper | |||||
673 | leading + (link || "#{prefix}#{sep}#{identifier}") |
|
673 | leading + (link || "#{prefix}#{sep}#{identifier}") | |
674 | end |
|
674 | end | |
675 | end |
|
675 | end | |
|
676 | ||||
|
677 | TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) | |||
|
678 | HEADING_RE = /<h(1|2|3)( [^>]+)?>(.+?)<\/h(1|2|3)>/i unless const_defined?(:HEADING_RE) | |||
|
679 | ||||
|
680 | # Headings and TOC | |||
|
681 | # Adds ids and links to headings and renders the TOC if needed unless options[:headings] is set to false | |||
|
682 | def parse_headings(text, project, obj, attr, only_path, options) | |||
|
683 | headings = [] | |||
|
684 | text.gsub!(HEADING_RE) do | |||
|
685 | level, attrs, content = $1, $2, $3 | |||
|
686 | item = strip_tags(content).strip | |||
|
687 | anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') | |||
|
688 | headings << [level, anchor, item] | |||
|
689 | "<h#{level} #{attrs} id=\"#{anchor}\">#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">¶</a></h#{level}>" | |||
|
690 | end unless options[:headings] == false | |||
|
691 | ||||
|
692 | text.gsub!(TOC_RE) do | |||
|
693 | if headings.empty? | |||
|
694 | '' | |||
|
695 | else | |||
|
696 | div_class = 'toc' | |||
|
697 | div_class << ' right' if $1 == '>' | |||
|
698 | div_class << ' left' if $1 == '<' | |||
|
699 | out = "<ul class=\"#{div_class}\">" | |||
|
700 | headings.each do |level, anchor, item| | |||
|
701 | out << "<li class=\"heading#{level}\"><a href=\"##{anchor}\">#{item}</a></li>\n" | |||
|
702 | end | |||
|
703 | out << '</ul>' | |||
|
704 | out | |||
|
705 | end | |||
|
706 | end | |||
|
707 | end | |||
676 |
|
708 | |||
677 | # Same as Rails' simple_format helper without using paragraphs |
|
709 | # Same as Rails' simple_format helper without using paragraphs | |
678 | def simple_format_without_paragraph(text) |
|
710 | def simple_format_without_paragraph(text) |
@@ -112,7 +112,7 module Redmine | |||||
112 | @included_wiki_pages ||= [] |
|
112 | @included_wiki_pages ||= [] | |
113 | raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) |
|
113 | raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) | |
114 | @included_wiki_pages << page.title |
|
114 | @included_wiki_pages << page.title | |
115 | out = textilizable(page.content, :text, :attachments => page.attachments) |
|
115 | out = textilizable(page.content, :text, :attachments => page.attachments, :headings => false) | |
116 | @included_wiki_pages.pop |
|
116 | @included_wiki_pages.pop | |
117 | out |
|
117 | out | |
118 | end |
|
118 | end |
@@ -1,5 +1,5 | |||||
1 | # Redmine - project management software |
|
1 | # Redmine - project management software | |
2 |
# Copyright (C) 2006-200 |
|
2 | # Copyright (C) 2006-2010 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # modify it under the terms of the GNU General Public License | |
@@ -24,7 +24,7 module Redmine | |||||
24 | include ActionView::Helpers::TagHelper |
|
24 | include ActionView::Helpers::TagHelper | |
25 |
|
25 | |||
26 | # auto_link rule after textile rules so that it doesn't break !image_url! tags |
|
26 | # auto_link rule after textile rules so that it doesn't break !image_url! tags | |
27 |
RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto |
|
27 | RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] | |
28 |
|
28 | |||
29 | def initialize(*args) |
|
29 | def initialize(*args) | |
30 | super |
|
30 | super | |
@@ -61,51 +61,6 module Redmine | |||||
61 | end |
|
61 | end | |
62 | end |
|
62 | end | |
63 |
|
63 | |||
64 | # Patch to add 'table of content' support to RedCloth |
|
|||
65 | def textile_p_withtoc(tag, atts, cite, content) |
|
|||
66 | # removes wiki links from the item |
|
|||
67 | toc_item = content.gsub(/(\[\[([^\]\|]*)(\|([^\]]*))?\]\])/) { $4 || $2 } |
|
|||
68 | # sanitizes titles from links |
|
|||
69 | # see redcloth3.rb, same as "#{pre}#{text}#{post}" |
|
|||
70 | toc_item.gsub!(LINK_RE) { [$2, $4, $9].join } |
|
|||
71 | # sanitizes image links from titles |
|
|||
72 | toc_item.gsub!(IMAGE_RE) { [$5].join } |
|
|||
73 | # removes styles |
|
|||
74 | # eg. %{color:red}Triggers% => Triggers |
|
|||
75 | toc_item.gsub! %r[%\{[^\}]*\}([^%]+)%], '\\1' |
|
|||
76 |
|
||||
77 | # replaces non word caracters by dashes |
|
|||
78 | anchor = toc_item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') |
|
|||
79 |
|
||||
80 | unless anchor.blank? |
|
|||
81 | if tag =~ /^h(\d)$/ |
|
|||
82 | @toc << [$1.to_i, anchor, toc_item] |
|
|||
83 | end |
|
|||
84 | atts << " id=\"#{anchor}\"" |
|
|||
85 | content = content + "<a href=\"##{anchor}\" class=\"wiki-anchor\">¶</a>" |
|
|||
86 | end |
|
|||
87 | textile_p(tag, atts, cite, content) |
|
|||
88 | end |
|
|||
89 |
|
||||
90 | alias :textile_h1 :textile_p_withtoc |
|
|||
91 | alias :textile_h2 :textile_p_withtoc |
|
|||
92 | alias :textile_h3 :textile_p_withtoc |
|
|||
93 |
|
||||
94 | def inline_toc(text) |
|
|||
95 | text.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i) do |
|
|||
96 | div_class = 'toc' |
|
|||
97 | div_class << ' right' if $1 == '>' |
|
|||
98 | div_class << ' left' if $1 == '<' |
|
|||
99 | out = "<ul class=\"#{div_class}\">" |
|
|||
100 | @toc.each do |heading| |
|
|||
101 | level, anchor, toc_item = heading |
|
|||
102 | out << "<li class=\"heading#{level}\"><a href=\"##{anchor}\">#{toc_item}</a></li>\n" |
|
|||
103 | end |
|
|||
104 | out << '</ul>' |
|
|||
105 | out |
|
|||
106 | end |
|
|||
107 | end |
|
|||
108 |
|
||||
109 | AUTO_LINK_RE = %r{ |
|
64 | AUTO_LINK_RE = %r{ | |
110 | ( # leading text |
|
65 | ( # leading text | |
111 | <\w+.*?>| # leading HTML tag, or |
|
66 | <\w+.*?>| # leading HTML tag, or |
@@ -1,5 +1,5 | |||||
1 | # Redmine - project management software |
|
1 | # Redmine - project management software | |
2 |
# Copyright (C) 2006-200 |
|
2 | # Copyright (C) 2006-2010 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # 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. | |||||
422 | h2. Subtitle with [[Wiki|another Wiki]] link |
|
422 | h2. Subtitle with [[Wiki|another Wiki]] link | |
423 |
|
423 | |||
424 | h2. Subtitle with %{color:red}red text% |
|
424 | h2. Subtitle with %{color:red}red text% | |
|
425 | ||||
|
426 | h2. Subtitle with *some* _modifiers_ | |||
425 |
|
427 | |||
426 | h1. Another title |
|
428 | h1. Another title | |
427 |
|
429 | |||
@@ -436,11 +438,31 RAW | |||||
436 | '<li class="heading2"><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' + |
|
438 | '<li class="heading2"><a href="#Subtitle-with-a-Wiki-link">Subtitle with a Wiki link</a></li>' + | |
437 | '<li class="heading2"><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' + |
|
439 | '<li class="heading2"><a href="#Subtitle-with-another-Wiki-link">Subtitle with another Wiki link</a></li>' + | |
438 | '<li class="heading2"><a href="#Subtitle-with-red-text">Subtitle with red text</a></li>' + |
|
440 | '<li class="heading2"><a href="#Subtitle-with-red-text">Subtitle with red text</a></li>' + | |
|
441 | '<li class="heading2"><a href="#Subtitle-with-some-modifiers">Subtitle with some modifiers</a></li>' + | |||
439 | '<li class="heading1"><a href="#Another-title">Another title</a></li>' + |
|
442 | '<li class="heading1"><a href="#Another-title">Another title</a></li>' + | |
440 | '<li class="heading2"><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' + |
|
443 | '<li class="heading2"><a href="#An-Internet-link-inside-subtitle">An Internet link inside subtitle</a></li>' + | |
441 | '<li class="heading2"><a href="#Project-Name">Project Name</a></li>' + |
|
444 | '<li class="heading2"><a href="#Project-Name">Project Name</a></li>' + | |
442 | '</ul>' |
|
445 | '</ul>' | |
443 |
|
446 | |||
|
447 | @project = Project.find(1) | |||
|
448 | assert textilizable(raw).gsub("\n", "").include?(expected) | |||
|
449 | end | |||
|
450 | ||||
|
451 | def test_table_of_content_should_contain_included_page_headings | |||
|
452 | raw = <<-RAW | |||
|
453 | {{toc}} | |||
|
454 | ||||
|
455 | h1. Included | |||
|
456 | ||||
|
457 | {{include(Child_1)}} | |||
|
458 | RAW | |||
|
459 | ||||
|
460 | expected = '<ul class="toc">' + | |||
|
461 | '<li class="heading1"><a href="#Included">Included</a></li>' + | |||
|
462 | '<li class="heading1"><a href="#Child-page-1">Child page 1</a></li>' + | |||
|
463 | '</ul>' | |||
|
464 | ||||
|
465 | @project = Project.find(1) | |||
444 | assert textilizable(raw).gsub("\n", "").include?(expected) |
|
466 | assert textilizable(raw).gsub("\n", "").include?(expected) | |
445 | end |
|
467 | end | |
446 |
|
468 |
@@ -20,6 +20,9 require File.dirname(__FILE__) + '/../../../../test_helper' | |||||
20 | class Redmine::WikiFormatting::MacrosTest < HelperTestCase |
|
20 | class Redmine::WikiFormatting::MacrosTest < HelperTestCase | |
21 | include ApplicationHelper |
|
21 | include ApplicationHelper | |
22 | include ActionView::Helpers::TextHelper |
|
22 | include ActionView::Helpers::TextHelper | |
|
23 | include ActionView::Helpers::SanitizeHelper | |||
|
24 | extend ActionView::Helpers::SanitizeHelper::ClassMethods | |||
|
25 | ||||
23 | fixtures :projects, :roles, :enabled_modules, :users, |
|
26 | fixtures :projects, :roles, :enabled_modules, :users, | |
24 | :repositories, :changesets, |
|
27 | :repositories, :changesets, | |
25 | :trackers, :issue_statuses, :issues, |
|
28 | :trackers, :issue_statuses, :issues, |
General Comments 0
You need to be logged in to leave comments.
Login now