Jelajahi Sumber

move defineProperty() into Binding, add setter for computed property

Evan You 12 tahun lalu
induk
melakukan
52645e33bf
5 mengubah file dengan 50 tambahan dan 39 penghapusan
  1. 2 1
      TODO.md
  2. 11 10
      examples/todos/app.js
  3. 1 2
      examples/todos/index.html
  4. 30 3
      src/binding.js
  5. 6 23
      src/seed.js

+ 2 - 1
TODO.md

@@ -4,4 +4,5 @@
     - select scope to defineProperty on based on path, create object if needed
     - when a new object is set, recursively replace all properties with getter/setters that emit events.
 - sd-with
-- standarized way to reuse components (sd-component?)
+- standarized way to reuse components (sd-component?)
+- plugins: seed-touch, seed-storage, seed-router

+ 11 - 10
examples/todos/app.js

@@ -28,9 +28,17 @@ Seed.controller('Todos', function (scope) {
         return scope.remaining > 1 ? 'items' : 'item'
     }}
 
-    scope.allDone = {get: function () {
-        return scope.remaining === 0
-    }}
+    scope.allDone = {
+        get: function () {
+            return scope.remaining === 0
+        },
+        set: function (value) {
+            scope.todos.forEach(function (todo) {
+                todo.done = value
+            })
+            scope.remaining = value ? 0 : scope.total
+        }
+    }
 
     // event handlers ---------------------------------------------------------
     scope.addTodo = function (e) {
@@ -62,13 +70,6 @@ Seed.controller('Todos', function (scope) {
         scope.filter = e.el.dataset.filter
     }
 
-    scope.toggleAll = function (e) {
-        scope.todos.forEach(function (todo) {
-            todo.done = e.el.checked
-        })
-        scope.remaining = e.el.checked ? 0 : scope.total
-    }
-
     scope.removeCompleted = function () {
         scope.todos = scope.todos.filter(function (todo) {
             return !todo.done

+ 1 - 2
examples/todos/index.html

@@ -25,8 +25,7 @@
                 <input 
                     id="toggle-all"
                     type="checkbox"
-                    sd-checked-oneway="allDone"
-                    sd-on="change:toggleAll"
+                    sd-checked="allDone"
                 >
                 <ul id="todo-list">
                     <!-- a single todo item -->

+ 30 - 3
src/binding.js

@@ -7,10 +7,14 @@ var Emitter  = require('emitter')
  *  which has multiple directive instances on the DOM
  *  and multiple computed property dependents
  */
-function Binding (value) {
-    this.value = value
+function Binding (seed, key) {
+    this.seed = seed
+    this.key = key
+    this.set(seed.scope[key])
+    this.defineAccessors(seed, key)
     this.instances = []
     this.dependents = []
+    this.dependencies = []
 }
 
 /*
@@ -21,7 +25,7 @@ Binding.prototype.set = function (value) {
         self = this
     // preprocess the value depending on its type
     if (type === 'Object') {
-        if (value.get) { // computed property
+        if (value.get || value.set) { // computed property
             self.isComputed = true
         } else { // normal object
             // TODO watchObject
@@ -35,6 +39,29 @@ Binding.prototype.set = function (value) {
     this.value = value
 }
 
+/*
+ *  Define getter/setter for this binding on scope
+ */
+Binding.prototype.defineAccessors = function (seed, key) {
+    var self = this
+    Object.defineProperty(seed.scope, key, {
+        get: function () {
+            seed.emit('get', key)
+            return self.isComputed
+                ? self.value.get()
+                : self.value
+        },
+        set: function (value) {
+            if (self.isComputed && self.value.set) {
+                self.value.set(value)
+            } else if (value !== self.value) {
+                self.value = value
+                self.update(value)
+            }
+        }
+    })
+}
+
 /*
  *  Process the value, then trigger updates on all dependents
  */

+ 6 - 23
src/seed.js

@@ -72,8 +72,12 @@ function Seed (el, options) {
     }
 
     // add event listener to update corresponding binding
-    // when a property is set
     var self = this
+    this.on('get', function (key) {
+        if (parsingDeps) {
+            depsObserver.emit('get', self._bindings[key])
+        }
+    })
     this.on('set', function (key, value) {
         self._bindings[key].update(value)
     })
@@ -211,29 +215,9 @@ Seed.prototype._bind = function (directive) {
  *  Create binding and attach getter/setter for a key to the scope object
  */
 Seed.prototype._createBinding = function (key) {
-
-    var binding = new Binding()
-    binding.set(this.scope[key])
+    var binding = new Binding(this, key)
     this._bindings[key] = binding
     if (binding.isComputed) this._computed.push(binding)
-
-    var seed = this
-    Object.defineProperty(this.scope, key, {
-        get: function () {
-            if (parsingDeps) {
-                depsObserver.emit('get', binding)
-            }
-            seed.emit('get', key)
-            return binding.isComputed
-                ? binding.value.get()
-                : binding.value
-        },
-        set: function (value) {
-            if (value === binding.value) return
-            seed.emit('set', key, value)
-        }
-    })
-
     return binding
 }
 
@@ -294,7 +278,6 @@ Seed.prototype._dump = function () {
  *  second pass in injectDeps()
  */
 function parseDeps (binding) {
-    binding.dependencies = []
     depsObserver.on('get', function (dep) {
         binding.dependencies.push(dep)
     })