Skip to content

Commit ee36fea

Browse files
author
Evan You
committed
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.
1 parent 5ad8ede commit ee36fea

File tree

6 files changed

+122
-44
lines changed

6 files changed

+122
-44
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Modern, lightweight JavaScript MVVM
44

55
## Features
66

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

src/compiler.js

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ function Compiler (vm, options) {
2828
compiler.init = true
2929

3030
// extend options
31+
utils.processOptions(options)
3132
options = compiler.options = options || makeHash()
3233
utils.extend(compiler, options.compilerOptions)
33-
utils.convertPartials(options.partials)
3434

3535
// initialize element
3636
compiler.setupElement(options)
@@ -146,18 +146,9 @@ CompilerProto.setupElement = function (options) {
146146

147147
// initialize template
148148
var template = options.template
149-
if (typeof template === 'string') {
150-
if (template.charAt(0) === '#') {
151-
var templateNode = document.querySelector(template)
152-
if (templateNode) {
153-
el.innerHTML = templateNode.innerHTML
154-
}
155-
} else {
156-
el.innerHTML = template
157-
}
158-
} else if (options.templateFragment) {
149+
if (template) {
159150
el.innerHTML = ''
160-
el.appendChild(options.templateFragment.cloneNode(true))
151+
el.appendChild(template.cloneNode(true))
161152
}
162153
}
163154

src/main.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ ViewModel.filter = function (id, fn) {
3838
*/
3939
ViewModel.component = function (id, Ctor) {
4040
if (!Ctor) return utils.components[id]
41-
utils.components[id] = Ctor.prototype instanceof ViewModel
42-
? Ctor
43-
: ViewModel.extend(Ctor)
41+
utils.components[id] = utils.toConstructor(Ctor)
4442
return this
4543
}
4644

@@ -49,7 +47,7 @@ ViewModel.component = function (id, Ctor) {
4947
*/
5048
ViewModel.partial = function (id, partial) {
5149
if (!partial) return utils.partials[id]
52-
utils.partials[id] = utils.templateToFragment(partial)
50+
utils.partials[id] = utils.toFragment(partial)
5351
return this
5452
}
5553

@@ -69,16 +67,22 @@ ViewModel.extend = extend
6967
* and add extend method
7068
*/
7169
function extend (options) {
70+
7271
var ParentVM = this
72+
7373
// inherit options
7474
options = inheritOptions(options, ParentVM.options, true)
75+
utils.processOptions(options)
76+
7577
var ExtendedVM = function (opts) {
7678
opts = inheritOptions(opts, options, true)
7779
ParentVM.call(this, opts)
7880
}
81+
7982
// inherit prototype props
8083
var proto = ExtendedVM.prototype = Object.create(ParentVM.prototype)
8184
utils.defProtected(proto, 'constructor', ExtendedVM)
85+
8286
// copy prototype props
8387
var protoMixins = options.proto
8488
if (protoMixins) {
@@ -88,10 +92,7 @@ function extend (options) {
8892
}
8993
}
9094
}
91-
// convert template to documentFragment
92-
if (options.template) {
93-
options.templateFragment = utils.templateToFragment(options.template)
94-
}
95+
9596
// allow extended VM to be further extended
9697
ExtendedVM.extend = extend
9798
ExtendedVM.super = ParentVM

src/utils.js

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
var config = require('./config'),
22
toString = Object.prototype.toString,
33
join = Array.prototype.join,
4-
console = window.console
4+
console = window.console,
5+
ViewModel // late def
56

67
/**
78
* Create a prototype-less object
@@ -66,23 +67,13 @@ var utils = module.exports = {
6667
}
6768
},
6869

69-
/**
70-
* Convert an object of partial strings
71-
* to domFragments
72-
*/
73-
convertPartials: function (partials) {
74-
if (!partials) return
75-
for (var key in partials) {
76-
if (typeof partials[key] === 'string') {
77-
partials[key] = utils.templateToFragment(partials[key])
78-
}
79-
}
80-
},
81-
8270
/**
8371
* Convert a string template to a dom fragment
8472
*/
85-
templateToFragment: function (template) {
73+
toFragment: function (template) {
74+
if (typeof template !== 'string') {
75+
return template
76+
}
8677
if (template.charAt(0) === '#') {
8778
var templateNode = document.getElementById(template.slice(1))
8879
if (!templateNode) return
@@ -99,6 +90,41 @@ var utils = module.exports = {
9990
return frag
10091
},
10192

93+
/**
94+
* Convert the object to a ViewModel constructor
95+
* if it is not already one
96+
*/
97+
toConstructor: function (obj) {
98+
ViewModel = ViewModel || require('./viewmodel')
99+
return obj.prototype instanceof ViewModel || obj === ViewModel
100+
? obj
101+
: ViewModel.extend(obj)
102+
},
103+
104+
/**
105+
* convert certain option values to the desired format.
106+
*/
107+
processOptions: function (options) {
108+
if (!options) return
109+
var components = options.components,
110+
partials = options.partials,
111+
template = options.template,
112+
key
113+
if (components) {
114+
for (key in components) {
115+
components[key] = utils.toConstructor(components[key])
116+
}
117+
}
118+
if (partials) {
119+
for (key in partials) {
120+
partials[key] = utils.toFragment(partials[key])
121+
}
122+
}
123+
if (template) {
124+
options.template = utils.toFragment(template)
125+
}
126+
},
127+
102128
/**
103129
* log for debugging
104130
*/

test/unit/specs/api.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,25 @@ describe('UNIT: API', function () {
525525
assert.strictEqual(p.$el.querySelector('div').textContent, 'child')
526526
})
527527

528+
it('should work with plain option object', function () {
529+
var Parent = Seed.extend({
530+
template: '<p>{{name}}</p><div sd-component="child">{{name}}</div>',
531+
scope: {
532+
name: 'dad'
533+
},
534+
components: {
535+
child: {
536+
scope: {
537+
name: 'child'
538+
}
539+
}
540+
}
541+
})
542+
var p = new Parent()
543+
assert.strictEqual(p.$el.querySelector('p').textContent, 'dad')
544+
assert.strictEqual(p.$el.querySelector('div').textContent, 'child')
545+
})
546+
528547
})
529548

530549
describe('partials', function () {

test/unit/specs/utils.js

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ describe('UNIT: Utils', function () {
9898

9999
})
100100

101-
describe('templateToFragment', function () {
101+
describe('toFragment', function () {
102102

103103
it('should convert a string tempalte to a documentFragment', function () {
104104
var template = '<div class="a">hi</div><p>ha</p>',
105-
frag = utils.templateToFragment(template)
105+
frag = utils.toFragment(template)
106106
assert.ok(frag instanceof window.DocumentFragment)
107107
assert.equal(frag.querySelector('.a').textContent, 'hi')
108108
assert.equal(frag.querySelector('p').textContent, 'ha')
@@ -116,22 +116,50 @@ describe('UNIT: Utils', function () {
116116
el.innerHTML = template
117117
document.getElementById('test').appendChild(el)
118118

119-
var frag = utils.templateToFragment('#' + id)
119+
var frag = utils.toFragment('#' + id)
120120
assert.ok(frag instanceof window.DocumentFragment)
121121
assert.equal(frag.querySelector('.a').textContent, 'hi')
122122
assert.equal(frag.querySelector('p').textContent, 'ha')
123123
})
124124

125125
})
126126

127-
describe('convertPartials', function () {
127+
describe('toConstructor', function () {
128128

129-
it('should convert a hash object of strings to fragments', function () {
130-
var partials = {
129+
it('should convert an non-VM object to a VM constructor', function () {
130+
var a = { test: 1 },
131+
A = utils.toConstructor(a)
132+
assert.ok(A.prototype instanceof Seed)
133+
assert.strictEqual(A.options, a)
134+
})
135+
136+
it('should return the argument if it is already a consutructor', function () {
137+
var A = utils.toConstructor(Seed)
138+
assert.strictEqual(A, Seed)
139+
})
140+
141+
})
142+
143+
describe('processOptions', function () {
144+
145+
var options = {
146+
partials: {
131147
a: '#utils-template-to-fragment',
132148
b: '<div class="a">hi</div><p>ha</p>'
133-
}
134-
utils.convertPartials(partials)
149+
},
150+
components: {
151+
a: { scope: { data: 1 } },
152+
b: { scope: { data: 2 } }
153+
},
154+
template: '<a>{{hi}}</a>'
155+
}
156+
157+
it('should convert string partials to fragment nodes', function () {
158+
159+
// call it here
160+
utils.processOptions(options)
161+
162+
var partials = options.partials
135163
for (var key in partials) {
136164
var frag = partials[key]
137165
assert.ok(frag instanceof window.DocumentFragment)
@@ -140,6 +168,19 @@ describe('UNIT: Utils', function () {
140168
}
141169
})
142170

171+
it('should convert string template to fragment node', function () {
172+
assert.ok(options.template instanceof window.DocumentFragment)
173+
assert.equal(options.template.querySelector('a').textContent, '{{hi}}')
174+
})
175+
176+
it('should convert plain object components to constructors', function () {
177+
var components = options.components
178+
assert.ok(components.a.prototype instanceof Seed)
179+
assert.strictEqual(components.a.options.scope.data, 1)
180+
assert.ok(components.b.prototype instanceof Seed)
181+
assert.strictEqual(components.b.options.scope.data, 2)
182+
})
183+
143184
})
144185

145186
})

0 commit comments

Comments
 (0)