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

@ -4,12 +4,12 @@ import deindent from '../../../../utils/deindent.js';
import flattenReference from '../../../../utils/flattenReference.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 => {
const name = attribute.name;
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;
let dynamic = false;
@ -32,28 +32,28 @@ export default function addElementAttributes ( generator, block, node, local ) {
// attributes without values, e.g. <textarea readonly>
if ( propertyName ) {
local.create.addLine(
`${local.name}.${propertyName} = true;`
`${state.parentNode}.${propertyName} = true;`
);
} else {
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
if ( name === 'autofocus' ) {
block.autofocus = local.name;
block.autofocus = state.parentNode;
}
}
else if ( attribute.value.length === 0 ) {
if ( propertyName ) {
local.create.addLine(
`${local.name}.${propertyName} = '';`
`${state.parentNode}.${propertyName} = '';`
);
} else {
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' ) {
// special case
// TODO this attribute must be static enforce at compile time
local.namespace = value.data;
state.namespace = value.data;
addAttribute = true;
} else if ( propertyName ) {
local.create.addLine(
`${local.name}.${propertyName} = ${result};`
`${state.parentNode}.${propertyName} = ${result};`
);
} else {
addAttribute = true;
@ -83,7 +83,7 @@ export default function addElementAttributes ( generator, block, node, local ) {
if ( addAttribute ) {
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
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};` );
let updater;
if ( propertyName ) {
updater = `${local.name}.${propertyName} = ${last};`;
updater = `${state.parentNode}.${propertyName} = ${last};`;
} else {
updater = `${generator.helper( method )}( ${local.name}, '${name}', ${last} );`;
updater = `${generator.helper( method )}( ${state.parentNode}, '${name}', ${last} );`;
}
local.create.addLine( updater );
@ -131,9 +131,9 @@ export default function addElementAttributes ( generator, block, node, local ) {
let updater;
if (propertyName) {
updater = `${local.name}.${propertyName} = ${value};`;
updater = `${state.parentNode}.${propertyName} = ${value};`;
} else {
updater = `${generator.helper( method )}( ${local.name}, '${name}', ${value} );`;
updater = `${generator.helper( method )}( ${state.parentNode}, '${name}', ${value} );`;
}
local.create.addLine( updater );
@ -141,7 +141,7 @@ export default function addElementAttributes ( generator, block, node, local ) {
}
if ( isIndirectlyBoundValue ) {
const updateValue = `${local.name}.value = ${local.name}.__value;`;
const updateValue = `${state.parentNode}.value = ${state.parentNode}.__value;`;
local.create.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 ) ) {
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}
}.bind( ${local.name} ) );
}.bind( ${state.parentNode} ) );
` );
block.builders.destroy.addLine( deindent`
@ -197,28 +197,28 @@ export default function addElementAttributes ( generator, block, node, local ) {
${handlerBody}
}
${generator.helper( 'addEventListener' )}( ${local.name}, '${name}', ${handlerName} );
${generator.helper( 'addEventListener' )}( ${state.parentNode}, '${name}', ${handlerName} );
` );
block.builders.destroy.addLine( deindent`
${generator.helper( 'removeEventListener' )}( ${local.name}, '${name}', ${handlerName} );
${generator.helper( 'removeEventListener' )}( ${state.parentNode}, '${name}', ${handlerName} );
` );
}
}
else if ( attribute.type === 'Binding' ) {
addElementBinding( generator, node, attribute, block, local );
addElementBinding( generator, node, block, state, attribute, local );
}
else if ( attribute.type === 'Ref' ) {
generator.usesRefs = true;
local.create.addLine(
`${block.component}.refs.${name} = ${local.name};`
`${block.component}.refs.${name} = ${state.parentNode};`
);
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 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 { 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 );
});
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 type = getStaticAttributeValue( node, 'type' );
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 );
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
if ( node.name === 'select' ) {
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' );
@ -45,8 +45,8 @@ export default function addElementBinding ( generator, node, attribute, block, l
updateElement = deindent`
var ${value} = ${snippet};
for ( var ${i} = 0; ${i} < ${local.name}.options.length; ${i} += 1 ) {
var ${option} = ${local.name}.options[${i}];
for ( var ${i} = 0; ${i} < ${state.parentNode}.options.length; ${i} += 1 ) {
var ${option} = ${state.parentNode}.options[${i}];
${ifStatement}
}
@ -57,32 +57,32 @@ export default function addElementBinding ( generator, node, attribute, block, l
else if ( attribute.name === 'group' ) {
if ( type === 'radio' ) {
setter = deindent`
if ( !${local.name}.checked ) return;
if ( !${state.parentNode}.checked ) return;
${setter}
`;
}
const condition = type === 'checkbox' ?
`~${snippet}.indexOf( ${local.name}.__value )` :
`${local.name}.__value === ${snippet}`;
`~${snippet}.indexOf( ${state.parentNode}.__value )` :
`${state.parentNode}.__value === ${snippet}`;
local.create.addLine(
`${block.component}._bindingGroups[${bindingGroup}].push( ${local.name} );`
`${block.component}._bindingGroups[${bindingGroup}].push( ${state.parentNode} );`
);
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
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`
var ${updating} = false;
@ -93,7 +93,7 @@ export default function addElementBinding ( generator, node, attribute, block, l
${updating} = false;
}
${generator.helper( 'addEventListener' )}( ${local.name}, '${eventName}', ${handler} );
${generator.helper( 'addEventListener' )}( ${state.parentNode}, '${eventName}', ${handler} );
` );
node.initialUpdate = updateElement;
@ -105,7 +105,7 @@ export default function addElementBinding ( generator, node, attribute, block, l
` );
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';
}
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>
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>
@ -141,16 +141,16 @@ function getBindingValue ( generator, block, local, node, attribute, isMultipleS
return `${generator.helper( 'getBindingGroupValue' )}( ${block.component}._bindingGroups[${bindingGroup}] )`;
}
return `${local.name}.__value`;
return `${state.parentNode}.__value`;
}
// <input type='range|number' bind:value>
if ( type === 'range' || type === 'number' ) {
return `+${local.name}.${attribute.name}`;
return `+${state.parentNode}.${attribute.name}`;
}
// everything else
return `${local.name}.${attribute.name}`;
return `${state.parentNode}.${attribute.name}`;
}
function getBindingGroup ( generator, keypath ) {

Loading…
Cancel
Save