diff --git a/src/generators/dom/Block.js b/src/generators/dom/Block.js index 4ef169b65592..2e8d54f03c0c 100644 --- a/src/generators/dom/Block.js +++ b/src/generators/dom/Block.js @@ -87,11 +87,6 @@ export default class Block { return this.generator.contextualise( this, expression, context, isEventHandler ); } - createAnchor ( name, parentNode ) { - const renderStatement = `${this.generator.helper( 'createComment' )}()`; - this.addElement( name, renderStatement, parentNode, true ); - } - findDependencies ( expression ) { return this.generator.findDependencies( this.contextDependencies, this.indexes, expression ); } diff --git a/src/generators/dom/index.js b/src/generators/dom/index.js index 1309c4ddb26d..173b987aa1b4 100644 --- a/src/generators/dom/index.js +++ b/src/generators/dom/index.js @@ -43,14 +43,14 @@ export default function dom ( parsed, source, options ) { const { computations, hasJs, templateProperties, namespace } = generator.parseJs(); - const block = preprocess( generator, parsed.html ); - const state = { namespace, parentNode: null, isTopLevel: true }; + const block = preprocess( generator, state, parsed.html ); + parsed.html.children.forEach( node => { visit( generator, block, state, node ); }); diff --git a/src/generators/dom/preprocess.js b/src/generators/dom/preprocess.js index f8ab06ddc37a..8661dbb0fb85 100644 --- a/src/generators/dom/preprocess.js +++ b/src/generators/dom/preprocess.js @@ -1,17 +1,62 @@ import Block from './Block.js'; import { trimStart, trimEnd } from '../../utils/trim.js'; +import { assign } from '../../shared/index.js'; function isElseIf ( node ) { return node && node.children.length === 1 && node.children[0].type === 'IfBlock'; } +function getChildState ( parent, child ) { + return assign( {}, parent, { name: null, parentNode: null }, child || {} ); +} + +// Whitespace inside one of these elements will not result in +// a whitespace node being created in any circumstances. (This +// list is almost certainly very incomplete) +const elementsWithoutText = new Set([ + 'audio', + 'datalist', + 'dl', + 'ol', + 'optgroup', + 'select', + 'ul', + 'video' +]); + const preprocessors = { - MustacheTag: ( generator, block, node ) => { + MustacheTag: ( generator, block, state, node ) => { + const dependencies = block.findDependencies( node.expression ); + block.addDependencies( dependencies ); + + node._state = getChildState( state, { + name: block.getUniqueName( 'text' ) + }); + }, + + RawMustacheTag: ( generator, block, state, node ) => { const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); + + const basename = block.getUniqueName( 'raw' ); + const name = block.getUniqueName( `${basename}_before` ); + + node._state = getChildState( state, { basename, name }); + }, + + Text: ( generator, block, state, node ) => { + node._state = getChildState( state ); + + if ( !/\S/.test( node.data ) ) { + if ( state.namespace ) return; + if ( elementsWithoutText.has( state.parentNodeName ) ) return; + } + + node._state.shouldCreate = true; + node._state.name = block.getUniqueName( `text` ); }, - IfBlock: ( generator, block, node ) => { + IfBlock: ( generator, block, state, node ) => { const blocks = []; let dynamic = false; @@ -23,8 +68,10 @@ const preprocessors = { name: generator.getUniqueName( `create_if_block` ) }); + node._state = getChildState( state ); + blocks.push( node._block ); - preprocessChildren( generator, node._block, node ); + preprocessChildren( generator, node._block, node._state, node ); if ( node._block.dependencies.size > 0 ) { dynamic = true; @@ -38,8 +85,10 @@ const preprocessors = { name: generator.getUniqueName( `create_if_block` ) }); + node.else._state = getChildState( state ); + blocks.push( node.else._block ); - preprocessChildren( generator, node.else._block, node.else ); + preprocessChildren( generator, node.else._block, node.else._state, node.else ); if ( node.else._block.dependencies.size > 0 ) { dynamic = true; @@ -57,7 +106,7 @@ const preprocessors = { generator.blocks.push( ...blocks ); }, - EachBlock: ( generator, block, node ) => { + EachBlock: ( generator, block, state, node ) => { const dependencies = block.findDependencies( node.expression ); block.addDependencies( dependencies ); @@ -97,8 +146,12 @@ const preprocessors = { params: block.params.concat( listName, context, indexName ) }); + node._state = getChildState( state, { + inEachBlock: true + }); + generator.blocks.push( node._block ); - preprocessChildren( generator, node._block, node ); + preprocessChildren( generator, node._block, node._state, node ); block.addDependencies( node._block.dependencies ); node._block.hasUpdateMethod = node._block.dependencies.size > 0; @@ -107,13 +160,32 @@ const preprocessors = { name: generator.getUniqueName( `${node._block.name}_else` ) }); + node.else._state = getChildState( state ); + generator.blocks.push( node.else._block ); - preprocessChildren( generator, node.else._block, node.else ); + preprocessChildren( generator, node.else._block, node.else._state, node.else ); node.else._block.hasUpdateMethod = node.else._block.dependencies.size > 0; } }, - Element: ( generator, block, node ) => { + Element: ( generator, block, state, node ) => { + const isComponent = generator.components.has( node.name ) || node.name === ':Self'; + + if ( isComponent ) { + node._state = getChildState( state ); + } else { + const name = block.getUniqueName( node.name.replace( /[^a-zA-Z0-9_$]/g, '_' ) ); + + node._state = getChildState( state, { + isTopLevel: false, + name, + parentNode: name, + parentNodeName: node.name, + namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace, + allUsedContexts: [] + }); + } + node.attributes.forEach( attribute => { if ( attribute.type === 'Attribute' && attribute.value !== true ) { attribute.value.forEach( chunk => { @@ -130,8 +202,6 @@ const preprocessors = { } }); - const isComponent = generator.components.has( node.name ) || node.name === ':Self'; - if ( node.children.length ) { if ( isComponent ) { const name = block.getUniqueName( ( node.name === ':Self' ? generator.name : node.name ).toLowerCase() ); @@ -141,21 +211,19 @@ const preprocessors = { }); generator.blocks.push( node._block ); - preprocessChildren( generator, node._block, node ); + preprocessChildren( generator, node._block, node._state, node ); block.addDependencies( node._block.dependencies ); node._block.hasUpdateMethod = node._block.dependencies.size > 0; } else { - preprocessChildren( generator, block, node ); + preprocessChildren( generator, block, node._state, node ); } } } }; -preprocessors.RawMustacheTag = preprocessors.MustacheTag; - -function preprocessChildren ( generator, block, node ) { +function preprocessChildren ( generator, block, state, node, isTopLevel ) { // glue text nodes together const cleaned = []; let lastChild; @@ -173,15 +241,43 @@ function preprocessChildren ( generator, block, node ) { lastChild = child; }); - node.children = cleaned; + if ( isTopLevel ) { + // trim leading and trailing whitespace from the top level + const firstChild = cleaned[0]; + if ( firstChild && firstChild.type === 'Text' ) { + firstChild.data = trimStart( firstChild.data ); + if ( !firstChild.data ) cleaned.shift(); + } + + const lastChild = cleaned[ cleaned.length - 1 ]; + if ( lastChild && lastChild.type === 'Text' ) { + lastChild.data = trimEnd( lastChild.data ); + if ( !lastChild.data ) cleaned.pop(); + } + } + + lastChild = null; cleaned.forEach( child => { const preprocess = preprocessors[ child.type ]; - if ( preprocess ) preprocess( generator, block, child ); + if ( preprocess ) preprocess( generator, block, state, child ); + + if ( lastChild ) { + lastChild.next = child; + lastChild.needsAnchor = !child._state.name; + } + + lastChild = child; }); + + if ( lastChild ) { + lastChild.needsAnchor = !state.parentNode; + } + + node.children = cleaned; } -export default function preprocess ( generator, node ) { +export default function preprocess ( generator, state, node ) { const block = new Block({ generator, name: generator.alias( 'create_main_fragment' ), @@ -199,21 +295,8 @@ export default function preprocess ( generator, node ) { }); generator.blocks.push( block ); - preprocessChildren( generator, block, node ); + preprocessChildren( generator, block, state, node, true ); block.hasUpdateMethod = block.dependencies.size > 0; - // trim leading and trailing whitespace from the top level - const firstChild = node.children[0]; - if ( firstChild && firstChild.type === 'Text' ) { - firstChild.data = trimStart( firstChild.data ); - if ( !firstChild.data ) node.children.shift(); - } - - const lastChild = node.children[ node.children.length - 1 ]; - if ( lastChild && lastChild.type === 'Text' ) { - lastChild.data = trimEnd( lastChild.data ); - if ( !lastChild.data ) node.children.pop(); - } - return block; } \ No newline at end of file diff --git a/src/generators/dom/visitors/Component/Component.js b/src/generators/dom/visitors/Component/Component.js index 9a2dbf0025ca..b2768d6cf12a 100644 --- a/src/generators/dom/visitors/Component/Component.js +++ b/src/generators/dom/visitors/Component/Component.js @@ -36,9 +36,7 @@ export default function visitComponent ( generator, block, state, node ) { const hasChildren = node.children.length > 0; const name = block.getUniqueName( ( node.name === ':Self' ? generator.name : node.name ).toLowerCase() ); - const childState = Object.assign( {}, state, { - parentNode: null - }); + const childState = node._state; const local = { name, diff --git a/src/generators/dom/visitors/EachBlock.js b/src/generators/dom/visitors/EachBlock.js index 5a1a71d16c8e..e4df8c575da6 100644 --- a/src/generators/dom/visitors/EachBlock.js +++ b/src/generators/dom/visitors/EachBlock.js @@ -9,13 +9,12 @@ export default function visitEachBlock ( generator, block, state, node ) { const iterations = block.getUniqueName( `${each_block}_iterations` ); const i = block.alias( `i` ); const params = block.params.join( ', ' ); - const anchor = block.getUniqueName( `${each_block}_anchor` ); + const anchor = node.needsAnchor ? block.getUniqueName( `${each_block}_anchor` ) : ( node.next && node.next._state.name ) || 'null'; const vars = { each_block, create_each_block, each_block_value, iterations, i, params, anchor }; const { snippet } = block.contextualise( node.expression ); - block.createAnchor( anchor, state.parentNode ); block.builders.create.addLine( `var ${each_block_value} = ${snippet};` ); block.builders.create.addLine( `var ${iterations} = [];` ); @@ -30,11 +29,17 @@ export default function visitEachBlock ( generator, block, state, node ) { if ( isToplevel ) { block.builders.mount.addBlock( deindent` for ( var ${i} = 0; ${i} < ${iterations}.length; ${i} += 1 ) { - ${iterations}[${i}].mount( ${block.target}, ${anchor} ); + ${iterations}[${i}].mount( ${block.target}, null ); } ` ); } + if ( node.needsAnchor ) { + block.addElement( anchor, `${generator.helper( 'createComment' )}()`, state.parentNode, true ); + } else if ( node.next ) { + node.next.usedAsAnchor = true; + } + block.builders.destroy.addBlock( `${generator.helper( 'destroyEach' )}( ${iterations}, ${isToplevel ? 'detach' : 'false'}, 0 );` ); @@ -47,23 +52,25 @@ export default function visitEachBlock ( generator, block, state, node ) { block.builders.create.addBlock( deindent` if ( !${each_block_value}.length ) { ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); - ${!isToplevel ? `${each_block_else}.mount( ${state.parentNode}, ${anchor} );` : ''} + ${!isToplevel ? `${each_block_else}.mount( ${state.parentNode}, null );` : ''} } ` ); block.builders.mount.addBlock( deindent` if ( ${each_block_else} ) { - ${each_block_else}.mount( ${state.parentNode || block.target}, ${anchor} ); + ${each_block_else}.mount( ${state.parentNode || block.target}, null ); } ` ); + const parentNode = state.parentNode || `${anchor}.parentNode`; + if ( node.else._block.hasUpdateMethod ) { block.builders.update.addBlock( deindent` if ( !${each_block_value}.length && ${each_block_else} ) { ${each_block_else}.update( changed, ${params} ); } else if ( !${each_block_value}.length ) { ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); - ${each_block_else}.mount( ${anchor}.parentNode, ${anchor} ); + ${each_block_else}.mount( ${parentNode}, ${anchor} ); } else if ( ${each_block_else} ) { ${each_block_else}.destroy( true ); ${each_block_else} = null; @@ -78,7 +85,7 @@ export default function visitEachBlock ( generator, block, state, node ) { } } else if ( !${each_block_else} ) { ${each_block_else} = ${node.else._block.name}( ${params}, ${block.component} ); - ${each_block_else}.mount( ${anchor}.parentNode, ${anchor} ); + ${each_block_else}.mount( ${parentNode}, ${anchor} ); } ` ); } @@ -91,22 +98,13 @@ export default function visitEachBlock ( generator, block, state, node ) { ` ); } - const childState = Object.assign( {}, state, { - parentNode: null, - inEachBlock: true - }); - node.children.forEach( child => { - visit( generator, node._block, childState, child ); + visit( generator, node._block, node._state, child ); }); if ( node.else ) { - const childState = Object.assign( {}, state, { - parentNode: null - }); - node.else.children.forEach( child => { - visit( generator, node.else._block, childState, child ); + visit( generator, node.else._block, node.else._state, child ); }); } } @@ -131,7 +129,7 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea if ( state.parentNode ) { create.addLine( - `${iterations}[${i}].mount( ${state.parentNode}, ${anchor} );` + `${iterations}[${i}].mount( ${state.parentNode}, null );` ); } @@ -148,6 +146,8 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea ` : `${_iterations}[${i}] = ${_lookup}[ ${key} ] = ${lookup}[ ${key} ];`; + const parentNode = state.parentNode || `${anchor}.parentNode`; + block.builders.update.addBlock( deindent` var ${each_block_value} = ${snippet}; var ${_iterations} = []; @@ -177,7 +177,7 @@ function keyed ( generator, block, state, node, snippet, { each_block, create_ea } } - ${anchor}.parentNode.insertBefore( ${fragment}, ${anchor} ); + ${parentNode}.insertBefore( ${fragment}, ${anchor} ); ${iterations} = ${_iterations}; ${lookup} = ${_lookup}; @@ -193,7 +193,7 @@ function unkeyed ( generator, block, state, node, snippet, { create_each_block, if ( state.parentNode ) { create.addLine( - `${iterations}[${i}].mount( ${state.parentNode}, ${anchor} );` + `${iterations}[${i}].mount( ${state.parentNode}, null );` ); } @@ -213,6 +213,8 @@ function unkeyed ( generator, block, state, node, snippet, { create_each_block, .map( dependency => `'${dependency}' in changed` ) .join( ' || ' ); + const parentNode = state.parentNode || `${anchor}.parentNode`; + if ( condition !== '' ) { const forLoopBody = node._block.hasUpdateMethod ? deindent` @@ -220,12 +222,12 @@ function unkeyed ( generator, block, state, node, snippet, { create_each_block, ${iterations}[${i}].update( changed, ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i} ); } else { ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].mount( ${anchor}.parentNode, ${anchor} ); + ${iterations}[${i}].mount( ${parentNode}, ${anchor} ); } ` : deindent` ${iterations}[${i}] = ${create_each_block}( ${params}, ${each_block_value}, ${each_block_value}[${i}], ${i}, ${block.component} ); - ${iterations}[${i}].mount( ${anchor}.parentNode, ${anchor} ); + ${iterations}[${i}].mount( ${parentNode}, ${anchor} ); `; const start = node._block.hasUpdateMethod ? '0' : `${iterations}.length`; diff --git a/src/generators/dom/visitors/Element/Element.js b/src/generators/dom/visitors/Element/Element.js index bcbce6004a00..5ce0f6ba5b63 100644 --- a/src/generators/dom/visitors/Element/Element.js +++ b/src/generators/dom/visitors/Element/Element.js @@ -34,15 +34,8 @@ export default function visitElement ( generator, block, state, node ) { return visitComponent( generator, block, state, node ); } - const name = block.getUniqueName( node.name.replace( /[^a-zA-Z_$]/g, '_' ) ); - - const childState = Object.assign( {}, state, { - isTopLevel: false, - parentNode: name, - parentNodeName: node.name, - namespace: node.name === 'svg' ? 'http://www.w3.org/2000/svg' : state.namespace, - allUsedContexts: [] - }); + const childState = node._state; + const name = childState.parentNode; block.builders.create.addLine( `var ${name} = ${getRenderStatement( generator, childState.namespace, node.name )};` ); block.mount( name, state.parentNode ); diff --git a/src/generators/dom/visitors/IfBlock.js b/src/generators/dom/visitors/IfBlock.js index 1f1800b536b1..e6c3d9952a7e 100644 --- a/src/generators/dom/visitors/IfBlock.js +++ b/src/generators/dom/visitors/IfBlock.js @@ -34,23 +34,23 @@ function getBranches ( generator, block, state, node ) { } function visitChildren ( generator, block, state, node ) { - const childState = Object.assign( {}, state, { - parentNode: null - }); - node.children.forEach( child => { - visit( generator, node._block, childState, child ); + visit( generator, node._block, node._state, child ); }); } export default function visitIfBlock ( generator, block, state, node ) { const name = generator.getUniqueName( `if_block` ); - const anchor = generator.getUniqueName( `${name}_anchor` ); + const anchor = node.needsAnchor ? block.getUniqueName( `${name}_anchor` ) : ( node.next && node.next._state.name ) || 'null'; const params = block.params.join( ', ' ); const vars = { name, anchor, params }; - block.createAnchor( anchor, state.parentNode ); + if ( node.needsAnchor ) { + block.addElement( anchor, `${generator.helper( 'createComment' )}()`, state.parentNode, true ); + } else if ( node.next ) { + node.next.usedAsAnchor = true; + } const branches = getBranches( generator, block, state, node, generator.getUniqueName( `create_if_block` ) ); const dynamic = branches.some( branch => branch.dynamic ); @@ -74,11 +74,13 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor const isToplevel = !state.parentNode; if ( isToplevel ) { - block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, ${anchor} );` ); + block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, null );` ); } else { - block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, ${anchor} );` ); + block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, null );` ); } + const parentNode = state.parentNode || `${anchor}.parentNode`; + if ( dynamic ) { block.builders.update.addBlock( deindent` if ( ${branch.condition} ) { @@ -86,7 +88,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor ${name}.update( changed, ${params} ); } else { ${name} = ${branch.block}( ${params}, ${block.component} ); - ${name}.mount( ${anchor}.parentNode, ${anchor} ); + ${name}.mount( ${parentNode}, ${anchor} ); } } else if ( ${name} ) { ${name}.destroy( true ); @@ -98,7 +100,7 @@ function simple ( generator, block, state, node, branch, dynamic, { name, anchor if ( ${branch.condition} ) { if ( !${name} ) { ${name} = ${branch.block}( ${params}, ${block.component} ); - ${name}.mount( ${anchor}.parentNode, ${anchor} ); + ${name}.mount( ${parentNode}, ${anchor} ); } } else if ( ${name} ) { ${name}.destroy( true ); @@ -126,11 +128,13 @@ function compound ( generator, block, state, node, branches, dynamic, { name, an const isToplevel = !state.parentNode; if ( isToplevel ) { - block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, ${anchor} );` ); + block.builders.mount.addLine( `if ( ${name} ) ${name}.mount( ${block.target}, null );` ); } else { - block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, ${anchor} );` ); + block.builders.create.addLine( `if ( ${name} ) ${name}.mount( ${state.parentNode}, null );` ); } + const parentNode = state.parentNode || `${anchor}.parentNode`; + if ( dynamic ) { block.builders.update.addBlock( deindent` if ( ${current_block} === ( ${current_block} = ${getBlock}( ${params} ) ) && ${name} ) { @@ -138,7 +142,7 @@ function compound ( generator, block, state, node, branches, dynamic, { name, an } else { if ( ${name} ) ${name}.destroy( true ); ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} ); - if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); + if ( ${name} ) ${name}.mount( ${parentNode}, ${anchor} ); } ` ); } else { @@ -146,7 +150,7 @@ function compound ( generator, block, state, node, branches, dynamic, { name, an if ( ${current_block} !== ( ${current_block} = ${getBlock}( ${params} ) ) ) { if ( ${name} ) ${name}.destroy( true ); ${name} = ${current_block} && ${current_block}( ${params}, ${block.component} ); - if ( ${name} ) ${name}.mount( ${anchor}.parentNode, ${anchor} ); + if ( ${name} ) ${name}.mount( ${parentNode}, ${anchor} ); } ` ); } diff --git a/src/generators/dom/visitors/MustacheTag.js b/src/generators/dom/visitors/MustacheTag.js index db4a57efc276..88bdee41a8f3 100644 --- a/src/generators/dom/visitors/MustacheTag.js +++ b/src/generators/dom/visitors/MustacheTag.js @@ -1,7 +1,7 @@ import deindent from '../../../utils/deindent.js'; export default function visitMustacheTag ( generator, block, state, node ) { - const name = block.getUniqueName( 'text' ); + const name = node._state.name; const value = block.getUniqueName( `${name}_value` ); const { snippet } = block.contextualise( node.expression ); diff --git a/src/generators/dom/visitors/RawMustacheTag.js b/src/generators/dom/visitors/RawMustacheTag.js index 2eed5bfdb6cf..7a3964315083 100644 --- a/src/generators/dom/visitors/RawMustacheTag.js +++ b/src/generators/dom/visitors/RawMustacheTag.js @@ -1,9 +1,9 @@ import deindent from '../../../utils/deindent.js'; export default function visitRawMustacheTag ( generator, block, state, node ) { - const name = block.getUniqueName( 'raw' ); + const name = node._state.basename; + const before = node._state.name; const value = block.getUniqueName( `${name}_value` ); - const before = block.getUniqueName( `${name}_before` ); const after = block.getUniqueName( `${name}_after` ); const { snippet } = block.contextualise( node.expression ); diff --git a/src/generators/dom/visitors/Text.js b/src/generators/dom/visitors/Text.js index 923175e5ab67..9abb0fa19ec0 100644 --- a/src/generators/dom/visitors/Text.js +++ b/src/generators/dom/visitors/Text.js @@ -1,23 +1,6 @@ -// Whitespace inside one of these elements will not result in -// a whitespace node being created in any circumstances. (This -// list is almost certainly very incomplete) -const elementsWithoutText = new Set([ - 'audio', - 'datalist', - 'dl', - 'ol', - 'optgroup', - 'select', - 'ul', - 'video' -]); -export default function visitText ( generator, block, state, node ) { - if ( !/\S/.test( node.data ) ) { - if ( state.namespace ) return; - if ( elementsWithoutText.has( state.parentNodeName) ) return; - } - const name = block.getUniqueName( `text` ); - block.addElement( name, `${generator.helper( 'createText' )}( ${JSON.stringify( node.data )} )`, state.parentNode, false ); +export default function visitText ( generator, block, state, node ) { + if ( !node._state.shouldCreate ) return; + block.addElement( node._state.name, `${generator.helper( 'createText' )}( ${JSON.stringify( node.data )} )`, state.parentNode, node.usedAsAnchor ); } \ No newline at end of file diff --git a/src/generators/dom/visitors/YieldTag.js b/src/generators/dom/visitors/YieldTag.js index 2ee310566919..aa95cd284e07 100644 --- a/src/generators/dom/visitors/YieldTag.js +++ b/src/generators/dom/visitors/YieldTag.js @@ -1,9 +1,6 @@ export default function visitYieldTag ( generator, block, state ) { - const anchor = `yield_anchor`; - block.createAnchor( anchor, state.parentNode ); - block.builders.mount.addLine( - `${block.component}._yield && ${block.component}._yield.mount( ${state.parentNode || block.target}, ${anchor} );` + `${block.component}._yield && ${block.component}._yield.mount( ${state.parentNode || block.target}, null );` ); block.builders.destroy.addLine( diff --git a/test/js/samples/each-block-changed-check/expected.js b/test/js/samples/each-block-changed-check/expected.js index ea742ff8edf9..24ed9066ee9c 100644 --- a/test/js/samples/each-block-changed-check/expected.js +++ b/test/js/samples/each-block-changed-check/expected.js @@ -1,9 +1,8 @@ -import { appendNode, assign, createComment, createElement, createText, destroyEach, detachBetween, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; +import { appendNode, assign, createElement, createText, destroyEach, detachBetween, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; function create_main_fragment ( state, component ) { var text_1_value; - var each_block_anchor = createComment(); var each_block_value = state.comments; var each_block_iterations = []; @@ -18,10 +17,8 @@ function create_main_fragment ( state, component ) { return { mount: function ( target, anchor ) { - insertNode( each_block_anchor, target, anchor ); - for ( var i = 0; i < each_block_iterations.length; i += 1 ) { - each_block_iterations[i].mount( target, each_block_anchor ); + each_block_iterations[i].mount( target, null ); } insertNode( text, target, anchor ); @@ -37,7 +34,7 @@ function create_main_fragment ( state, component ) { each_block_iterations[i].update( changed, state, each_block_value, each_block_value[i], i ); } else { each_block_iterations[i] = create_each_block( state, each_block_value, each_block_value[i], i, component ); - each_block_iterations[i].mount( each_block_anchor.parentNode, each_block_anchor ); + each_block_iterations[i].mount( text.parentNode, text ); } } @@ -55,7 +52,6 @@ function create_main_fragment ( state, component ) { destroyEach( each_block_iterations, detach, 0 ); if ( detach ) { - detachNode( each_block_anchor ); detachNode( text ); detachNode( p ); } diff --git a/test/js/samples/if-block-no-update/expected.js b/test/js/samples/if-block-no-update/expected.js index 1ed5eb2e7fe6..ef158af47d47 100644 --- a/test/js/samples/if-block-no-update/expected.js +++ b/test/js/samples/if-block-no-update/expected.js @@ -14,7 +14,7 @@ function create_main_fragment ( state, component ) { return { mount: function ( target, anchor ) { insertNode( if_block_anchor, target, anchor ); - if ( if_block ) if_block.mount( target, if_block_anchor ); + if ( if_block ) if_block.mount( target, null ); }, update: function ( changed, state ) { diff --git a/test/js/samples/if-block-simple/expected.js b/test/js/samples/if-block-simple/expected.js index fcdd72f55d02..c31e4ae91442 100644 --- a/test/js/samples/if-block-simple/expected.js +++ b/test/js/samples/if-block-simple/expected.js @@ -8,7 +8,7 @@ function create_main_fragment ( state, component ) { return { mount: function ( target, anchor ) { insertNode( if_block_anchor, target, anchor ); - if ( if_block ) if_block.mount( target, if_block_anchor ); + if ( if_block ) if_block.mount( target, null ); }, update: function ( changed, state ) { diff --git a/test/js/samples/use-elements-as-anchors/expected.js b/test/js/samples/use-elements-as-anchors/expected.js new file mode 100644 index 000000000000..792dac264e80 --- /dev/null +++ b/test/js/samples/use-elements-as-anchors/expected.js @@ -0,0 +1,243 @@ +import { appendNode, assign, createComment, createElement, createText, detachNode, dispatchObservers, insertNode, proto } from "svelte/shared.js"; + +function create_main_fragment ( state, component ) { + var div = createElement( 'div' ); + + var if_block = state.a && create_if_block( state, component ); + + if ( if_block ) if_block.mount( div, null ); + var text = createText( "\n\n\t" ); + appendNode( text, div ); + var p = createElement( 'p' ); + appendNode( p, div ); + appendNode( createText( "this can be used as an anchor" ), p ); + appendNode( createText( "\n\n\t" ), div ); + + var if_block_1 = state.b && create_if_block_1( state, component ); + + if ( if_block_1 ) if_block_1.mount( div, null ); + var text_3 = createText( "\n\n\t" ); + appendNode( text_3, div ); + + var if_block_2 = state.c && create_if_block_2( state, component ); + + if ( if_block_2 ) if_block_2.mount( div, null ); + var text_4 = createText( "\n\n\t" ); + appendNode( text_4, div ); + var p_1 = createElement( 'p' ); + appendNode( p_1, div ); + appendNode( createText( "so can this" ), p_1 ); + appendNode( createText( "\n\n\t" ), div ); + + var if_block_3 = state.d && create_if_block_3( state, component ); + + if ( if_block_3 ) if_block_3.mount( div, null ); + var text_7 = createText( "\n\n\t" ); + appendNode( text_7, div ); + var text_8 = createText( "\n\n" ); + var if_block_4_anchor = createComment(); + + var if_block_4 = state.e && create_if_block_4( state, component ); + + return { + mount: function ( target, anchor ) { + insertNode( div, target, anchor ); + insertNode( text_8, target, anchor ); + insertNode( if_block_4_anchor, target, anchor ); + if ( if_block_4 ) if_block_4.mount( target, null ); + }, + + update: function ( changed, state ) { + if ( state.a ) { + if ( !if_block ) { + if_block = create_if_block( state, component ); + if_block.mount( div, text ); + } + } else if ( if_block ) { + if_block.destroy( true ); + if_block = null; + } + + if ( state.b ) { + if ( !if_block_1 ) { + if_block_1 = create_if_block_1( state, component ); + if_block_1.mount( div, text_3 ); + } + } else if ( if_block_1 ) { + if_block_1.destroy( true ); + if_block_1 = null; + } + + if ( state.c ) { + if ( !if_block_2 ) { + if_block_2 = create_if_block_2( state, component ); + if_block_2.mount( div, text_4 ); + } + } else if ( if_block_2 ) { + if_block_2.destroy( true ); + if_block_2 = null; + } + + if ( state.d ) { + if ( !if_block_3 ) { + if_block_3 = create_if_block_3( state, component ); + if_block_3.mount( div, text_7 ); + } + } else if ( if_block_3 ) { + if_block_3.destroy( true ); + if_block_3 = null; + } + + if ( state.e ) { + if ( !if_block_4 ) { + if_block_4 = create_if_block_4( state, component ); + if_block_4.mount( if_block_4_anchor.parentNode, if_block_4_anchor ); + } + } else if ( if_block_4 ) { + if_block_4.destroy( true ); + if_block_4 = null; + } + }, + + destroy: function ( detach ) { + if ( if_block ) if_block.destroy( false ); + if ( if_block_1 ) if_block_1.destroy( false ); + if ( if_block_2 ) if_block_2.destroy( false ); + if ( if_block_3 ) if_block_3.destroy( false ); + if ( if_block_4 ) if_block_4.destroy( detach ); + + if ( detach ) { + detachNode( div ); + detachNode( text_8 ); + detachNode( if_block_4_anchor ); + } + } + }; +} + +function create_if_block ( state, component ) { + var p = createElement( 'p' ); + appendNode( createText( "a" ), p ); + + return { + mount: function ( target, anchor ) { + insertNode( p, target, anchor ); + }, + + destroy: function ( detach ) { + if ( detach ) { + detachNode( p ); + } + } + }; +} + +function create_if_block_1 ( state, component ) { + var p = createElement( 'p' ); + appendNode( createText( "b" ), p ); + + return { + mount: function ( target, anchor ) { + insertNode( p, target, anchor ); + }, + + destroy: function ( detach ) { + if ( detach ) { + detachNode( p ); + } + } + }; +} + +function create_if_block_2 ( state, component ) { + var p = createElement( 'p' ); + appendNode( createText( "c" ), p ); + + return { + mount: function ( target, anchor ) { + insertNode( p, target, anchor ); + }, + + destroy: function ( detach ) { + if ( detach ) { + detachNode( p ); + } + } + }; +} + +function create_if_block_3 ( state, component ) { + var p = createElement( 'p' ); + appendNode( createText( "d" ), p ); + + return { + mount: function ( target, anchor ) { + insertNode( p, target, anchor ); + }, + + destroy: function ( detach ) { + if ( detach ) { + detachNode( p ); + } + } + }; +} + +function create_if_block_4 ( state, component ) { + var p = createElement( 'p' ); + appendNode( createText( "e" ), p ); + + return { + mount: function ( target, anchor ) { + insertNode( p, target, anchor ); + }, + + destroy: function ( detach ) { + if ( detach ) { + detachNode( p ); + } + } + }; +} + +function SvelteComponent ( options ) { + options = options || {}; + this._state = options.data || {}; + + this._observers = { + pre: Object.create( null ), + post: Object.create( null ) + }; + + this._handlers = Object.create( null ); + + this._root = options._root; + this._yield = options._yield; + + this._torndown = false; + + this._fragment = create_main_fragment( this._state, this ); + if ( options.target ) this._fragment.mount( options.target, null ); +} + +assign( SvelteComponent.prototype, proto ); + +SvelteComponent.prototype._set = function _set ( newState ) { + var oldState = this._state; + this._state = assign( {}, oldState, newState ); + dispatchObservers( this, this._observers.pre, newState, oldState ); + if ( this._fragment ) this._fragment.update( newState, this._state ); + dispatchObservers( this, this._observers.post, newState, oldState ); +}; + +SvelteComponent.prototype.teardown = SvelteComponent.prototype.destroy = function destroy ( detach ) { + this.fire( 'destroy' ); + + this._fragment.destroy( detach !== false ); + this._fragment = null; + + this._state = {}; + this._torndown = true; +}; + +export default SvelteComponent; \ No newline at end of file diff --git a/test/js/samples/use-elements-as-anchors/input.html b/test/js/samples/use-elements-as-anchors/input.html new file mode 100644 index 000000000000..c55e7bd4de7b --- /dev/null +++ b/test/js/samples/use-elements-as-anchors/input.html @@ -0,0 +1,27 @@ +
+ {{#if a}} +

a

+ {{/if}} + +

this can be used as an anchor

+ + {{#if b}} +

b

+ {{/if}} + + {{#if c}} +

c

+ {{/if}} + +

so can this

+ + {{#if d}} +

d

+ {{/if}} + + +
+ +{{#if e}} +

e

+{{/if}} \ No newline at end of file diff --git a/test/runtime/samples/if-block-widget/_config.js b/test/runtime/samples/if-block-widget/_config.js index 40d9d050e979..b82b4dfeb946 100644 --- a/test/runtime/samples/if-block-widget/_config.js +++ b/test/runtime/samples/if-block-widget/_config.js @@ -2,11 +2,26 @@ export default { data: { visible: true }, - html: 'before\n

Widget

\nafter', + + html: ` + before +

Widget

+ after + `, + test ( assert, component, target ) { component.set({ visible: false }); - assert.equal( target.innerHTML, 'before\n\nafter' ); + assert.htmlEqual( target.innerHTML, ` + before + + after + ` ); + component.set({ visible: true }); - assert.equal( target.innerHTML, 'before\n

Widget

\nafter' ); + assert.htmlEqual( target.innerHTML, ` + before +

Widget

+ after + ` ); } };