diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2008-10-27 11:08:29 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2008-10-27 11:08:29 +0000 |
commit | a3b9a5aa5fe344cf33a47ccbf1d26a95fbe4e255 (patch) | |
tree | 6b19387c81e2d865a57cf3357340deffdbc5e858 /lib/redmine/wiki_formatting.rb | |
parent | 9b624fd1d6f66bbe60d738522d9fc5fd547ef3af (diff) | |
download | redmine-a3b9a5aa5fe344cf33a47ccbf1d26a95fbe4e255.tar.gz redmine-a3b9a5aa5fe344cf33a47ccbf1d26a95fbe4e255.zip |
Makes wiki text formatter pluggable.
Original patch #2025 by Yuki Sonoda slightly edited.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@1955 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'lib/redmine/wiki_formatting.rb')
-rw-r--r-- | lib/redmine/wiki_formatting.rb | 193 |
1 files changed, 41 insertions, 152 deletions
diff --git a/lib/redmine/wiki_formatting.rb b/lib/redmine/wiki_formatting.rb index 7dffff492..1525dbc19 100644 --- a/lib/redmine/wiki_formatting.rb +++ b/lib/redmine/wiki_formatting.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2008 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 @@ -15,176 +15,65 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -require 'redcloth3' -require 'coderay' - module Redmine module WikiFormatting - - private - - class TextileFormatter < RedCloth3 - - # 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, :inline_macros] + @@formatters = {} + + class << self + def map + yield self + end - def initialize(*args) - super - self.hard_breaks=true - self.no_span_caps=true + def register(name, formatter, helper) + raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name] + @@formatters[name.to_sym] = {:formatter => formatter, :helper => helper} end - def to_html(*rules, &block) - @toc = [] - @macros_runner = block - super(*RULES).to_s + def formatter_for(name) + entry = @@formatters[name.to_sym] + (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter end - - private - - # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. - # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a> - def hard_break( text ) - text.gsub!( /(.)\n(?!\n|\Z|>| *(>? *[#*=]+(\s|$)|[{|]))/, "\\1<br />\n" ) if hard_breaks + + def helper_for(name) + entry = @@formatters[name.to_sym] + (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper end - # Patch to add code highlighting support to RedCloth - def smooth_offtags( text ) - unless @pre_list.empty? - ## replace <pre> content - text.gsub!(/<redpre#(\d+)>/) do - content = @pre_list[$1.to_i] - if content.match(/<code\s+class="(\w+)">\s?(.+)/m) - content = "<code class=\"#{$1} CodeRay\">" + - CodeRay.scan($2, $1.downcase).html(:escape => false, :line_numbers => :inline) - end - content - end - end + def format_names + @@formatters.keys.map 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(/(\[\[|\]\])/, '') - # removes styles - # eg. %{color:red}Triggers% => Triggers - toc_item.gsub! %r[%\{[^\}]*\}([^%]+)%], '\\1' + def to_html(format, text, options = {}, &block) + formatter_for(format).new(text).to_html(&block) + end + end + + # Default formatter module + module NullFormatter + class Formatter + include ActionView::Helpers::TagHelper + include ActionView::Helpers::TextHelper - # 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\">¶</a>" + def initialize(text) + @text = text 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 + + def to_html(*args) + simple_format(auto_link(CGI::escapeHTML(@text))) end end - MACROS_RE = / - (!)? # escaping - ( - \{\{ # opening tag - ([\w]+) # macro name - (\(([^\}]*)\))? # optional arguments - \}\} # closing tag - ) - /x unless const_defined?(:MACROS_RE) - - def inline_macros(text) - text.gsub!(MACROS_RE) do - esc, all, macro = $1, $2, $3.downcase - args = ($5 || '').split(',').each(&:strip) - if esc.nil? - begin - @macros_runner.call(macro, args) - rescue => e - "<div class=\"flash error\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>" - end || all - else - all - end + module Helper + def wikitoolbar_for(field_id) end - end - AUTO_LINK_RE = %r{ - ( # leading text - <\w+.*?>| # leading HTML tag, or - [^=<>!:'"/]| # leading punctuation, or - ^ # beginning of line - ) - ( - (?:https?://)| # protocol spec, or - (?:ftp://)| - (?:www\.) # www.* - ) - ( - (\S+?) # url - (\/)? # slash - ) - ([^\w\=\/;\(\)]*?) # post - (?=<|\s|$) - }x unless const_defined?(:AUTO_LINK_RE) - - # Turns all urls into clickable links (code from Rails). - def inline_auto_link(text) - text.gsub!(AUTO_LINK_RE) do - all, leading, proto, url, post = $&, $1, $2, $3, $6 - if leading =~ /<a\s/i || leading =~ /![<>=]?/ - # don't replace URL's that are already linked - # and URL's prefixed with ! !> !< != (textile images) - all - else - # Idea below : an URL with unbalanced parethesis and - # ending by ')' is put into external parenthesis - if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) - url=url[0..-2] # discard closing parenth from url - post = ")"+post # add closing parenth to post - end - %(#{leading}<a class="external" href="#{proto=="www."?"http://www.":proto}#{url}">#{proto + url}</a>#{post}) - end + def heads_for_wiki_formatter end - end - - # Turns all email addresses into clickable links (code from Rails). - def inline_auto_mailto(text) - text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do - mail = $1 - if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) - mail - else - %{<a href="mailto:#{mail}" class="email">#{mail}</a>} - end + + def initial_page_content(page) + page.pretty_title.to_s end end end - - public - - def self.to_html(text, options = {}, &block) - TextileFormatter.new(text).to_html(&block) - end end end |