use textContent and innerHTML where appropriate (#23)

pull/860/head
Rich Harris 7 years ago
parent 3b68d1f5dc
commit 66ae0d9c94

@ -41,6 +41,13 @@ function createDebuggingComment(node: Node, generator: DomGenerator) {
return `${loc} ${source.slice(c, d)}`.replace(/\n/g, ' ');
}
function cannotUseInnerHTML(node: Node) {
while (node && node.canUseInnerHTML) {
node.canUseInnerHTML = false;
node = node.parent;
}
}
// 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)
@ -65,6 +72,7 @@ const preprocessors = {
componentStack: Node[],
stripWhitespace: boolean
) => {
cannotUseInnerHTML(node);
node.var = block.getUniqueName('text');
const dependencies = block.findDependencies(node.expression);
@ -80,6 +88,7 @@ const preprocessors = {
componentStack: Node[],
stripWhitespace: boolean
) => {
cannotUseInnerHTML(node);
node.var = block.getUniqueName('raw');
const dependencies = block.findDependencies(node.expression);
@ -114,6 +123,8 @@ const preprocessors = {
stripWhitespace: boolean,
nextSibling: Node
) => {
cannotUseInnerHTML(node);
const blocks: Block[] = [];
let dynamic = false;
let hasIntros = false;
@ -195,6 +206,7 @@ const preprocessors = {
stripWhitespace: boolean,
nextSibling: Node
) => {
cannotUseInnerHTML(node);
node.var = block.getUniqueName(`each_block`);
const dependencies = block.findDependencies(node.expression);
@ -286,10 +298,16 @@ const preprocessors = {
stripWhitespace: boolean,
nextSibling: Node
) => {
if (node.name === 'slot') {
cannotUseInnerHTML(node);
}
node.attributes.forEach((attribute: Node) => {
if (attribute.type === 'Attribute' && attribute.value !== true) {
attribute.value.forEach((chunk: Node) => {
if (chunk.type !== 'Text') {
if (node.parent) cannotUseInnerHTML(node.parent);
const dependencies = block.findDependencies(chunk.expression);
block.addDependencies(dependencies);
@ -307,20 +325,24 @@ const preprocessors = {
}
}
});
} else if (attribute.type === 'EventHandler' && attribute.expression) {
attribute.expression.arguments.forEach((arg: Node) => {
const dependencies = block.findDependencies(arg);
} else {
if (node.parent) cannotUseInnerHTML(node.parent);
if (attribute.type === 'EventHandler' && attribute.expression) {
attribute.expression.arguments.forEach((arg: Node) => {
const dependencies = block.findDependencies(arg);
block.addDependencies(dependencies);
});
} else if (attribute.type === 'Binding') {
const dependencies = block.findDependencies(attribute.value);
block.addDependencies(dependencies);
});
} else if (attribute.type === 'Binding') {
const dependencies = block.findDependencies(attribute.value);
block.addDependencies(dependencies);
} else if (attribute.type === 'Transition') {
if (attribute.intro)
generator.hasIntroTransitions = block.hasIntroMethod = true;
if (attribute.outro) {
generator.hasOutroTransitions = block.hasOutroMethod = true;
block.outros += 1;
} else if (attribute.type === 'Transition') {
if (attribute.intro)
generator.hasIntroTransitions = block.hasIntroMethod = true;
if (attribute.outro) {
generator.hasOutroTransitions = block.hasOutroMethod = true;
block.outros += 1;
}
}
}
});
@ -336,6 +358,8 @@ const preprocessors = {
// so that if `foo.qux` changes, we know that we need to
// mark `bar` and `baz` as dirty too
if (node.name === 'select') {
cannotUseInnerHTML(node);
const value = node.attributes.find(
(attribute: Node) => attribute.name === 'value'
);
@ -355,6 +379,8 @@ const preprocessors = {
generator.components.has(node.name) || node.name === ':Self';
if (isComponent) {
cannotUseInnerHTML(node);
node.var = block.getUniqueName(
(node.name === ':Self' ? generator.name : node.name).toLowerCase()
);
@ -365,6 +391,7 @@ const preprocessors = {
} else {
const slot = getStaticAttributeValue(node, 'slot');
if (slot && isChildOfComponent(node, generator)) {
cannotUseInnerHTML(node);
node.slotted = true;
// TODO validate slots — no nesting, no dynamic names...
const component = componentStack[componentStack.length - 1];
@ -438,6 +465,7 @@ function preprocessChildren(
cleaned.forEach((child: Node, i: number) => {
child.parent = node;
child.canUseInnerHTML = !generator.hydratable;
const preprocessor = preprocessors[child.type];
if (preprocessor) preprocessor(generator, block, state, child, inEachBlock, elementStack, componentStack, stripWhitespace, cleaned[i + 1] || nextSibling);

@ -9,6 +9,7 @@ import visitBinding from './Binding';
import visitRef from './Ref';
import * as namespaces from '../../../../utils/namespaces';
import getStaticAttributeValue from '../../../../utils/getStaticAttributeValue';
import isVoidElementName from '../../../../utils/isVoidElementName';
import addTransitions from './addTransitions';
import { DomGenerator } from '../../index';
import Block from '../../Block';
@ -94,7 +95,6 @@ export default function visitElement(
}
// add CSS encapsulation attribute
// TODO add a helper for this, rather than repeating it
if (node._needsCssAttribute && !generator.customElement) {
generator.needsEncapsulateHelper = true;
block.builders.hydrate.addLine(
@ -202,9 +202,21 @@ export default function visitElement(
node.initialUpdate = node.lateUpdate = statement;
}
node.children.forEach((child: Node) => {
visit(generator, block, childState, child, elementStack.concat(node), componentStack);
});
if (!childState.namespace && node.canUseInnerHTML && node.children.length > 0) {
if (node.children.length === 1 && node.children[0].type === 'Text') {
block.builders.create.addLine(
`${name}.textContent = ${JSON.stringify(node.children[0].data)};`
);
} else {
block.builders.create.addLine(
`${name}.innerHTML = ${JSON.stringify(node.children.map(toHTML).join(''))};`
);
}
} else {
node.children.forEach((child: Node) => {
visit(generator, block, childState, child, elementStack.concat(node), componentStack);
});
}
if (node.lateUpdate) {
block.builders.update.addLine(node.lateUpdate);
@ -221,6 +233,29 @@ export default function visitElement(
block.builders.claim.addLine(
`${childState.parentNodes}.forEach(@detachNode);`
);
function toHTML(node: Node) {
if (node.type === 'Text') return node.data;
let open = `<${node.name}`;
if (node._needsCssAttribute) {
open += ` ${generator.stylesheet.id}`;
}
if (node._cssRefAttribute) {
open += ` svelte-ref-${node._cssRefAttribute}`;
}
node.attributes.forEach((attr: Node) => {
open += ` ${attr.name}${stringifyAttributeValue(attr.value)}`
});
if (isVoidElementName(node.name)) return open + '>';
if (node.children.length === 0) return open + '/>';
return `${open}>${node.children.map(toHTML).join('')}</${node.name}>`;
}
}
function getRenderStatement(
@ -263,3 +298,11 @@ function quoteProp(name: string, legacy: boolean) {
if (/[^a-zA-Z_$0-9]/.test(name) || isLegacyPropName) return `"${name}"`;
return name;
}
function stringifyAttributeValue(value: Node | true) {
if (value === true) return '';
if (value.length === 0) return `=""`;
const data = value[0].data;
return `=${JSON.stringify(data)}`;
}

@ -13,10 +13,6 @@ function assign(target) {
return target;
}
function appendNode(node, target) {
target.appendChild(node);
}
function insertNode(node, target, anchor) {
target.insertBefore(node, anchor);
}
@ -29,10 +25,6 @@ function createElement(name) {
return document.createElement(name);
}
function createText(data) {
return document.createTextNode(data);
}
function blankObject() {
return Object.create(null);
}
@ -188,17 +180,16 @@ var proto = {
/* generated by Svelte vX.Y.Z */
function create_main_fragment(state, component) {
var div, text;
var div;
return {
create: function() {
div = createElement("div");
text = createText("fades in");
div.textContent = "fades in";
},
mount: function(target, anchor) {
insertNode(div, target, anchor);
appendNode(text, div);
},
update: noop,

@ -1,19 +1,18 @@
/* generated by Svelte vX.Y.Z */
import { appendNode, assign, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
import { assign, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
function create_main_fragment(state, component) {
var div, text;
var div;
return {
create: function() {
div = createElement("div");
text = createText("fades in");
div.textContent = "fades in";
},
mount: function(target, anchor) {
insertNode(div, target, anchor);
appendNode(text, div);
},
update: noop,

@ -13,10 +13,6 @@ function assign(target) {
return target;
}
function appendNode(node, target) {
target.appendChild(node);
}
function insertNode(node, target, anchor) {
target.insertBefore(node, anchor);
}
@ -29,10 +25,6 @@ function createElement(name) {
return document.createElement(name);
}
function createText(data) {
return document.createTextNode(data);
}
function blankObject() {
return Object.create(null);
}
@ -203,12 +195,12 @@ var template = (function() {
}());
function create_main_fragment(state, component) {
var button, foo_handler, text;
var button, foo_handler;
return {
create: function() {
button = createElement("button");
text = createText("foo");
button.textContent = "foo";
this.hydrate();
},
@ -221,7 +213,6 @@ function create_main_fragment(state, component) {
mount: function(target, anchor) {
insertNode(button, target, anchor);
appendNode(text, button);
},
update: noop,

@ -1,6 +1,6 @@
/* generated by Svelte vX.Y.Z */
import { appendNode, assign, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
import { assign, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
var template = (function() {
return {
@ -18,12 +18,12 @@ var template = (function() {
}());
function create_main_fragment(state, component) {
var button, foo_handler, text;
var button, foo_handler;
return {
create: function() {
button = createElement("button");
text = createText("foo");
button.textContent = "foo";
this.hydrate();
},
@ -36,7 +36,6 @@ function create_main_fragment(state, component) {
mount: function(target, anchor) {
insertNode(button, target, anchor);
appendNode(text, button);
},
update: noop,

@ -13,10 +13,6 @@ function assign(target) {
return target;
}
function appendNode(node, target) {
target.appendChild(node);
}
function insertNode(node, target, anchor) {
target.insertBefore(node, anchor);
}
@ -29,10 +25,6 @@ function createElement(name) {
return document.createElement(name);
}
function createText(data) {
return document.createTextNode(data);
}
function createComment() {
return document.createComment('');
}
@ -231,17 +223,16 @@ function create_main_fragment(state, component) {
// (1:0) {{#if foo}}
function create_if_block(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("foo!");
p.textContent = "foo!";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -254,17 +245,16 @@ function create_if_block(state, component) {
// (3:0) {{else}}
function create_if_block_1(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("not foo!");
p.textContent = "not foo!";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {

@ -1,6 +1,6 @@
/* generated by Svelte vX.Y.Z */
import { appendNode, assign, createComment, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
import { assign, createComment, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
function create_main_fragment(state, component) {
var if_block_anchor;
@ -42,17 +42,16 @@ function create_main_fragment(state, component) {
// (1:0) {{#if foo}}
function create_if_block(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("foo!");
p.textContent = "foo!";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -65,17 +64,16 @@ function create_if_block(state, component) {
// (3:0) {{else}}
function create_if_block_1(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("not foo!");
p.textContent = "not foo!";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {

@ -13,10 +13,6 @@ function assign(target) {
return target;
}
function appendNode(node, target) {
target.appendChild(node);
}
function insertNode(node, target, anchor) {
target.insertBefore(node, anchor);
}
@ -29,10 +25,6 @@ function createElement(name) {
return document.createElement(name);
}
function createText(data) {
return document.createTextNode(data);
}
function createComment() {
return document.createComment('');
}
@ -234,17 +226,16 @@ function create_main_fragment(state, component) {
// (1:0) {{#if foo}}
function create_if_block(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("foo!");
p.textContent = "foo!";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {

@ -1,6 +1,6 @@
/* generated by Svelte vX.Y.Z */
import { appendNode, assign, createComment, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
import { assign, createComment, createElement, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
function create_main_fragment(state, component) {
var if_block_anchor;
@ -45,17 +45,16 @@ function create_main_fragment(state, component) {
// (1:0) {{#if foo}}
function create_if_block(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("foo!");
p.textContent = "foo!";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {

@ -192,7 +192,7 @@ var proto = {
/* generated by Svelte vX.Y.Z */
function create_main_fragment(state, component) {
var div, text, p, text_1, text_2, text_3, text_4, p_1, text_5, text_6, text_8, if_block_4_anchor;
var div, text, p, text_2, text_3, text_4, p_1, text_6, text_8, if_block_4_anchor;
var if_block = (state.a) && create_if_block(state, component);
@ -210,14 +210,14 @@ function create_main_fragment(state, component) {
if (if_block) if_block.create();
text = createText("\n\n\t");
p = createElement("p");
text_1 = createText("this can be used as an anchor");
p.textContent = "this can be used as an anchor";
text_2 = createText("\n\n\t");
if (if_block_1) if_block_1.create();
text_3 = createText("\n\n\t");
if (if_block_2) if_block_2.create();
text_4 = createText("\n\n\t");
p_1 = createElement("p");
text_5 = createText("so can this");
p_1.textContent = "so can this";
text_6 = createText("\n\n\t");
if (if_block_3) if_block_3.create();
text_8 = createText("\n\n");
@ -230,14 +230,12 @@ function create_main_fragment(state, component) {
if (if_block) if_block.mount(div, null);
appendNode(text, div);
appendNode(p, div);
appendNode(text_1, p);
appendNode(text_2, div);
if (if_block_1) if_block_1.mount(div, null);
appendNode(text_3, div);
if (if_block_2) if_block_2.mount(div, null);
appendNode(text_4, div);
appendNode(p_1, div);
appendNode(text_5, p_1);
appendNode(text_6, div);
if (if_block_3) if_block_3.mount(div, null);
insertNode(text_8, target, anchor);
@ -330,17 +328,16 @@ function create_main_fragment(state, component) {
// (2:1) {{#if a}}
function create_if_block(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("a");
p.textContent = "a";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -353,17 +350,16 @@ function create_if_block(state, component) {
// (8:1) {{#if b}}
function create_if_block_1(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("b");
p.textContent = "b";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -376,17 +372,16 @@ function create_if_block_1(state, component) {
// (12:1) {{#if c}}
function create_if_block_2(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("c");
p.textContent = "c";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -399,17 +394,16 @@ function create_if_block_2(state, component) {
// (18:1) {{#if d}}
function create_if_block_3(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("d");
p.textContent = "d";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -422,17 +416,16 @@ function create_if_block_3(state, component) {
// (25:0) {{#if e}}
function create_if_block_4(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("e");
p.textContent = "e";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {

@ -3,7 +3,7 @@
import { appendNode, assign, createComment, createElement, createText, detachNode, init, insertNode, noop, proto } from "svelte/shared.js";
function create_main_fragment(state, component) {
var div, text, p, text_1, text_2, text_3, text_4, p_1, text_5, text_6, text_8, if_block_4_anchor;
var div, text, p, text_2, text_3, text_4, p_1, text_6, text_8, if_block_4_anchor;
var if_block = (state.a) && create_if_block(state, component);
@ -21,14 +21,14 @@ function create_main_fragment(state, component) {
if (if_block) if_block.create();
text = createText("\n\n\t");
p = createElement("p");
text_1 = createText("this can be used as an anchor");
p.textContent = "this can be used as an anchor";
text_2 = createText("\n\n\t");
if (if_block_1) if_block_1.create();
text_3 = createText("\n\n\t");
if (if_block_2) if_block_2.create();
text_4 = createText("\n\n\t");
p_1 = createElement("p");
text_5 = createText("so can this");
p_1.textContent = "so can this";
text_6 = createText("\n\n\t");
if (if_block_3) if_block_3.create();
text_8 = createText("\n\n");
@ -41,14 +41,12 @@ function create_main_fragment(state, component) {
if (if_block) if_block.mount(div, null);
appendNode(text, div);
appendNode(p, div);
appendNode(text_1, p);
appendNode(text_2, div);
if (if_block_1) if_block_1.mount(div, null);
appendNode(text_3, div);
if (if_block_2) if_block_2.mount(div, null);
appendNode(text_4, div);
appendNode(p_1, div);
appendNode(text_5, p_1);
appendNode(text_6, div);
if (if_block_3) if_block_3.mount(div, null);
insertNode(text_8, target, anchor);
@ -141,17 +139,16 @@ function create_main_fragment(state, component) {
// (2:1) {{#if a}}
function create_if_block(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("a");
p.textContent = "a";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -164,17 +161,16 @@ function create_if_block(state, component) {
// (8:1) {{#if b}}
function create_if_block_1(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("b");
p.textContent = "b";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -187,17 +183,16 @@ function create_if_block_1(state, component) {
// (12:1) {{#if c}}
function create_if_block_2(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("c");
p.textContent = "c";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -210,17 +205,16 @@ function create_if_block_2(state, component) {
// (18:1) {{#if d}}
function create_if_block_3(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("d");
p.textContent = "d";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {
@ -233,17 +227,16 @@ function create_if_block_3(state, component) {
// (25:0) {{#if e}}
function create_if_block_4(state, component) {
var p, text;
var p;
return {
create: function() {
p = createElement("p");
text = createText("e");
p.textContent = "e";
},
mount: function(target, anchor) {
insertNode(p, target, anchor);
appendNode(text, p);
},
unmount: function() {

Loading…
Cancel
Save