Chromium Code Reviews| Index: pkg/polymer/lib/src/loader.dart |
| diff --git a/pkg/polymer/lib/src/loader.dart b/pkg/polymer/lib/src/loader.dart |
| index e6f17f5fbb3c1983a10e60a8bcd5fd9b5a44f7e1..d7c29b2a87b4da3f564f07b7b062aa559010d74e 100644 |
| --- a/pkg/polymer/lib/src/loader.dart |
| +++ b/pkg/polymer/lib/src/loader.dart |
| @@ -46,20 +46,12 @@ Zone initPolymer() { |
| Zone initPolymerOptimized() { |
| // TODO(sigmund): refactor this so we can replace it by codegen. |
| smoke.useMirrors(); |
| - // TODO(jmesserly): there is some code in src/declaration/polymer-element.js, |
| - // git version 37eea00e13b9f86ab21c85a955585e8e4237e3d2, right before |
| - // it registers polymer-element, which uses Platform.deliverDeclarations to |
| - // coordinate with HTML Imports. I don't think we need it so skipping. |
| - document.register(PolymerDeclaration._TAG, PolymerDeclaration); |
| + _hookJsPolymer(); |
| for (var initializer in _initializers) { |
| initializer(); |
| } |
| - // Run this after user code so they can add to Polymer.veiledElements |
| - _preventFlashOfUnstyledContent(); |
| - |
| - customElementsReady.then((_) => Polymer._ready.complete()); |
| return Zone.current; |
| } |
| @@ -188,15 +180,14 @@ void _loadLibrary(String uriString, List<Function> initializers) { |
| _addInitMethod(lib, f, initializers); |
| } |
| - for (var c in lib.declarations.values.where((d) => d is ClassMirror)) { |
| - // Search for @CustomTag on classes |
| - for (var m in c.metadata) { |
| - var meta = m.reflectee; |
| - if (meta is CustomTag) { |
| - initializers.add(() => Polymer.register(meta.tagName, c.reflectedType)); |
| - } |
| - } |
| + // Dart note: we don't get back @CustomTags in a reliable order from mirrors, |
| + // at least on Dart VM. So we need to sort them so base classes are registered |
| + // first, which ensures that document.register will work correctly for a |
| + // set of types within in the same library. |
| + var customTags = new LinkedHashMap<Type, Function>(); |
| + for (var c in lib.declarations.values.where((d) => d is ClassMirror)) { |
| + _loadCustomTags(lib, c, customTags); |
| // TODO(sigmund): check also static methods marked with @initMethod. |
| // This is blocked on two bugs: |
| // - dartbug.com/12133 (static methods are incorrectly listed as top-level |
| @@ -204,6 +195,38 @@ void _loadLibrary(String uriString, List<Function> initializers) { |
| // - dartbug.com/12134 (sometimes "method.metadata" throws an exception, |
| // we could wrap and hide those exceptions, but it's not ideal). |
| } |
| + |
| + initializers.addAll(customTags.values); |
| +} |
| + |
| +void _loadCustomTags(LibraryMirror lib, ClassMirror cls, |
| + LinkedHashMap registerFns) { |
| + if (cls == null || cls.reflectedType == HtmlElement) return; |
| + |
| + // Register superclass first. |
| + _loadCustomTags(lib, cls.superclass, registerFns); |
| + |
| + if (cls.owner != lib) { |
| + // Don't register classes from different libraries. |
| + // TODO(jmesserly): @CustomTag does not currently respect re-export, because |
| + // LibraryMirror.declarations doesn't include these. |
| + return; |
| + } |
| + |
| + var meta = _getCustomTagMetadata(cls); |
| + if (meta == null) return; |
| + |
| + registerFns.putIfAbsent(cls.reflectedType, () => |
| + () => Polymer.register(meta.tagName, cls.reflectedType)); |
| +} |
| + |
| +/// Search for @CustomTag on a classemirror |
| +CustomTag _getCustomTagMetadata(ClassMirror c) { |
| + for (var m in c.metadata) { |
| + var meta = m.reflectee; |
| + if (meta is CustomTag) return meta; |
| + } |
| + return null; |
| } |
| void _addInitMethod(ObjectMirror obj, MethodMirror method, |
| @@ -232,3 +255,63 @@ void _addInitMethod(ObjectMirror obj, MethodMirror method, |
| class _InitMethodAnnotation { |
| const _InitMethodAnnotation(); |
| } |
| + |
| +/// To ensure Dart can interoperate with polymer-element registered by |
| +/// polymer.js, we need to be able to execute Dart code if we are registering |
| +/// a Dart class for that element. We trigger Dart logic by patching |
| +/// polymer-element's register function and: |
| +/// |
| +/// * if it has a Dart class, run PolymerDeclaration's register. |
| +/// * otherwise it is a JS prototype, run polymer-element's normal register. |
| +void _hookJsPolymer() { |
| + var polymerJs = js.context['Polymer']; |
| + if (polymerJs == null) { |
| + throw new StateError('polymer.js must be loaded before polymer.dart, please' |
| + ' add <link rel="import" href="packages/polymer/polymer.html"> to your' |
| + ' <head> before any Dart scripts. Alternatively you can get a different' |
| + ' version of polymer.js by following the instructions at' |
| + ' http://www.polymer-project.org; if you do that be sure to include' |
| + ' the platform polyfills.'); |
| + } |
| + |
| + // TODO(jmesserly): dart:js appears to not callback in the correct zone: |
| + // https://code.google.com/p/dart/issues/detail?id=17301 |
| + var zone = Zone.current; |
| + |
| + polymerJs.callMethod('whenPolymerReady', |
| + [zone.bindCallback(() => Polymer._ready.complete())]); |
| + |
| + // Note: we need to call createElement through JavaScript to get the right |
| + // JavaScript prototype. |
| + // TODO(jmesserly): what's going on here? Are we getting a strange mix of |
|
Siggi Cherem (dart-lang)
2014/03/06 18:18:08
not sure I understand the TODO, what does this app
Jennifer Messerly
2014/03/06 21:05:08
Well, at the time I didn't understand the problem
|
| + // polyfilled things in JS and native in Dart? |
| + var jsPolymer = new JsObject.fromBrowserObject(document) |
| + .callMethod('createElement', ['polymer-element']); |
| + |
| + var proto = js.context['Object'].callMethod('getPrototypeOf', [jsPolymer]); |
| + if (proto is Node) { |
| + proto = new JsObject.fromBrowserObject(proto); |
| + } |
| + |
| + JsFunction originalRegister = proto['register']; |
| + if (originalRegister == null) { |
| + throw new StateError('polymer.js must expose "register" function on ' |
| + 'polymer-element to enable polymer.dart to interoperate.'); |
| + } |
| + |
| + registerDart(jsElem, String name, String extendee) { |
| + // By the time we get here, we'll know for sure if it is a Dart object |
| + // or not, because polymer-element will wait for us to notify that |
| + // the @CustomTag was found. |
| + final type = _getRegisteredType(name); |
| + if (type != null) { |
| + final extendsDecl = _getDeclaration(extendee); |
| + return zone.run(() => |
| + new PolymerDeclaration(jsElem, name, type, extendsDecl).register()); |
| + } |
| + // It's a JavaScript polymer element, fall back to the original register. |
| + return originalRegister.apply([name, extendee], thisArg: jsElem); |
| + } |
| + |
| + proto['register'] = new JsFunction.withThis(registerDart); |
|
Siggi Cherem (dart-lang)
2014/03/06 18:18:08
wow -- I knew you were going to do this, was just
Jennifer Messerly
2014/03/06 21:05:08
Yeah, it's kinda neat we can do it. It's a lot cle
|
| +} |