Evan You пре 12 година
родитељ
комит
3cbf498d5a
7 измењених фајлова са 112 додато и 41 уклоњено
  1. 31 19
      src/compiler.js
  2. 4 5
      src/directive.js
  3. 1 6
      src/directives/each.js
  4. 13 0
      src/main.js
  5. 55 9
      test/unit/specs/api.js
  6. 1 0
      test/unit/specs/directive.js
  7. 7 2
      test/unit/specs/text-parser.js

+ 31 - 19
src/compiler.js

@@ -173,10 +173,9 @@ CompilerProto.compile = function (node, root) {
     var compiler = this
     if (node.nodeType === 1) {
         // a normal node
-        var opts       = compiler.options,
-            eachExp    = node.getAttribute(eachAttr),
-            vmExp      = node.getAttribute(vmAttr),
-            partialExp = node.getAttribute(partialAttr)
+        var eachExp    = node.getAttribute(eachAttr),
+            vmId       = node.getAttribute(vmAttr),
+            partialId  = node.getAttribute(partialAttr)
         // we need to check for any possbile special directives
         // e.g. sd-each, sd-viewmodel & sd-partial
         if (eachExp) { // each block
@@ -184,11 +183,9 @@ CompilerProto.compile = function (node, root) {
             if (directive) {
                 compiler.bindDirective(directive)
             }
-        } else if (vmExp && !root) { // nested ViewModels
+        } else if (vmId && !root) { // nested ViewModels
             node.removeAttribute(vmAttr)
-            var ChildVM =
-                (opts.vms && opts.vms[vmExp]) ||
-                utils.vms[vmExp]
+            var ChildVM = compiler.getOption('vms', vmId)
             if (ChildVM) {
                 new ChildVM({
                     el: node,
@@ -199,11 +196,9 @@ CompilerProto.compile = function (node, root) {
                 })
             }
         } else {
-            if (partialExp) { // replace innerHTML with partial
+            if (partialId) { // replace innerHTML with partial
                 node.removeAttribute(partialAttr)
-                var partial =
-                    (opts.partials && opts.partials[partialExp]) ||
-                    utils.partials[partialExp]
+                var partial = compiler.getOption('partials', partialId)
                 if (partial) {
                     node.innerHTML = ''
                     node.appendChild(partial.cloneNode(true))
@@ -265,14 +260,23 @@ CompilerProto.compileTextNode = function (node) {
         el, token, directive
     for (var i = 0, l = tokens.length; i < l; i++) {
         token = tokens[i]
-        el = document.createTextNode('')
-        if (token.key) {
-            directive = Directive.parse(dirname, token.key, this, el)
-            if (directive) {
-                this.bindDirective(directive)
+        if (token.key) { // a binding
+            if (token.key.charAt(0) === '>') { // a partial
+                var partialId = token.key.slice(1),
+                    partial = this.getOption('partials', partialId)
+                if (partial) {
+                    el = partial.cloneNode(true)
+                    this.compileNode(el)
+                }
+            } else { // a binding
+                el = document.createTextNode('')
+                directive = Directive.parse(dirname, token.key, this, el)
+                if (directive) {
+                    this.bindDirective(directive)
+                }
             }
-        } else {
-            el.nodeValue = token
+        } else { // a plain string
+            el = document.createTextNode(token)
         }
         node.parentNode.insertBefore(el, node)
     }
@@ -505,6 +509,14 @@ CompilerProto.bindContexts = function (bindings) {
     }
 }
 
+/*
+ *  Retrive an option from the compiler
+ */
+CompilerProto.getOption = function (type, id) {
+    var opts = this.options
+    return (opts[type] && opts[type][id]) || (utils[type] && utils[type][id])
+}
+
 /*
  *  Unbind and remove element
  */

+ 4 - 5
src/directive.js

@@ -46,7 +46,7 @@ function Directive (definition, directiveName, expression, rawKey, compiler, nod
         this.filters = []
         var i = 0, l = filterExps.length, filter
         for (; i < l; i++) {
-            filter = parseFilter(filterExps[i], this.compiler.options)
+            filter = parseFilter(filterExps[i], this.compiler)
             if (filter) this.filters.push(filter)
         }
         if (!this.filters.length) this.filters = null
@@ -91,7 +91,7 @@ function parseKey (dir, rawKey) {
 /*
  *  parse a filter expression
  */
-function parseFilter (filter, options) {
+function parseFilter (filter, compiler) {
 
     var tokens = filter.slice(1).match(FILTER_TOKEN_RE)
     if (!tokens) return
@@ -100,7 +100,7 @@ function parseFilter (filter, options) {
     })
 
     var name = tokens[0],
-        apply = (options.filters && options.filters[name]) || filters[name]
+        apply = compiler.getOption('filters', name) || filters[name]
     if (!apply) {
         utils.warn('Unknown filter: ' + name)
         return
@@ -190,8 +190,7 @@ Directive.parse = function (dirname, expression, compiler, node) {
     if (dirname.indexOf(prefix) === -1) return null
     dirname = dirname.slice(prefix.length + 1)
 
-    var opts = compiler.options,
-        dir = (opts.directives && opts.directives[dirname]) || directives[dirname],
+    var dir = compiler.getOption('directives', dirname) || directives[dirname],
         keyMatch = expression.match(KEY_RE),
         rawKey = keyMatch && keyMatch[0].trim()
 

+ 1 - 6
src/directives/each.js

@@ -1,5 +1,4 @@
 var config   = require('../config'),
-    utils    = require('../utils'),
     Observer = require('../observer'),
     Emitter  = require('../emitter'),
     ViewModel // lazy def to avoid circular dependency
@@ -139,11 +138,7 @@ module.exports = {
         var node = this.el.cloneNode(true),
             ctn  = this.container,
             vmID = node.getAttribute(config.prefix + '-viewmodel'),
-            opts = this.compiler.options,
-            ChildVM =
-                (opts.vms && opts.vms[vmID]) ||
-                utils.vms[vmID] ||
-                ViewModel,
+            ChildVM = this.compiler.getOption('vms', vmID) || ViewModel,
             wrappedData = {}
         wrappedData[this.arg] = data || {}
         var item = new ChildVM({

+ 13 - 0
src/main.js

@@ -109,6 +109,7 @@ function extend (options) {
  */
 function inheritOptions (child, parent, topLevel) {
     child = child || {}
+    convertPartials(child.partials)
     if (!parent) return child
     for (var key in parent) {
         if (key === 'el' || key === 'props') continue
@@ -121,6 +122,18 @@ function inheritOptions (child, parent, topLevel) {
     return child
 }
 
+/*
+ *  Convert an object of partials to dom fragments
+ */
+function convertPartials (partials) {
+    if (!partials) return
+    for (var key in partials) {
+        if (typeof partials[key] === 'string') {
+            partials[key] = templateToFragment(partials[key])
+        }
+    }
+}
+
 /*
  *  Convert a string template to a dom fragment
  */

+ 55 - 9
test/unit/specs/api.js

@@ -167,16 +167,28 @@ describe('UNIT: API', function () {
             assert.strictEqual(utils.partials[testId], seed.partial(testId))
         })
 
-        it('should work with sd-partial', function () {
-            mock(testId, 'hello', {
-                'sd-partial': testId
+        it('should work with sd-partial as a directive', function () {
+            var testId = 'api-partial-direcitve'
+            seed.partial(testId, partial)
+            mock(testId, '<div class="directive" sd-partial="' + testId + '">hello</div>')
+            var t = new seed.ViewModel({
+                el: '#' + testId,
+                data: { hi: 'hohoho' }
             })
+            assert.strictEqual(t.$el.querySelector('.directive .partial-test a').textContent, 'hohoho')
+            assert.strictEqual(t.$el.querySelector('.directive span').innerHTML, 'hahaha')
+        })
+
+        it('should work with sd-partial as an inline interpolation', function () {
+            var testId = 'api-partial-inline'
+            seed.partial(testId, partial)
+            mock(testId, '<div class="inline">{{>' + testId + '}}</div>')
             var t = new seed.ViewModel({
                 el: '#' + testId,
                 data: { hi: 'hohoho' }
             })
-            assert.strictEqual(t.$el.querySelector('.partial-test a').textContent, 'hohoho')
-            assert.strictEqual(t.$el.querySelector('span').innerHTML, 'hahaha')
+            assert.strictEqual(t.$el.querySelector('.inline .partial-test a').textContent, 'hohoho')
+            assert.strictEqual(t.$el.querySelector('.inline span').innerHTML, 'hahaha')
         })
     })
 
@@ -441,15 +453,49 @@ describe('UNIT: API', function () {
             })
 
             describe('vms', function () {
-                it('should be tested', function () {
-                    assert.ok(false)
+
+                it('should allow the VM to use private child VMs', function () {
+                    var Child = seed.ViewModel.extend({
+                        data: {
+                            name: 'child'
+                        }
+                    })
+                    var Parent = seed.ViewModel.extend({
+                        template: '<p>{{name}}</p><div sd-viewmodel="child">{{name}}</div>',
+                        data: {
+                            name: 'dad'
+                        },
+                        vms: {
+                            child: Child
+                        }
+                    })
+                    var p = new Parent()
+                    assert.strictEqual(p.$el.querySelector('p').textContent, 'dad')
+                    assert.strictEqual(p.$el.querySelector('div').textContent, 'child')
                 })
+
             })
 
             describe('partials', function () {
-                it('should be tested', function () {
-                    assert.ok(false)
+                
+                it('should allow the VM to use private partials', function () {
+                    var Test = seed.ViewModel.extend({
+                        attributes: {
+                            'sd-partial': 'test'
+                        },
+                        partials: {
+                            test: '<a>{{a}}</a><p>{{b}}</p>'
+                        },
+                        data: {
+                            a: 'hi',
+                            b: 'ho'
+                        }
+                    })
+                    var t = new Test()
+                    assert.strictEqual(t.$el.querySelector('a').textContent, 'hi')
+                    assert.strictEqual(t.$el.querySelector('p').textContent, 'ho')
                 })
+
             })
 
             describe('transitions', function () {

+ 1 - 0
test/unit/specs/directive.js

@@ -5,6 +5,7 @@ describe('UNIT: Directive', function () {
 
     var compiler = {
         options: {},
+        getOption: function () {},
         vm: {
             constructor: {}
         }

+ 7 - 2
test/unit/specs/text-parser.js

@@ -16,16 +16,17 @@ describe('UNIT: TextNode Parser', function () {
             assert.strictEqual(result[2], ' &#123;&#123;hello&#125;&#125;')
         })
 
-        var tokens = TextParser.parse('hello {{a}}! {{ bcd }}{{d.e.f}} {{a + (b || c) ? d : e}}')
+        var tokens = TextParser.parse('hello {{a}}! {{ bcd }}{{d.e.f}} {{a + (b || c) ? d : e}} {{>test}}')
         
         it('should extract correct amount of tokens', function () {
-            assert.strictEqual(tokens.length, 7)
+            assert.strictEqual(tokens.length, 9)
         })
 
         it('should extract plain strings', function () {
             assert.strictEqual(typeof tokens[0], 'string')
             assert.strictEqual(typeof tokens[2], 'string')
             assert.strictEqual(typeof tokens[5], 'string')
+            assert.strictEqual(typeof tokens[7], 'string')
         })
 
         it('should extract basic keys', function () {
@@ -44,6 +45,10 @@ describe('UNIT: TextNode Parser', function () {
             assert.strictEqual(tokens[6].key, 'a + (b || c) ? d : e')
         })
 
+        it('should extract partials', function () {
+            assert.strictEqual(tokens[8].key, '>test')
+        })
+
     })
 
     describe('.buildRegex()', function () {