Comparing version
@@ -108,7 +108,9 @@ /** | ||
const attributeString = this._strings[partIndex]; | ||
partIndex += strings.length - 1; | ||
const match = attributeString.match(/((?:\w|[.\-_])+)=?("|')?$/); | ||
// Trim the trailing literal value if this is an interpolation | ||
const rawNameString = attributeString.substring(0, attributeString.length - strings[0].length); | ||
const match = rawNameString.match(/((?:\w|[.\-_$])+)=["']?$/); | ||
const rawName = match[1]; | ||
this.parts.push(new TemplatePart('attribute', index, attribute.name, rawName, strings)); | ||
attributesToRemove.push(attribute); | ||
partIndex += strings.length - 1; | ||
} | ||
@@ -136,3 +138,2 @@ } | ||
nodesToRemove.push(node); | ||
index--; | ||
} | ||
@@ -252,17 +253,28 @@ } | ||
let next = values.next(); | ||
if (current.done) { | ||
// Empty iterable, just clear | ||
this.clear(); | ||
} | ||
while (!current.done) { | ||
if (next.done) { | ||
// on the last item, reuse this part's endNode | ||
itemEnd = this.endNode; | ||
} | ||
else { | ||
itemEnd = new Text(); | ||
this.endNode.parentNode.insertBefore(itemEnd, this.endNode); | ||
} | ||
// Reuse a part if we can, otherwise create a new one | ||
// Reuse a previous part if we can, otherwise create a new one | ||
let itemPart; | ||
if (previousParts !== undefined && previousPartsIndex < previousParts.length) { | ||
itemPart = previousParts[previousPartsIndex++]; | ||
if (next.done && itemPart.endNode !== this.endNode) { | ||
// Since this is the last part we'll use, set it's endNode to the | ||
// container's endNode. Setting the value of this part will clean | ||
// up any residual nodes from a previously longer iterable. | ||
itemPart.endNode = this.endNode; | ||
} | ||
itemEnd = itemPart.endNode; | ||
} | ||
else { | ||
if (next.done) { | ||
// on the last item, reuse this part's endNode | ||
itemEnd = this.endNode; | ||
} | ||
else { | ||
itemEnd = new Text(); | ||
this.endNode.parentNode.insertBefore(itemEnd, this.endNode); | ||
} | ||
itemPart = new NodePart(itemStart, itemEnd); | ||
@@ -277,17 +289,2 @@ } | ||
this._previousValue = itemParts; | ||
// If the new list is shorter than the old list, clean up: | ||
if (previousParts !== undefined && previousPartsIndex < previousParts.length) { | ||
const clearStart = previousParts[previousPartsIndex].startNode; | ||
const clearEnd = previousParts[previousParts.length - 1].endNode; | ||
const clearRange = document.createRange(); | ||
if (previousPartsIndex === 0) { | ||
clearRange.setStartBefore(clearStart); | ||
} | ||
else { | ||
clearRange.setStartAfter(clearStart); | ||
} | ||
clearRange.setEndAfter(clearEnd); | ||
clearRange.deleteContents(); | ||
clearRange.detach(); // is this neccessary? | ||
} | ||
} | ||
@@ -304,9 +301,7 @@ else { | ||
this._previousValue = undefined; | ||
let node = this.startNode; | ||
let next = node.nextSibling; | ||
while (next !== null && next !== this.endNode) { | ||
node = next; | ||
next = next.nextSibling; | ||
node.parentNode.removeChild(node); | ||
} | ||
const range = document.createRange(); | ||
range.setStartAfter(this.startNode); | ||
range.setEndBefore(this.endNode); | ||
range.deleteContents(); | ||
range.detach(); | ||
} | ||
@@ -313,0 +308,0 @@ } |
@@ -160,3 +160,3 @@ /** | ||
}); | ||
test('renders to an attribute and node', () => { | ||
test('renders to an attribute before a node', () => { | ||
const container = document.createElement('div'); | ||
@@ -166,2 +166,7 @@ html `<div foo="${'bar'}">${'baz'}</div>`.renderTo(container); | ||
}); | ||
test('renders to an attribute after a node', () => { | ||
const container = document.createElement('div'); | ||
html `<div>${'baz'}</div><div foo="${'bar'}"></div>`.renderTo(container); | ||
assert.equal(container.innerHTML, '<div>baz</div><div foo="bar"></div>'); | ||
}); | ||
test('renders a combination of stuff', () => { | ||
@@ -377,3 +382,11 @@ const container = document.createElement('div'); | ||
assert.equal(container.innerHTML, '123'); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
test('accepts an empty array', () => { | ||
part.setValue([]); | ||
assert.equal(container.innerHTML, ''); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
test('accepts nested templates', () => { | ||
@@ -405,9 +418,34 @@ part.setValue(html `<h1>${'foo'}</h1>`); | ||
assert.equal(container.innerHTML, '123'); | ||
assert.deepEqual(['', '1', '', '2', '', '3', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
const n2 = container.childNodes.item(2); | ||
const n4 = container.childNodes.item(4); | ||
part.setValue([]); | ||
assert.equal(container.innerHTML, ''); | ||
assert.deepEqual(['', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
test('updates when called multiple times with arrays', () => { | ||
part.setValue([1, 2, 3]); | ||
assert.equal(container.innerHTML, '123'); | ||
assert.deepEqual(['', '1', '', '2', '', '3', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
part.setValue([4, 5]); | ||
assert.equal(container.innerHTML, '45'); | ||
// check that we're not leaving orphaned marker nodes around | ||
assert.deepEqual(['', '4', '', '5', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
part.setValue([]); | ||
assert.equal(container.innerHTML, ''); | ||
assert.deepEqual([], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.deepEqual(['', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
part.setValue([4, 5]); | ||
assert.equal(container.innerHTML, '45'); | ||
assert.deepEqual(['', '4', '', '5', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
@@ -414,0 +452,0 @@ test('updates are stable when called multiple times with templates', () => { |
{ | ||
"name": "lit-html", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "HTML template literals in JavaScript", | ||
@@ -5,0 +5,0 @@ "license": "BSD-3-Clause", |
@@ -123,7 +123,9 @@ /** | ||
const attributeString = this._strings[partIndex]; | ||
partIndex += strings.length - 1; | ||
const match = attributeString.match(/((?:\w|[.\-_])+)=?("|')?$/); | ||
// Trim the trailing literal value if this is an interpolation | ||
const rawNameString = attributeString.substring(0, attributeString.length - strings[0].length); | ||
const match = rawNameString.match(/((?:\w|[.\-_$])+)=["']?$/); | ||
const rawName = match![1]; | ||
this.parts.push(new TemplatePart('attribute', index, attribute.name, rawName, strings)); | ||
attributesToRemove.push(attribute); | ||
partIndex += strings.length - 1; | ||
} | ||
@@ -150,6 +152,6 @@ } | ||
nodesToRemove.push(node); | ||
index--; | ||
} | ||
} | ||
} | ||
// Remove text binding nodes after the walk to not disturb the TreeWalker | ||
@@ -283,3 +285,3 @@ for (const n of nodesToRemove) { | ||
const previousParts = Array.isArray(this._previousValue) ? this._previousValue : undefined; | ||
const previousParts: NodePart[]|undefined = Array.isArray(this._previousValue) ? this._previousValue : undefined; | ||
let previousPartsIndex = 0; | ||
@@ -290,16 +292,26 @@ const itemParts = []; | ||
if (current.done) { | ||
// Empty iterable, just clear | ||
this.clear(); | ||
} | ||
while (!current.done) { | ||
if (next.done) { | ||
// on the last item, reuse this part's endNode | ||
itemEnd = this.endNode; | ||
} else { | ||
itemEnd = new Text(); | ||
this.endNode.parentNode!.insertBefore(itemEnd, this.endNode); | ||
} | ||
// Reuse a part if we can, otherwise create a new one | ||
let itemPart; | ||
// Reuse a previous part if we can, otherwise create a new one | ||
let itemPart: NodePart; | ||
if (previousParts !== undefined && previousPartsIndex < previousParts.length) { | ||
itemPart = previousParts[previousPartsIndex++]; | ||
if (next.done && itemPart.endNode !== this.endNode) { | ||
// Since this is the last part we'll use, set it's endNode to the | ||
// container's endNode. Setting the value of this part will clean | ||
// up any residual nodes from a previously longer iterable. | ||
itemPart.endNode = this.endNode; | ||
} | ||
itemEnd = itemPart.endNode; | ||
} else { | ||
if (next.done) { | ||
// on the last item, reuse this part's endNode | ||
itemEnd = this.endNode; | ||
} else { | ||
itemEnd = new Text(); | ||
this.endNode.parentNode!.insertBefore(itemEnd, this.endNode); | ||
} | ||
itemPart = new NodePart(itemStart, itemEnd); | ||
@@ -316,18 +328,2 @@ } | ||
this._previousValue = itemParts; | ||
// If the new list is shorter than the old list, clean up: | ||
if (previousParts !== undefined && previousPartsIndex < previousParts.length) { | ||
const clearStart = previousParts[previousPartsIndex].startNode; | ||
const clearEnd = previousParts[previousParts.length - 1].endNode; | ||
const clearRange = document.createRange(); | ||
if (previousPartsIndex === 0) { | ||
clearRange.setStartBefore(clearStart); | ||
} else { | ||
clearRange.setStartAfter(clearStart); | ||
} | ||
clearRange.setEndAfter(clearEnd); | ||
clearRange.deleteContents(); | ||
clearRange.detach(); // is this neccessary? | ||
} | ||
} else { | ||
@@ -344,12 +340,9 @@ this.clear(); | ||
this._previousValue = undefined; | ||
let node: Node = this.startNode; | ||
let next: Node|null = node.nextSibling; | ||
while (next !== null && next !== this.endNode) { | ||
node = next; | ||
next = next.nextSibling; | ||
node.parentNode!.removeChild(node); | ||
} | ||
const range = document.createRange(); | ||
range.setStartAfter(this.startNode); | ||
range.setEndBefore(this.endNode); | ||
range.deleteContents(); | ||
range.detach(); | ||
} | ||
// detach(): DocumentFragment ? | ||
} | ||
@@ -356,0 +349,0 @@ |
@@ -192,3 +192,3 @@ /** | ||
test('renders to an attribute and node', () => { | ||
test('renders to an attribute before a node', () => { | ||
const container = document.createElement('div'); | ||
@@ -199,2 +199,8 @@ html`<div foo="${'bar'}">${'baz'}</div>`.renderTo(container); | ||
test('renders to an attribute after a node', () => { | ||
const container = document.createElement('div'); | ||
html`<div>${'baz'}</div><div foo="${'bar'}"></div>`.renderTo(container); | ||
assert.equal(container.innerHTML, '<div>baz</div><div foo="bar"></div>'); | ||
}); | ||
test('renders a combination of stuff', () => { | ||
@@ -460,4 +466,13 @@ const container = document.createElement('div'); | ||
assert.equal(container.innerHTML, '123'); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
test('accepts an empty array', () => { | ||
part.setValue([]); | ||
assert.equal(container.innerHTML, ''); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
test('accepts nested templates', () => { | ||
@@ -493,11 +508,39 @@ part.setValue(html`<h1>${'foo'}</h1>`); | ||
assert.equal(container.innerHTML, '123'); | ||
assert.deepEqual(['', '1', '', '2', '', '3', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
const n2 = container.childNodes.item(2); | ||
const n4 = container.childNodes.item(4); | ||
part.setValue([]); | ||
assert.equal(container.innerHTML, ''); | ||
assert.deepEqual(['', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
test('updates when called multiple times with arrays', () => { | ||
part.setValue([1, 2, 3]); | ||
assert.equal(container.innerHTML, '123'); | ||
assert.deepEqual(['', '1', '', '2', '', '3', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
part.setValue([4, 5]); | ||
assert.equal(container.innerHTML, '45'); | ||
// check that we're not leaving orphaned marker nodes around | ||
assert.deepEqual(['', '4', '', '5', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
part.setValue([]); | ||
assert.equal(container.innerHTML, ''); | ||
assert.deepEqual([], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.deepEqual(['', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
part.setValue([4, 5]); | ||
assert.equal(container.innerHTML, '45'); | ||
assert.deepEqual(['', '4', '', '5', ''], Array.from(container.childNodes).map((n) => n.nodeValue)); | ||
assert.strictEqual(container.firstChild, startNode); | ||
assert.strictEqual(container.lastChild, endNode); | ||
}); | ||
@@ -504,0 +547,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
163871
4.48%2481
2.73%