UNPKG

8.98 kBJavaScriptView Raw
1/**
2 * Copyright (c) Facebook, Inc. and its affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @format
8 *
9 * @emails oncall+draft_js
10 */
11'use strict';
12
13function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
14
15function _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; }
16
17var ContentBlock = require("./ContentBlock");
18
19var ContentBlockNode = require("./ContentBlockNode");
20
21var ContentState = require("./ContentState");
22
23var DraftEntity = require("./DraftEntity");
24
25var DraftTreeAdapter = require("./DraftTreeAdapter");
26
27var DraftTreeInvariants = require("./DraftTreeInvariants");
28
29var SelectionState = require("./SelectionState");
30
31var createCharacterList = require("./createCharacterList");
32
33var decodeEntityRanges = require("./decodeEntityRanges");
34
35var decodeInlineStyleRanges = require("./decodeInlineStyleRanges");
36
37var generateRandomKey = require("./generateRandomKey");
38
39var gkx = require("./gkx");
40
41var Immutable = require("immutable");
42
43var invariant = require("fbjs/lib/invariant");
44
45var experimentalTreeDataSupport = gkx('draft_tree_data_support');
46var List = Immutable.List,
47 Map = Immutable.Map,
48 OrderedMap = Immutable.OrderedMap;
49
50var decodeBlockNodeConfig = function decodeBlockNodeConfig(block, entityMap) {
51 var key = block.key,
52 type = block.type,
53 data = block.data,
54 text = block.text,
55 depth = block.depth;
56 var blockNodeConfig = {
57 text: text,
58 depth: depth || 0,
59 type: type || 'unstyled',
60 key: key || generateRandomKey(),
61 data: Map(data),
62 characterList: decodeCharacterList(block, entityMap)
63 };
64 return blockNodeConfig;
65};
66
67var decodeCharacterList = function decodeCharacterList(block, entityMap) {
68 var text = block.text,
69 rawEntityRanges = block.entityRanges,
70 rawInlineStyleRanges = block.inlineStyleRanges;
71 var entityRanges = rawEntityRanges || [];
72 var inlineStyleRanges = rawInlineStyleRanges || []; // Translate entity range keys to the DraftEntity map.
73
74 return createCharacterList(decodeInlineStyleRanges(text, inlineStyleRanges), decodeEntityRanges(text, entityRanges.filter(function (range) {
75 return entityMap.hasOwnProperty(range.key);
76 }).map(function (range) {
77 return _objectSpread({}, range, {
78 key: entityMap[range.key]
79 });
80 })));
81};
82
83var addKeyIfMissing = function addKeyIfMissing(block) {
84 return _objectSpread({}, block, {
85 key: block.key || generateRandomKey()
86 });
87};
88/**
89 * Node stack is responsible to ensure we traverse the tree only once
90 * in depth order, while also providing parent refs to inner nodes to
91 * construct their links.
92 */
93
94
95var updateNodeStack = function updateNodeStack(stack, nodes, parentRef) {
96 var nodesWithParentRef = nodes.map(function (block) {
97 return _objectSpread({}, block, {
98 parentRef: parentRef
99 });
100 }); // since we pop nodes from the stack we need to insert them in reverse
101
102 return stack.concat(nodesWithParentRef.reverse());
103};
104/**
105 * This will build a tree draft content state by creating the node
106 * reference links into a single tree walk. Each node has a link
107 * reference to "parent", "children", "nextSibling" and "prevSibling"
108 * blockMap will be created using depth ordering.
109 */
110
111
112var decodeContentBlockNodes = function decodeContentBlockNodes(blocks, entityMap) {
113 return blocks // ensure children have valid keys to enable sibling links
114 .map(addKeyIfMissing).reduce(function (blockMap, block, index) {
115 !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
116
117 var children = block.children.map(addKeyIfMissing); // root level nodes
118
119 var contentBlockNode = new ContentBlockNode(_objectSpread({}, decodeBlockNodeConfig(block, entityMap), {
120 prevSibling: index === 0 ? null : blocks[index - 1].key,
121 nextSibling: index === blocks.length - 1 ? null : blocks[index + 1].key,
122 children: List(children.map(function (child) {
123 return child.key;
124 }))
125 })); // push root node to blockMap
126
127 blockMap = blockMap.set(contentBlockNode.getKey(), contentBlockNode); // this stack is used to ensure we visit all nodes respecting depth ordering
128
129 var stack = updateNodeStack([], children, contentBlockNode); // start computing children nodes
130
131 while (stack.length > 0) {
132 // we pop from the stack and start processing this node
133 var node = stack.pop(); // parentRef already points to a converted ContentBlockNode
134
135 var parentRef = node.parentRef;
136 var siblings = parentRef.getChildKeys();
137
138 var _index = siblings.indexOf(node.key);
139
140 var isValidBlock = Array.isArray(node.children);
141
142 if (!isValidBlock) {
143 !isValidBlock ? process.env.NODE_ENV !== "production" ? invariant(false, 'invalid RawDraftContentBlock can not be converted to ContentBlockNode') : invariant(false) : void 0;
144 break;
145 } // ensure children have valid keys to enable sibling links
146
147
148 var _children = node.children.map(addKeyIfMissing);
149
150 var _contentBlockNode = new ContentBlockNode(_objectSpread({}, decodeBlockNodeConfig(node, entityMap), {
151 parent: parentRef.getKey(),
152 children: List(_children.map(function (child) {
153 return child.key;
154 })),
155 prevSibling: _index === 0 ? null : siblings.get(_index - 1),
156 nextSibling: _index === siblings.size - 1 ? null : siblings.get(_index + 1)
157 })); // push node to blockMap
158
159
160 blockMap = blockMap.set(_contentBlockNode.getKey(), _contentBlockNode); // this stack is used to ensure we visit all nodes respecting depth ordering
161
162 stack = updateNodeStack(stack, _children, _contentBlockNode);
163 }
164
165 return blockMap;
166 }, OrderedMap());
167};
168
169var decodeContentBlocks = function decodeContentBlocks(blocks, entityMap) {
170 return OrderedMap(blocks.map(function (block) {
171 var contentBlock = new ContentBlock(decodeBlockNodeConfig(block, entityMap));
172 return [contentBlock.getKey(), contentBlock];
173 }));
174};
175
176var decodeRawBlocks = function decodeRawBlocks(rawState, entityMap) {
177 var isTreeRawBlock = rawState.blocks.find(function (block) {
178 return Array.isArray(block.children) && block.children.length > 0;
179 });
180 var rawBlocks = experimentalTreeDataSupport && !isTreeRawBlock ? DraftTreeAdapter.fromRawStateToRawTreeState(rawState).blocks : rawState.blocks;
181
182 if (!experimentalTreeDataSupport) {
183 return decodeContentBlocks(isTreeRawBlock ? DraftTreeAdapter.fromRawTreeStateToRawState(rawState).blocks : rawBlocks, entityMap);
184 }
185
186 var blockMap = decodeContentBlockNodes(rawBlocks, entityMap); // in dev mode, check that the tree invariants are met
187
188 if (process.env.NODE_ENV !== "production") {
189 !DraftTreeInvariants.isValidTree(blockMap) ? process.env.NODE_ENV !== "production" ? invariant(false, 'Should be a valid tree') : invariant(false) : void 0;
190 }
191
192 return blockMap;
193};
194
195var decodeRawEntityMap = function decodeRawEntityMap(rawState) {
196 var rawEntityMap = rawState.entityMap;
197 var entityMap = {}; // TODO: Update this once we completely remove DraftEntity
198
199 Object.keys(rawEntityMap).forEach(function (rawEntityKey) {
200 var _rawEntityMap$rawEnti = rawEntityMap[rawEntityKey],
201 type = _rawEntityMap$rawEnti.type,
202 mutability = _rawEntityMap$rawEnti.mutability,
203 data = _rawEntityMap$rawEnti.data; // get the key reference to created entity
204
205 entityMap[rawEntityKey] = DraftEntity.__create(type, mutability, data || {});
206 });
207 return entityMap;
208};
209
210var convertFromRawToDraftState = function convertFromRawToDraftState(rawState) {
211 !Array.isArray(rawState.blocks) ? process.env.NODE_ENV !== "production" ? invariant(false, 'invalid RawDraftContentState') : invariant(false) : void 0; // decode entities
212
213 var entityMap = decodeRawEntityMap(rawState); // decode blockMap
214
215 var blockMap = decodeRawBlocks(rawState, entityMap); // create initial selection
216
217 var selectionState = blockMap.isEmpty() ? new SelectionState() : SelectionState.createEmpty(blockMap.first().getKey());
218 return new ContentState({
219 blockMap: blockMap,
220 entityMap: entityMap,
221 selectionBefore: selectionState,
222 selectionAfter: selectionState
223 });
224};
225
226module.exports = convertFromRawToDraftState;
\No newline at end of file