Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1436)

Side by Side Diff: pkg/polymer/lib/src/instance.dart

Issue 723393003: update to polymer js 0.5.1 (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: little bit of cleanup Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 /// Use this annotation to publish a property as an attribute. 7 /// Use this annotation to publish a property as an attribute.
8 /// 8 ///
9 /// You can also use [PublishedProperty] to provide additional information, 9 /// You can also use [PublishedProperty] to provide additional information,
10 /// such as automatically syncing the property back to the attribute. 10 /// such as automatically syncing the property back to the attribute.
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 // new JsObject.fromBrowserObject(poly).callMethod('init') 191 // new JsObject.fromBrowserObject(poly).callMethod('init')
192 // 192 //
193 // However doing it that way hits an issue with JS-interop in IE10: we get a 193 // However doing it that way hits an issue with JS-interop in IE10: we get a
194 // JsObject that wraps something other than `poly`, due to improper caching. 194 // JsObject that wraps something other than `poly`, due to improper caching.
195 // By reusing _polymerElementProto that we used for 'register', we can 195 // By reusing _polymerElementProto that we used for 'register', we can
196 // then call apply on it to invoke init() with the correct `this` pointer. 196 // then call apply on it to invoke init() with the correct `this` pointer.
197 JsFunction init = _polymerElementProto['init']; 197 JsFunction init = _polymerElementProto['init'];
198 init.apply([], thisArg: poly); 198 init.apply([], thisArg: poly);
199 } 199 }
200 200
201 // Note: these are from src/declaration/import.js 201 // Warning for when people try to use `importElements` or `import`.
202 // For now proxy to the JS methods, because we want to share the loader with 202 static const String _DYNAMIC_IMPORT_WARNING = 'Dynamically loading html '
203 // polymer.js for interop purposes. 203 'imports has very limited support right now in dart, see '
204 'http://dartbug.com/17873.';
205
206 /// Loads the set of HTMLImports contained in `node`. Returns a future that
207 /// resolves when all the imports have been loaded. This method can be used to
208 /// lazily load imports. For example, given a template:
209 ///
210 /// <template>
211 /// <link rel="import" href="my-import1.html">
212 /// <link rel="import" href="my-import2.html">
213 /// </template>
214 ///
215 /// Polymer.importElements(template.content)
216 /// .then((_) => print('imports lazily loaded'));
217 ///
Siggi Cherem (dart-lang) 2014/11/25 17:53:42 maybe add a line here in the docs about the limite
jakemac 2014/12/01 18:42:51 Done.
218 /// Dart Notes: From src/lib/import.js For now proxy to the JS methods,
Siggi Cherem (dart-lang) 2014/11/25 17:53:42 nit use only 2 // for this part of the comment (so
jakemac 2014/12/01 18:42:52 Done.
219 /// because we want to share the loader with polymer.js for interop purposes.
204 static Future importElements(Node elementOrFragment) { 220 static Future importElements(Node elementOrFragment) {
221 print(_DYNAMIC_IMPORT_WARNING);
205 var completer = new Completer(); 222 var completer = new Completer();
206 js.context['Polymer'].callMethod('importElements', 223 js.context['Polymer'].callMethod('importElements',
207 [elementOrFragment, () => completer.complete()]); 224 [elementOrFragment, () => completer.complete()]);
208 return completer.future; 225 return completer.future;
209 } 226 }
210 227
211 static Future importUrls(List urls) { 228 /// Loads an HTMLImport for each url specified in the `urls` array. Notifies
229 /// when all the imports have loaded by calling the `callback` function
230 /// argument. This method can be used to lazily load imports. For example,
231 /// For example,
232 ///
233 /// Polymer.import(['my-import1.html', 'my-import2.html'])
234 /// .then((_) => print('imports lazily loaded'));
235 ///
236 /// Dart Notes: From src/lib/import.js. For now proxy to the JS methods,
Siggi Cherem (dart-lang) 2014/11/25 17:53:42 same two comments here
jakemac 2014/12/01 18:42:52 Done.
237 /// because we want to share the loader with polymer.js for interop purposes.
238 static Future import(List urls) {
239 print(_DYNAMIC_IMPORT_WARNING);
212 var completer = new Completer(); 240 var completer = new Completer();
213 js.context['Polymer'].callMethod('importUrls', 241 js.context['Polymer'].callMethod('import',
214 [urls, () => completer.complete()]); 242 [urls, () => completer.complete()]);
215 return completer.future; 243 return completer.future;
216 } 244 }
217 245
246 /// Deprecated: Use `import` instead.
247 @deprecated
248 static Future importUrls(List urls) {
249 return import(urls);
250 }
251
218 static final Completer _onReady = new Completer(); 252 static final Completer _onReady = new Completer();
219 253
220 /// Future indicating that the Polymer library has been loaded and is ready 254 /// Future indicating that the Polymer library has been loaded and is ready
221 /// for use. 255 /// for use.
222 static Future get onReady => _onReady.future; 256 static Future get onReady => _onReady.future;
223 257
224 /// Returns a list of elements that have had polymer-elements created but 258 /// Returns a list of elements that have had polymer-elements created but
225 /// are not yet ready to register. The list is an array of element 259 /// are not yet ready to register. The list is an array of element
226 /// definitions. 260 /// definitions.
227 static List<Element> get waitingFor => 261 static List<Element> get waitingFor =>
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
357 /// If this class is a superclass, calling `super.created()` is sufficient. 391 /// If this class is a superclass, calling `super.created()` is sufficient.
358 void polymerCreated() { 392 void polymerCreated() {
359 var t = nodeBind(this).templateInstance; 393 var t = nodeBind(this).templateInstance;
360 if (t != null && t.model != null) { 394 if (t != null && t.model != null) {
361 window.console.warn('Attributes on $_name were data bound ' 395 window.console.warn('Attributes on $_name were data bound '
362 'prior to Polymer upgrading the element. This may result in ' 396 'prior to Polymer upgrading the element. This may result in '
363 'incorrect binding types.'); 397 'incorrect binding types.');
364 } 398 }
365 prepareElement(); 399 prepareElement();
366 if (!isTemplateStagingDocument(ownerDocument)) { 400 if (!isTemplateStagingDocument(ownerDocument)) {
367 makeElementReady(); 401 _makeElementReady();
368 } 402 }
369 } 403 }
370 404
371 /// *Deprecated* use [shadowRoots] instead. 405 /// *Deprecated* use [shadowRoots] instead.
372 @deprecated 406 @deprecated
373 ShadowRoot getShadowRoot(String customTagName) => shadowRoots[customTagName]; 407 ShadowRoot getShadowRoot(String customTagName) => shadowRoots[customTagName];
374 408
375 void prepareElement() { 409 void prepareElement() {
376 if (_elementPrepared) { 410 if (_elementPrepared) {
377 window.console.warn('Element already prepared: $_name'); 411 window.console.warn('Element already prepared: $_name');
378 return; 412 return;
379 } 413 }
380 _initJsObject(); 414 _initJsObject();
381 // Dart note: get the corresponding <polymer-element> declaration. 415 // Dart note: get the corresponding <polymer-element> declaration.
382 _element = _getDeclaration(_name); 416 _element = _getDeclaration(_name);
383 // install property storage 417 // install property storage
384 createPropertyObserver(); 418 createPropertyObserver();
385 openPropertyObserver(); 419 openPropertyObserver();
386 // install boilerplate attributes 420 // install boilerplate attributes
387 copyInstanceAttributes(); 421 copyInstanceAttributes();
388 // process input attributes 422 // process input attributes
389 takeAttributes(); 423 takeAttributes();
390 // add event listeners 424 // add event listeners
391 addHostListeners(); 425 addHostListeners();
392 } 426 }
393 427
394 /// Initialize JS interop for this element. For now we just initialize the 428 /// Initialize JS interop for this element. For now we just initialize the
395 // JsObject, but in the future we could also initialize JS APIs here. 429 /// JsObject, but in the future we could also initialize JS APIs here.
396 _initJsObject() { 430 _initJsObject() {
397 _jsElem = new JsObject.fromBrowserObject(this); 431 _jsElem = new JsObject.fromBrowserObject(this);
398 } 432 }
399 433
400 makeElementReady() { 434 /// Deprecated: This is no longer a public method.
435 @deprecated
436 makeElementReady() => _makeElementReady();
437
438 _makeElementReady() {
401 if (_readied) return; 439 if (_readied) return;
402 _readied = true; 440 _readied = true;
403 createComputedProperties(); 441 createComputedProperties();
404 442
405 // TODO(sorvell): We could create an entry point here
406 // for the user to compute property values.
407 // process declarative resources
408 parseDeclarations(_element); 443 parseDeclarations(_element);
409 // TODO(sorvell): CE polyfill uses unresolved attribute to simulate 444 // NOTE: Support use of the `unresolved` attribute to help polyfill
410 // :unresolved; remove this attribute to be compatible with native 445 // custom elements' `:unresolved` feature.
411 // CE.
412 attributes.remove('unresolved'); 446 attributes.remove('unresolved');
413 // user entry point 447 // user entry point
414 _readyLog.info(() => '[$this]: ready'); 448 _readyLog.info(() => '[$this]: ready');
415 ready(); 449 ready();
416 } 450 }
417 451
418 /// Called when [prepareElement] is finished, which means that the element's 452 /// Lifecycle method called when the element has populated it's `shadowRoot`,
419 /// shadowRoot has been created, its event listeners have been setup, 453 /// prepared data-observation, and made itself ready for API interaction.
420 /// attributes have been reflected to properties, and property observers have
421 /// been setup. To wait until the element has been attached to the default
Siggi Cherem (dart-lang) 2014/11/25 17:53:42 maybe keep this last sentence to help guide our us
jakemac 2014/12/01 18:42:51 Done.
422 /// view, use [attached] or [domReady].
423 void ready() {} 454 void ready() {}
424 455
425 /// domReady can be used to access elements in dom (descendants, 456 /// Implement to access custom elements in dom descendants, ancestors,
426 /// ancestors, siblings) such that the developer is enured to upgrade 457 /// or siblings. Because custom elements upgrade in document order,
427 /// ordering. If the element definitions have loaded, domReady 458 /// elements accessed in `ready` or `attached` may not be upgraded. When
428 /// can be used to access upgraded elements. 459 /// `domReady` is called, all registered custom elements are guaranteed
429 /// 460 /// to have been upgraded.
430 /// To use, override this method in your element.
431 void domReady() {} 461 void domReady() {}
432 462
433 void attached() { 463 void attached() {
434 if (!_elementPrepared) { 464 if (!_elementPrepared) {
435 // Dart specific message for a common issue. 465 // Dart specific message for a common issue.
436 throw new StateError('polymerCreated was not called for custom element ' 466 throw new StateError('polymerCreated was not called for custom element '
437 '$_name, this should normally be done in the .created() if Polymer ' 467 '$_name, this should normally be done in the .created() if Polymer '
438 'is used as a mixin.'); 468 'is used as a mixin.');
439 } 469 }
440 470
441 cancelUnbindAll(); 471 cancelUnbindAll();
442 if (!hasBeenAttached) { 472 if (!hasBeenAttached) {
443 _hasBeenAttached = true; 473 _hasBeenAttached = true;
444 async((_) => domReady()); 474 async((_) => domReady());
445 } 475 }
446 } 476 }
447 477
448 void detached() { 478 void detached() {
449 if (!preventDispose) asyncUnbindAll(); 479 if (!preventDispose) asyncUnbindAll();
450 } 480 }
451 481
452 /// Recursive ancestral <element> initialization, oldest first. 482 /// Walks the prototype-chain of this element and allows specific
483 /// classes a chance to process static declarations.
484 ///
485 /// In particular, each polymer-element has it's own `template`.
486 /// `parseDeclarations` is used to accumulate all element `template`s
487 /// from an inheritance chain.
488 ///
489 /// `parseDeclaration` static methods implemented in the chain are called
490 /// recursively, oldest first, with the `<polymer-element>` associated
491 /// with the current prototype passed as an argument.
492 ///
493 /// An element may override this method to customize shadow-root generation.
453 void parseDeclarations(PolymerDeclaration declaration) { 494 void parseDeclarations(PolymerDeclaration declaration) {
454 if (declaration != null) { 495 if (declaration != null) {
455 parseDeclarations(declaration.superDeclaration); 496 parseDeclarations(declaration.superDeclaration);
456 parseDeclaration(declaration.element); 497 parseDeclaration(declaration.element);
457 } 498 }
458 } 499 }
459 500
460 /// Parse input `<polymer-element>` as needed, override for custom behavior. 501 /// Perform init-time actions based on static information in the
502 /// `<polymer-element>` instance argument.
503 ///
504 /// For example, the standard implementation locates the template associated
505 /// with the given `<polymer-element>` and stamps it into a shadow-root to
506 /// implement shadow inheritance.
507 ///
508 /// An element may override this method for custom behavior.
461 void parseDeclaration(Element elementElement) { 509 void parseDeclaration(Element elementElement) {
462 var template = fetchTemplate(elementElement); 510 var template = fetchTemplate(elementElement);
463 511
464 if (template != null) { 512 if (template != null) {
465 var root = shadowFromTemplate(template); 513 var root = shadowFromTemplate(template);
466 514
467 var name = elementElement.attributes['name']; 515 var name = elementElement.attributes['name'];
468 if (name == null) return; 516 if (name == null) return;
469 shadowRoots[name] = root; 517 shadowRoots[name] = root;
470 } 518 }
471 } 519 }
472 520
473 /// Return a shadow-root template (if desired), override for custom behavior. 521 /// Given a `<polymer-element>`, find an associated template (if any) to be
522 /// used for shadow-root generation.
523 ///
524 /// An element may override this method for custom behavior.
474 Element fetchTemplate(Element elementElement) => 525 Element fetchTemplate(Element elementElement) =>
475 elementElement.querySelector('template'); 526 elementElement.querySelector('template');
476 527
477 /// Utility function that stamps a `<template>` into light-dom. 528 /// Utility function that stamps a `<template>` into light-dom.
478 Node lightFromTemplate(Element template, [Node refNode]) { 529 Node lightFromTemplate(Element template, [Node refNode]) {
479 if (template == null) return null; 530 if (template == null) return null;
480 531
481 // TODO(sorvell): mark this element as an event controller so that 532 // TODO(sorvell): mark this element as an event controller so that
482 // event listeners on bound nodes inside it will be called on it. 533 // event listeners on bound nodes inside it will be called on it.
483 // Note, the expectation here is that events on all descendants 534 // Note, the expectation here is that events on all descendants
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 /// Use [MutationObserver] if you want to listen to a stream of changes. 605 /// Use [MutationObserver] if you want to listen to a stream of changes.
555 Future<List<MutationRecord>> onMutation(Node node) { 606 Future<List<MutationRecord>> onMutation(Node node) {
556 var completer = new Completer(); 607 var completer = new Completer();
557 new MutationObserver((mutations, observer) { 608 new MutationObserver((mutations, observer) {
558 observer.disconnect(); 609 observer.disconnect();
559 completer.complete(mutations); 610 completer.complete(mutations);
560 })..observe(node, childList: true, subtree: true); 611 })..observe(node, childList: true, subtree: true);
561 return completer.future; 612 return completer.future;
562 } 613 }
563 614
615 // copy attributes defined in the element declaration to the instance
616 // e.g. <polymer-element name="x-foo" tabIndex="0"> tabIndex is copied
617 // to the element instance here.
564 void copyInstanceAttributes() { 618 void copyInstanceAttributes() {
565 _element._instanceAttributes.forEach((name, value) { 619 _element._instanceAttributes.forEach((name, value) {
566 attributes.putIfAbsent(name, () => value); 620 attributes.putIfAbsent(name, () => value);
567 }); 621 });
568 } 622 }
569 623
570 void takeAttributes() { 624 void takeAttributes() {
571 if (_element._publishLC == null) return; 625 if (_element._publishLC == null) return;
572 attributes.forEach(attributeToProperty); 626 attributes.forEach(attributeToProperty);
573 } 627 }
(...skipping 26 matching lines...) Expand all
600 // install new value (has side-effects) 654 // install new value (has side-effects)
601 smoke.write(this, decl.name, newValue); 655 smoke.write(this, decl.name, newValue);
602 } 656 }
603 } 657 }
604 658
605 /// Return the published property matching name, or null. 659 /// Return the published property matching name, or null.
606 // TODO(jmesserly): should we just return Symbol here? 660 // TODO(jmesserly): should we just return Symbol here?
607 smoke.Declaration propertyForAttribute(String name) { 661 smoke.Declaration propertyForAttribute(String name) {
608 final publishLC = _element._publishLC; 662 final publishLC = _element._publishLC;
609 if (publishLC == null) return null; 663 if (publishLC == null) return null;
610 //console.log('propertyForAttribute:', name, 'matches', match);
611 return publishLC[name]; 664 return publishLC[name];
612 } 665 }
613 666
614 /// Convert representation of [value] based on [type] and [currentValue]. 667 /// Convert representation of [value] based on [type] and [currentValue].
615 Object deserializeValue(String value, Object currentValue, Type type) => 668 Object deserializeValue(String value, Object currentValue, Type type) =>
616 deserialize.deserializeValue(value, currentValue, type); 669 deserialize.deserializeValue(value, currentValue, type);
617 670
618 String serializeValue(Object value) { 671 String serializeValue(Object value) {
619 if (value == null) return null; 672 if (value == null) return null;
620 673
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 var syntax = this.syntax; 712 var syntax = this.syntax;
660 var t = templateBind(template); 713 var t = templateBind(template);
661 if (syntax == null && t.bindingDelegate == null) { 714 if (syntax == null && t.bindingDelegate == null) {
662 syntax = element.syntax; 715 syntax = element.syntax;
663 } 716 }
664 var dom = t.createInstance(this, syntax); 717 var dom = t.createInstance(this, syntax);
665 _observers.addAll(getTemplateInstanceBindings(dom)); 718 _observers.addAll(getTemplateInstanceBindings(dom));
666 return dom; 719 return dom;
667 } 720 }
668 721
722 /// Called by TemplateBinding/NodeBind to setup a binding to the given
723 /// property. It's overridden here to support property bindings in addition to
724 /// attribute bindings that are supported by default.
669 Bindable bind(String name, bindable, {bool oneTime: false}) { 725 Bindable bind(String name, bindable, {bool oneTime: false}) {
670 var decl = propertyForAttribute(name); 726 var decl = propertyForAttribute(name);
671 if (decl == null) { 727 if (decl == null) {
672 // Cannot call super.bind because template_binding is its own package 728 // Cannot call super.bind because template_binding is its own package
673 return nodeBindFallback(this).bind(name, bindable, oneTime: oneTime); 729 return nodeBindFallback(this).bind(name, bindable, oneTime: oneTime);
674 } else { 730 } else {
675 // use n-way Polymer binding 731 // use n-way Polymer binding
676 var observer = bindProperty(decl.name, bindable, oneTime: oneTime); 732 var observer = bindProperty(decl.name, bindable, oneTime: oneTime);
677 // NOTE: reflecting binding information is typically required only for 733 // NOTE: reflecting binding information is typically required only for
678 // tooling. It has a performance cost so it's opt-in in Node.bind. 734 // tooling. It has a performance cost so it's opt-in in Node.bind.
(...skipping 11 matching lines...) Expand all
690 } 746 }
691 return observer; 747 return observer;
692 } 748 }
693 } 749 }
694 750
695 _recordBinding(String name, observer) { 751 _recordBinding(String name, observer) {
696 if (bindings == null) bindings = {}; 752 if (bindings == null) bindings = {};
697 this.bindings[name] = observer; 753 this.bindings[name] = observer;
698 } 754 }
699 755
700 bindFinished() => makeElementReady(); 756 /// Called by TemplateBinding when all bindings on an element have been
757 /// executed. This signals that all element inputs have been gathered and it's
758 /// safe to ready the element, create shadow-root and start data-observation.
759 bindFinished() => _makeElementReady();
701 760
702 Map<String, Bindable> get bindings => nodeBindFallback(this).bindings; 761 Map<String, Bindable> get bindings => nodeBindFallback(this).bindings;
703 set bindings(Map value) { nodeBindFallback(this).bindings = value; } 762 set bindings(Map value) { nodeBindFallback(this).bindings = value; }
704 763
705 TemplateInstance get templateInstance => 764 TemplateInstance get templateInstance =>
706 nodeBindFallback(this).templateInstance; 765 nodeBindFallback(this).templateInstance;
707 766
708 // TODO(sorvell): unbind/unbindAll has been removed, as public api, from 767 /// Called at detached time to signal that an element's bindings should be
709 // TemplateBinding. We still need to close/dispose of observers but perhaps 768 /// cleaned up. This is done asynchronously so that users have the chance to
710 // we should choose a more explicit name. 769 /// call `cancelUnbindAll` to prevent unbinding.
711 void asyncUnbindAll() { 770 void asyncUnbindAll() {
712 if (_unbound == true) return; 771 if (_unbound == true) return;
713 _unbindLog.fine(() => '[$_name] asyncUnbindAll'); 772 _unbindLog.fine(() => '[$_name] asyncUnbindAll');
714 _unbindAllJob = scheduleJob(_unbindAllJob, unbindAll); 773 _unbindAllJob = scheduleJob(_unbindAllJob, unbindAll);
715 } 774 }
716 775
776 /// This method should rarely be used and only if `cancelUnbindAll` has been
777 /// called to prevent element unbinding. In this case, the element's bindings
778 /// will not be automatically cleaned up and it cannot be garbage collected by
779 /// by the system. If memory pressure is a concern or a large amount of
780 /// elements need to be managed in this way, `unbindAll` can be called to
781 /// deactivate the element's bindings and allow its memory to be reclaimed.
717 void unbindAll() { 782 void unbindAll() {
718 if (_unbound == true) return; 783 if (_unbound == true) return;
719 closeObservers(); 784 closeObservers();
720 closeNamedObservers(); 785 closeNamedObservers();
721 _unbound = true; 786 _unbound = true;
722 } 787 }
723 788
789 //// Call in `detached` to prevent the element from unbinding when it is
790 //// detached from the dom. The element is unbound as a cleanup step that
791 //// allows its memory to be reclaimed. If `cancelUnbindAll` is used, consider
792 /// calling `unbindAll` when the element is no longer needed. This will allow
793 /// its memory to be reclaimed.
724 void cancelUnbindAll() { 794 void cancelUnbindAll() {
725 if (_unbound == true) { 795 if (_unbound == true) {
726 _unbindLog.warning(() => 796 _unbindLog.warning(() =>
727 '[$_name] already unbound, cannot cancel unbindAll'); 797 '[$_name] already unbound, cannot cancel unbindAll');
728 return; 798 return;
729 } 799 }
730 _unbindLog.fine(() => '[$_name] cancelUnbindAll'); 800 _unbindLog.fine(() => '[$_name] cancelUnbindAll');
731 if (_unbindAllJob != null) { 801 if (_unbindAllJob != null) {
732 _unbindAllJob.stop(); 802 _unbindAllJob.stop();
733 _unbindAllJob = null; 803 _unbindAllJob = null;
734 } 804 }
735 } 805 }
736 806
737 static void _forNodeTree(Node node, void callback(Node node)) { 807 static void _forNodeTree(Node node, void callback(Node node)) {
738 if (node == null) return; 808 if (node == null) return;
739 809
740 callback(node); 810 callback(node);
741 for (var child = node.firstChild; child != null; child = child.nextNode) { 811 for (var child = node.firstChild; child != null; child = child.nextNode) {
742 _forNodeTree(child, callback); 812 _forNodeTree(child, callback);
743 } 813 }
744 } 814 }
745 815
746 /// Set up property observers. 816 /// Creates a CompoundObserver to observe property changes.
817 /// NOTE, this is only done if there are any properties in the `_observe`
818 /// object.
747 void createPropertyObserver() { 819 void createPropertyObserver() {
748 final observe = _element._observe; 820 final observe = _element._observe;
749 if (observe != null) { 821 if (observe != null) {
750 var o = _propertyObserver = new CompoundObserver(); 822 var o = _propertyObserver = new CompoundObserver();
751 // keep track of property observer so we can shut it down 823 // keep track of property observer so we can shut it down
752 _observers.add(o); 824 _observers.add(o);
753 825
754 for (var path in observe.keys) { 826 for (var path in observe.keys) {
755 o.addPath(this, path); 827 o.addPath(this, path);
756 828
757 // TODO(jmesserly): on the Polymer side it doesn't look like they 829 // TODO(jmesserly): on the Polymer side it doesn't look like they
758 // will observe arrays unless it is a length == 1 path. 830 // will observe arrays unless it is a length == 1 path.
759 observeArrayValue(path, path.getValueFrom(this), null); 831 observeArrayValue(path, path.getValueFrom(this), null);
760 } 832 }
761 } 833 }
762 } 834 }
763 835
836 /// Start observing property changes.
764 void openPropertyObserver() { 837 void openPropertyObserver() {
765 if (_propertyObserver != null) { 838 if (_propertyObserver != null) {
766 _propertyObserver.open(notifyPropertyChanges); 839 _propertyObserver.open(notifyPropertyChanges);
767 } 840 }
768 841
769 // Dart note: we need an extra listener only to continue supporting 842 // Dart note: we need an extra listener only to continue supporting
770 // @published properties that follow the old syntax until we get rid of it. 843 // @published properties that follow the old syntax until we get rid of it.
771 // This workaround has timing issues so we prefer the new, not so nice, 844 // This workaround has timing issues so we prefer the new, not so nice,
772 // syntax. 845 // syntax.
773 if (_element._publish != null) { 846 if (_element._publish != null) {
774 changes.listen(_propertyChangeWorkaround); 847 changes.listen(_propertyChangeWorkaround);
775 } 848 }
776 } 849 }
777 850
778 /// Responds to property changes on this element. 851 /// Handler for property changes; routes changes to observing methods.
852 /// Note: array valued properties are observed for array splices.
779 void notifyPropertyChanges(List newValues, Map oldValues, List paths) { 853 void notifyPropertyChanges(List newValues, Map oldValues, List paths) {
780 final observe = _element._observe; 854 final observe = _element._observe;
781 final called = new HashSet(); 855 final called = new HashSet();
782 856
783 oldValues.forEach((i, oldValue) { 857 oldValues.forEach((i, oldValue) {
784 final newValue = newValues[i]; 858 final newValue = newValues[i];
785 859
786 // Date note: we don't need any special checking for null and undefined. 860 // Date note: we don't need any special checking for null and undefined.
787 861
788 // note: paths is of form [object, path, object, path] 862 // note: paths is of form [object, path, object, path]
(...skipping 11 matching lines...) Expand all
800 // TODO(sorvell): call method with the set of values it's expecting; 874 // TODO(sorvell): call method with the set of values it's expecting;
801 // e.g. 'foo bar': 'invalidate' expects the new and old values for 875 // e.g. 'foo bar': 'invalidate' expects the new and old values for
802 // foo and bar. Currently we give only one of these and then 876 // foo and bar. Currently we give only one of these and then
803 // deliver all the arguments. 877 // deliver all the arguments.
804 smoke.invoke(this, method, 878 smoke.invoke(this, method,
805 [oldValue, newValue, newValues, oldValues, paths], adjust: true); 879 [oldValue, newValue, newValues, oldValues, paths], adjust: true);
806 } 880 }
807 }); 881 });
808 } 882 }
809 883
810 // Dart note: had to rename this to avoid colliding with 884 /// Force any pending property changes to synchronously deliver to handlers
811 // Observable.deliverChanges. Even worse, super calls aren't possible or 885 /// specified in the `observe` object.
812 // it prevents Polymer from being a mixin, so we can't override it even if 886 /// Note: normally changes are processed at microtask time.
813 // we wanted to. 887 ///
888 /// Dart note: had to rename this to avoid colliding with
Siggi Cherem (dart-lang) 2014/11/25 17:53:42 same here, remove one / - this comment is meant fo
jakemac 2014/12/01 18:42:52 Done.
889 /// Observable.deliverChanges. Even worse, super calls aren't possible or
890 /// it prevents Polymer from being a mixin, so we can't override it even if
891 /// we wanted to.
814 void deliverPropertyChanges() { 892 void deliverPropertyChanges() {
815 if (_propertyObserver != null) { 893 if (_propertyObserver != null) {
816 _propertyObserver.deliver(); 894 _propertyObserver.deliver();
817 } 895 }
818 } 896 }
819 897
820 // Dart note: this workaround is only for old-style @published properties, 898 // Dart note: this workaround is only for old-style @published properties,
821 // which have timing issues. See _bindOldStylePublishedProperty below. 899 // which have timing issues. See _bindOldStylePublishedProperty below.
822 // TODO(sigmund): deprecate this. 900 // TODO(sigmund): deprecate this.
823 void _propertyChangeWorkaround(List<ChangeRecord> records) { 901 void _propertyChangeWorkaround(List<ChangeRecord> records) {
(...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 } 1136 }
1059 1137
1060 _eventsLog.fine(() => '<<< [$_name]: dispatch $callbackOrMethod'); 1138 _eventsLog.fine(() => '<<< [$_name]: dispatch $callbackOrMethod');
1061 } 1139 }
1062 1140
1063 /// Call [methodName] method on this object with [args]. 1141 /// Call [methodName] method on this object with [args].
1064 invokeMethod(Symbol methodName, List args) => 1142 invokeMethod(Symbol methodName, List args) =>
1065 smoke.invoke(this, methodName, args, adjust: true); 1143 smoke.invoke(this, methodName, args, adjust: true);
1066 1144
1067 /// Invokes a function asynchronously. 1145 /// Invokes a function asynchronously.
1068 /// This will call `Platform.flush()` and then return a `new Timer` 1146 /// This will call `WebComponents.flush()` and then return a `new Timer`
1069 /// with the provided [method] and [timeout]. 1147 /// with the provided [method] and [timeout].
1070 /// 1148 ///
1071 /// If you would prefer to run the callback using 1149 /// If you would prefer to run the callback using
1072 /// [window.requestAnimationFrame], see the [async] method. 1150 /// [window.requestAnimationFrame], see the [async] method.
1073 /// 1151 ///
1074 /// To cancel, call [Timer.cancel] on the result of this method. 1152 /// To cancel, call [Timer.cancel] on the result of this method.
1075 Timer asyncTimer(void method(), Duration timeout) { 1153 Timer asyncTimer(void method(), Duration timeout) {
1076 // Dart note: "async" is split into 2 methods so it can have a sensible type 1154 // Dart note: "async" is split into 2 methods so it can have a sensible type
1077 // signatures. Also removed the various features that don't make sense in a 1155 // signatures. Also removed the various features that don't make sense in a
1078 // Dart world, like binding to "this" and taking arguments list. 1156 // Dart world, like binding to "this" and taking arguments list.
1079 1157
1080 // when polyfilling Object.observe, ensure changes 1158 // when polyfilling Object.observe, ensure changes
1081 // propagate before executing the async method 1159 // propagate before executing the async method
1082 scheduleMicrotask(Observable.dirtyCheck); 1160 scheduleMicrotask(Observable.dirtyCheck);
1083 _Platform.callMethod('flush'); // for polymer-js interop 1161 _Polymer.callMethod('flush'); // for polymer-js interop
Siggi Cherem (dart-lang) 2014/11/25 17:53:42 I thought this was going to call _WebComponents.fl
jakemac 2014/12/01 18:42:52 One is an alias of the other, they moved over to u
Siggi Cherem (dart-lang) 2014/12/02 01:31:26 OK. It might be worth to fix the comment then (sam
jakemac 2014/12/03 18:34:57 Done.
1084 return new Timer(timeout, method); 1162 return new Timer(timeout, method);
1085 } 1163 }
1086 1164
1087 /// Invokes a function asynchronously. 1165 /// Invokes a function asynchronously. The context of the callback function is
1088 /// This will call `Platform.flush()` and then call 1166 /// function is bound to 'this' automatically. Returns a handle which may be
1089 /// [window.requestAnimationFrame] with the provided [method] and return the 1167 /// passed to cancelAsync to cancel the asynchronous call.
1090 /// result.
1091 /// 1168 ///
1092 /// If you would prefer to run the callback after a given duration, see 1169 /// If you would prefer to run the callback after a given duration, see
1093 /// the [asyncTimer] method. 1170 /// the [asyncTimer] method.
1094 /// 1171 ///
1095 /// If you would like to cancel this, use [cancelAsync]. 1172 /// If you would like to cancel this, use [cancelAsync].
1096 int async(RequestAnimationFrameCallback method) { 1173 int async(RequestAnimationFrameCallback method) {
1097 // when polyfilling Object.observe, ensure changes 1174 // when polyfilling Object.observe, ensure changes
1098 // propagate before executing the async method 1175 // propagate before executing the async method
1099 scheduleMicrotask(Observable.dirtyCheck); 1176 scheduleMicrotask(Observable.dirtyCheck);
1100 _Platform.callMethod('flush'); // for polymer-js interop 1177 _Polymer.callMethod('flush'); // for polymer-js interop
Siggi Cherem (dart-lang) 2014/11/25 17:53:42 ditto
jakemac 2014/12/01 18:42:51 same
jakemac 2014/12/03 18:34:57 Done.
1101 return window.requestAnimationFrame(method); 1178 return window.requestAnimationFrame(method);
1102 } 1179 }
1103 1180
1104 /// Cancel an operation scenduled by [async]. This is just shorthand for: 1181 /// Cancel an operation scheduled by [async].
1105 /// window.cancelAnimationFrame(id);
1106 void cancelAsync(int id) => window.cancelAnimationFrame(id); 1182 void cancelAsync(int id) => window.cancelAnimationFrame(id);
1107 1183
1108 /// Fire a [CustomEvent] targeting [onNode], or `this` if onNode is not 1184 /// Fire a [CustomEvent] targeting [onNode], or `this` if onNode is not
1109 /// supplied. Returns the new event. 1185 /// supplied. Returns the new event.
1110 CustomEvent fire(String type, {Object detail, Node onNode, bool canBubble, 1186 CustomEvent fire(String type, {Object detail, Node onNode, bool canBubble,
1111 bool cancelable}) { 1187 bool cancelable}) {
1112 var node = onNode != null ? onNode : this; 1188 var node = onNode != null ? onNode : this;
1113 var event = new CustomEvent( 1189 var event = new CustomEvent(
1114 type, 1190 type,
1115 canBubble: canBubble != null ? canBubble : true, 1191 canBubble: canBubble != null ? canBubble : true,
(...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after
1369 final Logger _eventsLog = new Logger('polymer.events'); 1445 final Logger _eventsLog = new Logger('polymer.events');
1370 final Logger _unbindLog = new Logger('polymer.unbind'); 1446 final Logger _unbindLog = new Logger('polymer.unbind');
1371 final Logger _bindLog = new Logger('polymer.bind'); 1447 final Logger _bindLog = new Logger('polymer.bind');
1372 final Logger _watchLog = new Logger('polymer.watch'); 1448 final Logger _watchLog = new Logger('polymer.watch');
1373 final Logger _readyLog = new Logger('polymer.ready'); 1449 final Logger _readyLog = new Logger('polymer.ready');
1374 1450
1375 final Expando _eventHandledTable = new Expando<Set<Node>>(); 1451 final Expando _eventHandledTable = new Expando<Set<Node>>();
1376 1452
1377 final JsObject _PolymerGestures = js.context['PolymerGestures']; 1453 final JsObject _PolymerGestures = js.context['PolymerGestures'];
1378 1454
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698