# $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"
num = -1
level = 1
to_s unless @html_converted
@html_converted.each do |line|
if HEADING_RE =~ line
new_level = $1.to_i - 1
num += 1
title = $2.gsub( TAG_RE, '' ).strip
if new_level > level
s << ( "\n" * ( new_level - level ) )
level = new_level
elsif new_level < level
s << ( "
\n" * ( level - new_level ) )
level = new_level
end
s << %Q!- #{title}
\n!
end
end
s << ("
\n" * level)
s
end
private
def replace_inline_image( text )
text.gsub( /(.+?)<\/a>/i ) do |str|
%Q|
|
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!(span|div)>!
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">\{\{(.+?)\}\}\1>!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( /, '<' ).
gsub( />/, '>' )
end
end
end