Index: pkg/web_components/lib/platform.concat.js |
diff --git a/pkg/web_components/lib/platform.concat.js b/pkg/web_components/lib/platform.concat.js |
index 6eea86858eae0662dae51b4d21570024a9388a2c..9b7ff43b306605248f61313126fcba359fd2e5f2 100644 |
--- a/pkg/web_components/lib/platform.concat.js |
+++ b/pkg/web_components/lib/platform.concat.js |
@@ -112,6 +112,9 @@ if (typeof WeakMap === 'undefined') { |
})(); |
} |
+// select ShadowDOM impl |
+if (Platform.flags.shadow) { |
+ |
// Copyright 2012 Google Inc. |
// |
// Licensed under the Apache License, Version 2.0 (the "License"); |
@@ -1840,9 +1843,6 @@ if (typeof WeakMap === 'undefined') { |
global.ObserverTransform = ObserverTransform; |
})(typeof global !== 'undefined' && global && typeof module !== 'undefined' && module ? global : this || window); |
-// select ShadowDOM impl |
-if (Platform.flags.shadow) { |
- |
// Copyright 2012 The Polymer Authors. All rights reserved. |
// Use of this source code is goverened by a BSD-style |
// license that can be found in the LICENSE file. |
@@ -8512,27 +8512,33 @@ var ShadowCSS = { |
cssText += this.scopeRules(rule.cssRules, scopeSelector); |
cssText += '\n}\n\n'; |
} else { |
- // TODO(sjmiles): KEYFRAMES_RULE in IE11 throws when we query cssText |
- // 'cssText' in rule returns true, but rule.cssText throws anyway |
- // We can test the rule type, e.g. |
- // else if (rule.type !== CSSRule.KEYFRAMES_RULE && rule.cssText) { |
- // but this will prevent cssText propagation in other browsers which |
- // support it. |
- // KEYFRAMES_RULE has a CSSRuleSet, so the text can probably be reconstructed |
- // from that collection; this would be a proper fix. |
- // For now, I'm trapping the exception so IE11 is unblocked in other areas. |
+ // KEYFRAMES_RULE in IE throws when we query cssText |
+ // when it contains a -webkit- property. |
+ // if this happens, we fallback to constructing the rule |
+ // from the CSSRuleSet |
+ // https://connect.microsoft.com/IE/feedbackdetail/view/955703/accessing-csstext-of-a-keyframe-rule-that-contains-a-webkit-property-via-cssom-generates-exception |
try { |
if (rule.cssText) { |
cssText += rule.cssText + '\n\n'; |
} |
} catch(x) { |
- // squelch |
+ if (rule.type === CSSRule.KEYFRAMES_RULE && rule.cssRules) { |
+ cssText += this.ieSafeCssTextFromKeyFrameRule(rule); |
+ } |
} |
} |
}, this); |
} |
return cssText; |
}, |
+ ieSafeCssTextFromKeyFrameRule: function(rule) { |
+ var cssText = '@keyframes ' + rule.name + ' {'; |
+ Array.prototype.forEach.call(rule.cssRules, function(rule) { |
+ cssText += ' ' + rule.keyText + ' {' + rule.style.cssText + '}'; |
+ }); |
+ cssText += ' }'; |
+ return cssText; |
+ }, |
scopeSelector: function(selector, scopeSelector, strict) { |
var r = [], parts = selector.split(','); |
parts.forEach(function(p) { |
@@ -8755,7 +8761,7 @@ function withCssRules(cssText, callback) { |
var style = cssTextToStyle(cssText); |
inFrame(function(doc) { |
doc.head.appendChild(style.impl); |
- rules = style.sheet.cssRules; |
+ rules = Array.prototype.slice.call(style.sheet.cssRules, 0); |
callback(rules); |
}); |
} else { |
@@ -8836,11 +8842,10 @@ if (window.ShadowDOMPolyfill) { |
} |
if (elt.__resource) { |
style = elt.ownerDocument.createElement('style'); |
- style.textContent = urlResolver.resolveCssText( |
- elt.__resource, elt.href); |
- } else { |
- urlResolver.resolveStyle(style); |
+ style.textContent = elt.__resource; |
} |
+ // relay on HTMLImports for path fixup |
+ HTMLImports.path.resolveUrlsInStyle(style); |
style.textContent = ShadowCSS.shimStyle(style); |
style.removeAttribute(SHIM_ATTRIBUTE, ''); |
style.setAttribute(SHIMMED_ATTRIBUTE, ''); |
@@ -8906,23 +8911,6 @@ scope.ShadowCSS = ShadowCSS; |
} |
}); |
- Platform.templateContent = function(inTemplate) { |
- // if MDV exists, it may need to boostrap this template to reveal content |
- if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { |
- HTMLTemplateElement.bootstrap(inTemplate); |
- } |
- // fallback when there is no Shadow DOM polyfill, no MDV polyfill, and no |
- // native template support |
- if (!inTemplate.content && !inTemplate._content) { |
- var frag = document.createDocumentFragment(); |
- while (inTemplate.firstChild) { |
- frag.appendChild(inTemplate.firstChild); |
- } |
- inTemplate._content = frag; |
- } |
- return inTemplate.content || inTemplate._content; |
- }; |
- |
})(window.Platform); |
} |
@@ -9530,42 +9518,6 @@ if (!Function.prototype.bind) { |
}; |
} |
-// mixin |
- |
-// copy all properties from inProps (et al) to inObj |
-function mixin(inObj/*, inProps, inMoreProps, ...*/) { |
- var obj = inObj || {}; |
- for (var i = 1; i < arguments.length; i++) { |
- var p = arguments[i]; |
- try { |
- for (var n in p) { |
- copyProperty(n, p, obj); |
- } |
- } catch(x) { |
- } |
- } |
- return obj; |
-} |
- |
-// copy property inName from inSource object to inTarget object |
-function copyProperty(inName, inSource, inTarget) { |
- var pd = getPropertyDescriptor(inSource, inName); |
- Object.defineProperty(inTarget, inName, pd); |
-} |
- |
-// get property descriptor for inName on inObject, even if |
-// inName exists on some link in inObject's prototype chain |
-function getPropertyDescriptor(inObject, inName) { |
- if (inObject) { |
- var pd = Object.getOwnPropertyDescriptor(inObject, inName); |
- return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName); |
- } |
-} |
- |
-// export |
- |
-scope.mixin = mixin; |
- |
})(window.Platform); |
/* |
@@ -9581,46 +9533,6 @@ scope.mixin = mixin; |
'use strict'; |
- // polyfill DOMTokenList |
- // * add/remove: allow these methods to take multiple classNames |
- // * toggle: add a 2nd argument which forces the given state rather |
- // than toggling. |
- |
- var add = DOMTokenList.prototype.add; |
- var remove = DOMTokenList.prototype.remove; |
- DOMTokenList.prototype.add = function() { |
- for (var i = 0; i < arguments.length; i++) { |
- add.call(this, arguments[i]); |
- } |
- }; |
- DOMTokenList.prototype.remove = function() { |
- for (var i = 0; i < arguments.length; i++) { |
- remove.call(this, arguments[i]); |
- } |
- }; |
- DOMTokenList.prototype.toggle = function(name, bool) { |
- if (arguments.length == 1) { |
- bool = !this.contains(name); |
- } |
- bool ? this.add(name) : this.remove(name); |
- }; |
- DOMTokenList.prototype.switch = function(oldName, newName) { |
- oldName && this.remove(oldName); |
- newName && this.add(newName); |
- }; |
- |
- // add array() to NodeList, NamedNodeMap, HTMLCollection |
- |
- var ArraySlice = function() { |
- return Array.prototype.slice.call(this); |
- }; |
- |
- var namedNodeMap = (window.NamedNodeMap || window.MozNamedAttrMap || {}); |
- |
- NodeList.prototype.array = ArraySlice; |
- namedNodeMap.prototype.array = ArraySlice; |
- HTMLCollection.prototype.array = ArraySlice; |
- |
// polyfill performance.now |
if (!window.performance) { |
@@ -9658,19 +9570,6 @@ scope.mixin = mixin; |
})(); |
} |
- // utility |
- |
- function createDOM(inTagOrNode, inHTML, inAttrs) { |
- var dom = typeof inTagOrNode == 'string' ? |
- document.createElement(inTagOrNode) : inTagOrNode.cloneNode(true); |
- dom.innerHTML = inHTML; |
- if (inAttrs) { |
- for (var n in inAttrs) { |
- dom.setAttribute(n, inAttrs[n]); |
- } |
- } |
- return dom; |
- } |
// Make a stub for Polymer() for polyfill purposes; under the HTMLImports |
// polyfill, scripts in the main document run before imports. That means |
// if (1) polymer is imported and (2) Polymer() is called in the main document |
@@ -9680,17 +9579,21 @@ scope.mixin = mixin; |
var elementDeclarations = []; |
var polymerStub = function(name, dictionary) { |
+ Array.prototype.push.call(arguments, document._currentScript); |
elementDeclarations.push(arguments); |
- } |
+ }; |
window.Polymer = polymerStub; |
// deliver queued delcarations |
- scope.deliverDeclarations = function() { |
- scope.deliverDeclarations = function() { |
+ scope.consumeDeclarations = function(callback) { |
+ scope.consumeDeclarations = function() { |
throw 'Possible attempt to load Polymer twice'; |
}; |
- return elementDeclarations; |
- } |
+ if (callback) { |
+ callback(elementDeclarations); |
+ } |
+ elementDeclarations = null; |
+ }; |
// Once DOMContent has loaded, any main document scripts that depend on |
// Polymer() should have run. Calling Polymer() now is an error until |
@@ -9705,583 +9608,107 @@ scope.mixin = mixin; |
} |
}); |
- // exports |
- scope.createDOM = createDOM; |
- |
-})(window.Platform); |
- |
-/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */ |
- |
-// poor man's adapter for template.content on various platform scenarios |
-(function(scope) { |
- scope.templateContent = scope.templateContent || function(inTemplate) { |
- return inTemplate.content; |
- }; |
})(window.Platform); |
/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
+ * Copyright 2012 The Polymer Authors. All rights reserved. |
+ * Use of this source code is goverened by a BSD-style |
+ * license that can be found in the LICENSE file. |
*/ |
-(function(scope) { |
- |
- scope = scope || (window.Inspector = {}); |
- |
- var inspector; |
- |
- window.sinspect = function(inNode, inProxy) { |
- if (!inspector) { |
- inspector = window.open('', 'ShadowDOM Inspector', null, true); |
- inspector.document.write(inspectorHTML); |
- //inspector.document.close(); |
- inspector.api = { |
- shadowize: shadowize |
- }; |
- } |
- inspect(inNode || wrap(document.body), inProxy); |
- }; |
- |
- var inspectorHTML = [ |
- '<!DOCTYPE html>', |
- '<html>', |
- ' <head>', |
- ' <title>ShadowDOM Inspector</title>', |
- ' <style>', |
- ' body {', |
- ' }', |
- ' pre {', |
- ' font: 9pt "Courier New", monospace;', |
- ' line-height: 1.5em;', |
- ' }', |
- ' tag {', |
- ' color: purple;', |
- ' }', |
- ' ul {', |
- ' margin: 0;', |
- ' padding: 0;', |
- ' list-style: none;', |
- ' }', |
- ' li {', |
- ' display: inline-block;', |
- ' background-color: #f1f1f1;', |
- ' padding: 4px 6px;', |
- ' border-radius: 4px;', |
- ' margin-right: 4px;', |
- ' }', |
- ' </style>', |
- ' </head>', |
- ' <body>', |
- ' <ul id="crumbs">', |
- ' </ul>', |
- ' <div id="tree"></div>', |
- ' </body>', |
- '</html>' |
- ].join('\n'); |
- |
- var crumbs = []; |
- |
- var displayCrumbs = function() { |
- // alias our document |
- var d = inspector.document; |
- // get crumbbar |
- var cb = d.querySelector('#crumbs'); |
- // clear crumbs |
- cb.textContent = ''; |
- // build new crumbs |
- for (var i=0, c; c=crumbs[i]; i++) { |
- var a = d.createElement('a'); |
- a.href = '#'; |
- a.textContent = c.localName; |
- a.idx = i; |
- a.onclick = function(event) { |
- var c; |
- while (crumbs.length > this.idx) { |
- c = crumbs.pop(); |
- } |
- inspect(c.shadow || c, c); |
- event.preventDefault(); |
- }; |
- cb.appendChild(d.createElement('li')).appendChild(a); |
- } |
- }; |
- |
- var inspect = function(inNode, inProxy) { |
- // alias our document |
- var d = inspector.document; |
- // reset list of drillable nodes |
- drillable = []; |
- // memoize our crumb proxy |
- var proxy = inProxy || inNode; |
- crumbs.push(proxy); |
- // update crumbs |
- displayCrumbs(); |
- // reflect local tree |
- d.body.querySelector('#tree').innerHTML = |
- '<pre>' + output(inNode, inNode.childNodes) + '</pre>'; |
- }; |
+(function(global) { |
- var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); |
+ var registrationsTable = new WeakMap(); |
- var blacklisted = {STYLE:1, SCRIPT:1, "#comment": 1, TEMPLATE: 1}; |
- var blacklist = function(inNode) { |
- return blacklisted[inNode.nodeName]; |
- }; |
+ // We use setImmediate or postMessage for our future callback. |
+ var setImmediate = window.msSetImmediate; |
- var output = function(inNode, inChildNodes, inIndent) { |
- if (blacklist(inNode)) { |
- return ''; |
- } |
- var indent = inIndent || ''; |
- if (inNode.localName || inNode.nodeType == 11) { |
- var name = inNode.localName || 'shadow-root'; |
- //inChildNodes = ShadowDOM.localNodes(inNode); |
- var info = indent + describe(inNode); |
- // if only textNodes |
- // TODO(sjmiles): make correct for ShadowDOM |
- /*if (!inNode.children.length && inNode.localName !== 'content' && inNode.localName !== 'shadow') { |
- info += catTextContent(inChildNodes); |
- } else*/ { |
- // TODO(sjmiles): native <shadow> has no reference to its projection |
- if (name == 'content' /*|| name == 'shadow'*/) { |
- inChildNodes = inNode.getDistributedNodes(); |
- } |
- info += '<br/>'; |
- var ind = indent + ' '; |
- forEach(inChildNodes, function(n) { |
- info += output(n, n.childNodes, ind); |
+ // Use post message to emulate setImmediate. |
+ if (!setImmediate) { |
+ var setImmediateQueue = []; |
+ var sentinel = String(Math.random()); |
+ window.addEventListener('message', function(e) { |
+ if (e.data === sentinel) { |
+ var queue = setImmediateQueue; |
+ setImmediateQueue = []; |
+ queue.forEach(function(func) { |
+ func(); |
}); |
- info += indent; |
- } |
- if (!({br:1}[name])) { |
- info += '<tag></' + name + '></tag>'; |
- info += '<br/>'; |
} |
- } else { |
- var text = inNode.textContent.trim(); |
- info = text ? indent + '"' + text + '"' + '<br/>' : ''; |
- } |
- return info; |
- }; |
- |
- var catTextContent = function(inChildNodes) { |
- var info = ''; |
- forEach(inChildNodes, function(n) { |
- info += n.textContent.trim(); |
}); |
- return info; |
- }; |
- |
- var drillable = []; |
+ setImmediate = function(func) { |
+ setImmediateQueue.push(func); |
+ window.postMessage(sentinel, '*'); |
+ }; |
+ } |
- var describe = function(inNode) { |
- var tag = '<tag>' + '<'; |
- var name = inNode.localName || 'shadow-root'; |
- if (inNode.webkitShadowRoot || inNode.shadowRoot) { |
- tag += ' <button idx="' + drillable.length + |
- '" onclick="api.shadowize.call(this)">' + name + '</button>'; |
- drillable.push(inNode); |
- } else { |
- tag += name || 'shadow-root'; |
- } |
- if (inNode.attributes) { |
- forEach(inNode.attributes, function(a) { |
- tag += ' ' + a.name + (a.value ? '="' + a.value + '"' : ''); |
- }); |
- } |
- tag += '>'+ '</tag>'; |
- return tag; |
- }; |
+ // This is used to ensure that we never schedule 2 callas to setImmediate |
+ var isScheduled = false; |
- // remote api |
+ // Keep track of observers that needs to be notified next time. |
+ var scheduledObservers = []; |
- shadowize = function() { |
- var idx = Number(this.attributes.idx.value); |
- //alert(idx); |
- var node = drillable[idx]; |
- if (node) { |
- inspect(node.webkitShadowRoot || node.shadowRoot, node) |
- } else { |
- console.log("bad shadowize node"); |
- console.dir(this); |
+ /** |
+ * Schedules |dispatchCallback| to be called in the future. |
+ * @param {MutationObserver} observer |
+ */ |
+ function scheduleCallback(observer) { |
+ scheduledObservers.push(observer); |
+ if (!isScheduled) { |
+ isScheduled = true; |
+ setImmediate(dispatchCallbacks); |
} |
- }; |
- |
- // export |
- |
- scope.output = output; |
- |
-})(window.Inspector); |
+ } |
-/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */ |
+ function wrapIfNeeded(node) { |
+ return window.ShadowDOMPolyfill && |
+ window.ShadowDOMPolyfill.wrapIfNeeded(node) || |
+ node; |
+ } |
-(function(scope) { |
+ function dispatchCallbacks() { |
+ // http://dom.spec.whatwg.org/#mutation-observers |
- // TODO(sorvell): It's desireable to provide a default stylesheet |
- // that's convenient for styling unresolved elements, but |
- // it's cumbersome to have to include this manually in every page. |
- // It would make sense to put inside some HTMLImport but |
- // the HTMLImports polyfill does not allow loading of stylesheets |
- // that block rendering. Therefore this injection is tolerated here. |
+ isScheduled = false; // Used to allow a new setImmediate call above. |
- var style = document.createElement('style'); |
- style.textContent = '' |
- + 'body {' |
- + 'transition: opacity ease-in 0.2s;' |
- + ' } \n' |
- + 'body[unresolved] {' |
- + 'opacity: 0; display: block; overflow: hidden;' |
- + ' } \n' |
- ; |
- var head = document.querySelector('head'); |
- head.insertBefore(style, head.firstChild); |
+ var observers = scheduledObservers; |
+ scheduledObservers = []; |
+ // Sort observers based on their creation UID (incremental). |
+ observers.sort(function(o1, o2) { |
+ return o1.uid_ - o2.uid_; |
+ }); |
-})(Platform); |
+ var anyNonEmpty = false; |
+ observers.forEach(function(observer) { |
-/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */ |
+ // 2.1, 2.2 |
+ var queue = observer.takeRecords(); |
+ // 2.3. Remove all transient registered observers whose observer is mo. |
+ removeTransientObserversFor(observer); |
-(function(scope) { |
+ // 2.4 |
+ if (queue.length) { |
+ observer.callback_(queue, observer); |
+ anyNonEmpty = true; |
+ } |
+ }); |
- function withDependencies(task, depends) { |
- depends = depends || []; |
- if (!depends.map) { |
- depends = [depends]; |
- } |
- return task.apply(this, depends.map(marshal)); |
+ // 3. |
+ if (anyNonEmpty) |
+ dispatchCallbacks(); |
} |
- function module(name, dependsOrFactory, moduleFactory) { |
- var module; |
- switch (arguments.length) { |
- case 0: |
+ function removeTransientObserversFor(observer) { |
+ observer.nodes_.forEach(function(node) { |
+ var registrations = registrationsTable.get(node); |
+ if (!registrations) |
return; |
- case 1: |
- module = null; |
- break; |
- case 2: |
- // dependsOrFactory is `factory` in this case |
- module = dependsOrFactory.apply(this); |
- break; |
- default: |
- // dependsOrFactory is `depends` in this case |
- module = withDependencies(moduleFactory, dependsOrFactory); |
- break; |
- } |
- modules[name] = module; |
- }; |
- |
- function marshal(name) { |
- return modules[name]; |
- } |
- |
- var modules = {}; |
- |
- function using(depends, task) { |
- HTMLImports.whenImportsReady(function() { |
- withDependencies(task, depends); |
+ registrations.forEach(function(registration) { |
+ if (registration.observer === observer) |
+ registration.removeTransientObservers(); |
+ }); |
}); |
- }; |
- |
- // exports |
- |
- scope.marshal = marshal; |
- // `module` confuses commonjs detectors |
- scope.modularize = module; |
- scope.using = using; |
- |
-})(window); |
- |
-/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */ |
- |
-(function(scope) { |
- |
-var iterations = 0; |
-var callbacks = []; |
-var twiddle = document.createTextNode(''); |
- |
-function endOfMicrotask(callback) { |
- twiddle.textContent = iterations++; |
- callbacks.push(callback); |
-} |
- |
-function atEndOfMicrotask() { |
- while (callbacks.length) { |
- callbacks.shift()(); |
- } |
-} |
- |
-new (window.MutationObserver || JsMutationObserver)(atEndOfMicrotask) |
- .observe(twiddle, {characterData: true}) |
- ; |
- |
-// exports |
- |
-scope.endOfMicrotask = endOfMicrotask; |
- |
-})(Platform); |
- |
- |
-/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */ |
- |
-(function(scope) { |
- |
-var urlResolver = { |
- resolveDom: function(root, url) { |
- url = url || root.ownerDocument.baseURI; |
- this.resolveAttributes(root, url); |
- this.resolveStyles(root, url); |
- // handle template.content |
- var templates = root.querySelectorAll('template'); |
- if (templates) { |
- for (var i = 0, l = templates.length, t; (i < l) && (t = templates[i]); i++) { |
- if (t.content) { |
- this.resolveDom(t.content, url); |
- } |
- } |
- } |
- }, |
- resolveTemplate: function(template) { |
- this.resolveDom(template.content, template.ownerDocument.baseURI); |
- }, |
- resolveStyles: function(root, url) { |
- var styles = root.querySelectorAll('style'); |
- if (styles) { |
- for (var i = 0, l = styles.length, s; (i < l) && (s = styles[i]); i++) { |
- this.resolveStyle(s, url); |
- } |
- } |
- }, |
- resolveStyle: function(style, url) { |
- url = url || style.ownerDocument.baseURI; |
- style.textContent = this.resolveCssText(style.textContent, url); |
- }, |
- resolveCssText: function(cssText, baseUrl, keepAbsolute) { |
- cssText = replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_URL_REGEXP); |
- return replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, CSS_IMPORT_REGEXP); |
- }, |
- resolveAttributes: function(root, url) { |
- if (root.hasAttributes && root.hasAttributes()) { |
- this.resolveElementAttributes(root, url); |
- } |
- // search for attributes that host urls |
- var nodes = root && root.querySelectorAll(URL_ATTRS_SELECTOR); |
- if (nodes) { |
- for (var i = 0, l = nodes.length, n; (i < l) && (n = nodes[i]); i++) { |
- this.resolveElementAttributes(n, url); |
- } |
- } |
- }, |
- resolveElementAttributes: function(node, url) { |
- url = url || node.ownerDocument.baseURI; |
- URL_ATTRS.forEach(function(v) { |
- var attr = node.attributes[v]; |
- var value = attr && attr.value; |
- var replacement; |
- if (value && value.search(URL_TEMPLATE_SEARCH) < 0) { |
- if (v === 'style') { |
- replacement = replaceUrlsInCssText(value, url, false, CSS_URL_REGEXP); |
- } else { |
- replacement = resolveRelativeUrl(url, value); |
- } |
- attr.value = replacement; |
- } |
- }); |
- } |
-}; |
- |
-var CSS_URL_REGEXP = /(url\()([^)]*)(\))/g; |
-var CSS_IMPORT_REGEXP = /(@import[\s]+(?!url\())([^;]*)(;)/g; |
-var URL_ATTRS = ['href', 'src', 'action', 'style', 'url']; |
-var URL_ATTRS_SELECTOR = '[' + URL_ATTRS.join('],[') + ']'; |
-var URL_TEMPLATE_SEARCH = '{{.*}}'; |
- |
-function replaceUrlsInCssText(cssText, baseUrl, keepAbsolute, regexp) { |
- return cssText.replace(regexp, function(m, pre, url, post) { |
- var urlPath = url.replace(/["']/g, ''); |
- urlPath = resolveRelativeUrl(baseUrl, urlPath, keepAbsolute); |
- return pre + '\'' + urlPath + '\'' + post; |
- }); |
-} |
- |
-function resolveRelativeUrl(baseUrl, url, keepAbsolute) { |
- // do not resolve '/' absolute urls |
- if (url && url[0] === '/') { |
- return url; |
- } |
- var u = new URL(url, baseUrl); |
- return keepAbsolute ? u.href : makeDocumentRelPath(u.href); |
-} |
- |
-function makeDocumentRelPath(url) { |
- var root = new URL(document.baseURI); |
- var u = new URL(url, root); |
- if (u.host === root.host && u.port === root.port && |
- u.protocol === root.protocol) { |
- return makeRelPath(root, u); |
- } else { |
- return url; |
- } |
-} |
- |
-// make a relative path from source to target |
-function makeRelPath(sourceUrl, targetUrl) { |
- var source = sourceUrl.pathname; |
- var target = targetUrl.pathname; |
- var s = source.split('/'); |
- var t = target.split('/'); |
- while (s.length && s[0] === t[0]){ |
- s.shift(); |
- t.shift(); |
- } |
- for (var i = 0, l = s.length - 1; i < l; i++) { |
- t.unshift('..'); |
- } |
- return t.join('/') + targetUrl.search + targetUrl.hash; |
-} |
- |
-// exports |
-scope.urlResolver = urlResolver; |
- |
-})(Platform); |
- |
-/* |
- * Copyright 2012 The Polymer Authors. All rights reserved. |
- * Use of this source code is goverened by a BSD-style |
- * license that can be found in the LICENSE file. |
- */ |
- |
-(function(global) { |
- |
- var registrationsTable = new WeakMap(); |
- |
- // We use setImmediate or postMessage for our future callback. |
- var setImmediate = window.msSetImmediate; |
- |
- // Use post message to emulate setImmediate. |
- if (!setImmediate) { |
- var setImmediateQueue = []; |
- var sentinel = String(Math.random()); |
- window.addEventListener('message', function(e) { |
- if (e.data === sentinel) { |
- var queue = setImmediateQueue; |
- setImmediateQueue = []; |
- queue.forEach(function(func) { |
- func(); |
- }); |
- } |
- }); |
- setImmediate = function(func) { |
- setImmediateQueue.push(func); |
- window.postMessage(sentinel, '*'); |
- }; |
- } |
- |
- // This is used to ensure that we never schedule 2 callas to setImmediate |
- var isScheduled = false; |
- |
- // Keep track of observers that needs to be notified next time. |
- var scheduledObservers = []; |
- |
- /** |
- * Schedules |dispatchCallback| to be called in the future. |
- * @param {MutationObserver} observer |
- */ |
- function scheduleCallback(observer) { |
- scheduledObservers.push(observer); |
- if (!isScheduled) { |
- isScheduled = true; |
- setImmediate(dispatchCallbacks); |
- } |
- } |
- |
- function wrapIfNeeded(node) { |
- return window.ShadowDOMPolyfill && |
- window.ShadowDOMPolyfill.wrapIfNeeded(node) || |
- node; |
- } |
- |
- function dispatchCallbacks() { |
- // http://dom.spec.whatwg.org/#mutation-observers |
- |
- isScheduled = false; // Used to allow a new setImmediate call above. |
- |
- var observers = scheduledObservers; |
- scheduledObservers = []; |
- // Sort observers based on their creation UID (incremental). |
- observers.sort(function(o1, o2) { |
- return o1.uid_ - o2.uid_; |
- }); |
- |
- var anyNonEmpty = false; |
- observers.forEach(function(observer) { |
- |
- // 2.1, 2.2 |
- var queue = observer.takeRecords(); |
- // 2.3. Remove all transient registered observers whose observer is mo. |
- removeTransientObserversFor(observer); |
- |
- // 2.4 |
- if (queue.length) { |
- observer.callback_(queue, observer); |
- anyNonEmpty = true; |
- } |
- }); |
- |
- // 3. |
- if (anyNonEmpty) |
- dispatchCallbacks(); |
- } |
- |
- function removeTransientObserversFor(observer) { |
- observer.nodes_.forEach(function(node) { |
- var registrations = registrationsTable.get(node); |
- if (!registrations) |
- return; |
- registrations.forEach(function(registration) { |
- if (registration.observer === observer) |
- registration.removeTransientObservers(); |
- }); |
- }); |
- } |
+ } |
/** |
* This function is used for the "For each registered observer observer (with |
@@ -10739,6 +10166,200 @@ scope.urlResolver = urlResolver; |
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
*/ |
window.HTMLImports = window.HTMLImports || {flags:{}}; |
+/* |
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
+ * Code distributed by Google as part of the polymer project is also |
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
+ */ |
+ |
+(function(scope) { |
+ |
+var hasNative = ('import' in document.createElement('link')); |
+var useNative = hasNative; |
+ |
+isIE = /Trident/.test(navigator.userAgent); |
+ |
+// TODO(sorvell): SD polyfill intrusion |
+var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill); |
+var wrap = function(node) { |
+ return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node; |
+}; |
+var mainDoc = wrap(document); |
+ |
+// NOTE: We cannot polyfill document.currentScript because it's not possible |
+// both to override and maintain the ability to capture the native value; |
+// therefore we choose to expose _currentScript both when native imports |
+// and the polyfill are in use. |
+var currentScriptDescriptor = { |
+ get: function() { |
+ var script = HTMLImports.currentScript || document.currentScript || |
+ // NOTE: only works when called in synchronously executing code. |
+ // readyState should check if `loading` but IE10 is |
+ // interactive when scripts run so we cheat. |
+ (document.readyState !== 'complete' ? |
+ document.scripts[document.scripts.length - 1] : null); |
+ return wrap(script); |
+ }, |
+ configurable: true |
+}; |
+ |
+Object.defineProperty(document, '_currentScript', currentScriptDescriptor); |
+Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor); |
+ |
+// call a callback when all HTMLImports in the document at call (or at least |
+// document ready) time have loaded. |
+// 1. ensure the document is in a ready state (has dom), then |
+// 2. watch for loading of imports and call callback when done |
+function whenImportsReady(callback, doc) { |
+ doc = doc || mainDoc; |
+ // if document is loading, wait and try again |
+ whenDocumentReady(function() { |
+ watchImportsLoad(callback, doc); |
+ }, doc); |
+} |
+ |
+// call the callback when the document is in a ready state (has dom) |
+var requiredReadyState = isIE ? 'complete' : 'interactive'; |
+var READY_EVENT = 'readystatechange'; |
+function isDocumentReady(doc) { |
+ return (doc.readyState === 'complete' || |
+ doc.readyState === requiredReadyState); |
+} |
+ |
+// call <callback> when we ensure the document is in a ready state |
+function whenDocumentReady(callback, doc) { |
+ if (!isDocumentReady(doc)) { |
+ var checkReady = function() { |
+ if (doc.readyState === 'complete' || |
+ doc.readyState === requiredReadyState) { |
+ doc.removeEventListener(READY_EVENT, checkReady); |
+ whenDocumentReady(callback, doc); |
+ } |
+ }; |
+ doc.addEventListener(READY_EVENT, checkReady); |
+ } else if (callback) { |
+ callback(); |
+ } |
+} |
+ |
+function markTargetLoaded(event) { |
+ event.target.__loaded = true; |
+} |
+ |
+// call <callback> when we ensure all imports have loaded |
+function watchImportsLoad(callback, doc) { |
+ var imports = doc.querySelectorAll('link[rel=import]'); |
+ var loaded = 0, l = imports.length; |
+ function checkDone(d) { |
+ if (loaded == l) { |
+ callback && callback(); |
+ } |
+ } |
+ function loadedImport(e) { |
+ markTargetLoaded(e); |
+ loaded++; |
+ checkDone(); |
+ } |
+ if (l) { |
+ for (var i=0, imp; (i<l) && (imp=imports[i]); i++) { |
+ if (isImportLoaded(imp)) { |
+ loadedImport.call(imp, {target: imp}); |
+ } else { |
+ imp.addEventListener('load', loadedImport); |
+ imp.addEventListener('error', loadedImport); |
+ } |
+ } |
+ } else { |
+ checkDone(); |
+ } |
+} |
+ |
+// NOTE: test for native imports loading is based on explicitly watching |
+// all imports (see below). |
+function isImportLoaded(link) { |
+ return useNative ? link.__loaded : link.__importParsed; |
+} |
+ |
+// TODO(sorvell): Workaround for |
+// https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007, should be removed when |
+// this bug is addressed. |
+// (1) Install a mutation observer to see when HTMLImports have loaded |
+// (2) if this script is run during document load it will watch any existing |
+// imports for loading. |
+// |
+// NOTE: The workaround has restricted functionality: (1) it's only compatible |
+// with imports that are added to document.head since the mutation observer |
+// watches only head for perf reasons, (2) it requires this script |
+// to run before any imports have completed loading. |
+if (useNative) { |
+ new MutationObserver(function(mxns) { |
+ for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) { |
+ if (m.addedNodes) { |
+ handleImports(m.addedNodes); |
+ } |
+ } |
+ }).observe(document.head, {childList: true}); |
+ |
+ function handleImports(nodes) { |
+ for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) { |
+ if (isImport(n)) { |
+ handleImport(n); |
+ } |
+ } |
+ } |
+ |
+ function isImport(element) { |
+ return element.localName === 'link' && element.rel === 'import'; |
+ } |
+ |
+ function handleImport(element) { |
+ var loaded = element.import; |
+ if (loaded) { |
+ markTargetLoaded({target: element}); |
+ } else { |
+ element.addEventListener('load', markTargetLoaded); |
+ element.addEventListener('error', markTargetLoaded); |
+ } |
+ } |
+ |
+ // make sure to catch any imports that are in the process of loading |
+ // when this script is run. |
+ (function() { |
+ if (document.readyState === 'loading') { |
+ var imports = document.querySelectorAll('link[rel=import]'); |
+ for (var i=0, l=imports.length, imp; (i<l) && (imp=imports[i]); i++) { |
+ handleImport(imp); |
+ } |
+ } |
+ })(); |
+ |
+} |
+ |
+// Fire the 'HTMLImportsLoaded' event when imports in document at load time |
+// have loaded. This event is required to simulate the script blocking |
+// behavior of native imports. A main document script that needs to be sure |
+// imports have loaded should wait for this event. |
+whenImportsReady(function() { |
+ HTMLImports.ready = true; |
+ HTMLImports.readyTime = new Date().getTime(); |
+ mainDoc.dispatchEvent( |
+ new CustomEvent('HTMLImportsLoaded', {bubbles: true}) |
+ ); |
+}); |
+ |
+// exports |
+scope.useNative = useNative; |
+scope.isImportLoaded = isImportLoaded; |
+scope.whenReady = whenImportsReady; |
+scope.isIE = isIE; |
+ |
+// deprecated |
+scope.whenImportsReady = whenImportsReady; |
+ |
+})(window.HTMLImports); |
/* |
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
@@ -10746,186 +10367,13 @@ window.HTMLImports = window.HTMLImports || {flags:{}}; |
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
* Code distributed by Google as part of the polymer project is also |
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */(function(scope) { |
- |
-var hasNative = ('import' in document.createElement('link')); |
-var useNative = hasNative; |
+ */ |
+(function(scope) { |
-isIE = /Trident/.test(navigator.userAgent); |
- |
-// TODO(sorvell): SD polyfill intrusion |
-var hasShadowDOMPolyfill = Boolean(window.ShadowDOMPolyfill); |
-var wrap = function(node) { |
- return hasShadowDOMPolyfill ? ShadowDOMPolyfill.wrapIfNeeded(node) : node; |
-}; |
-var mainDoc = wrap(document); |
- |
-// NOTE: We cannot polyfill document.currentScript because it's not possible |
-// both to override and maintain the ability to capture the native value; |
-// therefore we choose to expose _currentScript both when native imports |
-// and the polyfill are in use. |
-var currentScriptDescriptor = { |
- get: function() { |
- var script = HTMLImports.currentScript || document.currentScript || |
- // NOTE: only works when called in synchronously executing code. |
- // readyState should check if `loading` but IE10 is |
- // interactive when scripts run so we cheat. |
- (document.readyState !== 'complete' ? |
- document.scripts[document.scripts.length - 1] : null); |
- return wrap(script); |
- }, |
- configurable: true |
-}; |
- |
-Object.defineProperty(document, '_currentScript', currentScriptDescriptor); |
-Object.defineProperty(mainDoc, '_currentScript', currentScriptDescriptor); |
- |
-// call a callback when all HTMLImports in the document at call (or at least |
-// document ready) time have loaded. |
-// 1. ensure the document is in a ready state (has dom), then |
-// 2. watch for loading of imports and call callback when done |
-function whenImportsReady(callback, doc) { |
- doc = doc || mainDoc; |
- // if document is loading, wait and try again |
- whenDocumentReady(function() { |
- watchImportsLoad(callback, doc); |
- }, doc); |
-} |
- |
-// call the callback when the document is in a ready state (has dom) |
-var requiredReadyState = isIE ? 'complete' : 'interactive'; |
-var READY_EVENT = 'readystatechange'; |
-function isDocumentReady(doc) { |
- return (doc.readyState === 'complete' || |
- doc.readyState === requiredReadyState); |
-} |
- |
-// call <callback> when we ensure the document is in a ready state |
-function whenDocumentReady(callback, doc) { |
- if (!isDocumentReady(doc)) { |
- var checkReady = function() { |
- if (doc.readyState === 'complete' || |
- doc.readyState === requiredReadyState) { |
- doc.removeEventListener(READY_EVENT, checkReady); |
- whenDocumentReady(callback, doc); |
- } |
- } |
- doc.addEventListener(READY_EVENT, checkReady); |
- } else if (callback) { |
- callback(); |
- } |
-} |
- |
-// call <callback> when we ensure all imports have loaded |
-function watchImportsLoad(callback, doc) { |
- var imports = doc.querySelectorAll('link[rel=import]'); |
- var loaded = 0, l = imports.length; |
- function checkDone(d) { |
- if (loaded == l) { |
- callback && callback(); |
- } |
- } |
- function loadedImport(e) { |
- loaded++; |
- checkDone(); |
- } |
- if (l) { |
- for (var i=0, imp; (i<l) && (imp=imports[i]); i++) { |
- if (isImportLoaded(imp)) { |
- loadedImport.call(imp); |
- } else { |
- imp.addEventListener('load', loadedImport); |
- imp.addEventListener('error', loadedImport); |
- } |
- } |
- } else { |
- checkDone(); |
- } |
-} |
- |
-// NOTE: test for native imports loading is based on explicitly watching |
-// all imports (see below). |
-function isImportLoaded(link) { |
- return useNative ? link.__loaded : link.__importParsed; |
-} |
- |
-// TODO(sorvell): install a mutation observer to see if HTMLImports have loaded |
-// this is a workaround for https://www.w3.org/Bugs/Public/show_bug.cgi?id=25007 |
-// and should be removed when this bug is addressed. |
-if (useNative) { |
- new MutationObserver(function(mxns) { |
- for (var i=0, l=mxns.length, m; (i < l) && (m=mxns[i]); i++) { |
- if (m.addedNodes) { |
- handleImports(m.addedNodes); |
- } |
- } |
- }).observe(document.head, {childList: true}); |
- |
- function handleImports(nodes) { |
- for (var i=0, l=nodes.length, n; (i<l) && (n=nodes[i]); i++) { |
- if (isImport(n)) { |
- handleImport(n); |
- } |
- } |
- } |
- |
- function isImport(element) { |
- return element.localName === 'link' && element.rel === 'import'; |
- } |
- |
- function handleImport(element) { |
- var loaded = element.import; |
- if (loaded) { |
- markTargetLoaded({target: element}); |
- } else { |
- element.addEventListener('load', markTargetLoaded); |
- element.addEventListener('error', markTargetLoaded); |
- } |
- } |
- |
- function markTargetLoaded(event) { |
- event.target.__loaded = true; |
- } |
- |
-} |
- |
-// Fire the 'HTMLImportsLoaded' event when imports in document at load time |
-// have loaded. This event is required to simulate the script blocking |
-// behavior of native imports. A main document script that needs to be sure |
-// imports have loaded should wait for this event. |
-whenImportsReady(function() { |
- HTMLImports.ready = true; |
- HTMLImports.readyTime = new Date().getTime(); |
- mainDoc.dispatchEvent( |
- new CustomEvent('HTMLImportsLoaded', {bubbles: true}) |
- ); |
-}); |
- |
-// exports |
-scope.useNative = useNative; |
-scope.isImportLoaded = isImportLoaded; |
-scope.whenReady = whenImportsReady; |
-scope.isIE = isIE; |
- |
-// deprecated |
-scope.whenImportsReady = whenImportsReady; |
- |
-})(window.HTMLImports); |
- |
-/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */ |
-(function(scope) { |
- |
- // imports |
- var path = scope.path; |
- var xhr = scope.xhr; |
- var flags = scope.flags; |
+ // imports |
+ var path = scope.path; |
+ var xhr = scope.xhr; |
+ var flags = scope.flags; |
// TODO(sorvell): this loader supports a dynamic list of urls |
// and an oncomplete callback that is called when the loader is done. |
@@ -12730,110 +12178,27 @@ if (window.ShadowDOMPolyfill) { |
*/ |
(function(scope) { |
- var endOfMicrotask = scope.endOfMicrotask; |
- |
- // Generic url loader |
- function Loader(regex) { |
- this.cache = Object.create(null); |
- this.map = Object.create(null); |
- this.requests = 0; |
- this.regex = regex; |
- } |
- Loader.prototype = { |
- |
- // TODO(dfreedm): there may be a better factoring here |
- // extract absolute urls from the text (full of relative urls) |
- extractUrls: function(text, base) { |
- var matches = []; |
- var matched, u; |
- while ((matched = this.regex.exec(text))) { |
- u = new URL(matched[1], base); |
- matches.push({matched: matched[0], url: u.href}); |
- } |
- return matches; |
- }, |
- // take a text blob, a root url, and a callback and load all the urls found within the text |
- // returns a map of absolute url to text |
- process: function(text, root, callback) { |
- var matches = this.extractUrls(text, root); |
- |
- // every call to process returns all the text this loader has ever received |
- var done = callback.bind(null, this.map); |
- this.fetch(matches, done); |
- }, |
- // build a mapping of url -> text from matches |
- fetch: function(matches, callback) { |
- var inflight = matches.length; |
- |
- // return early if there is no fetching to be done |
- if (!inflight) { |
- return callback(); |
- } |
- |
- // wait for all subrequests to return |
- var done = function() { |
- if (--inflight === 0) { |
- callback(); |
- } |
- }; |
- |
- // start fetching all subrequests |
- var m, req, url; |
- for (var i = 0; i < inflight; i++) { |
- m = matches[i]; |
- url = m.url; |
- req = this.cache[url]; |
- // if this url has already been requested, skip requesting it again |
- if (!req) { |
- req = this.xhr(url); |
- req.match = m; |
- this.cache[url] = req; |
- } |
- // wait for the request to process its subrequests |
- req.wait(done); |
- } |
- }, |
- handleXhr: function(request) { |
- var match = request.match; |
- var url = match.url; |
- |
- // handle errors with an empty string |
- var response = request.response || request.responseText || ''; |
- this.map[url] = response; |
- this.fetch(this.extractUrls(response, url), request.resolve); |
- }, |
- xhr: function(url) { |
- this.requests++; |
- var request = new XMLHttpRequest(); |
- request.open('GET', url, true); |
- request.send(); |
- request.onerror = request.onload = this.handleXhr.bind(this, request); |
- |
- // queue of tasks to run after XHR returns |
- request.pending = []; |
- request.resolve = function() { |
- var pending = request.pending; |
- for(var i = 0; i < pending.length; i++) { |
- pending[i](); |
- } |
- request.pending = null; |
- }; |
- // if we have already resolved, pending is null, async call the callback |
- request.wait = function(fn) { |
- if (request.pending) { |
- request.pending.push(fn); |
- } else { |
- endOfMicrotask(fn); |
- } |
- }; |
+ // TODO(sorvell): It's desireable to provide a default stylesheet |
+ // that's convenient for styling unresolved elements, but |
+ // it's cumbersome to have to include this manually in every page. |
+ // It would make sense to put inside some HTMLImport but |
+ // the HTMLImports polyfill does not allow loading of stylesheets |
+ // that block rendering. Therefore this injection is tolerated here. |
- return request; |
- } |
- }; |
+ var style = document.createElement('style'); |
+ style.textContent = '' |
+ + 'body {' |
+ + 'transition: opacity ease-in 0.2s;' |
+ + ' } \n' |
+ + 'body[unresolved] {' |
+ + 'opacity: 0; display: block; overflow: hidden;' |
+ + ' } \n' |
+ ; |
+ var head = document.querySelector('head'); |
+ head.insertBefore(style, head.firstChild); |
- scope.Loader = Loader; |
-})(window.Platform); |
+})(Platform); |
/* |
* Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
@@ -12846,1755 +12211,53 @@ if (window.ShadowDOMPolyfill) { |
(function(scope) { |
-var urlResolver = scope.urlResolver; |
-var Loader = scope.Loader; |
- |
-function StyleResolver() { |
- this.loader = new Loader(this.regex); |
-} |
-StyleResolver.prototype = { |
- regex: /@import\s+(?:url)?["'\(]*([^'"\)]*)['"\)]*;/g, |
- // Recursively replace @imports with the text at that url |
- resolve: function(text, url, callback) { |
- var done = function(map) { |
- callback(this.flatten(text, url, map)); |
- }.bind(this); |
- this.loader.process(text, url, done); |
- }, |
- // resolve the textContent of a style node |
- resolveNode: function(style, url, callback) { |
- var text = style.textContent; |
- var done = function(text) { |
- style.textContent = text; |
- callback(style); |
- }; |
- this.resolve(text, url, done); |
- }, |
- // flatten all the @imports to text |
- flatten: function(text, base, map) { |
- var matches = this.loader.extractUrls(text, base); |
- var match, url, intermediate; |
- for (var i = 0; i < matches.length; i++) { |
- match = matches[i]; |
- url = match.url; |
- // resolve any css text to be relative to the importer, keep absolute url |
- intermediate = urlResolver.resolveCssText(map[url], url, true); |
- // flatten intermediate @imports |
- intermediate = this.flatten(intermediate, base, map); |
- text = text.replace(match.matched, intermediate); |
- } |
- return text; |
- }, |
- loadStyles: function(styles, base, callback) { |
- var loaded=0, l = styles.length; |
- // called in the context of the style |
- function loadedStyle(style) { |
- loaded++; |
- if (loaded === l && callback) { |
- callback(); |
- } |
- } |
- for (var i=0, s; (i<l) && (s=styles[i]); i++) { |
- this.resolveNode(s, base, loadedStyle); |
+ function withDependencies(task, depends) { |
+ depends = depends || []; |
+ if (!depends.map) { |
+ depends = [depends]; |
} |
+ return task.apply(this, depends.map(marshal)); |
} |
-}; |
- |
-var styleResolver = new StyleResolver(); |
- |
-// exports |
-scope.styleResolver = styleResolver; |
-})(window.Platform); |
- |
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
-// Code distributed by Google as part of the polymer project is also |
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- |
-(function(global) { |
- 'use strict'; |
- |
- var filter = Array.prototype.filter.call.bind(Array.prototype.filter); |
- |
- function getTreeScope(node) { |
- while (node.parentNode) { |
- node = node.parentNode; |
+ function module(name, dependsOrFactory, moduleFactory) { |
+ var module; |
+ switch (arguments.length) { |
+ case 0: |
+ return; |
+ case 1: |
+ module = null; |
+ break; |
+ case 2: |
+ // dependsOrFactory is `factory` in this case |
+ module = dependsOrFactory.apply(this); |
+ break; |
+ default: |
+ // dependsOrFactory is `depends` in this case |
+ module = withDependencies(moduleFactory, dependsOrFactory); |
+ break; |
} |
- |
- return typeof node.getElementById === 'function' ? node : null; |
- } |
- |
- Node.prototype.bind = function(name, observable) { |
- console.error('Unhandled binding to Node: ', this, name, observable); |
+ modules[name] = module; |
}; |
- Node.prototype.bindFinished = function() {}; |
- |
- function updateBindings(node, name, binding) { |
- var bindings = node.bindings_; |
- if (!bindings) |
- bindings = node.bindings_ = {}; |
- |
- if (bindings[name]) |
- binding[name].close(); |
- |
- return bindings[name] = binding; |
- } |
- |
- function returnBinding(node, name, binding) { |
- return binding; |
- } |
- |
- function sanitizeValue(value) { |
- return value == null ? '' : value; |
- } |
- |
- function updateText(node, value) { |
- node.data = sanitizeValue(value); |
- } |
- |
- function textBinding(node) { |
- return function(value) { |
- return updateText(node, value); |
- }; |
- } |
- |
- var maybeUpdateBindings = returnBinding; |
- |
- Object.defineProperty(Platform, 'enableBindingsReflection', { |
- get: function() { |
- return maybeUpdateBindings === updateBindings; |
- }, |
- set: function(enable) { |
- maybeUpdateBindings = enable ? updateBindings : returnBinding; |
- return enable; |
- }, |
- configurable: true |
- }); |
- |
- Text.prototype.bind = function(name, value, oneTime) { |
- if (name !== 'textContent') |
- return Node.prototype.bind.call(this, name, value, oneTime); |
- |
- if (oneTime) |
- return updateText(this, value); |
- |
- var observable = value; |
- updateText(this, observable.open(textBinding(this))); |
- return maybeUpdateBindings(this, name, observable); |
- } |
- |
- function updateAttribute(el, name, conditional, value) { |
- if (conditional) { |
- if (value) |
- el.setAttribute(name, ''); |
- else |
- el.removeAttribute(name); |
- return; |
- } |
- |
- el.setAttribute(name, sanitizeValue(value)); |
- } |
- |
- function attributeBinding(el, name, conditional) { |
- return function(value) { |
- updateAttribute(el, name, conditional, value); |
- }; |
+ function marshal(name) { |
+ return modules[name]; |
} |
- Element.prototype.bind = function(name, value, oneTime) { |
- var conditional = name[name.length - 1] == '?'; |
- if (conditional) { |
- this.removeAttribute(name); |
- name = name.slice(0, -1); |
- } |
- |
- if (oneTime) |
- return updateAttribute(this, name, conditional, value); |
- |
- |
- var observable = value; |
- updateAttribute(this, name, conditional, |
- observable.open(attributeBinding(this, name, conditional))); |
- |
- return maybeUpdateBindings(this, name, observable); |
- }; |
+ var modules = {}; |
- var checkboxEventType; |
- (function() { |
- // Attempt to feature-detect which event (change or click) is fired first |
- // for checkboxes. |
- var div = document.createElement('div'); |
- var checkbox = div.appendChild(document.createElement('input')); |
- checkbox.setAttribute('type', 'checkbox'); |
- var first; |
- var count = 0; |
- checkbox.addEventListener('click', function(e) { |
- count++; |
- first = first || 'click'; |
- }); |
- checkbox.addEventListener('change', function() { |
- count++; |
- first = first || 'change'; |
+ function using(depends, task) { |
+ HTMLImports.whenImportsReady(function() { |
+ withDependencies(task, depends); |
}); |
+ }; |
- var event = document.createEvent('MouseEvent'); |
- event.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, |
- false, false, false, 0, null); |
- checkbox.dispatchEvent(event); |
- // WebKit/Blink don't fire the change event if the element is outside the |
- // document, so assume 'change' for that case. |
- checkboxEventType = count == 1 ? 'change' : first; |
- })(); |
- |
- function getEventForInputType(element) { |
- switch (element.type) { |
- case 'checkbox': |
- return checkboxEventType; |
- case 'radio': |
- case 'select-multiple': |
- case 'select-one': |
- return 'change'; |
- case 'range': |
- if (/Trident|MSIE/.test(navigator.userAgent)) |
- return 'change'; |
- default: |
- return 'input'; |
- } |
- } |
- |
- function updateInput(input, property, value, santizeFn) { |
- input[property] = (santizeFn || sanitizeValue)(value); |
- } |
- |
- function inputBinding(input, property, santizeFn) { |
- return function(value) { |
- return updateInput(input, property, value, santizeFn); |
- } |
- } |
- |
- function noop() {} |
- |
- function bindInputEvent(input, property, observable, postEventFn) { |
- var eventType = getEventForInputType(input); |
- |
- function eventHandler() { |
- observable.setValue(input[property]); |
- observable.discardChanges(); |
- (postEventFn || noop)(input); |
- Platform.performMicrotaskCheckpoint(); |
- } |
- input.addEventListener(eventType, eventHandler); |
- |
- return { |
- close: function() { |
- input.removeEventListener(eventType, eventHandler); |
- observable.close(); |
- }, |
- |
- observable_: observable |
- } |
- } |
- |
- function booleanSanitize(value) { |
- return Boolean(value); |
- } |
- |
- // |element| is assumed to be an HTMLInputElement with |type| == 'radio'. |
- // Returns an array containing all radio buttons other than |element| that |
- // have the same |name|, either in the form that |element| belongs to or, |
- // if no form, in the document tree to which |element| belongs. |
- // |
- // This implementation is based upon the HTML spec definition of a |
- // "radio button group": |
- // http://www.whatwg.org/specs/web-apps/current-work/multipage/number-state.html#radio-button-group |
- // |
- function getAssociatedRadioButtons(element) { |
- if (element.form) { |
- return filter(element.form.elements, function(el) { |
- return el != element && |
- el.tagName == 'INPUT' && |
- el.type == 'radio' && |
- el.name == element.name; |
- }); |
- } else { |
- var treeScope = getTreeScope(element); |
- if (!treeScope) |
- return []; |
- var radios = treeScope.querySelectorAll( |
- 'input[type="radio"][name="' + element.name + '"]'); |
- return filter(radios, function(el) { |
- return el != element && !el.form; |
- }); |
- } |
- } |
- |
- function checkedPostEvent(input) { |
- // Only the radio button that is getting checked gets an event. We |
- // therefore find all the associated radio buttons and update their |
- // check binding manually. |
- if (input.tagName === 'INPUT' && |
- input.type === 'radio') { |
- getAssociatedRadioButtons(input).forEach(function(radio) { |
- var checkedBinding = radio.bindings_.checked; |
- if (checkedBinding) { |
- // Set the value directly to avoid an infinite call stack. |
- checkedBinding.observable_.setValue(false); |
- } |
- }); |
- } |
- } |
- |
- HTMLInputElement.prototype.bind = function(name, value, oneTime) { |
- if (name !== 'value' && name !== 'checked') |
- return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
- |
- this.removeAttribute(name); |
- var sanitizeFn = name == 'checked' ? booleanSanitize : sanitizeValue; |
- var postEventFn = name == 'checked' ? checkedPostEvent : noop; |
- |
- if (oneTime) |
- return updateInput(this, name, value, sanitizeFn); |
- |
- |
- var observable = value; |
- var binding = bindInputEvent(this, name, observable, postEventFn); |
- updateInput(this, name, |
- observable.open(inputBinding(this, name, sanitizeFn)), |
- sanitizeFn); |
- |
- // Checkboxes may need to update bindings of other checkboxes. |
- return updateBindings(this, name, binding); |
- } |
- |
- HTMLTextAreaElement.prototype.bind = function(name, value, oneTime) { |
- if (name !== 'value') |
- return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
- |
- this.removeAttribute('value'); |
+ // exports |
- if (oneTime) |
- return updateInput(this, 'value', value); |
- |
- var observable = value; |
- var binding = bindInputEvent(this, 'value', observable); |
- updateInput(this, 'value', |
- observable.open(inputBinding(this, 'value', sanitizeValue))); |
- return maybeUpdateBindings(this, name, binding); |
- } |
- |
- function updateOption(option, value) { |
- var parentNode = option.parentNode;; |
- var select; |
- var selectBinding; |
- var oldValue; |
- if (parentNode instanceof HTMLSelectElement && |
- parentNode.bindings_ && |
- parentNode.bindings_.value) { |
- select = parentNode; |
- selectBinding = select.bindings_.value; |
- oldValue = select.value; |
- } |
- |
- option.value = sanitizeValue(value); |
- |
- if (select && select.value != oldValue) { |
- selectBinding.observable_.setValue(select.value); |
- selectBinding.observable_.discardChanges(); |
- Platform.performMicrotaskCheckpoint(); |
- } |
- } |
- |
- function optionBinding(option) { |
- return function(value) { |
- updateOption(option, value); |
- } |
- } |
- |
- HTMLOptionElement.prototype.bind = function(name, value, oneTime) { |
- if (name !== 'value') |
- return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
- |
- this.removeAttribute('value'); |
- |
- if (oneTime) |
- return updateOption(this, value); |
- |
- var observable = value; |
- var binding = bindInputEvent(this, 'value', observable); |
- updateOption(this, observable.open(optionBinding(this))); |
- return maybeUpdateBindings(this, name, binding); |
- } |
- |
- HTMLSelectElement.prototype.bind = function(name, value, oneTime) { |
- if (name === 'selectedindex') |
- name = 'selectedIndex'; |
- |
- if (name !== 'selectedIndex' && name !== 'value') |
- return HTMLElement.prototype.bind.call(this, name, value, oneTime); |
- |
- this.removeAttribute(name); |
- |
- if (oneTime) |
- return updateInput(this, name, value); |
- |
- var observable = value; |
- var binding = bindInputEvent(this, name, observable); |
- updateInput(this, name, |
- observable.open(inputBinding(this, name))); |
- |
- // Option update events may need to access select bindings. |
- return updateBindings(this, name, binding); |
- } |
-})(this); |
- |
-// Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
-// This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
-// The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
-// The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
-// Code distributed by Google as part of the polymer project is also |
-// subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- |
-(function(global) { |
- 'use strict'; |
- |
- function assert(v) { |
- if (!v) |
- throw new Error('Assertion failed'); |
- } |
- |
- var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach); |
- |
- function getFragmentRoot(node) { |
- var p; |
- while (p = node.parentNode) { |
- node = p; |
- } |
- |
- return node; |
- } |
- |
- function searchRefId(node, id) { |
- if (!id) |
- return; |
- |
- var ref; |
- var selector = '#' + id; |
- while (!ref) { |
- node = getFragmentRoot(node); |
- |
- if (node.protoContent_) |
- ref = node.protoContent_.querySelector(selector); |
- else if (node.getElementById) |
- ref = node.getElementById(id); |
- |
- if (ref || !node.templateCreator_) |
- break |
- |
- node = node.templateCreator_; |
- } |
- |
- return ref; |
- } |
- |
- function getInstanceRoot(node) { |
- while (node.parentNode) { |
- node = node.parentNode; |
- } |
- return node.templateCreator_ ? node : null; |
- } |
- |
- var Map; |
- if (global.Map && typeof global.Map.prototype.forEach === 'function') { |
- Map = global.Map; |
- } else { |
- Map = function() { |
- this.keys = []; |
- this.values = []; |
- }; |
- |
- Map.prototype = { |
- set: function(key, value) { |
- var index = this.keys.indexOf(key); |
- if (index < 0) { |
- this.keys.push(key); |
- this.values.push(value); |
- } else { |
- this.values[index] = value; |
- } |
- }, |
- |
- get: function(key) { |
- var index = this.keys.indexOf(key); |
- if (index < 0) |
- return; |
- |
- return this.values[index]; |
- }, |
- |
- delete: function(key, value) { |
- var index = this.keys.indexOf(key); |
- if (index < 0) |
- return false; |
- |
- this.keys.splice(index, 1); |
- this.values.splice(index, 1); |
- return true; |
- }, |
- |
- forEach: function(f, opt_this) { |
- for (var i = 0; i < this.keys.length; i++) |
- f.call(opt_this || this, this.values[i], this.keys[i], this); |
- } |
- }; |
- } |
- |
- // JScript does not have __proto__. We wrap all object literals with |
- // createObject which uses Object.create, Object.defineProperty and |
- // Object.getOwnPropertyDescriptor to create a new object that does the exact |
- // same thing. The main downside to this solution is that we have to extract |
- // all those property descriptors for IE. |
- var createObject = ('__proto__' in {}) ? |
- function(obj) { return obj; } : |
- function(obj) { |
- var proto = obj.__proto__; |
- if (!proto) |
- return obj; |
- var newObject = Object.create(proto); |
- Object.getOwnPropertyNames(obj).forEach(function(name) { |
- Object.defineProperty(newObject, name, |
- Object.getOwnPropertyDescriptor(obj, name)); |
- }); |
- return newObject; |
- }; |
- |
- // IE does not support have Document.prototype.contains. |
- if (typeof document.contains != 'function') { |
- Document.prototype.contains = function(node) { |
- if (node === this || node.parentNode === this) |
- return true; |
- return this.documentElement.contains(node); |
- } |
- } |
- |
- var BIND = 'bind'; |
- var REPEAT = 'repeat'; |
- var IF = 'if'; |
- |
- var templateAttributeDirectives = { |
- 'template': true, |
- 'repeat': true, |
- 'bind': true, |
- 'ref': true |
- }; |
- |
- var semanticTemplateElements = { |
- 'THEAD': true, |
- 'TBODY': true, |
- 'TFOOT': true, |
- 'TH': true, |
- 'TR': true, |
- 'TD': true, |
- 'COLGROUP': true, |
- 'COL': true, |
- 'CAPTION': true, |
- 'OPTION': true, |
- 'OPTGROUP': true |
- }; |
- |
- var hasTemplateElement = typeof HTMLTemplateElement !== 'undefined'; |
- if (hasTemplateElement) { |
- // TODO(rafaelw): Remove when fix for |
- // https://codereview.chromium.org/164803002/ |
- // makes it to Chrome release. |
- (function() { |
- var t = document.createElement('template'); |
- var d = t.content.ownerDocument; |
- var html = d.appendChild(d.createElement('html')); |
- var head = html.appendChild(d.createElement('head')); |
- var base = d.createElement('base'); |
- base.href = document.baseURI; |
- head.appendChild(base); |
- })(); |
- } |
- |
- var allTemplatesSelectors = 'template, ' + |
- Object.keys(semanticTemplateElements).map(function(tagName) { |
- return tagName.toLowerCase() + '[template]'; |
- }).join(', '); |
- |
- function isSVGTemplate(el) { |
- return el.tagName == 'template' && |
- el.namespaceURI == 'http://www.w3.org/2000/svg'; |
- } |
- |
- function isHTMLTemplate(el) { |
- return el.tagName == 'TEMPLATE' && |
- el.namespaceURI == 'http://www.w3.org/1999/xhtml'; |
- } |
- |
- function isAttributeTemplate(el) { |
- return Boolean(semanticTemplateElements[el.tagName] && |
- el.hasAttribute('template')); |
- } |
- |
- function isTemplate(el) { |
- if (el.isTemplate_ === undefined) |
- el.isTemplate_ = el.tagName == 'TEMPLATE' || isAttributeTemplate(el); |
- |
- return el.isTemplate_; |
- } |
- |
- // FIXME: Observe templates being added/removed from documents |
- // FIXME: Expose imperative API to decorate and observe templates in |
- // "disconnected tress" (e.g. ShadowRoot) |
- document.addEventListener('DOMContentLoaded', function(e) { |
- bootstrapTemplatesRecursivelyFrom(document); |
- // FIXME: Is this needed? Seems like it shouldn't be. |
- Platform.performMicrotaskCheckpoint(); |
- }, false); |
- |
- function forAllTemplatesFrom(node, fn) { |
- var subTemplates = node.querySelectorAll(allTemplatesSelectors); |
- |
- if (isTemplate(node)) |
- fn(node) |
- forEach(subTemplates, fn); |
- } |
- |
- function bootstrapTemplatesRecursivelyFrom(node) { |
- function bootstrap(template) { |
- if (!HTMLTemplateElement.decorate(template)) |
- bootstrapTemplatesRecursivelyFrom(template.content); |
- } |
- |
- forAllTemplatesFrom(node, bootstrap); |
- } |
- |
- if (!hasTemplateElement) { |
- /** |
- * This represents a <template> element. |
- * @constructor |
- * @extends {HTMLElement} |
- */ |
- global.HTMLTemplateElement = function() { |
- throw TypeError('Illegal constructor'); |
- }; |
- } |
- |
- var hasProto = '__proto__' in {}; |
- |
- function mixin(to, from) { |
- Object.getOwnPropertyNames(from).forEach(function(name) { |
- Object.defineProperty(to, name, |
- Object.getOwnPropertyDescriptor(from, name)); |
- }); |
- } |
- |
- // http://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/templates/index.html#dfn-template-contents-owner |
- function getOrCreateTemplateContentsOwner(template) { |
- var doc = template.ownerDocument |
- if (!doc.defaultView) |
- return doc; |
- var d = doc.templateContentsOwner_; |
- if (!d) { |
- // TODO(arv): This should either be a Document or HTMLDocument depending |
- // on doc. |
- d = doc.implementation.createHTMLDocument(''); |
- while (d.lastChild) { |
- d.removeChild(d.lastChild); |
- } |
- doc.templateContentsOwner_ = d; |
- } |
- return d; |
- } |
- |
- function getTemplateStagingDocument(template) { |
- if (!template.stagingDocument_) { |
- var owner = template.ownerDocument; |
- if (!owner.stagingDocument_) { |
- owner.stagingDocument_ = owner.implementation.createHTMLDocument(''); |
- owner.stagingDocument_.isStagingDocument = true; |
- // TODO(rafaelw): Remove when fix for |
- // https://codereview.chromium.org/164803002/ |
- // makes it to Chrome release. |
- var base = owner.stagingDocument_.createElement('base'); |
- base.href = document.baseURI; |
- owner.stagingDocument_.head.appendChild(base); |
- |
- owner.stagingDocument_.stagingDocument_ = owner.stagingDocument_; |
- } |
- |
- template.stagingDocument_ = owner.stagingDocument_; |
- } |
- |
- return template.stagingDocument_; |
- } |
- |
- // For non-template browsers, the parser will disallow <template> in certain |
- // locations, so we allow "attribute templates" which combine the template |
- // element with the top-level container node of the content, e.g. |
- // |
- // <tr template repeat="{{ foo }}"" class="bar"><td>Bar</td></tr> |
- // |
- // becomes |
- // |
- // <template repeat="{{ foo }}"> |
- // + #document-fragment |
- // + <tr class="bar"> |
- // + <td>Bar</td> |
- // |
- function extractTemplateFromAttributeTemplate(el) { |
- var template = el.ownerDocument.createElement('template'); |
- el.parentNode.insertBefore(template, el); |
- |
- var attribs = el.attributes; |
- var count = attribs.length; |
- while (count-- > 0) { |
- var attrib = attribs[count]; |
- if (templateAttributeDirectives[attrib.name]) { |
- if (attrib.name !== 'template') |
- template.setAttribute(attrib.name, attrib.value); |
- el.removeAttribute(attrib.name); |
- } |
- } |
- |
- return template; |
- } |
- |
- function extractTemplateFromSVGTemplate(el) { |
- var template = el.ownerDocument.createElement('template'); |
- el.parentNode.insertBefore(template, el); |
- |
- var attribs = el.attributes; |
- var count = attribs.length; |
- while (count-- > 0) { |
- var attrib = attribs[count]; |
- template.setAttribute(attrib.name, attrib.value); |
- el.removeAttribute(attrib.name); |
- } |
- |
- el.parentNode.removeChild(el); |
- return template; |
- } |
- |
- function liftNonNativeTemplateChildrenIntoContent(template, el, useRoot) { |
- var content = template.content; |
- if (useRoot) { |
- content.appendChild(el); |
- return; |
- } |
- |
- var child; |
- while (child = el.firstChild) { |
- content.appendChild(child); |
- } |
- } |
- |
- var templateObserver; |
- if (typeof MutationObserver == 'function') { |
- templateObserver = new MutationObserver(function(records) { |
- for (var i = 0; i < records.length; i++) { |
- records[i].target.refChanged_(); |
- } |
- }); |
- } |
- |
- /** |
- * Ensures proper API and content model for template elements. |
- * @param {HTMLTemplateElement} opt_instanceRef The template element which |
- * |el| template element will return as the value of its ref(), and whose |
- * content will be used as source when createInstance() is invoked. |
- */ |
- HTMLTemplateElement.decorate = function(el, opt_instanceRef) { |
- if (el.templateIsDecorated_) |
- return false; |
- |
- var templateElement = el; |
- templateElement.templateIsDecorated_ = true; |
- |
- var isNativeHTMLTemplate = isHTMLTemplate(templateElement) && |
- hasTemplateElement; |
- var bootstrapContents = isNativeHTMLTemplate; |
- var liftContents = !isNativeHTMLTemplate; |
- var liftRoot = false; |
- |
- if (!isNativeHTMLTemplate) { |
- if (isAttributeTemplate(templateElement)) { |
- assert(!opt_instanceRef); |
- templateElement = extractTemplateFromAttributeTemplate(el); |
- templateElement.templateIsDecorated_ = true; |
- isNativeHTMLTemplate = hasTemplateElement; |
- liftRoot = true; |
- } else if (isSVGTemplate(templateElement)) { |
- templateElement = extractTemplateFromSVGTemplate(el); |
- templateElement.templateIsDecorated_ = true; |
- isNativeHTMLTemplate = hasTemplateElement; |
- } |
- } |
- |
- if (!isNativeHTMLTemplate) { |
- fixTemplateElementPrototype(templateElement); |
- var doc = getOrCreateTemplateContentsOwner(templateElement); |
- templateElement.content_ = doc.createDocumentFragment(); |
- } |
- |
- if (opt_instanceRef) { |
- // template is contained within an instance, its direct content must be |
- // empty |
- templateElement.instanceRef_ = opt_instanceRef; |
- } else if (liftContents) { |
- liftNonNativeTemplateChildrenIntoContent(templateElement, |
- el, |
- liftRoot); |
- } else if (bootstrapContents) { |
- bootstrapTemplatesRecursivelyFrom(templateElement.content); |
- } |
- |
- return true; |
- }; |
- |
- // TODO(rafaelw): This used to decorate recursively all templates from a given |
- // node. This happens by default on 'DOMContentLoaded', but may be needed |
- // in subtrees not descendent from document (e.g. ShadowRoot). |
- // Review whether this is the right public API. |
- HTMLTemplateElement.bootstrap = bootstrapTemplatesRecursivelyFrom; |
- |
- var htmlElement = global.HTMLUnknownElement || HTMLElement; |
- |
- var contentDescriptor = { |
- get: function() { |
- return this.content_; |
- }, |
- enumerable: true, |
- configurable: true |
- }; |
- |
- if (!hasTemplateElement) { |
- // Gecko is more picky with the prototype than WebKit. Make sure to use the |
- // same prototype as created in the constructor. |
- HTMLTemplateElement.prototype = Object.create(htmlElement.prototype); |
- |
- Object.defineProperty(HTMLTemplateElement.prototype, 'content', |
- contentDescriptor); |
- } |
- |
- function fixTemplateElementPrototype(el) { |
- if (hasProto) |
- el.__proto__ = HTMLTemplateElement.prototype; |
- else |
- mixin(el, HTMLTemplateElement.prototype); |
- } |
- |
- function ensureSetModelScheduled(template) { |
- if (!template.setModelFn_) { |
- template.setModelFn_ = function() { |
- template.setModelFnScheduled_ = false; |
- var map = getBindings(template, |
- template.delegate_ && template.delegate_.prepareBinding); |
- processBindings(template, map, template.model_); |
- }; |
- } |
- |
- if (!template.setModelFnScheduled_) { |
- template.setModelFnScheduled_ = true; |
- Observer.runEOM_(template.setModelFn_); |
- } |
- } |
- |
- mixin(HTMLTemplateElement.prototype, { |
- bind: function(name, value, oneTime) { |
- if (name != 'ref') |
- return Element.prototype.bind.call(this, name, value, oneTime); |
- |
- var self = this; |
- var ref = oneTime ? value : value.open(function(ref) { |
- self.setAttribute('ref', ref); |
- self.refChanged_(); |
- }); |
- |
- this.setAttribute('ref', ref); |
- this.refChanged_(); |
- if (oneTime) |
- return; |
- |
- if (!this.bindings_) { |
- this.bindings_ = { ref: value }; |
- } else { |
- this.bindings_.ref = value; |
- } |
- |
- return value; |
- }, |
- |
- processBindingDirectives_: function(directives) { |
- if (this.iterator_) |
- this.iterator_.closeDeps(); |
- |
- if (!directives.if && !directives.bind && !directives.repeat) { |
- if (this.iterator_) { |
- this.iterator_.close(); |
- this.iterator_ = undefined; |
- } |
- |
- return; |
- } |
- |
- if (!this.iterator_) { |
- this.iterator_ = new TemplateIterator(this); |
- } |
- |
- this.iterator_.updateDependencies(directives, this.model_); |
- |
- if (templateObserver) { |
- templateObserver.observe(this, { attributes: true, |
- attributeFilter: ['ref'] }); |
- } |
- |
- return this.iterator_; |
- }, |
- |
- createInstance: function(model, bindingDelegate, delegate_) { |
- if (bindingDelegate) |
- delegate_ = this.newDelegate_(bindingDelegate); |
- else if (!delegate_) |
- delegate_ = this.delegate_; |
- |
- if (!this.refContent_) |
- this.refContent_ = this.ref_.content; |
- var content = this.refContent_; |
- if (content.firstChild === null) |
- return emptyInstance; |
- |
- var map = getInstanceBindingMap(content, delegate_); |
- var stagingDocument = getTemplateStagingDocument(this); |
- var instance = stagingDocument.createDocumentFragment(); |
- instance.templateCreator_ = this; |
- instance.protoContent_ = content; |
- instance.bindings_ = []; |
- instance.terminator_ = null; |
- var instanceRecord = instance.templateInstance_ = { |
- firstNode: null, |
- lastNode: null, |
- model: model |
- }; |
- |
- var i = 0; |
- var collectTerminator = false; |
- for (var child = content.firstChild; child; child = child.nextSibling) { |
- // The terminator of the instance is the clone of the last child of the |
- // content. If the last child is an active template, it may produce |
- // instances as a result of production, so simply collecting the last |
- // child of the instance after it has finished producing may be wrong. |
- if (child.nextSibling === null) |
- collectTerminator = true; |
- |
- var clone = cloneAndBindInstance(child, instance, stagingDocument, |
- map.children[i++], |
- model, |
- delegate_, |
- instance.bindings_); |
- clone.templateInstance_ = instanceRecord; |
- if (collectTerminator) |
- instance.terminator_ = clone; |
- } |
- |
- instanceRecord.firstNode = instance.firstChild; |
- instanceRecord.lastNode = instance.lastChild; |
- instance.templateCreator_ = undefined; |
- instance.protoContent_ = undefined; |
- return instance; |
- }, |
- |
- get model() { |
- return this.model_; |
- }, |
- |
- set model(model) { |
- this.model_ = model; |
- ensureSetModelScheduled(this); |
- }, |
- |
- get bindingDelegate() { |
- return this.delegate_ && this.delegate_.raw; |
- }, |
- |
- refChanged_: function() { |
- if (!this.iterator_ || this.refContent_ === this.ref_.content) |
- return; |
- |
- this.refContent_ = undefined; |
- this.iterator_.valueChanged(); |
- this.iterator_.updateIteratedValue(this.iterator_.getUpdatedValue()); |
- }, |
- |
- clear: function() { |
- this.model_ = undefined; |
- this.delegate_ = undefined; |
- if (this.bindings_ && this.bindings_.ref) |
- this.bindings_.ref.close() |
- this.refContent_ = undefined; |
- if (!this.iterator_) |
- return; |
- this.iterator_.valueChanged(); |
- this.iterator_.close() |
- this.iterator_ = undefined; |
- }, |
- |
- setDelegate_: function(delegate) { |
- this.delegate_ = delegate; |
- this.bindingMap_ = undefined; |
- if (this.iterator_) { |
- this.iterator_.instancePositionChangedFn_ = undefined; |
- this.iterator_.instanceModelFn_ = undefined; |
- } |
- }, |
- |
- newDelegate_: function(bindingDelegate) { |
- if (!bindingDelegate) |
- return; |
- |
- function delegateFn(name) { |
- var fn = bindingDelegate && bindingDelegate[name]; |
- if (typeof fn != 'function') |
- return; |
- |
- return function() { |
- return fn.apply(bindingDelegate, arguments); |
- }; |
- } |
- |
- return { |
- bindingMaps: {}, |
- raw: bindingDelegate, |
- prepareBinding: delegateFn('prepareBinding'), |
- prepareInstanceModel: delegateFn('prepareInstanceModel'), |
- prepareInstancePositionChanged: |
- delegateFn('prepareInstancePositionChanged') |
- }; |
- }, |
- |
- set bindingDelegate(bindingDelegate) { |
- if (this.delegate_) { |
- throw Error('Template must be cleared before a new bindingDelegate ' + |
- 'can be assigned'); |
- } |
- |
- this.setDelegate_(this.newDelegate_(bindingDelegate)); |
- }, |
- |
- get ref_() { |
- var ref = searchRefId(this, this.getAttribute('ref')); |
- if (!ref) |
- ref = this.instanceRef_; |
- |
- if (!ref) |
- return this; |
- |
- var nextRef = ref.ref_; |
- return nextRef ? nextRef : ref; |
- } |
- }); |
- |
- // Returns |
- // a) undefined if there are no mustaches. |
- // b) [TEXT, (ONE_TIME?, PATH, DELEGATE_FN, TEXT)+] if there is at least one mustache. |
- function parseMustaches(s, name, node, prepareBindingFn) { |
- if (!s || !s.length) |
- return; |
- |
- var tokens; |
- var length = s.length; |
- var startIndex = 0, lastIndex = 0, endIndex = 0; |
- var onlyOneTime = true; |
- while (lastIndex < length) { |
- var startIndex = s.indexOf('{{', lastIndex); |
- var oneTimeStart = s.indexOf('[[', lastIndex); |
- var oneTime = false; |
- var terminator = '}}'; |
- |
- if (oneTimeStart >= 0 && |
- (startIndex < 0 || oneTimeStart < startIndex)) { |
- startIndex = oneTimeStart; |
- oneTime = true; |
- terminator = ']]'; |
- } |
- |
- endIndex = startIndex < 0 ? -1 : s.indexOf(terminator, startIndex + 2); |
- |
- if (endIndex < 0) { |
- if (!tokens) |
- return; |
- |
- tokens.push(s.slice(lastIndex)); // TEXT |
- break; |
- } |
- |
- tokens = tokens || []; |
- tokens.push(s.slice(lastIndex, startIndex)); // TEXT |
- var pathString = s.slice(startIndex + 2, endIndex).trim(); |
- tokens.push(oneTime); // ONE_TIME? |
- onlyOneTime = onlyOneTime && oneTime; |
- var delegateFn = prepareBindingFn && |
- prepareBindingFn(pathString, name, node); |
- // Don't try to parse the expression if there's a prepareBinding function |
- if (delegateFn == null) { |
- tokens.push(Path.get(pathString)); // PATH |
- } else { |
- tokens.push(null); |
- } |
- tokens.push(delegateFn); // DELEGATE_FN |
- lastIndex = endIndex + 2; |
- } |
- |
- if (lastIndex === length) |
- tokens.push(''); // TEXT |
- |
- tokens.hasOnePath = tokens.length === 5; |
- tokens.isSimplePath = tokens.hasOnePath && |
- tokens[0] == '' && |
- tokens[4] == ''; |
- tokens.onlyOneTime = onlyOneTime; |
- |
- tokens.combinator = function(values) { |
- var newValue = tokens[0]; |
- |
- for (var i = 1; i < tokens.length; i += 4) { |
- var value = tokens.hasOnePath ? values : values[(i - 1) / 4]; |
- if (value !== undefined) |
- newValue += value; |
- newValue += tokens[i + 3]; |
- } |
- |
- return newValue; |
- } |
- |
- return tokens; |
- }; |
- |
- function processOneTimeBinding(name, tokens, node, model) { |
- if (tokens.hasOnePath) { |
- var delegateFn = tokens[3]; |
- var value = delegateFn ? delegateFn(model, node, true) : |
- tokens[2].getValueFrom(model); |
- return tokens.isSimplePath ? value : tokens.combinator(value); |
- } |
- |
- var values = []; |
- for (var i = 1; i < tokens.length; i += 4) { |
- var delegateFn = tokens[i + 2]; |
- values[(i - 1) / 4] = delegateFn ? delegateFn(model, node) : |
- tokens[i + 1].getValueFrom(model); |
- } |
- |
- return tokens.combinator(values); |
- } |
- |
- function processSinglePathBinding(name, tokens, node, model) { |
- var delegateFn = tokens[3]; |
- var observer = delegateFn ? delegateFn(model, node, false) : |
- new PathObserver(model, tokens[2]); |
- |
- return tokens.isSimplePath ? observer : |
- new ObserverTransform(observer, tokens.combinator); |
- } |
- |
- function processBinding(name, tokens, node, model) { |
- if (tokens.onlyOneTime) |
- return processOneTimeBinding(name, tokens, node, model); |
- |
- if (tokens.hasOnePath) |
- return processSinglePathBinding(name, tokens, node, model); |
- |
- var observer = new CompoundObserver(); |
- |
- for (var i = 1; i < tokens.length; i += 4) { |
- var oneTime = tokens[i]; |
- var delegateFn = tokens[i + 2]; |
- |
- if (delegateFn) { |
- var value = delegateFn(model, node, oneTime); |
- if (oneTime) |
- observer.addPath(value) |
- else |
- observer.addObserver(value); |
- continue; |
- } |
- |
- var path = tokens[i + 1]; |
- if (oneTime) |
- observer.addPath(path.getValueFrom(model)) |
- else |
- observer.addPath(model, path); |
- } |
- |
- return new ObserverTransform(observer, tokens.combinator); |
- } |
- |
- function processBindings(node, bindings, model, instanceBindings) { |
- for (var i = 0; i < bindings.length; i += 2) { |
- var name = bindings[i] |
- var tokens = bindings[i + 1]; |
- var value = processBinding(name, tokens, node, model); |
- var binding = node.bind(name, value, tokens.onlyOneTime); |
- if (binding && instanceBindings) |
- instanceBindings.push(binding); |
- } |
- |
- node.bindFinished(); |
- if (!bindings.isTemplate) |
- return; |
- |
- node.model_ = model; |
- var iter = node.processBindingDirectives_(bindings); |
- if (instanceBindings && iter) |
- instanceBindings.push(iter); |
- } |
- |
- function parseWithDefault(el, name, prepareBindingFn) { |
- var v = el.getAttribute(name); |
- return parseMustaches(v == '' ? '{{}}' : v, name, el, prepareBindingFn); |
- } |
- |
- function parseAttributeBindings(element, prepareBindingFn) { |
- assert(element); |
- |
- var bindings = []; |
- var ifFound = false; |
- var bindFound = false; |
- |
- for (var i = 0; i < element.attributes.length; i++) { |
- var attr = element.attributes[i]; |
- var name = attr.name; |
- var value = attr.value; |
- |
- // Allow bindings expressed in attributes to be prefixed with underbars. |
- // We do this to allow correct semantics for browsers that don't implement |
- // <template> where certain attributes might trigger side-effects -- and |
- // for IE which sanitizes certain attributes, disallowing mustache |
- // replacements in their text. |
- while (name[0] === '_') { |
- name = name.substring(1); |
- } |
- |
- if (isTemplate(element) && |
- (name === IF || name === BIND || name === REPEAT)) { |
- continue; |
- } |
- |
- var tokens = parseMustaches(value, name, element, |
- prepareBindingFn); |
- if (!tokens) |
- continue; |
- |
- bindings.push(name, tokens); |
- } |
- |
- if (isTemplate(element)) { |
- bindings.isTemplate = true; |
- bindings.if = parseWithDefault(element, IF, prepareBindingFn); |
- bindings.bind = parseWithDefault(element, BIND, prepareBindingFn); |
- bindings.repeat = parseWithDefault(element, REPEAT, prepareBindingFn); |
- |
- if (bindings.if && !bindings.bind && !bindings.repeat) |
- bindings.bind = parseMustaches('{{}}', BIND, element, prepareBindingFn); |
- } |
- |
- return bindings; |
- } |
- |
- function getBindings(node, prepareBindingFn) { |
- if (node.nodeType === Node.ELEMENT_NODE) |
- return parseAttributeBindings(node, prepareBindingFn); |
- |
- if (node.nodeType === Node.TEXT_NODE) { |
- var tokens = parseMustaches(node.data, 'textContent', node, |
- prepareBindingFn); |
- if (tokens) |
- return ['textContent', tokens]; |
- } |
- |
- return []; |
- } |
- |
- function cloneAndBindInstance(node, parent, stagingDocument, bindings, model, |
- delegate, |
- instanceBindings, |
- instanceRecord) { |
- var clone = parent.appendChild(stagingDocument.importNode(node, false)); |
- |
- var i = 0; |
- for (var child = node.firstChild; child; child = child.nextSibling) { |
- cloneAndBindInstance(child, clone, stagingDocument, |
- bindings.children[i++], |
- model, |
- delegate, |
- instanceBindings); |
- } |
- |
- if (bindings.isTemplate) { |
- HTMLTemplateElement.decorate(clone, node); |
- if (delegate) |
- clone.setDelegate_(delegate); |
- } |
- |
- processBindings(clone, bindings, model, instanceBindings); |
- return clone; |
- } |
- |
- function createInstanceBindingMap(node, prepareBindingFn) { |
- var map = getBindings(node, prepareBindingFn); |
- map.children = {}; |
- var index = 0; |
- for (var child = node.firstChild; child; child = child.nextSibling) { |
- map.children[index++] = createInstanceBindingMap(child, prepareBindingFn); |
- } |
- |
- return map; |
- } |
- |
- var contentUidCounter = 1; |
- |
- // TODO(rafaelw): Setup a MutationObserver on content which clears the id |
- // so that bindingMaps regenerate when the template.content changes. |
- function getContentUid(content) { |
- var id = content.id_; |
- if (!id) |
- id = content.id_ = contentUidCounter++; |
- return id; |
- } |
- |
- // Each delegate is associated with a set of bindingMaps, one for each |
- // content which may be used by a template. The intent is that each binding |
- // delegate gets the opportunity to prepare the instance (via the prepare* |
- // delegate calls) once across all uses. |
- // TODO(rafaelw): Separate out the parse map from the binding map. In the |
- // current implementation, if two delegates need a binding map for the same |
- // content, the second will have to reparse. |
- function getInstanceBindingMap(content, delegate_) { |
- var contentId = getContentUid(content); |
- if (delegate_) { |
- var map = delegate_.bindingMaps[contentId]; |
- if (!map) { |
- map = delegate_.bindingMaps[contentId] = |
- createInstanceBindingMap(content, delegate_.prepareBinding) || []; |
- } |
- return map; |
- } |
- |
- var map = content.bindingMap_; |
- if (!map) { |
- map = content.bindingMap_ = |
- createInstanceBindingMap(content, undefined) || []; |
- } |
- return map; |
- } |
- |
- Object.defineProperty(Node.prototype, 'templateInstance', { |
- get: function() { |
- var instance = this.templateInstance_; |
- return instance ? instance : |
- (this.parentNode ? this.parentNode.templateInstance : undefined); |
- } |
- }); |
- |
- var emptyInstance = document.createDocumentFragment(); |
- emptyInstance.bindings_ = []; |
- emptyInstance.terminator_ = null; |
- |
- function TemplateIterator(templateElement) { |
- this.closed = false; |
- this.templateElement_ = templateElement; |
- this.instances = []; |
- this.deps = undefined; |
- this.iteratedValue = []; |
- this.presentValue = undefined; |
- this.arrayObserver = undefined; |
- } |
- |
- TemplateIterator.prototype = { |
- closeDeps: function() { |
- var deps = this.deps; |
- if (deps) { |
- if (deps.ifOneTime === false) |
- deps.ifValue.close(); |
- if (deps.oneTime === false) |
- deps.value.close(); |
- } |
- }, |
- |
- updateDependencies: function(directives, model) { |
- this.closeDeps(); |
- |
- var deps = this.deps = {}; |
- var template = this.templateElement_; |
- |
- var ifValue = true; |
- if (directives.if) { |
- deps.hasIf = true; |
- deps.ifOneTime = directives.if.onlyOneTime; |
- deps.ifValue = processBinding(IF, directives.if, template, model); |
- |
- ifValue = deps.ifValue; |
- |
- // oneTime if & predicate is false. nothing else to do. |
- if (deps.ifOneTime && !ifValue) { |
- this.valueChanged(); |
- return; |
- } |
- |
- if (!deps.ifOneTime) |
- ifValue = ifValue.open(this.updateIfValue, this); |
- } |
- |
- if (directives.repeat) { |
- deps.repeat = true; |
- deps.oneTime = directives.repeat.onlyOneTime; |
- deps.value = processBinding(REPEAT, directives.repeat, template, model); |
- } else { |
- deps.repeat = false; |
- deps.oneTime = directives.bind.onlyOneTime; |
- deps.value = processBinding(BIND, directives.bind, template, model); |
- } |
- |
- var value = deps.value; |
- if (!deps.oneTime) |
- value = value.open(this.updateIteratedValue, this); |
- |
- if (!ifValue) { |
- this.valueChanged(); |
- return; |
- } |
- |
- this.updateValue(value); |
- }, |
- |
- /** |
- * Gets the updated value of the bind/repeat. This can potentially call |
- * user code (if a bindingDelegate is set up) so we try to avoid it if we |
- * already have the value in hand (from Observer.open). |
- */ |
- getUpdatedValue: function() { |
- var value = this.deps.value; |
- if (!this.deps.oneTime) |
- value = value.discardChanges(); |
- return value; |
- }, |
- |
- updateIfValue: function(ifValue) { |
- if (!ifValue) { |
- this.valueChanged(); |
- return; |
- } |
- |
- this.updateValue(this.getUpdatedValue()); |
- }, |
- |
- updateIteratedValue: function(value) { |
- if (this.deps.hasIf) { |
- var ifValue = this.deps.ifValue; |
- if (!this.deps.ifOneTime) |
- ifValue = ifValue.discardChanges(); |
- if (!ifValue) { |
- this.valueChanged(); |
- return; |
- } |
- } |
- |
- this.updateValue(value); |
- }, |
- |
- updateValue: function(value) { |
- if (!this.deps.repeat) |
- value = [value]; |
- var observe = this.deps.repeat && |
- !this.deps.oneTime && |
- Array.isArray(value); |
- this.valueChanged(value, observe); |
- }, |
- |
- valueChanged: function(value, observeValue) { |
- if (!Array.isArray(value)) |
- value = []; |
- |
- if (value === this.iteratedValue) |
- return; |
- |
- this.unobserve(); |
- this.presentValue = value; |
- if (observeValue) { |
- this.arrayObserver = new ArrayObserver(this.presentValue); |
- this.arrayObserver.open(this.handleSplices, this); |
- } |
- |
- this.handleSplices(ArrayObserver.calculateSplices(this.presentValue, |
- this.iteratedValue)); |
- }, |
- |
- getLastInstanceNode: function(index) { |
- if (index == -1) |
- return this.templateElement_; |
- var instance = this.instances[index]; |
- var terminator = instance.terminator_; |
- if (!terminator) |
- return this.getLastInstanceNode(index - 1); |
- |
- if (terminator.nodeType !== Node.ELEMENT_NODE || |
- this.templateElement_ === terminator) { |
- return terminator; |
- } |
- |
- var subtemplateIterator = terminator.iterator_; |
- if (!subtemplateIterator) |
- return terminator; |
- |
- return subtemplateIterator.getLastTemplateNode(); |
- }, |
- |
- getLastTemplateNode: function() { |
- return this.getLastInstanceNode(this.instances.length - 1); |
- }, |
- |
- insertInstanceAt: function(index, fragment) { |
- var previousInstanceLast = this.getLastInstanceNode(index - 1); |
- var parent = this.templateElement_.parentNode; |
- this.instances.splice(index, 0, fragment); |
- |
- parent.insertBefore(fragment, previousInstanceLast.nextSibling); |
- }, |
- |
- extractInstanceAt: function(index) { |
- var previousInstanceLast = this.getLastInstanceNode(index - 1); |
- var lastNode = this.getLastInstanceNode(index); |
- var parent = this.templateElement_.parentNode; |
- var instance = this.instances.splice(index, 1)[0]; |
- |
- while (lastNode !== previousInstanceLast) { |
- var node = previousInstanceLast.nextSibling; |
- if (node == lastNode) |
- lastNode = previousInstanceLast; |
- |
- instance.appendChild(parent.removeChild(node)); |
- } |
- |
- return instance; |
- }, |
- |
- getDelegateFn: function(fn) { |
- fn = fn && fn(this.templateElement_); |
- return typeof fn === 'function' ? fn : null; |
- }, |
- |
- handleSplices: function(splices) { |
- if (this.closed || !splices.length) |
- return; |
- |
- var template = this.templateElement_; |
- |
- if (!template.parentNode) { |
- this.close(); |
- return; |
- } |
- |
- ArrayObserver.applySplices(this.iteratedValue, this.presentValue, |
- splices); |
- |
- var delegate = template.delegate_; |
- if (this.instanceModelFn_ === undefined) { |
- this.instanceModelFn_ = |
- this.getDelegateFn(delegate && delegate.prepareInstanceModel); |
- } |
- |
- if (this.instancePositionChangedFn_ === undefined) { |
- this.instancePositionChangedFn_ = |
- this.getDelegateFn(delegate && |
- delegate.prepareInstancePositionChanged); |
- } |
- |
- // Instance Removals |
- var instanceCache = new Map; |
- var removeDelta = 0; |
- for (var i = 0; i < splices.length; i++) { |
- var splice = splices[i]; |
- var removed = splice.removed; |
- for (var j = 0; j < removed.length; j++) { |
- var model = removed[j]; |
- var instance = this.extractInstanceAt(splice.index + removeDelta); |
- if (instance !== emptyInstance) { |
- instanceCache.set(model, instance); |
- } |
- } |
- |
- removeDelta -= splice.addedCount; |
- } |
- |
- // Instance Insertions |
- for (var i = 0; i < splices.length; i++) { |
- var splice = splices[i]; |
- var addIndex = splice.index; |
- for (; addIndex < splice.index + splice.addedCount; addIndex++) { |
- var model = this.iteratedValue[addIndex]; |
- var instance = instanceCache.get(model); |
- if (instance) { |
- instanceCache.delete(model); |
- } else { |
- if (this.instanceModelFn_) { |
- model = this.instanceModelFn_(model); |
- } |
- |
- if (model === undefined) { |
- instance = emptyInstance; |
- } else { |
- instance = template.createInstance(model, undefined, delegate); |
- } |
- } |
- |
- this.insertInstanceAt(addIndex, instance); |
- } |
- } |
- |
- instanceCache.forEach(function(instance) { |
- this.closeInstanceBindings(instance); |
- }, this); |
- |
- if (this.instancePositionChangedFn_) |
- this.reportInstancesMoved(splices); |
- }, |
- |
- reportInstanceMoved: function(index) { |
- var instance = this.instances[index]; |
- if (instance === emptyInstance) |
- return; |
- |
- this.instancePositionChangedFn_(instance.templateInstance_, index); |
- }, |
- |
- reportInstancesMoved: function(splices) { |
- var index = 0; |
- var offset = 0; |
- for (var i = 0; i < splices.length; i++) { |
- var splice = splices[i]; |
- if (offset != 0) { |
- while (index < splice.index) { |
- this.reportInstanceMoved(index); |
- index++; |
- } |
- } else { |
- index = splice.index; |
- } |
- |
- while (index < splice.index + splice.addedCount) { |
- this.reportInstanceMoved(index); |
- index++; |
- } |
- |
- offset += splice.addedCount - splice.removed.length; |
- } |
- |
- if (offset == 0) |
- return; |
- |
- var length = this.instances.length; |
- while (index < length) { |
- this.reportInstanceMoved(index); |
- index++; |
- } |
- }, |
- |
- closeInstanceBindings: function(instance) { |
- var bindings = instance.bindings_; |
- for (var i = 0; i < bindings.length; i++) { |
- bindings[i].close(); |
- } |
- }, |
- |
- unobserve: function() { |
- if (!this.arrayObserver) |
- return; |
- |
- this.arrayObserver.close(); |
- this.arrayObserver = undefined; |
- }, |
- |
- close: function() { |
- if (this.closed) |
- return; |
- this.unobserve(); |
- for (var i = 0; i < this.instances.length; i++) { |
- this.closeInstanceBindings(this.instances[i]); |
- } |
- |
- this.instances.length = 0; |
- this.closeDeps(); |
- this.templateElement_.iterator_ = undefined; |
- this.closed = true; |
- } |
- }; |
- |
- // Polyfill-specific API. |
- HTMLTemplateElement.forAllTemplatesFrom_ = forAllTemplatesFrom; |
-})(this); |
- |
-/* |
- * Copyright (c) 2014 The Polymer Project Authors. All rights reserved. |
- * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt |
- * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt |
- * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt |
- * Code distributed by Google as part of the polymer project is also |
- * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt |
- */ |
- |
-(function(scope) { |
- |
-// inject style sheet |
-var style = document.createElement('style'); |
-style.textContent = 'template {display: none !important;} /* injected by platform.js */'; |
-var head = document.querySelector('head'); |
-head.insertBefore(style, head.firstChild); |
- |
-// flush (with logging) |
-var flushing; |
-function flush() { |
- if (!flushing) { |
- flushing = true; |
- scope.endOfMicrotask(function() { |
- flushing = false; |
- logFlags.data && console.group('Platform.flush()'); |
- scope.performMicrotaskCheckpoint(); |
- logFlags.data && console.groupEnd(); |
- }); |
- } |
-}; |
- |
-// polling dirty checker |
-// flush periodically if platform does not have object observe. |
-if (!Observer.hasObjectObserve) { |
- var FLUSH_POLL_INTERVAL = 125; |
- window.addEventListener('WebComponentsReady', function() { |
- flush(); |
- scope.flushPoll = setInterval(flush, FLUSH_POLL_INTERVAL); |
- }); |
-} else { |
- // make flush a no-op when we have Object.observe |
- flush = function() {}; |
-} |
- |
-if (window.CustomElements && !CustomElements.useNative) { |
- var originalImportNode = Document.prototype.importNode; |
- Document.prototype.importNode = function(node, deep) { |
- var imported = originalImportNode.call(this, node, deep); |
- CustomElements.upgradeAll(imported); |
- return imported; |
- } |
-} |
- |
-// exports |
-scope.flush = flush; |
- |
-})(window.Platform); |
+ scope.marshal = marshal; |
+ // `module` confuses commonjs detectors |
+ scope.modularize = module; |
+ scope.using = using; |
+})(window); |
//# sourceMappingURL=platform.concat.js.map |