var Cache = require('../cache') var templateCache = new Cache(100) 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, '', '' ] var TAG_RE = /<([\w:]+)/ /** * 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 = TAG_RE.exec(templateString) if (!tagMatch) { // text only, return a single text node. frag.appendChild( document.createTextNode(templateString) ) } else { var tag = 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 /* jshint boss:true */ while (child = node.firstChild) { frag.appendChild(child) } } templateCache.put(templateString, frag) return frag } /** * Convert a template node to a DocumentFragment. * * @param {Node} node * @return {DocumentFragment} */ function nodeToFragment (node) { var tag = node.tagName // if its a template tag and the browser supports it, // its content is already a document fragment. if ( tag === 'TEMPLATE' && node.content instanceof DocumentFragment ) { return node.content } return tag === 'SCRIPT' ? stringToFragment(node.textContent) : stringToFragment(node.innerHTML) } /** * Process the template option and normalizes it into a * a DocumentFragment that can be used as a partial or a * instance template. * * @param {*} template * Possible values include: * - DocumentFragment object * - Node object of type Template * - id selector: '#some-template-id' * - template string: '
{{msg}}
' * @param {Boolean} clone * @return {DocumentFragment|undefined} */ exports.parse = function (template, clone) { var node, frag // if the template is already a document fragment, // do nothing if (template instanceof DocumentFragment) { return clone ? template.cloneNode(true) : template } if (typeof template === 'string') { // id selector if (template.charAt(0) === '#') { // id selector can be cached too frag = templateCache.get(template) if (!frag) { node = document.getElementById(template.slice(1)) if (node) { frag = nodeToFragment(node) // save selector to cache templateCache.put(template, frag) } } } else { // normal string template frag = stringToFragment(template) } } else if (template.nodeType) { // a direct node frag = nodeToFragment(template) } return frag && clone ? frag.cloneNode(true) : frag }