Skip to content

Commit

Permalink
utils.processOptions()
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Evan You committed Nov 14, 2013
1 parent 5ad8ede commit ee36fea
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 44 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -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.
Expand Down
15 changes: 3 additions & 12 deletions src/compiler.js
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
}
}

Expand Down
17 changes: 9 additions & 8 deletions src/main.js
Expand Up @@ -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
}

Expand All @@ -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
}

Expand All @@ -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) {
Expand All @@ -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
Expand Down
56 changes: 41 additions & 15 deletions 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
Expand Down Expand Up @@ -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
Expand All @@ -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
*/
Expand Down
19 changes: 19 additions & 0 deletions test/unit/specs/api.js
Expand Up @@ -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 () {
Expand Down
57 changes: 49 additions & 8 deletions test/unit/specs/utils.js
Expand Up @@ -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')
Expand All @@ -116,22 +116,50 @@ 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')
})

})

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)
Expand All @@ -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)
})

})

})

0 comments on commit ee36fea

Please sign in to comment.