diff --git a/dist/diffhtml.js b/dist/diffhtml.js index d18735d2..7259ca8c 100644 --- a/dist/diffhtml.js +++ b/dist/diffhtml.js @@ -1329,7 +1329,7 @@ function process(element, patches) { if (descriptor.nodeName === '#text' || descriptor.nodeName === 'text') { var textPromises = transition.makePromises('textChanged', [element], null, descriptor.nodeValue); - element.nodeValue = descriptor.nodeValue; + element.innerHTML = descriptor.nodeValue; triggerTransition('textChanged', textPromises, function (promises) {}); } @@ -1948,6 +1948,7 @@ var pools = _pools2.pools; // Code based off of: // https://github.com/ashi009/node-fast-html-parser var parser = makeParser(); +var slice = Array.prototype.slice; /** * parseHTML @@ -1974,15 +1975,6 @@ function makeParser() { var reAttrPattern = /\b([a-z][a-z0-9\-]*)\s*(=\s*("([^"]+)"|'([^']+)'|(\S+)))?/ig; - var kBlockElements = { - div: true, - p: true, - li: true, - td: true, - section: true, - br: true - }; - var kSelfClosingElements = { meta: true, img: true, @@ -2049,6 +2041,15 @@ function makeParser() { template: true }; + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + /** * TextNode to contain a text element in DOM tree. * @param {string} value [description] @@ -2179,6 +2180,10 @@ function makeParser() { var newText = data.slice(match.index + match[0].length, index); if (newText.trim()) { + newText = slice.call(newText).map(function (ch) { + return escapeMap[ch] || ch; + }).join(''); + currentParent.childNodes.push(TextNode(newText)); } } diff --git a/lib/patches/process.js b/lib/patches/process.js index 08e9ecbc..7cfdcce2 100644 --- a/lib/patches/process.js +++ b/lib/patches/process.js @@ -29,7 +29,7 @@ export default function process(element, patches) { let textPromises = transition.makePromises('textChanged', [element], null, descriptor.nodeValue); - element.nodeValue = descriptor.nodeValue; + element.innerHTML = descriptor.nodeValue; triggerTransition('textChanged', textPromises, promises => {}); } diff --git a/lib/util/parser.js b/lib/util/parser.js index e146924e..acd44ad8 100644 --- a/lib/util/parser.js +++ b/lib/util/parser.js @@ -5,6 +5,7 @@ import { pools as _pools } from './pools'; var pools = _pools; var parser = makeParser(); +var slice = Array.prototype.slice; /** * parseHTML @@ -13,8 +14,8 @@ var parser = makeParser(); * @return */ export function parseHTML(newHTML, isInner) { - let documentElement = parser.parse(newHTML); - let nodes = documentElement.childNodes; + var documentElement = parser.parse(newHTML); + var nodes = documentElement.childNodes; return isInner ? nodes : nodes[0]; } @@ -25,24 +26,15 @@ export function parseHTML(newHTML, isInner) { * @return */ export function makeParser() { - let kMarkupPattern = + var kMarkupPattern = /)-->|<(\/?)([a-z\-][a-z0-9\-]*)\s*([^>]*?)(\/?)>/ig; - let kAttributePattern = /\b(id|class)\s*(=\s*("([^"]+)"|'([^']+)'|(\S+)))?/ig; + var kAttributePattern = /\b(id|class)\s*(=\s*("([^"]+)"|'([^']+)'|(\S+)))?/ig; - let reAttrPattern = + var reAttrPattern = /\b([a-z][a-z0-9\-]*)\s*(=\s*("([^"]+)"|'([^']+)'|(\S+)))?/ig; - let kBlockElements = { - div: true, - p: true, - li: true, - td: true, - section: true, - br: true - }; - - let kSelfClosingElements = { + var kSelfClosingElements = { meta: true, img: true, link: true, @@ -52,7 +44,7 @@ export function makeParser() { hr: true }; - let kElementsClosedByOpening = { + var kElementsClosedByOpening = { li: { li: true }, @@ -70,7 +62,7 @@ export function makeParser() { } }; - let kElementsClosedByClosing = { + var kElementsClosedByClosing = { li: { ul: true, ol: true }, @@ -108,12 +100,21 @@ export function makeParser() { template: true }; + var escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + '`': '`' + }; + /** * TextNode to contain a text element in DOM tree. * @param {string} value [description] */ function TextNode(value) { - let instance = pools.elementObject.get(); + var instance = pools.elementObject.get(); instance.nodeName = '#text'; instance.nodeValue = value; @@ -135,7 +136,7 @@ export function makeParser() { * @param {Object} rawAttrs attributes in string */ function HTMLElement(name, keyAttrs, rawAttrs) { - let instance = pools.elementObject.get(); + var instance = pools.elementObject.get(); instance.nodeName = name; instance.nodeValue = ''; @@ -163,18 +164,18 @@ export function makeParser() { /** * Parses HTML and returns a root element */ - let htmlParser = { + var htmlParser = { /** * Parse a chuck of HTML source. * @param {string} data html * @return {HTMLElement} root element */ parse: function(data) { - let rootObject = {}; - let root = HTMLElement(null, rootObject); - let currentParent = root; - let stack = [root]; - let lastTextPos = -1; + var rootObject = {}; + var root = HTMLElement(null, rootObject); + var currentParent = root; + var stack = [root]; + var lastTextPos = -1; if (data.indexOf('<') === -1 && data) { currentParent.childNodes[currentParent.childNodes.length] = TextNode(data); @@ -241,6 +242,10 @@ export function makeParser() { let newText = data.slice(match.index + match[0].length, index); if (newText.trim()) { + newText = slice.call(newText).map(ch => { + return escapeMap[ch] || ch; + }).join(''); + currentParent.childNodes.push(TextNode(newText)); } diff --git a/test/integration/inner.js b/test/integration/inner.js index 73317a89..701ca40b 100644 --- a/test/integration/inner.js +++ b/test/integration/inner.js @@ -44,7 +44,7 @@ describe('Integration: innerHTML', function() { describe('Text', function() { it('can decode HTML entities', function() { diff.innerHTML(this.fixture, '
<
'); - assert.equal(this.fixture.innerText, '<'); + assert.equal(this.fixture.innerText, '<'); }); it('can be override existing content', function() { @@ -79,10 +79,10 @@ describe('Integration: innerHTML', function() { assert.equal(this.fixture.firstChild.firstChild, span, 'are the same element'); }); - it('supports html5 entities', function() { + it('supports HTML5 entities', function() { diff.innerHTML(this.fixture, '
'); - assert.equal(this.fixture.firstChild.innerText, '⪥'); + assert.equal(this.fixture.firstChild.innerText, 'тке'); }); }); diff --git a/test/integration/outer.js b/test/integration/outer.js index 20393e65..aa39f1d9 100644 --- a/test/integration/outer.js +++ b/test/integration/outer.js @@ -92,12 +92,6 @@ describe('Integration: outerHTML', function() { assert.equal(this.fixture.firstChild, span, 'are the same element'); }); - it('supports HTML5 entities', function() { - diff.outerHTML(this.fixture, '
'); - - assert.equal(this.fixture.innerText, '⪥'); - }); - it('will properly escape markup being injected into script tags', function() { diff.outerHTML(this.fixture, `