| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 part of polymer; | 5 part of polymer; |
| 6 | 6 |
| 7 /** Annotation used to automatically register polymer elements. */ | 7 /** Annotation used to automatically register polymer elements. */ |
| 8 class CustomTag { | 8 class CustomTag { |
| 9 final String tagName; | 9 final String tagName; |
| 10 const CustomTag(this.tagName); | 10 const CustomTag(this.tagName); |
| 11 } | 11 } |
| 12 | 12 |
| 13 /** | 13 /** |
| 14 * Metadata used to label static or top-level methods that are called | 14 * Metadata used to label static or top-level methods that are called |
| 15 * automatically when loading the library of a custom element. | 15 * automatically when loading the library of a custom element. |
| 16 */ | 16 */ |
| 17 const initMethod = const _InitMethodAnnotation(); | 17 const initMethod = const _InitMethodAnnotation(); |
| 18 | 18 |
| 19 /** | 19 /** |
| 20 * Initializes a polymer application as follows: | 20 * Initializes a polymer application as follows: |
| 21 * * set up up polling for observable changes | 21 * * set up up polling for observable changes |
| 22 * * initialize MDV | 22 * * initialize Model-Driven Views |
| 23 * * for each library in [libraries], register custom elements labeled with | 23 * * Include some style to prevent flash of unstyled content (FOUC) |
| 24 * [CustomTag] and invoke the initialization method on it. | 24 * * for each library in [libraries], register custom elements labeled with |
| 25 * [CustomTag] and invoke the initialization method on it. If [libraries] |
| 26 * is null, first find all libraries that need to be loaded by scanning for |
| 27 * HTML imports in the main document. |
| 25 * | 28 * |
| 26 * The initialization on each library is either a method named `main` or | 29 * The initialization on each library is a top-level function and annotated with |
| 27 * a top-level function and annotated with [initMethod]. | 30 * [initMethod]. |
| 28 * | 31 * |
| 29 * The urls in [libraries] can be absolute or relative to [srcUrl]. | 32 * The urls in [libraries] can be absolute or relative to |
| 33 * `currentMirrorSystem().isolate.rootLibrary.uri`. |
| 30 */ | 34 */ |
| 31 void initPolymer(List<String> libraries, [String srcUrl]) { | 35 void initPolymer([List<String> libraries]) { |
| 32 runMicrotask(() { | 36 runMicrotask(() { |
| 33 // DOM events don't yet go through microtasks, so we catch those here. | 37 // DOM events don't yet go through microtasks, so we catch those here. |
| 34 new Timer.periodic(new Duration(milliseconds: 125), | 38 new Timer.periodic(new Duration(milliseconds: 125), |
| 35 (_) => performMicrotaskCheckpoint()); | 39 (_) => performMicrotaskCheckpoint()); |
| 36 | 40 |
| 41 preventFlashOfUnstyledContent(); |
| 42 |
| 37 // TODO(jmesserly): mdv should use initMdv instead of mdv.initialize. | 43 // TODO(jmesserly): mdv should use initMdv instead of mdv.initialize. |
| 38 mdv.initialize(); | 44 mdv.initialize(); |
| 39 document.register(PolymerDeclaration._TAG, PolymerDeclaration); | 45 document.register(PolymerDeclaration._TAG, PolymerDeclaration); |
| 40 | 46 |
| 41 for (var lib in libraries) { | 47 // Note: we synchronously load all libraries because the script invoking |
| 42 _loadLibrary(lib, srcUrl); | 48 // this is run after all HTML imports are resolved. |
| 49 if (libraries == null) { |
| 50 libraries = _discoverScripts(document, window.location.href); |
| 43 } | 51 } |
| 52 _loadLibraries(libraries); |
| 53 }); |
| 54 } |
| 44 | 55 |
| 45 Polymer._ready.complete(); | 56 void _loadLibraries(libraries) { |
| 57 for (var lib in libraries) { |
| 58 _loadLibrary(lib); |
| 59 } |
| 60 Polymer._ready.complete(); |
| 61 } |
| 46 | 62 |
| 47 // TODO(sigmund): move to boot.dart once it's ready. | 63 /** |
| 48 document.body.style.transition = 'opacity 0.3s'; | 64 * Walks the HTML import structure to discover all script tags that are |
| 49 document.body.style.opacity = '1'; | 65 * implicitly loaded. |
| 50 }); | 66 */ |
| 67 List<String> _discoverScripts(Document doc, String baseUri, |
| 68 [Set<Document> seen, List<String> scripts]) { |
| 69 if (seen == null) seen = new Set<Document>(); |
| 70 if (scripts == null) scripts = <String>[]; |
| 71 if (seen.contains(doc)) return scripts; |
| 72 seen.add(doc); |
| 73 |
| 74 var inlinedScriptCount = 0; |
| 75 for (var node in doc.queryAll('script,link[rel="import"]')) { |
| 76 if (node is LinkElement) { |
| 77 _discoverScripts(node.import, node.href, seen, scripts); |
| 78 } else if (node is ScriptElement && node.type == 'application/dart') { |
| 79 var url = node.src; |
| 80 if (url != '') { |
| 81 // TODO(sigmund): consider either normalizing package: urls or add a |
| 82 // warning to let users know about cannonicalization issues. |
| 83 scripts.add(url); |
| 84 } else { |
| 85 // We generate a unique identifier for inlined scripts which we later |
| 86 // translate to the unique identifiers used by Dartium. Dartium uses |
| 87 // line/column number information which we can't compute here. |
| 88 scripts.add('$baseUri:$inlinedScriptCount'); |
| 89 inlinedScriptCount++; |
| 90 } |
| 91 } |
| 92 } |
| 93 return scripts; |
| 51 } | 94 } |
| 52 | 95 |
| 53 /** All libraries in the current isolate. */ | 96 /** All libraries in the current isolate. */ |
| 54 final _libs = currentMirrorSystem().libraries; | 97 final _libs = currentMirrorSystem().libraries; |
| 55 | 98 |
| 99 // TODO(sigmund): explore other (cheaper) ways to resolve URIs relative to the |
| 100 // root library (see dartbug.com/12612) |
| 101 final _rootUri = currentMirrorSystem().isolate.rootLibrary.uri; |
| 102 |
| 103 /** Regex that matches urls used to represent inlined scripts. */ |
| 104 final RegExp _inlineScriptRegExp = new RegExp('\(.*\.html.*\):\([0-9]\+\)'); |
| 105 |
| 106 /** |
| 107 * Map URLs fabricated by polymer to URLs fabricated by Dartium to represent |
| 108 * inlined scripts. Polymer uses baseUri:script#, Dartium uses baseUri:line# |
| 109 */ |
| 110 // TODO(sigmund): figure out if we can generate the same URL and expose it. |
| 111 final Map<Uri, List<Uri>> _inlinedScriptMapping = () { |
| 112 var map = {}; |
| 113 for (var uri in _libs.keys) { |
| 114 var uriString = uri.toString(); |
| 115 var match = _inlineScriptRegExp.firstMatch(uriString); |
| 116 if (match == null) continue; |
| 117 var baseUri = Uri.parse(match.group(1)); |
| 118 if (map[baseUri] == null) map[baseUri] = []; |
| 119 map[baseUri].add(uri); |
| 120 } |
| 121 return map; |
| 122 }(); |
| 123 |
| 124 /** Returns a new Uri that replaces [path] in [uri]. */ |
| 125 Uri _replacePath(Uri uri, String path) { |
| 126 return new Uri(scheme: uri.scheme, host: uri.host, port: uri.port, |
| 127 path: path, query: uri.query, fragment: uri.fragment); |
| 128 } |
| 129 |
| 130 /** Returns the Uri in [href] without query parameters or fragments. */ |
| 131 String _baseUri(String href) { |
| 132 var uri = Uri.parse(window.location.href); |
| 133 var trimUri = new Uri(scheme: uri.scheme, host: uri.host, |
| 134 port: uri.port, path: uri.path); |
| 135 return trimUri.toString(); |
| 136 } |
| 137 |
| 56 /** | 138 /** |
| 57 * Reads the library at [uriString] (which can be an absolute URI or a relative | 139 * Reads the library at [uriString] (which can be an absolute URI or a relative |
| 58 * URI from [srcUrl]), and: | 140 * URI from the root library), and: |
| 59 * | |
| 60 * * If present, invokes `main`. | |
| 61 * | 141 * |
| 62 * * If present, invokes any top-level and static functions marked | 142 * * If present, invokes any top-level and static functions marked |
| 63 * with the [initMethod] annotation (in the order they appear). | 143 * with the [initMethod] annotation (in the order they appear). |
| 64 * | 144 * |
| 65 * * Registers any [PolymerElement] that is marked with the [CustomTag] | 145 * * Registers any [PolymerElement] that is marked with the [CustomTag] |
| 66 * annotation. | 146 * annotation. |
| 67 */ | 147 */ |
| 68 void _loadLibrary(String uriString, [String srcUrl]) { | 148 void _loadLibrary(String uriString) { |
| 69 var uri = Uri.parse(uriString); | 149 var uri = _rootUri.resolve(uriString); |
| 70 if (uri.scheme == '' && srcUrl != null) { | 150 var lib; |
| 71 uri = Uri.parse(path.normalize(path.join(path.dirname(srcUrl), uriString))); | 151 var match = _inlineScriptRegExp.firstMatch(uriString); |
| 152 if (match != null) { |
| 153 var baseUri = Uri.parse(match.group(1)); |
| 154 var list = _inlinedScriptMapping[baseUri]; |
| 155 var pos = int.parse(match.group(2), onError: (_) => -1); |
| 156 if (list != null && pos >= 0 && pos < list.length && list[pos] != null) { |
| 157 lib = _libs[list[pos]]; |
| 158 } |
| 159 } else { |
| 160 lib = _libs[uri]; |
| 72 } | 161 } |
| 73 var lib = _libs[uri]; | |
| 74 if (lib == null) { | 162 if (lib == null) { |
| 75 print('warning: $uri library not found'); | 163 print('warning: $uri library not found'); |
| 76 return; | 164 return; |
| 77 } | 165 } |
| 78 | 166 |
| 79 // Invoke `main`, if present. | |
| 80 if (lib.functions[#main] != null) { | |
| 81 lib.invoke(#main, const []); | |
| 82 } | |
| 83 | |
| 84 // Search top-level functions marked with @initMethod | 167 // Search top-level functions marked with @initMethod |
| 85 for (var f in lib.functions.values) { | 168 for (var f in lib.functions.values) { |
| 86 _maybeInvoke(lib, f); | 169 _maybeInvoke(lib, f); |
| 87 } | 170 } |
| 88 | 171 |
| 89 for (var c in lib.classes.values) { | 172 for (var c in lib.classes.values) { |
| 90 // Search for @CustomTag on classes | 173 // Search for @CustomTag on classes |
| 91 for (var m in c.metadata) { | 174 for (var m in c.metadata) { |
| 92 var meta = m.reflectee; | 175 var meta = m.reflectee; |
| 93 if (meta is CustomTag) { | 176 if (meta is CustomTag) { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 122 print("warning: methods marked with @initMethod should take no " | 205 print("warning: methods marked with @initMethod should take no " |
| 123 "arguments, ${method.simpleName} expects some."); | 206 "arguments, ${method.simpleName} expects some."); |
| 124 return; | 207 return; |
| 125 } | 208 } |
| 126 obj.invoke(method.simpleName, const []); | 209 obj.invoke(method.simpleName, const []); |
| 127 } | 210 } |
| 128 | 211 |
| 129 class _InitMethodAnnotation { | 212 class _InitMethodAnnotation { |
| 130 const _InitMethodAnnotation(); | 213 const _InitMethodAnnotation(); |
| 131 } | 214 } |
| OLD | NEW |