diff --git a/mocha.opts b/mocha.opts index af6b17a845..427b029758 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 ee04867668..393c83fe1f 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) && - `this._flush();`} - ${generator.hasComplexBindings && - `while ( this._bindings.length ) this._bindings.pop()();`} + ${generator.hasComponents && `@callAll(this._oncreate);`} + ${generator.hasComplexBindings && `@callAll(this._bindings);`} + ${generator.hasIntroTransitions && `@callAll(this._postcreate);`} `; if (hasJs) { @@ -158,7 +157,7 @@ export default function dom( ? `@proto ` : deindent` { - ${['get', 'fire', 'observe', 'on', 'set', '_flush'] + ${['get', 'fire', 'observe', 'on', 'set'] .map(n => `${n}: @${n}`) .join(',\n')} }`; @@ -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,17 @@ export default function dom( this._fragment.${block.hasIntroMethod ? 'intro' : 'mount'}( options.target, null ); } - ${(generator.hasComponents || generator.hasIntroTransitions) && - `this._flush();`} - ${generator.hasComplexBindings && - `while ( this._bindings.length ) this._bindings.pop()();`} + ${generator.hasComponents && `@callAll(this._oncreate);`} + ${generator.hasComplexBindings && `@callAll(this._bindings);`} - ${templateProperties.oncreate && - deindent` + ${templateProperties.oncreate && deindent` 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 d5f0f4c6f9..84b31a4201 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 5dde09c66f..acac5b216c 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -106,15 +106,11 @@ export function onDev(eventName, handler) { export function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -export function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +export function callAll(fns) { + while (fns && fns.length) fns.pop()(); } export var proto = { @@ -122,8 +118,7 @@ export var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; export var protoDev = { @@ -131,6 +126,5 @@ export var protoDev = { fire: fire, observe: observeDev, on: onDev, - set: set, - _flush: _flush + set: set }; diff --git a/src/shared/transitions.js b/src/shared/transitions.js index 30b5c73342..6d573f68fd 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 057ece3065..ea478745cd 100644 --- a/test/js/samples/collapses-text-around-comments/expected-bundle.js +++ b/test/js/samples/collapses-text-around-comments/expected-bundle.js @@ -115,15 +115,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -131,8 +127,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; var template = (function () { diff --git a/test/js/samples/computed-collapsed-if/expected-bundle.js b/test/js/samples/computed-collapsed-if/expected-bundle.js index d85fd55c51..5cd719b372 100644 --- a/test/js/samples/computed-collapsed-if/expected-bundle.js +++ b/test/js/samples/computed-collapsed-if/expected-bundle.js @@ -91,15 +91,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -107,8 +103,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; function recompute ( state, newState, oldState, isInitial ) { 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 4bbecf3f71..d98ac1db37 100644 --- a/test/js/samples/each-block-changed-check/expected-bundle.js +++ b/test/js/samples/each-block-changed-check/expected-bundle.js @@ -124,15 +124,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -140,8 +136,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; function create_main_fragment ( state, component ) { diff --git a/test/js/samples/event-handlers-custom/expected-bundle.js b/test/js/samples/event-handlers-custom/expected-bundle.js index 8fa8ead617..3912710a15 100644 --- a/test/js/samples/event-handlers-custom/expected-bundle.js +++ b/test/js/samples/event-handlers-custom/expected-bundle.js @@ -109,15 +109,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -125,8 +121,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; var template = (function () { 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 65634e0748..f00e3816a9 100644 --- a/test/js/samples/if-block-no-update/expected-bundle.js +++ b/test/js/samples/if-block-no-update/expected-bundle.js @@ -115,15 +115,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -131,8 +127,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; function create_main_fragment ( state, component ) { diff --git a/test/js/samples/if-block-simple/expected-bundle.js b/test/js/samples/if-block-simple/expected-bundle.js index bf78f1ca68..2e2e7e7c09 100644 --- a/test/js/samples/if-block-simple/expected-bundle.js +++ b/test/js/samples/if-block-simple/expected-bundle.js @@ -115,15 +115,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -131,8 +127,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; function create_main_fragment ( state, component ) { diff --git a/test/js/samples/non-imported-component/expected-bundle.js b/test/js/samples/non-imported-component/expected-bundle.js index 030c57369b..878bdf223e 100644 --- a/test/js/samples/non-imported-component/expected-bundle.js +++ b/test/js/samples/non-imported-component/expected-bundle.js @@ -103,15 +103,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -119,8 +115,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; var template = (function () { @@ -192,7 +187,7 @@ function SvelteComponent ( options ) { this._fragment.mount( options.target, null ); } - this._flush(); + callAll(this._oncreate); } assign( SvelteComponent.prototype, proto ); @@ -202,7 +197,7 @@ SvelteComponent.prototype._set = function _set ( newState ) { this._state = assign( {}, oldState, newState ); dispatchObservers( this, this._observers.pre, newState, oldState ); dispatchObservers( this, this._observers.post, newState, oldState ); - this._flush(); + callAll(this._oncreate); }; SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { diff --git a/test/js/samples/non-imported-component/expected.js b/test/js/samples/non-imported-component/expected.js index e2aa2d4457..c154930593 100644 --- a/test/js/samples/non-imported-component/expected.js +++ b/test/js/samples/non-imported-component/expected.js @@ -1,6 +1,6 @@ import Imported from 'Imported.html'; -import { assign, createText, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; +import { assign, callAll, createText, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; var template = (function () { return { @@ -71,7 +71,7 @@ function SvelteComponent ( options ) { this._fragment.mount( options.target, null ); } - this._flush(); + callAll(this._oncreate); } assign( SvelteComponent.prototype, proto ); @@ -81,7 +81,7 @@ SvelteComponent.prototype._set = function _set ( newState ) { this._state = assign( {}, oldState, newState ); dispatchObservers( this, this._observers.pre, newState, oldState ); dispatchObservers( this, this._observers.post, newState, oldState ); - this._flush(); + callAll(this._oncreate); }; SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { diff --git a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js index f5849818fe..e74522a945 100644 --- a/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js +++ b/test/js/samples/onrender-onteardown-rewritten/expected-bundle.js @@ -91,15 +91,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -107,8 +103,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; var template = (function () { 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 63138c0157..62a6ac86e0 100644 --- a/test/js/samples/use-elements-as-anchors/expected-bundle.js +++ b/test/js/samples/use-elements-as-anchors/expected-bundle.js @@ -115,15 +115,11 @@ function on(eventName, handler) { function set(newState) { this._set(assign({}, newState)); - this._root._flush(); + callAll(this._root._oncreate); } -function _flush() { - if (!this._oncreate) return; - - while (this._oncreate.length) { - this._oncreate.pop()(); - } +function callAll(fns) { + while (fns && fns.length) fns.pop()(); } var proto = { @@ -131,8 +127,7 @@ var proto = { fire: fire, observe: observe, on: on, - set: set, - _flush: _flush + set: set }; function create_main_fragment ( state, component ) { 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 0000000000..71e9ccd39c --- /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 0000000000..0436513348 --- /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