Index: lib/init.dart |
diff --git a/lib/init.dart b/lib/init.dart |
index 3a56305a7fb3c4a6392c5dcf58cff7d9c52ac324..86912f56924b770912dfe6c3360508c07aaa481b 100644 |
--- a/lib/init.dart |
+++ b/lib/init.dart |
@@ -5,6 +5,7 @@ library polymer.lib.init; |
import 'dart:async'; |
import 'dart:js'; |
+import 'package:reflectable/reflectable.dart'; |
import 'package:web_components/web_components.dart'; |
import 'src/common/js_proxy.dart'; |
import 'src/common/polymer_register.dart'; |
@@ -13,27 +14,64 @@ main() => initPolymer(); |
Future initPolymer() async { |
await initWebComponents(typeFilter: [HtmlImport], initAll: false); |
- // Make sure `src/js/polymer_array_methods.html` is loaded first. |
- _setUpListMethods(); |
+ // Make sure polymer is loaded first. |
+ _setUpPropertyChanged(); |
await initWebComponents( |
typeFilter: [CustomElement, CustomElementProxy, PolymerRegister], |
initAll: true); |
} |
-void _setUpListMethods() { |
- var polymerDart = context['Polymer']['Dart']; |
- polymerDart['push'] = (List list, Iterable items) { |
- list.addAll(items.map((item) => dartValue(item))); |
- }; |
- polymerDart['pop'] = (List list) => list.removeLast(); |
- polymerDart['shift'] = (List list) => list.removeAt(0); |
- polymerDart['unshift'] = (List list, Iterable items) { |
- list.insertAll(0, items.map((item) => dartValue(item))); |
- }; |
- polymerDart['splice'] = |
- (List list, int start, int deleteCount, Iterable items) { |
- if (start < 0) start = list.length + start; |
- if (deleteCount > 0) list.removeRange(start, start + deleteCount); |
- list.insertAll(start, items.map((item) => dartValue(item))); |
+final _polymerDart = context['Polymer']['Dart']; |
+ |
+void _setUpPropertyChanged() { |
+ _polymerDart['propertyChanged'] = (instance, String path, newValue) { |
+ if (instance is List) { |
+ // We only care about `splices` for Lists. This does mean we don't support |
+ // setting special properties of custom List implementations though. |
+ if (path == 'splices') { |
+ // Only apply splices once, if multiple elements have a binding set up |
+ // for the same list then they will each get called here. |
+ var alreadyApplied = newValue['_applied']; |
+ if (alreadyApplied == true) return; |
+ newValue['_applied'] = true; |
+ |
+ var splices = newValue['indexSplices']; |
+ for (var splice in splices) { |
+ var index = splice['index']; |
+ var removed = splice['removed']; |
+ if (removed != null && removed.length > 0) { |
+ instance.removeRange(index, index + removed.length); |
+ } |
+ var addedCount = splice['addedCount']; |
+ var original = splice['object'] as JsArray; |
+ instance.insertAll(index, |
+ original.getRange(index, addedCount + index).map(dartValue)); |
+ } |
+ } else if (path == 'length') { |
+ // Ignore this case, wait for `splices`. |
+ return; |
+ } else { |
+ try { |
+ var index = int.parse(path); |
+ instance[index] = dartValue(newValue); |
+ } on FormatException catch (_) { |
+ throw 'Only `splices`, `length`, and index paths are supported for ' |
+ 'list types, found $path.'; |
+ } |
+ } |
+ } else if (instance is Map) { |
+ instance[path] = dartValue(newValue); |
+ } else { |
+ var instanceMirror = jsProxyReflectable.reflect(instance); |
+ // Catch errors for read only properties. Checking for setters using |
+ // reflection is too slow. |
+ // https://github.com/dart-lang/polymer-dart/issues/590 |
+ try { |
+ instanceMirror.invokeSetter(path, dartValue(newValue)); |
+ } on NoSuchMethodError catch (_) {} on NoSuchCapabilityError catch (_) { |
+ // TODO(jakemac): Remove once |
+ // https://github.com/dart-lang/reflectable/issues/30 is fixed. |
+ } |
+ } |
}; |
} |