##// END OF EJS Templates
Add Redcloth's :block_markdown_rule to allow horizontal rules in wiki (#967)....
Jean-Philippe Lang -
r1374:6d637ad98255
parent child
Show More
@@ -1,168 +1,168
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'redcloth'
18 require 'redcloth'
19 require 'coderay'
19 require 'coderay'
20
20
21 module Redmine
21 module Redmine
22 module WikiFormatting
22 module WikiFormatting
23
23
24 private
24 private
25
25
26 class TextileFormatter < RedCloth
26 class TextileFormatter < RedCloth
27
27
28 # auto_link rule after textile rules so that it doesn't break !image_url! tags
28 # auto_link rule after textile rules so that it doesn't break !image_url! tags
29 RULES = [:textile, :inline_auto_link, :inline_auto_mailto, :inline_toc, :inline_macros]
29 RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_toc, :inline_macros]
30
30
31 def initialize(*args)
31 def initialize(*args)
32 super
32 super
33 self.hard_breaks=true
33 self.hard_breaks=true
34 self.no_span_caps=true
34 self.no_span_caps=true
35 end
35 end
36
36
37 def to_html(*rules, &block)
37 def to_html(*rules, &block)
38 @toc = []
38 @toc = []
39 @macros_runner = block
39 @macros_runner = block
40 super(*RULES).to_s
40 super(*RULES).to_s
41 end
41 end
42
42
43 private
43 private
44
44
45 # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet.
45 # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet.
46 # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
46 # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
47 def hard_break( text )
47 def hard_break( text )
48 text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
48 text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
49 end
49 end
50
50
51 # Patch to add code highlighting support to RedCloth
51 # Patch to add code highlighting support to RedCloth
52 def smooth_offtags( text )
52 def smooth_offtags( text )
53 unless @pre_list.empty?
53 unless @pre_list.empty?
54 ## replace <pre> content
54 ## replace <pre> content
55 text.gsub!(/<redpre#(\d+)>/) do
55 text.gsub!(/<redpre#(\d+)>/) do
56 content = @pre_list[$1.to_i]
56 content = @pre_list[$1.to_i]
57 if content.match(/<code\s+class="(\w+)">\s?(.+)/m)
57 if content.match(/<code\s+class="(\w+)">\s?(.+)/m)
58 content = "<code class=\"#{$1} CodeRay\">" +
58 content = "<code class=\"#{$1} CodeRay\">" +
59 CodeRay.scan($2, $1).html(:escape => false, :line_numbers => :inline)
59 CodeRay.scan($2, $1).html(:escape => false, :line_numbers => :inline)
60 end
60 end
61 content
61 content
62 end
62 end
63 end
63 end
64 end
64 end
65
65
66 # Patch to add 'table of content' support to RedCloth
66 # Patch to add 'table of content' support to RedCloth
67 def textile_p_withtoc(tag, atts, cite, content)
67 def textile_p_withtoc(tag, atts, cite, content)
68 if tag =~ /^h(\d)$/
68 if tag =~ /^h(\d)$/
69 @toc << [$1.to_i, content]
69 @toc << [$1.to_i, content]
70 end
70 end
71 content = "<a name=\"#{@toc.length}\" class=\"wiki-page\"></a>" + content
71 content = "<a name=\"#{@toc.length}\" class=\"wiki-page\"></a>" + content
72 textile_p(tag, atts, cite, content)
72 textile_p(tag, atts, cite, content)
73 end
73 end
74
74
75 alias :textile_h1 :textile_p_withtoc
75 alias :textile_h1 :textile_p_withtoc
76 alias :textile_h2 :textile_p_withtoc
76 alias :textile_h2 :textile_p_withtoc
77 alias :textile_h3 :textile_p_withtoc
77 alias :textile_h3 :textile_p_withtoc
78
78
79 def inline_toc(text)
79 def inline_toc(text)
80 text.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i) do
80 text.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i) do
81 div_class = 'toc'
81 div_class = 'toc'
82 div_class << ' right' if $1 == '>'
82 div_class << ' right' if $1 == '>'
83 div_class << ' left' if $1 == '<'
83 div_class << ' left' if $1 == '<'
84 out = "<div class=\"#{div_class}\">"
84 out = "<div class=\"#{div_class}\">"
85 @toc.each_with_index do |heading, index|
85 @toc.each_with_index do |heading, index|
86 # remove wiki links from the item
86 # remove wiki links from the item
87 toc_item = heading.last.gsub(/(\[\[|\]\])/, '')
87 toc_item = heading.last.gsub(/(\[\[|\]\])/, '')
88 out << "<a href=\"##{index+1}\" class=\"heading#{heading.first}\">#{toc_item}</a>"
88 out << "<a href=\"##{index+1}\" class=\"heading#{heading.first}\">#{toc_item}</a>"
89 end
89 end
90 out << '</div>'
90 out << '</div>'
91 out
91 out
92 end
92 end
93 end
93 end
94
94
95 MACROS_RE = /
95 MACROS_RE = /
96 (!)? # escaping
96 (!)? # escaping
97 (
97 (
98 \{\{ # opening tag
98 \{\{ # opening tag
99 ([\w]+) # macro name
99 ([\w]+) # macro name
100 (\(([^\}]*)\))? # optional arguments
100 (\(([^\}]*)\))? # optional arguments
101 \}\} # closing tag
101 \}\} # closing tag
102 )
102 )
103 /x unless const_defined?(:MACROS_RE)
103 /x unless const_defined?(:MACROS_RE)
104
104
105 def inline_macros(text)
105 def inline_macros(text)
106 text.gsub!(MACROS_RE) do
106 text.gsub!(MACROS_RE) do
107 esc, all, macro = $1, $2, $3.downcase
107 esc, all, macro = $1, $2, $3.downcase
108 args = ($5 || '').split(',').each(&:strip)
108 args = ($5 || '').split(',').each(&:strip)
109 if esc.nil?
109 if esc.nil?
110 begin
110 begin
111 @macros_runner.call(macro, args)
111 @macros_runner.call(macro, args)
112 rescue => e
112 rescue => e
113 "<div class=\"flash error\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>"
113 "<div class=\"flash error\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>"
114 end || all
114 end || all
115 else
115 else
116 all
116 all
117 end
117 end
118 end
118 end
119 end
119 end
120
120
121 AUTO_LINK_RE = %r{
121 AUTO_LINK_RE = %r{
122 ( # leading text
122 ( # leading text
123 <\w+.*?>| # leading HTML tag, or
123 <\w+.*?>| # leading HTML tag, or
124 [^=<>!:'"/]| # leading punctuation, or
124 [^=<>!:'"/]| # leading punctuation, or
125 ^ # beginning of line
125 ^ # beginning of line
126 )
126 )
127 (
127 (
128 (?:https?://)| # protocol spec, or
128 (?:https?://)| # protocol spec, or
129 (?:www\.) # www.*
129 (?:www\.) # www.*
130 )
130 )
131 (
131 (
132 (\S+?) # url
132 (\S+?) # url
133 (\/)? # slash
133 (\/)? # slash
134 )
134 )
135 ([^\w\=\/;]*?) # post
135 ([^\w\=\/;]*?) # post
136 (?=<|\s|$)
136 (?=<|\s|$)
137 }x unless const_defined?(:AUTO_LINK_RE)
137 }x unless const_defined?(:AUTO_LINK_RE)
138
138
139 # Turns all urls into clickable links (code from Rails).
139 # Turns all urls into clickable links (code from Rails).
140 def inline_auto_link(text)
140 def inline_auto_link(text)
141 text.gsub!(AUTO_LINK_RE) do
141 text.gsub!(AUTO_LINK_RE) do
142 all, leading, proto, url, post = $&, $1, $2, $3, $6
142 all, leading, proto, url, post = $&, $1, $2, $3, $6
143 if leading =~ /<a\s/i || leading =~ /![<>=]?/
143 if leading =~ /<a\s/i || leading =~ /![<>=]?/
144 # don't replace URL's that are already linked
144 # don't replace URL's that are already linked
145 # and URL's prefixed with ! !> !< != (textile images)
145 # and URL's prefixed with ! !> !< != (textile images)
146 all
146 all
147 else
147 else
148 %(#{leading}<a class="external" href="#{proto=="www."?"http://www.":proto}#{url}">#{proto + url}</a>#{post})
148 %(#{leading}<a class="external" href="#{proto=="www."?"http://www.":proto}#{url}">#{proto + url}</a>#{post})
149 end
149 end
150 end
150 end
151 end
151 end
152
152
153 # Turns all email addresses into clickable links (code from Rails).
153 # Turns all email addresses into clickable links (code from Rails).
154 def inline_auto_mailto(text)
154 def inline_auto_mailto(text)
155 text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
155 text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
156 text = $1
156 text = $1
157 %{<a href="mailto:#{$1}" class="email">#{text}</a>}
157 %{<a href="mailto:#{$1}" class="email">#{text}</a>}
158 end
158 end
159 end
159 end
160 end
160 end
161
161
162 public
162 public
163
163
164 def self.to_html(text, options = {}, &block)
164 def self.to_html(text, options = {}, &block)
165 TextileFormatter.new(text).to_html(&block)
165 TextileFormatter.new(text).to_html(&block)
166 end
166 end
167 end
167 end
168 end
168 end
@@ -1,216 +1,221
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 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
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../../test_helper'
18 require File.dirname(__FILE__) + '/../../test_helper'
19
19
20 class ApplicationHelperTest < HelperTestCase
20 class ApplicationHelperTest < HelperTestCase
21 include ApplicationHelper
21 include ApplicationHelper
22 include ActionView::Helpers::TextHelper
22 include ActionView::Helpers::TextHelper
23 fixtures :projects, :repositories, :changesets, :trackers, :issue_statuses, :issues, :documents, :versions, :wikis, :wiki_pages, :wiki_contents, :roles, :enabled_modules
23 fixtures :projects, :repositories, :changesets, :trackers, :issue_statuses, :issues, :documents, :versions, :wikis, :wiki_pages, :wiki_contents, :roles, :enabled_modules
24
24
25 def setup
25 def setup
26 super
26 super
27 end
27 end
28
28
29 def test_auto_links
29 def test_auto_links
30 to_test = {
30 to_test = {
31 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
31 'http://foo.bar' => '<a class="external" href="http://foo.bar">http://foo.bar</a>',
32 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
32 'http://foo.bar/~user' => '<a class="external" href="http://foo.bar/~user">http://foo.bar/~user</a>',
33 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
33 'http://foo.bar.' => '<a class="external" href="http://foo.bar">http://foo.bar</a>.',
34 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
34 'http://foo.bar/foo.bar#foo.bar.' => '<a class="external" href="http://foo.bar/foo.bar#foo.bar">http://foo.bar/foo.bar#foo.bar</a>.',
35 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
35 'www.foo.bar' => '<a class="external" href="http://www.foo.bar">www.foo.bar</a>',
36 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
36 'http://foo.bar/page?p=1&t=z&s=' => '<a class="external" href="http://foo.bar/page?p=1&#38;t=z&#38;s=">http://foo.bar/page?p=1&#38;t=z&#38;s=</a>',
37 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>'
37 'http://foo.bar/page#125' => '<a class="external" href="http://foo.bar/page#125">http://foo.bar/page#125</a>'
38 }
38 }
39 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
39 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
40 end
40 end
41
41
42 def test_auto_mailto
42 def test_auto_mailto
43 assert_equal '<p><a href="mailto:test@foo.bar" class="email">test@foo.bar</a></p>',
43 assert_equal '<p><a href="mailto:test@foo.bar" class="email">test@foo.bar</a></p>',
44 textilizable('test@foo.bar')
44 textilizable('test@foo.bar')
45 end
45 end
46
46
47 def test_inline_images
47 def test_inline_images
48 to_test = {
48 to_test = {
49 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
49 '!http://foo.bar/image.jpg!' => '<img src="http://foo.bar/image.jpg" alt="" />',
50 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
50 'floating !>http://foo.bar/image.jpg!' => 'floating <div style="float:right"><img src="http://foo.bar/image.jpg" alt="" /></div>',
51 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
51 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class <img src="http://foo.bar/image.jpg" class="some-class" alt="" />',
52 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height100px;" alt="" />',
52 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style <img src="http://foo.bar/image.jpg" style="width:100px;height100px;" alt="" />',
53 }
53 }
54 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
54 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
55 end
55 end
56
56
57 def test_textile_external_links
57 def test_textile_external_links
58 to_test = {
58 to_test = {
59 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
59 'This is a "link":http://foo.bar' => 'This is a <a href="http://foo.bar" class="external">link</a>',
60 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
60 'This is an intern "link":/foo/bar' => 'This is an intern <a href="/foo/bar">link</a>',
61 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>'
61 '"link (Link title)":http://foo.bar' => '<a href="http://foo.bar" title="Link title" class="external">link</a>'
62 }
62 }
63 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
63 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
64 end
64 end
65
65
66 def test_redmine_links
66 def test_redmine_links
67 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
67 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
68 :class => 'issue', :title => 'Error 281 when updating a recipe (New)')
68 :class => 'issue', :title => 'Error 281 when updating a recipe (New)')
69
69
70 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
70 changeset_link = link_to('r1', {:controller => 'repositories', :action => 'revision', :id => 'ecookbook', :rev => 1},
71 :class => 'changeset', :title => 'My very first commit')
71 :class => 'changeset', :title => 'My very first commit')
72
72
73 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
73 document_link = link_to('Test document', {:controller => 'documents', :action => 'show', :id => 1},
74 :class => 'document')
74 :class => 'document')
75
75
76 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
76 version_link = link_to('1.0', {:controller => 'versions', :action => 'show', :id => 2},
77 :class => 'version')
77 :class => 'version')
78
78
79 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => 'some/file'}
79 source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => 'some/file'}
80
80
81 to_test = {
81 to_test = {
82 # tickets
82 # tickets
83 '#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.",
83 '#3, #3 and #3.' => "#{issue_link}, #{issue_link} and #{issue_link}.",
84 # changesets
84 # changesets
85 'r1' => changeset_link,
85 'r1' => changeset_link,
86 # documents
86 # documents
87 'document#1' => document_link,
87 'document#1' => document_link,
88 'document:"Test document"' => document_link,
88 'document:"Test document"' => document_link,
89 # versions
89 # versions
90 'version#2' => version_link,
90 'version#2' => version_link,
91 'version:1.0' => version_link,
91 'version:1.0' => version_link,
92 'version:"1.0"' => version_link,
92 'version:"1.0"' => version_link,
93 # source
93 # source
94 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
94 'source:/some/file' => link_to('source:/some/file', source_url, :class => 'source'),
95 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
95 'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
96 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
96 'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
97 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
97 'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
98 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
98 'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
99 # escaping
99 # escaping
100 '!#3.' => '#3.',
100 '!#3.' => '#3.',
101 '!r1' => 'r1',
101 '!r1' => 'r1',
102 '!document#1' => 'document#1',
102 '!document#1' => 'document#1',
103 '!document:"Test document"' => 'document:"Test document"',
103 '!document:"Test document"' => 'document:"Test document"',
104 '!version#2' => 'version#2',
104 '!version#2' => 'version#2',
105 '!version:1.0' => 'version:1.0',
105 '!version:1.0' => 'version:1.0',
106 '!version:"1.0"' => 'version:"1.0"',
106 '!version:"1.0"' => 'version:"1.0"',
107 '!source:/some/file' => 'source:/some/file',
107 '!source:/some/file' => 'source:/some/file',
108 # invalid expressions
108 # invalid expressions
109 'source:' => 'source:'
109 'source:' => 'source:'
110 }
110 }
111 @project = Project.find(1)
111 @project = Project.find(1)
112 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
112 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
113 end
113 end
114
114
115 def test_wiki_links
115 def test_wiki_links
116 to_test = {
116 to_test = {
117 '[[CookBook documentation]]' => '<a href="/wiki/ecookbook/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
117 '[[CookBook documentation]]' => '<a href="/wiki/ecookbook/CookBook_documentation" class="wiki-page">CookBook documentation</a>',
118 '[[Another page|Page]]' => '<a href="/wiki/ecookbook/Another_page" class="wiki-page">Page</a>',
118 '[[Another page|Page]]' => '<a href="/wiki/ecookbook/Another_page" class="wiki-page">Page</a>',
119 # page that doesn't exist
119 # page that doesn't exist
120 '[[Unknown page]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">Unknown page</a>',
120 '[[Unknown page]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">Unknown page</a>',
121 '[[Unknown page|404]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">404</a>',
121 '[[Unknown page|404]]' => '<a href="/wiki/ecookbook/Unknown_page" class="wiki-page new">404</a>',
122 # link to another project wiki
122 # link to another project wiki
123 '[[onlinestore:]]' => '<a href="/wiki/onlinestore/" class="wiki-page">onlinestore</a>',
123 '[[onlinestore:]]' => '<a href="/wiki/onlinestore/" class="wiki-page">onlinestore</a>',
124 '[[onlinestore:|Wiki]]' => '<a href="/wiki/onlinestore/" class="wiki-page">Wiki</a>',
124 '[[onlinestore:|Wiki]]' => '<a href="/wiki/onlinestore/" class="wiki-page">Wiki</a>',
125 '[[onlinestore:Start page]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Start page</a>',
125 '[[onlinestore:Start page]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Start page</a>',
126 '[[onlinestore:Start page|Text]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Text</a>',
126 '[[onlinestore:Start page|Text]]' => '<a href="/wiki/onlinestore/Start_page" class="wiki-page">Text</a>',
127 '[[onlinestore:Unknown page]]' => '<a href="/wiki/onlinestore/Unknown_page" class="wiki-page new">Unknown page</a>',
127 '[[onlinestore:Unknown page]]' => '<a href="/wiki/onlinestore/Unknown_page" class="wiki-page new">Unknown page</a>',
128 # escaping
128 # escaping
129 '![[Another page|Page]]' => '[[Another page|Page]]',
129 '![[Another page|Page]]' => '[[Another page|Page]]',
130 }
130 }
131 @project = Project.find(1)
131 @project = Project.find(1)
132 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
132 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
133 end
133 end
134
134
135 def test_html_tags
135 def test_html_tags
136 to_test = {
136 to_test = {
137 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
137 "<div>content</div>" => "<p>&lt;div&gt;content&lt;/div&gt;</p>",
138 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
138 "<div class=\"bold\">content</div>" => "<p>&lt;div class=\"bold\"&gt;content&lt;/div&gt;</p>",
139 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
139 "<script>some script;</script>" => "<p>&lt;script&gt;some script;&lt;/script&gt;</p>",
140 # do not escape pre/code tags
140 # do not escape pre/code tags
141 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
141 "<pre>\nline 1\nline2</pre>" => "<pre>\nline 1\nline2</pre>",
142 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
142 "<pre><code>\nline 1\nline2</code></pre>" => "<pre><code>\nline 1\nline2</code></pre>",
143 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
143 "<pre><div>content</div></pre>" => "<pre>&lt;div&gt;content&lt;/div&gt;</pre>",
144 }
144 }
145 to_test.each { |text, result| assert_equal result, textilizable(text) }
145 to_test.each { |text, result| assert_equal result, textilizable(text) }
146 end
146 end
147
147
148 def test_wiki_links_in_tables
148 def test_wiki_links_in_tables
149 to_test = {"|Cell 11|Cell 12|Cell 13|\n|Cell 21|Cell 22||\n|Cell 31||Cell 33|" =>
149 to_test = {"|Cell 11|Cell 12|Cell 13|\n|Cell 21|Cell 22||\n|Cell 31||Cell 33|" =>
150 '<tr><td>Cell 11</td><td>Cell 12</td><td>Cell 13</td></tr>' +
150 '<tr><td>Cell 11</td><td>Cell 12</td><td>Cell 13</td></tr>' +
151 '<tr><td>Cell 21</td><td>Cell 22</td></tr>' +
151 '<tr><td>Cell 21</td><td>Cell 22</td></tr>' +
152 '<tr><td>Cell 31</td><td>Cell 33</td></tr>',
152 '<tr><td>Cell 31</td><td>Cell 33</td></tr>',
153
153
154 "|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" =>
154 "|[[Page|Link title]]|[[Other Page|Other title]]|\n|Cell 21|[[Last page]]|" =>
155 '<tr><td><a href="/wiki/ecookbook/Page" class="wiki-page new">Link title</a></td>' +
155 '<tr><td><a href="/wiki/ecookbook/Page" class="wiki-page new">Link title</a></td>' +
156 '<td><a href="/wiki/ecookbook/Other_Page" class="wiki-page new">Other title</a></td>' +
156 '<td><a href="/wiki/ecookbook/Other_Page" class="wiki-page new">Other title</a></td>' +
157 '</tr><tr><td>Cell 21</td><td><a href="/wiki/ecookbook/Last_page" class="wiki-page new">Last page</a></td></tr>'
157 '</tr><tr><td>Cell 21</td><td><a href="/wiki/ecookbook/Last_page" class="wiki-page new">Last page</a></td></tr>'
158 }
158 }
159 @project = Project.find(1)
159 @project = Project.find(1)
160 to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') }
160 to_test.each { |text, result| assert_equal "<table>#{result}</table>", textilizable(text).gsub(/[\t\n]/, '') }
161 end
161 end
162
162
163 def test_wiki_horizontal_rule
164 assert_equal '<hr />', textilizable('---')
165 assert_equal '<p>Dashes: ---</p>', textilizable('Dashes: ---')
166 end
167
163 def test_macro_hello_world
168 def test_macro_hello_world
164 text = "{{hello_world}}"
169 text = "{{hello_world}}"
165 assert textilizable(text).match(/Hello world!/)
170 assert textilizable(text).match(/Hello world!/)
166 # escaping
171 # escaping
167 text = "!{{hello_world}}"
172 text = "!{{hello_world}}"
168 assert_equal '<p>{{hello_world}}</p>', textilizable(text)
173 assert_equal '<p>{{hello_world}}</p>', textilizable(text)
169 end
174 end
170
175
171 def test_macro_include
176 def test_macro_include
172 @project = Project.find(1)
177 @project = Project.find(1)
173 # include a page of the current project wiki
178 # include a page of the current project wiki
174 text = "{{include(Another page)}}"
179 text = "{{include(Another page)}}"
175 assert textilizable(text).match(/This is a link to a ticket/)
180 assert textilizable(text).match(/This is a link to a ticket/)
176
181
177 @project = nil
182 @project = nil
178 # include a page of a specific project wiki
183 # include a page of a specific project wiki
179 text = "{{include(ecookbook:Another page)}}"
184 text = "{{include(ecookbook:Another page)}}"
180 assert textilizable(text).match(/This is a link to a ticket/)
185 assert textilizable(text).match(/This is a link to a ticket/)
181
186
182 text = "{{include(ecookbook:)}}"
187 text = "{{include(ecookbook:)}}"
183 assert textilizable(text).match(/CookBook documentation/)
188 assert textilizable(text).match(/CookBook documentation/)
184
189
185 text = "{{include(unknowidentifier:somepage)}}"
190 text = "{{include(unknowidentifier:somepage)}}"
186 assert textilizable(text).match(/Unknow project/)
191 assert textilizable(text).match(/Unknow project/)
187 end
192 end
188
193
189 def test_date_format_default
194 def test_date_format_default
190 today = Date.today
195 today = Date.today
191 Setting.date_format = ''
196 Setting.date_format = ''
192 assert_equal l_date(today), format_date(today)
197 assert_equal l_date(today), format_date(today)
193 end
198 end
194
199
195 def test_date_format
200 def test_date_format
196 today = Date.today
201 today = Date.today
197 Setting.date_format = '%d %m %Y'
202 Setting.date_format = '%d %m %Y'
198 assert_equal today.strftime('%d %m %Y'), format_date(today)
203 assert_equal today.strftime('%d %m %Y'), format_date(today)
199 end
204 end
200
205
201 def test_time_format_default
206 def test_time_format_default
202 now = Time.now
207 now = Time.now
203 Setting.date_format = ''
208 Setting.date_format = ''
204 Setting.time_format = ''
209 Setting.time_format = ''
205 assert_equal l_datetime(now), format_time(now)
210 assert_equal l_datetime(now), format_time(now)
206 assert_equal l_time(now), format_time(now, false)
211 assert_equal l_time(now), format_time(now, false)
207 end
212 end
208
213
209 def test_time_format
214 def test_time_format
210 now = Time.now
215 now = Time.now
211 Setting.date_format = '%d %m %Y'
216 Setting.date_format = '%d %m %Y'
212 Setting.time_format = '%H %M'
217 Setting.time_format = '%H %M'
213 assert_equal now.strftime('%d %m %Y %H %M'), format_time(now)
218 assert_equal now.strftime('%d %m %Y %H %M'), format_time(now)
214 assert_equal now.strftime('%H %M'), format_time(now, false)
219 assert_equal now.strftime('%H %M'), format_time(now, false)
215 end
220 end
216 end
221 end
General Comments 0
You need to be logged in to leave comments. Login now