1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
# frozen_string_literal: true
module Temple
module HTML
# @api public
class Fast < Filter
DOCTYPES = {
xml: {
'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">'
},
html: {
'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">'
}
}
DOCTYPES[:xhtml] = DOCTYPES[:xml]
DOCTYPES.freeze
# See http://www.w3.org/html/wg/drafts/html/master/single-page.html#void-elements
HTML_VOID_ELEMENTS = %w[area base br col embed hr img input keygen link menuitem meta param source track wbr]
define_options format: :xhtml,
attr_quote: '"',
autoclose: HTML_VOID_ELEMENTS,
js_wrapper: nil
def initialize(opts = {})
super
@format = options[:format]
unless [:xhtml, :html, :xml].include?(@format)
if @format == :html4 || @format == :html5
warn "Format #{@format.inspect} is deprecated, use :html"
@format = :html
else
raise ArgumentError, "Invalid format #{@format.inspect}"
end
end
wrapper = options[:js_wrapper]
wrapper = @format == :xml || @format == :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 on_html_doctype(type)
type = type.to_s.downcase
if type =~ /^xml(\s+(.+))?$/
raise(FilterError, 'Invalid xml directive in html mode') if @format == :html
w = options[:attr_quote]
str = "<?xml version=#{w}1.0#{w} encoding=#{w}#{$2 || 'utf-8'}#{w} ?>"
else
str = DOCTYPES[@format][type] || raise(FilterError, "Invalid 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) && (@format == :xml || options[:autoclose].include?(name)))
result = [:multi, [:static, "<#{name}"], compile(attrs)]
result << [:static, (closed && @format != :html ? ' /' : '') + '>']
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 @format == :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
|