Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 // TODO(jacobr): use _Lists.dart to remove some of the duplicated | 5 // TODO(jacobr): use _Lists.dart to remove some of the duplicated |
| 6 // functionality. | 6 // functionality. |
| 7 class _ChildrenElementList implements ElementList { | 7 class _ChildrenElementList implements ElementList { |
| 8 // Raw Element. | 8 // Raw Element. |
| 9 final _ElementImpl _element; | 9 final _ElementImpl _element; |
| 10 final _HTMLCollectionImpl _childElements; | 10 final _HTMLCollectionImpl _childElements; |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 class _ElementList extends _ListWrapper<Element> implements ElementList { | 298 class _ElementList extends _ListWrapper<Element> implements ElementList { |
| 299 _ElementList(List<Element> list) : super(list); | 299 _ElementList(List<Element> list) : super(list); |
| 300 | 300 |
| 301 ElementList filter(bool f(Element element)) => | 301 ElementList filter(bool f(Element element)) => |
| 302 new _ElementList(super.filter(f)); | 302 new _ElementList(super.filter(f)); |
| 303 | 303 |
| 304 ElementList getRange(int start, int length) => | 304 ElementList getRange(int start, int length) => |
| 305 new _ElementList(super.getRange(start, length)); | 305 new _ElementList(super.getRange(start, length)); |
| 306 } | 306 } |
| 307 | 307 |
| 308 class ElementAttributeMap implements Map<String, String> { | 308 class _ElementAttributeMap implements AttributeMap { |
| 309 | 309 |
| 310 final _ElementImpl _element; | 310 final _ElementImpl _element; |
| 311 | 311 |
| 312 ElementAttributeMap._wrap(this._element); | 312 _ElementAttributeMap(this._element); |
| 313 | 313 |
| 314 bool containsValue(String value) { | 314 bool containsValue(String value) { |
| 315 final attributes = _element.$dom_attributes; | 315 final attributes = _element.$dom_attributes; |
| 316 for (int i = 0, len = attributes.length; i < len; i++) { | 316 for (int i = 0, len = attributes.length; i < len; i++) { |
| 317 if(value == attributes[i].value) { | 317 if(value == attributes[i].value) { |
| 318 return true; | 318 return true; |
| 319 } | 319 } |
| 320 } | 320 } |
| 321 return false; | 321 return false; |
| 322 } | 322 } |
| 323 | 323 |
| 324 bool containsKey(String key) { | 324 bool containsKey(String key) { |
| 325 return _element.$dom_hasAttribute(key); | 325 return _element.$dom_hasAttribute(key); |
| 326 } | 326 } |
| 327 | 327 |
| 328 String operator [](String key) { | 328 String operator [](String key) { |
| 329 return _element.$dom_getAttribute(key); | 329 return _element.$dom_getAttribute(key); |
| 330 } | 330 } |
| 331 | 331 |
| 332 void operator []=(String key, String value) { | 332 void operator []=(String key, value) { |
| 333 _element.$dom_setAttribute(key, value); | 333 _element.$dom_setAttribute(key, '$value'); |
| 334 } | 334 } |
| 335 | 335 |
| 336 String putIfAbsent(String key, String ifAbsent()) { | 336 String putIfAbsent(String key, String ifAbsent()) { |
| 337 if (!containsKey(key)) { | 337 if (!containsKey(key)) { |
| 338 this[key] = ifAbsent(); | 338 this[key] = ifAbsent(); |
| 339 } | 339 } |
| 340 } | 340 } |
| 341 | 341 |
| 342 String remove(String key) { | 342 String remove(String key) { |
| 343 _element.$dom_removeAttribute(key); | 343 _element.$dom_removeAttribute(key); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 386 } | 386 } |
| 387 | 387 |
| 388 /** | 388 /** |
| 389 * Returns true if there is no {key, value} pair in the map. | 389 * Returns true if there is no {key, value} pair in the map. |
| 390 */ | 390 */ |
| 391 bool isEmpty() { | 391 bool isEmpty() { |
| 392 return length == 0; | 392 return length == 0; |
| 393 } | 393 } |
| 394 } | 394 } |
| 395 | 395 |
| 396 /** | |
| 397 * Provides a Map abstraction on top of data-* attributes, similar to the | |
| 398 * dataSet in the old DOM. | |
| 399 */ | |
| 400 class _DataAttributeMap implements AttributeMap { | |
| 401 | |
| 402 final Map<String, String> $dom_attributes; | |
| 403 | |
| 404 _DataAttributeMap(this.$dom_attributes); | |
| 405 | |
| 406 // interface Map | |
| 407 | |
| 408 // TODO: Use lazy iterator when it is available on Map. | |
| 409 bool containsValue(String value) => getValues().some((v) => v == value); | |
| 410 | |
| 411 bool containsKey(String key) => $dom_attributes.containsKey(_attr(key)); | |
| 412 | |
| 413 String operator [](String key) => $dom_attributes[_attr(key)]; | |
| 414 | |
| 415 void operator []=(String key, value) { | |
| 416 $dom_attributes[_attr(key)] = '$value'; | |
| 417 } | |
| 418 | |
| 419 String putIfAbsent(String key, String ifAbsent()) { | |
| 420 if (!containsKey(key)) { | |
|
nweiz
2012/03/30 00:06:23
Can't this just call $dom_attributes.putIfAbsent?
Jacob
2012/03/30 00:40:53
Yep. Done. FYI this code isn't new I just moved it
| |
| 421 return this[key] = ifAbsent(); | |
| 422 } | |
| 423 return this[key]; | |
| 424 } | |
| 425 | |
| 426 String remove(String key) => $dom_attributes.remove(_attr(key)); | |
| 427 | |
| 428 void clear() { | |
| 429 // Needs to operate on a snapshot since we are mutatiting the collection. | |
|
nweiz
2012/03/30 00:06:23
mutating
Jacob
2012/03/30 00:40:53
Done.
| |
| 430 for (String key in getKeys()) { | |
| 431 remove(key); | |
| 432 } | |
| 433 } | |
| 434 | |
| 435 void forEach(void f(String key, String value)) { | |
| 436 $dom_attributes.forEach((String key, String value) { | |
| 437 if (_matches(key)) { | |
| 438 f(_strip(key), value); | |
| 439 } | |
| 440 }); | |
| 441 } | |
| 442 | |
| 443 Collection<String> getKeys() { | |
| 444 final keys = new List<String>(); | |
| 445 $dom_attributes.forEach((String key, String value) { | |
|
nweiz
2012/03/30 00:06:23
This would be a little cleaner if you used this cl
Jacob
2012/03/30 00:40:53
Reasonable idea but I'd rather leave it unchanged.
| |
| 446 if (_matches(key)) { | |
| 447 keys.add(_strip(key)); | |
| 448 } | |
| 449 }); | |
| 450 return keys; | |
| 451 } | |
| 452 | |
| 453 Collection<String> getValues() { | |
| 454 final values = new List<String>(); | |
| 455 $dom_attributes.forEach((String key, String value) { | |
|
nweiz
2012/03/30 00:06:23
As above, a little cleaner to use this class's for
Jacob
2012/03/30 00:40:53
feel free to send an alternate CL.
| |
| 456 if (_matches(key)) { | |
| 457 values.add(value); | |
| 458 } | |
| 459 }); | |
| 460 return values; | |
| 461 } | |
| 462 | |
| 463 int get length() => getKeys().length; | |
| 464 | |
| 465 // TODO: Use lazy iterator when it is available on Map. | |
| 466 bool isEmpty() => length == 0; | |
| 467 | |
| 468 // Helpers. | |
| 469 String _attr(String key) => 'data-$key'; | |
| 470 bool _matches(String key) => key.startsWith('data-'); | |
| 471 String _strip(String key) => key.substring(5); | |
| 472 } | |
| 473 | |
| 474 class _CssClassSet implements Set<String> { | |
| 475 | |
| 476 final _ElementImpl _element; | |
| 477 | |
| 478 _CssClassSet(this._element); | |
| 479 | |
| 480 String toString() { | |
| 481 return _formatSet(_read()); | |
|
nweiz
2012/03/30 00:06:23
=>, here and below.
Jacob
2012/03/30 00:40:53
Done.
| |
| 482 } | |
| 483 | |
| 484 // interface Iterable - BEGIN | |
| 485 Iterator<String> iterator() { | |
| 486 return _read().iterator(); | |
| 487 } | |
| 488 // interface Iterable - END | |
| 489 | |
| 490 // interface Collection - BEGIN | |
| 491 void forEach(void f(String element)) { | |
| 492 _read().forEach(f); | |
| 493 } | |
| 494 | |
| 495 Collection map(f(String element)) { | |
| 496 return _read().map(f); | |
| 497 } | |
| 498 | |
| 499 Collection<String> filter(bool f(String element)) { | |
| 500 return _read().filter(f); | |
| 501 } | |
| 502 | |
| 503 bool every(bool f(String element)) { | |
| 504 return _read().every(f); | |
| 505 } | |
| 506 | |
| 507 bool some(bool f(String element)) { | |
| 508 return _read().some(f); | |
| 509 } | |
| 510 | |
| 511 bool isEmpty() { | |
| 512 return _read().isEmpty(); | |
| 513 } | |
| 514 | |
| 515 int get length() { | |
| 516 return _read().length; | |
| 517 } | |
| 518 // interface Collection - END | |
| 519 | |
| 520 // interface Set - BEGIN | |
| 521 bool contains(String value) { | |
| 522 return _read().contains(value); | |
| 523 } | |
| 524 | |
| 525 void add(String value) { | |
| 526 // TODO - figure out if we need to do any validation here | |
| 527 // or if the browser natively does enough | |
| 528 _modify((s) => s.add(value)); | |
| 529 } | |
| 530 | |
| 531 bool remove(String value) { | |
| 532 Set<String> s = _read(); | |
| 533 bool result = s.remove(value); | |
|
nweiz
2012/03/30 00:06:23
Couldn't you use _modify here if you changed it to
Jacob
2012/03/30 00:40:53
i don't follow. if you want to send a cleanup cl f
| |
| 534 _write(s); | |
| 535 return result; | |
| 536 } | |
| 537 | |
| 538 void addAll(Collection<String> collection) { | |
| 539 // TODO - see comment above about validation | |
| 540 _modify((s) => s.addAll(collection)); | |
| 541 } | |
| 542 | |
| 543 void removeAll(Collection<String> collection) { | |
| 544 _modify((s) => s.removeAll(collection)); | |
| 545 } | |
| 546 | |
| 547 bool isSubsetOf(Collection<String> collection) { | |
| 548 return _read().isSubsetOf(collection); | |
| 549 } | |
| 550 | |
| 551 bool containsAll(Collection<String> collection) { | |
| 552 return _read().containsAll(collection); | |
| 553 } | |
| 554 | |
| 555 Set<String> intersection(Collection<String> other) { | |
| 556 return _read().intersection(other); | |
| 557 } | |
| 558 | |
| 559 void clear() { | |
| 560 _modify((s) => s.clear()); | |
| 561 } | |
| 562 // interface Set - END | |
| 563 | |
| 564 /** | |
| 565 * Helper method used to modify the set of css classes on this element. | |
| 566 * | |
| 567 * f - callback with: | |
| 568 * s - a Set of all the css class name currently on this element. | |
| 569 * | |
| 570 * After f returns, the modified set is written to the | |
| 571 * className property of this element. | |
| 572 */ | |
| 573 void _modify( f(Set<String> s)) { | |
| 574 Set<String> s = _read(); | |
| 575 f(s); | |
| 576 _write(s); | |
| 577 } | |
| 578 | |
| 579 /** | |
| 580 * Read the class names from the Element class property, | |
| 581 * and put them into a set (duplicates are discarded). | |
| 582 */ | |
| 583 Set<String> _read() { | |
| 584 // TODO(mattsh) simplify this once split can take regex. | |
| 585 Set<String> s = new Set<String>(); | |
| 586 for (String name in $dom_className().split(' ')) { | |
| 587 String trimmed = name.trim(); | |
| 588 if (!trimmed.isEmpty()) { | |
| 589 s.add(trimmed); | |
| 590 } | |
| 591 } | |
| 592 return s; | |
| 593 } | |
| 594 | |
| 595 /** | |
| 596 * Read the class names as a space-separated string. This is meant to be | |
| 597 * overridden by subclasses. | |
| 598 */ | |
| 599 String $dom_className() => _element.$dom_className; | |
|
nweiz
2012/03/30 00:06:23
Why does this need to be implemented here?
Jacob
2012/03/30 00:40:53
Good catch... my regexp adding $dom to the names o
| |
| 600 | |
| 601 /** | |
| 602 * Join all the elements of a set into one string and write | |
| 603 * back to the element. | |
| 604 */ | |
| 605 void _write(Set s) { | |
| 606 _element.$dom_className = _formatSet(s); | |
| 607 } | |
| 608 | |
| 609 String _formatSet(Set<String> s) { | |
| 610 // TODO(mattsh) should be able to pass Set to String.joins http:/b/5398605 | |
| 611 List list = new List.from(s); | |
| 612 return Strings.join(list, ' '); | |
| 613 } | |
| 614 } | |
| 615 | |
| 396 class _SimpleClientRect implements ClientRect { | 616 class _SimpleClientRect implements ClientRect { |
| 397 final num left; | 617 final num left; |
| 398 final num top; | 618 final num top; |
| 399 final num width; | 619 final num width; |
| 400 final num height; | 620 final num height; |
| 401 num get right() => left + width; | 621 num get right() => left + width; |
| 402 num get bottom() => top + height; | 622 num get bottom() => top + height; |
| 403 | 623 |
| 404 const _SimpleClientRect(this.left, this.top, this.width, this.height); | 624 const _SimpleClientRect(this.left, this.top, this.width, this.height); |
| 405 | 625 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 451 final out = new List(_clientRects.length); | 671 final out = new List(_clientRects.length); |
| 452 for (num i = 0; i < _clientRects.length; i++) { | 672 for (num i = 0; i < _clientRects.length; i++) { |
| 453 out[i] = _clientRects.item(i); | 673 out[i] = _clientRects.item(i); |
| 454 } | 674 } |
| 455 return out; | 675 return out; |
| 456 } | 676 } |
| 457 } | 677 } |
| 458 | 678 |
| 459 class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | 679 class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
| 460 | 680 |
| 461 // TODO(jacobr): caching these may hurt performance. | |
| 462 ElementAttributeMap _elementAttributeMap; | |
| 463 _CssClassSet _cssClassSet; | |
| 464 _DataAttributeMap _dataAttributes; | |
| 465 | |
| 466 /** | 681 /** |
| 467 * @domName Element.hasAttribute, Element.getAttribute, Element.setAttribute, | 682 * @domName Element.hasAttribute, Element.getAttribute, Element.setAttribute, |
| 468 * Element.removeAttribute | 683 * Element.removeAttribute |
| 469 */ | 684 */ |
| 470 Map<String, String> get attributes() { | 685 _ElementAttributeMap get attributes() => new _ElementAttributeMap(this); |
| 471 if (_elementAttributeMap === null) { | |
| 472 _elementAttributeMap = new ElementAttributeMap._wrap(this); | |
| 473 } | |
| 474 return _elementAttributeMap; | |
| 475 } | |
| 476 | 686 |
| 477 void set attributes(Map<String, String> value) { | 687 void set attributes(Map<String, String> value) { |
| 478 Map<String, String> attributes = this.attributes; | 688 Map<String, String> attributes = this.attributes; |
| 479 attributes.clear(); | 689 attributes.clear(); |
| 480 for (String key in value.getKeys()) { | 690 for (String key in value.getKeys()) { |
| 481 attributes[key] = value[key]; | 691 attributes[key] = value[key]; |
| 482 } | 692 } |
| 483 } | 693 } |
| 484 | 694 |
| 485 void set elements(Collection<Element> value) { | 695 void set elements(Collection<Element> value) { |
| 486 final elements = this.elements; | 696 final elements = this.elements; |
| 487 elements.clear(); | 697 elements.clear(); |
| 488 elements.addAll(value); | 698 elements.addAll(value); |
| 489 } | 699 } |
| 490 | 700 |
| 491 ElementList get elements() => new _ChildrenElementList._wrap(this); | 701 ElementList get elements() => new _ChildrenElementList._wrap(this); |
| 492 | 702 |
| 493 ElementList queryAll(String selectors) => | 703 ElementList queryAll(String selectors) => |
| 494 new _FrozenElementList._wrap($dom_querySelectorAll(selectors)); | 704 new _FrozenElementList._wrap($dom_querySelectorAll(selectors)); |
| 495 | 705 |
| 496 Set<String> get classes() { | 706 _CssClassSet get classes() => new _CssClassSet(this); |
| 497 if (_cssClassSet === null) { | |
| 498 _cssClassSet = new _CssClassSet(this); | |
| 499 } | |
| 500 return _cssClassSet; | |
| 501 } | |
| 502 | 707 |
| 503 void set classes(Collection<String> value) { | 708 void set classes(Collection<String> value) { |
| 504 _CssClassSet classSet = classes; | 709 _CssClassSet classSet = classes; |
| 505 classSet.clear(); | 710 classSet.clear(); |
| 506 classSet.addAll(value); | 711 classSet.addAll(value); |
| 507 } | 712 } |
| 508 | 713 |
| 509 Map<String, String> get dataAttributes() { | 714 Map<String, String> get dataAttributes() { |
| 510 if (_dataAttributes === null) { | 715 return new _DataAttributeMap(attributes); |
|
nweiz
2012/03/30 00:06:23
=>
Jacob
2012/03/30 00:40:53
Done.
| |
| 511 _dataAttributes = new _DataAttributeMap(attributes); | |
| 512 } | |
| 513 return _dataAttributes; | |
| 514 } | 716 } |
| 515 | 717 |
| 516 void set dataAttributes(Map<String, String> value) { | 718 void set dataAttributes(Map<String, String> value) { |
| 517 Map<String, String> dataAttributes = this.dataAttributes; | 719 final dataAttributes = this.dataAttributes; |
| 518 dataAttributes.clear(); | 720 dataAttributes.clear(); |
| 519 for (String key in value.getKeys()) { | 721 for (String key in value.getKeys()) { |
| 520 dataAttributes[key] = value[key]; | 722 dataAttributes[key] = value[key]; |
| 521 } | 723 } |
| 522 } | 724 } |
| 523 | 725 |
| 524 Future<ElementRect> get rect() { | 726 Future<ElementRect> get rect() { |
| 525 return _createMeasurementFuture( | 727 return _createMeasurementFuture( |
| 526 () => new _ElementRectImpl(this), | 728 () => new _ElementRectImpl(this), |
| 527 new Completer<ElementRect>()); | 729 new Completer<ElementRect>()); |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 594 | 796 |
| 595 /** @domName Document.createElement */ | 797 /** @domName Document.createElement */ |
| 596 $if FROG | 798 $if FROG |
| 597 // Optimization to improve performance until the frog compiler inlines this | 799 // Optimization to improve performance until the frog compiler inlines this |
| 598 // method. | 800 // method. |
| 599 factory Element.tag(String tag) native "return document.createElement(tag)"; | 801 factory Element.tag(String tag) native "return document.createElement(tag)"; |
| 600 $else | 802 $else |
| 601 factory Element.tag(String tag) => _document.$dom_createElement(tag); | 803 factory Element.tag(String tag) => _document.$dom_createElement(tag); |
| 602 $endif | 804 $endif |
| 603 } | 805 } |
| OLD | NEW |