Skip to content

Commit bcc1047

Browse files
committed
compiler: handle adjacent text nodes, fix interpolation issues in IE
1 parent 371850b commit bcc1047

File tree

2 files changed

+60
-1
lines changed

2 files changed

+60
-1
lines changed

src/compiler/compile.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,27 @@ function compileElement (el, options) {
325325
*/
326326

327327
function compileTextNode (node, options) {
328-
var tokens = textParser.parse(node.data)
328+
// skip marked text nodes
329+
if (node._skip) {
330+
return removeText
331+
}
332+
333+
var tokens = textParser.parse(node.wholeText)
329334
if (!tokens) {
330335
return null
331336
}
337+
338+
// mark adjacent text nodes as skipped,
339+
// because we are using node.wholeText to compile
340+
// all adjacent text nodes together. This fixes
341+
// issues in IE where sometimes it splits up a single
342+
// text node into multiple ones.
343+
var next = node.nextSibling
344+
while (next && next.nodeType === 3) {
345+
next._skip = true
346+
next = next.nextSibling
347+
}
348+
332349
var frag = document.createDocumentFragment()
333350
var el, token
334351
for (var i = 0, l = tokens.length; i < l; i++) {
@@ -341,6 +358,17 @@ function compileTextNode (node, options) {
341358
return makeTextNodeLinkFn(tokens, frag, options)
342359
}
343360

361+
/**
362+
* Linker for an skipped text node.
363+
*
364+
* @param {Vue} vm
365+
* @param {Text} node
366+
*/
367+
368+
function removeText (vm, node) {
369+
_.remove(node)
370+
}
371+
344372
/**
345373
* Process a single text token.
346374
*

test/unit/specs/compiler/compile_spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,37 @@ if (_.inBrowser) {
186186
expect(el.innerHTML).toBe(' and yeah')
187187
})
188188

189+
it('text interpolation, adjacent nodes', function () {
190+
data.b = 'yeah'
191+
el.appendChild(document.createTextNode('{{a'))
192+
el.appendChild(document.createTextNode('}} and {{'))
193+
el.appendChild(document.createTextNode('*b}}'))
194+
var def = Vue.options.directives.text
195+
var linker = compile(el, Vue.options)
196+
linker(vm, el)
197+
// expect 1 call because one-time bindings do not generate a directive.
198+
expect(vm._bindDir.calls.count()).toBe(1)
199+
var args = vm._bindDir.calls.argsFor(0)
200+
expect(args[0].name).toBe('text')
201+
expect(args[0].expression).toBe('a')
202+
expect(args[0].def).toBe(def)
203+
// skip the node because it's generated in the linker fn via cloneNode
204+
// expect $eval to be called during onetime
205+
expect(vm.$eval).toHaveBeenCalledWith('b')
206+
// {{a}} is mocked so it's a space.
207+
// but we want to make sure {{*b}} worked.
208+
expect(el.innerHTML).toBe(' and yeah')
209+
})
210+
211+
it('adjacent text nodes with no interpolation', function () {
212+
el.appendChild(document.createTextNode('a'))
213+
el.appendChild(document.createTextNode('b'))
214+
el.appendChild(document.createTextNode('c'))
215+
var linker = compile(el, Vue.options)
216+
linker(vm, el)
217+
expect(el.innerHTML).toBe('abc')
218+
})
219+
189220
it('inline html', function () {
190221
data.html = '<div>yoyoyo</div>'
191222
el.innerHTML = '{{{html}}} {{{*html}}}'

0 commit comments

Comments
 (0)