| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of polymer; | |
| 6 | |
| 7 /// Initializes a polymer application as follows: | |
| 8 /// * if running in development mode, set up a dirty-checking zone that polls | |
| 9 /// for observable changes | |
| 10 /// * initialize template binding and polymer-element | |
| 11 /// * for each library included transitively from HTML and HTML imports, | |
| 12 /// register custom elements declared there (labeled with [CustomTag]) and | |
| 13 /// invoke the initialization method on it (top-level functions annotated with | |
| 14 /// [initMethod]). | |
| 15 Future<Zone> initPolymer() { | |
| 16 _initializeLogging(); | |
| 17 if (_deployMode) { | |
| 18 return startPolymer().then((_) => Zone.current); | |
| 19 } | |
| 20 return dirtyCheckZone() | |
| 21 .run(() => startPolymer().then((_) => dirtyCheckZone())); | |
| 22 } | |
| 23 | |
| 24 bool _startPolymerCalled = false; | |
| 25 | |
| 26 /// Starts polymer by hooking the polymer.js code. **Note**: this function is | |
| 27 /// not meant to be invoked directly by application developers. It is invoked | |
| 28 /// by [initPolymer]. | |
| 29 Future startPolymer() { | |
| 30 // First wait for all html imports to finish, then run the rest of the | |
| 31 // initializers. | |
| 32 return initWebComponents(initAll: false).then((_) { | |
| 33 // Polymer js is now loaded, hook it before running @CustomTag annotations. | |
| 34 if (_startPolymerCalled) throw 'Initialization was already done.'; | |
| 35 _startPolymerCalled = true; | |
| 36 _hookJsPolymer(); | |
| 37 }).then((_) => initWebComponents()).then((_) { | |
| 38 Polymer.registerSync('auto-binding-dart', AutoBindingElement, | |
| 39 extendsTag: 'template'); | |
| 40 | |
| 41 _watchWaitingFor(); | |
| 42 Polymer._onInitDone.complete(); | |
| 43 }); | |
| 44 } | |
| 45 | |
| 46 /// Configures [initPolymer] making it optimized for deployment to the internet. | |
| 47 /// Additionally, after this method is called [initPolymer] omits the [Zone] | |
| 48 /// that automatically invokes [Observable.dirtyCheck]. | |
| 49 void configureForDeployment() { | |
| 50 _deployMode = true; | |
| 51 } | |
| 52 | |
| 53 /// To ensure Dart can interoperate with polymer-element registered by | |
| 54 /// polymer.js, we need to be able to execute Dart code if we are registering | |
| 55 /// a Dart class for that element. We trigger Dart logic by patching | |
| 56 /// polymer-element's register function and: | |
| 57 /// | |
| 58 /// * if it has a Dart class, run PolymerDeclaration's register. | |
| 59 /// * otherwise it is a JS prototype, run polymer-element's normal register. | |
| 60 void _hookJsPolymer() { | |
| 61 if (!PolymerJs.checkExists()) { | |
| 62 throw new StateError('An error occurred initializing polymer, (could not' | |
| 63 'find polymer js). Please file a bug at ' | |
| 64 'https://github.com/dart-lang/polymer-dart/issues/new.'); | |
| 65 } | |
| 66 | |
| 67 // TODO(jmesserly): dart:js appears to not callback in the correct zone: | |
| 68 // https://code.google.com/p/dart/issues/detail?id=17301 | |
| 69 var zone = Zone.current; | |
| 70 | |
| 71 PolymerJs.whenPolymerReady(() => Polymer._onReady.complete()); | |
| 72 | |
| 73 JsFunction originalRegister = _polymerElementProto['register']; | |
| 74 if (originalRegister == null) { | |
| 75 throw new StateError('polymer.js must expose "register" function on ' | |
| 76 'polymer-element to enable polymer.dart to interoperate.'); | |
| 77 } | |
| 78 | |
| 79 registerDart(jsElem, String name, String extendee) { | |
| 80 // By the time we get here, we'll know for sure if it is a Dart object | |
| 81 // or not, because polymer-element will wait for us to notify that | |
| 82 // the @CustomTag was found. | |
| 83 final type = _getRegisteredType(name); | |
| 84 if (type != null) { | |
| 85 final extendsDecl = _getDeclaration(extendee); | |
| 86 return zone.run(() => | |
| 87 new PolymerDeclaration(jsElem, name, type, extendsDecl).register()); | |
| 88 } | |
| 89 // It's a JavaScript polymer element, fall back to the original register. | |
| 90 return originalRegister.apply([name, extendee], thisArg: jsElem); | |
| 91 } | |
| 92 | |
| 93 _polymerElementProto['register'] = new JsFunction.withThis(registerDart); | |
| 94 } | |
| 95 | |
| 96 // Note: we cache this so we can use it later to look up 'init'. | |
| 97 // See registerSync. | |
| 98 JsObject _polymerElementProto = () { | |
| 99 var polyElem = document.createElement('polymer-element'); | |
| 100 var proto = new JsObject.fromBrowserObject(polyElem)['__proto__']; | |
| 101 if (proto is Node) proto = new JsObject.fromBrowserObject(proto); | |
| 102 return proto; | |
| 103 }(); | |
| 104 | |
| 105 // Add support for the polymer js style of enabling logging. The global logging | |
| 106 // level is respected for specified loggers (see http://goo.gl/btfDe1). All | |
| 107 // other loggers will be set to [Level.OFF]. Logs will also be printed to the | |
| 108 // console automatically if any are supplied. | |
| 109 void _initializeLogging() { | |
| 110 hierarchicalLoggingEnabled = true; | |
| 111 var webComponents = js.context['WebComponents']; | |
| 112 var logFlags = (webComponents == null || webComponents['flags'] == null) | |
| 113 ? {} | |
| 114 : webComponents['flags']['log']; | |
| 115 if (logFlags == null) logFlags = {}; | |
| 116 var loggers = [ | |
| 117 _observeLog, | |
| 118 _eventsLog, | |
| 119 _unbindLog, | |
| 120 _bindLog, | |
| 121 _watchLog, | |
| 122 _readyLog | |
| 123 ]; | |
| 124 var polymerLogger = new Logger('polymer'); | |
| 125 | |
| 126 // If no loggers specified then disable globally and return. | |
| 127 if (!loggers.any((logger) => logFlags[logger.name] == true)) { | |
| 128 polymerLogger.level = Level.OFF; | |
| 129 return; | |
| 130 } | |
| 131 | |
| 132 // Disable the loggers that were not specified. | |
| 133 loggers.where((logger) => logFlags[logger.name] != true).forEach((logger) { | |
| 134 logger.level = Level.OFF; | |
| 135 }); | |
| 136 | |
| 137 // Listen to the polymer logs and print them to the console. | |
| 138 polymerLogger.onRecord.listen((rec) { | |
| 139 print(rec); | |
| 140 }); | |
| 141 } | |
| 142 | |
| 143 /// Watches the waitingFor queue and if it fails to make progress then prints | |
| 144 /// a message to the console. | |
| 145 void _watchWaitingFor() { | |
| 146 int lastWaiting = Polymer.waitingFor.length; | |
| 147 int lastAlert; | |
| 148 new Timer.periodic(new Duration(seconds: 1), (Timer timer) { | |
| 149 var waiting = Polymer.waitingFor; | |
| 150 // Done, cancel timer. | |
| 151 if (waiting.isEmpty) { | |
| 152 timer.cancel(); | |
| 153 return; | |
| 154 } | |
| 155 // Made progress, don't alert. | |
| 156 if (waiting.length != lastWaiting) { | |
| 157 lastWaiting = waiting.length; | |
| 158 return; | |
| 159 } | |
| 160 // Only alert once per waiting state. | |
| 161 if (lastAlert == lastWaiting) return; | |
| 162 lastAlert = lastWaiting; | |
| 163 | |
| 164 print('No elements registered in a while, but still waiting on ' | |
| 165 '${waiting.length} elements to be registered. Check that you have a ' | |
| 166 'class with an @CustomTag annotation for each of the following tags: ' | |
| 167 '${waiting.map((e) => "'${e.attributes['name']}'").join(', ')}'); | |
| 168 }); | |
| 169 } | |
| OLD | NEW |