Explorar o código

Release-v0.8.8

Evan You %!s(int64=12) %!d(string=hai) anos
pai
achega
a701b9f402

+ 1 - 1
bower.json

@@ -1,6 +1,6 @@
 {
     "name": "vue",
-    "version": "0.8.7",
+    "version": "0.8.8",
     "main": "dist/vue.js",
     "description": "Simple, Fast & Composable MVVM for building interative interfaces",
     "authors": ["Evan You <yyx990803@gmail.com>"],

+ 1 - 1
component.json

@@ -1,6 +1,6 @@
 {
     "name": "vue",
-    "version": "0.8.7",
+    "version": "0.8.8",
     "main": "src/main.js",
     "author": "Evan You <yyx990803@gmail.com>",
     "description": "Simple, Fast & Composable MVVM for building interative interfaces",

+ 51 - 11
dist/vue.js

@@ -1,5 +1,5 @@
 /*
- Vue.js v0.8.7
+ Vue.js v0.8.8
  (c) 2014 Evan You
  License: MIT
 */
@@ -3287,12 +3287,7 @@ module.exports = {
         ) return
 
         if (utils.typeOf(collection) === 'Object') {
-            if (this.object) {
-                delete this.object.$repeater
-            }
-            this.object = collection
-            collection = objectToArray(collection)
-            def(this.object, '$repeater', collection, false, true)
+            collection = this.convertObject(collection)
         }
 
         this.reset()
@@ -3456,23 +3451,68 @@ module.exports = {
         }
     },
 
+    /**
+     *  Convert an object to a repeater Array
+     *  and make sure changes in the object are synced to the repeater
+     */
+    convertObject: function (object) {
+
+        if (this.object) {
+            delete this.object.$repeater
+            this.object.__emitter__.off('set', this.updateRepeater)
+        }
+
+        this.object = object
+        var collection = objectToArray(object)
+        def(object, '$repeater', collection, false, true)
+
+        var self = this
+        this.updateRepeater = function (key, val) {
+            if (key.indexOf('.') === -1) {
+                var i = collection.length, item
+                while (i--) {
+                    item = collection[i]
+                    if (item.$key === key) {
+                        if (item !== val && item.$value !== val) {
+                            if ('$value' in item) {
+                                item.$value = val
+                            } else {
+                                def(val, '$key', key, false, true)
+                                self.lock = true
+                                collection.set(i, val)
+                                self.lock = false
+                            }
+                        }
+                        break
+                    }
+                }
+            }
+        }
+
+        object.__emitter__.on('set', this.updateRepeater)
+        return collection
+    },
+
     /**
      *  Sync changes in the $repeater Array
      *  back to the represented Object
      */
     updateObject: function (data, action) {
-        if (this.object && data.$key) {
+        if (this.lock) return
+        var obj = this.object
+        if (obj && data.$key) {
             var key = data.$key,
                 val = data.$value || data
             if (action > 0) { // new property
                 // make key ienumerable
                 delete data.$key
                 def(data, '$key', key, false, true)
-                this.object[key] = val
+                obj[key] = val
+                Observer.convert(obj, key)
             } else {
-                delete this.object[key]
+                delete obj[key]
             }
-            this.object.__emitter__.emit('set', key, val, true)
+            obj.__emitter__.emit('set', key, val, true)
         }
     },
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 1 - 1
dist/vue.min.js


+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "vue",
-  "version": "0.8.7",
+  "version": "0.8.8",
   "author": {
     "name": "Evan You",
     "email": "yyx990803@gmail.com",

+ 50 - 10
src/directives/repeat.js

@@ -170,12 +170,7 @@ module.exports = {
         ) return
 
         if (utils.typeOf(collection) === 'Object') {
-            if (this.object) {
-                delete this.object.$repeater
-            }
-            this.object = collection
-            collection = objectToArray(collection)
-            def(this.object, '$repeater', collection, false, true)
+            collection = this.convertObject(collection)
         }
 
         this.reset()
@@ -339,23 +334,68 @@ module.exports = {
         }
     },
 
+    /**
+     *  Convert an object to a repeater Array
+     *  and make sure changes in the object are synced to the repeater
+     */
+    convertObject: function (object) {
+
+        if (this.object) {
+            delete this.object.$repeater
+            this.object.__emitter__.off('set', this.updateRepeater)
+        }
+
+        this.object = object
+        var collection = objectToArray(object)
+        def(object, '$repeater', collection, false, true)
+
+        var self = this
+        this.updateRepeater = function (key, val) {
+            if (key.indexOf('.') === -1) {
+                var i = collection.length, item
+                while (i--) {
+                    item = collection[i]
+                    if (item.$key === key) {
+                        if (item !== val && item.$value !== val) {
+                            if ('$value' in item) {
+                                item.$value = val
+                            } else {
+                                def(val, '$key', key, false, true)
+                                self.lock = true
+                                collection.set(i, val)
+                                self.lock = false
+                            }
+                        }
+                        break
+                    }
+                }
+            }
+        }
+
+        object.__emitter__.on('set', this.updateRepeater)
+        return collection
+    },
+
     /**
      *  Sync changes in the $repeater Array
      *  back to the represented Object
      */
     updateObject: function (data, action) {
-        if (this.object && data.$key) {
+        if (this.lock) return
+        var obj = this.object
+        if (obj && data.$key) {
             var key = data.$key,
                 val = data.$value || data
             if (action > 0) { // new property
                 // make key ienumerable
                 delete data.$key
                 def(data, '$key', key, false, true)
-                this.object[key] = val
+                obj[key] = val
+                Observer.convert(obj, key)
             } else {
-                delete this.object[key]
+                delete obj[key]
             }
-            this.object.__emitter__.emit('set', key, val, true)
+            obj.__emitter__.emit('set', key, val, true)
         }
     },
 

+ 5 - 0
test/functional/fixtures/repeat-object.html

@@ -10,6 +10,7 @@
     <button id="shift" v-on="click:t3">shift from object</button>
     <button id="unshift" v-on="click:t4">unshift to object</button>
     <button id="splice" v-on="click:t5">splice in object</button>
+    <button id="set" v-on="click:t6">Setting the original object</button>
     <p id="primitive">{{primitive}}</p>
     <p id="obj">{{obj}}</p>
 </div>
@@ -52,6 +53,10 @@ var test = new Vue({
                 $key: 'd',
                 msg: 'he!'
             })
+        },
+        t6: function () {
+            this.primitive.a = 3
+            this.obj.c = { msg: 'hu!' }
         }
     }
 })

+ 8 - 1
test/functional/specs/repeat-object.js

@@ -1,4 +1,4 @@
-casper.test.begin('Repeat properties of an Object', 24, function (test) {
+casper.test.begin('Repeat properties of an Object', 28, function (test) {
     
     casper
     .start('./fixtures/repeat-object.html')
@@ -38,6 +38,13 @@ casper.test.begin('Repeat properties of an Object', 24, function (test) {
         test.assertSelectorHasText('.obj:nth-child(2)', 'd he!')
         test.assertSelectorHasText('#obj', '{"c":{"msg":"ho!"},"d":{"msg":"he!"}}')
     })
+    // changing the object syncs to repeater
+    .thenClick('#set', function () {
+        test.assertSelectorHasText('.primitive:nth-child(1)', 'a 3')
+        test.assertSelectorHasText('.obj:nth-child(1)', 'c hu!')
+        test.assertSelectorHasText('#primitive', '{"a":3,"b":2}')
+        test.assertSelectorHasText('#obj', '{"c":{"msg":"hu!"},"d":{"msg":"he!"}}')
+    })
     .run(function () {
         test.done()
     })

+ 104 - 3
test/unit/specs/directives.js

@@ -1,4 +1,7 @@
 describe('UNIT: Directives', function () {
+
+    var nextTick = require('vue/src/utils').nextTick,
+        VM = require('vue/src/viewmodel')
     
     describe('attr', function () {
 
@@ -644,9 +647,6 @@ describe('UNIT: Directives', function () {
     // this is mainly for code coverage
     describe('repeat', function () {
 
-        var nextTick = require('vue/src/utils').nextTick,
-            VM = require('vue/src/viewmodel')
-
         it('should work', function (done) {
             var handlerCalled = false
             var v = new Vue({
@@ -694,6 +694,92 @@ describe('UNIT: Directives', function () {
             }
         })
 
+        it('should work with primitive values', function () {
+            var v = new Vue({
+                template: '<span v-repeat="tags" v-ref="tags">{{$value}}</span>',
+                data: {
+                    tags: ['a', 'b', 'c']
+                }
+            })
+            assert.strictEqual(v.$el.textContent, 'abc')
+            v.$.tags[0].$value = 'd'
+            assert.strictEqual(v.tags[0], 'd')
+        })
+
+        it('should diff and reuse existing VMs when reseting arrays', function (done) {
+            var v = new Vue({
+                template: '<span v-repeat="tags" v-ref="tags">{{$value}}</span>',
+                data: {
+                    tags: ['a', 'b', 'c']
+                }
+            })
+            var oldVMs = v.$.tags
+            v.tags = v.tags.slice()
+            nextTick(function () {
+                assert.deepEqual(oldVMs, v.$.tags)
+                done()
+            })
+        })
+        
+        it('should also work on objects', function (done) {
+            var v = new Vue({
+                template: '<span v-repeat="obj">{{$key}} {{msg}}</span>',
+                data: {
+                    obj: {
+                        a: {
+                            msg: 'hi!'
+                        },
+                        b: {
+                            msg: 'ha!'
+                        }
+                    }
+                }
+            })
+            assert.strictEqual(v.$el.textContent, 'a hi!b ha!')
+
+            v.obj.a.msg = 'ho!'
+            
+            nextTick(function () {
+                assert.strictEqual(v.$el.textContent, 'a ho!b ha!')
+                testAddKey()
+            })
+
+            function testAddKey () {
+                v.obj.$repeater.push({ $key: 'c', msg: 'he!' })
+                nextTick(function () {
+                    assert.strictEqual(v.$el.textContent, 'a ho!b ha!c he!')
+                    assert.strictEqual(v.obj.c.msg, 'he!')
+                    testRemoveKey()
+                })
+            }
+
+            function testRemoveKey () {
+                v.obj.$repeater.shift()
+                nextTick(function () {
+                    assert.strictEqual(v.$el.textContent, 'b ha!c he!')
+                    assert.strictEqual(v.obj.a, undefined)
+                    testSwap()
+                })
+            }
+
+            function testSwap () {
+                v.obj.b = { msg: 'hehe' }
+                nextTick(function () {
+                    assert.strictEqual(v.$el.textContent, 'b hehec he!')
+                    testRootSwap()
+                })
+            }
+
+            function testRootSwap () {
+                v.obj = { b: { msg: 'wa'}, c: {msg: 'wo'} }
+                nextTick(function () {
+                    assert.strictEqual(v.$el.textContent, 'b wac wo')
+                    done()
+                })
+            }
+           
+        })
+
     })
 
     describe('style', function () {
@@ -758,6 +844,21 @@ describe('UNIT: Directives', function () {
 
     })
 
+    describe('data', function () {
+        
+        it('should set data on the child VM', function () {
+            var v = new Vue({
+                template: '<div v-component="test" v-ref="test" v-data="a:1,b:hi"></div>',
+                components: {
+                    test: Vue
+                }
+            })
+            assert.strictEqual(v.$.test.a, 1)
+            assert.strictEqual(v.$.test.b, 'hi')
+        })
+
+    })
+
 })
 
 function mockDirective (dirName, tag, type) {

+ 12 - 0
test/unit/specs/misc.js

@@ -36,6 +36,18 @@ describe('Misc Features', function () {
         })
     })
 
+    describe('triple mustache', function () {
+        it('should set unescaped HTML', function () {
+            var v = new Vue({
+                template: '{{{html}}}',
+                data: {
+                    html: '<span>a</span><a>hi</a>'
+                }
+            })
+            assert.strictEqual(v.$el.innerHTML, '<span>a</span><a>hi</a><!--v-html-->')
+        })
+    })
+
     describe('computed properties', function () {
         it('should be accessible like a normal attribtue', function () {
             var b = 2

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio