Преглед изворни кода

utils.processOptions()
merge utils.convertPartials & utils.convertComponents into one function
so it's cleaner in both main.js and compiler.js. Also removed some redundancy
for processing options.template.

Evan You пре 12 година
родитељ
комит
ee36feac09
6 измењених фајлова са 122 додато и 44 уклоњено
  1. 1 1
      README.md
  2. 3 12
      src/compiler.js
  3. 9 8
      src/main.js
  4. 41 15
      src/utils.js
  5. 19 0
      test/unit/specs/api.js
  6. 49 8
      test/unit/specs/utils.js

+ 1 - 1
README.md

@@ -4,7 +4,7 @@ Modern, lightweight JavaScript MVVM
 
 ## Features
 
-- <10kb gzipped, no dependency.
+- 10kb gzipped, no dependency.
 - DOM based templates with two-way data binding.
 - Precise and efficient DOM manipulation with granularity down to a TextNode.
 - POJSO (Plain Old JavaScript Objects) Models that can be shared across ViewModels with arbitrary levels of nesting.

+ 3 - 12
src/compiler.js

@@ -28,9 +28,9 @@ function Compiler (vm, options) {
     compiler.init = true
 
     // extend options
+    utils.processOptions(options)
     options = compiler.options = options || makeHash()
     utils.extend(compiler, options.compilerOptions)
-    utils.convertPartials(options.partials)
 
     // initialize element
     compiler.setupElement(options)
@@ -146,18 +146,9 @@ CompilerProto.setupElement = function (options) {
 
     // initialize template
     var template = options.template
-    if (typeof template === 'string') {
-        if (template.charAt(0) === '#') {
-            var templateNode = document.querySelector(template)
-            if (templateNode) {
-                el.innerHTML = templateNode.innerHTML
-            }
-        } else {
-            el.innerHTML = template
-        }
-    } else if (options.templateFragment) {
+    if (template) {
         el.innerHTML = ''
-        el.appendChild(options.templateFragment.cloneNode(true))
+        el.appendChild(template.cloneNode(true))
     }
 }
 

+ 9 - 8
src/main.js

@@ -38,9 +38,7 @@ ViewModel.filter = function (id, fn) {
  */
 ViewModel.component = function (id, Ctor) {
     if (!Ctor) return utils.components[id]
-    utils.components[id] = Ctor.prototype instanceof ViewModel
-        ? Ctor
-        : ViewModel.extend(Ctor)
+    utils.components[id] = utils.toConstructor(Ctor)
     return this
 }
 
@@ -49,7 +47,7 @@ ViewModel.component = function (id, Ctor) {
  */
 ViewModel.partial = function (id, partial) {
     if (!partial) return utils.partials[id]
-    utils.partials[id] = utils.templateToFragment(partial)
+    utils.partials[id] = utils.toFragment(partial)
     return this
 }
 
@@ -69,16 +67,22 @@ ViewModel.extend = extend
  *  and add extend method
  */
 function extend (options) {
+
     var ParentVM = this
+
     // inherit options
     options = inheritOptions(options, ParentVM.options, true)
+    utils.processOptions(options)
+
     var ExtendedVM = function (opts) {
         opts = inheritOptions(opts, options, true)
         ParentVM.call(this, opts)
     }
+
     // inherit prototype props
     var proto = ExtendedVM.prototype = Object.create(ParentVM.prototype)
     utils.defProtected(proto, 'constructor', ExtendedVM)
+
     // copy prototype props
     var protoMixins = options.proto
     if (protoMixins) {
@@ -88,10 +92,7 @@ function extend (options) {
             }
         }
     }
-    // convert template to documentFragment
-    if (options.template) {
-        options.templateFragment = utils.templateToFragment(options.template)
-    }
+
     // allow extended VM to be further extended
     ExtendedVM.extend = extend
     ExtendedVM.super = ParentVM

+ 41 - 15
src/utils.js

@@ -1,7 +1,8 @@
 var config    = require('./config'),
     toString  = Object.prototype.toString,
     join      = Array.prototype.join,
-    console   = window.console
+    console   = window.console,
+    ViewModel // late def
 
 /**
  *  Create a prototype-less object
@@ -66,23 +67,13 @@ var utils = module.exports = {
         }
     },
 
-    /**
-     *  Convert an object of partial strings
-     *  to domFragments
-     */
-    convertPartials: function (partials) {
-        if (!partials) return
-        for (var key in partials) {
-            if (typeof partials[key] === 'string') {
-                partials[key] = utils.templateToFragment(partials[key])
-            }
-        }
-    },
-
     /**
      *  Convert a string template to a dom fragment
      */
-    templateToFragment: function (template) {
+    toFragment: function (template) {
+        if (typeof template !== 'string') {
+            return template
+        }
         if (template.charAt(0) === '#') {
             var templateNode = document.getElementById(template.slice(1))
             if (!templateNode) return
@@ -99,6 +90,41 @@ var utils = module.exports = {
         return frag
     },
 
+    /**
+     *  Convert the object to a ViewModel constructor
+     *  if it is not already one
+     */
+    toConstructor: function (obj) {
+        ViewModel = ViewModel || require('./viewmodel')
+        return obj.prototype instanceof ViewModel || obj === ViewModel
+            ? obj
+            : ViewModel.extend(obj)
+    },
+
+    /**
+     *  convert certain option values to the desired format.
+     */
+    processOptions: function (options) {
+        if (!options) return
+        var components = options.components,
+            partials   = options.partials,
+            template   = options.template,
+            key
+        if (components) {
+            for (key in components) {
+                components[key] = utils.toConstructor(components[key])
+            }
+        }
+        if (partials) {
+            for (key in partials) {
+                partials[key] = utils.toFragment(partials[key])
+            }
+        }
+        if (template) {
+            options.template = utils.toFragment(template)
+        }
+    },
+
     /**
      *  log for debugging
      */

+ 19 - 0
test/unit/specs/api.js

@@ -525,6 +525,25 @@ describe('UNIT: API', function () {
                     assert.strictEqual(p.$el.querySelector('div').textContent, 'child')
                 })
 
+                it('should work with plain option object', function () {
+                    var Parent = Seed.extend({
+                        template: '<p>{{name}}</p><div sd-component="child">{{name}}</div>',
+                        scope: {
+                            name: 'dad'
+                        },
+                        components: {
+                            child: {
+                                scope: {
+                                    name: 'child'
+                                }
+                            }
+                        }
+                    })
+                    var p = new Parent()
+                    assert.strictEqual(p.$el.querySelector('p').textContent, 'dad')
+                    assert.strictEqual(p.$el.querySelector('div').textContent, 'child')
+                })
+
             })
 
             describe('partials', function () {

+ 49 - 8
test/unit/specs/utils.js

@@ -98,11 +98,11 @@ describe('UNIT: Utils', function () {
 
     })
 
-    describe('templateToFragment', function () {
+    describe('toFragment', function () {
         
         it('should convert a string tempalte to a documentFragment', function () {
             var template = '<div class="a">hi</div><p>ha</p>',
-                frag = utils.templateToFragment(template)
+                frag = utils.toFragment(template)
             assert.ok(frag instanceof window.DocumentFragment)
             assert.equal(frag.querySelector('.a').textContent, 'hi')
             assert.equal(frag.querySelector('p').textContent, 'ha')
@@ -116,7 +116,7 @@ describe('UNIT: Utils', function () {
                 el.innerHTML = template
             document.getElementById('test').appendChild(el)
 
-            var frag = utils.templateToFragment('#' + id)
+            var frag = utils.toFragment('#' + id)
             assert.ok(frag instanceof window.DocumentFragment)
             assert.equal(frag.querySelector('.a').textContent, 'hi')
             assert.equal(frag.querySelector('p').textContent, 'ha')
@@ -124,14 +124,42 @@ describe('UNIT: Utils', function () {
 
     })
 
-    describe('convertPartials', function () {
+    describe('toConstructor', function () {
         
-        it('should convert a hash object of strings to fragments', function () {
-            var partials = {
+        it('should convert an non-VM object to a VM constructor', function () {
+            var a = { test: 1 },
+                A = utils.toConstructor(a)
+            assert.ok(A.prototype instanceof Seed)
+            assert.strictEqual(A.options, a)
+        })
+
+        it('should return the argument if it is already a consutructor', function () {
+            var A = utils.toConstructor(Seed)
+            assert.strictEqual(A, Seed)
+        })
+
+    })
+
+    describe('processOptions', function () {
+        
+        var options = {
+            partials: {
                 a: '#utils-template-to-fragment',
                 b: '<div class="a">hi</div><p>ha</p>'
-            }
-            utils.convertPartials(partials)
+            },
+            components: {
+                a: { scope: { data: 1 } },
+                b: { scope: { data: 2 } }
+            },
+            template: '<a>{{hi}}</a>'
+        }
+
+        it('should convert string partials to fragment nodes', function () {
+
+            // call it here
+            utils.processOptions(options)
+
+            var partials = options.partials
             for (var key in partials) {
                 var frag = partials[key]
                 assert.ok(frag instanceof window.DocumentFragment)
@@ -140,6 +168,19 @@ describe('UNIT: Utils', function () {
             }
         })
 
+        it('should convert string template to fragment node', function () {
+            assert.ok(options.template instanceof window.DocumentFragment)
+            assert.equal(options.template.querySelector('a').textContent, '{{hi}}')
+        })
+
+        it('should convert plain object components to constructors', function () {
+            var components = options.components
+            assert.ok(components.a.prototype instanceof Seed)
+            assert.strictEqual(components.a.options.scope.data, 1)
+            assert.ok(components.b.prototype instanceof Seed)
+            assert.strictEqual(components.b.options.scope.data, 2)
+        })
+
     })
 
 })