Evan You пре 12 година
родитељ
комит
7ad304eb9d
10 измењених фајлова са 87 додато и 56 уклоњено
  1. 0 1
      TODO.md
  2. 1 1
      component.json
  3. 1 0
      examples/todos/app.js
  4. 9 7
      src/config.js
  5. 8 0
      src/deps-parser.js
  6. 0 0
      src/directive-parser.js
  7. 27 18
      src/directives/each.js
  8. 34 25
      src/directives/on.js
  9. 4 4
      src/seed.js
  10. 3 0
      src/text-parser.js

+ 0 - 1
TODO.md

@@ -1,4 +1,3 @@
-- computed setters
 - nested properties in scope
     - parse path in Directive parser
     - select scope to defineProperty on based on path, create object if needed

+ 1 - 1
component.json

@@ -7,7 +7,7 @@
     "src/config.js",
     "src/seed.js",
     "src/binding.js",
-    "src/directive.js",
+    "src/directive-parser.js",
     "src/text-parser.js",
     "src/deps-parser.js",
     "src/filters.js",

+ 1 - 0
examples/todos/app.js

@@ -71,6 +71,7 @@ Seed.controller('Todos', function (scope) {
     }
 
     scope.removeCompleted = function () {
+        if (scope.completed === 0) return
         scope.todos = scope.todos.filter(function (todo) {
             return !todo.done
         })

+ 9 - 7
src/config.js

@@ -1,9 +1,11 @@
 module.exports = {
-    prefix: 'sd',
-    interpolateTags: {
-        open: '{{',
-        close: '}}'
-    },
-    controllers: {},
-    datum: {}
+
+    prefix      : 'sd',
+    datum       : {},
+    controllers : {},
+
+    interpolateTags : {
+        open  : '{{',
+        close : '}}'
+    }
 }

+ 8 - 0
src/deps-parser.js

@@ -30,7 +30,15 @@ function injectDeps (binding) {
 }
 
 module.exports = {
+
+    /*
+     *  the observer that catches events triggered by getters
+     */
     observer: observer,
+
+    /*
+     *  parse a list of computed property bindings
+     */
     parse: function (bindings) {
         observer.isObserving = true
         bindings.forEach(catchDeps)

+ 0 - 0
src/directive.js → src/directive-parser.js


+ 27 - 18
src/directives/each.js

@@ -1,12 +1,16 @@
 var config = require('../config')
 
+/*
+ *  Mathods that perform precise DOM manipulation
+ *  based on mutator method triggered
+ */
 var mutationHandlers = {
 
     push: function (m) {
         var self = this
         m.args.forEach(function (data, i) {
             var seed = self.buildItem(data, self.collection.length + i)
-            self.container.insertBefore(seed.el, self.marker)
+            self.container.insertBefore(seed.el, self.ref)
         })
     },
 
@@ -20,7 +24,7 @@ var mutationHandlers = {
             var seed = self.buildItem(data, i),
                 ref  = self.collection.length > m.args.length
                      ? self.collection[m.args.length].$el
-                     : self.marker
+                     : self.ref
             self.container.insertBefore(seed.el, ref)
         })
         self.updateIndexes()
@@ -46,7 +50,7 @@ var mutationHandlers = {
                     pos  = index - removed + added + 1,
                     ref  = self.collection[pos]
                          ? self.collection[pos].$el
-                         : self.marker
+                         : self.ref
                 self.container.insertBefore(seed.el, ref)
             })
         }
@@ -59,7 +63,7 @@ var mutationHandlers = {
         var self = this
         self.collection.forEach(function (scope, i) {
             scope.$index = i
-            self.container.insertBefore(scope.$el, self.marker)
+            self.container.insertBefore(scope.$el, self.ref)
         })
     }
 }
@@ -71,25 +75,32 @@ module.exports = {
     bind: function () {
         this.el.removeAttribute(config.prefix + '-each')
         var ctn = this.container = this.el.parentNode
-        this.marker = document.createComment('sd-each-' + this.arg)
-        ctn.insertBefore(this.marker, this.el)
-        this.delegator = this.el.parentNode
+        // create a comment node as a reference node for DOM insertions
+        this.ref = document.createComment('sd-each-' + this.arg)
+        ctn.insertBefore(this.ref, this.el)
         ctn.removeChild(this.el)
     },
 
     update: function (collection) {
+
         this.unbind(true)
-        // for event delegation
         if (!Array.isArray(collection)) return
         this.collection = collection
-        this.delegator.sdDelegationHandlers = {}
+
+        // attach an object to container to hold handlers
+        this.container.sd_dHandlers = {}
+
+        // listen for collection mutation events
+        // the collection has been augmented during Binding.set()
         var self = this
         collection.on('mutate', function (mutation) {
             mutationHandlers[mutation.method].call(self, mutation)
         })
+
+        // create child-seeds and append to DOM
         collection.forEach(function (data, i) {
             var seed = self.buildItem(data, i)
-            self.container.insertBefore(seed.el, self.marker)
+            self.container.insertBefore(seed.el, self.ref)
         })
     },
 
@@ -102,7 +113,7 @@ module.exports = {
                 parentSeed: this.seed,
                 index: index,
                 data: data,
-                delegator: this.delegator
+                delegator: this.container
             })
         this.collection[index] = spore.scope
         return spore
@@ -122,13 +133,11 @@ module.exports = {
             })
             this.collection = null
         }
-        var delegator = this.delegator
-        if (delegator) {
-            var handlers = delegator.sdDelegationHandlers
-            for (var key in handlers) {
-                delegator.removeEventListener(handlers[key].event, handlers[key])
-            }
-            delete delegator.sdDelegationHandlers
+        var ctn = this.container,
+            handlers = ctn.sd_dHandlers
+        for (var key in handlers) {
+            ctn.removeEventListener(handlers[key].event, handlers[key])
         }
+        delete ctn.sd_dHandlers
     }
 }

+ 34 - 25
src/directives/on.js

@@ -1,10 +1,10 @@
-function delegateCheck (current, top, marker) {
-    if (current[marker]) {
+function delegateCheck (current, top, identifier) {
+    if (current[identifier]) {
         return current
     } else if (current === top) {
         return false
     } else {
-        return delegateCheck(current.parentNode, top, marker)
+        return delegateCheck(current.parentNode, top, identifier)
     }
 }
 
@@ -14,49 +14,58 @@ module.exports = {
 
     bind: function () {
         if (this.seed.each) {
+            // attach an identifier to the el
+            // so it can be matched during event delegation
             this.el[this.expression] = true
-            this.el.seed = this.seed
+            // attach the owner scope of this directive
+            this.el.sd_scope = this.seed.scope
         }
     },
 
     update: function (handler) {
+
         this.unbind()
         if (!handler) return
-        var self  = this,
+
+        var seed  = this.seed,
             event = this.arg
-        if (this.seed.each && event !== 'blur' && event !== 'blur') {
+
+        if (seed.each && event !== 'blur' && event !== 'blur') {
+
             // for each blocks, delegate for better performance
             // focus and blur events dont bubble so exclude them
-            var delegator = this.seed.delegator
-            if (!delegator) return
-            var marker    = this.expression,
-                dHandler  = delegator.sdDelegationHandlers[marker]
-            // this only gets run once!!!
-            if (!dHandler) {
-                dHandler = delegator.sdDelegationHandlers[marker] = function (e) {
-                    var target = delegateCheck(e.target, delegator, marker)
-                    if (target) {
-                        handler({
-                            originalEvent : e,
-                            el            : target,
-                            scope         : target.seed.scope
-                        })
-                    }
+            var delegator  = seed.delegator,
+                identifier = this.expression,
+                dHandler   = delegator.sd_dHandlers[identifier]
+
+            if (dHandler) return
+
+            // the following only gets run once for the entire each block
+            dHandler = delegator.sd_dHandlers[identifier] = function (e) {
+                var target = delegateCheck(e.target, delegator, identifier)
+                if (target) {
+                    handler({
+                        originalEvent : e,
+                        el            : target,
+                        scope         : target.sd_scope
+                    })
                 }
-                dHandler.event = event
-                delegator.addEventListener(event, dHandler)
             }
+            dHandler.event = event
+            delegator.addEventListener(event, dHandler)
 
         } else {
-            // a normal handler
+
+            // a normal, single element handler
             this.handler = function (e) {
                 handler({
                     originalEvent : e,
                     el            : e.currentTarget,
-                    scope         : self.seed.scope
+                    scope         : seed.scope
                 })
             }
             this.el.addEventListener(event, this.handler)
+
         }
     },
 

+ 4 - 4
src/seed.js

@@ -1,6 +1,6 @@
 var config          = require('./config'),
     Binding         = require('./binding'),
-    Directive       = require('./directive'),
+    DirectiveParser = require('./directive-parser'),
     TextParser      = require('./text-parser'),
     depsParser      = require('./deps-parser')
 
@@ -93,7 +93,7 @@ Seed.prototype._compileNode = function (node, root) {
 
         if (eachExp) { // each block
 
-            var directive = Directive.parse(eachAttr, eachExp)
+            var directive = DirectiveParser.parse(eachAttr, eachExp)
             if (directive) {
                 directive.el = node
                 seed._bind(directive)
@@ -116,7 +116,7 @@ Seed.prototype._compileNode = function (node, root) {
                     if (attr.name === ctrlAttr) return
                     var valid = false
                     attr.value.split(',').forEach(function (exp) {
-                        var directive = Directive.parse(attr.name, exp)
+                        var directive = DirectiveParser.parse(attr.name, exp)
                         if (directive) {
                             valid = true
                             directive.el = node
@@ -148,7 +148,7 @@ Seed.prototype._compileTextNode = function (node) {
     tokens.forEach(function (token) {
         var el = document.createTextNode()
         if (token.key) {
-            var directive = Directive.parse(dirname, token.key)
+            var directive = DirectiveParser.parse(dirname, token.key)
             if (directive) {
                 directive.el = el
                 seed._bind(directive)

+ 3 - 0
src/text-parser.js

@@ -2,6 +2,9 @@ var config     = require('./config'),
     ESCAPE_RE  = /[-.*+?^${}()|[\]\/\\]/g,
     BINDING_RE
 
+/*
+ *  Escapes a string so that it can be used to construct RegExp
+ */
 function escapeRegex (val) {
     return val.replace(ESCAPE_RE, '\\$&')
 }