html5 0.1.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. data/History.txt +9 -2
  2. data/Manifest.txt +61 -2
  3. data/README +41 -5
  4. data/Rakefile.rb +22 -6
  5. data/{parse.rb → bin/html5} +11 -11
  6. data/lib/core_ext/string.rb +17 -0
  7. data/lib/html5/constants.rb +228 -0
  8. data/lib/html5/filters/iso639codes.rb +752 -0
  9. data/lib/html5/filters/rfc2046.rb +30 -0
  10. data/lib/html5/filters/rfc3987.rb +89 -0
  11. data/lib/html5/filters/validator.rb +830 -0
  12. data/lib/html5/html5parser.rb +25 -25
  13. data/lib/html5/html5parser/after_body_phase.rb +3 -3
  14. data/lib/html5/html5parser/after_frameset_phase.rb +3 -4
  15. data/lib/html5/html5parser/after_head_phase.rb +6 -6
  16. data/lib/html5/html5parser/before_head_phase.rb +1 -1
  17. data/lib/html5/html5parser/in_body_phase.rb +54 -48
  18. data/lib/html5/html5parser/in_caption_phase.rb +7 -6
  19. data/lib/html5/html5parser/in_cell_phase.rb +3 -3
  20. data/lib/html5/html5parser/in_column_group_phase.rb +1 -1
  21. data/lib/html5/html5parser/in_frameset_phase.rb +5 -5
  22. data/lib/html5/html5parser/in_head_phase.rb +10 -10
  23. data/lib/html5/html5parser/in_row_phase.rb +4 -2
  24. data/lib/html5/html5parser/in_select_phase.rb +7 -6
  25. data/lib/html5/html5parser/in_table_body_phase.rb +8 -5
  26. data/lib/html5/html5parser/in_table_phase.rb +12 -7
  27. data/lib/html5/html5parser/initial_phase.rb +5 -6
  28. data/lib/html5/html5parser/phase.rb +5 -9
  29. data/lib/html5/html5parser/root_element_phase.rb +1 -2
  30. data/lib/html5/html5parser/trailing_end_phase.rb +3 -3
  31. data/lib/html5/inputstream.rb +25 -31
  32. data/lib/html5/liberalxmlparser.rb +2 -2
  33. data/lib/html5/sanitizer.rb +6 -6
  34. data/lib/html5/serializer/htmlserializer.rb +2 -3
  35. data/lib/html5/sniffer.rb +45 -0
  36. data/lib/html5/tokenizer.rb +57 -59
  37. data/lib/html5/treebuilders/rexml.rb +7 -6
  38. data/lib/html5/treebuilders/simpletree.rb +1 -1
  39. data/lib/html5/treewalkers/base.rb +8 -0
  40. data/lib/html5/version.rb +3 -0
  41. data/testdata/encoding/chardet/test_big5.txt +51 -0
  42. data/testdata/encoding/test-yahoo-jp.dat +10 -0
  43. data/testdata/encoding/tests1.dat +394 -0
  44. data/testdata/encoding/tests2.dat +81 -0
  45. data/testdata/sanitizer/tests1.dat +416 -0
  46. data/testdata/serializer/core.test +104 -0
  47. data/testdata/serializer/injectmeta.test +65 -0
  48. data/testdata/serializer/optionaltags.test +900 -0
  49. data/testdata/serializer/options.test +60 -0
  50. data/testdata/serializer/whitespace.test +51 -0
  51. data/testdata/sites/google-results.htm +1 -0
  52. data/testdata/sites/python-ref-import.htm +1 -0
  53. data/testdata/sites/web-apps-old.htm +1 -0
  54. data/testdata/sites/web-apps.htm +34275 -0
  55. data/testdata/sniffer/htmlOrFeed.json +43 -0
  56. data/testdata/tokenizer/contentModelFlags.test +48 -0
  57. data/testdata/tokenizer/entities.test +2339 -0
  58. data/testdata/tokenizer/escapeFlag.test +21 -0
  59. data/testdata/tokenizer/test1.test +172 -0
  60. data/testdata/tokenizer/test2.test +129 -0
  61. data/testdata/tokenizer/test3.test +367 -0
  62. data/testdata/tokenizer/test4.test +198 -0
  63. data/testdata/tree-construction/tests1.dat +1950 -0
  64. data/testdata/tree-construction/tests2.dat +773 -0
  65. data/testdata/tree-construction/tests3.dat +270 -0
  66. data/testdata/tree-construction/tests4.dat +60 -0
  67. data/testdata/tree-construction/tests5.dat +175 -0
  68. data/testdata/tree-construction/tests6.dat +196 -0
  69. data/testdata/validator/attributes.test +1035 -0
  70. data/testdata/validator/base-href-attribute.test +787 -0
  71. data/testdata/validator/base-target-attribute.test +35 -0
  72. data/testdata/validator/blockquote-cite-attribute.test +7 -0
  73. data/testdata/validator/classattribute.test +152 -0
  74. data/testdata/validator/contenteditableattribute.test +59 -0
  75. data/testdata/validator/contextmenuattribute.test +115 -0
  76. data/testdata/validator/dirattribute.test +59 -0
  77. data/testdata/validator/draggableattribute.test +63 -0
  78. data/testdata/validator/html-xmlns-attribute.test +23 -0
  79. data/testdata/validator/idattribute.test +115 -0
  80. data/testdata/validator/inputattributes.test +2795 -0
  81. data/testdata/validator/irrelevantattribute.test +63 -0
  82. data/testdata/validator/langattribute.test +5579 -0
  83. data/testdata/validator/li-value-attribute.test +7 -0
  84. data/testdata/validator/link-href-attribute.test +7 -0
  85. data/testdata/validator/link-hreflang-attribute.test +7 -0
  86. data/testdata/validator/link-rel-attribute.test +271 -0
  87. data/testdata/validator/ol-start-attribute.test +7 -0
  88. data/testdata/validator/starttags.test +375 -0
  89. data/testdata/validator/style-scoped-attribute.test +7 -0
  90. data/testdata/validator/tabindexattribute.test +79 -0
  91. data/tests/preamble.rb +7 -17
  92. data/tests/test_encoding.rb +1 -1
  93. data/tests/test_lxp.rb +16 -0
  94. data/tests/test_parser.rb +2 -2
  95. data/tests/test_sniffer.rb +27 -0
  96. data/tests/test_treewalkers.rb +41 -22
  97. data/tests/test_validator.rb +31 -0
  98. metadata +65 -6
@@ -46,8 +46,8 @@ module HTML5
46
46
  @tree = TreeBuilders::REXML::TreeBuilder
47
47
 
48
48
  options.each {|name, value| instance_variable_set("@#{name}", value) }
49
- @lowercase_attr_name = nil unless instance_variable_defined?(:@lowercase_attr_name)
50
- @lowercase_element_name = nil unless instance_variable_defined?(:@lowercase_element_name)
49
+ @lowercase_attr_name = nil unless instance_variables.include?("@lowercase_attr_name")
50
+ @lowercase_element_name = nil unless instance_variables.include?("@lowercase_element_name")
51
51
 
52
52
  @tree = @tree.new
53
53
 
@@ -69,15 +69,15 @@ module HTML5
69
69
 
70
70
  if inner_html
71
71
  case @inner_html = container.downcase
72
- when 'title', 'textarea'
73
- @tokenizer.content_model_flag = :RCDATA
74
- when 'style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'noscript'
75
- @tokenizer.content_model_flag = :CDATA
76
- when 'plaintext'
77
- @tokenizer.content_model_flag = :PLAINTEXT
78
- else
72
+ when 'title', 'textarea'
73
+ @tokenizer.content_model_flag = :RCDATA
74
+ when 'style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'noscript'
75
+ @tokenizer.content_model_flag = :CDATA
76
+ when 'plaintext'
77
+ @tokenizer.content_model_flag = :PLAINTEXT
78
+ else
79
79
  # content_model_flag already is PCDATA
80
- #@tokenizer.content_model_flag = :PCDATA
80
+ @tokenizer.content_model_flag = :PCDATA
81
81
  end
82
82
 
83
83
  @phase = @phases[:rootElement]
@@ -100,17 +100,17 @@ module HTML5
100
100
  method = 'process%s' % token[:type]
101
101
 
102
102
  case token[:type]
103
- when :Characters, :SpaceCharacters, :Comment
104
- @phase.send method, token[:data]
105
- when :StartTag
106
- @phase.send method, token[:name], token[:data]
107
- when :EndTag
108
- @phase.send method, token[:name]
109
- when :Doctype
110
- @phase.send method, token[:name], token[:publicId],
111
- token[:systemId], token[:correct]
112
- else
113
- parse_error(token[:data])
103
+ when :Characters, :SpaceCharacters, :Comment
104
+ @phase.send method, token[:data]
105
+ when :StartTag
106
+ @phase.send method, token[:name], token[:data]
107
+ when :EndTag
108
+ @phase.send method, token[:name]
109
+ when :Doctype
110
+ @phase.send method, token[:name], token[:publicId],
111
+ token[:systemId], token[:correct]
112
+ else
113
+ parse_error(token[:data], token[:datavars])
114
114
  end
115
115
  end
116
116
 
@@ -147,9 +147,9 @@ module HTML5
147
147
  @tree.get_fragment
148
148
  end
149
149
 
150
- def parse_error(data = 'XXX ERROR MESSAGE NEEDED')
150
+ def parse_error(code = 'XXX-undefined-error', data = {})
151
151
  # XXX The idea is to make data mandatory.
152
- @errors.push([@tokenizer.stream.position, data])
152
+ @errors.push([@tokenizer.stream.position, code, data])
153
153
  raise ParseError if @strict
154
154
  end
155
155
 
@@ -163,7 +163,7 @@ module HTML5
163
163
  # thing and if it doesn't it's wrong for everyone.
164
164
 
165
165
  unless VOID_ELEMENTS.include?(token[:name])
166
- parse_error(_('Solidus (/) incorrectly placed in tag.'))
166
+ parse_error("incorrectly-placed-solidus")
167
167
  end
168
168
 
169
169
  token[:type] = :StartTag
@@ -181,7 +181,7 @@ module HTML5
181
181
  end
182
182
 
183
183
  elsif token[:type] == :EndTag
184
- parse_error(_('End tag contains unexpected attributes.')) unless token[:data].empty?
184
+ parse_error("attributes-in-end-tag") unless token[:data].empty?
185
185
  token[:name] = token[:name].downcase
186
186
  end
187
187
 
@@ -12,13 +12,13 @@ module HTML5
12
12
  end
13
13
 
14
14
  def processCharacters(data)
15
- parse_error(_('Unexpected non-space characters in the after body phase.'))
15
+ parse_error("unexpected-char-after-body")
16
16
  @parser.phase = @parser.phases[:inBody]
17
17
  @parser.phase.processCharacters(data)
18
18
  end
19
19
 
20
20
  def processStartTag(name, attributes)
21
- parse_error(_("Unexpected start tag token (#{name}) in the after body phase."))
21
+ parse_error("unexpected-start-tag-after-body", {"name" => name})
22
22
  @parser.phase = @parser.phases[:inBody]
23
23
  @parser.phase.processStartTag(name, attributes)
24
24
  end
@@ -37,7 +37,7 @@ module HTML5
37
37
  end
38
38
 
39
39
  def endTagOther(name)
40
- parse_error(_("Unexpected end tag token (#{name}) in the after body phase."))
40
+ parse_error("unexpected-end-tag-after-body", {"name" => name})
41
41
  @parser.phase = @parser.phases[:inBody]
42
42
  @parser.phase.processEndTag(name)
43
43
  end
@@ -10,7 +10,7 @@ module HTML5
10
10
  handle_end 'html'
11
11
 
12
12
  def processCharacters(data)
13
- parse_error(_('Unexpected non-space characters in the after frameset phase. Ignored.'))
13
+ parse_error("unexpected-char-after-frameset")
14
14
  end
15
15
 
16
16
  def startTagNoframes(name, attributes)
@@ -18,7 +18,7 @@ module HTML5
18
18
  end
19
19
 
20
20
  def startTagOther(name, attributes)
21
- parse_error(_("Unexpected start tag (#{name}) in the after frameset phase. Ignored."))
21
+ parse_error("unexpected-start-tag-after-frameset", {"name" => name})
22
22
  end
23
23
 
24
24
  def endTagHtml(name)
@@ -27,8 +27,7 @@ module HTML5
27
27
  end
28
28
 
29
29
  def endTagOther(name)
30
- parse_error(_("Unexpected end tag (#{name}) in the after frameset phase. Ignored."))
30
+ parse_error("unexpected-end-tag-after-frameset", {"name" => name})
31
31
  end
32
-
33
32
  end
34
33
  end
@@ -6,12 +6,12 @@ module HTML5
6
6
  handle_start 'html', 'body', 'frameset', %w( base link meta script style title ) => 'FromHead'
7
7
 
8
8
  def process_eof
9
- anythingElse
9
+ anything_else
10
10
  @parser.phase.process_eof
11
11
  end
12
12
 
13
13
  def processCharacters(data)
14
- anythingElse
14
+ anything_else
15
15
  @parser.phase.processCharacters(data)
16
16
  end
17
17
 
@@ -26,22 +26,22 @@ module HTML5
26
26
  end
27
27
 
28
28
  def startTagFromHead(name, attributes)
29
- parse_error(_("Unexpected start tag (#{name}) that can be in head. Moved."))
29
+ parse_error("unexpected-start-tag-out-of-my-head", {"name" => name})
30
30
  @parser.phase = @parser.phases[:inHead]
31
31
  @parser.phase.processStartTag(name, attributes)
32
32
  end
33
33
 
34
34
  def startTagOther(name, attributes)
35
- anythingElse
35
+ anything_else
36
36
  @parser.phase.processStartTag(name, attributes)
37
37
  end
38
38
 
39
39
  def processEndTag(name)
40
- anythingElse
40
+ anything_else
41
41
  @parser.phase.processEndTag(name)
42
42
  end
43
43
 
44
- def anythingElse
44
+ def anything_else
45
45
  @tree.insert_element('body', {})
46
46
  @parser.phase = @parser.phases[:inBody]
47
47
  end
@@ -34,7 +34,7 @@ module HTML5
34
34
  end
35
35
 
36
36
  def endTagOther(name)
37
- parse_error(_("Unexpected end tag (#{name}) after the (implied) root element."))
37
+ parse_error("end-tag-after-implied-root", {"name" => name})
38
38
  end
39
39
 
40
40
  end
@@ -6,45 +6,45 @@ module HTML5
6
6
  # http://www.whatwg.org/specs/web-apps/current-work/#in-body
7
7
 
8
8
  handle_start 'html'
9
- handle_start %w( base link meta script style ) => 'ProcessInHead'
9
+ handle_start %w(base link meta script style) => 'ProcessInHead'
10
10
  handle_start 'title'
11
11
 
12
12
  handle_start 'body', 'form', 'plaintext', 'a', 'button', 'xmp', 'table', 'hr', 'image'
13
13
 
14
- handle_start 'input', 'textarea', 'select', 'isindex', %w( marquee object )
14
+ handle_start 'input', 'textarea', 'select', 'isindex', %w(marquee object)
15
15
 
16
- handle_start %w( li dd dt ) => 'ListItem'
17
-
18
- handle_start %w( address blockquote center dir div dl fieldset listing menu ol p pre ul ) => 'CloseP'
16
+ handle_start %w(li dd dt) => 'ListItem'
19
17
 
20
- handle_start %w( b big em font i s small strike strong tt u ) => 'Formatting'
18
+ handle_start %w(address blockquote center dir div dl fieldset listing menu ol p pre ul) => 'CloseP'
19
+
20
+ handle_start %w(b big em font i s small strike strong tt u) => 'Formatting'
21
21
  handle_start 'nobr'
22
22
 
23
- handle_start %w( area basefont bgsound br embed img param spacer wbr ) => 'VoidFormatting'
23
+ handle_start %w(area basefont bgsound br embed img param spacer wbr) => 'VoidFormatting'
24
24
 
25
- handle_start %w( iframe noembed noframes noscript ) => 'Cdata', HEADING_ELEMENTS => 'Heading'
25
+ handle_start %w(iframe noembed noframes noscript) => 'Cdata', HEADING_ELEMENTS => 'Heading'
26
26
 
27
- handle_start %w( caption col colgroup frame frameset head option optgroup tbody td tfoot th thead tr ) => 'Misplaced'
27
+ handle_start %w(caption col colgroup frame frameset head option optgroup tbody td tfoot th thead tr) => 'Misplaced'
28
28
 
29
- handle_start %w( event-source section nav article aside header footer datagrid command ) => 'New'
29
+ handle_start %w(event-source section nav article aside header footer datagrid command) => 'New'
30
30
 
31
- handle_end 'p', 'body', 'html', 'form', %w( button marquee object ), %w( dd dt li ) => 'ListItem'
31
+ handle_end 'p', 'body', 'html', 'form', %w(button marquee object), %w(dd dt li) => 'ListItem'
32
32
 
33
- handle_end %w( address blockquote center div dl fieldset listing menu ol pre ul ) => 'Block'
33
+ handle_end %w(address blockquote center div dl fieldset listing menu ol pre ul) => 'Block'
34
34
 
35
35
  handle_end HEADING_ELEMENTS => 'Heading'
36
36
 
37
- handle_end %w( a b big em font i nobr s small strike strong tt u ) => 'Formatting'
37
+ handle_end %w(a b big em font i nobr s small strike strong tt u) => 'Formatting'
38
38
 
39
- handle_end %w( head frameset select optgroup option table caption colgroup col thead tfoot tbody tr td th ) => 'Misplaced'
39
+ handle_end %w(head frameset select optgroup option table caption colgroup col thead tfoot tbody tr td th) => 'Misplaced'
40
40
 
41
41
  handle_end 'br'
42
42
 
43
- handle_end %w( area basefont bgsound embed hr image img input isindex param spacer wbr frame ) => 'None'
43
+ handle_end %w(area basefont bgsound embed hr image img input isindex param spacer wbr frame) => 'None'
44
44
 
45
- handle_end %w( noframes noscript noembed textarea xmp iframe ) => 'CdataTextAreaXmp'
45
+ handle_end %w(noframes noscript noembed textarea xmp iframe ) => 'CdataTextAreaXmp'
46
46
 
47
- handle_end %w( event-source section nav article aside header footer datagrid command ) => 'New'
47
+ handle_end %w(event-source section nav article aside header footer datagrid command) => 'New'
48
48
 
49
49
  def initialize(parser, tree)
50
50
  super(parser, tree)
@@ -100,14 +100,14 @@ module HTML5
100
100
  end
101
101
 
102
102
  def startTagTitle(name, attributes)
103
- parse_error(_("Unexpected start tag (#{name}) that belongs in the head. Moved."))
103
+ parse_error("unexpected-start-tag-out-of-my-head", {"name" => name})
104
104
  @parser.phases[:inHead].processStartTag(name, attributes)
105
105
  end
106
106
 
107
107
  def startTagBody(name, attributes)
108
- parse_error(_('Unexpected start tag (body).'))
108
+ parse_error("unexpected-start-tag", {"name" => "body"})
109
109
 
110
- if (@tree.open_elements.length == 1 || @tree.open_elements[1].name != 'body')
110
+ if @tree.open_elements.length == 1 || @tree.open_elements[1].name != 'body'
111
111
  assert @parser.inner_html
112
112
  else
113
113
  attributes.each do |attr, value|
@@ -126,11 +126,11 @@ module HTML5
126
126
 
127
127
  def startTagForm(name, attributes)
128
128
  if @tree.formPointer
129
- parse_error(_('Unexpected start tag (form). Ignored.'))
129
+ parse_error("unexpected-start-tag", {"name" => name})
130
130
  else
131
131
  endTagP('p') if in_scope?('p')
132
132
  @tree.insert_element(name, attributes)
133
- @tree.formPointer = @tree.open_elements[-1]
133
+ @tree.formPointer = @tree.open_elements.last
134
134
  end
135
135
  end
136
136
 
@@ -143,7 +143,10 @@ module HTML5
143
143
  if stopName.include?(node.name)
144
144
  poppedNodes = (0..i).collect { @tree.open_elements.pop }
145
145
  if i >= 1
146
- parse_error(_("Missing end tag%s (%s)" % [(i>1 ? 's' : ''), poppedNodes.reverse.map{|item| item.name}.join(', ')]))
146
+ parse_error(
147
+ i == 1 ? "missing-end-tag" : "missing-end-tags",
148
+ {"name" => poppedNodes[0..-1].collect{|n| n.name}.join(", ")})
149
+
147
150
  end
148
151
  break
149
152
  end
@@ -169,7 +172,7 @@ module HTML5
169
172
  # Uncomment the following for IE7 behavior:
170
173
  # HEADING_ELEMENTS.each do |element|
171
174
  # if in_scope?(element)
172
- # parse_error(_("Unexpected start tag (#{name})."))
175
+ # parse_error("unexpected-start-tag", {"name" => name})
173
176
  #
174
177
  # remove_open_elements_until do |element|
175
178
  # HEADING_ELEMENTS.include?(element.name)
@@ -183,7 +186,7 @@ module HTML5
183
186
 
184
187
  def startTagA(name, attributes)
185
188
  if afeAElement = @tree.elementInActiveFormattingElements('a')
186
- parse_error(_('Unexpected start tag (a) implies end tag (a).'))
189
+ parse_error("unexpected-start-tag-implies-end-tag", {"startName" => "a", "endName" => "a"})
187
190
  endTagFormatting('a')
188
191
  @tree.open_elements.delete(afeAElement) if @tree.open_elements.include?(afeAElement)
189
192
  @tree.activeFormattingElements.delete(afeAElement) if @tree.activeFormattingElements.include?(afeAElement)
@@ -200,7 +203,7 @@ module HTML5
200
203
  def startTagNobr(name, attributes)
201
204
  @tree.reconstructActiveFormattingElements
202
205
  if in_scope?('nobr')
203
- parse_error(_('Unexpected start tag (nobr) implies end tag (nobr).'))
206
+ parse_error("unexpected-start-tag-implies-end-tag", {"startName" => "nobr", "endName" => "nobr"})
204
207
  processEndTag('nobr')
205
208
  # XXX Need tests that trigger the following
206
209
  @tree.reconstructActiveFormattingElements
@@ -210,7 +213,7 @@ module HTML5
210
213
 
211
214
  def startTagButton(name, attributes)
212
215
  if in_scope?('button')
213
- parse_error(_('Unexpected start tag (button) implied end tag (button).'))
216
+ parse_error("unexpected-start-tag-implies-end-tag", {"startName" => "button", "endName" => "button"})
214
217
  processEndTag('button')
215
218
  @parser.phase.processStartTag(name, attributes)
216
219
  else
@@ -252,7 +255,7 @@ module HTML5
252
255
 
253
256
  def startTagImage(name, attributes)
254
257
  # No really...
255
- parse_error(_('Unexpected start tag (image). Treated as img.'))
258
+ parse_error("unexpected-start-tag-treated-as", {"originalName" => "image", "newName" => "img"})
256
259
  processStartTag('img', attributes)
257
260
  end
258
261
 
@@ -267,7 +270,7 @@ module HTML5
267
270
  end
268
271
 
269
272
  def startTagIsindex(name, attributes)
270
- parse_error(_("Unexpected start tag isindex. Don't use it!"))
273
+ parse_error("deprecated-tag", {"name" => "isindex"})
271
274
  return if @tree.formPointer
272
275
  processStartTag('form', {})
273
276
  processStartTag('hr', {})
@@ -310,13 +313,13 @@ module HTML5
310
313
  # "caption", "col", "colgroup", "frame", "frameset", "head",
311
314
  # "option", "optgroup", "tbody", "td", "tfoot", "th", "thead",
312
315
  # "tr", "noscript"
313
- parse_error(_("Unexpected start tag (#{name}). Ignored."))
316
+ parse_error("unexpected-start-tag-ignored", {"name" => name})
314
317
  end
315
318
 
316
319
  def startTagNew(name, attributes)
317
320
  # New HTML5 elements, "event-source", "section", "nav",
318
321
  # "article", "aside", "header", "footer", "datagrid", "command"
319
- sys.stderr.write("Warning: Undefined behaviour for start tag #{name}")
322
+ # $stderr.puts("Warning: Undefined behaviour for start tag #{name}")
320
323
  startTagOther(name, attributes)
321
324
  #raise NotImplementedError
322
325
  end
@@ -328,7 +331,7 @@ module HTML5
328
331
 
329
332
  def endTagP(name)
330
333
  @tree.generateImpliedEndTags('p') if in_scope?('p')
331
- parse_error(_('Unexpected end tag (p).')) unless @tree.open_elements.last.name == 'p'
334
+ parse_error("unexpected-end-tag", {"name" => "p"}) unless @tree.open_elements.last.name == 'p'
332
335
  if in_scope?('p')
333
336
  @tree.open_elements.pop while in_scope?('p')
334
337
  else
@@ -347,7 +350,9 @@ module HTML5
347
350
  return
348
351
  end
349
352
  unless @tree.open_elements.last.name == 'body'
350
- parse_error(_("Unexpected end tag (body). Missing end tag (#{@tree.open_elements[-1].name})."))
353
+ parse_error("expected-one-end-tag-but-got-another",
354
+ {"expectedName" => "body",
355
+ "gotName" => @tree.open_elements.last.name})
351
356
  end
352
357
  @parser.phase = @parser.phases[:afterBody]
353
358
  end
@@ -364,7 +369,7 @@ module HTML5
364
369
  @tree.generateImpliedEndTags if in_scope?(name)
365
370
 
366
371
  unless @tree.open_elements.last.name == name
367
- parse_error(_("End tag (#{name}) seen too early. Expected other end tag."))
372
+ parse_error("end-tag-too-early", {"name" => name})
368
373
  end
369
374
 
370
375
  if in_scope?(name)
@@ -377,7 +382,7 @@ module HTML5
377
382
  @tree.generateImpliedEndTags
378
383
  end
379
384
  if @tree.open_elements.last.name != name
380
- parse_error(_("End tag (form) seen too early. Ignored."))
385
+ parse_error("end-tag-too-early-ignored", {"name" => "form"})
381
386
  else
382
387
  @tree.open_elements.pop
383
388
  end
@@ -389,7 +394,7 @@ module HTML5
389
394
  @tree.generateImpliedEndTags(name) if in_scope?(name)
390
395
 
391
396
  unless @tree.open_elements.last.name == name
392
- parse_error(_("End tag (#{name}) seen too early. " + 'Expected other end tag.'))
397
+ parse_error("end-tag-too-early", {"name" => name})
393
398
  end
394
399
 
395
400
  remove_open_elements_until(name) if in_scope?(name)
@@ -404,7 +409,7 @@ module HTML5
404
409
  end
405
410
 
406
411
  unless @tree.open_elements.last.name == name
407
- parse_error(_("Unexpected end tag (#{name}). Expected other end tag."))
412
+ parse_error("end-tag-too-early", {"name" => name})
408
413
  end
409
414
 
410
415
  HEADING_ELEMENTS.each do |element|
@@ -423,18 +428,18 @@ module HTML5
423
428
  # Step 1 paragraph 1
424
429
  afeElement = @tree.elementInActiveFormattingElements(name)
425
430
  if !afeElement or (@tree.open_elements.include?(afeElement) && !in_scope?(afeElement.name))
426
- parse_error(_("End tag (#{name}) violates step 1, paragraph 1 of the adoption agency algorithm."))
431
+ parse_error("adoption-agency-1.1", {"name" => name})
427
432
  return
428
433
  # Step 1 paragraph 2
429
434
  elsif not @tree.open_elements.include?(afeElement)
430
- parse_error(_("End tag (#{name}) violates step 1, paragraph 2 of the adoption agency algorithm."))
435
+ parse_error("adoption-agency-1.2", {"name" => name})
431
436
  @tree.activeFormattingElements.delete(afeElement)
432
437
  return
433
438
  end
434
439
 
435
440
  # Step 1 paragraph 3
436
441
  if afeElement != @tree.open_elements.last
437
- parse_error(_("End tag (#{name}) violates step 1, paragraph 3 of the adoption agency algorithm."))
442
+ parse_error("adoption-agency-1.3", {"name" => name})
438
443
  end
439
444
 
440
445
  # Step 2
@@ -531,7 +536,7 @@ module HTML5
531
536
  @tree.generateImpliedEndTags if in_scope?(name)
532
537
 
533
538
  unless @tree.open_elements.last.name == name
534
- parse_error(_("Unexpected end tag (#{name}). Expected other end tag first."))
539
+ parse_error("end-tag-too-early", {"name" => name})
535
540
  end
536
541
 
537
542
  if in_scope?(name)
@@ -543,11 +548,12 @@ module HTML5
543
548
 
544
549
  def endTagMisplaced(name)
545
550
  # This handles elements with end tags in other insertion modes.
546
- parse_error(_("Unexpected end tag (#{name}). Ignored."))
551
+ parse_error("unexpected-end-tag", {"name" => name})
547
552
  end
548
553
 
549
554
  def endTagBr(name)
550
- parse_error(_("Unexpected end tag (br). Treated as br element."))
555
+ parse_error("unexpected-end-tag-treated-as",
556
+ {"originalName" => "br", "newName" => "br element"})
551
557
  @tree.reconstructActiveFormattingElements
552
558
  @tree.insert_element(name, {})
553
559
  @tree.open_elements.pop()
@@ -555,21 +561,21 @@ module HTML5
555
561
 
556
562
  def endTagNone(name)
557
563
  # This handles elements with no end tag.
558
- parse_error(_("This tag (#{name}) has no end tag"))
564
+ parse_error("no-end-tag", {"name" => name})
559
565
  end
560
566
 
561
567
  def endTagCdataTextAreaXmp(name)
562
568
  if @tree.open_elements.last.name == name
563
569
  @tree.open_elements.pop
564
570
  else
565
- parse_error(_("Unexpected end tag (#{name}). Ignored."))
571
+ parse_error("unexpected-end-tag", {"name" => name})
566
572
  end
567
573
  end
568
574
 
569
575
  def endTagNew(name)
570
576
  # New HTML5 elements, "event-source", "section", "nav",
571
577
  # "article", "aside", "header", "footer", "datagrid", "command"
572
- STDERR.puts "Warning: Undefined behaviour for end tag #{name}"
578
+ # STDERR.puts "Warning: Undefined behaviour for end tag #{name}"
573
579
  endTagOther(name)
574
580
  #raise NotImplementedError
575
581
  end
@@ -581,7 +587,7 @@ module HTML5
581
587
  @tree.generateImpliedEndTags
582
588
 
583
589
  unless @tree.open_elements.last.name == name
584
- parse_error(_("Unexpected end tag (#{name})."))
590
+ parse_error("unexpected-end-tag", {"name" => name})
585
591
  end
586
592
 
587
593
  remove_open_elements_until {|element| element == node }
@@ -589,7 +595,7 @@ module HTML5
589
595
  break
590
596
  else
591
597
  if (SPECIAL_ELEMENTS + SCOPING_ELEMENTS).include?(node.name)
592
- parse_error(_("Unexpected end tag (#{name}). Ignored."))
598
+ parse_error("unexpected-end-tag", {"name" => name})
593
599
  break
594
600
  end
595
601
  end