| OLD | NEW |
| 1 /** | 1 /** |
| 2 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 2 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 3 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 3 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 4 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 4 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 5 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 5 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 6 * Code distributed by Google as part of the polymer project is also | 6 * Code distributed by Google as part of the polymer project is also |
| 7 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 7 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 8 */ | 8 */ |
| 9 | 9 |
| 10 window.Platform = window.Platform || {}; | 10 window.Platform = window.Platform || {}; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 var entry = key[this.name]; | 105 var entry = key[this.name]; |
| 106 if (!entry) return false; | 106 if (!entry) return false; |
| 107 return entry[0] === key; | 107 return entry[0] === key; |
| 108 } | 108 } |
| 109 }; | 109 }; |
| 110 | 110 |
| 111 window.WeakMap = WeakMap; | 111 window.WeakMap = WeakMap; |
| 112 })(); | 112 })(); |
| 113 } | 113 } |
| 114 | 114 |
| 115 // select ShadowDOM impl |
| 116 if (Platform.flags.shadow) { |
| 117 |
| 115 // Copyright 2012 Google Inc. | 118 // Copyright 2012 Google Inc. |
| 116 // | 119 // |
| 117 // Licensed under the Apache License, Version 2.0 (the "License"); | 120 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 118 // you may not use this file except in compliance with the License. | 121 // you may not use this file except in compliance with the License. |
| 119 // You may obtain a copy of the License at | 122 // You may obtain a copy of the License at |
| 120 // | 123 // |
| 121 // http://www.apache.org/licenses/LICENSE-2.0 | 124 // http://www.apache.org/licenses/LICENSE-2.0 |
| 122 // | 125 // |
| 123 // Unless required by applicable law or agreed to in writing, software | 126 // Unless required by applicable law or agreed to in writing, software |
| 124 // distributed under the License is distributed on an "AS IS" BASIS, | 127 // distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 1708 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1833 }; | 1836 }; |
| 1834 | 1837 |
| 1835 global.ArraySplice = ArraySplice; | 1838 global.ArraySplice = ArraySplice; |
| 1836 global.ObjectObserver = ObjectObserver; | 1839 global.ObjectObserver = ObjectObserver; |
| 1837 global.PathObserver = PathObserver; | 1840 global.PathObserver = PathObserver; |
| 1838 global.CompoundObserver = CompoundObserver; | 1841 global.CompoundObserver = CompoundObserver; |
| 1839 global.Path = Path; | 1842 global.Path = Path; |
| 1840 global.ObserverTransform = ObserverTransform; | 1843 global.ObserverTransform = ObserverTransform; |
| 1841 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m
odule ? global : this || window); | 1844 })(typeof global !== 'undefined' && global && typeof module !== 'undefined' && m
odule ? global : this || window); |
| 1842 | 1845 |
| 1843 // select ShadowDOM impl | |
| 1844 if (Platform.flags.shadow) { | |
| 1845 | |
| 1846 // Copyright 2012 The Polymer Authors. All rights reserved. | 1846 // Copyright 2012 The Polymer Authors. All rights reserved. |
| 1847 // Use of this source code is goverened by a BSD-style | 1847 // Use of this source code is goverened by a BSD-style |
| 1848 // license that can be found in the LICENSE file. | 1848 // license that can be found in the LICENSE file. |
| 1849 | 1849 |
| 1850 window.ShadowDOMPolyfill = {}; | 1850 window.ShadowDOMPolyfill = {}; |
| 1851 | 1851 |
| 1852 (function(scope) { | 1852 (function(scope) { |
| 1853 'use strict'; | 1853 'use strict'; |
| 1854 | 1854 |
| 1855 var constructorTable = new WeakMap(); | 1855 var constructorTable = new WeakMap(); |
| (...skipping 6649 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8505 Array.prototype.forEach.call(cssRules, function(rule) { | 8505 Array.prototype.forEach.call(cssRules, function(rule) { |
| 8506 if (rule.selectorText && (rule.style && rule.style.cssText !== undefined
)) { | 8506 if (rule.selectorText && (rule.style && rule.style.cssText !== undefined
)) { |
| 8507 cssText += this.scopeSelector(rule.selectorText, scopeSelector, | 8507 cssText += this.scopeSelector(rule.selectorText, scopeSelector, |
| 8508 this.strictStyling) + ' {\n\t'; | 8508 this.strictStyling) + ' {\n\t'; |
| 8509 cssText += this.propertiesFromRule(rule) + '\n}\n\n'; | 8509 cssText += this.propertiesFromRule(rule) + '\n}\n\n'; |
| 8510 } else if (rule.type === CSSRule.MEDIA_RULE) { | 8510 } else if (rule.type === CSSRule.MEDIA_RULE) { |
| 8511 cssText += '@media ' + rule.media.mediaText + ' {\n'; | 8511 cssText += '@media ' + rule.media.mediaText + ' {\n'; |
| 8512 cssText += this.scopeRules(rule.cssRules, scopeSelector); | 8512 cssText += this.scopeRules(rule.cssRules, scopeSelector); |
| 8513 cssText += '\n}\n\n'; | 8513 cssText += '\n}\n\n'; |
| 8514 } else { | 8514 } else { |
| 8515 // TODO(sjmiles): KEYFRAMES_RULE in IE11 throws when we query cssText | 8515 // KEYFRAMES_RULE in IE throws when we query cssText |
| 8516 // 'cssText' in rule returns true, but rule.cssText throws anyway | 8516 // when it contains a -webkit- property. |
| 8517 // We can test the rule type, e.g. | 8517 // if this happens, we fallback to constructing the rule |
| 8518 // else if (rule.type !== CSSRule.KEYFRAMES_RULE && rule.cssText) { | 8518 // from the CSSRuleSet |
| 8519 // but this will prevent cssText propagation in other browsers which | 8519 // https://connect.microsoft.com/IE/feedbackdetail/view/955703/accessi
ng-csstext-of-a-keyframe-rule-that-contains-a-webkit-property-via-cssom-generate
s-exception |
| 8520 // support it. | |
| 8521 // KEYFRAMES_RULE has a CSSRuleSet, so the text can probably be recons
tructed | |
| 8522 // from that collection; this would be a proper fix. | |
| 8523 // For now, I'm trapping the exception so IE11 is unblocked in other a
reas. | |
| 8524 try { | 8520 try { |
| 8525 if (rule.cssText) { | 8521 if (rule.cssText) { |
| 8526 cssText += rule.cssText + '\n\n'; | 8522 cssText += rule.cssText + '\n\n'; |
| 8527 } | 8523 } |
| 8528 } catch(x) { | 8524 } catch(x) { |
| 8529 // squelch | 8525 if (rule.type === CSSRule.KEYFRAMES_RULE && rule.cssRules) { |
| 8526 cssText += this.ieSafeCssTextFromKeyFrameRule(rule); |
| 8527 } |
| 8530 } | 8528 } |
| 8531 } | 8529 } |
| 8532 }, this); | 8530 }, this); |
| 8533 } | 8531 } |
| 8534 return cssText; | 8532 return cssText; |
| 8535 }, | 8533 }, |
| 8534 ieSafeCssTextFromKeyFrameRule: function(rule) { |
| 8535 var cssText = '@keyframes ' + rule.name + ' {'; |
| 8536 Array.prototype.forEach.call(rule.cssRules, function(rule) { |
| 8537 cssText += ' ' + rule.keyText + ' {' + rule.style.cssText + '}'; |
| 8538 }); |
| 8539 cssText += ' }'; |
| 8540 return cssText; |
| 8541 }, |
| 8536 scopeSelector: function(selector, scopeSelector, strict) { | 8542 scopeSelector: function(selector, scopeSelector, strict) { |
| 8537 var r = [], parts = selector.split(','); | 8543 var r = [], parts = selector.split(','); |
| 8538 parts.forEach(function(p) { | 8544 parts.forEach(function(p) { |
| 8539 p = p.trim(); | 8545 p = p.trim(); |
| 8540 if (this.selectorNeedsScoping(p, scopeSelector)) { | 8546 if (this.selectorNeedsScoping(p, scopeSelector)) { |
| 8541 p = (strict && !p.match(polyfillHostNoCombinator)) ? | 8547 p = (strict && !p.match(polyfillHostNoCombinator)) ? |
| 8542 this.applyStrictSelectorScope(p, scopeSelector) : | 8548 this.applyStrictSelectorScope(p, scopeSelector) : |
| 8543 this.applySelectorScope(p, scopeSelector); | 8549 this.applySelectorScope(p, scopeSelector); |
| 8544 } | 8550 } |
| 8545 r.push(p); | 8551 r.push(p); |
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8748 var isChrome = navigator.userAgent.match('Chrome'); | 8754 var isChrome = navigator.userAgent.match('Chrome'); |
| 8749 function withCssRules(cssText, callback) { | 8755 function withCssRules(cssText, callback) { |
| 8750 if (!callback) { | 8756 if (!callback) { |
| 8751 return; | 8757 return; |
| 8752 } | 8758 } |
| 8753 var rules; | 8759 var rules; |
| 8754 if (cssText.match('@import') && isChrome) { | 8760 if (cssText.match('@import') && isChrome) { |
| 8755 var style = cssTextToStyle(cssText); | 8761 var style = cssTextToStyle(cssText); |
| 8756 inFrame(function(doc) { | 8762 inFrame(function(doc) { |
| 8757 doc.head.appendChild(style.impl); | 8763 doc.head.appendChild(style.impl); |
| 8758 rules = style.sheet.cssRules; | 8764 rules = Array.prototype.slice.call(style.sheet.cssRules, 0); |
| 8759 callback(rules); | 8765 callback(rules); |
| 8760 }); | 8766 }); |
| 8761 } else { | 8767 } else { |
| 8762 rules = cssToRules(cssText); | 8768 rules = cssToRules(cssText); |
| 8763 callback(rules); | 8769 callback(rules); |
| 8764 } | 8770 } |
| 8765 } | 8771 } |
| 8766 | 8772 |
| 8767 function rulesToCss(cssRules) { | 8773 function rulesToCss(cssRules) { |
| 8768 for (var i=0, css=[]; i < cssRules.length; i++) { | 8774 for (var i=0, css=[]; i < cssRules.length; i++) { |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8829 if (elt[SHIMMED_ATTRIBUTE]) { | 8835 if (elt[SHIMMED_ATTRIBUTE]) { |
| 8830 return; | 8836 return; |
| 8831 } | 8837 } |
| 8832 var style = elt.__importElement || elt; | 8838 var style = elt.__importElement || elt; |
| 8833 if (!style.hasAttribute(SHIM_ATTRIBUTE)) { | 8839 if (!style.hasAttribute(SHIM_ATTRIBUTE)) { |
| 8834 originalParseGeneric.call(this, elt); | 8840 originalParseGeneric.call(this, elt); |
| 8835 return; | 8841 return; |
| 8836 } | 8842 } |
| 8837 if (elt.__resource) { | 8843 if (elt.__resource) { |
| 8838 style = elt.ownerDocument.createElement('style'); | 8844 style = elt.ownerDocument.createElement('style'); |
| 8839 style.textContent = urlResolver.resolveCssText( | 8845 style.textContent = elt.__resource; |
| 8840 elt.__resource, elt.href); | |
| 8841 } else { | |
| 8842 urlResolver.resolveStyle(style); | |
| 8843 } | 8846 } |
| 8847 // relay on HTMLImports for path fixup |
| 8848 HTMLImports.path.resolveUrlsInStyle(style); |
| 8844 style.textContent = ShadowCSS.shimStyle(style); | 8849 style.textContent = ShadowCSS.shimStyle(style); |
| 8845 style.removeAttribute(SHIM_ATTRIBUTE, ''); | 8850 style.removeAttribute(SHIM_ATTRIBUTE, ''); |
| 8846 style.setAttribute(SHIMMED_ATTRIBUTE, ''); | 8851 style.setAttribute(SHIMMED_ATTRIBUTE, ''); |
| 8847 style[SHIMMED_ATTRIBUTE] = true; | 8852 style[SHIMMED_ATTRIBUTE] = true; |
| 8848 // place in document | 8853 // place in document |
| 8849 if (style.parentNode !== head) { | 8854 if (style.parentNode !== head) { |
| 8850 // replace links in head | 8855 // replace links in head |
| 8851 if (elt.parentNode === head) { | 8856 if (elt.parentNode === head) { |
| 8852 head.replaceChild(style, elt); | 8857 head.replaceChild(style, elt); |
| 8853 } else { | 8858 } else { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8899 if (CustomElements.useNative === false) { | 8904 if (CustomElements.useNative === false) { |
| 8900 var originalCreateShadowRoot = Element.prototype.createShadowRoot; | 8905 var originalCreateShadowRoot = Element.prototype.createShadowRoot; |
| 8901 Element.prototype.createShadowRoot = function() { | 8906 Element.prototype.createShadowRoot = function() { |
| 8902 var root = originalCreateShadowRoot.call(this); | 8907 var root = originalCreateShadowRoot.call(this); |
| 8903 CustomElements.watchShadow(this); | 8908 CustomElements.watchShadow(this); |
| 8904 return root; | 8909 return root; |
| 8905 }; | 8910 }; |
| 8906 } | 8911 } |
| 8907 }); | 8912 }); |
| 8908 | 8913 |
| 8909 Platform.templateContent = function(inTemplate) { | |
| 8910 // if MDV exists, it may need to boostrap this template to reveal content | |
| 8911 if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { | |
| 8912 HTMLTemplateElement.bootstrap(inTemplate); | |
| 8913 } | |
| 8914 // fallback when there is no Shadow DOM polyfill, no MDV polyfill, and no | |
| 8915 // native template support | |
| 8916 if (!inTemplate.content && !inTemplate._content) { | |
| 8917 var frag = document.createDocumentFragment(); | |
| 8918 while (inTemplate.firstChild) { | |
| 8919 frag.appendChild(inTemplate.firstChild); | |
| 8920 } | |
| 8921 inTemplate._content = frag; | |
| 8922 } | |
| 8923 return inTemplate.content || inTemplate._content; | |
| 8924 }; | |
| 8925 | |
| 8926 })(window.Platform); | 8914 })(window.Platform); |
| 8927 | 8915 |
| 8928 } | 8916 } |
| 8929 /* Any copyright is dedicated to the Public Domain. | 8917 /* Any copyright is dedicated to the Public Domain. |
| 8930 * http://creativecommons.org/publicdomain/zero/1.0/ */ | 8918 * http://creativecommons.org/publicdomain/zero/1.0/ */ |
| 8931 | 8919 |
| 8932 (function(scope) { | 8920 (function(scope) { |
| 8933 'use strict'; | 8921 'use strict'; |
| 8934 | 8922 |
| 8935 // feature detect for URL constructor | 8923 // feature detect for URL constructor |
| (...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9523 var self = this; | 9511 var self = this; |
| 9524 var args = Array.prototype.slice.call(arguments, 1); | 9512 var args = Array.prototype.slice.call(arguments, 1); |
| 9525 return function() { | 9513 return function() { |
| 9526 var args2 = args.slice(); | 9514 var args2 = args.slice(); |
| 9527 args2.push.apply(args2, arguments); | 9515 args2.push.apply(args2, arguments); |
| 9528 return self.apply(scope, args2); | 9516 return self.apply(scope, args2); |
| 9529 }; | 9517 }; |
| 9530 }; | 9518 }; |
| 9531 } | 9519 } |
| 9532 | 9520 |
| 9533 // mixin | |
| 9534 | |
| 9535 // copy all properties from inProps (et al) to inObj | |
| 9536 function mixin(inObj/*, inProps, inMoreProps, ...*/) { | |
| 9537 var obj = inObj || {}; | |
| 9538 for (var i = 1; i < arguments.length; i++) { | |
| 9539 var p = arguments[i]; | |
| 9540 try { | |
| 9541 for (var n in p) { | |
| 9542 copyProperty(n, p, obj); | |
| 9543 } | |
| 9544 } catch(x) { | |
| 9545 } | |
| 9546 } | |
| 9547 return obj; | |
| 9548 } | |
| 9549 | |
| 9550 // copy property inName from inSource object to inTarget object | |
| 9551 function copyProperty(inName, inSource, inTarget) { | |
| 9552 var pd = getPropertyDescriptor(inSource, inName); | |
| 9553 Object.defineProperty(inTarget, inName, pd); | |
| 9554 } | |
| 9555 | |
| 9556 // get property descriptor for inName on inObject, even if | |
| 9557 // inName exists on some link in inObject's prototype chain | |
| 9558 function getPropertyDescriptor(inObject, inName) { | |
| 9559 if (inObject) { | |
| 9560 var pd = Object.getOwnPropertyDescriptor(inObject, inName); | |
| 9561 return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName); | |
| 9562 } | |
| 9563 } | |
| 9564 | |
| 9565 // export | |
| 9566 | |
| 9567 scope.mixin = mixin; | |
| 9568 | |
| 9569 })(window.Platform); | 9521 })(window.Platform); |
| 9570 | 9522 |
| 9571 /* | 9523 /* |
| 9572 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 9524 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 9573 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 9525 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 9574 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 9526 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 9575 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 9527 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 9576 * Code distributed by Google as part of the polymer project is also | 9528 * Code distributed by Google as part of the polymer project is also |
| 9577 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 9529 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 9578 */ | 9530 */ |
| 9579 | 9531 |
| 9580 (function(scope) { | 9532 (function(scope) { |
| 9581 | 9533 |
| 9582 'use strict'; | 9534 'use strict'; |
| 9583 | 9535 |
| 9584 // polyfill DOMTokenList | |
| 9585 // * add/remove: allow these methods to take multiple classNames | |
| 9586 // * toggle: add a 2nd argument which forces the given state rather | |
| 9587 // than toggling. | |
| 9588 | |
| 9589 var add = DOMTokenList.prototype.add; | |
| 9590 var remove = DOMTokenList.prototype.remove; | |
| 9591 DOMTokenList.prototype.add = function() { | |
| 9592 for (var i = 0; i < arguments.length; i++) { | |
| 9593 add.call(this, arguments[i]); | |
| 9594 } | |
| 9595 }; | |
| 9596 DOMTokenList.prototype.remove = function() { | |
| 9597 for (var i = 0; i < arguments.length; i++) { | |
| 9598 remove.call(this, arguments[i]); | |
| 9599 } | |
| 9600 }; | |
| 9601 DOMTokenList.prototype.toggle = function(name, bool) { | |
| 9602 if (arguments.length == 1) { | |
| 9603 bool = !this.contains(name); | |
| 9604 } | |
| 9605 bool ? this.add(name) : this.remove(name); | |
| 9606 }; | |
| 9607 DOMTokenList.prototype.switch = function(oldName, newName) { | |
| 9608 oldName && this.remove(oldName); | |
| 9609 newName && this.add(newName); | |
| 9610 }; | |
| 9611 | |
| 9612 // add array() to NodeList, NamedNodeMap, HTMLCollection | |
| 9613 | |
| 9614 var ArraySlice = function() { | |
| 9615 return Array.prototype.slice.call(this); | |
| 9616 }; | |
| 9617 | |
| 9618 var namedNodeMap = (window.NamedNodeMap || window.MozNamedAttrMap || {}); | |
| 9619 | |
| 9620 NodeList.prototype.array = ArraySlice; | |
| 9621 namedNodeMap.prototype.array = ArraySlice; | |
| 9622 HTMLCollection.prototype.array = ArraySlice; | |
| 9623 | |
| 9624 // polyfill performance.now | 9536 // polyfill performance.now |
| 9625 | 9537 |
| 9626 if (!window.performance) { | 9538 if (!window.performance) { |
| 9627 var start = Date.now(); | 9539 var start = Date.now(); |
| 9628 // only at millisecond precision | 9540 // only at millisecond precision |
| 9629 window.performance = {now: function(){ return Date.now() - start }}; | 9541 window.performance = {now: function(){ return Date.now() - start }}; |
| 9630 } | 9542 } |
| 9631 | 9543 |
| 9632 // polyfill for requestAnimationFrame | 9544 // polyfill for requestAnimationFrame |
| 9633 | 9545 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 9651 if (!window.cancelAnimationFrame) { | 9563 if (!window.cancelAnimationFrame) { |
| 9652 window.cancelAnimationFrame = (function() { | 9564 window.cancelAnimationFrame = (function() { |
| 9653 return window.webkitCancelAnimationFrame || | 9565 return window.webkitCancelAnimationFrame || |
| 9654 window.mozCancelAnimationFrame || | 9566 window.mozCancelAnimationFrame || |
| 9655 function(id) { | 9567 function(id) { |
| 9656 clearTimeout(id); | 9568 clearTimeout(id); |
| 9657 }; | 9569 }; |
| 9658 })(); | 9570 })(); |
| 9659 } | 9571 } |
| 9660 | 9572 |
| 9661 // utility | |
| 9662 | |
| 9663 function createDOM(inTagOrNode, inHTML, inAttrs) { | |
| 9664 var dom = typeof inTagOrNode == 'string' ? | |
| 9665 document.createElement(inTagOrNode) : inTagOrNode.cloneNode(true); | |
| 9666 dom.innerHTML = inHTML; | |
| 9667 if (inAttrs) { | |
| 9668 for (var n in inAttrs) { | |
| 9669 dom.setAttribute(n, inAttrs[n]); | |
| 9670 } | |
| 9671 } | |
| 9672 return dom; | |
| 9673 } | |
| 9674 // Make a stub for Polymer() for polyfill purposes; under the HTMLImports | 9573 // Make a stub for Polymer() for polyfill purposes; under the HTMLImports |
| 9675 // polyfill, scripts in the main document run before imports. That means | 9574 // polyfill, scripts in the main document run before imports. That means |
| 9676 // if (1) polymer is imported and (2) Polymer() is called in the main document | 9575 // if (1) polymer is imported and (2) Polymer() is called in the main document |
| 9677 // in a script after the import, 2 occurs before 1. We correct this here | 9576 // in a script after the import, 2 occurs before 1. We correct this here |
| 9678 // by specfiically patching Polymer(); this is not necessary under native | 9577 // by specfiically patching Polymer(); this is not necessary under native |
| 9679 // HTMLImports. | 9578 // HTMLImports. |
| 9680 var elementDeclarations = []; | 9579 var elementDeclarations = []; |
| 9681 | 9580 |
| 9682 var polymerStub = function(name, dictionary) { | 9581 var polymerStub = function(name, dictionary) { |
| 9582 Array.prototype.push.call(arguments, document._currentScript); |
| 9683 elementDeclarations.push(arguments); | 9583 elementDeclarations.push(arguments); |
| 9684 } | 9584 }; |
| 9685 window.Polymer = polymerStub; | 9585 window.Polymer = polymerStub; |
| 9686 | 9586 |
| 9687 // deliver queued delcarations | 9587 // deliver queued delcarations |
| 9688 scope.deliverDeclarations = function() { | 9588 scope.consumeDeclarations = function(callback) { |
| 9689 scope.deliverDeclarations = function() { | 9589 scope.consumeDeclarations = function() { |
| 9690 throw 'Possible attempt to load Polymer twice'; | 9590 throw 'Possible attempt to load Polymer twice'; |
| 9691 }; | 9591 }; |
| 9692 return elementDeclarations; | 9592 if (callback) { |
| 9693 } | 9593 callback(elementDeclarations); |
| 9594 } |
| 9595 elementDeclarations = null; |
| 9596 }; |
| 9694 | 9597 |
| 9695 // Once DOMContent has loaded, any main document scripts that depend on | 9598 // Once DOMContent has loaded, any main document scripts that depend on |
| 9696 // Polymer() should have run. Calling Polymer() now is an error until | 9599 // Polymer() should have run. Calling Polymer() now is an error until |
| 9697 // polymer is imported. | 9600 // polymer is imported. |
| 9698 window.addEventListener('DOMContentLoaded', function() { | 9601 window.addEventListener('DOMContentLoaded', function() { |
| 9699 if (window.Polymer === polymerStub) { | 9602 if (window.Polymer === polymerStub) { |
| 9700 window.Polymer = function() { | 9603 window.Polymer = function() { |
| 9701 console.error('You tried to use polymer without loading it first. To ' + | 9604 console.error('You tried to use polymer without loading it first. To ' + |
| 9702 'load polymer, <link rel="import" href="' + | 9605 'load polymer, <link rel="import" href="' + |
| 9703 'components/polymer/polymer.html">'); | 9606 'components/polymer/polymer.html">'); |
| 9704 }; | 9607 }; |
| 9705 } | 9608 } |
| 9706 }); | 9609 }); |
| 9707 | 9610 |
| 9708 // exports | |
| 9709 scope.createDOM = createDOM; | |
| 9710 | |
| 9711 })(window.Platform); | 9611 })(window.Platform); |
| 9712 | 9612 |
| 9713 /* | 9613 /* |
| 9714 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 9715 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 9716 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 9717 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 9718 * Code distributed by Google as part of the polymer project is also | |
| 9719 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 9720 */ | |
| 9721 | |
| 9722 // poor man's adapter for template.content on various platform scenarios | |
| 9723 (function(scope) { | |
| 9724 scope.templateContent = scope.templateContent || function(inTemplate) { | |
| 9725 return inTemplate.content; | |
| 9726 }; | |
| 9727 })(window.Platform); | |
| 9728 | |
| 9729 /* | |
| 9730 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 9731 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 9732 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 9733 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 9734 * Code distributed by Google as part of the polymer project is also | |
| 9735 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 9736 */ | |
| 9737 | |
| 9738 (function(scope) { | |
| 9739 | |
| 9740 scope = scope || (window.Inspector = {}); | |
| 9741 | |
| 9742 var inspector; | |
| 9743 | |
| 9744 window.sinspect = function(inNode, inProxy) { | |
| 9745 if (!inspector) { | |
| 9746 inspector = window.open('', 'ShadowDOM Inspector', null, true); | |
| 9747 inspector.document.write(inspectorHTML); | |
| 9748 //inspector.document.close(); | |
| 9749 inspector.api = { | |
| 9750 shadowize: shadowize | |
| 9751 }; | |
| 9752 } | |
| 9753 inspect(inNode || wrap(document.body), inProxy); | |
| 9754 }; | |
| 9755 | |
| 9756 var inspectorHTML = [ | |
| 9757 '<!DOCTYPE html>', | |
| 9758 '<html>', | |
| 9759 ' <head>', | |
| 9760 ' <title>ShadowDOM Inspector</title>', | |
| 9761 ' <style>', | |
| 9762 ' body {', | |
| 9763 ' }', | |
| 9764 ' pre {', | |
| 9765 ' font: 9pt "Courier New", monospace;', | |
| 9766 ' line-height: 1.5em;', | |
| 9767 ' }', | |
| 9768 ' tag {', | |
| 9769 ' color: purple;', | |
| 9770 ' }', | |
| 9771 ' ul {', | |
| 9772 ' margin: 0;', | |
| 9773 ' padding: 0;', | |
| 9774 ' list-style: none;', | |
| 9775 ' }', | |
| 9776 ' li {', | |
| 9777 ' display: inline-block;', | |
| 9778 ' background-color: #f1f1f1;', | |
| 9779 ' padding: 4px 6px;', | |
| 9780 ' border-radius: 4px;', | |
| 9781 ' margin-right: 4px;', | |
| 9782 ' }', | |
| 9783 ' </style>', | |
| 9784 ' </head>', | |
| 9785 ' <body>', | |
| 9786 ' <ul id="crumbs">', | |
| 9787 ' </ul>', | |
| 9788 ' <div id="tree"></div>', | |
| 9789 ' </body>', | |
| 9790 '</html>' | |
| 9791 ].join('\n'); | |
| 9792 | |
| 9793 var crumbs = []; | |
| 9794 | |
| 9795 var displayCrumbs = function() { | |
| 9796 // alias our document | |
| 9797 var d = inspector.document; | |
| 9798 // get crumbbar | |
| 9799 var cb = d.querySelector('#crumbs'); | |
| 9800 // clear crumbs | |
| 9801 cb.textContent = ''; | |
| 9802 // build new crumbs | |
| 9803 for (var i=0, c; c=crumbs[i]; i++) { | |
| 9804 var a = d.createElement('a'); | |
| 9805 a.href = '#'; | |
| 9806 a.textContent = c.localName; | |
| 9807 a.idx = i; | |
| 9808 a.onclick = function(event) { | |
| 9809 var c; | |
| 9810 while (crumbs.length > this.idx) { | |
| 9811 c = crumbs.pop(); | |
| 9812 } | |
| 9813 inspect(c.shadow || c, c); | |
| 9814 event.preventDefault(); | |
| 9815 }; | |
| 9816 cb.appendChild(d.createElement('li')).appendChild(a); | |
| 9817 } | |
| 9818 }; | |
| 9819 | |
| 9820 var inspect = function(inNode, inProxy) { | |
| 9821 // alias our document | |
| 9822 var d = inspector.document; | |
| 9823 // reset list of drillable nodes | |
| 9824 drillable = []; | |
| 9825 // memoize our crumb proxy | |
| 9826 var proxy = inProxy || inNode; | |
| 9827 crumbs.push(proxy); | |
| 9828 // update crumbs | |
| 9829 displayCrumbs(); | |
| 9830 // reflect local tree | |
| 9831 d.body.querySelector('#tree').innerHTML = | |
| 9832 '<pre>' + output(inNode, inNode.childNodes) + '</pre>'; | |
| 9833 }; | |
| 9834 | |
| 9835 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); | |
| 9836 | |
| 9837 var blacklisted = {STYLE:1, SCRIPT:1, "#comment": 1, TEMPLATE: 1}; | |
| 9838 var blacklist = function(inNode) { | |
| 9839 return blacklisted[inNode.nodeName]; | |
| 9840 }; | |
| 9841 | |
| 9842 var output = function(inNode, inChildNodes, inIndent) { | |
| 9843 if (blacklist(inNode)) { | |
| 9844 return ''; | |
| 9845 } | |
| 9846 var indent = inIndent || ''; | |
| 9847 if (inNode.localName || inNode.nodeType == 11) { | |
| 9848 var name = inNode.localName || 'shadow-root'; | |
| 9849 //inChildNodes = ShadowDOM.localNodes(inNode); | |
| 9850 var info = indent + describe(inNode); | |
| 9851 // if only textNodes | |
| 9852 // TODO(sjmiles): make correct for ShadowDOM | |
| 9853 /*if (!inNode.children.length && inNode.localName !== 'content' && inNode.
localName !== 'shadow') { | |
| 9854 info += catTextContent(inChildNodes); | |
| 9855 } else*/ { | |
| 9856 // TODO(sjmiles): native <shadow> has no reference to its projection | |
| 9857 if (name == 'content' /*|| name == 'shadow'*/) { | |
| 9858 inChildNodes = inNode.getDistributedNodes(); | |
| 9859 } | |
| 9860 info += '<br/>'; | |
| 9861 var ind = indent + ' '; | |
| 9862 forEach(inChildNodes, function(n) { | |
| 9863 info += output(n, n.childNodes, ind); | |
| 9864 }); | |
| 9865 info += indent; | |
| 9866 } | |
| 9867 if (!({br:1}[name])) { | |
| 9868 info += '<tag></' + name + '></tag>'; | |
| 9869 info += '<br/>'; | |
| 9870 } | |
| 9871 } else { | |
| 9872 var text = inNode.textContent.trim(); | |
| 9873 info = text ? indent + '"' + text + '"' + '<br/>' : ''; | |
| 9874 } | |
| 9875 return info; | |
| 9876 }; | |
| 9877 | |
| 9878 var catTextContent = function(inChildNodes) { | |
| 9879 var info = ''; | |
| 9880 forEach(inChildNodes, function(n) { | |
| 9881 info += n.textContent.trim(); | |
| 9882 }); | |
| 9883 return info; | |
| 9884 }; | |
| 9885 | |
| 9886 var drillable = []; | |
| 9887 | |
| 9888 var describe = function(inNode) { | |
| 9889 var tag = '<tag>' + '<'; | |
| 9890 var name = inNode.localName || 'shadow-root'; | |
| 9891 if (inNode.webkitShadowRoot || inNode.shadowRoot) { | |
| 9892 tag += ' <button idx="' + drillable.length + | |
| 9893 '" onclick="api.shadowize.call(this)">' + name + '</button>'; | |
| 9894 drillable.push(inNode); | |
| 9895 } else { | |
| 9896 tag += name || 'shadow-root'; | |
| 9897 } | |
| 9898 if (inNode.attributes) { | |
| 9899 forEach(inNode.attributes, function(a) { | |
| 9900 tag += ' ' + a.name + (a.value ? '="' + a.value + '"' : ''); | |
| 9901 }); | |
| 9902 } | |
| 9903 tag += '>'+ '</tag>'; | |
| 9904 return tag; | |
| 9905 }; | |
| 9906 | |
| 9907 // remote api | |
| 9908 | |
| 9909 shadowize = function() { | |
| 9910 var idx = Number(this.attributes.idx.value); | |
| 9911 //alert(idx); | |
| 9912 var node = drillable[idx]; | |
| 9913 if (node) { | |
| 9914 inspect(node.webkitShadowRoot || node.shadowRoot, node) | |
| 9915 } else { | |
| 9916 console.log("bad shadowize node"); | |
| 9917 console.dir(this); | |
| 9918 } | |
| 9919 }; | |
| 9920 | |
| 9921 // export | |
| 9922 | |
| 9923 scope.output = output; | |
| 9924 | |
| 9925 })(window.Inspector); | |
| 9926 | |
| 9927 /* | |
| 9928 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 9929 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 9930 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 9931 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 9932 * Code distributed by Google as part of the polymer project is also | |
| 9933 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 9934 */ | |
| 9935 | |
| 9936 (function(scope) { | |
| 9937 | |
| 9938 // TODO(sorvell): It's desireable to provide a default stylesheet | |
| 9939 // that's convenient for styling unresolved elements, but | |
| 9940 // it's cumbersome to have to include this manually in every page. | |
| 9941 // It would make sense to put inside some HTMLImport but | |
| 9942 // the HTMLImports polyfill does not allow loading of stylesheets | |
| 9943 // that block rendering. Therefore this injection is tolerated here. | |
| 9944 | |
| 9945 var style = document.createElement('style'); | |
| 9946 style.textContent = '' | |
| 9947 + 'body {' | |
| 9948 + 'transition: opacity ease-in 0.2s;' | |
| 9949 + ' } \n' | |
| 9950 + 'body[unresolved] {' | |
| 9951 + 'opacity: 0; display: block; overflow: hidden;' | |
| 9952 + ' } \n' | |
| 9953 ; | |
| 9954 var head = document.querySelector('head'); | |
| 9955 head.insertBefore(style, head.firstChild); | |
| 9956 | |
| 9957 })(Platform); | |
| 9958 | |
| 9959 /* | |
| 9960 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 9961 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 9962 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 9963 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 9964 * Code distributed by Google as part of the polymer project is also | |
| 9965 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 9966 */ | |
| 9967 | |
| 9968 (function(scope) { | |
| 9969 | |
| 9970 function withDependencies(task, depends) { | |
| 9971 depends = depends || []; | |
| 9972 if (!depends.map) { | |
| 9973 depends = [depends]; | |
| 9974 } | |
| 9975 return task.apply(this, depends.map(marshal)); | |
| 9976 } | |
| 9977 | |
| 9978 function module(name, dependsOrFactory, moduleFactory) { | |
| 9979 var module; | |
| 9980 switch (arguments.length) { | |
| 9981 case 0: | |
| 9982 return; | |
| 9983 case 1: | |
| 9984 module = null; | |
| 9985 break; | |
| 9986 case 2: | |
| 9987 // dependsOrFactory is `factory` in this case | |
| 9988 module = dependsOrFactory.apply(this); | |
| 9989 break; | |
| 9990 default: | |
| 9991 // dependsOrFactory is `depends` in this case | |
| 9992 module = withDependencies(moduleFactory, dependsOrFactory); | |
| 9993 break; | |
| 9994 } | |
| 9995 modules[name] = module; | |
| 9996 }; | |
| 9997 | |
| 9998 function marshal(name) { | |
| 9999 return modules[name]; | |
| 10000 } | |
| 10001 | |
| 10002 var modules = {}; | |
| 10003 | |
| 10004 function using(depends, task) { | |
| 10005 HTMLImports.whenImportsReady(function() { | |
| 10006 withDependencies(task, depends); | |
| 10007 }); | |
| 10008 }; | |
| 10009 | |
| 10010 // exports | |
| 10011 | |
| 10012 scope.marshal = marshal; | |
| 10013 // `module` confuses commonjs detectors | |
| 10014 scope.modularize = module; | |
| 10015 scope.using = using; | |
| 10016 | |
| 10017 })(window); | |
| 10018 | |
| 10019 /* | |
| 10020 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 10021 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 10022 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 10023 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 10024 * Code distributed by Google as part of the polymer project is also | |
| 10025 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 10026 */ | |
| 10027 | |
| 10028 (function(scope) { | |
| 10029 | |
| 10030 var iterations = 0; | |
| 10031 var callbacks = []; | |
| 10032 var twiddle = document.createTextNode(''); | |
| 10033 | |
| 10034 function endOfMicrotask(callback) { | |
| 10035 twiddle.textContent = iterations++; | |
| 10036 callbacks.push(callback); | |
| 10037 } | |
| 10038 | |
| 10039 function atEndOfMicrotask() { | |
| 10040 while (callbacks.length) { | |
| 10041 callbacks.shift()(); | |
| 10042 } | |
| 10043 } | |
| 10044 | |
| 10045 new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask) | |
| 10046 .observe(twiddle, {characterData: true}) | |
| 10047 ; | |
| 10048 | |
| 10049 // exports | |
| 10050 | |
| 10051 scope.endOfMicrotask = endOfMicrotask; | |
| 10052 | |
| 10053 })(Platform); | |
| 10054 | |
| 10055 | |
| 10056 /* | |
| 10057 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 10058 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 10059 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 10060 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 10061 * Code distributed by Google as part of the polymer project is also | |
| 10062 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 10063 */ | |
| 10064 | |
| 10065 (function(scope) { | |
| 10066 | |
| 10067 var urlResolver = { | |
| 10068 resolveDom: function(root, url) { | |
| 10069 url = url || root.ownerDocument.baseURI; | |
| 10070 this.resolveAttributes(root, url); | |
| 10071 this.resolveStyles(root, url); | |
| 10072 // handle template.content | |
| 10073 var templates = root.querySelectorAll('template'); | |
| 10074 if (templates) { | |
| 10075 for (var i = 0, l = templates.length, t; (i < l) && (t = templates[i]); i+
+) { | |
| 10076 if (t.content) { | |
| 10077 this.resolveDom(t.content, url); | |
| 10078 } | |
| 10079 } | |
| 10080 } | |
| 10081 }, | |
| 10082 resolveTemplate: function(template) { | |
| 10083 this.resolveDom(template.content, template.ownerDocument.baseURI); | |
| 10084 }, | |
| 10085 resolveStyles: function(root, url) { | |
| 10086 var styles = root.querySelectorAll('style'); | |
| 10087 if (styles) { | |
| 10088 for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) { | |
| 10089 this.resolveStyle(s, url); | |
| 10090 } | |
| 10091 } | |
| 10092 }, | |
| 10093 resolveStyle: function(style, url) { | |
| 10094 url = url || style.ownerDocument.baseURI; | |
| 10095 style.textContent = this.resolveCssText(style.textContent, url); | |
| 10096 }, | |
| 10097 resolveCssText: function(cssText, baseUrl, keepAbsolute) { | |
| 10098 cssText = replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_URL_REGEX
P); | |
| 10099 return replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_IMPORT_REGEX
P); | |
| 10100 }, | |
| 10101 resolveAttributes: function(root, url) { | |
| 10102 if (root.hasAttributes && root.hasAttributes()) { | |
| 10103 this.resolveElementAttributes(root, url); | |
| 10104 } | |
| 10105 // search for attributes that host urls | |
| 10106 var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR); | |
| 10107 if (nodes) { | |
| 10108 for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) { | |
| 10109 this.resolveElementAttributes(n, url); | |
| 10110 } | |
| 10111 } | |
| 10112 }, | |
| 10113 resolveElementAttributes: function(node, url) { | |
| 10114 url = url || node.ownerDocument.baseURI; | |
| 10115 URL_ATTRS.forEach(function(v) { | |
| 10116 var attr = node.attributes[v]; | |
| 10117 var value = attr && attr.value; | |
| 10118 var replacement; | |
| 10119 if (value && value.search(URL_TEMPLATE_SEARCH) < 0) { | |
| 10120 if (v === 'style') { | |
| 10121 replacement = replaceUrlsInCssText(value, url, false, CSS_URL_REGEXP); | |
| 10122 } else { | |
| 10123 replacement = resolveRelativeUrl(url, value); | |
| 10124 } | |
| 10125 attr.value = replacement; | |
| 10126 } | |
| 10127 }); | |
| 10128 } | |
| 10129 }; | |
| 10130 | |
| 10131 var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g; | |
| 10132 var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g; | |
| 10133 var URL_ATTRS = ['href', 'src', 'action', 'style', 'url']; | |
| 10134 var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']'; | |
| 10135 var URL_TEMPLATE_SEARCH = '{{.*}}'; | |
| 10136 | |
| 10137 function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) { | |
| 10138 return cssText.replace(regexp, function(m, pre, url, post) { | |
| 10139 var urlPath = url.replace(/["']/g, ''); | |
| 10140 urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute); | |
| 10141 return pre + '\'' + urlPath + '\'' + post; | |
| 10142 }); | |
| 10143 } | |
| 10144 | |
| 10145 function resolveRelativeUrl(baseUrl, url, keepAbsolute) { | |
| 10146 // do not resolve '/' absolute urls | |
| 10147 if (url && url[0] === '/') { | |
| 10148 return url; | |
| 10149 } | |
| 10150 var u = new URL(url, baseUrl); | |
| 10151 return keepAbsolute ? u.href : makeDocumentRelPath(u.href); | |
| 10152 } | |
| 10153 | |
| 10154 function makeDocumentRelPath(url) { | |
| 10155 var root = new URL(document.baseURI); | |
| 10156 var u = new URL(url, root); | |
| 10157 if (u.host === root.host && u.port === root.port && | |
| 10158 u.protocol === root.protocol) { | |
| 10159 return makeRelPath(root, u); | |
| 10160 } else { | |
| 10161 return url; | |
| 10162 } | |
| 10163 } | |
| 10164 | |
| 10165 // make a relative path from source to target | |
| 10166 function makeRelPath(sourceUrl, targetUrl) { | |
| 10167 var source = sourceUrl.pathname; | |
| 10168 var target = targetUrl.pathname; | |
| 10169 var s = source.split('/'); | |
| 10170 var t = target.split('/'); | |
| 10171 while (s.length && s[0] === t[0]){ | |
| 10172 s.shift(); | |
| 10173 t.shift(); | |
| 10174 } | |
| 10175 for (var i = 0, l = s.length - 1; i < l; i++) { | |
| 10176 t.unshift('..'); | |
| 10177 } | |
| 10178 return t.join('/') + targetUrl.search + targetUrl.hash; | |
| 10179 } | |
| 10180 | |
| 10181 // exports | |
| 10182 scope.urlResolver = urlResolver; | |
| 10183 | |
| 10184 })(Platform); | |
| 10185 | |
| 10186 /* | |
| 10187 * Copyright 2012 The Polymer Authors. All rights reserved. | 9614 * Copyright 2012 The Polymer Authors. All rights reserved. |
| 10188 * Use of this source code is goverened by a BSD-style | 9615 * Use of this source code is goverened by a BSD-style |
| 10189 * license that can be found in the LICENSE file. | 9616 * license that can be found in the LICENSE file. |
| 10190 */ | 9617 */ |
| 10191 | 9618 |
| 10192 (function(global) { | 9619 (function(global) { |
| 10193 | 9620 |
| 10194 var registrationsTable = new WeakMap(); | 9621 var registrationsTable = new WeakMap(); |
| 10195 | 9622 |
| 10196 // We use setImmediate or postMessage for our future callback. | 9623 // We use setImmediate or postMessage for our future callback. |
| (...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10735 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 10162 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 10736 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 10163 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 10737 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 10164 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 10738 * Code distributed by Google as part of the polymer project is also | 10165 * Code distributed by Google as part of the polymer project is also |
| 10739 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 10166 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 10740 */ | 10167 */ |
| 10741 window.HTMLImports = window.HTMLImports || {flags:{}}; | 10168 window.HTMLImports = window.HTMLImports || {flags:{}}; |
| 10742 /* | 10169 /* |
| 10743 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 10170 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 10744 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 10171 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 10172 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 10173 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 10174 * Code distributed by Google as part of the polymer project is also |
| 10175 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 10176 */ |
| 10177 |
| 10178 (function(scope) { |
| 10179 |
| 10180 var hasNative = ('import' in document.createElement('link')); |
| 10181 var useNative = hasNative; |
| 10182 |
| 10183 isIE = /Trident/.test(navigator.userAgent); |
| 10184 |
| 10185 // TODO(sorvell): SD polyfill intrusion |
| 10186 var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill); |
| 10187 var wrap = function(node) { |
| 10188 return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node; |
| 10189 }; |
| 10190 var mainDoc = wrap(document); |
| 10191 |
| 10192 // NOTE: We cannot polyfill document.currentScript because it's not possible |
| 10193 // both to override and maintain the ability to capture the native value; |
| 10194 // therefore we choose to expose _currentScript both when native imports |
| 10195 // and the polyfill are in use. |
| 10196 var currentScriptDescriptor = { |
| 10197 get: function() { |
| 10198 var script = HTMLImports.currentScript || document.currentScript || |
| 10199 // NOTE: only works when called in synchronously executing code. |
| 10200 // readyState should check if `loading` but IE10 is |
| 10201 // interactive when scripts run so we cheat. |
| 10202 (document.readyState !== 'complete' ? |
| 10203 document.scripts[document.scripts.length - 1] : null); |
| 10204 return wrap(script); |
| 10205 }, |
| 10206 configurable: true |
| 10207 }; |
| 10208 |
| 10209 Object.defineProperty(document, '_currentScript', currentScriptDescriptor); |
| 10210 Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor); |
| 10211 |
| 10212 // call a callback when all HTMLImports in the document at call (or at least |
| 10213 // document ready) time have loaded. |
| 10214 // 1. ensure the document is in a ready state (has dom), then |
| 10215 // 2. watch for loading of imports and call callback when done |
| 10216 function whenImportsReady(callback, doc) { |
| 10217 doc = doc || mainDoc; |
| 10218 // if document is loading, wait and try again |
| 10219 whenDocumentReady(function() { |
| 10220 watchImportsLoad(callback, doc); |
| 10221 }, doc); |
| 10222 } |
| 10223 |
| 10224 // call the callback when the document is in a ready state (has dom) |
| 10225 var requiredReadyState = isIE ? 'complete' : 'interactive'; |
| 10226 var READY_EVENT = 'readystatechange'; |
| 10227 function isDocumentReady(doc) { |
| 10228 return (doc.readyState === 'complete' || |
| 10229 doc.readyState === requiredReadyState); |
| 10230 } |
| 10231 |
| 10232 // call <callback> when we ensure the document is in a ready state |
| 10233 function whenDocumentReady(callback, doc) { |
| 10234 if (!isDocumentReady(doc)) { |
| 10235 var checkReady = function() { |
| 10236 if (doc.readyState === 'complete' || |
| 10237 doc.readyState === requiredReadyState) { |
| 10238 doc.removeEventListener(READY_EVENT, checkReady); |
| 10239 whenDocumentReady(callback, doc); |
| 10240 } |
| 10241 }; |
| 10242 doc.addEventListener(READY_EVENT, checkReady); |
| 10243 } else if (callback) { |
| 10244 callback(); |
| 10245 } |
| 10246 } |
| 10247 |
| 10248 function markTargetLoaded(event) { |
| 10249 event.target.__loaded = true; |
| 10250 } |
| 10251 |
| 10252 // call <callback> when we ensure all imports have loaded |
| 10253 function watchImportsLoad(callback, doc) { |
| 10254 var imports = doc.querySelectorAll('link[rel=import]'); |
| 10255 var loaded = 0, l = imports.length; |
| 10256 function checkDone(d) { |
| 10257 if (loaded == l) { |
| 10258 callback && callback(); |
| 10259 } |
| 10260 } |
| 10261 function loadedImport(e) { |
| 10262 markTargetLoaded(e); |
| 10263 loaded++; |
| 10264 checkDone(); |
| 10265 } |
| 10266 if (l) { |
| 10267 for (var i=0, imp; (i<l) && (imp=imports[i]); i++) { |
| 10268 if (isImportLoaded(imp)) { |
| 10269 loadedImport.call(imp, {target: imp}); |
| 10270 } else { |
| 10271 imp.addEventListener('load', loadedImport); |
| 10272 imp.addEventListener('error', loadedImport); |
| 10273 } |
| 10274 } |
| 10275 } else { |
| 10276 checkDone(); |
| 10277 } |
| 10278 } |
| 10279 |
| 10280 // NOTE: test for native imports loading is based on explicitly watching |
| 10281 // all imports (see below). |
| 10282 function isImportLoaded(link) { |
| 10283 return useNative ? link.__loaded : link.__importParsed; |
| 10284 } |
| 10285 |
| 10286 // TODO(sorvell): Workaround for |
| 10287 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007, should be removed when |
| 10288 // this bug is addressed. |
| 10289 // (1) Install a mutation observer to see when HTMLImports have loaded |
| 10290 // (2) if this script is run during document load it will watch any existing |
| 10291 // imports for loading. |
| 10292 // |
| 10293 // NOTE: The workaround has restricted functionality: (1) it's only compatible |
| 10294 // with imports that are added to document.head since the mutation observer |
| 10295 // watches only head for perf reasons, (2) it requires this script |
| 10296 // to run before any imports have completed loading. |
| 10297 if (useNative) { |
| 10298 new MutationObserver(function(mxns) { |
| 10299 for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) { |
| 10300 if (m.addedNodes) { |
| 10301 handleImports(m.addedNodes); |
| 10302 } |
| 10303 } |
| 10304 }).observe(document.head, {childList: true}); |
| 10305 |
| 10306 function handleImports(nodes) { |
| 10307 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) { |
| 10308 if (isImport(n)) { |
| 10309 handleImport(n); |
| 10310 } |
| 10311 } |
| 10312 } |
| 10313 |
| 10314 function isImport(element) { |
| 10315 return element.localName === 'link' && element.rel === 'import'; |
| 10316 } |
| 10317 |
| 10318 function handleImport(element) { |
| 10319 var loaded = element.import; |
| 10320 if (loaded) { |
| 10321 markTargetLoaded({target: element}); |
| 10322 } else { |
| 10323 element.addEventListener('load', markTargetLoaded); |
| 10324 element.addEventListener('error', markTargetLoaded); |
| 10325 } |
| 10326 } |
| 10327 |
| 10328 // make sure to catch any imports that are in the process of loading |
| 10329 // when this script is run. |
| 10330 (function() { |
| 10331 if (document.readyState === 'loading') { |
| 10332 var imports = document.querySelectorAll('link[rel=import]'); |
| 10333 for (var i=0, l=imports.length, imp; (i<l) && (imp=imports[i]); i++) { |
| 10334 handleImport(imp); |
| 10335 } |
| 10336 } |
| 10337 })(); |
| 10338 |
| 10339 } |
| 10340 |
| 10341 // Fire the 'HTMLImportsLoaded' event when imports in document at load time |
| 10342 // have loaded. This event is required to simulate the script blocking |
| 10343 // behavior of native imports. A main document script that needs to be sure |
| 10344 // imports have loaded should wait for this event. |
| 10345 whenImportsReady(function() { |
| 10346 HTMLImports.ready = true; |
| 10347 HTMLImports.readyTime = new Date().getTime(); |
| 10348 mainDoc.dispatchEvent( |
| 10349 new CustomEvent('HTMLImportsLoaded', {bubbles: true}) |
| 10350 ); |
| 10351 }); |
| 10352 |
| 10353 // exports |
| 10354 scope.useNative = useNative; |
| 10355 scope.isImportLoaded = isImportLoaded; |
| 10356 scope.whenReady = whenImportsReady; |
| 10357 scope.isIE = isIE; |
| 10358 |
| 10359 // deprecated |
| 10360 scope.whenImportsReady = whenImportsReady; |
| 10361 |
| 10362 })(window.HTMLImports); |
| 10363 /* |
| 10364 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 10365 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 10745 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 10366 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 10746 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 10367 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 10747 * Code distributed by Google as part of the polymer project is also | 10368 * Code distributed by Google as part of the polymer project is also |
| 10748 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 10369 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 10749 */(function(scope) { | |
| 10750 | |
| 10751 var hasNative = ('import' in document.createElement('link')); | |
| 10752 var useNative = hasNative; | |
| 10753 | |
| 10754 isIE = /Trident/.test(navigator.userAgent); | |
| 10755 | |
| 10756 // TODO(sorvell): SD polyfill intrusion | |
| 10757 var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill); | |
| 10758 var wrap = function(node) { | |
| 10759 return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node; | |
| 10760 }; | |
| 10761 var mainDoc = wrap(document); | |
| 10762 | |
| 10763 // NOTE: We cannot polyfill document.currentScript because it's not possible | |
| 10764 // both to override and maintain the ability to capture the native value; | |
| 10765 // therefore we choose to expose _currentScript both when native imports | |
| 10766 // and the polyfill are in use. | |
| 10767 var currentScriptDescriptor = { | |
| 10768 get: function() { | |
| 10769 var script = HTMLImports.currentScript || document.currentScript || | |
| 10770 // NOTE: only works when called in synchronously executing code. | |
| 10771 // readyState should check if `loading` but IE10 is | |
| 10772 // interactive when scripts run so we cheat. | |
| 10773 (document.readyState !== 'complete' ? | |
| 10774 document.scripts[document.scripts.length - 1] : null); | |
| 10775 return wrap(script); | |
| 10776 }, | |
| 10777 configurable: true | |
| 10778 }; | |
| 10779 | |
| 10780 Object.defineProperty(document, '_currentScript', currentScriptDescriptor); | |
| 10781 Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor); | |
| 10782 | |
| 10783 // call a callback when all HTMLImports in the document at call (or at least | |
| 10784 // document ready) time have loaded. | |
| 10785 // 1. ensure the document is in a ready state (has dom), then | |
| 10786 // 2. watch for loading of imports and call callback when done | |
| 10787 function whenImportsReady(callback, doc) { | |
| 10788 doc = doc || mainDoc; | |
| 10789 // if document is loading, wait and try again | |
| 10790 whenDocumentReady(function() { | |
| 10791 watchImportsLoad(callback, doc); | |
| 10792 }, doc); | |
| 10793 } | |
| 10794 | |
| 10795 // call the callback when the document is in a ready state (has dom) | |
| 10796 var requiredReadyState = isIE ? 'complete' : 'interactive'; | |
| 10797 var READY_EVENT = 'readystatechange'; | |
| 10798 function isDocumentReady(doc) { | |
| 10799 return (doc.readyState === 'complete' || | |
| 10800 doc.readyState === requiredReadyState); | |
| 10801 } | |
| 10802 | |
| 10803 // call <callback> when we ensure the document is in a ready state | |
| 10804 function whenDocumentReady(callback, doc) { | |
| 10805 if (!isDocumentReady(doc)) { | |
| 10806 var checkReady = function() { | |
| 10807 if (doc.readyState === 'complete' || | |
| 10808 doc.readyState === requiredReadyState) { | |
| 10809 doc.removeEventListener(READY_EVENT, checkReady); | |
| 10810 whenDocumentReady(callback, doc); | |
| 10811 } | |
| 10812 } | |
| 10813 doc.addEventListener(READY_EVENT, checkReady); | |
| 10814 } else if (callback) { | |
| 10815 callback(); | |
| 10816 } | |
| 10817 } | |
| 10818 | |
| 10819 // call <callback> when we ensure all imports have loaded | |
| 10820 function watchImportsLoad(callback, doc) { | |
| 10821 var imports = doc.querySelectorAll('link[rel=import]'); | |
| 10822 var loaded = 0, l = imports.length; | |
| 10823 function checkDone(d) { | |
| 10824 if (loaded == l) { | |
| 10825 callback && callback(); | |
| 10826 } | |
| 10827 } | |
| 10828 function loadedImport(e) { | |
| 10829 loaded++; | |
| 10830 checkDone(); | |
| 10831 } | |
| 10832 if (l) { | |
| 10833 for (var i=0, imp; (i<l) && (imp=imports[i]); i++) { | |
| 10834 if (isImportLoaded(imp)) { | |
| 10835 loadedImport.call(imp); | |
| 10836 } else { | |
| 10837 imp.addEventListener('load', loadedImport); | |
| 10838 imp.addEventListener('error', loadedImport); | |
| 10839 } | |
| 10840 } | |
| 10841 } else { | |
| 10842 checkDone(); | |
| 10843 } | |
| 10844 } | |
| 10845 | |
| 10846 // NOTE: test for native imports loading is based on explicitly watching | |
| 10847 // all imports (see below). | |
| 10848 function isImportLoaded(link) { | |
| 10849 return useNative ? link.__loaded : link.__importParsed; | |
| 10850 } | |
| 10851 | |
| 10852 // TODO(sorvell): install a mutation observer to see if HTMLImports have loaded | |
| 10853 // this is a workaround for https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007 | |
| 10854 // and should be removed when this bug is addressed. | |
| 10855 if (useNative) { | |
| 10856 new MutationObserver(function(mxns) { | |
| 10857 for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) { | |
| 10858 if (m.addedNodes) { | |
| 10859 handleImports(m.addedNodes); | |
| 10860 } | |
| 10861 } | |
| 10862 }).observe(document.head, {childList: true}); | |
| 10863 | |
| 10864 function handleImports(nodes) { | |
| 10865 for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) { | |
| 10866 if (isImport(n)) { | |
| 10867 handleImport(n); | |
| 10868 } | |
| 10869 } | |
| 10870 } | |
| 10871 | |
| 10872 function isImport(element) { | |
| 10873 return element.localName === 'link' && element.rel === 'import'; | |
| 10874 } | |
| 10875 | |
| 10876 function handleImport(element) { | |
| 10877 var loaded = element.import; | |
| 10878 if (loaded) { | |
| 10879 markTargetLoaded({target: element}); | |
| 10880 } else { | |
| 10881 element.addEventListener('load', markTargetLoaded); | |
| 10882 element.addEventListener('error', markTargetLoaded); | |
| 10883 } | |
| 10884 } | |
| 10885 | |
| 10886 function markTargetLoaded(event) { | |
| 10887 event.target.__loaded = true; | |
| 10888 } | |
| 10889 | |
| 10890 } | |
| 10891 | |
| 10892 // Fire the 'HTMLImportsLoaded' event when imports in document at load time | |
| 10893 // have loaded. This event is required to simulate the script blocking | |
| 10894 // behavior of native imports. A main document script that needs to be sure | |
| 10895 // imports have loaded should wait for this event. | |
| 10896 whenImportsReady(function() { | |
| 10897 HTMLImports.ready = true; | |
| 10898 HTMLImports.readyTime = new Date().getTime(); | |
| 10899 mainDoc.dispatchEvent( | |
| 10900 new CustomEvent('HTMLImportsLoaded', {bubbles: true}) | |
| 10901 ); | |
| 10902 }); | |
| 10903 | |
| 10904 // exports | |
| 10905 scope.useNative = useNative; | |
| 10906 scope.isImportLoaded = isImportLoaded; | |
| 10907 scope.whenReady = whenImportsReady; | |
| 10908 scope.isIE = isIE; | |
| 10909 | |
| 10910 // deprecated | |
| 10911 scope.whenImportsReady = whenImportsReady; | |
| 10912 | |
| 10913 })(window.HTMLImports); | |
| 10914 | |
| 10915 /* | |
| 10916 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 10917 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 10918 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 10919 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 10920 * Code distributed by Google as part of the polymer project is also | |
| 10921 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 10922 */ | 10370 */ |
| 10923 (function(scope) { | 10371 (function(scope) { |
| 10924 | 10372 |
| 10925 // imports | 10373 // imports |
| 10926 var path = scope.path; | 10374 var path = scope.path; |
| 10927 var xhr = scope.xhr; | 10375 var xhr = scope.xhr; |
| 10928 var flags = scope.flags; | 10376 var flags = scope.flags; |
| 10929 | 10377 |
| 10930 // TODO(sorvell): this loader supports a dynamic list of urls | 10378 // TODO(sorvell): this loader supports a dynamic list of urls |
| 10931 // and an oncomplete callback that is called when the loader is done. | 10379 // and an oncomplete callback that is called when the loader is done. |
| (...skipping 1791 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12723 /* | 12171 /* |
| 12724 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 12172 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 12725 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 12173 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 12726 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 12174 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 12727 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 12175 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 12728 * Code distributed by Google as part of the polymer project is also | 12176 * Code distributed by Google as part of the polymer project is also |
| 12729 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 12177 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 12730 */ | 12178 */ |
| 12731 | 12179 |
| 12732 (function(scope) { | 12180 (function(scope) { |
| 12733 var endOfMicrotask = scope.endOfMicrotask; | |
| 12734 | 12181 |
| 12735 // Generic url loader | 12182 // TODO(sorvell): It's desireable to provide a default stylesheet |
| 12736 function Loader(regex) { | 12183 // that's convenient for styling unresolved elements, but |
| 12737 this.cache = Object.create(null); | 12184 // it's cumbersome to have to include this manually in every page. |
| 12738 this.map = Object.create(null); | 12185 // It would make sense to put inside some HTMLImport but |
| 12739 this.requests = 0; | 12186 // the HTMLImports polyfill does not allow loading of stylesheets |
| 12740 this.regex = regex; | 12187 // that block rendering. Therefore this injection is tolerated here. |
| 12741 } | |
| 12742 Loader.prototype = { | |
| 12743 | 12188 |
| 12744 // TODO(dfreedm): there may be a better factoring here | 12189 var style = document.createElement('style'); |
| 12745 // extract absolute urls from the text (full of relative urls) | 12190 style.textContent = '' |
| 12746 extractUrls: function(text, base) { | 12191 + 'body {' |
| 12747 var matches = []; | 12192 + 'transition: opacity ease-in 0.2s;' |
| 12748 var matched, u; | 12193 + ' } \n' |
| 12749 while ((matched = this.regex.exec(text))) { | 12194 + 'body[unresolved] {' |
| 12750 u = new URL(matched[1], base); | 12195 + 'opacity: 0; display: block; overflow: hidden;' |
| 12751 matches.push({matched: matched[0], url: u.href}); | 12196 + ' } \n' |
| 12752 } | 12197 ; |
| 12753 return matches; | 12198 var head = document.querySelector('head'); |
| 12754 }, | 12199 head.insertBefore(style, head.firstChild); |
| 12755 // take a text blob, a root url, and a callback and load all the urls found
within the text | |
| 12756 // returns a map of absolute url to text | |
| 12757 process: function(text, root, callback) { | |
| 12758 var matches = this.extractUrls(text, root); | |
| 12759 | 12200 |
| 12760 // every call to process returns all the text this loader has ever receive
d | 12201 })(Platform); |
| 12761 var done = callback.bind(null, this.map); | |
| 12762 this.fetch(matches, done); | |
| 12763 }, | |
| 12764 // build a mapping of url -> text from matches | |
| 12765 fetch: function(matches, callback) { | |
| 12766 var inflight = matches.length; | |
| 12767 | |
| 12768 // return early if there is no fetching to be done | |
| 12769 if (!inflight) { | |
| 12770 return callback(); | |
| 12771 } | |
| 12772 | |
| 12773 // wait for all subrequests to return | |
| 12774 var done = function() { | |
| 12775 if (--inflight === 0) { | |
| 12776 callback(); | |
| 12777 } | |
| 12778 }; | |
| 12779 | |
| 12780 // start fetching all subrequests | |
| 12781 var m, req, url; | |
| 12782 for (var i = 0; i < inflight; i++) { | |
| 12783 m = matches[i]; | |
| 12784 url = m.url; | |
| 12785 req = this.cache[url]; | |
| 12786 // if this url has already been requested, skip requesting it again | |
| 12787 if (!req) { | |
| 12788 req = this.xhr(url); | |
| 12789 req.match = m; | |
| 12790 this.cache[url] = req; | |
| 12791 } | |
| 12792 // wait for the request to process its subrequests | |
| 12793 req.wait(done); | |
| 12794 } | |
| 12795 }, | |
| 12796 handleXhr: function(request) { | |
| 12797 var match = request.match; | |
| 12798 var url = match.url; | |
| 12799 | |
| 12800 // handle errors with an empty string | |
| 12801 var response = request.response || request.responseText || ''; | |
| 12802 this.map[url] = response; | |
| 12803 this.fetch(this.extractUrls(response, url), request.resolve); | |
| 12804 }, | |
| 12805 xhr: function(url) { | |
| 12806 this.requests++; | |
| 12807 var request = new XMLHttpRequest(); | |
| 12808 request.open('GET', url, true); | |
| 12809 request.send(); | |
| 12810 request.onerror = request.onload = this.handleXhr.bind(this, request); | |
| 12811 | |
| 12812 // queue of tasks to run after XHR returns | |
| 12813 request.pending = []; | |
| 12814 request.resolve = function() { | |
| 12815 var pending = request.pending; | |
| 12816 for(var i = 0; i < pending.length; i++) { | |
| 12817 pending[i](); | |
| 12818 } | |
| 12819 request.pending = null; | |
| 12820 }; | |
| 12821 | |
| 12822 // if we have already resolved, pending is null, async call the callback | |
| 12823 request.wait = function(fn) { | |
| 12824 if (request.pending) { | |
| 12825 request.pending.push(fn); | |
| 12826 } else { | |
| 12827 endOfMicrotask(fn); | |
| 12828 } | |
| 12829 }; | |
| 12830 | |
| 12831 return request; | |
| 12832 } | |
| 12833 }; | |
| 12834 | |
| 12835 scope.Loader = Loader; | |
| 12836 })(window.Platform); | |
| 12837 | 12202 |
| 12838 /* | 12203 /* |
| 12839 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | 12204 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
| 12840 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | 12205 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt |
| 12841 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | 12206 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt |
| 12842 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | 12207 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt |
| 12843 * Code distributed by Google as part of the polymer project is also | 12208 * Code distributed by Google as part of the polymer project is also |
| 12844 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | 12209 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt |
| 12845 */ | 12210 */ |
| 12846 | 12211 |
| 12847 (function(scope) { | 12212 (function(scope) { |
| 12848 | 12213 |
| 12849 var urlResolver = scope.urlResolver; | 12214 function withDependencies(task, depends) { |
| 12850 var Loader = scope.Loader; | 12215 depends = depends || []; |
| 12851 | 12216 if (!depends.map) { |
| 12852 function StyleResolver() { | 12217 depends = [depends]; |
| 12853 this.loader = new Loader(this.regex); | |
| 12854 } | |
| 12855 StyleResolver.prototype = { | |
| 12856 regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g, | |
| 12857 // Recursively replace @imports with the text at that url | |
| 12858 resolve: function(text, url, callback) { | |
| 12859 var done = function(map) { | |
| 12860 callback(this.flatten(text, url, map)); | |
| 12861 }.bind(this); | |
| 12862 this.loader.process(text, url, done); | |
| 12863 }, | |
| 12864 // resolve the textContent of a style node | |
| 12865 resolveNode: function(style, url, callback) { | |
| 12866 var text = style.textContent; | |
| 12867 var done = function(text) { | |
| 12868 style.textContent = text; | |
| 12869 callback(style); | |
| 12870 }; | |
| 12871 this.resolve(text, url, done); | |
| 12872 }, | |
| 12873 // flatten all the @imports to text | |
| 12874 flatten: function(text, base, map) { | |
| 12875 var matches = this.loader.extractUrls(text, base); | |
| 12876 var match, url, intermediate; | |
| 12877 for (var i = 0; i < matches.length; i++) { | |
| 12878 match = matches[i]; | |
| 12879 url = match.url; | |
| 12880 // resolve any css text to be relative to the importer, keep absolute url | |
| 12881 intermediate = urlResolver.resolveCssText(map[url], url, true); | |
| 12882 // flatten intermediate @imports | |
| 12883 intermediate = this.flatten(intermediate, base, map); | |
| 12884 text = text.replace(match.matched, intermediate); | |
| 12885 } | 12218 } |
| 12886 return text; | 12219 return task.apply(this, depends.map(marshal)); |
| 12887 }, | |
| 12888 loadStyles: function(styles, base, callback) { | |
| 12889 var loaded=0, l = styles.length; | |
| 12890 // called in the context of the style | |
| 12891 function loadedStyle(style) { | |
| 12892 loaded++; | |
| 12893 if (loaded === l && callback) { | |
| 12894 callback(); | |
| 12895 } | |
| 12896 } | |
| 12897 for (var i=0, s; (i<l) && (s=styles[i]); i++) { | |
| 12898 this.resolveNode(s, base, loadedStyle); | |
| 12899 } | |
| 12900 } | |
| 12901 }; | |
| 12902 | |
| 12903 var styleResolver = new StyleResolver(); | |
| 12904 | |
| 12905 // exports | |
| 12906 scope.styleResolver = styleResolver; | |
| 12907 | |
| 12908 })(window.Platform); | |
| 12909 | |
| 12910 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 12911 // This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 12912 // The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 12913 // The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 12914 // Code distributed by Google as part of the polymer project is also | |
| 12915 // subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 12916 | |
| 12917 (function(global) { | |
| 12918 'use strict'; | |
| 12919 | |
| 12920 var filter = Array.prototype.filter.call.bind(Array.prototype.filter); | |
| 12921 | |
| 12922 function getTreeScope(node) { | |
| 12923 while (node.parentNode) { | |
| 12924 node = node.parentNode; | |
| 12925 } | |
| 12926 | |
| 12927 return typeof node.getElementById === 'function' ? node : null; | |
| 12928 } | 12220 } |
| 12929 | 12221 |
| 12930 Node.prototype.bind = function(name, observable) { | 12222 function module(name, dependsOrFactory, moduleFactory) { |
| 12931 console.error('Unhandled binding to Node: ', this, name, observable); | 12223 var module; |
| 12224 switch (arguments.length) { |
| 12225 case 0: |
| 12226 return; |
| 12227 case 1: |
| 12228 module = null; |
| 12229 break; |
| 12230 case 2: |
| 12231 // dependsOrFactory is `factory` in this case |
| 12232 module = dependsOrFactory.apply(this); |
| 12233 break; |
| 12234 default: |
| 12235 // dependsOrFactory is `depends` in this case |
| 12236 module = withDependencies(moduleFactory, dependsOrFactory); |
| 12237 break; |
| 12238 } |
| 12239 modules[name] = module; |
| 12932 }; | 12240 }; |
| 12933 | 12241 |
| 12934 Node.prototype.bindFinished = function() {}; | 12242 function marshal(name) { |
| 12935 | 12243 return modules[name]; |
| 12936 function updateBindings(node, name, binding) { | |
| 12937 var bindings = node.bindings_; | |
| 12938 if (!bindings) | |
| 12939 bindings = node.bindings_ = {}; | |
| 12940 | |
| 12941 if (bindings[name]) | |
| 12942 binding[name].close(); | |
| 12943 | |
| 12944 return bindings[name] = binding; | |
| 12945 } | 12244 } |
| 12946 | 12245 |
| 12947 function returnBinding(node, name, binding) { | 12246 var modules = {}; |
| 12948 return binding; | |
| 12949 } | |
| 12950 | 12247 |
| 12951 function sanitizeValue(value) { | 12248 function using(depends, task) { |
| 12952 return value == null ? '' : value; | 12249 HTMLImports.whenImportsReady(function() { |
| 12953 } | 12250 withDependencies(task, depends); |
| 12954 | 12251 }); |
| 12955 function updateText(node, value) { | |
| 12956 node.data = sanitizeValue(value); | |
| 12957 } | |
| 12958 | |
| 12959 function textBinding(node) { | |
| 12960 return function(value) { | |
| 12961 return updateText(node, value); | |
| 12962 }; | |
| 12963 } | |
| 12964 | |
| 12965 var maybeUpdateBindings = returnBinding; | |
| 12966 | |
| 12967 Object.defineProperty(Platform, 'enableBindingsReflection', { | |
| 12968 get: function() { | |
| 12969 return maybeUpdateBindings === updateBindings; | |
| 12970 }, | |
| 12971 set: function(enable) { | |
| 12972 maybeUpdateBindings = enable ? updateBindings : returnBinding; | |
| 12973 return enable; | |
| 12974 }, | |
| 12975 configurable: true | |
| 12976 }); | |
| 12977 | |
| 12978 Text.prototype.bind = function(name, value, oneTime) { | |
| 12979 if (name !== 'textContent') | |
| 12980 return Node.prototype.bind.call(this, name, value, oneTime); | |
| 12981 | |
| 12982 if (oneTime) | |
| 12983 return updateText(this, value); | |
| 12984 | |
| 12985 var observable = value; | |
| 12986 updateText(this, observable.open(textBinding(this))); | |
| 12987 return maybeUpdateBindings(this, name, observable); | |
| 12988 } | |
| 12989 | |
| 12990 function updateAttribute(el, name, conditional, value) { | |
| 12991 if (conditional) { | |
| 12992 if (value) | |
| 12993 el.setAttribute(name, ''); | |
| 12994 else | |
| 12995 el.removeAttribute(name); | |
| 12996 return; | |
| 12997 } | |
| 12998 | |
| 12999 el.setAttribute(name, sanitizeValue(value)); | |
| 13000 } | |
| 13001 | |
| 13002 function attributeBinding(el, name, conditional) { | |
| 13003 return function(value) { | |
| 13004 updateAttribute(el, name, conditional, value); | |
| 13005 }; | |
| 13006 } | |
| 13007 | |
| 13008 Element.prototype.bind = function(name, value, oneTime) { | |
| 13009 var conditional = name[name.length - 1] == '?'; | |
| 13010 if (conditional) { | |
| 13011 this.removeAttribute(name); | |
| 13012 name = name.slice(0, -1); | |
| 13013 } | |
| 13014 | |
| 13015 if (oneTime) | |
| 13016 return updateAttribute(this, name, conditional, value); | |
| 13017 | |
| 13018 | |
| 13019 var observable = value; | |
| 13020 updateAttribute(this, name, conditional, | |
| 13021 observable.open(attributeBinding(this, name, conditional))); | |
| 13022 | |
| 13023 return maybeUpdateBindings(this, name, observable); | |
| 13024 }; | 12252 }; |
| 13025 | 12253 |
| 13026 var checkboxEventType; | 12254 // exports |
| 13027 (function() { | |
| 13028 // Attempt to feature-detect which event (change or click) is fired first | |
| 13029 // for checkboxes. | |
| 13030 var div = document.createElement('div'); | |
| 13031 var checkbox = div.appendChild(document.createElement('input')); | |
| 13032 checkbox.setAttribute('type', 'checkbox'); | |
| 13033 var first; | |
| 13034 var count = 0; | |
| 13035 checkbox.addEventListener('click', function(e) { | |
| 13036 count++; | |
| 13037 first = first || 'click'; | |
| 13038 }); | |
| 13039 checkbox.addEventListener('change', function() { | |
| 13040 count++; | |
| 13041 first = first || 'change'; | |
| 13042 }); | |
| 13043 | 12255 |
| 13044 var event = document.createEvent('MouseEvent'); | 12256 scope.marshal = marshal; |
| 13045 event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, | 12257 // `module` confuses commonjs detectors |
| 13046 false, false, false, 0, null); | 12258 scope.modularize = module; |
| 13047 checkbox.dispatchEvent(event); | 12259 scope.using = using; |
| 13048 // WebKit/Blink don't fire the change event if the element is outside the | |
| 13049 // document, so assume 'change' for that case. | |
| 13050 checkboxEventType = count == 1 ? 'change' : first; | |
| 13051 })(); | |
| 13052 | 12260 |
| 13053 function getEventForInputType(element) { | 12261 })(window); |
| 13054 switch (element.type) { | |
| 13055 case 'checkbox': | |
| 13056 return checkboxEventType; | |
| 13057 case 'radio': | |
| 13058 case 'select-multiple': | |
| 13059 case 'select-one': | |
| 13060 return 'change'; | |
| 13061 case 'range': | |
| 13062 if (/Trident|MSIE/.test(navigator.userAgent)) | |
| 13063 return 'change'; | |
| 13064 default: | |
| 13065 return 'input'; | |
| 13066 } | |
| 13067 } | |
| 13068 | |
| 13069 function updateInput(input, property, value, santizeFn) { | |
| 13070 input[property] = (santizeFn || sanitizeValue)(value); | |
| 13071 } | |
| 13072 | |
| 13073 function inputBinding(input, property, santizeFn) { | |
| 13074 return function(value) { | |
| 13075 return updateInput(input, property, value, santizeFn); | |
| 13076 } | |
| 13077 } | |
| 13078 | |
| 13079 function noop() {} | |
| 13080 | |
| 13081 function bindInputEvent(input, property, observable, postEventFn) { | |
| 13082 var eventType = getEventForInputType(input); | |
| 13083 | |
| 13084 function eventHandler() { | |
| 13085 observable.setValue(input[property]); | |
| 13086 observable.discardChanges(); | |
| 13087 (postEventFn || noop)(input); | |
| 13088 Platform.performMicrotaskCheckpoint(); | |
| 13089 } | |
| 13090 input.addEventListener(eventType, eventHandler); | |
| 13091 | |
| 13092 return { | |
| 13093 close: function() { | |
| 13094 input.removeEventListener(eventType, eventHandler); | |
| 13095 observable.close(); | |
| 13096 }, | |
| 13097 | |
| 13098 observable_: observable | |
| 13099 } | |
| 13100 } | |
| 13101 | |
| 13102 function booleanSanitize(value) { | |
| 13103 return Boolean(value); | |
| 13104 } | |
| 13105 | |
| 13106 // |element| is assumed to be an HTMLInputElement with |type| == 'radio'. | |
| 13107 // Returns an array containing all radio buttons other than |element| that | |
| 13108 // have the same |name|, either in the form that |element| belongs to or, | |
| 13109 // if no form, in the document tree to which |element| belongs. | |
| 13110 // | |
| 13111 // This implementation is based upon the HTML spec definition of a | |
| 13112 // "radio button group": | |
| 13113 // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.
html#radio-button-group | |
| 13114 // | |
| 13115 function getAssociatedRadioButtons(element) { | |
| 13116 if (element.form) { | |
| 13117 return filter(element.form.elements, function(el) { | |
| 13118 return el != element && | |
| 13119 el.tagName == 'INPUT' && | |
| 13120 el.type == 'radio' && | |
| 13121 el.name == element.name; | |
| 13122 }); | |
| 13123 } else { | |
| 13124 var treeScope = getTreeScope(element); | |
| 13125 if (!treeScope) | |
| 13126 return []; | |
| 13127 var radios = treeScope.querySelectorAll( | |
| 13128 'input[type="radio"][name="' + element.name + '"]'); | |
| 13129 return filter(radios, function(el) { | |
| 13130 return el != element && !el.form; | |
| 13131 }); | |
| 13132 } | |
| 13133 } | |
| 13134 | |
| 13135 function checkedPostEvent(input) { | |
| 13136 // Only the radio button that is getting checked gets an event. We | |
| 13137 // therefore find all the associated radio buttons and update their | |
| 13138 // check binding manually. | |
| 13139 if (input.tagName === 'INPUT' && | |
| 13140 input.type === 'radio') { | |
| 13141 getAssociatedRadioButtons(input).forEach(function(radio) { | |
| 13142 var checkedBinding = radio.bindings_.checked; | |
| 13143 if (checkedBinding) { | |
| 13144 // Set the value directly to avoid an infinite call stack. | |
| 13145 checkedBinding.observable_.setValue(false); | |
| 13146 } | |
| 13147 }); | |
| 13148 } | |
| 13149 } | |
| 13150 | |
| 13151 HTMLInputElement.prototype.bind = function(name, value, oneTime) { | |
| 13152 if (name !== 'value' && name !== 'checked') | |
| 13153 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | |
| 13154 | |
| 13155 this.removeAttribute(name); | |
| 13156 var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue; | |
| 13157 var postEventFn = name == 'checked' ? checkedPostEvent : noop; | |
| 13158 | |
| 13159 if (oneTime) | |
| 13160 return updateInput(this, name, value, sanitizeFn); | |
| 13161 | |
| 13162 | |
| 13163 var observable = value; | |
| 13164 var binding = bindInputEvent(this, name, observable, postEventFn); | |
| 13165 updateInput(this, name, | |
| 13166 observable.open(inputBinding(this, name, sanitizeFn)), | |
| 13167 sanitizeFn); | |
| 13168 | |
| 13169 // Checkboxes may need to update bindings of other checkboxes. | |
| 13170 return updateBindings(this, name, binding); | |
| 13171 } | |
| 13172 | |
| 13173 HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) { | |
| 13174 if (name !== 'value') | |
| 13175 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | |
| 13176 | |
| 13177 this.removeAttribute('value'); | |
| 13178 | |
| 13179 if (oneTime) | |
| 13180 return updateInput(this, 'value', value); | |
| 13181 | |
| 13182 var observable = value; | |
| 13183 var binding = bindInputEvent(this, 'value', observable); | |
| 13184 updateInput(this, 'value', | |
| 13185 observable.open(inputBinding(this, 'value', sanitizeValue))); | |
| 13186 return maybeUpdateBindings(this, name, binding); | |
| 13187 } | |
| 13188 | |
| 13189 function updateOption(option, value) { | |
| 13190 var parentNode = option.parentNode;; | |
| 13191 var select; | |
| 13192 var selectBinding; | |
| 13193 var oldValue; | |
| 13194 if (parentNode instanceof HTMLSelectElement && | |
| 13195 parentNode.bindings_ && | |
| 13196 parentNode.bindings_.value) { | |
| 13197 select = parentNode; | |
| 13198 selectBinding = select.bindings_.value; | |
| 13199 oldValue = select.value; | |
| 13200 } | |
| 13201 | |
| 13202 option.value = sanitizeValue(value); | |
| 13203 | |
| 13204 if (select && select.value != oldValue) { | |
| 13205 selectBinding.observable_.setValue(select.value); | |
| 13206 selectBinding.observable_.discardChanges(); | |
| 13207 Platform.performMicrotaskCheckpoint(); | |
| 13208 } | |
| 13209 } | |
| 13210 | |
| 13211 function optionBinding(option) { | |
| 13212 return function(value) { | |
| 13213 updateOption(option, value); | |
| 13214 } | |
| 13215 } | |
| 13216 | |
| 13217 HTMLOptionElement.prototype.bind = function(name, value, oneTime) { | |
| 13218 if (name !== 'value') | |
| 13219 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | |
| 13220 | |
| 13221 this.removeAttribute('value'); | |
| 13222 | |
| 13223 if (oneTime) | |
| 13224 return updateOption(this, value); | |
| 13225 | |
| 13226 var observable = value; | |
| 13227 var binding = bindInputEvent(this, 'value', observable); | |
| 13228 updateOption(this, observable.open(optionBinding(this))); | |
| 13229 return maybeUpdateBindings(this, name, binding); | |
| 13230 } | |
| 13231 | |
| 13232 HTMLSelectElement.prototype.bind = function(name, value, oneTime) { | |
| 13233 if (name === 'selectedindex') | |
| 13234 name = 'selectedIndex'; | |
| 13235 | |
| 13236 if (name !== 'selectedIndex' && name !== 'value') | |
| 13237 return HTMLElement.prototype.bind.call(this, name, value, oneTime); | |
| 13238 | |
| 13239 this.removeAttribute(name); | |
| 13240 | |
| 13241 if (oneTime) | |
| 13242 return updateInput(this, name, value); | |
| 13243 | |
| 13244 var observable = value; | |
| 13245 var binding = bindInputEvent(this, name, observable); | |
| 13246 updateInput(this, name, | |
| 13247 observable.open(inputBinding(this, name))); | |
| 13248 | |
| 13249 // Option update events may need to access select bindings. | |
| 13250 return updateBindings(this, name, binding); | |
| 13251 } | |
| 13252 })(this); | |
| 13253 | |
| 13254 // Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 13255 // This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 13256 // The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 13257 // The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 13258 // Code distributed by Google as part of the polymer project is also | |
| 13259 // subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 13260 | |
| 13261 (function(global) { | |
| 13262 'use strict'; | |
| 13263 | |
| 13264 function assert(v) { | |
| 13265 if (!v) | |
| 13266 throw new Error('Assertion failed'); | |
| 13267 } | |
| 13268 | |
| 13269 var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); | |
| 13270 | |
| 13271 function getFragmentRoot(node) { | |
| 13272 var p; | |
| 13273 while (p = node.parentNode) { | |
| 13274 node = p; | |
| 13275 } | |
| 13276 | |
| 13277 return node; | |
| 13278 } | |
| 13279 | |
| 13280 function searchRefId(node, id) { | |
| 13281 if (!id) | |
| 13282 return; | |
| 13283 | |
| 13284 var ref; | |
| 13285 var selector = '#' + id; | |
| 13286 while (!ref) { | |
| 13287 node = getFragmentRoot(node); | |
| 13288 | |
| 13289 if (node.protoContent_) | |
| 13290 ref = node.protoContent_.querySelector(selector); | |
| 13291 else if (node.getElementById) | |
| 13292 ref = node.getElementById(id); | |
| 13293 | |
| 13294 if (ref || !node.templateCreator_) | |
| 13295 break | |
| 13296 | |
| 13297 node = node.templateCreator_; | |
| 13298 } | |
| 13299 | |
| 13300 return ref; | |
| 13301 } | |
| 13302 | |
| 13303 function getInstanceRoot(node) { | |
| 13304 while (node.parentNode) { | |
| 13305 node = node.parentNode; | |
| 13306 } | |
| 13307 return node.templateCreator_ ? node : null; | |
| 13308 } | |
| 13309 | |
| 13310 var Map; | |
| 13311 if (global.Map && typeof global.Map.prototype.forEach === 'function') { | |
| 13312 Map = global.Map; | |
| 13313 } else { | |
| 13314 Map = function() { | |
| 13315 this.keys = []; | |
| 13316 this.values = []; | |
| 13317 }; | |
| 13318 | |
| 13319 Map.prototype = { | |
| 13320 set: function(key, value) { | |
| 13321 var index = this.keys.indexOf(key); | |
| 13322 if (index < 0) { | |
| 13323 this.keys.push(key); | |
| 13324 this.values.push(value); | |
| 13325 } else { | |
| 13326 this.values[index] = value; | |
| 13327 } | |
| 13328 }, | |
| 13329 | |
| 13330 get: function(key) { | |
| 13331 var index = this.keys.indexOf(key); | |
| 13332 if (index < 0) | |
| 13333 return; | |
| 13334 | |
| 13335 return this.values[index]; | |
| 13336 }, | |
| 13337 | |
| 13338 delete: function(key, value) { | |
| 13339 var index = this.keys.indexOf(key); | |
| 13340 if (index < 0) | |
| 13341 return false; | |
| 13342 | |
| 13343 this.keys.splice(index, 1); | |
| 13344 this.values.splice(index, 1); | |
| 13345 return true; | |
| 13346 }, | |
| 13347 | |
| 13348 forEach: function(f, opt_this) { | |
| 13349 for (var i = 0; i < this.keys.length; i++) | |
| 13350 f.call(opt_this || this, this.values[i], this.keys[i], this); | |
| 13351 } | |
| 13352 }; | |
| 13353 } | |
| 13354 | |
| 13355 // JScript does not have __proto__. We wrap all object literals with | |
| 13356 // createObject which uses Object.create, Object.defineProperty and | |
| 13357 // Object.getOwnPropertyDescriptor to create a new object that does the exact | |
| 13358 // same thing. The main downside to this solution is that we have to extract | |
| 13359 // all those property descriptors for IE. | |
| 13360 var createObject = ('__proto__' in {}) ? | |
| 13361 function(obj) { return obj; } : | |
| 13362 function(obj) { | |
| 13363 var proto = obj.__proto__; | |
| 13364 if (!proto) | |
| 13365 return obj; | |
| 13366 var newObject = Object.create(proto); | |
| 13367 Object.getOwnPropertyNames(obj).forEach(function(name) { | |
| 13368 Object.defineProperty(newObject, name, | |
| 13369 Object.getOwnPropertyDescriptor(obj, name)); | |
| 13370 }); | |
| 13371 return newObject; | |
| 13372 }; | |
| 13373 | |
| 13374 // IE does not support have Document.prototype.contains. | |
| 13375 if (typeof document.contains != 'function') { | |
| 13376 Document.prototype.contains = function(node) { | |
| 13377 if (node === this || node.parentNode === this) | |
| 13378 return true; | |
| 13379 return this.documentElement.contains(node); | |
| 13380 } | |
| 13381 } | |
| 13382 | |
| 13383 var BIND = 'bind'; | |
| 13384 var REPEAT = 'repeat'; | |
| 13385 var IF = 'if'; | |
| 13386 | |
| 13387 var templateAttributeDirectives = { | |
| 13388 'template': true, | |
| 13389 'repeat': true, | |
| 13390 'bind': true, | |
| 13391 'ref': true | |
| 13392 }; | |
| 13393 | |
| 13394 var semanticTemplateElements = { | |
| 13395 'THEAD': true, | |
| 13396 'TBODY': true, | |
| 13397 'TFOOT': true, | |
| 13398 'TH': true, | |
| 13399 'TR': true, | |
| 13400 'TD': true, | |
| 13401 'COLGROUP': true, | |
| 13402 'COL': true, | |
| 13403 'CAPTION': true, | |
| 13404 'OPTION': true, | |
| 13405 'OPTGROUP': true | |
| 13406 }; | |
| 13407 | |
| 13408 var hasTemplateElement = typeof HTMLTemplateElement !== 'undefined'; | |
| 13409 if (hasTemplateElement) { | |
| 13410 // TODO(rafaelw): Remove when fix for | |
| 13411 // https://codereview.chromium.org/164803002/ | |
| 13412 // makes it to Chrome release. | |
| 13413 (function() { | |
| 13414 var t = document.createElement('template'); | |
| 13415 var d = t.content.ownerDocument; | |
| 13416 var html = d.appendChild(d.createElement('html')); | |
| 13417 var head = html.appendChild(d.createElement('head')); | |
| 13418 var base = d.createElement('base'); | |
| 13419 base.href = document.baseURI; | |
| 13420 head.appendChild(base); | |
| 13421 })(); | |
| 13422 } | |
| 13423 | |
| 13424 var allTemplatesSelectors = 'template, ' + | |
| 13425 Object.keys(semanticTemplateElements).map(function(tagName) { | |
| 13426 return tagName.toLowerCase() + '[template]'; | |
| 13427 }).join(', '); | |
| 13428 | |
| 13429 function isSVGTemplate(el) { | |
| 13430 return el.tagName == 'template' && | |
| 13431 el.namespaceURI == 'http://www.w3.org/2000/svg'; | |
| 13432 } | |
| 13433 | |
| 13434 function isHTMLTemplate(el) { | |
| 13435 return el.tagName == 'TEMPLATE' && | |
| 13436 el.namespaceURI == 'http://www.w3.org/1999/xhtml'; | |
| 13437 } | |
| 13438 | |
| 13439 function isAttributeTemplate(el) { | |
| 13440 return Boolean(semanticTemplateElements[el.tagName] && | |
| 13441 el.hasAttribute('template')); | |
| 13442 } | |
| 13443 | |
| 13444 function isTemplate(el) { | |
| 13445 if (el.isTemplate_ === undefined) | |
| 13446 el.isTemplate_ = el.tagName == 'TEMPLATE' || isAttributeTemplate(el); | |
| 13447 | |
| 13448 return el.isTemplate_; | |
| 13449 } | |
| 13450 | |
| 13451 // FIXME: Observe templates being added/removed from documents | |
| 13452 // FIXME: Expose imperative API to decorate and observe templates in | |
| 13453 // "disconnected tress" (e.g. ShadowRoot) | |
| 13454 document.addEventListener('DOMContentLoaded', function(e) { | |
| 13455 bootstrapTemplatesRecursivelyFrom(document); | |
| 13456 // FIXME: Is this needed? Seems like it shouldn't be. | |
| 13457 Platform.performMicrotaskCheckpoint(); | |
| 13458 }, false); | |
| 13459 | |
| 13460 function forAllTemplatesFrom(node, fn) { | |
| 13461 var subTemplates = node.querySelectorAll(allTemplatesSelectors); | |
| 13462 | |
| 13463 if (isTemplate(node)) | |
| 13464 fn(node) | |
| 13465 forEach(subTemplates, fn); | |
| 13466 } | |
| 13467 | |
| 13468 function bootstrapTemplatesRecursivelyFrom(node) { | |
| 13469 function bootstrap(template) { | |
| 13470 if (!HTMLTemplateElement.decorate(template)) | |
| 13471 bootstrapTemplatesRecursivelyFrom(template.content); | |
| 13472 } | |
| 13473 | |
| 13474 forAllTemplatesFrom(node, bootstrap); | |
| 13475 } | |
| 13476 | |
| 13477 if (!hasTemplateElement) { | |
| 13478 /** | |
| 13479 * This represents a <template> element. | |
| 13480 * @constructor | |
| 13481 * @extends {HTMLElement} | |
| 13482 */ | |
| 13483 global.HTMLTemplateElement = function() { | |
| 13484 throw TypeError('Illegal constructor'); | |
| 13485 }; | |
| 13486 } | |
| 13487 | |
| 13488 var hasProto = '__proto__' in {}; | |
| 13489 | |
| 13490 function mixin(to, from) { | |
| 13491 Object.getOwnPropertyNames(from).forEach(function(name) { | |
| 13492 Object.defineProperty(to, name, | |
| 13493 Object.getOwnPropertyDescriptor(from, name)); | |
| 13494 }); | |
| 13495 } | |
| 13496 | |
| 13497 // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#
dfn-template-contents-owner | |
| 13498 function getOrCreateTemplateContentsOwner(template) { | |
| 13499 var doc = template.ownerDocument | |
| 13500 if (!doc.defaultView) | |
| 13501 return doc; | |
| 13502 var d = doc.templateContentsOwner_; | |
| 13503 if (!d) { | |
| 13504 // TODO(arv): This should either be a Document or HTMLDocument depending | |
| 13505 // on doc. | |
| 13506 d = doc.implementation.createHTMLDocument(''); | |
| 13507 while (d.lastChild) { | |
| 13508 d.removeChild(d.lastChild); | |
| 13509 } | |
| 13510 doc.templateContentsOwner_ = d; | |
| 13511 } | |
| 13512 return d; | |
| 13513 } | |
| 13514 | |
| 13515 function getTemplateStagingDocument(template) { | |
| 13516 if (!template.stagingDocument_) { | |
| 13517 var owner = template.ownerDocument; | |
| 13518 if (!owner.stagingDocument_) { | |
| 13519 owner.stagingDocument_ = owner.implementation.createHTMLDocument(''); | |
| 13520 owner.stagingDocument_.isStagingDocument = true; | |
| 13521 // TODO(rafaelw): Remove when fix for | |
| 13522 // https://codereview.chromium.org/164803002/ | |
| 13523 // makes it to Chrome release. | |
| 13524 var base = owner.stagingDocument_.createElement('base'); | |
| 13525 base.href = document.baseURI; | |
| 13526 owner.stagingDocument_.head.appendChild(base); | |
| 13527 | |
| 13528 owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_; | |
| 13529 } | |
| 13530 | |
| 13531 template.stagingDocument_ = owner.stagingDocument_; | |
| 13532 } | |
| 13533 | |
| 13534 return template.stagingDocument_; | |
| 13535 } | |
| 13536 | |
| 13537 // For non-template browsers, the parser will disallow <template> in certain | |
| 13538 // locations, so we allow "attribute templates" which combine the template | |
| 13539 // element with the top-level container node of the content, e.g. | |
| 13540 // | |
| 13541 // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr> | |
| 13542 // | |
| 13543 // becomes | |
| 13544 // | |
| 13545 // <template repeat="{{ foo }}"> | |
| 13546 // + #document-fragment | |
| 13547 // + <tr class="bar"> | |
| 13548 // + <td>Bar</td> | |
| 13549 // | |
| 13550 function extractTemplateFromAttributeTemplate(el) { | |
| 13551 var template = el.ownerDocument.createElement('template'); | |
| 13552 el.parentNode.insertBefore(template, el); | |
| 13553 | |
| 13554 var attribs = el.attributes; | |
| 13555 var count = attribs.length; | |
| 13556 while (count-- > 0) { | |
| 13557 var attrib = attribs[count]; | |
| 13558 if (templateAttributeDirectives[attrib.name]) { | |
| 13559 if (attrib.name !== 'template') | |
| 13560 template.setAttribute(attrib.name, attrib.value); | |
| 13561 el.removeAttribute(attrib.name); | |
| 13562 } | |
| 13563 } | |
| 13564 | |
| 13565 return template; | |
| 13566 } | |
| 13567 | |
| 13568 function extractTemplateFromSVGTemplate(el) { | |
| 13569 var template = el.ownerDocument.createElement('template'); | |
| 13570 el.parentNode.insertBefore(template, el); | |
| 13571 | |
| 13572 var attribs = el.attributes; | |
| 13573 var count = attribs.length; | |
| 13574 while (count-- > 0) { | |
| 13575 var attrib = attribs[count]; | |
| 13576 template.setAttribute(attrib.name, attrib.value); | |
| 13577 el.removeAttribute(attrib.name); | |
| 13578 } | |
| 13579 | |
| 13580 el.parentNode.removeChild(el); | |
| 13581 return template; | |
| 13582 } | |
| 13583 | |
| 13584 function liftNonNativeTemplateChildrenIntoContent(template, el, useRoot) { | |
| 13585 var content = template.content; | |
| 13586 if (useRoot) { | |
| 13587 content.appendChild(el); | |
| 13588 return; | |
| 13589 } | |
| 13590 | |
| 13591 var child; | |
| 13592 while (child = el.firstChild) { | |
| 13593 content.appendChild(child); | |
| 13594 } | |
| 13595 } | |
| 13596 | |
| 13597 var templateObserver; | |
| 13598 if (typeof MutationObserver == 'function') { | |
| 13599 templateObserver = new MutationObserver(function(records) { | |
| 13600 for (var i = 0; i < records.length; i++) { | |
| 13601 records[i].target.refChanged_(); | |
| 13602 } | |
| 13603 }); | |
| 13604 } | |
| 13605 | |
| 13606 /** | |
| 13607 * Ensures proper API and content model for template elements. | |
| 13608 * @param {HTMLTemplateElement} opt_instanceRef The template element which | |
| 13609 * |el| template element will return as the value of its ref(), and whose | |
| 13610 * content will be used as source when createInstance() is invoked. | |
| 13611 */ | |
| 13612 HTMLTemplateElement.decorate = function(el, opt_instanceRef) { | |
| 13613 if (el.templateIsDecorated_) | |
| 13614 return false; | |
| 13615 | |
| 13616 var templateElement = el; | |
| 13617 templateElement.templateIsDecorated_ = true; | |
| 13618 | |
| 13619 var isNativeHTMLTemplate = isHTMLTemplate(templateElement) && | |
| 13620 hasTemplateElement; | |
| 13621 var bootstrapContents = isNativeHTMLTemplate; | |
| 13622 var liftContents = !isNativeHTMLTemplate; | |
| 13623 var liftRoot = false; | |
| 13624 | |
| 13625 if (!isNativeHTMLTemplate) { | |
| 13626 if (isAttributeTemplate(templateElement)) { | |
| 13627 assert(!opt_instanceRef); | |
| 13628 templateElement = extractTemplateFromAttributeTemplate(el); | |
| 13629 templateElement.templateIsDecorated_ = true; | |
| 13630 isNativeHTMLTemplate = hasTemplateElement; | |
| 13631 liftRoot = true; | |
| 13632 } else if (isSVGTemplate(templateElement)) { | |
| 13633 templateElement = extractTemplateFromSVGTemplate(el); | |
| 13634 templateElement.templateIsDecorated_ = true; | |
| 13635 isNativeHTMLTemplate = hasTemplateElement; | |
| 13636 } | |
| 13637 } | |
| 13638 | |
| 13639 if (!isNativeHTMLTemplate) { | |
| 13640 fixTemplateElementPrototype(templateElement); | |
| 13641 var doc = getOrCreateTemplateContentsOwner(templateElement); | |
| 13642 templateElement.content_ = doc.createDocumentFragment(); | |
| 13643 } | |
| 13644 | |
| 13645 if (opt_instanceRef) { | |
| 13646 // template is contained within an instance, its direct content must be | |
| 13647 // empty | |
| 13648 templateElement.instanceRef_ = opt_instanceRef; | |
| 13649 } else if (liftContents) { | |
| 13650 liftNonNativeTemplateChildrenIntoContent(templateElement, | |
| 13651 el, | |
| 13652 liftRoot); | |
| 13653 } else if (bootstrapContents) { | |
| 13654 bootstrapTemplatesRecursivelyFrom(templateElement.content); | |
| 13655 } | |
| 13656 | |
| 13657 return true; | |
| 13658 }; | |
| 13659 | |
| 13660 // TODO(rafaelw): This used to decorate recursively all templates from a given | |
| 13661 // node. This happens by default on 'DOMContentLoaded', but may be needed | |
| 13662 // in subtrees not descendent from document (e.g. ShadowRoot). | |
| 13663 // Review whether this is the right public API. | |
| 13664 HTMLTemplateElement.bootstrap = bootstrapTemplatesRecursivelyFrom; | |
| 13665 | |
| 13666 var htmlElement = global.HTMLUnknownElement || HTMLElement; | |
| 13667 | |
| 13668 var contentDescriptor = { | |
| 13669 get: function() { | |
| 13670 return this.content_; | |
| 13671 }, | |
| 13672 enumerable: true, | |
| 13673 configurable: true | |
| 13674 }; | |
| 13675 | |
| 13676 if (!hasTemplateElement) { | |
| 13677 // Gecko is more picky with the prototype than WebKit. Make sure to use the | |
| 13678 // same prototype as created in the constructor. | |
| 13679 HTMLTemplateElement.prototype = Object.create(htmlElement.prototype); | |
| 13680 | |
| 13681 Object.defineProperty(HTMLTemplateElement.prototype, 'content', | |
| 13682 contentDescriptor); | |
| 13683 } | |
| 13684 | |
| 13685 function fixTemplateElementPrototype(el) { | |
| 13686 if (hasProto) | |
| 13687 el.__proto__ = HTMLTemplateElement.prototype; | |
| 13688 else | |
| 13689 mixin(el, HTMLTemplateElement.prototype); | |
| 13690 } | |
| 13691 | |
| 13692 function ensureSetModelScheduled(template) { | |
| 13693 if (!template.setModelFn_) { | |
| 13694 template.setModelFn_ = function() { | |
| 13695 template.setModelFnScheduled_ = false; | |
| 13696 var map = getBindings(template, | |
| 13697 template.delegate_ && template.delegate_.prepareBinding); | |
| 13698 processBindings(template, map, template.model_); | |
| 13699 }; | |
| 13700 } | |
| 13701 | |
| 13702 if (!template.setModelFnScheduled_) { | |
| 13703 template.setModelFnScheduled_ = true; | |
| 13704 Observer.runEOM_(template.setModelFn_); | |
| 13705 } | |
| 13706 } | |
| 13707 | |
| 13708 mixin(HTMLTemplateElement.prototype, { | |
| 13709 bind: function(name, value, oneTime) { | |
| 13710 if (name != 'ref') | |
| 13711 return Element.prototype.bind.call(this, name, value, oneTime); | |
| 13712 | |
| 13713 var self = this; | |
| 13714 var ref = oneTime ? value : value.open(function(ref) { | |
| 13715 self.setAttribute('ref', ref); | |
| 13716 self.refChanged_(); | |
| 13717 }); | |
| 13718 | |
| 13719 this.setAttribute('ref', ref); | |
| 13720 this.refChanged_(); | |
| 13721 if (oneTime) | |
| 13722 return; | |
| 13723 | |
| 13724 if (!this.bindings_) { | |
| 13725 this.bindings_ = { ref: value }; | |
| 13726 } else { | |
| 13727 this.bindings_.ref = value; | |
| 13728 } | |
| 13729 | |
| 13730 return value; | |
| 13731 }, | |
| 13732 | |
| 13733 processBindingDirectives_: function(directives) { | |
| 13734 if (this.iterator_) | |
| 13735 this.iterator_.closeDeps(); | |
| 13736 | |
| 13737 if (!directives.if && !directives.bind && !directives.repeat) { | |
| 13738 if (this.iterator_) { | |
| 13739 this.iterator_.close(); | |
| 13740 this.iterator_ = undefined; | |
| 13741 } | |
| 13742 | |
| 13743 return; | |
| 13744 } | |
| 13745 | |
| 13746 if (!this.iterator_) { | |
| 13747 this.iterator_ = new TemplateIterator(this); | |
| 13748 } | |
| 13749 | |
| 13750 this.iterator_.updateDependencies(directives, this.model_); | |
| 13751 | |
| 13752 if (templateObserver) { | |
| 13753 templateObserver.observe(this, { attributes: true, | |
| 13754 attributeFilter: ['ref'] }); | |
| 13755 } | |
| 13756 | |
| 13757 return this.iterator_; | |
| 13758 }, | |
| 13759 | |
| 13760 createInstance: function(model, bindingDelegate, delegate_) { | |
| 13761 if (bindingDelegate) | |
| 13762 delegate_ = this.newDelegate_(bindingDelegate); | |
| 13763 else if (!delegate_) | |
| 13764 delegate_ = this.delegate_; | |
| 13765 | |
| 13766 if (!this.refContent_) | |
| 13767 this.refContent_ = this.ref_.content; | |
| 13768 var content = this.refContent_; | |
| 13769 if (content.firstChild === null) | |
| 13770 return emptyInstance; | |
| 13771 | |
| 13772 var map = getInstanceBindingMap(content, delegate_); | |
| 13773 var stagingDocument = getTemplateStagingDocument(this); | |
| 13774 var instance = stagingDocument.createDocumentFragment(); | |
| 13775 instance.templateCreator_ = this; | |
| 13776 instance.protoContent_ = content; | |
| 13777 instance.bindings_ = []; | |
| 13778 instance.terminator_ = null; | |
| 13779 var instanceRecord = instance.templateInstance_ = { | |
| 13780 firstNode: null, | |
| 13781 lastNode: null, | |
| 13782 model: model | |
| 13783 }; | |
| 13784 | |
| 13785 var i = 0; | |
| 13786 var collectTerminator = false; | |
| 13787 for (var child = content.firstChild; child; child = child.nextSibling) { | |
| 13788 // The terminator of the instance is the clone of the last child of the | |
| 13789 // content. If the last child is an active template, it may produce | |
| 13790 // instances as a result of production, so simply collecting the last | |
| 13791 // child of the instance after it has finished producing may be wrong. | |
| 13792 if (child.nextSibling === null) | |
| 13793 collectTerminator = true; | |
| 13794 | |
| 13795 var clone = cloneAndBindInstance(child, instance, stagingDocument, | |
| 13796 map.children[i++], | |
| 13797 model, | |
| 13798 delegate_, | |
| 13799 instance.bindings_); | |
| 13800 clone.templateInstance_ = instanceRecord; | |
| 13801 if (collectTerminator) | |
| 13802 instance.terminator_ = clone; | |
| 13803 } | |
| 13804 | |
| 13805 instanceRecord.firstNode = instance.firstChild; | |
| 13806 instanceRecord.lastNode = instance.lastChild; | |
| 13807 instance.templateCreator_ = undefined; | |
| 13808 instance.protoContent_ = undefined; | |
| 13809 return instance; | |
| 13810 }, | |
| 13811 | |
| 13812 get model() { | |
| 13813 return this.model_; | |
| 13814 }, | |
| 13815 | |
| 13816 set model(model) { | |
| 13817 this.model_ = model; | |
| 13818 ensureSetModelScheduled(this); | |
| 13819 }, | |
| 13820 | |
| 13821 get bindingDelegate() { | |
| 13822 return this.delegate_ && this.delegate_.raw; | |
| 13823 }, | |
| 13824 | |
| 13825 refChanged_: function() { | |
| 13826 if (!this.iterator_ || this.refContent_ === this.ref_.content) | |
| 13827 return; | |
| 13828 | |
| 13829 this.refContent_ = undefined; | |
| 13830 this.iterator_.valueChanged(); | |
| 13831 this.iterator_.updateIteratedValue(this.iterator_.getUpdatedValue()); | |
| 13832 }, | |
| 13833 | |
| 13834 clear: function() { | |
| 13835 this.model_ = undefined; | |
| 13836 this.delegate_ = undefined; | |
| 13837 if (this.bindings_ && this.bindings_.ref) | |
| 13838 this.bindings_.ref.close() | |
| 13839 this.refContent_ = undefined; | |
| 13840 if (!this.iterator_) | |
| 13841 return; | |
| 13842 this.iterator_.valueChanged(); | |
| 13843 this.iterator_.close() | |
| 13844 this.iterator_ = undefined; | |
| 13845 }, | |
| 13846 | |
| 13847 setDelegate_: function(delegate) { | |
| 13848 this.delegate_ = delegate; | |
| 13849 this.bindingMap_ = undefined; | |
| 13850 if (this.iterator_) { | |
| 13851 this.iterator_.instancePositionChangedFn_ = undefined; | |
| 13852 this.iterator_.instanceModelFn_ = undefined; | |
| 13853 } | |
| 13854 }, | |
| 13855 | |
| 13856 newDelegate_: function(bindingDelegate) { | |
| 13857 if (!bindingDelegate) | |
| 13858 return; | |
| 13859 | |
| 13860 function delegateFn(name) { | |
| 13861 var fn = bindingDelegate && bindingDelegate[name]; | |
| 13862 if (typeof fn != 'function') | |
| 13863 return; | |
| 13864 | |
| 13865 return function() { | |
| 13866 return fn.apply(bindingDelegate, arguments); | |
| 13867 }; | |
| 13868 } | |
| 13869 | |
| 13870 return { | |
| 13871 bindingMaps: {}, | |
| 13872 raw: bindingDelegate, | |
| 13873 prepareBinding: delegateFn('prepareBinding'), | |
| 13874 prepareInstanceModel: delegateFn('prepareInstanceModel'), | |
| 13875 prepareInstancePositionChanged: | |
| 13876 delegateFn('prepareInstancePositionChanged') | |
| 13877 }; | |
| 13878 }, | |
| 13879 | |
| 13880 set bindingDelegate(bindingDelegate) { | |
| 13881 if (this.delegate_) { | |
| 13882 throw Error('Template must be cleared before a new bindingDelegate ' + | |
| 13883 'can be assigned'); | |
| 13884 } | |
| 13885 | |
| 13886 this.setDelegate_(this.newDelegate_(bindingDelegate)); | |
| 13887 }, | |
| 13888 | |
| 13889 get ref_() { | |
| 13890 var ref = searchRefId(this, this.getAttribute('ref')); | |
| 13891 if (!ref) | |
| 13892 ref = this.instanceRef_; | |
| 13893 | |
| 13894 if (!ref) | |
| 13895 return this; | |
| 13896 | |
| 13897 var nextRef = ref.ref_; | |
| 13898 return nextRef ? nextRef : ref; | |
| 13899 } | |
| 13900 }); | |
| 13901 | |
| 13902 // Returns | |
| 13903 // a) undefined if there are no mustaches. | |
| 13904 // b) [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one
mustache. | |
| 13905 function parseMustaches(s, name, node, prepareBindingFn) { | |
| 13906 if (!s || !s.length) | |
| 13907 return; | |
| 13908 | |
| 13909 var tokens; | |
| 13910 var length = s.length; | |
| 13911 var startIndex = 0, lastIndex = 0, endIndex = 0; | |
| 13912 var onlyOneTime = true; | |
| 13913 while (lastIndex < length) { | |
| 13914 var startIndex = s.indexOf('{{', lastIndex); | |
| 13915 var oneTimeStart = s.indexOf('[[', lastIndex); | |
| 13916 var oneTime = false; | |
| 13917 var terminator = '}}'; | |
| 13918 | |
| 13919 if (oneTimeStart >= 0 && | |
| 13920 (startIndex < 0 || oneTimeStart < startIndex)) { | |
| 13921 startIndex = oneTimeStart; | |
| 13922 oneTime = true; | |
| 13923 terminator = ']]'; | |
| 13924 } | |
| 13925 | |
| 13926 endIndex = startIndex < 0 ? -1 : s.indexOf(terminator, startIndex + 2); | |
| 13927 | |
| 13928 if (endIndex < 0) { | |
| 13929 if (!tokens) | |
| 13930 return; | |
| 13931 | |
| 13932 tokens.push(s.slice(lastIndex)); // TEXT | |
| 13933 break; | |
| 13934 } | |
| 13935 | |
| 13936 tokens = tokens || []; | |
| 13937 tokens.push(s.slice(lastIndex, startIndex)); // TEXT | |
| 13938 var pathString = s.slice(startIndex + 2, endIndex).trim(); | |
| 13939 tokens.push(oneTime); // ONE_TIME? | |
| 13940 onlyOneTime = onlyOneTime && oneTime; | |
| 13941 var delegateFn = prepareBindingFn && | |
| 13942 prepareBindingFn(pathString, name, node); | |
| 13943 // Don't try to parse the expression if there's a prepareBinding function | |
| 13944 if (delegateFn == null) { | |
| 13945 tokens.push(Path.get(pathString)); // PATH | |
| 13946 } else { | |
| 13947 tokens.push(null); | |
| 13948 } | |
| 13949 tokens.push(delegateFn); // DELEGATE_FN | |
| 13950 lastIndex = endIndex + 2; | |
| 13951 } | |
| 13952 | |
| 13953 if (lastIndex === length) | |
| 13954 tokens.push(''); // TEXT | |
| 13955 | |
| 13956 tokens.hasOnePath = tokens.length === 5; | |
| 13957 tokens.isSimplePath = tokens.hasOnePath && | |
| 13958 tokens[0] == '' && | |
| 13959 tokens[4] == ''; | |
| 13960 tokens.onlyOneTime = onlyOneTime; | |
| 13961 | |
| 13962 tokens.combinator = function(values) { | |
| 13963 var newValue = tokens[0]; | |
| 13964 | |
| 13965 for (var i = 1; i < tokens.length; i += 4) { | |
| 13966 var value = tokens.hasOnePath ? values : values[(i - 1) / 4]; | |
| 13967 if (value !== undefined) | |
| 13968 newValue += value; | |
| 13969 newValue += tokens[i + 3]; | |
| 13970 } | |
| 13971 | |
| 13972 return newValue; | |
| 13973 } | |
| 13974 | |
| 13975 return tokens; | |
| 13976 }; | |
| 13977 | |
| 13978 function processOneTimeBinding(name, tokens, node, model) { | |
| 13979 if (tokens.hasOnePath) { | |
| 13980 var delegateFn = tokens[3]; | |
| 13981 var value = delegateFn ? delegateFn(model, node, true) : | |
| 13982 tokens[2].getValueFrom(model); | |
| 13983 return tokens.isSimplePath ? value : tokens.combinator(value); | |
| 13984 } | |
| 13985 | |
| 13986 var values = []; | |
| 13987 for (var i = 1; i < tokens.length; i += 4) { | |
| 13988 var delegateFn = tokens[i + 2]; | |
| 13989 values[(i - 1) / 4] = delegateFn ? delegateFn(model, node) : | |
| 13990 tokens[i + 1].getValueFrom(model); | |
| 13991 } | |
| 13992 | |
| 13993 return tokens.combinator(values); | |
| 13994 } | |
| 13995 | |
| 13996 function processSinglePathBinding(name, tokens, node, model) { | |
| 13997 var delegateFn = tokens[3]; | |
| 13998 var observer = delegateFn ? delegateFn(model, node, false) : | |
| 13999 new PathObserver(model, tokens[2]); | |
| 14000 | |
| 14001 return tokens.isSimplePath ? observer : | |
| 14002 new ObserverTransform(observer, tokens.combinator); | |
| 14003 } | |
| 14004 | |
| 14005 function processBinding(name, tokens, node, model) { | |
| 14006 if (tokens.onlyOneTime) | |
| 14007 return processOneTimeBinding(name, tokens, node, model); | |
| 14008 | |
| 14009 if (tokens.hasOnePath) | |
| 14010 return processSinglePathBinding(name, tokens, node, model); | |
| 14011 | |
| 14012 var observer = new CompoundObserver(); | |
| 14013 | |
| 14014 for (var i = 1; i < tokens.length; i += 4) { | |
| 14015 var oneTime = tokens[i]; | |
| 14016 var delegateFn = tokens[i + 2]; | |
| 14017 | |
| 14018 if (delegateFn) { | |
| 14019 var value = delegateFn(model, node, oneTime); | |
| 14020 if (oneTime) | |
| 14021 observer.addPath(value) | |
| 14022 else | |
| 14023 observer.addObserver(value); | |
| 14024 continue; | |
| 14025 } | |
| 14026 | |
| 14027 var path = tokens[i + 1]; | |
| 14028 if (oneTime) | |
| 14029 observer.addPath(path.getValueFrom(model)) | |
| 14030 else | |
| 14031 observer.addPath(model, path); | |
| 14032 } | |
| 14033 | |
| 14034 return new ObserverTransform(observer, tokens.combinator); | |
| 14035 } | |
| 14036 | |
| 14037 function processBindings(node, bindings, model, instanceBindings) { | |
| 14038 for (var i = 0; i < bindings.length; i += 2) { | |
| 14039 var name = bindings[i] | |
| 14040 var tokens = bindings[i + 1]; | |
| 14041 var value = processBinding(name, tokens, node, model); | |
| 14042 var binding = node.bind(name, value, tokens.onlyOneTime); | |
| 14043 if (binding && instanceBindings) | |
| 14044 instanceBindings.push(binding); | |
| 14045 } | |
| 14046 | |
| 14047 node.bindFinished(); | |
| 14048 if (!bindings.isTemplate) | |
| 14049 return; | |
| 14050 | |
| 14051 node.model_ = model; | |
| 14052 var iter = node.processBindingDirectives_(bindings); | |
| 14053 if (instanceBindings && iter) | |
| 14054 instanceBindings.push(iter); | |
| 14055 } | |
| 14056 | |
| 14057 function parseWithDefault(el, name, prepareBindingFn) { | |
| 14058 var v = el.getAttribute(name); | |
| 14059 return parseMustaches(v == '' ? '{{}}' : v, name, el, prepareBindingFn); | |
| 14060 } | |
| 14061 | |
| 14062 function parseAttributeBindings(element, prepareBindingFn) { | |
| 14063 assert(element); | |
| 14064 | |
| 14065 var bindings = []; | |
| 14066 var ifFound = false; | |
| 14067 var bindFound = false; | |
| 14068 | |
| 14069 for (var i = 0; i < element.attributes.length; i++) { | |
| 14070 var attr = element.attributes[i]; | |
| 14071 var name = attr.name; | |
| 14072 var value = attr.value; | |
| 14073 | |
| 14074 // Allow bindings expressed in attributes to be prefixed with underbars. | |
| 14075 // We do this to allow correct semantics for browsers that don't implement | |
| 14076 // <template> where certain attributes might trigger side-effects -- and | |
| 14077 // for IE which sanitizes certain attributes, disallowing mustache | |
| 14078 // replacements in their text. | |
| 14079 while (name[0] === '_') { | |
| 14080 name = name.substring(1); | |
| 14081 } | |
| 14082 | |
| 14083 if (isTemplate(element) && | |
| 14084 (name === IF || name === BIND || name === REPEAT)) { | |
| 14085 continue; | |
| 14086 } | |
| 14087 | |
| 14088 var tokens = parseMustaches(value, name, element, | |
| 14089 prepareBindingFn); | |
| 14090 if (!tokens) | |
| 14091 continue; | |
| 14092 | |
| 14093 bindings.push(name, tokens); | |
| 14094 } | |
| 14095 | |
| 14096 if (isTemplate(element)) { | |
| 14097 bindings.isTemplate = true; | |
| 14098 bindings.if = parseWithDefault(element, IF, prepareBindingFn); | |
| 14099 bindings.bind = parseWithDefault(element, BIND, prepareBindingFn); | |
| 14100 bindings.repeat = parseWithDefault(element, REPEAT, prepareBindingFn); | |
| 14101 | |
| 14102 if (bindings.if && !bindings.bind && !bindings.repeat) | |
| 14103 bindings.bind = parseMustaches('{{}}', BIND, element, prepareBindingFn); | |
| 14104 } | |
| 14105 | |
| 14106 return bindings; | |
| 14107 } | |
| 14108 | |
| 14109 function getBindings(node, prepareBindingFn) { | |
| 14110 if (node.nodeType === Node.ELEMENT_NODE) | |
| 14111 return parseAttributeBindings(node, prepareBindingFn); | |
| 14112 | |
| 14113 if (node.nodeType === Node.TEXT_NODE) { | |
| 14114 var tokens = parseMustaches(node.data, 'textContent', node, | |
| 14115 prepareBindingFn); | |
| 14116 if (tokens) | |
| 14117 return ['textContent', tokens]; | |
| 14118 } | |
| 14119 | |
| 14120 return []; | |
| 14121 } | |
| 14122 | |
| 14123 function cloneAndBindInstance(node, parent, stagingDocument, bindings, model, | |
| 14124 delegate, | |
| 14125 instanceBindings, | |
| 14126 instanceRecord) { | |
| 14127 var clone = parent.appendChild(stagingDocument.importNode(node, false)); | |
| 14128 | |
| 14129 var i = 0; | |
| 14130 for (var child = node.firstChild; child; child = child.nextSibling) { | |
| 14131 cloneAndBindInstance(child, clone, stagingDocument, | |
| 14132 bindings.children[i++], | |
| 14133 model, | |
| 14134 delegate, | |
| 14135 instanceBindings); | |
| 14136 } | |
| 14137 | |
| 14138 if (bindings.isTemplate) { | |
| 14139 HTMLTemplateElement.decorate(clone, node); | |
| 14140 if (delegate) | |
| 14141 clone.setDelegate_(delegate); | |
| 14142 } | |
| 14143 | |
| 14144 processBindings(clone, bindings, model, instanceBindings); | |
| 14145 return clone; | |
| 14146 } | |
| 14147 | |
| 14148 function createInstanceBindingMap(node, prepareBindingFn) { | |
| 14149 var map = getBindings(node, prepareBindingFn); | |
| 14150 map.children = {}; | |
| 14151 var index = 0; | |
| 14152 for (var child = node.firstChild; child; child = child.nextSibling) { | |
| 14153 map.children[index++] = createInstanceBindingMap(child, prepareBindingFn); | |
| 14154 } | |
| 14155 | |
| 14156 return map; | |
| 14157 } | |
| 14158 | |
| 14159 var contentUidCounter = 1; | |
| 14160 | |
| 14161 // TODO(rafaelw): Setup a MutationObserver on content which clears the id | |
| 14162 // so that bindingMaps regenerate when the template.content changes. | |
| 14163 function getContentUid(content) { | |
| 14164 var id = content.id_; | |
| 14165 if (!id) | |
| 14166 id = content.id_ = contentUidCounter++; | |
| 14167 return id; | |
| 14168 } | |
| 14169 | |
| 14170 // Each delegate is associated with a set of bindingMaps, one for each | |
| 14171 // content which may be used by a template. The intent is that each binding | |
| 14172 // delegate gets the opportunity to prepare the instance (via the prepare* | |
| 14173 // delegate calls) once across all uses. | |
| 14174 // TODO(rafaelw): Separate out the parse map from the binding map. In the | |
| 14175 // current implementation, if two delegates need a binding map for the same | |
| 14176 // content, the second will have to reparse. | |
| 14177 function getInstanceBindingMap(content, delegate_) { | |
| 14178 var contentId = getContentUid(content); | |
| 14179 if (delegate_) { | |
| 14180 var map = delegate_.bindingMaps[contentId]; | |
| 14181 if (!map) { | |
| 14182 map = delegate_.bindingMaps[contentId] = | |
| 14183 createInstanceBindingMap(content, delegate_.prepareBinding) || []; | |
| 14184 } | |
| 14185 return map; | |
| 14186 } | |
| 14187 | |
| 14188 var map = content.bindingMap_; | |
| 14189 if (!map) { | |
| 14190 map = content.bindingMap_ = | |
| 14191 createInstanceBindingMap(content, undefined) || []; | |
| 14192 } | |
| 14193 return map; | |
| 14194 } | |
| 14195 | |
| 14196 Object.defineProperty(Node.prototype, 'templateInstance', { | |
| 14197 get: function() { | |
| 14198 var instance = this.templateInstance_; | |
| 14199 return instance ? instance : | |
| 14200 (this.parentNode ? this.parentNode.templateInstance : undefined); | |
| 14201 } | |
| 14202 }); | |
| 14203 | |
| 14204 var emptyInstance = document.createDocumentFragment(); | |
| 14205 emptyInstance.bindings_ = []; | |
| 14206 emptyInstance.terminator_ = null; | |
| 14207 | |
| 14208 function TemplateIterator(templateElement) { | |
| 14209 this.closed = false; | |
| 14210 this.templateElement_ = templateElement; | |
| 14211 this.instances = []; | |
| 14212 this.deps = undefined; | |
| 14213 this.iteratedValue = []; | |
| 14214 this.presentValue = undefined; | |
| 14215 this.arrayObserver = undefined; | |
| 14216 } | |
| 14217 | |
| 14218 TemplateIterator.prototype = { | |
| 14219 closeDeps: function() { | |
| 14220 var deps = this.deps; | |
| 14221 if (deps) { | |
| 14222 if (deps.ifOneTime === false) | |
| 14223 deps.ifValue.close(); | |
| 14224 if (deps.oneTime === false) | |
| 14225 deps.value.close(); | |
| 14226 } | |
| 14227 }, | |
| 14228 | |
| 14229 updateDependencies: function(directives, model) { | |
| 14230 this.closeDeps(); | |
| 14231 | |
| 14232 var deps = this.deps = {}; | |
| 14233 var template = this.templateElement_; | |
| 14234 | |
| 14235 var ifValue = true; | |
| 14236 if (directives.if) { | |
| 14237 deps.hasIf = true; | |
| 14238 deps.ifOneTime = directives.if.onlyOneTime; | |
| 14239 deps.ifValue = processBinding(IF, directives.if, template, model); | |
| 14240 | |
| 14241 ifValue = deps.ifValue; | |
| 14242 | |
| 14243 // oneTime if & predicate is false. nothing else to do. | |
| 14244 if (deps.ifOneTime && !ifValue) { | |
| 14245 this.valueChanged(); | |
| 14246 return; | |
| 14247 } | |
| 14248 | |
| 14249 if (!deps.ifOneTime) | |
| 14250 ifValue = ifValue.open(this.updateIfValue, this); | |
| 14251 } | |
| 14252 | |
| 14253 if (directives.repeat) { | |
| 14254 deps.repeat = true; | |
| 14255 deps.oneTime = directives.repeat.onlyOneTime; | |
| 14256 deps.value = processBinding(REPEAT, directives.repeat, template, model); | |
| 14257 } else { | |
| 14258 deps.repeat = false; | |
| 14259 deps.oneTime = directives.bind.onlyOneTime; | |
| 14260 deps.value = processBinding(BIND, directives.bind, template, model); | |
| 14261 } | |
| 14262 | |
| 14263 var value = deps.value; | |
| 14264 if (!deps.oneTime) | |
| 14265 value = value.open(this.updateIteratedValue, this); | |
| 14266 | |
| 14267 if (!ifValue) { | |
| 14268 this.valueChanged(); | |
| 14269 return; | |
| 14270 } | |
| 14271 | |
| 14272 this.updateValue(value); | |
| 14273 }, | |
| 14274 | |
| 14275 /** | |
| 14276 * Gets the updated value of the bind/repeat. This can potentially call | |
| 14277 * user code (if a bindingDelegate is set up) so we try to avoid it if we | |
| 14278 * already have the value in hand (from Observer.open). | |
| 14279 */ | |
| 14280 getUpdatedValue: function() { | |
| 14281 var value = this.deps.value; | |
| 14282 if (!this.deps.oneTime) | |
| 14283 value = value.discardChanges(); | |
| 14284 return value; | |
| 14285 }, | |
| 14286 | |
| 14287 updateIfValue: function(ifValue) { | |
| 14288 if (!ifValue) { | |
| 14289 this.valueChanged(); | |
| 14290 return; | |
| 14291 } | |
| 14292 | |
| 14293 this.updateValue(this.getUpdatedValue()); | |
| 14294 }, | |
| 14295 | |
| 14296 updateIteratedValue: function(value) { | |
| 14297 if (this.deps.hasIf) { | |
| 14298 var ifValue = this.deps.ifValue; | |
| 14299 if (!this.deps.ifOneTime) | |
| 14300 ifValue = ifValue.discardChanges(); | |
| 14301 if (!ifValue) { | |
| 14302 this.valueChanged(); | |
| 14303 return; | |
| 14304 } | |
| 14305 } | |
| 14306 | |
| 14307 this.updateValue(value); | |
| 14308 }, | |
| 14309 | |
| 14310 updateValue: function(value) { | |
| 14311 if (!this.deps.repeat) | |
| 14312 value = [value]; | |
| 14313 var observe = this.deps.repeat && | |
| 14314 !this.deps.oneTime && | |
| 14315 Array.isArray(value); | |
| 14316 this.valueChanged(value, observe); | |
| 14317 }, | |
| 14318 | |
| 14319 valueChanged: function(value, observeValue) { | |
| 14320 if (!Array.isArray(value)) | |
| 14321 value = []; | |
| 14322 | |
| 14323 if (value === this.iteratedValue) | |
| 14324 return; | |
| 14325 | |
| 14326 this.unobserve(); | |
| 14327 this.presentValue = value; | |
| 14328 if (observeValue) { | |
| 14329 this.arrayObserver = new ArrayObserver(this.presentValue); | |
| 14330 this.arrayObserver.open(this.handleSplices, this); | |
| 14331 } | |
| 14332 | |
| 14333 this.handleSplices(ArrayObserver.calculateSplices(this.presentValue, | |
| 14334 this.iteratedValue)); | |
| 14335 }, | |
| 14336 | |
| 14337 getLastInstanceNode: function(index) { | |
| 14338 if (index == -1) | |
| 14339 return this.templateElement_; | |
| 14340 var instance = this.instances[index]; | |
| 14341 var terminator = instance.terminator_; | |
| 14342 if (!terminator) | |
| 14343 return this.getLastInstanceNode(index - 1); | |
| 14344 | |
| 14345 if (terminator.nodeType !== Node.ELEMENT_NODE || | |
| 14346 this.templateElement_ === terminator) { | |
| 14347 return terminator; | |
| 14348 } | |
| 14349 | |
| 14350 var subtemplateIterator = terminator.iterator_; | |
| 14351 if (!subtemplateIterator) | |
| 14352 return terminator; | |
| 14353 | |
| 14354 return subtemplateIterator.getLastTemplateNode(); | |
| 14355 }, | |
| 14356 | |
| 14357 getLastTemplateNode: function() { | |
| 14358 return this.getLastInstanceNode(this.instances.length - 1); | |
| 14359 }, | |
| 14360 | |
| 14361 insertInstanceAt: function(index, fragment) { | |
| 14362 var previousInstanceLast = this.getLastInstanceNode(index - 1); | |
| 14363 var parent = this.templateElement_.parentNode; | |
| 14364 this.instances.splice(index, 0, fragment); | |
| 14365 | |
| 14366 parent.insertBefore(fragment, previousInstanceLast.nextSibling); | |
| 14367 }, | |
| 14368 | |
| 14369 extractInstanceAt: function(index) { | |
| 14370 var previousInstanceLast = this.getLastInstanceNode(index - 1); | |
| 14371 var lastNode = this.getLastInstanceNode(index); | |
| 14372 var parent = this.templateElement_.parentNode; | |
| 14373 var instance = this.instances.splice(index, 1)[0]; | |
| 14374 | |
| 14375 while (lastNode !== previousInstanceLast) { | |
| 14376 var node = previousInstanceLast.nextSibling; | |
| 14377 if (node == lastNode) | |
| 14378 lastNode = previousInstanceLast; | |
| 14379 | |
| 14380 instance.appendChild(parent.removeChild(node)); | |
| 14381 } | |
| 14382 | |
| 14383 return instance; | |
| 14384 }, | |
| 14385 | |
| 14386 getDelegateFn: function(fn) { | |
| 14387 fn = fn && fn(this.templateElement_); | |
| 14388 return typeof fn === 'function' ? fn : null; | |
| 14389 }, | |
| 14390 | |
| 14391 handleSplices: function(splices) { | |
| 14392 if (this.closed || !splices.length) | |
| 14393 return; | |
| 14394 | |
| 14395 var template = this.templateElement_; | |
| 14396 | |
| 14397 if (!template.parentNode) { | |
| 14398 this.close(); | |
| 14399 return; | |
| 14400 } | |
| 14401 | |
| 14402 ArrayObserver.applySplices(this.iteratedValue, this.presentValue, | |
| 14403 splices); | |
| 14404 | |
| 14405 var delegate = template.delegate_; | |
| 14406 if (this.instanceModelFn_ === undefined) { | |
| 14407 this.instanceModelFn_ = | |
| 14408 this.getDelegateFn(delegate && delegate.prepareInstanceModel); | |
| 14409 } | |
| 14410 | |
| 14411 if (this.instancePositionChangedFn_ === undefined) { | |
| 14412 this.instancePositionChangedFn_ = | |
| 14413 this.getDelegateFn(delegate && | |
| 14414 delegate.prepareInstancePositionChanged); | |
| 14415 } | |
| 14416 | |
| 14417 // Instance Removals | |
| 14418 var instanceCache = new Map; | |
| 14419 var removeDelta = 0; | |
| 14420 for (var i = 0; i < splices.length; i++) { | |
| 14421 var splice = splices[i]; | |
| 14422 var removed = splice.removed; | |
| 14423 for (var j = 0; j < removed.length; j++) { | |
| 14424 var model = removed[j]; | |
| 14425 var instance = this.extractInstanceAt(splice.index + removeDelta); | |
| 14426 if (instance !== emptyInstance) { | |
| 14427 instanceCache.set(model, instance); | |
| 14428 } | |
| 14429 } | |
| 14430 | |
| 14431 removeDelta -= splice.addedCount; | |
| 14432 } | |
| 14433 | |
| 14434 // Instance Insertions | |
| 14435 for (var i = 0; i < splices.length; i++) { | |
| 14436 var splice = splices[i]; | |
| 14437 var addIndex = splice.index; | |
| 14438 for (; addIndex < splice.index + splice.addedCount; addIndex++) { | |
| 14439 var model = this.iteratedValue[addIndex]; | |
| 14440 var instance = instanceCache.get(model); | |
| 14441 if (instance) { | |
| 14442 instanceCache.delete(model); | |
| 14443 } else { | |
| 14444 if (this.instanceModelFn_) { | |
| 14445 model = this.instanceModelFn_(model); | |
| 14446 } | |
| 14447 | |
| 14448 if (model === undefined) { | |
| 14449 instance = emptyInstance; | |
| 14450 } else { | |
| 14451 instance = template.createInstance(model, undefined, delegate); | |
| 14452 } | |
| 14453 } | |
| 14454 | |
| 14455 this.insertInstanceAt(addIndex, instance); | |
| 14456 } | |
| 14457 } | |
| 14458 | |
| 14459 instanceCache.forEach(function(instance) { | |
| 14460 this.closeInstanceBindings(instance); | |
| 14461 }, this); | |
| 14462 | |
| 14463 if (this.instancePositionChangedFn_) | |
| 14464 this.reportInstancesMoved(splices); | |
| 14465 }, | |
| 14466 | |
| 14467 reportInstanceMoved: function(index) { | |
| 14468 var instance = this.instances[index]; | |
| 14469 if (instance === emptyInstance) | |
| 14470 return; | |
| 14471 | |
| 14472 this.instancePositionChangedFn_(instance.templateInstance_, index); | |
| 14473 }, | |
| 14474 | |
| 14475 reportInstancesMoved: function(splices) { | |
| 14476 var index = 0; | |
| 14477 var offset = 0; | |
| 14478 for (var i = 0; i < splices.length; i++) { | |
| 14479 var splice = splices[i]; | |
| 14480 if (offset != 0) { | |
| 14481 while (index < splice.index) { | |
| 14482 this.reportInstanceMoved(index); | |
| 14483 index++; | |
| 14484 } | |
| 14485 } else { | |
| 14486 index = splice.index; | |
| 14487 } | |
| 14488 | |
| 14489 while (index < splice.index + splice.addedCount) { | |
| 14490 this.reportInstanceMoved(index); | |
| 14491 index++; | |
| 14492 } | |
| 14493 | |
| 14494 offset += splice.addedCount - splice.removed.length; | |
| 14495 } | |
| 14496 | |
| 14497 if (offset == 0) | |
| 14498 return; | |
| 14499 | |
| 14500 var length = this.instances.length; | |
| 14501 while (index < length) { | |
| 14502 this.reportInstanceMoved(index); | |
| 14503 index++; | |
| 14504 } | |
| 14505 }, | |
| 14506 | |
| 14507 closeInstanceBindings: function(instance) { | |
| 14508 var bindings = instance.bindings_; | |
| 14509 for (var i = 0; i < bindings.length; i++) { | |
| 14510 bindings[i].close(); | |
| 14511 } | |
| 14512 }, | |
| 14513 | |
| 14514 unobserve: function() { | |
| 14515 if (!this.arrayObserver) | |
| 14516 return; | |
| 14517 | |
| 14518 this.arrayObserver.close(); | |
| 14519 this.arrayObserver = undefined; | |
| 14520 }, | |
| 14521 | |
| 14522 close: function() { | |
| 14523 if (this.closed) | |
| 14524 return; | |
| 14525 this.unobserve(); | |
| 14526 for (var i = 0; i < this.instances.length; i++) { | |
| 14527 this.closeInstanceBindings(this.instances[i]); | |
| 14528 } | |
| 14529 | |
| 14530 this.instances.length = 0; | |
| 14531 this.closeDeps(); | |
| 14532 this.templateElement_.iterator_ = undefined; | |
| 14533 this.closed = true; | |
| 14534 } | |
| 14535 }; | |
| 14536 | |
| 14537 // Polyfill-specific API. | |
| 14538 HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom; | |
| 14539 })(this); | |
| 14540 | |
| 14541 /* | |
| 14542 * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. | |
| 14543 * This code may only be used under the BSD style license found at http://polyme
r.github.io/LICENSE.txt | |
| 14544 * The complete set of authors may be found at http://polymer.github.io/AUTHORS.
txt | |
| 14545 * The complete set of contributors may be found at http://polymer.github.io/CON
TRIBUTORS.txt | |
| 14546 * Code distributed by Google as part of the polymer project is also | |
| 14547 * subject to an additional IP rights grant found at http://polymer.github.io/PA
TENTS.txt | |
| 14548 */ | |
| 14549 | |
| 14550 (function(scope) { | |
| 14551 | |
| 14552 // inject style sheet | |
| 14553 var style = document.createElement('style'); | |
| 14554 style.textContent = 'template {display: none !important;} /* injected by platfor
m.js */'; | |
| 14555 var head = document.querySelector('head'); | |
| 14556 head.insertBefore(style, head.firstChild); | |
| 14557 | |
| 14558 // flush (with logging) | |
| 14559 var flushing; | |
| 14560 function flush() { | |
| 14561 if (!flushing) { | |
| 14562 flushing = true; | |
| 14563 scope.endOfMicrotask(function() { | |
| 14564 flushing = false; | |
| 14565 logFlags.data && console.group('Platform.flush()'); | |
| 14566 scope.performMicrotaskCheckpoint(); | |
| 14567 logFlags.data && console.groupEnd(); | |
| 14568 }); | |
| 14569 } | |
| 14570 }; | |
| 14571 | |
| 14572 // polling dirty checker | |
| 14573 // flush periodically if platform does not have object observe. | |
| 14574 if (!Observer.hasObjectObserve) { | |
| 14575 var FLUSH_POLL_INTERVAL = 125; | |
| 14576 window.addEventListener('WebComponentsReady', function() { | |
| 14577 flush(); | |
| 14578 scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL); | |
| 14579 }); | |
| 14580 } else { | |
| 14581 // make flush a no-op when we have Object.observe | |
| 14582 flush = function() {}; | |
| 14583 } | |
| 14584 | |
| 14585 if (window.CustomElements && !CustomElements.useNative) { | |
| 14586 var originalImportNode = Document.prototype.importNode; | |
| 14587 Document.prototype.importNode = function(node, deep) { | |
| 14588 var imported = originalImportNode.call(this, node, deep); | |
| 14589 CustomElements.upgradeAll(imported); | |
| 14590 return imported; | |
| 14591 } | |
| 14592 } | |
| 14593 | |
| 14594 // exports | |
| 14595 scope.flush = flush; | |
| 14596 | |
| 14597 })(window.Platform); | |
| 14598 | |
| 14599 | 12262 |
| 14600 //# sourceMappingURL=platform.concat.js.map | 12263 //# sourceMappingURL=platform.concat.js.map |
| OLD | NEW |