Add sync setAttribute, removeAttribute, and importNode

This commit is contained in:
Justin Fagnani
2016-09-02 09:29:52 -07:00
parent ce12747dce
commit 0dc1ca4002
2 changed files with 68 additions and 21 deletions

View File

@@ -402,7 +402,7 @@ var Deferred;
},
/**
* @param {!NodeList<!Node>} nodeList
* @param {!(NodeList<!Node>|Array<!Node>)} nodeList
* @param {?Set<Node>=} visitedNodes
* @private
*/
@@ -556,8 +556,8 @@ var Deferred;
element.__proto__ = prototype;
if (callConstructor) {
this._setNewInstance(element);
element.__upgraded = true;
new (definition.constructor)();
element.__upgraded = true;
console.assert(this._newInstance == null);
}
@@ -597,8 +597,11 @@ var Deferred;
var name = /** @type {!string} */(mutation.attributeName);
var oldValue = mutation.oldValue;
var newValue = target.getAttribute(name);
var namespace = mutation.attributeNamespace;
definition.attributeChangedCallback.call(target, name, oldValue, newValue, namespace);
// Skip changes that were handled synchronously by setAttribute
if (newValue !== oldValue) {
var namespace = mutation.attributeNamespace;
definition.attributeChangedCallback.call(target, name, oldValue, newValue, namespace);
}
}
}
},
@@ -780,6 +783,50 @@ var Deferred;
});
}
// patch doc.importNode
var rawImportNode = doc.importNode;
doc.importNode = function(node, deep) {
var clone = rawImportNode.call(doc, node, deep);
var customElements = win['customElements'];
/** @type {CustomElementsRegistry} */(window['customElements'])._addNodes(isElement(clone) ? [clone] : clone.childNodes);
return clone;
};
// patch Element.setAttribute & removeAttribute
var _origSetAttribute = Element.prototype.setAttribute;
Element.prototype['setAttribute'] = function(name, value) {
changeAttribute(this, name, value, _origSetAttribute);
};
var _origRemoveAttribute = Element.prototype.removeAttribute;
Element.prototype['removeAttribute'] = function(name) {
changeAttribute(this, name, null, _origRemoveAttribute);
};
function changeAttribute(element, name, value, operation) {
name = name.toLowerCase();
var oldValue = element.getAttribute(name);
operation.call(element, name, value);
// Bail if this wasn't a fully upgraded custom element
if (element.__upgraded == true) {
var definition = window['customElements']._definitions.get(element.localName);
if (definition.observedAttributes.indexOf(name) >= 0) {
var newValue = element.getAttribute(name);
if (newValue !== oldValue) {
element.attributeChangedCallback(name, oldValue, newValue);
}
}
}
}
/** @type {CustomElementsRegistry} */
window['customElements'] = new CustomElementsRegistry();
// // TODO(justinfagnani): Remove. Temporary for backward-compatibility
window['CustomElements'] = {
takeRecords() {
if (window['customElements'].flush) window['customElements'].flush();
}
}
})();

View File

@@ -375,20 +375,7 @@ suite('Custom Element Reactions', function() {
suite('clone/import/adopt', function() {
test('cloned custom elements are not customized', function() {
class XCloned extends HTMLElement {}
customElements.define('x-cloned', XCloned);
var original = document.createElement('x-cloned');
customElements.flush();
assert.instanceOf(original, XCloned);
var imported = document.importNode(original, true);
customElements.flush();
assert.notInstanceOf(imported, XCloned);
});
test('imported custom elements are not customized', function() {
test('imported custom elements are customized', function() {
class XImported extends HTMLElement {}
customElements.define('x-imported', XImported);
@@ -400,10 +387,23 @@ suite('Custom Element Reactions', function() {
var imported = document.importNode(original, true);
customElements.flush();
assert.notInstanceOf(imported, XImported);
assert.instanceOf(imported, XImported);
});
test('adopted custom elements are not customized', function() {
test.skip('cloned custom elements are customized', function() {
class XCloned extends HTMLElement {}
customElements.define('x-cloned', XCloned);
var original = document.createElement('x-cloned');
customElements.flush();
assert.instanceOf(original, XCloned);
var imported = original.cloneNode(true);
customElements.flush();
assert.instanceOf(imported, XCloned);
});
test.skip('adopted custom elements are customized', function() {
class XAdopted extends HTMLElement {}
customElements.define('x-adopted', XAdopted);
@@ -413,7 +413,7 @@ suite('Custom Element Reactions', function() {
// x-adopted is not defined in its document
assert.notInstanceOf(original, XAdopted);
var imported = document.importNode(original, true);
var imported = document.adoptNode(original);
customElements.flush();
assert.notInstanceOf(imported, XAdopted);
});