Skip to content

Commit

Permalink
Dirty check primitive values passed to unsafeHTML() (lit#384)
Browse files Browse the repository at this point in the history
  • Loading branch information
justinfagnani authored and dfreedm committed Jun 27, 2018
1 parent 1afb21d commit e011499
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 5 deletions.
6 changes: 5 additions & 1 deletion src/lib/unsafe-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* http://polymer.github.io/PATENTS.txt
*/

import {directive, DirectiveFn, NodePart} from '../lit-html.js';
import {directive, DirectiveFn, NodePart, _isPrimitiveValue} from '../lit-html.js';

/**
* Renders the result as HTML, rather than text.
Expand All @@ -23,7 +23,11 @@ import {directive, DirectiveFn, NodePart} from '../lit-html.js';
*/
export const unsafeHTML = (value: any): DirectiveFn<NodePart> =>
directive((part: NodePart): void => {
if (part._previousValue === value && _isPrimitiveValue(value)) {
return;
}
const tmp = document.createElement('template');
tmp.innerHTML = value;
part.setValue(document.importNode(tmp.content, true));
part._previousValue = value;
});
6 changes: 3 additions & 3 deletions src/lit-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ export const noChange = {};
*/
export { noChange as directiveValue };

const isPrimitiveValue = (value: any) => value === null ||
export const _isPrimitiveValue = (value: any) => value === null ||
!(typeof value === 'object' || typeof value === 'function');

export interface Part {
Expand Down Expand Up @@ -531,7 +531,7 @@ export class AttributePart implements MultiPart {
}
for (let i = startIndex; i < startIndex + this.size; i++) {
if (this._previousValues[i] !== values[i] ||
!isPrimitiveValue(values[i])) {
!_isPrimitiveValue(values[i])) {
return false;
}
}
Expand Down Expand Up @@ -579,7 +579,7 @@ export class NodePart implements SinglePart {
if (value === noChange) {
return;
}
if (isPrimitiveValue(value)) {
if (_isPrimitiveValue(value)) {
// Handle primitive values
// If the value didn't change, do nothing
if (value === this._previousValue) {
Expand Down
44 changes: 43 additions & 1 deletion src/test/lib/unsafe-html_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,55 @@ const assert = chai.assert;

suite('unsafeHTML', () => {

let container: HTMLElement;

setup(() => {
container = document.createElement('div');
});

test('renders HTML', () => {
const container = document.createElement('div');
render(
html`<div>before${unsafeHTML('<span>inner</span>after</div>')}`,
container);
assert.equal(
stripExpressionDelimeters(container.innerHTML), '<div>before<span>inner</span>after</div>');
});

test('dirty checks primitive values', () => {
const value = 'aaa';
const t = () => html`<div>${unsafeHTML(value)}</div>`;

// Initial render
render(t(), container);
assert.equal(stripExpressionDelimeters(container.innerHTML), '<div>aaa</div>');

// Modify instance directly. Since lit-html doesn't dirty check against
// actual DOM, but again previous part values, this modification should
// persist through the next render if dirty checking works.
const text = container.firstChild!.childNodes[1] as Text;
text.textContent = 'bbb';
assert.equal(stripExpressionDelimeters(container.innerHTML), '<div>bbb</div>');

// Re-render with the same value
render(t(), container);

assert.equal(stripExpressionDelimeters(container.innerHTML), '<div>bbb</div>');
const text2 = container.firstChild!.childNodes[1] as Text;
assert.strictEqual(text, text2);
});

test('does not dirty check complex values', () => {
const value = ['aaa'];
const t = () => html`<div>${unsafeHTML(value)}</div>`;

// Initial render
render(t(), container);
assert.equal(stripExpressionDelimeters(container.innerHTML), '<div>aaa</div>');

// Re-render with the same value, but a different deep property
value[0] = 'bbb';
render(t(), container);
assert.equal(stripExpressionDelimeters(container.innerHTML), '<div>bbb</div>');
});

});

0 comments on commit e011499

Please sign in to comment.