| 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..f3dc5e86e27becce5afdfd415909524c945ceffa 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,59 @@ 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())]);
|
| +
|
| + var jsPolymer = new JsObject.fromBrowserObject(
|
| + document.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);
|
| +}
|
|
|