forked from knockout/knockout
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.domManipulation.js
88 lines (72 loc) · 4.47 KB
/
utils.domManipulation.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
(function () {
var leadingCommentRegex = /^(\s*)<!--(.*?)-->/;
function simpleHtmlParse(html) {
// Based on jQuery's "clean" function, but only accounting for table-related elements.
// If you have referenced jQuery, this won't be used anyway - KO will use jQuery's "clean" function directly
// Note that there's still an issue in IE < 9 whereby it will discard comment nodes that are the first child of
// a descendant node. For example: "<div><!-- mycomment -->abc</div>" will get parsed as "<div>abc</div>"
// This won't affect anyone who has referenced jQuery, and there's always the workaround of inserting a dummy node
// (possibly a text node) in front of the comment. So, KO does not attempt to workaround this IE issue automatically at present.
// Trim whitespace, otherwise indexOf won't work as expected
var tags = ko.utils.stringTrim(html).toLowerCase(), div = document.createElement("div");
// Finds the first match from the left column, and returns the corresponding "wrap" data from the right column
var wrap = tags.match(/^<(thead|tbody|tfoot)/) && [1, "<table>", "</table>"] ||
!tags.indexOf("<tr") && [2, "<table><tbody>", "</tbody></table>"] ||
(!tags.indexOf("<td") || !tags.indexOf("<th")) && [3, "<table><tbody><tr>", "</tr></tbody></table>"] ||
/* anything else */ [0, "", ""];
// Go to html and back, then peel off extra wrappers
// Note that we always prefix with some dummy text, because otherwise, IE<9 will strip out leading comment nodes in descendants. Total madness.
var markup = "ignored<div>" + wrap[1] + html + wrap[2] + "</div>";
if (typeof window['innerShiv'] == "function") {
div.appendChild(window['innerShiv'](markup));
} else {
div.innerHTML = markup;
}
// Move to the right depth
while (wrap[0]--)
div = div.lastChild;
return ko.utils.makeArray(div.lastChild.childNodes);
}
function jQueryHtmlParse(html) {
var elems = jQuery['clean']([html]);
// As of jQuery 1.7.1, jQuery parses the HTML by appending it to some dummy parent nodes held in an in-memory document fragment.
// Unfortunately, it never clears the dummy parent nodes from the document fragment, so it leaks memory over time.
// Fix this by finding the top-most dummy parent element, and detaching it from its owner fragment.
if (elems && elems[0]) {
// Find the top-most parent element that's a direct child of a document fragment
var elem = elems[0];
while (elem.parentNode && elem.parentNode.nodeType !== 11 /* i.e., DocumentFragment */)
elem = elem.parentNode;
// ... then detach it
if (elem.parentNode)
elem.parentNode.removeChild(elem);
}
return elems;
}
ko.utils.parseHtmlFragment = function(html) {
return typeof jQuery != 'undefined' ? jQueryHtmlParse(html) // As below, benefit from jQuery's optimisations where possible
: simpleHtmlParse(html); // ... otherwise, this simple logic will do in most common cases.
};
ko.utils.setHtml = function(node, html) {
ko.utils.emptyDomNode(node);
// There's no legitimate reason to display a stringified observable without unwrapping it, so we'll unwrap it
html = ko.utils.unwrapObservable(html);
if ((html !== null) && (html !== undefined)) {
if (typeof html != 'string')
html = html.toString();
// jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
// for example <tr> elements which are not normally allowed to exist on their own.
// If you've referenced jQuery we'll use that rather than duplicating its code.
if (typeof jQuery != 'undefined') {
jQuery(node)['html'](html);
} else {
// ... otherwise, use KO's own parsing logic.
var parsedNodes = ko.utils.parseHtmlFragment(html);
for (var i = 0; i < parsedNodes.length; i++)
node.appendChild(parsedNodes[i]);
}
}
};
})();
ko.exportSymbol('utils.parseHtmlFragment', ko.utils.parseHtmlFragment);
ko.exportSymbol('utils.setHtml', ko.utils.setHtml);