Comparing version 0.10.4 to 0.10.5
@@ -7,2 +7,38 @@ # Changelog | ||
## 0.10.5 (January 19th, 2018) | ||
### Added | ||
* Add support for `ariaDescribedBy` prop, for better a11y. (Suraj Karnati in | ||
[a6af3e15](https://github.com/facebook/draft-js/commit/a6af3e15120e74c8797c5670f5bb63cb45c49a32)) | ||
* Add support for `ariaLabelledBy` prop, for better a11y. ([@jackyho112](https://github.com/jackyho112) | ||
in [#1519](https://github.com/facebook/draft-js/pull/1519)) | ||
### Changed | ||
* Cause editor to break out of code block when user enters two blank lines. (Hanzhi Zhang | ||
in [548fd5d1](https://github.com/facebook/draft-js/commit/548fd5d1b1c31b7b4c79cd70b101fae69d522b3f)) | ||
### Fixed | ||
* Preserve list indentation when copying and pasting from one Draft.js editor | ||
into another. ([@GordyD](https://github.com/GordyD) in [#1605](https://github.com/facebook/draft-js/pull/1605)) | ||
* Fix `cannot read property 'update' of undefined` error that was thrown when | ||
typing same character into selection that starts with that character. ([@existentialism](https://github.com/existentialism) in | ||
[#1512](https://github.com/facebook/draft-js/pull/1512)) | ||
* Fix `encodeRawBlocks` to handle non-contiguous entities. Entities should | ||
always be contigious, and cover one sequential range of characters. However, | ||
in cases where entityState is corrupted to include non-contiguous entities, | ||
`encodeRawBlocks` would improperly process the entities in that case. (Frank | ||
Thompson in [0059dd46](https://github.com/facebook/draft-js/commit/0059dd46f4d23af7d9803316aa93d8deddb5e8ae)) | ||
* Updated CSS for DraftEditorPlaceholder to support multiline placeholder (Gaurav Vaish in | ||
[c38b0285](https://github.com/facebook/draft-js/commit/c38b028513214416d66a3fdf191745dfde04ed2b) | ||
* Fix issue where typing at the end of a link caused the link to continue. (Ian | ||
Jones in | ||
[d16833b3](https://github.com/facebook/draft-js/commit/d16833b3dae77ccf13e3af7f5e42c8131b0d1d2c)) | ||
* Fix regression of bug where clicking a link caused the focus to move but the | ||
selection state was not cleared, leading to a 'node not found' error. | ||
([@flarnie](https://github.com/flarnie) | ||
in [55316176](https://github.com/facebook/draft-js/commit/553161761903bed7fad971d73e1fe04bb0ff360e)) | ||
* Loosen Flow type definition for DraftBlockType to allow user-defined custom | ||
block types. ([@mitermayer](https://github.com/mitermayer) | ||
in [#1480](https://github.com/facebook/draft-js/pull/1480)) | ||
## 0.10.4 (October 24th, 2017) | ||
@@ -9,0 +45,0 @@ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule addEntityToContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule addEntityToEntityMap | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule adjustBlockDepthForContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule applyEntityToContentBlock | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule applyEntityToContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule AtomicBlockUtils | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -17,5 +17,11 @@ */ | ||
var _assign = require('object-assign'); | ||
var _extends = _assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var BlockMapBuilder = require('./BlockMapBuilder'); | ||
var CharacterMetadata = require('./CharacterMetadata'); | ||
var ContentBlock = require('./ContentBlock'); | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var DraftFeatureFlags = require('./DraftFeatureFlags'); | ||
var DraftModifier = require('./DraftModifier'); | ||
@@ -29,2 +35,5 @@ var EditorState = require('./EditorState'); | ||
var experimentalTreeDataSupport = DraftFeatureFlags.draft_tree_data_support; | ||
var ContentBlockRecord = experimentalTreeDataSupport ? ContentBlockNode : ContentBlock; | ||
var List = Immutable.List, | ||
@@ -49,3 +58,3 @@ Repeat = Immutable.Repeat; | ||
var fragmentArray = [new ContentBlock({ | ||
var atomicBlockConfig = { | ||
key: generateRandomKey(), | ||
@@ -55,9 +64,20 @@ type: 'atomic', | ||
characterList: List(Repeat(charData, character.length)) | ||
}), new ContentBlock({ | ||
}; | ||
var atomicDividerBlockConfig = { | ||
key: generateRandomKey(), | ||
type: 'unstyled', | ||
text: '', | ||
characterList: List() | ||
})]; | ||
type: 'unstyled' | ||
}; | ||
if (experimentalTreeDataSupport) { | ||
atomicBlockConfig = _extends({}, atomicBlockConfig, { | ||
nextSibling: atomicDividerBlockConfig.key | ||
}); | ||
atomicDividerBlockConfig = _extends({}, atomicDividerBlockConfig, { | ||
prevSibling: atomicBlockConfig.key | ||
}); | ||
} | ||
var fragmentArray = [new ContentBlockRecord(atomicBlockConfig), new ContentBlockRecord(atomicDividerBlockConfig)]; | ||
var fragment = BlockMapBuilder.createFromArray(fragmentArray); | ||
@@ -64,0 +84,0 @@ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule BlockMap | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule BlockMapBuilder | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule BlockTree | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule CharacterMetadata | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -90,3 +90,6 @@ */ | ||
var defaultConfig = { style: EMPTY_SET, entity: null }; | ||
var defaultConfig = { | ||
style: EMPTY_SET, | ||
entity: null | ||
}; | ||
@@ -93,0 +96,0 @@ // Fill in unspecified properties, if necessary. |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule ComposedEntityMutability | ||
* @format | ||
* | ||
@@ -17,7 +18,7 @@ */ | ||
var ComposedEntityMutability = { | ||
'MUTABLE': true, | ||
'IMMUTABLE': true, | ||
'SEGMENTED': true | ||
MUTABLE: true, | ||
IMMUTABLE: true, | ||
SEGMENTED: true | ||
}; | ||
module.exports = ComposedEntityMutability; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule ComposedEntityType | ||
* @format | ||
* | ||
@@ -17,8 +18,8 @@ */ | ||
var ComposedEntityType = { | ||
'LINK': true, | ||
'TOKEN': true, | ||
'PHOTO': true, | ||
'IMAGE': true | ||
LINK: true, | ||
TOKEN: true, | ||
PHOTO: true, | ||
IMAGE: true | ||
}; | ||
module.exports = ComposedEntityType; |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule CompositeDraftDecorator | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule ContentBlock | ||
* @format | ||
* | ||
@@ -22,2 +23,3 @@ */ | ||
var CharacterMetadata = require('./CharacterMetadata'); | ||
var Immutable = require('immutable'); | ||
@@ -30,3 +32,4 @@ | ||
OrderedSet = Immutable.OrderedSet, | ||
Record = Immutable.Record; | ||
Record = Immutable.Record, | ||
Repeat = Immutable.Repeat; | ||
@@ -47,9 +50,25 @@ | ||
var decorateCharacterList = function decorateCharacterList(config) { | ||
if (!config) { | ||
return config; | ||
} | ||
var characterList = config.characterList, | ||
text = config.text; | ||
if (text && !characterList) { | ||
config.characterList = List(Repeat(CharacterMetadata.EMPTY, text.length)); | ||
} | ||
return config; | ||
}; | ||
var ContentBlock = function (_ContentBlockRecord) { | ||
_inherits(ContentBlock, _ContentBlockRecord); | ||
function ContentBlock() { | ||
function ContentBlock(config) { | ||
_classCallCheck(this, ContentBlock); | ||
return _possibleConstructorReturn(this, _ContentBlockRecord.apply(this, arguments)); | ||
return _possibleConstructorReturn(this, _ContentBlockRecord.call(this, decorateCharacterList(config))); | ||
} | ||
@@ -56,0 +75,0 @@ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule ContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -26,3 +26,5 @@ */ | ||
var ContentBlock = require('./ContentBlock'); | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var DraftEntity = require('./DraftEntity'); | ||
var DraftFeatureFlags = require('./DraftFeatureFlags'); | ||
var Immutable = require('immutable'); | ||
@@ -39,2 +41,4 @@ var SelectionState = require('./SelectionState'); | ||
var experimentalTreeDataSupport = DraftFeatureFlags.draft_tree_data_support; | ||
var defaultRecord = { | ||
@@ -47,2 +51,4 @@ entityMap: null, | ||
var ContentBlockNodeRecord = experimentalTreeDataSupport ? ContentBlockNode : ContentBlock; | ||
var ContentStateRecord = Record(defaultRecord); | ||
@@ -183,3 +189,3 @@ | ||
block = sanitizeDraftText(block); | ||
return new ContentBlock({ | ||
return new ContentBlockNodeRecord({ | ||
key: generateRandomKey(), | ||
@@ -186,0 +192,0 @@ text: block, |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule ContentStateInlineStyle | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule convertFromDraftStateToRaw | ||
* @format | ||
* | ||
@@ -16,2 +17,8 @@ */ | ||
var _assign = require('object-assign'); | ||
var _extends = _assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var ContentBlock = require('./ContentBlock'); | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var DraftStringKey = require('./DraftStringKey'); | ||
@@ -21,37 +28,89 @@ | ||
var encodeInlineStyleRanges = require('./encodeInlineStyleRanges'); | ||
var invariant = require('fbjs/lib/invariant'); | ||
function convertFromDraftStateToRaw(contentState) { | ||
var entityStorageKey = 0; | ||
var entityStorageMap = {}; | ||
var createRawBlock = function createRawBlock(block, entityStorageMap) { | ||
return { | ||
key: block.getKey(), | ||
text: block.getText(), | ||
type: block.getType(), | ||
depth: block.getDepth(), | ||
inlineStyleRanges: encodeInlineStyleRanges(block), | ||
entityRanges: encodeEntityRanges(block, entityStorageMap), | ||
data: block.getData().toObject() | ||
}; | ||
}; | ||
var insertRawBlock = function insertRawBlock(block, entityMap, rawBlocks, blockCacheRef) { | ||
if (block instanceof ContentBlock) { | ||
rawBlocks.push(createRawBlock(block, entityMap)); | ||
return; | ||
} | ||
!(block instanceof ContentBlockNode) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'block is not a BlockNode') : invariant(false) : void 0; | ||
var parentKey = block.getParentKey(); | ||
var rawBlock = blockCacheRef[block.getKey()] = _extends({}, createRawBlock(block, entityMap), { | ||
children: [] | ||
}); | ||
if (parentKey) { | ||
blockCacheRef[parentKey].children.push(rawBlock); | ||
return; | ||
} | ||
rawBlocks.push(rawBlock); | ||
}; | ||
var encodeRawBlocks = function encodeRawBlocks(contentState, rawState) { | ||
var entityMap = rawState.entityMap; | ||
var rawBlocks = []; | ||
contentState.getBlockMap().forEach(function (block, blockKey) { | ||
var blockCacheRef = {}; | ||
var entityCacheRef = {}; | ||
var entityStorageKey = 0; | ||
contentState.getBlockMap().forEach(function (block) { | ||
block.findEntityRanges(function (character) { | ||
return character.getEntity() !== null; | ||
}, function (start) { | ||
var entityKey = block.getEntityAt(start); | ||
// Stringify to maintain order of otherwise numeric keys. | ||
var stringifiedEntityKey = DraftStringKey.stringify(block.getEntityAt(start)); | ||
if (!entityStorageMap.hasOwnProperty(stringifiedEntityKey)) { | ||
entityStorageMap[stringifiedEntityKey] = '' + entityStorageKey++; | ||
var stringifiedEntityKey = DraftStringKey.stringify(entityKey); | ||
// This makes this function resilient to two entities | ||
// erroneously having the same key | ||
if (entityCacheRef[stringifiedEntityKey]) { | ||
return; | ||
} | ||
entityCacheRef[stringifiedEntityKey] = entityKey; | ||
// we need the `any` casting here since this is a temporary state | ||
// where we will later on flip the entity map and populate it with | ||
// real entity, at this stage we just need to map back the entity | ||
// key used by the BlockNode | ||
entityMap[stringifiedEntityKey] = '' + entityStorageKey; | ||
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() | ||
}); | ||
insertRawBlock(block, entityMap, rawBlocks, blockCacheRef); | ||
}); | ||
// 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) { | ||
return { | ||
blocks: rawBlocks, | ||
entityMap: entityMap | ||
}; | ||
}; | ||
// Flip storage map so that our storage keys map to global | ||
// DraftEntity keys. | ||
var encodeRawEntityMap = function encodeRawEntityMap(contentState, rawState) { | ||
var blocks = rawState.blocks, | ||
entityMap = rawState.entityMap; | ||
var rawEntityMap = {}; | ||
Object.keys(entityMap).forEach(function (key, index) { | ||
var entity = contentState.getEntity(DraftStringKey.unstringify(key)); | ||
flippedStorageMap[jj] = { | ||
rawEntityMap[index] = { | ||
type: entity.getType(), | ||
@@ -64,7 +123,22 @@ mutability: entity.getMutability(), | ||
return { | ||
entityMap: flippedStorageMap, | ||
blocks: rawBlocks | ||
blocks: blocks, | ||
entityMap: rawEntityMap | ||
}; | ||
} | ||
}; | ||
var convertFromDraftStateToRaw = function convertFromDraftStateToRaw(contentState) { | ||
var rawDraftContentState = { | ||
entityMap: {}, | ||
blocks: [] | ||
}; | ||
// add blocks | ||
rawDraftContentState = encodeRawBlocks(contentState, rawDraftContentState); | ||
// add entities | ||
rawDraftContentState = encodeRawEntityMap(contentState, rawDraftContentState); | ||
return rawDraftContentState; | ||
}; | ||
module.exports = convertFromDraftStateToRaw; |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule convertFromHTMLToContentBlocks | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -17,6 +17,15 @@ */ | ||
var _extends = _assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _knownListItemDepthCl, | ||
_assign = require('object-assign'); | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
var CharacterMetadata = require('./CharacterMetadata'); | ||
var ContentBlock = require('./ContentBlock'); | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var DefaultDraftBlockRenderMap = require('./DefaultDraftBlockRenderMap'); | ||
var DraftEntity = require('./DraftEntity'); | ||
var DraftFeatureFlags = require('./DraftFeatureFlags'); | ||
var Immutable = require('immutable'); | ||
@@ -29,8 +38,10 @@ | ||
var cx = require('fbjs/lib/cx'); | ||
var generateRandomKey = require('./generateRandomKey'); | ||
var getSafeBodyFromHTML = require('./getSafeBodyFromHTML'); | ||
var invariant = require('fbjs/lib/invariant'); | ||
var nullthrows = require('fbjs/lib/nullthrows'); | ||
var sanitizeDraftText = require('./sanitizeDraftText'); | ||
var experimentalTreeDataSupport = DraftFeatureFlags.draft_tree_data_support; | ||
var List = Immutable.List, | ||
@@ -71,2 +82,4 @@ OrderedSet = Immutable.OrderedSet; | ||
var knownListItemDepthClasses = (_knownListItemDepthCl = {}, _defineProperty(_knownListItemDepthCl, cx('public/DraftStyleDefault/depth0'), 0), _defineProperty(_knownListItemDepthCl, cx('public/DraftStyleDefault/depth1'), 1), _defineProperty(_knownListItemDepthCl, cx('public/DraftStyleDefault/depth2'), 2), _defineProperty(_knownListItemDepthCl, cx('public/DraftStyleDefault/depth3'), 3), _defineProperty(_knownListItemDepthCl, cx('public/DraftStyleDefault/depth4'), 4), _knownListItemDepthCl); | ||
var anchorAttr = ['className', 'href', 'rel', 'target', 'title']; | ||
@@ -76,48 +89,19 @@ | ||
var lastBlock; | ||
var lastBlock = void 0; | ||
function getEmptyChunk() { | ||
return { | ||
text: '', | ||
inlines: [], | ||
entities: [], | ||
blocks: [] | ||
}; | ||
} | ||
var EMPTY_CHUNK = { | ||
text: '', | ||
inlines: [], | ||
entities: [], | ||
blocks: [] | ||
}; | ||
function getWhitespaceChunk(inEntity) { | ||
var entities = new Array(1); | ||
if (inEntity) { | ||
entities[0] = inEntity; | ||
} | ||
return { | ||
text: SPACE, | ||
inlines: [OrderedSet()], | ||
entities: entities, | ||
blocks: [] | ||
}; | ||
} | ||
var EMPTY_BLOCK = { | ||
children: List(), | ||
depth: 0, | ||
key: '', | ||
type: '' | ||
}; | ||
function getSoftNewlineChunk() { | ||
return { | ||
text: '\n', | ||
inlines: [OrderedSet()], | ||
entities: new Array(1), | ||
blocks: [] | ||
}; | ||
} | ||
function getBlockDividerChunk(block, depth) { | ||
return { | ||
text: '\r', | ||
inlines: [OrderedSet()], | ||
entities: new Array(1), | ||
blocks: [{ | ||
type: block, | ||
depth: Math.max(0, Math.min(MAX_DEPTH, depth)) | ||
}] | ||
}; | ||
} | ||
function getListBlockType(tag, lastList) { | ||
var getListBlockType = function getListBlockType(tag, lastList) { | ||
if (tag === 'li') { | ||
@@ -127,5 +111,5 @@ return lastList === 'ol' ? 'ordered-list-item' : 'unordered-list-item'; | ||
return null; | ||
} | ||
}; | ||
function getBlockMapSupportedTags(blockRenderMap) { | ||
var getBlockMapSupportedTags = function getBlockMapSupportedTags(blockRenderMap) { | ||
var unstyledElement = blockRenderMap.get('unstyled').element; | ||
@@ -147,6 +131,6 @@ var tags = Set([]); | ||
}).toArray().sort(); | ||
} | ||
}; | ||
// custom element conversions | ||
function getMultiMatchedType(tag, lastList, multiMatchExtractor) { | ||
var getMultiMatchedType = function getMultiMatchedType(tag, lastList, multiMatchExtractor) { | ||
for (var ii = 0; ii < multiMatchExtractor.length; ii++) { | ||
@@ -159,5 +143,5 @@ var matchType = multiMatchExtractor[ii](tag, lastList); | ||
return null; | ||
} | ||
}; | ||
function getBlockTypeForTag(tag, lastList, blockRenderMap) { | ||
var getBlockTypeForTag = function getBlockTypeForTag(tag, lastList, blockRenderMap) { | ||
var matchedTypes = blockRenderMap.filter(function (draftBlock) { | ||
@@ -180,5 +164,5 @@ return draftBlock.element === tag || draftBlock.wrapper === tag || draftBlock.aliasedElements && draftBlock.aliasedElements.some(function (alias) { | ||
} | ||
} | ||
}; | ||
function processInlineTag(tag, node, currentStyle) { | ||
var processInlineTag = function processInlineTag(tag, node, currentStyle) { | ||
var styleToCheck = inlineTags[tag]; | ||
@@ -219,5 +203,5 @@ if (styleToCheck) { | ||
return currentStyle; | ||
} | ||
}; | ||
function joinChunks(A, B) { | ||
var joinChunks = function joinChunks(A, B, experimentalHasNestedBlocks) { | ||
// Sometimes two blocks will touch in the DOM and we need to strip the | ||
@@ -228,3 +212,3 @@ // extra delimiter to preserve niceness. | ||
if (lastInA === '\r' && firstInB === '\r') { | ||
if (lastInA === '\r' && firstInB === '\r' && !experimentalHasNestedBlocks) { | ||
A.text = A.text.slice(0, -1); | ||
@@ -253,3 +237,3 @@ A.inlines.pop(); | ||
}; | ||
} | ||
}; | ||
@@ -261,25 +245,97 @@ /** | ||
*/ | ||
function containsSemanticBlockMarkup(html, blockTags) { | ||
var containsSemanticBlockMarkup = function containsSemanticBlockMarkup(html, blockTags) { | ||
return blockTags.some(function (tag) { | ||
return html.indexOf('<' + tag) !== -1; | ||
}); | ||
} | ||
}; | ||
function hasValidLinkText(link) { | ||
var hasValidLinkText = function hasValidLinkText(link) { | ||
!(link instanceof HTMLAnchorElement) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Link must be an HTMLAnchorElement.') : invariant(false) : void 0; | ||
var protocol = link.protocol; | ||
return protocol === 'http:' || protocol === 'https:' || protocol === 'mailto:'; | ||
} | ||
}; | ||
function genFragment(entityMap, node, inlineStyle, lastList, inBlock, blockTags, depth, blockRenderMap, inEntity) { | ||
var getWhitespaceChunk = function getWhitespaceChunk(inEntity) { | ||
var entities = new Array(1); | ||
if (inEntity) { | ||
entities[0] = inEntity; | ||
} | ||
return _extends({}, EMPTY_CHUNK, { | ||
text: SPACE, | ||
inlines: [OrderedSet()], | ||
entities: entities | ||
}); | ||
}; | ||
var getSoftNewlineChunk = function getSoftNewlineChunk() { | ||
return _extends({}, EMPTY_CHUNK, { | ||
text: '\n', | ||
inlines: [OrderedSet()], | ||
entities: new Array(1) | ||
}); | ||
}; | ||
var getChunkedBlock = function getChunkedBlock() { | ||
var props = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
return _extends({}, EMPTY_BLOCK, props); | ||
}; | ||
var getBlockDividerChunk = function getBlockDividerChunk(block, depth) { | ||
var parentKey = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; | ||
return { | ||
text: '\r', | ||
inlines: [OrderedSet()], | ||
entities: new Array(1), | ||
blocks: [getChunkedBlock({ | ||
parent: parentKey, | ||
key: generateRandomKey(), | ||
type: block, | ||
depth: Math.max(0, Math.min(MAX_DEPTH, depth)) | ||
})] | ||
}; | ||
}; | ||
/** | ||
* If we're pasting from one DraftEditor to another we can check to see if | ||
* existing list item depth classes are being used and preserve this style | ||
*/ | ||
var getListItemDepth = function getListItemDepth(node) { | ||
var depth = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; | ||
Object.keys(knownListItemDepthClasses).some(function (depthClass) { | ||
if (node.classList.contains(depthClass)) { | ||
depth = knownListItemDepthClasses[depthClass]; | ||
} | ||
}); | ||
return depth; | ||
}; | ||
var genFragment = function genFragment(entityMap, node, inlineStyle, lastList, inBlock, blockTags, depth, blockRenderMap, inEntity, parentKey) { | ||
var lastLastBlock = lastBlock; | ||
var nodeName = node.nodeName.toLowerCase(); | ||
var newEntityMap = entityMap; | ||
var nextBlockType = 'unstyled'; | ||
var newBlock = false; | ||
var nextBlockType = 'unstyled'; | ||
var lastLastBlock = lastBlock; | ||
var newEntityMap = entityMap; | ||
var inBlockType = inBlock && getBlockTypeForTag(inBlock, lastList, blockRenderMap); | ||
var chunk = _extends({}, EMPTY_CHUNK); | ||
var newChunk = null; | ||
var blockKey = void 0; | ||
// Base Case | ||
if (nodeName === '#text') { | ||
var text = node.textContent; | ||
if (text.trim() === '' && inBlock !== 'pre') { | ||
var _text = node.textContent; | ||
var nodeTextContent = _text.trim(); | ||
// We should not create blocks for leading spaces that are | ||
// existing around ol/ul and their children list items | ||
if (lastList && nodeTextContent === '' && node.parentElement) { | ||
var parentNodeName = node.parentElement.nodeName.toLowerCase(); | ||
if (parentNodeName === 'ol' || parentNodeName === 'ul') { | ||
return { chunk: _extends({}, EMPTY_CHUNK), entityMap: entityMap }; | ||
} | ||
} | ||
if (nodeTextContent === '' && inBlock !== 'pre') { | ||
return { chunk: getWhitespaceChunk(inEntity), entityMap: entityMap }; | ||
@@ -289,3 +345,3 @@ } | ||
// Can't use empty string because MSWord | ||
text = text.replace(REGEX_LF, SPACE); | ||
_text = _text.replace(REGEX_LF, SPACE); | ||
} | ||
@@ -298,5 +354,5 @@ | ||
chunk: { | ||
text: text, | ||
inlines: Array(text.length).fill(inlineStyle), | ||
entities: Array(text.length).fill(inEntity), | ||
text: _text, | ||
inlines: Array(_text.length).fill(inlineStyle), | ||
entities: Array(_text.length).fill(inEntity), | ||
blocks: [] | ||
@@ -313,4 +369,7 @@ }, | ||
if (nodeName === 'br') { | ||
if (lastLastBlock === 'br' && (!inBlock || getBlockTypeForTag(inBlock, lastList, blockRenderMap) === 'unstyled')) { | ||
return { chunk: getBlockDividerChunk('unstyled', depth), entityMap: entityMap }; | ||
if (lastLastBlock === 'br' && (!inBlock || inBlockType === 'unstyled')) { | ||
return { | ||
chunk: getBlockDividerChunk('unstyled', depth, parentKey), | ||
entityMap: entityMap | ||
}; | ||
} | ||
@@ -342,5 +401,2 @@ return { chunk: getSoftNewlineChunk(), entityMap: entityMap }; | ||
var chunk = getEmptyChunk(); | ||
var newChunk = null; | ||
// Inline tags | ||
@@ -357,11 +413,20 @@ inlineStyle = processInlineTag(nodeName, node, inlineStyle); | ||
if (!experimentalTreeDataSupport && nodeName === 'li' && node instanceof HTMLElement) { | ||
depth = getListItemDepth(node, depth); | ||
} | ||
var blockType = getBlockTypeForTag(nodeName, lastList, blockRenderMap); | ||
var inListBlock = lastList && inBlock === 'li' && nodeName === 'li'; | ||
var inBlockOrHasNestedBlocks = (!inBlock || experimentalTreeDataSupport) && blockTags.indexOf(nodeName) !== -1; | ||
// Block Tags | ||
if (!inBlock && blockTags.indexOf(nodeName) !== -1) { | ||
chunk = getBlockDividerChunk(getBlockTypeForTag(nodeName, lastList, blockRenderMap), depth); | ||
if (inListBlock || inBlockOrHasNestedBlocks) { | ||
chunk = getBlockDividerChunk(blockType, depth, parentKey); | ||
blockKey = chunk.blocks[0].key; | ||
inBlock = nodeName; | ||
newBlock = true; | ||
} else if (lastList && inBlock === 'li' && nodeName === 'li') { | ||
chunk = getBlockDividerChunk(getBlockTypeForTag(nodeName, lastList, blockRenderMap), depth); | ||
inBlock = nodeName; | ||
newBlock = true; | ||
newBlock = !experimentalTreeDataSupport; | ||
} | ||
// this is required so that we can handle 'ul' and 'ol' | ||
if (inListBlock) { | ||
nextBlockType = lastList === 'ul' ? 'unordered-list-item' : 'ordered-list-item'; | ||
@@ -399,3 +464,3 @@ } | ||
var _genFragment = genFragment(newEntityMap, child, inlineStyle, lastList, inBlock, blockTags, depth, blockRenderMap, entityId || inEntity), | ||
var _genFragment = genFragment(newEntityMap, child, inlineStyle, lastList, inBlock, blockTags, depth, blockRenderMap, entityId || inEntity, experimentalTreeDataSupport ? blockKey : null), | ||
generatedChunk = _genFragment.chunk, | ||
@@ -407,7 +472,7 @@ maybeUpdatedEntityMap = _genFragment.entityMap; | ||
chunk = joinChunks(chunk, newChunk); | ||
chunk = joinChunks(chunk, newChunk, experimentalTreeDataSupport); | ||
var sibling = child.nextSibling; | ||
// Put in a newline to break up blocks inside blocks | ||
if (sibling && blockTags.indexOf(nodeName) >= 0 && inBlock) { | ||
if (!parentKey && sibling && blockTags.indexOf(nodeName) >= 0 && inBlock) { | ||
chunk = joinChunks(chunk, getSoftNewlineChunk()); | ||
@@ -422,9 +487,9 @@ } | ||
if (newBlock) { | ||
chunk = joinChunks(chunk, getBlockDividerChunk(nextBlockType, depth)); | ||
chunk = joinChunks(chunk, getBlockDividerChunk(nextBlockType, depth, parentKey)); | ||
} | ||
return { chunk: chunk, entityMap: newEntityMap }; | ||
} | ||
}; | ||
function getChunkForHTML(html, DOMBuilder, blockRenderMap, entityMap) { | ||
var getChunkForHTML = function getChunkForHTML(html, DOMBuilder, blockRenderMap, entityMap) { | ||
html = html.trim().replace(REGEX_CR, '').replace(REGEX_NBSP, SPACE).replace(REGEX_CARRIAGE, '').replace(REGEX_ZWS, ''); | ||
@@ -447,10 +512,8 @@ | ||
// UL block to start with. | ||
var fragment = genFragment(entityMap, safeBody, OrderedSet(), 'ul', null, workingBlocks, -1, blockRenderMap); | ||
var _genFragment2 = genFragment(entityMap, safeBody, OrderedSet(), 'ul', null, workingBlocks, -1, blockRenderMap), | ||
chunk = _genFragment2.chunk, | ||
newEntityMap = _genFragment2.entityMap; | ||
var chunk = fragment.chunk; | ||
var newEntityMap = fragment.entityMap; | ||
// join with previous block to prevent weirdness on paste | ||
if (chunk.text.indexOf('\r') === 0) { | ||
@@ -475,3 +538,6 @@ chunk = { | ||
if (chunk.blocks.length === 0) { | ||
chunk.blocks.push({ type: 'unstyled', depth: 0 }); | ||
chunk.blocks.push(_extends({}, EMPTY_CHUNK, { | ||
type: 'unstyled', | ||
depth: 0 | ||
})); | ||
} | ||
@@ -487,5 +553,99 @@ | ||
return { chunk: chunk, entityMap: newEntityMap }; | ||
} | ||
}; | ||
function convertFromHTMLtoContentBlocks(html) { | ||
var convertChunkToContentBlocks = function convertChunkToContentBlocks(chunk) { | ||
if (!chunk || !chunk.text || !Array.isArray(chunk.blocks)) { | ||
return null; | ||
} | ||
var initialState = { | ||
cacheRef: {}, | ||
contentBlocks: [] | ||
}; | ||
var start = 0; | ||
var rawBlocks = chunk.blocks, | ||
rawInlines = chunk.inlines, | ||
rawEntities = chunk.entities; | ||
var BlockNodeRecord = experimentalTreeDataSupport ? ContentBlockNode : ContentBlock; | ||
return chunk.text.split('\r').reduce(function (acc, textBlock, index) { | ||
// Make absolutely certain that our text is acceptable. | ||
textBlock = sanitizeDraftText(textBlock); | ||
var block = rawBlocks[index]; | ||
var end = start + textBlock.length; | ||
var inlines = rawInlines.slice(start, end); | ||
var entities = rawEntities.slice(start, end); | ||
var characterList = List(inlines.map(function (style, index) { | ||
var data = { style: style, entity: null }; | ||
if (entities[index]) { | ||
data.entity = entities[index]; | ||
} | ||
return CharacterMetadata.create(data); | ||
})); | ||
start = end + 1; | ||
var depth = block.depth, | ||
type = block.type, | ||
parent = block.parent; | ||
var key = block.key || generateRandomKey(); | ||
var parentTextNodeKey = null; // will be used to store container text nodes | ||
// childrens add themselves to their parents since we are iterating in order | ||
if (parent) { | ||
var parentIndex = acc.cacheRef[parent]; | ||
var parentRecord = acc.contentBlocks[parentIndex]; | ||
// if parent has text we need to split it into a separate unstyled element | ||
if (parentRecord.getChildKeys().isEmpty() && parentRecord.getText()) { | ||
var parentCharacterList = parentRecord.getCharacterList(); | ||
var parentText = parentRecord.getText(); | ||
parentTextNodeKey = generateRandomKey(); | ||
var textNode = new ContentBlockNode({ | ||
key: parentTextNodeKey, | ||
text: parentText, | ||
characterList: parentCharacterList, | ||
parent: parent, | ||
nextSibling: key | ||
}); | ||
acc.contentBlocks.push(textNode); | ||
parentRecord = parentRecord.withMutations(function (block) { | ||
block.set('characterList', List()).set('text', '').set('children', parentRecord.children.push(textNode.getKey())); | ||
}); | ||
} | ||
acc.contentBlocks[parentIndex] = parentRecord.set('children', parentRecord.children.push(key)); | ||
} | ||
var blockNode = new BlockNodeRecord({ | ||
key: key, | ||
parent: parent, | ||
type: type, | ||
depth: depth, | ||
text: textBlock, | ||
characterList: characterList, | ||
prevSibling: parentTextNodeKey || (index === 0 || rawBlocks[index - 1].parent !== parent ? null : rawBlocks[index - 1].key), | ||
nextSibling: index === rawBlocks.length - 1 || rawBlocks[index + 1].parent !== parent ? null : rawBlocks[index + 1].key | ||
}); | ||
// insert node | ||
acc.contentBlocks.push(blockNode); | ||
// cache ref for building links | ||
acc.cacheRef[blockNode.key] = index; | ||
return acc; | ||
}, initialState).contentBlocks; | ||
}; | ||
var convertFromHTMLtoContentBlocks = function convertFromHTMLtoContentBlocks(html) { | ||
var DOMBuilder = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : getSafeBodyFromHTML; | ||
@@ -506,34 +666,12 @@ var blockRenderMap = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : DefaultDraftBlockRenderMap; | ||
var chunk = chunkData.chunk, | ||
newEntityMap = chunkData.entityMap; | ||
entityMap = chunkData.entityMap; | ||
var contentBlocks = convertChunkToContentBlocks(chunk); | ||
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 | ||
contentBlocks: contentBlocks, | ||
entityMap: entityMap | ||
}; | ||
} | ||
}; | ||
module.exports = convertFromHTMLtoContentBlocks; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule convertFromRawToDraftState | ||
* @format | ||
* | ||
@@ -21,5 +22,9 @@ */ | ||
var ContentBlock = require('./ContentBlock'); | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var ContentState = require('./ContentState'); | ||
var DraftEntity = require('./DraftEntity'); | ||
var DraftFeatureFlags = require('./DraftFeatureFlags'); | ||
var DraftTreeAdapter = require('./DraftTreeAdapter'); | ||
var Immutable = require('immutable'); | ||
var SelectionState = require('./SelectionState'); | ||
@@ -30,58 +35,197 @@ var createCharacterList = require('./createCharacterList'); | ||
var generateRandomKey = require('./generateRandomKey'); | ||
var invariant = require('fbjs/lib/invariant'); | ||
var Map = Immutable.Map; | ||
var experimentalTreeDataSupport = DraftFeatureFlags.draft_tree_data_support; | ||
var List = Immutable.List, | ||
Map = Immutable.Map, | ||
OrderedMap = Immutable.OrderedMap; | ||
function convertFromRawToDraftState(rawState) { | ||
var blocks = rawState.blocks, | ||
entityMap = rawState.entityMap; | ||
var decodeBlockNodeConfig = function decodeBlockNodeConfig(block, entityMap) { | ||
var key = block.key, | ||
type = block.type, | ||
data = block.data, | ||
text = block.text, | ||
depth = block.depth; | ||
var fromStorageToLocal = {}; | ||
var blockNodeConfig = { | ||
text: text, | ||
depth: depth || 0, | ||
type: type || 'unstyled', | ||
key: key || generateRandomKey(), | ||
data: Map(data), | ||
characterList: decodeCharacterList(block, entityMap) | ||
}; | ||
return blockNodeConfig; | ||
}; | ||
var decodeCharacterList = function decodeCharacterList(block, entityMap) { | ||
var text = block.text, | ||
rawEntityRanges = block.entityRanges, | ||
rawInlineStyleRanges = block.inlineStyleRanges; | ||
var entityRanges = rawEntityRanges || []; | ||
var inlineStyleRanges = rawInlineStyleRanges || []; | ||
// Translate entity range keys to the DraftEntity map. | ||
return createCharacterList(decodeInlineStyleRanges(text, inlineStyleRanges), decodeEntityRanges(text, entityRanges.filter(function (range) { | ||
return entityMap.hasOwnProperty(range.key); | ||
}).map(function (range) { | ||
return _extends({}, range, { key: entityMap[range.key] }); | ||
}))); | ||
}; | ||
var addKeyIfMissing = function addKeyIfMissing(block) { | ||
return _extends({}, block, { | ||
key: block.key || generateRandomKey() | ||
}); | ||
}; | ||
/** | ||
* Node stack is responsible to ensure we traverse the tree only once | ||
* in depth order, while also providing parent refs to inner nodes to | ||
* construct their links. | ||
*/ | ||
var updateNodeStack = function updateNodeStack(stack, nodes, parentRef) { | ||
var nodesWithParentRef = nodes.map(function (block) { | ||
return _extends({}, block, { | ||
parentRef: parentRef | ||
}); | ||
}); | ||
// since we pop nodes from the stack we need to insert them in reverse | ||
return stack.concat(nodesWithParentRef.reverse()); | ||
}; | ||
/** | ||
* This will build a tree draft content state by creating the node | ||
* reference links into a single tree walk. Each node has a link | ||
* reference to "parent", "children", "nextSibling" and "prevSibling" | ||
* blockMap will be created using depth ordering. | ||
*/ | ||
var decodeContentBlockNodes = function decodeContentBlockNodes(blocks, entityMap) { | ||
return blocks | ||
// ensure children have valid keys to enable sibling links | ||
.map(addKeyIfMissing).reduce(function (blockMap, block, index) { | ||
!Array.isArray(block.children) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'invalid RawDraftContentBlock can not be converted to ContentBlockNode') : invariant(false) : void 0; | ||
// ensure children have valid keys to enable sibling links | ||
var children = block.children.map(addKeyIfMissing); | ||
// root level nodes | ||
var contentBlockNode = new ContentBlockNode(_extends({}, decodeBlockNodeConfig(block, entityMap), { | ||
prevSibling: index === 0 ? null : blocks[index - 1].key, | ||
nextSibling: index === blocks.length - 1 ? null : blocks[index + 1].key, | ||
children: List(children.map(function (child) { | ||
return child.key; | ||
})) | ||
})); | ||
// push root node to blockMap | ||
blockMap = blockMap.set(contentBlockNode.getKey(), contentBlockNode); | ||
// this stack is used to ensure we visit all nodes respecting depth ordering | ||
var stack = updateNodeStack([], children, contentBlockNode); | ||
// start computing children nodes | ||
while (stack.length > 0) { | ||
// we pop from the stack and start processing this node | ||
var node = stack.pop(); | ||
// parentRef already points to a converted ContentBlockNode | ||
var parentRef = node.parentRef; | ||
var siblings = parentRef.getChildKeys(); | ||
var _index = siblings.indexOf(node.key); | ||
var isValidBlock = Array.isArray(node.children); | ||
if (!isValidBlock) { | ||
!isValidBlock ? process.env.NODE_ENV !== 'production' ? invariant(false, 'invalid RawDraftContentBlock can not be converted to ContentBlockNode') : invariant(false) : void 0; | ||
break; | ||
} | ||
// ensure children have valid keys to enable sibling links | ||
var _children = node.children.map(addKeyIfMissing); | ||
var _contentBlockNode = new ContentBlockNode(_extends({}, decodeBlockNodeConfig(node, entityMap), { | ||
parent: parentRef.getKey(), | ||
children: List(_children.map(function (child) { | ||
return child.key; | ||
})), | ||
prevSibling: _index === 0 ? null : siblings.get(_index - 1), | ||
nextSibling: _index === siblings.size - 1 ? null : siblings.get(_index + 1) | ||
})); | ||
// push node to blockMap | ||
blockMap = blockMap.set(_contentBlockNode.getKey(), _contentBlockNode); | ||
// this stack is used to ensure we visit all nodes respecting depth ordering | ||
stack = updateNodeStack(stack, _children, _contentBlockNode); | ||
} | ||
return blockMap; | ||
}, OrderedMap()); | ||
}; | ||
var decodeContentBlocks = function decodeContentBlocks(blocks, entityMap) { | ||
return OrderedMap(blocks.map(function (block) { | ||
var contentBlock = new ContentBlock(decodeBlockNodeConfig(block, entityMap)); | ||
return [contentBlock.getKey(), contentBlock]; | ||
})); | ||
}; | ||
var decodeRawBlocks = function decodeRawBlocks(rawState, entityMap) { | ||
var isTreeRawBlock = Array.isArray(rawState.blocks[0].children); | ||
var rawBlocks = experimentalTreeDataSupport && !isTreeRawBlock ? DraftTreeAdapter.fromRawStateToRawTreeState(rawState).blocks : rawState.blocks; | ||
if (!experimentalTreeDataSupport) { | ||
return decodeContentBlocks(isTreeRawBlock ? DraftTreeAdapter.fromRawTreeStateToRawState(rawState).blocks : rawBlocks, entityMap); | ||
} | ||
return decodeContentBlockNodes(rawBlocks, entityMap); | ||
}; | ||
var decodeRawEntityMap = function decodeRawEntityMap(rawState) { | ||
var rawEntityMap = rawState.entityMap; | ||
var entityMap = {}; | ||
// TODO: Update this once we completely remove DraftEntity | ||
Object.keys(entityMap).forEach(function (storageKey) { | ||
var encodedEntity = entityMap[storageKey]; | ||
var type = encodedEntity.type, | ||
mutability = encodedEntity.mutability, | ||
data = encodedEntity.data; | ||
Object.keys(rawEntityMap).forEach(function (rawEntityKey) { | ||
var _rawEntityMap$rawEnti = rawEntityMap[rawEntityKey], | ||
type = _rawEntityMap$rawEnti.type, | ||
mutability = _rawEntityMap$rawEnti.mutability, | ||
data = _rawEntityMap$rawEnti.data; | ||
var newKey = DraftEntity.__create(type, mutability, data || {}); | ||
fromStorageToLocal[storageKey] = newKey; | ||
// get the key reference to created entity | ||
entityMap[rawEntityKey] = DraftEntity.__create(type, mutability, data || {}); | ||
}); | ||
var contentBlocks = blocks.map(function (block) { | ||
var key = block.key, | ||
type = block.type, | ||
text = block.text, | ||
depth = block.depth, | ||
inlineStyleRanges = block.inlineStyleRanges, | ||
entityRanges = block.entityRanges, | ||
data = block.data; | ||
return entityMap; | ||
}; | ||
key = key || generateRandomKey(); | ||
type = type || 'unstyled'; | ||
depth = depth || 0; | ||
inlineStyleRanges = inlineStyleRanges || []; | ||
entityRanges = entityRanges || []; | ||
data = Map(data); | ||
var convertFromRawToDraftState = function convertFromRawToDraftState(rawState) { | ||
!Array.isArray(rawState.blocks) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'invalid RawDraftContentState') : invariant(false) : void 0; | ||
var inlineStyles = decodeInlineStyleRanges(text, inlineStyleRanges); | ||
// decode entities | ||
var entityMap = decodeRawEntityMap(rawState); | ||
// 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] }); | ||
}); | ||
// decode blockMap | ||
var blockMap = decodeRawBlocks(rawState, entityMap); | ||
var entities = decodeEntityRanges(text, filteredEntityRanges); | ||
var characterList = createCharacterList(inlineStyles, entities); | ||
// create initial selection | ||
var selectionState = blockMap.isEmpty() ? new SelectionState() : SelectionState.createEmpty(blockMap.first().getKey()); | ||
return new ContentBlock({ key: key, type: type, text: text, depth: depth, characterList: characterList, data: data }); | ||
return new ContentState({ | ||
blockMap: blockMap, | ||
entityMap: entityMap, | ||
selectionBefore: selectionState, | ||
selectionAfter: selectionState | ||
}); | ||
}; | ||
return ContentState.createFromBlockArray(contentBlocks); | ||
} | ||
module.exports = convertFromRawToDraftState; |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule createCharacterList | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule createEntityInContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule decodeEntityRanges | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule decodeInlineStyleRanges | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DefaultDraftBlockRenderMap | ||
* @format | ||
* | ||
@@ -54,6 +55,6 @@ */ | ||
}, | ||
'blockquote': { | ||
blockquote: { | ||
element: 'blockquote' | ||
}, | ||
'atomic': { | ||
atomic: { | ||
element: 'figure' | ||
@@ -65,3 +66,3 @@ }, | ||
}, | ||
'unstyled': { | ||
unstyled: { | ||
element: 'div', | ||
@@ -68,0 +69,0 @@ aliasedElements: ['p'] |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DefaultDraftInlineStyle | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DOMDerivedSelection | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule Draft | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftBlockRenderConfig | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftBlockRenderMap | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftBlockType | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftDecorator | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftDecoratorType | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftDragType | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftEditor.react | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -59,7 +59,7 @@ * @preventMunge | ||
var handlerMap = { | ||
'edit': DraftEditorEditHandler, | ||
'composite': DraftEditorCompositionHandler, | ||
'drag': DraftEditorDragHandler, | ||
'cut': null, | ||
'render': null | ||
edit: DraftEditorEditHandler, | ||
composite: DraftEditorCompositionHandler, | ||
drag: DraftEditorDragHandler, | ||
cut: null, | ||
render: null | ||
}; | ||
@@ -80,2 +80,83 @@ | ||
_this.focus = function (scrollPosition) { | ||
var editorState = _this.props.editorState; | ||
var alreadyHasFocus = editorState.getSelection().getHasFocus(); | ||
var editorNode = ReactDOM.findDOMNode(_this.editor); | ||
if (!editorNode) { | ||
// once in a while people call 'focus' in a setTimeout, and the node has | ||
// been deleted, so it can be null in that case. | ||
return; | ||
} | ||
var scrollParent = Style.getScrollParent(editorNode); | ||
var _ref = scrollPosition || getScrollPosition(scrollParent), | ||
x = _ref.x, | ||
y = _ref.y; | ||
!(editorNode instanceof HTMLElement) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'editorNode is not an HTMLElement') : invariant(false) : void 0; | ||
editorNode.focus(); | ||
// Restore scroll position | ||
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())); | ||
} | ||
}; | ||
_this.blur = function () { | ||
var editorNode = ReactDOM.findDOMNode(_this.editor); | ||
!(editorNode instanceof HTMLElement) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'editorNode is not an HTMLElement') : invariant(false) : void 0; | ||
editorNode.blur(); | ||
}; | ||
_this.setMode = function (mode) { | ||
_this._handler = handlerMap[mode]; | ||
}; | ||
_this.exitCurrentMode = function () { | ||
_this.setMode('edit'); | ||
}; | ||
_this.restoreEditorDOM = function (scrollPosition) { | ||
_this.setState({ contentsKey: _this.state.contentsKey + 1 }, function () { | ||
_this.focus(scrollPosition); | ||
}); | ||
}; | ||
_this.setClipboard = function (clipboard) { | ||
_this._clipboard = clipboard; | ||
}; | ||
_this.getClipboard = function () { | ||
return _this._clipboard; | ||
}; | ||
_this.update = function (editorState) { | ||
_this._latestEditorState = editorState; | ||
_this.props.onChange(editorState); | ||
}; | ||
_this.onDragEnter = function () { | ||
_this._dragCount++; | ||
}; | ||
_this.onDragLeave = function () { | ||
_this._dragCount--; | ||
if (_this._dragCount === 0) { | ||
_this.exitCurrentMode(); | ||
} | ||
}; | ||
_this._blockSelectEvents = false; | ||
@@ -111,18 +192,7 @@ _this._clipboard = null; | ||
// 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()`. | ||
// See `restoreEditorDOM()`. | ||
_this.state = { contentsKey: 0 }; | ||
@@ -161,14 +231,10 @@ return _this; | ||
if (this._showPlaceholder()) { | ||
return ( | ||
/* $FlowFixMe(>=0.53.0 site=www,mobile) This comment suppresses an | ||
* error when upgrading Flow's support for React. Common errors found | ||
* when upgrading Flow's React support are documented at | ||
* https://fburl.com/eq7bs81w */ | ||
React.createElement(DraftEditorPlaceholder, { | ||
text: nullthrows(this.props.placeholder), | ||
editorState: this.props.editorState, | ||
textAlignment: this.props.textAlignment, | ||
accessibilityID: this._placeholderAccessibilityID | ||
}) | ||
); | ||
var placeHolderProps = { | ||
text: nullthrows(this.props.placeholder), | ||
editorState: this.props.editorState, | ||
textAlignment: this.props.textAlignment, | ||
accessibilityID: this._placeholderAccessibilityID | ||
}; | ||
return React.createElement(DraftEditorPlaceholder, placeHolderProps); | ||
} | ||
@@ -179,6 +245,16 @@ return null; | ||
DraftEditor.prototype.render = function render() { | ||
var _this3 = this; | ||
var _props = this.props, | ||
blockRenderMap = _props.blockRenderMap, | ||
blockRendererFn = _props.blockRendererFn, | ||
blockStyleFn = _props.blockStyleFn, | ||
customStyleFn = _props.customStyleFn, | ||
customStyleMap = _props.customStyleMap, | ||
editorState = _props.editorState, | ||
readOnly = _props.readOnly, | ||
textAlignment = _props.textAlignment; | ||
textAlignment = _props.textAlignment, | ||
textDirectionality = _props.textDirectionality; | ||
var rootClass = cx({ | ||
@@ -205,2 +281,14 @@ 'DraftEditor/root': true, | ||
var editorContentsProps = { | ||
blockRenderMap: blockRenderMap, | ||
blockRendererFn: blockRendererFn, | ||
blockStyleFn: blockStyleFn, | ||
customStyleMap: _extends({}, DefaultDraftInlineStyle, customStyleMap), | ||
customStyleFn: customStyleFn, | ||
editorKey: this._editorKey, | ||
editorState: editorState, | ||
key: 'contents' + this.state.contentsKey, | ||
textDirectionality: textDirectionality | ||
}; | ||
return React.createElement( | ||
@@ -214,3 +302,5 @@ 'div', | ||
className: cx('DraftEditor/editorContainer'), | ||
ref: 'editorContainer' }, | ||
ref: function ref(_ref3) { | ||
return _this3.editorContainer = _ref3; | ||
} }, | ||
React.createElement( | ||
@@ -222,5 +312,6 @@ 'div', | ||
'aria-controls': readOnly ? null : this.props.ariaControls, | ||
'aria-describedby': this._showPlaceholder() ? this._placeholderAccessibilityID : null, | ||
'aria-describedby': this.props.ariaDescribedBy || this._placeholderAccessibilityID, | ||
'aria-expanded': readOnly ? null : ariaExpanded, | ||
'aria-label': this.props.ariaLabel, | ||
'aria-labelledby': this.props.ariaLabelledBy, | ||
'aria-multiline': this.props.ariaMultiline, | ||
@@ -235,3 +326,3 @@ autoCapitalize: this.props.autoCapitalize, | ||
// here which makes its autotranslation skip over this subtree. | ||
'notranslate': !readOnly, | ||
notranslate: !readOnly, | ||
'public/DraftEditor/content': true | ||
@@ -261,3 +352,5 @@ }), | ||
onSelect: this._onSelect, | ||
ref: 'editor', | ||
ref: function ref(_ref2) { | ||
return _this3.editor = _ref2; | ||
}, | ||
role: readOnly ? null : ariaRole, | ||
@@ -268,13 +361,3 @@ spellCheck: allowSpellCheck && this.props.spellCheck, | ||
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, | ||
key: 'contents' + this.state.contentsKey, | ||
textDirectionality: this.props.textDirectionality | ||
}) | ||
React.createElement(DraftEditorContents, editorContentsProps) | ||
) | ||
@@ -330,45 +413,2 @@ ) | ||
DraftEditor.prototype._focus = function _focus(scrollPosition) { | ||
var editorState = this.props.editorState; | ||
var alreadyHasFocus = editorState.getSelection().getHasFocus(); | ||
var editorNode = ReactDOM.findDOMNode(this.refs.editor); | ||
if (!editorNode) { | ||
// once in a while people call 'focus' in a setTimeout, and the node has | ||
// been deleted, so it can be null in that case. | ||
return; | ||
} | ||
var scrollParent = Style.getScrollParent(editorNode); | ||
var _ref = scrollPosition || getScrollPosition(scrollParent), | ||
x = _ref.x, | ||
y = _ref.y; | ||
!(editorNode instanceof HTMLElement) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'editorNode is not an HTMLElement') : invariant(false) : void 0; | ||
editorNode.focus(); | ||
// Restore scroll position | ||
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._blur = function _blur() { | ||
var editorNode = ReactDOM.findDOMNode(this.refs.editor); | ||
!(editorNode instanceof HTMLElement) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'editorNode is not an HTMLElement') : invariant(false) : void 0; | ||
editorNode.blur(); | ||
}; | ||
/** | ||
@@ -383,10 +423,2 @@ * Used via `this.setMode(...)`. | ||
DraftEditor.prototype._setMode = function _setMode(mode) { | ||
this._handler = handlerMap[mode]; | ||
}; | ||
DraftEditor.prototype._exitCurrentMode = function _exitCurrentMode() { | ||
this.setMode('edit'); | ||
}; | ||
/** | ||
@@ -403,10 +435,2 @@ * Used via `this.restoreEditorDOM()`. | ||
DraftEditor.prototype._restoreEditorDOM = function _restoreEditorDOM(scrollPosition) { | ||
var _this3 = this; | ||
this.setState({ contentsKey: this.state.contentsKey + 1 }, function () { | ||
_this3._focus(scrollPosition); | ||
}); | ||
}; | ||
/** | ||
@@ -419,6 +443,2 @@ * Used via `this.setClipboard(...)`. | ||
DraftEditor.prototype._setClipboard = function _setClipboard(clipboard) { | ||
this._clipboard = clipboard; | ||
}; | ||
/** | ||
@@ -431,6 +451,2 @@ * Used via `this.getClipboard()`. | ||
DraftEditor.prototype._getClipboard = function _getClipboard() { | ||
return this._clipboard; | ||
}; | ||
/** | ||
@@ -447,9 +463,4 @@ * Used via `this.update(...)`. | ||
DraftEditor.prototype._update = function _update(editorState) { | ||
this._latestEditorState = editorState; | ||
this.props.onChange(editorState); | ||
}; | ||
/** | ||
* Used in conjunction with `_onDragLeave()`, by counting the number of times | ||
* Used in conjunction with `onDragLeave()`, by counting the number of times | ||
* a dragged element enters and leaves the editor (or any of its children), | ||
@@ -460,18 +471,7 @@ * to determine when the dragged element absolutely leaves the editor. | ||
DraftEditor.prototype._onDragEnter = function _onDragEnter() { | ||
this._dragCount++; | ||
}; | ||
/** | ||
* See `_onDragEnter()`. | ||
* See `onDragEnter()`. | ||
*/ | ||
DraftEditor.prototype._onDragLeave = function _onDragLeave() { | ||
this._dragCount--; | ||
if (this._dragCount === 0) { | ||
this.exitCurrentMode(); | ||
} | ||
}; | ||
return DraftEditor; | ||
@@ -478,0 +478,0 @@ }(React.Component); |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftEditorBlock.react | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -46,2 +46,9 @@ */ | ||
/** | ||
* Return whether a block overlaps with either edge of the `SelectionState`. | ||
*/ | ||
var isBlockOnSelectionEdge = function isBlockOnSelectionEdge(selection, key) { | ||
return selection.getAnchorKey() === key || selection.getFocusKey() === key; | ||
}; | ||
/** | ||
* The default block renderer for a `DraftEditor` component. | ||
@@ -52,2 +59,3 @@ * | ||
*/ | ||
var DraftEditorBlock = function (_React$Component) { | ||
@@ -90,3 +98,3 @@ _inherits(DraftEditorBlock, _React$Component); | ||
var scrollPosition = getScrollPosition(scrollParent); | ||
var scrollDelta; | ||
var scrollDelta = void 0; | ||
@@ -128,21 +136,15 @@ if (scrollParent === window) { | ||
var end = leaf.get('end'); | ||
return ( | ||
/* $FlowFixMe(>=0.53.0 site=www,mobile) This comment suppresses an | ||
* error when upgrading Flow's support for React. Common errors found | ||
* when upgrading Flow's React support are documented at | ||
* https://fburl.com/eq7bs81w */ | ||
React.createElement(DraftEditorLeaf, { | ||
key: offsetKey, | ||
offsetKey: offsetKey, | ||
block: block, | ||
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 | ||
}) | ||
); | ||
return React.createElement(DraftEditorLeaf, { | ||
key: offsetKey, | ||
offsetKey: offsetKey, | ||
block: block, | ||
start: start, | ||
selection: hasSelection ? _this2.props.selection : null, | ||
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(); | ||
@@ -189,6 +191,2 @@ | ||
DraftEditorBlock.prototype.render = function render() { | ||
/* $FlowFixMe(>=0.53.0 site=www,mobile) This comment suppresses an error | ||
* when upgrading Flow's support for React. Common errors found when | ||
* upgrading Flow's React support are documented at | ||
* https://fburl.com/eq7bs81w */ | ||
var _props = this.props, | ||
@@ -214,11 +212,2 @@ direction = _props.direction, | ||
/** | ||
* Return whether a block overlaps with either edge of the `SelectionState`. | ||
*/ | ||
function isBlockOnSelectionEdge(selection, key) { | ||
return selection.getAnchorKey() === key || selection.getFocusKey() === key; | ||
} | ||
module.exports = DraftEditorBlock; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftEditorCommand | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftEditorCompositionHandler | ||
* @format | ||
* | ||
@@ -16,2 +17,3 @@ */ | ||
var DraftFeatureFlags = require('./DraftFeatureFlags'); | ||
var DraftModifier = require('./DraftModifier'); | ||
@@ -22,2 +24,3 @@ var EditorState = require('./EditorState'); | ||
var getEntityKeyForSelection = require('./getEntityKeyForSelection'); | ||
var isEventHandled = require('./isEventHandled'); | ||
var isSelectionAtLeafStart = require('./isSelectionAtLeafStart'); | ||
@@ -156,2 +159,5 @@ | ||
if (composedChars) { | ||
if (DraftFeatureFlags.draft_handlebeforeinput_composed_text && editor.props.handleBeforeInput && isEventHandled(editor.props.handleBeforeInput(composedChars, editorState))) { | ||
return; | ||
} | ||
// If characters have been composed, re-rendering with the update | ||
@@ -158,0 +164,0 @@ // is sufficient to reset the editor. |
/** | ||
* Copyright (c) 2013-present, Facebook, Inc. | ||
* Copyright 2013-present, Facebook, Inc. | ||
* All rights reserved. | ||
@@ -10,3 +10,3 @@ * | ||
* @providesModule DraftEditorContents.react | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -17,240 +17,4 @@ */ | ||
var _assign = require('object-assign'); | ||
var DraftEditorContents = require('./DraftEditorContents-core.react'); | ||
var _extends = _assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
var DraftEditorBlock = require('./DraftEditorBlock.react'); | ||
var DraftOffsetKey = require('./DraftOffsetKey'); | ||
var EditorState = require('./EditorState'); | ||
var React = require('react'); | ||
var cx = require('fbjs/lib/cx'); | ||
var joinClasses = require('fbjs/lib/joinClasses'); | ||
var nullthrows = require('fbjs/lib/nullthrows'); | ||
/** | ||
* `DraftEditorContents` is the container component for all block components | ||
* rendered for a `DraftEditor`. It is optimized to aggressively avoid | ||
* re-rendering blocks whenever possible. | ||
* | ||
* This component is separate from `DraftEditor` because certain props | ||
* (for instance, ARIA props) must be allowed to update without affecting | ||
* the contents of the editor. | ||
*/ | ||
var DraftEditorContents = function (_React$Component) { | ||
_inherits(DraftEditorContents, _React$Component); | ||
function DraftEditorContents() { | ||
_classCallCheck(this, DraftEditorContents); | ||
return _possibleConstructorReturn(this, _React$Component.apply(this, arguments)); | ||
} | ||
DraftEditorContents.prototype.shouldComponentUpdate = 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(); | ||
}; | ||
DraftEditorContents.prototype.render = function render() { | ||
var _props = this.props, | ||
blockRenderMap = _props.blockRenderMap, | ||
blockRendererFn = _props.blockRendererFn, | ||
customStyleMap = _props.customStyleMap, | ||
customStyleFn = _props.customStyleFn, | ||
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 _textDirectionality = this.props.textDirectionality; | ||
var direction = _textDirectionality ? _textDirectionality : 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) || blockRenderMap.get('unstyled'); | ||
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, | ||
/* $FlowFixMe(>=0.53.0 site=www,mobile) This comment suppresses an | ||
* error when upgrading Flow's support for React. Common errors found | ||
* when upgrading Flow's React support are documented at | ||
* https://fburl.com/eq7bs81w */ | ||
'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, | ||
/* $FlowFixMe(>=0.53.0 site=www,mobile) This comment suppresses an | ||
* error when upgrading Flow's support for React. Common errors found | ||
* when upgrading Flow's React support are documented at | ||
* https://fburl.com/eq7bs81w */ | ||
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 | ||
); | ||
}; | ||
return DraftEditorContents; | ||
}(React.Component); | ||
/** | ||
* Provide default styling for list items. This way, lists will be styled with | ||
* proper counters and indentation even if the caller does not specify | ||
* their own styling at all. If more than five levels of nesting are needed, | ||
* the necessary CSS classes can be provided via `blockStyleFn` configuration. | ||
*/ | ||
function getListItemClasses(type, depth, shouldResetCount, direction) { | ||
return cx({ | ||
'public/DraftStyleDefault/unorderedListItem': type === 'unordered-list-item', | ||
'public/DraftStyleDefault/orderedListItem': type === 'ordered-list-item', | ||
'public/DraftStyleDefault/reset': shouldResetCount, | ||
'public/DraftStyleDefault/depth0': depth === 0, | ||
'public/DraftStyleDefault/depth1': depth === 1, | ||
'public/DraftStyleDefault/depth2': depth === 2, | ||
'public/DraftStyleDefault/depth3': depth === 3, | ||
'public/DraftStyleDefault/depth4': depth === 4, | ||
'public/DraftStyleDefault/listLTR': direction === 'LTR', | ||
'public/DraftStyleDefault/listRTL': direction === 'RTL' | ||
}); | ||
} | ||
module.exports = DraftEditorContents; |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftEditorDragHandler | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -100,3 +100,2 @@ */ | ||
} | ||
}; | ||
@@ -103,0 +102,0 @@ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftEditorEditHandler | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftEditorLeaf.react | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -25,3 +25,2 @@ */ | ||
var ContentBlock = require('./ContentBlock'); | ||
var DraftEditorTextNode = require('./DraftEditorTextNode.react'); | ||
@@ -52,11 +51,2 @@ var React = require('react'); | ||
/** | ||
* By making individual leaf instances aware of their context within | ||
* the text of the editor, we can set our selection range more | ||
* easily than we could in the non-React world. | ||
* | ||
* Note that this depends on our maintaining tight control over the | ||
* DOM structure of the DraftEditor component. If leaves had multiple | ||
* text nodes, this would be harder. | ||
*/ | ||
DraftEditorLeaf.prototype._setSelection = function _setSelection() { | ||
@@ -102,5 +92,14 @@ var selection = this.props.selection; | ||
}; | ||
/** | ||
* By making individual leaf instances aware of their context within | ||
* the text of the editor, we can set our selection range more | ||
* easily than we could in the non-React world. | ||
* | ||
* Note that this depends on our maintaining tight control over the | ||
* DOM structure of the DraftEditor component. If leaves had multiple | ||
* text nodes, this would be harder. | ||
*/ | ||
DraftEditorLeaf.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps) { | ||
var leafNode = ReactDOM.findDOMNode(this.refs.leaf); | ||
var leafNode = ReactDOM.findDOMNode(this.leaf); | ||
!leafNode ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Missing leafNode') : invariant(false) : void 0; | ||
@@ -119,2 +118,4 @@ return leafNode.textContent !== nextProps.text || nextProps.styleSet !== this.props.styleSet || nextProps.forceSelection; | ||
DraftEditorLeaf.prototype.render = function render() { | ||
var _this2 = this; | ||
var block = this.props.block; | ||
@@ -159,3 +160,5 @@ var text = this.props.text; | ||
'data-offset-key': offsetKey, | ||
ref: 'leaf', | ||
ref: function ref(_ref) { | ||
return _this2.leaf = _ref; | ||
}, | ||
style: styleObj }, | ||
@@ -162,0 +165,0 @@ React.createElement( |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftEditorModes | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftEditorPlaceholder.react | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -54,2 +54,6 @@ */ | ||
var contentStyle = { | ||
whiteSpace: 'pre-wrap' | ||
}; | ||
return React.createElement( | ||
@@ -62,3 +66,4 @@ 'div', | ||
className: cx('public/DraftEditorPlaceholder/inner'), | ||
id: this.props.accessibilityID }, | ||
id: this.props.accessibilityID, | ||
style: contentStyle }, | ||
this.props.text | ||
@@ -65,0 +70,0 @@ ) |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftEditorProps | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftEditorTextNode.react | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -76,2 +76,4 @@ */ | ||
// By flipping this flag, we also keep flipping keys which forces | ||
// React to remount this node every time it rerenders. | ||
var _this = _possibleConstructorReturn(this, _React$Component.call(this, props)); | ||
@@ -93,8 +95,10 @@ | ||
DraftEditorTextNode.prototype.componentWillUpdate = function componentWillUpdate() { | ||
// By flipping this flag, we also keep flipping keys which forces | ||
// React to remount this node every time it rerenders. | ||
DraftEditorTextNode.prototype.componentDidMount = function componentDidMount() { | ||
this._forceFlag = !this._forceFlag; | ||
}; | ||
DraftEditorTextNode.prototype.componentDidUpdate = function componentDidUpdate() { | ||
this._forceFlag = !this._forceFlag; | ||
}; | ||
DraftEditorTextNode.prototype.render = function render() { | ||
@@ -101,0 +105,0 @@ if (this.props.children === '') { |
@@ -16,3 +16,3 @@ 'use strict'; | ||
* @providesModule DraftEntity | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -19,0 +19,0 @@ */ |
@@ -10,2 +10,4 @@ /** | ||
* @providesModule DraftEntityInstance | ||
* @legacyServerCallableInstance | ||
* @format | ||
* | ||
@@ -12,0 +14,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftEntityMutability | ||
* @format | ||
* | ||
@@ -39,3 +40,3 @@ */ | ||
* Segmented entities allow the removal of partial ranges of text, as | ||
* separated by a delimiter. Adding characters wihin the range will remove | ||
* separated by a delimiter. Adding characters within the range will remove | ||
* the entity from the entire range. Deleting characters within a segmented | ||
@@ -42,0 +43,0 @@ * entity will delete only the segments affected by the deletion. Example: |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftEntitySegments | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftEntityType | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftFeatureFlags-core | ||
* @format | ||
* | ||
@@ -18,5 +19,7 @@ */ | ||
draft_killswitch_allow_nontextnodes: false, | ||
draft_segmented_entities_behavior: false | ||
draft_segmented_entities_behavior: false, | ||
draft_handlebeforeinput_composed_text: false, | ||
draft_tree_data_support: false | ||
}; | ||
module.exports = DraftFeatureFlags; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftFeatureFlags | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftHandleValue | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftInlineStyle | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftInsertionType | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftModifier | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftOffsetKey | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftOffsetKeyPath | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftPasteProcessor | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -17,4 +17,10 @@ */ | ||
var _assign = require('object-assign'); | ||
var _extends = _assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var CharacterMetadata = require('./CharacterMetadata'); | ||
var ContentBlock = require('./ContentBlock'); | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var DraftFeatureFlags = require('./DraftFeatureFlags'); | ||
var Immutable = require('immutable'); | ||
@@ -31,2 +37,5 @@ | ||
var experimentalTreeDataSupport = DraftFeatureFlags.draft_tree_data_support; | ||
var ContentBlockRecord = experimentalTreeDataSupport ? ContentBlockNode : ContentBlock; | ||
var DraftPasteProcessor = { | ||
@@ -37,11 +46,29 @@ processHTML: function processHTML(html, blockRenderMap) { | ||
processText: function processText(textBlocks, character, type) { | ||
return textBlocks.map(function (textLine) { | ||
return textBlocks.reduce(function (acc, textLine, index) { | ||
textLine = sanitizeDraftText(textLine); | ||
return new ContentBlock({ | ||
key: generateRandomKey(), | ||
var key = generateRandomKey(); | ||
var blockNodeConfig = { | ||
key: key, | ||
type: type, | ||
text: textLine, | ||
characterList: List(Repeat(character, textLine.length)) | ||
}); | ||
}); | ||
}; | ||
// next block updates previous block | ||
if (experimentalTreeDataSupport && index !== 0) { | ||
var prevSiblingIndex = index - 1; | ||
// update previous block | ||
var previousBlock = acc[prevSiblingIndex] = acc[prevSiblingIndex].merge({ | ||
nextSibling: key | ||
}); | ||
blockNodeConfig = _extends({}, blockNodeConfig, { | ||
prevSibling: previousBlock.getKey() | ||
}); | ||
} | ||
acc.push(new ContentBlockRecord(blockNodeConfig)); | ||
return acc; | ||
}, []); | ||
} | ||
@@ -48,0 +75,0 @@ }; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftRange | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftRemovableWord | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftRemovalDirection | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftScrollPosition | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule DraftStringKey | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule DraftTextAlignment | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnBeforeInput | ||
* @format | ||
* | ||
@@ -34,4 +35,4 @@ */ | ||
// trigger quickfind. | ||
var FF_QUICKFIND_CHAR = '\''; | ||
var FF_QUICKFIND_LINK_CHAR = '\/'; | ||
var FF_QUICKFIND_CHAR = "'"; | ||
var FF_QUICKFIND_LINK_CHAR = '/'; | ||
var isFirefox = UserAgent.isBrowser('Firefox'); | ||
@@ -98,8 +99,8 @@ | ||
// If the character that the user is trying to replace with | ||
// is the same as the current selection text the just update the | ||
// `SelectionState`. Else, update the ContentState with the new text | ||
// If the currently selected text matches what the user is trying to | ||
// replace it with, let's just update the `SelectionState`. If not, update | ||
// the `ContentState` with the new text. | ||
var currentlySelectedChars = editorState.getCurrentContent().getPlainText().slice(selectionStart, selectionEnd); | ||
if (chars === currentlySelectedChars) { | ||
this.update(EditorState.forceSelection(editorState, selection.merge({ | ||
editor.update(EditorState.forceSelection(editorState, selection.merge({ | ||
focusOffset: selectionEnd | ||
@@ -106,0 +107,0 @@ }))); |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnBlur | ||
* @format | ||
* | ||
@@ -32,3 +33,3 @@ */ | ||
var _selection = global.getSelection(); | ||
var editorNode = editor.refs.editor; | ||
var editorNode = editor.editor; | ||
if (_selection.rangeCount === 1 && containsNode(editorNode, _selection.anchorNode) && containsNode(editorNode, _selection.focusNode)) { | ||
@@ -35,0 +36,0 @@ _selection.removeAllRanges(); |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnCompositionStart | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnCopy | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnCut | ||
* @format | ||
* | ||
@@ -35,2 +36,4 @@ */ | ||
var selection = editorState.getSelection(); | ||
var element = e.target; | ||
var scrollPosition = void 0; | ||
@@ -45,9 +48,6 @@ // No selection, so there's nothing to cut. | ||
// after the editor regains control of the DOM. | ||
// $FlowFixMe e.target should be an instanceof Node | ||
var scrollParent = Style.getScrollParent(e.target); | ||
if (element instanceof Node) { | ||
scrollPosition = getScrollPosition(Style.getScrollParent(element)); | ||
} | ||
var _getScrollPosition = getScrollPosition(scrollParent), | ||
x = _getScrollPosition.x, | ||
y = _getScrollPosition.y; | ||
var fragment = getFragmentFromSelection(editorState); | ||
@@ -61,3 +61,3 @@ editor.setClipboard(fragment); | ||
setTimeout(function () { | ||
editor.restoreEditorDOM({ x: x, y: y }); | ||
editor.restoreEditorDOM(scrollPosition); | ||
editor.exitCurrentMode(); | ||
@@ -64,0 +64,0 @@ editor.update(removeFragment(editorState)); |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnDragOver | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnDragStart | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnFocus | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnInput | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnKeyDown | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnPaste | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule editOnSelect | ||
* @format | ||
* | ||
@@ -28,3 +29,3 @@ */ | ||
var editorState = editor.props.editorState; | ||
var editorNode = ReactDOM.findDOMNode(editor.refs.editorContainer); | ||
var editorNode = ReactDOM.findDOMNode(editor.editorContainer); | ||
!editorNode ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Missing editorNode') : invariant(false) : void 0; | ||
@@ -31,0 +32,0 @@ !(editorNode.firstChild instanceof HTMLElement) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'editorNode.firstChild is not an HTMLElement') : invariant(false) : void 0; |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule EditorBidiService | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule EditorChangeType | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule EditorState | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule EditorStateCreationConfig | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule encodeEntityRanges | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule encodeInlineStyleRanges | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule EntityMap | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule EntityRange | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -12,3 +12,3 @@ 'use strict'; | ||
* @providesModule expandRangeToStartOfLine | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -15,0 +15,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule findAncestorOffsetKey | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule findRangesImmutable | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule generateRandomKey | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getCharacterRemovalRange | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getContentStateFragment | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -17,6 +17,6 @@ */ | ||
var generateRandomKey = require('./generateRandomKey'); | ||
var randomizeBlockMapKeys = require('./randomizeBlockMapKeys'); | ||
var removeEntitiesAtEdges = require('./removeEntitiesAtEdges'); | ||
function getContentStateFragment(contentState, selectionState) { | ||
var getContentStateFragment = function getContentStateFragment(contentState, selectionState) { | ||
var startKey = selectionState.getStartKey(); | ||
@@ -37,5 +37,3 @@ var startOffset = selectionState.getStartOffset(); | ||
var slice = blockMap.slice(startIndex, endIndex).map(function (block, blockKey) { | ||
var newKey = generateRandomKey(); | ||
return randomizeBlockMapKeys(blockMap.slice(startIndex, endIndex).map(function (block, blockKey) { | ||
var text = block.getText(); | ||
@@ -46,3 +44,2 @@ var chars = block.getCharacterList(); | ||
return block.merge({ | ||
key: newKey, | ||
text: text.slice(startOffset, endOffset), | ||
@@ -55,3 +52,2 @@ characterList: chars.slice(startOffset, endOffset) | ||
return block.merge({ | ||
key: newKey, | ||
text: text.slice(startOffset), | ||
@@ -64,3 +60,2 @@ characterList: chars.slice(startOffset) | ||
return block.merge({ | ||
key: newKey, | ||
text: text.slice(0, endOffset), | ||
@@ -71,8 +66,6 @@ characterList: chars.slice(0, endOffset) | ||
return block.set('key', newKey); | ||
}); | ||
return block; | ||
})); | ||
}; | ||
return slice.toOrderedMap(); | ||
} | ||
module.exports = getContentStateFragment; |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getDefaultKeyBinding | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getDraftEditorSelection | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getDraftEditorSelectionWithNodes | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -98,3 +98,5 @@ */ | ||
function getFirstLeaf(node) { | ||
while (node.firstChild && getSelectionOffsetKeyForNode(node.firstChild)) { | ||
while (node.firstChild && ( | ||
// data-blocks has no offset | ||
node.firstChild instanceof Element && node.firstChild.getAttribute('data-blocks') === 'true' || getSelectionOffsetKeyForNode(node.firstChild))) { | ||
node = node.firstChild; | ||
@@ -109,3 +111,5 @@ } | ||
function getLastLeaf(node) { | ||
while (node.lastChild && getSelectionOffsetKeyForNode(node.lastChild)) { | ||
while (node.lastChild && ( | ||
// data-blocks has no offset | ||
node.lastChild instanceof Element && node.lastChild.getAttribute('data-blocks') === 'true' || getSelectionOffsetKeyForNode(node.lastChild))) { | ||
node = node.lastChild; | ||
@@ -112,0 +116,0 @@ } |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getEntityKeyForSelection | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -30,2 +30,5 @@ */ | ||
entityKey = contentState.getBlockForKey(key).getEntityAt(offset - 1); | ||
if (entityKey !== contentState.getBlockForKey(key).getEntityAt(offset)) { | ||
return null; | ||
} | ||
return filterKey(contentState.getEntityMap(), entityKey); | ||
@@ -32,0 +35,0 @@ } |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule getFragmentFromSelection | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getRangeBoundingClientRect | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getRangeClientRects | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getRangesForDraftEntity | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule getSafeBodyFromHTML | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getSampleStateForTesting | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -29,3 +29,3 @@ */ | ||
var ENTITY_KEY = '123'; | ||
var ENTITY_KEY = '1'; | ||
@@ -44,2 +44,17 @@ var BLOCKS = [new ContentBlock({ | ||
key: 'c', | ||
type: 'code-block', | ||
text: 'Test', | ||
characterList: Immutable.List(Immutable.Repeat(CharacterMetadata.EMPTY, 4)) | ||
}), new ContentBlock({ | ||
key: 'd', | ||
type: 'code-block', | ||
text: '', | ||
characterList: Immutable.List() | ||
}), new ContentBlock({ | ||
key: 'e', | ||
type: 'code-block', | ||
text: '', | ||
characterList: Immutable.List() | ||
}), new ContentBlock({ | ||
key: 'f', | ||
type: 'blockquote', | ||
@@ -65,2 +80,6 @@ text: 'Charlie', | ||
selectionAfter: selectionState | ||
}).createEntity({ | ||
type: 'IMAGE', | ||
mutability: 'IMMUTABLE', | ||
data: null | ||
}); | ||
@@ -71,6 +90,6 @@ | ||
function getSampleStateForTesting() { | ||
var getSampleStateForTesting = function getSampleStateForTesting() { | ||
return { editorState: editorState, contentState: contentState, selectionState: selectionState }; | ||
} | ||
}; | ||
module.exports = getSampleStateForTesting; |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getSelectionOffsetKeyForNode | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getTextAfterNearestEntity | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule getTextContentFromFiles | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule getUpdatedSelectionState | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule getVisibleSelectionRect | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule InlineStyleRange | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule insertFragmentIntoContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -18,98 +18,202 @@ */ | ||
var BlockMapBuilder = require('./BlockMapBuilder'); | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var Immutable = require('immutable'); | ||
var generateRandomKey = require('./generateRandomKey'); | ||
var insertIntoList = require('./insertIntoList'); | ||
var invariant = require('fbjs/lib/invariant'); | ||
var randomizeBlockMapKeys = require('./randomizeBlockMapKeys'); | ||
function insertFragmentIntoContentState(contentState, selectionState, fragment) { | ||
!selectionState.isCollapsed() ? process.env.NODE_ENV !== 'production' ? invariant(false, '`insertFragment` should only be called with a collapsed selection state.') : invariant(false) : void 0; | ||
var List = Immutable.List; | ||
var targetKey = selectionState.getStartKey(); | ||
var targetOffset = selectionState.getStartOffset(); | ||
var blockMap = contentState.getBlockMap(); | ||
var updateExistingBlock = function updateExistingBlock(contentState, selectionState, blockMap, fragmentBlock, targetKey, targetOffset) { | ||
var targetBlock = blockMap.get(targetKey); | ||
var text = targetBlock.getText(); | ||
var chars = targetBlock.getCharacterList(); | ||
var finalKey = targetKey; | ||
var finalOffset = targetOffset + fragmentBlock.getText().length; | ||
var fragmentSize = fragment.size; | ||
var finalKey; | ||
var finalOffset; | ||
var newBlock = targetBlock.merge({ | ||
text: text.slice(0, targetOffset) + fragmentBlock.getText() + text.slice(targetOffset), | ||
characterList: insertIntoList(chars, fragmentBlock.getCharacterList(), targetOffset), | ||
data: fragmentBlock.getData() | ||
}); | ||
if (fragmentSize === 1) { | ||
var targetBlock = blockMap.get(targetKey); | ||
var pastedBlock = fragment.first(); | ||
var text = targetBlock.getText(); | ||
var chars = targetBlock.getCharacterList(); | ||
return contentState.merge({ | ||
blockMap: blockMap.set(targetKey, newBlock), | ||
selectionBefore: selectionState, | ||
selectionAfter: selectionState.merge({ | ||
anchorKey: finalKey, | ||
anchorOffset: finalOffset, | ||
focusKey: finalKey, | ||
focusOffset: finalOffset, | ||
isBackward: false | ||
}) | ||
}); | ||
}; | ||
var newBlock = targetBlock.merge({ | ||
text: text.slice(0, targetOffset) + pastedBlock.getText() + text.slice(targetOffset), | ||
characterList: insertIntoList(chars, pastedBlock.getCharacterList(), targetOffset), | ||
data: pastedBlock.getData() | ||
}); | ||
/** | ||
* Appends text/characterList from the fragment first block to | ||
* target block. | ||
*/ | ||
var updateHead = function updateHead(block, targetOffset, fragment) { | ||
var text = block.getText(); | ||
var chars = block.getCharacterList(); | ||
finalKey = targetKey; | ||
finalOffset = targetOffset + pastedBlock.getText().length; | ||
// Modify head portion of block. | ||
var headText = text.slice(0, targetOffset); | ||
var headCharacters = chars.slice(0, targetOffset); | ||
var appendToHead = fragment.first(); | ||
return contentState.merge({ | ||
blockMap: blockMap.set(targetKey, newBlock), | ||
selectionBefore: selectionState, | ||
selectionAfter: selectionState.merge({ | ||
anchorKey: finalKey, | ||
anchorOffset: finalOffset, | ||
focusKey: finalKey, | ||
focusOffset: finalOffset, | ||
isBackward: false | ||
}) | ||
}); | ||
return block.merge({ | ||
text: headText + appendToHead.getText(), | ||
characterList: headCharacters.concat(appendToHead.getCharacterList()), | ||
type: headText ? block.getType() : appendToHead.getType(), | ||
data: appendToHead.getData() | ||
}); | ||
}; | ||
/** | ||
* Appends offset text/characterList from the target block to the last | ||
* fragment block. | ||
*/ | ||
var updateTail = function updateTail(block, targetOffset, fragment) { | ||
// Modify tail portion of block. | ||
var text = block.getText(); | ||
var chars = block.getCharacterList(); | ||
// Modify head portion of block. | ||
var blockSize = text.length; | ||
var tailText = text.slice(targetOffset, blockSize); | ||
var tailCharacters = chars.slice(targetOffset, blockSize); | ||
var prependToTail = fragment.last(); | ||
return prependToTail.merge({ | ||
text: prependToTail.getText() + tailText, | ||
characterList: prependToTail.getCharacterList().concat(tailCharacters), | ||
data: prependToTail.getData() | ||
}); | ||
}; | ||
var getRootBlocks = function getRootBlocks(block, blockMap) { | ||
var headKey = block.getKey(); | ||
var rootBlock = block; | ||
var rootBlocks = []; | ||
// sometimes the fragment head block will not be part of the blockMap itself this can happen when | ||
// the fragment head is used to update the target block, however when this does not happen we need | ||
// to make sure that we include it on the rootBlocks since the first block of a fragment is always a | ||
// fragment root block | ||
if (blockMap.get(headKey)) { | ||
rootBlocks.push(headKey); | ||
} | ||
var newBlockArr = []; | ||
while (rootBlock && rootBlock.getNextSiblingKey()) { | ||
var lastSiblingKey = rootBlock.getNextSiblingKey(); | ||
contentState.getBlockMap().forEach(function (block, blockKey) { | ||
if (blockKey !== targetKey) { | ||
newBlockArr.push(block); | ||
return; | ||
if (!lastSiblingKey) { | ||
break; | ||
} | ||
var text = block.getText(); | ||
var chars = block.getCharacterList(); | ||
rootBlocks.push(lastSiblingKey); | ||
rootBlock = blockMap.get(lastSiblingKey); | ||
} | ||
// Modify head portion of block. | ||
var blockSize = text.length; | ||
var headText = text.slice(0, targetOffset); | ||
var headCharacters = chars.slice(0, targetOffset); | ||
var appendToHead = fragment.first(); | ||
return rootBlocks; | ||
}; | ||
var modifiedHead = block.merge({ | ||
text: headText + appendToHead.getText(), | ||
characterList: headCharacters.concat(appendToHead.getCharacterList()), | ||
type: headText ? block.getType() : appendToHead.getType(), | ||
data: appendToHead.getData() | ||
}); | ||
var updateBlockMapLinks = function updateBlockMapLinks(blockMap, originalBlockMap, targetBlock, fragmentHeadBlock) { | ||
return blockMap.withMutations(function (blockMapState) { | ||
var targetKey = targetBlock.getKey(); | ||
var headKey = fragmentHeadBlock.getKey(); | ||
var targetNextKey = targetBlock.getNextSiblingKey(); | ||
var targetParentKey = targetBlock.getParentKey(); | ||
var fragmentRootBlocks = getRootBlocks(fragmentHeadBlock, blockMap); | ||
var lastRootFragmentBlockKey = fragmentRootBlocks[fragmentRootBlocks.length - 1]; | ||
newBlockArr.push(modifiedHead); | ||
if (blockMapState.get(headKey)) { | ||
// update the fragment head when it is part of the blockMap otherwise | ||
blockMapState.setIn([targetKey, 'nextSibling'], headKey); | ||
blockMapState.setIn([headKey, 'prevSibling'], targetKey); | ||
} else { | ||
// update the target block that had the fragment head contents merged into it | ||
blockMapState.setIn([targetKey, 'nextSibling'], fragmentHeadBlock.getNextSiblingKey()); | ||
blockMapState.setIn([fragmentHeadBlock.getNextSiblingKey(), 'prevSibling'], targetKey); | ||
} | ||
// Insert fragment blocks after the head and before the tail. | ||
fragment.slice(1, fragmentSize - 1).forEach(function (fragmentBlock) { | ||
newBlockArr.push(fragmentBlock.set('key', generateRandomKey())); | ||
// update the last root block fragment | ||
blockMapState.setIn([lastRootFragmentBlockKey, 'nextSibling'], targetNextKey); | ||
// update the original target next block | ||
if (targetNextKey) { | ||
blockMapState.setIn([targetNextKey, 'prevSibling'], lastRootFragmentBlockKey); | ||
} | ||
// update fragment parent links | ||
fragmentRootBlocks.forEach(function (blockKey) { | ||
return blockMapState.setIn([blockKey, 'parent'], targetParentKey); | ||
}); | ||
// Modify tail portion of block. | ||
var tailText = text.slice(targetOffset, blockSize); | ||
var tailCharacters = chars.slice(targetOffset, blockSize); | ||
var prependToTail = fragment.last(); | ||
finalKey = generateRandomKey(); | ||
// update targetBlock parent child links | ||
if (targetParentKey) { | ||
var targetParent = blockMap.get(targetParentKey); | ||
var originalTargetParentChildKeys = targetParent.getChildKeys(); | ||
var modifiedTail = prependToTail.merge({ | ||
key: finalKey, | ||
text: prependToTail.getText() + tailText, | ||
characterList: prependToTail.getCharacterList().concat(tailCharacters), | ||
data: prependToTail.getData() | ||
var targetBlockIndex = originalTargetParentChildKeys.indexOf(targetKey); | ||
var insertionIndex = targetBlockIndex + 1; | ||
var newChildrenKeysArray = originalTargetParentChildKeys.toArray(); | ||
// insert fragment children | ||
newChildrenKeysArray.splice.apply(newChildrenKeysArray, [insertionIndex, 0].concat(fragmentRootBlocks)); | ||
blockMapState.setIn([targetParentKey, 'children'], List(newChildrenKeysArray)); | ||
} | ||
}); | ||
}; | ||
var insertFragment = function insertFragment(contentState, selectionState, blockMap, fragment, targetKey, targetOffset) { | ||
var isTreeBasedBlockMap = blockMap.first() instanceof ContentBlockNode; | ||
var newBlockArr = []; | ||
var fragmentSize = fragment.size; | ||
var target = blockMap.get(targetKey); | ||
var head = fragment.first(); | ||
var tail = fragment.last(); | ||
var finalOffset = tail.getLength(); | ||
var finalKey = tail.getKey(); | ||
var shouldNotUpdateFromFragmentBlock = isTreeBasedBlockMap && (!target.getChildKeys().isEmpty() || !head.getChildKeys().isEmpty()); | ||
blockMap.forEach(function (block, blockKey) { | ||
if (blockKey !== targetKey) { | ||
newBlockArr.push(block); | ||
return; | ||
} | ||
if (shouldNotUpdateFromFragmentBlock) { | ||
newBlockArr.push(block); | ||
} else { | ||
newBlockArr.push(updateHead(block, targetOffset, fragment)); | ||
} | ||
// Insert fragment blocks after the head and before the tail. | ||
fragment | ||
// when we are updating the target block with the head fragment block we skip the first fragment | ||
// head since its contents have already been merged with the target block otherwise we include | ||
// the whole fragment | ||
.slice(shouldNotUpdateFromFragmentBlock ? 0 : 1, fragmentSize - 1).forEach(function (fragmentBlock) { | ||
return newBlockArr.push(fragmentBlock); | ||
}); | ||
newBlockArr.push(modifiedTail); | ||
// update tail | ||
newBlockArr.push(updateTail(block, targetOffset, fragment)); | ||
}); | ||
finalOffset = fragment.last().getLength(); | ||
var updatedBlockMap = BlockMapBuilder.createFromArray(newBlockArr); | ||
if (isTreeBasedBlockMap) { | ||
updatedBlockMap = updateBlockMapLinks(updatedBlockMap, blockMap, target, head); | ||
} | ||
return contentState.merge({ | ||
blockMap: BlockMapBuilder.createFromArray(newBlockArr), | ||
blockMap: updatedBlockMap, | ||
selectionBefore: selectionState, | ||
@@ -124,4 +228,27 @@ selectionAfter: selectionState.merge({ | ||
}); | ||
} | ||
}; | ||
var insertFragmentIntoContentState = function insertFragmentIntoContentState(contentState, selectionState, fragmentBlockMap) { | ||
!selectionState.isCollapsed() ? process.env.NODE_ENV !== 'production' ? invariant(false, '`insertFragment` should only be called with a collapsed selection state.') : invariant(false) : void 0; | ||
var blockMap = contentState.getBlockMap(); | ||
var fragment = randomizeBlockMapKeys(fragmentBlockMap); | ||
var targetKey = selectionState.getStartKey(); | ||
var targetOffset = selectionState.getStartOffset(); | ||
var targetBlock = blockMap.get(targetKey); | ||
if (targetBlock instanceof ContentBlockNode) { | ||
!targetBlock.getChildKeys().isEmpty() ? process.env.NODE_ENV !== 'production' ? invariant(false, '`insertFragment` should not be called when a container node is selected.') : invariant(false) : void 0; | ||
} | ||
// When we insert a fragment with a single block we simply update the target block | ||
// with the contents of the inserted fragment block | ||
if (fragment.size === 1) { | ||
return updateExistingBlock(contentState, selectionState, blockMap, fragment.first(), targetKey, targetOffset); | ||
} | ||
return insertFragment(contentState, selectionState, blockMap, fragment, targetKey, targetOffset); | ||
}; | ||
module.exports = insertFragmentIntoContentState; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule insertIntoList | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule insertTextIntoContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule isEventHandled | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule isSelectionAtLeafStart | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule isSoftNewlineEvent | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule KeyBindingUtil | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandBackspaceToStartOfLine | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandBackspaceWord | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandDeleteWord | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandInsertNewline | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandMoveSelectionToEndOfBlock | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandMoveSelectionToStartOfBlock | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandPlainBackspace | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandPlainDelete | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandTransposeCharacters | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule keyCommandUndo | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule modifyBlockForContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule moveBlockInContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -17,44 +17,179 @@ */ | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var Immutable = require('immutable'); | ||
var getNextDelimiterBlockKey = require('./getNextDelimiterBlockKey'); | ||
var invariant = require('fbjs/lib/invariant'); | ||
function moveBlockInContentState(contentState, blockToBeMoved, targetBlock, insertionMode) { | ||
!(blockToBeMoved.getKey() !== targetBlock.getKey()) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Block cannot be moved next to itself.') : invariant(false) : void 0; | ||
var OrderedMap = Immutable.OrderedMap, | ||
List = Immutable.List; | ||
var transformBlock = function transformBlock(key, blockMap, func) { | ||
if (!key) { | ||
return; | ||
} | ||
var block = blockMap.get(key); | ||
if (!block) { | ||
return; | ||
} | ||
blockMap.set(key, func(block)); | ||
}; | ||
var updateBlockMapLinks = function updateBlockMapLinks(blockMap, originalBlockToBeMoved, originalTargetBlock, insertionMode, isExperimentalTreeBlock) { | ||
if (!isExperimentalTreeBlock) { | ||
return blockMap; | ||
} | ||
// possible values of 'insertionMode' are: 'after', 'before' | ||
var isInsertedAfterTarget = insertionMode === 'after'; | ||
var originalBlockKey = originalBlockToBeMoved.getKey(); | ||
var originalTargetKey = originalTargetBlock.getKey(); | ||
var originalParentKey = originalBlockToBeMoved.getParentKey(); | ||
var originalNextSiblingKey = originalBlockToBeMoved.getNextSiblingKey(); | ||
var originalPrevSiblingKey = originalBlockToBeMoved.getPrevSiblingKey(); | ||
var newParentKey = originalTargetBlock.getParentKey(); | ||
var newNextSiblingKey = isInsertedAfterTarget ? originalTargetBlock.getNextSiblingKey() : originalTargetKey; | ||
var newPrevSiblingKey = isInsertedAfterTarget ? originalTargetKey : originalTargetBlock.getPrevSiblingKey(); | ||
return blockMap.withMutations(function (blocks) { | ||
// update old parent | ||
transformBlock(originalParentKey, blocks, function (block) { | ||
var parentChildrenList = block.getChildKeys(); | ||
return block.merge({ | ||
children: parentChildrenList['delete'](parentChildrenList.indexOf(originalBlockKey)) | ||
}); | ||
}); | ||
// update old prev | ||
transformBlock(originalPrevSiblingKey, blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: originalNextSiblingKey | ||
}); | ||
}); | ||
// update old next | ||
transformBlock(originalNextSiblingKey, blocks, function (block) { | ||
return block.merge({ | ||
prevSibling: originalPrevSiblingKey | ||
}); | ||
}); | ||
// update new next | ||
transformBlock(newNextSiblingKey, blocks, function (block) { | ||
return block.merge({ | ||
prevSibling: originalBlockKey | ||
}); | ||
}); | ||
// update new prev | ||
transformBlock(newPrevSiblingKey, blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: originalBlockKey | ||
}); | ||
}); | ||
// update new parent | ||
transformBlock(newParentKey, blocks, function (block) { | ||
var newParentChildrenList = block.getChildKeys(); | ||
var targetBlockIndex = newParentChildrenList.indexOf(originalTargetKey); | ||
var insertionIndex = isInsertedAfterTarget ? targetBlockIndex + 1 : targetBlockIndex !== 0 ? targetBlockIndex - 1 : 0; | ||
var newChildrenArray = newParentChildrenList.toArray(); | ||
newChildrenArray.splice(insertionIndex, 0, originalBlockKey); | ||
return block.merge({ | ||
children: List(newChildrenArray) | ||
}); | ||
}); | ||
// update block | ||
transformBlock(originalBlockKey, blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: newNextSiblingKey, | ||
prevSibling: newPrevSiblingKey, | ||
parent: newParentKey | ||
}); | ||
}); | ||
}); | ||
}; | ||
var moveBlockInContentState = function moveBlockInContentState(contentState, blockToBeMoved, targetBlock, insertionMode) { | ||
!(insertionMode !== 'replace') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Replacing blocks is not supported.') : invariant(false) : void 0; | ||
var targetKey = targetBlock.getKey(); | ||
var blockBefore = contentState.getBlockBefore(targetKey); | ||
var blockAfter = contentState.getBlockAfter(targetKey); | ||
var blockKey = blockToBeMoved.getKey(); | ||
!(blockKey !== targetKey) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Block cannot be moved next to itself.') : invariant(false) : void 0; | ||
var blockMap = contentState.getBlockMap(); | ||
var blockMapWithoutBlockToBeMoved = blockMap['delete'](blockToBeMoved.getKey()); | ||
var blocksBefore = blockMapWithoutBlockToBeMoved.toSeq().takeUntil(function (v) { | ||
var isExperimentalTreeBlock = blockToBeMoved instanceof ContentBlockNode; | ||
var blocksToBeMoved = [blockToBeMoved]; | ||
var blockMapWithoutBlocksToBeMoved = blockMap['delete'](blockKey); | ||
if (isExperimentalTreeBlock) { | ||
blocksToBeMoved = []; | ||
blockMapWithoutBlocksToBeMoved = blockMap.withMutations(function (blocks) { | ||
var nextSiblingKey = blockToBeMoved.getNextSiblingKey(); | ||
var nextDelimiterBlockKey = getNextDelimiterBlockKey(blockToBeMoved, blocks); | ||
blocks.toSeq().skipUntil(function (block) { | ||
return block.getKey() === blockKey; | ||
}).takeWhile(function (block) { | ||
var key = block.getKey(); | ||
var isBlockToBeMoved = key === blockKey; | ||
var hasNextSiblingAndIsNotNextSibling = nextSiblingKey && key !== nextSiblingKey; | ||
var doesNotHaveNextSiblingAndIsNotDelimiter = !nextSiblingKey && block.getParentKey() && (!nextDelimiterBlockKey || key !== nextDelimiterBlockKey); | ||
return !!(isBlockToBeMoved || hasNextSiblingAndIsNotNextSibling || doesNotHaveNextSiblingAndIsNotDelimiter); | ||
}).forEach(function (block) { | ||
blocksToBeMoved.push(block); | ||
blocks['delete'](block.getKey()); | ||
}); | ||
}); | ||
} | ||
var blocksBefore = blockMapWithoutBlocksToBeMoved.toSeq().takeUntil(function (v) { | ||
return v === targetBlock; | ||
}); | ||
var blocksAfter = blockMapWithoutBlockToBeMoved.toSeq().skipUntil(function (v) { | ||
var blocksAfter = blockMapWithoutBlocksToBeMoved.toSeq().skipUntil(function (v) { | ||
return v === targetBlock; | ||
}).skip(1); | ||
var newBlocks = void 0; | ||
var slicedBlocks = blocksToBeMoved.map(function (block) { | ||
return [block.getKey(), block]; | ||
}); | ||
var newBlocks = OrderedMap(); | ||
if (insertionMode === 'before') { | ||
var blockBefore = contentState.getBlockBefore(targetKey); | ||
!(!blockBefore || blockBefore.getKey() !== blockToBeMoved.getKey()) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Block cannot be moved next to itself.') : invariant(false) : void 0; | ||
newBlocks = blocksBefore.concat([[blockToBeMoved.getKey(), blockToBeMoved], [targetBlock.getKey(), targetBlock]], blocksAfter).toOrderedMap(); | ||
newBlocks = blocksBefore.concat([].concat(slicedBlocks, [[targetKey, targetBlock]]), blocksAfter).toOrderedMap(); | ||
} else if (insertionMode === 'after') { | ||
!(!blockAfter || blockAfter.getKey() !== blockToBeMoved.getKey()) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Block cannot be moved next to itself.') : invariant(false) : void 0; | ||
var blockAfter = contentState.getBlockAfter(targetKey); | ||
newBlocks = blocksBefore.concat([[targetBlock.getKey(), targetBlock], [blockToBeMoved.getKey(), blockToBeMoved]], blocksAfter).toOrderedMap(); | ||
!(!blockAfter || blockAfter.getKey() !== blockKey) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Block cannot be moved next to itself.') : invariant(false) : void 0; | ||
newBlocks = blocksBefore.concat([[targetKey, targetBlock]].concat(slicedBlocks), blocksAfter).toOrderedMap(); | ||
} | ||
return contentState.merge({ | ||
blockMap: newBlocks, | ||
blockMap: updateBlockMapLinks(newBlocks, blockToBeMoved, targetBlock, insertionMode, isExperimentalTreeBlock), | ||
selectionBefore: contentState.getSelectionAfter(), | ||
selectionAfter: contentState.getSelectionAfter().merge({ | ||
anchorKey: blockToBeMoved.getKey(), | ||
focusKey: blockToBeMoved.getKey() | ||
anchorKey: blockKey, | ||
focusKey: blockKey | ||
}) | ||
}); | ||
} | ||
}; | ||
module.exports = moveBlockInContentState; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule moveSelectionBackward | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule moveSelectionForward | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule RawDraftContentBlock | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule RawDraftContentState | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule RawDraftEntity | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule removeEntitiesAtEdges | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule removeRangeFromContentState | ||
* @format | ||
* | ||
@@ -16,5 +17,188 @@ */ | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var Immutable = require('immutable'); | ||
function removeRangeFromContentState(contentState, selectionState) { | ||
var getNextDelimiterBlockKey = require('./getNextDelimiterBlockKey'); | ||
var List = Immutable.List, | ||
Map = Immutable.Map; | ||
var transformBlock = function transformBlock(key, blockMap, func) { | ||
if (!key) { | ||
return; | ||
} | ||
var block = blockMap.get(key); | ||
if (!block) { | ||
return; | ||
} | ||
blockMap.set(key, func(block)); | ||
}; | ||
/** | ||
* Ancestors needs to be preserved when there are non selected | ||
* children to make sure we do not leave any orphans behind | ||
*/ | ||
var getAncestorsKeys = function getAncestorsKeys(blockKey, blockMap) { | ||
var parents = []; | ||
if (!blockKey) { | ||
return parents; | ||
} | ||
var blockNode = blockMap.get(blockKey); | ||
while (blockNode && blockNode.getParentKey()) { | ||
var parentKey = blockNode.getParentKey(); | ||
if (parentKey) { | ||
parents.push(parentKey); | ||
} | ||
blockNode = parentKey ? blockMap.get(parentKey) : null; | ||
} | ||
return parents; | ||
}; | ||
/** | ||
* Get all next delimiter keys until we hit a root delimiter and return | ||
* an array of key references | ||
*/ | ||
var getNextDelimitersBlockKeys = function getNextDelimitersBlockKeys(block, blockMap) { | ||
var nextDelimiters = []; | ||
if (!block) { | ||
return nextDelimiters; | ||
} | ||
var nextDelimiter = getNextDelimiterBlockKey(block, blockMap); | ||
while (nextDelimiter && blockMap.get(nextDelimiter)) { | ||
var _block = blockMap.get(nextDelimiter); | ||
nextDelimiters.push(nextDelimiter); | ||
// we do not need to keep checking all root node siblings, just the first occurance | ||
nextDelimiter = _block.getParentKey() ? getNextDelimiterBlockKey(_block, blockMap) : null; | ||
} | ||
return nextDelimiters; | ||
}; | ||
var getNextValidSibling = function getNextValidSibling(block, blockMap, originalBlockMap) { | ||
if (!block) { | ||
return null; | ||
} | ||
// note that we need to make sure we refer to the original block since this | ||
// function is called within a withMutations | ||
var nextValidSiblingKey = originalBlockMap.get(block.getKey()).getNextSiblingKey(); | ||
while (nextValidSiblingKey && !blockMap.get(nextValidSiblingKey)) { | ||
nextValidSiblingKey = originalBlockMap.get(nextValidSiblingKey).getNextSiblingKey() || null; | ||
} | ||
return nextValidSiblingKey; | ||
}; | ||
var getPrevValidSibling = function getPrevValidSibling(block, blockMap, originalBlockMap) { | ||
if (!block) { | ||
return null; | ||
} | ||
// note that we need to make sure we refer to the original block since this | ||
// function is called within a withMutations | ||
var prevValidSiblingKey = originalBlockMap.get(block.getKey()).getPrevSiblingKey(); | ||
while (prevValidSiblingKey && !blockMap.get(prevValidSiblingKey)) { | ||
prevValidSiblingKey = originalBlockMap.get(prevValidSiblingKey).getPrevSiblingKey() || null; | ||
} | ||
return prevValidSiblingKey; | ||
}; | ||
var updateBlockMapLinks = function updateBlockMapLinks(blockMap, startBlock, endBlock, originalBlockMap) { | ||
return blockMap.withMutations(function (blocks) { | ||
// update start block if its retained | ||
transformBlock(startBlock.getKey(), blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: getNextValidSibling(startBlock, blocks, originalBlockMap), | ||
prevSibling: getPrevValidSibling(startBlock, blocks, originalBlockMap) | ||
}); | ||
}); | ||
// update endblock if its retained | ||
transformBlock(endBlock.getKey(), blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: getNextValidSibling(endBlock, blocks, originalBlockMap), | ||
prevSibling: getPrevValidSibling(endBlock, blocks, originalBlockMap) | ||
}); | ||
}); | ||
// update start block parent ancestors | ||
getAncestorsKeys(startBlock.getKey(), originalBlockMap).forEach(function (parentKey) { | ||
return transformBlock(parentKey, blocks, function (block) { | ||
return block.merge({ | ||
children: block.getChildKeys().filter(function (key) { | ||
return blocks.get(key); | ||
}), | ||
nextSibling: getNextValidSibling(block, blocks, originalBlockMap), | ||
prevSibling: getPrevValidSibling(block, blocks, originalBlockMap) | ||
}); | ||
}); | ||
}); | ||
// update start block next - can only happen if startBlock == endBlock | ||
transformBlock(startBlock.getNextSiblingKey(), blocks, function (block) { | ||
return block.merge({ | ||
prevSibling: startBlock.getPrevSiblingKey() | ||
}); | ||
}); | ||
// update start block prev | ||
transformBlock(startBlock.getPrevSiblingKey(), blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: getNextValidSibling(startBlock, blocks, originalBlockMap) | ||
}); | ||
}); | ||
// update end block next | ||
transformBlock(endBlock.getNextSiblingKey(), blocks, function (block) { | ||
return block.merge({ | ||
prevSibling: getPrevValidSibling(endBlock, blocks, originalBlockMap) | ||
}); | ||
}); | ||
// update end block prev | ||
transformBlock(endBlock.getPrevSiblingKey(), blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: endBlock.getNextSiblingKey() | ||
}); | ||
}); | ||
// update end block parent ancestors | ||
getAncestorsKeys(endBlock.getKey(), originalBlockMap).forEach(function (parentKey) { | ||
transformBlock(parentKey, blocks, function (block) { | ||
return block.merge({ | ||
children: block.getChildKeys().filter(function (key) { | ||
return blocks.get(key); | ||
}), | ||
nextSibling: getNextValidSibling(block, blocks, originalBlockMap), | ||
prevSibling: getPrevValidSibling(block, blocks, originalBlockMap) | ||
}); | ||
}); | ||
}); | ||
// update next delimiters all the way to a root delimiter | ||
getNextDelimitersBlockKeys(endBlock, originalBlockMap).forEach(function (delimiterKey) { | ||
return transformBlock(delimiterKey, blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: getNextValidSibling(block, blocks, originalBlockMap), | ||
prevSibling: getPrevValidSibling(block, blocks, originalBlockMap) | ||
}); | ||
}); | ||
}); | ||
}); | ||
}; | ||
var removeRangeFromContentState = function removeRangeFromContentState(contentState, selectionState) { | ||
if (selectionState.isCollapsed()) { | ||
@@ -32,4 +216,29 @@ return contentState; | ||
var endBlock = blockMap.get(endKey); | ||
var characterList; | ||
// we assume that ContentBlockNode and ContentBlocks are not mixed together | ||
var isExperimentalTreeBlock = startBlock instanceof ContentBlockNode; | ||
// used to retain blocks that should not be deleted to avoid orphan children | ||
var parentAncestors = []; | ||
if (isExperimentalTreeBlock) { | ||
var endBlockchildrenKeys = endBlock.getChildKeys(); | ||
var endBlockAncestors = getAncestorsKeys(endKey, blockMap); | ||
// endBlock has unselected sibblings so we can not remove its ancestors parents | ||
if (endBlock.getNextSiblingKey()) { | ||
parentAncestors = parentAncestors.concat(endBlockAncestors); | ||
} | ||
// endBlock has children so can not remove this block or any of its ancestors | ||
if (!endBlockchildrenKeys.isEmpty()) { | ||
parentAncestors = parentAncestors.concat(endBlockAncestors.concat([endKey])); | ||
} | ||
// we need to retain all ancestors of the next delimiter block | ||
parentAncestors = parentAncestors.concat(getAncestorsKeys(getNextDelimiterBlockKey(endBlock, blockMap), blockMap)); | ||
} | ||
var characterList = void 0; | ||
if (startBlock === endBlock) { | ||
@@ -50,12 +259,18 @@ characterList = removeFromList(startBlock.getCharacterList(), startOffset, endOffset); | ||
return k === endKey; | ||
}).concat(Immutable.Map([[endKey, null]])).map(function (_, k) { | ||
}).filter(function (_, k) { | ||
return parentAncestors.indexOf(k) === -1; | ||
}).concat(Map([[endKey, null]])).map(function (_, k) { | ||
return k === startKey ? modifiedStart : null; | ||
}); | ||
blockMap = blockMap.merge(newBlocks).filter(function (block) { | ||
var updatedBlockMap = blockMap.merge(newBlocks).filter(function (block) { | ||
return !!block; | ||
}); | ||
if (isExperimentalTreeBlock) { | ||
updatedBlockMap = updateBlockMapLinks(updatedBlockMap, startBlock, endBlock, blockMap); | ||
} | ||
return contentState.merge({ | ||
blockMap: blockMap, | ||
blockMap: updatedBlockMap, | ||
selectionBefore: selectionState, | ||
@@ -70,3 +285,3 @@ selectionAfter: selectionState.merge({ | ||
}); | ||
} | ||
}; | ||
@@ -77,3 +292,3 @@ /** | ||
*/ | ||
function removeFromList(targetList, startOffset, endOffset) { | ||
var removeFromList = function removeFromList(targetList, startOffset, endOffset) { | ||
if (startOffset === 0) { | ||
@@ -95,4 +310,4 @@ while (startOffset < endOffset) { | ||
return targetList; | ||
} | ||
}; | ||
module.exports = removeRangeFromContentState; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule removeTextWithStrategy | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule RichTextEditorUtil | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -93,3 +93,6 @@ */ | ||
var blockMap = content.getBlockMap()['delete'](blockBefore.getKey()); | ||
var withoutAtomicBlock = content.merge({ blockMap: blockMap, selectionAfter: selection }); | ||
var withoutAtomicBlock = content.merge({ | ||
blockMap: blockMap, | ||
selectionAfter: selection | ||
}); | ||
if (withoutAtomicBlock !== content) { | ||
@@ -278,4 +281,4 @@ return EditorState.push(editorState, withoutAtomicBlock, 'remove-range'); | ||
/** | ||
* When a collapsed cursor is at the start of the first styled block, or | ||
* an empty styled block, changes block to 'unstyled'. Returns null if | ||
* When a collapsed cursor is at the start of the first styled block, or | ||
* an empty styled block, changes block to 'unstyled'. Returns null if | ||
* block or selection does not meet that criteria. | ||
@@ -298,3 +301,3 @@ */ | ||
var blockBefore = content.getBlockBefore(key); | ||
if (type === 'code-block' && blockBefore && blockBefore.getType() === 'code-block') { | ||
if (type === 'code-block' && blockBefore && blockBefore.getType() === 'code-block' && blockBefore.getLength() !== 0) { | ||
return null; | ||
@@ -301,0 +304,0 @@ } |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule SampleDraftInlineStyle | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule sanitizeDraftText | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule SecondaryClipboard | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule SelectionState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
@@ -10,3 +10,2 @@ /** | ||
* @providesModule setDraftEditorSelection | ||
* @typechecks | ||
* @format | ||
@@ -13,0 +12,0 @@ * |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule splitBlockInContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -17,2 +17,3 @@ */ | ||
var ContentBlockNode = require('./ContentBlockNode'); | ||
var Immutable = require('immutable'); | ||
@@ -23,6 +24,62 @@ | ||
var Map = Immutable.Map; | ||
var List = Immutable.List, | ||
Map = Immutable.Map; | ||
function splitBlockInContentState(contentState, selectionState) { | ||
var transformBlock = function transformBlock(key, blockMap, func) { | ||
if (!key) { | ||
return; | ||
} | ||
var block = blockMap.get(key); | ||
if (!block) { | ||
return; | ||
} | ||
blockMap.set(key, func(block)); | ||
}; | ||
var updateBlockMapLinks = function updateBlockMapLinks(blockMap, originalBlock, belowBlock) { | ||
return blockMap.withMutations(function (blocks) { | ||
var originalBlockKey = originalBlock.getKey(); | ||
var belowBlockKey = belowBlock.getKey(); | ||
// update block parent | ||
transformBlock(originalBlock.getParentKey(), blocks, function (block) { | ||
var parentChildrenList = block.getChildKeys(); | ||
var insertionIndex = parentChildrenList.indexOf(originalBlockKey) + 1; | ||
var newChildrenArray = parentChildrenList.toArray(); | ||
newChildrenArray.splice(insertionIndex, 0, belowBlockKey); | ||
return block.merge({ | ||
children: List(newChildrenArray) | ||
}); | ||
}); | ||
// update original next block | ||
transformBlock(originalBlock.getNextSiblingKey(), blocks, function (block) { | ||
return block.merge({ | ||
prevSibling: belowBlockKey | ||
}); | ||
}); | ||
// update original block | ||
transformBlock(originalBlockKey, blocks, function (block) { | ||
return block.merge({ | ||
nextSibling: belowBlockKey | ||
}); | ||
}); | ||
// update below block | ||
transformBlock(belowBlockKey, blocks, function (block) { | ||
return block.merge({ | ||
prevSibling: originalBlockKey | ||
}); | ||
}); | ||
}); | ||
}; | ||
var splitBlockInContentState = function splitBlockInContentState(contentState, selectionState) { | ||
!selectionState.isCollapsed() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Selection range must be collapsed.') : invariant(false) : void 0; | ||
@@ -34,5 +91,6 @@ | ||
var blockToSplit = blockMap.get(key); | ||
var text = blockToSplit.getText(); | ||
var chars = blockToSplit.getCharacterList(); | ||
var keyBelow = generateRandomKey(); | ||
var isExperimentalTreeBlock = blockToSplit instanceof ContentBlockNode; | ||
@@ -43,4 +101,2 @@ var blockAbove = blockToSplit.merge({ | ||
}); | ||
var keyBelow = generateRandomKey(); | ||
var blockBelow = blockAbove.merge({ | ||
@@ -59,4 +115,10 @@ key: keyBelow, | ||
}).rest(); | ||
var newBlocks = blocksBefore.concat([[blockAbove.getKey(), blockAbove], [blockBelow.getKey(), blockBelow]], blocksAfter).toOrderedMap(); | ||
var newBlocks = blocksBefore.concat([[key, blockAbove], [keyBelow, blockBelow]], blocksAfter).toOrderedMap(); | ||
if (isExperimentalTreeBlock) { | ||
!blockToSplit.getChildKeys().isEmpty() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'ContentBlockNode must not have children') : invariant(false) : void 0; | ||
newBlocks = updateBlockMapLinks(newBlocks, blockAbove, blockBelow); | ||
} | ||
return contentState.merge({ | ||
@@ -73,4 +135,4 @@ blockMap: newBlocks, | ||
}); | ||
} | ||
}; | ||
module.exports = splitBlockInContentState; |
@@ -10,2 +10,3 @@ /** | ||
* @providesModule splitTextIntoTextBlocks | ||
* @format | ||
* | ||
@@ -12,0 +13,0 @@ */ |
@@ -10,3 +10,3 @@ /** | ||
* @providesModule updateEntityDataInContentState | ||
* @typechecks | ||
* @format | ||
* | ||
@@ -13,0 +13,0 @@ */ |
{ | ||
"name": "draft-js", | ||
"description": "A React framework for building text editors.", | ||
"version": "0.10.4", | ||
"version": "0.10.5", | ||
"keywords": [ | ||
@@ -27,4 +27,6 @@ "draftjs", | ||
"build": "gulp", | ||
"dev": "gulp dev", | ||
"postbuild": "node node_modules/fbjs-scripts/node/check-lib-requires.js lib", | ||
"lint": "eslint .", | ||
"format": "eslint . --fix", | ||
"flow": "flow src", | ||
@@ -49,13 +51,14 @@ "test": "NODE_ENV=test jest", | ||
"envify": "^3.4.0", | ||
"enzyme": "^2.9.1", | ||
"es6-shim": "^0.34.4", | ||
"eslint": "^4.2.0", | ||
"eslint-config-fbjs": "^2.0.0", | ||
"eslint-config-prettier": "^2.6.0", | ||
"eslint-plugin-babel": "^4.1.1", | ||
"eslint-plugin-flowtype": "^2.17.1", | ||
"eslint-plugin-jsx-a11y": "^6.0.2", | ||
"eslint-plugin-prettier": "^2.3.1", | ||
"eslint-plugin-react": "^7.3.0", | ||
"eslint-plugin-relay": "^0.0.8", | ||
"fbjs-scripts": "^0.8.0", | ||
"flow-bin": "^0.53.1", | ||
"flow-bin": "^0.59.0", | ||
"gulp": "^3.9.0", | ||
@@ -72,6 +75,7 @@ "gulp-babel": "^6.1.2", | ||
"gulp-util": "^3.0.6", | ||
"jest": "^15.1.1", | ||
"react": "^15.0.0-rc.1", | ||
"react-dom": "^15.0.0-rc.1", | ||
"react-test-renderer": "^15.5.4", | ||
"jest": "^21.2.1", | ||
"prettier": "1.9.1", | ||
"react": "^16.0.0", | ||
"react-dom": "^16.0.0", | ||
"react-test-renderer": "^16.0.0", | ||
"run-sequence": "^1.1.2", | ||
@@ -83,12 +87,20 @@ "through2": "^2.0.1", | ||
"devEngines": { | ||
"node": "6.x", | ||
"npm": "2.x || 3.x" | ||
"node": "6.x || 8.x", | ||
"npm": "2.x || 3.x || 5.x" | ||
}, | ||
"jest": { | ||
"automock": true, | ||
"globals": { | ||
"__DEV__": true | ||
}, | ||
"rootDir": "./", | ||
"scriptPreprocessor": "scripts/jest/preprocessor.js", | ||
"roots": [ | ||
"<rootDir>/src/" | ||
], | ||
"setupFiles": [ | ||
"node_modules/fbjs-scripts/jest/environment.js" | ||
"<rootDir>/scripts/jest/shims.js" | ||
], | ||
"transform": { | ||
".*": "<rootDir>/scripts/jest/preprocessor.js" | ||
}, | ||
"modulePathIgnorePatterns": [ | ||
@@ -98,8 +110,5 @@ "<rootDir>/lib/", | ||
], | ||
"preprocessorIgnorePatterns": [ | ||
"transformIgnorePatterns": [ | ||
"<rootDir>/node_modules/" | ||
], | ||
"testPathDirs": [ | ||
"<rootDir>/src/" | ||
], | ||
"unmockedModulePathPatterns": [ | ||
@@ -106,0 +115,0 @@ "<rootDir>/node_modules/fbjs/node_modules/", |
@@ -1,2 +0,2 @@ | ||
# [Draft.js](http://draftjs.org/) [![Build Status](https://img.shields.io/travis/facebook/draft-js/master.svg?style=flat)](https://travis-ci.org/facebook/draft-js) [![npm version](https://img.shields.io/npm/v/draft-js.svg?style=flat)](https://www.npmjs.com/package/draft-js) | ||
# [Draft.js](http://draftjs.org/) [![Build Status](https://img.shields.io/travis/facebook/draft-js/master.svg?style=flat)](https://travis-ci.org/facebook/draft-js) [![npm version](https://img.shields.io/npm/v/draft-js.svg?style=flat)](https://yarn.pm/draft-js) | ||
@@ -95,2 +95,14 @@ Draft.js is a JavaScript rich text editor framework, built for React and | ||
## Browser Support | ||
| ![IE / Edge](https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/edge.png) <br /> IE / Edge | ![Firefox](https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/firefox.png) <br /> Firefox | ![Chrome](https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/chrome.png) <br /> Chrome | ![Safari](https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/safari.png ) <br /> Safari | ![iOS Safari](https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/safari-ios.png) <br />iOS Safari | ![Chrome for Anroid](https://raw.githubusercontent.com/godban/browsers-support-badges/master/src/images/chrome-android.png) <br/> Chrome for Android | | ||
| --------- | --------- | --------- | --------- | --------- | --------- | | ||
| IE11, Edge [1, 2]| last 2 versions| last 2 versions| last 2 versions| not fully supported [3] | not fully supported [3] | ||
[1] May need a shim or a polyfill for some syntax used in Draft.js ([docs](https://draftjs.org/docs/advanced-topics-issues-and-pitfalls.html#polyfills)). | ||
[2] IME inputs have known issues in these browsers, especially Korean ([docs](https://draftjs.org/docs/advanced-topics-issues-and-pitfalls.html#ime-and-internet-explorer)). | ||
[3] There are known issues with mobile browsers, especially on Android ([docs](https://draftjs.org/docs/advanced-topics-issues-and-pitfalls.html#mobile-not-yet-supported)). | ||
## Resources and Ecosystem | ||
@@ -97,0 +109,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1576507
324
24236
127
37
47