Skip to content

Commit 89a767c

Browse files
author
Steven Orvell
committed
Fixes #2039: Polymer.dom.flush now triggers Custom Elements polyfill mutations and includes an api (Polymer.dom.addDebouncer(debouncer)) for adding debouncers which should run at flush time. Template rendering debouncers are placed in the flush list.
1 parent a26247b commit 89a767c

File tree

2 files changed

+60
-43
lines changed

2 files changed

+60
-43
lines changed

src/lib/dom-api.html

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
var nativeCloneNode = Element.prototype.cloneNode;
2525
var nativeImportNode = Document.prototype.importNode;
2626

27-
var dirtyRoots = [];
28-
2927
var DomApi = function(node) {
3028
this.node = node;
3129
if (this.patch) {
@@ -36,20 +34,15 @@
3634
DomApi.prototype = {
3735

3836
flush: function() {
39-
for (var i=0, host; i<dirtyRoots.length; i++) {
40-
host = dirtyRoots[i];
41-
host.flushDebouncer('_distribute');
42-
}
43-
dirtyRoots = [];
37+
flush();
4438
},
4539

4640
_lazyDistribute: function(host) {
4741
// note: only try to distribute if the root is not clean; this ensures
4842
// we don't distribute before initial distribution
4943
if (host.shadyRoot && host.shadyRoot._distributionClean) {
5044
host.shadyRoot._distributionClean = false;
51-
host.debounce('_distribute', host._distributeContent);
52-
dirtyRoots.push(host);
45+
addDebouncer(host.debounce('_distribute', host._distributeContent));
5346
}
5447
},
5548

@@ -773,8 +766,54 @@
773766
}
774767
};
775768

776-
// make flush available directly.
777-
Polymer.dom.flush = DomApi.prototype.flush;
769+
// flush and debounce exposed as statics on Polymer.dom
770+
var flush = Polymer.dom.flush = function() {
771+
// first make any pending CE mutations that might trigger debouncer
772+
// additions go...
773+
flush.flushPolyfills();
774+
// flush debouncers
775+
for (var i=0; i < flush._debouncers.length; i++) {
776+
flush._debouncers[i].complete();
777+
}
778+
// clear the list of debouncers
779+
if (flush._finishDebouncer) {
780+
flush._finishDebouncer.complete();
781+
}
782+
// again make any pending CE mutations that might trigger debouncer
783+
// additions go...
784+
flush.flushPolyfills();
785+
// flush again if there are now any debouncers to process
786+
if (flush._debouncers.length && flush.guard < flush.MAX) {
787+
flush.guard++;
788+
flush();
789+
} else {
790+
flush.guard = 0;
791+
}
792+
};
793+
794+
flush.guard = 0;
795+
flush.MAX = 10;
796+
flush._needsTakeRecords = !Polymer.Settings.useNativeCustomElements;
797+
// TODO(sorvell): There is currently not a good way
798+
// to process all custom elements mutations under SD polyfill because
799+
// these mutations may be inside shadowRoots.
800+
flush.flushPolyfills = function() {
801+
if (this._needsTakeRecords) {
802+
CustomElements.takeRecords();
803+
}
804+
}
805+
flush._debouncers = [];
806+
flush._finishDebouncer;
807+
808+
var addDebouncer = Polymer.dom.addDebouncer = function(debouncer) {
809+
flush._debouncers.push(debouncer);
810+
// ensure the list of active debouncers is cleared when done.
811+
flush._finishDebouncer = Polymer.Debounce(flush._finishDebouncer,
812+
function() {
813+
flush._debouncers = [];
814+
}
815+
);
816+
};
778817

779818
function getLightChildren(node) {
780819
var children = node._lightChildren;

src/lib/template/templatizer.html

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,10 @@
7070
}
7171
},
7272

73-
// Intentionally static object
74-
_templatizerStatic: {
75-
count: 0,
76-
callbacks: {},
77-
debouncer: null
78-
},
79-
8073
// Extension point for overrides
8174
_instanceProps: Polymer.nob,
8275

83-
created: function() {
84-
// id used for consolidated debouncer
85-
this._templatizerId = this._templatizerStatic.count++;
86-
},
76+
_parentPropPrefix: '_parent_',
8777

8878
/**
8979
* Prepares a template containing Polymer bindings by generating
@@ -162,24 +152,11 @@
162152
},
163153

164154
_debounceTemplate: function(fn) {
165-
this._templatizerStatic.callbacks[this._templatizerId] = fn.bind(this);
166-
this._templatizerStatic.debouncer =
167-
Polymer.Debounce(this._templatizerStatic.debouncer,
168-
this._flushTemplates.bind(this, true));
155+
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
169156
},
170157

171158
_flushTemplates: function(debouncerExpired) {
172-
var db = this._templatizerStatic.debouncer;
173-
// completely flush any re-queued callbacks resulting from stamping
174-
while (debouncerExpired || (db && db.finish)) {
175-
db.stop();
176-
var cbs = this._templatizerStatic.callbacks;
177-
this._templatizerStatic.callbacks = {};
178-
for (var id in cbs) {
179-
cbs[id]();
180-
}
181-
debouncerExpired = false;
182-
}
159+
Polymer.dom.flush();
183160
},
184161

185162
_customPrepEffects: function(archetype) {
@@ -236,7 +213,7 @@
236213
// to template instances through abstract _forwardParentProp API
237214
// that should be implemented by Templatizer users
238215
for (prop in parentProps) {
239-
var parentProp = '_parent_' + prop;
216+
var parentProp = this._parentPropPrefix + prop;
240217
var effects = [{
241218
kind: 'function',
242219
effect: this._createForwardPropEffector(prop)
@@ -263,8 +240,9 @@
263240
},
264241

265242
_createHostPropEffector: function(prop) {
243+
var prefix = this._parentPropPrefix;
266244
return function(source, value) {
267-
this.dataHost['_parent_' + prop] = value;
245+
this.dataHost[prefix + prop] = value;
268246
};
269247
},
270248

@@ -304,22 +282,22 @@
304282
// Call extension point for Templatizer sub-classes
305283
dataHost._forwardInstancePath.call(dataHost, this, path, value);
306284
if (root in dataHost._parentProps) {
307-
dataHost.notifyPath('_parent_' + path, value);
285+
dataHost.notifyPath(dataHost._parentPropPrefix + path, value);
308286
}
309287
},
310288

311289
// Overrides Base notify-path module
312290
_pathEffector: function(path, value, fromAbove) {
313291
if (this._forwardParentPath) {
314-
if (path.indexOf('_parent_') === 0) {
292+
if (path.indexOf(this._parentPropPrefix) === 0) {
315293
this._forwardParentPath(path.substring(8), value);
316294
}
317295
}
318296
Polymer.Base._pathEffector.apply(this, arguments);
319297
},
320298

321299
_constructorImpl: function(model, host) {
322-
this._rootDataHost = host._getRootDataHost();
300+
this._rootDataHost = host._getRootDataHost() || host;
323301
this._setupConfigure(model);
324302
this._pushHost(host);
325303
this.root = this.instanceTemplate(this._template);
@@ -391,7 +369,7 @@
391369
model = model || {};
392370
if (this._parentProps) {
393371
for (var prop in this._parentProps) {
394-
model[prop] = this['_parent_' + prop];
372+
model[prop] = this[this._parentPropPrefix + prop];
395373
}
396374
}
397375
return new this.ctor(model, this);

0 commit comments

Comments
 (0)