initialise fragments with data, rather than waiting for first update

pull/31/head
Rich-Harris 8 years ago
parent 7736866397
commit 04388f7a0e

@ -17,11 +17,11 @@ export default function generate ( parsed, source, options ) {
} }
renderers.push( deindent` renderers.push( deindent`
function ${fragment.name} ( component, target${fragment.useAnchor ? ', anchor' : ''} ) { function ${fragment.name} ( ${fragment.params}, component, target${fragment.useAnchor ? ', anchor' : ''} ) {
${fragment.initStatements.join( '\n\n' )} ${fragment.initStatements.join( '\n\n' )}
return { return {
update: function ( ${fragment.params.join( ', ' )} ) { update: function ( changed, ${fragment.params} ) {
${fragment.updateStatements.join( '\n\n' )} ${fragment.updateStatements.join( '\n\n' )}
}, },
@ -86,7 +86,8 @@ export default function generate ( parsed, source, options ) {
return { return {
dependencies, dependencies,
contexts: usedContexts, contexts: usedContexts,
snippet: `[✂${expression.start}-${expression.end}✂]` snippet: `[✂${expression.start}-${expression.end}✂]`,
string: generator.code.slice( expression.start, expression.end )
}; };
}, },
@ -211,7 +212,7 @@ export default function generate ( parsed, source, options ) {
contexts: {}, contexts: {},
indexes: {}, indexes: {},
params: [ 'changed', 'root' ], params: 'root',
indexNames: {}, indexNames: {},
listNames: {}, listNames: {},
@ -222,12 +223,15 @@ export default function generate ( parsed, source, options ) {
generator.addRenderer( generator.pop() ); generator.addRenderer( generator.pop() );
const topLevelStatements = [];
const setStatements = [ deindent` const setStatements = [ deindent`
const oldState = state; const oldState = state;
state = Object.assign( {}, oldState, newState ); state = Object.assign( {}, oldState, newState );
` ]; ` ];
if ( templateProperties.computed ) { if ( templateProperties.computed ) {
const statements = [];
const dependencies = new Map(); const dependencies = new Map();
templateProperties.computed.properties.forEach( prop => { templateProperties.computed.properties.forEach( prop => {
@ -249,7 +253,7 @@ export default function generate ( parsed, source, options ) {
const deps = dependencies.get( key ); const deps = dependencies.get( key );
deps.forEach( visit ); deps.forEach( visit );
setStatements.push( deindent` statements.push( deindent`
if ( ${deps.map( dep => `( '${dep}' in newState && typeof state.${dep} === 'object' || state.${dep} !== oldState.${dep} )` ).join( ' || ' )} ) { if ( ${deps.map( dep => `( '${dep}' in newState && typeof state.${dep} === 'object' || state.${dep} !== oldState.${dep} )` ).join( ' || ' )} ) {
state.${key} = newState.${key} = template.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} ); state.${key} = newState.${key} = template.computed.${key}( ${deps.map( dep => `state.${dep}` ).join( ', ' )} );
} }
@ -257,6 +261,14 @@ export default function generate ( parsed, source, options ) {
} }
templateProperties.computed.properties.forEach( prop => visit( prop.key.name ) ); templateProperties.computed.properties.forEach( prop => visit( prop.key.name ) );
topLevelStatements.push( deindent`
function applyComputations ( state, newState, oldState ) {
${statements.join( '\n\n' )}
}
` );
setStatements.push( `applyComputations( state, newState, oldState )` );
} }
setStatements.push( deindent` setStatements.push( deindent`
@ -265,8 +277,6 @@ export default function generate ( parsed, source, options ) {
dispatchObservers( observers.deferred, newState, oldState ); dispatchObservers( observers.deferred, newState, oldState );
` ); ` );
const topLevelStatements = [];
if ( parsed.js ) { if ( parsed.js ) {
if ( imports.length ) { if ( imports.length ) {
topLevelStatements.push( imports.join( '' ).trim() ); topLevelStatements.push( imports.join( '' ).trim() );
@ -290,23 +300,27 @@ export default function generate ( parsed, source, options ) {
} }
if ( generator.hasComplexBindings ) { if ( generator.hasComplexBindings ) {
initStatements.push( `this.__bindings = [];` ); initStatements.push( deindent`
this.__bindings = [];
var mainFragment = renderMainFragment( state, this, options.target );
while ( this.__bindings.length ) this.__bindings.pop()();
` );
setStatements.push( `while ( this.__bindings.length ) this.__bindings.pop()();` ); setStatements.push( `while ( this.__bindings.length ) this.__bindings.pop()();` );
} else {
initStatements.push( `var mainFragment = renderMainFragment( state, this, options.target );` );
} }
initStatements.push( deindent`
var mainFragment = renderMainFragment( this, options.target );
this.set( ${templateProperties.data ? `Object.assign( template.data(), options.data )` : `options.data || {}`} );
` );
if ( templateProperties.onrender ) { if ( templateProperties.onrender ) {
initStatements.push( `template.onrender.call( this );` ); initStatements.push( `template.onrender.call( this );` );
} }
const initialState = templateProperties.data ? `Object.assign( template.data(), options.data )` : `options.data || {}`;
topLevelStatements.push( deindent` topLevelStatements.push( deindent`
export default function ${constructorName} ( options ) { export default function ${constructorName} ( options ) {
var component = this;${generator.usesRefs ? `\nthis.refs = {}` : ``} var component = this;${generator.usesRefs ? `\nthis.refs = {}` : ``}
var state = {}; var state = ${initialState};${templateProperties.computed ? `\napplyComputations( state, state, {} );` : ``}
var observers = { var observers = {
immediate: Object.create( null ), immediate: Object.create( null ),

@ -9,27 +9,34 @@ export default {
const listName = `${name}_value`; const listName = `${name}_value`;
generator.addSourcemapLocations( node.expression );
const { dependencies, snippet, string } = generator.contextualise( node.expression );
generator.current.initStatements.push( deindent` generator.current.initStatements.push( deindent`
var ${name}_anchor = document.createComment( ${JSON.stringify( `#each ${generator.source.slice( node.expression.start, node.expression.end )}` )} ); var ${name}_anchor = document.createComment( ${JSON.stringify( `#each ${generator.source.slice( node.expression.start, node.expression.end )}` )} );
${generator.current.target}.appendChild( ${name}_anchor ); ${generator.current.target}.appendChild( ${name}_anchor );
var ${name}_value = ${snippet};
var ${name}_fragment = document.createDocumentFragment();
var ${name}_iterations = []; var ${name}_iterations = [];
const ${name}_fragment = document.createDocumentFragment();
` );
generator.addSourcemapLocations( node.expression ); for ( var i = 0; i < ${name}_value.length; i += 1 ) {
${name}_iterations[i] = ${renderer}( ${generator.current.params}, ${listName}, ${listName}[i], i, component, ${name}_fragment );
}
const { dependencies, snippet } = generator.contextualise( node.expression ); ${name}_anchor.parentNode.insertBefore( ${name}_fragment, ${name}_anchor );
` );
generator.current.updateStatements.push( deindent` generator.current.updateStatements.push( deindent`
var ${name}_value = ${snippet}; var ${name}_value = ${string};
for ( var i = 0; i < ${name}_value.length; i += 1 ) { for ( var i = 0; i < ${name}_value.length; i += 1 ) {
if ( !${name}_iterations[i] ) { if ( !${name}_iterations[i] ) {
${name}_iterations[i] = ${renderer}( component, ${name}_fragment ); ${name}_iterations[i] = ${renderer}( ${generator.current.params}, ${listName}, ${listName}[i], i, component, ${name}_fragment );
} else {
${name}_iterations[i].update( changed, ${generator.current.params}, ${listName}, ${listName}[i], i );
} }
const iteration = ${name}_iterations[i];
${name}_iterations[i].update( ${generator.current.params.join( ', ' )}, ${listName}, ${listName}[i], i );
} }
for ( var i = ${name}_value.length; i < ${name}_iterations.length; i += 1 ) { for ( var i = ${name}_value.length; i < ${name}_iterations.length; i += 1 ) {
@ -63,7 +70,7 @@ export default {
const contextDependencies = Object.assign( {}, generator.current.contextDependencies ); const contextDependencies = Object.assign( {}, generator.current.contextDependencies );
contextDependencies[ node.context ] = dependencies; contextDependencies[ node.context ] = dependencies;
const params = generator.current.params.concat( listName, node.context, indexName ); const params = generator.current.params + `, ${listName}, ${node.context}, ${indexName}`;
generator.current = { generator.current = {
useAnchor: false, useAnchor: false,

@ -22,13 +22,39 @@ export default {
if ( isComponent ) { if ( isComponent ) {
addComponentAttributes( generator, node, local ); addComponentAttributes( generator, node, local );
if ( local.staticAttributes.length ) { if ( local.staticAttributes.length || local.dynamicAttributes.length || local.bindings.length ) {
const initialProps = local.staticAttributes
.concat( local.dynamicAttributes )
.map( attribute => `${attribute.name}: ${attribute.value}` );
const statements = [];
if ( initialProps.length ) {
statements.push( deindent`
var ${name}_initialData = {
${initialProps.join( ',\n' )}
};
` );
} else {
statements.push( `var ${name}_initialData = {};` );
}
if ( local.bindings.length ) {
const bindings = local.bindings.map( binding => {
const parts = binding.value.split( '.' );
const tail = parts.pop();
return `if ( '${tail}' in ${parts.join( '.' )} ) ${name}_initialData.${binding.name} = ${binding.value};`;
});
statements.push( bindings.join( '\n' ) );
}
local.init.unshift( deindent` local.init.unshift( deindent`
${statements.join( '\n\n' )}
var ${name} = new template.components.${node.name}({ var ${name} = new template.components.${node.name}({
target: ${generator.current.target}, target: ${generator.current.target},
data: { data: ${name}_initialData
${local.staticAttributes.join( ',\n' )}
}
}); });
` ); ` );
} else { } else {
@ -62,11 +88,18 @@ export default {
addElementAttributes( generator, node, local ); addElementAttributes( generator, node, local );
if ( local.allUsedContexts.size ) { if ( local.allUsedContexts.size ) {
local.init.push( deindent` const contextNames = [...local.allUsedContexts];
${name}.__svelte = {};
` ); const initialProps = contextNames.map( contextName => {
if ( contextName === 'root' ) return `root: root`;
const declarations = [...local.allUsedContexts].map( contextName => { const listName = generator.current.listNames[ contextName ];
const indexName = generator.current.indexNames[ contextName ];
return `${listName}: ${listName},\n${indexName}: ${indexName}`;
}).join( ',\n' );
const updates = contextNames.map( contextName => {
if ( contextName === 'root' ) return `${name}.__svelte.root = root;`; if ( contextName === 'root' ) return `${name}.__svelte.root = root;`;
const listName = generator.current.listNames[ contextName ]; const listName = generator.current.listNames[ contextName ];
@ -75,7 +108,13 @@ export default {
return `${name}.__svelte.${listName} = ${listName};\n${name}.__svelte.${indexName} = ${indexName};`; return `${name}.__svelte.${listName} = ${listName};\n${name}.__svelte.${indexName} = ${indexName};`;
}).join( '\n' ); }).join( '\n' );
local.update.push( declarations ); local.init.push( deindent`
${name}.__svelte = {
${initialProps}
};
` );
local.update.push( updates );
} }
let render = local.namespace ? let render = local.namespace ?

@ -10,18 +10,36 @@ export default {
const elseName = `elseBlock_${i}`; const elseName = `elseBlock_${i}`;
const elseRenderer = `renderElseBlock_${i}`; const elseRenderer = `renderElseBlock_${i}`;
generator.addSourcemapLocations( node.expression );
const { snippet, string } = generator.contextualise( node.expression );
generator.current.initStatements.push( deindent` generator.current.initStatements.push( deindent`
var ${name}_anchor = document.createComment( ${JSON.stringify( `#if ${generator.source.slice( node.expression.start, node.expression.end )}` )} ); var ${name}_anchor = document.createComment( ${JSON.stringify( `#if ${generator.source.slice( node.expression.start, node.expression.end )}` )} );
${generator.current.target}.appendChild( ${name}_anchor ); ${generator.current.target}.appendChild( ${name}_anchor );
var ${name} = null;${node.else ? `\nvar ${elseName} = null;` : ``}
` ); ` );
generator.addSourcemapLocations( node.expression ); if ( node.else ) {
const { snippet } = generator.contextualise( node.expression ); generator.current.initStatements.push( deindent`
var ${name} = null;
var ${elseName} = null;
if ( ${snippet} ) {
${name} = ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
} else {
${elseName} = ${elseRenderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
}
` );
} else {
generator.current.initStatements.push( deindent`
var ${name} = ${snippet} ? ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor ) : null;
` );
}
const ifTrue = [ deindent` const ifTrue = [ deindent`
if ( !${name } ) { if ( !${name } ) {
${name} = ${renderer}( component, ${generator.current.target}, ${name}_anchor ); ${name} = ${renderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
} else {
${name}.update( changed, ${generator.current.params} );
} }
` ]; ` ];
@ -44,25 +62,25 @@ export default {
if ( node.else ) { if ( node.else ) {
ifFalse.push( deindent` ifFalse.push( deindent`
if ( !${elseName } ) { if ( !${elseName } ) {
${elseName} = ${elseRenderer}( component, ${generator.current.target}, ${name}_anchor ); ${elseName} = ${elseRenderer}( ${generator.current.params}, component, ${generator.current.target}, ${name}_anchor );
} else {
${elseName}.update( changed, ${generator.current.params} );
} }
` ); ` );
} }
let update = deindent` let update = deindent`
if ( ${snippet} ) { if ( ${string} ) {
${ifTrue.join( '\n\n' )} ${ifTrue.join( '\n\n' )}
} }
else { else {
${ifFalse.join( '\n\n' )} ${ifFalse.join( '\n\n' )}
} }
if ( ${name} ) ${name}.update( ${generator.current.params.join( ', ' )} );
`; `;
if ( node.else ) { if ( node.else ) {
update += `\nif ( ${elseName} ) ${elseName}.update( ${generator.current.params.join( ', ' )} );`; update += `\nif ( ${elseName} ) ${elseName}.update( changed, ${generator.current.params} );`;
} }
generator.current.updateStatements.push( update ); generator.current.updateStatements.push( update );

@ -5,36 +5,17 @@ export default {
enter ( generator, node ) { enter ( generator, node ) {
const name = generator.current.counter( 'text' ); const name = generator.current.counter( 'text' );
const { snippet, string } = generator.contextualise( node.expression );
generator.current.initStatements.push( deindent` generator.current.initStatements.push( deindent`
var ${name} = document.createTextNode( '' ); var ${name} = document.createTextNode( ${snippet} );
var ${name}_value = '';
${generator.current.target}.appendChild( ${name} ); ${generator.current.target}.appendChild( ${name} );
` ); ` );
generator.addSourcemapLocations( node.expression ); generator.addSourcemapLocations( node.expression );
const { contexts, snippet } = generator.contextualise( node.expression ); generator.current.updateStatements.push( deindent`
${name}.data = ${string};
if ( isReference( node.expression ) ) { ` );
const reference = `${generator.source.slice( node.expression.start, node.expression.end )}`;
const qualified = contexts[0] === 'root' ? `root.${reference}` : reference;
generator.current.updateStatements.push( deindent`
if ( ${snippet} !== ${name}_value ) {
${name}_value = ${qualified};
${name}.data = ${name}_value;
}
` );
} else {
const temp = generator.getName( 'temp' );
generator.current.updateStatements.push( deindent`
var ${temp} = ${snippet};
if ( ${temp} !== ${name}_value ) {
${name}_value = ${temp};
${name}.data = ${name}_value;
}
` );
}
} }
}; };

@ -4,12 +4,16 @@ import deindent from '../../utils/deindent.js';
export default function addComponentAttributes ( generator, node, local ) { export default function addComponentAttributes ( generator, node, local ) {
local.staticAttributes = []; local.staticAttributes = [];
local.dynamicAttributes = []; local.dynamicAttributes = [];
local.bindings = [];
node.attributes.forEach( attribute => { node.attributes.forEach( attribute => {
if ( attribute.type === 'Attribute' ) { if ( attribute.type === 'Attribute' ) {
if ( attribute.value === true ) { if ( attribute.value === true ) {
// attributes without values, e.g. <textarea readonly> // attributes without values, e.g. <textarea readonly>
local.staticAttributes.push( `${attribute.name}: true` ); local.staticAttributes.push({
name: attribute.name,
value: true
});
} }
else if ( attribute.value.length === 1 ) { else if ( attribute.value.length === 1 ) {
@ -18,17 +22,20 @@ export default function addComponentAttributes ( generator, node, local ) {
if ( value.type === 'Text' ) { if ( value.type === 'Text' ) {
// static attributes // static attributes
const result = isNaN( parseFloat( value.data ) ) ? JSON.stringify( value.data ) : value.data; const result = isNaN( parseFloat( value.data ) ) ? JSON.stringify( value.data ) : value.data;
local.staticAttributes.push( `${attribute.name}: ${result}` ); local.staticAttributes.push({
name: attribute.name,
value: result
});
} }
else { else {
// simple dynamic attributes // simple dynamic attributes
const { dependencies, snippet } = generator.contextualise( value.expression ); const { dependencies, string } = generator.contextualise( value.expression );
// TODO only update attributes that have changed // TODO only update attributes that have changed
local.dynamicAttributes.push({ local.dynamicAttributes.push({
name: attribute.name, name: attribute.name,
value: snippet, value: string,
dependencies dependencies
}); });
} }
@ -45,12 +52,12 @@ export default function addComponentAttributes ( generator, node, local ) {
} else { } else {
generator.addSourcemapLocations( chunk.expression ); generator.addSourcemapLocations( chunk.expression );
const { dependencies, snippet } = generator.contextualise( chunk.expression ); const { dependencies, string } = generator.contextualise( chunk.expression );
dependencies.forEach( dependency => { dependencies.forEach( dependency => {
if ( !~allDependencies.indexOf( dependency ) ) allDependencies.push( dependency ); if ( !~allDependencies.indexOf( dependency ) ) allDependencies.push( dependency );
}); });
return `( ${snippet} )`; return `( ${string} )`;
} }
}).join( ' + ' ) }).join( ' + ' )
); );

@ -61,17 +61,14 @@ export default function addElementAttributes ( generator, node, local ) {
dynamic = true; dynamic = true;
// dynamic but potentially non-string attributes // dynamic but potentially non-string attributes
const { snippet } = generator.contextualise( value.expression ); const { snippet, string } = generator.contextualise( value.expression );
if ( propertyName ) { const updater = propertyName ?
local.update.push( deindent` `${local.name}.${propertyName} = ${snippet};` :
${local.name}.${propertyName} = ${snippet}; `${local.name}.setAttribute( '${attribute.name}', ${string} );`; // TODO use snippet both times see note below
` );
} else { local.init.push( updater );
local.update.push( deindent` local.update.push( updater );
${local.name}.setAttribute( '${attribute.name}', ${snippet} );
` );
}
} }
} }
@ -85,21 +82,18 @@ export default function addElementAttributes ( generator, node, local ) {
} else { } else {
generator.addSourcemapLocations( chunk.expression ); generator.addSourcemapLocations( chunk.expression );
const { snippet } = generator.contextualise( chunk.expression ); const { string } = generator.contextualise( chunk.expression ); // TODO use snippet for sourcemap support need to add a 'copy' feature to MagicString first
return `( ${snippet} )`; return `( ${string} )`;
} }
}).join( ' + ' ) }).join( ' + ' )
); );
if ( propertyName ) { const updater = propertyName ?
local.update.push( deindent` `${local.name}.${propertyName} = ${value};` :
${local.name}.${propertyName} = ${value}; `${local.name}.setAttribute( '${attribute.name}', ${value} );`;
` );
} else { local.init.push( updater );
local.update.push( deindent` local.update.push( updater );
${local.name}.setAttribute( '${attribute.name}', ${value} );
` );
}
} }
if ( isBoundOptionValue ) { if ( isBoundOptionValue ) {

@ -7,8 +7,16 @@ export default function createBinding ( generator, node, attribute, current, loc
const deep = parts.length > 1; const deep = parts.length > 1;
const contextual = parts[0] in current.contexts; const contextual = parts[0] in current.contexts;
if ( contextual ) local.allUsedContexts.add( parts[0] ); if ( contextual ) local.allUsedContexts.add( parts[0] );
if ( local.isComponent ) {
local.bindings.push({
name: attribute.name,
value: contextual ? attribute.value : `root.${attribute.value}`
});
}
const handler = current.counter( `${local.name}ChangeHandler` ); const handler = current.counter( `${local.name}ChangeHandler` );
let setter; let setter;
@ -94,6 +102,8 @@ export default function createBinding ( generator, node, attribute, current, loc
} }
` ); ` );
} else { } else {
const updateElement = `${local.name}.${attribute.name} = ${contextual ? attribute.value : `root.${attribute.value}`}`;
local.init.push( deindent` local.init.push( deindent`
var ${local.name}_updating = false; var ${local.name}_updating = false;
@ -104,10 +114,11 @@ export default function createBinding ( generator, node, attribute, current, loc
} }
${local.name}.addEventListener( '${eventName}', ${handler}, false ); ${local.name}.addEventListener( '${eventName}', ${handler}, false );
${updateElement};
` ); ` );
local.update.push( deindent` local.update.push( deindent`
if ( !${local.name}_updating ) ${local.name}.${attribute.name} = ${contextual ? attribute.value : `root.${attribute.value}`} if ( !${local.name}_updating ) ${updateElement};
` ); ` );
local.teardown.push( deindent` local.teardown.push( deindent`

@ -6,5 +6,6 @@ export default {
{ foo: true, bar: true } { foo: true, bar: true }
] ]
}, },
html: `<div class="foo ">1</div><div class=" bar">2</div><div class="foo bar">3</div><!--#each items-->` html: `<div class="foo ">1</div><div class=" bar">2</div><div class="foo bar">3</div><!--#each items-->`
}; };

@ -1,5 +1,6 @@
export default { export default {
html: '<!--#if visible-->', html: '',
test ( assert, component, target, window ) { test ( assert, component, target, window ) {
component.set({ visible: true }); component.set({ visible: true });
assert.equal( component.refs.input, window.document.activeElement ); assert.equal( component.refs.input, window.document.activeElement );

@ -6,7 +6,12 @@ export default {
{ description: 'three', completed: false } { description: 'three', completed: false }
] ]
}, },
html: `<div><input type="checkbox"><p>one</p></div><div><input type="checkbox"><p>two</p></div><div><input type="checkbox"><p>three</p></div><!--#each items-->\n\n<p>1 completed</p>`,
html: `
<div><input type="checkbox"><p>one</p></div><div><input type="checkbox"><p>two</p></div><div><input type="checkbox"><p>three</p></div>
<p>1 completed</p>
`,
test ( assert, component, target, window ) { test ( assert, component, target, window ) {
const inputs = [ ...target.querySelectorAll( 'input' ) ]; const inputs = [ ...target.querySelectorAll( 'input' ) ];
@ -20,13 +25,19 @@ export default {
inputs[1].dispatchEvent( event ); inputs[1].dispatchEvent( event );
assert.equal( component.get( 'numCompleted' ), 2 ); assert.equal( component.get( 'numCompleted' ), 2 );
assert.equal( target.innerHTML, `<div><input type="checkbox"><p>one</p></div><div><input type="checkbox"><p>two</p></div><div><input type="checkbox"><p>three</p></div><!--#each items-->\n\n<p>2 completed</p>` ); assert.htmlEqual( target.innerHTML, `
<div><input type="checkbox"><p>one</p></div><div><input type="checkbox"><p>two</p></div><div><input type="checkbox"><p>three</p></div>
<p>2 completed</p>
` );
const items = component.get( 'items' ); const items = component.get( 'items' );
items[2].completed = true; items[2].completed = true;
component.set({ items }); component.set({ items });
assert.ok( inputs[2].checked ); assert.ok( inputs[2].checked );
assert.equal( target.innerHTML, `<div><input type="checkbox"><p>one</p></div><div><input type="checkbox"><p>two</p></div><div><input type="checkbox"><p>three</p></div><!--#each items-->\n\n<p>3 completed</p>` ); assert.htmlEqual( target.innerHTML, `
<div><input type="checkbox"><p>one</p></div><div><input type="checkbox"><p>two</p></div><div><input type="checkbox"><p>three</p></div>
<p>3 completed</p>
` );
} }
}; };

@ -4,7 +4,9 @@ export default {
name: 'alice' name: 'alice'
} }
}, },
html: `<input>\n<p>hello alice</p>`, html: `<input>\n<p>hello alice</p>`,
test ( assert, component, target, window ) { test ( assert, component, target, window ) {
const input = target.querySelector( 'input' ); const input = target.querySelector( 'input' );

@ -0,0 +1,10 @@
export default {
test ( assert, component, target ) {
component.set({ q: 42 });
component.set({ foo: true });
assert.htmlEqual( target.innerHTML, `
<p>42</p>
` );
}
};

@ -0,0 +1,17 @@
{{#if foo}}
<Widget p='{{q}}'/>
{{/if}}
<script>
import Widget from './Widget.html';
export default {
data: () => ({
foo: false
}),
components: {
Widget
}
};
</script>

@ -2,7 +2,9 @@ export default {
data: { data: {
visible: true visible: true
}, },
html: '<div><!--#if visible--><p>i am a widget</p></div>', // TODO comment should follow component...
html: '<div><p>i am a widget</p></div>',
test ( assert, component ) { test ( assert, component ) {
let count = 0; let count = 0;

@ -5,6 +5,8 @@ export default {
component.set({ currentFilter: 'all' }); component.set({ currentFilter: 'all' });
assert.equal( target.innerHTML, `<ul><li>one</li><!--#if filter(item, currentFilter)--><li>two</li><!--#if filter(item, currentFilter)--><li>three</li><!--#if filter(item, currentFilter)--><!--#each items--></ul>` ); assert.htmlEqual( target.innerHTML, `
<ul><li>one</li><li>two</li><li>three</li></ul>`
);
} }
}; };

@ -1,9 +1,13 @@
export default { export default {
solo: true,
data: { data: {
columns: [ 'a', 'b', 'c' ], columns: [ 'a', 'b', 'c' ],
rows: [ 1, 2, 3 ] rows: [ 1, 2, 3 ]
}, },
html: `<div>a, 1</div><div>a, 2</div><div>a, 3</div><!--#each rows--><div>b, 1</div><div>b, 2</div><div>b, 3</div><!--#each rows--><div>c, 1</div><div>c, 2</div><div>c, 3</div><!--#each rows--><!--#each columns-->`, html: `<div>a, 1</div><div>a, 2</div><div>a, 3</div><!--#each rows--><div>b, 1</div><div>b, 2</div><div>b, 3</div><!--#each rows--><div>c, 1</div><div>c, 2</div><div>c, 3</div><!--#each rows--><!--#each columns-->`,
test ( assert, component, target ) { test ( assert, component, target ) {
// TODO // TODO
} }

Loading…
Cancel
Save