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 $dom_attributes.putIfAbsent(_attr(key), ifAbsent); |
| 421 } |
| 422 |
| 423 String remove(String key) => $dom_attributes.remove(_attr(key)); |
| 424 |
| 425 void clear() { |
| 426 // Needs to operate on a snapshot since we are mutating the collection. |
| 427 for (String key in getKeys()) { |
| 428 remove(key); |
| 429 } |
| 430 } |
| 431 |
| 432 void forEach(void f(String key, String value)) { |
| 433 $dom_attributes.forEach((String key, String value) { |
| 434 if (_matches(key)) { |
| 435 f(_strip(key), value); |
| 436 } |
| 437 }); |
| 438 } |
| 439 |
| 440 Collection<String> getKeys() { |
| 441 final keys = new List<String>(); |
| 442 $dom_attributes.forEach((String key, String value) { |
| 443 if (_matches(key)) { |
| 444 keys.add(_strip(key)); |
| 445 } |
| 446 }); |
| 447 return keys; |
| 448 } |
| 449 |
| 450 Collection<String> getValues() { |
| 451 final values = new List<String>(); |
| 452 $dom_attributes.forEach((String key, String value) { |
| 453 if (_matches(key)) { |
| 454 values.add(value); |
| 455 } |
| 456 }); |
| 457 return values; |
| 458 } |
| 459 |
| 460 int get length() => getKeys().length; |
| 461 |
| 462 // TODO: Use lazy iterator when it is available on Map. |
| 463 bool isEmpty() => length == 0; |
| 464 |
| 465 // Helpers. |
| 466 String _attr(String key) => 'data-$key'; |
| 467 bool _matches(String key) => key.startsWith('data-'); |
| 468 String _strip(String key) => key.substring(5); |
| 469 } |
| 470 |
| 471 class _CssClassSet implements Set<String> { |
| 472 |
| 473 final _ElementImpl _element; |
| 474 |
| 475 _CssClassSet(this._element); |
| 476 |
| 477 String toString() => _formatSet(_read()); |
| 478 |
| 479 // interface Iterable - BEGIN |
| 480 Iterator<String> iterator() => _read().iterator(); |
| 481 // interface Iterable - END |
| 482 |
| 483 // interface Collection - BEGIN |
| 484 void forEach(void f(String element)) { |
| 485 _read().forEach(f); |
| 486 } |
| 487 |
| 488 Collection map(f(String element)) => _read().map(f); |
| 489 |
| 490 Collection<String> filter(bool f(String element)) => _read().filter(f); |
| 491 |
| 492 bool every(bool f(String element)) => _read().every(f); |
| 493 |
| 494 bool some(bool f(String element)) => _read().some(f); |
| 495 |
| 496 bool isEmpty() => _read().isEmpty(); |
| 497 |
| 498 int get length() =>_read().length; |
| 499 |
| 500 // interface Collection - END |
| 501 |
| 502 // interface Set - BEGIN |
| 503 bool contains(String value) => _read().contains(value); |
| 504 |
| 505 void add(String value) { |
| 506 // TODO - figure out if we need to do any validation here |
| 507 // or if the browser natively does enough |
| 508 _modify((s) => s.add(value)); |
| 509 } |
| 510 |
| 511 bool remove(String value) { |
| 512 Set<String> s = _read(); |
| 513 bool result = s.remove(value); |
| 514 _write(s); |
| 515 return result; |
| 516 } |
| 517 |
| 518 void addAll(Collection<String> collection) { |
| 519 // TODO - see comment above about validation |
| 520 _modify((s) => s.addAll(collection)); |
| 521 } |
| 522 |
| 523 void removeAll(Collection<String> collection) { |
| 524 _modify((s) => s.removeAll(collection)); |
| 525 } |
| 526 |
| 527 bool isSubsetOf(Collection<String> collection) => |
| 528 _read().isSubsetOf(collection); |
| 529 |
| 530 bool containsAll(Collection<String> collection) => |
| 531 _read().containsAll(collection); |
| 532 |
| 533 Set<String> intersection(Collection<String> other) => |
| 534 _read().intersection(other); |
| 535 |
| 536 void clear() { |
| 537 _modify((s) => s.clear()); |
| 538 } |
| 539 // interface Set - END |
| 540 |
| 541 /** |
| 542 * Helper method used to modify the set of css classes on this element. |
| 543 * |
| 544 * f - callback with: |
| 545 * s - a Set of all the css class name currently on this element. |
| 546 * |
| 547 * After f returns, the modified set is written to the |
| 548 * className property of this element. |
| 549 */ |
| 550 void _modify( f(Set<String> s)) { |
| 551 Set<String> s = _read(); |
| 552 f(s); |
| 553 _write(s); |
| 554 } |
| 555 |
| 556 /** |
| 557 * Read the class names from the Element class property, |
| 558 * and put them into a set (duplicates are discarded). |
| 559 */ |
| 560 Set<String> _read() { |
| 561 // TODO(mattsh) simplify this once split can take regex. |
| 562 Set<String> s = new Set<String>(); |
| 563 for (String name in _classname().split(' ')) { |
| 564 String trimmed = name.trim(); |
| 565 if (!trimmed.isEmpty()) { |
| 566 s.add(trimmed); |
| 567 } |
| 568 } |
| 569 return s; |
| 570 } |
| 571 |
| 572 /** |
| 573 * Read the class names as a space-separated string. This is meant to be |
| 574 * overridden by subclasses. |
| 575 */ |
| 576 String _classname() => _element.$dom_className; |
| 577 |
| 578 /** |
| 579 * Join all the elements of a set into one string and write |
| 580 * back to the element. |
| 581 */ |
| 582 void _write(Set s) { |
| 583 _element.$dom_className = _formatSet(s); |
| 584 } |
| 585 |
| 586 String _formatSet(Set<String> s) { |
| 587 // TODO(mattsh) should be able to pass Set to String.joins http:/b/5398605 |
| 588 List list = new List.from(s); |
| 589 return Strings.join(list, ' '); |
| 590 } |
| 591 } |
| 592 |
396 class _SimpleClientRect implements ClientRect { | 593 class _SimpleClientRect implements ClientRect { |
397 final num left; | 594 final num left; |
398 final num top; | 595 final num top; |
399 final num width; | 596 final num width; |
400 final num height; | 597 final num height; |
401 num get right() => left + width; | 598 num get right() => left + width; |
402 num get bottom() => top + height; | 599 num get bottom() => top + height; |
403 | 600 |
404 const _SimpleClientRect(this.left, this.top, this.width, this.height); | 601 const _SimpleClientRect(this.left, this.top, this.width, this.height); |
405 | 602 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
451 final out = new List(_clientRects.length); | 648 final out = new List(_clientRects.length); |
452 for (num i = 0; i < _clientRects.length; i++) { | 649 for (num i = 0; i < _clientRects.length; i++) { |
453 out[i] = _clientRects.item(i); | 650 out[i] = _clientRects.item(i); |
454 } | 651 } |
455 return out; | 652 return out; |
456 } | 653 } |
457 } | 654 } |
458 | 655 |
459 class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { | 656 class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC { |
460 | 657 |
461 // TODO(jacobr): caching these may hurt performance. | |
462 ElementAttributeMap _elementAttributeMap; | |
463 _CssClassSet _cssClassSet; | |
464 _DataAttributeMap _dataAttributes; | |
465 | |
466 /** | 658 /** |
467 * @domName Element.hasAttribute, Element.getAttribute, Element.setAttribute, | 659 * @domName Element.hasAttribute, Element.getAttribute, Element.setAttribute, |
468 * Element.removeAttribute | 660 * Element.removeAttribute |
469 */ | 661 */ |
470 Map<String, String> get attributes() { | 662 _ElementAttributeMap get attributes() => new _ElementAttributeMap(this); |
471 if (_elementAttributeMap === null) { | |
472 _elementAttributeMap = new ElementAttributeMap._wrap(this); | |
473 } | |
474 return _elementAttributeMap; | |
475 } | |
476 | 663 |
477 void set attributes(Map<String, String> value) { | 664 void set attributes(Map<String, String> value) { |
478 Map<String, String> attributes = this.attributes; | 665 Map<String, String> attributes = this.attributes; |
479 attributes.clear(); | 666 attributes.clear(); |
480 for (String key in value.getKeys()) { | 667 for (String key in value.getKeys()) { |
481 attributes[key] = value[key]; | 668 attributes[key] = value[key]; |
482 } | 669 } |
483 } | 670 } |
484 | 671 |
485 void set elements(Collection<Element> value) { | 672 void set elements(Collection<Element> value) { |
486 final elements = this.elements; | 673 final elements = this.elements; |
487 elements.clear(); | 674 elements.clear(); |
488 elements.addAll(value); | 675 elements.addAll(value); |
489 } | 676 } |
490 | 677 |
491 ElementList get elements() => new _ChildrenElementList._wrap(this); | 678 ElementList get elements() => new _ChildrenElementList._wrap(this); |
492 | 679 |
493 ElementList queryAll(String selectors) => | 680 ElementList queryAll(String selectors) => |
494 new _FrozenElementList._wrap($dom_querySelectorAll(selectors)); | 681 new _FrozenElementList._wrap($dom_querySelectorAll(selectors)); |
495 | 682 |
496 Set<String> get classes() { | 683 _CssClassSet get classes() => new _CssClassSet(this); |
497 if (_cssClassSet === null) { | |
498 _cssClassSet = new _CssClassSet(this); | |
499 } | |
500 return _cssClassSet; | |
501 } | |
502 | 684 |
503 void set classes(Collection<String> value) { | 685 void set classes(Collection<String> value) { |
504 _CssClassSet classSet = classes; | 686 _CssClassSet classSet = classes; |
505 classSet.clear(); | 687 classSet.clear(); |
506 classSet.addAll(value); | 688 classSet.addAll(value); |
507 } | 689 } |
508 | 690 |
509 Map<String, String> get dataAttributes() { | 691 Map<String, String> get dataAttributes() => |
510 if (_dataAttributes === null) { | 692 new _DataAttributeMap(attributes); |
511 _dataAttributes = new _DataAttributeMap(attributes); | |
512 } | |
513 return _dataAttributes; | |
514 } | |
515 | 693 |
516 void set dataAttributes(Map<String, String> value) { | 694 void set dataAttributes(Map<String, String> value) { |
517 Map<String, String> dataAttributes = this.dataAttributes; | 695 final dataAttributes = this.dataAttributes; |
518 dataAttributes.clear(); | 696 dataAttributes.clear(); |
519 for (String key in value.getKeys()) { | 697 for (String key in value.getKeys()) { |
520 dataAttributes[key] = value[key]; | 698 dataAttributes[key] = value[key]; |
521 } | 699 } |
522 } | 700 } |
523 | 701 |
524 Future<ElementRect> get rect() { | 702 Future<ElementRect> get rect() { |
525 return _createMeasurementFuture( | 703 return _createMeasurementFuture( |
526 () => new _ElementRectImpl(this), | 704 () => new _ElementRectImpl(this), |
527 new Completer<ElementRect>()); | 705 new Completer<ElementRect>()); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 | 772 |
595 /** @domName Document.createElement */ | 773 /** @domName Document.createElement */ |
596 $if FROG | 774 $if FROG |
597 // Optimization to improve performance until the frog compiler inlines this | 775 // Optimization to improve performance until the frog compiler inlines this |
598 // method. | 776 // method. |
599 factory Element.tag(String tag) native "return document.createElement(tag)"; | 777 factory Element.tag(String tag) native "return document.createElement(tag)"; |
600 $else | 778 $else |
601 factory Element.tag(String tag) => _document.$dom_createElement(tag); | 779 factory Element.tag(String tag) => _document.$dom_createElement(tag); |
602 $endif | 780 $endif |
603 } | 781 } |
OLD | NEW |