diff --git a/src/lib/template/templatizer.html b/src/lib/template/templatizer.html index 82be23f30d..9aea9bd52a 100644 --- a/src/lib/template/templatizer.html +++ b/src/lib/template/templatizer.html @@ -120,7 +120,7 @@ archetype._prepBindings(); // boilerplate code - archetype._notifyPathUp = this._notifyPathUpImpl; + archetype._notifyPathUp = function() {}; archetype._scopeElementClass = this._scopeElementClassImpl; archetype.listen = this._listenImpl; archetype._showHideChildren = this._showHideChildrenImpl; @@ -193,7 +193,7 @@ } for (prop in this._instanceProps) { archetype._addPropertyEffect(prop, 'function', - this._createInstancePropEffector(prop)); + this._createInstancePropEffector()); } }, @@ -215,13 +215,14 @@ archetype._parentProps = c._parentProps; }, - // Sets up accessors on the template to call abstract _forwardParentProp - // API that should be implemented by Templatizer users to get parent - // properties to their template instances. These accessors are memoized - // on the archetype and copied to instances. + // Sets up accessors on the template to call abstract + // _forwardParentProp/Path API that should be implemented by Templatizer + // users to get parent properties to their template instances. These + // accessors are memoized on the archetype and copied to instances. _prepParentProperties: function(archetype, template) { var parentProps = this._parentProps = archetype._parentProps; - if (this._forwardParentProp && parentProps) { + if ((this._forwardParentProp || this._forwardParentPath) && + parentProps) { // Prototype setup (memoized on archetype) var proto = archetype._parentPropProto; var prop; @@ -229,9 +230,9 @@ for (prop in this._instanceProps) { delete parentProps[prop]; } - // Create accessors for each parent prop that forward the property - // to template instances through abstract _forwardParentProp API - // that should be implemented by Templatizer users + // Create accessors for each parent prop that forward the property to + // template instances through abstract _forwardParentProp/Path API + // that should be implemented by Templatizer users. var propertyEffects = this.mixin({}, this._propertyEffects); var propertyInfo = this.mixin({}, this._propertyInfo); var prefixedParentProps = {}; @@ -242,7 +243,8 @@ var effects = [{ kind: 'function', effect: this._createForwardPropEffector(prop), - fn: Polymer.Bind._functionEffect + fn: Polymer.Bind._functionEffect, + pathFn: this._functionPathEffect }, { kind: 'notify', fn: Polymer.Bind._notifyEffect, @@ -266,36 +268,59 @@ Polymer.Bind.prepareModel(template); Polymer.Base.prepareModelNotifyPath(template); Polymer.Bind.prepareInstance(template); - template._forwardParentProp = function(source, value) { - self._forwardParentProp(source, value); + if (self._forwardParentProp) { + template._forwardParentProp = function(prop, value) { + self._forwardParentProp(prop, value); + } + } + if (self._forwardParentPath) { + template._forwardParentPath = function(path, value) { + self._forwardParentPath(path, value); + } } } this._extendTemplate(template, proto); - template._pathEffector = function(path, value, fromAbove) { - return self._pathEffectorImpl(path, value, fromAbove); - } } }, + _createForwardPropEffector: function(prop) { - return function(source, value) { - this._forwardParentProp(prop, value); + var prefixLength = this._parentPropPrefix.length; + return function(path, value) { + if (path.indexOf('.') !== -1) { + if (this._forwardParentPath) { + var newPath = path.slice(prefixLength); + this._forwardParentPath(newPath, value); + } + } else if (this._forwardParentProp) { + this._forwardParentProp(prop, value); + } }; }, _createHostPropEffector: function(prop) { var prefix = this._parentPropPrefix; - return function(source, value) { - if (source !== prop) return; - this.dataHost._templatized.__setProperty(prefix + prop, value); + var prefixedProp = prefix + prop; + return function(path, value, old, fromAbove) { + if (!fromAbove) { + var dataHost = this.dataHost; + if (path.indexOf('.') !== -1) { + dataHost._templatized._notifyPath(prefix + path, value, false); + } else { + dataHost._templatized.__setProperty(prefixedProp, value, false); + } + } }; }, - _createInstancePropEffector: function(prop) { - return function(source, value, old, fromAbove) { - if (source !== prop) return; + _createInstancePropEffector: function() { + return function(path, value, old, fromAbove) { if (!fromAbove) { - this.dataHost._forwardInstanceProp(this, prop, value); + if (path.indexOf('.') !== -1) { + this.dataHost._forwardInstancePath(this, path, value); + } else { + this.dataHost._forwardInstanceProp(this, path, value); + } } }; }, @@ -321,31 +346,6 @@ // _forwardParentProp: function(prop, value) { }, /* eslint-enable no-unused-vars */ - _notifyPathUpImpl: function(path, value) { - var dataHost = this.dataHost; - var dot = path.indexOf('.'); - var root = dot < 0 ? path : path.slice(0, dot); - // Call extension point for Templatizer sub-classes - dataHost._forwardInstancePath.call(dataHost, this, path, value); - if (root in dataHost._parentProps) { - dataHost._templatized._notifyPath(dataHost._parentPropPrefix + path, value); - } - }, - - // Overrides Base notify-path module - _pathEffectorImpl: function(path, value, fromAbove) { - if (this._forwardParentPath) { - if (path.indexOf(this._parentPropPrefix) === 0) { - var subPath = path.substring(this._parentPropPrefix.length); - var model = this._modelForPath(subPath); - if (model in this._parentProps) { - this._forwardParentPath(subPath, value); - } - } - } - Polymer.Base._pathEffector.call(this._templatized, path, value, fromAbove); - }, - _constructorImpl: function(model, host) { this._rootDataHost = host._getRootDataHost(); this._setupConfigure(model); diff --git a/src/standard/notify-path.html b/src/standard/notify-path.html index 0b4e416c32..2931cd918a 100644 --- a/src/standard/notify-path.html +++ b/src/standard/notify-path.html @@ -98,7 +98,7 @@ // console.group((this.localName || this.dataHost.id + '-' + this.dataHost.dataHost.index) + '#' + (this.id || this.index) + ' ' + path, value); // Take path effects at this level for exact path matches, // and notify down for any bindings to a subset of this path - this._pathEffector(path, value); + this._pathEffector(path, value, fromAbove); // Send event to notify the path change upwards // Optimization: don't notify up if we know the notification // is coming from above already (avoid wasted event dispatch) @@ -267,7 +267,7 @@ return prop; }, - _pathEffector: function(path, value) { + _pathEffector: function(path, value, fromAbove) { // get root property var model = this._modelForPath(path); // search property effects of the root property for 'annotation' effects @@ -278,7 +278,7 @@ // use memoized path functions var fxFn = fx.pathFn; if (fxFn) { - fxFn.call(this, path, value, fx.effect); + fxFn.call(this, path, value, fx.effect, fromAbove); } } } @@ -322,8 +322,9 @@ } }, - _functionPathEffect: function(path, value, effect) { - Polymer.Bind._functionEffect.call(this, path, value, effect); + _functionPathEffect: function(path, value, effect, fromAbove) { + Polymer.Bind._functionEffect.call(this, path, value, effect, + undefined, fromAbove); }, _pathMatchesEffect: function(path, effect) {