Browse Source

compiler: handle adjacent text nodes, fix interpolation issues in IE

Evan You 10 years ago
parent
commit
bcc104789a
2 changed files with 60 additions and 1 deletions
  1. 29 1
      src/compiler/compile.js
  2. 31 0
      test/unit/specs/compiler/compile_spec.js

+ 29 - 1
src/compiler/compile.js

@@ -325,10 +325,27 @@ function compileElement (el, options) {
  */
 
 function compileTextNode (node, options) {
-  var tokens = textParser.parse(node.data)
+  // skip marked text nodes
+  if (node._skip) {
+    return removeText
+  }
+
+  var tokens = textParser.parse(node.wholeText)
   if (!tokens) {
     return null
   }
+
+  // mark adjacent text nodes as skipped,
+  // because we are using node.wholeText to compile
+  // all adjacent text nodes together. This fixes
+  // issues in IE where sometimes it splits up a single
+  // text node into multiple ones.
+  var next = node.nextSibling
+  while (next && next.nodeType === 3) {
+    next._skip = true
+    next = next.nextSibling
+  }
+
   var frag = document.createDocumentFragment()
   var el, token
   for (var i = 0, l = tokens.length; i < l; i++) {
@@ -341,6 +358,17 @@ function compileTextNode (node, options) {
   return makeTextNodeLinkFn(tokens, frag, options)
 }
 
+/**
+ * Linker for an skipped text node.
+ *
+ * @param {Vue} vm
+ * @param {Text} node
+ */
+
+function removeText (vm, node) {
+  _.remove(node)
+}
+
 /**
  * Process a single text token.
  *

+ 31 - 0
test/unit/specs/compiler/compile_spec.js

@@ -186,6 +186,37 @@ if (_.inBrowser) {
       expect(el.innerHTML).toBe('  and yeah')
     })
 
+    it('text interpolation, adjacent nodes', function () {
+      data.b = 'yeah'
+      el.appendChild(document.createTextNode('{{a'))
+      el.appendChild(document.createTextNode('}} and {{'))
+      el.appendChild(document.createTextNode('*b}}'))
+      var def = Vue.options.directives.text
+      var linker = compile(el, Vue.options)
+      linker(vm, el)
+      // expect 1 call because one-time bindings do not generate a directive.
+      expect(vm._bindDir.calls.count()).toBe(1)
+      var args = vm._bindDir.calls.argsFor(0)
+      expect(args[0].name).toBe('text')
+      expect(args[0].expression).toBe('a')
+      expect(args[0].def).toBe(def)
+      // skip the node because it's generated in the linker fn via cloneNode
+      // expect $eval to be called during onetime
+      expect(vm.$eval).toHaveBeenCalledWith('b')
+      // {{a}} is mocked so it's a space.
+      // but we want to make sure {{*b}} worked.
+      expect(el.innerHTML).toBe('  and yeah')
+    })
+
+    it('adjacent text nodes with no interpolation', function () {
+      el.appendChild(document.createTextNode('a'))
+      el.appendChild(document.createTextNode('b'))
+      el.appendChild(document.createTextNode('c'))
+      var linker = compile(el, Vue.options)
+      linker(vm, el)
+      expect(el.innerHTML).toBe('abc')
+    })
+
     it('inline html', function () {
       data.html = '<div>yoyoyo</div>'
       el.innerHTML = '{{{html}}} {{{*html}}}'