| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * This library exports all of the commonly used functions and types for | 6 * This library exports all of the commonly used functions and types for |
| 7 * building UI's. | 7 * building UI's. |
| 8 * | 8 * |
| 9 * See this article for more information: | 9 * See this article for more information: |
| 10 * <http://www.dartlang.org/articles/dart-web-components/>. | 10 * <http://www.dartlang.org/articles/dart-web-components/>. |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 /** Annotation used to automatically register polymer elements. */ | 32 /** Annotation used to automatically register polymer elements. */ |
| 33 class CustomTag { | 33 class CustomTag { |
| 34 final String tagName; | 34 final String tagName; |
| 35 const CustomTag(this.tagName); | 35 const CustomTag(this.tagName); |
| 36 } | 36 } |
| 37 | 37 |
| 38 /** | 38 /** |
| 39 * Metadata used to label static or top-level methods that are called | 39 * Metadata used to label static or top-level methods that are called |
| 40 * automatically when loading the library of a custom element. | 40 * automatically when loading the library of a custom element. |
| 41 */ | 41 */ |
| 42 const polymerInitMethod = const _InitPolymerAnnotation(); | 42 const initMethod = const _InitMethodAnnotation(); |
| 43 | 43 |
| 44 /** | 44 /** |
| 45 * Initializes a polymer application by: setting up polling for observable | 45 * Initializes a polymer application as follows: |
| 46 * changes, initializing MDV, registering and initializing custom elements from | 46 * * set up up polling for observable changes |
| 47 * each library in [elementLibraries], and finally invoking [userMain]. | 47 * * initialize MDV |
| 48 * * for each library in [libraries], register custom elements labeled with |
| 49 * [CustomTag] and invoke the initialization method on it. |
| 48 * | 50 * |
| 49 * There are two mechanisms by which custom elements can be initialized: | 51 * The initialization on each library is either a method named `main` or |
| 50 * annotating the class that declares a custom element with [CustomTag] or | 52 * a top-level function and annotated with [initMethod]. |
| 51 * programatically registering the element in a static or top-level function and | |
| 52 * annotating that function with [polymerInitMethod]. | |
| 53 * | 53 * |
| 54 * The urls in [elementLibraries] can be absolute or relative to [srcUrl]. | 54 * The urls in [libraries] can be absolute or relative to [srcUrl]. |
| 55 */ | 55 */ |
| 56 void initPolymer(List<String> elementLibraries, void userMain(), [String srcUrl]
) { | 56 void initPolymer(List<String> libraries, [String srcUrl]) { |
| 57 wrapMicrotask(() { | 57 wrapMicrotask(() { |
| 58 // DOM events don't yet go through microtasks, so we catch those here. | 58 // DOM events don't yet go through microtasks, so we catch those here. |
| 59 new Timer.periodic(new Duration(milliseconds: 125), | 59 new Timer.periodic(new Duration(milliseconds: 125), |
| 60 (_) => performMicrotaskCheckpoint()); | 60 (_) => performMicrotaskCheckpoint()); |
| 61 | 61 |
| 62 // TODO(jmesserly): mdv should use initMdv instead of mdv.initialize. | 62 // TODO(jmesserly): mdv should use initMdv instead of mdv.initialize. |
| 63 mdv.initialize(); | 63 mdv.initialize(); |
| 64 for (var lib in elementLibraries) { | 64 for (var lib in libraries) { |
| 65 _registerPolymerElementsOf(lib, srcUrl); | 65 _loadLibrary(lib, srcUrl); |
| 66 } | 66 } |
| 67 userMain(); | |
| 68 })(); | 67 })(); |
| 69 } | 68 } |
| 70 | 69 |
| 71 /** All libraries in the current isolate. */ | 70 /** All libraries in the current isolate. */ |
| 72 final _libs = currentMirrorSystem().libraries; | 71 final _libs = currentMirrorSystem().libraries; |
| 73 | 72 |
| 74 /** | 73 /** |
| 75 * Reads the library at [uriString] (which can be an absolute URI or a relative | 74 * Reads the library at [uriString] (which can be an absolute URI or a relative |
| 76 * URI from [srcUrl]), and: | 75 * URI from [srcUrl]), and: |
| 77 * | 76 * |
| 78 * * Invokes top-level and static functions marked with the | 77 * * If present, invokes `main`. |
| 79 * [polymerInitMethod] annotation. | 78 * |
| 79 * * If present, invokes any top-level and static functions marked |
| 80 * with the [initMethod] annotation (in the order they appear). |
| 80 * | 81 * |
| 81 * * Registers any [PolymerElement] that is marked with the [CustomTag] | 82 * * Registers any [PolymerElement] that is marked with the [CustomTag] |
| 82 * annotation. | 83 * annotation. |
| 83 */ | 84 */ |
| 84 void _registerPolymerElementsOf(String uriString, [String srcUrl]) { | 85 void _loadLibrary(String uriString, [String srcUrl]) { |
| 85 var uri = Uri.parse(uriString); | 86 var uri = Uri.parse(uriString); |
| 86 if (uri.scheme == '' && srcUrl != null) { | 87 if (uri.scheme == '' && srcUrl != null) { |
| 87 uri = Uri.parse(path.normalize(path.join(path.dirname(srcUrl), uriString))); | 88 uri = Uri.parse(path.normalize(path.join(path.dirname(srcUrl), uriString))); |
| 88 } | 89 } |
| 89 var lib = _libs[uri]; | 90 var lib = _libs[uri]; |
| 90 if (lib == null) { | 91 if (lib == null) { |
| 91 print('warning: $uri library not found'); | 92 print('warning: $uri library not found'); |
| 92 return; | 93 return; |
| 93 } | 94 } |
| 94 | 95 |
| 95 // Search top-level functions marked with @polymerInitMethod | 96 // Invoke `main`, if present. |
| 97 if (lib.functions[const Symbol('main')] != null) { |
| 98 lib.invoke(const Symbol('main'), const []); |
| 99 } |
| 100 |
| 101 // Search top-level functions marked with @initMethod |
| 96 for (var f in lib.functions.values) { | 102 for (var f in lib.functions.values) { |
| 97 _maybeInvoke(lib, f); | 103 _maybeInvoke(lib, f); |
| 98 } | 104 } |
| 99 | 105 |
| 100 for (var c in lib.classes.values) { | 106 for (var c in lib.classes.values) { |
| 101 // Search for @CustomTag on classes | 107 // Search for @CustomTag on classes |
| 102 for (var m in c.metadata) { | 108 for (var m in c.metadata) { |
| 103 var meta = m.reflectee; | 109 var meta = m.reflectee; |
| 104 if (meta is CustomTag) { | 110 if (meta is CustomTag) { |
| 105 registerPolymerElement(meta.tagName, | 111 registerPolymerElement(meta.tagName, |
| 106 () => c.newInstance(const Symbol(''), const []).reflectee); | 112 () => c.newInstance(const Symbol(''), const []).reflectee); |
| 107 } | 113 } |
| 108 } | 114 } |
| 109 | 115 |
| 110 // TODO(sigmund): check also static methods marked with @polymerInitMethod. | 116 // TODO(sigmund): check also static methods marked with @initMethod. |
| 111 // This is blocked on two bugs: | 117 // This is blocked on two bugs: |
| 112 // - dartbug.com/12133 (static methods are incorrectly listed as top-level | 118 // - dartbug.com/12133 (static methods are incorrectly listed as top-level |
| 113 // in dart2js, so they end up being called twice) | 119 // in dart2js, so they end up being called twice) |
| 114 // - dartbug.com/12134 (sometimes "method.metadata" throws an exception, | 120 // - dartbug.com/12134 (sometimes "method.metadata" throws an exception, |
| 115 // we could wrap and hide those exceptions, but it's not ideal). | 121 // we could wrap and hide those exceptions, but it's not ideal). |
| 116 } | 122 } |
| 117 } | 123 } |
| 118 | 124 |
| 119 void _maybeInvoke(ObjectMirror obj, MethodMirror method) { | 125 void _maybeInvoke(ObjectMirror obj, MethodMirror method) { |
| 120 var annotationFound = false; | 126 var annotationFound = false; |
| 121 for (var meta in method.metadata) { | 127 for (var meta in method.metadata) { |
| 122 if (identical(meta.reflectee, polymerInitMethod)) { | 128 if (identical(meta.reflectee, initMethod)) { |
| 123 annotationFound = true; | 129 annotationFound = true; |
| 124 break; | 130 break; |
| 125 } | 131 } |
| 126 } | 132 } |
| 127 if (!annotationFound) return; | 133 if (!annotationFound) return; |
| 128 if (!method.isStatic) { | 134 if (!method.isStatic) { |
| 129 print("warning: methods marked with @polymerInitMethod should be static," | 135 print("warning: methods marked with @initMethod should be static," |
| 130 " ${method.simpleName} is not."); | 136 " ${method.simpleName} is not."); |
| 131 return; | 137 return; |
| 132 } | 138 } |
| 133 if (!method.parameters.where((p) => !p.isOptional).isEmpty) { | 139 if (!method.parameters.where((p) => !p.isOptional).isEmpty) { |
| 134 print("warning: methods marked with @polymerInitMethod should take no " | 140 print("warning: methods marked with @initMethod should take no " |
| 135 "arguments, ${method.simpleName} expects some."); | 141 "arguments, ${method.simpleName} expects some."); |
| 136 return; | 142 return; |
| 137 } | 143 } |
| 138 obj.invoke(method.simpleName, const []); | 144 obj.invoke(method.simpleName, const []); |
| 139 } | 145 } |
| 140 | 146 |
| 141 class _InitPolymerAnnotation { | 147 class _InitMethodAnnotation { |
| 142 const _InitPolymerAnnotation(); | 148 const _InitMethodAnnotation(); |
| 143 } | 149 } |
| OLD | NEW |