diff --git a/tracks/app/views/layouts/standard.rhtml b/tracks/app/views/layouts/standard.rhtml index 4daf50d4..749912c3 100644 --- a/tracks/app/views/layouts/standard.rhtml +++ b/tracks/app/views/layouts/standard.rhtml @@ -3,9 +3,9 @@ <% tracks_path = app_configurations["path"]["base"] %> - <%= "" %> + <%= @page_title %> diff --git a/tracks/lib/redcloth.rb b/tracks/lib/redcloth.rb index ddb49447..03df12b3 100644 --- a/tracks/lib/redcloth.rb +++ b/tracks/lib/redcloth.rb @@ -14,7 +14,6 @@ # Textism for PHP: http://www.textism.com/tools/textile/ # # -require 'uri' # = RedCloth # @@ -167,7 +166,8 @@ require 'uri' class RedCloth < String - VERSION = '3.0.0' + VERSION = '3.0.3' + DEFAULT_RULES = [:textile, :markdown] # # Two accessor for setting security restrictions. @@ -193,6 +193,16 @@ class RedCloth < String # attr_accessor :hard_breaks + # + # Accessor for toggling span caps. + # + # Textile places `span' tags around capitalized + # words by default, but this wreaks havoc on Wikis. + # If +:no_span_caps+ is set, this will be + # suppressed. + # + attr_accessor :no_span_caps + # # Establishes the markup predence. Available rules include: # @@ -231,7 +241,6 @@ class RedCloth < String # def initialize( string, restrictions = [] ) restrictions.each { |r| method( "#{ r }=" ).call( true ) } - @rules = [:textile, :markdown] super( string ) end @@ -243,7 +252,7 @@ class RedCloth < String # #=>"And then? She fell!" # def to_html( *rules ) - rules = @rules if rules.empty? + rules = DEFAULT_RULES if rules.empty? # make our working copy text = self.dup @@ -251,7 +260,7 @@ class RedCloth < String @shelf = [] textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists, :block_textile_prefix, :inline_textile_image, :inline_textile_link, - :inline_textile_code, :inline_textile_span, :inline_textile_glyphs] + :inline_textile_code, :inline_textile_glyphs, :inline_textile_span] markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule, :block_markdown_bq, :block_markdown_lists, :inline_markdown_reflink, :inline_markdown_link] @@ -269,18 +278,22 @@ class RedCloth < String # standard clean up incoming_entities text clean_white_space text + no_textile text # start processor - pre_list = rip_offtags text + @pre_list = [] + rip_offtags text + hard_break text refs text blocks text inline text - smooth_offtags text, pre_list + smooth_offtags text retrieve text text.gsub!( /<\/?notextile>/, '' ) text.gsub!( /x%x%/, '&' ) + clean_html text if filter_html text.strip! text @@ -341,9 +354,9 @@ class RedCloth < String [ /"/, '“' ], # double opening [ /\b( )?\.{3}/, '\1…' ], # ellipsis [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '\1' ], # 3+ uppercase acronym - [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^\2\3' ], # 3+ uppercase caps + [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]{2,})([^\2\3', :no_span_caps ], # 3+ uppercase caps [ /(\.\s)?\s?--\s?/, '\1—' ], # em dash - [ /\s->\s/, ' → ' ], # en dash + [ /\s->\s/, ' → ' ], # right arrow [ /\s-\s/, ' – ' ], # en dash [ /(\d+) ?x ?(\d+)/, '\1×\2' ], # dimension sign [ /\b ?[(\[]TM[\])]/i, '™' ], # trademark @@ -367,27 +380,36 @@ class RedCloth < String QTAGS = [ ['**', 'b'], ['*', 'strong'], - ['??', 'cite'], - ['-', 'del'], + ['??', 'cite', :limit], + ['-', 'del', :limit], ['__', 'i'], - ['_', 'em'], - ['%', 'span'], - ['+', 'ins'], + ['_', 'em', :limit], + ['%', 'span', :limit], + ['+', 'ins', :limit], ['^', 'sup'], ['~', 'sub'] - ].collect do |rc, ht| - ttr = Regexp.quote(rc) - punct = PUNCT.sub( Regexp::quote(rc), '' ) - re = /(^|[\s\>#{punct}{(\[]) - #{ttr} + ] + QTAGS.collect! do |rc, ht, rtype| + rcq = Regexp::quote rc + re = + case rtype + when :limit + /(\W) + (#{rcq}) (#{C}) (?::(\S+?))? - ([^\s#{ttr}]+?(?:[^\n]|\n(?!\n))*?) - ([#{punct}]*?) - #{ttr} - (?=[\s\])}<#{punct}]|$)/xm - [re, ht] - end + (.+?) + #{rcq} + (?=\W)/x + else + /(#{rcq}) + (#{C}) + (?::(\S+?))? + (.+?) + #{rcq}/xm + end + [rc, ht, re, rtype] + end # # Flexible HTML escaping @@ -402,7 +424,8 @@ class RedCloth < String # Search and replace for Textile glyphs (quotes, dashes, other symbols) def pgl( text ) - GLYPHS.each do |re, resub| + GLYPHS.each do |re, resub, tog| + next if tog and method( tog ).call text.gsub! re, resub end end @@ -420,7 +443,7 @@ class RedCloth < String style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN end - style << "#{ $1 };" if not @filter_styles and + style << "#{ $1 };" if not filter_styles and text.sub!( /\{([^}]*)\}/, '' ) lang = $1 if @@ -457,6 +480,7 @@ class RedCloth < String tatts, fullrow = $~[1..2] tatts = pba( tatts, 'table' ) + tatts = shelve( tatts ) if tatts rows = [] fullrow. @@ -475,9 +499,11 @@ class RedCloth < String catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/ unless cell.strip.empty? + catts = shelve( catts ) if catts cells << "\t\t\t#{ cell }" end end + ratts = shelve( ratts ) if ratts rows << "\t\t\n#{ cells.join( "\n" ) }\n\t\t" end "\t\n#{ rows.join( "\n" ) }\n\t\n\n" @@ -511,6 +537,7 @@ class RedCloth < String unless depth.last == tl depth << tl atts = pba( atts ) + atts = shelve( atts ) if atts lines[line_id] = "\t<#{ lT(tl) }l#{ atts }>\n\t
  • #{ content }" else lines[line_id] = "\t\t
  • #{ content }" @@ -530,20 +557,18 @@ class RedCloth < String end end - CODE_RE = / - (^|[\s>#{PUNCT}{(\[]) # 1 open bracket? - @ # opening - (?:\|(\w+?)\|)? # 2 language - (\S(?:[^\n]|\n(?!\n))*?) # 3 code - @ # closing - (?=[\s\]}\)<#{PUNCT}]|$) # 4 closing bracket? - /x + CODE_RE = /(\W) + @ + (?:\|(\w+?)\|)? + (.+?) + @ + (?=\W)/x def inline_textile_code( text ) text.gsub!( CODE_RE ) do |m| before,lang,code,after = $~[1..4] lang = " lang=\"#{ lang }\"" if lang - "#{ before }#{ code }#{ after }" + rip_offtags( "#{ before }#{ code }#{ after }" ) end end @@ -552,19 +577,14 @@ class RedCloth < String end def hard_break( text ) - text.gsub!( /(.)\n(?! *[#*\s|])/, "\\1
    " ) if @hard_breaks + text.gsub!( /(.)\n(?! *[#*\s|]|$)/, "\\1
    " ) if hard_breaks end - BLOCKS_GROUP_RE = /(#{ - ['#', '*', '>'].collect do |sym| - sym = Regexp::quote( sym ) - '(?:\n*[' + sym + ' ](?:[^\n]|\n+[' + sym + ' ]|\n(?!\n|\Z))+)' - end.join '|' - })|((?:[^\n]+|\n+ +|\n(?![#*\n]|\Z))+)/m + BLOCKS_GROUP_RE = /\n{2,}(?! )/m def blocks( text, deep_code = false ) - text.gsub!( BLOCKS_GROUP_RE ) do |blk| - plain = $2 ? true : false + text.replace( text.split( BLOCKS_GROUP_RE ).collect do |blk| + plain = blk !~ /\A[#*> ]/ # skip blocks that are complex HTML if blk =~ /^<\/?(\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1 @@ -587,11 +607,11 @@ class RedCloth < String end end - block_applied = nil + block_applied = 0 @rules.each do |rule_name| - break if block_applied = ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) ) + block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) ) end - unless block_applied + if block_applied.zero? if deep_code blk = "\t
    #{ blk }
    " else @@ -603,16 +623,18 @@ class RedCloth < String end end - end + end.join( "\n\n" ) ) end def textile_bq( tag, atts, cite, content ) cite, cite_title = check_refs( cite ) cite = " cite=\"#{ cite }\"" if cite + atts = shelve( atts ) if atts "\t\n\t\t#{ content }

    \n\t" end def textile_p( tag, atts, cite, content ) + atts = shelve( atts ) if atts "\t<#{ tag }#{ atts }>#{ content }" end @@ -626,6 +648,7 @@ class RedCloth < String def textile_fn_( tag, num, atts, cite, content ) atts << " id=\"fn#{ num }\"" content = "#{ num } #{ content }" + atts = shelve( atts ) if atts "\t#{ content }

    " end @@ -700,14 +723,21 @@ class RedCloth < String end def inline_textile_span( text ) - QTAGS.each do |ttr, ht| - text.gsub!(ttr) do |m| - - start,atts,cite,content,tend = $~[1..5] + QTAGS.each do |qtag_rc, ht, qtag_re, rtype| + text.gsub!( qtag_re ) do |m| + + case rtype + when :limit + sta,qtag,atts,cite,content = $~[1..5] + else + qtag,atts,cite,content = $~[1..4] + sta = '' + end atts = pba( atts ) atts << " cite=\"#{ cite }\"" if cite + atts = shelve( atts ) if atts - "#{ start }<#{ ht }#{ atts }>#{ content }#{ tend }" + "#{ sta }<#{ ht }#{ atts }>#{ content }" end end @@ -890,6 +920,13 @@ class RedCloth < String text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" ) end + def no_textile( text ) + text.gsub!( /(^|\s)==([^=]+.*?)==(\s|$)?/, + '\1\2\3' ) + text.gsub!( /^ *==([^=]+.*?)==/m, + '\1\2\3' ) + end + def clean_white_space( text ) # normalize line breaks text.gsub!( /\r\n/, "\n" ) @@ -906,11 +943,13 @@ class RedCloth < String def flush_left( text ) indt = 0 - while text !~ /^ {#{indt}}\S/ - indt += 1 - end - if indt.nonzero? - text.gsub!( /^ {#{indt}}/, '' ) + if text =~ /^ / + while text !~ /^ {#{indt}}\S/ + indt += 1 + end unless text.empty? + if indt.nonzero? + text.gsub!( /^ {#{indt}}/, '' ) + end end end @@ -935,9 +974,7 @@ class RedCloth < String text.gsub!( ALLTAG_MATCH ) do |line| ## matches are off if we're between ,
     etc.
                     if $1
    -                    if @filter_html
    -                        htmlesc( line, :NoQuotes )
    -                    elsif line =~ OFFTAG_OPEN
    +                    if line =~ OFFTAG_OPEN
                             codepre += 1
                         elsif line =~ OFFTAG_CLOSE
                             codepre -= 1
    @@ -956,7 +993,6 @@ class RedCloth < String
         end
     
         def rip_offtags( text )
    -        pre_list = []
             if text =~ /<.*>/
                 ## strip and encode 
     content
                 codepre, used_offtags = 0, {}
    @@ -967,17 +1003,17 @@ class RedCloth < String
                         used_offtags[offtag] = true
                         if codepre - used_offtags.length > 0
                             htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
    -                        pre_list.last << line
    +                        @pre_list.last << line
                             line = ""
                         else
                             htmlesc( aftertag, :NoQuotes ) if aftertag and not used_offtags['notextile']
    -                        line = ""
    -                        pre_list << "#{ $3 }#{ aftertag }"
    +                        line = ""
    +                        @pre_list << "#{ $3 }#{ aftertag }"
                         end
                     elsif $1 and codepre > 0
                         if codepre - used_offtags.length > 0
                             htmlesc( line, :NoQuotes ) unless used_offtags['notextile']
    -                        pre_list.last << line
    +                        @pre_list.last << line
                             line = ""
                         end
                         codepre -= 1 unless codepre.zero?
    @@ -986,13 +1022,13 @@ class RedCloth < String
                     line
                 end
             end
    -        pre_list
    +        text
         end
     
    -    def smooth_offtags( text, pre_list )
    -        unless pre_list.empty?
    +    def smooth_offtags( text )
    +        unless @pre_list.empty?
                 ## replace 
     content
    -            text.gsub!( // ) { pre_list[$1.to_i] }
    +            text.gsub!( // ) { @pre_list[$1.to_i] }
             end
         end
     
    @@ -1014,5 +1050,64 @@ class RedCloth < String
             ' ' + name + '
    ' end + # HTML cleansing stuff + BASIC_TAGS = { + 'a' => ['href', 'title'], + 'img' => ['src', 'alt', 'title'], + 'br' => [], + 'i' => nil, + 'u' => nil, + 'b' => nil, + 'pre' => nil, + 'kbd' => nil, + 'code' => ['lang'], + 'cite' => nil, + 'strong' => nil, + 'em' => nil, + 'ins' => nil, + 'sup' => nil, + 'sub' => nil, + 'del' => nil, + 'table' => nil, + 'tr' => nil, + 'td' => ['colspan', 'rowspan'], + 'th' => nil, + 'ol' => nil, + 'ul' => nil, + 'li' => nil, + 'p' => nil, + 'h1' => nil, + 'h2' => nil, + 'h3' => nil, + 'h4' => nil, + 'h5' => nil, + 'h6' => nil, + 'blockquote' => ['cite'] + } + + def clean_html( text, tags = BASIC_TAGS ) + text.gsub!( /]*)>/ ) do + raw = $~ + tag = raw[2].downcase + if tags.has_key? tag + pcs = [tag] + tags[tag].each do |prop| + ['"', "'", ''].each do |q| + q2 = ( q != '' ? q : '\s' ) + if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i + attrv = $1 + next if prop == 'src' and attrv !~ /^http/ + pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\"" + break + end + end + end if tags[tag] + "<#{raw[1]}#{pcs.join " "}>" + else + " " + end + end + end end diff --git a/tracks/public/.htaccess b/tracks/public/.htaccess index 5a6a18a5..e2cee75e 100644 --- a/tracks/public/.htaccess +++ b/tracks/public/.htaccess @@ -7,7 +7,7 @@ Options +FollowSymLinks +ExecCGI RewriteEngine On # Change extension from .cgi to .fcgi to switch to FCGI and to .rb to switch to mod_ruby -RewriteBase /dispatch.cgi +RewriteBase /dispatch.fcgi # Enable this rewrite rule to point to the controller/action that should serve root. RewriteRule ^$ /todo/list [R] @@ -16,9 +16,9 @@ RewriteRule ^$ /todo/list [R] RewriteRule ^([-_a-zA-Z0-9]+)$ /$1/ [R] # Default rewriting rules. -RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?controller=$1&action=$2&id=$3 [QSA,L] -RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?controller=$1&action=$2 [QSA,L] -RewriteRule ^([-_a-zA-Z0-9]+)/$ ?controller=$1&action=index [QSA,L] +RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?controller=$1&action=$2&id=$3 [QSA,L] +RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?controller=$1&action=$2 [QSA,L] +RewriteRule ^([-_a-zA-Z0-9]+)/$ ?controller=$1&action=index [QSA,L] RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?module=$1&controller=$2&action=$3&id=$4 [QSA,L] RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?module=$1&controller=$2&action=$3 [QSA,L]