Skip to content
This repository has been archived by the owner on Mar 13, 2018. It is now read-only.

Commit

Permalink
Work around busted IE MutationObserver.
Browse files Browse the repository at this point in the history
Setting innerHTML in IE 11 will result in removedNodes that are always childless.
This leaves no way for the CustomElements observer to call those detachedCallbacks.

Work around funky XML Namespace for unknown elements in IE

Last commit needed for passing tests in IE 11

Work around lack of prototype swizzling in IE 10

customMixin should stop on HTMLElement prototype

With be729c3, no call to customMixin will have HTMLUnknownElement.prototype in the chain, only HTMLElement.prototype
  • Loading branch information
dfreedm committed Feb 10, 2014
1 parent 6236589 commit 2876609
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 64 deletions.
8 changes: 3 additions & 5 deletions src/CustomElements.js
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,9 @@ if (useNative) {
var used = {};
// start with inSrc
var p = inSrc;
// sometimes the default is HTMLUnknownElement.prototype instead of
// 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 !== inNative && p !== HTMLUnknownElement.prototype) {
// The default is HTMLElement.prototype, so we add a test to avoid mixing in
// native prototypes
while (p !== inNative && p !== HTMLElement.prototype) {
var keys = Object.getOwnPropertyNames(p);
for (var i=0, k; k=keys[i]; i++) {
if (!used[k]) {
Expand Down
2 changes: 1 addition & 1 deletion test/js/customElements.js
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@
'</x-boo2-ordering>';

CustomElements.takeRecords();
work.innerHTML = '';
work.removeChild(work.firstElementChild);
CustomElements.takeRecords();
assert.deepEqual(['a', 'b', 'c', 'd', 'e'], log);
});
Expand Down
147 changes: 89 additions & 58 deletions test/js/documentRegister.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,37 @@ function isFormControl(element)
return element.form == testForm;
}


/*
* Work around IE's insertion of XML Namespace elements into .outerHTML of HTMLUnknownElements
*
* Clone the input node, insert it into a div, and then read back the outerHTML, which is now stripped of the XML *
* Namespace element
*/
var isIE = navigator.userAgent.indexOf('Trident') > -1;
function assertOuterHTML(element, expected) {
var outerHTML = element.outerHTML;
if (isIE) {
var div = document.createElement('div');
div.appendChild(element.cloneNode(true));
outerHTML = div.firstChild.outerHTML;
}
chai.assert.equal(outerHTML, expected);
}

var hasProto = ({}.__proto__);
function assertInstanceOf(element, constructor) {
if (hasProto) {
chai.assert.instanceOf(element, constructor);
}
}

function assertNotInstanceOf(element, constructor) {
if (hasProto) {
chai.assert.notInstanceOf(element, constructor);
}
}

suite('register-type-extensions', function() {
var assert = chai.assert;

Expand All @@ -41,12 +72,12 @@ suite('register-type-extensions', function() {
suite('generated constructors', function() {
test('custom tag', function() {
var fooNewed = new fooConstructor();
assert.equal(fooNewed.outerHTML, fooOuterHTML);
assert.instanceOf(fooNewed, fooConstructor);
assert.instanceOf(fooNewed, HTMLElement);
assertOuterHTML(fooNewed, fooOuterHTML);
assertInstanceOf(fooNewed, fooConstructor);
assertInstanceOf(fooNewed, HTMLElement);
// This is part of the Blink tests, but not supported in Firefox with
// polyfill. Similar assertions are also commented out below.
// assert.notInstanceOf(fooNewed, HTMLUnknownElement);
// assertNotInstanceOf(fooNewed, HTMLUnknownElement);

test('custom tag constructor', function() {
assert.equal('a', 'b');
Expand All @@ -55,109 +86,109 @@ suite('register-type-extensions', function() {

test('type extension', function() {
var barNewed = new barConstructor();
assert.equal(barNewed.outerHTML, barOuterHTML);
assert.instanceOf(barNewed, barConstructor);
assert.instanceOf(barNewed, HTMLInputElement);
assertOuterHTML(barNewed, barOuterHTML);
assertInstanceOf(barNewed, barConstructor);
assertInstanceOf(barNewed, HTMLInputElement);
assert.ok(isFormControl(barNewed));
});

test('custom tag deriving from custom tag', function() {
var bazNewed = new bazConstructor();
var bazOuterHTML = '<x-baz></x-baz>';
assert.equal(bazNewed.outerHTML, bazOuterHTML);
assert.instanceOf(bazNewed, bazConstructor);
assert.instanceOf(bazNewed, HTMLElement);
// assert.notInstanceOf(bazNewed, HTMLUnknownElement);
assertOuterHTML(bazNewed, bazOuterHTML);
assertInstanceOf(bazNewed, bazConstructor);
assertInstanceOf(bazNewed, HTMLElement);
// assertNotInstanceOf(bazNewed, HTMLUnknownElement);
});

test('type extension deriving from custom tag', function() {
var quxNewed = new quxConstructor();
var quxOuterHTML = '<input is="x-qux">';
assert.instanceOf(quxNewed, quxConstructor);
assert.instanceOf(quxNewed, barConstructor);
assert.instanceOf(quxNewed, HTMLInputElement);
assert.equal(quxNewed.outerHTML, quxOuterHTML);
assertInstanceOf(quxNewed, quxConstructor);
assertInstanceOf(quxNewed, barConstructor);
assertInstanceOf(quxNewed, HTMLInputElement);
assertOuterHTML(quxNewed, quxOuterHTML);
assert.ok(isFormControl(quxNewed));
});
});

suite('single-parameter createElement', function() {
test('custom tag', function() {
var fooCreated = document.createElement('x-foo-x');
assert.equal(fooCreated.outerHTML, fooOuterHTML);
assert.instanceOf(fooCreated, fooConstructor);
assertOuterHTML(fooCreated, fooOuterHTML);
assertInstanceOf(fooCreated, fooConstructor);
});

test('type extension', function() {
var barCreated = document.createElement('x-bar-x');
assert.equal(barCreated.outerHTML, '<x-bar-x></x-bar-x>');
assert.notInstanceOf(barCreated, barConstructor);
// assert.notInstanceOf(barCreated, HTMLUnknownElement);
assert.instanceOf(barCreated, HTMLElement);
assertOuterHTML(barCreated, '<x-bar-x></x-bar-x>');
assertNotInstanceOf(barCreated, barConstructor);
// assertNotInstanceOf(barCreated, HTMLUnknownElement);
assertInstanceOf(barCreated, HTMLElement);
});

test('custom tag deriving from custom tag', function() {
bazCreated = document.createElement('x-baz');
assert.equal(bazCreated.outerHTML, '<x-baz></x-baz>');
assert.instanceOf(bazCreated, bazConstructor);
// assert.notInstanceOf(bazCreated, HTMLUnknownElement);
assertOuterHTML(bazCreated, '<x-baz></x-baz>');
assertInstanceOf(bazCreated, bazConstructor);
// assertNotInstanceOf(bazCreated, HTMLUnknownElement);
});

test('type extension deriving from custom tag', function() {
quxCreated = document.createElement('x-qux');
assert.equal(quxCreated.outerHTML, '<x-qux></x-qux>');
assert.notInstanceOf(quxCreated, quxConstructor);
// assert.notInstanceOf(quxCreated, HTMLUnknownElement);
assert.instanceOf(quxCreated, HTMLElement);
assertOuterHTML(quxCreated, '<x-qux></x-qux>');
assertNotInstanceOf(quxCreated, quxConstructor);
// assertNotInstanceOf(quxCreated, HTMLUnknownElement);
assertInstanceOf(quxCreated, HTMLElement);
});
});

suite('createElement with type extensions', function() {
test('extension is custom tag', function() {
var divFooCreated = document.createElement('div', 'x-foo-x');
assert.equal(divFooCreated.outerHTML, '<div is="x-foo-x"></div>');
assert.notInstanceOf(divFooCreated, fooConstructor);
assert.instanceOf(divFooCreated, HTMLDivElement);
assertOuterHTML(divFooCreated, '<div is="x-foo-x"></div>');
assertNotInstanceOf(divFooCreated, fooConstructor);
assertInstanceOf(divFooCreated, HTMLDivElement);
});

test('valid extension', function() {
var inputBarCreated = document.createElement('input', 'x-bar-x');
assert.equal(inputBarCreated.outerHTML, barOuterHTML);
assert.instanceOf(inputBarCreated, barConstructor);
assert.notInstanceOf(inputBarCreated, HTMLUnknownElement);
assertOuterHTML(inputBarCreated, barOuterHTML);
assertInstanceOf(inputBarCreated, barConstructor);
assertNotInstanceOf(inputBarCreated, HTMLUnknownElement);
assert.ok(isFormControl(inputBarCreated));
});

test('type extension of incorrect tag', function() {
var divBarCreated = document.createElement('div', 'x-bar-x');
assert.equal(divBarCreated.outerHTML, '<div is="x-bar-x"></div>');
assert.notInstanceOf(divBarCreated, barConstructor);
assert.instanceOf(divBarCreated, HTMLDivElement);
assertOuterHTML(divBarCreated, '<div is="x-bar-x"></div>');
assertNotInstanceOf(divBarCreated, barConstructor);
assertInstanceOf(divBarCreated, HTMLDivElement);
});

test('incorrect extension of custom tag', function() {
var fooBarCreated = document.createElement('x-foo-x', 'x-bar-x');
assert.equal(fooBarCreated.outerHTML, '<x-foo-x is="x-bar-x"></x-foo-x>');
assert.instanceOf(fooBarCreated, fooConstructor);
assertOuterHTML(fooBarCreated, '<x-foo-x is="x-bar-x"></x-foo-x>');
assertInstanceOf(fooBarCreated, fooConstructor);
});

test('incorrect extension of type extension', function() {
var barFooCreated = document.createElement('x-bar-x', 'x-foo-x');
assert.equal(barFooCreated.outerHTML, '<x-bar-x is="x-foo-x"></x-bar-x>');
// assert.notInstanceOf(barFooCreated, HTMLUnknownElement);
assert.instanceOf(barFooCreated, HTMLElement);
assertOuterHTML(barFooCreated, '<x-bar-x is="x-foo-x"></x-bar-x>');
// assertNotInstanceOf(barFooCreated, HTMLUnknownElement);
assertInstanceOf(barFooCreated, HTMLElement);
});

test('null type extension', function() {
var fooCreatedNull = document.createElement('x-foo-x', null);
assert.equal(fooCreatedNull.outerHTML, fooOuterHTML);
assert.instanceOf(fooCreatedNull, fooConstructor);
assertOuterHTML(fooCreatedNull, fooOuterHTML);
assertInstanceOf(fooCreatedNull, fooConstructor);
});

test('empty type extension', function() {
fooCreatedEmpty = document.createElement('x-foo-x', '');
assert.equal(fooCreatedEmpty.outerHTML, fooOuterHTML);
assert.instanceOf(fooCreatedEmpty, fooConstructor);
assertOuterHTML(fooCreatedEmpty, fooOuterHTML);
assertInstanceOf(fooCreatedEmpty, fooConstructor);
});

test('invalid tag name', function() {
Expand All @@ -179,33 +210,33 @@ suite('register-type-extensions', function() {

test('custom tag', function() {
var fooParsed = createElementFromHTML('<x-foo-x>');
assert.instanceOf(fooParsed, fooConstructor);
assertInstanceOf(fooParsed, fooConstructor);
});

test('type extension', function() {
var barParsed = createElementFromHTML('<input is="x-bar-x">')
assert.instanceOf(barParsed, barConstructor);
var barParsed = createElementFromHTML('<input is="x-bar-x">');
assertInstanceOf(barParsed, barConstructor);
assert.ok(isFormControl(barParsed));
});

test('custom tag as type extension', function() {
var divFooParsed = createElementFromHTML('<div is="x-foo-x">')
assert.notInstanceOf(divFooParsed, fooConstructor);
assert.instanceOf(divFooParsed, HTMLDivElement);
var divFooParsed = createElementFromHTML('<div is="x-foo-x">');
assertNotInstanceOf(divFooParsed, fooConstructor);
assertInstanceOf(divFooParsed, HTMLDivElement);
});

// Should we upgrade invalid tags to HTMLElement?
/*test('type extension as custom tag', function() {
var namedBarParsed = createElementFromHTML('<x-bar-x>')
assert.notInstanceOf(namedBarParsed, barConstructor);
assert.notInstanceOf(namedBarParsed, HTMLUnknownElement);
assert.instanceOf(namedBarParsed, HTMLElement);
assertNotInstanceOf(namedBarParsed, barConstructor);
assertNotInstanceOf(namedBarParsed, HTMLUnknownElement);
assertInstanceOf(namedBarParsed, HTMLElement);
});*/

test('type extension of incorrect tag', function() {
var divBarParsed = createElementFromHTML('<div is="x-bar-x">')
assert.notInstanceOf(divBarParsed, barConstructor);
assert.instanceOf(divBarParsed, HTMLDivElement);
var divBarParsed = createElementFromHTML('<div is="x-bar-x">');
assertNotInstanceOf(divBarParsed, barConstructor);
assertInstanceOf(divBarParsed, HTMLDivElement);
});
});
});

0 comments on commit 2876609

Please sign in to comment.