| Index: pkg/custom_element/lib/custom-elements.debug.js
|
| diff --git a/pkg/custom_element/lib/custom-elements.debug.js b/pkg/custom_element/lib/custom-elements.debug.js
|
| index 11ae6246b304eb3c1c91e4e7acb890099ebaa041..7ff04c01d1a5b749354041f53a8fe9795e13e14d 100644
|
| --- a/pkg/custom_element/lib/custom-elements.debug.js
|
| +++ b/pkg/custom_element/lib/custom-elements.debug.js
|
| @@ -25,23 +25,16 @@
|
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
| -window.CustomElements = {flags:{}};
|
| -// SideTable is a weak map where possible. If WeakMap is not available the
|
| -// association is stored as an expando property.
|
| -var SideTable;
|
| -// TODO(arv): WeakMap does not allow for Node etc to be keys in Firefox
|
| -if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') < 0) {
|
| - SideTable = WeakMap;
|
| -} else {
|
| +if (typeof WeakMap === 'undefined') {
|
| (function() {
|
| var defineProperty = Object.defineProperty;
|
| var counter = Date.now() % 1e9;
|
|
|
| - SideTable = function() {
|
| + var WeakMap = function() {
|
| this.name = '__st' + (Math.random() * 1e9 >>> 0) + (counter++ + '__');
|
| };
|
|
|
| - SideTable.prototype = {
|
| + WeakMap.prototype = {
|
| set: function(key, value) {
|
| var entry = key[this.name];
|
| if (entry && entry[0] === key)
|
| @@ -57,13 +50,15 @@ if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') <
|
| delete: function(key) {
|
| this.set(key, undefined);
|
| }
|
| - }
|
| + };
|
| +
|
| + window.WeakMap = WeakMap;
|
| })();
|
| }
|
|
|
| (function(global) {
|
|
|
| - var registrationsTable = new SideTable();
|
| + var registrationsTable = new WeakMap();
|
|
|
| // We use setImmediate or postMessage for our future callback.
|
| var setImmediate = window.msSetImmediate;
|
| @@ -596,344 +591,333 @@ if (typeof WeakMap !== 'undefined' && navigator.userAgent.indexOf('Firefox/') <
|
|
|
| global.JsMutationObserver = JsMutationObserver;
|
|
|
| -})(this);
|
| -
|
| -if (!window.MutationObserver) {
|
| - window.MutationObserver =
|
| - window.WebKitMutationObserver ||
|
| - window.JsMutationObserver;
|
| - if (!MutationObserver) {
|
| - throw new Error("no mutation observer support");
|
| - }
|
| -}
|
| -
|
| -(function(scope){
|
| -
|
| -var logFlags = window.logFlags || {};
|
| -
|
| -// walk the subtree rooted at node, applying 'find(element, data)' function
|
| -// to each element
|
| -// if 'find' returns true for 'element', do not search element's subtree
|
| -function findAll(node, find, data) {
|
| - var e = node.firstElementChild;
|
| - if (!e) {
|
| - e = node.firstChild;
|
| - while (e && e.nodeType !== Node.ELEMENT_NODE) {
|
| - e = e.nextSibling;
|
| - }
|
| - }
|
| - while (e) {
|
| - if (find(e, data) !== true) {
|
| - findAll(e, find, data);
|
| - }
|
| - e = e.nextElementSibling;
|
| - }
|
| - return null;
|
| -}
|
| -
|
| -// walk all shadowRoots on a given node.
|
| -function forRoots(node, cb) {
|
| - var root = node.shadowRoot;
|
| - while(root) {
|
| - forSubtree(root, cb);
|
| - root = root.olderShadowRoot;
|
| - }
|
| -}
|
| -
|
| -// walk the subtree rooted at node, including descent into shadow-roots,
|
| -// applying 'cb' to each element
|
| -function forSubtree(node, cb) {
|
| - //logFlags.dom && node.childNodes && node.childNodes.length && console.group('subTree: ', node);
|
| - findAll(node, function(e) {
|
| - if (cb(e)) {
|
| - return true;
|
| - }
|
| - forRoots(e, cb);
|
| - });
|
| - forRoots(node, cb);
|
| - //logFlags.dom && node.childNodes && node.childNodes.length && console.groupEnd();
|
| -}
|
| -
|
| -// manage lifecycle on added node
|
| -function added(node) {
|
| - if (upgrade(node)) {
|
| - insertedNode(node);
|
| - return true;
|
| - }
|
| - inserted(node);
|
| -}
|
| -
|
| -// manage lifecycle on added node's subtree only
|
| -function addedSubtree(node) {
|
| - forSubtree(node, function(e) {
|
| - if (added(e)) {
|
| - return true;
|
| - }
|
| - });
|
| -}
|
| -
|
| -// manage lifecycle on added node and it's subtree
|
| -function addedNode(node) {
|
| - return added(node) || addedSubtree(node);
|
| -}
|
| -
|
| -// upgrade custom elements at node, if applicable
|
| -function upgrade(node) {
|
| - if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
|
| - var type = node.getAttribute('is') || node.localName;
|
| - var definition = scope.registry[type];
|
| - if (definition) {
|
| - logFlags.dom && console.group('upgrade:', node.localName);
|
| - scope.upgrade(node);
|
| - logFlags.dom && console.groupEnd();
|
| - return true;
|
| - }
|
| - }
|
| -}
|
| + // Provide unprefixed MutationObserver with native or JS implementation
|
| + if (!global.MutationObserver && global.WebKitMutationObserver)
|
| + global.MutationObserver = global.WebKitMutationObserver;
|
|
|
| -function insertedNode(node) {
|
| - inserted(node);
|
| - if (inDocument(node)) {
|
| - forSubtree(node, function(e) {
|
| - inserted(e);
|
| - });
|
| - }
|
| -}
|
| + if (!global.MutationObserver)
|
| + global.MutationObserver = JsMutationObserver;
|
|
|
|
|
| -// TODO(sorvell): on platforms without MutationObserver, mutations may not be
|
| -// reliable and therefore entered/leftView are not reliable.
|
| -// To make these callbacks less likely to fail, we defer all inserts and removes
|
| -// to give a chance for elements to be inserted into dom.
|
| -// This ensures enteredViewCallback fires for elements that are created and
|
| -// immediately added to dom.
|
| -var hasPolyfillMutations = (!window.MutationObserver ||
|
| - (window.MutationObserver === window.JsMutationObserver));
|
| -scope.hasPolyfillMutations = hasPolyfillMutations;
|
| -
|
| -var isPendingMutations = false;
|
| -var pendingMutations = [];
|
| -function deferMutation(fn) {
|
| - pendingMutations.push(fn);
|
| - if (!isPendingMutations) {
|
| - isPendingMutations = true;
|
| - var async = (window.Platform && window.Platform.endOfMicrotask) ||
|
| - setTimeout;
|
| - async(takeMutations);
|
| - }
|
| -}
|
| -
|
| -function takeMutations() {
|
| - isPendingMutations = false;
|
| - var $p = pendingMutations;
|
| - for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) {
|
| - p();
|
| - }
|
| - pendingMutations = [];
|
| -}
|
| -
|
| -function inserted(element) {
|
| - if (hasPolyfillMutations) {
|
| - deferMutation(function() {
|
| - _inserted(element);
|
| - });
|
| - } else {
|
| - _inserted(element);
|
| - }
|
| -}
|
| -
|
| -// TODO(sjmiles): if there are descents into trees that can never have inDocument(*) true, fix this
|
| -function _inserted(element) {
|
| - // TODO(sjmiles): it's possible we were inserted and removed in the space
|
| - // of one microtask, in which case we won't be 'inDocument' here
|
| - // But there are other cases where we are testing for inserted without
|
| - // specific knowledge of mutations, and must test 'inDocument' to determine
|
| - // whether to call inserted
|
| - // If we can factor these cases into separate code paths we can have
|
| - // better diagnostics.
|
| - // TODO(sjmiles): when logging, do work on all custom elements so we can
|
| - // track behavior even when callbacks not defined
|
| - //console.log('inserted: ', element.localName);
|
| - if (element.enteredViewCallback || (element.__upgraded__ && logFlags.dom)) {
|
| - logFlags.dom && console.group('inserted:', element.localName);
|
| - if (inDocument(element)) {
|
| - element.__inserted = (element.__inserted || 0) + 1;
|
| - // if we are in a 'removed' state, bluntly adjust to an 'inserted' state
|
| - if (element.__inserted < 1) {
|
| - element.__inserted = 1;
|
| - }
|
| - // if we are 'over inserted', squelch the callback
|
| - if (element.__inserted > 1) {
|
| - logFlags.dom && console.warn('inserted:', element.localName,
|
| - 'insert/remove count:', element.__inserted)
|
| - } else if (element.enteredViewCallback) {
|
| - logFlags.dom && console.log('inserted:', element.localName);
|
| - element.enteredViewCallback();
|
| - }
|
| - }
|
| - logFlags.dom && console.groupEnd();
|
| - }
|
| -}
|
| -
|
| -function removedNode(node) {
|
| - removed(node);
|
| - forSubtree(node, function(e) {
|
| - removed(e);
|
| - });
|
| -}
|
| -
|
| -
|
| -function removed(element) {
|
| - if (hasPolyfillMutations) {
|
| - deferMutation(function() {
|
| - _removed(element);
|
| - });
|
| - } else {
|
| - _removed(element);
|
| - }
|
| -}
|
| -
|
| -function removed(element) {
|
| - // TODO(sjmiles): temporary: do work on all custom elements so we can track
|
| - // behavior even when callbacks not defined
|
| - if (element.leftViewCallback || (element.__upgraded__ && logFlags.dom)) {
|
| - logFlags.dom && console.log('removed:', element.localName);
|
| - if (!inDocument(element)) {
|
| - element.__inserted = (element.__inserted || 0) - 1;
|
| - // if we are in a 'inserted' state, bluntly adjust to an 'removed' state
|
| - if (element.__inserted > 0) {
|
| - element.__inserted = 0;
|
| - }
|
| - // if we are 'over removed', squelch the callback
|
| - if (element.__inserted < 0) {
|
| - logFlags.dom && console.warn('removed:', element.localName,
|
| - 'insert/remove count:', element.__inserted)
|
| - } else if (element.leftViewCallback) {
|
| - element.leftViewCallback();
|
| - }
|
| - }
|
| - }
|
| -}
|
| -
|
| -function inDocument(element) {
|
| - var p = element;
|
| - var doc = window.ShadowDOMPolyfill &&
|
| - window.ShadowDOMPolyfill.wrapIfNeeded(document) || document;
|
| - while (p) {
|
| - if (p == doc) {
|
| - return true;
|
| - }
|
| - p = p.parentNode || p.host;
|
| - }
|
| -}
|
| -
|
| -function watchShadow(node) {
|
| - if (node.shadowRoot && !node.shadowRoot.__watched) {
|
| - logFlags.dom && console.log('watching shadow-root for: ', node.localName);
|
| - // watch all unwatched roots...
|
| - var root = node.shadowRoot;
|
| - while (root) {
|
| - watchRoot(root);
|
| - root = root.olderShadowRoot;
|
| - }
|
| - }
|
| -}
|
| -
|
| -function watchRoot(root) {
|
| - if (!root.__watched) {
|
| - observe(root);
|
| - root.__watched = true;
|
| - }
|
| -}
|
| -
|
| -function filter(inNode) {
|
| - switch (inNode.localName) {
|
| - case 'style':
|
| - case 'script':
|
| - case 'template':
|
| - case undefined:
|
| - return true;
|
| - }
|
| -}
|
| -
|
| -function handler(mutations) {
|
| - //
|
| - if (logFlags.dom) {
|
| - var mx = mutations[0];
|
| - if (mx && mx.type === 'childList' && mx.addedNodes) {
|
| - if (mx.addedNodes) {
|
| - var d = mx.addedNodes[0];
|
| - while (d && d !== document && !d.host) {
|
| - d = d.parentNode;
|
| - }
|
| - var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || '';
|
| - u = u.split('/?').shift().split('/').pop();
|
| - }
|
| - }
|
| - console.group('mutations (%d) [%s]', mutations.length, u || '');
|
| - }
|
| - //
|
| - mutations.forEach(function(mx) {
|
| - //logFlags.dom && console.group('mutation');
|
| - if (mx.type === 'childList') {
|
| - forEach(mx.addedNodes, function(n) {
|
| - //logFlags.dom && console.log(n.localName);
|
| - if (filter(n)) {
|
| - return;
|
| - }
|
| - // nodes added may need lifecycle management
|
| - addedNode(n);
|
| - });
|
| - // removed nodes may need lifecycle management
|
| - forEach(mx.removedNodes, function(n) {
|
| - //logFlags.dom && console.log(n.localName);
|
| - if (filter(n)) {
|
| - return;
|
| - }
|
| - removedNode(n);
|
| - });
|
| - }
|
| - //logFlags.dom && console.groupEnd();
|
| - });
|
| - logFlags.dom && console.groupEnd();
|
| -};
|
| -
|
| -var observer = new MutationObserver(handler);
|
| -
|
| -function takeRecords() {
|
| - // TODO(sjmiles): ask Raf why we have to call handler ourselves
|
| - handler(observer.takeRecords());
|
| - takeMutations();
|
| -}
|
| -
|
| -var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
|
| -
|
| -function observe(inRoot) {
|
| - observer.observe(inRoot, {childList: true, subtree: true});
|
| -}
|
| -
|
| -function observeDocument(document) {
|
| - observe(document);
|
| -}
|
| -
|
| -function upgradeDocument(document) {
|
| - logFlags.dom && console.group('upgradeDocument: ', (document.URL || document._URL || '').split('/').pop());
|
| - addedNode(document);
|
| - logFlags.dom && console.groupEnd();
|
| -}
|
| -
|
| -// exports
|
| -
|
| -scope.watchShadow = watchShadow;
|
| -scope.upgradeAll = addedNode;
|
| -scope.upgradeSubtree = addedSubtree;
|
| -
|
| -scope.observeDocument = observeDocument;
|
| -scope.upgradeDocument = upgradeDocument;
|
| -
|
| -scope.takeRecords = takeRecords;
|
| +})(this);
|
|
|
| -})(window.CustomElements);
|
| +window.CustomElements = window.CustomElements || {flags:{}};
|
| +(function(scope){
|
| +
|
| +var logFlags = window.logFlags || {};
|
| +
|
| +// walk the subtree rooted at node, applying 'find(element, data)' function
|
| +// to each element
|
| +// if 'find' returns true for 'element', do not search element's subtree
|
| +function findAll(node, find, data) {
|
| + var e = node.firstElementChild;
|
| + if (!e) {
|
| + e = node.firstChild;
|
| + while (e && e.nodeType !== Node.ELEMENT_NODE) {
|
| + e = e.nextSibling;
|
| + }
|
| + }
|
| + while (e) {
|
| + if (find(e, data) !== true) {
|
| + findAll(e, find, data);
|
| + }
|
| + e = e.nextElementSibling;
|
| + }
|
| + return null;
|
| +}
|
| +
|
| +// walk all shadowRoots on a given node.
|
| +function forRoots(node, cb) {
|
| + var root = node.shadowRoot;
|
| + while(root) {
|
| + forSubtree(root, cb);
|
| + root = root.olderShadowRoot;
|
| + }
|
| +}
|
| +
|
| +// walk the subtree rooted at node, including descent into shadow-roots,
|
| +// applying 'cb' to each element
|
| +function forSubtree(node, cb) {
|
| + //logFlags.dom && node.childNodes && node.childNodes.length && console.group('subTree: ', node);
|
| + findAll(node, function(e) {
|
| + if (cb(e)) {
|
| + return true;
|
| + }
|
| + forRoots(e, cb);
|
| + });
|
| + forRoots(node, cb);
|
| + //logFlags.dom && node.childNodes && node.childNodes.length && console.groupEnd();
|
| +}
|
| +
|
| +// manage lifecycle on added node
|
| +function added(node) {
|
| + if (upgrade(node)) {
|
| + insertedNode(node);
|
| + return true;
|
| + }
|
| + inserted(node);
|
| +}
|
| +
|
| +// manage lifecycle on added node's subtree only
|
| +function addedSubtree(node) {
|
| + forSubtree(node, function(e) {
|
| + if (added(e)) {
|
| + return true;
|
| + }
|
| + });
|
| +}
|
| +
|
| +// manage lifecycle on added node and it's subtree
|
| +function addedNode(node) {
|
| + return added(node) || addedSubtree(node);
|
| +}
|
| +
|
| +// upgrade custom elements at node, if applicable
|
| +function upgrade(node) {
|
| + if (!node.__upgraded__ && node.nodeType === Node.ELEMENT_NODE) {
|
| + var type = node.getAttribute('is') || node.localName;
|
| + var definition = scope.registry[type];
|
| + if (definition) {
|
| + logFlags.dom && console.group('upgrade:', node.localName);
|
| + scope.upgrade(node);
|
| + logFlags.dom && console.groupEnd();
|
| + return true;
|
| + }
|
| + }
|
| +}
|
| +
|
| +function insertedNode(node) {
|
| + inserted(node);
|
| + if (inDocument(node)) {
|
| + forSubtree(node, function(e) {
|
| + inserted(e);
|
| + });
|
| + }
|
| +}
|
| +
|
| +
|
| +// TODO(sorvell): on platforms without MutationObserver, mutations may not be
|
| +// reliable and therefore entered/leftView are not reliable.
|
| +// To make these callbacks less likely to fail, we defer all inserts and removes
|
| +// to give a chance for elements to be inserted into dom.
|
| +// This ensures enteredViewCallback fires for elements that are created and
|
| +// immediately added to dom.
|
| +var hasPolyfillMutations = (!window.MutationObserver ||
|
| + (window.MutationObserver === window.JsMutationObserver));
|
| +scope.hasPolyfillMutations = hasPolyfillMutations;
|
| +
|
| +var isPendingMutations = false;
|
| +var pendingMutations = [];
|
| +function deferMutation(fn) {
|
| + pendingMutations.push(fn);
|
| + if (!isPendingMutations) {
|
| + isPendingMutations = true;
|
| + var async = (window.Platform && window.Platform.endOfMicrotask) ||
|
| + setTimeout;
|
| + async(takeMutations);
|
| + }
|
| +}
|
| +
|
| +function takeMutations() {
|
| + isPendingMutations = false;
|
| + var $p = pendingMutations;
|
| + for (var i=0, l=$p.length, p; (i<l) && (p=$p[i]); i++) {
|
| + p();
|
| + }
|
| + pendingMutations = [];
|
| +}
|
| +
|
| +function inserted(element) {
|
| + if (hasPolyfillMutations) {
|
| + deferMutation(function() {
|
| + _inserted(element);
|
| + });
|
| + } else {
|
| + _inserted(element);
|
| + }
|
| +}
|
| +
|
| +// TODO(sjmiles): if there are descents into trees that can never have inDocument(*) true, fix this
|
| +function _inserted(element) {
|
| + // TODO(sjmiles): it's possible we were inserted and removed in the space
|
| + // of one microtask, in which case we won't be 'inDocument' here
|
| + // But there are other cases where we are testing for inserted without
|
| + // specific knowledge of mutations, and must test 'inDocument' to determine
|
| + // whether to call inserted
|
| + // If we can factor these cases into separate code paths we can have
|
| + // better diagnostics.
|
| + // TODO(sjmiles): when logging, do work on all custom elements so we can
|
| + // track behavior even when callbacks not defined
|
| + //console.log('inserted: ', element.localName);
|
| + if (element.enteredViewCallback || (element.__upgraded__ && logFlags.dom)) {
|
| + logFlags.dom && console.group('inserted:', element.localName);
|
| + if (inDocument(element)) {
|
| + element.__inserted = (element.__inserted || 0) + 1;
|
| + // if we are in a 'removed' state, bluntly adjust to an 'inserted' state
|
| + if (element.__inserted < 1) {
|
| + element.__inserted = 1;
|
| + }
|
| + // if we are 'over inserted', squelch the callback
|
| + if (element.__inserted > 1) {
|
| + logFlags.dom && console.warn('inserted:', element.localName,
|
| + 'insert/remove count:', element.__inserted)
|
| + } else if (element.enteredViewCallback) {
|
| + logFlags.dom && console.log('inserted:', element.localName);
|
| + element.enteredViewCallback();
|
| + }
|
| + }
|
| + logFlags.dom && console.groupEnd();
|
| + }
|
| +}
|
| +
|
| +function removedNode(node) {
|
| + removed(node);
|
| + forSubtree(node, function(e) {
|
| + removed(e);
|
| + });
|
| +}
|
| +
|
| +function removed(element) {
|
| + if (hasPolyfillMutations) {
|
| + deferMutation(function() {
|
| + _removed(element);
|
| + });
|
| + } else {
|
| + _removed(element);
|
| + }
|
| +}
|
| +
|
| +function _removed(element) {
|
| + // TODO(sjmiles): temporary: do work on all custom elements so we can track
|
| + // behavior even when callbacks not defined
|
| + if (element.leftViewCallback || (element.__upgraded__ && logFlags.dom)) {
|
| + logFlags.dom && console.log('removed:', element.localName);
|
| + if (!inDocument(element)) {
|
| + element.__inserted = (element.__inserted || 0) - 1;
|
| + // if we are in a 'inserted' state, bluntly adjust to an 'removed' state
|
| + if (element.__inserted > 0) {
|
| + element.__inserted = 0;
|
| + }
|
| + // if we are 'over removed', squelch the callback
|
| + if (element.__inserted < 0) {
|
| + logFlags.dom && console.warn('removed:', element.localName,
|
| + 'insert/remove count:', element.__inserted)
|
| + } else if (element.leftViewCallback) {
|
| + element.leftViewCallback();
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +function inDocument(element) {
|
| + var p = element;
|
| + var doc = window.ShadowDOMPolyfill &&
|
| + window.ShadowDOMPolyfill.wrapIfNeeded(document) || document;
|
| + while (p) {
|
| + if (p == doc) {
|
| + return true;
|
| + }
|
| + p = p.parentNode || p.host;
|
| + }
|
| +}
|
| +
|
| +function watchShadow(node) {
|
| + if (node.shadowRoot && !node.shadowRoot.__watched) {
|
| + logFlags.dom && console.log('watching shadow-root for: ', node.localName);
|
| + // watch all unwatched roots...
|
| + var root = node.shadowRoot;
|
| + while (root) {
|
| + watchRoot(root);
|
| + root = root.olderShadowRoot;
|
| + }
|
| + }
|
| +}
|
| +
|
| +function watchRoot(root) {
|
| + if (!root.__watched) {
|
| + observe(root);
|
| + root.__watched = true;
|
| + }
|
| +}
|
| +
|
| +function handler(mutations) {
|
| + //
|
| + if (logFlags.dom) {
|
| + var mx = mutations[0];
|
| + if (mx && mx.type === 'childList' && mx.addedNodes) {
|
| + if (mx.addedNodes) {
|
| + var d = mx.addedNodes[0];
|
| + while (d && d !== document && !d.host) {
|
| + d = d.parentNode;
|
| + }
|
| + var u = d && (d.URL || d._URL || (d.host && d.host.localName)) || '';
|
| + u = u.split('/?').shift().split('/').pop();
|
| + }
|
| + }
|
| + console.group('mutations (%d) [%s]', mutations.length, u || '');
|
| + }
|
| + //
|
| + mutations.forEach(function(mx) {
|
| + //logFlags.dom && console.group('mutation');
|
| + if (mx.type === 'childList') {
|
| + forEach(mx.addedNodes, function(n) {
|
| + //logFlags.dom && console.log(n.localName);
|
| + if (!n.localName) {
|
| + return;
|
| + }
|
| + // nodes added may need lifecycle management
|
| + addedNode(n);
|
| + });
|
| + // removed nodes may need lifecycle management
|
| + forEach(mx.removedNodes, function(n) {
|
| + //logFlags.dom && console.log(n.localName);
|
| + if (!n.localName) {
|
| + return;
|
| + }
|
| + removedNode(n);
|
| + });
|
| + }
|
| + //logFlags.dom && console.groupEnd();
|
| + });
|
| + logFlags.dom && console.groupEnd();
|
| +};
|
| +
|
| +var observer = new MutationObserver(handler);
|
| +
|
| +function takeRecords() {
|
| + // TODO(sjmiles): ask Raf why we have to call handler ourselves
|
| + handler(observer.takeRecords());
|
| + takeMutations();
|
| +}
|
| +
|
| +var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
|
| +
|
| +function observe(inRoot) {
|
| + observer.observe(inRoot, {childList: true, subtree: true});
|
| +}
|
| +
|
| +function observeDocument(document) {
|
| + observe(document);
|
| +}
|
| +
|
| +function upgradeDocument(document) {
|
| + logFlags.dom && console.group('upgradeDocument: ', (document.URL || document._URL || '').split('/').pop());
|
| + addedNode(document);
|
| + logFlags.dom && console.groupEnd();
|
| +}
|
| +
|
| +// exports
|
| +
|
| +scope.watchShadow = watchShadow;
|
| +scope.upgradeAll = addedNode;
|
| +scope.upgradeSubtree = addedSubtree;
|
| +
|
| +scope.observeDocument = observeDocument;
|
| +scope.upgradeDocument = upgradeDocument;
|
| +
|
| +scope.takeRecords = takeRecords;
|
| +
|
| +})(window.CustomElements);
|
|
|
| /**
|
| * Implements `document.register`
|
| @@ -1031,8 +1015,10 @@ if (useNative) {
|
| // offer guidance)
|
| throw new Error('document.register: first argument (\'name\') must contain a dash (\'-\'). Argument provided was \'' + String(name) + '\'.');
|
| }
|
| - // record name
|
| - definition.name = name;
|
| + // elements may only be registered once
|
| + if (getRegisteredDefinition(name)) {
|
| + throw new Error('DuplicateDefinitionError: a type with name \'' + String(name) + '\' is already registered');
|
| + }
|
| // must have a prototype, default to an extension of HTMLElement
|
| // TODO(sjmiles): probably should throw if no prototype, check spec
|
| if (!definition.prototype) {
|
| @@ -1040,6 +1026,8 @@ if (useNative) {
|
| // offer guidance)
|
| throw new Error('Options missing required prototype property');
|
| }
|
| + // record name
|
| + definition.name = name.toLowerCase();
|
| // ensure a lifecycle object so we don't have to null test it
|
| definition.lifecycle = definition.lifecycle || {};
|
| // build a list of ancestral custom elements (for native base detection)
|
| @@ -1055,7 +1043,7 @@ if (useNative) {
|
| // overrides to implement attributeChanged callback
|
| overrideAttributeApi(definition.prototype);
|
| // 7.1.5: Register the DEFINITION with DOCUMENT
|
| - registerDefinition(name, definition);
|
| + registerDefinition(definition.name, definition);
|
| // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
|
| // 7.1.8. Return the output of the previous step.
|
| definition.ctor = generateConstructor(definition);
|
| @@ -1071,7 +1059,7 @@ if (useNative) {
|
| }
|
|
|
| function ancestry(extnds) {
|
| - var extendee = registry[extnds];
|
| + var extendee = getRegisteredDefinition(extnds);
|
| if (extendee) {
|
| return ancestry(extendee.extends).concat([extendee]);
|
| }
|
| @@ -1139,6 +1127,8 @@ if (useNative) {
|
| if (definition.is) {
|
| element.setAttribute('is', definition.is);
|
| }
|
| + // remove 'unresolved' attr, which is a standin for :unresolved.
|
| + element.removeAttribute('unresolved');
|
| // make 'element' implement definition.prototype
|
| implement(element, definition);
|
| // flag as upgraded
|
| @@ -1176,7 +1166,7 @@ if (useNative) {
|
| // HTMLElement.prototype, so we add a test
|
| // the idea is to avoid mixing in native prototypes, so adding
|
| // the second test is WLOG
|
| - while (p && p !== inNative && p !== HTMLUnknownElement.prototype) {
|
| + while (p !== inNative && p !== HTMLUnknownElement.prototype) {
|
| var keys = Object.getOwnPropertyNames(p);
|
| for (var i=0, k; k=keys[i]; i++) {
|
| if (!used[k]) {
|
| @@ -1202,6 +1192,9 @@ if (useNative) {
|
| // overrides to implement callbacks
|
| // TODO(sjmiles): should support access via .attributes NamedNodeMap
|
| // TODO(sjmiles): preserves user defined overrides, if any
|
| + if (prototype.setAttribute._polyfilled) {
|
| + return;
|
| + }
|
| var setAttribute = prototype.setAttribute;
|
| prototype.setAttribute = function(name, value) {
|
| changeAttribute.call(this, name, value, setAttribute);
|
| @@ -1210,14 +1203,18 @@ if (useNative) {
|
| prototype.removeAttribute = function(name) {
|
| changeAttribute.call(this, name, null, removeAttribute);
|
| }
|
| + prototype.setAttribute._polyfilled = true;
|
| }
|
|
|
| + // https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/
|
| + // index.html#dfn-attribute-changed-callback
|
| function changeAttribute(name, value, operation) {
|
| var oldValue = this.getAttribute(name);
|
| operation.apply(this, arguments);
|
| + var newValue = this.getAttribute(name);
|
| if (this.attributeChangedCallback
|
| - && (this.getAttribute(name) !== oldValue)) {
|
| - this.attributeChangedCallback(name, oldValue, value);
|
| + && (newValue !== oldValue)) {
|
| + this.attributeChangedCallback(name, oldValue, newValue);
|
| }
|
| }
|
|
|
| @@ -1225,9 +1222,15 @@ if (useNative) {
|
|
|
| var registry = {};
|
|
|
| + function getRegisteredDefinition(name) {
|
| + if (name) {
|
| + return registry[name.toLowerCase()];
|
| + }
|
| + }
|
| +
|
| function registerDefinition(name, definition) {
|
| if (registry[name]) {
|
| - throw new Error('Cannot register a tag more than once');
|
| + throw new Error('a type with that name is already registered.');
|
| }
|
| registry[name] = definition;
|
| }
|
| @@ -1239,7 +1242,9 @@ if (useNative) {
|
| }
|
|
|
| function createElement(tag, typeExtension) {
|
| - var definition = registry[typeExtension || tag];
|
| + // TODO(sjmiles): ignore 'tag' when using 'typeExtension', we could
|
| + // error check it, or perhaps there should only ever be one argument
|
| + var definition = getRegisteredDefinition(typeExtension || tag);
|
| if (definition) {
|
| if (tag == definition.tag && typeExtension == definition.is) {
|
| return new definition.ctor();
|
| @@ -1377,7 +1382,7 @@ var forEach = Array.prototype.forEach.call.bind(Array.prototype.forEach);
|
| CustomElements.parser = parser;
|
|
|
| })();
|
| -(function(){
|
| +(function(scope){
|
|
|
| // bootstrap parsing
|
| function bootstrap() {
|
| @@ -1409,21 +1414,31 @@ function bootstrap() {
|
| // CustomEvent shim for IE
|
| if (typeof window.CustomEvent !== 'function') {
|
| window.CustomEvent = function(inType) {
|
| - var e = document.createEvent('HTMLEvents');
|
| - e.initEvent(inType, true, true);
|
| - return e;
|
| + var e = document.createEvent('HTMLEvents');
|
| + e.initEvent(inType, true, true);
|
| + return e;
|
| };
|
| }
|
|
|
| -if (document.readyState === 'complete') {
|
| +// When loading at readyState complete time (or via flag), boot custom elements
|
| +// immediately.
|
| +// If relevant, HTMLImports must already be loaded.
|
| +if (document.readyState === 'complete' || scope.flags.eager) {
|
| bootstrap();
|
| +// When loading at readyState interactive time, bootstrap only if HTMLImports
|
| +// are not pending. Also avoid IE as the semantics of this state are unreliable.
|
| +} else if (document.readyState === 'interactive' && !window.attachEvent &&
|
| + (!window.HTMLImports || window.HTMLImports.ready)) {
|
| + bootstrap();
|
| +// When loading at other readyStates, wait for the appropriate DOM event to
|
| +// bootstrap.
|
| } else {
|
| var loadEvent = window.HTMLImports ? 'HTMLImportsLoaded' :
|
| document.readyState == 'loading' ? 'DOMContentLoaded' : 'load';
|
| window.addEventListener(loadEvent, bootstrap);
|
| }
|
|
|
| -})();
|
| +})(window.CustomElements);
|
|
|
| (function() {
|
| // Patch to allow custom element and shadow dom to work together, from:
|
| @@ -1440,13 +1455,8 @@ if (HTMLElement.prototype.createShadowRoot) {
|
|
|
|
|
| // Patch to allow custom elements and shadow dom to work together, from:
|
| -// https://github.com/Polymer/platform/blob/master/src/patches-custom-elements.js
|
| +// https://github.com/Polymer/platform-dev/blob/2bb9c56d90f9ac19c2e65cdad368668aff514f14/src/patches-custom-elements.js
|
| if (window.ShadowDOMPolyfill) {
|
| - function nop() {};
|
| -
|
| - // disable shadow dom watching
|
| - CustomElements.watchShadow = nop;
|
| - CustomElements.watchAllShadows = nop;
|
|
|
| // ensure wrapped inputs for these functions
|
| var fns = ['upgradeAll', 'upgradeSubtree', 'observeDocument',
|
| @@ -1461,9 +1471,21 @@ if (window.ShadowDOMPolyfill) {
|
| // override
|
| fns.forEach(function(fn) {
|
| CustomElements[fn] = function(inNode) {
|
| - return original[fn](ShadowDOMPolyfill.wrapIfNeeded(inNode));
|
| + return original[fn](window.ShadowDOMPolyfill.wrapIfNeeded(inNode));
|
| };
|
| });
|
| +
|
| +}
|
| +
|
| +// Patch to make importNode work.
|
| +// https://github.com/Polymer/platform-dev/blob/64a92f273462f04a84abbe2f054294f2b62dbcd6/src/patches-mdv.js
|
| +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;
|
| + }
|
| }
|
|
|
| })();
|
|
|