Mercurial > hg > soundsoftware-site
comparison lib/redmine/wiki_formatting/textile/formatter.rb @ 909:cbb26bc654de redmine-1.3
Update to Redmine 1.3-stable branch (Redmine SVN rev 8964)
author | Chris Cannam |
---|---|
date | Fri, 24 Feb 2012 19:09:32 +0000 |
parents | cbce1fd3b1b7 |
children | 433d4f72a19b |
comparison
equal
deleted
inserted
replaced
908:c6c2cbd0afee | 909:cbb26bc654de |
---|---|
1 # Redmine - project management software | 1 # Redmine - project management software |
2 # Copyright (C) 2006-2010 Jean-Philippe Lang | 2 # Copyright (C) 2006-2011 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 'redcloth3' | 18 require 'redcloth3' |
19 require 'digest/md5' | |
19 | 20 |
20 module Redmine | 21 module Redmine |
21 module WikiFormatting | 22 module WikiFormatting |
22 module Textile | 23 module Textile |
23 class Formatter < RedCloth3 | 24 class Formatter < RedCloth3 |
24 include ActionView::Helpers::TagHelper | 25 include ActionView::Helpers::TagHelper |
25 | 26 |
26 # auto_link rule after textile rules so that it doesn't break !image_url! tags | 27 # 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] | 28 RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] |
28 | 29 |
29 def initialize(*args) | 30 def initialize(*args) |
30 super | 31 super |
31 self.hard_breaks=true | 32 self.hard_breaks=true |
32 self.no_span_caps=true | 33 self.no_span_caps=true |
33 self.filter_styles=true | 34 self.filter_styles=true |
34 end | 35 end |
35 | 36 |
36 def to_html(*rules) | 37 def to_html(*rules) |
37 @toc = [] | 38 @toc = [] |
38 super(*RULES).to_s | 39 super(*RULES).to_s |
39 end | 40 end |
40 | 41 |
42 def get_section(index) | |
43 section = extract_sections(index)[1] | |
44 hash = Digest::MD5.hexdigest(section) | |
45 return section, hash | |
46 end | |
47 | |
48 def update_section(index, update, hash=nil) | |
49 t = extract_sections(index) | |
50 if hash.present? && hash != Digest::MD5.hexdigest(t[1]) | |
51 raise Redmine::WikiFormatting::StaleSectionError | |
52 end | |
53 t[1] = update unless t[1].blank? | |
54 t.reject(&:blank?).join "\n\n" | |
55 end | |
56 | |
57 def extract_sections(index) | |
58 @pre_list = [] | |
59 text = self.dup | |
60 rip_offtags text, false, false | |
61 before = '' | |
62 s = '' | |
63 after = '' | |
64 i = 0 | |
65 l = 1 | |
66 started = false | |
67 ended = false | |
68 text.scan(/(((?:.*?)(\A|\r?\n\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))? (.*?)$)|.*)/m).each do |all, content, lf, heading, level| | |
69 if heading.nil? | |
70 if ended | |
71 after << all | |
72 elsif started | |
73 s << all | |
74 else | |
75 before << all | |
76 end | |
77 break | |
78 end | |
79 i += 1 | |
80 if ended | |
81 after << all | |
82 elsif i == index | |
83 l = level.to_i | |
84 before << content | |
85 s << heading | |
86 started = true | |
87 elsif i > index | |
88 s << content | |
89 if level.to_i > l | |
90 s << heading | |
91 else | |
92 after << heading | |
93 ended = true | |
94 end | |
95 else | |
96 before << all | |
97 end | |
98 end | |
99 sections = [before.strip, s.strip, after.strip] | |
100 sections.each {|section| smooth_offtags_without_code_highlighting section} | |
101 sections | |
102 end | |
103 | |
41 private | 104 private |
42 | 105 |
43 # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. | 106 # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. |
44 # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a> | 107 # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a> |
45 def hard_break( text ) | 108 def hard_break( text ) |
46 text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks | 109 text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks |
47 end | 110 end |
48 | 111 |
112 alias :smooth_offtags_without_code_highlighting :smooth_offtags | |
49 # Patch to add code highlighting support to RedCloth | 113 # Patch to add code highlighting support to RedCloth |
50 def smooth_offtags( text ) | 114 def smooth_offtags( text ) |
51 unless @pre_list.empty? | 115 unless @pre_list.empty? |
52 ## replace <pre> content | 116 ## replace <pre> content |
53 text.gsub!(/<redpre#(\d+)>/) do | 117 text.gsub!(/<redpre#(\d+)>/) do |
54 content = @pre_list[$1.to_i] | 118 content = @pre_list[$1.to_i] |
55 if content.match(/<code\s+class="(\w+)">\s?(.+)/m) | 119 if content.match(/<code\s+class="(\w+)">\s?(.+)/m) |
56 content = "<code class=\"#{$1} syntaxhl\">" + | 120 content = "<code class=\"#{$1} syntaxhl\">" + |
57 Redmine::SyntaxHighlighting.highlight_by_language($2, $1) | 121 Redmine::SyntaxHighlighting.highlight_by_language($2, $1) |
58 end | 122 end |
59 content | 123 content |
60 end | 124 end |
61 end | 125 end |
62 end | 126 end |
63 | 127 |
64 AUTO_LINK_RE = %r{ | 128 AUTO_LINK_RE = %r{ |
65 ( # leading text | 129 ( # leading text |
66 <\w+.*?>| # leading HTML tag, or | 130 <\w+.*?>| # leading HTML tag, or |
67 [^=<>!:'"/]| # leading punctuation, or | 131 [^=<>!:'"/]| # leading punctuation, or |
68 ^ # beginning of line | 132 ^ # beginning of line |
69 ) | 133 ) |
70 ( | 134 ( |
71 (?:https?://)| # protocol spec, or | 135 (?:https?://)| # protocol spec, or |
72 (?:s?ftps?://)| | 136 (?:s?ftps?://)| |
77 (\/)? # slash | 141 (\/)? # slash |
78 ) | 142 ) |
79 ((?:>)?|[^\w\=\/;\(\)]*?) # post | 143 ((?:>)?|[^\w\=\/;\(\)]*?) # post |
80 (?=<|\s|$) | 144 (?=<|\s|$) |
81 }x unless const_defined?(:AUTO_LINK_RE) | 145 }x unless const_defined?(:AUTO_LINK_RE) |
82 | 146 |
83 # Turns all urls into clickable links (code from Rails). | 147 # Turns all urls into clickable links (code from Rails). |
84 def inline_auto_link(text) | 148 def inline_auto_link(text) |
85 text.gsub!(AUTO_LINK_RE) do | 149 text.gsub!(AUTO_LINK_RE) do |
86 all, leading, proto, url, post = $&, $1, $2, $3, $6 | 150 all, leading, proto, url, post = $&, $1, $2, $3, $6 |
87 if leading =~ /<a\s/i || leading =~ /![<>=]?/ | 151 if leading =~ /<a\s/i || leading =~ /![<>=]?/ |
98 tag = content_tag('a', proto + url, :href => "#{proto=="www."?"http://www.":proto}#{url}", :class => 'external') | 162 tag = content_tag('a', proto + url, :href => "#{proto=="www."?"http://www.":proto}#{url}", :class => 'external') |
99 %(#{leading}#{tag}#{post}) | 163 %(#{leading}#{tag}#{post}) |
100 end | 164 end |
101 end | 165 end |
102 end | 166 end |
103 | 167 |
104 # Turns all email addresses into clickable links (code from Rails). | 168 # Turns all email addresses into clickable links (code from Rails). |
105 def inline_auto_mailto(text) | 169 def inline_auto_mailto(text) |
106 text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do | 170 text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do |
107 mail = $1 | 171 mail = $1 |
108 if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) | 172 if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) |