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

support nested VMs and update examples to use new API

Evan You 12 лет назад
Родитель
Сommit
bf01a14629
10 измененных файлов с 130 добавлено и 91 удалено
  1. 3 2
      README.md
  2. 6 5
      TODO.md
  3. 44 0
      examples/nested-props.html
  4. 29 13
      examples/nested-viewmodels.html
  5. 0 48
      examples/nested_props.html
  6. 3 8
      examples/simple.html
  7. 28 13
      src/compiler.js
  8. 4 1
      src/directives/each.js
  9. 3 0
      src/main.js
  10. 10 1
      src/utils.js

+ 3 - 2
README.md

@@ -1,11 +1,12 @@
 # Seed (WIP)
 # Seed (WIP)
 ## a mini MVVM framework
 ## a mini MVVM framework
 
 
-- 6kb gzipped!
+- 7kb gzipped, no dependency.
 - DOM based templates with precise and efficient manipulation
 - DOM based templates with precise and efficient manipulation
 - POJSO (Plain Old JavaScript Objects) Models FTW - even nested objects.
 - POJSO (Plain Old JavaScript Objects) Models FTW - even nested objects.
+- Logic-less templating which enforces separation of concerns.
 - Auto dependency extraction for computed properties.
 - Auto dependency extraction for computed properties.
-- computed properties with dynamic context
+- Computed properties can have dynamic context.
 - Auto event delegation on repeated items.
 - Auto event delegation on repeated items.
 - [Component](https://github.com/component/component) based, can be used as a CommonJS module but can also be used alone.
 - [Component](https://github.com/component/component) based, can be used as a CommonJS module but can also be used alone.
 
 

+ 6 - 5
TODO.md

@@ -1,9 +1,10 @@
 - ability to register a ViewModel so it can be auto-compiled as a nested vm
 - ability to register a ViewModel so it can be auto-compiled as a nested vm
-- literals, function arguments, simple logic comparisons
 - let user specify which keys are data/state (i.e. available in $dump())
 - let user specify which keys are data/state (i.e. available in $dump())
 - tests
 - tests
 - docs
 - docs
-- validation as filter, e.g. sd-value="email | validate email"
-- sd-with
-- standarized way to reuse components (sd-component?)
-- plugins: seed-touch, seed-storage, seed-router
+- sd-with?
+- plugins
+    - seed-touch (e.g. sd-drag="onDrag" sd-swipe="onSwipe")
+    - seed-storage (RESTful sync)
+    - seed-router (express style)
+    - sd-validation (e.g. sd-validate="type:email, max:100, required:true")

+ 44 - 0
examples/nested-props.html

@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html lang="en">
+    <head>
+        <title></title>
+        <meta charset="utf-8">
+        <script src="../dist/seed.js"></script>
+    </head>
+    <body>
+        <h1>a.b.c : {{a.b.c}}</h1>
+        <h2>a.c : {{a.c}}</h2>
+        <h3>Computed property that concats the two: {{d}}</h3>
+        <button sd-on="click:one">one</button>
+        <button sd-on="click:two">two</button>
+        <button sd-on="click:three">three</button>
+        <script>
+            var Demo = Seed.ViewModel.extend({
+                properties: {
+                    one: function () {
+                        this.a = {
+                            c: 1,
+                            b: {
+                                c: 'one'
+                            }
+                        }
+                    },
+                    two: function () {
+                        this.a.b = {
+                            c: 'two'
+                        }
+                        this.a.c = 2
+                    },
+                    three: function () {
+                        this.a.b.c = 'three'
+                        this.a.c = 3
+                    },
+                    d: {get: function () {
+                        return (this.a.b.c + this.a.c) || ''
+                    }}
+                }
+            })
+            var app = new Demo({ el: document.body })
+        </script>
+    </body>
+</html>

+ 29 - 13
examples/nested_controllers.html → examples/nested-viewmodels.html

@@ -10,13 +10,13 @@
     <script src="../dist/seed.js"></script>
     <script src="../dist/seed.js"></script>
 </head>
 </head>
 <body>
 <body>
-    <div sd-controller="Grandpa">
+    <div id="grandpa">
         <p sd-text="name"></p>
         <p sd-text="name"></p>
-        <div sd-controller="Dad">
+        <div sd-viewmodel="Dad">
             <p><span sd-text="name"></span>, son of <span sd-text="^name"></span></p>
             <p><span sd-text="name"></span>, son of <span sd-text="^name"></span></p>
-            <div sd-controller="Son">
+            <div sd-viewmodel="Son">
                 <p><span sd-text="name"></span>,son of <span sd-text="^name"></span></p>
                 <p><span sd-text="name"></span>,son of <span sd-text="^name"></span></p>
-                <div sd-controller="Baby">
+                <div sd-viewmodel="Baby">
                     <p>
                     <p>
                         <span sd-text="name"></span>,
                         <span sd-text="name"></span>,
                         son of <span sd-text="^name"></span>,
                         son of <span sd-text="^name"></span>,
@@ -29,23 +29,39 @@
     </div>
     </div>
 
 
     <script>
     <script>
-        Seed.controller('Grandpa', function (scope, seed) {
-            scope.name = 'John'
+        Seed.config({
+            debug: true
         })
         })
 
 
-        Seed.controller('Dad', function (scope, seed) {
-            scope.name = 'Jack'
+        var Grandpa = Seed.ViewModel.extend({
+            properties: {
+                name: 'Andy'
+            }
         })
         })
 
 
-        Seed.controller('Son', function (scope, seed) {
-            scope.name = 'Jason'
+        var Dad = Seed.ViewModel.extend({
+            id: 'Dad',
+            properties: {
+                name: 'Jack'
+            }
         })
         })
 
 
-        Seed.controller('Baby', function (scope, seed) {
-            scope.name = 'James'
+        var Son = Seed.ViewModel.extend({
+            id: 'Son',
+            properties: {
+                name: 'Mike'
+            }
         })
         })
 
 
-        Seed.bootstrap()
+        var Baby = Seed.ViewModel.extend({
+            id: 'Baby',
+            properties: {
+                name: 'Tim'
+            }
+        })
+
+        var demo = new Grandpa({ el: '#grandpa' })
+
     </script>
     </script>
 </body>
 </body>
 </html>
 </html>

+ 0 - 48
examples/nested_props.html

@@ -1,48 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-    <head>
-        <title></title>
-        <meta charset="utf-8">
-        <script src="../dist/seed.js"></script>
-    </head>
-    <body sd-controller="test">
-        <h1>a.b.c : {{a.b.c}}</h1>
-        <h2>a.c : {{a.c}}</h2>
-        <h3>Computed property that concats the two: {{d}}</h3>
-        <button sd-on="click:one">one</button>
-        <button sd-on="click:two">two</button>
-        <button sd-on="click:three">three</button>
-        <script>
-            Seed.controller('test', function (scope) {
-
-                // set the data any way you want.
-                scope.one = function () {
-                    scope.a = {
-                        c: 1,
-                        b: {
-                            c: 'one'
-                        }
-                    }
-                }
-
-                scope.two = function () {
-                    scope.a.b = {
-                        c: 'two'
-                    }
-                    scope.a.c = 2
-                }
-
-                scope.three = function () {
-                    scope.a.b.c = 'three'
-                    scope.a.c = 3
-                }
-
-                // computed properties also works!!!!
-                scope.d = {get: function () {
-                    return (scope.a.b.c + scope.a.c) || ''
-                }}
-            })
-            var app = Seed.bootstrap()
-        </script>
-    </body>
-</html>

+ 3 - 8
examples/simple.html

@@ -8,17 +8,12 @@
         </style>
         </style>
         <script src="../dist/seed.js"></script>
         <script src="../dist/seed.js"></script>
     </head>
     </head>
-    <body sd-controller="hello">
+    <body>
         <input type="checkbox" sd-checked="checked">
         <input type="checkbox" sd-checked="checked">
         <span sd-text="hello | uppercase" sd-class="red:checked"></span>
         <span sd-text="hello | uppercase" sd-class="red:checked"></span>
         <script>
         <script>
-            Seed.controller('hello', function (scope) {
-                scope.hello = {get:function () {
-                    return scope.checked ? 'red!!!' : 'hello seed'
-                }}
-            })
-
-            Seed.bootstrap()
+            var demo = new Seed.ViewModel({ el: 'body' })
+            demo.hello = 'hi'
         </script>
         </script>
     </body>
     </body>
 </html>
 </html>

+ 28 - 13
src/compiler.js

@@ -5,9 +5,10 @@ var config          = require('./config'),
     TextParser      = require('./text-parser'),
     TextParser      = require('./text-parser'),
     DepsParser      = require('./deps-parser')
     DepsParser      = require('./deps-parser')
 
 
-var slice           = Array.prototype.slice,
-    ctrlAttr        = config.prefix + '-controller',
-    eachAttr        = config.prefix + '-each'
+var slice           = Array.prototype.slice
+
+// late bindings
+var vmAttr, eachAttr
 
 
 /*
 /*
  *  The DOM compiler
  *  The DOM compiler
@@ -17,6 +18,10 @@ function Compiler (vm, options) {
 
 
     utils.log('\nnew Compiler instance: ', vm.$el, '\n')
     utils.log('\nnew Compiler instance: ', vm.$el, '\n')
 
 
+    // need to refresh this everytime we compile
+    eachAttr = config.prefix + '-each'
+    vmAttr   = config.prefix + '-viewmodel'
+
     // copy options
     // copy options
     options = options || {}
     options = options || {}
     for (var op in options) {
     for (var op in options) {
@@ -81,7 +86,8 @@ var CompilerProto = Compiler.prototype
  *  Compile a DOM node (recursive)
  *  Compile a DOM node (recursive)
  */
  */
 CompilerProto.compileNode = function (node, root) {
 CompilerProto.compileNode = function (node, root) {
-    var compiler = this
+
+    var compiler = this, i, j
 
 
     if (node.nodeType === 3) { // text node
     if (node.nodeType === 3) { // text node
 
 
@@ -90,7 +96,7 @@ CompilerProto.compileNode = function (node, root) {
     } else if (node.nodeType === 1) {
     } else if (node.nodeType === 1) {
 
 
         var eachExp = node.getAttribute(eachAttr),
         var eachExp = node.getAttribute(eachAttr),
-            ctrlExp = node.getAttribute(ctrlAttr),
+            vmExp   = node.getAttribute(vmAttr),
             directive
             directive
 
 
         if (eachExp) { // each block
         if (eachExp) { // each block
@@ -101,22 +107,27 @@ CompilerProto.compileNode = function (node, root) {
                 compiler.bindDirective(directive)
                 compiler.bindDirective(directive)
             }
             }
 
 
-        } else if (ctrlExp && !root) { // nested controllers
+        } else if (vmExp && !root) { // nested ViewModels
 
 
-            new Compiler(node, {
-                child: true,
-                parentCompiler: compiler
-            })
+            var ChildVM = utils.getVM(vmExp)
+            if (ChildVM) {
+                new ChildVM({
+                    el: node,
+                    child: true,
+                    parentCompiler: compiler
+                })
+            }
 
 
         } else { // normal node
         } else { // normal node
 
 
             // parse if has attributes
             // parse if has attributes
             if (node.attributes && node.attributes.length) {
             if (node.attributes && node.attributes.length) {
                 var attrs = slice.call(node.attributes),
                 var attrs = slice.call(node.attributes),
-                    i = attrs.length, attr, j, valid, exps, exp
+                    attr, valid, exps, exp
+                i = attrs.length
                 while (i--) {
                 while (i--) {
                     attr = attrs[i]
                     attr = attrs[i]
-                    if (attr.name === ctrlAttr) continue
+                    if (attr.name === vmAttr) continue
                     valid = false
                     valid = false
                     exps = attr.value.split(',')
                     exps = attr.value.split(',')
                     j = exps.length
                     j = exps.length
@@ -135,7 +146,11 @@ CompilerProto.compileNode = function (node, root) {
 
 
             // recursively compile childNodes
             // recursively compile childNodes
             if (node.childNodes.length) {
             if (node.childNodes.length) {
-                slice.call(node.childNodes).forEach(compiler.compileNode, compiler)
+                var nodes = slice.call(node.childNodes)
+                i = nodes.length
+                while (i--) {
+                    this.compileNode(nodes[i])
+                }
             }
             }
         }
         }
     }
     }

+ 4 - 1
src/directives/each.js

@@ -1,4 +1,5 @@
 var config = require('../config'),
 var config = require('../config'),
+    utils  = require('../utils'),
     ViewModel // lazy def to avoid circular dependency
     ViewModel // lazy def to avoid circular dependency
 
 
 /*
 /*
@@ -111,7 +112,9 @@ module.exports = {
         var node = this.el.cloneNode(true)
         var node = this.el.cloneNode(true)
         this.container.insertBefore(node, ref)
         this.container.insertBefore(node, ref)
         ViewModel = ViewModel || require('../viewmodel')
         ViewModel = ViewModel || require('../viewmodel')
-        var item = new ViewModel({
+        var vmID = node.getAttribute(config.prefix + '-viewmodel'),
+            ChildVM = utils.getVM(vmID) || ViewModel
+        var item = new ChildVM({
             el: node,
             el: node,
             each: true,
             each: true,
             eachPrefix: this.arg + '.',
             eachPrefix: this.arg + '.',

+ 3 - 0
src/main.js

@@ -72,6 +72,9 @@ ViewModel.extend = function (options) {
             p[prop] = options.properties[prop]
             p[prop] = options.properties[prop]
         }
         }
     }
     }
+    if (options.id) {
+        utils.registerVM(options.id, ExtendedVM)
+    }
     return ExtendedVM
     return ExtendedVM
 }
 }
 
 

+ 10 - 1
src/utils.js

@@ -2,7 +2,8 @@ var config        = require('./config'),
     Emitter       = require('emitter'),
     Emitter       = require('emitter'),
     toString      = Object.prototype.toString,
     toString      = Object.prototype.toString,
     aproto        = Array.prototype,
     aproto        = Array.prototype,
-    templates     = {}
+    templates     = {},
+    VMs           = {}
 
 
 var arrayAugmentations = {
 var arrayAugmentations = {
     remove: function (index) {
     remove: function (index) {
@@ -126,6 +127,14 @@ module.exports = {
         return el
         return el
     },
     },
 
 
+    registerVM: function (id, VM) {
+        VMs[id] = VM
+    },
+
+    getVM: function (id) {
+        return VMs[id]
+    },
+
     log: function () {
     log: function () {
         if (config.debug) console.log.apply(console, arguments)
         if (config.debug) console.log.apply(console, arguments)
         return this
         return this