Răsfoiți Sursa

Fix inline partial parentNode problem

Directives inside inline partials would get the fragment as the parentNode
if they are compiled before the partial is appended to the correct parentNode.
Therefore keep the reference of the fragment's childNodes, append it,
then compile afterwards fixes the problem.
Evan You 12 ani în urmă
părinte
comite
5f21eed2c9
3 a modificat fișierele cu 42 adăugiri și 9 ștergeri
  1. 22 5
      src/compiler.js
  2. 18 3
      test/functional/fixtures/template.html
  3. 2 1
      test/functional/specs/template.js

+ 22 - 5
src/compiler.js

@@ -343,20 +343,24 @@ CompilerProto.compileNode = function (node) {
  *  Compile a text node
  *  Compile a text node
  */
  */
 CompilerProto.compileTextNode = function (node) {
 CompilerProto.compileTextNode = function (node) {
+
     var tokens = TextParser.parse(node.nodeValue)
     var tokens = TextParser.parse(node.nodeValue)
     if (!tokens) return
     if (!tokens) return
-    var el, token, directive
+    var el, token, directive, partial, partialId, partialNodes
+
     for (var i = 0, l = tokens.length; i < l; i++) {
     for (var i = 0, l = tokens.length; i < l; i++) {
         token = tokens[i]
         token = tokens[i]
         if (token.key) { // a binding
         if (token.key) { // a binding
             if (token.key.charAt(0) === '>') { // a partial
             if (token.key.charAt(0) === '>') { // a partial
-                var partialId = token.key.slice(1).trim(),
-                    partial = this.getOption('partials', partialId)
+                partialId = token.key.slice(1).trim()
+                partial = this.getOption('partials', partialId)
                 if (partial) {
                 if (partial) {
                     el = partial.cloneNode(true)
                     el = partial.cloneNode(true)
-                    this.compileNode(el)
+                    // save an Array reference of the partial's nodes
+                    // so we can compile them AFTER appending the fragment
+                    partialNodes = slice.call(el.childNodes)
                 }
                 }
-            } else { // a binding
+            } else { // a real binding
                 el = document.createTextNode('')
                 el = document.createTextNode('')
                 directive = Directive.parse('text', token.key, this, el)
                 directive = Directive.parse('text', token.key, this, el)
                 if (directive) {
                 if (directive) {
@@ -366,7 +370,20 @@ CompilerProto.compileTextNode = function (node) {
         } else { // a plain string
         } else { // a plain string
             el = document.createTextNode(token)
             el = document.createTextNode(token)
         }
         }
+
+        // insert node
         node.parentNode.insertBefore(el, node)
         node.parentNode.insertBefore(el, node)
+
+        // compile partial after appending, because its children's parentNode
+        // will change from the fragment to the correct parentNode.
+        // This could affect directives that need access to its element's parentNode.
+        if (partialNodes) {
+            for (var j = 0, k = partialNodes.length; j < k; j++) {
+                this.compile(partialNodes[j])
+            }
+            partialNodes = null
+        }
+
     }
     }
     node.parentNode.removeChild(node)
     node.parentNode.removeChild(node)
 }
 }

+ 18 - 3
test/functional/fixtures/template.html

@@ -8,15 +8,20 @@
     <body>
     <body>
 
 
         <div id="usa" v-partial="global"></div>
         <div id="usa" v-partial="global"></div>
-        <div id="japan" v-partial="local"></div>
+        <div id="japan">{{> local}}</div>
+        <div id="repeat">{{> repeat}}</div>
 
 
         <script type="text/v-template" id="test">
         <script type="text/v-template" id="test">
             <p>{{hi}}!</p>
             <p>{{hi}}!</p>
         </script>
         </script>
 
 
+        <script type="text/v-template" id="repeat-template">
+            <p v-repeat="items">{{title}}</p>
+        </script>
+
         <script>
         <script>
 
 
-            Vue.config({debug:true})
+           // Vue.config({debug:true})
 
 
             // direct usage
             // direct usage
             var china  = new Vue({
             var china  = new Vue({
@@ -48,10 +53,20 @@
             var japan = new Vue({
             var japan = new Vue({
                 el: '#japan',
                 el: '#japan',
                 partials: {
                 partials: {
-                    local: document.querySelector('#test').innerHTML
+                    local: '#test'
                 }
                 }
             })
             })
             japan.hi = 'こんにちは'
             japan.hi = 'こんにちは'
+
+            var repeat = new Vue({
+                el: '#repeat',
+                partials: {
+                    repeat: '#repeat-template'
+                },
+                data: {
+                    items: [{ title: 'Repeat' }]
+                }
+            })
         </script>
         </script>
     </body>
     </body>
 </html>
 </html>

+ 2 - 1
test/functional/specs/template.js

@@ -1,4 +1,4 @@
-casper.test.begin('Template', 4, function (test) {
+casper.test.begin('Templates and Partials', 5, function (test) {
     
     
     casper
     casper
     .start('./fixtures/template.html')
     .start('./fixtures/template.html')
@@ -7,6 +7,7 @@ casper.test.begin('Template', 4, function (test) {
         test.assertSelectorHasText('#japan', 'こんにちは', 'local partial')
         test.assertSelectorHasText('#japan', 'こんにちは', 'local partial')
         test.assertSelectorHasText('#china', '你好', 'direct option')
         test.assertSelectorHasText('#china', '你好', 'direct option')
         test.assertSelectorHasText('#hawaii', 'Aloha', 'extend option')
         test.assertSelectorHasText('#hawaii', 'Aloha', 'extend option')
+        test.assertSelectorHasText('#repeat', 'Repeat', 'inline partial with repeat')
     })
     })
     .run(function () {
     .run(function () {
         test.done()
         test.done()