diff --git a/test/patch/registerElement.spec.js b/test/patch/registerElement.spec.js new file mode 100644 index 000000000..2e5235fa5 --- /dev/null +++ b/test/patch/registerElement.spec.js @@ -0,0 +1,109 @@ +/* + * check that document.registerElement(name, { prototype: proto }); + * is properly patched + */ + +'use strict'; + +describe('document.registerElement', function () { + if (!'registerElement' in document) { + console.log('WARNING: skipping document.registerElement test (missing this API)'); + return; + } + + var flag, hasParent; + + // register a custom element for each callback + var callbacks = [ + 'created', + 'attached', + 'detached', + 'attributeChanged' + ]; + + function flagAndCheckZone() { + flag = true; + hasParent = !!window.zone.parent; + } + + var customElements = callbacks.map(function (callbackName) { + var fullCallbackName = callbackName + 'Callback'; + var proto = Object.create(HTMLElement.prototype); + proto[fullCallbackName] = flagAndCheckZone; + return document.registerElement('x-' + callbackName.toLowerCase(), { + prototype: proto + }); + }); + + + beforeEach(function () { + flag = false; + hasParent = false; + }); + + + it('should work with createdCallback', function () { + runs(function () { + var elt = document.createElement('x-created'); + }); + + waitsFor(function() { + return flag; + }, 'createdCallback to fire', 100); + + runs(function() { + expect(hasParent).toBe(true); + }); + }); + + + it('should work with attachedCallback', function () { + runs(function () { + var elt = document.createElement('x-attached'); + document.body.appendChild(elt); + document.body.removeChild(elt); + }); + + waitsFor(function() { + return flag; + }, 'attachedCallback to fire', 100); + + runs(function() { + expect(hasParent).toBe(true); + }); + }); + + + it('should work with detachedCallback', function () { + runs(function () { + var elt = document.createElement('x-detached'); + document.body.appendChild(elt); + document.body.removeChild(elt); + }); + + waitsFor(function() { + return flag; + }, 'detachedCallback to fire', 100); + + runs(function() { + expect(hasParent).toBe(true); + }); + }); + + + it('should work with attributeChanged', function () { + runs(function () { + var elt = document.createElement('x-attributechanged'); + elt.id = 'bar'; + }); + + waitsFor(function() { + return flag; + }, 'attributeChanged to fire', 100); + + runs(function() { + expect(hasParent).toBe(true); + }); + }); + +}); diff --git a/zone.js b/zone.js index a084bc075..102c668e5 100644 --- a/zone.js +++ b/zone.js @@ -366,6 +366,7 @@ Zone.patch = function patch () { } Zone.patchMutationObserverClass('MutationObserver'); Zone.patchMutationObserverClass('WebKitMutationObserver'); + Zone.patchRegisterElement(); }; // @@ -510,6 +511,27 @@ Zone.patchMutationObserverClass = function (className) { } }; +Zone.patchRegisterElement = function () { + if (!'registerElement' in document) { + return; + } + var _registerElement = document.registerElement; + var callbacks = [ + 'createdCallback', + 'attachedCallback', + 'detachedCallback', + 'attributeChangedCallback' + ]; + document.registerElement = function (name, opts) { + callbacks.forEach(function (callback) { + if (opts.prototype[callback]) { + opts.prototype[callback] = zone.bind(opts.prototype[callback]); + } + }); + return _registerElement.apply(document, [name, opts]); + }; +} + Zone.eventNames = 'copy cut paste abort blur focus canplay canplaythrough change click contextmenu dblclick drag dragend dragenter dragleave dragover dragstart drop durationchange emptied ended input invalid keydown keypress keyup load loadeddata loadedmetadata loadstart mousedown mouseenter mouseleave mousemove mouseout mouseover mouseup pause play playing progress ratechange reset scroll seeked seeking select show stalled submit suspend timeupdate volumechange waiting mozfullscreenchange mozfullscreenerror mozpointerlockchange mozpointerlockerror error'.split(' '); Zone.onEventNames = Zone.eventNames.map(function (property) { return 'on' + property;