| 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 /** | 
|  | 6  * Custom Elements let authors define their own elements. Authors associate code | 
|  | 7  * with custom tag names, and then use those custom tag names as they would any | 
|  | 8  * standard tag. See <www.polymer-project.org/platform/custom-elements.html> | 
|  | 9  * for more information. | 
|  | 10  */ | 
|  | 11 library custom_element; | 
|  | 12 | 
|  | 13 import 'dart:async'; | 
|  | 14 import 'dart:html'; | 
|  | 15 import 'package:mdv/mdv.dart' as mdv; | 
|  | 16 import 'package:meta/meta.dart'; | 
|  | 17 import 'src/custom_tag_name.dart'; | 
|  | 18 | 
|  | 19 // TODO(jmesserly): replace with a real custom element polyfill. | 
|  | 20 // This is just something temporary. | 
|  | 21 /** | 
|  | 22  * *Warning*: this implementation is a work in progress. It only implements | 
|  | 23  * the specification partially. | 
|  | 24  * | 
|  | 25  * Registers a custom HTML element with [localName] and the associated | 
|  | 26  * constructor. This will ensure the element is detected and | 
|  | 27  * | 
|  | 28  * See the specification at: | 
|  | 29  * <https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html> | 
|  | 30  */ | 
|  | 31 void registerCustomElement(String localName, CustomElement create()) { | 
|  | 32   if (_customElements == null) { | 
|  | 33     _customElements = {}; | 
|  | 34     CustomElement.templateCreated.add(_createElements); | 
|  | 35     // TODO(jmesserly): use MutationObserver to watch for inserts? | 
|  | 36   } | 
|  | 37 | 
|  | 38   if (!isCustomTag(localName)) { | 
|  | 39     throw new ArgumentError('$localName is not a valid custom element name, ' | 
|  | 40         'it should have at least one dash and not be a reserved name.'); | 
|  | 41   } | 
|  | 42 | 
|  | 43   if (_customElements.containsKey(localName)) { | 
|  | 44     throw new ArgumentError('custom element $localName already registered.'); | 
|  | 45   } | 
|  | 46 | 
|  | 47   // TODO(jmesserly): validate this is a valid tag name, not a selector. | 
|  | 48   _customElements[localName] = create; | 
|  | 49 | 
|  | 50   // Initialize elements already on the page. | 
|  | 51   for (var query in [localName, '[is=$localName]']) { | 
|  | 52     for (var element in document.queryAll(query)) { | 
|  | 53       _initCustomElement(element, create); | 
|  | 54     } | 
|  | 55   } | 
|  | 56 } | 
|  | 57 | 
|  | 58 /** | 
|  | 59  * The base class for all Dart web components. In addition to the [Element] | 
|  | 60  * interface, it also provides lifecycle methods: | 
|  | 61  * - [created] | 
|  | 62  * - [inserted] | 
|  | 63  * - [attributeChanged] | 
|  | 64  * - [removed] | 
|  | 65  */ | 
|  | 66 class CustomElement implements Element { | 
|  | 67   /** The web component element wrapped by this class. */ | 
|  | 68   Element _host; | 
|  | 69   List _shadowRoots; | 
|  | 70 | 
|  | 71   /** | 
|  | 72    * Shadow roots generated by dwc for each custom element, indexed by the | 
|  | 73    * custom element tag name. | 
|  | 74    */ | 
|  | 75   Map<String, dynamic> _generatedRoots = {}; | 
|  | 76 | 
|  | 77   /** | 
|  | 78    * Temporary property until components extend [Element]. An element can | 
|  | 79    * only be associated with one host, and it is an error to use a web component | 
|  | 80    * without an associated host element. | 
|  | 81    */ | 
|  | 82   Element get host { | 
|  | 83     if (_host == null) throw new StateError('host element has not been set.'); | 
|  | 84     return _host; | 
|  | 85   } | 
|  | 86 | 
|  | 87   set host(Element value) { | 
|  | 88     if (value == null) { | 
|  | 89       throw new ArgumentError('host must not be null.'); | 
|  | 90     } | 
|  | 91     // TODO(jmesserly): xtag used to return "null" if unset, now it checks for | 
|  | 92     // "this". Temporarily allow both. | 
|  | 93     var xtag = value.xtag; | 
|  | 94     if (xtag != null && xtag != value) { | 
|  | 95       throw new ArgumentError('host must not have its xtag property set.'); | 
|  | 96     } | 
|  | 97     if (_host != null) { | 
|  | 98       throw new StateError('host can only be set once.'); | 
|  | 99     } | 
|  | 100 | 
|  | 101     value.xtag = this; | 
|  | 102     _host = value; | 
|  | 103   } | 
|  | 104 | 
|  | 105   /** | 
|  | 106    * **Note**: This is an implementation helper and should not need to be called | 
|  | 107    * from your code. | 
|  | 108    * | 
|  | 109    * Creates the [ShadowRoot] backing this component. | 
|  | 110    */ | 
|  | 111   createShadowRoot([String componentName]) { | 
|  | 112     var root = host.createShadowRoot(); | 
|  | 113     if (componentName != null) { | 
|  | 114       _generatedRoots[componentName] = root; | 
|  | 115     } | 
|  | 116     return root; | 
|  | 117   } | 
|  | 118 | 
|  | 119   getShadowRoot(String componentName) => _generatedRoots[componentName]; | 
|  | 120 | 
|  | 121 | 
|  | 122   /** | 
|  | 123    * *Warning*: This is an implementation helper for Custom Elements and | 
|  | 124    * should not be used in your code. | 
|  | 125    * | 
|  | 126    * Clones the template, instantiates custom elements and hooks events, then | 
|  | 127    * returns it. | 
|  | 128    */ | 
|  | 129   DocumentFragment cloneTemplate(DocumentFragment shadowTemplate) { | 
|  | 130     var result = shadowTemplate.clone(true); | 
|  | 131     // TODO(jmesserly): should bindModel ensure this happens? | 
|  | 132     TemplateElement.bootstrap(result); | 
|  | 133     if (_templateCreated != null) { | 
|  | 134       for (var callback in _templateCreated) callback(result); | 
|  | 135     } | 
|  | 136     return result; | 
|  | 137   } | 
|  | 138 | 
|  | 139   // TODO(jmesserly): ideally this would be a stream, but they don't allow | 
|  | 140   // reentrancy. | 
|  | 141   static Set<DocumentFragmentCreated> _templateCreated; | 
|  | 142 | 
|  | 143   /** | 
|  | 144    * *Warning*: This is an implementation helper for Custom Elements and | 
|  | 145    * should not be used in your code. | 
|  | 146    * | 
|  | 147    * This event is fired whenever a template is instantiated via | 
|  | 148    * [cloneTemplate] or via [Element.createInstance] | 
|  | 149    */ | 
|  | 150   // TODO(jmesserly): This is a hack, and is neccesary for the polyfill | 
|  | 151   // because custom elements are not upgraded during clone() | 
|  | 152   static Set<DocumentFragmentCreated> get templateCreated { | 
|  | 153     if (_templateCreated == null) { | 
|  | 154       _templateCreated = new Set<DocumentFragmentCreated>(); | 
|  | 155       mdv.instanceCreated.listen((value) { | 
|  | 156         for (var callback in _templateCreated) callback(value); | 
|  | 157       }); | 
|  | 158     } | 
|  | 159     return _templateCreated; | 
|  | 160   } | 
|  | 161   /** | 
|  | 162    * Invoked when this component gets created. | 
|  | 163    * Note that [root] will be a [ShadowRoot] if the browser supports Shadow DOM. | 
|  | 164    */ | 
|  | 165   void created() {} | 
|  | 166 | 
|  | 167   /** Invoked when this component gets inserted in the DOM tree. */ | 
|  | 168   void inserted() {} | 
|  | 169 | 
|  | 170   /** Invoked when this component is removed from the DOM tree. */ | 
|  | 171   void removed() {} | 
|  | 172 | 
|  | 173   // TODO(jmesserly): how do we implement this efficiently? | 
|  | 174   // See https://github.com/dart-lang/web-ui/issues/37 | 
|  | 175   /** Invoked when any attribute of the component is modified. */ | 
|  | 176   void attributeChanged(String name, String oldValue, String newValue) {} | 
|  | 177 | 
|  | 178   get model => host.model; | 
|  | 179 | 
|  | 180   void set model(newModel) { | 
|  | 181     host.model = newModel; | 
|  | 182   } | 
|  | 183 | 
|  | 184   get templateInstance => host.templateInstance; | 
|  | 185   get isTemplate => host.isTemplate; | 
|  | 186   get ref => host.ref; | 
|  | 187   get content => host.content; | 
|  | 188   DocumentFragment createInstance(model, BindingDelegate delegate) => | 
|  | 189       host.createInstance(model, delegate); | 
|  | 190   createBinding(String name, model, String path) => | 
|  | 191       host.createBinding(name, model, path); | 
|  | 192   void bind(String name, model, String path) => host.bind(name, model, path); | 
|  | 193   void unbind(String name) => host.unbind(name); | 
|  | 194   void unbindAll() => host.unbindAll(); | 
|  | 195   get bindings => host.bindings; | 
|  | 196   BindingDelegate get bindingDelegate => host.bindingDelegate; | 
|  | 197   set bindingDelegate(BindingDelegate value) { host.bindingDelegate = value; } | 
|  | 198 | 
|  | 199   // TODO(jmesserly): this forwarding is temporary until Dart supports | 
|  | 200   // subclassing Elements. | 
|  | 201   // TODO(jmesserly): we were missing the setter for title, are other things | 
|  | 202   // missing setters? | 
|  | 203 | 
|  | 204   List<Node> get nodes => host.nodes; | 
|  | 205 | 
|  | 206   set nodes(Iterable<Node> value) { host.nodes = value; } | 
|  | 207 | 
|  | 208   /** | 
|  | 209    * Replaces this node with another node. | 
|  | 210    */ | 
|  | 211   Node replaceWith(Node otherNode) { host.replaceWith(otherNode); } | 
|  | 212 | 
|  | 213   /** | 
|  | 214    * Removes this node from the DOM. | 
|  | 215    */ | 
|  | 216   void remove() => host.remove(); | 
|  | 217 | 
|  | 218   Node get nextNode => host.nextNode; | 
|  | 219 | 
|  | 220   String get nodeName => host.nodeName; | 
|  | 221 | 
|  | 222   Document get document => host.document; | 
|  | 223 | 
|  | 224   Node get previousNode => host.previousNode; | 
|  | 225 | 
|  | 226   String get text => host.text; | 
|  | 227 | 
|  | 228   set text(String v) { host.text = v; } | 
|  | 229 | 
|  | 230   bool contains(Node other) => host.contains(other); | 
|  | 231 | 
|  | 232   bool hasChildNodes() => host.hasChildNodes(); | 
|  | 233 | 
|  | 234   Node insertBefore(Node newChild, Node refChild) => | 
|  | 235     host.insertBefore(newChild, refChild); | 
|  | 236 | 
|  | 237   Node insertAllBefore(Iterable<Node> newChild, Node refChild) => | 
|  | 238     host.insertAllBefore(newChild, refChild); | 
|  | 239 | 
|  | 240   Map<String, String> get attributes => host.attributes; | 
|  | 241   set attributes(Map<String, String> value) { | 
|  | 242     host.attributes = value; | 
|  | 243   } | 
|  | 244 | 
|  | 245   List<Element> get elements => host.children; | 
|  | 246 | 
|  | 247   set elements(List<Element> value) { | 
|  | 248     host.children = value; | 
|  | 249   } | 
|  | 250 | 
|  | 251   List<Element> get children => host.children; | 
|  | 252 | 
|  | 253   set children(List<Element> value) { | 
|  | 254     host.children = value; | 
|  | 255   } | 
|  | 256 | 
|  | 257   Set<String> get classes => host.classes; | 
|  | 258 | 
|  | 259   set classes(Iterable<String> value) { | 
|  | 260     host.classes = value; | 
|  | 261   } | 
|  | 262 | 
|  | 263   CssRect get contentEdge => host.contentEdge; | 
|  | 264   CssRect get paddingEdge => host.paddingEdge; | 
|  | 265   CssRect get borderEdge => host.borderEdge; | 
|  | 266   CssRect get marginEdge => host.marginEdge; | 
|  | 267   Point get documentOffset => host.documentOffset; | 
|  | 268   Point offsetTo(Element parent) => host.offsetTo(parent); | 
|  | 269 | 
|  | 270   Map<String, String> getNamespacedAttributes(String namespace) => | 
|  | 271       host.getNamespacedAttributes(namespace); | 
|  | 272 | 
|  | 273   CssStyleDeclaration getComputedStyle([String pseudoElement]) | 
|  | 274     => host.getComputedStyle(pseudoElement); | 
|  | 275 | 
|  | 276   Element clone(bool deep) => host.clone(deep); | 
|  | 277 | 
|  | 278   Element get parent => host.parent; | 
|  | 279 | 
|  | 280   Node get parentNode => host.parentNode; | 
|  | 281 | 
|  | 282   String get nodeValue => host.nodeValue; | 
|  | 283 | 
|  | 284   @deprecated | 
|  | 285   // TODO(sigmund): restore the old return type and call host.on when | 
|  | 286   // dartbug.com/8131 is fixed. | 
|  | 287   dynamic get on { throw new UnsupportedError('on is deprecated'); } | 
|  | 288 | 
|  | 289   String get contentEditable => host.contentEditable; | 
|  | 290   set contentEditable(String v) { host.contentEditable = v; } | 
|  | 291 | 
|  | 292   String get dir => host.dir; | 
|  | 293   set dir(String v) { host.dir = v; } | 
|  | 294 | 
|  | 295   bool get draggable => host.draggable; | 
|  | 296   set draggable(bool v) { host.draggable = v; } | 
|  | 297 | 
|  | 298   bool get hidden => host.hidden; | 
|  | 299   set hidden(bool v) { host.hidden = v; } | 
|  | 300 | 
|  | 301   String get id => host.id; | 
|  | 302   set id(String v) { host.id = v; } | 
|  | 303 | 
|  | 304   String get innerHTML => host.innerHtml; | 
|  | 305 | 
|  | 306   void set innerHTML(String v) { | 
|  | 307     host.innerHtml = v; | 
|  | 308   } | 
|  | 309 | 
|  | 310   String get innerHtml => host.innerHtml; | 
|  | 311   void set innerHtml(String v) { | 
|  | 312     host.innerHtml = v; | 
|  | 313   } | 
|  | 314 | 
|  | 315   bool get isContentEditable => host.isContentEditable; | 
|  | 316 | 
|  | 317   String get lang => host.lang; | 
|  | 318   set lang(String v) { host.lang = v; } | 
|  | 319 | 
|  | 320   String get outerHtml => host.outerHtml; | 
|  | 321 | 
|  | 322   bool get spellcheck => host.spellcheck; | 
|  | 323   set spellcheck(bool v) { host.spellcheck = v; } | 
|  | 324 | 
|  | 325   int get tabIndex => host.tabIndex; | 
|  | 326   set tabIndex(int i) { host.tabIndex = i; } | 
|  | 327 | 
|  | 328   String get title => host.title; | 
|  | 329 | 
|  | 330   set title(String value) { host.title = value; } | 
|  | 331 | 
|  | 332   bool get translate => host.translate; | 
|  | 333   set translate(bool v) { host.translate = v; } | 
|  | 334 | 
|  | 335   String get dropzone => host.dropzone; | 
|  | 336   set dropzone(String v) { host.dropzone = v; } | 
|  | 337 | 
|  | 338   void click() { host.click(); } | 
|  | 339 | 
|  | 340   InputMethodContext getInputContext() => host.getInputContext(); | 
|  | 341 | 
|  | 342   Element insertAdjacentElement(String where, Element element) => | 
|  | 343     host.insertAdjacentElement(where, element); | 
|  | 344 | 
|  | 345   void insertAdjacentHtml(String where, String html) { | 
|  | 346     host.insertAdjacentHtml(where, html); | 
|  | 347   } | 
|  | 348 | 
|  | 349   void insertAdjacentText(String where, String text) { | 
|  | 350     host.insertAdjacentText(where, text); | 
|  | 351   } | 
|  | 352 | 
|  | 353   Map<String, String> get dataset => host.dataset; | 
|  | 354 | 
|  | 355   set dataset(Map<String, String> value) { | 
|  | 356     host.dataset = value; | 
|  | 357   } | 
|  | 358 | 
|  | 359   Element get nextElementSibling => host.nextElementSibling; | 
|  | 360 | 
|  | 361   Element get offsetParent => host.offsetParent; | 
|  | 362 | 
|  | 363   Element get previousElementSibling => host.previousElementSibling; | 
|  | 364 | 
|  | 365   CssStyleDeclaration get style => host.style; | 
|  | 366 | 
|  | 367   String get tagName => host.tagName; | 
|  | 368 | 
|  | 369   String get pseudo => host.pseudo; | 
|  | 370 | 
|  | 371   void set pseudo(String value) { | 
|  | 372     host.pseudo = value; | 
|  | 373   } | 
|  | 374 | 
|  | 375   // Note: we are not polyfilling the shadow root here. This will be fixed when | 
|  | 376   // we migrate to the JS Shadow DOM polyfills. You can still use getShadowRoot | 
|  | 377   // to retrieve a node that behaves as the shadow root when Shadow DOM is not | 
|  | 378   // enabled. | 
|  | 379   ShadowRoot get shadowRoot => host.shadowRoot; | 
|  | 380 | 
|  | 381   void blur() { host.blur(); } | 
|  | 382 | 
|  | 383   void focus() { host.focus(); } | 
|  | 384 | 
|  | 385   void scrollByLines(int lines) { | 
|  | 386     host.scrollByLines(lines); | 
|  | 387   } | 
|  | 388 | 
|  | 389   void scrollByPages(int pages) { | 
|  | 390     host.scrollByPages(pages); | 
|  | 391   } | 
|  | 392 | 
|  | 393   void scrollIntoView([ScrollAlignment alignment]) { | 
|  | 394     host.scrollIntoView(alignment); | 
|  | 395   } | 
|  | 396 | 
|  | 397   bool matches(String selectors) => host.matches(selectors); | 
|  | 398 | 
|  | 399   @deprecated | 
|  | 400   void requestFullScreen(int flags) { requestFullscreen(); } | 
|  | 401 | 
|  | 402   void requestFullscreen() { host.requestFullscreen(); } | 
|  | 403 | 
|  | 404   void requestPointerLock() { host.requestPointerLock(); } | 
|  | 405 | 
|  | 406   Element query(String selectors) => host.query(selectors); | 
|  | 407 | 
|  | 408   ElementList queryAll(String selectors) => host.queryAll(selectors); | 
|  | 409 | 
|  | 410   HtmlCollection get $dom_children => host.$dom_children; | 
|  | 411 | 
|  | 412   int get $dom_childElementCount => host.$dom_childElementCount; | 
|  | 413 | 
|  | 414   String get className => host.className; | 
|  | 415   set className(String value) { host.className = value; } | 
|  | 416 | 
|  | 417   @deprecated | 
|  | 418   int get clientHeight => client.height; | 
|  | 419 | 
|  | 420   @deprecated | 
|  | 421   int get clientLeft => client.left; | 
|  | 422 | 
|  | 423   @deprecated | 
|  | 424   int get clientTop => client.top; | 
|  | 425 | 
|  | 426   @deprecated | 
|  | 427   int get clientWidth => client.width; | 
|  | 428 | 
|  | 429   Rect get client => host.client; | 
|  | 430 | 
|  | 431   Element get $dom_firstElementChild => host.$dom_firstElementChild; | 
|  | 432 | 
|  | 433   Element get $dom_lastElementChild => host.$dom_lastElementChild; | 
|  | 434 | 
|  | 435   @deprecated | 
|  | 436   int get offsetHeight => offset.height; | 
|  | 437 | 
|  | 438   @deprecated | 
|  | 439   int get offsetLeft => offset.left; | 
|  | 440 | 
|  | 441   @deprecated | 
|  | 442   int get offsetTop => offset.top; | 
|  | 443 | 
|  | 444   @deprecated | 
|  | 445   int get offsetWidth => offset.width; | 
|  | 446 | 
|  | 447   Rect get offset => host.offset; | 
|  | 448 | 
|  | 449   int get scrollHeight => host.scrollHeight; | 
|  | 450 | 
|  | 451   int get scrollLeft => host.scrollLeft; | 
|  | 452 | 
|  | 453   int get scrollTop => host.scrollTop; | 
|  | 454 | 
|  | 455   set scrollLeft(int value) { host.scrollLeft = value; } | 
|  | 456 | 
|  | 457   set scrollTop(int value) { host.scrollTop = value; } | 
|  | 458 | 
|  | 459   int get scrollWidth => host.scrollWidth; | 
|  | 460 | 
|  | 461   String $dom_getAttribute(String name) => | 
|  | 462       host.$dom_getAttribute(name); | 
|  | 463 | 
|  | 464   String $dom_getAttributeNS(String namespaceUri, String localName) => | 
|  | 465       host.$dom_getAttributeNS(namespaceUri, localName); | 
|  | 466 | 
|  | 467   String $dom_setAttributeNS( | 
|  | 468       String namespaceUri, String localName, String value) { | 
|  | 469     host.$dom_setAttributeNS(namespaceUri, localName, value); | 
|  | 470   } | 
|  | 471 | 
|  | 472   bool $dom_hasAttributeNS(String namespaceUri, String localName) => | 
|  | 473       host.$dom_hasAttributeNS(namespaceUri, localName); | 
|  | 474 | 
|  | 475   void $dom_removeAttributeNS(String namespaceUri, String localName) => | 
|  | 476       host.$dom_removeAttributeNS(namespaceUri, localName); | 
|  | 477 | 
|  | 478   Rect getBoundingClientRect() => host.getBoundingClientRect(); | 
|  | 479 | 
|  | 480   List<Rect> getClientRects() => host.getClientRects(); | 
|  | 481 | 
|  | 482   List<Node> getElementsByClassName(String name) => | 
|  | 483       host.getElementsByClassName(name); | 
|  | 484 | 
|  | 485   List<Node> $dom_getElementsByTagName(String name) => | 
|  | 486       host.$dom_getElementsByTagName(name); | 
|  | 487 | 
|  | 488   bool $dom_hasAttribute(String name) => | 
|  | 489       host.$dom_hasAttribute(name); | 
|  | 490 | 
|  | 491   List<Node> $dom_querySelectorAll(String selectors) => | 
|  | 492       host.$dom_querySelectorAll(selectors); | 
|  | 493 | 
|  | 494   void $dom_removeAttribute(String name) => | 
|  | 495       host.$dom_removeAttribute(name); | 
|  | 496 | 
|  | 497   void $dom_setAttribute(String name, String value) => | 
|  | 498       host.$dom_setAttribute(name, value); | 
|  | 499 | 
|  | 500   get $dom_attributes => host.$dom_attributes; | 
|  | 501 | 
|  | 502   List<Node> get $dom_childNodes => host.$dom_childNodes; | 
|  | 503 | 
|  | 504   Node get firstChild => host.firstChild; | 
|  | 505 | 
|  | 506   Node get lastChild => host.lastChild; | 
|  | 507 | 
|  | 508   String get localName => host.localName; | 
|  | 509   String get $dom_localName => host.$dom_localName; | 
|  | 510 | 
|  | 511   String get namespaceUri => host.namespaceUri; | 
|  | 512   String get $dom_namespaceUri => host.$dom_namespaceUri; | 
|  | 513 | 
|  | 514   int get nodeType => host.nodeType; | 
|  | 515 | 
|  | 516   void $dom_addEventListener(String type, EventListener listener, | 
|  | 517                              [bool useCapture]) { | 
|  | 518     host.$dom_addEventListener(type, listener, useCapture); | 
|  | 519   } | 
|  | 520 | 
|  | 521   bool dispatchEvent(Event event) => host.dispatchEvent(event); | 
|  | 522 | 
|  | 523   Node $dom_removeChild(Node oldChild) => host.$dom_removeChild(oldChild); | 
|  | 524 | 
|  | 525   void $dom_removeEventListener(String type, EventListener listener, | 
|  | 526                                 [bool useCapture]) { | 
|  | 527     host.$dom_removeEventListener(type, listener, useCapture); | 
|  | 528   } | 
|  | 529 | 
|  | 530   Node $dom_replaceChild(Node newChild, Node oldChild) => | 
|  | 531       host.$dom_replaceChild(newChild, oldChild); | 
|  | 532 | 
|  | 533   get xtag => host.xtag; | 
|  | 534 | 
|  | 535   set xtag(value) { host.xtag = value; } | 
|  | 536 | 
|  | 537   Node append(Node e) => host.append(e); | 
|  | 538 | 
|  | 539   void appendText(String text) => host.appendText(text); | 
|  | 540 | 
|  | 541   void appendHtml(String html) => host.appendHtml(html); | 
|  | 542 | 
|  | 543   void $dom_scrollIntoView([bool alignWithTop]) { | 
|  | 544     if (alignWithTop == null) { | 
|  | 545       host.$dom_scrollIntoView(); | 
|  | 546     } else { | 
|  | 547       host.$dom_scrollIntoView(alignWithTop); | 
|  | 548     } | 
|  | 549   } | 
|  | 550 | 
|  | 551   void $dom_scrollIntoViewIfNeeded([bool centerIfNeeded]) { | 
|  | 552     if (centerIfNeeded == null) { | 
|  | 553       host.$dom_scrollIntoViewIfNeeded(); | 
|  | 554     } else { | 
|  | 555       host.$dom_scrollIntoViewIfNeeded(centerIfNeeded); | 
|  | 556     } | 
|  | 557   } | 
|  | 558 | 
|  | 559   String get regionOverset => host.regionOverset; | 
|  | 560 | 
|  | 561   List<Range> getRegionFlowRanges() => host.getRegionFlowRanges(); | 
|  | 562 | 
|  | 563   // TODO(jmesserly): rename "created" to "onCreated". | 
|  | 564   void onCreated() => created(); | 
|  | 565 | 
|  | 566   Stream<Event> get onAbort => host.onAbort; | 
|  | 567   Stream<Event> get onBeforeCopy => host.onBeforeCopy; | 
|  | 568   Stream<Event> get onBeforeCut => host.onBeforeCut; | 
|  | 569   Stream<Event> get onBeforePaste => host.onBeforePaste; | 
|  | 570   Stream<Event> get onBlur => host.onBlur; | 
|  | 571   Stream<Event> get onChange => host.onChange; | 
|  | 572   Stream<MouseEvent> get onClick => host.onClick; | 
|  | 573   Stream<MouseEvent> get onContextMenu => host.onContextMenu; | 
|  | 574   Stream<Event> get onCopy => host.onCopy; | 
|  | 575   Stream<Event> get onCut => host.onCut; | 
|  | 576   Stream<Event> get onDoubleClick => host.onDoubleClick; | 
|  | 577   Stream<MouseEvent> get onDrag => host.onDrag; | 
|  | 578   Stream<MouseEvent> get onDragEnd => host.onDragEnd; | 
|  | 579   Stream<MouseEvent> get onDragEnter => host.onDragEnter; | 
|  | 580   Stream<MouseEvent> get onDragLeave => host.onDragLeave; | 
|  | 581   Stream<MouseEvent> get onDragOver => host.onDragOver; | 
|  | 582   Stream<MouseEvent> get onDragStart => host.onDragStart; | 
|  | 583   Stream<MouseEvent> get onDrop => host.onDrop; | 
|  | 584   Stream<Event> get onError => host.onError; | 
|  | 585   Stream<Event> get onFocus => host.onFocus; | 
|  | 586   Stream<Event> get onInput => host.onInput; | 
|  | 587   Stream<Event> get onInvalid => host.onInvalid; | 
|  | 588   Stream<KeyboardEvent> get onKeyDown => host.onKeyDown; | 
|  | 589   Stream<KeyboardEvent> get onKeyPress => host.onKeyPress; | 
|  | 590   Stream<KeyboardEvent> get onKeyUp => host.onKeyUp; | 
|  | 591   Stream<Event> get onLoad => host.onLoad; | 
|  | 592   Stream<MouseEvent> get onMouseDown => host.onMouseDown; | 
|  | 593   Stream<MouseEvent> get onMouseMove => host.onMouseMove; | 
|  | 594   Stream<Event> get onFullscreenChange => host.onFullscreenChange; | 
|  | 595   Stream<Event> get onFullscreenError => host.onFullscreenError; | 
|  | 596   Stream<Event> get onPaste => host.onPaste; | 
|  | 597   Stream<Event> get onReset => host.onReset; | 
|  | 598   Stream<Event> get onScroll => host.onScroll; | 
|  | 599   Stream<Event> get onSearch => host.onSearch; | 
|  | 600   Stream<Event> get onSelect => host.onSelect; | 
|  | 601   Stream<Event> get onSelectStart => host.onSelectStart; | 
|  | 602   Stream<Event> get onSubmit => host.onSubmit; | 
|  | 603   Stream<MouseEvent> get onMouseOut => host.onMouseOut; | 
|  | 604   Stream<MouseEvent> get onMouseOver => host.onMouseOver; | 
|  | 605   Stream<MouseEvent> get onMouseUp => host.onMouseUp; | 
|  | 606   Stream<TouchEvent> get onTouchCancel => host.onTouchCancel; | 
|  | 607   Stream<TouchEvent> get onTouchEnd => host.onTouchEnd; | 
|  | 608   Stream<TouchEvent> get onTouchEnter => host.onTouchEnter; | 
|  | 609   Stream<TouchEvent> get onTouchLeave => host.onTouchLeave; | 
|  | 610   Stream<TouchEvent> get onTouchMove => host.onTouchMove; | 
|  | 611   Stream<TouchEvent> get onTouchStart => host.onTouchStart; | 
|  | 612   Stream<TransitionEvent> get onTransitionEnd => host.onTransitionEnd; | 
|  | 613 | 
|  | 614   // TODO(sigmund): do the normal forwarding when dartbug.com/7919 is fixed. | 
|  | 615   Stream<WheelEvent> get onMouseWheel { | 
|  | 616     throw new UnsupportedError('onMouseWheel is not supported'); | 
|  | 617   } | 
|  | 618 } | 
|  | 619 | 
|  | 620 | 
|  | 621 typedef DocumentFragmentCreated(DocumentFragment fragment); | 
|  | 622 | 
|  | 623 Map<String, Function> _customElements; | 
|  | 624 | 
|  | 625 void _createElements(Node node) { | 
|  | 626   for (var c = node.firstChild; c != null; c = c.nextNode) { | 
|  | 627     _createElements(c); | 
|  | 628   } | 
|  | 629   if (node is Element) { | 
|  | 630     var ctor = _customElements[node.localName]; | 
|  | 631     if (ctor == null) { | 
|  | 632       var attr = node.attributes['is']; | 
|  | 633       if (attr != null) ctor = _customElements[attr]; | 
|  | 634     } | 
|  | 635     if (ctor != null) _initCustomElement(node, ctor); | 
|  | 636   } | 
|  | 637 } | 
|  | 638 | 
|  | 639 void _initCustomElement(Element node, CustomElement ctor()) { | 
|  | 640   CustomElement element = ctor(); | 
|  | 641   element.host = node; | 
|  | 642 | 
|  | 643   // TODO(jmesserly): replace lifecycle stuff with a proper polyfill. | 
|  | 644   element.created(); | 
|  | 645 | 
|  | 646   _registerLifecycleInsert(element); | 
|  | 647 } | 
|  | 648 | 
|  | 649 void _registerLifecycleInsert(CustomElement element) { | 
|  | 650   runAsync(() { | 
|  | 651     // TODO(jmesserly): bottom up or top down insert? | 
|  | 652     var node = element.host; | 
|  | 653 | 
|  | 654     // TODO(jmesserly): need a better check to see if the node has been removed. | 
|  | 655     if (node.parentNode == null) return; | 
|  | 656 | 
|  | 657     _registerLifecycleRemove(element); | 
|  | 658     element.inserted(); | 
|  | 659   }); | 
|  | 660 } | 
|  | 661 | 
|  | 662 void _registerLifecycleRemove(CustomElement element) { | 
|  | 663   // TODO(jmesserly): need fallback or polyfill for MutationObserver. | 
|  | 664   if (!MutationObserver.supported) return; | 
|  | 665 | 
|  | 666   new MutationObserver((records, observer) { | 
|  | 667     var node = element.host; | 
|  | 668     for (var record in records) { | 
|  | 669       for (var removed in record.removedNodes) { | 
|  | 670         if (identical(node, removed)) { | 
|  | 671           observer.disconnect(); | 
|  | 672           element.removed(); | 
|  | 673           return; | 
|  | 674         } | 
|  | 675       } | 
|  | 676     } | 
|  | 677   }).observe(element.parentNode, childList: true); | 
|  | 678 } | 
| OLD | NEW | 
|---|