Chromium Code Reviews| Index: pkg/polymer/lib/src/instance.dart |
| diff --git a/pkg/polymer/lib/src/instance.dart b/pkg/polymer/lib/src/instance.dart |
| index dc99d48e4a653db049634b5e123a44796d6a1e37..094b5000c5b106db4919091c1f2cd08754395b3a 100644 |
| --- a/pkg/polymer/lib/src/instance.dart |
| +++ b/pkg/polymer/lib/src/instance.dart |
| @@ -363,32 +363,34 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| void attributeToProperty(String name, String value) { |
| // try to match this attribute to a property (attributes are |
| // all lower-case, so this is case-insensitive search) |
| - var property = propertyForAttribute(name); |
| - if (property == null) return; |
| + var decl = propertyForAttribute(name); |
| + if (decl == null) return; |
| // filter out 'mustached' values, these are to be |
| // replaced with bound-data and are not yet values |
| // themselves. |
| if (value == null || value.contains(Polymer.bindPattern)) return; |
| - // get original value |
| - final self = reflect(this); |
| - final currentValue = self.getField(property.simpleName).reflectee; |
| + final currentValue = smoke.read(this, decl.name); |
| // deserialize Boolean or Number values from attribute |
| - final newValue = deserializeValue(value, currentValue, |
| - _inferPropertyType(currentValue, property)); |
| + var type = decl.type; |
| + if ((type == Object || type == dynamic) && currentValue != null) { |
| + // Attempt to infer field type from the current value. |
| + type = currentValue.runtimeType; |
|
Jennifer Messerly
2014/02/20 21:15:41
Hmm, did the VM fix .runtimeType? It used to retur
Siggi Cherem (dart-lang)
2014/02/21 03:55:13
Oh, funny, I was wondering why you had that :). Ye
|
| + } |
| + final newValue = deserializeValue(value, currentValue, type); |
| // only act if the value has changed |
| if (!identical(newValue, currentValue)) { |
| // install new value (has side-effects) |
| - self.setField(property.simpleName, newValue); |
| + smoke.write(this, decl.name, newValue); |
| } |
| } |
| /** Return the published property matching name, or null. */ |
| // TODO(jmesserly): should we just return Symbol here? |
| - DeclarationMirror propertyForAttribute(String name) { |
| + smoke.Declaration propertyForAttribute(String name) { |
| final publishLC = _declaration._publishLC; |
| if (publishLC == null) return null; |
| //console.log('propertyForAttribute:', name, 'matches', match); |
| @@ -398,10 +400,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| /** |
| * Convert representation of [value] based on [type] and [currentValue]. |
| */ |
| - // TODO(jmesserly): this should probably take a ClassMirror instead of |
| - // TypeMirror, but it is currently impossible to get from a TypeMirror to a |
| - // ClassMirror. |
| - Object deserializeValue(String value, Object currentValue, TypeMirror type) => |
| + Object deserializeValue(String value, Object currentValue, Type type) => |
|
Jennifer Messerly
2014/02/20 21:15:41
lovely!
|
| deserialize.deserializeValue(value, currentValue, type); |
| String serializeValue(Object value) { |
| @@ -458,15 +457,15 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| // property changes that occur as a result of binding will be observed. |
| if (!_elementPrepared) prepareElement(); |
| - var property = propertyForAttribute(name); |
| - if (property == null) { |
| + var decl = propertyForAttribute(name); |
| + if (decl == null) { |
| // Cannot call super.bind because template_binding is its own package |
| return nodeBindFallback(this).bind(name, bindable, oneTime: oneTime); |
| } else { |
| // clean out the closets |
| unbind(name); |
| // use n-way Polymer binding |
| - var observer = bindProperty(property.simpleName, bindable); |
| + var observer = bindProperty(decl.name, bindable); |
| // reflect bound property to attribute when binding |
| // to ensure binding is not left on attribute if property |
| @@ -476,7 +475,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| // TODO(jmesserly): polymer has the path_ in their observer object, should |
| // we use that too instead of allocating it here? |
| - reflectPropertyToAttribute(new PropertyPath([property.simpleName])); |
| + reflectPropertyToAttribute(new PropertyPath([decl.name])); |
| return bindings[name] = observer; |
| } |
| } |
| @@ -598,7 +597,8 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| // observes the value if it is an array |
| observeArrayValue(path, newValue, oldValue); |
| // Dart note: JS passes "arguments", so we pass along our args. |
| - invokeMethod(method, [oldValue, newValue, newValues, oldValues, paths]); |
| + smoke.invoke(this, method, |
| + [oldValue, newValue, newValues, oldValues, paths], adjust: true); |
| } |
| }); |
| } |
| @@ -628,7 +628,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| } |
| var sub = value.listChanges.listen((changes) { |
| for (var callback in callbacks) { |
| - invokeMethod(callback, [old]); |
| + smoke.invoke(this, callback, [old], adjust: true); |
| } |
| }); |
| registerObserver('${name}__array', sub); |
| @@ -761,9 +761,16 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| if (log) _eventsLog.fine('>>> [$localName]: dispatch $callbackOrMethod'); |
| if (callbackOrMethod is Function) { |
| + int maxArgs = smoke.maxArgs(callbackOrMethod); |
| + if (maxArgs == -1) { |
| + _eventsLog.warning( |
| + 'invalid callback: expected callback of 0, 1, 2, or 3 arguments'); |
| + } |
| + args.length = maxArgs; |
| Function.apply(callbackOrMethod, args); |
| } else if (callbackOrMethod is String) { |
| - _invokeMethod(object, new Symbol(callbackOrMethod), args); |
| + smoke.invoke(object, smoke.nameToSymbol(callbackOrMethod), args, |
| + adjust: true); |
| } else { |
| _eventsLog.warning('invalid callback'); |
| } |
| @@ -799,31 +806,7 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| /** Call [methodName] method on this object with [args]. */ |
| invokeMethod(Symbol methodName, List args) => |
| - _invokeMethod(this, methodName, args); |
| - |
| - /** Call [methodName] method on [receiver] with [args]. */ |
| - static _invokeMethod(receiver, Symbol methodName, List args) { |
| - // TODO(jmesserly): use function type tests instead of mirrors for dispatch. |
| - var receiverMirror = reflect(receiver); |
| - var method = _findMethod(receiverMirror.type, methodName); |
| - if (method != null) { |
| - // This will either truncate the argument list or extend it with extra |
| - // null arguments, so it will match the signature. |
| - // TODO(sigmund): consider accepting optional arguments when we can tell |
| - // them appart from named arguments (see http://dartbug.com/11334) |
| - args.length = method.parameters.where((p) => !p.isOptional).length; |
| - } |
| - return receiverMirror.invoke(methodName, args).reflectee; |
| - } |
| - |
| - static MethodMirror _findMethod(ClassMirror type, Symbol name) { |
| - do { |
| - var member = type.declarations[name]; |
| - if (member is MethodMirror) return member; |
| - type = type.superclass; |
| - } while (type != null); |
| - return null; // unreachable |
| - } |
| + smoke.invoke(this, methodName, args, adjust: true); |
| /** |
| * Invokes a function asynchronously. |
| @@ -1002,28 +985,26 @@ abstract class Polymer implements Element, Observable, NodeBindExtension { |
| // TODO(jmesserly): our approach leads to race conditions in the bindings. |
| // See http://code.google.com/p/dart/issues/detail?id=13567 |
| class _PolymerBinding extends Bindable { |
| - final InstanceMirror _target; |
| + final Polymer _target; |
| final Symbol _property; |
| final Bindable _bindable; |
| StreamSubscription _sub; |
| Object _lastValue; |
| - _PolymerBinding(Polymer node, this._property, this._bindable) |
| - : _target = reflect(node) { |
| - |
| - _sub = node.changes.listen(_propertyValueChanged); |
| + _PolymerBinding(this._target, this._property, this._bindable) { |
| + _sub = _target.changes.listen(_propertyValueChanged); |
| _updateNode(open(_updateNode)); |
| } |
| void _updateNode(newValue) { |
| _lastValue = newValue; |
| - _target.setField(_property, newValue); |
| + smoke.write(_target, _property, newValue); |
| } |
| void _propertyValueChanged(List<ChangeRecord> records) { |
| for (var record in records) { |
| if (record is PropertyChangeRecord && record.name == _property) { |
| - final newValue = _target.getField(_property).reflectee; |
| + final newValue = smoke.read(_target, _property); |
| if (!identical(_lastValue, newValue)) { |
| this.value = newValue; |
| } |
| @@ -1047,35 +1028,6 @@ class _PolymerBinding extends Bindable { |
| bool _toBoolean(value) => null != value && false != value; |
| -TypeMirror _propertyType(DeclarationMirror property) => |
| - property is VariableMirror ? property.type |
| - : (property as MethodMirror).returnType; |
| - |
| -TypeMirror _inferPropertyType(Object value, DeclarationMirror property) { |
| - var type = _propertyType(property); |
| - if (type.qualifiedName == #dart.core.Object || |
| - type.qualifiedName == #dynamic) { |
| - // Attempt to infer field type from the default value. |
| - if (value != null) { |
| - Type t = _getCoreType(value); |
| - if (t != null) return reflectClass(t); |
| - return reflect(value).type; |
| - } |
| - } |
| - return type; |
| -} |
| - |
| -Type _getCoreType(Object value) { |
| - if (value == null) return Null; |
| - if (value is int) return int; |
| - // Avoid "is double" to prevent warning that it won't work in dart2js. |
| - if (value is num) return double; |
| - if (value is bool) return bool; |
| - if (value is String) return String; |
| - if (value is DateTime) return DateTime; |
| - return null; |
| -} |
| - |
| final Logger _observeLog = new Logger('polymer.observe'); |
| final Logger _eventsLog = new Logger('polymer.events'); |
| final Logger _unbindLog = new Logger('polymer.unbind'); |
| @@ -1156,4 +1108,4 @@ class _EventBindable extends Bindable { |
| _sub = null; |
| } |
| } |
| -} |
| +} |