custom-app
Version:
ITIMS��Ʒ�鿪��ר��React���,�Dz��ý��ּ�dhcc-app���������
178 lines (138 loc) • 6.77 kB
Flow
/**
* Copyright (c) 2013-present, 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 moveBlockInContentState
* @format
* @flow
*/
;
import type { BlockMap } from './BlockMap';
import type { BlockNodeRecord } from './BlockNodeRecord';
import type ContentState from './ContentState';
import type { DraftInsertionType } from './DraftInsertionType';
const ContentBlockNode = require('./ContentBlockNode');
const Immutable = require('immutable');
const getNextDelimiterBlockKey = require('./getNextDelimiterBlockKey');
const invariant = require('fbjs/lib/invariant');
const { OrderedMap, List } = Immutable;
const transformBlock = (key: ?string, blockMap: BlockMap, func: (block: ContentBlockNode) => ContentBlockNode): void => {
if (!key) {
return;
}
const block = blockMap.get(key);
if (!block) {
return;
}
blockMap.set(key, func(block));
};
const updateBlockMapLinks = (blockMap: BlockMap, originalBlockToBeMoved: BlockNodeRecord, originalTargetBlock: BlockNodeRecord, insertionMode: DraftInsertionType, isExperimentalTreeBlock: boolean): BlockMap => {
if (!isExperimentalTreeBlock) {
return blockMap;
}
// possible values of 'insertionMode' are: 'after', 'before'
const isInsertedAfterTarget = insertionMode === 'after';
const originalBlockKey = originalBlockToBeMoved.getKey();
const originalTargetKey = originalTargetBlock.getKey();
const originalParentKey = originalBlockToBeMoved.getParentKey();
const originalNextSiblingKey = originalBlockToBeMoved.getNextSiblingKey();
const originalPrevSiblingKey = originalBlockToBeMoved.getPrevSiblingKey();
const newParentKey = originalTargetBlock.getParentKey();
const newNextSiblingKey = isInsertedAfterTarget ? originalTargetBlock.getNextSiblingKey() : originalTargetKey;
const newPrevSiblingKey = isInsertedAfterTarget ? originalTargetKey : originalTargetBlock.getPrevSiblingKey();
return blockMap.withMutations(blocks => {
// update old parent
transformBlock(originalParentKey, blocks, block => {
const parentChildrenList = block.getChildKeys();
return block.merge({
children: parentChildrenList.delete(parentChildrenList.indexOf(originalBlockKey))
});
});
// update old prev
transformBlock(originalPrevSiblingKey, blocks, block => block.merge({
nextSibling: originalNextSiblingKey
}));
// update old next
transformBlock(originalNextSiblingKey, blocks, block => block.merge({
prevSibling: originalPrevSiblingKey
}));
// update new next
transformBlock(newNextSiblingKey, blocks, block => block.merge({
prevSibling: originalBlockKey
}));
// update new prev
transformBlock(newPrevSiblingKey, blocks, block => block.merge({
nextSibling: originalBlockKey
}));
// update new parent
transformBlock(newParentKey, blocks, block => {
const newParentChildrenList = block.getChildKeys();
const targetBlockIndex = newParentChildrenList.indexOf(originalTargetKey);
const insertionIndex = isInsertedAfterTarget ? targetBlockIndex + 1 : targetBlockIndex !== 0 ? targetBlockIndex - 1 : 0;
const newChildrenArray = newParentChildrenList.toArray();
newChildrenArray.splice(insertionIndex, 0, originalBlockKey);
return block.merge({
children: List(newChildrenArray)
});
});
// update block
transformBlock(originalBlockKey, blocks, block => block.merge({
nextSibling: newNextSiblingKey,
prevSibling: newPrevSiblingKey,
parent: newParentKey
}));
});
};
const moveBlockInContentState = (contentState: ContentState, blockToBeMoved: BlockNodeRecord, targetBlock: BlockNodeRecord, insertionMode: DraftInsertionType): ContentState => {
invariant(insertionMode !== 'replace', 'Replacing blocks is not supported.');
const targetKey = targetBlock.getKey();
const blockKey = blockToBeMoved.getKey();
invariant(blockKey !== targetKey, 'Block cannot be moved next to itself.');
const blockMap = contentState.getBlockMap();
const isExperimentalTreeBlock = blockToBeMoved instanceof ContentBlockNode;
let blocksToBeMoved = [blockToBeMoved];
let blockMapWithoutBlocksToBeMoved = blockMap.delete(blockKey);
if (isExperimentalTreeBlock) {
blocksToBeMoved = [];
blockMapWithoutBlocksToBeMoved = blockMap.withMutations(blocks => {
const nextSiblingKey = blockToBeMoved.getNextSiblingKey();
const nextDelimiterBlockKey = getNextDelimiterBlockKey(blockToBeMoved, blocks);
blocks.toSeq().skipUntil(block => block.getKey() === blockKey).takeWhile(block => {
const key = block.getKey();
const isBlockToBeMoved = key === blockKey;
const hasNextSiblingAndIsNotNextSibling = nextSiblingKey && key !== nextSiblingKey;
const doesNotHaveNextSiblingAndIsNotDelimiter = !nextSiblingKey && block.getParentKey() && (!nextDelimiterBlockKey || key !== nextDelimiterBlockKey);
return !!(isBlockToBeMoved || hasNextSiblingAndIsNotNextSibling || doesNotHaveNextSiblingAndIsNotDelimiter);
}).forEach(block => {
blocksToBeMoved.push(block);
blocks.delete(block.getKey());
});
});
}
const blocksBefore = blockMapWithoutBlocksToBeMoved.toSeq().takeUntil(v => v === targetBlock);
const blocksAfter = blockMapWithoutBlocksToBeMoved.toSeq().skipUntil(v => v === targetBlock).skip(1);
const slicedBlocks = blocksToBeMoved.map(block => [block.getKey(), block]);
let newBlocks = OrderedMap();
if (insertionMode === 'before') {
const blockBefore = contentState.getBlockBefore(targetKey);
invariant(!blockBefore || blockBefore.getKey() !== blockToBeMoved.getKey(), 'Block cannot be moved next to itself.');
newBlocks = blocksBefore.concat([...slicedBlocks, [targetKey, targetBlock]], blocksAfter).toOrderedMap();
} else if (insertionMode === 'after') {
const blockAfter = contentState.getBlockAfter(targetKey);
invariant(!blockAfter || blockAfter.getKey() !== blockKey, 'Block cannot be moved next to itself.');
newBlocks = blocksBefore.concat([[targetKey, targetBlock], ...slicedBlocks], blocksAfter).toOrderedMap();
}
return contentState.merge({
blockMap: updateBlockMapLinks(newBlocks, blockToBeMoved, targetBlock, insertionMode, isExperimentalTreeBlock),
selectionBefore: contentState.getSelectionAfter(),
selectionAfter: contentState.getSelectionAfter().merge({
anchorKey: blockKey,
focusKey: blockKey
})
});
};
module.exports = moveBlockInContentState;