From 6601a27ad08f0ed39bd0778074620603689cb0e7 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Mon, 1 May 2017 14:41:11 -0400 Subject: [PATCH] intro transitions in each-blocks --- src/generators/dom/Block.js | 38 +++++++++---------- src/generators/dom/preprocess.js | 8 ++-- src/generators/dom/visitors/EachBlock.js | 27 ++++++------- .../transition-js-each-block-intro/_config.js | 32 ++++++++++++++++ .../transition-js-each-block-intro/main.html | 18 +++++++++ .../samples/comment/_actual.html | 2 +- 6 files changed, 88 insertions(+), 37 deletions(-) create mode 100644 test/runtime/samples/transition-js-each-block-intro/_config.js create mode 100644 test/runtime/samples/transition-js-each-block-intro/main.html diff --git a/src/generators/dom/Block.js b/src/generators/dom/Block.js index 922306d8f3..f905754815 100644 --- a/src/generators/dom/Block.js +++ b/src/generators/dom/Block.js @@ -33,8 +33,6 @@ export default class Block { this.hasIntroMethod = false; // a block could have an intro method but not intro transitions, e.g. if a sibling block has intros this.hasOutroMethod = false; - this.hasIntroTransitions = false; - this.hasOutroTransitions = false; this.outros = 0; this.aliases = new Map(); @@ -109,13 +107,15 @@ export default class Block { render () { let introing; - if ( this.hasIntroTransitions ) { + const hasIntros = !this.builders.intro.isEmpty(); + if ( hasIntros ) { introing = this.getUniqueName( 'introing' ); this.addVariable( introing ); } let outroing; - if ( this.hasOutroTransitions ) { + const hasOutros = !this.builders.outro.isEmpty(); + if ( hasOutros ) { outroing = this.getUniqueName( 'outroing' ); this.addVariable( outroing ); } @@ -178,21 +178,21 @@ export default class Block { } if ( this.hasIntroMethod ) { - if ( this.builders.intro.isEmpty() ) { + if ( hasIntros ) { properties.addBlock( deindent` intro: function ( ${this.target}, anchor ) { + if ( ${introing} ) return; + ${introing} = true; + ${hasOutros && `${outroing} = false;`} + + ${this.builders.intro} + this.mount( ${this.target}, anchor ); }, ` ); } else { properties.addBlock( deindent` intro: function ( ${this.target}, anchor ) { - if ( ${introing} ) return; - ${introing} = true; - ${this.hasOutroTransitions && `${outroing} = false;`} - - ${this.builders.intro} - this.mount( ${this.target}, anchor ); }, ` ); @@ -200,24 +200,24 @@ export default class Block { } if ( this.hasOutroMethod ) { - if ( this.builders.outro.isEmpty() ) { - properties.addBlock( deindent` - outro: function ( outrocallback ) { - outrocallback(); - }, - ` ); - } else { + if ( hasOutros ) { properties.addBlock( deindent` outro: function ( ${this.alias( 'outrocallback' )} ) { if ( ${outroing} ) return; ${outroing} = true; - ${this.hasIntroTransitions && `${introing} = false;`} + ${hasIntros && `${introing} = false;`} var ${this.alias( 'outros' )} = ${this.outros}; ${this.builders.outro} }, ` ); + } else { + properties.addBlock( deindent` + outro: function ( outrocallback ) { + outrocallback(); + }, + ` ); } } diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.js index 6b43f93460..522a682074 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.js @@ -80,8 +80,8 @@ const preprocessors = { block.addDependencies( node._block.dependencies ); } - if ( node._block.hasIntroTransitions ) hasIntros = true; - if ( node._block.hasOutroTransitions ) hasOutros = true; + if ( node._block.hasIntroMethod ) hasIntros = true; + if ( node._block.hasOutroMethod ) hasOutros = true; if ( isElseIf( node.else ) ) { attachBlocks( node.else.children[0] ); @@ -209,9 +209,9 @@ const preprocessors = { } else if ( attribute.type === 'Transition' ) { - if ( attribute.intro ) generator.hasIntroTransitions = block.hasIntroTransitions = true; + if ( attribute.intro ) generator.hasIntroTransitions = block.hasIntroMethod = true; if ( attribute.outro ) { - generator.hasOutroTransitions = block.hasOutroTransitions = true; + generator.hasOutroTransitions = block.hasOutroMethod = true; block.outros += 1; } } diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index e4df8c575d..641ad9b8b5 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -11,7 +11,8 @@ export default function visitEachBlock ( generator, block, state, node ) { const params = block.params.join( ', ' ); const anchor = node.needsAnchor ? block.getUniqueName( `${each_block}_anchor` ) : ( node.next && node.next._state.name ) || 'null'; - const vars = { each_block, create_each_block, each_block_value, iterations, i, params, anchor }; + const mountOrIntro = node._block.hasIntroMethod ? 'intro' : 'mount'; + const vars = { each_block, create_each_block, each_block_value, iterations, i, params, anchor, mountOrIntro }; const { snippet } = block.contextualise( node.expression ); @@ -29,7 +30,7 @@ export default function visitEachBlock ( generator, block, state, node ) { if ( isToplevel ) { block.builders.mount.addBlock( deindent` for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { - ${iterations}[${i}].mount( ${block.target}, null ); + ${iterations}[${i}].${mountOrIntro}( ${block.target}, null ); } ` ); } @@ -52,13 +53,13 @@ export default function visitEachBlock ( generator, block, state, node ) { block.builders.create.addBlock( deindent` if ( !${each_block_value}.length ) { ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); - ${!isToplevel ? `${each_block_else}.mount( ${state.parentNode}, null );` : ''} + ${!isToplevel ? `${each_block_else}.${mountOrIntro}( ${state.parentNode}, null );` : ''} } ` ); block.builders.mount.addBlock( deindent` if ( ${each_block_else} ) { - ${each_block_else}.mount( ${state.parentNode || block.target}, null ); + ${each_block_else}.${mountOrIntro}( ${state.parentNode || block.target}, null ); } ` ); @@ -70,7 +71,7 @@ export default function visitEachBlock ( generator, block, state, node ) { ${each_block_else}.update( changed, ${params} ); } else if ( !${each_block_value}.length ) { ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); - ${each_block_else}.mount( ${parentNode}, ${anchor} ); + ${each_block_else}.${mountOrIntro}( ${parentNode}, ${anchor} ); } else if ( ${each_block_else} ) { ${each_block_else}.destroy( true ); ${each_block_else} = null; @@ -85,7 +86,7 @@ export default function visitEachBlock ( generator, block, state, node ) { } } else if ( !${each_block_else} ) { ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); - ${each_block_else}.mount( ${parentNode}, ${anchor} ); + ${each_block_else}.${mountOrIntro}( ${parentNode}, ${anchor} ); } ` ); } @@ -109,7 +110,7 @@ export default function visitEachBlock ( generator, block, state, node ) { } } -function keyed ( generator, block, state, node, snippet, { each_block, create_each_block, each_block_value, iterations, i, params, anchor } ) { +function keyed ( generator, block, state, node, snippet, { each_block, create_each_block, each_block_value, iterations, i, params, anchor, mountOrIntro } ) { const fragment = block.getUniqueName( 'fragment' ); const value = block.getUniqueName( 'value' ); const key = block.getUniqueName( 'key' ); @@ -129,7 +130,7 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea if ( state.parentNode ) { create.addLine( - `${iterations}[${i}].mount( ${state.parentNode}, null );` + `${iterations}[${i}].${mountOrIntro}( ${state.parentNode}, null );` ); } @@ -166,7 +167,7 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea ${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component}${node.key ? `, ${key}` : `` } ); } - ${_iterations}[${i}].mount( ${fragment}, null ); + ${_iterations}[${i}].${mountOrIntro}( ${fragment}, null ); } // remove old iterations @@ -184,7 +185,7 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea ` ); } -function unkeyed ( generator, block, state, node, snippet, { create_each_block, each_block_value, iterations, i, params, anchor } ) { +function unkeyed ( generator, block, state, node, snippet, { create_each_block, each_block_value, iterations, i, params, anchor, mountOrIntro } ) { const create = new CodeBuilder(); create.addLine( @@ -193,7 +194,7 @@ function unkeyed ( generator, block, state, node, snippet, { create_each_block, if ( state.parentNode ) { create.addLine( - `${iterations}[${i}].mount( ${state.parentNode}, null );` + `${iterations}[${i}].${mountOrIntro}( ${state.parentNode}, null );` ); } @@ -222,12 +223,12 @@ function unkeyed ( generator, block, state, node, snippet, { create_each_block, ${iterations}[${i}].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); } else { ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].mount( ${parentNode}, ${anchor} ); + ${iterations}[${i}].${mountOrIntro}( ${parentNode}, ${anchor} ); } ` : deindent` ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].mount( ${parentNode}, ${anchor} ); + ${iterations}[${i}].${mountOrIntro}( ${parentNode}, ${anchor} ); `; const start = node._block.hasUpdateMethod ? '0' : `${iterations}.length`; diff --git a/test/runtime/samples/transition-js-each-block-intro/_config.js b/test/runtime/samples/transition-js-each-block-intro/_config.js new file mode 100644 index 0000000000..7deb8c97a9 --- /dev/null +++ b/test/runtime/samples/transition-js-each-block-intro/_config.js @@ -0,0 +1,32 @@ +export default { + data: { + things: [ 'a', 'b', 'c' ] + }, + + test ( assert, component, target, window, raf ) { + let divs = target.querySelectorAll( 'div' ); + assert.equal( divs[0].foo, 0 ); + assert.equal( divs[1].foo, 0 ); + assert.equal( divs[2].foo, 0 ); + + raf.tick( 50 ); + assert.equal( divs[0].foo, 0.5 ); + assert.equal( divs[1].foo, 0.5 ); + assert.equal( divs[2].foo, 0.5 ); + + component.set({ things: [ 'a', 'b', 'c', 'd' ] }); + divs = target.querySelectorAll( 'div' ); + assert.equal( divs[0].foo, 0.5 ); + assert.equal( divs[1].foo, 0.5 ); + assert.equal( divs[2].foo, 0.5 ); + assert.equal( divs[3].foo, 0 ); + + raf.tick( 75 ); + assert.equal( divs[0].foo, 0.75 ); + assert.equal( divs[1].foo, 0.75 ); + assert.equal( divs[2].foo, 0.75 ); + assert.equal( divs[3].foo, 0.25 ); + + component.destroy(); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/transition-js-each-block-intro/main.html b/test/runtime/samples/transition-js-each-block-intro/main.html new file mode 100644 index 0000000000..7f12ef1d8f --- /dev/null +++ b/test/runtime/samples/transition-js-each-block-intro/main.html @@ -0,0 +1,18 @@ +{{#each things as thing}} +
{{thing}}
+{{/each}} + + \ No newline at end of file diff --git a/test/server-side-rendering/samples/comment/_actual.html b/test/server-side-rendering/samples/comment/_actual.html index e2adc073dc..e5c61a4b0e 100644 --- a/test/server-side-rendering/samples/comment/_actual.html +++ b/test/server-side-rendering/samples/comment/_actual.html @@ -1,3 +1,3 @@

before

- +

after

\ No newline at end of file