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 |