Quellcode durchsuchen

support nested VMs and update examples to use new API

Evan You vor 13 Jahren
Ursprung
Commit
bf01a14629
10 geänderte Dateien mit 130 neuen und 91 gelöschten Zeilen
  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)
 ## a mini MVVM framework
 
-- 6kb gzipped!
+- 7kb gzipped, no dependency.
 - DOM based templates with precise and efficient manipulation
 - POJSO (Plain Old JavaScript Objects) Models FTW - even nested objects.
+- Logic-less templating which enforces separation of concerns.
 - Auto dependency extraction for computed properties.
-- computed properties with dynamic context
+- Computed properties can have dynamic context.
 - 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.
 

+ 6 - 5
TODO.md

@@ -1,9 +1,10 @@
 - 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())
 - tests
 - 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>
 </head>
 <body>
-    <div sd-controller="Grandpa">
+    <div id="grandpa">
         <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>
-            <div sd-controller="Son">
+            <div sd-viewmodel="Son">
                 <p><span sd-text="name"></span>,son of <span sd-text="^name"></span></p>
-                <div sd-controller="Baby">
+                <div sd-viewmodel="Baby">
                     <p>
                         <span sd-text="name"></span>,
                         son of <span sd-text="^name"></span>,
@@ -29,23 +29,39 @@
     </div>
 
     <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>
 </body>
 </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>
         <script src="../dist/seed.js"></script>
     </head>
-    <body sd-controller="hello">
+    <body>
         <input type="checkbox" sd-checked="checked">
         <span sd-text="hello | uppercase" sd-class="red:checked"></span>
         <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>
     </body>
 </html>

+ 28 - 13
src/compiler.js

@@ -5,9 +5,10 @@ var config          = require('./config'),
     TextParser      = require('./text-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
@@ -17,6 +18,10 @@ function Compiler (vm, options) {
 
     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
     options = options || {}
     for (var op in options) {
@@ -81,7 +86,8 @@ var CompilerProto = Compiler.prototype
  *  Compile a DOM node (recursive)
  */
 CompilerProto.compileNode = function (node, root) {
-    var compiler = this
+
+    var compiler = this, i, j
 
     if (node.nodeType === 3) { // text node
 
@@ -90,7 +96,7 @@ CompilerProto.compileNode = function (node, root) {
     } else if (node.nodeType === 1) {
 
         var eachExp = node.getAttribute(eachAttr),
-            ctrlExp = node.getAttribute(ctrlAttr),
+            vmExp   = node.getAttribute(vmAttr),
             directive
 
         if (eachExp) { // each block
@@ -101,22 +107,27 @@ CompilerProto.compileNode = function (node, root) {
                 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
 
             // parse if has attributes
             if (node.attributes && node.attributes.length) {
                 var attrs = slice.call(node.attributes),
-                    i = attrs.length, attr, j, valid, exps, exp
+                    attr, valid, exps, exp
+                i = attrs.length
                 while (i--) {
                     attr = attrs[i]
-                    if (attr.name === ctrlAttr) continue
+                    if (attr.name === vmAttr) continue
                     valid = false
                     exps = attr.value.split(',')
                     j = exps.length
@@ -135,7 +146,11 @@ CompilerProto.compileNode = function (node, root) {
 
             // recursively compile childNodes
             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'),
+    utils  = require('../utils'),
     ViewModel // lazy def to avoid circular dependency
 
 /*
@@ -111,7 +112,9 @@ module.exports = {
         var node = this.el.cloneNode(true)
         this.container.insertBefore(node, ref)
         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,
             each: true,
             eachPrefix: this.arg + '.',

+ 3 - 0
src/main.js

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

+ 10 - 1
src/utils.js

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