Ver código fonte

fix #484 Safari nested <template> clone fail

Evan You 11 anos atrás
pai
commit
da385adbb2
5 arquivos alterados com 43 adições e 4 exclusões
  1. 1 1
      gruntfile.js
  2. 1 0
      package.json
  3. 2 1
      src/directives/component.js
  4. 1 1
      src/directives/repeat.js
  5. 38 1
      src/parse/template.js

+ 1 - 1
gruntfile.js

@@ -51,7 +51,7 @@ module.exports = function (grunt) {
       },
       browsers: {
         options: {
-          browsers: ['Chrome', 'Firefox'],
+          browsers: ['Chrome', 'Firefox', 'Safari'],
           reporters: ['progress']
         }
       },

+ 1 - 0
package.json

@@ -33,6 +33,7 @@
     "karma-firefox-launcher": "^0.1.3",
     "karma-jasmine": "^0.2.2",
     "karma-phantomjs-launcher": "^0.1.4",
+    "karma-safari-launcher": "^0.1.1",
     "karma-sauce-launcher": "^0.2.10",
     "semver": "^4.0.3",
     "shell-task": "^1.0.0",

+ 2 - 1
src/directives/component.js

@@ -1,5 +1,6 @@
 var _ = require('../util')
 var Watcher = require('../watcher')
+var templateParser = require('../parse/template')
 
 module.exports = {
 
@@ -131,7 +132,7 @@ module.exports = {
     }
     if (this.Ctor && !this.childVM) {
       this.childVM = this.vm.$addChild({
-        el: this.el.cloneNode(true)
+        el: templateParser.clone(this.el)
       }, this.Ctor)
       if (this.keepAlive) {
         this.cache[this.ctorId] = this.childVM

+ 1 - 1
src/directives/repeat.js

@@ -280,7 +280,7 @@ module.exports = {
     // resolve constructor
     var Ctor = this.Ctor || this.resolveCtor(data, meta)
     var vm = this.vm.$addChild({
-      el: this.template.cloneNode(true),
+      el: templateParser.clone(this.template),
       _linker: this._linker,
       _meta: meta,
       data: data,

+ 38 - 1
src/parse/template.js

@@ -1,6 +1,17 @@
 var Cache = require('../cache')
 var templateCache = new Cache(100)
 
+/**
+ * Test for the presence of the Safari template cloning bug
+ * https://bugs.webkit.org/show_bug.cgi?id=137755
+ */
+
+var hasBrokenTemplate = (function () {
+  var a = document.createElement('div')
+  a.innerHTML = '<template>1</template>'
+  return !a.cloneNode(true).firstChild.innerHTML
+})()
+
 var map = {
   _default : [0, '', ''],
   legend   : [1, '<fieldset>', '</fieldset>'],
@@ -127,6 +138,32 @@ function nodeToFragment (node) {
     : stringToFragment(node.innerHTML)
 }
 
+/**
+ * Deal with Safari cloning nested <template> bug by
+ * manually cloning all template instances.
+ *
+ * @param {Element|DocumentFragment} node
+ * @return {Element|DocumentFragment}
+ */
+
+exports.clone = function (node) {
+  var res = node.cloneNode(true)
+  if (hasBrokenTemplate) {
+    var templates = node.querySelectorAll('template')
+    if (templates.length) {
+      var cloned = res.querySelectorAll('template')
+      var i = cloned.length
+      while (i--) {
+        cloned[i].parentNode.replaceChild(
+          templates[i].cloneNode(true),
+          cloned[i]
+        )
+      }
+    }
+  }
+  return res
+}
+
 /**
  * Process the template option and normalizes it into a
  * a DocumentFragment that can be used as a partial or a
@@ -176,6 +213,6 @@ exports.parse = function (template, clone) {
   }
 
   return frag && clone
-    ? frag.cloneNode(true)
+    ? exports.clone(frag)
     : frag
 }