github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/public/libs/vue-1.0.24/src/parsers/template.js (about) 1 import Cache from '../cache' 2 import { 3 inBrowser, 4 trimNode, 5 isTemplate, 6 isFragment 7 } from '../util/index' 8 9 const templateCache = new Cache(1000) 10 const idSelectorCache = new Cache(1000) 11 12 const map = { 13 efault: [0, '', ''], 14 legend: [1, '<fieldset>', '</fieldset>'], 15 tr: [2, '<table><tbody>', '</tbody></table>'], 16 col: [ 17 2, 18 '<table><tbody></tbody><colgroup>', 19 '</colgroup></table>' 20 ] 21 } 22 23 map.td = 24 map.th = [ 25 3, 26 '<table><tbody><tr>', 27 '</tr></tbody></table>' 28 ] 29 30 map.option = 31 map.optgroup = [ 32 1, 33 '<select multiple="multiple">', 34 '</select>' 35 ] 36 37 map.thead = 38 map.tbody = 39 map.colgroup = 40 map.caption = 41 map.tfoot = [1, '<table>', '</table>'] 42 43 map.g = 44 map.defs = 45 map.symbol = 46 map.use = 47 map.image = 48 map.text = 49 map.circle = 50 map.ellipse = 51 map.line = 52 map.path = 53 map.polygon = 54 map.polyline = 55 map.rect = [ 56 1, 57 '<svg ' + 58 'xmlns="http://www.w3.org/2000/svg" ' + 59 'xmlns:xlink="http://www.w3.org/1999/xlink" ' + 60 'xmlns:ev="http://www.w3.org/2001/xml-events"' + 61 'version="1.1">', 62 '</svg>' 63 ] 64 65 /** 66 * Check if a node is a supported template node with a 67 * DocumentFragment content. 68 * 69 * @param {Node} node 70 * @return {Boolean} 71 */ 72 73 function isRealTemplate (node) { 74 return isTemplate(node) && isFragment(node.content) 75 } 76 77 const tagRE = /<([\w:-]+)/ 78 const entityRE = /&#?\w+?;/ 79 80 /** 81 * Convert a string template to a DocumentFragment. 82 * Determines correct wrapping by tag types. Wrapping 83 * strategy found in jQuery & component/domify. 84 * 85 * @param {String} templateString 86 * @param {Boolean} raw 87 * @return {DocumentFragment} 88 */ 89 90 function stringToFragment (templateString, raw) { 91 // try a cache hit first 92 var cacheKey = raw 93 ? templateString 94 : templateString.trim() 95 var hit = templateCache.get(cacheKey) 96 if (hit) { 97 return hit 98 } 99 100 var frag = document.createDocumentFragment() 101 var tagMatch = templateString.match(tagRE) 102 var entityMatch = entityRE.test(templateString) 103 104 if (!tagMatch && !entityMatch) { 105 // text only, return a single text node. 106 frag.appendChild( 107 document.createTextNode(templateString) 108 ) 109 } else { 110 var tag = tagMatch && tagMatch[1] 111 var wrap = map[tag] || map.efault 112 var depth = wrap[0] 113 var prefix = wrap[1] 114 var suffix = wrap[2] 115 var node = document.createElement('div') 116 117 node.innerHTML = prefix + templateString + suffix 118 while (depth--) { 119 node = node.lastChild 120 } 121 122 var child 123 /* eslint-disable no-cond-assign */ 124 while (child = node.firstChild) { 125 /* eslint-enable no-cond-assign */ 126 frag.appendChild(child) 127 } 128 } 129 if (!raw) { 130 trimNode(frag) 131 } 132 templateCache.put(cacheKey, frag) 133 return frag 134 } 135 136 /** 137 * Convert a template node to a DocumentFragment. 138 * 139 * @param {Node} node 140 * @return {DocumentFragment} 141 */ 142 143 function nodeToFragment (node) { 144 // if its a template tag and the browser supports it, 145 // its content is already a document fragment. However, iOS Safari has 146 // bug when using directly cloned template content with touch 147 // events and can cause crashes when the nodes are removed from DOM, so we 148 // have to treat template elements as string templates. (#2805) 149 /* istanbul ignore if */ 150 if (isRealTemplate(node)) { 151 return stringToFragment(node.innerHTML) 152 } 153 // script template 154 if (node.tagName === 'SCRIPT') { 155 return stringToFragment(node.textContent) 156 } 157 // normal node, clone it to avoid mutating the original 158 var clonedNode = cloneNode(node) 159 var frag = document.createDocumentFragment() 160 var child 161 /* eslint-disable no-cond-assign */ 162 while (child = clonedNode.firstChild) { 163 /* eslint-enable no-cond-assign */ 164 frag.appendChild(child) 165 } 166 trimNode(frag) 167 return frag 168 } 169 170 // Test for the presence of the Safari template cloning bug 171 // https://bugs.webkit.org/showug.cgi?id=137755 172 var hasBrokenTemplate = (function () { 173 /* istanbul ignore else */ 174 if (inBrowser) { 175 var a = document.createElement('div') 176 a.innerHTML = '<template>1</template>' 177 return !a.cloneNode(true).firstChild.innerHTML 178 } else { 179 return false 180 } 181 })() 182 183 // Test for IE10/11 textarea placeholder clone bug 184 var hasTextareaCloneBug = (function () { 185 /* istanbul ignore else */ 186 if (inBrowser) { 187 var t = document.createElement('textarea') 188 t.placeholder = 't' 189 return t.cloneNode(true).value === 't' 190 } else { 191 return false 192 } 193 })() 194 195 /** 196 * 1. Deal with Safari cloning nested <template> bug by 197 * manually cloning all template instances. 198 * 2. Deal with IE10/11 textarea placeholder bug by setting 199 * the correct value after cloning. 200 * 201 * @param {Element|DocumentFragment} node 202 * @return {Element|DocumentFragment} 203 */ 204 205 export function cloneNode (node) { 206 /* istanbul ignore if */ 207 if (!node.querySelectorAll) { 208 return node.cloneNode() 209 } 210 var res = node.cloneNode(true) 211 var i, original, cloned 212 /* istanbul ignore if */ 213 if (hasBrokenTemplate) { 214 var tempClone = res 215 if (isRealTemplate(node)) { 216 node = node.content 217 tempClone = res.content 218 } 219 original = node.querySelectorAll('template') 220 if (original.length) { 221 cloned = tempClone.querySelectorAll('template') 222 i = cloned.length 223 while (i--) { 224 cloned[i].parentNode.replaceChild( 225 cloneNode(original[i]), 226 cloned[i] 227 ) 228 } 229 } 230 } 231 /* istanbul ignore if */ 232 if (hasTextareaCloneBug) { 233 if (node.tagName === 'TEXTAREA') { 234 res.value = node.value 235 } else { 236 original = node.querySelectorAll('textarea') 237 if (original.length) { 238 cloned = res.querySelectorAll('textarea') 239 i = cloned.length 240 while (i--) { 241 cloned[i].value = original[i].value 242 } 243 } 244 } 245 } 246 return res 247 } 248 249 /** 250 * Process the template option and normalizes it into a 251 * a DocumentFragment that can be used as a partial or a 252 * instance template. 253 * 254 * @param {*} template 255 * Possible values include: 256 * - DocumentFragment object 257 * - Node object of type Template 258 * - id selector: '#some-template-id' 259 * - template string: '<div><span>{{msg}}</span></div>' 260 * @param {Boolean} shouldClone 261 * @param {Boolean} raw 262 * inline HTML interpolation. Do not check for id 263 * selector and keep whitespace in the string. 264 * @return {DocumentFragment|undefined} 265 */ 266 267 export function parseTemplate (template, shouldClone, raw) { 268 var node, frag 269 270 // if the template is already a document fragment, 271 // do nothing 272 if (isFragment(template)) { 273 trimNode(template) 274 return shouldClone 275 ? cloneNode(template) 276 : template 277 } 278 279 if (typeof template === 'string') { 280 // id selector 281 if (!raw && template.charAt(0) === '#') { 282 // id selector can be cached too 283 frag = idSelectorCache.get(template) 284 if (!frag) { 285 node = document.getElementById(template.slice(1)) 286 if (node) { 287 frag = nodeToFragment(node) 288 // save selector to cache 289 idSelectorCache.put(template, frag) 290 } 291 } 292 } else { 293 // normal string template 294 frag = stringToFragment(template, raw) 295 } 296 } else if (template.nodeType) { 297 // a direct node 298 frag = nodeToFragment(template) 299 } 300 301 return frag && shouldClone 302 ? cloneNode(frag) 303 : frag 304 }