180 lines
5.6 KiB
Plaintext
180 lines
5.6 KiB
Plaintext
/**
|
|
* Copyright (c) 2013-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*
|
|
* @providesModule ContentState
|
|
* @format
|
|
* @flow
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
import type { BlockMap } from './BlockMap';
|
|
import type { BlockNodeRecord } from './BlockNodeRecord';
|
|
import type DraftEntityInstance from './DraftEntityInstance';
|
|
import type { DraftEntityMutability } from './DraftEntityMutability';
|
|
import type { DraftEntityType } from './DraftEntityType';
|
|
|
|
const BlockMapBuilder = require('./BlockMapBuilder');
|
|
const CharacterMetadata = require('./CharacterMetadata');
|
|
const ContentBlock = require('./ContentBlock');
|
|
const ContentBlockNode = require('./ContentBlockNode');
|
|
const DraftEntity = require('./DraftEntity');
|
|
const DraftFeatureFlags = require('./DraftFeatureFlags');
|
|
const Immutable = require('immutable');
|
|
const SelectionState = require('./SelectionState');
|
|
|
|
const generateRandomKey = require('./generateRandomKey');
|
|
const sanitizeDraftText = require('./sanitizeDraftText');
|
|
|
|
const { List, Record, Repeat } = Immutable;
|
|
|
|
const experimentalTreeDataSupport = DraftFeatureFlags.draft_tree_data_support;
|
|
|
|
const defaultRecord: {
|
|
entityMap: ?any;
|
|
blockMap: ?BlockMap;
|
|
selectionBefore: ?SelectionState;
|
|
selectionAfter: ?SelectionState;
|
|
} = {
|
|
entityMap: null,
|
|
blockMap: null,
|
|
selectionBefore: null,
|
|
selectionAfter: null
|
|
};
|
|
|
|
const ContentBlockNodeRecord = experimentalTreeDataSupport ? ContentBlockNode : ContentBlock;
|
|
|
|
const ContentStateRecord = Record(defaultRecord);
|
|
|
|
class ContentState extends ContentStateRecord {
|
|
getEntityMap(): any {
|
|
// TODO: update this when we fully remove DraftEntity
|
|
return DraftEntity;
|
|
}
|
|
|
|
getBlockMap(): BlockMap {
|
|
return this.get('blockMap');
|
|
}
|
|
|
|
getSelectionBefore(): SelectionState {
|
|
return this.get('selectionBefore');
|
|
}
|
|
|
|
getSelectionAfter(): SelectionState {
|
|
return this.get('selectionAfter');
|
|
}
|
|
|
|
getBlockForKey(key: string): BlockNodeRecord {
|
|
var block: BlockNodeRecord = this.getBlockMap().get(key);
|
|
return block;
|
|
}
|
|
|
|
getKeyBefore(key: string): ?string {
|
|
return this.getBlockMap().reverse().keySeq().skipUntil(v => v === key).skip(1).first();
|
|
}
|
|
|
|
getKeyAfter(key: string): ?string {
|
|
return this.getBlockMap().keySeq().skipUntil(v => v === key).skip(1).first();
|
|
}
|
|
|
|
getBlockAfter(key: string): ?BlockNodeRecord {
|
|
return this.getBlockMap().skipUntil((_, k) => k === key).skip(1).first();
|
|
}
|
|
|
|
getBlockBefore(key: string): ?BlockNodeRecord {
|
|
return this.getBlockMap().reverse().skipUntil((_, k) => k === key).skip(1).first();
|
|
}
|
|
|
|
getBlocksAsArray(): Array<BlockNodeRecord> {
|
|
return this.getBlockMap().toArray();
|
|
}
|
|
|
|
getFirstBlock(): BlockNodeRecord {
|
|
return this.getBlockMap().first();
|
|
}
|
|
|
|
getLastBlock(): BlockNodeRecord {
|
|
return this.getBlockMap().last();
|
|
}
|
|
|
|
getPlainText(delimiter?: string): string {
|
|
return this.getBlockMap().map(block => {
|
|
return block ? block.getText() : '';
|
|
}).join(delimiter || '\n');
|
|
}
|
|
|
|
getLastCreatedEntityKey() {
|
|
// TODO: update this when we fully remove DraftEntity
|
|
return DraftEntity.__getLastCreatedEntityKey();
|
|
}
|
|
|
|
hasText(): boolean {
|
|
var blockMap = this.getBlockMap();
|
|
return blockMap.size > 1 || blockMap.first().getLength() > 0;
|
|
}
|
|
|
|
createEntity(type: DraftEntityType, mutability: DraftEntityMutability, data?: Object): ContentState {
|
|
// TODO: update this when we fully remove DraftEntity
|
|
DraftEntity.__create(type, mutability, data);
|
|
return this;
|
|
}
|
|
|
|
mergeEntityData(key: string, toMerge: { [key: string]: any }): ContentState {
|
|
// TODO: update this when we fully remove DraftEntity
|
|
DraftEntity.__mergeData(key, toMerge);
|
|
return this;
|
|
}
|
|
|
|
replaceEntityData(key: string, newData: { [key: string]: any }): ContentState {
|
|
// TODO: update this when we fully remove DraftEntity
|
|
DraftEntity.__replaceData(key, newData);
|
|
return this;
|
|
}
|
|
|
|
addEntity(instance: DraftEntityInstance): ContentState {
|
|
// TODO: update this when we fully remove DraftEntity
|
|
DraftEntity.__add(instance);
|
|
return this;
|
|
}
|
|
|
|
getEntity(key: string): DraftEntityInstance {
|
|
// TODO: update this when we fully remove DraftEntity
|
|
return DraftEntity.__get(key);
|
|
}
|
|
|
|
static createFromBlockArray(
|
|
// TODO: update flow type when we completely deprecate the old entity API
|
|
blocks: Array<BlockNodeRecord> | { contentBlocks: Array<BlockNodeRecord> }, entityMap: ?any): ContentState {
|
|
// TODO: remove this when we completely deprecate the old entity API
|
|
const 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,
|
|
entityMap: entityMap || DraftEntity,
|
|
selectionBefore: selectionState,
|
|
selectionAfter: selectionState
|
|
});
|
|
}
|
|
|
|
static createFromText(text: string, delimiter: string | RegExp = /\r\n?|\n/g): ContentState {
|
|
const strings = text.split(delimiter);
|
|
const blocks = strings.map(block => {
|
|
block = sanitizeDraftText(block);
|
|
return new ContentBlockNodeRecord({
|
|
key: generateRandomKey(),
|
|
text: block,
|
|
type: 'unstyled',
|
|
characterList: List(Repeat(CharacterMetadata.EMPTY, block.length))
|
|
});
|
|
});
|
|
return ContentState.createFromBlockArray(blocks);
|
|
}
|
|
}
|
|
|
|
module.exports = ContentState; |