@@ -92,35 +92,6 @@ var mutationHandlers = {
9292 }
9393}
9494
95- /**
96- * Convert an Object to a v-repeat friendly Array
97- */
98- function objectToArray ( obj ) {
99- var res = [ ] , val , data
100- for ( var key in obj ) {
101- val = obj [ key ]
102- data = utils . typeOf ( val ) === 'Object'
103- ? val
104- : { $value : val }
105- def ( data , '$key' , key )
106- res . push ( data )
107- }
108- return res
109- }
110-
111- /**
112- * Find an object or a wrapped data object
113- * from an Array
114- */
115- function indexOf ( arr , obj ) {
116- for ( var i = 0 , l = arr . length ; i < l ; i ++ ) {
117- if ( arr [ i ] === obj || ( obj . $value && arr [ i ] . $value === obj . $value ) ) {
118- return i
119- }
120- }
121- return - 1
122- }
123-
12495module . exports = {
12596
12697 bind : function ( ) {
@@ -178,8 +149,7 @@ module.exports = {
178149 // force a compile so that we get all the bindings for
179150 // dependency extraction.
180151 if ( ! this . initiated && ( ! collection || ! collection . length ) ) {
181- this . buildItem ( )
182- this . initiated = true
152+ this . dryBuild ( )
183153 }
184154
185155 // keep reference of old data and VMs
@@ -205,17 +175,7 @@ module.exports = {
205175 }
206176
207177 // destroy unused old VMs
208- if ( oldVMs ) {
209- var i = oldVMs . length , vm
210- while ( i -- ) {
211- vm = oldVMs [ i ]
212- if ( vm . $reused ) {
213- vm . $reused = false
214- } else {
215- vm . $destroy ( )
216- }
217- }
218- }
178+ if ( oldVMs ) destroyVMs ( oldVMs )
219179 this . old = this . oldVMs = null
220180 } ,
221181
@@ -236,6 +196,20 @@ module.exports = {
236196 } )
237197 } ,
238198
199+ /**
200+ * Run a dry buildItem just to collect bindings
201+ */
202+ dryBuild : function ( ) {
203+ new this . Ctor ( {
204+ el : this . el . cloneNode ( true ) ,
205+ compilerOptions : {
206+ repeat : true ,
207+ parentCompiler : this . compiler
208+ }
209+ } ) . $destroy ( )
210+ this . initiated = true
211+ } ,
212+
239213 /**
240214 * Create a new child VM from a data object
241215 * passing along compiler options indicating this
@@ -246,103 +220,92 @@ module.exports = {
246220 var ctn = this . container ,
247221 vms = this . vms ,
248222 col = this . collection ,
249- el , i , existing , ref , item , primitive , detached
223+ el , oldIndex , existing , item , nonObject
224+
225+ // get our DOM insertion reference node
226+ var ref = vms . length > index
227+ ? vms [ index ] . $el
228+ : this . ref
229+
230+ // if reference VM is detached by v-if,
231+ // use its v-if ref node instead
232+ if ( ! ref . parentNode ) {
233+ ref = ref . vue_if_ref
234+ }
250235
251- // append node into DOM first
252- // so v-if can get access to parentNode
253- // TODO: logic here is a total mess.
254- if ( data ) {
236+ // check if data already exists in the old array
237+ oldIndex = this . old ? indexOf ( this . old , data ) : - 1
238+ existing = oldIndex > - 1
255239
256- if ( this . old ) {
257- i = indexOf ( this . old , data )
258- }
259- existing = i > - 1
260-
261- if ( existing ) { // existing, reuse the old VM
262-
263- item = this . oldVMs [ i ]
264- // mark, so it won't be destroyed
265- item . $reused = true
266- el = item . $el
267- // existing VM's el can possibly be detached by v-if.
268- // in that case don't insert.
269- detached = ! el . parentNode
270-
271- } else { // new data, need to create new VM
272-
273- el = this . el . cloneNode ( true )
274- // process transition info before appending
275- el . vue_trans = utils . attr ( el , 'transition' , true )
276- el . vue_anim = utils . attr ( el , 'animation' , true )
277- el . vue_effect = utils . attr ( el , 'effect' , true )
278- // wrap primitive element in an object
279- if ( utils . typeOf ( data ) !== 'Object' ) {
280- primitive = true
281- data = { $value : data }
282- }
240+ if ( existing ) {
283241
284- }
242+ // existing, reuse the old VM
243+ item = this . oldVMs [ oldIndex ]
244+ // mark, so it won't be destroyed
245+ item . $reused = true
285246
286- ref = vms . length > index
287- ? vms [ index ] . $el
288- : this . ref
289-
290- // if ref VM's el is detached by v-if
291- // use its v-if ref node instead
292- if ( ! ref . parentNode ) {
293- ref = ref . vue_if_ref
294- }
247+ } else {
295248
296- if ( existing ) {
297- // existing node
298- // if not detached, just re-insert to new location
299- // else re-insert its v-if ref node
300- ctn . insertBefore ( detached ? el . vue_if_ref : el , ref )
301- } else {
302- // new node, prepare it for v-if
303- el . vue_if_parent = ctn
304- el . vue_if_ref = ref
249+ // new data, need to create new VM.
250+ // there's some preparation work to do...
251+
252+ // first clone the template node
253+ el = this . el . cloneNode ( true )
254+ // then we provide the parentNode for v-if
255+ // so that it can still work in a detached state
256+ el . vue_if_parent = ctn
257+ el . vue_if_ref = ref
258+ // wrap non-object value in an object
259+ nonObject = utils . typeOf ( data ) !== 'Object'
260+ if ( nonObject ) {
261+ data = { $value : data }
305262 }
306- // set index so vm can init with it
307- // and do not trigger stuff early
263+ // set index so vm can init with the correct
264+ // index instead of undefined
308265 data . $index = index
309- }
310-
311- item = item || new this . Ctor ( {
312- el : el ,
313- data : data ,
314- compilerOptions : {
315- repeat : true ,
316- parentCompiler : this . compiler
317- }
318- } )
319- item . $index = index
320-
321- if ( ! data ) {
322- // this is a forced compile for an empty collection.
323- // let's remove it...
324- item . $destroy ( )
325- } else {
326- vms . splice ( index , 0 , item )
327-
328- // for primitive values, listen for value change
329- if ( primitive ) {
266+ // initialize the new VM
267+ item = new this . Ctor ( {
268+ el : el ,
269+ data : data ,
270+ compilerOptions : {
271+ repeat : true ,
272+ parentCompiler : this . compiler
273+ }
274+ } )
275+ // for non-object values, listen for value change
276+ // so we can sync it back to the original Array
277+ if ( nonObject ) {
330278 item . $compiler . observer . on ( 'set' , function ( key , val ) {
331279 if ( key === '$value' ) {
332280 col [ item . $index ] = val
333281 }
334282 } )
335283 }
336284
337- // new instance and v-if doesn't want it detached
338- // good to insert.
339- if ( ! existing && el . vue_if !== false ) {
285+ }
286+
287+ // put the item into the VM Array
288+ vms . splice ( index , 0 , item )
289+ // update the index
290+ item . $index = index
291+
292+ // Finally, DOM operations...
293+ el = item . $el
294+ if ( existing ) {
295+ // we simplify need to re-insert the existing node
296+ // to its new position. However, it can possibly be
297+ // detached by v-if. in that case we insert its v-if
298+ // ref node instead.
299+ ctn . insertBefore ( el . parentNode ? el : el . vue_if_ref , ref )
300+ } else {
301+ if ( el . vue_if !== false ) {
340302 if ( this . compiler . init ) {
341- // do not transition on initial compile.
342- ctn . insertBefore ( item . $el , ref )
303+ // do not transition on initial compile,
304+ // just manually insert.
305+ ctn . insertBefore ( el , ref )
343306 item . $compiler . execHook ( 'attached' )
344307 } else {
345- // transition in.. .
308+ // give it some nice transition .
346309 item . $before ( ref )
347310 }
348311 }
@@ -401,8 +364,6 @@ module.exports = {
401364 var key = vm . $key ,
402365 val = vm . $value || vm . $data
403366 if ( action > 0 ) { // new property
404- // make key ienumerable
405- delete vm . $data . $key
406367 obj [ key ] = val
407368 Observer . convert ( obj , key )
408369 } else {
@@ -412,22 +373,65 @@ module.exports = {
412373 }
413374 } ,
414375
415- reset : function ( destroyAll ) {
376+ reset : function ( destroy ) {
416377 if ( this . childId ) {
417378 delete this . vm . $ [ this . childId ]
418379 }
419380 if ( this . collection ) {
420381 this . collection . __emitter__ . off ( 'mutate' , this . mutationListener )
421- if ( destroyAll ) {
422- var i = this . vms . length
423- while ( i -- ) {
424- this . vms [ i ] . $destroy ( )
425- }
382+ if ( destroy ) {
383+ destroyVMs ( this . vms )
426384 }
427385 }
428386 } ,
429387
430388 unbind : function ( ) {
431389 this . reset ( true )
432390 }
391+ }
392+
393+ // Helpers --------------------------------------------------------------------
394+
395+ /**
396+ * Convert an Object to a v-repeat friendly Array
397+ */
398+ function objectToArray ( obj ) {
399+ var res = [ ] , val , data
400+ for ( var key in obj ) {
401+ val = obj [ key ]
402+ data = utils . typeOf ( val ) === 'Object'
403+ ? val
404+ : { $value : val }
405+ def ( data , '$key' , key )
406+ res . push ( data )
407+ }
408+ return res
409+ }
410+
411+ /**
412+ * Find an object or a wrapped data object
413+ * from an Array
414+ */
415+ function indexOf ( arr , obj ) {
416+ for ( var i = 0 , l = arr . length ; i < l ; i ++ ) {
417+ if ( arr [ i ] === obj || ( obj . $value && arr [ i ] . $value === obj . $value ) ) {
418+ return i
419+ }
420+ }
421+ return - 1
422+ }
423+
424+ /**
425+ * Destroy some VMs, yeah.
426+ */
427+ function destroyVMs ( vms ) {
428+ var i = vms . length , vm
429+ while ( i -- ) {
430+ vm = vms [ i ]
431+ if ( vm . $reused ) {
432+ vm . $reused = false
433+ } else {
434+ vm . $destroy ( )
435+ }
436+ }
433437}
0 commit comments