Просмотр исходного кода

sd-on can now execute expressions

Evan You 12 лет назад
Родитель
Сommit
9dc45ea9f6
6 измененных файлов с 44 добавлено и 22 удалено
  1. 2 1
      src/binding.js
  2. 19 11
      src/compiler.js
  3. 1 0
      src/deps-parser.js
  4. 11 6
      src/directive.js
  5. 2 1
      src/directives/on.js
  6. 9 3
      src/exp-parser.js

+ 2 - 1
src/binding.js

@@ -5,9 +5,10 @@
  *  which has multiple directive instances on the DOM
  *  which has multiple directive instances on the DOM
  *  and multiple computed property dependents
  *  and multiple computed property dependents
  */
  */
-function Binding (compiler, key, isExp) {
+function Binding (compiler, key, isExp, isFn) {
     this.value = undefined
     this.value = undefined
     this.isExp = !!isExp
     this.isExp = !!isExp
+    this.isFn = isFn
     this.root = !this.isExp && key.indexOf('.') === -1
     this.root = !this.isExp && key.indexOf('.') === -1
     this.compiler = compiler
     this.compiler = compiler
     this.key = key
     this.key = key

+ 19 - 11
src/compiler.js

@@ -368,7 +368,7 @@ CompilerProto.bindDirective = function (directive) {
 
 
     if (directive.isExp) {
     if (directive.isExp) {
         // expression bindings are always created on current compiler
         // 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)) {
     } else if (ownerCompiler.vm.hasOwnProperty(baseKey)) {
         // If the directive's owner compiler's VM has the key,
         // If the directive's owner compiler's VM has the key,
         // it belongs there. Create the binding if it's not already
         // it belongs there. Create the binding if it's not already
@@ -415,11 +415,11 @@ CompilerProto.bindDirective = function (directive) {
 /**
 /**
  *  Create binding and attach getter/setter for a key to the viewmodel object
  *  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,
     var compiler = this,
         bindings = compiler.bindings,
         bindings = compiler.bindings,
-        binding  = new Binding(compiler, key, isExp)
+        binding  = new Binding(compiler, key, isExp, isFn)
 
 
     if (isExp) {
     if (isExp) {
         // a complex expression binding
         // a complex expression binding
@@ -427,16 +427,20 @@ CompilerProto.createBinding = function (key, isExp) {
         var result = ExpParser.parse(key)
         var result = ExpParser.parse(key)
         if (result) {
         if (result) {
             log('  created anonymous binding: ' + key)
             log('  created anonymous binding: ' + key)
-            binding.value = { get: result.getter }
+            binding.value = isFn
+                ? result.getter
+                : { get: result.getter }
             compiler.markComputed(binding)
             compiler.markComputed(binding)
             compiler.exps.push(binding)
             compiler.exps.push(binding)
             // need to create the bindings for keys
             // need to create the bindings for keys
             // that do not exist yet
             // 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 {
         } else {
@@ -548,8 +552,12 @@ CompilerProto.markComputed = function (binding) {
         vm    = this.vm
         vm    = this.vm
     binding.isComputed = true
     binding.isComputed = true
     // bind the accessors to the vm
     // 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
     // keep track for dep parsing later
     this.computed.push(binding)
     this.computed.push(binding)
 }
 }

+ 1 - 0
src/deps-parser.js

@@ -7,6 +7,7 @@ var Emitter  = require('./emitter'),
  *  by recording the getters triggered when evaluating it.
  *  by recording the getters triggered when evaluating it.
  */
  */
 function catchDeps (binding) {
 function catchDeps (binding) {
+    if (binding.isFn) return
     utils.log('\n─ ' + binding.key)
     utils.log('\n─ ' + binding.key)
     var depsHash = utils.hash()
     var depsHash = utils.hash()
     observer.on('get', function (dep) {
     observer.on('get', function (dep) {

+ 11 - 6
src/directive.js

@@ -142,12 +142,17 @@ DirProto.refresh = function (value) {
     // pass element and viewmodel info to the getter
     // pass element and viewmodel info to the getter
     // enables context-aware bindings
     // enables context-aware bindings
     if (value) this.value = value
     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)
     this.apply(value)
 }
 }
 
 

+ 2 - 1
src/directives/on.js

@@ -12,6 +12,8 @@ function delegateCheck (current, top, identifier) {
 
 
 module.exports = {
 module.exports = {
 
 
+    isFn: true,
+
     bind: function () {
     bind: function () {
         if (this.compiler.repeat) {
         if (this.compiler.repeat) {
             // attach an identifier to the el
             // attach an identifier to the el
@@ -23,7 +25,6 @@ module.exports = {
     },
     },
 
 
     update: function (handler) {
     update: function (handler) {
-
         this.unbind(true)
         this.unbind(true)
         if (typeof handler !== 'function') {
         if (typeof handler !== 'function') {
             return utils.warn('Directive "on" expects a function value.')
             return utils.warn('Directive "on" expects a function value.')

+ 9 - 3
src/exp-parser.js

@@ -11,7 +11,9 @@ var KEYWORDS =
         ',package,private,protected,public,short,static,super,synchronized' +
         ',package,private,protected,public,short,static,super,synchronized' +
         ',throws,transient,volatile' +
         ',throws,transient,volatile' +
         // ECMA 5 - use strict
         // 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'),
     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,
     REMOVE_RE   = /\/\*(?:.|\n)*?\*\/|\/\/[^\n]*\n|\/\/[^\n]*$|'[^']*'|"[^"]*"|[\s\t\n]*\.[\s\t\n]*[$\w\.]+/g,
@@ -52,9 +54,14 @@ module.exports = {
      *  created as bindings.
      *  created as bindings.
      */
      */
     parse: function (exp) {
     parse: function (exp) {
+        /* jshint evil: true */
         // extract variable names
         // extract variable names
         var vars = getVariables(exp)
         var vars = getVariables(exp)
-        if (!vars.length) return null
+        if (!vars.length) {
+            return {
+                getter: new Function('return ' + exp)
+            }
+        }
         var args = [],
         var args = [],
             v, i, keyPrefix,
             v, i, keyPrefix,
             l = vars.length,
             l = vars.length,
@@ -73,7 +80,6 @@ module.exports = {
                 ))
                 ))
         }
         }
         args = 'var ' + args.join(',') + ';return ' + exp
         args = 'var ' + args.join(',') + ';return ' + exp
-        /* jshint evil: true */
         return {
         return {
             getter: new Function(args),
             getter: new Function(args),
             paths: getPaths(exp, Object.keys(hash))
             paths: getPaths(exp, Object.keys(hash))