Skip to content

Commit

Permalink
Fixes #2039: Polymer.dom.flush now triggers Custom Elements polyfill …
Browse files Browse the repository at this point in the history
…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.
  • Loading branch information
Steven Orvell committed Jul 15, 2015
1 parent a26247b commit 89a767c
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 43 deletions.
61 changes: 50 additions & 11 deletions src/lib/dom-api.html
Expand Up @@ -24,8 +24,6 @@
var nativeCloneNode = Element.prototype.cloneNode;
var nativeImportNode = Document.prototype.importNode;

var dirtyRoots = [];

var DomApi = function(node) {
this.node = node;
if (this.patch) {
Expand All @@ -36,20 +34,15 @@
DomApi.prototype = {

flush: function() {
for (var i=0, host; i<dirtyRoots.length; i++) {
host = dirtyRoots[i];
host.flushDebouncer('_distribute');
}
dirtyRoots = [];
flush();
},

_lazyDistribute: function(host) {
// note: only try to distribute if the root is not clean; this ensures
// we don't distribute before initial distribution
if (host.shadyRoot && host.shadyRoot._distributionClean) {
host.shadyRoot._distributionClean = false;
host.debounce('_distribute', host._distributeContent);
dirtyRoots.push(host);
addDebouncer(host.debounce('_distribute', host._distributeContent));
}
},

Expand Down Expand Up @@ -773,8 +766,54 @@
}
};

// make flush available directly.
Polymer.dom.flush = DomApi.prototype.flush;
// flush and debounce exposed as statics on Polymer.dom
var flush = Polymer.dom.flush = function() {
// first make any pending CE mutations that might trigger debouncer
// additions go...
flush.flushPolyfills();
// flush debouncers
for (var i=0; i < flush._debouncers.length; i++) {
flush._debouncers[i].complete();
}
// clear the list of debouncers
if (flush._finishDebouncer) {
flush._finishDebouncer.complete();
}
// again make any pending CE mutations that might trigger debouncer
// additions go...
flush.flushPolyfills();
// flush again if there are now any debouncers to process
if (flush._debouncers.length && flush.guard < flush.MAX) {
flush.guard++;
flush();
} else {
flush.guard = 0;
}
};

flush.guard = 0;
flush.MAX = 10;
flush._needsTakeRecords = !Polymer.Settings.useNativeCustomElements;
// TODO(sorvell): There is currently not a good way
// to process all custom elements mutations under SD polyfill because
// these mutations may be inside shadowRoots.
flush.flushPolyfills = function() {
if (this._needsTakeRecords) {
CustomElements.takeRecords();
}
}
flush._debouncers = [];
flush._finishDebouncer;

var addDebouncer = Polymer.dom.addDebouncer = function(debouncer) {
flush._debouncers.push(debouncer);
// ensure the list of active debouncers is cleared when done.
flush._finishDebouncer = Polymer.Debounce(flush._finishDebouncer,
function() {
flush._debouncers = [];
}
);
};

function getLightChildren(node) {
var children = node._lightChildren;
Expand Down
42 changes: 10 additions & 32 deletions src/lib/template/templatizer.html
Expand Up @@ -70,20 +70,10 @@
}
},

// Intentionally static object
_templatizerStatic: {
count: 0,
callbacks: {},
debouncer: null
},

// Extension point for overrides
_instanceProps: Polymer.nob,

created: function() {
// id used for consolidated debouncer
this._templatizerId = this._templatizerStatic.count++;
},
_parentPropPrefix: '_parent_',

/**
* Prepares a template containing Polymer bindings by generating
Expand Down Expand Up @@ -162,24 +152,11 @@
},

_debounceTemplate: function(fn) {
this._templatizerStatic.callbacks[this._templatizerId] = fn.bind(this);
this._templatizerStatic.debouncer =
Polymer.Debounce(this._templatizerStatic.debouncer,
this._flushTemplates.bind(this, true));
Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', fn));
},

_flushTemplates: function(debouncerExpired) {
var db = this._templatizerStatic.debouncer;
// completely flush any re-queued callbacks resulting from stamping
while (debouncerExpired || (db && db.finish)) {
db.stop();
var cbs = this._templatizerStatic.callbacks;
this._templatizerStatic.callbacks = {};
for (var id in cbs) {
cbs[id]();
}
debouncerExpired = false;
}
Polymer.dom.flush();
},

_customPrepEffects: function(archetype) {
Expand Down Expand Up @@ -236,7 +213,7 @@
// to template instances through abstract _forwardParentProp API
// that should be implemented by Templatizer users
for (prop in parentProps) {
var parentProp = '_parent_' + prop;
var parentProp = this._parentPropPrefix + prop;
var effects = [{
kind: 'function',
effect: this._createForwardPropEffector(prop)
Expand All @@ -263,8 +240,9 @@
},

_createHostPropEffector: function(prop) {
var prefix = this._parentPropPrefix;
return function(source, value) {
this.dataHost['_parent_' + prop] = value;
this.dataHost[prefix + prop] = value;
};
},

Expand Down Expand Up @@ -304,22 +282,22 @@
// Call extension point for Templatizer sub-classes
dataHost._forwardInstancePath.call(dataHost, this, path, value);
if (root in dataHost._parentProps) {
dataHost.notifyPath('_parent_' + path, value);
dataHost.notifyPath(dataHost._parentPropPrefix + path, value);
}
},

// Overrides Base notify-path module
_pathEffector: function(path, value, fromAbove) {
if (this._forwardParentPath) {
if (path.indexOf('_parent_') === 0) {
if (path.indexOf(this._parentPropPrefix) === 0) {
this._forwardParentPath(path.substring(8), value);
}
}
Polymer.Base._pathEffector.apply(this, arguments);
},

_constructorImpl: function(model, host) {
this._rootDataHost = host._getRootDataHost();
this._rootDataHost = host._getRootDataHost() || host;
this._setupConfigure(model);
this._pushHost(host);
this.root = this.instanceTemplate(this._template);
Expand Down Expand Up @@ -391,7 +369,7 @@
model = model || {};
if (this._parentProps) {
for (var prop in this._parentProps) {
model[prop] = this['_parent_' + prop];
model[prop] = this[this._parentPropPrefix + prop];
}
}
return new this.ctor(model, this);
Expand Down

0 comments on commit 89a767c

Please sign in to comment.