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

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

Powered by Google App Engine
This is Rietveld 408576698