# $Id: html_formatter.rb,v 1.61 2006/10/11 13:06:14 yanagita Exp $ # Copyright (C) 2002-2003 TAKEUCHI Hitoshi require 'hiki/util' require 'hiki/pluginutil' require 'hiki/interwiki' require 'hiki/aliaswiki' require 'hiki/hiki_formatter' require 'uri' module Hiki class HTMLFormatter_default < HikiFormatter def initialize( s, db, plugin, conf, prefix = 'l') @html = s @db = db @plugin = plugin @conf = conf @prefix = prefix @references = Array::new @interwiki = InterWiki::new( @db.load( @conf.interwiki_name ) ) @aliaswiki = AliasWiki::new( @db.load( @conf.aliaswiki_name ) ) get_auto_links if @conf.auto_link end def to_s s = @html s = replace_inline_image( s ) s = replace_wikiname( s ) if @conf.use_wikiname s = replace_link( s ) s = replace_auto_link( s ) if @conf.auto_link s = replace_heading( s ) s = replace_plugin( s ) if @conf.use_plugin @html_converted = s s end def references @references.uniq end HEADING_RE = %r!.*.*?(.*?)! TAG_RE = %r!(<.+?>)! def toc s = "\n" * level) s end private def replace_inline_image( text ) text.gsub( /(.+?)<\/a>/i ) do |str| %Q|#{$3}| end end def replace_auto_link( text ) return text if @auto_links.empty? replace_inline( text ) do |str| str.gsub!( @auto_links_re ) do |match| @plugin.hiki_anchor( @auto_links[match].unescapeHTML.escape, match ) end end end WIKINAME_RE = /(\b(?:[A-Z][a-z0-9]+){2,}[A-Z]*\b)/n def replace_wikiname( text ) replace_inline( text ) do |str| str.gsub!( WIKINAME_RE ) do |i| %Q|#{i}| end end end PLUGIN_OPEN_RE = /<(span|div) class="plugin">/ PLUGIN_CLOSE_RE = %r!! LINK_OPEN_RE = /! PRE_OPEN_RE = /
/
    PRE_CLOSE_RE = %r!
! def replace_inline( text ) status = [] ret = text.split( TAG_RE ).collect do |str| case str when PLUGIN_OPEN_RE status << :plugin when LINK_OPEN_RE status << :a when PRE_OPEN_RE status << :pre when PLUGIN_CLOSE_RE, LINK_CLOSE_RE, PRE_CLOSE_RE status.pop when TAG_RE # do nothing else if status.empty? yield( str ) end end str end ret.join end URI_RE = /\A#{URI.regexp( %w( http https ftp file mailto ) )}\z/ def replace_link( text ) text.gsub( %r|
(.+?)| ) do |str| k, u = $2, $1 if URI_RE =~ u # uri @plugin.make_anchor(u, k, 'external') else u = u.unescapeHTML u = @aliaswiki.aliaswiki_names.key( u ) || u # alias wiki if /(.*)(#l\d+)\z/ =~ u u, anchor = $1, $2 else anchor = '' end if @db.exist?( u ) # page name k = @plugin.page_name( k ) if k == u @references << u @plugin.hiki_anchor( u.escape + anchor, k ) elsif orig = @db.select{|i| i[:title] == u}.first # page title k = @plugin.page_name( k ) if k == u u = orig @references << u @plugin.hiki_anchor( u.escape + anchor, k ) elsif outer_alias = @interwiki.outer_alias( u ) # outer alias @plugin.make_anchor(outer_alias[0] + anchor, k, 'external') elsif /:/ =~ u # inter wiki ? s, p = u.split( /:/, 2 ) if s.empty? # normal link @plugin.make_anchor( p.escapeHTML + anchor, k, 'external') elsif inter_link = @interwiki.interwiki( s, p.unescapeHTML, "#{s}:#{p}" ) @plugin.make_anchor(inter_link[0], k, 'external') else missing_page_anchor( k, u ) end else missing_page_anchor( k, u ) end end end end def missing_page_anchor( k, u ) if @plugin.creatable? missing_anchor_title = @conf.msg_missing_anchor_title % [ u.escapeHTML ] "#{k}?" else k end end BLOCKQUOTE_OPEN_RE = /
/ BLOCKQUOTE_CLOSE_RE = %r!
! HEADING_OPEN_RE = // HEADING_CLOSE_RE = %r!! def replace_heading( text ) status = [] num = -1 ret = text.split( TAG_RE ).collect do |str| case str when BLOCKQUOTE_OPEN_RE status << :blockquote when BLOCKQUOTE_CLOSE_RE status.pop when HEADING_OPEN_RE unless status.include?( :blockquote ) num += 1 level = $1.to_i status << level case level when 2 str << %Q! ! when 3 str << %Q! ! else str << %Q! ! end end when HEADING_CLOSE_RE unless status.include?( :blockquote ) level = status.pop str = "#{str}" if level == 2 end end str end ret.join end def replace_plugin( text ) text.gsub( %r!<(span|div) class="plugin">\{\{(.+?)\}\}!m ) do |str| tag, plugin_str = $1, $2 begin case tag when 'span' result = @plugin.inline_context{ apply_plugin( plugin_str, @plugin, @conf ) } when 'div' result = @plugin.block_context{ apply_plugin( plugin_str, @plugin, @conf ) } end result.class == String ? result : '' rescue Exception => e $& + e.message end end end def get_auto_links pages = {} @db.pages.each do |p| page_h = escape_html( p ) pages[page_h] = page_h title_h = @plugin.page_name( p ).gsub( /"/, '"' ) pages[title_h] = page_h unless title_h == page_h end @aliaswiki.aliaswiki_names.each do |key, value| orig_h = escape_html( key ) alias_h = escape_html( value ) pages[alias_h] = orig_h end @auto_links_re = Regexp.union( * pages.keys.sort_by{|i| -i.size} ) @auto_links = pages end def escape_html( text ) text.gsub( /&/, '&' ). gsub( //, '>' ) end end end