Merge pull request #803 from sveltejs/gh-637

[WIP] Only insert <noscript> tags when necessary
pull/806/head
Rich Harris 7 years ago committed by GitHub
commit 223dbee98c

@ -3,13 +3,10 @@ import Block from './Block';
import { Node } from '../../interfaces'; import { Node } from '../../interfaces';
export interface State { export interface State {
name?: string;
namespace: string; namespace: string;
parentNode: string; parentNode: string;
parentNodes: string; parentNodes: string;
isTopLevel: boolean;
parentNodeName?: string; parentNodeName?: string;
basename?: string;
inEachBlock?: boolean; inEachBlock?: boolean;
allUsedContexts?: string[]; allUsedContexts?: string[];
usesComponent?: boolean; usesComponent?: boolean;

@ -16,7 +16,7 @@ function getChildState(parent: State, child = {}) {
return assign( return assign(
{}, {},
parent, parent,
{ name: null, parentNode: null, parentNodes: 'nodes' }, { parentNode: null, parentNodes: 'nodes' },
child || {} child || {}
); );
} }
@ -45,12 +45,10 @@ const preprocessors = {
componentStack: Node[], componentStack: Node[],
stripWhitespace: boolean stripWhitespace: boolean
) => { ) => {
node.var = block.getUniqueName('text');
const dependencies = block.findDependencies(node.expression); const dependencies = block.findDependencies(node.expression);
block.addDependencies(dependencies); block.addDependencies(dependencies);
node._state = getChildState(state, {
name: block.getUniqueName('text'),
});
}, },
RawMustacheTag: ( RawMustacheTag: (
@ -62,13 +60,10 @@ const preprocessors = {
componentStack: Node[], componentStack: Node[],
stripWhitespace: boolean stripWhitespace: boolean
) => { ) => {
node.var = block.getUniqueName('raw');
const dependencies = block.findDependencies(node.expression); const dependencies = block.findDependencies(node.expression);
block.addDependencies(dependencies); block.addDependencies(dependencies);
const basename = block.getUniqueName('raw');
const name = block.getUniqueName(`${basename}_before`);
node._state = getChildState(state, { basename, name });
}, },
Text: ( Text: (
@ -80,15 +75,12 @@ const preprocessors = {
componentStack: Node[], componentStack: Node[],
stripWhitespace: boolean stripWhitespace: boolean
) => { ) => {
node._state = getChildState(state); if (!/\S/.test(node.data) && (state.namespace || elementsWithoutText.has(state.parentNodeName))) {
node.shouldSkip = true;
if (!/\S/.test(node.data)) { return;
if (state.namespace) return;
if (elementsWithoutText.has(state.parentNodeName)) return;
} }
node._state.shouldCreate = true; node.var = block.getUniqueName(`text`);
node._state.name = block.getUniqueName(`text`);
}, },
IfBlock: ( IfBlock: (
@ -108,6 +100,8 @@ const preprocessors = {
let hasOutros = false; let hasOutros = false;
function attachBlocks(node: Node) { function attachBlocks(node: Node) {
node.var = block.getUniqueName(`if_block`);
const dependencies = block.findDependencies(node.expression); const dependencies = block.findDependencies(node.expression);
block.addDependencies(dependencies); block.addDependencies(dependencies);
@ -179,6 +173,8 @@ const preprocessors = {
stripWhitespace: boolean, stripWhitespace: boolean,
nextSibling: Node nextSibling: Node
) => { ) => {
node.var = block.getUniqueName(`each_block`);
const dependencies = block.findDependencies(node.expression); const dependencies = block.findDependencies(node.expression);
block.addDependencies(dependencies); block.addDependencies(dependencies);
@ -335,13 +331,12 @@ const preprocessors = {
generator.components.has(node.name) || node.name === ':Self'; generator.components.has(node.name) || node.name === ':Self';
if (isComponent) { if (isComponent) {
const name = block.getUniqueName( node.var = block.getUniqueName(
(node.name === ':Self' ? generator.name : node.name).toLowerCase() (node.name === ':Self' ? generator.name : node.name).toLowerCase()
); );
node._state = getChildState(state, { node._state = getChildState(state, {
name, parentNode: `${node.var}._slotted.default`
parentNode: `${name}._slotted.default`
}); });
} else { } else {
const slot = getStaticAttributeValue(node, 'slot'); const slot = getStaticAttributeValue(node, 'slot');
@ -351,15 +346,14 @@ const preprocessors = {
component._slots.add(slot); component._slots.add(slot);
} }
const name = block.getUniqueName( node.var = block.getUniqueName(
node.name.replace(/[^a-zA-Z0-9_$]/g, '_') node.name.replace(/[^a-zA-Z0-9_$]/g, '_')
); );
node._state = getChildState(state, { node._state = getChildState(state, {
isTopLevel: false, isTopLevel: false,
name, parentNode: node.var,
parentNode: name, parentNodes: block.getUniqueName(`${node.var}_nodes`),
parentNodes: block.getUniqueName(`${name}_nodes`),
parentNodeName: node.name, parentNodeName: node.name,
namespace: node.name === 'svg' namespace: node.name === 'svg'
? 'http://www.w3.org/2000/svg' ? 'http://www.w3.org/2000/svg'
@ -421,10 +415,8 @@ function preprocessChildren(
const preprocessor = preprocessors[child.type]; const preprocessor = preprocessors[child.type];
if (preprocessor) preprocessor(generator, block, state, child, inEachBlock, elementStack, componentStack, stripWhitespace, cleaned[i + 1] || nextSibling); if (preprocessor) preprocessor(generator, block, state, child, inEachBlock, elementStack, componentStack, stripWhitespace, cleaned[i + 1] || nextSibling);
if (lastChild) { if (lastChild) lastChild.next = child;
lastChild.next = child; child.prev = lastChild;
lastChild.needsAnchor = !child._state || !child._state.name;
}
lastChild = child; lastChild = child;
}); });
@ -446,10 +438,6 @@ function preprocessChildren(
} }
} }
if (lastChild) {
lastChild.needsAnchor = !state.parentNode;
}
node.children = cleaned; node.children = cleaned;
} }

@ -48,7 +48,7 @@ export default function visitComponent(
) { ) {
generator.hasComponents = true; generator.hasComponents = true;
const name = node._state.name; const name = node.var;
const componentInitProperties = [`_root: #component._root`]; const componentInitProperties = [`_root: #component._root`];

@ -2,6 +2,7 @@ import deindent from '../../../utils/deindent';
import visit from '../visit'; import visit from '../visit';
import { DomGenerator } from '../index'; import { DomGenerator } from '../index';
import Block from '../Block'; import Block from '../Block';
import isDomNode from './shared/isDomNode';
import { Node } from '../../../interfaces'; import { Node } from '../../../interfaces';
import { State } from '../interfaces'; import { State } from '../interfaces';
@ -13,14 +14,17 @@ export default function visitEachBlock(
elementStack: Node[], elementStack: Node[],
componentStack: Node[] componentStack: Node[]
) { ) {
const each_block = generator.getUniqueName(`each_block`); const each_block = node.var;
const create_each_block = node._block.name; const create_each_block = node._block.name;
const each_block_value = node._block.listName; const each_block_value = node._block.listName;
const iterations = block.getUniqueName(`${each_block}_iterations`); const iterations = block.getUniqueName(`${each_block}_iterations`);
const params = block.params.join(', '); const params = block.params.join(', ');
const anchor = node.needsAnchor
const needsAnchor = node.next ? !isDomNode(node.next) : !state.parentNode;
const anchor = needsAnchor
? block.getUniqueName(`${each_block}_anchor`) ? block.getUniqueName(`${each_block}_anchor`)
: (node.next && node.next._state.name) || 'null'; : (node.next && node.next.var) || 'null';
// hack the sourcemap, so that if data is missing the bug // hack the sourcemap, so that if data is missing the bug
// is easy to find // is easy to find
@ -53,15 +57,13 @@ export default function visitEachBlock(
const isToplevel = !state.parentNode; const isToplevel = !state.parentNode;
if (node.needsAnchor) { if (needsAnchor) {
block.addElement( block.addElement(
anchor, anchor,
`@createComment()`, `@createComment()`,
`@createComment()`, `@createComment()`,
state.parentNode state.parentNode
); );
} else if (node.next) {
node.next.usedAsAnchor = true;
} }
if (node.else) { if (node.else) {

@ -45,7 +45,7 @@ export default function visitElement(
} }
if (node.name === 'slot') { if (node.name === 'slot') {
return visitSlot(generator, block, state, node, elementStack); return visitSlot(generator, block, state, node, elementStack, componentStack);
} }
if (generator.components.has(node.name) || node.name === ':Self') { if (generator.components.has(node.name) || node.name === ':Self') {
@ -57,7 +57,7 @@ export default function visitElement(
const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot'); const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot');
const parentNode = slot ? const parentNode = slot ?
`${componentStack[componentStack.length - 1]._state.name}._slotted.${slot.value[0].data}` : // TODO this looks bonkers `${componentStack[componentStack.length - 1].var}._slotted.${slot.value[0].data}` : // TODO this looks bonkers
state.parentNode; state.parentNode;
const isToplevel = !parentNode; const isToplevel = !parentNode;

@ -13,7 +13,7 @@ export default function addTransitions(
outro outro
) { ) {
if (intro === outro) { if (intro === outro) {
const name = block.getUniqueName(`${state.name}_transition`); const name = block.getUniqueName(`${node.var}_transition`);
const snippet = intro.expression const snippet = intro.expression
? block.contextualise(intro.expression).snippet ? block.contextualise(intro.expression).snippet
: '{}'; : '{}';
@ -24,23 +24,23 @@ export default function addTransitions(
block.builders.intro.addBlock(deindent` block.builders.intro.addBlock(deindent`
#component._root._aftercreate.push( function () { #component._root._aftercreate.push( function () {
if ( !${name} ) ${name} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null ); if ( !${name} ) ${name} = @wrapTransition( #component, ${node.var}, ${fn}, ${snippet}, true, null );
${name}.run( true, function () { ${name}.run( true, function () {
#component.fire( 'intro.end', { node: ${state.name} }); #component.fire( 'intro.end', { node: ${node.var} });
}); });
}); });
`); `);
block.builders.outro.addBlock(deindent` block.builders.outro.addBlock(deindent`
${name}.run( false, function () { ${name}.run( false, function () {
#component.fire( 'outro.end', { node: ${state.name} }); #component.fire( 'outro.end', { node: ${node.var} });
if ( --#outros === 0 ) #outrocallback(); if ( --#outros === 0 ) #outrocallback();
${name} = null; ${name} = null;
}); });
`); `);
} else { } else {
const introName = intro && block.getUniqueName(`${state.name}_intro`); const introName = intro && block.getUniqueName(`${node.var}_intro`);
const outroName = outro && block.getUniqueName(`${state.name}_outro`); const outroName = outro && block.getUniqueName(`${node.var}_outro`);
if (intro) { if (intro) {
block.addVariable(introName); block.addVariable(introName);
@ -59,9 +59,9 @@ export default function addTransitions(
block.builders.intro.addBlock(deindent` block.builders.intro.addBlock(deindent`
#component._root._aftercreate.push( function () { #component._root._aftercreate.push( function () {
${introName} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, true, null ); ${introName} = @wrapTransition( #component, ${node.var}, ${fn}, ${snippet}, true, null );
${introName}.run( true, function () { ${introName}.run( true, function () {
#component.fire( 'intro.end', { node: ${state.name} }); #component.fire( 'intro.end', { node: ${node.var} });
}); });
}); });
`); `);
@ -78,9 +78,9 @@ export default function addTransitions(
// TODO hide elements that have outro'd (unless they belong to a still-outroing // TODO hide elements that have outro'd (unless they belong to a still-outroing
// group) prior to their removal from the DOM // group) prior to their removal from the DOM
block.builders.outro.addBlock(deindent` block.builders.outro.addBlock(deindent`
${outroName} = @wrapTransition( #component, ${state.name}, ${fn}, ${snippet}, false, null ); ${outroName} = @wrapTransition( #component, ${node.var}, ${fn}, ${snippet}, false, null );
${outroName}.run( false, function () { ${outroName}.run( false, function () {
#component.fire( 'outro.end', { node: ${state.name} }); #component.fire( 'outro.end', { node: ${node.var} });
if ( --#outros === 0 ) #outrocallback(); if ( --#outros === 0 ) #outrocallback();
}); });
`); `);

@ -2,6 +2,7 @@ import deindent from '../../../utils/deindent';
import visit from '../visit'; import visit from '../visit';
import { DomGenerator } from '../index'; import { DomGenerator } from '../index';
import Block from '../Block'; import Block from '../Block';
import isDomNode from './shared/isDomNode';
import { Node } from '../../../interfaces'; import { Node } from '../../../interfaces';
import { State } from '../interfaces'; import { State } from '../interfaces';
@ -77,10 +78,12 @@ export default function visitIfBlock(
elementStack: Node[], elementStack: Node[],
componentStack: Node[] componentStack: Node[]
) { ) {
const name = generator.getUniqueName(`if_block`); const name = node.var;
const anchor = node.needsAnchor
const needsAnchor = node.next ? !isDomNode(node.next) : !state.parentNode;
const anchor = needsAnchor
? block.getUniqueName(`${name}_anchor`) ? block.getUniqueName(`${name}_anchor`)
: (node.next && node.next._state.name) || 'null'; : (node.next && node.next.var) || 'null';
const params = block.params.join(', '); const params = block.params.join(', ');
const branches = getBranches(generator, block, state, node, elementStack, componentStack); const branches = getBranches(generator, block, state, node, elementStack, componentStack);
@ -117,15 +120,13 @@ export default function visitIfBlock(
`${if_name}${name}.claim( ${state.parentNodes} );` `${if_name}${name}.claim( ${state.parentNodes} );`
); );
if (node.needsAnchor) { if (needsAnchor) {
block.addElement( block.addElement(
anchor, anchor,
`@createComment()`, `@createComment()`,
`@createComment()`, `@createComment()`,
state.parentNode state.parentNode
); );
} else if (node.next) {
node.next.usedAsAnchor = true;
} }
} }

@ -11,19 +11,17 @@ export default function visitMustacheTag(
state: State, state: State,
node: Node node: Node
) { ) {
const { name } = node._state;
const { init } = visitTag( const { init } = visitTag(
generator, generator,
block, block,
state, state,
node, node,
name, node.var,
value => `${name}.data = ${value};` value => `${node.var}.data = ${value};`
); );
block.addElement( block.addElement(
name, node.var,
`@createText( ${init} )`, `@createText( ${init} )`,
`@claimText( ${state.parentNodes}, ${init} )`, `@claimText( ${state.parentNodes}, ${init} )`,
state.parentNode state.parentNode

@ -1,5 +1,4 @@
import deindent from '../../../utils/deindent'; import deindent from '../../../utils/deindent';
import addUpdateBlock from './shared/addUpdateBlock';
import visitTag from './shared/Tag'; import visitTag from './shared/Tag';
import { DomGenerator } from '../index'; import { DomGenerator } from '../index';
import Block from '../Block'; import Block from '../Block';
@ -12,9 +11,37 @@ export default function visitRawMustacheTag(
state: State, state: State,
node: Node node: Node
) { ) {
const name = node._state.basename; const name = node.var;
const before = node._state.name;
const after = block.getUniqueName(`${name}_after`); const needsAnchorBefore = node.prev ? node.prev.type !== 'Element' : !state.parentNode;
const needsAnchorAfter = node.next ? node.next.type !== 'Element' : !state.parentNode;
const anchorBefore = needsAnchorBefore
? block.getUniqueName(`${name}_before`)
: (node.prev && node.prev.var) || 'null';
const anchorAfter = needsAnchorAfter
? block.getUniqueName(`${name}_after`)
: (node.next && node.next.var) || 'null';
let detach: string;
let insert: (content: string) => string;
let useInnerHTML = false;
if (anchorBefore === 'null' && anchorAfter === 'null') {
useInnerHTML = true;
detach = `${state.parentNode}.innerHTML = '';`;
insert = content => `${state.parentNode}.innerHTML = ${content};`;
} else if (anchorBefore === 'null') {
detach = `@detachBefore(${anchorAfter});`;
insert = content => `${anchorAfter}.insertAdjacentHTML('beforebegin', ${content});`;
} else if (anchorAfter === 'null') {
detach = `@detachAfter(${anchorBefore});`;
insert = content => `${anchorBefore}.insertAdjacentHTML('afterend', ${content});`;
} else {
detach = `@detachBetween(${anchorBefore}, ${anchorAfter});`;
insert = content => `${anchorBefore}.insertAdjacentHTML('afterend', ${content});`;
}
const { init } = visitTag( const { init } = visitTag(
generator, generator,
@ -22,28 +49,43 @@ export default function visitRawMustacheTag(
state, state,
node, node,
name, name,
value => deindent` content => deindent`
@detachBetween( ${before}, ${after} ); ${!useInnerHTML && detach}
${before}.insertAdjacentHTML( 'afterend', ${value} ); ${insert(content)}
` `
); );
// we would have used comments here, but the `insertAdjacentHTML` api only // we would have used comments here, but the `insertAdjacentHTML` api only
// exists for `Element`s. // exists for `Element`s.
if (needsAnchorBefore) {
block.addElement( block.addElement(
before, anchorBefore,
`@createElement( 'noscript' )`, `@createElement( 'noscript' )`,
`@createElement( 'noscript' )`, `@createElement( 'noscript' )`,
state.parentNode state.parentNode
); );
}
function addAnchorAfter() {
block.addElement( block.addElement(
after, anchorAfter,
`@createElement( 'noscript' )`, `@createElement( 'noscript' )`,
`@createElement( 'noscript' )`, `@createElement( 'noscript' )`,
state.parentNode state.parentNode
); );
}
if (needsAnchorAfter && anchorBefore === 'null') {
// anchorAfter needs to be in the DOM before we
// insert the HTML...
addAnchorAfter();
}
block.builders.mount.addLine(insert(init));
block.builders.detachRaw.addBlock(detach);
block.builders.mount.addLine(`${before}.insertAdjacentHTML( 'afterend', ${init} );`); if (needsAnchorAfter && anchorBefore !== 'null') {
block.builders.detachRaw.addBlock(`@detachBetween( ${before}, ${after} );`); // ...otherwise it should go afterwards
addAnchorAfter();
}
} }

@ -20,11 +20,19 @@ export default function visitSlot(
const content_name = block.getUniqueName(`slot_content_${slotName}`); const content_name = block.getUniqueName(`slot_content_${slotName}`);
block.addVariable(content_name, `#component._slotted.${slotName}`); block.addVariable(content_name, `#component._slotted.${slotName}`);
// TODO use surrounds as anchors where possible, a la if/each blocks const needsAnchorBefore = node.prev ? node.prev.type !== 'Element' : !state.parentNode;
const before = block.getUniqueName(`${content_name}_before`); const needsAnchorAfter = node.next ? node.next.type !== 'Element' : !state.parentNode;
const after = block.getUniqueName(`${content_name}_after`);
block.addVariable(before); const anchorBefore = needsAnchorBefore
block.addVariable(after); ? block.getUniqueName(`${content_name}_before`)
: (node.prev && node.prev.var) || 'null';
const anchorAfter = needsAnchorAfter
? block.getUniqueName(`${content_name}_after`)
: (node.next && node.next.var) || 'null';
if (needsAnchorBefore) block.addVariable(anchorBefore);
if (needsAnchorAfter) block.addVariable(anchorAfter);
block.builders.create.pushCondition(`!${content_name}`); block.builders.create.pushCondition(`!${content_name}`);
block.builders.hydrate.pushCondition(`!${content_name}`); block.builders.hydrate.pushCondition(`!${content_name}`);
@ -46,17 +54,17 @@ export default function visitSlot(
if (state.parentNode) { if (state.parentNode) {
block.builders.mount.addBlock(deindent` block.builders.mount.addBlock(deindent`
if (${content_name}) { if (${content_name}) {
@appendNode(${before} || (${before} = @createComment()), ${state.parentNode}); ${needsAnchorBefore && `@appendNode(${anchorBefore} || (${anchorBefore} = @createComment()), ${state.parentNode});`}
@appendNode(${content_name}, ${state.parentNode}); @appendNode(${content_name}, ${state.parentNode});
@appendNode(${after} || (${after} = @createComment()), ${state.parentNode}); ${needsAnchorAfter && `@appendNode(${anchorAfter} || (${anchorAfter} = @createComment()), ${state.parentNode});`}
} }
`); `);
} else { } else {
block.builders.mount.addBlock(deindent` block.builders.mount.addBlock(deindent`
if (${content_name}) { if (${content_name}) {
@insertNode(${before} || (${before} = @createComment()), #target, anchor); ${needsAnchorBefore && `@insertNode(${anchorBefore} || (${anchorBefore} = @createComment()), #target, anchor);`}
@insertNode(${content_name}, #target, anchor); @insertNode(${content_name}, #target, anchor);
@insertNode(${after} || (${after} = @createComment()), #target, anchor); ${needsAnchorAfter && `@insertNode(${anchorAfter} || (${anchorAfter} = @createComment()), #target, anchor);`}
} }
`); `);
} }
@ -66,11 +74,31 @@ export default function visitSlot(
// TODO so that this can work with public API, component._slotted should // TODO so that this can work with public API, component._slotted should
// be all fragments, derived from options.slots. Not === options.slots // be all fragments, derived from options.slots. Not === options.slots
// TODO can we use an else here? // TODO can we use an else here?
if (anchorBefore === 'null' && anchorAfter === 'null') {
block.builders.unmount.addBlock(deindent` block.builders.unmount.addBlock(deindent`
if (${content_name}) { if (${content_name}) {
@reinsertBetween(${before}, ${after}, ${content_name}); @reinsertChildren(${state.parentNode}, ${content_name});
@detachNode(${before});
@detachNode(${after});
} }
`); `);
} else if (anchorBefore === 'null') {
block.builders.unmount.addBlock(deindent`
if (${content_name}) {
@reinsertBefore(${anchorAfter}, ${content_name});
}
`);
} else if (anchorAfter === 'null') {
block.builders.unmount.addBlock(deindent`
if (${content_name}) {
@reinsertAfter(${anchorBefore}, ${content_name});
}
`);
} else {
block.builders.unmount.addBlock(deindent`
if (${content_name}) {
@reinsertBetween(${anchorBefore}, ${anchorAfter}, ${content_name});
@detachNode(${anchorBefore});
@detachNode(${anchorAfter});
}
`);
}
} }

@ -10,9 +10,10 @@ export default function visitText(
state: State, state: State,
node: Node node: Node
) { ) {
if (!node._state.shouldCreate) return; if (node.shouldSkip) return;
block.addElement( block.addElement(
node._state.name, node.var,
`@createText( ${stringify(node.data)} )`, `@createText( ${stringify(node.data)} )`,
`@claimText( ${state.parentNodes}, ${stringify(node.data)} )`, `@claimText( ${state.parentNodes}, ${stringify(node.data)} )`,
state.parentNode state.parentNode

@ -1,19 +0,0 @@
import { DomGenerator } from '../index';
import Block from '../Block';
import { State } from '../interfaces';
export default function visitYieldTag(
generator: DomGenerator,
block: Block,
state: State
) {
const parentNode = state.parentNode || '#target';
block.builders.mount.addLine(
`if ( #component._yield ) #component._yield.mount( ${parentNode}, null );`
);
block.builders.unmount.addLine(
`if ( #component._yield ) #component._yield.unmount();`
);
}

@ -4,7 +4,6 @@ import IfBlock from './IfBlock';
import MustacheTag from './MustacheTag'; import MustacheTag from './MustacheTag';
import RawMustacheTag from './RawMustacheTag'; import RawMustacheTag from './RawMustacheTag';
import Text from './Text'; import Text from './Text';
import YieldTag from './YieldTag';
import { Visitor } from '../interfaces'; import { Visitor } from '../interfaces';
const visitors: Record<string, Visitor> = { const visitors: Record<string, Visitor> = {
@ -13,8 +12,7 @@ const visitors: Record<string, Visitor> = {
IfBlock, IfBlock,
MustacheTag, MustacheTag,
RawMustacheTag, RawMustacheTag,
Text, Text
YieldTag,
}; };
export default visitors; export default visitors;

@ -23,7 +23,7 @@ export default function visitTag(
); );
const value = shouldCache && block.getUniqueName(`${name}_value`); const value = shouldCache && block.getUniqueName(`${name}_value`);
const init = shouldCache ? value : snippet; const content = shouldCache ? value : snippet;
if (shouldCache) block.addVariable(value, snippet); if (shouldCache) block.addVariable(value, snippet);
@ -41,9 +41,9 @@ export default function visitTag(
block.builders.update.addConditional( block.builders.update.addConditional(
condition, condition,
update(shouldCache ? value : snippet) update(content)
); );
} }
return { init }; return { init: content };
} }

@ -0,0 +1,5 @@
import { Node } from '../../../../interfaces';
export default function isDomNode(node: Node) {
return node.type === 'Element' || node.type === 'Text' || node.type === 'MustacheTag';
}

@ -16,12 +16,37 @@ export function detachBetween(before, after) {
} }
} }
export function detachBefore(after) {
while (after.previousSibling) {
after.parentNode.removeChild(after.previousSibling);
}
}
export function detachAfter(before) {
while (before.nextSibling) {
before.parentNode.removeChild(before.nextSibling);
}
}
export function reinsertBetween(before, after, target) { export function reinsertBetween(before, after, target) {
while (before.nextSibling && before.nextSibling !== after) { while (before.nextSibling && before.nextSibling !== after) {
target.appendChild(before.parentNode.removeChild(before.nextSibling)); target.appendChild(before.parentNode.removeChild(before.nextSibling));
} }
} }
export function reinsertChildren(parent, target) {
while (parent.firstChild) target.appendChild(parent.firstChild);
}
export function reinsertAfter(before, target) {
while (before.nextSibling) target.appendChild(before.nextSibling);
}
export function reinsertBefore(after, target) {
var parent = after.parentNode;
while (parent.firstChild !== after) target.appendChild(parent.firstChild);
}
// TODO this is out of date // TODO this is out of date
export function destroyEach(iterations, detach, start) { export function destroyEach(iterations, detach, start) {
for (var i = start; i < iterations.length; i += 1) { for (var i = start; i < iterations.length; i += 1) {

@ -25,8 +25,8 @@ function detachNode(node) {
node.parentNode.removeChild(node); node.parentNode.removeChild(node);
} }
function detachBetween(before, after) { function detachAfter(before) {
while (before.nextSibling && before.nextSibling !== after) { while (before.nextSibling) {
before.parentNode.removeChild(before.nextSibling); before.parentNode.removeChild(before.nextSibling);
} }
} }
@ -247,7 +247,7 @@ function create_main_fragment ( state, component ) {
} }
function create_each_block ( state, each_block_value, comment, i, component ) { function create_each_block ( state, each_block_value, comment, i, component ) {
var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before, raw_after; var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before;
return { return {
create: function () { create: function () {
@ -262,7 +262,6 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
text_5 = createText( " ago:" ); text_5 = createText( " ago:" );
text_6 = createText( "\n\n\t\t" ); text_6 = createText( "\n\n\t\t" );
raw_before = createElement( 'noscript' ); raw_before = createElement( 'noscript' );
raw_after = createElement( 'noscript' );
this.hydrate(); this.hydrate();
}, },
@ -283,8 +282,7 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
appendNode( text_5, span ); appendNode( text_5, span );
appendNode( text_6, div ); appendNode( text_6, div );
appendNode( raw_before, div ); appendNode( raw_before, div );
appendNode( raw_after, div ); raw_before.insertAdjacentHTML('afterend', raw_value);
raw_before.insertAdjacentHTML( 'afterend', raw_value );
}, },
update: function ( changed, state, each_block_value, comment, i ) { update: function ( changed, state, each_block_value, comment, i ) {
@ -297,13 +295,13 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
} }
if ( ( changed.comments ) && raw_value !== ( raw_value = comment.html ) ) { if ( ( changed.comments ) && raw_value !== ( raw_value = comment.html ) ) {
detachBetween( raw_before, raw_after ); detachAfter(raw_before);
raw_before.insertAdjacentHTML( 'afterend', raw_value ); raw_before.insertAdjacentHTML('afterend', raw_value);
} }
}, },
unmount: function () { unmount: function () {
detachBetween( raw_before, raw_after ); detachAfter(raw_before);
detachNode( div ); detachNode( div );
}, },

@ -1,4 +1,4 @@
import { appendNode, assign, createElement, createText, destroyEach, detachBetween, detachNode, insertNode, noop, proto } from "svelte/shared.js"; import { appendNode, assign, createElement, createText, destroyEach, detachAfter, detachNode, insertNode, noop, proto } from "svelte/shared.js";
function create_main_fragment ( state, component ) { function create_main_fragment ( state, component ) {
var text, p, text_1; var text, p, text_1;
@ -74,7 +74,7 @@ function create_main_fragment ( state, component ) {
} }
function create_each_block ( state, each_block_value, comment, i, component ) { function create_each_block ( state, each_block_value, comment, i, component ) {
var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before, raw_after; var div, strong, text, text_1, span, text_2_value = comment.author, text_2, text_3, text_4_value = state.elapsed(comment.time, state.time), text_4, text_5, text_6, raw_value = comment.html, raw_before;
return { return {
create: function () { create: function () {
@ -89,7 +89,6 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
text_5 = createText( " ago:" ); text_5 = createText( " ago:" );
text_6 = createText( "\n\n\t\t" ); text_6 = createText( "\n\n\t\t" );
raw_before = createElement( 'noscript' ); raw_before = createElement( 'noscript' );
raw_after = createElement( 'noscript' );
this.hydrate(); this.hydrate();
}, },
@ -110,8 +109,7 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
appendNode( text_5, span ); appendNode( text_5, span );
appendNode( text_6, div ); appendNode( text_6, div );
appendNode( raw_before, div ); appendNode( raw_before, div );
appendNode( raw_after, div ); raw_before.insertAdjacentHTML('afterend', raw_value);
raw_before.insertAdjacentHTML( 'afterend', raw_value );
}, },
update: function ( changed, state, each_block_value, comment, i ) { update: function ( changed, state, each_block_value, comment, i ) {
@ -124,13 +122,13 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
} }
if ( ( changed.comments ) && raw_value !== ( raw_value = comment.html ) ) { if ( ( changed.comments ) && raw_value !== ( raw_value = comment.html ) ) {
detachBetween( raw_before, raw_after ); detachAfter(raw_before);
raw_before.insertAdjacentHTML( 'afterend', raw_value ); raw_before.insertAdjacentHTML('afterend', raw_value);
} }
}, },
unmount: function () { unmount: function () {
detachBetween( raw_before, raw_after ); detachAfter(raw_before);
detachNode( div ); detachNode( div );
}, },

@ -0,0 +1,14 @@
export default {
data: {
raw: `<span>foo</span>`
},
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.ok(!span.previousSibling);
component.set({
raw: `<span>bar</span>`
});
}
};

@ -0,0 +1 @@
<div>{{{raw}}}{{#if maybe}}after{{/if}}</div>

@ -0,0 +1,15 @@
export default {
data: {
raw: `<span>foo</span>`
},
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.ok(!span.previousSibling);
assert.ok(!span.nextSibling);
component.set({
raw: `<span>bar</span>`
});
}
};

@ -0,0 +1,14 @@
export default {
data: {
raw: `<span>foo</span>`
},
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.ok(!span.nextSibling);
component.set({
raw: `<span>bar</span>`
});
}
};

@ -0,0 +1 @@
<div>{{#if maybe}}after{{/if}}{{{raw}}}</div>

@ -0,0 +1,15 @@
export default {
data: {
raw: `<span>foo</span>`
},
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.equal(span.previousSibling.nodeName, 'BR');
assert.equal(span.nextSibling.nodeName, 'BR');
component.set({
raw: `<span>bar</span>`
});
}
};

@ -0,0 +1,14 @@
export default {
data: {
raw: `<span>foo</span>`
},
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.equal(span.previousSibling.nodeName, 'BR');
component.set({
raw: `<span>bar</span>`
});
}
};

@ -0,0 +1 @@
before<br>{{{raw}}}{{#if maybe}}after{{/if}}

@ -0,0 +1,14 @@
export default {
data: {
raw: `<span>foo</span>`
},
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.equal(span.previousSibling.nodeName, 'BR');
component.set({
raw: `<span>bar</span>`
});
}
};

@ -0,0 +1 @@
before<br>{{{raw}}}{{#if maybe}}after{{/if}}

@ -1,5 +1,3 @@
const ns = '<noscript></noscript>';
export default { export default {
'skip-ssr': true, 'skip-ssr': true,
@ -7,13 +5,13 @@ export default {
raw: '<p>does not change</p>' raw: '<p>does not change</p>'
}, },
html: `<div>${ns}<p>does not change</p>${ns}</div>`, html: `<div><p>does not change</p></div>`,
test ( assert, component, target ) { test ( assert, component, target ) {
const p = target.querySelector( 'p' ); const p = target.querySelector( 'p' );
component.set({ raw: '<p>does not change</p>' }); component.set({ raw: '<p>does not change</p>' });
assert.equal( target.innerHTML, `<div>${ns}<p>does not change</p>${ns}</div>` ); assert.equal( target.innerHTML, `<div><p>does not change</p></div>` );
assert.strictEqual( target.querySelector( 'p' ), p ); assert.strictEqual( target.querySelector( 'p' ), p );
component.destroy(); component.destroy();

Loading…
Cancel
Save