OLD | NEW |
1 /** Internals to the tree builders. */ | 1 /** Internals to the tree builders. */ |
2 library treebuilder; | 2 library treebuilder; |
3 | 3 |
4 import 'package:html5lib/dom.dart'; | 4 import 'package:html5lib/dom.dart'; |
5 import 'package:html5lib/dom_parsing.dart'; | 5 import 'package:html5lib/dom_parsing.dart'; |
6 import 'constants.dart'; | 6 import 'constants.dart'; |
7 import 'list_proxy.dart'; | 7 import 'list_proxy.dart'; |
8 import 'token.dart'; | 8 import 'token.dart'; |
9 import 'utils.dart'; | 9 import 'utils.dart'; |
10 | 10 |
(...skipping 24 matching lines...) Expand all Loading... |
35 } | 35 } |
36 super.add(node); | 36 super.add(node); |
37 } | 37 } |
38 } | 38 } |
39 | 39 |
40 // TODO(jmesserly): this should exist in corelib... | 40 // TODO(jmesserly): this should exist in corelib... |
41 bool _mapEquals(Map a, Map b) { | 41 bool _mapEquals(Map a, Map b) { |
42 if (a.length != b.length) return false; | 42 if (a.length != b.length) return false; |
43 if (a.length == 0) return true; | 43 if (a.length == 0) return true; |
44 | 44 |
45 for (var keyA in a.getKeys()) { | 45 for (var keyA in a.keys) { |
46 var valB = b[keyA]; | 46 var valB = b[keyA]; |
47 if (valB == null && !b.containsKey(keyA)) { | 47 if (valB == null && !b.containsKey(keyA)) { |
48 return false; | 48 return false; |
49 } | 49 } |
50 | 50 |
51 if (a[keyA] != valB) { | 51 if (a[keyA] != valB) { |
52 return false; | 52 return false; |
53 } | 53 } |
54 } | 54 } |
55 return true; | 55 return true; |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 data: new LinkedHashMap.from(entry.attributes)) | 187 data: new LinkedHashMap.from(entry.attributes)) |
188 ..span = entry.span; | 188 ..span = entry.span; |
189 | 189 |
190 // Step 9 | 190 // Step 9 |
191 var element = insertElement(cloneToken); | 191 var element = insertElement(cloneToken); |
192 | 192 |
193 // Step 10 | 193 // Step 10 |
194 activeFormattingElements[i] = element; | 194 activeFormattingElements[i] = element; |
195 | 195 |
196 // Step 11 | 196 // Step 11 |
197 if (element == activeFormattingElements.last()) { | 197 if (element == activeFormattingElements.last) { |
198 break; | 198 break; |
199 } | 199 } |
200 } | 200 } |
201 } | 201 } |
202 | 202 |
203 void clearActiveFormattingElements() { | 203 void clearActiveFormattingElements() { |
204 var entry = activeFormattingElements.removeLast(); | 204 var entry = activeFormattingElements.removeLast(); |
205 while (activeFormattingElements.length > 0 && entry != Marker) { | 205 while (activeFormattingElements.length > 0 && entry != Marker) { |
206 entry = activeFormattingElements.removeLast(); | 206 entry = activeFormattingElements.removeLast(); |
207 } | 207 } |
(...skipping 24 matching lines...) Expand all Loading... |
232 } | 232 } |
233 | 233 |
234 void insertDoctype(DoctypeToken token) { | 234 void insertDoctype(DoctypeToken token) { |
235 var doctype = new DocumentType(token.name, token.publicId, token.systemId) | 235 var doctype = new DocumentType(token.name, token.publicId, token.systemId) |
236 ..span = token.span; | 236 ..span = token.span; |
237 document.nodes.add(doctype); | 237 document.nodes.add(doctype); |
238 } | 238 } |
239 | 239 |
240 void insertComment(Token token, [Node parent]) { | 240 void insertComment(Token token, [Node parent]) { |
241 if (parent == null) { | 241 if (parent == null) { |
242 parent = openElements.last(); | 242 parent = openElements.last; |
243 } | 243 } |
244 parent.nodes.add(new Comment(token.data)..span = token.span); | 244 parent.nodes.add(new Comment(token.data)..span = token.span); |
245 } | 245 } |
246 | 246 |
247 /** Create an element but don't insert it anywhere */ | 247 /** Create an element but don't insert it anywhere */ |
248 Element createElement(StartTagToken token) { | 248 Element createElement(StartTagToken token) { |
249 var name = token.name; | 249 var name = token.name; |
250 var namespace = token.namespace; | 250 var namespace = token.namespace; |
251 if (namespace == null) namespace = defaultNamespace; | 251 if (namespace == null) namespace = defaultNamespace; |
252 var element = new Element(name, namespace) | 252 var element = new Element(name, namespace) |
253 ..attributes = token.data | 253 ..attributes = token.data |
254 ..span = token.span; | 254 ..span = token.span; |
255 return element; | 255 return element; |
256 } | 256 } |
257 | 257 |
258 Element insertElement(StartTagToken token) { | 258 Element insertElement(StartTagToken token) { |
259 if (insertFromTable) return insertElementTable(token); | 259 if (insertFromTable) return insertElementTable(token); |
260 return insertElementNormal(token); | 260 return insertElementNormal(token); |
261 } | 261 } |
262 | 262 |
263 Element insertElementNormal(StartTagToken token) { | 263 Element insertElementNormal(StartTagToken token) { |
264 var name = token.name; | 264 var name = token.name; |
265 var namespace = token.namespace; | 265 var namespace = token.namespace; |
266 if (namespace == null) namespace = defaultNamespace; | 266 if (namespace == null) namespace = defaultNamespace; |
267 var element = new Element(name, namespace) | 267 var element = new Element(name, namespace) |
268 ..attributes = token.data | 268 ..attributes = token.data |
269 ..span = token.span; | 269 ..span = token.span; |
270 openElements.last().nodes.add(element); | 270 openElements.last.nodes.add(element); |
271 openElements.add(element); | 271 openElements.add(element); |
272 return element; | 272 return element; |
273 } | 273 } |
274 | 274 |
275 Element insertElementTable(token) { | 275 Element insertElementTable(token) { |
276 /** Create an element and insert it into the tree */ | 276 /** Create an element and insert it into the tree */ |
277 var element = createElement(token); | 277 var element = createElement(token); |
278 if (!tableInsertModeElements.contains(openElements.last().tagName)) { | 278 if (!tableInsertModeElements.contains(openElements.last.tagName)) { |
279 return insertElementNormal(token); | 279 return insertElementNormal(token); |
280 } else { | 280 } else { |
281 // We should be in the InTable mode. This means we want to do | 281 // We should be in the InTable mode. This means we want to do |
282 // special magic element rearranging | 282 // special magic element rearranging |
283 var nodePos = getTableMisnestedNodePosition(); | 283 var nodePos = getTableMisnestedNodePosition(); |
284 if (nodePos[1] == null) { | 284 if (nodePos[1] == null) { |
285 // TODO(jmesserly): I don't think this is reachable. If insertFromTable | 285 // TODO(jmesserly): I don't think this is reachable. If insertFromTable |
286 // is true, there will be a <table> element open, and it always has a | 286 // is true, there will be a <table> element open, and it always has a |
287 // parent pointer. | 287 // parent pointer. |
288 nodePos[0].nodes.add(element); | 288 nodePos[0].nodes.add(element); |
289 } else { | 289 } else { |
290 nodePos[0].insertBefore(element, nodePos[1]); | 290 nodePos[0].insertBefore(element, nodePos[1]); |
291 } | 291 } |
292 openElements.add(element); | 292 openElements.add(element); |
293 } | 293 } |
294 return element; | 294 return element; |
295 } | 295 } |
296 | 296 |
297 /** Insert text data. */ | 297 /** Insert text data. */ |
298 void insertText(String data, SourceSpan span) { | 298 void insertText(String data, SourceSpan span) { |
299 var parent = openElements.last(); | 299 var parent = openElements.last; |
300 | 300 |
301 if (!insertFromTable || insertFromTable && | 301 if (!insertFromTable || insertFromTable && |
302 !tableInsertModeElements.contains(openElements.last().tagName)) { | 302 !tableInsertModeElements.contains(openElements.last.tagName)) { |
303 _insertText(parent, data, span); | 303 _insertText(parent, data, span); |
304 } else { | 304 } else { |
305 // We should be in the InTable mode. This means we want to do | 305 // We should be in the InTable mode. This means we want to do |
306 // special magic element rearranging | 306 // special magic element rearranging |
307 var nodePos = getTableMisnestedNodePosition(); | 307 var nodePos = getTableMisnestedNodePosition(); |
308 _insertText(nodePos[0], data, span, nodePos[1]); | 308 _insertText(nodePos[0], data, span, nodePos[1]); |
309 } | 309 } |
310 } | 310 } |
311 | 311 |
312 /** | 312 /** |
313 * Insert [data] as text in the current node, positioned before the | 313 * Insert [data] as text in the current node, positioned before the |
314 * start of node [refNode] or to the end of the node's text. | 314 * start of node [refNode] or to the end of the node's text. |
315 */ | 315 */ |
316 static void _insertText(Node parent, String data, SourceSpan span, | 316 static void _insertText(Node parent, String data, SourceSpan span, |
317 [Element refNode]) { | 317 [Element refNode]) { |
318 var nodes = parent.nodes; | 318 var nodes = parent.nodes; |
319 if (refNode == null) { | 319 if (refNode == null) { |
320 if (nodes.length > 0 && nodes.last() is Text) { | 320 if (nodes.length > 0 && nodes.last is Text) { |
321 Text last = nodes.last(); | 321 Text last = nodes.last; |
322 last.value = '${last.value}$data'; | 322 last.value = '${last.value}$data'; |
323 } else { | 323 } else { |
324 nodes.add(new Text(data)..span = span); | 324 nodes.add(new Text(data)..span = span); |
325 } | 325 } |
326 } else { | 326 } else { |
327 int index = nodes.indexOf(refNode); | 327 int index = nodes.indexOf(refNode); |
328 if (index > 0 && nodes[index - 1] is Text) { | 328 if (index > 0 && nodes[index - 1] is Text) { |
329 Text last = nodes[index - 1]; | 329 Text last = nodes[index - 1]; |
330 last.value = '${last.value}$data'; | 330 last.value = '${last.value}$data'; |
331 } else { | 331 } else { |
(...skipping 28 matching lines...) Expand all Loading... |
360 } else { | 360 } else { |
361 fosterParent = openElements[openElements.indexOf(lastTable) - 1]; | 361 fosterParent = openElements[openElements.indexOf(lastTable) - 1]; |
362 } | 362 } |
363 } else { | 363 } else { |
364 fosterParent = openElements[0]; | 364 fosterParent = openElements[0]; |
365 } | 365 } |
366 return [fosterParent, insertBefore]; | 366 return [fosterParent, insertBefore]; |
367 } | 367 } |
368 | 368 |
369 void generateImpliedEndTags([String exclude]) { | 369 void generateImpliedEndTags([String exclude]) { |
370 var name = openElements.last().tagName; | 370 var name = openElements.last.tagName; |
371 // XXX td, th and tr are not actually needed | 371 // XXX td, th and tr are not actually needed |
372 if (name != exclude && const ["dd", "dt", "li", "option", "optgroup", "p", | 372 if (name != exclude && const ["dd", "dt", "li", "option", "optgroup", "p", |
373 "rp", "rt"].contains(name)) { | 373 "rp", "rt"].contains(name)) { |
374 openElements.removeLast(); | 374 openElements.removeLast(); |
375 // XXX This is not entirely what the specification says. We should | 375 // XXX This is not entirely what the specification says. We should |
376 // investigate it more closely. | 376 // investigate it more closely. |
377 generateImpliedEndTags(exclude); | 377 generateImpliedEndTags(exclude); |
378 } | 378 } |
379 } | 379 } |
380 | 380 |
381 /** Return the final tree. */ | 381 /** Return the final tree. */ |
382 Document getDocument() => document; | 382 Document getDocument() => document; |
383 | 383 |
384 /** Return the final fragment. */ | 384 /** Return the final fragment. */ |
385 DocumentFragment getFragment() { | 385 DocumentFragment getFragment() { |
386 //XXX assert innerHTML | 386 //XXX assert innerHTML |
387 var fragment = new DocumentFragment(); | 387 var fragment = new DocumentFragment(); |
388 openElements[0].reparentChildren(fragment); | 388 openElements[0].reparentChildren(fragment); |
389 return fragment; | 389 return fragment; |
390 } | 390 } |
391 } | 391 } |
OLD | NEW |