module RedCloth::Formatters::HTML include RedCloth::Formatters::Base [:h1, :h2, :h3, :h4, :h5, :h6, :p, :pre, :div].each do |m| define_method(m) do |opts| "<#{m}#{pba(opts)}>#{opts[:text]}\n" end end [:strong, :code, :em, :i, :b, :ins, :sup, :sub, :span, :cite].each do |m| define_method(m) do |opts| opts[:block] = true "<#{m}#{pba(opts)}>#{opts[:text]}" end end def hr(opts) "\n" end def acronym(opts) opts[:block] = true "#{caps(:text => opts[:text])}" end def caps(opts) if no_span_caps opts[:text] else opts[:class] = 'caps' span(opts) end end def del(opts) opts[:block] = true "#{opts[:text]}" end [:ol, :ul].each do |m| define_method("#{m}_open") do |opts| opts[:block] = true "#{"\n" if opts[:nest] > 1}#{"\t" * (opts[:nest] - 1)}<#{m}#{pba(opts)}>\n" end define_method("#{m}_close") do |opts| "#{"\t" * (opts[:nest] - 1)}#{"\n" if opts[:nest] <= 1}" end end def li_open(opts) "#{"\t" * opts[:nest]}#{opts[:text]}" end def li_close(opts=nil) "\n" end def dl_open(opts) opts[:block] = true "\n" end def dl_close(opts=nil) "\n" end [:dt, :dd].each do |m| define_method(m) do |opts| "\t<#{m}#{pba(opts)}>#{opts[:text]}\n" end end def td(opts) tdtype = opts[:th] ? 'th' : 'td' "\t\t<#{tdtype}#{pba(opts)}>#{opts[:text]}\n" end def tr_open(opts) "\t\n" end def tr_close(opts) "\t\n" end def table_open(opts) "\n" end def table_close(opts) "\n" end def bc_open(opts) opts[:block] = true "" end def bc_close(opts) "\n" end def bq_open(opts) opts[:block] = true cite = opts[:cite] ? " cite=\"#{ escape_attribute opts[:cite] }\"" : '' "\n" end def bq_close(opts) "\n" end def link(opts) "#{opts[:name]}" end def truncate(text, length = 30, truncate_string = "...") if text.nil? then return end l = length - truncate_string.chars.to_a.size (text.chars.to_a.size > length ? text.chars.to_a[0...l].join + truncate_string : text).to_s end def auto_link(opts) return opts[:href] unless auto_link_urls href_with_proto = opts[:href] href_with_proto = 'http://' + href_with_proto unless href_with_proto.index('http') == 0 text = opts[:href] text = truncate(text[0, text.length - 6] + text[-5,3].replace("...") + text[-2..-1], 50) "#{escape_attribute text}" end def image(opts) opts.delete(:align) opts[:alt] = opts[:title] img = "\"#{escape_attribute" img = "#{img}" if opts[:href] img end def footno(opts) opts[:id] ||= opts[:text] %Q{#{opts[:text]}} end def fn(opts) no = opts[:id] opts[:id] = "fn#{no}" opts[:class] = ["footnote", opts[:class]].compact.join(" ") "#{no} #{opts[:text]}

\n" end def snip(opts) "#{opts[:text]}\n" end def quote1(opts) "‘#{opts[:text]}’" end def quote2(opts) "“#{opts[:text]}”" end def multi_paragraph_quote(opts) "“#{opts[:text]}" end def ellipsis(opts) "#{opts[:text]}…" end def emdash(opts) "—" end def endash(opts) " – " end def arrow(opts) "→" end def dim(opts) opts[:text].gsub!('x', '×') opts[:text].gsub!("'", '′') opts[:text].gsub!('"', '″') opts[:text] end def trademark(opts) "™" end def registered(opts) "®" end def copyright(opts) "©" end def entity(opts) "&#{opts[:text]};" end def amp(opts) "&" end def gt(opts) ">" end def lt(opts) "<" end def br(opts) if hard_breaks == false "\n" else "\n" end end def quot(opts) """ end def squot(opts) "’" end def apos(opts) "'" end def html(opts) "#{opts[:text]}\n" end def html_block(opts) inline_html(:text => "#{opts[:indent_before_start]}#{opts[:start_tag]}#{opts[:indent_after_start]}") + "#{opts[:text]}" + inline_html(:text => "#{opts[:indent_before_end]}#{opts[:end_tag]}#{opts[:indent_after_end]}") end def notextile(opts) if filter_html html_esc(opts[:text], :html_escape_preformatted) else opts[:text] end end def inline_html(opts) if filter_html html_esc(opts[:text], :html_escape_preformatted) else "#{opts[:text]}" # nil-safe end end def ignored_line(opts) opts[:text] + "\n" end private # escapement for regular HTML (not in PRE tag) def escape(text) html_esc(text) end # escapement for HTML in a PRE tag def escape_pre(text) html_esc(text, :html_escape_preformatted) end # escaping for HTML attributes def escape_attribute(text) html_esc(text, :html_escape_attributes) end def after_transform(text) text.chomp! end def before_transform(text) clean_html(text) if sanitize_html 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' => ['start'], 'ul' => nil, 'li' => nil, 'p' => nil, 'h1' => nil, 'h2' => nil, 'h3' => nil, 'h4' => nil, 'h5' => nil, 'h6' => nil, 'blockquote' => ['cite'], 'notextile' => nil } # Clean unauthorized tags. def clean_html( text, allowed_tags = BASIC_TAGS ) text.gsub!( /]*?)(\s?\/?)>/ ) do |m| raw = $~ tag = raw[2].downcase if allowed_tags.has_key? tag pcs = [tag] allowed_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' or prop == 'href') and not attrv =~ %r{^(http|https|ftp):} pcs << "#{prop}=\"#{attrv.gsub('"', '\\"')}\"" break end end end if allowed_tags[tag] "<#{raw[1]}#{pcs.join " "}#{raw[4]}>" else # Unauthorized tag if block_given? yield m else '' end end end end end