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

Unified Diff: pkg/polymer/lib/src/instance.dart

Issue 44573005: Update polymer to commit b7200854b2441a22ce89f6563963f36c50f5150d (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 2 months 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 side-by-side diff with in-line comments
Download patch
Index: pkg/polymer/lib/src/instance.dart
diff --git a/pkg/polymer/lib/src/instance.dart b/pkg/polymer/lib/src/instance.dart
index ed5d1fe17efffc0caf8f10164d7934db3246c231..cab11626ccb47121ccdc9a1f2f8873b608f428a7 100644
--- a/pkg/polymer/lib/src/instance.dart
+++ b/pkg/polymer/lib/src/instance.dart
@@ -27,7 +27,7 @@ class PublishedProperty extends ObservableProperty {
*/
abstract class Polymer implements Element, Observable, NodeBindExtension {
// Fully ported from revision:
- // https://github.com/Polymer/polymer/blob/00e2982c78fcd396adaebff3118e94029a2b9fb0
+ // https://github.com/Polymer/polymer/blob/b7200854b2441a22ce89f6563963f36c50f5150d
//
// src/boot.js (static APIs on "Polymer" object)
// src/instance/attributes.js
@@ -63,7 +63,8 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
}
/// The one syntax to rule them all.
- static final BindingDelegate _polymerSyntax = new PolymerExpressions();
+ static final BindingDelegate _polymerSyntax =
+ new _PolymerExpressionsWithEventDelegate();
static int _preparingElements = 0;
@@ -93,6 +94,8 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
bool get alwaysPrepare => false;
bool get preventDispose => false;
+ BindingDelegate syntax = _polymerSyntax;
+
/**
* Shadow roots created by [parseElement]. See [getShadowRoot].
*/
@@ -279,8 +282,6 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
void shadowRootReady(Node root, Element template) {
// locate nodes with id and store references to them in this.$ hash
marshalNodeReferences(root);
- // add local events of interest...
- addInstanceListeners(root, template);
// TODO(jmesserly): port this
// set up pointer gestures
// PointerGestures.register(root);
@@ -420,7 +421,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
* template, for example to use a different data-binding syntax.
*/
DocumentFragment instanceTemplate(Element template) =>
- templateBind(template).createInstance(this, _polymerSyntax);
+ templateBind(template).createInstance(this, syntax);
NodeBinding createBinding(String name, model, String path) =>
nodeBindFallback(this).createBinding(name, model, path);
@@ -431,7 +432,11 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
if (!_elementPrepared) prepareElement();
var property = propertyForAttribute(name);
- if (property != null) {
+ if (property == null) {
+ // Cannot call super.bind because template_binding is its own package
+ return nodeBindFallback(this).bind(name, model, path);
+ } else {
+ // clean out the closets
unbind(name);
// use n-way Polymer binding
var observer = bindProperty(property.simpleName, model, path);
@@ -442,9 +447,6 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
// https://github.com/Polymer/polymer/pull/319
reflectPropertyToAttribute(property.simpleName);
return bindings[name] = observer;
- } else {
- // Cannot call super.bind because template_binding is its own package
- return nodeBindFallback(this).bind(name, model, path);
}
}
@@ -556,7 +558,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
// TODO(jmesserly): the JS code tries to avoid calling the same method
// twice, but I don't see how that is possible.
// Dart note: JS also passes "arguments", so we pass all change records.
- invokeMethod(method, [pair.oldValue, pair.newValue, changes]);
+ invokeMethod(this, method, [pair.oldValue, pair.newValue, changes]);
}
});
}
@@ -585,7 +587,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
'$name');
}
var sub = (value as ObservableList).changes.listen((changes) {
- invokeMethod(callbackName, [old]);
+ invokeMethod(this, callbackName, [old]);
});
registerObserver('${MirrorSystem.getName(name)}__array', sub);
}
@@ -612,7 +614,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
bool unregisterObserver(String name) {
var sub = _observers.remove(name);
if (sub == null) return false;
- subl.cancel();
Jennifer Messerly 2013/10/25 22:00:41 ouch! nice catch
Siggi Cherem (dart-lang) 2013/10/26 00:02:35 dart2js warning =)
+ sub.cancel();
return true;
}
@@ -629,8 +631,8 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
*
* var myProperty;
*
- * created() {
- * super.created();
+ * ready() {
+ * super.ready();
* bindProperty(#myProperty, this, 'myModel.path.to.otherProp');
* }
*/
@@ -678,19 +680,6 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
addNodeListeners(this, events.keys, hostEventListener);
}
- /** Attach event listeners inside a shadow [root]. */
- void addInstanceListeners(Node root, Element template) {
- var templateDelegates = _declaration._templateDelegates;
- if (templateDelegates == null) return;
- var events = templateDelegates[template];
- if (events == null) return;
-
- if (_eventsLog.isLoggable(Level.FINE)) {
- _eventsLog.fine('[$localName] addInstanceListeners: $events');
- }
- addNodeListeners(root, events, instanceEventListener);
- }
-
void addNodeListeners(Node node, Iterable<String> events,
void listener(Event e)) {
@@ -719,7 +708,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
var detail = event is CustomEvent ?
(event as CustomEvent).detail : null;
// TODO(jmesserly): cache the symbols?
- dispatchMethod(new Symbol(h), [event, detail, this]);
+ dispatchMethod(this, h, [event, detail, this]);
}
if (log) {
@@ -730,23 +719,32 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
String findEventDelegate(Event event) =>
_declaration._eventDelegates[_eventNameFromType(event.type)];
- /** Call [methodName] method on [this] with [args], if the method exists. */
- // TODO(jmesserly): I removed the [node] argument as it was unused. Reconcile.
- void dispatchMethod(Symbol methodName, List args) {
+ /**
+ * Calls [methodOrCallback] with [args] if it is a closure, otherwise, treat
+ * it as a method name in [object], and invoke it.
+ */
+ void dispatchMethod(object, callbackOrMethod, List args) {
bool log = _eventsLog.isLoggable(Level.FINE);
- if (log) _eventsLog.fine('>>> [$localName]: dispatch $methodName');
+ if (log) _eventsLog.fine('>>> [$localName]: dispatch $callbackOrMethod');
- invokeMethod(methodName, args);
+ if (callbackOrMethod is Function) {
+ Function.apply(callbackOrMethod, args);
+ } else if (callbackOrMethod is String) {
+ invokeMethod(object, new Symbol(callbackOrMethod), args);
+ } else {
+ _eventsLog.warning('invalid callback');
+ }
- if (log) _eventsLog.info('<<< [$localName]: dispatch $methodName');
+ if (log) _eventsLog.info('<<< [$localName]: dispatch $callbackOrMethod');
}
- invokeMethod(Symbol methodName, List args) {
+ /** Call [methodName] method on [receiver] with [args]. */
+ static invokeMethod(receiver, Symbol methodName, List args) {
Jennifer Messerly 2013/10/25 22:00:41 fyi -- this is an instance method in Polymer: htt
Siggi Cherem (dart-lang) 2013/10/26 00:02:35 Done.
// TODO(sigmund): consider making callbacks list all arguments
// explicitly. Unless VM mirrors are optimized first, this will be expensive
// once custom elements extend directly from Element (see issue 11108).
- var self = reflect(this);
- var method = self.type.methods[methodName];
+ var receiverMirror = reflect(receiver);
+ var method = receiverMirror.type.methods[methodName];
if (method != null) {
// This will either truncate the argument list or extend it with extra
// null arguments, so it will match the signature.
@@ -754,125 +752,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension {
// them appart from named arguments (see http://dartbug.com/11334)
args.length = method.parameters.where((p) => !p.isOptional).length;
}
- return self.invoke(methodName, args).reflectee;
- }
-
- void instanceEventListener(Event event) {
- _listenLocal(this, event);
- }
-
- // TODO(sjmiles): much of the below privatized only because of the vague
- // notion this code is too fiddly and we need to revisit the core feature
- void _listenLocal(Polymer host, Event event) {
Jennifer Messerly 2013/10/25 22:00:41 yay! so much code gone :)
- // TODO(jmesserly): do we need this check? It was using cancelBubble, see:
- // https://github.com/Polymer/polymer/issues/292
- if (!event.bubbles) return;
-
- bool log = _eventsLog.isLoggable(Level.FINE);
- if (log) _eventsLog.fine('>>> [$localName]: listenLocal [${event.type}]');
-
- final eventOn = '$_EVENT_PREFIX${_eventNameFromType(event.type)}';
- if (event.path == null) {
- _listenLocalNoEventPath(host, event, eventOn);
- } else {
- _listenLocalEventPath(host, event, eventOn);
- }
-
- if (log) _eventsLog.fine('<<< [$localName]: listenLocal [${event.type}]');
- }
-
- static void _listenLocalEventPath(Polymer host, Event event, String eventOn) {
- var c = null;
- for (var target in event.path) {
- // if we hit host, stop
- if (identical(target, host)) return;
-
- // find a controller for the target, unless we already found `host`
- // as a controller
- c = identical(c, host) ? c : _findController(target);
-
- // if we have a controller, dispatch the event, and stop if the handler
- // returns true
- if (c != null && _handleEvent(c, target, event, eventOn)) {
- return;
- }
- }
- }
-
- // TODO(sorvell): remove when ShadowDOM polyfill supports event path.
- // Note that _findController will not return the expected controller when the
- // event target is a distributed node. This is because we cannot traverse
- // from a composed node to a node in shadowRoot.
- // This will be addressed via an event path api
- // https://www.w3.org/Bugs/Public/show_bug.cgi?id=21066
- static void _listenLocalNoEventPath(Polymer host, Event event,
- String eventOn) {
-
- if (_eventsLog.isLoggable(Level.FINE)) {
- _eventsLog.fine('event.path() not supported for ${event.type}');
- }
-
- var target = event.target;
- var c = null;
- // if we hit dirt or host, stop
- while (target != null && target != host) {
- // find a controller for target `t`, unless we already found `host`
- // as a controller
- c = identical(c, host) ? c : _findController(target);
-
- // if we have a controller, dispatch the event, return 'true' if
- // handler returns true
- if (c != null && _handleEvent(c, target, event, eventOn)) {
- return;
- }
- target = target.parent;
- }
- }
-
- // TODO(jmesserly): this won't find the correct host unless the ShadowRoot
- // was created on a PolymerElement.
- static Polymer _findController(Node node) {
- while (node.parentNode != null) {
- node = node.parentNode;
- }
- return _shadowHost[node];
- }
-
- static bool _handleEvent(Polymer ctrlr, Node node, Event event,
- String eventOn) {
-
- // Note: local events are listened only in the shadow root. This dynamic
- // lookup is used to distinguish determine whether the target actually has a
- // listener, and if so, to determine lazily what's the target method.
- var name = node is Element ? (node as Element).attributes[eventOn] : null;
- if (name != null && _handleIfNotHandled(node, event)) {
- if (_eventsLog.isLoggable(Level.FINE)) {
- _eventsLog.fine('[${ctrlr.localName}] found handler name [$name]');
- }
- var detail = event is CustomEvent ?
- (event as CustomEvent).detail : null;
-
- if (node != null) {
- // TODO(jmesserly): cache symbols?
- ctrlr.dispatchMethod(new Symbol(name), [event, detail, node]);
- }
- }
-
- // TODO(jmesserly): do we need this? It was using cancelBubble, see:
- // https://github.com/Polymer/polymer/issues/292
- return !event.bubbles;
- }
-
- // TODO(jmesserly): I don't understand this bit. It seems to be a duplicate
- // delivery prevention mechanism?
- static bool _handleIfNotHandled(Node node, Event event) {
- var list = _eventHandledTable[event];
- if (list == null) _eventHandledTable[event] = list = new Set<Node>();
- if (!list.contains(node)) {
- list.add(node);
- return true;
- }
- return false;
+ return receiverMirror.invoke(methodName, args).reflectee;
}
/**
@@ -1145,3 +1025,61 @@ class _PropertyValue {
Object oldValue, newValue;
_PropertyValue(this.oldValue);
}
+
+// TODO(sorvell): we're patching the syntax while evaluating
+// event bindings. we'll move this to a better spot when that's done
+class _PolymerExpressionsWithEventDelegate extends PolymerExpressions {
Jennifer Messerly 2013/10/25 22:00:41 I wonder if we should make this functionality avai
Siggi Cherem (dart-lang) 2013/10/26 00:02:35 Good idea, done.
+ /**
+ * Bind events via attributes of the form `on-eventName`. This method hooks
+ * into the model syntax and does adds event listeners as needed. By default,
+ * binding paths are always method names on the root model, the custom element
+ * in which the node exists. Adding a '@' in the path directs the event
+ * binding to use the model path as the event listener. In both cases, the
+ * actual listener is attached to a generic method which evaluates the bound
+ * path at event execution time.
+ */
+ // from src/instance/event.js#prepareBinding
+ // Dart note: template_binding doesn't have the notion of a delegateBinding
+ // function, so we implement this by overriding getBinding instead.
+ getBinding(model, String path, name, node) {
+ // if lhs an event prefix,
+ if (name is! String || !_hasEventPrefix(name)) {
+ return super.getBinding(model, path, name, node);
+ }
+
+ // provide an event-binding callback.
+ // return (model, name, node) {
+ if (_eventsLog.isLoggable(Level.FINE)) {
+ _eventsLog.fine('event: [${node.localName}].$name => '
+ '[${model.localName}].$path())');
+ }
+ var eventName = _removeEventPrefix(name);
+ // TODO(sigmund): polymer.js dropped event translations. reconcile?
+ var translated = _eventTranslations[eventName];
+ eventName = translated != null ? translated : eventName;
+ return node.on[eventName].listen((event) {
+ var ctrlr = _findController(node);
+ if (ctrlr is! Polymer) return;
Jennifer Messerly 2013/10/25 22:00:41 fyi -- _findController should not return something
+ var obj = ctrlr;
+ var method = path;
+ if (path[0] == '@') {
+ obj = model;
+ // Dart note: using getBinding gets us the result of evaluating the
+ // original path (without the @) as a normal expression.
+ method = super.getBinding(model, path.substring(1), name, node).value;
+ }
+ var detail = event is CustomEvent ?
+ (event as CustomEvent).detail : null;
+ ctrlr.dispatchMethod(obj, method, [event, detail, node]);
+ });
+ }
+
+ // TODO(jmesserly): this won't find the correct host unless the ShadowRoot
+ // was created on a PolymerElement.
+ static Polymer _findController(Node node) {
+ while (node.parentNode != null) {
+ node = node.parentNode;
+ }
+ return _shadowHost[node];
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698