| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of polymer; | 5 part of polymer; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Use this annotation to publish a field as an attribute. For example: | 8 * Use this annotation to publish a field as an attribute. For example: |
| 9 * | 9 * |
| 10 * class MyPlaybackElement extends PolymerElement { | 10 * class MyPlaybackElement extends PolymerElement { |
| (...skipping 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 401 } else { | 401 } else { |
| 402 // Cannot call super.bind because of | 402 // Cannot call super.bind because of |
| 403 // https://code.google.com/p/dart/issues/detail?id=13156 | 403 // https://code.google.com/p/dart/issues/detail?id=13156 |
| 404 // https://code.google.com/p/dart/issues/detail?id=12456 | 404 // https://code.google.com/p/dart/issues/detail?id=12456 |
| 405 return TemplateElement.mdvPackage(this).bind(name, model, path); | 405 return TemplateElement.mdvPackage(this).bind(name, model, path); |
| 406 } | 406 } |
| 407 } | 407 } |
| 408 | 408 |
| 409 void asyncUnbindAll() { | 409 void asyncUnbindAll() { |
| 410 if (_unbound == true) return; | 410 if (_unbound == true) return; |
| 411 _unbindLog.info('[$localName] asyncUnbindAll'); | 411 _unbindLog.fine('[$localName] asyncUnbindAll'); |
| 412 _unbindAllJob = job(_unbindAllJob, unbindAll, const Duration(seconds: 0)); | 412 _unbindAllJob = job(_unbindAllJob, unbindAll, const Duration(seconds: 0)); |
| 413 } | 413 } |
| 414 | 414 |
| 415 void unbindAll() { | 415 void unbindAll() { |
| 416 if (_unbound == true) return; | 416 if (_unbound == true) return; |
| 417 | 417 |
| 418 unbindAllProperties(); | 418 unbindAllProperties(); |
| 419 // Cannot call super.bind because of | 419 // Cannot call super.bind because of |
| 420 // https://code.google.com/p/dart/issues/detail?id=13156 | 420 // https://code.google.com/p/dart/issues/detail?id=13156 |
| 421 // https://code.google.com/p/dart/issues/detail?id=12456 | 421 // https://code.google.com/p/dart/issues/detail?id=12456 |
| 422 TemplateElement.mdvPackage(this).unbindAll(); | 422 TemplateElement.mdvPackage(this).unbindAll(); |
| 423 | 423 |
| 424 _unbindNodeTree(shadowRoot); | 424 _unbindNodeTree(shadowRoot); |
| 425 // TODO(sjmiles): must also unbind inherited shadow roots | 425 // TODO(sjmiles): must also unbind inherited shadow roots |
| 426 _unbound = true; | 426 _unbound = true; |
| 427 } | 427 } |
| 428 | 428 |
| 429 void cancelUnbindAll({bool preventCascade}) { | 429 void cancelUnbindAll({bool preventCascade}) { |
| 430 if (_unbound == true) { | 430 if (_unbound == true) { |
| 431 _unbindLog.warning( | 431 _unbindLog.warning( |
| 432 '[$localName] already unbound, cannot cancel unbindAll'); | 432 '[$localName] already unbound, cannot cancel unbindAll'); |
| 433 return; | 433 return; |
| 434 } | 434 } |
| 435 _unbindLog.info('[$localName] cancelUnbindAll'); | 435 _unbindLog.fine('[$localName] cancelUnbindAll'); |
| 436 if (_unbindAllJob != null) { | 436 if (_unbindAllJob != null) { |
| 437 _unbindAllJob.stop(); | 437 _unbindAllJob.stop(); |
| 438 _unbindAllJob = null; | 438 _unbindAllJob = null; |
| 439 } | 439 } |
| 440 | 440 |
| 441 // cancel unbinding our shadow tree iff we're not in the process of | 441 // cancel unbinding our shadow tree iff we're not in the process of |
| 442 // cascading our tree (as we do, for example, when the element is inserted). | 442 // cascading our tree (as we do, for example, when the element is inserted). |
| 443 if (preventCascade == true) return; | 443 if (preventCascade == true) return; |
| 444 _forNodeTree(shadowRoot, (n) { | 444 _forNodeTree(shadowRoot, (n) { |
| 445 if (n is Polymer) { | 445 if (n is Polymer) { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 484 if (publish != null) { | 484 if (publish != null) { |
| 485 publish.forEach((name, value) { | 485 publish.forEach((name, value) { |
| 486 if (observe == null || !observe.containsKey(name)) { | 486 if (observe == null || !observe.containsKey(name)) { |
| 487 observeAttributeProperty(name); | 487 observeAttributeProperty(name); |
| 488 } | 488 } |
| 489 }); | 489 }); |
| 490 } | 490 } |
| 491 } | 491 } |
| 492 | 492 |
| 493 void _observe(String name, void callback(newValue, oldValue)) { | 493 void _observe(String name, void callback(newValue, oldValue)) { |
| 494 _observeLog.info('[$localName] watching [$name]'); | 494 _observeLog.fine('[$localName] watching [$name]'); |
| 495 // TODO(jmesserly): this is a little different than the JS version so we | 495 // TODO(jmesserly): this is a little different than the JS version so we |
| 496 // can pass the oldValue, which is missing from Dart's PathObserver. | 496 // can pass the oldValue, which is missing from Dart's PathObserver. |
| 497 // This probably gives us worse performance. | 497 // This probably gives us worse performance. |
| 498 var path = new PathObserver(this, name); | 498 var path = new PathObserver(this, name); |
| 499 Object oldValue = null; | 499 Object oldValue = null; |
| 500 _registerObserver(name, path.changes.listen((_) { | 500 _registerObserver(name, path.changes.listen((_) { |
| 501 final newValue = path.value; | 501 final newValue = path.value; |
| 502 final old = oldValue; | 502 final old = oldValue; |
| 503 oldValue = newValue; | 503 oldValue = newValue; |
| 504 callback(newValue, old); | 504 callback(newValue, old); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 558 // apply Polymer two-way reference binding | 558 // apply Polymer two-way reference binding |
| 559 _bindProperties(this, name, model, path); | 559 _bindProperties(this, name, model, path); |
| 560 | 560 |
| 561 /** | 561 /** |
| 562 * bind a property in A to a path in B by converting A[property] to a | 562 * bind a property in A to a path in B by converting A[property] to a |
| 563 * getter/setter pair that accesses B[...path...] | 563 * getter/setter pair that accesses B[...path...] |
| 564 */ | 564 */ |
| 565 static NodeBinding _bindProperties(Polymer inA, Symbol inProperty, | 565 static NodeBinding _bindProperties(Polymer inA, Symbol inProperty, |
| 566 Object inB, String inPath) { | 566 Object inB, String inPath) { |
| 567 | 567 |
| 568 if (_bindLog.isLoggable(Level.INFO)) { | 568 if (_bindLog.isLoggable(Level.FINE)) { |
| 569 _bindLog.info('[$inB]: bindProperties: [$inPath] to ' | 569 _bindLog.fine('[$inB]: bindProperties: [$inPath] to ' |
| 570 '[${inA.localName}].[$inProperty]'); | 570 '[${inA.localName}].[$inProperty]'); |
| 571 } | 571 } |
| 572 | 572 |
| 573 // Dart note: normally we only reach this code when we know it's a | 573 // Dart note: normally we only reach this code when we know it's a |
| 574 // property, but if someone uses bindProperty directly they might get a | 574 // property, but if someone uses bindProperty directly they might get a |
| 575 // NoSuchMethodError either from the getField below, or from the setField | 575 // NoSuchMethodError either from the getField below, or from the setField |
| 576 // inside PolymerBinding. That doesn't seem unreasonable, but it's a slight | 576 // inside PolymerBinding. That doesn't seem unreasonable, but it's a slight |
| 577 // difference from Polymer.js behavior. | 577 // difference from Polymer.js behavior. |
| 578 | 578 |
| 579 // capture A's value if B's value is null or undefined, | 579 // capture A's value if B's value is null or undefined, |
| 580 // otherwise use B's value | 580 // otherwise use B's value |
| 581 var path = new PathObserver(inB, inPath); | 581 var path = new PathObserver(inB, inPath); |
| 582 if (path.value == null) { | 582 if (path.value == null) { |
| 583 path.value = reflect(inA).getField(inProperty).reflectee; | 583 path.value = reflect(inA).getField(inProperty).reflectee; |
| 584 } | 584 } |
| 585 return new _PolymerBinding(inA, inProperty, inB, inPath); | 585 return new _PolymerBinding(inA, inProperty, inB, inPath); |
| 586 } | 586 } |
| 587 | 587 |
| 588 /** Attach event listeners on the host (this) element. */ | 588 /** Attach event listeners on the host (this) element. */ |
| 589 void addHostListeners() { | 589 void addHostListeners() { |
| 590 var events = _declaration._eventDelegates; | 590 var events = _declaration._eventDelegates; |
| 591 if (events.isEmpty) return; | 591 if (events.isEmpty) return; |
| 592 | 592 |
| 593 if (_eventsLog.isLoggable(Level.INFO)) { | 593 if (_eventsLog.isLoggable(Level.FINE)) { |
| 594 _eventsLog.info('[$localName] addHostListeners: $events'); | 594 _eventsLog.fine('[$localName] addHostListeners: $events'); |
| 595 } | 595 } |
| 596 addNodeListeners(this, events.keys, hostEventListener); | 596 addNodeListeners(this, events.keys, hostEventListener); |
| 597 } | 597 } |
| 598 | 598 |
| 599 /** Attach event listeners inside a shadow [root]. */ | 599 /** Attach event listeners inside a shadow [root]. */ |
| 600 void addInstanceListeners(ShadowRoot root, Element template) { | 600 void addInstanceListeners(ShadowRoot root, Element template) { |
| 601 var templateDelegates = _declaration._templateDelegates; | 601 var templateDelegates = _declaration._templateDelegates; |
| 602 if (templateDelegates == null) return; | 602 if (templateDelegates == null) return; |
| 603 var events = templateDelegates[template]; | 603 var events = templateDelegates[template]; |
| 604 if (events == null) return; | 604 if (events == null) return; |
| 605 | 605 |
| 606 if (_eventsLog.isLoggable(Level.INFO)) { | 606 if (_eventsLog.isLoggable(Level.FINE)) { |
| 607 _eventsLog.info('[$localName] addInstanceListeners: $events'); | 607 _eventsLog.fine('[$localName] addInstanceListeners: $events'); |
| 608 } | 608 } |
| 609 addNodeListeners(root, events, instanceEventListener); | 609 addNodeListeners(root, events, instanceEventListener); |
| 610 } | 610 } |
| 611 | 611 |
| 612 void addNodeListeners(Node node, Iterable<String> events, | 612 void addNodeListeners(Node node, Iterable<String> events, |
| 613 void listener(Event e)) { | 613 void listener(Event e)) { |
| 614 | 614 |
| 615 for (var name in events) { | 615 for (var name in events) { |
| 616 addNodeListener(node, name, listener); | 616 addNodeListener(node, name, listener); |
| 617 } | 617 } |
| 618 } | 618 } |
| 619 | 619 |
| 620 void addNodeListener(Node node, String event, void listener(Event e)) { | 620 void addNodeListener(Node node, String event, void listener(Event e)) { |
| 621 node.on[event].listen(listener); | 621 node.on[event].listen(listener); |
| 622 } | 622 } |
| 623 | 623 |
| 624 void hostEventListener(Event event) { | 624 void hostEventListener(Event event) { |
| 625 // TODO(jmesserly): do we need this check? It was using cancelBubble, see: | 625 // TODO(jmesserly): do we need this check? It was using cancelBubble, see: |
| 626 // https://github.com/Polymer/polymer/issues/292 | 626 // https://github.com/Polymer/polymer/issues/292 |
| 627 if (!event.bubbles) return; | 627 if (!event.bubbles) return; |
| 628 | 628 |
| 629 bool log = _eventsLog.isLoggable(Level.INFO); | 629 bool log = _eventsLog.isLoggable(Level.FINE); |
| 630 if (log) { | 630 if (log) { |
| 631 _eventsLog.info('>>> [$localName]: hostEventListener(${event.type})'); | 631 _eventsLog.fine('>>> [$localName]: hostEventListener(${event.type})'); |
| 632 } | 632 } |
| 633 | 633 |
| 634 var h = findEventDelegate(event); | 634 var h = findEventDelegate(event); |
| 635 if (h != null) { | 635 if (h != null) { |
| 636 if (log) _eventsLog.info('[$localName] found host handler name [$h]'); | 636 if (log) _eventsLog.fine('[$localName] found host handler name [$h]'); |
| 637 var detail = event is CustomEvent ? | 637 var detail = event is CustomEvent ? |
| 638 (event as CustomEvent).detail : null; | 638 (event as CustomEvent).detail : null; |
| 639 // TODO(jmesserly): cache the symbols? | 639 // TODO(jmesserly): cache the symbols? |
| 640 dispatchMethod(new Symbol(h), [event, detail, this]); | 640 dispatchMethod(new Symbol(h), [event, detail, this]); |
| 641 } | 641 } |
| 642 | 642 |
| 643 if (log) { | 643 if (log) { |
| 644 _eventsLog.info('<<< [$localName]: hostEventListener(${event.type})'); | 644 _eventsLog.fine('<<< [$localName]: hostEventListener(${event.type})'); |
| 645 } | 645 } |
| 646 } | 646 } |
| 647 | 647 |
| 648 String findEventDelegate(Event event) => | 648 String findEventDelegate(Event event) => |
| 649 _declaration._eventDelegates[_eventNameFromType(event.type)]; | 649 _declaration._eventDelegates[_eventNameFromType(event.type)]; |
| 650 | 650 |
| 651 /** Call [methodName] method on [this] with [args], if the method exists. */ | 651 /** Call [methodName] method on [this] with [args], if the method exists. */ |
| 652 // TODO(jmesserly): I removed the [node] argument as it was unused. Reconcile. | 652 // TODO(jmesserly): I removed the [node] argument as it was unused. Reconcile. |
| 653 void dispatchMethod(Symbol methodName, List args) { | 653 void dispatchMethod(Symbol methodName, List args) { |
| 654 bool log = _eventsLog.isLoggable(Level.INFO); | 654 bool log = _eventsLog.isLoggable(Level.FINE); |
| 655 if (log) _eventsLog.info('>>> [$localName]: dispatch $methodName'); | 655 if (log) _eventsLog.fine('>>> [$localName]: dispatch $methodName'); |
| 656 | 656 |
| 657 // TODO(sigmund): consider making event listeners list all arguments | 657 // TODO(sigmund): consider making event listeners list all arguments |
| 658 // explicitly. Unless VM mirrors are optimized first, this reflectClass call | 658 // explicitly. Unless VM mirrors are optimized first, this reflectClass call |
| 659 // will be expensive once custom elements extend directly from Element (see | 659 // will be expensive once custom elements extend directly from Element (see |
| 660 // dartbug.com/11108). | 660 // dartbug.com/11108). |
| 661 var self = reflect(this); | 661 var self = reflect(this); |
| 662 var method = self.type.methods[methodName]; | 662 var method = self.type.methods[methodName]; |
| 663 if (method != null) { | 663 if (method != null) { |
| 664 // This will either truncate the argument list or extend it with extra | 664 // This will either truncate the argument list or extend it with extra |
| 665 // null arguments, so it will match the signature. | 665 // null arguments, so it will match the signature. |
| 666 // TODO(sigmund): consider accepting optional arguments when we can tell | 666 // TODO(sigmund): consider accepting optional arguments when we can tell |
| 667 // them appart from named arguments (see http://dartbug.com/11334) | 667 // them appart from named arguments (see http://dartbug.com/11334) |
| 668 args.length = method.parameters.where((p) => !p.isOptional).length; | 668 args.length = method.parameters.where((p) => !p.isOptional).length; |
| 669 } | 669 } |
| 670 self.invoke(methodName, args); | 670 self.invoke(methodName, args); |
| 671 | 671 |
| 672 if (log) _eventsLog.info('<<< [$localName]: dispatch $methodName'); | 672 if (log) _eventsLog.fine('<<< [$localName]: dispatch $methodName'); |
| 673 | 673 |
| 674 // TODO(jmesserly): workaround for HTML events not supporting zones. | 674 // TODO(jmesserly): workaround for HTML events not supporting zones. |
| 675 performMicrotaskCheckpoint(); | 675 performMicrotaskCheckpoint(); |
| 676 } | 676 } |
| 677 | 677 |
| 678 void instanceEventListener(Event event) { | 678 void instanceEventListener(Event event) { |
| 679 _listenLocal(this, event); | 679 _listenLocal(this, event); |
| 680 } | 680 } |
| 681 | 681 |
| 682 // TODO(sjmiles): much of the below privatized only because of the vague | 682 // TODO(sjmiles): much of the below privatized only because of the vague |
| 683 // notion this code is too fiddly and we need to revisit the core feature | 683 // notion this code is too fiddly and we need to revisit the core feature |
| 684 void _listenLocal(Polymer host, Event event) { | 684 void _listenLocal(Polymer host, Event event) { |
| 685 // TODO(jmesserly): do we need this check? It was using cancelBubble, see: | 685 // TODO(jmesserly): do we need this check? It was using cancelBubble, see: |
| 686 // https://github.com/Polymer/polymer/issues/292 | 686 // https://github.com/Polymer/polymer/issues/292 |
| 687 if (!event.bubbles) return; | 687 if (!event.bubbles) return; |
| 688 | 688 |
| 689 bool log = _eventsLog.isLoggable(Level.INFO); | 689 bool log = _eventsLog.isLoggable(Level.FINE); |
| 690 if (log) _eventsLog.info('>>> [$localName]: listenLocal [${event.type}]'); | 690 if (log) _eventsLog.fine('>>> [$localName]: listenLocal [${event.type}]'); |
| 691 | 691 |
| 692 final eventOn = '$_EVENT_PREFIX${_eventNameFromType(event.type)}'; | 692 final eventOn = '$_EVENT_PREFIX${_eventNameFromType(event.type)}'; |
| 693 if (event.path == null) { | 693 if (event.path == null) { |
| 694 _listenLocalNoEventPath(host, event, eventOn); | 694 _listenLocalNoEventPath(host, event, eventOn); |
| 695 } else { | 695 } else { |
| 696 _listenLocalEventPath(host, event, eventOn); | 696 _listenLocalEventPath(host, event, eventOn); |
| 697 } | 697 } |
| 698 | 698 |
| 699 if (log) _eventsLog.info('<<< [$localName]: listenLocal [${event.type}]'); | 699 if (log) _eventsLog.fine('<<< [$localName]: listenLocal [${event.type}]'); |
| 700 } | 700 } |
| 701 | 701 |
| 702 static void _listenLocalEventPath(Polymer host, Event event, String eventOn) { | 702 static void _listenLocalEventPath(Polymer host, Event event, String eventOn) { |
| 703 var c = null; | 703 var c = null; |
| 704 for (var target in event.path) { | 704 for (var target in event.path) { |
| 705 // if we hit host, stop | 705 // if we hit host, stop |
| 706 if (identical(target, host)) return; | 706 if (identical(target, host)) return; |
| 707 | 707 |
| 708 // find a controller for the target, unless we already found `host` | 708 // find a controller for the target, unless we already found `host` |
| 709 // as a controller | 709 // as a controller |
| 710 c = identical(c, host) ? c : _findController(target); | 710 c = identical(c, host) ? c : _findController(target); |
| 711 | 711 |
| 712 // if we have a controller, dispatch the event, and stop if the handler | 712 // if we have a controller, dispatch the event, and stop if the handler |
| 713 // returns true | 713 // returns true |
| 714 if (c != null && _handleEvent(c, target, event, eventOn)) { | 714 if (c != null && _handleEvent(c, target, event, eventOn)) { |
| 715 return; | 715 return; |
| 716 } | 716 } |
| 717 } | 717 } |
| 718 } | 718 } |
| 719 | 719 |
| 720 // TODO(sorvell): remove when ShadowDOM polyfill supports event path. | 720 // TODO(sorvell): remove when ShadowDOM polyfill supports event path. |
| 721 // Note that _findController will not return the expected controller when the | 721 // Note that _findController will not return the expected controller when the |
| 722 // event target is a distributed node. This is because we cannot traverse | 722 // event target is a distributed node. This is because we cannot traverse |
| 723 // from a composed node to a node in shadowRoot. | 723 // from a composed node to a node in shadowRoot. |
| 724 // This will be addressed via an event path api | 724 // This will be addressed via an event path api |
| 725 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21066 | 725 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21066 |
| 726 static void _listenLocalNoEventPath(Polymer host, Event event, | 726 static void _listenLocalNoEventPath(Polymer host, Event event, |
| 727 String eventOn) { | 727 String eventOn) { |
| 728 | 728 |
| 729 if (_eventsLog.isLoggable(Level.INFO)) { | 729 if (_eventsLog.isLoggable(Level.FINE)) { |
| 730 _eventsLog.info('event.path() not supported for ${event.type}'); | 730 _eventsLog.fine('event.path() not supported for ${event.type}'); |
| 731 } | 731 } |
| 732 | 732 |
| 733 var target = event.target; | 733 var target = event.target; |
| 734 var c = null; | 734 var c = null; |
| 735 // if we hit dirt or host, stop | 735 // if we hit dirt or host, stop |
| 736 while (target != null && target != host) { | 736 while (target != null && target != host) { |
| 737 // find a controller for target `t`, unless we already found `host` | 737 // find a controller for target `t`, unless we already found `host` |
| 738 // as a controller | 738 // as a controller |
| 739 c = identical(c, host) ? c : _findController(target); | 739 c = identical(c, host) ? c : _findController(target); |
| 740 | 740 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 757 } | 757 } |
| 758 | 758 |
| 759 static bool _handleEvent(Polymer ctrlr, Node node, Event event, | 759 static bool _handleEvent(Polymer ctrlr, Node node, Event event, |
| 760 String eventOn) { | 760 String eventOn) { |
| 761 | 761 |
| 762 // Note: local events are listened only in the shadow root. This dynamic | 762 // Note: local events are listened only in the shadow root. This dynamic |
| 763 // lookup is used to distinguish determine whether the target actually has a | 763 // lookup is used to distinguish determine whether the target actually has a |
| 764 // listener, and if so, to determine lazily what's the target method. | 764 // listener, and if so, to determine lazily what's the target method. |
| 765 var name = node is Element ? (node as Element).attributes[eventOn] : null; | 765 var name = node is Element ? (node as Element).attributes[eventOn] : null; |
| 766 if (name != null && _handleIfNotHandled(node, event)) { | 766 if (name != null && _handleIfNotHandled(node, event)) { |
| 767 if (_eventsLog.isLoggable(Level.INFO)) { | 767 if (_eventsLog.isLoggable(Level.FINE)) { |
| 768 _eventsLog.info('[${ctrlr.localName}] found handler name [$name]'); | 768 _eventsLog.fine('[${ctrlr.localName}] found handler name [$name]'); |
| 769 } | 769 } |
| 770 var detail = event is CustomEvent ? | 770 var detail = event is CustomEvent ? |
| 771 (event as CustomEvent).detail : null; | 771 (event as CustomEvent).detail : null; |
| 772 | 772 |
| 773 if (node != null) { | 773 if (node != null) { |
| 774 // TODO(jmesserly): cache symbols? | 774 // TODO(jmesserly): cache symbols? |
| 775 ctrlr.dispatchMethod(new Symbol(name), [event, detail, node]); | 775 ctrlr.dispatchMethod(new Symbol(name), [event, detail, node]); |
| 776 } | 776 } |
| 777 } | 777 } |
| 778 | 778 |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 940 /** | 940 /** |
| 941 * Base class for PolymerElements deriving from HtmlElement. | 941 * Base class for PolymerElements deriving from HtmlElement. |
| 942 * | 942 * |
| 943 * See [Polymer]. | 943 * See [Polymer]. |
| 944 */ | 944 */ |
| 945 class PolymerElement extends HtmlElement with Polymer, ObservableMixin { | 945 class PolymerElement extends HtmlElement with Polymer, ObservableMixin { |
| 946 PolymerElement.created() : super.created() { | 946 PolymerElement.created() : super.created() { |
| 947 polymerCreated(); | 947 polymerCreated(); |
| 948 } | 948 } |
| 949 } | 949 } |
| OLD | NEW |