You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
134 lines
4.4 KiB
134 lines
4.4 KiB
/** |
|
* Copyright 2013-2015, Facebook, Inc. |
|
* All rights reserved. |
|
* |
|
* This source code is licensed under the BSD-style license found in the |
|
* LICENSE file in the root directory of this source tree. An additional grant |
|
* of patent rights can be found in the PATENTS file in the same directory. |
|
* |
|
* @providesModule DOMChildrenOperations |
|
* @typechecks static-only |
|
*/ |
|
|
|
'use strict'; |
|
|
|
var Danger = require("./Danger"); |
|
var ReactMultiChildUpdateTypes = require("./ReactMultiChildUpdateTypes"); |
|
|
|
var setTextContent = require("./setTextContent"); |
|
var invariant = require("./invariant"); |
|
|
|
/** |
|
* 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) { |
|
// By exploiting arrays returning `undefined` for an undefined index, we can |
|
// rely exclusively on `insertBefore(node, null)` instead of also using |
|
// `appendChild(node)`. However, using `undefined` is not allowed by all |
|
// browsers so we must replace it with `null`. |
|
parentNode.insertBefore( |
|
childNode, |
|
parentNode.childNodes[index] || null |
|
); |
|
} |
|
|
|
/** |
|
* Operations for updating with DOM children. |
|
*/ |
|
var DOMChildrenOperations = { |
|
|
|
dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, |
|
|
|
updateTextContent: setTextContent, |
|
|
|
/** |
|
* 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; i < updates.length; i++) { |
|
update = updates[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; |
|
|
|
("production" !== process.env.NODE_ENV ? invariant( |
|
updatedChild, |
|
'processUpdates(): Unable to find child %s of element. This ' + |
|
'probably means the DOM was unexpectedly mutated (e.g., by the ' + |
|
'browser), usually due to forgetting a <tbody> when using tables, ' + |
|
'nesting tags like <form>, <p>, or <a>, or using non-SVG elements ' + |
|
'in an <svg> parent. Try inspecting the child nodes of the element ' + |
|
'with React ID `%s`.', |
|
updatedIndex, |
|
parentID |
|
) : invariant(updatedChild)); |
|
|
|
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; k < updates.length; k++) { |
|
update = updates[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: |
|
setTextContent( |
|
update.parentNode, |
|
update.textContent |
|
); |
|
break; |
|
case ReactMultiChildUpdateTypes.REMOVE_NODE: |
|
// Already removed by the for-loop above. |
|
break; |
|
} |
|
} |
|
} |
|
|
|
}; |
|
|
|
module.exports = DOMChildrenOperations;
|
|
|