From 91903cb92721f52abce5d238396869ac7842afaa Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Mon, 5 Dec 2016 14:55:05 +0100 Subject: [PATCH] add codegen support for raw mustache tags --- compiler/generate/visitors/RawMustacheTag.js | 47 ++++++++++++++++++++ compiler/generate/visitors/index.js | 2 + test/compiler/raw-mustaches/_config.js | 16 +++++++ test/compiler/raw-mustaches/main.html | 1 + 4 files changed, 66 insertions(+) create mode 100644 compiler/generate/visitors/RawMustacheTag.js create mode 100644 test/compiler/raw-mustaches/_config.js create mode 100644 test/compiler/raw-mustaches/main.html diff --git a/compiler/generate/visitors/RawMustacheTag.js b/compiler/generate/visitors/RawMustacheTag.js new file mode 100644 index 0000000000..1b0b39e302 --- /dev/null +++ b/compiler/generate/visitors/RawMustacheTag.js @@ -0,0 +1,47 @@ +import deindent from '../utils/deindent.js'; + +export default { + enter ( generator, node ) { + const name = generator.current.counter( 'raw' ); + + generator.addSourcemapLocations( node.expression ); + const { snippet } = generator.contextualise( node.expression ); + + // we would have used comments here, but the `insertAdjacentHTML` api only + // exists for `Element`s. + const before = `${name}_before`; + generator.addElement( before, `document.createElement( 'noscript' )`, true ); + const after = `${name}_after`; + generator.addElement( after, `document.createElement( 'noscript' )`, true ); + + const isToplevel = generator.current.localElementDepth === 0; + + const mountStatement = deindent` + ${before}.insertAdjacentHTML( 'afterend', ${snippet} ); + `; + const detachStatement = deindent` + while ( ${before}.nextSibling && ${before}.nextSibling !== ${after} ) { + ${before}.parentNode.removeChild( ${before}.nextSibling ); + } + `; + + if ( isToplevel ) { + generator.current.mountStatements.push(mountStatement); + } else { + generator.current.initStatements.push(mountStatement); + } + + generator.current.updateStatements.push( deindent` + ${detachStatement} + ${mountStatement} + ` ); + + if ( isToplevel ) { + const { detachStatements } = generator.current; + // we need `before` and `after` to still be in the DOM when running the + // detach code, so splice in the detach code *before* detaching + // `before`/`after`. + detachStatements.splice( detachStatements.length - 2, 0, detachStatement); + } + } +}; diff --git a/compiler/generate/visitors/index.js b/compiler/generate/visitors/index.js index 70ba9e3298..8e125e5d8b 100644 --- a/compiler/generate/visitors/index.js +++ b/compiler/generate/visitors/index.js @@ -3,6 +3,7 @@ import EachBlock from './EachBlock.js'; import Element from './Element.js'; import IfBlock from './IfBlock.js'; import MustacheTag from './MustacheTag.js'; +import RawMustacheTag from './RawMustacheTag.js'; import Text from './Text.js'; import YieldTag from './YieldTag.js'; @@ -12,6 +13,7 @@ export default { Element, IfBlock, MustacheTag, + RawMustacheTag, Text, YieldTag }; diff --git a/test/compiler/raw-mustaches/_config.js b/test/compiler/raw-mustaches/_config.js new file mode 100644 index 0000000000..850a169e02 --- /dev/null +++ b/test/compiler/raw-mustaches/_config.js @@ -0,0 +1,16 @@ +const ns = ''; +export default { + data: { + raw: 'raw html!!!\\o/' + }, + html: `before${ns}raw html!!!\\o/${ns}after`, + + test ( assert, component, target ) { + component.set({ raw: '' }); + assert.equal( target.innerHTML, `before${ns}${ns}after` ); + component.set({ raw: 'how about unclosed elements?' }); + assert.equal( target.innerHTML, `before${ns}how about unclosed elements?${ns}after` ); + component.teardown(); + assert.equal( target.innerHTML, '' ); + } +}; diff --git a/test/compiler/raw-mustaches/main.html b/test/compiler/raw-mustaches/main.html new file mode 100644 index 0000000000..1a733843df --- /dev/null +++ b/test/compiler/raw-mustaches/main.html @@ -0,0 +1 @@ +before{{{raw}}}after