Skip to content

Commit

Permalink
Merge pull request #2533 from Polymer/2505-kschaaf-templatizer-path
Browse files Browse the repository at this point in the history
Add notify-path API to templatized template. Fixes #2505.
  • Loading branch information
Steve Orvell committed Oct 8, 2015
2 parents 552fe41 + 79dfe1f commit 0657dfe
Show file tree
Hide file tree
Showing 5 changed files with 499 additions and 11 deletions.
26 changes: 15 additions & 11 deletions src/lib/template/templatizer.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
* @param {HTMLTemplateElement} template The template to process.
*/
templatize: function(template) {
this._templatized = template;
// TODO(sjmiles): supply _alternate_ content reference missing from root
// templates (not nested). `_content` exists to provide content sharing
// for nested templates.
Expand All @@ -108,15 +109,15 @@
// archetypes do special caching
this._customPrepAnnotations(archetype, template);

// forward parent properties to archetype
this._prepParentProperties(archetype, template);

// setup accessors
archetype._prepEffects();
this._customPrepEffects(archetype);
archetype._prepBehaviors();
archetype._prepBindings();

// forward parent properties to archetype
this._prepParentProperties(archetype, template);

// boilerplate code
archetype._notifyPath = this._notifyPathImpl;
archetype._scopeElementClass = this._scopeElementClassImpl;
Expand Down Expand Up @@ -223,6 +224,7 @@
// assume that the template is not a Poylmer.Base, so prep it
// for binding
Polymer.Bind.prepareModel(proto);
Polymer.Base.prepareModelNotifyPath(proto);
}
// Create accessors for each parent prop that forward the property
// to template instances through abstract _forwardParentProp API
Expand All @@ -241,10 +243,10 @@
// Instance setup
if (template != this) {
Polymer.Bind.prepareInstance(template);
template._forwardParentProp =
this._forwardParentProp.bind(this);
template._forwardParentProp = this._forwardParentProp.bind(this);
}
this._extendTemplate(template, proto);
template._pathEffector = this._pathEffectorImpl.bind(this);
}
},

Expand All @@ -257,7 +259,7 @@
_createHostPropEffector: function(prop) {
var prefix = this._parentPropPrefix;
return function(source, value) {
this.dataHost[prefix + prop] = value;
this.dataHost._templatized[prefix + prop] = value;
};
},

Expand Down Expand Up @@ -297,18 +299,19 @@
// Call extension point for Templatizer sub-classes
dataHost._forwardInstancePath.call(dataHost, this, path, value);
if (root in dataHost._parentProps) {
dataHost.notifyPath(dataHost._parentPropPrefix + path, value);
dataHost._templatized.notifyPath(dataHost._parentPropPrefix + path, value);
}
},

// Overrides Base notify-path module
_pathEffector: function(path, value, fromAbove) {
_pathEffectorImpl: function(path, value, fromAbove) {
if (this._forwardParentPath) {
if (path.indexOf(this._parentPropPrefix) === 0) {
this._forwardParentPath(path.substring(8), value);
var subPath = path.substring(this._parentPropPrefix.length);
this._forwardParentPath(subPath, value);
}
}
Polymer.Base._pathEffector.apply(this, arguments);
Polymer.Base._pathEffector.call(this._templatized, path, value, fromAbove);
},

_constructorImpl: function(model, host) {
Expand Down Expand Up @@ -383,8 +386,9 @@
stamp: function(model) {
model = model || {};
if (this._parentProps) {
var templatized = this._templatized;
for (var prop in this._parentProps) {
model[prop] = this[this._parentPropPrefix + prop];
model[prop] = templatized[this._parentPropPrefix + prop];
}
}
return new this.ctor(model, this);
Expand Down
21 changes: 21 additions & 0 deletions src/standard/notify-path.html
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,27 @@
this._notifySplice(array, path, 0, args.length, []);
}
return ret;
},

// TODO(kschaaf): This is the path analogue to Polymer.Bind.prepareModel,
// which provides API for path-based notification on elements with property
// effects; this should be re-factored along with the Bind lib, either all on
// Base or all in Bind (see issue https://github.com/Polymer/polymer/issues/2547).
prepareModelNotifyPath: function(model) {
this.mixin(model, {
fire: Polymer.Base.fire,
notifyPath: Polymer.Base.notifyPath,
_EVENT_CHANGED: Polymer.Base._EVENT_CHANGED,
_notifyPath: Polymer.Base._notifyPath,
_pathEffector: Polymer.Base._pathEffector,
_annotationPathEffect: Polymer.Base._annotationPathEffect,
_complexObserverPathEffect: Polymer.Base._complexObserverPathEffect,
_annotatedComputationPathEffect: Polymer.Base._annotatedComputationPathEffect,
_computePathEffect: Polymer.Base._computePathEffect,
_modelForPath: Polymer.Base._modelForPath,
_pathMatchesEffect: Polymer.Base._pathMatchesEffect,
_notifyBoundPaths: Polymer.Base._notifyBoundPaths
});
}

});
Expand Down
1 change: 1 addition & 0 deletions test/runner.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
'unit/styling-cross-scope-unknown-host.html',
'unit/custom-style.html',
'unit/dynamic-import.html',
'unit/templatizer.html',
'unit/dom-repeat.html',
'unit/dom-if.html',
'unit/dom-bind.html',
Expand Down
221 changes: 221 additions & 0 deletions test/unit/templatizer-elements.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
<dom-module id="x-host">
<template>

<x-templatizer obj="{{objA}}" prop="{{propA}}" id="templatizer">
<template>
<x-child id="childA"
outer-prop="{{outerProp}}"
outer-obj="{{outerObj}}"
outer-obj-prop="{{outerObj.prop}}"
prop="{{prop}}"
obj="{{obj}}"
obj-prop="{{obj.prop}}"
></x-child>
</template>
</x-templatizer>

<template is="x-templatizee" obj="{{objB}}" prop="{{propB}}" id="templatizee">
<x-child id="childB"
outer-prop="{{outerProp}}"
outer-obj="{{outerObj}}"
outer-obj-prop="{{outerObj.prop}}"
prop="{{prop}}"
obj="{{obj}}"
obj-prop="{{obj.prop}}"
></x-child>
</template>

</template>
</dom-module>

<script>
Polymer({
is: 'x-child',
properties: {
outerProp: {
notify: true
},
outerObj: {
notify: true
},
outerObjProp: {
notify: true
},
prop: {
notify: true
},
obj: {
notify: true
},
objProp: {
notify: true
}
},
observers: [
'objChanged(obj.*)',
'outerObjChanged(outerObj.*)'
],
objChanged: function() {},
outerObjChanged: function() {}
});

Polymer({
is: 'x-templatizer',
behaviors: [Polymer.Templatizer],
properties: {
obj: {
notify: true
},
prop: {
notify: true,
observer: 'propChanged'
}
},
observers: [
'objChanged(obj.*)'
],
_instanceProps: {
obj: true,
prop: true
},
propChanged: function(value) {
this._forwardParentProp('prop', value);
},
objChanged: function(info) {
if (info.path == 'obj') {
this._forwardParentProp('obj', info.value);
} else {
this._forwardParentPath(info.path, info.value);
}
},
_forwardParentProp: function(prop, value) {
if (this.instance) {
this.instance[prop] = value;
}
},
_forwardParentPath: function(path, value) {
if (this.instance) {
this.instance.notifyPath(path, value, true);
}
},
_forwardInstanceProp: function(inst, prop, value) {
if (prop == 'obj') {
this.obj = value;
} else if (prop == 'prop') {
this.prop = value;
}
},
_forwardInstancePath: function(inst, path, value) {
if ((path.indexOf('obj.') === 0) || (path.indexOf('prop.') === 0)) {
this.notifyPath(path, value);
}
},
go: function() {
var template = Polymer.dom(this).querySelector('template');
this.templatize(template);
this.instance = this.stamp({obj: this.obj, prop: this.prop});
var parent = Polymer.dom(this).parentNode;
Polymer.dom(parent).appendChild(this.instance.root);
}
});

Polymer({
is: 'x-templatizee',
extends: 'template',
behaviors: [Polymer.Templatizer],
properties: {
obj: {
notify: true
},
prop: {
notify: true,
observer: 'propChanged'
}
},
observers: [
'objChanged(obj.*)'
],
_instanceProps: {
obj: true,
prop: true
},
propChanged: function(value) {
this._forwardParentProp('prop', value);
},
objChanged: function(info) {
if (info.path == 'obj') {
this._forwardParentProp('obj', info.value);
} else {
this._forwardParentPath(info.path, info.value);
}
},
_forwardParentProp: function(prop, value) {
if (this.instance) {
this.instance[prop] = value;
}
},
_forwardParentPath: function(path, value) {
if (this.instance) {
this.instance.notifyPath(path, value, true);
}
},
_forwardInstanceProp: function(inst, prop, value) {
if (prop == 'obj') {
this.obj = value;
} else if (prop == 'prop') {
this.prop = value;
}
},
_forwardInstancePath: function(inst, path, value) {
if ((path.indexOf('obj.') === 0) || (path.indexOf('prop.') === 0)) {
this.notifyPath(path, value);
}
},
go: function() {
this.templatize(this);
this.instance = this.stamp({obj: this.obj, prop: this.prop});
var parent = Polymer.dom(this).parentNode;
Polymer.dom(parent).appendChild(this.instance.root);
}
});

Polymer({
is: 'x-host',
properties: {
outerProp: {
value: 'outerProp'
},
outerObj: {
value: function() {
return { prop: 'outerObj.prop' };
}
},
propA: {
value: 'prop-a'
},
objA: {
value: function() {
return { prop: 'objA.prop' };
}
},
propB: {
value: 'prop-b'
},
objB: {
value: function() {
return { prop: 'objB.prop' };
}
}
},
observers: [
'outerObjChanged(outerObj.*)',
'objAChanged(objA.*)',
'objBChanged(objB.*)'
],
outerObjChanged: function() {},
objAChanged: function() {},
objBChanged: function() {}
});

</script>

Loading

0 comments on commit 0657dfe

Please sign in to comment.