Răsfoiți Sursa

nested properties

Evan You 13 ani în urmă
părinte
comite
4126f41b08
11 a modificat fișierele cu 121 adăugiri și 46 ștergeri
  1. 2 1
      .gitignore
  2. 0 4
      TODO.md
  3. 1 1
      component.json
  4. 0 0
      examples/nested_controllers.html
  5. 39 0
      examples/nested_props.html
  6. 1 1
      package.json
  7. 70 29
      src/binding.js
  8. 0 6
      src/directive-parser.js
  9. 1 1
      src/directives/each.js
  10. 4 2
      src/main.js
  11. 3 1
      src/seed.js

+ 2 - 1
.gitignore

@@ -2,4 +2,5 @@
 .sass-cache
 .sass-cache
 node_modules
 node_modules
 components
 components
-dist
+dist
+explorations

+ 0 - 4
TODO.md

@@ -1,7 +1,3 @@
-- nested properties in scope
-    - parse path in Directive parser
-    - 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
 - sd-with
 - standarized way to reuse components (sd-component?)
 - standarized way to reuse components (sd-component?)
 - plugins: seed-touch, seed-storage, seed-router
 - plugins: seed-touch, seed-storage, seed-router

+ 1 - 1
component.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "seed",
   "name": "seed",
-  "version": "0.0.1",
+  "version": "0.1.0",
   "main": "src/main.js",
   "main": "src/main.js",
   "scripts": [
   "scripts": [
     "src/main.js",
     "src/main.js",

+ 0 - 0
examples/nested.html → examples/nested_controllers.html


+ 39 - 0
examples/nested_props.html

@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <title></title>
+        <meta charset="utf-8">
+        <script src="../dist/seed.js"></script>
+    </head>
+    <body sd-controller="test">
+        <h1 sd-text="a.b.c"></h1>
+        <h3 sd-text="a.c"></h3>
+        <button sd-on="click:one">one</button>
+        <button sd-on="click:two">two</button>
+        <button sd-on="click:three">three</button>
+        <script>
+            var Seed = require('seed')
+            Seed.controller('test', function (scope) {
+                scope.one = function () {
+                    scope.a = {
+                        c: 1,
+                        b: {
+                            c: 1
+                        }
+                    }
+                }
+                scope.two = function () {
+                    scope.a.b = {
+                        c: 2
+                    }
+                    scope.a.c = 2
+                }
+                scope.three = function () {
+                    scope.a.b.c = 3
+                    scope.a.c = 3
+                }
+            })
+            var app = Seed.bootstrap()
+        </script>
+    </body>
+</html>

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "seed",
   "name": "seed",
-  "version": "0.0.1",
+  "version": "0.1.0",
   "devDependencies": {
   "devDependencies": {
     "grunt": "~0.4.1",
     "grunt": "~0.4.1",
     "grunt-contrib-watch": "~0.4.4",
     "grunt-contrib-watch": "~0.4.4",

+ 70 - 29
src/binding.js

@@ -10,11 +10,12 @@ var Emitter  = require('emitter'),
  */
  */
 function Binding (seed, key) {
 function Binding (seed, key) {
     this.seed = seed
     this.seed = seed
-    this.key = key
-    this.set(seed.scope[key])
-    this.defineAccessors(seed, key)
-    this.instances = []
-    this.dependents = []
+    this.key  = key
+    var path = key.split('.')
+    this.set(getValue(seed.scope, path))
+    this.defineAccessors(seed.scope, path)
+    this.instances    = []
+    this.dependents   = []
     this.dependencies = []
     this.dependencies = []
 }
 }
 
 
@@ -28,8 +29,6 @@ Binding.prototype.set = function (value) {
     if (type === 'Object') {
     if (type === 'Object') {
         if (value.get || value.set) { // computed property
         if (value.get || value.set) { // computed property
             self.isComputed = true
             self.isComputed = true
-        } else { // normal object
-            // TODO watchObject
         }
         }
     } else if (type === 'Array') {
     } else if (type === 'Array') {
         watchArray(value)
         watchArray(value)
@@ -43,31 +42,57 @@ Binding.prototype.set = function (value) {
 /*
 /*
  *  Define getter/setter for this binding on scope
  *  Define getter/setter for this binding on scope
  */
  */
-Binding.prototype.defineAccessors = function (seed, key) {
-    var self = this
-    Object.defineProperty(seed.scope, key, {
-        get: function () {
-            if (observer.isObserving) {
-                observer.emit('get', self)
-            }
-            return self.isComputed
-                ? self.value.get()
-                : self.value
-        },
-        set: function (value) {
-            if (self.isComputed) {
-                // computed properties cannot be redefined
-                // no need to call binding.update() here,
-                // as dependency extraction has taken care of that
-                if (self.value.set) {
-                    self.value.set(value)
+Binding.prototype.defineAccessors = function (scope, path) {
+    var self = this,
+        key = path[0]
+    if (path.length === 1) {
+        // here we are! at the end of the path!
+        // define the real value accessors.
+        Object.defineProperty(scope, key, {
+            get: function () {
+                if (observer.isObserving) {
+                    observer.emit('get', self)
+                }
+                return self.isComputed
+                    ? self.value.get()
+                    : self.value
+            },
+            set: function (value) {
+                if (self.isComputed) {
+                    // computed properties cannot be redefined
+                    // no need to call binding.update() here,
+                    // as dependency extraction has taken care of that
+                    if (self.value.set) {
+                        self.value.set(value)
+                    }
+                } else if (value !== self.value) {
+                    self.value = value
+                    self.update(value)
                 }
                 }
-            } else if (value !== self.value) {
-                self.value = value
-                self.update(value)
             }
             }
+        })
+    } else {
+        // we are not there yet!!!
+        // create an intermediate subscope
+        // which also has its own getter/setters
+        var subScope = scope[key]
+        if (!subScope) {
+            subScope = {}
+            Object.defineProperty(scope, key, {
+                get: function () {
+                    return subScope
+                },
+                set: function (value) {
+                    // when the subScope is given a new value,
+                    // copy everything over to trigger the setters
+                    for (var prop in value) {
+                        subScope[prop] = value[prop]
+                    }
+                }
+            })
         }
         }
-    })
+        this.defineAccessors(subScope, path.slice(1))
+    }
 }
 }
 
 
 /*
 /*
@@ -91,6 +116,22 @@ Binding.prototype.emitChange = function () {
     })
     })
 }
 }
 
 
+// Helpers --------------------------------------------------------------------
+
+/*
+ *  Get a value from an object based on a path array
+ */
+function getValue (scope, path) {
+    if (path.length === 1) return scope[path[0]]
+    var i = 0
+    /* jshint boss: true */
+    while (scope[path[i]]) {
+        scope = scope[path[i]]
+        i++
+    }
+    return i === path.length ? scope : undefined
+}
+
 /*
 /*
  *  get accurate type of an object
  *  get accurate type of an object
  */
  */

+ 0 - 6
src/directive-parser.js

@@ -125,12 +125,6 @@ Directive.prototype.parseKey = function (rawKey) {
         key = key.slice(1)
         key = key.slice(1)
     }
     }
 
 
-    if (key.indexOf('.') > 0) {
-        var path = key.split('.')
-        key = path[path.length - 1]
-        this.path = path.slice(0, -1)
-    }
-
     this.key = key
     this.key = key
 }
 }
 
 

+ 1 - 1
src/directives/each.js

@@ -109,7 +109,7 @@ module.exports = {
             node = this.el.cloneNode(true)
             node = this.el.cloneNode(true)
         var spore = new Seed(node, {
         var spore = new Seed(node, {
                 each: true,
                 each: true,
-                eachPrefix: this.arg,
+                eachPrefix: this.arg + '.',
                 parentSeed: this.seed,
                 parentSeed: this.seed,
                 index: index,
                 index: index,
                 data: data,
                 data: data,

+ 4 - 2
src/main.js

@@ -65,11 +65,13 @@ api.bootstrap = function (opts) {
     textParser.buildRegex()
     textParser.buildRegex()
     var el,
     var el,
         ctrlSlt = '[' + config.prefix + '-controller]',
         ctrlSlt = '[' + config.prefix + '-controller]',
-        dataSlt = '[' + config.prefix + '-data]'
+        dataSlt = '[' + config.prefix + '-data]',
+        seeds = []
     /* jshint boss: true */
     /* jshint boss: true */
     while (el = document.querySelector(ctrlSlt) || document.querySelector(dataSlt)) {
     while (el = document.querySelector(ctrlSlt) || document.querySelector(dataSlt)) {
-        new Seed(el)
+        seeds.push(new Seed(el))
     }
     }
+    return seeds
 }
 }
 
 
 module.exports = api
 module.exports = api

+ 3 - 1
src/seed.js

@@ -170,7 +170,9 @@ Seed.prototype._bind = function (directive) {
         seed = directive.seed = this
         seed = directive.seed = this
 
 
     if (this.each) {
     if (this.each) {
-        if (!directive.path || directive.path[0] !== this.eachPrefix) {
+        if (key.indexOf(this.eachPrefix) === 0) {
+            key = directive.key = key.replace(this.eachPrefix, '')
+        } else {
             seed = this.parentSeed
             seed = this.parentSeed
         }
         }
     }
     }