Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 functionality. | 5 // TODO(jacobr): use Lists.dart to remove some of the duplicated functionality. |
| 6 class _ChildrenElementList implements ElementList { | 6 class _ChildrenElementList implements ElementList { |
| 7 // Raw Element. | 7 // Raw Element. |
| 8 final _element; | 8 final _element; |
| 9 final _childElements; | 9 final _childElements; |
| 10 | 10 |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 404 EventListenerList get search() => _get("search"); | 404 EventListenerList get search() => _get("search"); |
| 405 EventListenerList get select() => _get("select"); | 405 EventListenerList get select() => _get("select"); |
| 406 EventListenerList get selectStart() => _get("selectstart"); | 406 EventListenerList get selectStart() => _get("selectstart"); |
| 407 EventListenerList get submit() => _get("submit"); | 407 EventListenerList get submit() => _get("submit"); |
| 408 EventListenerList get touchCancel() => _get("touchcancel"); | 408 EventListenerList get touchCancel() => _get("touchcancel"); |
| 409 EventListenerList get touchEnd() => _get("touchend"); | 409 EventListenerList get touchEnd() => _get("touchend"); |
| 410 EventListenerList get touchLeave() => _get("touchleave"); | 410 EventListenerList get touchLeave() => _get("touchleave"); |
| 411 EventListenerList get touchMove() => _get("touchmove"); | 411 EventListenerList get touchMove() => _get("touchmove"); |
| 412 EventListenerList get touchStart() => _get("touchstart"); | 412 EventListenerList get touchStart() => _get("touchstart"); |
| 413 EventListenerList get transitionEnd() => _get("webkitTransitionEnd"); | 413 EventListenerList get transitionEnd() => _get("webkitTransitionEnd"); |
| 414 EventListenerList get fullscreenChange() => _get("fullscreenchange"); | 414 EventListenerList get fullscreenChange() => _get("webkitfullscreenchange"); |
| 415 } | |
| 416 | |
| 417 class SimpleClientRect implements ClientRect { | |
| 418 final num left; | |
| 419 final num top; | |
| 420 final num width; | |
| 421 final num height; | |
| 422 num get right() => left + width; | |
| 423 num get bottom() => top + height; | |
| 424 | |
| 425 SimpleClientRect(this.left, this.top, this.width, this.height); | |
| 426 | |
| 427 bool operator ==(ClientRect other) { | |
| 428 return other !== null && left == other.left && top == other.top | |
| 429 && width == other.width && height == other.height; | |
| 430 } | |
| 431 | |
| 432 String toString() => "($left, $top, $width, $height)"; | |
| 433 } | |
| 434 | |
| 435 // TODO(jacobr): we cannot currently be lazy about calculating the client | |
| 436 // rects as we must perform all measurement queries at a safe point to avoid | |
| 437 // triggering unneeded layouts. | |
| 438 /** | |
| 439 * All your element measurement needs in one place | |
| 440 */ | |
| 441 class ElementRectWrappingImplementation implements ElementRect { | |
| 442 final ClientRect client; | |
| 443 final ClientRect offset; | |
| 444 final ClientRect scroll; | |
| 445 | |
| 446 // TODO(jacobr): should we move these outside of ElementRect to avoid the | |
| 447 // overhead of computing them every time even though they are rarely used. | |
| 448 // This should be type dom.ClientRect but that fails on dartium. b/5522629 | |
| 449 final _boundingClientRect; | |
| 450 // an exception due to a dartium bug. | |
| 451 final dom.ClientRectList _clientRects; | |
| 452 | |
| 453 ElementRectWrappingImplementation(dom.HTMLElement element) : | |
| 454 client = new SimpleClientRect(element.clientLeft, | |
| 455 element.clientTop, | |
| 456 element.clientWidth, | |
| 457 element.clientHeight), | |
| 458 offset = new SimpleClientRect(element.offsetLeft, | |
| 459 element.offsetTop, | |
| 460 element.offsetWidth, | |
| 461 element.offsetHeight), | |
| 462 scroll = new SimpleClientRect(element.scrollLeft, | |
| 463 element.scrollTop, | |
| 464 element.scrollWidth, | |
| 465 element.scrollHeight), | |
| 466 _boundingClientRect = element.getBoundingClientRect(), | |
| 467 _clientRects = element.getClientRects(); | |
| 468 | |
| 469 ClientRect get bounding() => | |
| 470 LevelDom.wrapClientRect(_boundingClientRect); | |
| 471 | |
| 472 List<ClientRect> get clientRects() { | |
|
arv (Not doing code reviews)
2011/10/27 03:16:13
Maybe just an iterable instead?
Jacob
2011/10/27 20:59:25
Any reason why this case should just be iterable w
| |
| 473 final out = new List(_clientRects.length); | |
| 474 for (num i = 0; i < _clientRects.length; i++) { | |
| 475 out[i] = LevelDom.wrapClientRect(_clientRects.item(i)); | |
| 476 } | |
| 477 return out; | |
| 478 } | |
| 415 } | 479 } |
| 416 | 480 |
| 417 class ElementWrappingImplementation extends NodeWrappingImplementation implement s Element { | 481 class ElementWrappingImplementation extends NodeWrappingImplementation implement s Element { |
| 482 | |
| 483 static final _START_TAG_REGEXP = const RegExp('<(\\w+)'); | |
|
arv (Not doing code reviews)
2011/10/27 03:16:13
Can this be moved to a different patch?
Jacob
2011/10/27 20:59:25
I agree this bug fix is unrelated but at this earl
| |
| 484 static final _CUSTOM_PARENT_TAG_MAP = const { | |
| 485 'body' : 'html', | |
| 486 'head' : 'html', | |
| 487 'caption' : 'table', | |
| 488 'td': 'tr', | |
| 489 'tbody': 'table', | |
| 490 'colgroup': 'table', | |
| 491 'col' : 'colgroup', | |
| 492 'tr' : 'tbody', | |
| 493 'tbody' : 'table', | |
| 494 'tfoot' : 'table', | |
| 495 'thead' : 'table', | |
| 496 'track' : 'audio', | |
| 497 }; | |
| 418 | 498 |
| 419 factory ElementWrappingImplementation.html(String html) { | 499 factory ElementWrappingImplementation.html(String html) { |
| 420 final temp = dom.document.createElement('div'); | 500 String parentTag = 'div'; |
| 501 String tag; | |
| 502 final match = _START_TAG_REGEXP.firstMatch(html); | |
| 503 if (null != match) { | |
| 504 tag = match.group(1).toLowerCase(); | |
| 505 if (_CUSTOM_PARENT_TAG_MAP.containsKey(tag)) { | |
| 506 parentTag = _CUSTOM_PARENT_TAG_MAP[tag]; | |
| 507 } | |
| 508 } | |
| 509 final temp = dom.document.createElement(parentTag); | |
|
arv (Not doing code reviews)
2011/10/27 03:16:13
This code is really great. A big improvement over
Jacob
2011/10/27 20:59:25
I think this can be improved further. Added a TODO
| |
| 421 temp.innerHTML = html; | 510 temp.innerHTML = html; |
| 422 | 511 |
| 423 if (temp.childElementCount != 1) { | 512 if (temp.childElementCount == 1) { |
| 513 return LevelDom.wrapElement(temp.firstElementChild); | |
| 514 } else if (temp.childElementCount > 0 && tag != null && | |
| 515 parentTag == 'html') { | |
| 516 // Work around for edge case where both body and head | |
|
arv (Not doing code reviews)
2011/10/27 03:16:13
Which browsers? Can we link to bugs here?
I think
Jacob
2011/10/27 20:59:25
The issue occurs in WebKit. I agree that your code
| |
| 517 // elements are created even though the html contains a head or | |
| 518 // body. | |
| 519 return LevelDom.wrapElement(temp.querySelector(tag)); | |
| 520 } else { | |
| 424 throw 'HTML had ${temp.childElementCount} top level elements but 1 expecte d'; | 521 throw 'HTML had ${temp.childElementCount} top level elements but 1 expecte d'; |
| 425 } | 522 } |
| 426 | |
| 427 return LevelDom.wrapElement(temp.firstElementChild); | |
| 428 } | 523 } |
| 429 | 524 |
| 430 factory ElementWrappingImplementation.tag(String tag) { | 525 factory ElementWrappingImplementation.tag(String tag) { |
| 431 return LevelDom.wrapElement(dom.document.createElement(tag)); | 526 return LevelDom.wrapElement(dom.document.createElement(tag)); |
| 432 } | 527 } |
| 433 | 528 |
| 434 ElementWrappingImplementation._wrap(ptr) : super._wrap(ptr); | 529 ElementWrappingImplementation._wrap(ptr) : super._wrap(ptr); |
| 435 | 530 |
| 436 ElementAttributeMap _elementAttributeMap; | 531 ElementAttributeMap _elementAttributeMap; |
| 437 ElementList _elements; | 532 ElementList _elements; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 489 } | 584 } |
| 490 | 585 |
| 491 void set dataAttributes(Map<String, String> value) { | 586 void set dataAttributes(Map<String, String> value) { |
| 492 Map<String, String> dataAttributes = this.dataAttributes; | 587 Map<String, String> dataAttributes = this.dataAttributes; |
| 493 dataAttributes.clear(); | 588 dataAttributes.clear(); |
| 494 for (String key in value.getKeys()) { | 589 for (String key in value.getKeys()) { |
| 495 dataAttributes[key] = value[key]; | 590 dataAttributes[key] = value[key]; |
| 496 } | 591 } |
| 497 } | 592 } |
| 498 | 593 |
| 499 int get clientHeight() => _ptr.clientHeight; | |
| 500 | |
| 501 int get clientLeft() => _ptr.clientLeft; | |
| 502 | |
| 503 int get clientTop() => _ptr.clientTop; | |
| 504 | |
| 505 int get clientWidth() => _ptr.clientWidth; | |
| 506 | |
| 507 String get contentEditable() => _ptr.contentEditable; | 594 String get contentEditable() => _ptr.contentEditable; |
| 508 | 595 |
| 509 void set contentEditable(String value) { _ptr.contentEditable = value; } | 596 void set contentEditable(String value) { _ptr.contentEditable = value; } |
| 510 | 597 |
| 511 String get dir() => _ptr.dir; | 598 String get dir() => _ptr.dir; |
| 512 | 599 |
| 513 void set dir(String value) { _ptr.dir = value; } | 600 void set dir(String value) { _ptr.dir = value; } |
| 514 | 601 |
| 515 bool get draggable() => _ptr.draggable; | 602 bool get draggable() => _ptr.draggable; |
| 516 | 603 |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 533 bool get isContentEditable() => _ptr.isContentEditable; | 620 bool get isContentEditable() => _ptr.isContentEditable; |
| 534 | 621 |
| 535 String get lang() => _ptr.lang; | 622 String get lang() => _ptr.lang; |
| 536 | 623 |
| 537 void set lang(String value) { _ptr.lang = value; } | 624 void set lang(String value) { _ptr.lang = value; } |
| 538 | 625 |
| 539 Element get lastElementChild() => LevelDom.wrapElement(_ptr.lastElementChild); | 626 Element get lastElementChild() => LevelDom.wrapElement(_ptr.lastElementChild); |
| 540 | 627 |
| 541 Element get nextElementSibling() => LevelDom.wrapElement(_ptr.nextElementSibli ng); | 628 Element get nextElementSibling() => LevelDom.wrapElement(_ptr.nextElementSibli ng); |
| 542 | 629 |
| 543 int get offsetHeight() => _ptr.offsetHeight; | |
| 544 | |
| 545 int get offsetLeft() => _ptr.offsetLeft; | |
| 546 | |
| 547 Element get offsetParent() => LevelDom.wrapElement(_ptr.offsetParent); | 630 Element get offsetParent() => LevelDom.wrapElement(_ptr.offsetParent); |
| 548 | 631 |
| 549 int get offsetTop() => _ptr.offsetTop; | |
| 550 | |
| 551 int get offsetWidth() => _ptr.offsetWidth; | |
| 552 | |
| 553 String get outerHTML() => _ptr.outerHTML; | 632 String get outerHTML() => _ptr.outerHTML; |
| 554 | 633 |
| 555 Element get previousElementSibling() => LevelDom.wrapElement(_ptr.previousElem entSibling); | 634 Element get previousElementSibling() => LevelDom.wrapElement(_ptr.previousElem entSibling); |
| 556 | 635 |
| 557 int get scrollHeight() => _ptr.scrollHeight; | |
| 558 | |
| 559 int get scrollLeft() => _ptr.scrollLeft; | |
| 560 | |
| 561 void set scrollLeft(int value) { _ptr.scrollLeft = value; } | |
| 562 | |
| 563 int get scrollTop() => _ptr.scrollTop; | |
| 564 | |
| 565 void set scrollTop(int value) { _ptr.scrollTop = value; } | |
| 566 | |
| 567 int get scrollWidth() => _ptr.scrollWidth; | |
| 568 | |
| 569 bool get spellcheck() => _ptr.spellcheck; | 636 bool get spellcheck() => _ptr.spellcheck; |
| 570 | 637 |
| 571 void set spellcheck(bool value) { _ptr.spellcheck = value; } | 638 void set spellcheck(bool value) { _ptr.spellcheck = value; } |
| 572 | 639 |
| 573 CSSStyleDeclaration get style() => LevelDom.wrapCSSStyleDeclaration(_ptr.style ); | 640 CSSStyleDeclaration get style() => LevelDom.wrapCSSStyleDeclaration(_ptr.style ); |
| 574 | 641 |
| 575 int get tabIndex() => _ptr.tabIndex; | 642 int get tabIndex() => _ptr.tabIndex; |
| 576 | 643 |
| 577 void set tabIndex(int value) { _ptr.tabIndex = value; } | 644 void set tabIndex(int value) { _ptr.tabIndex = value; } |
| 578 | 645 |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 591 } | 658 } |
| 592 | 659 |
| 593 bool contains(Node element) { | 660 bool contains(Node element) { |
| 594 return _ptr.contains(LevelDom.unwrap(element)); | 661 return _ptr.contains(LevelDom.unwrap(element)); |
| 595 } | 662 } |
| 596 | 663 |
| 597 void focus() { | 664 void focus() { |
| 598 _ptr.focus(); | 665 _ptr.focus(); |
| 599 } | 666 } |
| 600 | 667 |
| 601 ClientRect getBoundingClientRect() { | |
| 602 return LevelDom.wrapClientRect(_ptr.getBoundingClientRect()); | |
| 603 } | |
| 604 | |
| 605 List<ClientRect> getClientRects() { | |
| 606 var rects = _ptr.getClientRects(); | |
| 607 var out = new List(rects.length); | |
| 608 for (var i = 0; i < rects.length; i++) { | |
| 609 out.add(LevelDom.wrapClientRect(rects.item(i))); | |
| 610 } | |
| 611 return out; | |
| 612 } | |
| 613 | |
| 614 Element insertAdjacentElement([String where = null, Element element = null]) { | 668 Element insertAdjacentElement([String where = null, Element element = null]) { |
| 615 return LevelDom.wrapElement(_ptr.insertAdjacentElement(where, LevelDom.unwra p(element))); | 669 return LevelDom.wrapElement(_ptr.insertAdjacentElement(where, LevelDom.unwra p(element))); |
| 616 } | 670 } |
| 617 | 671 |
| 618 void insertAdjacentHTML([String position_OR_where = null, String text = null]) { | 672 void insertAdjacentHTML([String position_OR_where = null, String text = null]) { |
| 619 _ptr.insertAdjacentHTML(position_OR_where, text); | 673 _ptr.insertAdjacentHTML(position_OR_where, text); |
| 620 } | 674 } |
| 621 | 675 |
| 622 void insertAdjacentText([String where = null, String text = null]) { | 676 void insertAdjacentText([String where = null, String text = null]) { |
| 623 _ptr.insertAdjacentText(where, text); | 677 _ptr.insertAdjacentText(where, text); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 642 } | 696 } |
| 643 | 697 |
| 644 void scrollIntoView([bool centerIfNeeded = null]) { | 698 void scrollIntoView([bool centerIfNeeded = null]) { |
| 645 _ptr.scrollIntoViewIfNeeded(centerIfNeeded); | 699 _ptr.scrollIntoViewIfNeeded(centerIfNeeded); |
| 646 } | 700 } |
| 647 | 701 |
| 648 bool matchesSelector([String selectors = null]) { | 702 bool matchesSelector([String selectors = null]) { |
| 649 return _ptr.webkitMatchesSelector(selectors); | 703 return _ptr.webkitMatchesSelector(selectors); |
| 650 } | 704 } |
| 651 | 705 |
| 706 void set scrollLeft(int value) { _ptr.scrollLeft = value; } | |
| 707 | |
| 708 void set scrollTop(int value) { _ptr.scrollTop = value; } | |
| 709 | |
| 710 Future<ElementRect> get rect() { | |
| 711 return _createMeasurementFuture( | |
| 712 () => new ElementRectWrappingImplementation(_ptr), | |
| 713 new Completer<ElementRect>()); | |
| 714 } | |
| 715 | |
| 716 Future<CSSStyleDeclaration> get computedStyle() { | |
| 717 // TODO(jacobr): last param should be null, see b/5045788 | |
| 718 return getComputedStyle(''); | |
| 719 } | |
| 720 | |
| 721 Future<CSSStyleDeclaration> getComputedStyle(String pseudoElement) { | |
| 722 return _createMeasurementFuture(() => | |
| 723 LevelDom.wrapCSSStyleDeclaration( | |
| 724 dom.window.getComputedStyle(_ptr, pseudoElement)), | |
| 725 new Completer<CSSStyleDeclaration>()); | |
| 726 } | |
| 727 | |
| 652 ElementEvents get on() { | 728 ElementEvents get on() { |
| 653 if (_on === null) { | 729 if (_on === null) { |
| 654 _on = new ElementEventsImplementation._wrap(_ptr); | 730 _on = new ElementEventsImplementation._wrap(_ptr); |
| 655 } | 731 } |
| 656 return _on; | 732 return _on; |
| 657 } | 733 } |
| 658 } | 734 } |
| OLD | NEW |