diff --git a/src/generators/dom/visitors/Element/Element.js b/src/generators/dom/visitors/Element/Element.js index c42e79c947..bdf408732f 100644 --- a/src/generators/dom/visitors/Element/Element.js +++ b/src/generators/dom/visitors/Element/Element.js @@ -63,13 +63,12 @@ export default function visitElement ( generator, block, state, node ) { }); if ( intro || outro ) addTransitions( generator, block, childState, node, intro, outro ); + } - if ( !outro && !state.parentNode ) { - // TODO this probably doesn't belong here. We eventually need to consider - // what happens to elements that belong to the same outgroup as an - // outroing element... - block.builders.detach.addLine( `${generator.helper( 'detachNode' )}( ${name} );` ); - } + if ( !state.parentNode ) { + // TODO we eventually need to consider what happens to elements + // that belong to the same outgroup as an outroing element... + block.builders.detach.addLine( `${generator.helper( 'detachNode' )}( ${name} );` ); } if ( node.name !== 'select' ) { diff --git a/src/generators/dom/visitors/Element/addTransitions.js b/src/generators/dom/visitors/Element/addTransitions.js index 42e46e36b6..5e19c3d283 100644 --- a/src/generators/dom/visitors/Element/addTransitions.js +++ b/src/generators/dom/visitors/Element/addTransitions.js @@ -22,7 +22,6 @@ export default function addTransitions ( generator, block, state, node, intro, o block.builders.outro.addBlock( deindent` ${name}.run( ${name}.t, 0, function () { - ${generator.helper( 'detachNode' )}( ${state.name} ); ${block.component}.fire( 'outro.end', { node: ${state.name} }); if ( --${block.alias( 'outros' )} === 0 ) ${block.alias( 'outrocallback' )}(); ${name} = null; @@ -60,10 +59,11 @@ export default function addTransitions ( generator, block, state, node, intro, o const fn = `${generator.alias( 'template' )}.transitions.${outro.name}`; + // TODO hide elements that have outro'd (unless they belong to a still-outroing + // group) prior to their removal from the DOM block.builders.outro.addBlock( deindent` ${outroName} = ${wrapTransition}( ${state.name}, ${fn}, ${snippet}, false, null ); ${outroName}.run( 1, 0, function () { - ${generator.helper( 'detachNode' )}( ${state.name} ); ${block.component}.fire( 'outro.end', { node: ${state.name} }); if ( --${block.alias( 'outros' )} === 0 ) ${block.alias( 'outrocallback' )}(); }); diff --git a/src/generators/dom/visitors/IfBlock.js b/src/generators/dom/visitors/IfBlock.js index 00ddd049e3..28b74fa5ff 100644 --- a/src/generators/dom/visitors/IfBlock.js +++ b/src/generators/dom/visitors/IfBlock.js @@ -86,37 +86,26 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor const parentNode = state.parentNode || `${anchor}.parentNode`; - const exit = branch.hasOutroTransitions ? - deindent` - ${name}.outro( function () { - ${name}.destroy( true ); - ${name} = null; - }); - ` : - deindent` - ${name}.destroy( true ); - ${name} = null; - `; - - if ( dynamic ) { - if ( branch.hasIntroTransitions ) { - throw new Error( 'TODO simple dynamic if-block with intro transitions' ); - } + const enter = dynamic ? + ( branch.hasIntroTransitions ? + deindent` + if ( ${name} ) { + ${name}.update( changed, ${params} ); + } else { + ${name} = ${branch.block}( ${params}, ${block.component} ); + } - block.builders.update.addBlock( deindent` - if ( ${branch.condition} ) { + ${name}.intro( ${parentNode}, ${anchor} ); + ` : + deindent` if ( ${name} ) { ${name}.update( changed, ${params} ); } else { ${name} = ${branch.block}( ${params}, ${block.component} ); ${name}.mount( ${parentNode}, ${anchor} ); } - } else if ( ${name} ) { - ${exit} - } - ` ); - } else { - const enter = branch.hasIntroTransitions ? + ` ) : + ( branch.hasIntroTransitions ? deindent` if ( !${name} ) ${name} = ${branch.block}( ${params}, ${block.component} ); ${name}.intro( ${parentNode}, ${anchor} ); @@ -126,16 +115,29 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor ${name} = ${branch.block}( ${params}, ${block.component} ); ${name}.mount( ${parentNode}, ${anchor} ); } - `; + ` ); - block.builders.update.addBlock( deindent` - if ( ${branch.condition} ) { - ${enter} - } else if ( ${name} ) { - ${exit} - } - ` ); - } + // no `update()` here — we don't want to update outroing nodes, + // as that will typically result in glitching + const exit = branch.hasOutroTransitions ? + deindent` + ${name}.outro( function () { + ${name}.destroy( true ); + ${name} = null; + }); + ` : + deindent` + ${name}.destroy( true ); + ${name} = null; + `; + + block.builders.update.addBlock( deindent` + if ( ${branch.condition} ) { + ${enter} + } else if ( ${name} ) { + ${exit} + } + ` ); } function compound ( generator, block, state, node, branches, dynamic, { name, anchor, params } ) { diff --git a/test/runtime/samples/transition-js-dynamic-if-block-bidi/_config.js b/test/runtime/samples/transition-js-dynamic-if-block-bidi/_config.js new file mode 100644 index 0000000000..9177411dd6 --- /dev/null +++ b/test/runtime/samples/transition-js-dynamic-if-block-bidi/_config.js @@ -0,0 +1,47 @@ +export default { + data: { + name: 'world' + }, + + test ( assert, component, target, window ) { + global.count = 0; + let now = 0; + let callback; + + window.performance = { now: () => now }; + global.requestAnimationFrame = cb => callback = cb; + + component.set({ visible: true }); + assert.equal( global.count, 1 ); + const div = target.querySelector( 'div' ); + assert.equal( div.foo, 0 ); + + now = 300; + callback(); + component.set({ name: 'everybody' }); + assert.equal( div.foo, 0.75 ); + assert.htmlEqual( div.innerHTML, 'hello everybody!' ); + + component.set({ visible: false, name: 'again' }); + assert.htmlEqual( div.innerHTML, 'hello everybody!' ); + + now = 500; + callback(); + assert.equal( div.foo, 0.25 ); + + component.set({ visible: true }); + now = 700; + callback(); + assert.equal( div.foo, 0.75 ); + assert.htmlEqual( div.innerHTML, 'hello again!' ); + + now = 800; + callback(); + assert.equal( div.foo, 1 ); + + now = 900; + callback(); + + component.destroy(); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/transition-js-dynamic-if-block-bidi/main.html b/test/runtime/samples/transition-js-dynamic-if-block-bidi/main.html new file mode 100644 index 0000000000..bc0dace68b --- /dev/null +++ b/test/runtime/samples/transition-js-dynamic-if-block-bidi/main.html @@ -0,0 +1,19 @@ +{{#if visible}} +