start refactoring element code a bit

pull/456/head
Rich-Harris 8 years ago
parent 31269e84f0
commit 57f1b64ddb

@ -20,11 +20,13 @@ export default function visitElement ( generator, block, state, node ) {
const name = block.getUniqueName( node.name ); const name = block.getUniqueName( node.name );
const local = { const childState = Object.assign( {}, state, {
name, isTopLevel: false,
namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace, parentNode: name,
isComponent: false, namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace
});
const local = {
allUsedContexts: [], allUsedContexts: [],
create: new CodeBuilder(), create: new CodeBuilder(),
@ -34,7 +36,7 @@ export default function visitElement ( generator, block, state, node ) {
const isToplevel = !state.parentNode; const isToplevel = !state.parentNode;
addElementAttributes( generator, block, node, local ); addElementAttributes( generator, block, childState, node, local );
if ( local.allUsedContexts.length ) { if ( local.allUsedContexts.length ) {
const initialProps = local.allUsedContexts.map( contextName => { const initialProps = local.allUsedContexts.map( contextName => {
@ -66,11 +68,11 @@ export default function visitElement ( generator, block, state, node ) {
let render; let render;
if ( local.namespace ) { if ( childState.namespace ) {
if ( local.namespace === 'http://www.w3.org/2000/svg' ) { if ( childState.namespace === 'http://www.w3.org/2000/svg' ) {
render = `var ${name} = ${generator.helper( 'createSvgElement' )}( '${node.name}' )`; render = `var ${name} = ${generator.helper( 'createSvgElement' )}( '${node.name}' )`;
} else { } else {
render = `var ${name} = document.createElementNS( '${local.namespace}', '${node.name}' );`; render = `var ${name} = document.createElementNS( '${childState.namespace}', '${node.name}' );`;
} }
} else { } else {
render = `var ${name} = ${generator.helper( 'createElement' )}( '${node.name}' );`; render = `var ${name} = ${generator.helper( 'createElement' )}( '${node.name}' );`;
@ -98,12 +100,6 @@ export default function visitElement ( generator, block, state, node ) {
block.createMountStatement( name, state.parentNode ); block.createMountStatement( name, state.parentNode );
const childState = Object.assign( {}, state, {
isTopLevel: false,
parentNode: name,
namespace: local.namespace
});
node.children.forEach( child => { node.children.forEach( child => {
visit( generator, block, childState, child ); visit( generator, block, childState, child );
}); });

@ -4,12 +4,12 @@ import deindent from '../../../../utils/deindent.js';
import flattenReference from '../../../../utils/flattenReference.js'; import flattenReference from '../../../../utils/flattenReference.js';
import getStaticAttributeValue from './binding/getStaticAttributeValue.js'; import getStaticAttributeValue from './binding/getStaticAttributeValue.js';
export default function addElementAttributes ( generator, block, node, local ) { export default function addElementAttributes ( generator, block, state, node, local ) {
node.attributes.forEach( attribute => { node.attributes.forEach( attribute => {
const name = attribute.name; const name = attribute.name;
if ( attribute.type === 'Attribute' ) { if ( attribute.type === 'Attribute' ) {
let metadata = local.namespace ? null : attributeLookup[ name ]; let metadata = state.namespace ? null : attributeLookup[ name ];
if ( metadata && metadata.appliesTo && !~metadata.appliesTo.indexOf( node.name ) ) metadata = null; if ( metadata && metadata.appliesTo && !~metadata.appliesTo.indexOf( node.name ) ) metadata = null;
let dynamic = false; let dynamic = false;
@ -32,28 +32,28 @@ export default function addElementAttributes ( generator, block, node, local ) {
// attributes without values, e.g. <textarea readonly> // attributes without values, e.g. <textarea readonly>
if ( propertyName ) { if ( propertyName ) {
local.create.addLine( local.create.addLine(
`${local.name}.${propertyName} = true;` `${state.parentNode}.${propertyName} = true;`
); );
} else { } else {
local.create.addLine( local.create.addLine(
`${generator.helper( method )}( ${local.name}, '${name}', true );` `${generator.helper( method )}( ${state.parentNode}, '${name}', true );`
); );
} }
// special case autofocus. has to be handled in a bit of a weird way // special case autofocus. has to be handled in a bit of a weird way
if ( name === 'autofocus' ) { if ( name === 'autofocus' ) {
block.autofocus = local.name; block.autofocus = state.parentNode;
} }
} }
else if ( attribute.value.length === 0 ) { else if ( attribute.value.length === 0 ) {
if ( propertyName ) { if ( propertyName ) {
local.create.addLine( local.create.addLine(
`${local.name}.${propertyName} = '';` `${state.parentNode}.${propertyName} = '';`
); );
} else { } else {
local.create.addLine( local.create.addLine(
`${generator.helper( method )}( ${local.name}, '${name}', '' );` `${generator.helper( method )}( ${state.parentNode}, '${name}', '' );`
); );
} }
} }
@ -71,11 +71,11 @@ export default function addElementAttributes ( generator, block, node, local ) {
if ( name === 'xmlns' ) { if ( name === 'xmlns' ) {
// special case // special case
// TODO this attribute must be static enforce at compile time // TODO this attribute must be static enforce at compile time
local.namespace = value.data; state.namespace = value.data;
addAttribute = true; addAttribute = true;
} else if ( propertyName ) { } else if ( propertyName ) {
local.create.addLine( local.create.addLine(
`${local.name}.${propertyName} = ${result};` `${state.parentNode}.${propertyName} = ${result};`
); );
} else { } else {
addAttribute = true; addAttribute = true;
@ -83,7 +83,7 @@ export default function addElementAttributes ( generator, block, node, local ) {
if ( addAttribute ) { if ( addAttribute ) {
local.create.addLine( local.create.addLine(
`${generator.helper( method )}( ${local.name}, '${name}', ${result} );` `${generator.helper( method )}( ${state.parentNode}, '${name}', ${result} );`
); );
} }
} }
@ -94,14 +94,14 @@ export default function addElementAttributes ( generator, block, node, local ) {
// dynamic but potentially non-string attributes // dynamic but potentially non-string attributes
const { snippet } = generator.contextualise( block, value.expression ); const { snippet } = generator.contextualise( block, value.expression );
const last = `last_${local.name}_${name.replace( /-/g, '_')}`; const last = `last_${state.parentNode}_${name.replace( /-/g, '_')}`;
local.create.addLine( `var ${last} = ${snippet};` ); local.create.addLine( `var ${last} = ${snippet};` );
let updater; let updater;
if ( propertyName ) { if ( propertyName ) {
updater = `${local.name}.${propertyName} = ${last};`; updater = `${state.parentNode}.${propertyName} = ${last};`;
} else { } else {
updater = `${generator.helper( method )}( ${local.name}, '${name}', ${last} );`; updater = `${generator.helper( method )}( ${state.parentNode}, '${name}', ${last} );`;
} }
local.create.addLine( updater ); local.create.addLine( updater );
@ -131,9 +131,9 @@ export default function addElementAttributes ( generator, block, node, local ) {
let updater; let updater;
if (propertyName) { if (propertyName) {
updater = `${local.name}.${propertyName} = ${value};`; updater = `${state.parentNode}.${propertyName} = ${value};`;
} else { } else {
updater = `${generator.helper( method )}( ${local.name}, '${name}', ${value} );`; updater = `${generator.helper( method )}( ${state.parentNode}, '${name}', ${value} );`;
} }
local.create.addLine( updater ); local.create.addLine( updater );
@ -141,7 +141,7 @@ export default function addElementAttributes ( generator, block, node, local ) {
} }
if ( isIndirectlyBoundValue ) { if ( isIndirectlyBoundValue ) {
const updateValue = `${local.name}.value = ${local.name}.__value;`; const updateValue = `${state.parentNode}.value = ${state.parentNode}.__value;`;
local.create.addLine( updateValue ); local.create.addLine( updateValue );
if ( dynamic ) local.update.addLine( updateValue ); if ( dynamic ) local.update.addLine( updateValue );
@ -183,9 +183,9 @@ export default function addElementAttributes ( generator, block, node, local ) {
if ( generator.events.has( name ) ) { if ( generator.events.has( name ) ) {
local.create.addBlock( deindent` local.create.addBlock( deindent`
var ${handlerName} = ${generator.alias( 'template' )}.events.${name}.call( ${block.component}, ${local.name}, function ( event ) { var ${handlerName} = ${generator.alias( 'template' )}.events.${name}.call( ${block.component}, ${state.parentNode}, function ( event ) {
${handlerBody} ${handlerBody}
}.bind( ${local.name} ) ); }.bind( ${state.parentNode} ) );
` ); ` );
block.builders.destroy.addLine( deindent` block.builders.destroy.addLine( deindent`
@ -197,28 +197,28 @@ export default function addElementAttributes ( generator, block, node, local ) {
${handlerBody} ${handlerBody}
} }
${generator.helper( 'addEventListener' )}( ${local.name}, '${name}', ${handlerName} ); ${generator.helper( 'addEventListener' )}( ${state.parentNode}, '${name}', ${handlerName} );
` ); ` );
block.builders.destroy.addLine( deindent` block.builders.destroy.addLine( deindent`
${generator.helper( 'removeEventListener' )}( ${local.name}, '${name}', ${handlerName} ); ${generator.helper( 'removeEventListener' )}( ${state.parentNode}, '${name}', ${handlerName} );
` ); ` );
} }
} }
else if ( attribute.type === 'Binding' ) { else if ( attribute.type === 'Binding' ) {
addElementBinding( generator, node, attribute, block, local ); addElementBinding( generator, node, block, state, attribute, local );
} }
else if ( attribute.type === 'Ref' ) { else if ( attribute.type === 'Ref' ) {
generator.usesRefs = true; generator.usesRefs = true;
local.create.addLine( local.create.addLine(
`${block.component}.refs.${name} = ${local.name};` `${block.component}.refs.${name} = ${state.parentNode};`
); );
block.builders.destroy.addLine( deindent` block.builders.destroy.addLine( deindent`
if ( ${block.component}.refs.${name} === ${local.name} ) ${block.component}.refs.${name} = null; if ( ${block.component}.refs.${name} === ${state.parentNode} ) ${block.component}.refs.${name} = null;
` ); ` );
} }

@ -3,7 +3,7 @@ import flattenReference from '../../../../utils/flattenReference.js';
import getSetter from './binding/getSetter.js'; import getSetter from './binding/getSetter.js';
import getStaticAttributeValue from './binding/getStaticAttributeValue.js'; import getStaticAttributeValue from './binding/getStaticAttributeValue.js';
export default function addElementBinding ( generator, node, attribute, block, local ) { export default function addElementBinding ( generator, node, block, state, attribute, local ) {
const { name, keypath } = flattenReference( attribute.value ); const { name, keypath } = flattenReference( attribute.value );
const { snippet, contexts, dependencies } = generator.contextualise( block, attribute.value ); const { snippet, contexts, dependencies } = generator.contextualise( block, attribute.value );
@ -13,12 +13,12 @@ export default function addElementBinding ( generator, node, attribute, block, l
if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context ); if ( !~local.allUsedContexts.indexOf( context ) ) local.allUsedContexts.push( context );
}); });
const handler = block.getUniqueName( `${local.name}_change_handler` ); const handler = block.getUniqueName( `${state.parentNode}_change_handler` );
const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue const isMultipleSelect = node.name === 'select' && node.attributes.find( attr => attr.name.toLowerCase() === 'multiple' ); // TODO use getStaticAttributeValue
const type = getStaticAttributeValue( node, 'type' ); const type = getStaticAttributeValue( node, 'type' );
const bindingGroup = attribute.name === 'group' ? getBindingGroup( generator, keypath ) : null; const bindingGroup = attribute.name === 'group' ? getBindingGroup( generator, keypath ) : null;
const value = getBindingValue( generator, block, local, node, attribute, isMultipleSelect, bindingGroup, type ); const value = getBindingValue( generator, block, state, local, node, attribute, isMultipleSelect, bindingGroup, type );
const eventName = getBindingEventName( node ); const eventName = getBindingEventName( node );
let setter = getSetter({ block, name, keypath, context: '__svelte', attribute, dependencies, value }); let setter = getSetter({ block, name, keypath, context: '__svelte', attribute, dependencies, value });
@ -27,7 +27,7 @@ export default function addElementBinding ( generator, node, attribute, block, l
// <select> special case // <select> special case
if ( node.name === 'select' ) { if ( node.name === 'select' ) {
if ( !isMultipleSelect ) { if ( !isMultipleSelect ) {
setter = `var selectedOption = ${local.name}.selectedOptions[0] || ${local.name}.options[0];\n${setter}`; setter = `var selectedOption = ${state.parentNode}.selectedOptions[0] || ${state.parentNode}.options[0];\n${setter}`;
} }
const value = block.getUniqueName( 'value' ); const value = block.getUniqueName( 'value' );
@ -45,8 +45,8 @@ export default function addElementBinding ( generator, node, attribute, block, l
updateElement = deindent` updateElement = deindent`
var ${value} = ${snippet}; var ${value} = ${snippet};
for ( var ${i} = 0; ${i} < ${local.name}.options.length; ${i} += 1 ) { for ( var ${i} = 0; ${i} < ${state.parentNode}.options.length; ${i} += 1 ) {
var ${option} = ${local.name}.options[${i}]; var ${option} = ${state.parentNode}.options[${i}];
${ifStatement} ${ifStatement}
} }
@ -57,32 +57,32 @@ export default function addElementBinding ( generator, node, attribute, block, l
else if ( attribute.name === 'group' ) { else if ( attribute.name === 'group' ) {
if ( type === 'radio' ) { if ( type === 'radio' ) {
setter = deindent` setter = deindent`
if ( !${local.name}.checked ) return; if ( !${state.parentNode}.checked ) return;
${setter} ${setter}
`; `;
} }
const condition = type === 'checkbox' ? const condition = type === 'checkbox' ?
`~${snippet}.indexOf( ${local.name}.__value )` : `~${snippet}.indexOf( ${state.parentNode}.__value )` :
`${local.name}.__value === ${snippet}`; `${state.parentNode}.__value === ${snippet}`;
local.create.addLine( local.create.addLine(
`${block.component}._bindingGroups[${bindingGroup}].push( ${local.name} );` `${block.component}._bindingGroups[${bindingGroup}].push( ${state.parentNode} );`
); );
local.destroy.addBlock( local.destroy.addBlock(
`${block.component}._bindingGroups[${bindingGroup}].splice( ${block.component}._bindingGroups[${bindingGroup}].indexOf( ${local.name} ), 1 );` `${block.component}._bindingGroups[${bindingGroup}].splice( ${block.component}._bindingGroups[${bindingGroup}].indexOf( ${state.parentNode} ), 1 );`
); );
updateElement = `${local.name}.checked = ${condition};`; updateElement = `${state.parentNode}.checked = ${condition};`;
} }
// everything else // everything else
else { else {
updateElement = `${local.name}.${attribute.name} = ${snippet};`; updateElement = `${state.parentNode}.${attribute.name} = ${snippet};`;
} }
const updating = block.getUniqueName( `${local.name}_updating` ); const updating = block.getUniqueName( `${state.parentNode}_updating` );
local.create.addBlock( deindent` local.create.addBlock( deindent`
var ${updating} = false; var ${updating} = false;
@ -93,7 +93,7 @@ export default function addElementBinding ( generator, node, attribute, block, l
${updating} = false; ${updating} = false;
} }
${generator.helper( 'addEventListener' )}( ${local.name}, '${eventName}', ${handler} ); ${generator.helper( 'addEventListener' )}( ${state.parentNode}, '${eventName}', ${handler} );
` ); ` );
node.initialUpdate = updateElement; node.initialUpdate = updateElement;
@ -105,7 +105,7 @@ export default function addElementBinding ( generator, node, attribute, block, l
` ); ` );
block.builders.destroy.addLine( deindent` block.builders.destroy.addLine( deindent`
${generator.helper( 'removeEventListener' )}( ${local.name}, '${eventName}', ${handler} ); ${generator.helper( 'removeEventListener' )}( ${state.parentNode}, '${eventName}', ${handler} );
` ); ` );
} }
@ -124,10 +124,10 @@ function getBindingEventName ( node ) {
return 'change'; return 'change';
} }
function getBindingValue ( generator, block, local, node, attribute, isMultipleSelect, bindingGroup, type ) { function getBindingValue ( generator, block, state, local, node, attribute, isMultipleSelect, bindingGroup, type ) {
// <select multiple bind:value='selected> // <select multiple bind:value='selected>
if ( isMultipleSelect ) { if ( isMultipleSelect ) {
return `[].map.call( ${local.name}.selectedOptions, function ( option ) { return option.__value; })`; return `[].map.call( ${state.parentNode}.selectedOptions, function ( option ) { return option.__value; })`;
} }
// <select bind:value='selected> // <select bind:value='selected>
@ -141,16 +141,16 @@ function getBindingValue ( generator, block, local, node, attribute, isMultipleS
return `${generator.helper( 'getBindingGroupValue' )}( ${block.component}._bindingGroups[${bindingGroup}] )`; return `${generator.helper( 'getBindingGroupValue' )}( ${block.component}._bindingGroups[${bindingGroup}] )`;
} }
return `${local.name}.__value`; return `${state.parentNode}.__value`;
} }
// <input type='range|number' bind:value> // <input type='range|number' bind:value>
if ( type === 'range' || type === 'number' ) { if ( type === 'range' || type === 'number' ) {
return `+${local.name}.${attribute.name}`; return `+${state.parentNode}.${attribute.name}`;
} }
// everything else // everything else
return `${local.name}.${attribute.name}`; return `${state.parentNode}.${attribute.name}`;
} }
function getBindingGroup ( generator, keypath ) { function getBindingGroup ( generator, keypath ) {

Loading…
Cancel
Save