function CharacterMetadata() {
_classCallCheck(this, CharacterMetadata);
return _possibleConstructorReturn(this, _CharacterMetadataRec.apply(this, arguments));
}n/a
function CompositeDraftDecorator(decorators) {
_classCallCheck(this, CompositeDraftDecorator);
// Copy the decorator array, since we use this array order to determine
// precedence of decoration matching. If the array is mutated externally,
// we don't want to be affected here.
this._decorators = decorators.slice();
}n/a
function ContentBlock() {
_classCallCheck(this, ContentBlock);
return _possibleConstructorReturn(this, _ContentBlockRecord.apply(this, arguments));
}n/a
function ContentState() {
_classCallCheck(this, ContentState);
return _possibleConstructorReturn(this, _ContentStateRecord.apply(this, arguments));
}n/a
function DraftEditorContents() {
_classCallCheck(this, DraftEditorContents);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function DraftEditorLeaf() {
_classCallCheck(this, DraftEditorLeaf);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function DraftEditorPlaceholder() {
_classCallCheck(this, DraftEditorPlaceholder);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function DraftEditorTextNode(props) {
_classCallCheck(this, DraftEditorTextNode);
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
_this._forceFlag = false;
return _this;
}n/a
function DraftEditor(props) {
_classCallCheck(this, DraftEditor);
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
_this._blockSelectEvents = false;
_this._clipboard = null;
_this._handler = null;
_this._dragCount = 0;
_this._editorKey = generateRandomKey();
_this._placeholderAccessibilityID = 'placeholder-' + _this._editorKey;
_this._latestEditorState = props.editorState;
_this._onBeforeInput = _this._buildHandler('onBeforeInput');
_this._onBlur = _this._buildHandler('onBlur');
_this._onCharacterData = _this._buildHandler('onCharacterData');
_this._onCompositionEnd = _this._buildHandler('onCompositionEnd');
_this._onCompositionStart = _this._buildHandler('onCompositionStart');
_this._onCopy = _this._buildHandler('onCopy');
_this._onCut = _this._buildHandler('onCut');
_this._onDragEnd = _this._buildHandler('onDragEnd');
_this._onDragOver = _this._buildHandler('onDragOver');
_this._onDragStart = _this._buildHandler('onDragStart');
_this._onDrop = _this._buildHandler('onDrop');
_this._onInput = _this._buildHandler('onInput');
_this._onFocus = _this._buildHandler('onFocus');
_this._onKeyDown = _this._buildHandler('onKeyDown');
_this._onKeyPress = _this._buildHandler('onKeyPress');
_this._onKeyUp = _this._buildHandler('onKeyUp');
_this._onMouseDown = _this._buildHandler('onMouseDown');
_this._onMouseUp = _this._buildHandler('onMouseUp');
_this._onPaste = _this._buildHandler('onPaste');
_this._onSelect = _this._buildHandler('onSelect');
// Manual binding for public and internal methods.
_this.focus = _this._focus.bind(_this);
_this.blur = _this._blur.bind(_this);
_this.setMode = _this._setMode.bind(_this);
_this.exitCurrentMode = _this._exitCurrentMode.bind(_this);
_this.restoreEditorDOM = _this._restoreEditorDOM.bind(_this);
_this.setClipboard = _this._setClipboard.bind(_this);
_this.getClipboard = _this._getClipboard.bind(_this);
_this.getEditorKey = function () {
return _this._editorKey;
};
_this.update = _this._update.bind(_this);
_this.onDragEnter = _this._onDragEnter.bind(_this);
_this.onDragLeave = _this._onDragLeave.bind(_this);
// See `_restoreEditorDOM()`.
_this.state = { containerKey: 0 };
return _this;
}n/a
function DraftEditorBlock() {
_classCallCheck(this, DraftEditorBlock);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function EditorState(immutable) {
_classCallCheck(this, EditorState);
this._immutable = immutable;
}n/a
function DraftEntityInstance() {
_classCallCheck(this, DraftEntityInstance);
return _possibleConstructorReturn(this, _DraftEntityInstanceR.apply(this, arguments));
}n/a
function SelectionState() {
_classCallCheck(this, SelectionState);
return _possibleConstructorReturn(this, _SelectionStateRecord.apply(this, arguments));
}n/a
function convertFromHTMLtoContentBlocks(html) {
var DOMBuilder = arguments.length <= 1 || arguments[1] === undefined ? getSafeBodyFromHTML : arguments[1];
var blockRenderMap = arguments.length <= 2 || arguments[2] === undefined ? DefaultDraftBlockRenderMap : arguments[2];
// Be ABSOLUTELY SURE that the dom builder you pass here won't execute
// arbitrary code in whatever environment you're running this in. For an
// example of how we try to do this in-browser, see getSafeBodyFromHTML.
// TODO: replace DraftEntity with an OrderedMap here
var chunkData = getChunkForHTML(html, DOMBuilder, blockRenderMap, DraftEntity);
if (chunkData == null) {
return null;
}
var chunk = chunkData.chunk;
var newEntityMap = chunkData.entityMap;
var start = 0;
return {
contentBlocks: chunk.text.split('\r').map(function (textBlock, ii) {
// Make absolutely certain that our text is acceptable.
textBlock = sanitizeDraftText(textBlock);
var end = start + textBlock.length;
var inlines = nullthrows(chunk).inlines.slice(start, end);
var entities = nullthrows(chunk).entities.slice(start, end);
var characterList = List(inlines.map(function (style, ii) {
var data = { style: style, entity: null };
if (entities[ii]) {
data.entity = entities[ii];
}
return CharacterMetadata.create(data);
}));
start = end + 1;
return new ContentBlock({
key: generateRandomKey(),
type: nullthrows(chunk).blocks[ii].type,
depth: nullthrows(chunk).blocks[ii].depth,
text: textBlock,
characterList: characterList
});
}),
entityMap: newEntityMap
};
}n/a
function convertFromRawToDraftState(rawState) {
var blocks = rawState.blocks;
var entityMap = rawState.entityMap;
var fromStorageToLocal = {};
// TODO: Update this once we completely remove DraftEntity
Object.keys(entityMap).forEach(function (storageKey) {
var encodedEntity = entityMap[storageKey];
var type = encodedEntity.type;
var mutability = encodedEntity.mutability;
var data = encodedEntity.data;
var newKey = DraftEntity.__create(type, mutability, data || {});
fromStorageToLocal[storageKey] = newKey;
});
var contentBlocks = blocks.map(function (block) {
var key = block.key;
var type = block.type;
var text = block.text;
var depth = block.depth;
var inlineStyleRanges = block.inlineStyleRanges;
var entityRanges = block.entityRanges;
var data = block.data;
key = key || generateRandomKey();
depth = depth || 0;
inlineStyleRanges = inlineStyleRanges || [];
entityRanges = entityRanges || [];
data = Map(data);
var inlineStyles = decodeInlineStyleRanges(text, inlineStyleRanges);
// Translate entity range keys to the DraftEntity map.
var filteredEntityRanges = entityRanges.filter(function (range) {
return fromStorageToLocal.hasOwnProperty(range.key);
}).map(function (range) {
return _extends({}, range, { key: fromStorageToLocal[range.key] });
});
var entities = decodeEntityRanges(text, filteredEntityRanges);
var characterList = createCharacterList(inlineStyles, entities);
return new ContentBlock({ key: key, type: type, text: text, depth: depth, characterList: characterList, data: data });
});
return ContentState.createFromBlockArray(contentBlocks);
}n/a
function convertFromDraftStateToRaw(contentState) {
var entityStorageKey = 0;
var entityStorageMap = {};
var rawBlocks = [];
contentState.getBlockMap().forEach(function (block, blockKey) {
block.findEntityRanges(function (character) {
return character.getEntity() !== null;
}, function (start) {
// Stringify to maintain order of otherwise numeric keys.
var stringifiedEntityKey = DraftStringKey.stringify(block.getEntityAt(start));
if (!entityStorageMap.hasOwnProperty(stringifiedEntityKey)) {
entityStorageMap[stringifiedEntityKey] = '' + entityStorageKey++;
}
});
rawBlocks.push({
key: blockKey,
text: block.getText(),
type: block.getType(),
depth: block.getDepth(),
inlineStyleRanges: encodeInlineStyleRanges(block),
entityRanges: encodeEntityRanges(block, entityStorageMap),
data: block.getData().toObject()
});
});
// Flip storage map so that our storage keys map to global
// DraftEntity keys.
var entityKeys = Object.keys(entityStorageMap);
var flippedStorageMap = {};
entityKeys.forEach(function (key, jj) {
var entity = contentState.getEntity(DraftStringKey.unstringify(key));
flippedStorageMap[jj] = {
type: entity.getType(),
mutability: entity.getMutability(),
data: entity.getData()
};
});
return {
entityMap: flippedStorageMap,
blocks: rawBlocks
};
}n/a
function generateRandomKey() {
var key = void 0;
while (key === undefined || seenKeys.hasOwnProperty(key) || !isNaN(+key)) {
key = Math.floor(Math.random() * MULTIPLIER).toString(32);
}
seenKeys[key] = true;
return key;
}n/a
function getDefaultKeyBinding(e) {
switch (e.keyCode) {
case 66:
// B
return hasCommandModifier(e) ? 'bold' : null;
case 68:
// D
return isCtrlKeyCommand(e) ? 'delete' : null;
case 72:
// H
return isCtrlKeyCommand(e) ? 'backspace' : null;
case 73:
// I
return hasCommandModifier(e) ? 'italic' : null;
case 74:
// J
return hasCommandModifier(e) ? 'code' : null;
case 75:
// K
return !isWindows && isCtrlKeyCommand(e) ? 'secondary-cut' : null;
case 77:
// M
return isCtrlKeyCommand(e) ? 'split-block' : null;
case 79:
// O
return isCtrlKeyCommand(e) ? 'split-block' : null;
case 84:
// T
return isOSX && isCtrlKeyCommand(e) ? 'transpose-characters' : null;
case 85:
// U
return hasCommandModifier(e) ? 'underline' : null;
case 87:
// W
return isOSX && isCtrlKeyCommand(e) ? 'backspace-word' : null;
case 89:
// Y
if (isCtrlKeyCommand(e)) {
return isWindows ? 'redo' : 'secondary-paste';
}
return null;
case 90:
// Z
return getZCommand(e) || null;
case Keys.RETURN:
return 'split-block';
case Keys.DELETE:
return getDeleteCommand(e);
case Keys.BACKSPACE:
return getBackspaceCommand(e);
// LEFT/RIGHT handlers serve as a workaround for a Firefox bug.
case Keys.LEFT:
return shouldFixFirefoxMovement && hasCommandModifier(e) ? 'move-selection-to-start-of-block' : null;
case Keys.RIGHT:
return shouldFixFirefoxMovement && hasCommandModifier(e) ? 'move-selection-to-end-of-block' : null;
default:
return null;
}
}n/a
function getVisibleSelectionRect(global) {
var selection = global.getSelection();
if (!selection.rangeCount) {
return null;
}
var range = selection.getRangeAt(0);
var boundingRect = getRangeBoundingClientRect(range);
var top = boundingRect.top;
var right = boundingRect.right;
var bottom = boundingRect.bottom;
var left = boundingRect.left;
// When a re-render leads to a node being removed, the DOM selection will
// temporarily be placed on an ancestor node, which leads to an invalid
// bounding rect. Discard this state.
if (top === 0 && right === 0 && bottom === 0 && left === 0) {
return null;
}
return boundingRect;
}n/a
function insertAtomicBlock(editorState, entityKey, character) {
var contentState = editorState.getCurrentContent();
var selectionState = editorState.getSelection();
var afterRemoval = DraftModifier.removeRange(contentState, selectionState, 'backward');
var targetSelection = afterRemoval.getSelectionAfter();
var afterSplit = DraftModifier.splitBlock(afterRemoval, targetSelection);
var insertionTarget = afterSplit.getSelectionAfter();
var asAtomicBlock = DraftModifier.setBlockType(afterSplit, insertionTarget, 'atomic');
var charData = CharacterMetadata.create({ entity: entityKey });
var fragmentArray = [new ContentBlock({
key: generateRandomKey(),
type: 'atomic',
text: character,
characterList: List(Repeat(charData, character.length))
}), new ContentBlock({
key: generateRandomKey(),
type: 'unstyled',
text: '',
characterList: List()
})];
var fragment = BlockMapBuilder.createFromArray(fragmentArray);
var withAtomicBlock = DraftModifier.replaceWithFragment(asAtomicBlock, insertionTarget, fragment);
var newContent = withAtomicBlock.merge({
selectionBefore: selectionState,
selectionAfter: withAtomicBlock.getSelectionAfter().set('hasFocus', true)
});
return EditorState.push(editorState, newContent, 'insert-fragment');
}n/a
function createFromArray(blocks) {
return OrderedMap(blocks.map(function (block) {
return [block.getKey(), block];
}));
}...
};
ContentState.createFromBlockArray = function createFromBlockArray(
// TODO: update flow type when we completely deprecate the old entity API
blocks, entityMap) {
// TODO: remove this when we completely deprecate the old entity API
var theBlocks = Array.isArray(blocks) ? blocks : blocks.contentBlocks;
var blockMap = BlockMapBuilder.createFromArray(theBlocks);
var selectionState = blockMap.isEmpty() ? new SelectionState() : SelectionState.createEmpty(blockMap.first().getKey());
return new ContentState({
blockMap: blockMap,
entityMap: entityMap || DraftEntity,
selectionBefore: selectionState,
selectionAfter: selectionState
});
...function generate(contentState, block, decorator) {
var textLength = block.getLength();
if (!textLength) {
return List.of(new DecoratorRange({
start: 0,
end: 0,
decoratorKey: null,
leaves: List.of(new LeafRange({ start: 0, end: 0 }))
}));
}
var leafSets = [];
var decorations = decorator ? decorator.getDecorations(block, contentState) : List(Repeat(null, textLength));
var chars = block.getCharacterList();
findRangesImmutable(decorations, areEqual, returnTrue, function (start, end) {
leafSets.push(new DecoratorRange({
start: start,
end: end,
decoratorKey: decorations.get(start),
leaves: generateLeaves(chars.slice(start, end).toList(), start)
}));
});
return List(leafSets);
}...
/**
* Regenerate the entire tree map for a given ContentState and decorator.
* Returns an OrderedMap that maps all available ContentBlock objects.
*/
function generateNewTreeMap(contentState, decorator) {
return contentState.getBlockMap().map(function (block) {
return BlockTree.generate(contentState, block, decorator);
}).toOrderedMap();
}
/**
* Regenerate tree map objects for all ContentBlocks that have changed
* between the current editorState and newContent. Returns an OrderedMap
* with only changed regenerated tree map objects.
...function getFingerprint(tree) {
return tree.map(function (leafSet) {
var decoratorKey = leafSet.get('decoratorKey');
var fingerprintString = decoratorKey !== null ? decoratorKey + '.' + (leafSet.get('end') - leafSet.get('start')) : '';
return '' + fingerprintString + '.' + leafSet.get('leaves').size;
}).join(FINGERPRINT_DELIMITER);
}...
var anchorKey = selection.getAnchorKey();
var anchorTree = editorState.getBlockTree(anchorKey);
// Check the old and new "fingerprints" of the current block to determine
// whether this insertion requires any addition or removal of text nodes,
// in which case we would prevent the native character insertion.
var originalFingerprint = BlockTree.getFingerprint(anchorTree);
var newFingerprint = BlockTree.getFingerprint(newEditorState.getBlockTree(anchorKey));
if (mustPreventDefaultForCharacter(chars) || originalFingerprint !== newFingerprint || nullthrows(newEditorState.getDirectionMap
()).get(anchorKey) !== nullthrows(editorState.getDirectionMap()).get(anchorKey)) {
e.preventDefault();
editor.update(newEditorState);
} else {
newEditorState = EditorState.set(newEditorState, {
...function CharacterMetadata() {
_classCallCheck(this, CharacterMetadata);
return _possibleConstructorReturn(this, _CharacterMetadataRec.apply(this, arguments));
}n/a
function applyEntity(record, entityKey) {
var withEntity = record.getEntity() === entityKey ? record : record.set('entity', entityKey);
return CharacterMetadata.create(withEntity);
}...
var start = _getRemovalRange.start;
var end = _getRemovalRange.end;
var current;
while (start < end) {
current = chars.get(start);
chars = chars.set(start, CharacterMetadata.applyEntity(current, null));
start++;
}
return block.set('characterList', chars);
}
}
return block;
...function applyStyle(record, style) {
var withStyle = record.set('style', record.getStyle().add(style));
return CharacterMetadata.create(withStyle);
}...
sliceEnd = blockKey === endKey ? endOffset : block.getLength();
}
var chars = block.getCharacterList();
var current;
while (sliceStart < sliceEnd) {
current = chars.get(sliceStart);
chars = chars.set(sliceStart, addOrRemove ? CharacterMetadata.applyStyle(current
, inlineStyle) : CharacterMetadata.removeStyle(current, inlineStyle));
sliceStart++;
}
return block.set('characterList', chars);
});
return contentState.merge({
...function create(config) {
if (!config) {
return EMPTY;
}
var defaultConfig = { style: EMPTY_SET, entity: null };
// Fill in unspecified properties, if necessary.
var configMap = Map(defaultConfig).merge(config);
var existing = pool.get(configMap);
if (existing) {
return existing;
}
var newCharacter = new CharacterMetadata(configMap);
pool = pool.set(configMap, newCharacter);
return newCharacter;
}...
var EditorState = function () {
EditorState.createEmpty = function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''), decorator);
};
EditorState.createWithContent = function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
redoStack: Stack(),
decorator: decorator || null,
selection: SelectionState.createEmpty(firstKey)
});
};
...function removeStyle(record, style) {
var withoutStyle = record.set('style', record.getStyle().remove(style));
return CharacterMetadata.create(withoutStyle);
}...
sliceEnd = blockKey === endKey ? endOffset : block.getLength();
}
var chars = block.getCharacterList();
var current;
while (sliceStart < sliceEnd) {
current = chars.get(sliceStart);
chars = chars.set(sliceStart, addOrRemove ? CharacterMetadata.applyStyle(current, inlineStyle) : CharacterMetadata.removeStyle(current, inlineStyle));
sliceStart++;
}
return block.set('characterList', chars);
});
return contentState.merge({
...function getEntity() {
return this.get('entity');
}...
CharacterMetadata.removeStyle = function removeStyle(record, style) {
var withoutStyle = record.set('style', record.getStyle().remove(style));
return CharacterMetadata.create(withoutStyle);
};
CharacterMetadata.applyEntity = function applyEntity(record, entityKey) {
var withEntity = record.getEntity() === entityKey ? record : record.set('entity
', entityKey);
return CharacterMetadata.create(withEntity);
};
/**
* Use this function instead of the `CharacterMetadata` constructor.
* Since most content generally uses only a very small number of
* style/entity permutations, we can reuse these objects as often as
...function getStyle() {
return this.get('style');
}...
};
CharacterMetadata.prototype.getEntity = function getEntity() {
return this.get('entity');
};
CharacterMetadata.prototype.hasStyle = function hasStyle(style) {
return this.getStyle().has(style);
};
CharacterMetadata.applyStyle = function applyStyle(record, style) {
var withStyle = record.set('style', record.getStyle().add(style));
return CharacterMetadata.create(withStyle);
};
...function hasStyle(style) {
return this.getStyle().has(style);
}n/a
function CompositeDraftDecorator(decorators) {
_classCallCheck(this, CompositeDraftDecorator);
// Copy the decorator array, since we use this array order to determine
// precedence of decoration matching. If the array is mutated externally,
// we don't want to be affected here.
this._decorators = decorators.slice();
}n/a
function getComponentForKey(key) {
var componentKey = parseInt(key.split(DELIMITER)[0], 10);
return this._decorators[componentKey].component;
}...
if (!_this2.props.decorator) {
return leaves;
}
var decorator = nullthrows(_this2.props.decorator);
var DecoratorComponent = decorator.getComponentForKey(decoratorKey);
if (!DecoratorComponent) {
return leaves;
}
var decoratorProps = decorator.getPropsForKey(decoratorKey);
var decoratorOffsetKey = DraftOffsetKey.encode(blockKey, ii, 0);
var decoratedText = text.slice(leavesForLeafSet.first().get('start'), leavesForLeafSet.last().get('end'
;));
...function getDecorations(block, contentState) {
var decorations = Array(block.getText().length).fill(null);
this._decorators.forEach(function ( /*object*/decorator, /*number*/ii) {
var counter = 0;
var strategy = decorator.strategy;
var callback = function callback( /*number*/start, /*number*/end) {
// Find out if any of our matching range is already occupied
// by another decorator. If so, discard the match. Otherwise, store
// the component key for rendering.
if (canOccupySlice(decorations, start, end)) {
occupySlice(decorations, start, end, ii + DELIMITER + counter);
counter++;
}
};
strategy(block, callback, contentState);
});
return List(decorations);
}...
*
* Note that in order for this to perform optimally, decoration Lists for
* decorators should be preserved when possible to allow for direct immutable
* List comparison.
*/
function regenerateTreeForNewDecorator(content, blockMap, previousTreeMap, decorator, existingDecorator) {
return previousTreeMap.merge(blockMap.toSeq().filter(function (block) {
return decorator.getDecorations(block, content) !== existingDecorator.getDecorations
(block, content);
}).map(function (block) {
return BlockTree.generate(content, block, decorator);
}));
}
/**
* Return whether a change should be considered a boundary state, given
...function getPropsForKey(key) {
var componentKey = parseInt(key.split(DELIMITER)[0], 10);
return this._decorators[componentKey].props;
}...
var decorator = nullthrows(_this2.props.decorator);
var DecoratorComponent = decorator.getComponentForKey(decoratorKey);
if (!DecoratorComponent) {
return leaves;
}
var decoratorProps = decorator.getPropsForKey(decoratorKey);
var decoratorOffsetKey = DraftOffsetKey.encode(blockKey, ii, 0);
var decoratedText = text.slice(leavesForLeafSet.first().get('start'), leavesForLeafSet.last().get('end'
;));
// Resetting dir to the same value on a child node makes Chrome/Firefox
// confused on cursor movement. See http://jsfiddle.net/d157kLck/3/
var dir = UnicodeBidiDirection.getHTMLDirIfDifferent(UnicodeBidi.getDirection(decoratedText), _this2.props.direction);
...function ContentBlock() {
_classCallCheck(this, ContentBlock);
return _possibleConstructorReturn(this, _ContentBlockRecord.apply(this, arguments));
}n/a
function findEntityRanges(filterFn, callback) {
findRangesImmutable(this.getCharacterList(), haveEqualEntity, filterFn, callback);
}...
function convertFromDraftStateToRaw(contentState) {
var entityStorageKey = 0;
var entityStorageMap = {};
var rawBlocks = [];
contentState.getBlockMap().forEach(function (block, blockKey) {
block.findEntityRanges(function (character) {
return character.getEntity() !== null;
}, function (start) {
// Stringify to maintain order of otherwise numeric keys.
var stringifiedEntityKey = DraftStringKey.stringify(block.getEntityAt(start));
if (!entityStorageMap.hasOwnProperty(stringifiedEntityKey)) {
entityStorageMap[stringifiedEntityKey] = '' + entityStorageKey++;
}
...function findStyleRanges(filterFn, callback) {
findRangesImmutable(this.getCharacterList(), haveEqualStyle, filterFn, callback);
}n/a
function getCharacterList() {
return this.get('characterList');
}...
};
ContentBlock.prototype.getData = function getData() {
return this.get('data');
};
ContentBlock.prototype.getInlineStyleAt = function getInlineStyleAt(offset) {
var character = this.getCharacterList().get(offset);
return character ? character.getStyle() : EMPTY_SET;
};
ContentBlock.prototype.getEntityAt = function getEntityAt(offset) {
var character = this.getCharacterList().get(offset);
return character ? character.getEntity() : null;
};
...function getData() {
return this.get('data');
}...
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ data: blockData });
});
},
mergeBlockData: function mergeBlockData(contentState, selectionState, blockData) {
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ data: block.getData().merge(blockData) });
});
},
applyEntity: function applyEntity(contentState, selectionState, entityKey) {
var withoutEntities = removeEntitiesAtEdges(contentState, selectionState);
return applyEntityToContentState(withoutEntities, selectionState, entityKey);
}
...function getDepth() {
return this.get('depth');
}...
};
var configForType = blockRenderMap.get(blockType);
var wrapperTemplate = configForType.wrapper;
var _Element = configForType.element || blockRenderMap.get('unstyled').element;
var depth = _block.getDepth();
var className = this.props.blockStyleFn(_block);
// List items are special snowflakes, since we handle nesting and
// counters manually.
if (_Element === 'li') {
var shouldResetCount = lastWrapperTemplate !== wrapperTemplate || currentDepth === null || depth > currentDepth;
className = joinClasses(className, getListItemClasses(blockType, depth, shouldResetCount, direction));
...function getEntityAt(offset) {
var character = this.getCharacterList().get(offset);
return character ? character.getEntity() : null;
}...
// If so, try to remove the appropriate substring of the entity text.
if (rangeToRemove.getAnchorKey() === rangeToRemove.getFocusKey()) {
var key = rangeToRemove.getAnchorKey();
var startOffset = rangeToRemove.getStartOffset();
var endOffset = rangeToRemove.getEndOffset();
var block = contentState.getBlockForKey(key);
var startEntity = block.getEntityAt(startOffset);
var endEntity = block.getEntityAt(endOffset - 1);
if (startEntity && startEntity === endEntity) {
var adjustedRemovalRange = getCharacterRemovalRange(contentState.getEntityMap(), block, rangeToRemove, removalDirection
);
return removeRangeFromContentState(contentState, adjustedRemovalRange);
}
}
...function getInlineStyleAt(offset) {
var character = this.getCharacterList().get(offset);
return character ? character.getStyle() : EMPTY_SET;
}...
var startKey = selection.getStartKey();
var startOffset = selection.getStartOffset();
var startBlock = content.getBlockForKey(startKey);
// If the cursor is not at the start of the block, look backward to
// preserve the style of the preceding character.
if (startOffset > 0) {
return startBlock.getInlineStyleAt(startOffset - 1);
}
// The caret is at position zero in this block. If the block has any
// text at all, use the style of the first character.
if (startBlock.getLength()) {
return startBlock.getInlineStyleAt(0);
}
...function getKey() {
return this.get('key');
}...
var EditorState = function () {
EditorState.createEmpty = function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''), decorator);
};
EditorState.createWithContent = function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
redoStack: Stack(),
decorator: decorator || null,
selection: SelectionState.createEmpty(firstKey)
});
...function getLength() {
return this.getText().length;
}...
return this.getSelection().hasEdgeWithin(firstKey, 0, 0);
};
EditorState.prototype.isSelectionAtEndOfContent = function isSelectionAtEndOfContent() {
var content = this.getCurrentContent();
var blockMap = content.getBlockMap();
var last = blockMap.last();
var end = last.getLength();
return this.getSelection().hasEdgeWithin(last.getKey(), end, end);
};
EditorState.prototype.getDirectionMap = function getDirectionMap() {
return this.getImmutable().get('directionMap');
};
...function getText() {
return this.get('text');
}...
};
ContentBlock.prototype.getCharacterList = function getCharacterList() {
return this.get('characterList');
};
ContentBlock.prototype.getLength = function getLength() {
return this.getText().length;
};
ContentBlock.prototype.getDepth = function getDepth() {
return this.get('depth');
};
ContentBlock.prototype.getData = function getData() {
...function getType() {
return this.get('type');
}...
var processedBlocks = [];
var currentDepth = null;
var lastWrapperTemplate = null;
for (var ii = 0; ii < blocksAsArray.length; ii++) {
var _block = blocksAsArray[ii];
var key = _block.getKey();
var blockType = _block.getType();
var customRenderer = blockRendererFn(_block);
var CustomComponent = void 0,
customProps = void 0,
customEditable = void 0;
if (customRenderer) {
CustomComponent = customRenderer.component;
...function ContentState() {
_classCallCheck(this, ContentState);
return _possibleConstructorReturn(this, _ContentStateRecord.apply(this, arguments));
}n/a
function createFromBlockArray( // TODO: update flow type when we completely deprecate the old entity API blocks, entityMap) {
// TODO: remove this when we completely deprecate the old entity API
var theBlocks = Array.isArray(blocks) ? blocks : blocks.contentBlocks;
var blockMap = BlockMapBuilder.createFromArray(theBlocks);
var selectionState = blockMap.isEmpty() ? new SelectionState() : SelectionState.createEmpty(blockMap.first().getKey());
return new ContentState({
blockMap: blockMap,
entityMap: entityMap || DraftEntity,
selectionBefore: selectionState,
selectionAfter: selectionState
});
}...
return new ContentBlock({
key: generateRandomKey(),
text: block,
type: 'unstyled',
characterList: List(Repeat(CharacterMetadata.EMPTY, block.length))
});
});
return ContentState.createFromBlockArray(blocks);
};
return ContentState;
}(ContentStateRecord);
module.exports = ContentState;
...function createFromText(text) {
var delimiter = arguments.length <= 1 || arguments[1] === undefined ? /\r\n?|\n/g : arguments[1];
var strings = text.split(delimiter);
var blocks = strings.map(function (block) {
block = sanitizeDraftText(block);
return new ContentBlock({
key: generateRandomKey(),
text: block,
type: 'unstyled',
characterList: List(Repeat(CharacterMetadata.EMPTY, block.length))
});
});
return ContentState.createFromBlockArray(blocks);
}...
undoStack: Stack()
};
var EditorStateRecord = Record(defaultRecord);
var EditorState = function () {
EditorState.createEmpty = function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''),
decorator);
};
EditorState.createWithContent = function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
...function addEntity(instance) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__add(instance);
return this;
}n/a
function createEntity(type, mutability, data) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__create(type, mutability, data);
return this;
}n/a
function getBlockAfter(key) {
return this.getBlockMap().skipUntil(function (_, k) {
return k === key;
}).skip(1).first();
}...
var length = block.getLength();
// The cursor is somewhere within the text. Behave normally.
if (selection.getStartOffset() < length) {
return null;
}
var blockAfter = content.getBlockAfter(startKey);
if (!blockAfter || blockAfter.getType() !== 'atomic') {
return null;
}
var atomicBlockTarget = selection.merge({
focusKey: blockAfter.getKey(),
...function getBlockBefore(key) {
return this.getBlockMap().reverse().skipUntil(function (_, k) {
return k === key;
}).skip(1).first();
}...
}
// Otherwise, look upward in the document to find the closest character.
return lookUpwardForInlineStyle(content, startKey);
}
function lookUpwardForInlineStyle(content, fromKey) {
var previousBlock = content.getBlockBefore(fromKey);
var previousLength;
while (previousBlock) {
previousLength = previousBlock.getLength();
if (previousLength) {
return previousBlock.getInlineStyleAt(previousLength - 1);
}
...function getBlockForKey(key) {
var block = this.getBlockMap().get(key);
return block;
}...
var lastChangeType = editorState.getLastChangeType();
return changeType !== lastChangeType || changeType !== 'insert-characters' && changeType !== 'backspace
-character' && changeType !== 'delete-character';
}
function getInlineStyleForCollapsedSelection(content, selection) {
var startKey = selection.getStartKey();
var startOffset = selection.getStartOffset();
var startBlock = content.getBlockForKey(startKey);
// If the cursor is not at the start of the block, look backward to
// preserve the style of the preceding character.
if (startOffset > 0) {
return startBlock.getInlineStyleAt(startOffset - 1);
}
...function getBlockMap() {
return this.get('blockMap');
}...
var EditorState = function () {
EditorState.createEmpty = function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''), decorator);
};
EditorState.createWithContent = function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
redoStack: Stack(),
decorator: decorator || null,
selection: SelectionState.createEmpty(firstKey)
});
...function getBlocksAsArray() {
return this.getBlockMap().toArray();
}...
var content = editorState.getCurrentContent();
var selection = editorState.getSelection();
var forceSelection = editorState.mustForceSelection();
var decorator = editorState.getDecorator();
var directionMap = nullthrows(editorState.getDirectionMap());
var blocksAsArray = content.getBlocksAsArray();
var processedBlocks = [];
var currentDepth = null;
var lastWrapperTemplate = null;
for (var ii = 0; ii < blocksAsArray.length; ii++) {
var _block = blocksAsArray[ii];
var key = _block.getKey();
...function getEntity(key) {
// TODO: update this when we fully remove DraftEntity
return DraftEntity.__get(key);
}...
CharacterMetadata.removeStyle = function removeStyle(record, style) {
var withoutStyle = record.set('style', record.getStyle().remove(style));
return CharacterMetadata.create(withoutStyle);
};
CharacterMetadata.applyEntity = function applyEntity(record, entityKey) {
var withEntity = record.getEntity() === entityKey ? record : record.set('entity
', entityKey);
return CharacterMetadata.create(withEntity);
};
/**
* Use this function instead of the `CharacterMetadata` constructor.
* Since most content generally uses only a very small number of
* style/entity permutations, we can reuse these objects as often as
...function getEntityMap() {
// TODO: update this when we fully remove DraftEntity
return DraftEntity;
}...
nativelyRenderedContent: null
});
return;
}
var existingContent = editorState.getCurrentContent();
if (newContent !== existingContent) {
state.set('treeMap', regenerateTreeForNewBlocks(editorState, newContent.getBlockMap(), newContent.getEntityMap(), decorator));
}
state.merge(put);
});
return new EditorState(map);
};
...function getFirstBlock() {
return this.getBlockMap().first();
}...
* Match Chrome `<textarea>` behavior during <kbd>cmd</kbd>+<kbd>backspace</kbd>
;
command at visual line-start
## 0.6.0 (April 27, 2016)
### Added
* `ContentState.getFirstBlock()` convenience method
### Changed
* <kbd>return</kbd> key handling now goes through command flow to enable easier
custom `'split-block'` handling.
* `convertFromRaw` now returns a `ContentState` object instead of an
`Array<ContentBlock>`
...function getKeyAfter(key) {
return this.getBlockMap().keySeq().skipUntil(function (v) {
return v === key;
}).skip(1).first();
}...
var focusKey = key;
var focusOffset;
var block = content.getBlockForKey(key);
if (maxDistance > block.getText().length - offset) {
focusKey = content.getKeyAfter(key);
focusOffset = 0;
} else {
focusOffset = offset + maxDistance;
}
return selection.merge({ focusKey: focusKey, focusOffset: focusOffset });
}
...function getKeyBefore(key) {
return this.getBlockMap().reverse().keySeq().skipUntil(function (v) {
return v === key;
}).skip(1).first();
}...
var key = selection.getStartKey();
var offset = selection.getStartOffset();
var focusKey = key;
var focusOffset = 0;
if (maxDistance > offset) {
var keyBefore = content.getKeyBefore(key);
if (keyBefore == null) {
focusKey = key;
} else {
focusKey = keyBefore;
var blockBefore = content.getBlockForKey(keyBefore);
focusOffset = blockBefore.getText().length;
}
...function getLastBlock() {
return this.getBlockMap().last();
}...
/**
* Move selection to the end of the editor without forcing focus.
*/
EditorState.moveSelectionToEnd = function moveSelectionToEnd(editorState) {
var content = editorState.getCurrentContent();
var lastBlock = content.getLastBlock();
var lastKey = lastBlock.getKey();
var length = lastBlock.getLength();
return EditorState.acceptSelection(editorState, new SelectionState({
anchorKey: lastKey,
anchorOffset: length,
focusKey: lastKey,
...function getLastCreatedEntityKey() {
// TODO: update this when we fully remove DraftEntity
return DraftEntity.__getLastCreatedEntityKey();
}n/a
function getPlainText(delimiter) {
return this.getBlockMap().map(function (block) {
return block ? block.getText() : '';
}).join(delimiter || '\n');
}n/a
function getSelectionAfter() {
return this.get('selectionAfter');
}...
var directionMap = EditorBidiService.getDirectionMap(contentState, editorState.getDirectionMap());
if (!editorState.getAllowUndo()) {
return EditorState.set(editorState, {
currentContent: contentState,
directionMap: directionMap,
lastChangeType: changeType,
selection: contentState.getSelectionAfter(),
forceSelection: forceSelection,
inlineStyleOverride: null
});
}
var selection = editorState.getSelection();
var currentContent = editorState.getCurrentContent();
...function getSelectionBefore() {
return this.get('selectionBefore');
}...
var newContent = contentState;
if (selection !== currentContent.getSelectionAfter() || mustBecomeBoundary(editorState, changeType)) {
undoStack = undoStack.push(currentContent);
newContent = newContent.set('selectionBefore', selection);
} else if (changeType === 'insert-characters' || changeType === 'backspace-character' || changeType ===
x27;delete-character') {
// Preserve the previous selection.
newContent = newContent.set('selectionBefore', currentContent.getSelectionBefore
());
}
var inlineStyleOverride = editorState.getInlineStyleOverride();
// Don't discard inline style overrides on block type or depth changes.
if (changeType !== 'adjust-depth' && changeType !== 'change-block-type') {
inlineStyleOverride = null;
...function hasText() {
var blockMap = this.getBlockMap();
return blockMap.size > 1 || blockMap.first().getLength() > 0;
}...
var method = _this2._handler && _this2._handler[eventName];
method && method(_this2, e);
}
};
};
DraftEditor.prototype._showPlaceholder = function _showPlaceholder() {
return !!this.props.placeholder && !this.props.editorState.isInCompositionMode() && !this.props.editorState
.getCurrentContent().hasText();
};
DraftEditor.prototype._renderPlaceholder = function _renderPlaceholder() {
if (this._showPlaceholder()) {
return React.createElement(DraftEditorPlaceholder, {
text: nullthrows(this.props.placeholder),
editorState: this.props.editorState,
...function mergeEntityData(key, toMerge) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__mergeData(key, toMerge);
return this;
}n/a
function replaceEntityData(key, newData) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__replaceData(key, newData);
return this;
}n/a
function add(contentState, selectionState, inlineStyle) {
return modifyInlineStyle(contentState, selectionState, inlineStyle, true);
}...
var withoutEntities = removeEntitiesAtEdges(contentState, selectionState);
var withoutText = removeRangeFromContentState(withoutEntities, selectionState);
return splitBlockInContentState(withoutText, withoutText.getSelectionAfter());
},
applyInlineStyle: function applyInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.add(contentState, selectionState, inlineStyle);
},
removeInlineStyle: function removeInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.remove(contentState, selectionState, inlineStyle);
},
setBlockType: function setBlockType(contentState, selectionState, blockType) {
...function remove(contentState, selectionState, inlineStyle) {
return modifyInlineStyle(contentState, selectionState, inlineStyle, false);
}...
},
applyInlineStyle: function applyInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.add(contentState, selectionState, inlineStyle);
},
removeInlineStyle: function removeInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.remove(contentState, selectionState, inlineStyle);
},
setBlockType: function setBlockType(contentState, selectionState, blockType) {
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ type: blockType, depth: 0 });
});
},
...function onBeforeInput(editor, e) {
textInputData = (textInputData || '') + e.data;
}n/a
function onCompositionEnd(editor) {
resolved = false;
stillComposing = false;
setTimeout(function () {
if (!resolved) {
DraftEditorCompositionHandler.resolveComposition(editor);
}
}, RESOLVE_DELAY);
}n/a
function onCompositionStart(editor) {
stillComposing = true;
}n/a
function onKeyDown(editor, e) {
if (!stillComposing) {
// If a keydown event is received after compositionend but before the
// 20ms timer expires (ex: type option-E then backspace, or type A then
// backspace in 2-Set Korean), we should immediately resolve the
// composition and reinterpret the key press in edit mode.
DraftEditorCompositionHandler.resolveComposition(editor);
editor._onKeyDown(e);
return;
}
if (e.which === Keys.RIGHT || e.which === Keys.LEFT) {
e.preventDefault();
}
}n/a
function onKeyPress(editor, e) {
if (e.which === Keys.RETURN) {
e.preventDefault();
}
}n/a
function resolveComposition(editor) {
if (stillComposing) {
return;
}
resolved = true;
var composedChars = textInputData;
textInputData = '';
var editorState = EditorState.set(editor._latestEditorState, {
inCompositionMode: false
});
var currentStyle = editorState.getCurrentInlineStyle();
var entityKey = getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection());
var mustReset = !composedChars || isSelectionAtLeafStart(editorState) || currentStyle.size > 0 || entityKey !== null;
if (mustReset) {
editor.restoreEditorDOM();
}
editor.exitCurrentMode();
if (composedChars) {
// If characters have been composed, re-rendering with the update
// is sufficient to reset the editor.
var contentState = DraftModifier.replaceText(editorState.getCurrentContent(), editorState.getSelection(), composedChars, currentStyle
, entityKey);
editor.update(EditorState.push(editorState, contentState, 'insert-characters'));
return;
}
if (mustReset) {
editor.update(EditorState.set(editorState, {
nativelyRenderedContent: null,
forceSelection: true
}));
}
}...
* Google Input Tools on Windows 8.1 fires `compositionend` three times.
*/
onCompositionEnd: function onCompositionEnd(editor) {
resolved = false;
stillComposing = false;
setTimeout(function () {
if (!resolved) {
DraftEditorCompositionHandler.resolveComposition(editor);
}
}, RESOLVE_DELAY);
},
/**
* In Safari, keydown events may fire when committing compositions. If
* the arrow keys are used to commit, prevent default so that the cursor
...function DraftEditorContents() {
_classCallCheck(this, DraftEditorContents);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function render() {
var _props = this.props;
var blockRenderMap = _props.blockRenderMap;
var blockRendererFn = _props.blockRendererFn;
var customStyleMap = _props.customStyleMap;
var customStyleFn = _props.customStyleFn;
var editorState = _props.editorState;
var content = editorState.getCurrentContent();
var selection = editorState.getSelection();
var forceSelection = editorState.mustForceSelection();
var decorator = editorState.getDecorator();
var directionMap = nullthrows(editorState.getDirectionMap());
var blocksAsArray = content.getBlocksAsArray();
var processedBlocks = [];
var currentDepth = null;
var lastWrapperTemplate = null;
for (var ii = 0; ii < blocksAsArray.length; ii++) {
var _block = blocksAsArray[ii];
var key = _block.getKey();
var blockType = _block.getType();
var customRenderer = blockRendererFn(_block);
var CustomComponent = void 0,
customProps = void 0,
customEditable = void 0;
if (customRenderer) {
CustomComponent = customRenderer.component;
customProps = customRenderer.props;
customEditable = customRenderer.editable;
}
var direction = directionMap.get(key);
var offsetKey = DraftOffsetKey.encode(key, 0, 0);
var componentProps = {
contentState: content,
block: _block,
blockProps: customProps,
customStyleMap: customStyleMap,
customStyleFn: customStyleFn,
decorator: decorator,
direction: direction,
forceSelection: forceSelection,
key: key,
offsetKey: offsetKey,
selection: selection,
tree: editorState.getBlockTree(key)
};
var configForType = blockRenderMap.get(blockType);
var wrapperTemplate = configForType.wrapper;
var _Element = configForType.element || blockRenderMap.get('unstyled').element;
var depth = _block.getDepth();
var className = this.props.blockStyleFn(_block);
// List items are special snowflakes, since we handle nesting and
// counters manually.
if (_Element === 'li') {
var shouldResetCount = lastWrapperTemplate !== wrapperTemplate || currentDepth === null || depth > currentDepth;
className = joinClasses(className, getListItemClasses(blockType, depth, shouldResetCount, direction));
}
var Component = CustomComponent || DraftEditorBlock;
var childProps = {
className: className,
'data-block': true,
'data-editor': this.props.editorKey,
'data-offset-key': offsetKey,
key: key
};
if (customEditable !== undefined) {
childProps = _extends({}, childProps, {
contentEditable: customEditable,
suppressContentEditableWarning: true
});
}
var child = React.createElement(_Element, childProps, React.createElement(Component, componentProps));
processedBlocks.push({
block: child,
wrapperTemplate: wrapperTemplate,
key: key,
offsetKey: offsetKey
});
if (wrapperTemplate) {
currentDepth = _block.getDepth();
} else {
currentDepth = null;
}
lastWrapperTemplate = wrapperTemplate;
}
// Group contiguous runs of blocks that have the same wrapperTemplate
var outputBlocks = [];
for (var _ii = 0; _ii < processedBlocks.length;) {
var info = processedBlocks[_ii];
if (info.wrapperTemplate) {
var blocks = [];
do {
blocks.push(processedBlocks[_ii].block);
_ii++;
} while (_ii < processedBlocks.length && processedBlocks[_ii].wrapperTemplate === info.wrapperTemplate);
var wrapperElement = React.cloneElement(info.wrapperTemplate, {
key: info.key + '-wrap',
'data-offset-key': info.offsetKey
}, blocks);
outputBlocks.push(wrapperElement);
} else {
outputBlocks.push(info.block);
_ii++;
}
}
return React.createElement(
'div',
{ 'data-contents': 'true' },
outputBlocks
);
}...
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('container')
);
```
Because Draft.js supports unicode, you must have the following meta tag in the `<head>` `</head>` block of your
HTML file:
...function shouldComponentUpdate(nextProps) {
var prevEditorState = this.props.editorState;
var nextEditorState = nextProps.editorState;
var prevDirectionMap = prevEditorState.getDirectionMap();
var nextDirectionMap = nextEditorState.getDirectionMap();
// Text direction has changed for one or more blocks. We must re-render.
if (prevDirectionMap !== nextDirectionMap) {
return true;
}
var didHaveFocus = prevEditorState.getSelection().getHasFocus();
var nowHasFocus = nextEditorState.getSelection().getHasFocus();
if (didHaveFocus !== nowHasFocus) {
return true;
}
var nextNativeContent = nextEditorState.getNativelyRenderedContent();
var wasComposing = prevEditorState.isInCompositionMode();
var nowComposing = nextEditorState.isInCompositionMode();
// If the state is unchanged or we're currently rendering a natively
// rendered state, there's nothing new to be done.
if (prevEditorState === nextEditorState || nextNativeContent !== null && nextEditorState.getCurrentContent() === nextNativeContent
|| wasComposing && nowComposing) {
return false;
}
var prevContent = prevEditorState.getCurrentContent();
var nextContent = nextEditorState.getCurrentContent();
var prevDecorator = prevEditorState.getDecorator();
var nextDecorator = nextEditorState.getDecorator();
return wasComposing !== nowComposing || prevContent !== nextContent || prevDecorator !== nextDecorator || nextEditorState.mustForceSelection
();
}n/a
function onDragEnd(editor) {
editor.exitCurrentMode();
}n/a
function onDrop(editor, e) {
var data = new DataTransfer(e.nativeEvent.dataTransfer);
var editorState = editor._latestEditorState;
var dropSelection = getSelectionForEvent(e.nativeEvent, editorState);
e.preventDefault();
editor.exitCurrentMode();
if (dropSelection == null) {
return;
}
var files = data.getFiles();
if (files.length > 0) {
if (editor.props.handleDroppedFiles && isEventHandled(editor.props.handleDroppedFiles(dropSelection, files))) {
return;
}
getTextContentFromFiles(files, function (fileText) {
fileText && editor.update(insertTextAtSelection(editorState, nullthrows(dropSelection), // flow wtf
fileText));
});
return;
}
var dragType = editor._internalDrag ? 'internal' : 'external';
if (editor.props.handleDrop && isEventHandled(editor.props.handleDrop(dropSelection, data, dragType))) {
return;
}
if (editor._internalDrag) {
editor.update(moveText(editorState, dropSelection));
return;
}
editor.update(insertTextAtSelection(editorState, dropSelection, data.getText()));
}n/a
function editOnBeforeInput(editor, e) {
if (editor._pendingStateFromBeforeInput !== undefined) {
editor.update(editor._pendingStateFromBeforeInput);
editor._pendingStateFromBeforeInput = undefined;
}
var chars = e.data;
// In some cases (ex: IE ideographic space insertion) no character data
// is provided. There's nothing to do when this happens.
if (!chars) {
return;
}
// Allow the top-level component to handle the insertion manually. This is
// useful when triggering interesting behaviors for a character insertion,
// Simple examples: replacing a raw text ':)' with a smile emoji or image
// decorator, or setting a block to be a list item after typing '- ' at the
// start of the block.
if (editor.props.handleBeforeInput && isEventHandled(editor.props.handleBeforeInput(chars))) {
e.preventDefault();
return;
}
// If selection is collapsed, conditionally allow native behavior. This
// reduces re-renders and preserves spellcheck highlighting. If the selection
// is not collapsed, we will re-render.
var editorState = editor._latestEditorState;
var selection = editorState.getSelection();
if (!selection.isCollapsed()) {
e.preventDefault();
editor.update(replaceText(editorState, chars, editorState.getCurrentInlineStyle(), getEntityKeyForSelection(editorState.getCurrentContent
(), editorState.getSelection())));
return;
}
var mayAllowNative = !isSelectionAtLeafStart(editorState);
var newEditorState = replaceText(editorState, chars, editorState.getCurrentInlineStyle(), getEntityKeyForSelection(editorState
.getCurrentContent(), editorState.getSelection()));
if (!mayAllowNative) {
e.preventDefault();
editor.update(newEditorState);
return;
}
var anchorKey = selection.getAnchorKey();
var anchorTree = editorState.getBlockTree(anchorKey);
// Check the old and new "fingerprints" of the current block to determine
// whether this insertion requires any addition or removal of text nodes,
// in which case we would prevent the native character insertion.
var originalFingerprint = BlockTree.getFingerprint(anchorTree);
var newFingerprint = BlockTree.getFingerprint(newEditorState.getBlockTree(anchorKey));
if (mustPreventDefaultForCharacter(chars) || originalFingerprint !== newFingerprint || nullthrows(newEditorState.getDirectionMap
()).get(anchorKey) !== nullthrows(editorState.getDirectionMap()).get(anchorKey)) {
e.preventDefault();
editor.update(newEditorState);
} else {
newEditorState = EditorState.set(newEditorState, {
nativelyRenderedContent: newEditorState.getCurrentContent()
});
// The native event is allowed to occur. To allow user onChange handlers to
// change the inserted text, we wait until the text is actually inserted
// before we actually update our state. That way when we rerender, the text
// we see in the DOM will already have been inserted properly.
editor._pendingStateFromBeforeInput = newEditorState;
setImmediate(function () {
if (editor._pendingStateFromBeforeInput !== undefined) {
editor.update(editor._pendingStateFromBeforeInput);
editor._pendingStateFromBeforeInput = undefined;
}
});
}
}n/a
function editOnBlur(editor, e) {
// Webkit has a bug in which blurring a contenteditable by clicking on
// other active elements will trigger the `blur` event but will not remove
// the DOM selection from the contenteditable. We therefore force the
// issue to be certain, checking whether the active element is `body`
// to force it when blurring occurs within the window (as opposed to
// clicking to another tab or window).
if (isWebKit && getActiveElement() === document.body) {
global.getSelection().removeAllRanges();
}
var editorState = editor._latestEditorState;
var currentSelection = editorState.getSelection();
if (!currentSelection.getHasFocus()) {
return;
}
var selection = currentSelection.set('hasFocus', false);
editor.props.onBlur && editor.props.onBlur(e);
editor.update(EditorState.acceptSelection(editorState, selection));
}...
var editorState = editor._latestEditorState;
var currentSelection = editorState.getSelection();
if (!currentSelection.getHasFocus()) {
return;
}
var selection = currentSelection.set('hasFocus', false);
editor.props.onBlur && editor.props.onBlur(e);
editor.update(EditorState.acceptSelection(editorState, selection));
}
module.exports = editOnBlur;
...function editOnCompositionStart(editor, e) {
editor.setMode('composite');
editor.update(EditorState.set(editor._latestEditorState, { inCompositionMode: true }));
// Allow composition handler to interpret the compositionstart event
editor._onCompositionStart(e);
}n/a
function editOnCopy(editor, e) {
var editorState = editor._latestEditorState;
var selection = editorState.getSelection();
// No selection, so there's nothing to copy.
if (selection.isCollapsed()) {
e.preventDefault();
return;
}
editor.setClipboard(getFragmentFromSelection(editor._latestEditorState));
}n/a
function editOnCut(editor, e) {
var editorState = editor._latestEditorState;
var selection = editorState.getSelection();
// No selection, so there's nothing to cut.
if (selection.isCollapsed()) {
e.preventDefault();
return;
}
// Track the current scroll position so that it can be forced back in place
// after the editor regains control of the DOM.
var scrollParent = Style.getScrollParent(e.target);
var _getScrollPosition = getScrollPosition(scrollParent);
var x = _getScrollPosition.x;
var y = _getScrollPosition.y;
var fragment = getFragmentFromSelection(editorState);
editor.setClipboard(fragment);
// Set `cut` mode to disable all event handling temporarily.
editor.setMode('cut');
// Let native `cut` behavior occur, then recover control.
setTimeout(function () {
editor.restoreEditorDOM({ x: x, y: y });
editor.exitCurrentMode();
editor.update(removeFragment(editorState));
}, 0);
}n/a
function editOnDragOver(editor, e) {
editor._internalDrag = false;
editor.setMode('drag');
e.preventDefault();
}n/a
function editOnDragStart(editor) {
editor._internalDrag = true;
editor.setMode('drag');
}n/a
function editOnFocus(editor, e) {
var editorState = editor._latestEditorState;
var currentSelection = editorState.getSelection();
if (currentSelection.getHasFocus()) {
return;
}
var selection = currentSelection.set('hasFocus', true);
editor.props.onFocus && editor.props.onFocus(e);
// When the tab containing this text editor is hidden and the user does a
// find-in-page in a _different_ tab, Chrome on Mac likes to forget what the
// selection was right after sending this focus event and (if you let it)
// moves the cursor back to the beginning of the editor, so we force the
// selection here instead of simply accepting it in order to preserve the
// old cursor position. See https://crbug.com/540004.
editor.update(EditorState.forceSelection(editorState, selection));
}...
var editorState = editor._latestEditorState;
var currentSelection = editorState.getSelection();
if (currentSelection.getHasFocus()) {
return;
}
var selection = currentSelection.set('hasFocus', true);
editor.props.onFocus && editor.props.onFocus(e);
// When the tab containing this text editor is hidden and the user does a
// find-in-page in a _different_ tab, Chrome on Mac likes to forget what the
// selection was right after sending this focus event and (if you let it)
// moves the cursor back to the beginning of the editor, so we force the
// selection here instead of simply accepting it in order to preserve the
// old cursor position. See https://crbug.com/540004.
...function editOnInput(editor) {
if (editor._pendingStateFromBeforeInput !== undefined) {
editor.update(editor._pendingStateFromBeforeInput);
editor._pendingStateFromBeforeInput = undefined;
}
var domSelection = global.getSelection();
var anchorNode = domSelection.anchorNode;
var isCollapsed = domSelection.isCollapsed;
if (anchorNode.nodeType !== Node.TEXT_NODE) {
return;
}
var domText = anchorNode.textContent;
var editorState = editor._latestEditorState;
var offsetKey = nullthrows(findAncestorOffsetKey(anchorNode));
var _DraftOffsetKey$decod = DraftOffsetKey.decode(offsetKey);
var blockKey = _DraftOffsetKey$decod.blockKey;
var decoratorKey = _DraftOffsetKey$decod.decoratorKey;
var leafKey = _DraftOffsetKey$decod.leafKey;
var _editorState$getBlock = editorState.getBlockTree(blockKey).getIn([decoratorKey, 'leaves', leafKey]);
var start = _editorState$getBlock.start;
var end = _editorState$getBlock.end;
var content = editorState.getCurrentContent();
var block = content.getBlockForKey(blockKey);
var modelText = block.getText().slice(start, end);
// Special-case soft newlines here. If the DOM text ends in a soft newline,
// we will have manually inserted an extra soft newline in DraftEditorLeaf.
// We want to remove this extra newline for the purpose of our comparison
// of DOM and model text.
if (domText.endsWith(DOUBLE_NEWLINE)) {
domText = domText.slice(0, -1);
}
// No change -- the DOM is up to date. Nothing to do here.
if (domText === modelText) {
return;
}
var selection = editorState.getSelection();
// We'll replace the entire leaf with the text content of the target.
var targetRange = selection.merge({
anchorOffset: start,
focusOffset: end,
isBackward: false
});
var entityKey = block.getEntityAt(start);
var entity = entityKey && content.getEntity(entityKey);
var entityType = entity && entity.getMutability();
var preserveEntity = entityType === 'MUTABLE';
// Immutable or segmented entities cannot properly be handled by the
// default browser undo, so we have to use a different change type to
// force using our internal undo method instead of falling through to the
// native browser undo.
var changeType = preserveEntity ? 'spellcheck-change' : 'apply-entity';
var newContent = DraftModifier.replaceText(content, targetRange, domText, block.getInlineStyleAt(start), preserveEntity ? block
.getEntityAt(start) : null);
var anchorOffset, focusOffset, startOffset, endOffset;
if (isGecko) {
// Firefox selection does not change while the context menu is open, so
// we preserve the anchor and focus values of the DOM selection.
anchorOffset = domSelection.anchorOffset;
focusOffset = domSelection.focusOffset;
startOffset = start + Math.min(anchorOffset, focusOffset);
endOffset = startOffset + Math.abs(anchorOffset - focusOffset);
anchorOffset = startOffset;
focusOffset = endOffset;
} else {
// Browsers other than Firefox may adjust DOM selection while the context
// menu is open, and Safari autocorrect is prone to providing an inaccurate
// DOM selection. Don't trust it. Instead, use our existing SelectionState
// and adjust it based on the number of characters changed during the
// mutation.
var charDelta = domText.length - modelText.length;
startOffset = selection.getStartOffset();
endOffset = selection.getEndOffset();
anchorOffset = isCollapsed ? endOffset + charDelta : startOffset;
focusOffset = endOffset + charDelta;
}
// Segmented entities are completely or partially removed when their
// text content changes. For this case we do not want any text to be selected
// after the change, so we are not merging the selection.
var contentWithAdjustedDOMSelection = newContent.merge({
selectionBefore: content.getSelectionAfter(),
selectionAfter: selection.merge({ anchorOffset: anchorOffset, focusOffset: focusOffset })
});
editor.update(EditorState.push(editorState, contentWithAdjustedDOMSelection, chang ...n/a
function editOnKeyDown(editor, e) {
var keyCode = e.which;
var editorState = editor._latestEditorState;
switch (keyCode) {
case Keys.RETURN:
e.preventDefault();
// The top-level component may manually handle newline insertion. If
// no special handling is performed, fall through to command handling.
if (editor.props.handleReturn && isEventHandled(editor.props.handleReturn(e))) {
return;
}
break;
case Keys.ESC:
e.preventDefault();
editor.props.onEscape && editor.props.onEscape(e);
return;
case Keys.TAB:
editor.props.onTab && editor.props.onTab(e);
return;
case Keys.UP:
editor.props.onUpArrow && editor.props.onUpArrow(e);
return;
case Keys.DOWN:
editor.props.onDownArrow && editor.props.onDownArrow(e);
return;
case Keys.SPACE:
// Handling for OSX where option + space scrolls.
if (isChrome && isOptionKeyCommand(e)) {
e.preventDefault();
// Insert a nbsp into the editor.
var contentState = DraftModifier.replaceText(editorState.getCurrentContent(), editorState.getSelection(), '\xA0');
editor.update(EditorState.push(editorState, contentState, 'insert-characters'));
return;
}
}
var command = editor.props.keyBindingFn(e);
// If no command is specified, allow keydown event to continue.
if (!command) {
return;
}
if (command === 'undo') {
// Since undo requires some special updating behavior to keep the editor
// in sync, handle it separately.
keyCommandUndo(e, editorState, editor.update);
return;
}
// At this point, we know that we're handling a command of some kind, so
// we don't want to insert a character following the keydown.
e.preventDefault();
// Allow components higher up the tree to handle the command first.
if (editor.props.handleKeyCommand && isEventHandled(editor.props.handleKeyCommand(command))) {
return;
}
var newState = onKeyCommand(command, editorState);
if (newState !== editorState) {
editor.update(newState);
}
}n/a
function editOnPaste(editor, e) {
e.preventDefault();
var data = new DataTransfer(e.clipboardData);
// Get files, unless this is likely to be a string the user wants inline.
if (!data.isRichText()) {
var files = data.getFiles();
var defaultFileText = data.getText();
if (files.length > 0) {
// Allow customized paste handling for images, etc. Otherwise, fall
// through to insert text contents into the editor.
if (editor.props.handlePastedFiles && isEventHandled(editor.props.handlePastedFiles(files))) {
return;
}
getTextContentFromFiles(files, function ( /*string*/fileText) {
fileText = fileText || defaultFileText;
if (!fileText) {
return;
}
var editorState = editor._latestEditorState;
var blocks = splitTextIntoTextBlocks(fileText);
var character = CharacterMetadata.create({
style: editorState.getCurrentInlineStyle(),
entity: getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection())
});
var text = DraftPasteProcessor.processText(blocks, character);
var fragment = BlockMapBuilder.createFromArray(text);
var withInsertedText = DraftModifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment
);
editor.update(EditorState.push(editorState, withInsertedText, 'insert-fragment'));
});
return;
}
}
var textBlocks = [];
var text = data.getText();
var html = data.getHTML();
if (editor.props.handlePastedText && isEventHandled(editor.props.handlePastedText(text, html))) {
return;
}
if (text) {
textBlocks = splitTextIntoTextBlocks(text);
}
if (!editor.props.stripPastedStyles) {
// If the text from the paste event is rich content that matches what we
// already have on the internal clipboard, assume that we should just use
// the clipboard fragment for the paste. This will allow us to preserve
// styling and entities, if any are present. Note that newlines are
// stripped during comparison -- this is because copy/paste within the
// editor in Firefox and IE will not include empty lines. The resulting
// paste will preserve the newlines correctly.
var internalClipboard = editor.getClipboard();
if (data.isRichText() && internalClipboard) {
if (
// If the editorKey is present in the pasted HTML, it should be safe to
// assume this is an internal paste.
html.indexOf(editor.getEditorKey()) !== -1 ||
// The copy may have been made within a single block, in which case the
// editor key won't be part of the paste. In this case, just check
// whether the pasted text matches the internal clipboard.
textBlocks.length === 1 && internalClipboard.size === 1 && internalClipboard.first().getText() === text) {
editor.update(insertFragment(editor._latestEditorState, internalClipboard));
return;
}
} else if (internalClipboard && data.types.includes('com.apple.webarchive') && !data.types.includes('text/html') && areTextBlocksAndClipboardEqual
(textBlocks, internalClipboard)) {
// Safari does not properly store text/html in some cases.
// Use the internalClipboard if present and equal to what is on
// the clipboard. See https://bugs.webkit.org/show_bug.cgi?id=19893.
editor.update(insertFragment(editor._latestEditorState, internalClipboard));
return;
}
// If there is html paste data, try to parse that.
if (html) {
var htmlFragment = DraftPasteProcessor.processHTML(html, editor.props.blockRenderMap);
if (htmlFragment) {
var contentBlocks = htmlFragment.contentBlocks;
var entityMap = htmlFragment.entityMap;
if (contentBlocks) {
var htmlMap = BlockMapBuilder.createFromArray(contentBlocks);
editor.update(insertFragment(editor._latestEditorState, htmlMap, entityMap));
return;
}
}
}
// Otherwise, create a new fragment from our pasted text. ...n/a
function editOnSelect(editor) {
if (editor._blockSelectEvents || editor._latestEditorState !== editor.props.editorState) {
return;
}
var editorState = editor.props.editorState;
var documentSelection = getDraftEditorSelection(editorState, ReactDOM.findDOMNode(editor.refs.editorContainer).firstChild);
var updatedSelectionState = documentSelection.selectionState;
if (updatedSelectionState !== editorState.getSelection()) {
if (documentSelection.needsRecovery) {
editorState = EditorState.forceSelection(editorState, updatedSelectionState);
} else {
editorState = EditorState.acceptSelection(editorState, updatedSelectionState);
}
editor.update(editorState);
}
}n/a
function DraftEditorLeaf() {
_classCallCheck(this, DraftEditorLeaf);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function _setSelection() {
var selection = this.props.selection;
// If selection state is irrelevant to the parent block, no-op.
if (selection == null || !selection.getHasFocus()) {
return;
}
var _props = this.props;
var blockKey = _props.blockKey;
var start = _props.start;
var text = _props.text;
var end = start + text.length;
if (!selection.hasEdgeWithin(blockKey, start, end)) {
return;
}
// Determine the appropriate target node for selection. If the child
// is not a text node, it is a <br /> spacer. In this case, use the
// <span> itself as the selection target.
var node = ReactDOM.findDOMNode(this);
var child = node.firstChild;
var targetNode = void 0;
if (child.nodeType === Node.TEXT_NODE) {
targetNode = child;
} else if (child.tagName === 'BR') {
targetNode = node;
} else {
targetNode = child.firstChild;
}
setDraftEditorSelection(selection, targetNode, blockKey, start, end);
}...
};
DraftEditorLeaf.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
return ReactDOM.findDOMNode(this.refs.leaf).textContent !== nextProps.text || nextProps.styleSet !== this.props.styleSet ||
nextProps.forceSelection;
};
DraftEditorLeaf.prototype.componentDidUpdate = function componentDidUpdate() {
this._setSelection();
};
DraftEditorLeaf.prototype.componentDidMount = function componentDidMount() {
this._setSelection();
};
DraftEditorLeaf.prototype.render = function render() {
...function componentDidMount() {
this._setSelection();
}n/a
function componentDidUpdate() {
this._setSelection();
}n/a
function render() {
var text = this.props.text;
// If the leaf is at the end of its block and ends in a soft newline, append
// an extra line feed character. Browsers collapse trailing newline
// characters, which leaves the cursor in the wrong place after a
// shift+enter. The extra character repairs this.
if (text.endsWith('\n') && this.props.isLast) {
text += '\n';
}
var _props2 = this.props;
var customStyleMap = _props2.customStyleMap;
var customStyleFn = _props2.customStyleFn;
var offsetKey = _props2.offsetKey;
var styleSet = _props2.styleSet;
var styleObj = styleSet.reduce(function (map, styleName) {
var mergedStyles = {};
var style = customStyleMap[styleName];
if (style !== undefined && map.textDecoration !== style.textDecoration) {
// .trim() is necessary for IE9/10/11 and Edge
mergedStyles.textDecoration = [map.textDecoration, style.textDecoration].join(' ').trim();
}
return _assign(map, style, mergedStyles);
}, {});
if (customStyleFn) {
var newStyles = customStyleFn(styleSet);
styleObj = _assign(styleObj, newStyles);
}
return React.createElement(
'span',
{
'data-offset-key': offsetKey,
ref: 'leaf',
style: styleObj },
React.createElement(
DraftEditorTextNode,
null,
text
)
);
}...
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('container')
);
```
Because Draft.js supports unicode, you must have the following meta tag in the `<head>` `</head>` block of your
HTML file:
...function shouldComponentUpdate(nextProps) {
return ReactDOM.findDOMNode(this.refs.leaf).textContent !== nextProps.text || nextProps.styleSet !== this.props.styleSet || nextProps
.forceSelection;
}n/a
function DraftEditorPlaceholder() {
_classCallCheck(this, DraftEditorPlaceholder);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function render() {
var hasFocus = this.props.editorState.getSelection().getHasFocus();
var className = cx({
'public/DraftEditorPlaceholder/root': true,
'public/DraftEditorPlaceholder/hasFocus': hasFocus
});
return React.createElement(
'div',
{ className: className },
React.createElement(
'div',
{
className: cx('public/DraftEditorPlaceholder/inner'),
id: this.props.accessibilityID },
this.props.text
)
);
}...
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('container')
);
```
Because Draft.js supports unicode, you must have the following meta tag in the `<head>` `</head>` block of your
HTML file:
...function shouldComponentUpdate(nextProps) {
return this.props.text !== nextProps.text || this.props.editorState.getSelection().getHasFocus() !== nextProps.editorState.getSelection
().getHasFocus();
}n/a
function DraftEditorTextNode(props) {
_classCallCheck(this, DraftEditorTextNode);
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
_this._forceFlag = false;
return _this;
}n/a
function componentWillUpdate() {
// By flipping this flag, we also keep flipping keys which forces
// React to remount this node every time it rerenders.
this._forceFlag = !this._forceFlag;
}n/a
function render() {
if (this.props.children === '') {
return this._forceFlag ? NEWLINE_A : NEWLINE_B;
}
return React.createElement(
'span',
{ key: this._forceFlag ? 'A' : 'B', 'data-text': 'true' },
this.props.children
);
}...
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('container')
);
```
Because Draft.js supports unicode, you must have the following meta tag in the `<head>` `</head>` block of your
HTML file:
...function shouldComponentUpdate(nextProps) {
var node = ReactDOM.findDOMNode(this);
var shouldBeNewline = nextProps.children === '';
if (shouldBeNewline) {
return !isNewline(node);
}
return node.textContent !== nextProps.children;
}n/a
function getRemovalRange(selectionStart, selectionEnd, text, entityStart, direction) {
var segments = text.split(' ');
segments = segments.map(function ( /*string*/segment, /*number*/ii) {
if (direction === 'forward') {
if (ii > 0) {
return ' ' + segment;
}
} else if (ii < segments.length - 1) {
return segment + ' ';
}
return segment;
});
var segmentStart = entityStart;
var segmentEnd;
var segment;
var removalStart = null;
var removalEnd = null;
for (var jj = 0; jj < segments.length; jj++) {
segment = segments[jj];
segmentEnd = segmentStart + segment.length;
// Our selection overlaps this segment.
if (selectionStart < segmentEnd && segmentStart < selectionEnd) {
if (removalStart !== null) {
removalEnd = segmentEnd;
} else {
removalStart = segmentStart;
removalEnd = segmentEnd;
}
} else if (removalStart !== null) {
break;
}
segmentStart = segmentEnd;
}
var entityEnd = entityStart + text.length;
var atStart = removalStart === entityStart;
var atEnd = removalEnd === entityEnd;
if (!atStart && atEnd || atStart && !atEnd) {
if (direction === 'forward') {
if (removalEnd !== entityEnd) {
removalEnd++;
}
} else if (removalStart !== entityStart) {
removalStart--;
}
}
return {
start: removalStart,
end: removalEnd
};
}...
focusOffset: entityRange.end,
isBackward: false
});
}
// For `SEGMENTED` entity types, determine the appropriate segment to
// remove.
var removalRange = DraftEntitySegments.getRemovalRange(start, end, block.getText().
slice(entityRange.start, entityRange.end), entityRange.start, direction);
return selectionState.merge({
anchorOffset: removalRange.start,
focusOffset: removalRange.end,
isBackward: false
});
}
...function decode(offsetKey) {
var _offsetKey$split = offsetKey.split(KEY_DELIMITER);
var blockKey = _offsetKey$split[0];
var decoratorKey = _offsetKey$split[1];
var leafKey = _offsetKey$split[2];
return {
blockKey: blockKey,
decoratorKey: parseInt(decoratorKey, 10),
leafKey: parseInt(leafKey, 10)
};
}...
/*eslint-disable no-console */
console.warn('Invalid selection state.', arguments, editorState.toJS());
/*eslint-enable no-console */
return selection;
}
}
var anchorPath = DraftOffsetKey.decode(anchorKey);
var anchorBlockKey = anchorPath.blockKey;
var anchorLeaf = editorState.getBlockTree(anchorBlockKey).getIn([anchorPath.decoratorKey, 'leaves', anchorPath.leafKey
]);
var focusPath = DraftOffsetKey.decode(focusKey);
var focusBlockKey = focusPath.blockKey;
var focusLeaf = editorState.getBlockTree(focusBlockKey).getIn([focusPath.decoratorKey, 'leaves', focusPath.leafKey]);
...function encode(blockKey, decoratorKey, leafKey) {
return blockKey + KEY_DELIMITER + decoratorKey + KEY_DELIMITER + leafKey;
}...
var lastLeafSet = this.props.tree.size - 1;
var hasSelection = isBlockOnSelectionEdge(this.props.selection, blockKey);
return this.props.tree.map(function (leafSet, ii) {
var leavesForLeafSet = leafSet.get('leaves');
var lastLeaf = leavesForLeafSet.size - 1;
var leaves = leavesForLeafSet.map(function (leaf, jj) {
var offsetKey = DraftOffsetKey.encode(blockKey, ii, jj);
var start = leaf.get('start');
var end = leaf.get('end');
return React.createElement(DraftEditorLeaf, {
key: offsetKey,
offsetKey: offsetKey,
blockKey: blockKey,
start: start,
...function processHTML(html, blockRenderMap) {
return convertFromHTMLtoContentBlocks(html, getSafeBodyFromHTML, blockRenderMap);
}...
// the clipboard. See https://bugs.webkit.org/show_bug.cgi?id=19893.
editor.update(insertFragment(editor._latestEditorState, internalClipboard));
return;
}
// If there is html paste data, try to parse that.
if (html) {
var htmlFragment = DraftPasteProcessor.processHTML(html, editor.props.blockRenderMap
);
if (htmlFragment) {
var contentBlocks = htmlFragment.contentBlocks;
var entityMap = htmlFragment.entityMap;
if (contentBlocks) {
var htmlMap = BlockMapBuilder.createFromArray(contentBlocks);
editor.update(insertFragment(editor._latestEditorState, htmlMap, entityMap));
...function processText(textBlocks, character) {
return textBlocks.map(function (textLine) {
textLine = sanitizeDraftText(textLine);
return new ContentBlock({
key: generateRandomKey(),
type: 'unstyled',
text: textLine,
characterList: List(Repeat(character, textLine.length))
});
});
}...
var editorState = editor._latestEditorState;
var blocks = splitTextIntoTextBlocks(fileText);
var character = CharacterMetadata.create({
style: editorState.getCurrentInlineStyle(),
entity: getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection())
});
var text = DraftPasteProcessor.processText(blocks, character);
var fragment = BlockMapBuilder.createFromArray(text);
var withInsertedText = DraftModifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), fragment
);
editor.update(EditorState.push(editorState, withInsertedText, 'insert-fragment'));
});
...function getBackward(text) {
return getRemovableWord(text, true);
}...
// If there are no words before the cursor, remove the preceding newline.
if (offset === 0) {
return moveSelectionBackward(strategyState, 1);
}
var key = selection.getStartKey();
var content = strategyState.getCurrentContent();
var text = content.getBlockForKey(key).getText().slice(0, offset);
var toRemove = DraftRemovableWord.getBackward(text);
return moveSelectionBackward(strategyState, toRemove.length || 1);
}, 'backward');
if (afterRemoval === editorState.getCurrentContent()) {
return editorState;
}
...function getForward(text) {
return getRemovableWord(text, false);
}...
function keyCommandDeleteWord(editorState) {
var afterRemoval = removeTextWithStrategy(editorState, function (strategyState) {
var selection = strategyState.getSelection();
var offset = selection.getStartOffset();
var key = selection.getStartKey();
var content = strategyState.getCurrentContent();
var text = content.getBlockForKey(key).getText().slice(offset);
var toRemove = DraftRemovableWord.getForward(text);
// If there are no words in front of the cursor, remove the newline.
return moveSelectionForward(strategyState, toRemove.length || 1);
}, 'forward');
if (afterRemoval === editorState.getCurrentContent()) {
return editorState;
...function stringify(key) {
return '_' + String(key);
}...
var rawBlocks = [];
contentState.getBlockMap().forEach(function (block, blockKey) {
block.findEntityRanges(function (character) {
return character.getEntity() !== null;
}, function (start) {
// Stringify to maintain order of otherwise numeric keys.
var stringifiedEntityKey = DraftStringKey.stringify(block.getEntityAt(start));
if (!entityStorageMap.hasOwnProperty(stringifiedEntityKey)) {
entityStorageMap[stringifiedEntityKey] = '' + entityStorageKey++;
}
});
rawBlocks.push({
key: blockKey,
...function unstringify(key) {
return key.slice(1);
}...
});
// Flip storage map so that our storage keys map to global
// DraftEntity keys.
var entityKeys = Object.keys(entityStorageMap);
var flippedStorageMap = {};
entityKeys.forEach(function (key, jj) {
var entity = contentState.getEntity(DraftStringKey.unstringify(key));
flippedStorageMap[jj] = {
type: entity.getType(),
mutability: entity.getMutability(),
data: entity.getData()
};
});
...function DraftEditor(props) {
_classCallCheck(this, DraftEditor);
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props));
_this._blockSelectEvents = false;
_this._clipboard = null;
_this._handler = null;
_this._dragCount = 0;
_this._editorKey = generateRandomKey();
_this._placeholderAccessibilityID = 'placeholder-' + _this._editorKey;
_this._latestEditorState = props.editorState;
_this._onBeforeInput = _this._buildHandler('onBeforeInput');
_this._onBlur = _this._buildHandler('onBlur');
_this._onCharacterData = _this._buildHandler('onCharacterData');
_this._onCompositionEnd = _this._buildHandler('onCompositionEnd');
_this._onCompositionStart = _this._buildHandler('onCompositionStart');
_this._onCopy = _this._buildHandler('onCopy');
_this._onCut = _this._buildHandler('onCut');
_this._onDragEnd = _this._buildHandler('onDragEnd');
_this._onDragOver = _this._buildHandler('onDragOver');
_this._onDragStart = _this._buildHandler('onDragStart');
_this._onDrop = _this._buildHandler('onDrop');
_this._onInput = _this._buildHandler('onInput');
_this._onFocus = _this._buildHandler('onFocus');
_this._onKeyDown = _this._buildHandler('onKeyDown');
_this._onKeyPress = _this._buildHandler('onKeyPress');
_this._onKeyUp = _this._buildHandler('onKeyUp');
_this._onMouseDown = _this._buildHandler('onMouseDown');
_this._onMouseUp = _this._buildHandler('onMouseUp');
_this._onPaste = _this._buildHandler('onPaste');
_this._onSelect = _this._buildHandler('onSelect');
// Manual binding for public and internal methods.
_this.focus = _this._focus.bind(_this);
_this.blur = _this._blur.bind(_this);
_this.setMode = _this._setMode.bind(_this);
_this.exitCurrentMode = _this._exitCurrentMode.bind(_this);
_this.restoreEditorDOM = _this._restoreEditorDOM.bind(_this);
_this.setClipboard = _this._setClipboard.bind(_this);
_this.getClipboard = _this._getClipboard.bind(_this);
_this.getEditorKey = function () {
return _this._editorKey;
};
_this.update = _this._update.bind(_this);
_this.onDragEnter = _this._onDragEnter.bind(_this);
_this.onDragLeave = _this._onDragLeave.bind(_this);
// See `_restoreEditorDOM()`.
_this.state = { containerKey: 0 };
return _this;
}n/a
blockRendererFn = function () {
return arg;
}n/a
blockStyleFn = function () {
return arg;
}...
var configForType = blockRenderMap.get(blockType);
var wrapperTemplate = configForType.wrapper;
var _Element = configForType.element || blockRenderMap.get('unstyled').element;
var depth = _block.getDepth();
var className = this.props.blockStyleFn(_block);
// List items are special snowflakes, since we handle nesting and
// counters manually.
if (_Element === 'li') {
var shouldResetCount = lastWrapperTemplate !== wrapperTemplate || currentDepth === null || depth > currentDepth;
className = joinClasses(className, getListItemClasses(blockType, depth, shouldResetCount, direction));
}
...function getDefaultKeyBinding(e) {
switch (e.keyCode) {
case 66:
// B
return hasCommandModifier(e) ? 'bold' : null;
case 68:
// D
return isCtrlKeyCommand(e) ? 'delete' : null;
case 72:
// H
return isCtrlKeyCommand(e) ? 'backspace' : null;
case 73:
// I
return hasCommandModifier(e) ? 'italic' : null;
case 74:
// J
return hasCommandModifier(e) ? 'code' : null;
case 75:
// K
return !isWindows && isCtrlKeyCommand(e) ? 'secondary-cut' : null;
case 77:
// M
return isCtrlKeyCommand(e) ? 'split-block' : null;
case 79:
// O
return isCtrlKeyCommand(e) ? 'split-block' : null;
case 84:
// T
return isOSX && isCtrlKeyCommand(e) ? 'transpose-characters' : null;
case 85:
// U
return hasCommandModifier(e) ? 'underline' : null;
case 87:
// W
return isOSX && isCtrlKeyCommand(e) ? 'backspace-word' : null;
case 89:
// Y
if (isCtrlKeyCommand(e)) {
return isWindows ? 'redo' : 'secondary-paste';
}
return null;
case 90:
// Z
return getZCommand(e) || null;
case Keys.RETURN:
return 'split-block';
case Keys.DELETE:
return getDeleteCommand(e);
case Keys.BACKSPACE:
return getBackspaceCommand(e);
// LEFT/RIGHT handlers serve as a workaround for a Firefox bug.
case Keys.LEFT:
return shouldFixFirefoxMovement && hasCommandModifier(e) ? 'move-selection-to-start-of-block' : null;
case Keys.RIGHT:
return shouldFixFirefoxMovement && hasCommandModifier(e) ? 'move-selection-to-end-of-block' : null;
default:
return null;
}
}...
// Insert a nbsp into the editor.
var contentState = DraftModifier.replaceText(editorState.getCurrentContent(), editorState.getSelection(), '\xA0');
editor.update(EditorState.push(editorState, contentState, 'insert-characters'));
return;
}
}
var command = editor.props.keyBindingFn(e);
// If no command is specified, allow keydown event to continue.
if (!command) {
return;
}
if (command === 'undo') {
...function _blur() {
ReactDOM.findDOMNode(this.refs.editor).blur();
}n/a
function _buildHandler(eventName) {
var _this2 = this;
return function (e) {
if (!_this2.props.readOnly) {
var method = _this2._handler && _this2._handler[eventName];
method && method(_this2, e);
}
};
}...
_this._clipboard = null;
_this._handler = null;
_this._dragCount = 0;
_this._editorKey = generateRandomKey();
_this._placeholderAccessibilityID = 'placeholder-' + _this._editorKey;
_this._latestEditorState = props.editorState;
_this._onBeforeInput = _this._buildHandler('onBeforeInput');
_this._onBlur = _this._buildHandler('onBlur');
_this._onCharacterData = _this._buildHandler('onCharacterData');
_this._onCompositionEnd = _this._buildHandler('onCompositionEnd');
_this._onCompositionStart = _this._buildHandler('onCompositionStart');
_this._onCopy = _this._buildHandler('onCopy');
_this._onCut = _this._buildHandler('onCut');
_this._onDragEnd = _this._buildHandler('onDragEnd');
...function _exitCurrentMode() {
this.setMode('edit');
}n/a
function _focus(scrollPosition) {
var editorState = this.props.editorState;
var alreadyHasFocus = editorState.getSelection().getHasFocus();
var editorNode = ReactDOM.findDOMNode(this.refs.editor);
var scrollParent = Style.getScrollParent(editorNode);
var _ref = scrollPosition || getScrollPosition(scrollParent);
var x = _ref.x;
var y = _ref.y;
editorNode.focus();
if (scrollParent === window) {
window.scrollTo(x, y);
} else {
Scroll.setTop(scrollParent, y);
}
// On Chrome and Safari, calling focus on contenteditable focuses the
// cursor at the first character. This is something you don't expect when
// you're clicking on an input element but not directly on a character.
// Put the cursor back where it was before the blur.
if (!alreadyHasFocus) {
this.update(EditorState.forceSelection(editorState, editorState.getSelection()));
}
}...
*/
DraftEditor.prototype._restoreEditorDOM = function _restoreEditorDOM(scrollPosition) {
var _this3 = this;
this.setState({ containerKey: this.state.containerKey + 1 }, function () {
_this3._focus(scrollPosition);
});
};
/**
* Used via `this.setClipboard(...)`.
*
* Set the clipboard state for a cut/copy event.
...function _getClipboard() {
return this._clipboard;
}n/a
function _onDragEnter() {
this._dragCount++;
}n/a
function _onDragLeave() {
this._dragCount--;
if (this._dragCount === 0) {
this.exitCurrentMode();
}
}n/a
function _renderPlaceholder() {
if (this._showPlaceholder()) {
return React.createElement(DraftEditorPlaceholder, {
text: nullthrows(this.props.placeholder),
editorState: this.props.editorState,
textAlignment: this.props.textAlignment,
accessibilityID: this._placeholderAccessibilityID
});
}
return null;
}...
whiteSpace: 'pre-wrap',
wordWrap: 'break-word'
};
return React.createElement(
'div',
{ className: rootClass },
this._renderPlaceholder(),
React.createElement(
'div',
{
className: cx('DraftEditor/editorContainer'),
key: 'editor' + this.state.containerKey,
ref: 'editorContainer' },
React.createElement(
...function _restoreEditorDOM(scrollPosition) {
var _this3 = this;
this.setState({ containerKey: this.state.containerKey + 1 }, function () {
_this3._focus(scrollPosition);
});
}n/a
function _setClipboard(clipboard) {
this._clipboard = clipboard;
}n/a
function _setMode(mode) {
this._handler = handlerMap[mode];
}n/a
function _showPlaceholder() {
return !!this.props.placeholder && !this.props.editorState.isInCompositionMode() && !this.props.editorState.getCurrentContent().
hasText();
}...
};
DraftEditor.prototype._showPlaceholder = function _showPlaceholder() {
return !!this.props.placeholder && !this.props.editorState.isInCompositionMode() && !this.props.editorState
.getCurrentContent().hasText();
};
DraftEditor.prototype._renderPlaceholder = function _renderPlaceholder() {
if (this._showPlaceholder()) {
return React.createElement(DraftEditorPlaceholder, {
text: nullthrows(this.props.placeholder),
editorState: this.props.editorState,
textAlignment: this.props.textAlignment,
accessibilityID: this._placeholderAccessibilityID
});
}
...function _update(editorState) {
this._latestEditorState = editorState;
this.props.onChange(editorState);
}n/a
function componentDidMount() {
this.setMode('edit');
/**
* IE has a hardcoded "feature" that attempts to convert link text into
* anchors in contentEditable DOM. This breaks the editor's expectations of
* the DOM, and control is lost. Disable it to make IE behave.
* See: http://blogs.msdn.com/b/ieinternals/archive/2010/09/15/
* ie9-beta-minor-change-list.aspx
*/
if (isIE) {
document.execCommand('AutoUrlDetect', false, false);
}
}n/a
function componentDidUpdate() {
this._blockSelectEvents = false;
}n/a
function componentWillUpdate(nextProps) {
this._blockSelectEvents = true;
this._latestEditorState = nextProps.editorState;
}n/a
function render() {
var _props = this.props;
var readOnly = _props.readOnly;
var textAlignment = _props.textAlignment;
var rootClass = cx({
'DraftEditor/root': true,
'DraftEditor/alignLeft': textAlignment === 'left',
'DraftEditor/alignRight': textAlignment === 'right',
'DraftEditor/alignCenter': textAlignment === 'center'
});
var contentStyle = {
outline: 'none',
whiteSpace: 'pre-wrap',
wordWrap: 'break-word'
};
return React.createElement(
'div',
{ className: rootClass },
this._renderPlaceholder(),
React.createElement(
'div',
{
className: cx('DraftEditor/editorContainer'),
key: 'editor' + this.state.containerKey,
ref: 'editorContainer' },
React.createElement(
'div',
{
'aria-activedescendant': readOnly ? null : this.props.ariaActiveDescendantID,
'aria-autocomplete': readOnly ? null : this.props.ariaAutoComplete,
'aria-describedby': this._showPlaceholder() ? this._placeholderAccessibilityID : null,
'aria-expanded': readOnly ? null : this.props.ariaExpanded,
'aria-haspopup': readOnly ? null : this.props.ariaHasPopup,
'aria-label': this.props.ariaLabel,
'aria-owns': readOnly ? null : this.props.ariaOwneeID,
className: cx('public/DraftEditor/content'),
contentEditable: !readOnly,
'data-testid': this.props.webDriverTestID,
onBeforeInput: this._onBeforeInput,
onBlur: this._onBlur,
onCompositionEnd: this._onCompositionEnd,
onCompositionStart: this._onCompositionStart,
onCopy: this._onCopy,
onCut: this._onCut,
onDragEnd: this._onDragEnd,
onDragEnter: this.onDragEnter,
onDragLeave: this.onDragLeave,
onDragOver: this._onDragOver,
onDragStart: this._onDragStart,
onDrop: this._onDrop,
onFocus: this._onFocus,
onInput: this._onInput,
onKeyDown: this._onKeyDown,
onKeyPress: this._onKeyPress,
onKeyUp: this._onKeyUp,
onMouseUp: this._onMouseUp,
onPaste: this._onPaste,
onSelect: this._onSelect,
ref: 'editor',
role: readOnly ? null : this.props.role || 'textbox',
spellCheck: allowSpellCheck && this.props.spellCheck,
style: contentStyle,
suppressContentEditableWarning: true,
tabIndex: this.props.tabIndex },
React.createElement(DraftEditorContents, {
blockRenderMap: this.props.blockRenderMap,
blockRendererFn: this.props.blockRendererFn,
blockStyleFn: this.props.blockStyleFn,
customStyleMap: _extends({}, DefaultDraftInlineStyle, this.props.customStyleMap),
customStyleFn: this.props.customStyleFn,
editorKey: this._editorKey,
editorState: this.props.editorState
})
)
)
);
}...
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('container')
);
```
Because Draft.js supports unicode, you must have the following meta tag in the `<head>` `</head>` block of your
HTML file:
...function getDirectionMap(content, prevBidiMap) {
if (!bidiService) {
bidiService = new UnicodeBidiService();
} else {
bidiService.reset();
}
var blockMap = content.getBlockMap();
var nextBidi = blockMap.valueSeq().map(function (block) {
return nullthrows(bidiService).getDirection(block.getText());
});
var bidiMap = OrderedMap(blockMap.keySeq().zip(nextBidi));
if (prevBidiMap != null && Immutable.is(prevBidiMap, bidiMap)) {
return prevBidiMap;
}
return bidiMap;
}...
EditorState.create = function create(config) {
var currentContent = config.currentContent;
var decorator = config.decorator;
var recordConfig = _extends({}, config, {
treeMap: generateNewTreeMap(currentContent, decorator),
directionMap: EditorBidiService.getDirectionMap(currentContent)
});
return new EditorState(new EditorStateRecord(recordConfig));
};
EditorState.set = function set(editorState, put) {
var map = editorState.getImmutable().withMutations(function (state) {
var existingDecorator = state.get('decorator');
...function DraftEditorBlock() {
_classCallCheck(this, DraftEditorBlock);
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments));
}n/a
function _renderChildren() {
var _this2 = this;
var block = this.props.block;
var blockKey = block.getKey();
var text = block.getText();
var lastLeafSet = this.props.tree.size - 1;
var hasSelection = isBlockOnSelectionEdge(this.props.selection, blockKey);
return this.props.tree.map(function (leafSet, ii) {
var leavesForLeafSet = leafSet.get('leaves');
var lastLeaf = leavesForLeafSet.size - 1;
var leaves = leavesForLeafSet.map(function (leaf, jj) {
var offsetKey = DraftOffsetKey.encode(blockKey, ii, jj);
var start = leaf.get('start');
var end = leaf.get('end');
return React.createElement(DraftEditorLeaf, {
key: offsetKey,
offsetKey: offsetKey,
blockKey: blockKey,
start: start,
selection: hasSelection ? _this2.props.selection : undefined,
forceSelection: _this2.props.forceSelection,
text: text.slice(start, end),
styleSet: block.getInlineStyleAt(start),
customStyleMap: _this2.props.customStyleMap,
customStyleFn: _this2.props.customStyleFn,
isLast: ii === lastLeafSet && jj === lastLeaf
});
}).toArray();
var decoratorKey = leafSet.get('decoratorKey');
if (decoratorKey == null) {
return leaves;
}
if (!_this2.props.decorator) {
return leaves;
}
var decorator = nullthrows(_this2.props.decorator);
var DecoratorComponent = decorator.getComponentForKey(decoratorKey);
if (!DecoratorComponent) {
return leaves;
}
var decoratorProps = decorator.getPropsForKey(decoratorKey);
var decoratorOffsetKey = DraftOffsetKey.encode(blockKey, ii, 0);
var decoratedText = text.slice(leavesForLeafSet.first().get('start'), leavesForLeafSet.last().get('end'));
// Resetting dir to the same value on a child node makes Chrome/Firefox
// confused on cursor movement. See http://jsfiddle.net/d157kLck/3/
var dir = UnicodeBidiDirection.getHTMLDirIfDifferent(UnicodeBidi.getDirection(decoratedText), _this2.props.direction);
return React.createElement(
DecoratorComponent,
_extends({}, decoratorProps, {
contentState: _this2.props.contentState,
decoratedText: decoratedText,
dir: dir,
key: decoratorOffsetKey,
entityKey: block.getEntityAt(leafSet.get('start')),
offsetKey: decoratorOffsetKey }),
leaves
);
}).toArray();
}...
'public/DraftStyleDefault/ltr': direction === 'LTR',
'public/DraftStyleDefault/rtl': direction === 'RTL'
});
return React.createElement(
'div',
{ 'data-offset-key': offsetKey, className: className },
this._renderChildren()
);
};
return DraftEditorBlock;
}(React.Component);
/**
...function componentDidMount() {
var selection = this.props.selection;
var endKey = selection.getEndKey();
if (!selection.getHasFocus() || endKey !== this.props.block.getKey()) {
return;
}
var blockNode = ReactDOM.findDOMNode(this);
var scrollParent = Style.getScrollParent(blockNode);
var scrollPosition = getScrollPosition(scrollParent);
var scrollDelta;
if (scrollParent === window) {
var nodePosition = getElementPosition(blockNode);
var nodeBottom = nodePosition.y + nodePosition.height;
var viewportHeight = getViewportDimensions().height;
scrollDelta = nodeBottom - viewportHeight;
if (scrollDelta > 0) {
window.scrollTo(scrollPosition.x, scrollPosition.y + scrollDelta + SCROLL_BUFFER);
}
} else {
var blockBottom = blockNode.offsetHeight + blockNode.offsetTop;
var scrollBottom = scrollParent.offsetHeight + scrollPosition.y;
scrollDelta = blockBottom - scrollBottom;
if (scrollDelta > 0) {
Scroll.setTop(scrollParent, Scroll.getTop(scrollParent) + scrollDelta + SCROLL_BUFFER);
}
}
}n/a
function render() {
var _props = this.props;
var direction = _props.direction;
var offsetKey = _props.offsetKey;
var className = cx({
'public/DraftStyleDefault/block': true,
'public/DraftStyleDefault/ltr': direction === 'LTR',
'public/DraftStyleDefault/rtl': direction === 'RTL'
});
return React.createElement(
'div',
{ 'data-offset-key': offsetKey, className: className },
this._renderChildren()
);
}...
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<MyEditor />,
document.getElementById('container')
);
```
Because Draft.js supports unicode, you must have the following meta tag in the `<head>` `</head>` block of your
HTML file:
...function shouldComponentUpdate(nextProps) {
return this.props.block !== nextProps.block || this.props.tree !== nextProps.tree || this.props.direction !== nextProps.direction
|| isBlockOnSelectionEdge(nextProps.selection, nextProps.block.getKey()) && nextProps.forceSelection;
}n/a
function EditorState(immutable) {
_classCallCheck(this, EditorState);
this._immutable = immutable;
}n/a
function acceptSelection(editorState, selection) {
return updateSelection(editorState, selection, false);
}...
EditorState.moveSelectionToEnd = function moveSelectionToEnd(editorState) {
var content = editorState.getCurrentContent();
var lastBlock = content.getLastBlock();
var lastKey = lastBlock.getKey();
var length = lastBlock.getLength();
return EditorState.acceptSelection(editorState, new SelectionState({
anchorKey: lastKey,
anchorOffset: length,
focusKey: lastKey,
focusOffset: length,
isBackward: false
}));
};
...function create(config) {
var currentContent = config.currentContent;
var decorator = config.decorator;
var recordConfig = _extends({}, config, {
treeMap: generateNewTreeMap(currentContent, decorator),
directionMap: EditorBidiService.getDirectionMap(currentContent)
});
return new EditorState(new EditorStateRecord(recordConfig));
}...
var EditorState = function () {
EditorState.createEmpty = function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''), decorator);
};
EditorState.createWithContent = function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
redoStack: Stack(),
decorator: decorator || null,
selection: SelectionState.createEmpty(firstKey)
});
};
...function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''), decorator);
}...
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
...function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
redoStack: Stack(),
decorator: decorator || null,
selection: SelectionState.createEmpty(firstKey)
});
}...
undoStack: Stack()
};
var EditorStateRecord = Record(defaultRecord);
var EditorState = function () {
EditorState.createEmpty = function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''),
decorator);
};
EditorState.createWithContent = function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
...function forceSelection(editorState, selection) {
if (!selection.getHasFocus()) {
selection = selection.set('hasFocus', true);
}
return updateSelection(editorState, selection, true);
}...
* where we want to programmatically focus the input and it makes sense
* to allow the user to continue working seamlessly.
*/
EditorState.moveFocusToEnd = function moveFocusToEnd(editorState) {
var afterSelectionMove = EditorState.moveSelectionToEnd(editorState);
return EditorState.forceSelection(afterSelectionMove, afterSelectionMove.getSelection
());
};
/**
* Push the current ContentState onto the undo stack if it should be
* considered a boundary state, and set the provided ContentState as the
* new current content.
*/
...function moveFocusToEnd(editorState) {
var afterSelectionMove = EditorState.moveSelectionToEnd(editorState);
return EditorState.forceSelection(afterSelectionMove, afterSelectionMove.getSelection());
}n/a
function moveSelectionToEnd(editorState) {
var content = editorState.getCurrentContent();
var lastBlock = content.getLastBlock();
var lastKey = lastBlock.getKey();
var length = lastBlock.getLength();
return EditorState.acceptSelection(editorState, new SelectionState({
anchorKey: lastKey,
anchorOffset: length,
focusKey: lastKey,
focusOffset: length,
isBackward: false
}));
}...
* Force focus to the end of the editor. This is useful in scenarios
* where we want to programmatically focus the input and it makes sense
* to allow the user to continue working seamlessly.
*/
EditorState.moveFocusToEnd = function moveFocusToEnd(editorState) {
var afterSelectionMove = EditorState.moveSelectionToEnd(editorState);
return EditorState.forceSelection(afterSelectionMove, afterSelectionMove.getSelection());
};
/**
* Push the current ContentState onto the undo stack if it should be
* considered a boundary state, and set the provided ContentState as the
* new current content.
...function push(editorState, contentState, changeType) {
if (editorState.getCurrentContent() === contentState) {
return editorState;
}
var forceSelection = changeType !== 'insert-characters';
var directionMap = EditorBidiService.getDirectionMap(contentState, editorState.getDirectionMap());
if (!editorState.getAllowUndo()) {
return EditorState.set(editorState, {
currentContent: contentState,
directionMap: directionMap,
lastChangeType: changeType,
selection: contentState.getSelectionAfter(),
forceSelection: forceSelection,
inlineStyleOverride: null
});
}
var selection = editorState.getSelection();
var currentContent = editorState.getCurrentContent();
var undoStack = editorState.getUndoStack();
var newContent = contentState;
if (selection !== currentContent.getSelectionAfter() || mustBecomeBoundary(editorState, changeType)) {
undoStack = undoStack.push(currentContent);
newContent = newContent.set('selectionBefore', selection);
} else if (changeType === 'insert-characters' || changeType === 'backspace-character' || changeType === 'delete-character') {
// Preserve the previous selection.
newContent = newContent.set('selectionBefore', currentContent.getSelectionBefore());
}
var inlineStyleOverride = editorState.getInlineStyleOverride();
// Don't discard inline style overrides on block type or depth changes.
if (changeType !== 'adjust-depth' && changeType !== 'change-block-type') {
inlineStyleOverride = null;
}
var editorStateChanges = {
currentContent: newContent,
directionMap: directionMap,
undoStack: undoStack,
redoStack: Stack(),
lastChangeType: changeType,
selection: contentState.getSelectionAfter(),
forceSelection: forceSelection,
inlineStyleOverride: inlineStyleOverride
};
return EditorState.set(editorState, editorStateChanges);
}...
var selection = editorState.getSelection();
var currentContent = editorState.getCurrentContent();
var undoStack = editorState.getUndoStack();
var newContent = contentState;
if (selection !== currentContent.getSelectionAfter() || mustBecomeBoundary(editorState, changeType)) {
undoStack = undoStack.push(currentContent);
newContent = newContent.set('selectionBefore', selection);
} else if (changeType === 'insert-characters' || changeType === 'backspace-character' || changeType ===
x27;delete-character') {
// Preserve the previous selection.
newContent = newContent.set('selectionBefore', currentContent.getSelectionBefore());
}
var inlineStyleOverride = editorState.getInlineStyleOverride();
...function redo(editorState) {
if (!editorState.getAllowUndo()) {
return editorState;
}
var redoStack = editorState.getRedoStack();
var newCurrentContent = redoStack.peek();
if (!newCurrentContent) {
return editorState;
}
var currentContent = editorState.getCurrentContent();
var directionMap = EditorBidiService.getDirectionMap(newCurrentContent, editorState.getDirectionMap());
return EditorState.set(editorState, {
currentContent: newCurrentContent,
directionMap: directionMap,
undoStack: editorState.getUndoStack().push(currentContent),
redoStack: redoStack.shift(),
forceSelection: true,
inlineStyleOverride: null,
lastChangeType: 'redo',
nativelyRenderedContent: null,
selection: newCurrentContent.getSelectionAfter()
});
}...
/**
* Map a `DraftEditorCommand` command value to a corresponding function.
*/
function onKeyCommand(command, editorState) {
switch (command) {
case 'redo':
return EditorState.redo(editorState);
case 'delete':
return keyCommandPlainDelete(editorState);
case 'delete-word':
return keyCommandDeleteWord(editorState);
case 'backspace':
return keyCommandPlainBackspace(editorState);
case 'backspace-word':
...function set(editorState, put) {
var map = editorState.getImmutable().withMutations(function (state) {
var existingDecorator = state.get('decorator');
var decorator = existingDecorator;
if (put.decorator === null) {
decorator = null;
} else if (put.decorator) {
decorator = put.decorator;
}
var newContent = put.currentContent || editorState.getCurrentContent();
if (decorator !== existingDecorator) {
var treeMap = state.get('treeMap');
var newTreeMap;
if (decorator && existingDecorator) {
newTreeMap = regenerateTreeForNewDecorator(newContent, newContent.getBlockMap(), treeMap, decorator, existingDecorator);
} else {
newTreeMap = generateNewTreeMap(newContent, decorator);
}
state.merge({
decorator: decorator,
treeMap: newTreeMap,
nativelyRenderedContent: null
});
return;
}
var existingContent = editorState.getCurrentContent();
if (newContent !== existingContent) {
state.set('treeMap', regenerateTreeForNewBlocks(editorState, newContent.getBlockMap(), newContent.getEntityMap(), decorator
));
}
state.merge(put);
});
return new EditorState(map);
}...
nativelyRenderedContent: null
});
return;
}
var existingContent = editorState.getCurrentContent();
if (newContent !== existingContent) {
state.set('treeMap', regenerateTreeForNewBlocks(editorState, newContent
.getBlockMap(), newContent.getEntityMap(), decorator));
}
state.merge(put);
});
return new EditorState(map);
};
...function setInlineStyleOverride(editorState, inlineStyleOverride) {
return EditorState.set(editorState, { inlineStyleOverride: inlineStyleOverride });
}...
var selection = editorState.getSelection();
var currentStyle = editorState.getCurrentInlineStyle();
// If the selection is collapsed, toggle the specified style on or off and
// set the result as the new inline style override. This will then be
// used as the inline style for the next character to be inserted.
if (selection.isCollapsed()) {
return EditorState.setInlineStyleOverride(editorState, currentStyle.has(inlineStyle
) ? currentStyle.remove(inlineStyle) : currentStyle.add(inlineStyle));
}
// If characters are selected, immediately apply or remove the
// inline style on the document state itself.
var content = editorState.getCurrentContent();
var newContent;
...function undo(editorState) {
if (!editorState.getAllowUndo()) {
return editorState;
}
var undoStack = editorState.getUndoStack();
var newCurrentContent = undoStack.peek();
if (!newCurrentContent) {
return editorState;
}
var currentContent = editorState.getCurrentContent();
var directionMap = EditorBidiService.getDirectionMap(newCurrentContent, editorState.getDirectionMap());
return EditorState.set(editorState, {
currentContent: newCurrentContent,
directionMap: directionMap,
undoStack: undoStack.shift(),
redoStack: editorState.getRedoStack().push(currentContent),
forceSelection: true,
inlineStyleOverride: null,
lastChangeType: 'undo',
nativelyRenderedContent: null,
selection: currentContent.getSelectionBefore()
});
}...
*/
'use strict';
var EditorState = require('./EditorState');
function keyCommandUndo(e, editorState, updateFn) {
var undoneState = EditorState.undo(editorState);
// If the last change to occur was a spellcheck change, allow the undo
// event to fall through to the browser. This allows the browser to record
// the unwanted change, which should soon lead it to learn not to suggest
// the correction again.
if (editorState.getLastChangeType() === 'spellcheck-change') {
var nativelyRenderedContent = undoneState.getCurrentContent();
...function getAllowUndo() {
return this.getImmutable().get('allowUndo');
}...
if (editorState.getCurrentContent() === contentState) {
return editorState;
}
var forceSelection = changeType !== 'insert-characters';
var directionMap = EditorBidiService.getDirectionMap(contentState, editorState.getDirectionMap());
if (!editorState.getAllowUndo()) {
return EditorState.set(editorState, {
currentContent: contentState,
directionMap: directionMap,
lastChangeType: changeType,
selection: contentState.getSelectionAfter(),
forceSelection: forceSelection,
inlineStyleOverride: null
...function getBlockTree(blockKey) {
return this.getImmutable().getIn(['treeMap', blockKey]);
}...
/*eslint-enable no-console */
return selection;
}
}
var anchorPath = DraftOffsetKey.decode(anchorKey);
var anchorBlockKey = anchorPath.blockKey;
var anchorLeaf = editorState.getBlockTree(anchorBlockKey).getIn([anchorPath.decoratorKey
, 'leaves', anchorPath.leafKey]);
var focusPath = DraftOffsetKey.decode(focusKey);
var focusBlockKey = focusPath.blockKey;
var focusLeaf = editorState.getBlockTree(focusBlockKey).getIn([focusPath.decoratorKey, 'leaves', focusPath.leafKey]);
var anchorLeafStart = anchorLeaf.get('start');
var focusLeafStart = focusLeaf.get('start');
...function getCurrentContent() {
return this.getImmutable().get('currentContent');
}...
var decorator = existingDecorator;
if (put.decorator === null) {
decorator = null;
} else if (put.decorator) {
decorator = put.decorator;
}
var newContent = put.currentContent || editorState.getCurrentContent();
if (decorator !== existingDecorator) {
var treeMap = state.get('treeMap');
var newTreeMap;
if (decorator && existingDecorator) {
newTreeMap = regenerateTreeForNewDecorator(newContent, newContent.getBlockMap(), treeMap, decorator, existingDecorator
);
} else {
...function getCurrentInlineStyle() {
var override = this.getInlineStyleOverride();
if (override != null) {
return override;
}
var content = this.getCurrentContent();
var selection = this.getSelection();
if (selection.isCollapsed()) {
return getInlineStyleForCollapsedSelection(content, selection);
}
return getInlineStyleForNonCollapsedSelection(content, selection);
}...
var composedChars = textInputData;
textInputData = '';
var editorState = EditorState.set(editor._latestEditorState, {
inCompositionMode: false
});
var currentStyle = editorState.getCurrentInlineStyle();
var entityKey = getEntityKeyForSelection(editorState.getCurrentContent(), editorState.getSelection());
var mustReset = !composedChars || isSelectionAtLeafStart(editorState) || currentStyle.size > 0 || entityKey !== null;
if (mustReset) {
editor.restoreEditorDOM();
}
...function getDecorator() {
return this.getImmutable().get('decorator');
}...
// rendered state, there's nothing new to be done.
if (prevEditorState === nextEditorState || nextNativeContent !== null && nextEditorState.getCurrentContent() ===
nextNativeContent || wasComposing && nowComposing) {
return false;
}
var prevContent = prevEditorState.getCurrentContent();
var nextContent = nextEditorState.getCurrentContent();
var prevDecorator = prevEditorState.getDecorator();
var nextDecorator = nextEditorState.getDecorator();
return wasComposing !== nowComposing || prevContent !== nextContent || prevDecorator !== nextDecorator || nextEditorState.mustForceSelection
();
};
DraftEditorContents.prototype.render = function render() {
var _props = this.props;
var blockRenderMap = _props.blockRenderMap;
...function getDirectionMap() {
return this.getImmutable().get('directionMap');
}...
EditorState.create = function create(config) {
var currentContent = config.currentContent;
var decorator = config.decorator;
var recordConfig = _extends({}, config, {
treeMap: generateNewTreeMap(currentContent, decorator),
directionMap: EditorBidiService.getDirectionMap(currentContent)
});
return new EditorState(new EditorStateRecord(recordConfig));
};
EditorState.set = function set(editorState, put) {
var map = editorState.getImmutable().withMutations(function (state) {
var existingDecorator = state.get('decorator');
...function getImmutable() {
return this._immutable;
}...
treeMap: generateNewTreeMap(currentContent, decorator),
directionMap: EditorBidiService.getDirectionMap(currentContent)
});
return new EditorState(new EditorStateRecord(recordConfig));
};
EditorState.set = function set(editorState, put) {
var map = editorState.getImmutable().withMutations(function (state) {
var existingDecorator = state.get('decorator');
var decorator = existingDecorator;
if (put.decorator === null) {
decorator = null;
} else if (put.decorator) {
decorator = put.decorator;
}
...function getInlineStyleOverride() {
return this.getImmutable().get('inlineStyleOverride');
}...
* Get the appropriate inline style for the editor state. If an
* override is in place, use it. Otherwise, the current style is
* based on the location of the selection state.
*/
EditorState.prototype.getCurrentInlineStyle = function getCurrentInlineStyle() {
var override = this.getInlineStyleOverride();
if (override != null) {
return override;
}
var content = this.getCurrentContent();
var selection = this.getSelection();
...function getLastChangeType() {
return this.getImmutable().get('lastChangeType');
}...
/**
* Return whether a change should be considered a boundary state, given
* the previous change type. Allows us to discard potential boundary states
* during standard typing or deletion behavior.
*/
function mustBecomeBoundary(editorState, changeType) {
var lastChangeType = editorState.getLastChangeType();
return changeType !== lastChangeType || changeType !== 'insert-characters' && changeType !== 'backspace
-character' && changeType !== 'delete-character';
}
function getInlineStyleForCollapsedSelection(content, selection) {
var startKey = selection.getStartKey();
var startOffset = selection.getStartOffset();
var startBlock = content.getBlockForKey(startKey);
...function getNativelyRenderedContent() {
return this.getImmutable().get('nativelyRenderedContent');
}...
var didHaveFocus = prevEditorState.getSelection().getHasFocus();
var nowHasFocus = nextEditorState.getSelection().getHasFocus();
if (didHaveFocus !== nowHasFocus) {
return true;
}
var nextNativeContent = nextEditorState.getNativelyRenderedContent();
var wasComposing = prevEditorState.isInCompositionMode();
var nowComposing = nextEditorState.isInCompositionMode();
// If the state is unchanged or we're currently rendering a natively
// rendered state, there's nothing new to be done.
if (prevEditorState === nextEditorState || nextNativeContent !== null && nextEditorState.getCurrentContent() ===
nextNativeContent || wasComposing && nowComposing) {
...function getRedoStack() {
return this.getImmutable().get('redoStack');
}...
var currentContent = editorState.getCurrentContent();
var directionMap = EditorBidiService.getDirectionMap(newCurrentContent, editorState.getDirectionMap());
return EditorState.set(editorState, {
currentContent: newCurrentContent,
directionMap: directionMap,
undoStack: undoStack.shift(),
redoStack: editorState.getRedoStack().push(currentContent),
forceSelection: true,
inlineStyleOverride: null,
lastChangeType: 'undo',
nativelyRenderedContent: null,
selection: currentContent.getSelectionBefore()
});
};
...function getSelection() {
return this.getImmutable().get('selection');
}...
EditorState.prototype.getCurrentInlineStyle = function getCurrentInlineStyle() {
var override = this.getInlineStyleOverride();
if (override != null) {
return override;
}
var content = this.getCurrentContent();
var selection = this.getSelection();
if (selection.isCollapsed()) {
return getInlineStyleForCollapsedSelection(content, selection);
}
return getInlineStyleForNonCollapsedSelection(content, selection);
};
...function getUndoStack() {
return this.getImmutable().get('undoStack');
}...
forceSelection: forceSelection,
inlineStyleOverride: null
});
}
var selection = editorState.getSelection();
var currentContent = editorState.getCurrentContent();
var undoStack = editorState.getUndoStack();
var newContent = contentState;
if (selection !== currentContent.getSelectionAfter() || mustBecomeBoundary(editorState, changeType)) {
undoStack = undoStack.push(currentContent);
newContent = newContent.set('selectionBefore', selection);
} else if (changeType === 'insert-characters' || changeType === 'backspace-character' || changeType ===
x27;delete-character') {
// Preserve the previous selection.
...function isInCompositionMode() {
return this.getImmutable().get('inCompositionMode');
}...
var method = _this2._handler && _this2._handler[eventName];
method && method(_this2, e);
}
};
};
DraftEditor.prototype._showPlaceholder = function _showPlaceholder() {
return !!this.props.placeholder && !this.props.editorState.isInCompositionMode
() && !this.props.editorState.getCurrentContent().hasText();
};
DraftEditor.prototype._renderPlaceholder = function _renderPlaceholder() {
if (this._showPlaceholder()) {
return React.createElement(DraftEditorPlaceholder, {
text: nullthrows(this.props.placeholder),
editorState: this.props.editorState,
...function isSelectionAtEndOfContent() {
var content = this.getCurrentContent();
var blockMap = content.getBlockMap();
var last = blockMap.last();
var end = last.getLength();
return this.getSelection().hasEdgeWithin(last.getKey(), end, end);
}...
*/
function removeTextWithStrategy(editorState, strategy, direction) {
var selection = editorState.getSelection();
var content = editorState.getCurrentContent();
var target = selection;
if (selection.isCollapsed()) {
if (direction === 'forward') {
if (editorState.isSelectionAtEndOfContent()) {
return content;
}
} else if (editorState.isSelectionAtStartOfContent()) {
return content;
}
target = strategy(editorState);
...function isSelectionAtStartOfContent() {
var firstKey = this.getCurrentContent().getBlockMap().first().getKey();
return this.getSelection().hasEdgeWithin(firstKey, 0, 0);
}...
var content = editorState.getCurrentContent();
var target = selection;
if (selection.isCollapsed()) {
if (direction === 'forward') {
if (editorState.isSelectionAtEndOfContent()) {
return content;
}
} else if (editorState.isSelectionAtStartOfContent()) {
return content;
}
target = strategy(editorState);
if (target === selection) {
return content;
}
...function mustForceSelection() {
return this.getImmutable().get('forceSelection');
}...
return false;
}
var prevContent = prevEditorState.getCurrentContent();
var nextContent = nextEditorState.getCurrentContent();
var prevDecorator = prevEditorState.getDecorator();
var nextDecorator = nextEditorState.getDecorator();
return wasComposing !== nowComposing || prevContent !== nextContent || prevDecorator !== nextDecorator || nextEditorState.<
span class="apidocCodeKeywordSpan">mustForceSelection();
};
DraftEditorContents.prototype.render = function render() {
var _props = this.props;
var blockRenderMap = _props.blockRenderMap;
var blockRendererFn = _props.blockRendererFn;
var customStyleMap = _props.customStyleMap;
...function toJS() {
return this.getImmutable().toJS();
}...
state.merge(put);
});
return new EditorState(map);
};
EditorState.prototype.toJS = function toJS() {
return this.getImmutable().toJS();
};
EditorState.prototype.getAllowUndo = function getAllowUndo() {
return this.getImmutable().get('allowUndo');
};
EditorState.prototype.getCurrentContent = function getCurrentContent() {
...function __add(instance) {
var key = '' + ++instanceKey;
instances = instances.set(key, instance);
return key;
}...
// TODO: update this when we fully remove DraftEntity
DraftEntity.__replaceData(key, newData);
return this;
};
ContentState.prototype.addEntity = function addEntity(instance) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__add(instance);
return this;
};
ContentState.prototype.getEntity = function getEntity(key) {
// TODO: update this when we fully remove DraftEntity
return DraftEntity.__get(key);
};
...function __create(type, mutability, data) {
return DraftEntity.__add(new DraftEntityInstance({ type: type, mutability: mutability, data: data || {} }));
}...
ContentState.prototype.hasText = function hasText() {
var blockMap = this.getBlockMap();
return blockMap.size > 1 || blockMap.first().getLength() > 0;
};
ContentState.prototype.createEntity = function createEntity(type, mutability, data) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__create(type, mutability, data);
return this;
};
ContentState.prototype.mergeEntityData = function mergeEntityData(key, toMerge) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__mergeData(key, toMerge);
return this;
...function __get(key) {
var instance = instances.get(key);
!!!instance ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Unknown DraftEntity key.') : invariant(false) : void 0
;
return instance;
}...
// TODO: update this when we fully remove DraftEntity
DraftEntity.__add(instance);
return this;
};
ContentState.prototype.getEntity = function getEntity(key) {
// TODO: update this when we fully remove DraftEntity
return DraftEntity.__get(key);
};
ContentState.createFromBlockArray = function createFromBlockArray(
// TODO: update flow type when we completely deprecate the old entity API
blocks, entityMap) {
// TODO: remove this when we completely deprecate the old entity API
var theBlocks = Array.isArray(blocks) ? blocks : blocks.contentBlocks;
...function __getLastCreatedEntityKey() {
return '' + instanceKey;
}...
return this.getBlockMap().map(function (block) {
return block ? block.getText() : '';
}).join(delimiter || '\n');
};
ContentState.prototype.getLastCreatedEntityKey = function getLastCreatedEntityKey() {
// TODO: update this when we fully remove DraftEntity
return DraftEntity.__getLastCreatedEntityKey();
};
ContentState.prototype.hasText = function hasText() {
var blockMap = this.getBlockMap();
return blockMap.size > 1 || blockMap.first().getLength() > 0;
};
...function __mergeData(key, toMerge) {
var instance = DraftEntity.__get(key);
var newData = _extends({}, instance.getData(), toMerge);
var newInstance = instance.set('data', newData);
instances = instances.set(key, newInstance);
return newInstance;
}...
// TODO: update this when we fully remove DraftEntity
DraftEntity.__create(type, mutability, data);
return this;
};
ContentState.prototype.mergeEntityData = function mergeEntityData(key, toMerge) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__mergeData(key, toMerge);
return this;
};
ContentState.prototype.replaceEntityData = function replaceEntityData(key, newData) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__replaceData(key, newData);
return this;
...function __replaceData(key, newData) {
var instance = DraftEntity.__get(key);
var newInstance = instance.set('data', newData);
instances = instances.set(key, newInstance);
return newInstance;
}...
// TODO: update this when we fully remove DraftEntity
DraftEntity.__mergeData(key, toMerge);
return this;
};
ContentState.prototype.replaceEntityData = function replaceEntityData(key, newData) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__replaceData(key, newData);
return this;
};
ContentState.prototype.addEntity = function addEntity(instance) {
// TODO: update this when we fully remove DraftEntity
DraftEntity.__add(instance);
return this;
...function add(instance) {
logWarning('DraftEntity.add', 'contentState.addEntity');
return DraftEntity.__add(instance);
}...
var withoutEntities = removeEntitiesAtEdges(contentState, selectionState);
var withoutText = removeRangeFromContentState(withoutEntities, selectionState);
return splitBlockInContentState(withoutText, withoutText.getSelectionAfter());
},
applyInlineStyle: function applyInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.add(contentState, selectionState, inlineStyle);
},
removeInlineStyle: function removeInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.remove(contentState, selectionState, inlineStyle);
},
setBlockType: function setBlockType(contentState, selectionState, blockType) {
...function create(type, mutability, data) {
logWarning('DraftEntity.create', 'contentState.createEntity');
return DraftEntity.__create(type, mutability, data);
}...
var EditorState = function () {
EditorState.createEmpty = function createEmpty(decorator) {
return EditorState.createWithContent(ContentState.createFromText(''), decorator);
};
EditorState.createWithContent = function createWithContent(contentState, decorator) {
var firstKey = contentState.getBlockMap().first().getKey();
return EditorState.create({
currentContent: contentState,
undoStack: Stack(),
redoStack: Stack(),
decorator: decorator || null,
selection: SelectionState.createEmpty(firstKey)
});
};
...function get(key) {
logWarning('DraftEntity.get', 'contentState.getEntity');
return DraftEntity.__get(key);
}...
directionMap: EditorBidiService.getDirectionMap(currentContent)
});
return new EditorState(new EditorStateRecord(recordConfig));
};
EditorState.set = function set(editorState, put) {
var map = editorState.getImmutable().withMutations(function (state) {
var existingDecorator = state.get('decorator');
var decorator = existingDecorator;
if (put.decorator === null) {
decorator = null;
} else if (put.decorator) {
decorator = put.decorator;
}
...function getLastCreatedEntityKey() {
logWarning('DraftEntity.getLastCreatedEntityKey', 'contentState.getLastCreatedEntityKey');
return DraftEntity.__getLastCreatedEntityKey();
}n/a
function mergeData(key, toMerge) {
logWarning('DraftEntity.mergeData', 'contentState.mergeEntityData');
return DraftEntity.__mergeData(key, toMerge);
}n/a
function replaceData(key, newData) {
logWarning('DraftEntity.replaceData', 'contentState.replaceEntityData');
return DraftEntity.__replaceData(key, newData);
}n/a
function DraftEntityInstance() {
_classCallCheck(this, DraftEntityInstance);
return _possibleConstructorReturn(this, _DraftEntityInstanceR.apply(this, arguments));
}n/a
function getData() {
return this.get('data');
}...
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ data: blockData });
});
},
mergeBlockData: function mergeBlockData(contentState, selectionState, blockData) {
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ data: block.getData().merge(blockData) });
});
},
applyEntity: function applyEntity(contentState, selectionState, entityKey) {
var withoutEntities = removeEntitiesAtEdges(contentState, selectionState);
return applyEntityToContentState(withoutEntities, selectionState, entityKey);
}
...function getMutability() {
return this.get('mutability');
}...
/**
* Determine whether an entity key corresponds to a `MUTABLE` entity. If so,
* return it. If not, return null.
*/
function filterKey(entityMap, entityKey) {
if (entityKey) {
var entity = entityMap.__get(entityKey);
return entity.getMutability() === 'MUTABLE' ? entityKey : null;
}
return null;
}
module.exports = getEntityKeyForSelection;
/***/ },
...function getType() {
return this.get('type');
}...
var processedBlocks = [];
var currentDepth = null;
var lastWrapperTemplate = null;
for (var ii = 0; ii < blocksAsArray.length; ii++) {
var _block = blocksAsArray[ii];
var key = _block.getKey();
var blockType = _block.getType();
var customRenderer = blockRendererFn(_block);
var CustomComponent = void 0,
customProps = void 0,
customEditable = void 0;
if (customRenderer) {
CustomComponent = customRenderer.component;
...function hasCommandModifier(e) {
return isOSX ? !!e.metaKey && !e.altKey : KeyBindingUtil.isCtrlKeyCommand(e);
}n/a
function isCtrlKeyCommand(e) {
return !!e.ctrlKey && !e.altKey;
}...
},
isOptionKeyCommand: function isOptionKeyCommand(e) {
return isOSX && e.altKey;
},
hasCommandModifier: function hasCommandModifier(e) {
return isOSX ? !!e.metaKey && !e.altKey : KeyBindingUtil.isCtrlKeyCommand(e);
}
};
module.exports = KeyBindingUtil;
/***/ },
/* 26 */
...function isOptionKeyCommand(e) {
return isOSX && e.altKey;
}n/a
function applyEntity(contentState, selectionState, entityKey) {
var withoutEntities = removeEntitiesAtEdges(contentState, selectionState);
return applyEntityToContentState(withoutEntities, selectionState, entityKey);
}...
var start = _getRemovalRange.start;
var end = _getRemovalRange.end;
var current;
while (start < end) {
current = chars.get(start);
chars = chars.set(start, CharacterMetadata.applyEntity(current, null));
start++;
}
return block.set('characterList', chars);
}
}
return block;
...function applyInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.add(contentState, selectionState, inlineStyle);
}...
var newContent;
// If the style is already present for the selection range, remove it.
// Otherwise, apply it.
if (currentStyle.has(inlineStyle)) {
newContent = DraftModifier.removeInlineStyle(content, selection, inlineStyle);
} else {
newContent = DraftModifier.applyInlineStyle(content, selection, inlineStyle);
}
return EditorState.push(editorState, newContent, 'change-inline-style');
},
toggleLink: function toggleLink(editorState, targetSelection, entityKey) {
var withoutLink = DraftModifier.applyEntity(editorState.getCurrentContent(), targetSelection, entityKey);
...function insertText(contentState, targetRange, text, inlineStyle, entityKey) {
!targetRange.isCollapsed() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Target range must be collapsed for `insertText
`.') : invariant(false) : void 0;
return DraftModifier.replaceText(contentState, targetRange, text, inlineStyle, entityKey);
}...
return EditorState.push(editorState, newContentState, 'insert-fragment');
}
/**
* Insert text at a specified selection.
*/
function insertTextAtSelection(editorState, selection, text) {
var newContentState = DraftModifier.insertText(editorState.getCurrentContent(), selection
, text, editorState.getCurrentInlineStyle());
return EditorState.push(editorState, newContentState, 'insert-fragment');
}
module.exports = DraftEditorDragHandler;
/***/ },
/* 66 */
...function mergeBlockData(contentState, selectionState, blockData) {
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ data: block.getData().merge(blockData) });
});
}n/a
function moveText(contentState, removalRange, targetRange) {
var movedFragment = getContentStateFragment(contentState, removalRange);
var afterRemoval = DraftModifier.removeRange(contentState, removalRange, 'backward');
return DraftModifier.replaceWithFragment(afterRemoval, targetRange, movedFragment);
}...
editor.update(insertTextAtSelection(editorState, dropSelection, data.getText()));
}
};
function moveText(editorState, targetSelection) {
var newContentState = DraftModifier.moveText(editorState.getCurrentContent(), editorState
.getSelection(), targetSelection);
return EditorState.push(editorState, newContentState, 'insert-fragment');
}
/**
* Insert text at a specified selection.
*/
function insertTextAtSelection(editorState, selection, text) {
...function removeInlineStyle(contentState, selectionState, inlineStyle) {
return ContentStateInlineStyle.remove(contentState, selectionState, inlineStyle);
}...
// inline style on the document state itself.
var content = editorState.getCurrentContent();
var newContent;
// If the style is already present for the selection range, remove it.
// Otherwise, apply it.
if (currentStyle.has(inlineStyle)) {
newContent = DraftModifier.removeInlineStyle(content, selection, inlineStyle);
} else {
newContent = DraftModifier.applyInlineStyle(content, selection, inlineStyle);
}
return EditorState.push(editorState, newContent, 'change-inline-style');
},
...function removeRange(contentState, rangeToRemove, removalDirection) {
// Check whether the selection state overlaps with a single entity.
// If so, try to remove the appropriate substring of the entity text.
if (rangeToRemove.getAnchorKey() === rangeToRemove.getFocusKey()) {
var key = rangeToRemove.getAnchorKey();
var startOffset = rangeToRemove.getStartOffset();
var endOffset = rangeToRemove.getEndOffset();
var block = contentState.getBlockForKey(key);
var startEntity = block.getEntityAt(startOffset);
var endEntity = block.getEntityAt(endOffset - 1);
if (startEntity && startEntity === endEntity) {
var adjustedRemovalRange = getCharacterRemovalRange(contentState.getEntityMap(), block, rangeToRemove, removalDirection);
return removeRangeFromContentState(contentState, adjustedRemovalRange);
}
}
var withoutEntities = removeEntitiesAtEdges(contentState, rangeToRemove);
return removeRangeFromContentState(withoutEntities, rangeToRemove);
}...
!targetRange.isCollapsed() ? true ? invariant(false, 'Target range must be collapsed for `insertText`.') : invariant
(false) : void 0;
return DraftModifier.replaceText(contentState, targetRange, text, inlineStyle, entityKey);
},
moveText: function moveText(contentState, removalRange, targetRange) {
var movedFragment = getContentStateFragment(contentState, removalRange);
var afterRemoval = DraftModifier.removeRange(contentState, removalRange, 'backward
');
return DraftModifier.replaceWithFragment(afterRemoval, targetRange, movedFragment);
},
replaceWithFragment: function replaceWithFragment(contentState, targetRange, fragment) {
var withoutEntities = removeEntitiesAtEdges(contentState, targetRange);
var withoutText = removeRangeFromContentState(withoutEntities, targetRange);
...function replaceText(contentState, rangeToReplace, text, inlineStyle, entityKey) {
var withoutEntities = removeEntitiesAtEdges(contentState, rangeToReplace);
var withoutText = removeRangeFromContentState(withoutEntities, rangeToReplace);
var character = CharacterMetadata.create({
style: inlineStyle || OrderedSet(),
entity: entityKey || null
});
return insertTextIntoContentState(withoutText, withoutText.getSelectionAfter(), text, character);
}...
});
return insertTextIntoContentState(withoutText, withoutText.getSelectionAfter(), text, character);
},
insertText: function insertText(contentState, targetRange, text, inlineStyle, entityKey) {
!targetRange.isCollapsed() ? true ? invariant(false, 'Target range must be collapsed for `insertText`.') : invariant
(false) : void 0;
return DraftModifier.replaceText(contentState, targetRange, text, inlineStyle, entityKey
);
},
moveText: function moveText(contentState, removalRange, targetRange) {
var movedFragment = getContentStateFragment(contentState, removalRange);
var afterRemoval = DraftModifier.removeRange(contentState, removalRange, 'backward');
...function replaceWithFragment(contentState, targetRange, fragment) {
var withoutEntities = removeEntitiesAtEdges(contentState, targetRange);
var withoutText = removeRangeFromContentState(withoutEntities, targetRange);
return insertFragmentIntoContentState(withoutText, withoutText.getSelectionAfter(), fragment);
}...
},
moveText: function moveText(contentState, removalRange, targetRange) {
var movedFragment = getContentStateFragment(contentState, removalRange);
var afterRemoval = DraftModifier.removeRange(contentState, removalRange, 'backward');
return DraftModifier.replaceWithFragment(afterRemoval, targetRange, movedFragment
);
},
replaceWithFragment: function replaceWithFragment(contentState, targetRange, fragment) {
var withoutEntities = removeEntitiesAtEdges(contentState, targetRange);
var withoutText = removeRangeFromContentState(withoutEntities, targetRange);
return insertFragmentIntoContentState(withoutText, withoutText.getSelectionAfter(), fragment);
...function setBlockData(contentState, selectionState, blockData) {
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ data: blockData });
});
}n/a
function setBlockType(contentState, selectionState, blockType) {
return modifyBlockForContentState(contentState, selectionState, function (block) {
return block.merge({ type: blockType, depth: 0 });
});
}...
var afterRemoval = DraftModifier.removeRange(contentState, selectionState, 'backward');
var targetSelection = afterRemoval.getSelectionAfter();
var afterSplit = DraftModifier.splitBlock(afterRemoval, targetSelection);
var insertionTarget = afterSplit.getSelectionAfter();
var asAtomicBlock = DraftModifier.setBlockType(afterSplit, insertionTarget, '
;atomic');
var charData = CharacterMetadata.create({ entity: entityKey });
var fragmentArray = [new ContentBlock({
key: generateRandomKey(),
type: 'atomic',
text: character,
...function splitBlock(contentState, selectionState) {
var withoutEntities = removeEntitiesAtEdges(contentState, selectionState);
var withoutText = removeRangeFromContentState(withoutEntities, selectionState);
return splitBlockInContentState(withoutText, withoutText.getSelectionAfter());
}...
insertAtomicBlock: function insertAtomicBlock(editorState, entityKey, character) {
var contentState = editorState.getCurrentContent();
var selectionState = editorState.getSelection();
var afterRemoval = DraftModifier.removeRange(contentState, selectionState, 'backward');
var targetSelection = afterRemoval.getSelectionAfter();
var afterSplit = DraftModifier.splitBlock(afterRemoval, targetSelection);
var insertionTarget = afterSplit.getSelectionAfter();
var asAtomicBlock = DraftModifier.setBlockType(afterSplit, insertionTarget, 'atomic');
var charData = CharacterMetadata.create({ entity: entityKey });
var fragmentArray = [new ContentBlock({
...function currentBlockContainsLink(editorState) {
var selection = editorState.getSelection();
var contentState = editorState.getCurrentContent();
var entityMap = contentState.getEntityMap();
return contentState.getBlockForKey(selection.getAnchorKey()).getCharacterList().slice(selection.getStartOffset(), selection.getEndOffset
()).some(function (v) {
var entity = v.getEntity();
return !!entity && entityMap.__get(entity).getType() === 'LINK';
});
}n/a
function getCurrentBlockType(editorState) {
var selection = editorState.getSelection();
return editorState.getCurrentContent().getBlockForKey(selection.getStartKey()).getType();
}n/a
function getDataObjectForLinkURL(uri) {
return { url: uri.toString() };
}n/a
function handleKeyCommand(editorState, command) {
switch (command) {
case 'bold':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'BOLD');
case 'italic':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'ITALIC');
case 'underline':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'UNDERLINE');
case 'code':
return RichTextEditorUtil.toggleCode(editorState);
case 'backspace':
case 'backspace-word':
case 'backspace-to-start-of-line':
return RichTextEditorUtil.onBackspace(editorState);
case 'delete':
case 'delete-word':
case 'delete-to-end-of-block':
return RichTextEditorUtil.onDelete(editorState);
default:
// they may have custom editor commands; ignore those
return null;
}
}...
}
// At this point, we know that we're handling a command of some kind, so
// we don't want to insert a character following the keydown.
e.preventDefault();
// Allow components higher up the tree to handle the command first.
if (editor.props.handleKeyCommand && isEventHandled(editor.props.handleKeyCommand
span>(command))) {
return;
}
var newState = onKeyCommand(command, editorState);
if (newState !== editorState) {
editor.update(newState);
}
...function insertSoftNewline(editorState) {
var contentState = DraftModifier.insertText(editorState.getCurrentContent(), editorState.getSelection(), '\n', editorState.getCurrentInlineStyle
(), null);
var newEditorState = EditorState.push(editorState, contentState, 'insert-characters');
return EditorState.forceSelection(newEditorState, contentState.getSelectionAfter());
}n/a
function onBackspace(editorState) {
var selection = editorState.getSelection();
if (!selection.isCollapsed() || selection.getAnchorOffset() || selection.getFocusOffset()) {
return null;
}
// First, try to remove a preceding atomic block.
var content = editorState.getCurrentContent();
var startKey = selection.getStartKey();
var blockBefore = content.getBlockBefore(startKey);
if (blockBefore && blockBefore.getType() === 'atomic') {
var blockMap = content.getBlockMap()['delete'](blockBefore.getKey());
var withoutAtomicBlock = content.merge({ blockMap: blockMap, selectionAfter: selection });
if (withoutAtomicBlock !== content) {
return EditorState.push(editorState, withoutAtomicBlock, 'remove-range');
}
}
// If that doesn't succeed, try to remove the current block style.
var withoutBlockStyle = RichTextEditorUtil.tryToRemoveBlockStyle(editorState);
if (withoutBlockStyle) {
return EditorState.push(editorState, withoutBlockStyle, 'change-block-type');
}
return null;
}...
case 'underline':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'UNDERLINE');
case 'code':
return RichTextEditorUtil.toggleCode(editorState);
case 'backspace':
case 'backspace-word':
case 'backspace-to-start-of-line':
return RichTextEditorUtil.onBackspace(editorState);
case 'delete':
case 'delete-word':
case 'delete-to-end-of-block':
return RichTextEditorUtil.onDelete(editorState);
default:
// they may have custom editor commands; ignore those
return null;
...function onDelete(editorState) {
var selection = editorState.getSelection();
if (!selection.isCollapsed()) {
return null;
}
var content = editorState.getCurrentContent();
var startKey = selection.getStartKey();
var block = content.getBlockForKey(startKey);
var length = block.getLength();
// The cursor is somewhere within the text. Behave normally.
if (selection.getStartOffset() < length) {
return null;
}
var blockAfter = content.getBlockAfter(startKey);
if (!blockAfter || blockAfter.getType() !== 'atomic') {
return null;
}
var atomicBlockTarget = selection.merge({
focusKey: blockAfter.getKey(),
focusOffset: blockAfter.getLength()
});
var withoutAtomicBlock = DraftModifier.removeRange(content, atomicBlockTarget, 'forward');
if (withoutAtomicBlock !== content) {
return EditorState.push(editorState, withoutAtomicBlock, 'remove-range');
}
return null;
}...
case 'backspace':
case 'backspace-word':
case 'backspace-to-start-of-line':
return RichTextEditorUtil.onBackspace(editorState);
case 'delete':
case 'delete-word':
case 'delete-to-end-of-block':
return RichTextEditorUtil.onDelete(editorState);
default:
// they may have custom editor commands; ignore those
return null;
}
},
insertSoftNewline: function insertSoftNewline(editorState) {
...function onTab(event, editorState, maxDepth) {
var selection = editorState.getSelection();
var key = selection.getAnchorKey();
if (key !== selection.getFocusKey()) {
return editorState;
}
var content = editorState.getCurrentContent();
var block = content.getBlockForKey(key);
var type = block.getType();
if (type !== 'unordered-list-item' && type !== 'ordered-list-item') {
return editorState;
}
event.preventDefault();
// Only allow indenting one level beyond the block above, and only if
// the block above is a list item as well.
var blockAbove = content.getBlockBefore(key);
if (!blockAbove) {
return editorState;
}
var typeAbove = blockAbove.getType();
if (typeAbove !== 'unordered-list-item' && typeAbove !== 'ordered-list-item') {
return editorState;
}
var depth = block.getDepth();
if (!event.shiftKey && depth === maxDepth) {
return editorState;
}
maxDepth = Math.min(blockAbove.getDepth() + 1, maxDepth);
var withAdjustment = adjustBlockDepthForContentState(content, selection, event.shiftKey ? -1 : 1, maxDepth);
return EditorState.push(editorState, withAdjustment, 'adjust-depth');
}...
}
break;
case Keys.ESC:
e.preventDefault();
editor.props.onEscape && editor.props.onEscape(e);
return;
case Keys.TAB:
editor.props.onTab && editor.props.onTab(e);
return;
case Keys.UP:
editor.props.onUpArrow && editor.props.onUpArrow(e);
return;
case Keys.DOWN:
editor.props.onDownArrow && editor.props.onDownArrow(e);
return;
...function toggleBlockType(editorState, blockType) {
var selection = editorState.getSelection();
var startKey = selection.getStartKey();
var endKey = selection.getEndKey();
var content = editorState.getCurrentContent();
var target = selection;
// Triple-click can lead to a selection that includes offset 0 of the
// following block. The `SelectionState` for this case is accurate, but
// we should avoid toggling block type for the trailing block because it
// is a confusing interaction.
if (startKey !== endKey && selection.getEndOffset() === 0) {
var blockBefore = nullthrows(content.getBlockBefore(endKey));
endKey = blockBefore.getKey();
target = target.merge({
anchorKey: startKey,
anchorOffset: selection.getStartOffset(),
focusKey: endKey,
focusOffset: blockBefore.getLength(),
isBackward: false
});
}
var hasAtomicBlock = content.getBlockMap().skipWhile(function (_, k) {
return k !== startKey;
}).reverse().skipWhile(function (_, k) {
return k !== endKey;
}).some(function (v) {
return v.getType() === 'atomic';
});
if (hasAtomicBlock) {
return editorState;
}
var typeToSet = content.getBlockForKey(startKey).getType() === blockType ? 'unstyled' : blockType;
return EditorState.push(editorState, DraftModifier.setBlockType(content, target, typeToSet), 'change-block-type');
}...
toggleCode: function toggleCode(editorState) {
var selection = editorState.getSelection();
var anchorKey = selection.getAnchorKey();
var focusKey = selection.getFocusKey();
if (selection.isCollapsed() || anchorKey !== focusKey) {
return RichTextEditorUtil.toggleBlockType(editorState, 'code-block');
}
return RichTextEditorUtil.toggleInlineStyle(editorState, 'CODE');
},
/**
* Toggle the specified inline style for the selection. If the
...function toggleCode(editorState) {
var selection = editorState.getSelection();
var anchorKey = selection.getAnchorKey();
var focusKey = selection.getFocusKey();
if (selection.isCollapsed() || anchorKey !== focusKey) {
return RichTextEditorUtil.toggleBlockType(editorState, 'code-block');
}
return RichTextEditorUtil.toggleInlineStyle(editorState, 'CODE');
}...
case 'bold':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'BOLD');
case 'italic':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'ITALIC');
case 'underline':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'UNDERLINE');
case 'code':
return RichTextEditorUtil.toggleCode(editorState);
case 'backspace':
case 'backspace-word':
case 'backspace-to-start-of-line':
return RichTextEditorUtil.onBackspace(editorState);
case 'delete':
case 'delete-word':
case 'delete-to-end-of-block':
...function toggleInlineStyle(editorState, inlineStyle) {
var selection = editorState.getSelection();
var currentStyle = editorState.getCurrentInlineStyle();
// If the selection is collapsed, toggle the specified style on or off and
// set the result as the new inline style override. This will then be
// used as the inline style for the next character to be inserted.
if (selection.isCollapsed()) {
return EditorState.setInlineStyleOverride(editorState, currentStyle.has(inlineStyle) ? currentStyle.remove(inlineStyle) : currentStyle
.add(inlineStyle));
}
// If characters are selected, immediately apply or remove the
// inline style on the document state itself.
var content = editorState.getCurrentContent();
var newContent;
// If the style is already present for the selection range, remove it.
// Otherwise, apply it.
if (currentStyle.has(inlineStyle)) {
newContent = DraftModifier.removeInlineStyle(content, selection, inlineStyle);
} else {
newContent = DraftModifier.applyInlineStyle(content, selection, inlineStyle);
}
return EditorState.push(editorState, newContent, 'change-inline-style');
}...
getDataObjectForLinkURL: function getDataObjectForLinkURL(uri) {
return { url: uri.toString() };
},
handleKeyCommand: function handleKeyCommand(editorState, command) {
switch (command) {
case 'bold':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'BOLD');
case 'italic':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'ITALIC');
case 'underline':
return RichTextEditorUtil.toggleInlineStyle(editorState, 'UNDERLINE');
case 'code':
return RichTextEditorUtil.toggleCode(editorState);
case 'backspace':
...function toggleLink(editorState, targetSelection, entityKey) {
var withoutLink = DraftModifier.applyEntity(editorState.getCurrentContent(), targetSelection, entityKey);
return EditorState.push(editorState, withoutLink, 'apply-entity');
}n/a
function tryToRemoveBlockStyle(editorState) {
var selection = editorState.getSelection();
var offset = selection.getAnchorOffset();
if (selection.isCollapsed() && offset === 0) {
var key = selection.getAnchorKey();
var content = editorState.getCurrentContent();
var block = content.getBlockForKey(key);
if (block.getLength() > 0) {
return null;
}
var type = block.getType();
var blockBefore = content.getBlockBefore(key);
if (type === 'code-block' && blockBefore && blockBefore.getType() === 'code-block') {
return null;
}
if (type !== 'unstyled') {
return DraftModifier.setBlockType(content, selection, 'unstyled');
}
}
return null;
}...
var withoutAtomicBlock = content.merge({ blockMap: blockMap, selectionAfter: selection });
if (withoutAtomicBlock !== content) {
return EditorState.push(editorState, withoutAtomicBlock, 'remove-range');
}
}
// If that doesn't succeed, try to remove the current block style.
var withoutBlockStyle = RichTextEditorUtil.tryToRemoveBlockStyle(editorState);
if (withoutBlockStyle) {
return EditorState.push(editorState, withoutBlockStyle, 'change-block-type');
}
return null;
},
...function cut(editorState) {
var content = editorState.getCurrentContent();
var selection = editorState.getSelection();
var targetRange = null;
if (selection.isCollapsed()) {
var anchorKey = selection.getAnchorKey();
var blockEnd = content.getBlockForKey(anchorKey).getLength();
if (blockEnd === selection.getAnchorOffset()) {
return editorState;
}
targetRange = selection.set('focusOffset', blockEnd);
} else {
targetRange = selection;
}
targetRange = nullthrows(targetRange);
clipboard = getContentStateFragment(content, targetRange);
var afterRemoval = DraftModifier.removeRange(content, targetRange, 'forward');
if (afterRemoval === content) {
return editorState;
}
return EditorState.push(editorState, afterRemoval, 'remove-range');
}...
case 'transpose-characters':
return keyCommandTransposeCharacters(editorState);
case 'move-selection-to-start-of-block':
return keyCommandMoveSelectionToStartOfBlock(editorState);
case 'move-selection-to-end-of-block':
return keyCommandMoveSelectionToEndOfBlock(editorState);
case 'secondary-cut':
return SecondaryClipboard.cut(editorState);
case 'secondary-paste':
return SecondaryClipboard.paste(editorState);
default:
return editorState;
}
}
...function paste(editorState) {
if (!clipboard) {
return editorState;
}
var newContent = DraftModifier.replaceWithFragment(editorState.getCurrentContent(), editorState.getSelection(), clipboard);
return EditorState.push(editorState, newContent, 'insert-fragment');
}...
case 'move-selection-to-start-of-block':
return keyCommandMoveSelectionToStartOfBlock(editorState);
case 'move-selection-to-end-of-block':
return keyCommandMoveSelectionToEndOfBlock(editorState);
case 'secondary-cut':
return SecondaryClipboard.cut(editorState);
case 'secondary-paste':
return SecondaryClipboard.paste(editorState);
default:
return editorState;
}
}
/**
* Intercept keydown behavior to handle keys and commands manually, if desired.
...function SelectionState() {
_classCallCheck(this, SelectionState);
return _possibleConstructorReturn(this, _SelectionStateRecord.apply(this, arguments));
}n/a
function createEmpty(key) {
return new SelectionState({
anchorKey: key,
anchorOffset: 0,
focusKey: key,
focusOffset: 0,
isBackward: false,
hasFocus: false
});
}...
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
...function getAnchorKey() {
return this.get('anchorKey');
}...
return insertFragmentIntoContentState(withoutText, withoutText.getSelectionAfter(), fragment);
},
removeRange: function removeRange(contentState, rangeToRemove, removalDirection) {
// Check whether the selection state overlaps with a single entity.
// If so, try to remove the appropriate substring of the entity text.
if (rangeToRemove.getAnchorKey() === rangeToRemove.getFocusKey()) {
var key = rangeToRemove.getAnchorKey();
var startOffset = rangeToRemove.getStartOffset();
var endOffset = rangeToRemove.getEndOffset();
var block = contentState.getBlockForKey(key);
var startEntity = block.getEntityAt(startOffset);
var endEntity = block.getEntityAt(endOffset - 1);
...function getAnchorOffset() {
return this.get('anchorOffset');
}...
function SelectionState() {
_classCallCheck(this, SelectionState);
return _possibleConstructorReturn(this, _SelectionStateRecord.apply(this, arguments));
}
SelectionState.prototype.serialize = function serialize() {
return 'Anchor: ' + this.getAnchorKey() + ':' + this.getAnchorOffset
() + ', ' + 'Focus: ' + this.getFocusKey() + ':' + this.getFocusOffset() + ', ' +
x27;Is Backward: ' + String(this.getIsBackward()) + ', ' + 'Has Focus: ' + String(this.getHasFocus());
};
SelectionState.prototype.getAnchorKey = function getAnchorKey() {
return this.get('anchorKey');
};
SelectionState.prototype.getAnchorOffset = function getAnchorOffset() {
...function getEndKey() {
return this.getIsBackward() ? this.getAnchorKey() : this.getFocusKey();
}...
var generateRandomKey = __webpack_require__(7);
var removeEntitiesAtEdges = __webpack_require__(53);
function getContentStateFragment(contentState, selectionState) {
var startKey = selectionState.getStartKey();
var startOffset = selectionState.getStartOffset();
var endKey = selectionState.getEndKey();
var endOffset = selectionState.getEndOffset();
// Edge entities should be stripped to ensure that we don't preserve
// invalid partial entities when the fragment is reused. We do, however,
// preserve entities that are entirely within the selection range.
var contentWithoutEdgeEntities = removeEntitiesAtEdges(contentState, selectionState);
...function getEndOffset() {
return this.getIsBackward() ? this.getAnchorOffset() : this.getFocusOffset();
}...
removeRange: function removeRange(contentState, rangeToRemove, removalDirection) {
// Check whether the selection state overlaps with a single entity.
// If so, try to remove the appropriate substring of the entity text.
if (rangeToRemove.getAnchorKey() === rangeToRemove.getFocusKey()) {
var key = rangeToRemove.getAnchorKey();
var startOffset = rangeToRemove.getStartOffset();
var endOffset = rangeToRemove.getEndOffset();
var block = contentState.getBlockForKey(key);
var startEntity = block.getEntityAt(startOffset);
var endEntity = block.getEntityAt(endOffset - 1);
if (startEntity && startEntity === endEntity) {
var adjustedRemovalRange = getCharacterRemovalRange(contentState.getEntityMap(), block, rangeToRemove, removalDirection
);
return removeRangeFromContentState(contentState, adjustedRemovalRange);
...function getFocusKey() {
return this.get('focusKey');
}...
return insertFragmentIntoContentState(withoutText, withoutText.getSelectionAfter(), fragment);
},
removeRange: function removeRange(contentState, rangeToRemove, removalDirection) {
// Check whether the selection state overlaps with a single entity.
// If so, try to remove the appropriate substring of the entity text.
if (rangeToRemove.getAnchorKey() === rangeToRemove.getFocusKey()) {
var key = rangeToRemove.getAnchorKey();
var startOffset = rangeToRemove.getStartOffset();
var endOffset = rangeToRemove.getEndOffset();
var block = contentState.getBlockForKey(key);
var startEntity = block.getEntityAt(startOffset);
var endEntity = block.getEntityAt(endOffset - 1);
...function getFocusOffset() {
return this.get('focusOffset');
}...
function SelectionState() {
_classCallCheck(this, SelectionState);
return _possibleConstructorReturn(this, _SelectionStateRecord.apply(this, arguments));
}
SelectionState.prototype.serialize = function serialize() {
return 'Anchor: ' + this.getAnchorKey() + ':' + this.getAnchorOffset() + ', ' + 'Focus:
x27; + this.getFocusKey() + ':' + this.getFocusOffset() + ', ' +
x27;Is Backward: ' + String(this.getIsBackward()) + ', ' + 'Has Focus: ' + String(this.getHasFocus());
};
SelectionState.prototype.getAnchorKey = function getAnchorKey() {
return this.get('anchorKey');
};
SelectionState.prototype.getAnchorOffset = function getAnchorOffset() {
...function getHasFocus() {
return this.get('hasFocus');
}...
* This method should be used in cases where you need to explicitly
* move the DOM selection from one place to another without a change
* in ContentState.
*/
EditorState.forceSelection = function forceSelection(editorState, selection) {
if (!selection.getHasFocus()) {
selection = selection.set('hasFocus', true);
}
return updateSelection(editorState, selection, true);
};
/**
* Move selection to the end of the editor without forcing focus.
...function getIsBackward() {
return this.get('isBackward');
}...
function SelectionState() {
_classCallCheck(this, SelectionState);
return _possibleConstructorReturn(this, _SelectionStateRecord.apply(this, arguments));
}
SelectionState.prototype.serialize = function serialize() {
return 'Anchor: ' + this.getAnchorKey() + ':' + this.getAnchorOffset() + ', ' + 'Focus:
x27; + this.getFocusKey() + ':' + this.getFocusOffset() + ', ' + 'Is Backward: ' + String(this.getIsBackward()) + ', ' + 'Has Focus: ' + String(this.getHasFocus());
};
SelectionState.prototype.getAnchorKey = function getAnchorKey() {
return this.get('anchorKey');
};
SelectionState.prototype.getAnchorOffset = function getAnchorOffset() {
...function getStartKey() {
return this.getIsBackward() ? this.getFocusKey() : this.getAnchorKey();
}...
*/
function mustBecomeBoundary(editorState, changeType) {
var lastChangeType = editorState.getLastChangeType();
return changeType !== lastChangeType || changeType !== 'insert-characters' && changeType !== 'backspace
-character' && changeType !== 'delete-character';
}
function getInlineStyleForCollapsedSelection(content, selection) {
var startKey = selection.getStartKey();
var startOffset = selection.getStartOffset();
var startBlock = content.getBlockForKey(startKey);
// If the cursor is not at the start of the block, look backward to
// preserve the style of the preceding character.
if (startOffset > 0) {
return startBlock.getInlineStyleAt(startOffset - 1);
...function getStartOffset() {
return this.getIsBackward() ? this.getFocusOffset() : this.getAnchorOffset();
}...
function mustBecomeBoundary(editorState, changeType) {
var lastChangeType = editorState.getLastChangeType();
return changeType !== lastChangeType || changeType !== 'insert-characters' && changeType !== 'backspace
-character' && changeType !== 'delete-character';
}
function getInlineStyleForCollapsedSelection(content, selection) {
var startKey = selection.getStartKey();
var startOffset = selection.getStartOffset();
var startBlock = content.getBlockForKey(startKey);
// If the cursor is not at the start of the block, look backward to
// preserve the style of the preceding character.
if (startOffset > 0) {
return startBlock.getInlineStyleAt(startOffset - 1);
}
...function hasEdgeWithin(blockKey, start, end) {
var anchorKey = this.getAnchorKey();
var focusKey = this.getFocusKey();
if (anchorKey === focusKey && anchorKey === blockKey) {
var selectionStart = this.getStartOffset();
var selectionEnd = this.getEndOffset();
return start <= selectionEnd && selectionStart <= end;
}
if (blockKey !== anchorKey && blockKey !== focusKey) {
return false;
}
var offsetToCheck = blockKey === anchorKey ? this.getAnchorOffset() : this.getFocusOffset();
return start <= offsetToCheck && end >= offsetToCheck;
}...
EditorState.prototype.getBlockTree = function getBlockTree(blockKey) {
return this.getImmutable().getIn(['treeMap', blockKey]);
};
EditorState.prototype.isSelectionAtStartOfContent = function isSelectionAtStartOfContent() {
var firstKey = this.getCurrentContent().getBlockMap().first().getKey();
return this.getSelection().hasEdgeWithin(firstKey, 0, 0);
};
EditorState.prototype.isSelectionAtEndOfContent = function isSelectionAtEndOfContent() {
var content = this.getCurrentContent();
var blockMap = content.getBlockMap();
var last = blockMap.last();
var end = last.getLength();
...function isCollapsed() {
return this.getAnchorKey() === this.getFocusKey() && this.getAnchorOffset() === this.getFocusOffset();
}...
if (override != null) {
return override;
}
var content = this.getCurrentContent();
var selection = this.getSelection();
if (selection.isCollapsed()) {
return getInlineStyleForCollapsedSelection(content, selection);
}
return getInlineStyleForNonCollapsedSelection(content, selection);
};
EditorState.prototype.getBlockTree = function getBlockTree(blockKey) {
...function serialize() {
return 'Anchor: ' + this.getAnchorKey() + ':' + this.getAnchorOffset() + ', ' + 'Focus: ' + this.getFocusKey() + ':' + this.getFocusOffset
() + ', ' + 'Is Backward: ' + String(this.getIsBackward()) + ', ' + 'Has Focus: ' + String(this.getHasFocus());
}n/a