Skip to content

Commit

Permalink
Merge pull request #2090 from Polymer/fix-flush
Browse files Browse the repository at this point in the history
Shady DOM rendering + Polymer.dom.flush improvements
  • Loading branch information
Steve Orvell committed Jul 18, 2015
2 parents 91577c9 + dff0421 commit 8134fbf
Show file tree
Hide file tree
Showing 14 changed files with 1,395 additions and 917 deletions.
1,799 changes: 923 additions & 876 deletions src/lib/dom-api.html

Large diffs are not rendered by default.

32 changes: 27 additions & 5 deletions src/lib/template/dom-bind.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,18 @@
created: function() {
// Ensure dom-bind doesn't stamp until all possible dependencies
// have resolved
Polymer.ImportStatus.whenLoaded(this._readySelf.bind(this));
Polymer.ImportStatus.whenLoaded(this._markImportsReady.bind(this));
},

_ensureReady: function() {
if (!this._readied) {
this._readySelf();
}
},

_markImportsReady: function() {
this._importsReady = true;
this._ensureReady();
},

_registerFeatures: function() {
Expand Down Expand Up @@ -114,6 +125,21 @@
},

attached: function() {
if (this._importsReady) {
this.render();
}
},

detached: function() {
this._removeChildren();
},

/**
* Forces the element to render its content. This is typically only
* necessary to call if HTMLImports with the async attribute are used.
*/
render: function() {
this._ensureReady();
if (!this._children) {
this._template = this;
this._prepAnnotations();
Expand All @@ -126,10 +152,6 @@
}
this._insertChildren();
this.fire('dom-change');
},

detached: function() {
this._removeChildren();
}

});
Expand Down
7 changes: 7 additions & 0 deletions src/lib/template/dom-if.html
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@
}
},

/**
* Forces the element to render its content. Normally rendering is
* asynchronous to a provoking change. This is done for efficiency so
* that multiple changes trigger only a single render. The render method
* should be called if, for example, template rendering is required to
* validate application state.
*/
render: function() {
this._flushTemplates();
},
Expand Down
7 changes: 7 additions & 0 deletions src/lib/template/dom-repeat.html
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,13 @@
}
},

/**
* Forces the element to render its content. Normally rendering is
* asynchronous to a provoking change. This is done for efficiency so
* that multiple changes trigger only a single render. The render method
* should be called if, for example, template rendering is required to
* validate application state.
*/
render: function() {
// Queue this repeater, then flush all in order
this._needFullRefresh = true;
Expand Down
40 changes: 9 additions & 31 deletions src/lib/template/templatizer.html
Original file line number Diff line number Diff line change
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,14 +282,14 @@
// 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);
}
}
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
2 changes: 1 addition & 1 deletion src/micro/debouncer.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
* last signal that must elapse before invoking `callback`
*/
debounce: function(jobName, callback, wait) {
this._debouncers[jobName] = Polymer.Debounce.call(this,
return this._debouncers[jobName] = Polymer.Debounce.call(this,
this._debouncers[jobName], callback, wait);
},

Expand Down
5 changes: 4 additions & 1 deletion src/mini/shady.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@
_finishDistribute: function() {
// compose self
if (this._useContent) {
// note: it's important to mark this clean before distribution
// so that attachment that provokes additional distribution (e.g.
// adding something to your parentNode) works
this.shadyRoot._distributionClean = true;
if (hasInsertionPoint(this.shadyRoot)) {
this._composeTree();
} else {
Expand All @@ -146,7 +150,6 @@
}
}
this.shadyRoot._hasDistributed = true;
this.shadyRoot._distributionClean = true;
}
},

Expand Down
86 changes: 86 additions & 0 deletions test/smoke/dom-bind-async.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<!doctype html>
<html>
<head>

<title>dom-bind</title>

<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../../polymer.html" async>

<script>
document.querySelector('link').addEventListener('load', function() {
app.render();
});
</script>

</head>
<body>

<template is="dom-bind" id="app">

<h3>Repeat index</h3>
<template is="dom-repeat" items="{{employees}}">
<div style="padding: 3px 0px;">
<button on-tap="modify">Modify</button>
<span>{{index}}</span>
<span>{{item.first}}</span>
<span>{{item.last}}</span>
</div>
</template>

<h3>Show person by index, demonstrate "dom-if" expressions</h3>
<template is="dom-repeat" items="{{employees}}">
<div>
<template is="dom-if" if="{{testit(index)}}">
<div style="padding: 3px 0px;">
<button on-tap="modify">Modify</button>
<span>{{index}}</span>
<span>{{item.first}}</span>
<span>{{item.last}}</span>
</div>
</template>
</div>
</template>

<h3>Show person by index, demonstrate filter</h3>
<template is="dom-repeat" items="{{employees}}" filter="onlyRob">
<div>
<div style="padding: 3px 0px;">
<button on-tap="modify">Modify</button>
<span>{{index}}</span>
<span>{{item.first}}</span>
<span>{{item.last}}</span>
</div>
</div>
</template>

</template>

<script>
var logEl = document.getElementById('log');
var app = document.getElementById('app');
app.testit = function(i) {
return i > 1;
};
app.modify = function(e) {
e.model.set('item.last', e.model.item.last + '*');
};
app.onlyRob = function(item) {
return item.first == 'Rob';
};
app.bar = true;
app.employees = [
{first: 'Bob', last: 'Smith'},
{first: 'Sally', last: 'Johnson'},
{first: 'Rob', last: 'Instructs'},
{first: 'Scott', last: 'Explains'},
{first: 'Taylor', last: 'Blogs'}
];

</script>

</body>
</html>
55 changes: 55 additions & 0 deletions test/smoke/dynamic-dom-bind.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<!doctype html>
<!--
@license
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<script src="../../../webcomponentsjs/webcomponents-lite.js"></script>
<link rel="import" href="../../polymer.html">

<body>
<x-test></x-test>

<dom-module id="x-foo">
<template>
<content></content>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-foo'
});
});
</script>
</dom-module>

<dom-module id="x-test">
<template>
Greeting:
<x-foo id="myCustomElement"></x-foo>
</template>
<script>
HTMLImports.whenReady(function() {
Polymer({
is: 'x-test',
attached: function() {
var appendTo = this.$.myCustomElement,
t = document.createElement('template', 'dom-bind'),
span = document.createElement('span');
span.innerHTML = '{{hello}}';
t.content.appendChild(span);
t.hello = 'hey';
Polymer.dom(appendTo).appendChild(t);
}
});
});
</script>
</dom-module>


</body>

Loading

0 comments on commit 8134fbf

Please sign in to comment.