From e9f17f34ff87f00c5b517e2431346ae9affab07b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sat, 8 Jul 2017 14:18:26 -0400 Subject: [PATCH] fire intro.start and outro.start events (#702) --- mocha.opts | 1 - src/generators/dom/index.ts | 26 +++++------ .../dom/visitors/Element/addTransitions.ts | 10 ++--- src/shared/index.js | 11 ++--- src/shared/transitions.js | 8 ++-- .../expected-bundle.js | 11 ++--- .../computed-collapsed-if/expected-bundle.js | 11 ++--- .../expected-bundle.js | 11 ++--- .../event-handlers-custom/expected-bundle.js | 11 ++--- .../if-block-no-update/expected-bundle.js | 11 ++--- .../if-block-simple/expected-bundle.js | 11 ++--- .../non-imported-component/expected-bundle.js | 11 ++--- .../expected-bundle.js | 13 +++--- .../onrender-onteardown-rewritten/expected.js | 2 + .../expected-bundle.js | 11 ++--- .../samples/transition-js-events/_config.js | 35 +++++++++++++++ .../samples/transition-js-events/main.html | 45 +++++++++++++++++++ 17 files changed, 166 insertions(+), 73 deletions(-) create mode 100644 test/runtime/samples/transition-js-events/_config.js create mode 100644 test/runtime/samples/transition-js-events/main.html diff --git a/mocha.opts b/mocha.opts index af6b17a845d6..427b029758d3 100644 --- a/mocha.opts +++ b/mocha.opts @@ -1,2 +1 @@ ---bail test/test.js \ No newline at end of file diff --git a/src/generators/dom/index.ts b/src/generators/dom/index.ts index ee0486766895..5c698821e9b1 100644 --- a/src/generators/dom/index.ts +++ b/src/generators/dom/index.ts @@ -122,10 +122,9 @@ export default function dom( @dispatchObservers( this, this._observers.pre, newState, oldState ); ${block.hasUpdateMethod && `this._fragment.update( newState, this._state );`} @dispatchObservers( this, this._observers.post, newState, oldState ); - ${(generator.hasComponents || generator.hasIntroTransitions) && + ${(generator.hasComponents || generator.hasComplexBindings) && `this._flush();`} - ${generator.hasComplexBindings && - `while ( this._bindings.length ) this._bindings.pop()();`} + ${generator.hasIntroTransitions && `@callAll(this._postcreate);`} `; if (hasJs) { @@ -199,9 +198,9 @@ export default function dom( ${generator.css && options.css !== false && `if ( !document.getElementById( '${generator.cssId}-style' ) ) @add_css();`} - ${(generator.hasComponents || generator.hasIntroTransitions) && - `this._oncreate = [];`} + ${generator.hasComponents && `this._oncreate = [];`} ${generator.hasComplexBindings && `this._bindings = [];`} + ${generator.hasIntroTransitions && `this._postcreate = [];`} this._fragment = @create_main_fragment( this._state, this ); @@ -219,19 +218,18 @@ export default function dom( this._fragment.${block.hasIntroMethod ? 'intro' : 'mount'}( options.target, null ); } - ${(generator.hasComponents || generator.hasIntroTransitions) && + ${(generator.hasComponents || generator.hasIntroTransitions || generator.hasComplexBindings || templateProperties.oncreate) && `this._flush();`} - ${generator.hasComplexBindings && - `while ( this._bindings.length ) this._bindings.pop()();`} ${templateProperties.oncreate && deindent` - if ( options._root ) { - options._root._oncreate.push( @template.oncreate.bind( this ) ); - } else { - @template.oncreate.call( this ); - } - `} + if ( options._root ) { + options._root._oncreate.push( @template.oncreate.bind( this ) ); + } else { + @template.oncreate.call( this ); + }`} + + ${generator.hasIntroTransitions && `@callAll(this._postcreate);`} } @assign( ${prototypeBase}, ${proto}); diff --git a/src/generators/dom/visitors/Element/addTransitions.ts b/src/generators/dom/visitors/Element/addTransitions.ts index d5f0f4c6f95e..84b31a4201be 100644 --- a/src/generators/dom/visitors/Element/addTransitions.ts +++ b/src/generators/dom/visitors/Element/addTransitions.ts @@ -23,8 +23,8 @@ export default function addTransitions( const fn = `@template.transitions.${intro.name}`; block.builders.intro.addBlock(deindent` - #component._oncreate.push( function () { - if ( !${name} ) ${name} = @wrapTransition( ${state.name}, ${fn}, ${snippet}, true, null ); + #component._postcreate.push( function () { + if ( !${name} ) ${name} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null ); ${name}.run( true, function () { #component.fire( 'intro.end', { node: ${state.name} }); }); @@ -58,8 +58,8 @@ export default function addTransitions( } block.builders.intro.addBlock(deindent` - #component._oncreate.push( function () { - ${introName} = @wrapTransition( ${state.name}, ${fn}, ${snippet}, true, null ); + #component._postcreate.push( function () { + ${introName} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null ); ${introName}.run( true, function () { #component.fire( 'intro.end', { node: ${state.name} }); }); @@ -78,7 +78,7 @@ export default function addTransitions( // 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} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, false, null ); ${outroName}.run( false, function () { #component.fire( 'outro.end', { node: ${state.name} }); if ( --#outros === 0 ) #outrocallback(); diff --git a/src/shared/index.js b/src/shared/index.js index 5dde09c66ffa..4a2f005058c0 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -109,12 +109,13 @@ export function set(newState) { this._root._flush(); } -export function _flush() { - if (!this._oncreate) return; +export function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +export function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } export var proto = { diff --git a/src/shared/transitions.js b/src/shared/transitions.js index 30b5c7334221..6d573f68fdde 100644 --- a/src/shared/transitions.js +++ b/src/shared/transitions.js @@ -32,7 +32,7 @@ export function hash(str) { return hash >>> 0; } -export function wrapTransition(node, fn, params, intro, outgroup) { +export function wrapTransition(component, node, fn, params, intro, outgroup) { var obj = fn(node, params); var duration = obj.duration || 300; var ease = obj.easing || linear; @@ -78,6 +78,8 @@ export function wrapTransition(node, fn, params, intro, outgroup) { } }, start: function(program) { + component.fire(program.intro ? 'intro.start' : 'outro.start', { node: node }); + program.a = this.t; program.b = program.intro ? 1 : 0; program.delta = program.b - program.a; @@ -149,7 +151,7 @@ export var transitionManager = { if (!this.running) { this.running = true; - this.next(); + requestAnimationFrame(this.bound || (this.bound = this.next.bind(this))); } }, @@ -186,7 +188,7 @@ export var transitionManager = { } if (this.running) { - requestAnimationFrame(this.bound || (this.bound = this.next.bind(this))); + requestAnimationFrame(this.bound); } else if (this.stylesheet) { var i = this.stylesheet.cssRules.length; while (i--) this.stylesheet.deleteRule(i); diff --git a/test/js/samples/collapses-text-around-comments/expected-bundle.js b/test/js/samples/collapses-text-around-comments/expected-bundle.js index 057ece30654c..e47fe8df289a 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -118,12 +118,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/js/samples/computed-collapsed-if/expected-bundle.js b/test/js/samples/computed-collapsed-if/expected-bundle.js index d85fd55c5134..b574e09f0f5b 100644 --- a/test/js/samples/computed-collapsed-if/expected-bundle.js +++ b/test/js/samples/computed-collapsed-if/expected-bundle.js @@ -94,12 +94,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/js/samples/each-block-changed-check/expected-bundle.js b/test/js/samples/each-block-changed-check/expected-bundle.js index 4bbecf3f71e8..5ac69c1c965c 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -127,12 +127,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/js/samples/event-handlers-custom/expected-bundle.js b/test/js/samples/event-handlers-custom/expected-bundle.js index 8fa8ead61713..b6c8d040abe2 100644 --- a/test/js/samples/event-handlers-custom/expected-bundle.js +++ b/test/js/samples/event-handlers-custom/expected-bundle.js @@ -112,12 +112,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/js/samples/if-block-no-update/expected-bundle.js b/test/js/samples/if-block-no-update/expected-bundle.js index 65634e0748b4..a445b1dbf49f 100644 --- a/test/js/samples/if-block-no-update/expected-bundle.js +++ b/test/js/samples/if-block-no-update/expected-bundle.js @@ -118,12 +118,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/js/samples/if-block-simple/expected-bundle.js b/test/js/samples/if-block-simple/expected-bundle.js index bf78f1ca6896..199809ac18eb 100644 --- a/test/js/samples/if-block-simple/expected-bundle.js +++ b/test/js/samples/if-block-simple/expected-bundle.js @@ -118,12 +118,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/js/samples/non-imported-component/expected-bundle.js b/test/js/samples/non-imported-component/expected-bundle.js index 030c57369b8f..809f4e1e77ca 100644 --- a/test/js/samples/non-imported-component/expected-bundle.js +++ b/test/js/samples/non-imported-component/expected-bundle.js @@ -106,12 +106,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js index f5849818fe83..ec4b795edde1 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js @@ -94,12 +94,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { @@ -155,6 +156,8 @@ function SvelteComponent ( options ) { this._fragment.mount( options.target, null ); } + this._flush(); + if ( options._root ) { options._root._oncreate.push( template.oncreate.bind( this ) ); } else { diff --git a/test/js/samples/onrender-onteardown-rewritten/expected.js b/test/js/samples/onrender-onteardown-rewritten/expected.js index 96aa37d766d5..cce718f92289 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected.js @@ -44,6 +44,8 @@ function SvelteComponent ( options ) { this._fragment.mount( options.target, null ); } + this._flush(); + if ( options._root ) { options._root._oncreate.push( template.oncreate.bind( this ) ); } else { diff --git a/test/js/samples/use-elements-as-anchors/expected-bundle.js b/test/js/samples/use-elements-as-anchors/expected-bundle.js index 63138c015745..13f89030e4f7 100644 --- a/test/js/samples/use-elements-as-anchors/expected-bundle.js +++ b/test/js/samples/use-elements-as-anchors/expected-bundle.js @@ -118,12 +118,13 @@ function set(newState) { this._root._flush(); } -function _flush() { - if (!this._oncreate) return; +function callAll(fns) { + while (fns && fns.length) fns.pop()(); +} - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function _flush() { + callAll(this._oncreate); + callAll(this._bindings); } var proto = { diff --git a/test/runtime/samples/transition-js-events/_config.js b/test/runtime/samples/transition-js-events/_config.js new file mode 100644 index 000000000000..71e9ccd39c38 --- /dev/null +++ b/test/runtime/samples/transition-js-events/_config.js @@ -0,0 +1,35 @@ +export default { + data: { + visible: true, + things: ['a', 'b', 'c', 'd'] + }, + + test (assert, component, target, window, raf) { + raf.tick(50); + assert.deepEqual(component.intros.sort(), ['a', 'b', 'c', 'd']); + assert.equal(component.introCount, 4); + + raf.tick(100); + assert.equal(component.introCount, 0); + + component.set({ visible: false }); + + raf.tick(150); + assert.deepEqual(component.outros.sort(), ['a', 'b', 'c', 'd']); + assert.equal(component.outroCount, 4); + + raf.tick(200); + assert.equal(component.outroCount, 0); + + component.set({ visible: true }); + component.on('intro.start', () => { + throw new Error(`intro.start should fire during set(), not after`); + }); + + raf.tick(250); + assert.deepEqual(component.intros.sort(), ['a', 'a', 'b', 'b', 'c', 'c', 'd', 'd']); + assert.equal(component.introCount, 4); + + component.destroy(); + } +}; \ No newline at end of file diff --git a/test/runtime/samples/transition-js-events/main.html b/test/runtime/samples/transition-js-events/main.html new file mode 100644 index 000000000000..043651334800 --- /dev/null +++ b/test/runtime/samples/transition-js-events/main.html @@ -0,0 +1,45 @@ +{{#each things as thing}} + {{#if visible}} +

{{thing}}

+ {{/if}} +{{/each}} + + \ No newline at end of file