File: fast.rb

package info (click to toggle)
ruby-temple 0.10.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 476 kB
  • sloc: ruby: 3,347; makefile: 6
file content (131 lines) | stat: -rw-r--r-- 5,093 bytes parent folder | download | duplicates (2)
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