|
|
@@ -0,0 +1,157 @@
|
|
|
+var Cache = require('../cache')
|
|
|
+var templateCache = new Cache(100)
|
|
|
+
|
|
|
+var map = {
|
|
|
+ legend : [1, '<fieldset>', '</fieldset>'],
|
|
|
+ tr : [2, '<table><tbody>', '</tbody></table>'],
|
|
|
+ col : [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
|
|
|
+ _default : [0, '', '']
|
|
|
+}
|
|
|
+
|
|
|
+map.td =
|
|
|
+map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>']
|
|
|
+
|
|
|
+map.option =
|
|
|
+map.optgroup = [1, '<select multiple="multiple">', '</select>']
|
|
|
+
|
|
|
+map.thead =
|
|
|
+map.tbody =
|
|
|
+map.colgroup =
|
|
|
+map.caption =
|
|
|
+map.tfoot = [1, '<table>', '</table>']
|
|
|
+
|
|
|
+map.text =
|
|
|
+map.circle =
|
|
|
+map.ellipse =
|
|
|
+map.line =
|
|
|
+map.path =
|
|
|
+map.polygon =
|
|
|
+map.polyline =
|
|
|
+map.rect = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>']
|
|
|
+
|
|
|
+var TAG_RE = /<([\w:]+)/
|
|
|
+
|
|
|
+/**
|
|
|
+ * Convert a string template to a DocumentFragment.
|
|
|
+ * Determines correct wrapping by tag types. Wrapping strategy
|
|
|
+ * originally from jQuery, scooped from 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
|
|
|
+ }
|
|
|
+
|
|
|
+ if (node.firstChild === node.lastChild) {
|
|
|
+ // one element
|
|
|
+ frag.appendChild(node.firstChild)
|
|
|
+ templateCache.put(templateString, frag)
|
|
|
+ return frag
|
|
|
+ } else {
|
|
|
+ // multiple nodes, return a fragment
|
|
|
+ /* jshint boss: true */
|
|
|
+ var child
|
|
|
+ while (child = node.firstChild) {
|
|
|
+ if (node.nodeType === 1) {
|
|
|
+ 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) {
|
|
|
+ return node.content
|
|
|
+ }
|
|
|
+ // script tag
|
|
|
+ if (tag === 'SCRIPT') {
|
|
|
+ return stringToFragment(node.textContent)
|
|
|
+ }
|
|
|
+ // non-script node. not recommended...
|
|
|
+ return toFragment(node.outerHTML)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 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: '<div><span>my template</span></div>'
|
|
|
+ * @return {DocumentFragment|undefined}
|
|
|
+ */
|
|
|
+
|
|
|
+exports.parse = function (template) {
|
|
|
+ var node, frag
|
|
|
+
|
|
|
+ // if the template is already a document fragment -- do nothing
|
|
|
+ if (template instanceof DocumentFragment) {
|
|
|
+ return 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
|
|
|
+}
|