var _ = require('../util') var Cache = require('../cache') var templateCache = new Cache(1000) var idSelectorCache = new Cache(1000) var map = { _default: [0, '', ''], legend: [1, '
', '
'], tr: [2, '', '
'], col: [ 2, '', '
' ] } map.td = map.th = [ 3, '', '
' ] map.option = map.optgroup = [ 1, '' ] map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '', '
'] map.g = map.defs = map.symbol = map.use = map.image = map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [ 1, '', '' ] /** * Check if a node is a supported template node with a * DocumentFragment content. * * @param {Node} node * @return {Boolean} */ function isRealTemplate (node) { return _.isTemplate(node) && node.content instanceof DocumentFragment } var tagRE = /<([\w:]+)/ var entityRE = /&\w+;|&#\d+;|&#x[\dA-F]+;/ /** * Convert a string template to a DocumentFragment. * Determines correct wrapping by tag types. Wrapping * strategy found in jQuery & component/domify. * * @param {String} templateString * @return {DocumentFragment} */ function stringToFragment (templateString) { // try a cache hit first var hit = templateCache.get(templateString) if (hit) { return hit } var frag = document.createDocumentFragment() var tagMatch = templateString.match(tagRE) var entityMatch = entityRE.test(templateString) if (!tagMatch && !entityMatch) { // text only, return a single text node. frag.appendChild( document.createTextNode(templateString) ) } else { var tag = tagMatch && tagMatch[1] var wrap = map[tag] || map._default var depth = wrap[0] var prefix = wrap[1] var suffix = wrap[2] var node = document.createElement('div') node.innerHTML = prefix + templateString.trim() + suffix while (depth--) { node = node.lastChild } var child /* eslint-disable no-cond-assign */ while (child = node.firstChild) { /* eslint-enable no-cond-assign */ frag.appendChild(child) } } templateCache.put(templateString, frag) return frag } /** * Convert a template node to a DocumentFragment. * * @param {Node} node * @return {DocumentFragment} */ function nodeToFragment (node) { // if its a template tag and the browser supports it, // its content is already a document fragment. if (isRealTemplate(node)) { _.trimNode(node.content) return node.content } // script template if (node.tagName === 'SCRIPT') { return stringToFragment(node.textContent) } // normal node, clone it to avoid mutating the original var clone = exports.clone(node) var frag = document.createDocumentFragment() var child /* eslint-disable no-cond-assign */ while (child = clone.firstChild) { /* eslint-enable no-cond-assign */ frag.appendChild(child) } _.trimNode(frag) return frag } // Test for the presence of the Safari template cloning bug // https://bugs.webkit.org/show_bug.cgi?id=137755 var hasBrokenTemplate = (function () { /* istanbul ignore else */ if (_.inBrowser) { var a = document.createElement('div') a.innerHTML = '' return !a.cloneNode(true).firstChild.innerHTML } else { return false } })() // Test for IE10/11 textarea placeholder clone bug var hasTextareaCloneBug = (function () { /* istanbul ignore else */ if (_.inBrowser) { var t = document.createElement('textarea') t.placeholder = 't' return t.cloneNode(true).value === 't' } else { return false } })() /** * 1. Deal with Safari cloning nested