Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(174)

Side by Side Diff: pkg/third_party/html5lib/lib/dom.dart

Issue 178303009: [html5lib] api updates: localName (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « pkg/polymer/lib/src/build/linter.dart ('k') | pkg/third_party/html5lib/lib/dom_parsing.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /// A simple tree API that results from parsing html. Intended to be compatible 1 /// A simple tree API that results from parsing html. Intended to be compatible
2 /// with dart:html, but right now it resembles the classic JS DOM. 2 /// with dart:html, but right now it resembles the classic JS DOM.
3 library dom; 3 library dom;
4 4
5 import 'dart:collection'; 5 import 'dart:collection';
6 import 'package:source_maps/span.dart' show FileSpan; 6 import 'package:source_maps/span.dart' show FileSpan;
7 7
8 import 'src/constants.dart'; 8 import 'src/constants.dart';
9 import 'src/list_proxy.dart'; 9 import 'src/list_proxy.dart';
10 import 'src/token.dart'; 10 import 'src/token.dart';
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
68 static const int DOCUMENT_FRAGMENT_NODE = 11; 68 static const int DOCUMENT_FRAGMENT_NODE = 11;
69 static const int DOCUMENT_NODE = 9; 69 static const int DOCUMENT_NODE = 9;
70 static const int DOCUMENT_TYPE_NODE = 10; 70 static const int DOCUMENT_TYPE_NODE = 10;
71 static const int ELEMENT_NODE = 1; 71 static const int ELEMENT_NODE = 1;
72 static const int ENTITY_NODE = 6; 72 static const int ENTITY_NODE = 6;
73 static const int ENTITY_REFERENCE_NODE = 5; 73 static const int ENTITY_REFERENCE_NODE = 5;
74 static const int NOTATION_NODE = 12; 74 static const int NOTATION_NODE = 12;
75 static const int PROCESSING_INSTRUCTION_NODE = 7; 75 static const int PROCESSING_INSTRUCTION_NODE = 7;
76 static const int TEXT_NODE = 3; 76 static const int TEXT_NODE = 3;
77 77
78 // TODO(jmesserly): this should be on Element 78 /// Note: For now we use it to implement the deprecated tagName property.
79 /// The tag name associated with the node. 79 final String _tagName;
80 final String tagName; 80
81 /// *Deprecated* use [Element.localName] instead.
82 /// Note: after removal, this will be replaced by a correct version that
83 /// returns uppercase [as specified](http://dom.spec.whatwg.org/#dom-element-t agname).
84 @deprecated String get tagName => _tagName;
81 85
82 /// The parent of the current node (or null for the document node). 86 /// The parent of the current node (or null for the document node).
83 Node parent; 87 Node parent;
84 88
85 // TODO(jmesserly): should move to Element. 89 // TODO(jmesserly): should move to Element.
86 /// A map holding name, value pairs for attributes of the node. 90 /// A map holding name, value pairs for attributes of the node.
87 /// 91 ///
88 /// Note that attribute order needs to be stable for serialization, so we use 92 /// Note that attribute order needs to be stable for serialization, so we use
89 /// a LinkedHashMap. Each key is a [String] or [AttributeName]. 93 /// a LinkedHashMap. Each key is a [String] or [AttributeName].
90 LinkedHashMap<dynamic, String> attributes = new LinkedHashMap(); 94 LinkedHashMap<dynamic, String> attributes = new LinkedHashMap();
91 95
92 /// A list of child nodes of the current node. This must 96 /// A list of child nodes of the current node. This must
93 /// include all elements but not necessarily other node types. 97 /// include all elements but not necessarily other node types.
94 final NodeList nodes = new NodeList._(); 98 final NodeList nodes = new NodeList._();
95 99
96 List<Element> _elements; 100 List<Element> _elements;
97 101
98 // TODO(jmesserly): consider using an Expando for this, and put it in 102 // TODO(jmesserly): consider using an Expando for this, and put it in
99 // dom_parsing. Need to check the performance affect. 103 // dom_parsing. Need to check the performance affect.
100 /// The source span of this node, if it was created by the [HtmlParser]. 104 /// The source span of this node, if it was created by the [HtmlParser].
101 FileSpan sourceSpan; 105 FileSpan sourceSpan;
102 106
103 /// The attribute spans if requested. Otherwise null. 107 /// The attribute spans if requested. Otherwise null.
104 LinkedHashMap<dynamic, FileSpan> _attributeSpans; 108 LinkedHashMap<dynamic, FileSpan> _attributeSpans;
105 LinkedHashMap<dynamic, FileSpan> _attributeValueSpans; 109 LinkedHashMap<dynamic, FileSpan> _attributeValueSpans;
106 110
107 Node(this.tagName) { 111 /// *Deprecated* use [new Element.tag] instead.
112 @deprecated Node(String tagName) : this._(tagName);
113
114 Node._([this._tagName]) {
108 nodes._parent = this; 115 nodes._parent = this;
109 } 116 }
110 117
111 /// If [sourceSpan] is available, this contains the spans of each attribute. 118 /// If [sourceSpan] is available, this contains the spans of each attribute.
112 /// The span of an attribute is the entire attribute, including the name and 119 /// The span of an attribute is the entire attribute, including the name and
113 /// quotes (if any). For example, the span of "attr" in `<a attr="value">` 120 /// quotes (if any). For example, the span of "attr" in `<a attr="value">`
114 /// would be the text `attr="value"`. 121 /// would be the text `attr="value"`.
115 LinkedHashMap<dynamic, FileSpan> get attributeSpans { 122 LinkedHashMap<dynamic, FileSpan> get attributeSpans {
116 _ensureAttributeSpans(); 123 _ensureAttributeSpans();
117 return _attributeSpans; 124 return _attributeSpans;
(...skipping 13 matching lines...) Expand all
131 _elements = new FilteredElementList(this); 138 _elements = new FilteredElementList(this);
132 } 139 }
133 return _elements; 140 return _elements;
134 } 141 }
135 142
136 // TODO(jmesserly): needs to support deep clone. 143 // TODO(jmesserly): needs to support deep clone.
137 /// Return a shallow copy of the current node i.e. a node with the same 144 /// Return a shallow copy of the current node i.e. a node with the same
138 /// name and attributes but with no parent or child nodes. 145 /// name and attributes but with no parent or child nodes.
139 Node clone(); 146 Node clone();
140 147
141 String get namespace => null; 148 /// *Deprecated* use [Element.namespaceUri] instead.
149 @deprecated String get namespace => null;
142 150
143 int get nodeType; 151 int get nodeType;
144 152
145 /// *Deprecated* use [text], [Text.data] or [Comment.data]. 153 /// *Deprecated* use [text], [Text.data] or [Comment.data].
146 @deprecated String get value => null; 154 @deprecated String get value => null;
147 155
148 /// *Deprecated* use [nodeType]. 156 /// *Deprecated* use [nodeType].
149 @deprecated int get $dom_nodeType => nodeType; 157 @deprecated int get $dom_nodeType => nodeType;
150 158
151 String get outerHtml { 159 /// *Deprecated* use [Element.outerHtml]
160 @deprecated String get outerHtml => _outerHtml;
161
162 /// *Deprecated* use [Element.innerHtml]
163 @deprecated String get innerHtml => _innerHtml;
164 @deprecated set innerHtml(String value) { _innerHtml = value; }
165
166 // http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
167 String get _outerHtml {
152 var str = new StringBuffer(); 168 var str = new StringBuffer();
153 _addOuterHtml(str); 169 _addOuterHtml(str);
154 return str.toString(); 170 return str.toString();
155 } 171 }
156 172
157 String get innerHtml { 173 String get _innerHtml {
158 var str = new StringBuffer(); 174 var str = new StringBuffer();
159 _addInnerHtml(str); 175 _addInnerHtml(str);
160 return str.toString(); 176 return str.toString();
161 } 177 }
162 178
163 set innerHtml(String value) { 179 set _innerHtml(String value) {
164 nodes.clear(); 180 nodes.clear();
165 // TODO(jmesserly): should be able to get the same effect by adding the 181 // TODO(jmesserly): should be able to get the same effect by adding the
166 // fragment directly. 182 // fragment directly.
167 nodes.addAll(parseFragment(value, container: tagName).nodes); 183 nodes.addAll(parseFragment(value, container: _tagName).nodes);
168 } 184 }
169 185
170 // Implemented per: http://dom.spec.whatwg.org/#dom-node-textcontent 186 // Implemented per: http://dom.spec.whatwg.org/#dom-node-textcontent
171 String get text => null; 187 String get text => null;
172 set text(String value) {} 188 set text(String value) {}
173 189
174 void append(Node node) => nodes.add(node); 190 void append(Node node) => nodes.add(node);
175 191
176 Node get firstChild => nodes.isNotEmpty ? nodes[0] : null; 192 Node get firstChild => nodes.isNotEmpty ? nodes[0] : null;
177 193
178 void _addOuterHtml(StringBuffer str); 194 void _addOuterHtml(StringBuffer str);
179 195
180 void _addInnerHtml(StringBuffer str) { 196 void _addInnerHtml(StringBuffer str) {
181 for (Node child in nodes) child._addOuterHtml(str); 197 for (Node child in nodes) child._addOuterHtml(str);
182 } 198 }
183 199
184 String toString() => tagName;
185
186 Node remove() { 200 Node remove() {
187 // TODO(jmesserly): is parent == null an error? 201 // TODO(jmesserly): is parent == null an error?
188 if (parent != null) { 202 if (parent != null) {
189 parent.nodes.remove(this); 203 parent.nodes.remove(this);
190 } 204 }
191 return this; 205 return this;
192 } 206 }
193 207
194 /// Insert [node] as a child of the current node, before [refNode] in the 208 /// Insert [node] as a child of the current node, before [refNode] in the
195 /// list of child nodes. Raises [UnsupportedOperationException] if [refNode] 209 /// list of child nodes. Raises [UnsupportedOperationException] if [refNode]
(...skipping 13 matching lines...) Expand all
209 throw new UnsupportedError('Node must have a parent to replace it.'); 223 throw new UnsupportedError('Node must have a parent to replace it.');
210 } 224 }
211 parent.nodes[parent.nodes.indexOf(this)] = otherNode; 225 parent.nodes[parent.nodes.indexOf(this)] = otherNode;
212 return this; 226 return this;
213 } 227 }
214 228
215 // TODO(jmesserly): should this be a property or remove? 229 // TODO(jmesserly): should this be a property or remove?
216 /// Return true if the node has children or text. 230 /// Return true if the node has children or text.
217 bool hasContent() => nodes.length > 0; 231 bool hasContent() => nodes.length > 0;
218 232
219 Pair<String, String> get nameTuple { 233 /// *Deprecated* construct a pair using the namespaceUri and the name.
220 var ns = namespace != null ? namespace : Namespaces.html; 234 @deprecated Pair<String, String> get nameTuple =>
221 return new Pair(ns, tagName); 235 this is Element ? getElementNameTuple(this) : null;
222 }
223 236
224 /// Move all the children of the current node to [newParent]. 237 /// Move all the children of the current node to [newParent].
225 /// This is needed so that trees that don't store text as nodes move the 238 /// This is needed so that trees that don't store text as nodes move the
226 /// text in the correct way. 239 /// text in the correct way.
227 void reparentChildren(Node newParent) { 240 void reparentChildren(Node newParent) {
228 newParent.nodes.addAll(nodes); 241 newParent.nodes.addAll(nodes);
229 nodes.clear(); 242 nodes.clear();
230 } 243 }
231 244
232 /// *Deprecated* use [querySelector] instead. 245 /// *Deprecated* use [querySelector] instead.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
301 return false; 314 return false;
302 } 315 }
303 } 316 }
304 317
305 return true; 318 return true;
306 } 319 }
307 320
308 Element _queryType(String tag) { 321 Element _queryType(String tag) {
309 for (var node in nodes) { 322 for (var node in nodes) {
310 if (node is! Element) continue; 323 if (node is! Element) continue;
311 if (node.tagName == tag) return node; 324 if (node.localName == tag) return node;
312 var result = node._queryType(tag); 325 var result = node._queryType(tag);
313 if (result != null) return result; 326 if (result != null) return result;
314 } 327 }
315 return null; 328 return null;
316 } 329 }
317 330
318 void _queryAllType(String tag, List<Element> results) { 331 void _queryAllType(String tag, List<Element> results) {
319 for (var node in nodes) { 332 for (var node in nodes) {
320 if (node is! Element) continue; 333 if (node is! Element) continue;
321 if (node.tagName == tag) results.add(node); 334 if (node.localName == tag) results.add(node);
322 node._queryAllType(tag, results); 335 node._queryAllType(tag, results);
323 } 336 }
324 } 337 }
325 338
326 /// Initialize [attributeSpans] using [sourceSpan]. 339 /// Initialize [attributeSpans] using [sourceSpan].
327 void _ensureAttributeSpans() { 340 void _ensureAttributeSpans() {
328 if (_attributeSpans != null) return; 341 if (_attributeSpans != null) return;
329 342
330 _attributeSpans = new LinkedHashMap<dynamic, FileSpan>(); 343 _attributeSpans = new LinkedHashMap<dynamic, FileSpan>();
331 _attributeValueSpans = new LinkedHashMap<dynamic, FileSpan>(); 344 _attributeValueSpans = new LinkedHashMap<dynamic, FileSpan>();
(...skipping 14 matching lines...) Expand all
346 offset + attr.start, offset + attr.end); 359 offset + attr.start, offset + attr.end);
347 if (attr.startValue != null) { 360 if (attr.startValue != null) {
348 _attributeValueSpans[attr.name] = sourceSpan.file.span( 361 _attributeValueSpans[attr.name] = sourceSpan.file.span(
349 offset + attr.startValue, offset + attr.endValue); 362 offset + attr.startValue, offset + attr.endValue);
350 } 363 }
351 } 364 }
352 } 365 }
353 } 366 }
354 367
355 class Document extends Node { 368 class Document extends Node {
356 Document() : super(null); 369 Document() : super._();
357 factory Document.html(String html) => parse(html); 370 factory Document.html(String html) => parse(html);
358 371
359 int get nodeType => Node.DOCUMENT_NODE; 372 int get nodeType => Node.DOCUMENT_NODE;
360 373
361 // TODO(jmesserly): optmize this if needed 374 // TODO(jmesserly): optmize this if needed
362 Element get documentElement => querySelector('html'); 375 Element get documentElement => querySelector('html');
363 Element get head => documentElement.querySelector('head'); 376 Element get head => documentElement.querySelector('head');
364 Element get body => documentElement.querySelector('body'); 377 Element get body => documentElement.querySelector('body');
365 378
379 /// Returns a fragment of HTML or XML that represents the element and its
380 /// contents.
381 // TODO(jmesserly): this API is not specified in:
382 // <http://domparsing.spec.whatwg.org/> nor is it in dart:html, instead
383 // only Element has outerHtml. However it is quite useful. Should we move it
384 // to dom_parsing, where we keep other custom APIs?
385 String get outerHtml => _outerHtml;
386
366 String toString() => "#document"; 387 String toString() => "#document";
367 388
368 void _addOuterHtml(StringBuffer str) => _addInnerHtml(str); 389 void _addOuterHtml(StringBuffer str) => _addInnerHtml(str);
369 390
370 Document clone() => new Document(); 391 Document clone() => new Document();
371 } 392 }
372 393
373 class DocumentFragment extends Document { 394 class DocumentFragment extends Document {
374 DocumentFragment(); 395 DocumentFragment();
375 factory DocumentFragment.html(String html) => parseFragment(html); 396 factory DocumentFragment.html(String html) => parseFragment(html);
376 397
377 int get nodeType => Node.DOCUMENT_FRAGMENT_NODE; 398 int get nodeType => Node.DOCUMENT_FRAGMENT_NODE;
378 399
379 String toString() => "#document-fragment"; 400 String toString() => "#document-fragment";
380 401
381 DocumentFragment clone() => new DocumentFragment(); 402 DocumentFragment clone() => new DocumentFragment();
382 403
383 String get text => _getText(this); 404 String get text => _getText(this);
384 set text(String value) => _setText(this, value); 405 set text(String value) => _setText(this, value);
385 } 406 }
386 407
387 class DocumentType extends Node { 408 class DocumentType extends Node {
409 final String name;
388 final String publicId; 410 final String publicId;
389 final String systemId; 411 final String systemId;
390 412
391 DocumentType(String name, this.publicId, this.systemId) : super(name); 413 DocumentType(String name, this.publicId, this.systemId)
414 // Note: once Node.tagName is removed, don't pass "name" to super
415 : name = name, super._(name);
392 416
393 int get nodeType => Node.DOCUMENT_TYPE_NODE; 417 int get nodeType => Node.DOCUMENT_TYPE_NODE;
394 418
395 String toString() { 419 String toString() {
396 if (publicId != null || systemId != null) { 420 if (publicId != null || systemId != null) {
397 // TODO(jmesserly): the html5 serialization spec does not add these. But 421 // TODO(jmesserly): the html5 serialization spec does not add these. But
398 // it seems useful, and the parser can handle it, so for now keeping it. 422 // it seems useful, and the parser can handle it, so for now keeping it.
399 var pid = publicId != null ? publicId : ''; 423 var pid = publicId != null ? publicId : '';
400 var sid = systemId != null ? systemId : ''; 424 var sid = systemId != null ? systemId : '';
401 return '<!DOCTYPE $tagName "$pid" "$sid">'; 425 return '<!DOCTYPE $name "$pid" "$sid">';
402 } else { 426 } else {
403 return '<!DOCTYPE $tagName>'; 427 return '<!DOCTYPE $name>';
404 } 428 }
405 } 429 }
406 430
407 431
408 void _addOuterHtml(StringBuffer str) { 432 void _addOuterHtml(StringBuffer str) {
409 str.write(toString()); 433 str.write(toString());
410 } 434 }
411 435
412 DocumentType clone() => new DocumentType(tagName, publicId, systemId); 436 DocumentType clone() => new DocumentType(name, publicId, systemId);
413 } 437 }
414 438
415 class Text extends Node { 439 class Text extends Node {
416 String data; 440 String data;
417 441
418 Text(this.data) : super(null); 442 Text(this.data) : super._();
419 443
420 /// *Deprecated* use [data]. 444 /// *Deprecated* use [data].
421 @deprecated String get value => data; 445 @deprecated String get value => data;
422 @deprecated set value(String x) { data = x; } 446 @deprecated set value(String x) { data = x; }
423 447
424 int get nodeType => Node.TEXT_NODE; 448 int get nodeType => Node.TEXT_NODE;
425 449
426 String toString() => '"$data"'; 450 String toString() => '"$data"';
427 451
428 void _addOuterHtml(StringBuffer str) { 452 void _addOuterHtml(StringBuffer str) => writeTextNodeAsHtml(str, this);
429 // Don't escape text for certain elements, notably <script>.
430 if (rcdataElements.contains(parent.tagName) ||
431 parent.tagName == 'plaintext') {
432 str.write(data);
433 } else {
434 str.write(htmlSerializeEscape(data));
435 }
436 }
437 453
438 Text clone() => new Text(data); 454 Text clone() => new Text(data);
439 455
440 String get text => data; 456 String get text => data;
441 set text(String value) { data = value; } 457 set text(String value) { data = value; }
442 } 458 }
443 459
444 class Element extends Node { 460 class Element extends Node {
445 final String namespace; 461 final String namespaceUri;
446 462
447 // TODO(jmesserly): deprecate in favor of Element.tag? Or rename? 463 @deprecated String get namespace => namespaceUri;
448 Element(String name, [this.namespace]) : super(name);
449 464
450 Element.tag(String name) : namespace = null, super(name); 465 /// The [local name](http://dom.spec.whatwg.org/#concept-element-local-name)
466 /// of this element.
467 String get localName => _tagName;
468
469 // TODO(jmesserly): deprecate in favor of [Document.createElementNS].
470 // However we need every element to have a Document before this can work.
471 Element(String name, [this.namespaceUri]) : super._(name);
472
473 Element.tag(String name) : namespaceUri = null, super._(name);
451 474
452 static final _START_TAG_REGEXP = new RegExp('<(\\w+)'); 475 static final _START_TAG_REGEXP = new RegExp('<(\\w+)');
453 476
454 static final _CUSTOM_PARENT_TAG_MAP = const { 477 static final _CUSTOM_PARENT_TAG_MAP = const {
455 'body': 'html', 478 'body': 'html',
456 'head': 'html', 479 'head': 'html',
457 'caption': 'table', 480 'caption': 'table',
458 'td': 'tr', 481 'td': 'tr',
459 'colgroup': 'table', 482 'colgroup': 'table',
460 'col': 'colgroup', 483 'col': 'colgroup',
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 throw new ArgumentError('HTML had ${fragment.children.length} ' 522 throw new ArgumentError('HTML had ${fragment.children.length} '
500 'top level elements but 1 expected'); 523 'top level elements but 1 expected');
501 } 524 }
502 element.remove(); 525 element.remove();
503 return element; 526 return element;
504 } 527 }
505 528
506 int get nodeType => Node.ELEMENT_NODE; 529 int get nodeType => Node.ELEMENT_NODE;
507 530
508 String toString() { 531 String toString() {
509 if (namespace == null) return "<$tagName>"; 532 if (namespaceUri == null) return "<$localName>";
510 return "<${Namespaces.getPrefix(namespace)} $tagName>"; 533 return "<${Namespaces.getPrefix(namespaceUri)} $localName>";
511 } 534 }
512 535
513 String get text => _getText(this); 536 String get text => _getText(this);
514 set text(String value) => _setText(this, value); 537 set text(String value) => _setText(this, value);
515 538
539 /// Returns a fragment of HTML or XML that represents the element and its
540 /// contents.
541 String get outerHtml => _outerHtml;
542
543 /// Returns a fragment of HTML or XML that represents the element's contents.
544 /// Can be set, to replace the contents of the element with nodes parsed from
545 /// the given string.
546 String get innerHtml => _innerHtml;
547 // TODO(jmesserly): deprecate in favor of:
548 // <https://api.dartlang.org/apidocs/channels/stable/#dart-dom-html.Element@id _setInnerHtml>
549 set innerHtml(String value) { _innerHtml = value; }
550
516 void _addOuterHtml(StringBuffer str) { 551 void _addOuterHtml(StringBuffer str) {
517 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# serializing-html-fragments 552 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# serializing-html-fragments
518 // Element is the most complicated one. 553 // Element is the most complicated one.
519 if (namespace == null || 554 if (namespaceUri == null ||
520 namespace == Namespaces.html || 555 namespaceUri == Namespaces.html ||
521 namespace == Namespaces.mathml || 556 namespaceUri == Namespaces.mathml ||
522 namespace == Namespaces.svg) { 557 namespaceUri == Namespaces.svg) {
523 str.write('<$tagName'); 558 str.write('<$localName');
524 } else { 559 } else {
525 // TODO(jmesserly): the spec doesn't define "qualified name". 560 // TODO(jmesserly): the spec doesn't define "qualified name".
526 // I'm not sure if this is correct, but it should parse reasonably. 561 // I'm not sure if this is correct, but it should parse reasonably.
527 str.write('<${Namespaces.getPrefix(namespace)}:$tagName'); 562 str.write('<${Namespaces.getPrefix(namespaceUri)}:$localName');
528 } 563 }
529 564
530 if (attributes.length > 0) { 565 if (attributes.length > 0) {
531 attributes.forEach((key, v) { 566 attributes.forEach((key, v) {
532 // Note: AttributeName.toString handles serialization of attribute 567 // Note: AttributeName.toString handles serialization of attribute
533 // namespace, if needed. 568 // namespace, if needed.
534 str.write(' $key="${htmlSerializeEscape(v, attributeMode: true)}"'); 569 str.write(' $key="${htmlSerializeEscape(v, attributeMode: true)}"');
535 }); 570 });
536 } 571 }
537 572
538 str.write('>'); 573 str.write('>');
539 574
540 if (nodes.length > 0) { 575 if (nodes.length > 0) {
541 if (tagName == 'pre' || tagName == 'textarea' || tagName == 'listing') { 576 if (localName == 'pre' || localName == 'textarea' ||
577 localName == 'listing') {
542 final first = nodes[0]; 578 final first = nodes[0];
543 if (first is Text && first.data.startsWith('\n')) { 579 if (first is Text && first.data.startsWith('\n')) {
544 // These nodes will remove a leading \n at parse time, so if we still 580 // These nodes will remove a leading \n at parse time, so if we still
545 // have one, it means we started with two. Add it back. 581 // have one, it means we started with two. Add it back.
546 str.write('\n'); 582 str.write('\n');
547 } 583 }
548 } 584 }
549 585
550 _addInnerHtml(str); 586 _addInnerHtml(str);
551 } 587 }
552 588
553 // void elements must not have an end tag 589 // void elements must not have an end tag
554 // http://dev.w3.org/html5/markup/syntax.html#void-elements 590 // http://dev.w3.org/html5/markup/syntax.html#void-elements
555 if (!isVoidElement(tagName)) str.write('</$tagName>'); 591 if (!isVoidElement(localName)) str.write('</$localName>');
556 } 592 }
557 593
558 Element clone() => new Element(tagName, namespace) 594 Element clone() => new Element(localName, namespaceUri)
559 ..attributes = new LinkedHashMap.from(attributes); 595 ..attributes = new LinkedHashMap.from(attributes);
560 596
561 String get id { 597 String get id {
562 var result = attributes['id']; 598 var result = attributes['id'];
563 return result != null ? result : ''; 599 return result != null ? result : '';
564 } 600 }
565 601
566 set id(String value) { 602 set id(String value) {
567 if (value == null) { 603 if (value == null) {
568 attributes.remove('id'); 604 attributes.remove('id');
569 } else { 605 } else {
570 attributes['id'] = value; 606 attributes['id'] = value;
571 } 607 }
572 } 608 }
573 } 609 }
574 610
575 class Comment extends Node { 611 class Comment extends Node {
576 String data; 612 String data;
577 613
578 Comment(this.data) : super(null); 614 Comment(this.data) : super._();
579 615
580 int get nodeType => Node.COMMENT_NODE; 616 int get nodeType => Node.COMMENT_NODE;
581 617
582 String toString() => "<!-- $data -->"; 618 String toString() => "<!-- $data -->";
583 619
584 void _addOuterHtml(StringBuffer str) { 620 void _addOuterHtml(StringBuffer str) {
585 str.write("<!--$data-->"); 621 str.write("<!--$data-->");
586 } 622 }
587 623
588 Comment clone() => new Comment(data); 624 Comment clone() => new Comment(data);
(...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after
891 927
892 class _ConcatTextVisitor extends TreeVisitor { 928 class _ConcatTextVisitor extends TreeVisitor {
893 final _str = new StringBuffer(); 929 final _str = new StringBuffer();
894 930
895 String toString() => _str.toString(); 931 String toString() => _str.toString();
896 932
897 visitText(Text node) { 933 visitText(Text node) {
898 _str.write(node.data); 934 _str.write(node.data);
899 } 935 }
900 } 936 }
OLDNEW
« no previous file with comments | « pkg/polymer/lib/src/build/linter.dart ('k') | pkg/third_party/html5lib/lib/dom_parsing.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698