UNPKG

react-addons

Version:

Simple packaging of react addons to avoid fiddly 'react/addons' npm module.

166 lines (147 loc) 5.12 kB
/** * Copyright 2013-2014 Facebook, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * @providesModule DOMChildrenOperations * @typechecks static-only */ "use strict"; var Danger = require("./Danger"); var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes"); var getTextContentAccessor = require("./getTextContentAccessor"); /** * The DOM property to use when setting text content. * * @type {string} * @private */ var textContentAccessor = getTextContentAccessor(); /** * Inserts `childNode` as a child of `parentNode` at the `index`. * * @param {DOMElement} parentNode Parent node in which to insert. * @param {DOMElement} childNode Child node to insert. * @param {number} index Index at which to insert the child. * @internal */ function insertChildAt(parentNode, childNode, index) { var childNodes = parentNode.childNodes; if (childNodes[index] === childNode) { return; } // If `childNode` is already a child of `parentNode`, remove it so that // computing `childNodes[index]` takes into account the removal. if (childNode.parentNode === parentNode) { parentNode.removeChild(childNode); } if (index >= childNodes.length) { parentNode.appendChild(childNode); } else { parentNode.insertBefore(childNode, childNodes[index]); } } /** * Sets the text content of `node` to `text`. * * @param {DOMElement} node Node to change * @param {string} text New text content */ var updateTextContent; if (textContentAccessor === 'textContent') { updateTextContent = function(node, text) { node.textContent = text; }; } else { updateTextContent = function(node, text) { // In order to preserve newlines correctly, we can't use .innerText to set // the contents (see #1080), so we empty the element then append a text node while (node.firstChild) { node.removeChild(node.firstChild); } if (text) { var doc = node.ownerDocument || document; node.appendChild(doc.createTextNode(text)); } }; } /** * Operations for updating with DOM children. */ var DOMChildrenOperations = { dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, updateTextContent: updateTextContent, /** * Updates a component's children by processing a series of updates. The * update configurations are each expected to have a `parentNode` property. * * @param {array<object>} updates List of update configurations. * @param {array<string>} markupList List of markup strings. * @internal */ processUpdates: function(updates, markupList) { var update; // Mapping from parent IDs to initial child orderings. var initialChildren = null; // List of children that will be moved or removed. var updatedChildren = null; for (var i = 0; update = updates[i]; i++) { if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING || update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) { var updatedIndex = update.fromIndex; var updatedChild = update.parentNode.childNodes[updatedIndex]; var parentID = update.parentID; initialChildren = initialChildren || {}; initialChildren[parentID] = initialChildren[parentID] || []; initialChildren[parentID][updatedIndex] = updatedChild; updatedChildren = updatedChildren || []; updatedChildren.push(updatedChild); } } var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); // Remove updated children first so that `toIndex` is consistent. if (updatedChildren) { for (var j = 0; j < updatedChildren.length; j++) { updatedChildren[j].parentNode.removeChild(updatedChildren[j]); } } for (var k = 0; update = updates[k]; k++) { switch (update.type) { case ReactMultiChildUpdateTypes.INSERT_MARKUP: insertChildAt( update.parentNode, renderedMarkup[update.markupIndex], update.toIndex ); break; case ReactMultiChildUpdateTypes.MOVE_EXISTING: insertChildAt( update.parentNode, initialChildren[update.parentID][update.fromIndex], update.toIndex ); break; case ReactMultiChildUpdateTypes.TEXT_CONTENT: updateTextContent( update.parentNode, update.textContent ); break; case ReactMultiChildUpdateTypes.REMOVE_NODE: // Already removed by the for-loop above. break; } } } }; module.exports = DOMChildrenOperations;