Răsfoiți Sursa

computed property progress

Evan You 13 ani în urmă
părinte
comite
3d33458b60
4 a modificat fișierele cu 79 adăugiri și 72 ștergeri
  1. 15 5
      src/directive-parser.js
  2. 2 1
      src/directives.js
  3. 1 27
      src/filters.js
  4. 61 39
      src/seed.js

+ 15 - 5
src/directive-parser.js

@@ -2,10 +2,11 @@ var config     = require('./config'),
     directives = require('./directives'),
     filters    = require('./filters')
 
-var KEY_RE          = /^[^\|]+/,
+var KEY_RE          = /^[^\|<]+/,
     ARG_RE          = /([^:]+):(.+)$/,
-    FILTERS_RE      = /\|[^\|]+/g,
+    FILTERS_RE      = /\|[^\|<]+/g,
     FILTER_TOKEN_RE = /[^\s']+|'[^']+'/g,
+    DEPS_RE         = /<[^<\|]+/g,
     QUOTE_RE        = /'/g
 
 function Directive (directiveName, expression) {
@@ -34,9 +35,9 @@ function Directive (directiveName, expression) {
         ? argMatch[1].trim()
         : null
     
-    var filterExpressions = expression.match(FILTERS_RE)
-    if (filterExpressions) {
-        this.filters = filterExpressions.map(function (filter) {
+    var filterExps = expression.match(FILTERS_RE)
+    if (filterExps) {
+        this.filters = filterExps.map(function (filter) {
             var tokens = filter.slice(1)
                 .match(FILTER_TOKEN_RE)
                 .map(function (token) {
@@ -53,9 +54,18 @@ function Directive (directiveName, expression) {
     } else {
         this.filters = null
     }
+
+    var depExp = expression.match(DEPS_RE)
+    if (depExp) {
+        this.deps = depExp[0].slice(1).trim().split(/\s+/)
+    }
 }
 
 Directive.prototype.update = function (value) {
+    // computed property
+    if (typeof value === 'function' && !this.fn) {
+        value = value()
+    }
     // apply filters
     if (this.filters) {
         value = this.applyFilters(value)

+ 2 - 1
src/directives.js

@@ -40,6 +40,7 @@ module.exports = {
     },
 
     on: {
+        fn : true,
         update: function (handler) {
             var self  = this,
                 event = this.arg
@@ -104,7 +105,7 @@ module.exports = {
         },
         unbind: function (rm) {
             if (this.childSeeds.length) {
-                var fn = rm ? 'destroy' : 'unbind'
+                var fn = rm ? '_destroy' : '_unbind'
                 this.childSeeds.forEach(function (child) {
                     child[fn]()
                 })

+ 1 - 27
src/filters.js

@@ -7,32 +7,6 @@ module.exports = {
 
     uppercase: function (value) {
         return value.toString().toUpperCase()
-    },
-
-    // TODO probably there's a better way.
-    // Angular doesn't support delegation either
-    // any real performance gain?
-    // delegate: function (handler, args) {
-    //     var selector = args[0]
-    //     return function (e) {
-    //         var oe = e.originalEvent,
-    //             target = delegateCheck(oe.target, oe.currentTarget, selector)
-    //         if (target) {
-    //             e.el = target
-    //             e.seed = target.seed
-    //             handler.call(this, e)
-    //         }
-    //     }
-    // }
-
-}
-
-function delegateCheck (current, top, selector) {
-    if (current.webkitMatchesSelector(selector)) {
-        return current
-    } else if (current === top) {
-        return false
-    } else {
-        return delegateCheck(current.parentNode, top, selector)
     }
+
 }

+ 61 - 39
src/seed.js

@@ -4,7 +4,6 @@ var Emitter         = require('emitter'),
 
 var slice           = Array.prototype.slice,
     ancestorKeyRE   = /\^/g,
-    rootKeyRE       = /^\$/,
     ctrlAttr        = config.prefix + '-controller',
     eachAttr        = config.prefix + '-each'
 
@@ -18,10 +17,9 @@ function Seed (el, options) {
     this._bindings  = {}
 
     // copy options
-    if (options) {
-        for (var op in options) {
-            this[op] = options[op]
-        }
+    options = options || {}
+    for (var op in options) {
+        this[op] = options[op]
     }
 
     // initialize the scope object
@@ -32,21 +30,24 @@ function Seed (el, options) {
             || {}
     el.removeAttribute(dataPrefix)
 
-    // if has controller
-    var ctrlID = el.getAttribute(ctrlAttr),
-        controller = null
-    if (ctrlID) {
-        controller = config.controllers[ctrlID]
-        if (!controller) console.warn('controller ' + ctrlID + ' is not defined.')
-        el.removeAttribute(ctrlAttr)
-    }
+    this.scope.$seed    = this
+    this.scope.$destroy = this._destroy.bind(this)
+    this.scope.$dump    = this._dump.bind(this)
+    this.scope.$index   = options.index
 
     // revursively process nodes for directives
     this._compileNode(el, true)
 
-    // copy in methods from controller
-    if (controller) {
-        controller.call(this, this.scope, this)
+    // if has controller, apply it
+    var ctrlID = el.getAttribute(ctrlAttr)
+    if (ctrlID) {
+        el.removeAttribute(ctrlAttr)
+        var controller = config.controllers[ctrlID]
+        if (controller) {
+            controller.call(this, this.scope, this)
+        } else {
+            console.warn('controller ' + ctrlID + ' is not defined.')
+        }
     }
 }
 
@@ -79,23 +80,25 @@ Seed.prototype._compileNode = function (node, root) {
                 self['$' + id] = seed
             }
 
-        } else if (node.attributes && node.attributes.length) { // normal node
-
-            slice.call(node.attributes).forEach(function (attr) {
-                var valid = false
-                attr.value.split(',').forEach(function (exp) {
-                    var binding = DirectiveParser.parse(attr.name, exp)
-                    if (binding) {
-                        valid = true
-                        self._bind(node, binding)
-                    }
+        } else { // normal node
+
+            // parse if has attributes
+            if (node.attributes && node.attributes.length) {
+                slice.call(node.attributes).forEach(function (attr) {
+                    if (attr.name === ctrlAttr) return
+                    var valid = false
+                    attr.value.split(',').forEach(function (exp) {
+                        var binding = DirectiveParser.parse(attr.name, exp)
+                        if (binding) {
+                            valid = true
+                            self._bind(node, binding)
+                        }
+                    })
+                    if (valid) node.removeAttribute(attr.name)
                 })
-                if (valid) node.removeAttribute(attr.name)
-            })
-        }
+            }
 
-        // recursively parse child nodes
-        if (!eachExp && !ctrlExp) {
+            // recursively compile childNodes
             if (node.childNodes.length) {
                 slice.call(node.childNodes).forEach(function (child) {
                     self._compileNode(child)
@@ -128,7 +131,7 @@ Seed.prototype._bind = function (node, directive) {
         scopeOwner = this.parentSeed
     } else {
         var ancestors = key.match(ancestorKeyRE),
-            root      = key.match(rootKeyRE)
+            root      = key.charAt(0) === '$'
         if (ancestors) {
             key = key.replace(ancestorKeyRE, '')
             var levels = ancestors.length
@@ -136,7 +139,7 @@ Seed.prototype._bind = function (node, directive) {
                 scopeOwner = scopeOwner.parentSeed
             }
         } else if (root) {
-            key = key.replace(rootKeyRE, '')
+            key = key.slice(1)
             while (scopeOwner.parentSeed) {
                 scopeOwner = scopeOwner.parentSeed
             }
@@ -166,6 +169,7 @@ Seed.prototype._createBinding = function (key) {
 
     var binding = {
         value: this.scope[key],
+        changed: false,
         instances: []
     }
 
@@ -177,6 +181,8 @@ Seed.prototype._createBinding = function (key) {
             return binding.value
         },
         set: function (value) {
+            if (value === binding) return
+            binding.changed = true
             binding.value = value
             binding.instances.forEach(function (instance) {
                 instance.update(value)
@@ -187,7 +193,7 @@ Seed.prototype._createBinding = function (key) {
     return binding
 }
 
-Seed.prototype.unbind = function () {
+Seed.prototype._unbind = function () {
     var unbind = function (instance) {
         if (instance.unbind) {
             instance.unbind()
@@ -196,19 +202,35 @@ Seed.prototype.unbind = function () {
     for (var key in this._bindings) {
         this._bindings[key].instances.forEach(unbind)
     }
-    this.childSeeds.forEach(function (child) {
-        child.unbind()
-    })
 }
 
-Seed.prototype.destroy = function () {
-    this.unbind()
+Seed.prototype._destroy = function () {
+    this._unbind()
     this.el.parentNode.removeChild(this.el)
     if (this.parentSeed && this.id) {
         delete this.parentSeed['$' + this.id]
     }
 }
 
+Seed.prototype._dump = function () {
+    var dump = {}, val,
+        subDump = function (scope) {
+            return scope.$dump()
+        }
+    for (var key in this.scope) {
+        if (key.charAt(0) !== '$') {
+            val = this._bindings[key]
+            if (!val) continue
+            if (Array.isArray(val)) {
+                dump[key] = val.map(subDump)
+            } else {
+                dump[key] = this._bindings[key].value
+            }
+        }
+    }
+    return dump
+}
+
 Emitter(Seed.prototype)
 
 module.exports = Seed