diff --git a/lib/mixins/element-mixin.html b/lib/mixins/element-mixin.html
index 309f680f5d..2e0e8c86ac 100644
--- a/lib/mixins/element-mixin.html
+++ b/lib/mixins/element-mixin.html
@@ -423,6 +423,8 @@
proto._bindTemplate(template, propertiesForClass(proto.constructor));
}
+ function flushPropertiesStub() {}
+
/**
* @polymerMixinClass
* @unrestricted
@@ -547,7 +549,6 @@
*/
_initializeProperties() {
Polymer.telemetry.instanceCount++;
- this.__upgradeFlush = null;
this.constructor.finalize();
const importPath = this.constructor.importPath;
// note: finalize template when we have access to `localName` to
@@ -678,16 +679,17 @@
* @override
*/
attributeChangedCallback(name, old, value) {
- // process `disable-upgrade` specially
- if (name === DISABLED) {
- const disabled = value !== null;
- if (this.__upgradeFlush && !disabled) {
- this._flushProperties = this.__upgradeFlush;
- this.__upgradeFlush = null;
+ // process `disable-upgrade` specially:
+ // First we see `disable-upgrade` added and disable `_flushProperties`,
+ // then when it's removed, restore regular flushing and flush.
+ // This should only be allowed before "readying".
+ if (name === DISABLED && !this.__dataInitialized) {
+ if (value !== null) {
+ this.__flushProperties = this._flushProperties;
+ this._flushProperties = flushPropertiesStub;
+ } else {
+ this._flushProperties = this.__flushProperties;
this._flushProperties();
- } else if (disabled) {
- this.__upgradeFlush = this._flushProperties;
- this._flushProperties = function() {};
}
} else if (old !== value) {
let property = caseMap.dashToCamelCase(name);
diff --git a/lib/utils/render-status.html b/lib/utils/render-status.html
index 8ab664ed5b..7c0bd907d8 100644
--- a/lib/utils/render-status.html
+++ b/lib/utils/render-status.html
@@ -26,27 +26,33 @@
flushQueue(beforeRenderQueue);
// after the render
setTimeout(function() {
- flushQueue(afterRenderQueue);
+ runQueue(afterRenderQueue);
});
});
}
function flushQueue(queue) {
- const max = queue.length;
- let i=0;
- while (queue.length && i < max) {
- i++;
- const q = queue.shift();
- const context = q[0];
- const callback = q[1];
- const args = q[2];
- try {
- callback.apply(context, args);
- } catch(e) {
- setTimeout(() => {
- throw e;
- })
- }
+ while (queue.length) {
+ callMethod(queue.shift());
+ }
+ }
+
+ function runQueue(queue) {
+ for (let i=0, l=queue.length; i < l; i++) {
+ callMethod(queue.shift());
+ }
+ }
+
+ function callMethod(info) {
+ const context = info[0];
+ const callback = info[1];
+ const args = info[2];
+ try {
+ callback.apply(context, args);
+ } catch(e) {
+ setTimeout(() => {
+ throw e;
+ })
}
}
@@ -55,6 +61,7 @@
flushQueue(beforeRenderQueue);
flushQueue(afterRenderQueue);
}
+ scheduled = false;
}
/**
diff --git a/test/unit/render-status.html b/test/unit/render-status.html
index 0f1e4509b4..6312c10732 100644
--- a/test/unit/render-status.html
+++ b/test/unit/render-status.html
@@ -21,18 +21,47 @@
class XFoo extends Polymer.LegacyElementMixin(HTMLElement) {
ready() {
super.ready();
+ sinon.spy(this, 'beforeNextRender');
+ sinon.spy(this, 'stillBeforeNextRender');
Polymer.RenderStatus.beforeNextRender(this, this.beforeNextRender,
['before']);
+ }
+
+ beforeNextRender() {
+ Polymer.RenderStatus.beforeNextRender(this, this.stillBeforeNextRender,
+ ['still-before']);
+ }
+ stillBeforeNextRender() {
+ if (this.beforeDone) {
+ this.beforeDone();
+ }
+ }
+ }
+ customElements.define('x-foo', XFoo);
+
+ class XBar extends Polymer.LegacyElementMixin(HTMLElement) {
+ ready() {
+ super.ready();
+ sinon.spy(this, 'afterNextRender');
+ sinon.spy(this, 'afterAfterNextRender');
Polymer.RenderStatus.afterNextRender(this, (a) => {
this.afterNextRender(a);
}, ['after']);
}
- beforeNextRender() {}
- afterNextRender() {}
+ afterNextRender() {
+ Polymer.RenderStatus.afterNextRender(this, (a) => {
+ this.afterAfterNextRender(a);
+ }, ['after-after']);
+ }
+ afterAfterNextRender() {
+ if (this.afterDone) {
+ this.afterDone();
+ }
+ }
}
- customElements.define('x-foo', XFoo);
+ customElements.define('x-bar', XBar);
});
@@ -42,51 +71,46 @@
test('beforeNextRender', function(done) {
let el = document.createElement('x-foo');
- let beforeCalled;
- el.beforeNextRender = function(a) {
- assert.equal(a, 'before', 'before render argument incorrect');
- beforeCalled = true;
- }
document.body.appendChild(el);
- requestAnimationFrame(() => {
- setTimeout(() => {
- assert.isTrue(beforeCalled);
- done();
- });
- });
+ el.beforeDone = function() {
+ assert.ok(el.beforeNextRender.withArgs('before').calledOnce);
+ assert.ok(el.stillBeforeNextRender.withArgs('still-before').calledOnce);
+ // break out of this raf so next test is not tainted.
+ requestAnimationFrame(() => { done() });
+ };
});
test('afterNextRender', function(done) {
- let el = document.createElement('x-foo');
- let afterCalled;
- let raf;
+ let el = document.createElement('x-bar');
+ let raf1 = sinon.spy();
+ let raf2 = sinon.spy();
requestAnimationFrame(() => {
- assert.notOk(afterCalled);
- raf = true;
- })
- el.afterNextRender = function(a) {
- assert.equal(a, 'after', 'after render argument incorrect');
- afterCalled = true;
- assert.ok(raf);
- done();
+ raf1();
+ requestAnimationFrame(() => {
+ raf2();
+ });
+ });
+ el.afterDone = function() {
+ assert.ok(el.afterNextRender.withArgs('after').calledOnce);
+ assert.ok(el.afterNextRender.calledAfter(raf1));
+ assert.ok(el.afterAfterNextRender.withArgs('after-after').calledOnce);
+ assert.ok(el.afterAfterNextRender.calledAfter(raf2));
+ // break out of this raf so next test is not tainted.
+ requestAnimationFrame(() => { done() });
}
document.body.appendChild(el);
});
test('flush', function() {
- let el = document.createElement('x-foo');
- let beforeCalled;
- el.beforeNextRender = function() {
- beforeCalled = true;
- }
- let afterCalled;
- el.afterNextRender = function() {
- afterCalled = true;
- }
- document.body.appendChild(el);
+ let el1 = document.createElement('x-foo');
+ let el2 = document.createElement('x-bar');
+ document.body.appendChild(el1);
+ document.body.appendChild(el2);
Polymer.RenderStatus.flush();
- assert.isTrue(beforeCalled);
- assert.isTrue(afterCalled);
+ assert.ok(el1.beforeNextRender.withArgs('before').calledOnce);
+ assert.ok(el1.stillBeforeNextRender.withArgs('still-before').calledOnce);
+ assert.ok(el2.afterNextRender.withArgs('after').calledOnce);
+ assert.ok(el2.afterAfterNextRender.withArgs('after-after').calledOnce);
});
});