react / react-0.13.3 / examples / basic-commonjs / node_modules / reactify / node_modules / react-tools / src / browser / ui / dom / DOMChildrenOperations.js
81159 views/**1* Copyright 2013-2014, Facebook, Inc.2* All rights reserved.3*4* This source code is licensed under the BSD-style license found in the5* LICENSE file in the root directory of this source tree. An additional grant6* of patent rights can be found in the PATENTS file in the same directory.7*8* @providesModule DOMChildrenOperations9* @typechecks static-only10*/1112"use strict";1314var Danger = require('Danger');15var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');1617var getTextContentAccessor = require('getTextContentAccessor');18var invariant = require('invariant');1920/**21* The DOM property to use when setting text content.22*23* @type {string}24* @private25*/26var textContentAccessor = getTextContentAccessor();2728/**29* Inserts `childNode` as a child of `parentNode` at the `index`.30*31* @param {DOMElement} parentNode Parent node in which to insert.32* @param {DOMElement} childNode Child node to insert.33* @param {number} index Index at which to insert the child.34* @internal35*/36function insertChildAt(parentNode, childNode, index) {37// By exploiting arrays returning `undefined` for an undefined index, we can38// rely exclusively on `insertBefore(node, null)` instead of also using39// `appendChild(node)`. However, using `undefined` is not allowed by all40// browsers so we must replace it with `null`.41parentNode.insertBefore(42childNode,43parentNode.childNodes[index] || null44);45}4647var updateTextContent;48if (textContentAccessor === 'textContent') {49/**50* Sets the text content of `node` to `text`.51*52* @param {DOMElement} node Node to change53* @param {string} text New text content54*/55updateTextContent = function(node, text) {56node.textContent = text;57};58} else {59/**60* Sets the text content of `node` to `text`.61*62* @param {DOMElement} node Node to change63* @param {string} text New text content64*/65updateTextContent = function(node, text) {66// In order to preserve newlines correctly, we can't use .innerText to set67// the contents (see #1080), so we empty the element then append a text node68while (node.firstChild) {69node.removeChild(node.firstChild);70}71if (text) {72var doc = node.ownerDocument || document;73node.appendChild(doc.createTextNode(text));74}75};76}7778/**79* Operations for updating with DOM children.80*/81var DOMChildrenOperations = {8283dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup,8485updateTextContent: updateTextContent,8687/**88* Updates a component's children by processing a series of updates. The89* update configurations are each expected to have a `parentNode` property.90*91* @param {array<object>} updates List of update configurations.92* @param {array<string>} markupList List of markup strings.93* @internal94*/95processUpdates: function(updates, markupList) {96var update;97// Mapping from parent IDs to initial child orderings.98var initialChildren = null;99// List of children that will be moved or removed.100var updatedChildren = null;101102for (var i = 0; update = updates[i]; i++) {103if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING ||104update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {105var updatedIndex = update.fromIndex;106var updatedChild = update.parentNode.childNodes[updatedIndex];107var parentID = update.parentID;108109invariant(110updatedChild,111'processUpdates(): Unable to find child %s of element. This ' +112'probably means the DOM was unexpectedly mutated (e.g., by the ' +113'browser), usually due to forgetting a <tbody> when using tables, ' +114'nesting tags like <form>, <p>, or <a>, or using non-SVG elements '+115'in an <svg> parent. Try inspecting the child nodes of the element ' +116'with React ID `%s`.',117updatedIndex,118parentID119);120121initialChildren = initialChildren || {};122initialChildren[parentID] = initialChildren[parentID] || [];123initialChildren[parentID][updatedIndex] = updatedChild;124125updatedChildren = updatedChildren || [];126updatedChildren.push(updatedChild);127}128}129130var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList);131132// Remove updated children first so that `toIndex` is consistent.133if (updatedChildren) {134for (var j = 0; j < updatedChildren.length; j++) {135updatedChildren[j].parentNode.removeChild(updatedChildren[j]);136}137}138139for (var k = 0; update = updates[k]; k++) {140switch (update.type) {141case ReactMultiChildUpdateTypes.INSERT_MARKUP:142insertChildAt(143update.parentNode,144renderedMarkup[update.markupIndex],145update.toIndex146);147break;148case ReactMultiChildUpdateTypes.MOVE_EXISTING:149insertChildAt(150update.parentNode,151initialChildren[update.parentID][update.fromIndex],152update.toIndex153);154break;155case ReactMultiChildUpdateTypes.TEXT_CONTENT:156updateTextContent(157update.parentNode,158update.textContent159);160break;161case ReactMultiChildUpdateTypes.REMOVE_NODE:162// Already removed by the for-loop above.163break;164}165}166}167168};169170module.exports = DOMChildrenOperations;171172173