UNPKG

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