Merge pull request #709 from sveltejs/gh-708

[WIP] Fix #708
pull/723/head
Rich Harris 8 years ago committed by GitHub
commit 1474556dc1

@ -125,9 +125,6 @@ export default function dom(
@dispatchObservers( this, this._observers.pre, newState, oldState ); @dispatchObservers( this, this._observers.pre, newState, oldState );
${block.hasUpdateMethod && `this._fragment.update( newState, this._state );`} ${block.hasUpdateMethod && `this._fragment.update( newState, this._state );`}
@dispatchObservers( this, this._observers.post, newState, oldState ); @dispatchObservers( this, this._observers.post, newState, oldState );
${generator.hasComponents && `@callAll(this._oncreate);`}
${generator.hasComplexBindings && `@callAll(this._bindings);`}
${generator.hasIntroTransitions && `@callAll(this._postcreate);`}
`; `;
if (hasJs) { if (hasJs) {
@ -207,9 +204,20 @@ export default function dom(
${generator.stylesheet.hasStyles && ${generator.stylesheet.hasStyles &&
options.css !== false && options.css !== false &&
`if ( !document.getElementById( '${generator.stylesheet.id}-style' ) ) @add_css();`} `if ( !document.getElementById( '${generator.stylesheet.id}-style' ) ) @add_css();`}
${generator.hasComponents && `this._oncreate = [];`}
${generator.hasComplexBindings && `this._bindings = [];`} ${templateProperties.oncreate && `var oncreate = @template.oncreate.bind( this );`}
${generator.hasIntroTransitions && `this._postcreate = [];`}
${(templateProperties.oncreate || generator.hasComponents || generator.hasComplexBindings || generator.hasIntroTransitions) && deindent`
if ( !options._root ) {
this._oncreate = [${templateProperties.oncreate && `oncreate`}];
${(generator.hasComponents || generator.hasComplexBindings) && `this._beforecreate = [];`}
${(generator.hasComponents || generator.hasIntroTransitions) && `this._aftercreate = [];`}
} ${templateProperties.oncreate && deindent`
else {
this._root._oncreate.push(oncreate);
}
`}
`}
this._fragment = @create_main_fragment( this._state, this ); this._fragment = @create_main_fragment( this._state, this );
@ -227,17 +235,15 @@ export default function dom(
this._fragment.${block.hasIntroMethod ? 'intro' : 'mount'}( options.target, null ); this._fragment.${block.hasIntroMethod ? 'intro' : 'mount'}( options.target, null );
} }
${generator.hasComponents && `@callAll(this._oncreate);`} ${(generator.hasComponents || generator.hasComplexBindings || templateProperties.oncreate || generator.hasIntroTransitions) && deindent`
${generator.hasComplexBindings && `@callAll(this._bindings);`} if ( !options._root ) {
${generator.hasComponents && `this._lock = true;`}
${templateProperties.oncreate && deindent` ${(generator.hasComponents || generator.hasComplexBindings) && `@callAll(this._beforecreate);`}
if ( options._root ) { ${(generator.hasComponents || templateProperties.oncreate) && `@callAll(this._oncreate);`}
options._root._oncreate.push( @template.oncreate.bind( this ) ); ${(generator.hasComponents || generator.hasIntroTransitions) && `@callAll(this._aftercreate);`}
} else { ${generator.hasComponents && `this._lock = false;`}
@template.oncreate.call( this ); }
}`} `}
${generator.hasIntroTransitions && `@callAll(this._postcreate);`}
} }
@assign( ${prototypeBase}, ${proto}); @assign( ${prototypeBase}, ${proto});

@ -66,15 +66,24 @@ export default function visitBinding(
const updating = block.getUniqueName(`${local.name}_updating`); const updating = block.getUniqueName(`${local.name}_updating`);
block.addVariable(updating, 'false'); block.addVariable(updating, 'false');
const observer = block.getUniqueName('observer');
const value = block.getUniqueName('value');
local.create.addBlock(deindent` local.create.addBlock(deindent`
#component._bindings.push( function () { function ${observer} ( value ) {
if ( ${local.name}._torndown ) return;
${local.name}.observe( '${attribute.name}', function ( value ) {
if ( ${updating} ) return; if ( ${updating} ) return;
${updating} = true; ${updating} = true;
${setter} ${setter}
${updating} = false; ${updating} = false;
}, { init: @differs( ${local.name}.get( '${attribute.name}' ), ${snippet} ) }); }
${local.name}.observe( '${attribute.name}', ${observer}, { init: false });
#component._root._beforecreate.push( function () {
var value = ${local.name}.get( '${attribute.name}' );
if ( @differs( value, ${snippet} ) ) {
${observer}.call( ${local.name}, value );
}
}); });
`); `);

@ -94,7 +94,7 @@ export default function visitBinding(
generator.hasComplexBindings = true; generator.hasComplexBindings = true;
block.builders.hydrate.addBlock( block.builders.hydrate.addBlock(
`if ( !('${name}' in state) ) #component._bindings.push( ${handler} );` `if ( !('${name}' in state) ) #component._root._beforecreate.push( ${handler} );`
); );
} else if (attribute.name === 'group') { } else if (attribute.name === 'group') {
// <input type='checkbox|radio' bind:group='selected'> special case // <input type='checkbox|radio' bind:group='selected'> special case
@ -120,7 +120,7 @@ export default function visitBinding(
updateElement = `${state.parentNode}.checked = ${condition};`; updateElement = `${state.parentNode}.checked = ${condition};`;
} else if (node.name === 'audio' || node.name === 'video') { } else if (node.name === 'audio' || node.name === 'video') {
generator.hasComplexBindings = true; generator.hasComplexBindings = true;
block.builders.hydrate.addBlock(`#component._bindings.push( ${handler} );`); block.builders.hydrate.addBlock(`#component._root._beforecreate.push( ${handler} );`);
if (attribute.name === 'currentTime') { if (attribute.name === 'currentTime') {
const frame = block.getUniqueName(`${state.parentNode}_animationframe`); const frame = block.getUniqueName(`${state.parentNode}_animationframe`);

@ -23,7 +23,7 @@ export default function addTransitions(
const fn = `@template.transitions.${intro.name}`; const fn = `@template.transitions.${intro.name}`;
block.builders.intro.addBlock(deindent` block.builders.intro.addBlock(deindent`
#component._postcreate.push( function () { #component._root._aftercreate.push( function () {
if ( !${name} ) ${name} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null ); if ( !${name} ) ${name} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null );
${name}.run( true, function () { ${name}.run( true, function () {
#component.fire( 'intro.end', { node: ${state.name} }); #component.fire( 'intro.end', { node: ${state.name} });
@ -58,7 +58,7 @@ export default function addTransitions(
} }
block.builders.intro.addBlock(deindent` block.builders.intro.addBlock(deindent`
#component._postcreate.push( function () { #component._root._aftercreate.push( function () {
${introName} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null ); ${introName} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null );
${introName}.run( true, function () { ${introName}.run( true, function () {
#component.fire( 'intro.end', { node: ${state.name} }); #component.fire( 'intro.end', { node: ${state.name} });

@ -27,10 +27,10 @@ export default function getSetter({
list[index]${tail} = ${value}; list[index]${tail} = ${value};
${computed ${computed
? `#component._set({ ${dependencies ? `#component.set({ ${dependencies
.map((prop: string) => `${prop}: state.${prop}`) .map((prop: string) => `${prop}: state.${prop}`)
.join(', ')} });` .join(', ')} });`
: `#component._set({ ${dependencies : `#component.set({ ${dependencies
.map((prop: string) => `${prop}: #component.get( '${prop}' )`) .map((prop: string) => `${prop}: #component.get( '${prop}' )`)
.join(', ')} });`} .join(', ')} });`}
`; `;
@ -40,13 +40,13 @@ export default function getSetter({
return deindent` return deindent`
var state = #component.get(); var state = #component.get();
${snippet} = ${value}; ${snippet} = ${value};
#component._set({ ${dependencies #component.set({ ${dependencies
.map((prop: string) => `${prop}: state.${prop}`) .map((prop: string) => `${prop}: state.${prop}`)
.join(', ')} }); .join(', ')} });
`; `;
} }
return `#component._set({ ${name}: ${value} });`; return `#component.set({ ${name}: ${value} });`;
} }
function isComputed(node: Node) { function isComputed(node: Node) {

@ -106,7 +106,12 @@ export function onDev(eventName, handler) {
export function set(newState) { export function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
export function callAll(fns) { export function callAll(fns) {

@ -115,7 +115,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {

@ -91,7 +91,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {

@ -124,7 +124,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {

@ -109,7 +109,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {

@ -115,7 +115,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {

@ -115,7 +115,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {

@ -103,7 +103,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {
@ -178,7 +183,12 @@ function SvelteComponent ( options ) {
this._yield = options._yield; this._yield = options._yield;
this._torndown = false; this._torndown = false;
if ( !options._root ) {
this._oncreate = []; this._oncreate = [];
this._beforecreate = [];
this._aftercreate = [];
}
this._fragment = create_main_fragment( this._state, this ); this._fragment = create_main_fragment( this._state, this );
@ -187,7 +197,13 @@ function SvelteComponent ( options ) {
this._fragment.mount( options.target, null ); this._fragment.mount( options.target, null );
} }
if ( !options._root ) {
this._lock = true;
callAll(this._beforecreate);
callAll(this._oncreate); callAll(this._oncreate);
callAll(this._aftercreate);
this._lock = false;
}
} }
assign( SvelteComponent.prototype, proto ); assign( SvelteComponent.prototype, proto );
@ -197,7 +213,6 @@ SvelteComponent.prototype._set = function _set ( newState ) {
this._state = assign( {}, oldState, newState ); this._state = assign( {}, oldState, newState );
dispatchObservers( this, this._observers.pre, newState, oldState ); dispatchObservers( this, this._observers.pre, newState, oldState );
dispatchObservers( this, this._observers.post, newState, oldState ); dispatchObservers( this, this._observers.post, newState, oldState );
callAll(this._oncreate);
}; };
SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) {

@ -62,7 +62,12 @@ function SvelteComponent ( options ) {
this._yield = options._yield; this._yield = options._yield;
this._torndown = false; this._torndown = false;
if ( !options._root ) {
this._oncreate = []; this._oncreate = [];
this._beforecreate = [];
this._aftercreate = [];
}
this._fragment = create_main_fragment( this._state, this ); this._fragment = create_main_fragment( this._state, this );
@ -71,7 +76,13 @@ function SvelteComponent ( options ) {
this._fragment.mount( options.target, null ); this._fragment.mount( options.target, null );
} }
if ( !options._root ) {
this._lock = true;
callAll(this._beforecreate);
callAll(this._oncreate); callAll(this._oncreate);
callAll(this._aftercreate);
this._lock = false;
}
} }
assign( SvelteComponent.prototype, proto ); assign( SvelteComponent.prototype, proto );
@ -81,7 +92,6 @@ SvelteComponent.prototype._set = function _set ( newState ) {
this._state = assign( {}, oldState, newState ); this._state = assign( {}, oldState, newState );
dispatchObservers( this, this._observers.pre, newState, oldState ); dispatchObservers( this, this._observers.pre, newState, oldState );
dispatchObservers( this, this._observers.post, newState, oldState ); dispatchObservers( this, this._observers.post, newState, oldState );
callAll(this._oncreate);
}; };
SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) {

@ -91,7 +91,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {
@ -143,6 +148,14 @@ function SvelteComponent ( options ) {
this._torndown = false; this._torndown = false;
var oncreate = template.oncreate.bind( this );
if ( !options._root ) {
this._oncreate = [oncreate];
} else {
this._root._oncreate.push(oncreate);
}
this._fragment = create_main_fragment( this._state, this ); this._fragment = create_main_fragment( this._state, this );
if ( options.target ) { if ( options.target ) {
@ -150,10 +163,8 @@ function SvelteComponent ( options ) {
this._fragment.mount( options.target, null ); this._fragment.mount( options.target, null );
} }
if ( options._root ) { if ( !options._root ) {
options._root._oncreate.push( template.oncreate.bind( this ) ); callAll(this._oncreate);
} else {
template.oncreate.call( this );
} }
} }

@ -1,4 +1,4 @@
import { assign, dispatchObservers, noop, proto } from "svelte/shared.js"; import { assign, callAll, dispatchObservers, noop, proto } from "svelte/shared.js";
var template = (function () { var template = (function () {
return { return {
@ -37,6 +37,14 @@ function SvelteComponent ( options ) {
this._torndown = false; this._torndown = false;
var oncreate = template.oncreate.bind( this );
if ( !options._root ) {
this._oncreate = [oncreate];
} else {
this._root._oncreate.push(oncreate);
}
this._fragment = create_main_fragment( this._state, this ); this._fragment = create_main_fragment( this._state, this );
if ( options.target ) { if ( options.target ) {
@ -44,10 +52,8 @@ function SvelteComponent ( options ) {
this._fragment.mount( options.target, null ); this._fragment.mount( options.target, null );
} }
if ( options._root ) { if ( !options._root ) {
options._root._oncreate.push( template.oncreate.bind( this ) ); callAll(this._oncreate);
} else {
template.oncreate.call( this );
} }
} }

@ -115,7 +115,12 @@ function on(eventName, handler) {
function set(newState) { function set(newState) {
this._set(assign({}, newState)); this._set(assign({}, newState));
if (this._root._lock) return;
this._root._lock = true;
callAll(this._root._beforecreate);
callAll(this._root._oncreate); callAll(this._root._oncreate);
callAll(this._root._aftercreate);
this._root._lock = false;
} }
function callAll(fns) { function callAll(fns) {

@ -137,10 +137,9 @@ describe("runtime", () => {
throw err; throw err;
} }
let usedObjectAssign = false;
Object.assign = () => { Object.assign = () => {
throw new Error( usedObjectAssign = true;
"cannot use Object.assign in generated code, as it is not supported everywhere"
);
}; };
global.window = window; global.window = window;
@ -182,14 +181,18 @@ describe("runtime", () => {
assert.htmlEqual(target.innerHTML, config.html); assert.htmlEqual(target.innerHTML, config.html);
} }
Object.assign = Object_assign;
if (config.test) { if (config.test) {
config.test(assert, component, target, window, raf); config.test(assert, component, target, window, raf);
} else { } else {
component.destroy(); component.destroy();
assert.equal(target.innerHTML, ""); assert.equal(target.innerHTML, "");
} }
if (usedObjectAssign) {
throw new Error(
"cannot use Object.assign in generated code, as it is not supported everywhere"
);
}
}) })
.catch(err => { .catch(err => {
Object.assign = Object_assign; Object.assign = Object_assign;

@ -0,0 +1,18 @@
<li>
{{yield}}
</li>
<script>
const initialValues = {
'id-0': 'zero',
'id-1': 'one',
'id-2': 'two',
'id-3': 'three'
};
export default {
oncreate() {
this.set({ value: initialValues[this.get('id')] });
}
};
</script>

@ -0,0 +1,33 @@
export default {
'skip-ssr': true,
data: {
count: 3
},
html: `
<input type='number'>
<ol>
<li>id-0: value is zero</li>
<li>id-1: value is one</li>
<li>id-2: value is two</li>
</ol>
`,
test (assert, component, target, window) {
const input = target.querySelector('input');
input.value = 4;
input.dispatchEvent(new window.Event('input'));
assert.htmlEqual(target.innerHTML, `
<input type='number'>
<ol>
<li>id-0: value is zero</li>
<li>id-1: value is one</li>
<li>id-2: value is two</li>
<li>id-3: value is three</li>
</ol>
`);
}
};

@ -0,0 +1,33 @@
<input type='number' bind:value='count'>
<ol>
{{#each ids as id}}
<Nested :id bind:value="idToValue[id]">
{{id}}: value is {{idToValue[id]}}
</Nested>
{{/each}}
</ol>
<script>
import Nested from './Nested.html';
export default {
data() {
return {
idToValue: Object.create(null)
};
},
computed: {
ids(count) {
return new Array(count)
.fill(null)
.map((_, i) => 'id-' + i);
}
},
components: {
Nested
}
};
</script>
Loading…
Cancel
Save