annotate lib/redmine/wiki_formatting/textile/formatter.rb @ 8:0c83d98252d9 yuya

* Add custom repo prefix and proper auth realm, remove auth cache (seems like an unwise feature), pass DB handle around, various other bits of tidying
author Chris Cannam
date Thu, 12 Aug 2010 15:31:37 +0100
parents 513646585e45
children 94944d00e43c
rev   line source
Chris@0 1 # Redmine - project management software
Chris@0 2 # Copyright (C) 2006-2008 Jean-Philippe Lang
Chris@0 3 #
Chris@0 4 # This program is free software; you can redistribute it and/or
Chris@0 5 # modify it under the terms of the GNU General Public License
Chris@0 6 # as published by the Free Software Foundation; either version 2
Chris@0 7 # of the License, or (at your option) any later version.
Chris@0 8 #
Chris@0 9 # This program is distributed in the hope that it will be useful,
Chris@0 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@0 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@0 12 # GNU General Public License for more details.
Chris@0 13 #
Chris@0 14 # You should have received a copy of the GNU General Public License
Chris@0 15 # along with this program; if not, write to the Free Software
Chris@0 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Chris@0 17
Chris@0 18 require 'redcloth3'
Chris@0 19
Chris@0 20 module Redmine
Chris@0 21 module WikiFormatting
Chris@0 22 module Textile
Chris@0 23 class Formatter < RedCloth3
Chris@0 24 include ActionView::Helpers::TagHelper
Chris@0 25
Chris@0 26 # auto_link rule after textile rules so that it doesn't break !image_url! tags
Chris@0 27 RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_toc]
Chris@0 28
Chris@0 29 def initialize(*args)
Chris@0 30 super
Chris@0 31 self.hard_breaks=true
Chris@0 32 self.no_span_caps=true
Chris@0 33 self.filter_styles=true
Chris@0 34 end
Chris@0 35
Chris@0 36 def to_html(*rules)
Chris@0 37 @toc = []
Chris@0 38 super(*RULES).to_s
Chris@0 39 end
Chris@0 40
Chris@0 41 private
Chris@0 42
Chris@0 43 # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet.
Chris@0 44 # <a href="http://code.whytheluckystiff.net/redcloth/changeset/128">http://code.whytheluckystiff.net/redcloth/changeset/128</a>
Chris@0 45 def hard_break( text )
Chris@0 46 text.gsub!( /(.)\n(?!\n|\Z|>| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks
Chris@0 47 end
Chris@0 48
Chris@0 49 # Patch to add code highlighting support to RedCloth
Chris@0 50 def smooth_offtags( text )
Chris@0 51 unless @pre_list.empty?
Chris@0 52 ## replace <pre> content
Chris@0 53 text.gsub!(/<redpre#(\d+)>/) do
Chris@0 54 content = @pre_list[$1.to_i]
Chris@0 55 if content.match(/<code\s+class="(\w+)">\s?(.+)/m)
Chris@0 56 content = "<code class=\"#{$1} syntaxhl\">" +
Chris@0 57 Redmine::SyntaxHighlighting.highlight_by_language($2, $1)
Chris@0 58 end
Chris@0 59 content
Chris@0 60 end
Chris@0 61 end
Chris@0 62 end
Chris@0 63
Chris@0 64 # Patch to add 'table of content' support to RedCloth
Chris@0 65 def textile_p_withtoc(tag, atts, cite, content)
Chris@0 66 # removes wiki links from the item
Chris@0 67 toc_item = content.gsub(/(\[\[([^\]\|]*)(\|([^\]]*))?\]\])/) { $4 || $2 }
Chris@0 68 # sanitizes titles from links
Chris@0 69 # see redcloth3.rb, same as "#{pre}#{text}#{post}"
Chris@0 70 toc_item.gsub!(LINK_RE) { [$2, $4, $9].join }
Chris@0 71 # sanitizes image links from titles
Chris@0 72 toc_item.gsub!(IMAGE_RE) { [$5].join }
Chris@0 73 # removes styles
Chris@0 74 # eg. %{color:red}Triggers% => Triggers
Chris@0 75 toc_item.gsub! %r[%\{[^\}]*\}([^%]+)%], '\\1'
Chris@0 76
Chris@0 77 # replaces non word caracters by dashes
Chris@0 78 anchor = toc_item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
Chris@0 79
Chris@0 80 unless anchor.blank?
Chris@0 81 if tag =~ /^h(\d)$/
Chris@0 82 @toc << [$1.to_i, anchor, toc_item]
Chris@0 83 end
Chris@0 84 atts << " id=\"#{anchor}\""
Chris@0 85 content = content + "<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a>"
Chris@0 86 end
Chris@0 87 textile_p(tag, atts, cite, content)
Chris@0 88 end
Chris@0 89
Chris@0 90 alias :textile_h1 :textile_p_withtoc
Chris@0 91 alias :textile_h2 :textile_p_withtoc
Chris@0 92 alias :textile_h3 :textile_p_withtoc
Chris@0 93
Chris@0 94 def inline_toc(text)
Chris@0 95 text.gsub!(/<p>\{\{([<>]?)toc\}\}<\/p>/i) do
Chris@0 96 div_class = 'toc'
Chris@0 97 div_class << ' right' if $1 == '>'
Chris@0 98 div_class << ' left' if $1 == '<'
Chris@0 99 out = "<ul class=\"#{div_class}\">"
Chris@0 100 @toc.each do |heading|
Chris@0 101 level, anchor, toc_item = heading
Chris@0 102 out << "<li class=\"heading#{level}\"><a href=\"##{anchor}\">#{toc_item}</a></li>\n"
Chris@0 103 end
Chris@0 104 out << '</ul>'
Chris@0 105 out
Chris@0 106 end
Chris@0 107 end
Chris@0 108
Chris@0 109 AUTO_LINK_RE = %r{
Chris@0 110 ( # leading text
Chris@0 111 <\w+.*?>| # leading HTML tag, or
Chris@0 112 [^=<>!:'"/]| # leading punctuation, or
Chris@0 113 ^ # beginning of line
Chris@0 114 )
Chris@0 115 (
Chris@0 116 (?:https?://)| # protocol spec, or
Chris@0 117 (?:s?ftps?://)|
Chris@0 118 (?:www\.) # www.*
Chris@0 119 )
Chris@0 120 (
Chris@0 121 (\S+?) # url
Chris@0 122 (\/)? # slash
Chris@0 123 )
Chris@0 124 ([^\w\=\/;\(\)]*?) # post
Chris@0 125 (?=<|\s|$)
Chris@0 126 }x unless const_defined?(:AUTO_LINK_RE)
Chris@0 127
Chris@0 128 # Turns all urls into clickable links (code from Rails).
Chris@0 129 def inline_auto_link(text)
Chris@0 130 text.gsub!(AUTO_LINK_RE) do
Chris@0 131 all, leading, proto, url, post = $&, $1, $2, $3, $6
Chris@0 132 if leading =~ /<a\s/i || leading =~ /![<>=]?/
Chris@0 133 # don't replace URL's that are already linked
Chris@0 134 # and URL's prefixed with ! !> !< != (textile images)
Chris@0 135 all
Chris@0 136 else
Chris@0 137 # Idea below : an URL with unbalanced parethesis and
Chris@0 138 # ending by ')' is put into external parenthesis
Chris@0 139 if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) )
Chris@0 140 url=url[0..-2] # discard closing parenth from url
Chris@0 141 post = ")"+post # add closing parenth to post
Chris@0 142 end
Chris@0 143 tag = content_tag('a', proto + url, :href => "#{proto=="www."?"http://www.":proto}#{url}", :class => 'external')
Chris@0 144 %(#{leading}#{tag}#{post})
Chris@0 145 end
Chris@0 146 end
Chris@0 147 end
Chris@0 148
Chris@0 149 # Turns all email addresses into clickable links (code from Rails).
Chris@0 150 def inline_auto_mailto(text)
Chris@0 151 text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do
Chris@0 152 mail = $1
Chris@0 153 if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/)
Chris@0 154 mail
Chris@0 155 else
Chris@0 156 content_tag('a', mail, :href => "mailto:#{mail}", :class => "email")
Chris@0 157 end
Chris@0 158 end
Chris@0 159 end
Chris@0 160 end
Chris@0 161 end
Chris@0 162 end
Chris@0 163 end