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