| Index: pkg/polymer/lib/src/loader.dart
|
| diff --git a/pkg/polymer/lib/src/loader.dart b/pkg/polymer/lib/src/loader.dart
|
| index cdc223bb4c08cd2bd65d23491e7672fe704489e3..c2e2f55a290e5f629eb0828f2f56f7ca7619a505 100644
|
| --- a/pkg/polymer/lib/src/loader.dart
|
| +++ b/pkg/polymer/lib/src/loader.dart
|
| @@ -19,45 +19,125 @@ const initMethod = const _InitMethodAnnotation();
|
| /**
|
| * Initializes a polymer application as follows:
|
| * * set up up polling for observable changes
|
| - * * initialize MDV
|
| - * * for each library in [libraries], register custom elements labeled with
|
| - * [CustomTag] and invoke the initialization method on it.
|
| + * * initialize Model-Driven Views
|
| + * * Include some style to prevent flash of unstyled content (FOUC)
|
| + * * for each library in [libraries], register custom elements labeled with
|
| + * [CustomTag] and invoke the initialization method on it. If [libraries]
|
| + * is null, first find all libraries that need to be loaded by scanning for
|
| + * HTML imports in the main document.
|
| *
|
| - * The initialization on each library is either a method named `main` or
|
| - * a top-level function and annotated with [initMethod].
|
| + * The initialization on each library is a top-level function and annotated with
|
| + * [initMethod].
|
| *
|
| - * The urls in [libraries] can be absolute or relative to [srcUrl].
|
| + * The urls in [libraries] can be absolute or relative to
|
| + * `currentMirrorSystem().isolate.rootLibrary.uri`.
|
| */
|
| -void initPolymer(List<String> libraries, [String srcUrl]) {
|
| +void initPolymer([List<String> libraries]) {
|
| runMicrotask(() {
|
| // DOM events don't yet go through microtasks, so we catch those here.
|
| new Timer.periodic(new Duration(milliseconds: 125),
|
| (_) => performMicrotaskCheckpoint());
|
|
|
| + preventFlashOfUnstyledContent();
|
| +
|
| // TODO(jmesserly): mdv should use initMdv instead of mdv.initialize.
|
| mdv.initialize();
|
| document.register(PolymerDeclaration._TAG, PolymerDeclaration);
|
|
|
| - for (var lib in libraries) {
|
| - _loadLibrary(lib, srcUrl);
|
| + // Note: we synchronously load all libraries because the script invoking
|
| + // this is run after all HTML imports are resolved.
|
| + if (libraries == null) {
|
| + libraries = _discoverScripts(document, window.location.href);
|
| }
|
| + _loadLibraries(libraries);
|
| + });
|
| +}
|
|
|
| - Polymer._ready.complete();
|
| +void _loadLibraries(libraries) {
|
| + for (var lib in libraries) {
|
| + _loadLibrary(lib);
|
| + }
|
| + Polymer._ready.complete();
|
| +}
|
|
|
| - // TODO(sigmund): move to boot.dart once it's ready.
|
| - document.body.style.transition = 'opacity 0.3s';
|
| - document.body.style.opacity = '1';
|
| - });
|
| +/**
|
| + * Walks the HTML import structure to discover all script tags that are
|
| + * implicitly loaded.
|
| + */
|
| +List<String> _discoverScripts(Document doc, String baseUri,
|
| + [Set<Document> seen, List<String> scripts]) {
|
| + if (seen == null) seen = new Set<Document>();
|
| + if (scripts == null) scripts = <String>[];
|
| + if (seen.contains(doc)) return scripts;
|
| + seen.add(doc);
|
| +
|
| + var inlinedScriptCount = 0;
|
| + for (var node in doc.queryAll('script,link[rel="import"]')) {
|
| + if (node is LinkElement) {
|
| + _discoverScripts(node.import, node.href, seen, scripts);
|
| + } else if (node is ScriptElement && node.type == 'application/dart') {
|
| + var url = node.src;
|
| + if (url != '') {
|
| + // TODO(sigmund): consider either normalizing package: urls or add a
|
| + // warning to let users know about cannonicalization issues.
|
| + scripts.add(url);
|
| + } else {
|
| + // We generate a unique identifier for inlined scripts which we later
|
| + // translate to the unique identifiers used by Dartium. Dartium uses
|
| + // line/column number information which we can't compute here.
|
| + scripts.add('$baseUri:$inlinedScriptCount');
|
| + inlinedScriptCount++;
|
| + }
|
| + }
|
| + }
|
| + return scripts;
|
| }
|
|
|
| /** All libraries in the current isolate. */
|
| final _libs = currentMirrorSystem().libraries;
|
|
|
| +// TODO(sigmund): explore other (cheaper) ways to resolve URIs relative to the
|
| +// root library (see dartbug.com/12612)
|
| +final _rootUri = currentMirrorSystem().isolate.rootLibrary.uri;
|
| +
|
| +/** Regex that matches urls used to represent inlined scripts. */
|
| +final RegExp _inlineScriptRegExp = new RegExp('\(.*\.html.*\):\([0-9]\+\)');
|
| +
|
| +/**
|
| + * Map URLs fabricated by polymer to URLs fabricated by Dartium to represent
|
| + * inlined scripts. Polymer uses baseUri:script#, Dartium uses baseUri:line#
|
| + */
|
| +// TODO(sigmund): figure out if we can generate the same URL and expose it.
|
| +final Map<Uri, List<Uri>> _inlinedScriptMapping = () {
|
| + var map = {};
|
| + for (var uri in _libs.keys) {
|
| + var uriString = uri.toString();
|
| + var match = _inlineScriptRegExp.firstMatch(uriString);
|
| + if (match == null) continue;
|
| + var baseUri = Uri.parse(match.group(1));
|
| + if (map[baseUri] == null) map[baseUri] = [];
|
| + map[baseUri].add(uri);
|
| + }
|
| + return map;
|
| +}();
|
| +
|
| +/** Returns a new Uri that replaces [path] in [uri]. */
|
| +Uri _replacePath(Uri uri, String path) {
|
| + return new Uri(scheme: uri.scheme, host: uri.host, port: uri.port,
|
| + path: path, query: uri.query, fragment: uri.fragment);
|
| +}
|
| +
|
| +/** Returns the Uri in [href] without query parameters or fragments. */
|
| +String _baseUri(String href) {
|
| + var uri = Uri.parse(window.location.href);
|
| + var trimUri = new Uri(scheme: uri.scheme, host: uri.host,
|
| + port: uri.port, path: uri.path);
|
| + return trimUri.toString();
|
| +}
|
| +
|
| /**
|
| * Reads the library at [uriString] (which can be an absolute URI or a relative
|
| - * URI from [srcUrl]), and:
|
| - *
|
| - * * If present, invokes `main`.
|
| + * URI from the root library), and:
|
| *
|
| * * If present, invokes any top-level and static functions marked
|
| * with the [initMethod] annotation (in the order they appear).
|
| @@ -65,22 +145,25 @@ final _libs = currentMirrorSystem().libraries;
|
| * * Registers any [PolymerElement] that is marked with the [CustomTag]
|
| * annotation.
|
| */
|
| -void _loadLibrary(String uriString, [String srcUrl]) {
|
| - var uri = Uri.parse(uriString);
|
| - if (uri.scheme == '' && srcUrl != null) {
|
| - uri = Uri.parse(path.normalize(path.join(path.dirname(srcUrl), uriString)));
|
| +void _loadLibrary(String uriString) {
|
| + var uri = _rootUri.resolve(uriString);
|
| + var lib;
|
| + var match = _inlineScriptRegExp.firstMatch(uriString);
|
| + if (match != null) {
|
| + var baseUri = Uri.parse(match.group(1));
|
| + var list = _inlinedScriptMapping[baseUri];
|
| + var pos = int.parse(match.group(2), onError: (_) => -1);
|
| + if (list != null && pos >= 0 && pos < list.length && list[pos] != null) {
|
| + lib = _libs[list[pos]];
|
| + }
|
| + } else {
|
| + lib = _libs[uri];
|
| }
|
| - var lib = _libs[uri];
|
| if (lib == null) {
|
| print('warning: $uri library not found');
|
| return;
|
| }
|
|
|
| - // Invoke `main`, if present.
|
| - if (lib.functions[#main] != null) {
|
| - lib.invoke(#main, const []);
|
| - }
|
| -
|
| // Search top-level functions marked with @initMethod
|
| for (var f in lib.functions.values) {
|
| _maybeInvoke(lib, f);
|
|
|