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

Side by Side Diff: client/dom/templates/html/frog/impl_Element.darttemplate

Issue 9403004: Wrapperless dart:html generator (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Final version to check in. changes generator script but doesn't check in an active version of the … Created 8 years, 10 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
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 // TODO(jacobr): use Lists.dart to remove some of the duplicated functionality.
6 class _ChildrenElementList implements ElementList {
7 // Raw Element.
8 final _ElementJs _element;
9 final _HTMLCollectionJs _childElements;
10
11 _ChildrenElementList._wrap(_ElementJs element)
12 : _childElements = element._children,
13 _element = element;
14
15 List<Element> _toList() {
16 final output = new List(_childElements.length);
17 for (int i = 0, len = _childElements.length; i < len; i++) {
18 output[i] = _childElements[i];
19 }
20 return output;
21 }
22
23 _ElementJs get first() {
24 return _element._firstElementChild;
25 }
26
27 void forEach(void f(Element element)) {
28 for (_ElementJs element in _childElements) {
29 f(element);
30 }
31 }
32
33 Collection<Element> filter(bool f(Element element)) {
34 List<Element> output = <Element>[];
35 forEach((Element element) {
36 if (f(element)) {
37 output.add(element);
38 }
39 });
40 return output;
41 }
42
43 bool every(bool f(Element element)) {
44 for(Element element in this) {
45 if (!f(element)) {
46 return false;
47 }
48 };
49 return true;
50 }
51
52 bool some(bool f(Element element)) {
53 for(Element element in this) {
54 if (f(element)) {
55 return true;
56 }
57 };
58 return false;
59 }
60
61 bool isEmpty() {
62 return _element._firstElementChild !== null;
63 }
64
65 int get length() {
66 return _childElements.length;
67 }
68
69 _ElementJs operator [](int index) {
70 return _childElements[index];
71 }
72
73 void operator []=(int index, _ElementJs value) {
74 _element._replaceChild(value, _childElements.item(index));
75 }
76
77 void set length(int newLength) {
78 // TODO(jacobr): remove children when length is reduced.
79 throw const UnsupportedOperationException('');
80 }
81
82 Element add(_ElementJs value) {
83 _element._appendChild(value);
84 return value;
85 }
86
87 Element addLast(_ElementJs value) => add(value);
88
89 Iterator<Element> iterator() => _toList().iterator();
90
91 void addAll(Collection<_ElementJs> collection) {
92 for (_ElementJs element in collection) {
93 _element._appendChild(element);
94 }
95 }
96
97 void sort(int compare(Element a, Element b)) {
98 throw const UnsupportedOperationException('TODO(jacobr): should we impl?');
99 }
100
101 void copyFrom(List<Object> src, int srcStart, int dstStart, int count) {
102 throw 'Not impl yet. todo(jacobr)';
103 }
104
105 void setRange(int start, int length, List from, [int startFrom = 0]) {
106 throw const NotImplementedException();
107 }
108
109 void removeRange(int start, int length) {
110 throw const NotImplementedException();
111 }
112
113 void insertRange(int start, int length, [initialValue = null]) {
114 throw const NotImplementedException();
115 }
116
117 List getRange(int start, int length) {
118 throw const NotImplementedException();
119 }
120
121 int indexOf(Element element, [int start = 0]) {
122 return _Lists.indexOf(this, element, start, this.length);
123 }
124
125 int lastIndexOf(Element element, [int start = null]) {
126 if (start === null) start = length - 1;
127 return _Lists.lastIndexOf(this, element, start);
128 }
129
130 void clear() {
131 // It is unclear if we want to keep non element nodes?
132 _element.text = '';
133 }
134
135 Element removeLast() {
136 final last = this.last();
137 if (last != null) {
138 _element._removeChild(last);
139 }
140 return last;
141 }
142
143 Element last() {
144 return _element.lastElementChild;
145 }
146 }
147
148 class ElementAttributeMap implements Map<String, String> {
149
150 final _ElementJs _element;
151
152 ElementAttributeMap._wrap(this._element);
153
154 bool containsValue(String value) {
155 final attributes = _element.attributes;
156 for (int i = 0, len = attributes.length; i < len; i++) {
157 if(value == attributes.item(i).value) {
158 return true;
159 }
160 }
161 return false;
162 }
163
164 bool containsKey(String key) {
165 return _element._hasAttribute(key);
166 }
167
168 String operator [](String key) {
169 return _element._getAttribute(key);
170 }
171
172 void operator []=(String key, String value) {
173 _element._setAttribute(key, value);
174 }
175
176 String putIfAbsent(String key, String ifAbsent()) {
177 if (!containsKey(key)) {
178 this[key] = ifAbsent();
179 }
180 }
181
182 String remove(String key) {
183 _element._removeAttribute(key);
184 }
185
186 void clear() {
187 final attributes = _element._attributes;
188 for (int i = attributes.length - 1; i >= 0; i--) {
189 remove(attributes.item(i).name);
190 }
191 }
192
193 void forEach(void f(String key, String value)) {
194 final attributes = _element.attributes;
195 for (int i = 0, len = attributes.length; i < len; i++) {
196 final item = attributes.item(i);
197 f(item.name, item.value);
198 }
199 }
200
201 Collection<String> getKeys() {
202 // TODO(jacobr): generate a lazy collection instead.
203 final attributes = _element.attributes;
204 final keys = new List<String>(attributes.length);
205 for (int i = 0, len = attributes.length; i < len; i++) {
206 keys[i] = attributes.item(i).name;
207 }
208 return keys;
209 }
210
211 Collection<String> getValues() {
212 // TODO(jacobr): generate a lazy collection instead.
213 final attributes = _element.attributes;
214 final values = new List<String>(attributes.length);
215 for (int i = 0, len = attributes.length; i < len; i++) {
216 values[i] = attributes.item(i).value;
217 }
218 return values;
219 }
220
221 /**
222 * The number of {key, value} pairs in the map.
223 */
224 int get length() {
225 return _element._attributes.length;
226 }
227
228 /**
229 * Returns true if there is no {key, value} pair in the map.
230 */
231 bool isEmpty() {
232 return length == 0;
233 }
234 }
235
236 class _SimpleClientRect implements ClientRect {
237 final num left;
238 final num top;
239 final num width;
240 final num height;
241 num get right() => left + width;
242 num get bottom() => top + height;
243
244 const _SimpleClientRect(this.left, this.top, this.width, this.height);
245
246 bool operator ==(ClientRect other) {
247 return other !== null && left == other.left && top == other.top
248 && width == other.width && height == other.height;
249 }
250
251 String toString() => "($left, $top, $width, $height)";
252 }
253
254 // TODO(jacobr): we cannot currently be lazy about calculating the client
255 // rects as we must perform all measurement queries at a safe point to avoid
256 // triggering unneeded layouts.
257 /**
258 * All your element measurement needs in one place
259 * @domName none
260 */
261 class _ElementRectImpl implements ElementRect {
262 final ClientRect client;
263 final ClientRect offset;
264 final ClientRect scroll;
265
266 // TODO(jacobr): should we move these outside of ElementRect to avoid the
267 // overhead of computing them every time even though they are rarely used.
268 final _ClientRectJs _boundingClientRect;
269 final _ClientRectListJs _clientRects;
270
271 _ElementRectImpl(_ElementJs element) :
272 client = new _SimpleClientRect(element._clientLeft,
273 element._clientTop,
274 element._clientWidth,
275 element._clientHeight),
276 offset = new _SimpleClientRect(element._offsetLeft,
277 element._offsetTop,
278 element._offsetWidth,
279 element._offsetHeight),
280 scroll = new _SimpleClientRect(element._scrollLeft,
281 element._scrollTop,
282 element._scrollWidth,
283 element._scrollHeight),
284 _boundingClientRect = element.getBoundingClientRect(),
285 _clientRects = element.getClientRects();
286
287 _ClientRectJs get bounding() => _boundingClientRect;
288
289 // TODO(jacobr): cleanup.
290 List<ClientRect> get clientRects() {
291 final out = new List(_clientRects.length);
292 for (num i = 0; i < _clientRects.length; i++) {
293 out[i] = _clientRects.item(i);
294 }
295 return out;
296 }
297 }
298
299 final _START_TAG_REGEXP = const RegExp('<(\\w+)');
300
301 class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
302
303 static final _CUSTOM_PARENT_TAG_MAP = const {
304 'body' : 'html',
305 'head' : 'html',
306 'caption' : 'table',
307 'td': 'tr',
308 'tbody': 'table',
309 'colgroup': 'table',
310 'col' : 'colgroup',
311 'tr' : 'tbody',
312 'tbody' : 'table',
313 'tfoot' : 'table',
314 'thead' : 'table',
315 'track' : 'audio',
316 };
317
318 /** @domName Document.createElement */
319 factory Element.html(String html) {
320 // TODO(jacobr): this method can be made more robust and performant.
321 // 1) Cache the dummy parent elements required to use innerHTML rather than
322 // creating them every call.
323 // 2) Verify that the html does not contain leading or trailing text nodes.
324 // 3) Verify that the html does not contain both <head> and <body> tags.
325 // 4) Detatch the created element from its dummy parent.
326 String parentTag = 'div';
327 String tag;
328 final match = _START_TAG_REGEXP.firstMatch(html);
329 if (match !== null) {
330 tag = match.group(1).toLowerCase();
331 if (_CUSTOM_PARENT_TAG_MAP.containsKey(tag)) {
332 parentTag = _CUSTOM_PARENT_TAG_MAP[tag];
333 }
334 }
335 _ElementJs temp = _document._createElement(parentTag);
336 temp.innerHTML = html;
337
338 if (temp._childElementCount == 1) {
339 return temp._firstElementChild;
340 } else if (parentTag == 'html' && temp._childElementCount == 2) {
341 // Work around for edge case in WebKit and possibly other browsers where
342 // both body and head elements are created even though the inner html
343 // only contains a head or body element.
344 return temp.elements[tag == 'head' ? 0 : 1];
345 } else {
346 throw new IllegalArgumentException('HTML had ${temp._childElementCount} ' +
347 'top level elements but 1 expected');
348 }
349 }
350
351 /** @domName Document.createElement */
352 factory Element.tag(String tag) {
353 return _document._createElement(tag);
354 }
355
356 // TODO(jacobr): caching these may hurt performance.
357 ElementAttributeMap _elementAttributeMap;
358 _CssClassSet _cssClassSet;
359 _DataAttributeMap _dataAttributes;
360
361 // TODO(jacobr): remove these methods and let them be generated automatically
362 // once dart supports defining fields with the same name in an interface and
363 // its parent interface.
364 String get title() native "return this.parentNode.title;";
365 void set title(String value) native "this.parentNode.title = value;";
366
367 /**
368 * @domName Element.hasAttribute, Element.getAttribute, Element.setAttribute,
369 * Element.removeAttribute
370 */
371 Map<String, String> get attributes() {
372 if (_elementAttributeMap === null) {
373 _elementAttributeMap = new ElementAttributeMap._wrap(this);
374 }
375 return _elementAttributeMap;
376 }
377
378 void set attributes(Map<String, String> value) {
379 Map<String, String> attributes = this.attributes;
380 attributes.clear();
381 for (String key in value.getKeys()) {
382 attributes[key] = value[key];
383 }
384 }
385
386 void set elements(Collection<Element> value) {
387 final elements = this.elements;
388 elements.clear();
389 elements.addAll(value);
390 }
391
392 /**
393 * @domName childElementCount, firstElementChild, lastElementChild,
394 * children, Node.nodes.add
395 */
396 ElementList get elements() => new _ChildrenElementList._wrap(this);
397
398 /** @domName querySelector, Document.getElementById */
399 Element query(String selectors) native "return this.querySelector(selectors);" ;
400
401 /**
402 * @domName querySelectorAll, getElementsByClassName, getElementsByTagName,
403 * getElementsByTagNameNS
404 */
405 ElementList queryAll(String selectors) native "return this.querySelectorAll(se lectors);";
406
407 /** @domName className, classList */
408 Set<String> get classes() {
409 if (_cssClassSet === null) {
410 _cssClassSet = new _CssClassSet(this);
411 }
412 return _cssClassSet;
413 }
414
415 void set classes(Collection<String> value) {
416 _CssClassSet classSet = classes;
417 classSet.clear();
418 classSet.addAll(value);
419 }
420
421 Map<String, String> get dataAttributes() {
422 if (_dataAttributes === null) {
423 _dataAttributes = new _DataAttributeMap(attributes);
424 }
425 return _dataAttributes;
426 }
427
428 void set dataAttributes(Map<String, String> value) {
429 Map<String, String> dataAttributes = this.dataAttributes;
430 dataAttributes.clear();
431 for (String key in value.getKeys()) {
432 dataAttributes[key] = value[key];
433 }
434 }
435
436 bool matchesSelector(String selectors) native "return this.webkitMatchesSelect or(selectors)";
437
438 /**
439 * @domName getClientRects, getBoundingClientRect, clientHeight, clientWidth,
440 * clientTop, clientLeft, offsetHeight, offsetWidth, offsetTop, offsetLeft,
441 * scrollHeight, scrollWidth, scrollTop, scrollLeft
442 */
443 Future<ElementRect> get rect() {
444 return _createMeasurementFuture(
445 () => new _ElementRectImpl(this),
446 new Completer<ElementRect>());
447 }
448
449 /** @domName Window.getComputedStyle */
450 Future<CSSStyleDeclaration> get computedStyle() {
451 // TODO(jacobr): last param should be null, see b/5045788
452 return getComputedStyle('');
453 }
454
455 /** @domName Window.getComputedStyle */
456 Future<CSSStyleDeclaration> getComputedStyle(String pseudoElement) {
457 return _createMeasurementFuture(() =>
458 _window._getComputedStyle(this, pseudoElement),
459 new Completer<CSSStyleDeclaration>());
460 }
461
462 _ElementJs clone(bool deep) native;
463 $!MEMBERS
464 }
OLDNEW
« no previous file with comments | « client/dom/templates/html/frog/impl_Document.darttemplate ('k') | client/dom/templates/html/frog/impl_Event.darttemplate » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698