module Temple
module HTML
# @api public
class Fast < Filter
XHTML_DOCTYPES = {
'1.1' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
'5' => '<!DOCTYPE html>',
'html' => '<!DOCTYPE html>',
'strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
'frameset' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
'mobile' => '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">',
'basic' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
'transitional' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
'svg' => '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">'
}.freeze
HTML_DOCTYPES = {
'5' => '<!DOCTYPE html>',
'html' => '<!DOCTYPE html>',
'strict' => '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">',
'frameset' => '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">',
'transitional' => '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
}.freeze
define_options :format => :xhtml,
:attr_quote => '"',
:autoclose => %w[base basefont bgsound link meta area br embed img keygen wbr input menuitem param source track hr col frame],
:js_wrapper => nil
HTML = [:html, :html4, :html5]
def initialize(opts = {})
super
unless [:xhtml, *HTML].include?(options[:format])
raise ArgumentError, "Invalid format #{options[:format].inspect}"
end
wrapper = options[:js_wrapper]
wrapper = xhtml? ? :cdata : :comment if wrapper == :guess
@js_wrapper =
case wrapper
when :comment
[ "<!--\n", "\n//-->" ]
when :cdata
[ "\n//<![CDATA[\n", "\n//]]>\n" ]
when :both
[ "<!--\n//<![CDATA[\n", "\n//]]>\n//-->" ]
when nil
when Array
wrapper
else
raise ArgumentError, "Invalid JavaScript wrapper #{wrapper.inspect}"
end
end
def xhtml?
options[:format] == :xhtml
end
def html?
!xhtml?
end
def on_html_doctype(type)
type = type.to_s.downcase
if type =~ /^xml(\s+(.+))?$/
raise(FilterError, 'Invalid xml directive in html mode') if html?
w = options[:attr_quote]
str = "<?xml version=#{w}1.0#{w} encoding=#{w}#{$2 || 'utf-8'}#{w} ?>"
elsif html?
str = HTML_DOCTYPES[type] || raise(FilterError, "Invalid html doctype #{type}")
else
str = XHTML_DOCTYPES[type] || raise(FilterError, "Invalid xhtml doctype #{type}")
end
[:static, str]
end
def on_html_comment(content)
[:multi,
[:static, '<!--'],
compile(content),
[:static, '-->']]
end
def on_html_condcomment(condition, content)
on_html_comment [:multi,
[:static, "[#{condition}]>"],
content,
[:static, '<![endif]']]
end
def on_html_tag(name, attrs, content = nil)
name = name.to_s
closed = !content || (empty_exp?(content) && options[:autoclose].include?(name))
result = [:multi, [:static, "<#{name}"], compile(attrs)]
result << [:static, (closed && xhtml? ? ' /' : '') + '>']
result << compile(content) if content
result << [:static, "</#{name}>"] if !closed
result
end
def on_html_attrs(*attrs)
[:multi, *attrs.map {|attr| compile(attr) }]
end
def on_html_attr(name, value)
if html? && empty_exp?(value)
[:static, " #{name}"]
else
[:multi,
[:static, " #{name}=#{options[:attr_quote]}"],
compile(value),
[:static, options[:attr_quote]]]
end
end
def on_html_js(content)
if @js_wrapper
[:multi,
[:static, @js_wrapper.first],
compile(content),
[:static, @js_wrapper.last]]
else
compile(content)
end
end
end
end
end