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

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

Issue 178843003: [html5lib] triple slash comment style (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: remove extra check 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 | « no previous file | 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 /** 1 /// A simple tree API that results from parsing html. Intended to be compatible
2 * 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.
3 * with dart:html, but right now it resembles the classic JS DOM.
4 */
5 library dom; 3 library dom;
6 4
7 import 'dart:collection'; 5 import 'dart:collection';
8 import 'package:source_maps/span.dart' show FileSpan; 6 import 'package:source_maps/span.dart' show FileSpan;
9 7
10 import 'src/constants.dart'; 8 import 'src/constants.dart';
11 import 'src/list_proxy.dart'; 9 import 'src/list_proxy.dart';
12 import 'src/token.dart'; 10 import 'src/token.dart';
13 import 'src/tokenizer.dart'; 11 import 'src/tokenizer.dart';
14 import 'src/utils.dart'; 12 import 'src/utils.dart';
15 import 'dom_parsing.dart'; 13 import 'dom_parsing.dart';
16 import 'parser.dart'; 14 import 'parser.dart';
17 15
18 // TODO(jmesserly): this needs to be replaced by an AttributeMap for attributes 16 // TODO(jmesserly): this needs to be replaced by an AttributeMap for attributes
19 // that exposes namespace info. 17 // that exposes namespace info.
20 class AttributeName implements Comparable { 18 class AttributeName implements Comparable {
21 /** The namespace prefix, e.g. `xlink`. */ 19 /// The namespace prefix, e.g. `xlink`.
22 final String prefix; 20 final String prefix;
23 21
24 /** The attribute name, e.g. `title`. */ 22 /// The attribute name, e.g. `title`.
25 final String name; 23 final String name;
26 24
27 /** The namespace url, e.g. `http://www.w3.org/1999/xlink` */ 25 /// The namespace url, e.g. `http://www.w3.org/1999/xlink`
28 final String namespace; 26 final String namespace;
29 27
30 const AttributeName(this.prefix, this.name, this.namespace); 28 const AttributeName(this.prefix, this.name, this.namespace);
31 29
32 String toString() { 30 String toString() {
33 // Implement: 31 // Implement:
34 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# serializing-html-fragments 32 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html# serializing-html-fragments
35 // If we get here we know we are xml, xmlns, or xlink, because of 33 // If we get here we know we are xml, xmlns, or xlink, because of
36 // [HtmlParser.adjustForeignAttriubtes] is the only place we create 34 // [HtmlParser.adjustForeignAttriubtes] is the only place we create
37 // an AttributeName. 35 // an AttributeName.
(...skipping 17 matching lines...) Expand all
55 if (cmp != 0) return cmp; 53 if (cmp != 0) return cmp;
56 return namespace.compareTo(other.namespace); 54 return namespace.compareTo(other.namespace);
57 } 55 }
58 56
59 bool operator ==(x) { 57 bool operator ==(x) {
60 if (x is! AttributeName) return false; 58 if (x is! AttributeName) return false;
61 return prefix == x.prefix && name == x.name && namespace == x.namespace; 59 return prefix == x.prefix && name == x.name && namespace == x.namespace;
62 } 60 }
63 } 61 }
64 62
65 /** Really basic implementation of a DOM-core like Node. */ 63 /// Really basic implementation of a DOM-core like Node.
66 abstract class Node { 64 abstract class Node {
67 static const int ATTRIBUTE_NODE = 2; 65 static const int ATTRIBUTE_NODE = 2;
68 static const int CDATA_SECTION_NODE = 4; 66 static const int CDATA_SECTION_NODE = 4;
69 static const int COMMENT_NODE = 8; 67 static const int COMMENT_NODE = 8;
70 static const int DOCUMENT_FRAGMENT_NODE = 11; 68 static const int DOCUMENT_FRAGMENT_NODE = 11;
71 static const int DOCUMENT_NODE = 9; 69 static const int DOCUMENT_NODE = 9;
72 static const int DOCUMENT_TYPE_NODE = 10; 70 static const int DOCUMENT_TYPE_NODE = 10;
73 static const int ELEMENT_NODE = 1; 71 static const int ELEMENT_NODE = 1;
74 static const int ENTITY_NODE = 6; 72 static const int ENTITY_NODE = 6;
75 static const int ENTITY_REFERENCE_NODE = 5; 73 static const int ENTITY_REFERENCE_NODE = 5;
76 static const int NOTATION_NODE = 12; 74 static const int NOTATION_NODE = 12;
77 static const int PROCESSING_INSTRUCTION_NODE = 7; 75 static const int PROCESSING_INSTRUCTION_NODE = 7;
78 static const int TEXT_NODE = 3; 76 static const int TEXT_NODE = 3;
79 77
80 // TODO(jmesserly): this should be on Element 78 // TODO(jmesserly): this should be on Element
81 /** The tag name associated with the node. */ 79 /// The tag name associated with the node.
82 final String tagName; 80 final String tagName;
83 81
84 /** The parent of the current node (or null for the document node). */ 82 /// The parent of the current node (or null for the document node).
85 Node parent; 83 Node parent;
86 84
87 // TODO(jmesserly): should move to Element. 85 // TODO(jmesserly): should move to Element.
88 /** 86 /// A map holding name, value pairs for attributes of the node.
89 * A map holding name, value pairs for attributes of the node. 87 ///
90 * 88 /// Note that attribute order needs to be stable for serialization, so we use a
Siggi Cherem (dart-lang) 2014/02/24 23:03:29 80
Jennifer Messerly 2014/02/25 00:32:08 funny. this was the line I was iterating on when I
91 * Note that attribute order needs to be stable for serialization, so we use a 89 /// LinkedHashMap. Each key is a [String] or [AttributeName].
92 * LinkedHashMap. Each key is a [String] or [AttributeName].
93 */
94 LinkedHashMap<dynamic, String> attributes = new LinkedHashMap(); 90 LinkedHashMap<dynamic, String> attributes = new LinkedHashMap();
95 91
96 /** 92 /// A list of child nodes of the current node. This must
97 * A list of child nodes of the current node. This must 93 /// include all elements but not necessarily other node types.
98 * include all elements but not necessarily other node types.
99 */
100 final NodeList nodes = new NodeList._(); 94 final NodeList nodes = new NodeList._();
101 95
102 List<Element> _elements; 96 List<Element> _elements;
103 97
104 // TODO(jmesserly): consider using an Expando for this, and put it in 98 // TODO(jmesserly): consider using an Expando for this, and put it in
105 // dom_parsing. Need to check the performance affect. 99 // dom_parsing. Need to check the performance affect.
106 /** The source span of this node, if it was created by the [HtmlParser]. */ 100 /// The source span of this node, if it was created by the [HtmlParser].
107 FileSpan sourceSpan; 101 FileSpan sourceSpan;
108 102
109 /** The attribute spans if requested. Otherwise null. */ 103 /// The attribute spans if requested. Otherwise null.
110 LinkedHashMap<dynamic, FileSpan> _attributeSpans; 104 LinkedHashMap<dynamic, FileSpan> _attributeSpans;
111 LinkedHashMap<dynamic, FileSpan> _attributeValueSpans; 105 LinkedHashMap<dynamic, FileSpan> _attributeValueSpans;
112 106
113 Node(this.tagName) { 107 Node(this.tagName) {
114 nodes._parent = this; 108 nodes._parent = this;
115 } 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"`.
122 */
123 LinkedHashMap<dynamic, FileSpan> get attributeSpans { 115 LinkedHashMap<dynamic, FileSpan> get attributeSpans {
124 _ensureAttributeSpans(); 116 _ensureAttributeSpans();
125 return _attributeSpans; 117 return _attributeSpans;
126 } 118 }
127 119
128 /** 120 /// If [sourceSpan] is available, this contains the spans of each attribute's
129 * If [sourceSpan] is available, this contains the spans of each attribute's 121 /// value. Unlike [attributeSpans], this span will inlcude only the value.
130 * value. Unlike [attributeSpans], this span will inlcude only the value. 122 /// For example, the value span of "attr" in `<a attr="value">` would be the
131 * For example, the value span of "attr" in `<a attr="value">` would be the 123 /// text `value`.
132 * text `value`.
133 */
134 LinkedHashMap<dynamic, FileSpan> get attributeValueSpans { 124 LinkedHashMap<dynamic, FileSpan> get attributeValueSpans {
135 _ensureAttributeSpans(); 125 _ensureAttributeSpans();
136 return _attributeValueSpans; 126 return _attributeValueSpans;
137 } 127 }
138 128
139 List<Element> get children { 129 List<Element> get children {
140 if (_elements == null) { 130 if (_elements == null) {
141 _elements = new FilteredElementList(this); 131 _elements = new FilteredElementList(this);
142 } 132 }
143 return _elements; 133 return _elements;
144 } 134 }
145 135
146 // TODO(jmesserly): needs to support deep clone. 136 // TODO(jmesserly): needs to support deep clone.
147 /** 137 /// Return a shallow copy of the current node i.e. a node with the same
148 * 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.
149 * name and attributes but with no parent or child nodes.
150 */
151 Node clone(); 139 Node clone();
152 140
153 String get namespace => null; 141 String get namespace => null;
154 142
155 int get nodeType; 143 int get nodeType;
156 144
157 /** *Deprecated* use [text], [Text.data] or [Comment.data]. */ 145 /// *Deprecated* use [text], [Text.data] or [Comment.data].
158 @deprecated String get value => null; 146 @deprecated String get value => null;
159 147
160 /** *Deprecated* use [nodeType]. */ 148 /// *Deprecated* use [nodeType].
161 @deprecated int get $dom_nodeType => nodeType; 149 @deprecated int get $dom_nodeType => nodeType;
162 150
163 String get outerHtml { 151 String get outerHtml {
164 var str = new StringBuffer(); 152 var str = new StringBuffer();
165 _addOuterHtml(str); 153 _addOuterHtml(str);
166 return str.toString(); 154 return str.toString();
167 } 155 }
168 156
169 String get innerHtml { 157 String get innerHtml {
170 var str = new StringBuffer(); 158 var str = new StringBuffer();
(...skipping 25 matching lines...) Expand all
196 String toString() => tagName; 184 String toString() => tagName;
197 185
198 Node remove() { 186 Node remove() {
199 // TODO(jmesserly): is parent == null an error? 187 // TODO(jmesserly): is parent == null an error?
200 if (parent != null) { 188 if (parent != null) {
201 parent.nodes.remove(this); 189 parent.nodes.remove(this);
202 } 190 }
203 return this; 191 return this;
204 } 192 }
205 193
206 /** 194 /// Insert [node] as a child of the current node, before [refNode] in the
207 * Insert [node] as a child of the current node, before [refNode] in the 195 /// list of child nodes. Raises [UnsupportedOperationException] if [refNode]
208 * list of child nodes. Raises [UnsupportedOperationException] if [refNode] 196 /// is not a child of the current node. If refNode is null, this adds to the
209 * is not a child of the current node. If refNode is null, this adds to the 197 /// end of the list.
210 * end of the list.
211 */
212 void insertBefore(Node node, Node refNode) { 198 void insertBefore(Node node, Node refNode) {
213 if (refNode == null) { 199 if (refNode == null) {
214 nodes.add(node); 200 nodes.add(node);
215 } else { 201 } else {
216 nodes.insert(nodes.indexOf(refNode), node); 202 nodes.insert(nodes.indexOf(refNode), node);
217 } 203 }
218 } 204 }
219 205
220 /** Replaces this node with another node. */ 206 /// Replaces this node with another node.
221 Node replaceWith(Node otherNode) { 207 Node replaceWith(Node otherNode) {
222 if (parent == null) { 208 if (parent == null) {
223 throw new UnsupportedError('Node must have a parent to replace it.'); 209 throw new UnsupportedError('Node must have a parent to replace it.');
224 } 210 }
225 parent.nodes[parent.nodes.indexOf(this)] = otherNode; 211 parent.nodes[parent.nodes.indexOf(this)] = otherNode;
226 return this; 212 return this;
227 } 213 }
228 214
229 // TODO(jmesserly): should this be a property or remove? 215 // TODO(jmesserly): should this be a property or remove?
230 /** Return true if the node has children or text. */ 216 /// Return true if the node has children or text.
231 bool hasContent() => nodes.length > 0; 217 bool hasContent() => nodes.length > 0;
232 218
233 Pair<String, String> get nameTuple { 219 Pair<String, String> get nameTuple {
234 var ns = namespace != null ? namespace : Namespaces.html; 220 var ns = namespace != null ? namespace : Namespaces.html;
235 return new Pair(ns, tagName); 221 return new Pair(ns, tagName);
236 } 222 }
237 223
238 /** 224 /// Move all the children of the current node to [newParent].
239 * 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
240 * This is needed so that trees that don't store text as nodes move the 226 /// text in the correct way.
241 * text in the correct way.
242 */
243 void reparentChildren(Node newParent) { 227 void reparentChildren(Node newParent) {
244 newParent.nodes.addAll(nodes); 228 newParent.nodes.addAll(nodes);
245 nodes.clear(); 229 nodes.clear();
246 } 230 }
247 231
248 /** *Deprecated* use [querySelector] instead. */ 232 /// *Deprecated* use [querySelector] instead.
249 @deprecated 233 @deprecated
250 Element query(String selectors) => querySelector(selectors); 234 Element query(String selectors) => querySelector(selectors);
251 235
252 /** *Deprecated* use [querySelectorAll] instead. */ 236 /// *Deprecated* use [querySelectorAll] instead.
253 @deprecated 237 @deprecated
254 List<Element> queryAll(String selectors) => querySelectorAll(selectors); 238 List<Element> queryAll(String selectors) => querySelectorAll(selectors);
255 239
256 /** 240 /// Seaches for the first descendant node matching the given selectors, using a
257 * Seaches for the first descendant node matching the given selectors, using a 241 /// preorder traversal. NOTE: right now, this supports only a single type
258 * preorder traversal. NOTE: right now, this supports only a single type 242 /// selectors, e.g. `node.query('div')`.
259 * selectors, e.g. `node.query('div')`.
260 */
261 243
262 Element querySelector(String selectors) => 244 Element querySelector(String selectors) =>
263 _queryType(_typeSelector(selectors)); 245 _queryType(_typeSelector(selectors));
264 246
265 /** 247 /// Returns all descendant nodes matching the given selectors, using a
266 * Returns all descendant nodes matching the given selectors, using a 248 /// preorder traversal. NOTE: right now, this supports only a single type
267 * preorder traversal. NOTE: right now, this supports only a single type 249 /// selectors, e.g. `node.queryAll('div')`.
268 * selectors, e.g. `node.queryAll('div')`.
269 */
270 List<Element> querySelectorAll(String selectors) { 250 List<Element> querySelectorAll(String selectors) {
271 var results = new List<Element>(); 251 var results = new List<Element>();
272 _queryAllType(_typeSelector(selectors), results); 252 _queryAllType(_typeSelector(selectors), results);
273 return results; 253 return results;
274 } 254 }
275 255
276 bool hasChildNodes() => !nodes.isEmpty; 256 bool hasChildNodes() => !nodes.isEmpty;
277 257
278 bool contains(Node node) => nodes.contains(node); 258 bool contains(Node node) => nodes.contains(node);
279 259
280 String _typeSelector(String selectors) { 260 String _typeSelector(String selectors) {
281 selectors = selectors.trim(); 261 selectors = selectors.trim();
282 if (!_isTypeSelector(selectors)) { 262 if (!_isTypeSelector(selectors)) {
283 throw new UnimplementedError('only type selectors are implemented'); 263 throw new UnimplementedError('only type selectors are implemented');
284 } 264 }
285 return selectors; 265 return selectors;
286 } 266 }
287 267
288 /** 268 /// Checks if this is a type selector.
289 * Checks if this is a type selector. 269 /// See <http://www.w3.org/TR/CSS2/grammar.html>.
290 * See <http://www.w3.org/TR/CSS2/grammar.html>. 270 /// Note: this doesn't support '*', the universal selector, non-ascii chars or
291 * Note: this doesn't support '*', the universal selector, non-ascii chars or 271 /// escape chars.
292 * escape chars.
293 */
294 bool _isTypeSelector(String selector) { 272 bool _isTypeSelector(String selector) {
295 // Parser: 273 // Parser:
296 274
297 // element_name 275 // element_name
298 // : IDENT | '*' 276 // : IDENT | '*'
299 // ; 277 // ;
300 278
301 // Lexer: 279 // Lexer:
302 280
303 // nmstart [_a-z]|{nonascii}|{escape} 281 // nmstart [_a-z]|{nonascii}|{escape}
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 } 316 }
339 317
340 void _queryAllType(String tag, List<Element> results) { 318 void _queryAllType(String tag, List<Element> results) {
341 for (var node in nodes) { 319 for (var node in nodes) {
342 if (node is! Element) continue; 320 if (node is! Element) continue;
343 if (node.tagName == tag) results.add(node); 321 if (node.tagName == tag) results.add(node);
344 node._queryAllType(tag, results); 322 node._queryAllType(tag, results);
345 } 323 }
346 } 324 }
347 325
348 /** Initialize [attributeSpans] using [sourceSpan]. */ 326 /// Initialize [attributeSpans] using [sourceSpan].
349 void _ensureAttributeSpans() { 327 void _ensureAttributeSpans() {
350 if (_attributeSpans != null) return; 328 if (_attributeSpans != null) return;
351 329
352 _attributeSpans = new LinkedHashMap<dynamic, FileSpan>(); 330 _attributeSpans = new LinkedHashMap<dynamic, FileSpan>();
353 _attributeValueSpans = new LinkedHashMap<dynamic, FileSpan>(); 331 _attributeValueSpans = new LinkedHashMap<dynamic, FileSpan>();
354 332
355 if (sourceSpan == null) return; 333 if (sourceSpan == null) return;
356 334
357 var tokenizer = new HtmlTokenizer(sourceSpan.text, generateSpans: true, 335 var tokenizer = new HtmlTokenizer(sourceSpan.text, generateSpans: true,
358 attributeSpans: true); 336 attributeSpans: true);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 } 410 }
433 411
434 DocumentType clone() => new DocumentType(tagName, publicId, systemId); 412 DocumentType clone() => new DocumentType(tagName, publicId, systemId);
435 } 413 }
436 414
437 class Text extends Node { 415 class Text extends Node {
438 String data; 416 String data;
439 417
440 Text(this.data) : super(null); 418 Text(this.data) : super(null);
441 419
442 /** *Deprecated* use [data]. */ 420 /// *Deprecated* use [data].
443 @deprecated String get value => data; 421 @deprecated String get value => data;
444 @deprecated set value(String x) { data = x; } 422 @deprecated set value(String x) { data = x; }
445 423
446 int get nodeType => Node.TEXT_NODE; 424 int get nodeType => Node.TEXT_NODE;
447 425
448 String toString() => '"$data"'; 426 String toString() => '"$data"';
449 427
450 void _addOuterHtml(StringBuffer str) { 428 void _addOuterHtml(StringBuffer str) {
451 // Don't escape text for certain elements, notably <script>. 429 // Don't escape text for certain elements, notably <script>.
452 if (rcdataElements.contains(parent.tagName) || 430 if (rcdataElements.contains(parent.tagName) ||
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after
713 super.retainWhere(test); 691 super.retainWhere(test);
714 } 692 }
715 693
716 void insertAll(int index, List<Node> nodes) { 694 void insertAll(int index, List<Node> nodes) {
717 for (var node in nodes) _setParent(node); 695 for (var node in nodes) _setParent(node);
718 super.insertAll(index, nodes); 696 super.insertAll(index, nodes);
719 } 697 }
720 } 698 }
721 699
722 700
723 /** 701 /// An indexable collection of a node's descendants in the document tree,
724 * An indexable collection of a node's descendants in the document tree, 702 /// filtered so that only elements are in the collection.
725 * filtered so that only elements are in the collection.
726 */
727 // TODO(jmesserly): this was copied from dart:html 703 // TODO(jmesserly): this was copied from dart:html
728 // TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug. 704 // TODO(jmesserly): "implements List<Element>" is a workaround for analyzer bug.
729 class FilteredElementList extends IterableBase<Element> with ListMixin<Element> 705 class FilteredElementList extends IterableBase<Element> with ListMixin<Element>
730 implements List<Element> { 706 implements List<Element> {
731 707
732 final Node _node; 708 final Node _node;
733 final List<Node> _childNodes; 709 final List<Node> _childNodes;
734 710
735 /** 711 /// Creates a collection of the elements that descend from a node.
736 * Creates a collection of the elements that descend from a node. 712 ///
737 * 713 /// Example usage:
738 * Example usage: 714 ///
739 * 715 /// var filteredElements = new FilteredElementList(query("#container"));
740 * var filteredElements = new FilteredElementList(query("#container")); 716 /// // filteredElements is [a, b, c].
741 * // filteredElements is [a, b, c].
742 */
743 FilteredElementList(Node node): _childNodes = node.nodes, _node = node; 717 FilteredElementList(Node node): _childNodes = node.nodes, _node = node;
744 718
745 // We can't memoize this, since it's possible that children will be messed 719 // We can't memoize this, since it's possible that children will be messed
746 // with externally to this class. 720 // with externally to this class.
747 // 721 //
748 // TODO(nweiz): we don't always need to create a new list. For example 722 // TODO(nweiz): we don't always need to create a new list. For example
749 // forEach, every, any, ... could directly work on the _childNodes. 723 // forEach, every, any, ... could directly work on the _childNodes.
750 List<Element> get _filtered => 724 List<Element> get _filtered =>
751 new List<Element>.from(_childNodes.where((n) => n is Element)); 725 new List<Element>.from(_childNodes.where((n) => n is Element));
752 726
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
917 891
918 class _ConcatTextVisitor extends TreeVisitor { 892 class _ConcatTextVisitor extends TreeVisitor {
919 final _str = new StringBuffer(); 893 final _str = new StringBuffer();
920 894
921 String toString() => _str.toString(); 895 String toString() => _str.toString();
922 896
923 visitText(Text node) { 897 visitText(Text node) {
924 _str.write(node.data); 898 _str.write(node.data);
925 } 899 }
926 } 900 }
OLDNEW
« no previous file with comments | « no previous file | pkg/third_party/html5lib/lib/dom_parsing.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698