only use noscript if necessary

pull/803/head
Rich Harris 8 years ago
parent 457f0189d4
commit 6499d4714d

@ -65,10 +65,8 @@ const preprocessors = {
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 });
const name = block.getUniqueName('raw');
node._state = getChildState(state, { name });
},
Text: (

@ -1,5 +1,4 @@
import deindent from '../../../utils/deindent';
import addUpdateBlock from './shared/addUpdateBlock';
import visitTag from './shared/Tag';
import { DomGenerator } from '../index';
import Block from '../Block';
@ -12,9 +11,35 @@ export default function visitRawMustacheTag(
state: State,
node: Node
) {
const name = node._state.basename;
const before = node._state.name;
const after = block.getUniqueName(`${name}_after`);
const name = node._state.name;
const needsAnchorBefore = node.prev ? (node.prev.type !== 'Element' || !node.prev._state || !node.prev._state.name) : !state.parentNode;
const needsAnchorAfter = node.next ? (node.next.type !== 'Element' || !node.next._state || !node.next._state.name) : !state.parentNode;
const anchorBefore = needsAnchorBefore
? block.getUniqueName(`${name}_before`)
: (node.prev && node.prev._state.name) || 'null';
const anchorAfter = needsAnchorAfter
? block.getUniqueName(`${name}_after`)
: (node.next && node.next._state.name) || 'null';
let detach: string;
let insert: (content: string) => string;
if (anchorBefore === 'null' && anchorAfter === 'null') {
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(
generator,
@ -22,28 +47,43 @@ export default function visitRawMustacheTag(
state,
node,
name,
value => deindent`
@detachBetween( ${before}, ${after} );
${before}.insertAdjacentHTML( 'afterend', ${value} );
content => deindent`
${detach}
${insert(content)}
`
);
// we would have used comments here, but the `insertAdjacentHTML` api only
// exists for `Element`s.
block.addElement(
before,
`@createElement( 'noscript' )`,
`@createElement( 'noscript' )`,
state.parentNode
);
if (needsAnchorBefore) {
block.addElement(
anchorBefore,
`@createElement( 'noscript' )`,
`@createElement( 'noscript' )`,
state.parentNode
);
}
block.addElement(
after,
`@createElement( 'noscript' )`,
`@createElement( 'noscript' )`,
state.parentNode
);
function addAnchorAfter() {
block.addElement(
anchorAfter,
`@createElement( 'noscript' )`,
`@createElement( 'noscript' )`,
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} );`);
block.builders.detachRaw.addBlock(`@detachBetween( ${before}, ${after} );`);
if (needsAnchorAfter && anchorBefore !== 'null') {
// ...otherwise it should go afterwards
addAnchorAfter();
}
}

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

@ -16,6 +16,18 @@ 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) {
while (before.nextSibling && before.nextSibling !== after) {
target.appendChild(before.parentNode.removeChild(before.nextSibling));

@ -25,8 +25,8 @@ function detachNode(node) {
node.parentNode.removeChild(node);
}
function detachBetween(before, after) {
while (before.nextSibling && before.nextSibling !== after) {
function detachAfter(before) {
while (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 ) {
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 {
create: function () {
@ -262,7 +262,6 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
text_5 = createText( " ago:" );
text_6 = createText( "\n\n\t\t" );
raw_before = createElement( 'noscript' );
raw_after = createElement( 'noscript' );
this.hydrate();
},
@ -283,8 +282,7 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
appendNode( text_5, span );
appendNode( text_6, 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 ) {
@ -297,13 +295,13 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
}
if ( ( changed.comments ) && raw_value !== ( raw_value = comment.html ) ) {
detachBetween( raw_before, raw_after );
raw_before.insertAdjacentHTML( 'afterend', raw_value );
detachAfter(raw_before);
raw_before.insertAdjacentHTML('afterend', raw_value);
}
},
unmount: function () {
detachBetween( raw_before, raw_after );
detachAfter(raw_before);
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 ) {
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 ) {
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 {
create: function () {
@ -89,7 +89,6 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
text_5 = createText( " ago:" );
text_6 = createText( "\n\n\t\t" );
raw_before = createElement( 'noscript' );
raw_after = createElement( 'noscript' );
this.hydrate();
},
@ -110,8 +109,7 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
appendNode( text_5, span );
appendNode( text_6, 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 ) {
@ -124,13 +122,13 @@ function create_each_block ( state, each_block_value, comment, i, component ) {
}
if ( ( changed.comments ) && raw_value !== ( raw_value = comment.html ) ) {
detachBetween( raw_before, raw_after );
raw_before.insertAdjacentHTML( 'afterend', raw_value );
detachAfter(raw_before);
raw_before.insertAdjacentHTML('afterend', raw_value);
}
},
unmount: function () {
detachBetween( raw_before, raw_after );
detachAfter(raw_before);
detachNode( div );
},

@ -5,6 +5,10 @@ export default {
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.equal(!span.previousSibling);
assert.ok(!span.previousSibling);
component.set({
raw: `<span>bar</span>`
});
}
};

@ -5,7 +5,11 @@ export default {
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.equal(!span.previousSibling);
assert.equal(!span.nextSibling);
assert.ok(!span.previousSibling);
assert.ok(!span.nextSibling);
component.set({
raw: `<span>bar</span>`
});
}
};

@ -5,6 +5,10 @@ export default {
test ( assert, component, target ) {
const span = target.querySelector('span');
assert.equal(!span.nextSibling);
assert.ok(!span.nextSibling);
component.set({
raw: `<span>bar</span>`
});
}
};

@ -7,5 +7,9 @@ export default {
const span = target.querySelector('span');
assert.equal(span.previousSibling.nodeName, 'BR');
assert.equal(span.nextSibling.nodeName, 'BR');
component.set({
raw: `<span>bar</span>`
});
}
};

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

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

@ -1,5 +1,3 @@
const ns = '<noscript></noscript>';
export default {
'skip-ssr': true,
@ -7,13 +5,13 @@ export default {
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 ) {
const p = target.querySelector( '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 );
component.destroy();

Loading…
Cancel
Save