| OLD | NEW |
| (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 | |
| 6 // functionality. | |
| 7 class _ChildrenElementList implements ElementList { | |
| 8 // Raw Element. | |
| 9 final _ElementImpl _element; | |
| 10 final _HTMLCollectionImpl _childElements; | |
| 11 | |
| 12 _ChildrenElementList._wrap(_ElementImpl element) | |
| 13 : _childElements = element._children, | |
| 14 _element = element; | |
| 15 | |
| 16 List<Element> _toList() { | |
| 17 final output = new List(_childElements.length); | |
| 18 for (int i = 0, len = _childElements.length; i < len; i++) { | |
| 19 output[i] = _childElements[i]; | |
| 20 } | |
| 21 return output; | |
| 22 } | |
| 23 | |
| 24 _ElementImpl get first() { | |
| 25 return _element._firstElementChild; | |
| 26 } | |
| 27 | |
| 28 void forEach(void f(Element element)) { | |
| 29 for (_ElementImpl element in _childElements) { | |
| 30 f(element); | |
| 31 } | |
| 32 } | |
| 33 | |
| 34 ElementList filter(bool f(Element element)) { | |
| 35 final output = <Element>[]; | |
| 36 forEach((Element element) { | |
| 37 if (f(element)) { | |
| 38 output.add(element); | |
| 39 } | |
| 40 }); | |
| 41 return new _FrozenElementList._wrap(output); | |
| 42 } | |
| 43 | |
| 44 bool every(bool f(Element element)) { | |
| 45 for(Element element in this) { | |
| 46 if (!f(element)) { | |
| 47 return false; | |
| 48 } | |
| 49 }; | |
| 50 return true; | |
| 51 } | |
| 52 | |
| 53 bool some(bool f(Element element)) { | |
| 54 for(Element element in this) { | |
| 55 if (f(element)) { | |
| 56 return true; | |
| 57 } | |
| 58 }; | |
| 59 return false; | |
| 60 } | |
| 61 | |
| 62 Collection map(f(Element element)) { | |
| 63 final out = []; | |
| 64 for (Element el in this) { | |
| 65 out.add(f(el)); | |
| 66 } | |
| 67 return out; | |
| 68 } | |
| 69 | |
| 70 bool isEmpty() { | |
| 71 return _element._firstElementChild == null; | |
| 72 } | |
| 73 | |
| 74 int get length() { | |
| 75 return _childElements.length; | |
| 76 } | |
| 77 | |
| 78 _ElementImpl operator [](int index) { | |
| 79 return _childElements[index]; | |
| 80 } | |
| 81 | |
| 82 void operator []=(int index, _ElementImpl value) { | |
| 83 _element._replaceChild(value, _childElements[index]); | |
| 84 } | |
| 85 | |
| 86 void set length(int newLength) { | |
| 87 // TODO(jacobr): remove children when length is reduced. | |
| 88 throw const UnsupportedOperationException(''); | |
| 89 } | |
| 90 | |
| 91 Element add(_ElementImpl value) { | |
| 92 _element._appendChild(value); | |
| 93 return value; | |
| 94 } | |
| 95 | |
| 96 Element addLast(_ElementImpl value) => add(value); | |
| 97 | |
| 98 Iterator<Element> iterator() => _toList().iterator(); | |
| 99 | |
| 100 void addAll(Collection<Element> collection) { | |
| 101 for (_ElementImpl element in collection) { | |
| 102 _element._appendChild(element); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 void sort(int compare(Element a, Element b)) { | |
| 107 throw const UnsupportedOperationException('TODO(jacobr): should we impl?'); | |
| 108 } | |
| 109 | |
| 110 void copyFrom(List<Object> src, int srcStart, int dstStart, int count) { | |
| 111 throw 'Not impl yet. todo(jacobr)'; | |
| 112 } | |
| 113 | |
| 114 void setRange(int start, int length, List from, [int startFrom = 0]) { | |
| 115 throw const NotImplementedException(); | |
| 116 } | |
| 117 | |
| 118 void removeRange(int start, int length) { | |
| 119 throw const NotImplementedException(); | |
| 120 } | |
| 121 | |
| 122 void insertRange(int start, int length, [initialValue = null]) { | |
| 123 throw const NotImplementedException(); | |
| 124 } | |
| 125 | |
| 126 List getRange(int start, int length) => | |
| 127 new _FrozenElementList._wrap(_Lists.getRange(this, start, length, | |
| 128 <Element>[])); | |
| 129 | |
| 130 int indexOf(Element element, [int start = 0]) { | |
| 131 return _Lists.indexOf(this, element, start, this.length); | |
| 132 } | |
| 133 | |
| 134 int lastIndexOf(Element element, [int start = null]) { | |
| 135 if (start === null) start = length - 1; | |
| 136 return _Lists.lastIndexOf(this, element, start); | |
| 137 } | |
| 138 | |
| 139 void clear() { | |
| 140 // It is unclear if we want to keep non element nodes? | |
| 141 _element.text = ''; | |
| 142 } | |
| 143 | |
| 144 Element removeLast() { | |
| 145 final last = this.last(); | |
| 146 if (last != null) { | |
| 147 _element._removeChild(last); | |
| 148 } | |
| 149 return last; | |
| 150 } | |
| 151 | |
| 152 Element last() { | |
| 153 return _element.lastElementChild; | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 // TODO(jacobr): this is an inefficient implementation but it is hard to see | |
| 158 // a better option given that we cannot quite force NodeList to be an | |
| 159 // ElementList as there are valid cases where a NodeList JavaScript object | |
| 160 // contains Node objects that are not Elements. | |
| 161 class _FrozenElementList implements ElementList { | |
| 162 final List<Node> _nodeList; | |
| 163 | |
| 164 _FrozenElementList._wrap(this._nodeList); | |
| 165 | |
| 166 Element get first() { | |
| 167 return _nodeList[0]; | |
| 168 } | |
| 169 | |
| 170 void forEach(void f(Element element)) { | |
| 171 for (Element el in this) { | |
| 172 f(el); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 Collection map(f(Element element)) { | |
| 177 final out = []; | |
| 178 for (Element el in this) { | |
| 179 out.add(f(el)); | |
| 180 } | |
| 181 return out; | |
| 182 } | |
| 183 | |
| 184 ElementList filter(bool f(Element element)) { | |
| 185 final out = new _ElementList([]); | |
| 186 for (Element el in this) { | |
| 187 if (f(el)) out.add(el); | |
| 188 } | |
| 189 return out; | |
| 190 } | |
| 191 | |
| 192 bool every(bool f(Element element)) { | |
| 193 for(Element element in this) { | |
| 194 if (!f(element)) { | |
| 195 return false; | |
| 196 } | |
| 197 }; | |
| 198 return true; | |
| 199 } | |
| 200 | |
| 201 bool some(bool f(Element element)) { | |
| 202 for(Element element in this) { | |
| 203 if (f(element)) { | |
| 204 return true; | |
| 205 } | |
| 206 }; | |
| 207 return false; | |
| 208 } | |
| 209 | |
| 210 bool isEmpty() => _nodeList.isEmpty(); | |
| 211 | |
| 212 int get length() => _nodeList.length; | |
| 213 | |
| 214 Element operator [](int index) => _nodeList[index]; | |
| 215 | |
| 216 void operator []=(int index, Element value) { | |
| 217 throw const UnsupportedOperationException(''); | |
| 218 } | |
| 219 | |
| 220 void set length(int newLength) { | |
| 221 _nodeList.length = newLength; | |
| 222 } | |
| 223 | |
| 224 void add(Element value) { | |
| 225 throw const UnsupportedOperationException(''); | |
| 226 } | |
| 227 | |
| 228 void addLast(Element value) { | |
| 229 throw const UnsupportedOperationException(''); | |
| 230 } | |
| 231 | |
| 232 Iterator<Element> iterator() => new _FrozenElementListIterator(this); | |
| 233 | |
| 234 void addAll(Collection<Element> collection) { | |
| 235 throw const UnsupportedOperationException(''); | |
| 236 } | |
| 237 | |
| 238 void sort(int compare(Element a, Element b)) { | |
| 239 throw const UnsupportedOperationException(''); | |
| 240 } | |
| 241 | |
| 242 void setRange(int start, int length, List from, [int startFrom = 0]) { | |
| 243 throw const UnsupportedOperationException(''); | |
| 244 } | |
| 245 | |
| 246 void removeRange(int start, int length) { | |
| 247 throw const UnsupportedOperationException(''); | |
| 248 } | |
| 249 | |
| 250 void insertRange(int start, int length, [initialValue = null]) { | |
| 251 throw const UnsupportedOperationException(''); | |
| 252 } | |
| 253 | |
| 254 ElementList getRange(int start, int length) => | |
| 255 new _FrozenElementList._wrap(_nodeList.getRange(start, length)); | |
| 256 | |
| 257 int indexOf(Element element, [int start = 0]) => | |
| 258 _nodeList.indexOf(element, start); | |
| 259 | |
| 260 int lastIndexOf(Element element, [int start = null]) => | |
| 261 _nodeList.lastIndexOf(element, start); | |
| 262 | |
| 263 void clear() { | |
| 264 throw const UnsupportedOperationException(''); | |
| 265 } | |
| 266 | |
| 267 Element removeLast() { | |
| 268 throw const UnsupportedOperationException(''); | |
| 269 } | |
| 270 | |
| 271 Element last() => _nodeList.last(); | |
| 272 } | |
| 273 | |
| 274 class _FrozenElementListIterator implements Iterator<Element> { | |
| 275 final _FrozenElementList _list; | |
| 276 int _index = 0; | |
| 277 | |
| 278 _FrozenElementListIterator(this._list); | |
| 279 | |
| 280 /** | |
| 281 * Gets the next element in the iteration. Throws a | |
| 282 * [NoMoreElementsException] if no element is left. | |
| 283 */ | |
| 284 Element next() { | |
| 285 if (!hasNext()) { | |
| 286 throw const NoMoreElementsException(); | |
| 287 } | |
| 288 | |
| 289 return _list[_index++]; | |
| 290 } | |
| 291 | |
| 292 /** | |
| 293 * Returns whether the [Iterator] has elements left. | |
| 294 */ | |
| 295 bool hasNext() => _index < _list.length; | |
| 296 } | |
| 297 | |
| 298 class _ElementList extends _ListWrapper<Element> implements ElementList { | |
| 299 _ElementList(List<Element> list) : super(list); | |
| 300 | |
| 301 ElementList filter(bool f(Element element)) => | |
| 302 new _ElementList(super.filter(f)); | |
| 303 | |
| 304 ElementList getRange(int start, int length) => | |
| 305 new _ElementList(super.getRange(start, length)); | |
| 306 } | |
| 307 | |
| 308 class ElementAttributeMap implements Map<String, String> { | |
| 309 | |
| 310 final _ElementImpl _element; | |
| 311 | |
| 312 ElementAttributeMap._wrap(this._element); | |
| 313 | |
| 314 bool containsValue(String value) { | |
| 315 final attributes = _element._attributes; | |
| 316 for (int i = 0, len = attributes.length; i < len; i++) { | |
| 317 if(value == attributes[i].value) { | |
| 318 return true; | |
| 319 } | |
| 320 } | |
| 321 return false; | |
| 322 } | |
| 323 | |
| 324 bool containsKey(String key) { | |
| 325 return _element._hasAttribute(key); | |
| 326 } | |
| 327 | |
| 328 String operator [](String key) { | |
| 329 return _element._getAttribute(key); | |
| 330 } | |
| 331 | |
| 332 void operator []=(String key, String value) { | |
| 333 _element._setAttribute(key, value); | |
| 334 } | |
| 335 | |
| 336 String putIfAbsent(String key, String ifAbsent()) { | |
| 337 if (!containsKey(key)) { | |
| 338 this[key] = ifAbsent(); | |
| 339 } | |
| 340 } | |
| 341 | |
| 342 String remove(String key) { | |
| 343 _element._removeAttribute(key); | |
| 344 } | |
| 345 | |
| 346 void clear() { | |
| 347 final attributes = _element._attributes; | |
| 348 for (int i = attributes.length - 1; i >= 0; i--) { | |
| 349 remove(attributes[i].name); | |
| 350 } | |
| 351 } | |
| 352 | |
| 353 void forEach(void f(String key, String value)) { | |
| 354 final attributes = _element._attributes; | |
| 355 for (int i = 0, len = attributes.length; i < len; i++) { | |
| 356 final item = attributes[i]; | |
| 357 f(item.name, item.value); | |
| 358 } | |
| 359 } | |
| 360 | |
| 361 Collection<String> getKeys() { | |
| 362 // TODO(jacobr): generate a lazy collection instead. | |
| 363 final attributes = _element._attributes; | |
| 364 final keys = new List<String>(attributes.length); | |
| 365 for (int i = 0, len = attributes.length; i < len; i++) { | |
| 366 keys[i] = attributes[i].name; | |
| 367 } | |
| 368 return keys; | |
| 369 } | |
| 370 | |
| 371 Collection<String> getValues() { | |
| 372 // TODO(jacobr): generate a lazy collection instead. | |
| 373 final attributes = _element._attributes; | |
| 374 final values = new List<String>(attributes.length); | |
| 375 for (int i = 0, len = attributes.length; i < len; i++) { | |
| 376 values[i] = attributes[i].value; | |
| 377 } | |
| 378 return values; | |
| 379 } | |
| 380 | |
| 381 /** | |
| 382 * The number of {key, value} pairs in the map. | |
| 383 */ | |
| 384 int get length() { | |
| 385 return _element._attributes.length; | |
| 386 } | |
| 387 | |
| 388 /** | |
| 389 * Returns true if there is no {key, value} pair in the map. | |
| 390 */ | |
| 391 bool isEmpty() { | |
| 392 return length == 0; | |
| 393 } | |
| 394 } | |
| 395 | |
| 396 class _SimpleClientRect implements ClientRect { | |
| 397 final num left; | |
| 398 final num top; | |
| 399 final num width; | |
| 400 final num height; | |
| 401 num get right() => left + width; | |
| 402 num get bottom() => top + height; | |
| 403 | |
| 404 const _SimpleClientRect(this.left, this.top, this.width, this.height); | |
| 405 | |
| 406 bool operator ==(ClientRect other) { | |
| 407 return other !== null && left == other.left && top == other.top | |
| 408 && width == other.width && height == other.height; | |
| 409 } | |
| 410 | |
| 411 String toString() => "($left, $top, $width, $height)"; | |
| 412 } | |
| 413 | |
| 414 // TODO(jacobr): we cannot currently be lazy about calculating the client | |
| 415 // rects as we must perform all measurement queries at a safe point to avoid | |
| 416 // triggering unneeded layouts. | |
| 417 /** | |
| 418 * All your element measurement needs in one place | |
| 419 * @domName none | |
| 420 */ | |
| 421 class _ElementRectImpl implements ElementRect { | |
| 422 final ClientRect client; | |
| 423 final ClientRect offset; | |
| 424 final ClientRect scroll; | |
| 425 | |
| 426 // TODO(jacobr): should we move these outside of ElementRect to avoid the | |
| 427 // overhead of computing them every time even though they are rarely used. | |
| 428 final _ClientRectImpl _boundingClientRect; | |
| 429 final _ClientRectListImpl _clientRects; | |
| 430 | |
| 431 _ElementRectImpl(_ElementImpl element) : | |
| 432 client = new _SimpleClientRect(element._clientLeft, | |
| 433 element._clientTop, | |
| 434 element._clientWidth, | |
| 435 element._clientHeight), | |
| 436 offset = new _SimpleClientRect(element._offsetLeft, | |
| 437 element._offsetTop, | |
| 438 element._offsetWidth, | |
| 439 element._offsetHeight), | |
| 440 scroll = new _SimpleClientRect(element._scrollLeft, | |
| 441 element._scrollTop, | |
| 442 element._scrollWidth, | |
| 443 element._scrollHeight), | |
| 444 _boundingClientRect = element._getBoundingClientRect(), | |
| 445 _clientRects = element._getClientRects(); | |
| 446 | |
| 447 _ClientRectImpl get bounding() => _boundingClientRect; | |
| 448 | |
| 449 // TODO(jacobr): cleanup. | |
| 450 List<ClientRect> get clientRects() { | |
| 451 final out = new List(_clientRects.length); | |
| 452 for (num i = 0; i < _clientRects.length; i++) { | |
| 453 out[i] = _clientRects.item(i); | |
| 454 } | |
| 455 return out; | |
| 456 } | |
| 457 } | |
| 458 | |
| 459 class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | |
| 460 | |
| 461 // TODO(jacobr): caching these may hurt performance. | |
| 462 ElementAttributeMap _elementAttributeMap; | |
| 463 _CssClassSet _cssClassSet; | |
| 464 _DataAttributeMap _dataAttributes; | |
| 465 | |
| 466 /** | |
| 467 * @domName Element.hasAttribute, Element.getAttribute, Element.setAttribute, | |
| 468 * Element.removeAttribute | |
| 469 */ | |
| 470 Map<String, String> get attributes() { | |
| 471 if (_elementAttributeMap === null) { | |
| 472 _elementAttributeMap = new ElementAttributeMap._wrap(this); | |
| 473 } | |
| 474 return _elementAttributeMap; | |
| 475 } | |
| 476 | |
| 477 void set attributes(Map<String, String> value) { | |
| 478 Map<String, String> attributes = this.attributes; | |
| 479 attributes.clear(); | |
| 480 for (String key in value.getKeys()) { | |
| 481 attributes[key] = value[key]; | |
| 482 } | |
| 483 } | |
| 484 | |
| 485 void set elements(Collection<Element> value) { | |
| 486 final elements = this.elements; | |
| 487 elements.clear(); | |
| 488 elements.addAll(value); | |
| 489 } | |
| 490 | |
| 491 ElementList get elements() => new _ChildrenElementList._wrap(this); | |
| 492 | |
| 493 ElementList queryAll(String selectors) => | |
| 494 new _FrozenElementList._wrap(_querySelectorAll(selectors)); | |
| 495 | |
| 496 Set<String> get classes() { | |
| 497 if (_cssClassSet === null) { | |
| 498 _cssClassSet = new _CssClassSet(this); | |
| 499 } | |
| 500 return _cssClassSet; | |
| 501 } | |
| 502 | |
| 503 void set classes(Collection<String> value) { | |
| 504 _CssClassSet classSet = classes; | |
| 505 classSet.clear(); | |
| 506 classSet.addAll(value); | |
| 507 } | |
| 508 | |
| 509 Map<String, String> get dataAttributes() { | |
| 510 if (_dataAttributes === null) { | |
| 511 _dataAttributes = new _DataAttributeMap(attributes); | |
| 512 } | |
| 513 return _dataAttributes; | |
| 514 } | |
| 515 | |
| 516 void set dataAttributes(Map<String, String> value) { | |
| 517 Map<String, String> dataAttributes = this.dataAttributes; | |
| 518 dataAttributes.clear(); | |
| 519 for (String key in value.getKeys()) { | |
| 520 dataAttributes[key] = value[key]; | |
| 521 } | |
| 522 } | |
| 523 | |
| 524 Future<ElementRect> get rect() { | |
| 525 return _createMeasurementFuture( | |
| 526 () => new _ElementRectImpl(this), | |
| 527 new Completer<ElementRect>()); | |
| 528 } | |
| 529 | |
| 530 Future<CSSStyleDeclaration> get computedStyle() { | |
| 531 // TODO(jacobr): last param should be null, see b/5045788 | |
| 532 return getComputedStyle(''); | |
| 533 } | |
| 534 | |
| 535 Future<CSSStyleDeclaration> getComputedStyle(String pseudoElement) { | |
| 536 return _createMeasurementFuture( | |
| 537 () => _window._getComputedStyle(this, pseudoElement), | |
| 538 new Completer<CSSStyleDeclaration>()); | |
| 539 } | |
| 540 $!MEMBERS | |
| 541 } | |
| OLD | NEW |