Skip to content

Commit a701b9f

Browse files
author
Evan You
committed
Release-v0.8.8
1 parent 9bfb8b8 commit a701b9f

File tree

10 files changed

+236
-31
lines changed

10 files changed

+236
-31
lines changed

bower.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue",
3-
"version": "0.8.7",
3+
"version": "0.8.8",
44
"main": "dist/vue.js",
55
"description": "Simple, Fast & Composable MVVM for building interative interfaces",
66
"authors": ["Evan You <[email protected]>"],

component.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue",
3-
"version": "0.8.7",
3+
"version": "0.8.8",
44
"main": "src/main.js",
55
"author": "Evan You <[email protected]>",
66
"description": "Simple, Fast & Composable MVVM for building interative interfaces",

dist/vue.js

+51-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Vue.js v0.8.7
2+
Vue.js v0.8.8
33
(c) 2014 Evan You
44
License: MIT
55
*/
@@ -3287,12 +3287,7 @@ module.exports = {
32873287
) return
32883288

32893289
if (utils.typeOf(collection) === 'Object') {
3290-
if (this.object) {
3291-
delete this.object.$repeater
3292-
}
3293-
this.object = collection
3294-
collection = objectToArray(collection)
3295-
def(this.object, '$repeater', collection, false, true)
3290+
collection = this.convertObject(collection)
32963291
}
32973292

32983293
this.reset()
@@ -3456,23 +3451,68 @@ module.exports = {
34563451
}
34573452
},
34583453

3454+
/**
3455+
* Convert an object to a repeater Array
3456+
* and make sure changes in the object are synced to the repeater
3457+
*/
3458+
convertObject: function (object) {
3459+
3460+
if (this.object) {
3461+
delete this.object.$repeater
3462+
this.object.__emitter__.off('set', this.updateRepeater)
3463+
}
3464+
3465+
this.object = object
3466+
var collection = objectToArray(object)
3467+
def(object, '$repeater', collection, false, true)
3468+
3469+
var self = this
3470+
this.updateRepeater = function (key, val) {
3471+
if (key.indexOf('.') === -1) {
3472+
var i = collection.length, item
3473+
while (i--) {
3474+
item = collection[i]
3475+
if (item.$key === key) {
3476+
if (item !== val && item.$value !== val) {
3477+
if ('$value' in item) {
3478+
item.$value = val
3479+
} else {
3480+
def(val, '$key', key, false, true)
3481+
self.lock = true
3482+
collection.set(i, val)
3483+
self.lock = false
3484+
}
3485+
}
3486+
break
3487+
}
3488+
}
3489+
}
3490+
}
3491+
3492+
object.__emitter__.on('set', this.updateRepeater)
3493+
return collection
3494+
},
3495+
34593496
/**
34603497
* Sync changes in the $repeater Array
34613498
* back to the represented Object
34623499
*/
34633500
updateObject: function (data, action) {
3464-
if (this.object && data.$key) {
3501+
if (this.lock) return
3502+
var obj = this.object
3503+
if (obj && data.$key) {
34653504
var key = data.$key,
34663505
val = data.$value || data
34673506
if (action > 0) { // new property
34683507
// make key ienumerable
34693508
delete data.$key
34703509
def(data, '$key', key, false, true)
3471-
this.object[key] = val
3510+
obj[key] = val
3511+
Observer.convert(obj, key)
34723512
} else {
3473-
delete this.object[key]
3513+
delete obj[key]
34743514
}
3475-
this.object.__emitter__.emit('set', key, val, true)
3515+
obj.__emitter__.emit('set', key, val, true)
34763516
}
34773517
},
34783518

dist/vue.min.js

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue",
3-
"version": "0.8.7",
3+
"version": "0.8.8",
44
"author": {
55
"name": "Evan You",
66
"email": "[email protected]",

src/directives/repeat.js

+50-10
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,7 @@ module.exports = {
170170
) return
171171

172172
if (utils.typeOf(collection) === 'Object') {
173-
if (this.object) {
174-
delete this.object.$repeater
175-
}
176-
this.object = collection
177-
collection = objectToArray(collection)
178-
def(this.object, '$repeater', collection, false, true)
173+
collection = this.convertObject(collection)
179174
}
180175

181176
this.reset()
@@ -339,23 +334,68 @@ module.exports = {
339334
}
340335
},
341336

337+
/**
338+
* Convert an object to a repeater Array
339+
* and make sure changes in the object are synced to the repeater
340+
*/
341+
convertObject: function (object) {
342+
343+
if (this.object) {
344+
delete this.object.$repeater
345+
this.object.__emitter__.off('set', this.updateRepeater)
346+
}
347+
348+
this.object = object
349+
var collection = objectToArray(object)
350+
def(object, '$repeater', collection, false, true)
351+
352+
var self = this
353+
this.updateRepeater = function (key, val) {
354+
if (key.indexOf('.') === -1) {
355+
var i = collection.length, item
356+
while (i--) {
357+
item = collection[i]
358+
if (item.$key === key) {
359+
if (item !== val && item.$value !== val) {
360+
if ('$value' in item) {
361+
item.$value = val
362+
} else {
363+
def(val, '$key', key, false, true)
364+
self.lock = true
365+
collection.set(i, val)
366+
self.lock = false
367+
}
368+
}
369+
break
370+
}
371+
}
372+
}
373+
}
374+
375+
object.__emitter__.on('set', this.updateRepeater)
376+
return collection
377+
},
378+
342379
/**
343380
* Sync changes in the $repeater Array
344381
* back to the represented Object
345382
*/
346383
updateObject: function (data, action) {
347-
if (this.object && data.$key) {
384+
if (this.lock) return
385+
var obj = this.object
386+
if (obj && data.$key) {
348387
var key = data.$key,
349388
val = data.$value || data
350389
if (action > 0) { // new property
351390
// make key ienumerable
352391
delete data.$key
353392
def(data, '$key', key, false, true)
354-
this.object[key] = val
393+
obj[key] = val
394+
Observer.convert(obj, key)
355395
} else {
356-
delete this.object[key]
396+
delete obj[key]
357397
}
358-
this.object.__emitter__.emit('set', key, val, true)
398+
obj.__emitter__.emit('set', key, val, true)
359399
}
360400
},
361401

test/functional/fixtures/repeat-object.html

+5
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
<button id="shift" v-on="click:t3">shift from object</button>
1111
<button id="unshift" v-on="click:t4">unshift to object</button>
1212
<button id="splice" v-on="click:t5">splice in object</button>
13+
<button id="set" v-on="click:t6">Setting the original object</button>
1314
<p id="primitive">{{primitive}}</p>
1415
<p id="obj">{{obj}}</p>
1516
</div>
@@ -52,6 +53,10 @@
5253
$key: 'd',
5354
msg: 'he!'
5455
})
56+
},
57+
t6: function () {
58+
this.primitive.a = 3
59+
this.obj.c = { msg: 'hu!' }
5560
}
5661
}
5762
})

test/functional/specs/repeat-object.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
casper.test.begin('Repeat properties of an Object', 24, function (test) {
1+
casper.test.begin('Repeat properties of an Object', 28, function (test) {
22

33
casper
44
.start('./fixtures/repeat-object.html')
@@ -38,6 +38,13 @@ casper.test.begin('Repeat properties of an Object', 24, function (test) {
3838
test.assertSelectorHasText('.obj:nth-child(2)', 'd he!')
3939
test.assertSelectorHasText('#obj', '{"c":{"msg":"ho!"},"d":{"msg":"he!"}}')
4040
})
41+
// changing the object syncs to repeater
42+
.thenClick('#set', function () {
43+
test.assertSelectorHasText('.primitive:nth-child(1)', 'a 3')
44+
test.assertSelectorHasText('.obj:nth-child(1)', 'c hu!')
45+
test.assertSelectorHasText('#primitive', '{"a":3,"b":2}')
46+
test.assertSelectorHasText('#obj', '{"c":{"msg":"hu!"},"d":{"msg":"he!"}}')
47+
})
4148
.run(function () {
4249
test.done()
4350
})

test/unit/specs/directives.js

+104-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
describe('UNIT: Directives', function () {
2+
3+
var nextTick = require('vue/src/utils').nextTick,
4+
VM = require('vue/src/viewmodel')
25

36
describe('attr', function () {
47

@@ -644,9 +647,6 @@ describe('UNIT: Directives', function () {
644647
// this is mainly for code coverage
645648
describe('repeat', function () {
646649

647-
var nextTick = require('vue/src/utils').nextTick,
648-
VM = require('vue/src/viewmodel')
649-
650650
it('should work', function (done) {
651651
var handlerCalled = false
652652
var v = new Vue({
@@ -694,6 +694,92 @@ describe('UNIT: Directives', function () {
694694
}
695695
})
696696

697+
it('should work with primitive values', function () {
698+
var v = new Vue({
699+
template: '<span v-repeat="tags" v-ref="tags">{{$value}}</span>',
700+
data: {
701+
tags: ['a', 'b', 'c']
702+
}
703+
})
704+
assert.strictEqual(v.$el.textContent, 'abc')
705+
v.$.tags[0].$value = 'd'
706+
assert.strictEqual(v.tags[0], 'd')
707+
})
708+
709+
it('should diff and reuse existing VMs when reseting arrays', function (done) {
710+
var v = new Vue({
711+
template: '<span v-repeat="tags" v-ref="tags">{{$value}}</span>',
712+
data: {
713+
tags: ['a', 'b', 'c']
714+
}
715+
})
716+
var oldVMs = v.$.tags
717+
v.tags = v.tags.slice()
718+
nextTick(function () {
719+
assert.deepEqual(oldVMs, v.$.tags)
720+
done()
721+
})
722+
})
723+
724+
it('should also work on objects', function (done) {
725+
var v = new Vue({
726+
template: '<span v-repeat="obj">{{$key}} {{msg}}</span>',
727+
data: {
728+
obj: {
729+
a: {
730+
msg: 'hi!'
731+
},
732+
b: {
733+
msg: 'ha!'
734+
}
735+
}
736+
}
737+
})
738+
assert.strictEqual(v.$el.textContent, 'a hi!b ha!')
739+
740+
v.obj.a.msg = 'ho!'
741+
742+
nextTick(function () {
743+
assert.strictEqual(v.$el.textContent, 'a ho!b ha!')
744+
testAddKey()
745+
})
746+
747+
function testAddKey () {
748+
v.obj.$repeater.push({ $key: 'c', msg: 'he!' })
749+
nextTick(function () {
750+
assert.strictEqual(v.$el.textContent, 'a ho!b ha!c he!')
751+
assert.strictEqual(v.obj.c.msg, 'he!')
752+
testRemoveKey()
753+
})
754+
}
755+
756+
function testRemoveKey () {
757+
v.obj.$repeater.shift()
758+
nextTick(function () {
759+
assert.strictEqual(v.$el.textContent, 'b ha!c he!')
760+
assert.strictEqual(v.obj.a, undefined)
761+
testSwap()
762+
})
763+
}
764+
765+
function testSwap () {
766+
v.obj.b = { msg: 'hehe' }
767+
nextTick(function () {
768+
assert.strictEqual(v.$el.textContent, 'b hehec he!')
769+
testRootSwap()
770+
})
771+
}
772+
773+
function testRootSwap () {
774+
v.obj = { b: { msg: 'wa'}, c: {msg: 'wo'} }
775+
nextTick(function () {
776+
assert.strictEqual(v.$el.textContent, 'b wac wo')
777+
done()
778+
})
779+
}
780+
781+
})
782+
697783
})
698784

699785
describe('style', function () {
@@ -758,6 +844,21 @@ describe('UNIT: Directives', function () {
758844

759845
})
760846

847+
describe('data', function () {
848+
849+
it('should set data on the child VM', function () {
850+
var v = new Vue({
851+
template: '<div v-component="test" v-ref="test" v-data="a:1,b:hi"></div>',
852+
components: {
853+
test: Vue
854+
}
855+
})
856+
assert.strictEqual(v.$.test.a, 1)
857+
assert.strictEqual(v.$.test.b, 'hi')
858+
})
859+
860+
})
861+
761862
})
762863

763864
function mockDirective (dirName, tag, type) {

test/unit/specs/misc.js

+12
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,18 @@ describe('Misc Features', function () {
3636
})
3737
})
3838

39+
describe('triple mustache', function () {
40+
it('should set unescaped HTML', function () {
41+
var v = new Vue({
42+
template: '{{{html}}}',
43+
data: {
44+
html: '<span>a</span><a>hi</a>'
45+
}
46+
})
47+
assert.strictEqual(v.$el.innerHTML, '<span>a</span><a>hi</a><!--v-html-->')
48+
})
49+
})
50+
3951
describe('computed properties', function () {
4052
it('should be accessible like a normal attribtue', function () {
4153
var b = 2

0 commit comments

Comments
 (0)