can-stache-bindings
Advanced tools
Comparing version 3.6.3 to 3.7.0
@@ -390,2 +390,10 @@ // # can-stache-bindings.js | ||
// check for `on:event:value:to` type things and call data bindings | ||
if(attributeName.indexOf(toMatchStr+":") !== -1 || | ||
attributeName.indexOf(fromMatchStr+":") !== -1 || | ||
attributeName.indexOf(bindMatchStr+":") !== -1 | ||
) { | ||
return this.data(el, data); | ||
} | ||
// legacy binding | ||
@@ -655,5 +663,12 @@ if(startsWith.call(attributeName, 'can-')) { | ||
viewCallbacks.attr(/^(:lb:)[(:c:)\w-]+(:rb:)$/, behaviors.data); | ||
viewCallbacks.attr(/[\w\.:]+:to/, behaviors.data); | ||
viewCallbacks.attr(/[\w\.:]+:from/, behaviors.data); | ||
viewCallbacks.attr(/[\w\.:]+:bind/, behaviors.data); | ||
// value:to="bar" data bindings | ||
// these are separate so that they only capture at the end | ||
// to avoid (toggle)="bar" which is encoded as :lp:toggle:rp:="bar" | ||
viewCallbacks.attr(/[\w\.:]+:to$/, behaviors.data); | ||
viewCallbacks.attr(/[\w\.:]+:from$/, behaviors.data); | ||
viewCallbacks.attr(/[\w\.:]+:bind$/, behaviors.data); | ||
// value:to:on:input="bar" data bindings | ||
viewCallbacks.attr(/[\w\.:]+:to:on:[\w\.:]+/, behaviors.data); | ||
viewCallbacks.attr(/[\w\.:]+:from:on:[\w\.:]+/, behaviors.data); | ||
viewCallbacks.attr(/[\w\.:]+:bind:on:[\w\.:]+/, behaviors.data); | ||
@@ -899,6 +914,56 @@ // `*ref-export` shorthand. | ||
}; | ||
var endsWith = String.prototype.endsWith || function(text){ | ||
var lastIndex = this.lastIndexOf(text); | ||
return lastIndex !== -1 && lastIndex === (this.length - text.length); | ||
// Gets an event name in the after part. | ||
function getEventName(result) { | ||
if(result.special.on !== undefined) { | ||
return result.tokens[result.special.on+1]; | ||
} | ||
} | ||
var bindingRules = { | ||
to: { | ||
childToParent: true, | ||
parentToChild: false, | ||
syncChildWithParent: false | ||
}, | ||
from: { | ||
childToParent: false, | ||
parentToChild: true, | ||
syncChildWithParent: false, | ||
}, | ||
bind: { | ||
childToParent: true, | ||
parentToChild: true, | ||
syncChildWithParent: true, | ||
} | ||
}; | ||
var bindingNames = []; | ||
var special = { | ||
vm: true, | ||
on: true | ||
}; | ||
each(bindingRules, function(value, key){ | ||
bindingNames.push(key); | ||
special[key] = true; | ||
}); | ||
// "on:click:value:to" //-> {tokens: [...], special: {on: 0, to: 3}} | ||
function tokenize(source) { | ||
var splitByColon = source.split(":"); | ||
// combine tokens that are not to, from, vm, | ||
var result = { | ||
tokens: [], | ||
special: {} | ||
}; | ||
splitByColon.forEach(function(token){ | ||
if(special[token]) { | ||
result.special[token] = result.tokens.push(token) - 1; | ||
} else { | ||
result.tokens.push(token); | ||
} | ||
}); | ||
return result; | ||
} | ||
// Regular expressions for getBindingInfo | ||
@@ -911,2 +976,13 @@ var bindingsRegExp = /\{(\()?(\^)?([^\}\)]+)\)?\}/, | ||
// ## getChildBindingStr | ||
var getChildBindingStr = function(tokens, favorViewModel) { | ||
if (tokens.indexOf('vm') >= 0) { | ||
return viewModelBindingStr; | ||
} else if (tokens.indexOf('el') >= 0) { | ||
return attributeBindingStr; | ||
} else { | ||
return favorViewModel ? viewModelBindingStr: viewModelOrAttributeBindingStr; | ||
} | ||
}; | ||
// ## getBindingInfo | ||
@@ -926,3 +1002,2 @@ // takes a node object like {name, value} and returns | ||
var getBindingInfo = function(node, attributeViewModelBindings, templateType, tagName, favorViewModel) { | ||
var bindingInfo, | ||
@@ -933,44 +1008,31 @@ attributeName = encoder.decode( node.name ), | ||
// check new binding syntaxes | ||
if(endsWith.call(attributeName, fromMatchStr)) { | ||
childName = attributeName.substr(0, attributeName.length - fromMatchStr.length); | ||
return { | ||
// START: check new binding syntaxes ====== | ||
var result = tokenize(attributeName), | ||
dataBindingName, | ||
specialIndex; | ||
// check if there's a match of a binding name with at least a value before it | ||
bindingNames.forEach(function(name){ | ||
if(result.special[name] !== undefined && result.special[name] > 0) { | ||
dataBindingName = name; | ||
specialIndex = result.special[name]; | ||
return false; | ||
} | ||
}); | ||
if(dataBindingName) { | ||
return assign({ | ||
parent: scopeBindingStr, | ||
child: favorViewModel ? viewModelBindingStr: viewModelOrAttributeBindingStr, | ||
childToParent: false, | ||
parentToChild: true, | ||
child: getChildBindingStr(result.tokens, favorViewModel), | ||
// the child is going to be the token before the special location | ||
childName: result.tokens[specialIndex-1], | ||
childEvent: getEventName(result), | ||
bindingAttributeName: attributeName, | ||
childName: decodeAttrName(string.camelize(childName)), | ||
parentName: attributeValue, | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}; | ||
} else if(endsWith.call(attributeName, toMatchStr)) { | ||
childName = attributeName.substr(0, attributeName.length - toMatchStr.length); | ||
return { | ||
parent: scopeBindingStr, | ||
child: favorViewModel ? viewModelBindingStr: viewModelOrAttributeBindingStr, | ||
childToParent: true, | ||
parentToChild: false, | ||
bindingAttributeName: attributeName, | ||
childName: decodeAttrName(string.camelize(childName)), | ||
parentName: attributeValue, | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}; | ||
} else if(endsWith.call(attributeName, bindMatchStr)) { | ||
childName = attributeName.substr(0, attributeName.length - bindMatchStr.length); | ||
return { | ||
parent: scopeBindingStr, | ||
child: favorViewModel ? viewModelBindingStr: viewModelOrAttributeBindingStr, | ||
childToParent: true, | ||
parentToChild: true, | ||
bindingAttributeName: attributeName, | ||
childName: decodeAttrName(string.camelize(childName)), | ||
parentName: attributeValue, | ||
initializeValues: true, | ||
syncChildWithParent: true | ||
}; | ||
initializeValues: true | ||
}, bindingRules[dataBindingName]); | ||
} | ||
// END: check new binding syntaxes ====== | ||
// Does this match the new binding syntax? | ||
@@ -1107,3 +1169,4 @@ var matches = attributeName.match(bindingsRegExp); | ||
bindingInfo.parentName, | ||
bindingData, bindingInfo.parentToChild | ||
bindingData, | ||
bindingInfo.parentToChild | ||
), | ||
@@ -1116,3 +1179,4 @@ childObservable = getObservableFrom[bindingInfo.child]( | ||
bindingInfo.childToParent, | ||
bindingInfo.stickyParentToChild && parentObservable | ||
bindingInfo.stickyParentToChild && parentObservable, | ||
bindingInfo.childEvent | ||
), | ||
@@ -1119,0 +1183,0 @@ // these are the functions bound to one compute that update the other. |
@@ -60,2 +60,4 @@ @module can-stache-bindings | ||
You can also explicitly use the [can-component::ViewModel ViewModel] using `vm:childProp:from="value"` or the element using `el:child-attr:from="value"`. | ||
> __Note:__ If value being passed to the component is an object, changes to the objects properties will still be visible to the component. Objects are passed by reference. See [can-stache-bindings#OneWayBindingWithObjects One Way Binding With Objects]. | ||
@@ -81,2 +83,4 @@ | ||
You can also explicitly use the [can-component::ViewModel ViewModel] using `vm:childProp:to="value"` or the element using `el:child-attr:to="value"`. | ||
> __Note:__ If value being passed to the component is an object, changes to the objects properties will still be visible to the component. Objects are passed by reference. See [can-stache-bindings#OneWayBindingWithObjects One Way Binding With Objects]. | ||
@@ -99,2 +103,4 @@ | ||
You can also explicitly use the [can-component::ViewModel ViewModel] using `vm:childProp:bind="value"` or the element using `el:child-attr:bind="value"`. | ||
## One Way Binding With Objects | ||
@@ -101,0 +107,0 @@ |
@@ -67,3 +67,45 @@ @function can-stache-bindings.event on:event | ||
@signature `on:SCOPE_EVENT:by:this='CALL_EXPRESSION'` | ||
Listens to an event on the [can-view-scope scope] and calls the [can-stache/expressions/call] when that event occurs. | ||
``` | ||
<my-component on:show:by:this="doSomething()"/> | ||
``` | ||
@param {String} SCOPE_EVENT a scope event. | ||
@param {can-stache.expressions} CALL_EXPRESSION A call expression like `method(key)` that is called when the `VIEW_MODEL_EVENT` | ||
is fired. The following key values are also supported: | ||
- `%element` - The element the event happened upon. | ||
- `%event` - The event object. | ||
- `%viewModel` - If the element is a [can-component], the component’s [can-component::ViewModel ViewModel]. | ||
- `%context` - The current context. | ||
- `%scope` - The current [can-view-scope]. | ||
- `%arguments` - The arguments passed when the event was dispatched/triggered. | ||
@signature `on:SCOPE_PROP_EVENT:by:SCOPE_PROP='CALL_EXPRESSION'` | ||
Listens to an event on a property of the [can-view-scope scope] and calls the [can-stache/expressions/call] when that event occurs. | ||
``` | ||
<my-component on:show:by:obj="doSomething()"/> | ||
``` | ||
@param {String} SCOPE_PROP_EVENT an event triggered by a scope property. | ||
@param {String} SCOPE_PROP a scope property. | ||
@param {can-stache.expressions} CALL_EXPRESSION A call expression like `method(key)` that is called when the `VIEW_MODEL_EVENT` | ||
is fired. The following key values are also supported: | ||
- `%element` - The element the event happened upon. | ||
- `%event` - The event object. | ||
- `%viewModel` - If the element is a [can-component], the component’s [can-component::ViewModel ViewModel]. | ||
- `%context` - The current context. | ||
- `%scope` - The current [can-view-scope]. | ||
- `%arguments` - The arguments passed when the event was dispatched/triggered. | ||
@body | ||
@@ -70,0 +112,0 @@ |
@function can-stache-bindings.toChild toChild:from | ||
@parent can-stache-bindings.syntaxes 1 | ||
@description One-way bind a value in the parent scope to the [can-component.prototype.ViewModel ViewModel]. | ||
@description One-way bind a value in the parent scope to the [can-component.prototype.ViewModel ViewModel] or element. | ||
@@ -35,2 +35,31 @@ @signature `childProp:from="key"` | ||
@signature `vm:childProp:from="key"` | ||
Imports [can-stache.key] in the [can-view-scope scope] to `childProp` in [can-component.prototype.view-model viewModel]. It also updates `childProp` with the value of `key` when `key` changes. | ||
``` | ||
<my-component vm:someProp:from="value"/> | ||
``` | ||
> __Note:__ If [can-stache.key] is an object, changes to the objects properties will still be visible to the component. Objects are passed by reference. See [can-stache-bindings#OneWayBindingWithObjects One Way Binding With Objects]. | ||
@param {String} childProp The name of the property to set in the | ||
component’s viewmodel. | ||
@param {can-stache/expressions/literal|can-stache/expressions/key-lookup|can-stache/expressions/call|can-stache/expressions/helper} key An expression whose resulting value is used to set as `childProp`. | ||
@signature `el:child-prop:from="key"` | ||
Imports [can-stache.key] in the [can-view-scope scope] to `child-prop` property or attribute on the element. | ||
``` | ||
<input el:value:from="name"/> | ||
``` | ||
This signature works, but the following should be used instead: | ||
``` | ||
<input value="{{name}}"/> | ||
``` | ||
@body | ||
@@ -37,0 +66,0 @@ |
@function can-stache-bindings.toParent toParent:to | ||
@parent can-stache-bindings.syntaxes 2 | ||
@description One-way bind a value in the current [can-component.prototype.view-model viewModel] to the parent scope. | ||
@description One-way bind a value from the [can-component.prototype.view-model viewModel] or element to the parent scope. | ||
@@ -35,3 +35,32 @@ @signature `childProp:to="key"` | ||
@signature `vm:childProp:to="key"` | ||
Exports `childProp` in the [can-component.prototype.ViewModel ViewModel] to [can-stache.key] in the parent [can-view-scope scope]. It also updates | ||
`key` with the value of `childProp` when `childProp` changes. | ||
``` | ||
<my-component vm:someProp:to="value"/> | ||
``` | ||
> __Note:__ If [can-stache.key] is an object, changes to the objects properties will still be visible to the component. Objects are passed by reference. See [can-stache-bindings#OneWayBindingWithObjects One Way Binding With Objects]. | ||
@param {String} childProp The name of the property to export from the | ||
child components viewmodel. Use `this:to` or `.:to` to export the entire viewModel. | ||
@param {can-stache/expressions/literal|can-stache/expressions/key-lookup|can-stache/expressions/call|can-stache/expressions/helper} key An expression that will be used to set in the parent scope. | ||
@signature `el:child-prop:to="key"` | ||
Exports the element’s `child-prop` property or attribute to [can-stache.key] in the parent [can-view-scope scope]. It also updates | ||
`key` with the value of `child-prop` when `child-prop` changes. | ||
``` | ||
<input el:value:to="name"/> | ||
``` | ||
@param {String} child-prop The name of the element’s property or attribute to export. | ||
@param {can-stache/expressions/literal|can-stache/expressions/key-lookup|can-stache/expressions/call|can-stache/expressions/helper} key An expression whose resulting value with be used to set in the parent scope. | ||
@body | ||
@@ -38,0 +67,0 @@ |
@@ -42,2 +42,38 @@ @function can-stache-bindings.twoWay twoWay:bind | ||
@signature `vm:childProp:bind="key"` | ||
Two-way binds `childProp` in the [can-component.prototype.ViewModel ViewModel] to | ||
[can-stache.key] in the parent [can-view-scope scope]. If `childProp` is updated `key` will be updated | ||
and vice-versa. | ||
``` | ||
<my-component vm:someProp:bind="value"/> | ||
``` | ||
When setting up the binding: | ||
- If `childProp` is `undefined`, `key` will be set to `childProp`. | ||
- If `key` is `undefined`, `childProp` will be set to `key`. | ||
- If both `childProp` and `key` are defined, `key` will be set to `childProp`. | ||
@param {String} childProp The name of the property of the viewModel to two-way bind. | ||
@param {can-stache/expressions/literal|can-stache/expressions/key-lookup|can-stache/expressions/call|can-stache/expressions/helper} key A call expression whose value will be used to two-way bind in the parent scope. | ||
@signature `el:child-prop:bind="key"` | ||
Two-way binds the element’s `child-prop` property or attribute to | ||
[can-stache.key] in the parent [can-view-scope scope]. If `child-prop` is updated `key` will be updated | ||
and vice-versa. | ||
``` | ||
<input el:value:bind="name"/> | ||
``` | ||
@param {String} child-prop The name of the element’s property or attribute to two-way bind. | ||
@param {can-stache/expressions/literal|can-stache/expressions/key-lookup|can-stache/expressions/call|can-stache/expressions/helper} key A call expression whose value will be used to two-way bind in the parent scope. | ||
@body | ||
@@ -44,0 +80,0 @@ |
{ | ||
"name": "can-stache-bindings", | ||
"version": "3.6.3", | ||
"version": "3.7.0", | ||
"description": "Default binding syntaxes for can-stache", | ||
@@ -5,0 +5,0 @@ "homepage": "http://canjs.com", |
@@ -146,5 +146,6 @@ var QUnit = require("steal-qunit"); | ||
child: "viewModelOrAttribute", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: false, | ||
childName: "fooEd", | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
@@ -154,3 +155,3 @@ bindingAttributeName: "foo-ed:from", | ||
syncChildWithParent: false | ||
}, "new vm binding"); | ||
}, ":from"); | ||
@@ -161,5 +162,6 @@ info = stacheBindings.getBindingInfo({name: "foo-ed:bind", value: "bar"}); | ||
child: "viewModelOrAttribute", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: true, | ||
childName: "fooEd", | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
@@ -169,3 +171,3 @@ bindingAttributeName: "foo-ed:bind", | ||
syncChildWithParent: true | ||
}, "new el binding"); | ||
}, ":bind"); | ||
@@ -176,5 +178,6 @@ info = stacheBindings.getBindingInfo({name: "foo-ed:to", value: "bar"}); | ||
child: "viewModelOrAttribute", | ||
childEvent: undefined, | ||
parentToChild: false, | ||
childToParent: true, | ||
childName: "fooEd", | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
@@ -184,3 +187,4 @@ bindingAttributeName: "foo-ed:to", | ||
syncChildWithParent: false | ||
}, "new el binding"); | ||
}, ":to"); | ||
info = stacheBindings.getBindingInfo({name: "foo-ed:from", value: "bar"}, null, null, null, true); | ||
@@ -190,5 +194,6 @@ deepEqual(info, { | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: false, | ||
childName: "fooEd", | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
@@ -198,3 +203,3 @@ bindingAttributeName: "foo-ed:from", | ||
syncChildWithParent: false | ||
}, "new vm binding"); | ||
}, ":from, favorViewModel=true"); | ||
@@ -205,5 +210,6 @@ info = stacheBindings.getBindingInfo({name: "foo-ed:bind", value: "bar"}, null, null, null, true); | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: true, | ||
childName: "fooEd", | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
@@ -213,3 +219,3 @@ bindingAttributeName: "foo-ed:bind", | ||
syncChildWithParent: true | ||
}, "new el binding"); | ||
}, ":bind, favorViewModel=true"); | ||
@@ -220,5 +226,6 @@ info = stacheBindings.getBindingInfo({name: "foo-ed:to", value: "bar"}, null, null, null, true); | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: false, | ||
childToParent: true, | ||
childName: "fooEd", | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
@@ -228,5 +235,177 @@ bindingAttributeName: "foo-ed:to", | ||
syncChildWithParent: false | ||
}, "new el binding"); | ||
}, ":to, favorViewModel=true"); | ||
}); | ||
test("getBindingInfo for vm:", function() { | ||
var info = stacheBindings.getBindingInfo({name: "vm:foo-ed:from", value: "bar"}); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: false, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "vm:foo-ed:from", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":from"); | ||
info = stacheBindings.getBindingInfo({name: "vm:foo-ed:bind", value: "bar"}); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "vm:foo-ed:bind", | ||
initializeValues: true, | ||
syncChildWithParent: true | ||
}, ":bind"); | ||
info = stacheBindings.getBindingInfo({name: "vm:foo-ed:to", value: "bar"}); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: false, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "vm:foo-ed:to", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":to"); | ||
info = stacheBindings.getBindingInfo({name: "vm:foo-ed:from", value: "bar"}, null, null, null, true); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: false, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "vm:foo-ed:from", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":from, favorViewModel=true"); | ||
info = stacheBindings.getBindingInfo({name: "vm:foo-ed:bind", value: "bar"}, null, null, null, true); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "vm:foo-ed:bind", | ||
initializeValues: true, | ||
syncChildWithParent: true | ||
}, ":bind, favorViewModel=true"); | ||
info = stacheBindings.getBindingInfo({name: "vm:foo-ed:to", value: "bar"}, null, null, null, true); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "viewModel", | ||
childEvent: undefined, | ||
parentToChild: false, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "vm:foo-ed:to", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":to, favorViewModel=true"); | ||
}); | ||
test("getBindingInfo for el:", function() { | ||
var info = stacheBindings.getBindingInfo({name: "el:foo-ed:from", value: "bar"}); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "attribute", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: false, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "el:foo-ed:from", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":from"); | ||
info = stacheBindings.getBindingInfo({name: "el:foo-ed:bind", value: "bar"}); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "attribute", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "el:foo-ed:bind", | ||
initializeValues: true, | ||
syncChildWithParent: true | ||
}, ":bind"); | ||
info = stacheBindings.getBindingInfo({name: "el:foo-ed:to", value: "bar"}); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "attribute", | ||
childEvent: undefined, | ||
parentToChild: false, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "el:foo-ed:to", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":to"); | ||
info = stacheBindings.getBindingInfo({name: "el:foo-ed:from", value: "bar"}, null, null, null, true); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "attribute", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: false, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "el:foo-ed:from", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":from, favorViewModel=true"); | ||
info = stacheBindings.getBindingInfo({name: "el:foo-ed:bind", value: "bar"}, null, null, null, true); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "attribute", | ||
childEvent: undefined, | ||
parentToChild: true, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "el:foo-ed:bind", | ||
initializeValues: true, | ||
syncChildWithParent: true | ||
}, ":bind, favorViewModel=true"); | ||
info = stacheBindings.getBindingInfo({name: "el:foo-ed:to", value: "bar"}, null, null, null, true); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "attribute", | ||
childEvent: undefined, | ||
parentToChild: false, | ||
childToParent: true, | ||
childName: "foo-ed", | ||
parentName: "bar", | ||
bindingAttributeName: "el:foo-ed:to", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, ":to, favorViewModel=true"); | ||
}); | ||
test("value:from works with camelCase and kebab-case properties", function() { | ||
@@ -460,31 +639,2 @@ var template = stache( | ||
test('can bind to property on viewModel using on:vm:prop:by:obj', function() { | ||
stop(); | ||
expect(1); | ||
var map = new SimpleMap({ | ||
obj: new SimpleMap({ | ||
prop: "Mercury" | ||
}) | ||
}); | ||
var MySimpleMap = SimpleMap.extend({ | ||
someMethod: function(scope, el, ev, newVal){ | ||
start(); | ||
equal(newVal, "Venus", "method called"); | ||
} | ||
}); | ||
var parent = new MySimpleMap(); | ||
MockComponent.extend({ | ||
tag: "view-model-able", | ||
viewModel: map | ||
}); | ||
var template = stache("<view-model-able on:vm:prop:by:obj='someMethod'/>"); | ||
template(parent); | ||
map.attr("obj").attr("prop", "Venus"); | ||
}); | ||
test('can bind to element using on:el:prop', function() { | ||
@@ -519,2 +669,44 @@ stop(); | ||
QUnit.test("getBindingInfo works for value:to:on:click (#269)", function(){ | ||
var info = stacheBindings.getBindingInfo({name: "value:to:on:click", value: "bar"}); | ||
deepEqual(info, { | ||
parent: "scope", | ||
child: "viewModelOrAttribute", | ||
childEvent: "click", | ||
parentToChild: false, | ||
childToParent: true, | ||
childName: "value", | ||
parentName: "bar", | ||
bindingAttributeName: "value:to:on:click", | ||
initializeValues: true, | ||
syncChildWithParent: false | ||
}, "new vm binding"); | ||
}); | ||
test("value:to:on:click and on:click:value:to work (#269)", function() { | ||
var template = stache( | ||
"<input value:to:on:click='theProp'/>" + | ||
"<input on:click:value:to='theProp'/>" | ||
); | ||
var map = new SimpleMap({}); | ||
var frag = template(map); | ||
var ta = this.fixture; | ||
ta.appendChild(frag); | ||
var bindFirstInput = ta.getElementsByTagName("input")[0]; | ||
bindFirstInput.value = "22"; | ||
canEvent.trigger.call(bindFirstInput, "click"); | ||
QUnit.equal(map.get('theProp'), "22"); | ||
var eventFirstInput = ta.getElementsByTagName("input")[1]; | ||
eventFirstInput.value = "23"; | ||
canEvent.trigger.call(eventFirstInput, "click"); | ||
QUnit.equal(map.get('theProp'), "23"); | ||
}); | ||
QUnit.test("on:el:click works inside {{#if}} on element with a viewModel (#279)", function() { | ||
@@ -544,2 +736,112 @@ var map = new SimpleMap({ | ||
QUnit.test("vm:prop:to/:from/:bind work (#280)", function() { | ||
var vm1 = new SimpleMap({ value: 'vm1' }); | ||
var vm2 = new SimpleMap({ value: 'vm2' }); | ||
var vm3 = new SimpleMap({ value: 'vm3' }); | ||
MockComponent.extend({ | ||
tag: "comp-1", | ||
viewModel: vm1 | ||
}); | ||
MockComponent.extend({ | ||
tag: "comp-2", | ||
viewModel: vm2 | ||
}); | ||
MockComponent.extend({ | ||
tag: "comp-3", | ||
viewModel: vm3 | ||
}); | ||
var template = stache( | ||
"<comp-1 vm:value:to='scope1'/>" + | ||
"<comp-2 vm:value:from='scope2'/>" + | ||
"<comp-3 vm:value:bind='scope3'/>" | ||
); | ||
var scope = new SimpleMap({ | ||
scope1: 'scope1', | ||
scope2: 'scope2', | ||
scope3: 'scope3' | ||
}); | ||
template(scope); | ||
// vm:value:to | ||
equal(scope.attr('scope1'), 'vm1', 'vm:value:to - scope value set from vm'); | ||
vm1.attr('value', 'vm4'); | ||
equal(scope.attr('scope1'), 'vm4', 'vm:value:to - scope updated when vm changes'); | ||
scope.attr('scope1', 'scope4'); | ||
equal(vm1.attr('value'), 'vm4', 'vm:value:to - vm not updated when scope changes'); | ||
// vm:value:from | ||
equal(vm2.attr('value'), 'scope2', 'vm:value:from - vm value set from scope'); | ||
scope.attr('scope2', 'scope5'); | ||
equal(vm2.attr('value'), 'scope5', 'vm:value:from - vm updated when scope changes'); | ||
vm2.attr('value', 'vm5'); | ||
equal(scope.attr('scope2'), 'scope5', 'vm:value:from - scope not updated when vm changes'); | ||
// vm:value:bind | ||
equal(vm3.attr('value'), 'scope3', 'vm:value:bind - vm value set from scope'); | ||
scope.attr('scope3', 'scope6'); | ||
equal(vm3.attr('value'), 'scope6', 'vm:value:bind - vm updated when scope changes'); | ||
vm3.attr('value', 'vm6'); | ||
equal(scope.attr('scope3'), 'vm6', 'vm:value:bind - scope updated when vm changes'); | ||
}); | ||
QUnit.test('el:prop:to/:from/:bind work (#280)', function() { | ||
var template = stache( | ||
"<input el:value:to='scope1' value='1'/>" + | ||
"<input el:value:from='scope2' value='2'/>" + | ||
"<input el:value:bind='scope3' value='3'/>" | ||
); | ||
var scope = new SimpleMap({ | ||
scope1: 'scope1', | ||
scope2: 'scope2', | ||
scope3: 'scope3' | ||
}); | ||
var frag = template(scope); | ||
var ta = this.fixture; | ||
ta.appendChild(frag); | ||
var inputTo = ta.getElementsByTagName('input')[0]; | ||
var inputFrom = ta.getElementsByTagName('input')[1]; | ||
var inputBind = ta.getElementsByTagName('input')[2]; | ||
// el:value:to | ||
equal(scope.attr('scope1'), '1', 'el:value:to - scope value set from attribute'); | ||
inputTo.value = '4'; | ||
canEvent.trigger.call(inputTo, 'change'); | ||
equal(scope.attr('scope1'), '4', 'el:value:to - scope updated when attribute changed'); | ||
scope.attr('scope1', 'scope4'); | ||
equal(inputTo.value, '4', 'el:value:to - attribute not updated when scope changed'); | ||
// el:value:from | ||
equal(inputFrom.value, 'scope2', 'el:value:from - attribute set from scope'); | ||
inputFrom.value = 'scope5'; | ||
canEvent.trigger.call(inputFrom, 'change'); | ||
equal(scope.attr('scope2'), 'scope2', 'el:value:from - scope not updated when attribute changed'); | ||
scope.attr('scope2', 'scope6'); | ||
equal(inputFrom.value, 'scope6', 'el:value:from - attribute updated when scope changed'); | ||
// el:value:bind | ||
equal(inputBind.value, 'scope3', 'el:value:bind - attribute set from scope prop (parent -> child wins)'); | ||
inputBind.value = 'scope6'; | ||
canEvent.trigger.call(inputBind, 'change'); | ||
equal(scope.attr('scope3'), 'scope6', 'el:value:bind - scope updated when attribute changed'); | ||
scope.attr('scope3', 'scope7'); | ||
equal(inputBind.value, 'scope7', 'el:value:bind - attribute updated when scope changed'); | ||
}); | ||
} |
@@ -467,1 +467,39 @@ var bindings = require('can-stache-bindings'); | ||
}); | ||
QUnit.test("events starting with `to`, `from`, and `bind` work (#285)", function() { | ||
expect(3); | ||
var ViewModel = DefineMap.extend({ | ||
toevent: '1', | ||
fromevent: '1', | ||
bindevent: '1', | ||
}); | ||
MockComponent.extend({ | ||
tag: 'view-model-able', | ||
viewModel: ViewModel | ||
}); | ||
var template = stache("<view-model-able (toevent)='toMethod()' (fromevent)='fromMethod()' (bindevent)='bindMethod()' />"); | ||
var Parent = DefineMap.extend({ | ||
toMethod: function() { | ||
QUnit.ok(true, '(toevent) worked'); | ||
}, | ||
fromMethod: function() { | ||
QUnit.ok(true, '(fromevent) worked'); | ||
}, | ||
bindMethod: function() { | ||
QUnit.ok(true, '(bindevent) worked'); | ||
} | ||
}); | ||
var parent = new Parent(); | ||
var frag = template(parent); | ||
var el = frag.firstChild; | ||
var vm = canViewModel(el); | ||
vm.toevent = '2'; | ||
vm.fromevent = '2'; | ||
vm.bindevent = '2'; | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
219402
4769