can-util
Version:
Common utilities for CanJS projects
80 lines (73 loc) • 3.07 kB
JavaScript
var getDocument = require('can-globals/document/document');
var childNodes = require("../child-nodes/child-nodes");
var namespace = require("can-namespace");
// fragment.js
// ---------
// _DOM Fragment support._
var fragmentRE = /^\s*<(\w+)[^>]*>/,
toString = {}.toString,
fragment = function (html, name, doc) {
if (name === undefined) {
name = fragmentRE.test(html) && RegExp.$1;
}
if (html && toString.call(html.replace) === "[object Function]") {
// Fix "XHTML"-style tags in all browsers
html = html.replace(/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, '<$1></$2>');
}
var container = doc.createElement('div'),
temp = doc.createElement('div');
// IE's parser will strip any `<tr><td>` tags when `innerHTML`
// is called on a `tbody`. To get around this, we construct a
// valid table with a `tbody` that has the `innerHTML` we want.
// Then the container is the `firstChild` of the `tbody`.
// [source](http://www.ericvasilik.com/2006/07/code-karma.html).
if (name === 'tbody' || name === 'tfoot' || name === 'thead' || name === 'colgroup') {
temp.innerHTML = '<table>' + html + '</table>';
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild;
} else if (name === 'col') {
temp.innerHTML = '<table><colgroup>' + html + '</colgroup></table>';
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild.firstChild;
} else if (name === 'tr') {
temp.innerHTML = '<table><tbody>' + html + '</tbody></table>';
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild.firstChild;
} else if (name === 'td' || name === 'th') {
temp.innerHTML = '<table><tbody><tr>' + html + '</tr></tbody></table>';
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild.firstChild.firstChild;
} else if (name === 'option') {
temp.innerHTML = '<select>' + html + '</select>';
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild;
} else {
container.innerHTML = '' + html;
}
// IE8 barfs if you pass slice a `childNodes` object, so make a copy.
var tmp = {},
children = childNodes( container );
tmp.length = children.length;
for (var i = 0; i < children.length; i++) {
tmp[i] = children[i];
}
return [].slice.call(tmp);
};
var buildFragment = function (html, doc) {
if(html && html.nodeType === 11) {
return html;
}
if(!doc) {
doc = getDocument();
} else if(doc.length) {
doc = doc[0];
}
var parts = fragment(html, undefined, doc),
frag = (doc || document).createDocumentFragment();
for(var i = 0, length = parts.length; i < length; i++) {
frag.appendChild(parts[i]);
}
return frag;
};
// ## Fix build fragment.
// In IE8, we can pass a fragment and it removes newlines.
// This checks for that and replaces can.buildFragment with something
// that if only a single text node is returned, returns a fragment with
// a text node that is set to the content.
module.exports = namespace.fragment = buildFragment;
;