mirror of
https://github.com/Polymer/polymer.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #3358 from kaste/computed-bound-methods
Support dynamic functions for computed annotations.
This commit is contained in:
commit
333f082609
@ -66,6 +66,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
if (args) {
|
if (args) {
|
||||||
fn.apply(this, args);
|
fn.apply(this, args);
|
||||||
}
|
}
|
||||||
|
} else if (effect.dynamicFn) {
|
||||||
|
// dynamic functions can be just like every other property `undefined`
|
||||||
|
// so we MUST ignore an undefined value here. (That's totally the
|
||||||
|
// same guard we use within `_marshalArgs` and part of the spec.)
|
||||||
} else {
|
} else {
|
||||||
this._warn(this._logf('_complexObserverEffect', 'observer method `' +
|
this._warn(this._logf('_complexObserverEffect', 'observer method `' +
|
||||||
effect.method + '` not defined'));
|
effect.method + '` not defined'));
|
||||||
@ -73,15 +77,20 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
},
|
},
|
||||||
|
|
||||||
_computeEffect: function(source, value, effect) {
|
_computeEffect: function(source, value, effect) {
|
||||||
var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
|
var fn = this[effect.method];
|
||||||
if (args) {
|
if (fn) {
|
||||||
var fn = this[effect.method];
|
var args = Polymer.Bind._marshalArgs(this.__data__, effect, source, value);
|
||||||
if (fn) {
|
if (args) {
|
||||||
this.__setProperty(effect.name, fn.apply(this, args));
|
var computedvalue = fn.apply(this, args);
|
||||||
} else {
|
this.__setProperty(effect.name, computedvalue);
|
||||||
this._warn(this._logf('_computeEffect', 'compute method `' +
|
|
||||||
effect.method + '` not defined'));
|
|
||||||
}
|
}
|
||||||
|
} else if (effect.dynamicFn) {
|
||||||
|
// dynamic functions can be just like every other property `undefined`
|
||||||
|
// so we MUST ignore an undefined value here. (That's totally the
|
||||||
|
// same guard we use within `_marshalArgs` and part of the spec.)
|
||||||
|
} else {
|
||||||
|
this._warn(this._logf('_computeEffect', 'compute method `' +
|
||||||
|
effect.method + '` not defined'));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -97,6 +106,10 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
}
|
}
|
||||||
this._applyEffectValue(effect, computedvalue);
|
this._applyEffectValue(effect, computedvalue);
|
||||||
}
|
}
|
||||||
|
} else if (effect.dynamicFn) {
|
||||||
|
// dynamic functions can be just like every other property `undefined`
|
||||||
|
// so we MUST ignore an undefined value here. (That's totally the
|
||||||
|
// same guard we use within `_marshalArgs` and part of the spec.)
|
||||||
} else {
|
} else {
|
||||||
computedHost._warn(computedHost._logf('_annotatedComputationEffect',
|
computedHost._warn(computedHost._logf('_annotatedComputationEffect',
|
||||||
'compute method `' + effect.method + '` not defined'));
|
'compute method `' + effect.method + '` not defined'));
|
||||||
@ -108,6 +121,9 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
_marshalArgs: function(model, effect, path, value) {
|
_marshalArgs: function(model, effect, path, value) {
|
||||||
var values = [];
|
var values = [];
|
||||||
var args = effect.args;
|
var args = effect.args;
|
||||||
|
// Actually we should return early as soon as we see an `undefined`,
|
||||||
|
// but dom-repeat relies on this behavior.
|
||||||
|
var bailoutEarly = (args.length > 1 || effect.dynamicFn);
|
||||||
for (var i=0, l=args.length; i<l; i++) {
|
for (var i=0, l=args.length; i<l; i++) {
|
||||||
var arg = args[i];
|
var arg = args[i];
|
||||||
var name = arg.name;
|
var name = arg.name;
|
||||||
@ -119,7 +135,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
} else {
|
} else {
|
||||||
v = model[name];
|
v = model[name];
|
||||||
}
|
}
|
||||||
if (args.length > 1 && v === undefined) {
|
if (bailoutEarly && v === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (arg.wildcard) {
|
if (arg.wildcard) {
|
||||||
|
@ -145,8 +145,10 @@ TODO(sjmiles): this module should produce either syntactic metadata
|
|||||||
for (var k=0; k<b.parts.length; k++) {
|
for (var k=0; k<b.parts.length; k++) {
|
||||||
var p = b.parts[k];
|
var p = b.parts[k];
|
||||||
if (!p.literal) {
|
if (!p.literal) {
|
||||||
p.signature = this._parseMethod(p.value);
|
var signature = this._parseMethod(p.value);
|
||||||
if (!p.signature) {
|
if (signature) {
|
||||||
|
p.signature = signature;
|
||||||
|
} else {
|
||||||
p.model = this._modelForPath(p.value);
|
p.model = this._modelForPath(p.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,14 +79,27 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
|
|
||||||
_addComputedEffect: function(name, expression) {
|
_addComputedEffect: function(name, expression) {
|
||||||
var sig = this._parseMethod(expression);
|
var sig = this._parseMethod(expression);
|
||||||
|
|
||||||
|
var dynamicFn = sig.dynamicFn;
|
||||||
|
|
||||||
for (var i=0, arg; (i<sig.args.length) && (arg=sig.args[i]); i++) {
|
for (var i=0, arg; (i<sig.args.length) && (arg=sig.args[i]); i++) {
|
||||||
this._addPropertyEffect(arg.model, 'compute', {
|
this._addPropertyEffect(arg.model, 'compute', {
|
||||||
method: sig.method,
|
method: sig.method,
|
||||||
args: sig.args,
|
args: sig.args,
|
||||||
trigger: arg,
|
trigger: arg,
|
||||||
name: name
|
name: name,
|
||||||
|
dynamicFn: dynamicFn
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (dynamicFn) {
|
||||||
|
this._addPropertyEffect(sig.method, 'compute', {
|
||||||
|
method: sig.method,
|
||||||
|
args: sig.args,
|
||||||
|
trigger: null,
|
||||||
|
name: name,
|
||||||
|
dynamicFn: dynamicFn
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_addObserverEffect: function(property, observer) {
|
_addObserverEffect: function(property, observer) {
|
||||||
@ -111,11 +124,22 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
throw new Error("Malformed observer expression '" + observer + "'");
|
throw new Error("Malformed observer expression '" + observer + "'");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var dynamicFn = sig.dynamicFn;
|
||||||
|
|
||||||
for (var i=0, arg; (i<sig.args.length) && (arg=sig.args[i]); i++) {
|
for (var i=0, arg; (i<sig.args.length) && (arg=sig.args[i]); i++) {
|
||||||
this._addPropertyEffect(arg.model, 'complexObserver', {
|
this._addPropertyEffect(arg.model, 'complexObserver', {
|
||||||
method: sig.method,
|
method: sig.method,
|
||||||
args: sig.args,
|
args: sig.args,
|
||||||
trigger: arg
|
trigger: arg,
|
||||||
|
dynamicFn: dynamicFn
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (dynamicFn) {
|
||||||
|
this._addPropertyEffect(sig.method, 'complexObserver', {
|
||||||
|
method: sig.method,
|
||||||
|
args: sig.args,
|
||||||
|
trigger: null,
|
||||||
|
dynamicFn: dynamicFn
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -171,6 +195,14 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
arg);
|
arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sig.dynamicFn) {
|
||||||
|
// trigger=null is sufficient as long as we don't allow paths to be
|
||||||
|
// used. If we change our mind, we must first implement this in the
|
||||||
|
// effects anyway where we basically do a `fn = this[methodName]` at
|
||||||
|
// the moment.
|
||||||
|
this.__addAnnotatedComputationEffect(
|
||||||
|
sig.method, index, note, part, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -184,7 +216,8 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
negate: part.negate,
|
negate: part.negate,
|
||||||
method: part.signature.method,
|
method: part.signature.method,
|
||||||
args: part.signature.args,
|
args: part.signature.args,
|
||||||
trigger: trigger
|
trigger: trigger,
|
||||||
|
dynamicFn: part.signature.dynamicFn
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -194,6 +227,11 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|||||||
var m = expression.match(/([^\s]+?)\(([\s\S]*)\)/);
|
var m = expression.match(/([^\s]+?)\(([\s\S]*)\)/);
|
||||||
if (m) {
|
if (m) {
|
||||||
var sig = { method: m[1], static: true };
|
var sig = { method: m[1], static: true };
|
||||||
|
// TODO(kaste): Optimize/memoize `getPropertyInfo`.
|
||||||
|
if (this.getPropertyInfo(sig.method) !== Polymer.nob) {
|
||||||
|
sig.static = false;
|
||||||
|
sig.dynamicFn = true;
|
||||||
|
}
|
||||||
if (m[2].trim()) {
|
if (m[2].trim()) {
|
||||||
// replace escaped commas with comma entity, split on un-escaped commas
|
// replace escaped commas with comma entity, split on un-escaped commas
|
||||||
var args = m[2].replace(/\\,/g, ',').split(',');
|
var args = m[2].replace(/\\,/g, ',').split(',');
|
||||||
|
@ -588,3 +588,73 @@
|
|||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
</dom-module>
|
</dom-module>
|
||||||
|
|
||||||
|
<dom-module id="x-bind-computed-property">
|
||||||
|
<template>
|
||||||
|
<div id="check">[[translate('Hello World.')]]</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
(function(){
|
||||||
|
var TranslateBehavior = {
|
||||||
|
properties: {
|
||||||
|
translate: {
|
||||||
|
type: Function,
|
||||||
|
computed: '_computeTranslateFn(translator)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Polymer({
|
||||||
|
is: 'x-bind-computed-property',
|
||||||
|
behaviors: [TranslateBehavior],
|
||||||
|
properties: {
|
||||||
|
translator: {
|
||||||
|
type: Function,
|
||||||
|
value: function() {
|
||||||
|
return function(message) {
|
||||||
|
return 'translated: ' + message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
_computeTranslateFn: function(translator) {
|
||||||
|
return function(message) {
|
||||||
|
return translator(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</dom-module>
|
||||||
|
|
||||||
|
<dom-module id="x-bind-computed-property-late-translator">
|
||||||
|
<template>
|
||||||
|
<div id="check">[[translate(message)]]</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
Polymer({
|
||||||
|
is: 'x-bind-computed-property-late-translator',
|
||||||
|
properties: {
|
||||||
|
message: {
|
||||||
|
type: String,
|
||||||
|
value: 'Hello'
|
||||||
|
},
|
||||||
|
translate: {
|
||||||
|
type: Function,
|
||||||
|
computed: '_computeTranslateFn(translator)'
|
||||||
|
},
|
||||||
|
translator: {
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
_computeTranslateFn: function(translator) {
|
||||||
|
return function(message) {
|
||||||
|
return translator(message);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</dom-module>
|
@ -285,6 +285,107 @@ suite('single-element binding effects', function() {
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
suite('computed bindings with dynamic functions', function() {
|
||||||
|
|
||||||
|
var el;
|
||||||
|
|
||||||
|
setup(function() {
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
teardown(function() {
|
||||||
|
document.body.removeChild(el);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('annotated computation with dynamic function', function() {
|
||||||
|
el = document.createElement('x-bind-computed-property');
|
||||||
|
document.body.appendChild(el);
|
||||||
|
|
||||||
|
assert.equal(el.$.check.textContent, 'translated: Hello World.');
|
||||||
|
|
||||||
|
el.translator = function(message) {
|
||||||
|
return 'changed: ' + message;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.equal(el.$.check.textContent, 'changed: Hello World.');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('annotated computation / late resolved dynamic function', function() {
|
||||||
|
el = document.createElement('x-bind-computed-property-late-translator');
|
||||||
|
document.body.appendChild(el);
|
||||||
|
|
||||||
|
assert.equal(el.$.check.textContent.trim(), '');
|
||||||
|
|
||||||
|
el.translator = function(message) {
|
||||||
|
return 'translated: ' + message;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.equal(el.$.check.textContent, 'translated: Hello');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('observer with dynamic function', function() {
|
||||||
|
Polymer({
|
||||||
|
is: 'x-observer-with-dynamic-function',
|
||||||
|
properties: {
|
||||||
|
translate: {
|
||||||
|
type: Function,
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
type: String,
|
||||||
|
value: 'Hello'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
observers: ['translate(message)'],
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
el = document.createElement('x-observer-with-dynamic-function');
|
||||||
|
document.body.appendChild(el);
|
||||||
|
|
||||||
|
var called = 0;
|
||||||
|
el.translate = function() {
|
||||||
|
called += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.equal(called, 1);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
test('computed property with dynamic function', function() {
|
||||||
|
Polymer({
|
||||||
|
is: 'x-computed-property-with-dynamic-function',
|
||||||
|
properties: {
|
||||||
|
computedValue: {
|
||||||
|
computed: "translate('Hello')"
|
||||||
|
},
|
||||||
|
translate: {
|
||||||
|
type: Function
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
el = document.createElement('x-computed-property-with-dynamic-function');
|
||||||
|
document.body.appendChild(el);
|
||||||
|
|
||||||
|
assert.equal(el.computedValue, undefined);
|
||||||
|
|
||||||
|
var called = 0;
|
||||||
|
el.translate = function(message) {
|
||||||
|
called += 1;
|
||||||
|
return 'translated: ' + message;
|
||||||
|
};
|
||||||
|
|
||||||
|
assert.equal(called, 1);
|
||||||
|
assert.equal(el.computedValue, 'translated: Hello');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script>
|
||||||
suite('2-way binding effects between elements', function() {
|
suite('2-way binding effects between elements', function() {
|
||||||
|
|
||||||
var el;
|
var el;
|
||||||
|
Loading…
Reference in New Issue
Block a user