Skip to content

Commit

Permalink
sd-on can now execute expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
Evan You committed Nov 14, 2013
1 parent 3dc6089 commit 9dc45ea
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 22 deletions.
3 changes: 2 additions & 1 deletion src/binding.js
Expand Up @@ -5,9 +5,10 @@
* which has multiple directive instances on the DOM
* and multiple computed property dependents
*/
function Binding (compiler, key, isExp) {
function Binding (compiler, key, isExp, isFn) {
this.value = undefined
this.isExp = !!isExp
this.isFn = isFn
this.root = !this.isExp && key.indexOf('.') === -1
this.compiler = compiler
this.key = key
Expand Down
30 changes: 19 additions & 11 deletions src/compiler.js
Expand Up @@ -368,7 +368,7 @@ CompilerProto.bindDirective = function (directive) {

if (directive.isExp) {
// expression bindings are always created on current compiler
binding = compiler.createBinding(key, true)
binding = compiler.createBinding(key, true, directive.isFn)
} else if (ownerCompiler.vm.hasOwnProperty(baseKey)) {
// If the directive's owner compiler's VM has the key,
// it belongs there. Create the binding if it's not already
Expand Down Expand Up @@ -415,28 +415,32 @@ CompilerProto.bindDirective = function (directive) {
/**
* Create binding and attach getter/setter for a key to the viewmodel object
*/
CompilerProto.createBinding = function (key, isExp) {
CompilerProto.createBinding = function (key, isExp, isFn) {

var compiler = this,
bindings = compiler.bindings,
binding = new Binding(compiler, key, isExp)
binding = new Binding(compiler, key, isExp, isFn)

if (isExp) {
// a complex expression binding
// we need to generate an anonymous computed property for it
var result = ExpParser.parse(key)
if (result) {
log(' created anonymous binding: ' + key)
binding.value = { get: result.getter }
binding.value = isFn
? result.getter
: { get: result.getter }
compiler.markComputed(binding)
compiler.exps.push(binding)
// need to create the bindings for keys
// that do not exist yet
var i = result.paths.length, v
while (i--) {
v = result.paths[i]
if (!bindings[v]) {
compiler.rootCompiler.createBinding(v)
if (result.paths) {
var i = result.paths.length, v
while (i--) {
v = result.paths[i]
if (!bindings[v]) {
compiler.rootCompiler.createBinding(v)
}
}
}
} else {
Expand Down Expand Up @@ -548,8 +552,12 @@ CompilerProto.markComputed = function (binding) {
vm = this.vm
binding.isComputed = true
// bind the accessors to the vm
value.get = value.get.bind(vm)
if (value.set) value.set = value.set.bind(vm)
if (binding.isFn) {
binding.value = value.bind(vm)
} else {
value.get = value.get.bind(vm)
if (value.set) value.set = value.set.bind(vm)
}
// keep track for dep parsing later
this.computed.push(binding)
}
Expand Down
1 change: 1 addition & 0 deletions src/deps-parser.js
Expand Up @@ -7,6 +7,7 @@ var Emitter = require('./emitter'),
* by recording the getters triggered when evaluating it.
*/
function catchDeps (binding) {
if (binding.isFn) return
utils.log('\n─ ' + binding.key)
var depsHash = utils.hash()
observer.on('get', function (dep) {
Expand Down
17 changes: 11 additions & 6 deletions src/directive.js
Expand Up @@ -142,12 +142,17 @@ DirProto.refresh = function (value) {
// pass element and viewmodel info to the getter
// enables context-aware bindings
if (value) this.value = value
value = this.value.get({
el: this.el,
vm: this.vm
})
if (value !== undefined && value === this.computedValue) return
this.computedValue = value

if (this.isFn) {
value = this.value
} else {
value = this.value.get({
el: this.el,
vm: this.vm
})
if (value !== undefined && value === this.computedValue) return
this.computedValue = value
}
this.apply(value)
}

Expand Down
3 changes: 2 additions & 1 deletion src/directives/on.js
Expand Up @@ -12,6 +12,8 @@ function delegateCheck (current, top, identifier) {

module.exports = {

isFn: true,

bind: function () {
if (this.compiler.repeat) {
// attach an identifier to the el
Expand All @@ -23,7 +25,6 @@ module.exports = {
},

update: function (handler) {

this.unbind(true)
if (typeof handler !== 'function') {
return utils.warn('Directive "on" expects a function value.')
Expand Down
12 changes: 9 additions & 3 deletions src/exp-parser.js
Expand Up @@ -11,7 +11,9 @@ var KEYWORDS =
',package,private,protected,public,short,static,super,synchronized' +
',throws,transient,volatile' +
// ECMA 5 - use strict
',arguments,let,yield',
',arguments,let,yield' +
// skip
',window',

KEYWORDS_RE = new RegExp(["\\b" + KEYWORDS.replace(/,/g, '\\b|\\b') + "\\b"].join('|'), 'g'),
REMOVE_RE = /\/\*(?:.|\n)*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|'[^']*'|"[^"]*"|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g,
Expand Down Expand Up @@ -52,9 +54,14 @@ module.exports = {
* created as bindings.
*/
parse: function (exp) {
/* jshint evil: true */
// extract variable names
var vars = getVariables(exp)
if (!vars.length) return null
if (!vars.length) {
return {
getter: new Function('return ' + exp)
}
}
var args = [],
v, i, keyPrefix,
l = vars.length,
Expand All @@ -73,7 +80,6 @@ module.exports = {
))
}
args = 'var ' + args.join(',') + ';return ' + exp
/* jshint evil: true */
return {
getter: new Function(args),
paths: getPaths(exp, Object.keys(hash))
Expand Down

0 comments on commit 9dc45ea

Please sign in to comment.