UNPKG

3.59 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2015-present, Facebook, Inc.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 */
8
9'use strict';
10
11var DOMNamespaces = require('./DOMNamespaces');
12var setInnerHTML = require('./setInnerHTML');
13
14var createMicrosoftUnsafeLocalFunction = require('./createMicrosoftUnsafeLocalFunction');
15var setTextContent = require('./setTextContent');
16
17var ELEMENT_NODE_TYPE = 1;
18var DOCUMENT_FRAGMENT_NODE_TYPE = 11;
19
20/**
21 * In IE (8-11) and Edge, appending nodes with no children is dramatically
22 * faster than appending a full subtree, so we essentially queue up the
23 * .appendChild calls here and apply them so each node is added to its parent
24 * before any children are added.
25 *
26 * In other browsers, doing so is slower or neutral compared to the other order
27 * (in Firefox, twice as slow) so we only do this inversion in IE.
28 *
29 * See https://github.com/spicyj/innerhtml-vs-createelement-vs-clonenode.
30 */
31var enableLazy = typeof document !== 'undefined' && typeof document.documentMode === 'number' || typeof navigator !== 'undefined' && typeof navigator.userAgent === 'string' && /\bEdge\/\d/.test(navigator.userAgent);
32
33function insertTreeChildren(tree) {
34 if (!enableLazy) {
35 return;
36 }
37 var node = tree.node;
38 var children = tree.children;
39 if (children.length) {
40 for (var i = 0; i < children.length; i++) {
41 insertTreeBefore(node, children[i], null);
42 }
43 } else if (tree.html != null) {
44 setInnerHTML(node, tree.html);
45 } else if (tree.text != null) {
46 setTextContent(node, tree.text);
47 }
48}
49
50var insertTreeBefore = createMicrosoftUnsafeLocalFunction(function (parentNode, tree, referenceNode) {
51 // DocumentFragments aren't actually part of the DOM after insertion so
52 // appending children won't update the DOM. We need to ensure the fragment
53 // is properly populated first, breaking out of our lazy approach for just
54 // this level. Also, some <object> plugins (like Flash Player) will read
55 // <param> nodes immediately upon insertion into the DOM, so <object>
56 // must also be populated prior to insertion into the DOM.
57 if (tree.node.nodeType === DOCUMENT_FRAGMENT_NODE_TYPE || tree.node.nodeType === ELEMENT_NODE_TYPE && tree.node.nodeName.toLowerCase() === 'object' && (tree.node.namespaceURI == null || tree.node.namespaceURI === DOMNamespaces.html)) {
58 insertTreeChildren(tree);
59 parentNode.insertBefore(tree.node, referenceNode);
60 } else {
61 parentNode.insertBefore(tree.node, referenceNode);
62 insertTreeChildren(tree);
63 }
64});
65
66function replaceChildWithTree(oldNode, newTree) {
67 oldNode.parentNode.replaceChild(newTree.node, oldNode);
68 insertTreeChildren(newTree);
69}
70
71function queueChild(parentTree, childTree) {
72 if (enableLazy) {
73 parentTree.children.push(childTree);
74 } else {
75 parentTree.node.appendChild(childTree.node);
76 }
77}
78
79function queueHTML(tree, html) {
80 if (enableLazy) {
81 tree.html = html;
82 } else {
83 setInnerHTML(tree.node, html);
84 }
85}
86
87function queueText(tree, text) {
88 if (enableLazy) {
89 tree.text = text;
90 } else {
91 setTextContent(tree.node, text);
92 }
93}
94
95function toString() {
96 return this.node.nodeName;
97}
98
99function DOMLazyTree(node) {
100 return {
101 node: node,
102 children: [],
103 html: null,
104 text: null,
105 toString: toString
106 };
107}
108
109DOMLazyTree.insertTreeBefore = insertTreeBefore;
110DOMLazyTree.replaceChildWithTree = replaceChildWithTree;
111DOMLazyTree.queueChild = queueChild;
112DOMLazyTree.queueHTML = queueHTML;
113DOMLazyTree.queueText = queueText;
114
115module.exports = DOMLazyTree;
\No newline at end of file