lexical 0.2.4 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Lexical.d.ts +48 -54
- package/Lexical.dev.js +611 -244
- package/Lexical.js.flow +39 -49
- package/Lexical.prod.js +164 -159
- package/package.json +1 -1
package/Lexical.dev.js
CHANGED
|
@@ -56,6 +56,7 @@ const IS_ALIGN_RIGHT = 3;
|
|
|
56
56
|
const IS_ALIGN_JUSTIFY = 4; // Reconciliation
|
|
57
57
|
|
|
58
58
|
const ZERO_WIDTH_CHAR = '\u200b';
|
|
59
|
+
const DOUBLE_LINE_BREAK = '\n\n';
|
|
59
60
|
const RTL = '\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC';
|
|
60
61
|
const LTR = 'A-Za-z\u00C0-\u00D6\u00D8-\u00F6' + '\u00F8-\u02B8\u0300-\u0590\u0800-\u1FFF\u200E\u2C00-\uFB1C' + '\uFE00-\uFE6F\uFEFD-\uFFFF';
|
|
61
62
|
const RTL_REGEX = new RegExp('^[^' + LTR + ']*[' + RTL + ']');
|
|
@@ -181,6 +182,9 @@ function getTextDirection(text) {
|
|
|
181
182
|
|
|
182
183
|
return null;
|
|
183
184
|
}
|
|
185
|
+
function $isTokenOrInertOrSegmented(node) {
|
|
186
|
+
return $isTokenOrInert(node) || node.isSegmented();
|
|
187
|
+
}
|
|
184
188
|
function $isTokenOrInert(node) {
|
|
185
189
|
return node.isToken() || node.isInert();
|
|
186
190
|
}
|
|
@@ -322,21 +326,24 @@ function $setCompositionKey(compositionKey) {
|
|
|
322
326
|
errorOnReadOnly();
|
|
323
327
|
const editor = getActiveEditor();
|
|
324
328
|
const previousCompositionKey = editor._compositionKey;
|
|
325
|
-
editor._compositionKey = compositionKey;
|
|
326
329
|
|
|
327
|
-
if (
|
|
328
|
-
|
|
330
|
+
if (compositionKey !== previousCompositionKey) {
|
|
331
|
+
editor._compositionKey = compositionKey;
|
|
329
332
|
|
|
330
|
-
if (
|
|
331
|
-
node
|
|
333
|
+
if (previousCompositionKey !== null) {
|
|
334
|
+
const node = $getNodeByKey(previousCompositionKey);
|
|
335
|
+
|
|
336
|
+
if (node !== null) {
|
|
337
|
+
node.getWritable();
|
|
338
|
+
}
|
|
332
339
|
}
|
|
333
|
-
}
|
|
334
340
|
|
|
335
|
-
|
|
336
|
-
|
|
341
|
+
if (compositionKey !== null) {
|
|
342
|
+
const node = $getNodeByKey(compositionKey);
|
|
337
343
|
|
|
338
|
-
|
|
339
|
-
|
|
344
|
+
if (node !== null) {
|
|
345
|
+
node.getWritable();
|
|
346
|
+
}
|
|
340
347
|
}
|
|
341
348
|
}
|
|
342
349
|
}
|
|
@@ -423,8 +430,15 @@ function internalGetRoot(editorState) {
|
|
|
423
430
|
function $setSelection(selection) {
|
|
424
431
|
const editorState = getActiveEditorState();
|
|
425
432
|
|
|
426
|
-
if (selection !== null
|
|
427
|
-
|
|
433
|
+
if (selection !== null) {
|
|
434
|
+
if (Object.isFrozen(selection)) {
|
|
435
|
+
{
|
|
436
|
+
throw Error(`$setSelection called on frozen selection object. Ensure selection is cloned before passing in.`);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
selection.dirty = true;
|
|
441
|
+
selection._cachedNodes = null;
|
|
428
442
|
}
|
|
429
443
|
|
|
430
444
|
editorState._selection = selection;
|
|
@@ -489,7 +503,7 @@ function getEditorsToPropagate(editor) {
|
|
|
489
503
|
function createUID() {
|
|
490
504
|
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
|
|
491
505
|
}
|
|
492
|
-
function $updateSelectedTextFromDOM(editor,
|
|
506
|
+
function $updateSelectedTextFromDOM(editor, isCompositionEnd, data) {
|
|
493
507
|
// Update the text content with the latest composition text
|
|
494
508
|
const domSelection = getDOMSelection();
|
|
495
509
|
|
|
@@ -507,8 +521,7 @@ function $updateSelectedTextFromDOM(editor, compositionEndEvent) {
|
|
|
507
521
|
const node = $getNearestNodeFromDOMNode(anchorNode);
|
|
508
522
|
|
|
509
523
|
if ($isTextNode(node)) {
|
|
510
|
-
let textContent = anchorNode.nodeValue;
|
|
511
|
-
const data = compositionEndEvent !== null && compositionEndEvent.data; // Data is intentionally truthy, as we check for boolean, null and empty string.
|
|
524
|
+
let textContent = anchorNode.nodeValue; // Data is intentionally truthy, as we check for boolean, null and empty string.
|
|
512
525
|
|
|
513
526
|
if (textContent === ZERO_WIDTH_CHAR && data) {
|
|
514
527
|
const offset = data.length;
|
|
@@ -517,7 +530,7 @@ function $updateSelectedTextFromDOM(editor, compositionEndEvent) {
|
|
|
517
530
|
focusOffset = offset;
|
|
518
531
|
}
|
|
519
532
|
|
|
520
|
-
$updateTextNodeFromDOMContent(node, textContent, anchorOffset, focusOffset,
|
|
533
|
+
$updateTextNodeFromDOMContent(node, textContent, anchorOffset, focusOffset, isCompositionEnd);
|
|
521
534
|
}
|
|
522
535
|
}
|
|
523
536
|
}
|
|
@@ -543,7 +556,9 @@ function $updateTextNodeFromDOMContent(textNode, textContent, anchorOffset, focu
|
|
|
543
556
|
const editor = getActiveEditor();
|
|
544
557
|
setTimeout(() => {
|
|
545
558
|
editor.update(() => {
|
|
546
|
-
node.
|
|
559
|
+
if (node.isAttached()) {
|
|
560
|
+
node.remove();
|
|
561
|
+
}
|
|
547
562
|
});
|
|
548
563
|
}, 20);
|
|
549
564
|
} else {
|
|
@@ -727,6 +742,9 @@ function isMoveDown(keyCode, ctrlKey, shiftKey, altKey, metaKey) {
|
|
|
727
742
|
function isModifier(ctrlKey, shiftKey, altKey, metaKey) {
|
|
728
743
|
return ctrlKey || shiftKey || altKey || metaKey;
|
|
729
744
|
}
|
|
745
|
+
function isSpace(keyCode) {
|
|
746
|
+
return keyCode === 32;
|
|
747
|
+
}
|
|
730
748
|
function controlOrMeta(metaKey, ctrlKey) {
|
|
731
749
|
if (IS_APPLE) {
|
|
732
750
|
return metaKey;
|
|
@@ -852,6 +870,9 @@ function isFirefoxClipboardEvents() {
|
|
|
852
870
|
function dispatchCommand(editor, type, payload) {
|
|
853
871
|
return triggerCommandListeners(editor, type, payload);
|
|
854
872
|
}
|
|
873
|
+
function $textContentRequiresDoubleLinebreakAtEnd(node) {
|
|
874
|
+
return !$isRootNode(node) && !node.isLastChild() && !node.isInline();
|
|
875
|
+
}
|
|
855
876
|
|
|
856
877
|
/**
|
|
857
878
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -1141,8 +1162,8 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
|
|
|
1141
1162
|
}
|
|
1142
1163
|
} else if (originalSelection.type === 'grid') {
|
|
1143
1164
|
const gridKey = originalSelection.gridKey;
|
|
1144
|
-
const anchorCellKey = originalSelection.
|
|
1145
|
-
const focusCellKey = originalSelection.
|
|
1165
|
+
const anchorCellKey = originalSelection.anchor.key;
|
|
1166
|
+
const focusCellKey = originalSelection.focus.key;
|
|
1146
1167
|
|
|
1147
1168
|
if (remappedSelection == null && (gridKey === parsedKey || gridKey === anchorCellKey || gridKey === focusCellKey)) {
|
|
1148
1169
|
state.remappedSelection = remappedSelection = { ...originalSelection,
|
|
@@ -1156,11 +1177,11 @@ function internalCreateNodeFromParse(parsedNode, parsedNodeMap, editor, parentKe
|
|
|
1156
1177
|
}
|
|
1157
1178
|
|
|
1158
1179
|
if (anchorCellKey === parsedKey) {
|
|
1159
|
-
remappedSelection.
|
|
1180
|
+
remappedSelection.anchor.key = key;
|
|
1160
1181
|
}
|
|
1161
1182
|
|
|
1162
1183
|
if (focusCellKey === parsedKey) {
|
|
1163
|
-
remappedSelection.
|
|
1184
|
+
remappedSelection.focus.key = key;
|
|
1164
1185
|
}
|
|
1165
1186
|
}
|
|
1166
1187
|
}
|
|
@@ -1199,6 +1220,7 @@ const KEY_ARROW_LEFT_COMMAND = createCommand();
|
|
|
1199
1220
|
const KEY_ARROW_UP_COMMAND = createCommand();
|
|
1200
1221
|
const KEY_ARROW_DOWN_COMMAND = createCommand();
|
|
1201
1222
|
const KEY_ENTER_COMMAND = createCommand();
|
|
1223
|
+
const KEY_SPACE_COMMAND = createCommand();
|
|
1202
1224
|
const KEY_BACKSPACE_COMMAND = createCommand();
|
|
1203
1225
|
const KEY_ESCAPE_COMMAND = createCommand();
|
|
1204
1226
|
const KEY_DELETE_COMMAND = createCommand();
|
|
@@ -1208,6 +1230,7 @@ const OUTDENT_CONTENT_COMMAND = createCommand();
|
|
|
1208
1230
|
const DROP_COMMAND = createCommand();
|
|
1209
1231
|
const FORMAT_ELEMENT_COMMAND = createCommand();
|
|
1210
1232
|
const DRAGSTART_COMMAND = createCommand();
|
|
1233
|
+
const DRAGEND_COMMAND = createCommand();
|
|
1211
1234
|
const COPY_COMMAND = createCommand();
|
|
1212
1235
|
const CUT_COMMAND = createCommand();
|
|
1213
1236
|
const CLEAR_EDITOR_COMMAND = createCommand();
|
|
@@ -1245,20 +1268,32 @@ if (CAN_USE_BEFORE_INPUT) {
|
|
|
1245
1268
|
let lastKeyDownTimeStamp = 0;
|
|
1246
1269
|
let rootElementsRegistered = 0;
|
|
1247
1270
|
let isSelectionChangeFromReconcile = false;
|
|
1271
|
+
let isInsertLineBreak = false;
|
|
1272
|
+
let isFirefoxEndingComposition = false;
|
|
1273
|
+
let collapsedSelectionFormat = [0, 0, 'root', 0];
|
|
1274
|
+
|
|
1275
|
+
function shouldSkipSelectionChange(domNode, offset) {
|
|
1276
|
+
return domNode !== null && domNode.nodeType === DOM_TEXT_TYPE && offset !== 0 && offset !== domNode.nodeValue.length;
|
|
1277
|
+
}
|
|
1248
1278
|
|
|
1249
1279
|
function onSelectionChange(domSelection, editor, isActive) {
|
|
1250
1280
|
if (isSelectionChangeFromReconcile) {
|
|
1251
1281
|
isSelectionChangeFromReconcile = false;
|
|
1252
1282
|
const {
|
|
1253
1283
|
anchorNode,
|
|
1254
|
-
|
|
1284
|
+
anchorOffset,
|
|
1285
|
+
focusNode,
|
|
1286
|
+
focusOffset
|
|
1255
1287
|
} = domSelection; // If native DOM selection is on a DOM element, then
|
|
1256
1288
|
// we should continue as usual, as Lexical's selection
|
|
1257
1289
|
// may have normalized to a better child. If the DOM
|
|
1258
1290
|
// element is a text node, we can safely apply this
|
|
1259
1291
|
// optimization and skip the selection change entirely.
|
|
1292
|
+
// We also need to check if the offset is at the boundary,
|
|
1293
|
+
// because in this case, we might need to normalize to a
|
|
1294
|
+
// sibling instead.
|
|
1260
1295
|
|
|
1261
|
-
if (anchorNode
|
|
1296
|
+
if (shouldSkipSelectionChange(anchorNode, anchorOffset) && shouldSkipSelectionChange(focusNode, focusOffset)) {
|
|
1262
1297
|
return;
|
|
1263
1298
|
}
|
|
1264
1299
|
}
|
|
@@ -1273,19 +1308,45 @@ function onSelectionChange(domSelection, editor, isActive) {
|
|
|
1273
1308
|
|
|
1274
1309
|
const selection = $getSelection(); // Update the selection format
|
|
1275
1310
|
|
|
1276
|
-
if ($isRangeSelection(selection)
|
|
1277
|
-
// Badly interpreted range selection when collapsed - #1482
|
|
1278
|
-
if (domSelection.type === 'Range') {
|
|
1279
|
-
selection.dirty = true;
|
|
1280
|
-
}
|
|
1281
|
-
|
|
1311
|
+
if ($isRangeSelection(selection)) {
|
|
1282
1312
|
const anchor = selection.anchor;
|
|
1313
|
+
const anchorNode = anchor.getNode();
|
|
1314
|
+
|
|
1315
|
+
if (selection.isCollapsed()) {
|
|
1316
|
+
// Badly interpreted range selection when collapsed - #1482
|
|
1317
|
+
if (domSelection.type === 'Range') {
|
|
1318
|
+
selection.dirty = true;
|
|
1319
|
+
} // If we have marked a collapsed selection format, and we're
|
|
1320
|
+
// within the given time range – then attempt to use that format
|
|
1321
|
+
// instead of getting the format from the anchor node.
|
|
1322
|
+
|
|
1323
|
+
|
|
1324
|
+
const currentTimeStamp = window.event.timeStamp;
|
|
1325
|
+
const [lastFormat, lastOffset, lastKey, timeStamp] = collapsedSelectionFormat;
|
|
1326
|
+
|
|
1327
|
+
if (currentTimeStamp < timeStamp + 200 && anchor.offset === lastOffset && anchor.key === lastKey) {
|
|
1328
|
+
selection.format = lastFormat;
|
|
1329
|
+
} else {
|
|
1330
|
+
if (anchor.type === 'text') {
|
|
1331
|
+
selection.format = anchorNode.getFormat();
|
|
1332
|
+
} else if (anchor.type === 'element') {
|
|
1333
|
+
selection.format = 0;
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
} else {
|
|
1337
|
+
const focus = selection.focus;
|
|
1338
|
+
const focusNode = focus.getNode();
|
|
1339
|
+
let combinedFormat = 0;
|
|
1340
|
+
|
|
1341
|
+
if (anchor.type === 'text') {
|
|
1342
|
+
combinedFormat |= anchorNode.getFormat();
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
if (focus.type === 'text' && !anchorNode.is(focusNode)) {
|
|
1346
|
+
combinedFormat |= focusNode.getFormat();
|
|
1347
|
+
}
|
|
1283
1348
|
|
|
1284
|
-
|
|
1285
|
-
const anchorNode = anchor.getNode();
|
|
1286
|
-
selection.format = anchorNode.getFormat();
|
|
1287
|
-
} else if (anchor.type === 'element') {
|
|
1288
|
-
selection.format = 0;
|
|
1349
|
+
selection.format = combinedFormat;
|
|
1289
1350
|
}
|
|
1290
1351
|
}
|
|
1291
1352
|
|
|
@@ -1306,7 +1367,7 @@ function onClick(event, editor) {
|
|
|
1306
1367
|
const anchor = selection.anchor;
|
|
1307
1368
|
|
|
1308
1369
|
if (anchor.type === 'element' && anchor.offset === 0 && selection.isCollapsed() && $getRoot().getChildrenSize() === 1 && anchor.getNode().getTopLevelElementOrThrow().isEmpty()) {
|
|
1309
|
-
const lastSelection =
|
|
1370
|
+
const lastSelection = $getPreviousSelection();
|
|
1310
1371
|
|
|
1311
1372
|
if (lastSelection !== null && selection.is(lastSelection)) {
|
|
1312
1373
|
getDOMSelection().removeAllRanges();
|
|
@@ -1383,25 +1444,36 @@ function onBeforeInput(event, editor) {
|
|
|
1383
1444
|
updateEditor(editor, () => {
|
|
1384
1445
|
const selection = $getSelection();
|
|
1385
1446
|
|
|
1386
|
-
if (!$isRangeSelection(selection)) {
|
|
1387
|
-
return;
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
1447
|
if (inputType === 'deleteContentBackward') {
|
|
1391
|
-
|
|
1448
|
+
if (selection === null) {
|
|
1449
|
+
// Use previous selection
|
|
1450
|
+
const prevSelection = $getPreviousSelection();
|
|
1451
|
+
|
|
1452
|
+
if (!$isRangeSelection(prevSelection)) {
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1456
|
+
$setSelection(prevSelection.clone());
|
|
1457
|
+
} // Used for Android
|
|
1458
|
+
|
|
1459
|
+
|
|
1392
1460
|
$setCompositionKey(null);
|
|
1393
1461
|
event.preventDefault();
|
|
1394
1462
|
lastKeyDownTimeStamp = 0;
|
|
1395
1463
|
dispatchCommand(editor, DELETE_CHARACTER_COMMAND, true); // Fixes an Android bug where selection flickers when backspacing
|
|
1396
1464
|
|
|
1397
1465
|
setTimeout(() => {
|
|
1398
|
-
editor
|
|
1466
|
+
updateEditor(editor, () => {
|
|
1399
1467
|
$setCompositionKey(null);
|
|
1400
1468
|
});
|
|
1401
1469
|
}, ANDROID_COMPOSITION_LATENCY);
|
|
1402
1470
|
return;
|
|
1403
1471
|
}
|
|
1404
1472
|
|
|
1473
|
+
if (!$isRangeSelection(selection)) {
|
|
1474
|
+
return;
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1405
1477
|
const data = event.data;
|
|
1406
1478
|
|
|
1407
1479
|
if (!selection.dirty && selection.isCollapsed() && !$isRootNode(selection.anchor.getNode())) {
|
|
@@ -1417,7 +1489,7 @@ function onBeforeInput(event, editor) {
|
|
|
1417
1489
|
if (data === '\n') {
|
|
1418
1490
|
event.preventDefault();
|
|
1419
1491
|
dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND);
|
|
1420
|
-
} else if (data ===
|
|
1492
|
+
} else if (data === DOUBLE_LINE_BREAK) {
|
|
1421
1493
|
event.preventDefault();
|
|
1422
1494
|
dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND);
|
|
1423
1495
|
} else if (data == null && event.dataTransfer) {
|
|
@@ -1466,8 +1538,16 @@ function onBeforeInput(event, editor) {
|
|
|
1466
1538
|
case 'insertParagraph':
|
|
1467
1539
|
{
|
|
1468
1540
|
// Used for Android
|
|
1469
|
-
$setCompositionKey(null);
|
|
1470
|
-
|
|
1541
|
+
$setCompositionKey(null); // Some browsers do not provide the type "insertLineBreak".
|
|
1542
|
+
// So instead, we need to infer it from the keyboard event.
|
|
1543
|
+
|
|
1544
|
+
if (isInsertLineBreak) {
|
|
1545
|
+
isInsertLineBreak = false;
|
|
1546
|
+
dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND);
|
|
1547
|
+
} else {
|
|
1548
|
+
dispatchCommand(editor, INSERT_PARAGRAPH_COMMAND);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1471
1551
|
break;
|
|
1472
1552
|
}
|
|
1473
1553
|
|
|
@@ -1575,14 +1655,27 @@ function onInput(event, editor) {
|
|
|
1575
1655
|
const data = event.data;
|
|
1576
1656
|
|
|
1577
1657
|
if (data != null && $isRangeSelection(selection) && $shouldPreventDefaultAndInsertText(selection, data, false)) {
|
|
1578
|
-
|
|
1658
|
+
// Given we're over-riding the default behavior, we will need
|
|
1659
|
+
// to ensure to disable composition before dispatching the
|
|
1660
|
+
// insertText command for when changing the sequence for FF.
|
|
1661
|
+
if (isFirefoxEndingComposition) {
|
|
1662
|
+
onCompositionEndImpl(editor, data);
|
|
1663
|
+
isFirefoxEndingComposition = false;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
dispatchCommand(editor, INSERT_TEXT_COMMAND, data); // This ensures consistency on Android.
|
|
1579
1667
|
|
|
1580
1668
|
if (editor._compositionKey !== null) {
|
|
1581
1669
|
lastKeyDownTimeStamp = 0;
|
|
1582
1670
|
$setCompositionKey(null);
|
|
1583
1671
|
}
|
|
1584
1672
|
} else {
|
|
1585
|
-
$updateSelectedTextFromDOM(editor,
|
|
1673
|
+
$updateSelectedTextFromDOM(editor, false); // onInput always fires after onCompositionEnd for FF.
|
|
1674
|
+
|
|
1675
|
+
if (isFirefoxEndingComposition) {
|
|
1676
|
+
onCompositionEndImpl(editor, data);
|
|
1677
|
+
isFirefoxEndingComposition = false;
|
|
1678
|
+
}
|
|
1586
1679
|
} // Also flush any other mutations that might have occurred
|
|
1587
1680
|
// since the change.
|
|
1588
1681
|
|
|
@@ -1601,7 +1694,9 @@ function onCompositionStart(event, editor) {
|
|
|
1601
1694
|
|
|
1602
1695
|
if ( // If it has been 30ms since the last keydown, then we should
|
|
1603
1696
|
// apply the empty space heuristic.
|
|
1604
|
-
event.timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY ||
|
|
1697
|
+
event.timeStamp < lastKeyDownTimeStamp + ANDROID_COMPOSITION_LATENCY || // FF has issues around composing multibyte characters, so we also
|
|
1698
|
+
// need to invoke the empty space heuristic below.
|
|
1699
|
+
IS_FIREFOX && anchor.type === 'element' || !selection.isCollapsed() || selection.anchor.getNode().getFormat() !== selection.format) {
|
|
1605
1700
|
// We insert an empty space, ready for the composition
|
|
1606
1701
|
// to get inserted into the new node we create. If
|
|
1607
1702
|
// we don't do this, Safari will fail on us because
|
|
@@ -1612,40 +1707,56 @@ function onCompositionStart(event, editor) {
|
|
|
1612
1707
|
});
|
|
1613
1708
|
}
|
|
1614
1709
|
|
|
1615
|
-
function
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
$setCompositionKey(null);
|
|
1619
|
-
const data = event.data; // Handle termination of composition.
|
|
1620
|
-
|
|
1621
|
-
if (compositionKey !== null && data != null) {
|
|
1622
|
-
// It can sometimes move to an adjacent DOM node when backspacing.
|
|
1623
|
-
// So check for the empty case.
|
|
1624
|
-
if (data === '') {
|
|
1625
|
-
const node = $getNodeByKey(compositionKey);
|
|
1626
|
-
const textNode = getDOMTextNode(editor.getElementByKey(compositionKey));
|
|
1627
|
-
|
|
1628
|
-
if (textNode !== null && $isTextNode(node)) {
|
|
1629
|
-
$updateTextNodeFromDOMContent(node, textNode.nodeValue, null, null, true);
|
|
1630
|
-
}
|
|
1710
|
+
function onCompositionEndImpl(editor, data) {
|
|
1711
|
+
const compositionKey = editor._compositionKey;
|
|
1712
|
+
$setCompositionKey(null); // Handle termination of composition.
|
|
1631
1713
|
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1714
|
+
if (compositionKey !== null && data != null) {
|
|
1715
|
+
// Composition can sometimes move to an adjacent DOM node when backspacing.
|
|
1716
|
+
// So check for the empty case.
|
|
1717
|
+
if (data === '') {
|
|
1718
|
+
const node = $getNodeByKey(compositionKey);
|
|
1719
|
+
const textNode = getDOMTextNode(editor.getElementByKey(compositionKey));
|
|
1635
1720
|
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1721
|
+
if (textNode !== null && $isTextNode(node)) {
|
|
1722
|
+
$updateTextNodeFromDOMContent(node, textNode.nodeValue, null, null, true);
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
return;
|
|
1726
|
+
} // Composition can sometimes be that of a new line. In which case, we need to
|
|
1727
|
+
// handle that accordingly.
|
|
1728
|
+
|
|
1729
|
+
|
|
1730
|
+
if (data[data.length - 1] === '\n') {
|
|
1731
|
+
const selection = $getSelection();
|
|
1732
|
+
|
|
1733
|
+
if ($isRangeSelection(selection)) {
|
|
1734
|
+
// If the last character is a line break, we also need to insert
|
|
1735
|
+
// a line break.
|
|
1736
|
+
const focus = selection.focus;
|
|
1737
|
+
selection.anchor.set(focus.key, focus.offset, focus.type);
|
|
1738
|
+
dispatchCommand(editor, KEY_ENTER_COMMAND, null);
|
|
1739
|
+
return;
|
|
1644
1740
|
}
|
|
1645
1741
|
}
|
|
1742
|
+
}
|
|
1646
1743
|
|
|
1647
|
-
|
|
1648
|
-
|
|
1744
|
+
$updateSelectedTextFromDOM(editor, true, data);
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
function onCompositionEnd(event, editor) {
|
|
1748
|
+
// Firefox fires onCompositionEnd before onInput, but Chrome/Webkit,
|
|
1749
|
+
// fire onInput before onCompositionEnd. To ensure the sequence works
|
|
1750
|
+
// like Chrome/Webkit we use the isFirefoxEndingComposition flag to
|
|
1751
|
+
// defer handling of onCompositionEnd in Firefox till we have processed
|
|
1752
|
+
// the logic in onInput.
|
|
1753
|
+
if (IS_FIREFOX) {
|
|
1754
|
+
isFirefoxEndingComposition = true;
|
|
1755
|
+
} else {
|
|
1756
|
+
updateEditor(editor, () => {
|
|
1757
|
+
onCompositionEndImpl(editor, event.data);
|
|
1758
|
+
});
|
|
1759
|
+
}
|
|
1649
1760
|
}
|
|
1650
1761
|
|
|
1651
1762
|
function onKeyDown(event, editor) {
|
|
@@ -1672,11 +1783,16 @@ function onKeyDown(event, editor) {
|
|
|
1672
1783
|
} else if (isMoveDown(keyCode, ctrlKey, shiftKey, altKey, metaKey)) {
|
|
1673
1784
|
dispatchCommand(editor, KEY_ARROW_DOWN_COMMAND, event);
|
|
1674
1785
|
} else if (isLineBreak(keyCode, shiftKey)) {
|
|
1786
|
+
isInsertLineBreak = true;
|
|
1675
1787
|
dispatchCommand(editor, KEY_ENTER_COMMAND, event);
|
|
1788
|
+
} else if (isSpace(keyCode)) {
|
|
1789
|
+
dispatchCommand(editor, KEY_SPACE_COMMAND, event);
|
|
1676
1790
|
} else if (isOpenLineBreak(keyCode, ctrlKey)) {
|
|
1677
1791
|
event.preventDefault();
|
|
1792
|
+
isInsertLineBreak = true;
|
|
1678
1793
|
dispatchCommand(editor, INSERT_LINE_BREAK_COMMAND, true);
|
|
1679
1794
|
} else if (isParagraph(keyCode, shiftKey)) {
|
|
1795
|
+
isInsertLineBreak = false;
|
|
1680
1796
|
dispatchCommand(editor, KEY_ENTER_COMMAND, event);
|
|
1681
1797
|
} else if (isDeleteBackward(keyCode, altKey, metaKey, ctrlKey)) {
|
|
1682
1798
|
if (isBackspace(keyCode)) {
|
|
@@ -1811,6 +1927,9 @@ function addRootElementEvents(rootElement, editor) {
|
|
|
1811
1927
|
case 'dragstart':
|
|
1812
1928
|
return dispatchCommand(editor, DRAGSTART_COMMAND, event);
|
|
1813
1929
|
|
|
1930
|
+
case 'dragend':
|
|
1931
|
+
return dispatchCommand(editor, DRAGEND_COMMAND, event);
|
|
1932
|
+
|
|
1814
1933
|
case 'focus':
|
|
1815
1934
|
return dispatchCommand(editor, FOCUS_COMMAND, event);
|
|
1816
1935
|
|
|
@@ -1877,6 +1996,9 @@ function cleanActiveNestedEditorsMap(editor) {
|
|
|
1877
1996
|
function markSelectionChangeFromReconcile() {
|
|
1878
1997
|
isSelectionChangeFromReconcile = true;
|
|
1879
1998
|
}
|
|
1999
|
+
function markCollapsedSelectionFormat(format, offset, key, timeStamp) {
|
|
2000
|
+
collapsedSelectionFormat = [format, offset, key, timeStamp];
|
|
2001
|
+
}
|
|
1880
2002
|
|
|
1881
2003
|
/**
|
|
1882
2004
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -1944,7 +2066,7 @@ function setTextAlign(domStyle, value) {
|
|
|
1944
2066
|
}
|
|
1945
2067
|
|
|
1946
2068
|
function setElementIndent(dom, indent) {
|
|
1947
|
-
dom.style.setProperty('padding-inline-start', indent === 0 ? '' : indent *
|
|
2069
|
+
dom.style.setProperty('padding-inline-start', indent === 0 ? '' : indent * 20 + 'px');
|
|
1948
2070
|
}
|
|
1949
2071
|
|
|
1950
2072
|
function setElementFormat(dom, format) {
|
|
@@ -2005,6 +2127,11 @@ function createNode(key, parentDOM, insertDOM) {
|
|
|
2005
2127
|
}
|
|
2006
2128
|
|
|
2007
2129
|
reconcileElementTerminatingLineBreak(null, children, dom);
|
|
2130
|
+
|
|
2131
|
+
if ($textContentRequiresDoubleLinebreakAtEnd(node)) {
|
|
2132
|
+
subTreeTextContent += DOUBLE_LINE_BREAK;
|
|
2133
|
+
editorTextContent += DOUBLE_LINE_BREAK;
|
|
2134
|
+
}
|
|
2008
2135
|
} else {
|
|
2009
2136
|
const text = node.getTextContent();
|
|
2010
2137
|
|
|
@@ -2176,12 +2303,12 @@ function reconcileBlockDirection(element, dom) {
|
|
|
2176
2303
|
function reconcileChildrenWithDirection(prevChildren, nextChildren, element, dom) {
|
|
2177
2304
|
const previousSubTreeDirectionTextContent = subTreeDirectionedTextContent;
|
|
2178
2305
|
subTreeDirectionedTextContent = '';
|
|
2179
|
-
reconcileChildren(prevChildren, nextChildren, dom);
|
|
2306
|
+
reconcileChildren(element, prevChildren, nextChildren, dom);
|
|
2180
2307
|
reconcileBlockDirection(element, dom);
|
|
2181
2308
|
subTreeDirectionedTextContent = previousSubTreeDirectionTextContent;
|
|
2182
2309
|
}
|
|
2183
2310
|
|
|
2184
|
-
function reconcileChildren(prevChildren, nextChildren, dom) {
|
|
2311
|
+
function reconcileChildren(element, prevChildren, nextChildren, dom) {
|
|
2185
2312
|
const previousSubTreeTextContent = subTreeTextContent;
|
|
2186
2313
|
subTreeTextContent = '';
|
|
2187
2314
|
const prevChildrenLength = prevChildren.length;
|
|
@@ -2216,7 +2343,11 @@ function reconcileChildren(prevChildren, nextChildren, dom) {
|
|
|
2216
2343
|
}
|
|
2217
2344
|
}
|
|
2218
2345
|
} else {
|
|
2219
|
-
reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom);
|
|
2346
|
+
reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, element, dom);
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
if ($textContentRequiresDoubleLinebreakAtEnd(element)) {
|
|
2350
|
+
subTreeTextContent += DOUBLE_LINE_BREAK;
|
|
2220
2351
|
} // $FlowFixMe: internal field
|
|
2221
2352
|
|
|
2222
2353
|
|
|
@@ -2311,6 +2442,11 @@ function reconcileNode(key, parentDOM) {
|
|
|
2311
2442
|
reconcileElementTerminatingLineBreak(prevChildren, nextChildren, dom);
|
|
2312
2443
|
}
|
|
2313
2444
|
}
|
|
2445
|
+
|
|
2446
|
+
if ($textContentRequiresDoubleLinebreakAtEnd(nextNode)) {
|
|
2447
|
+
subTreeTextContent += DOUBLE_LINE_BREAK;
|
|
2448
|
+
editorTextContent += DOUBLE_LINE_BREAK;
|
|
2449
|
+
}
|
|
2314
2450
|
} else {
|
|
2315
2451
|
const text = nextNode.getTextContent();
|
|
2316
2452
|
|
|
@@ -2320,6 +2456,9 @@ function reconcileNode(key, parentDOM) {
|
|
|
2320
2456
|
if (decorator !== null) {
|
|
2321
2457
|
reconcileDecorator(key, decorator);
|
|
2322
2458
|
}
|
|
2459
|
+
|
|
2460
|
+
subTreeTextContent += text;
|
|
2461
|
+
editorTextContent += text;
|
|
2323
2462
|
} else if ($isTextNode(nextNode) && !nextNode.isDirectionless()) {
|
|
2324
2463
|
// Handle text content, for LTR, LTR cases.
|
|
2325
2464
|
subTreeDirectionedTextContent += text;
|
|
@@ -2368,7 +2507,7 @@ function getNextSibling(element) {
|
|
|
2368
2507
|
return element.nextSibling;
|
|
2369
2508
|
}
|
|
2370
2509
|
|
|
2371
|
-
function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, dom) {
|
|
2510
|
+
function reconcileNodeChildren(prevChildren, nextChildren, prevChildrenLength, nextChildrenLength, element, dom) {
|
|
2372
2511
|
const prevEndIndex = prevChildrenLength - 1;
|
|
2373
2512
|
const nextEndIndex = nextChildrenLength - 1;
|
|
2374
2513
|
let prevChildrenSet;
|
|
@@ -2582,11 +2721,15 @@ function reconcileSelection(prevSelection, nextSelection, editor, domSelection)
|
|
|
2582
2721
|
const focusDOM = getElementByKeyOrThrow(editor, focusKey);
|
|
2583
2722
|
const nextAnchorOffset = anchor.offset;
|
|
2584
2723
|
const nextFocusOffset = focus.offset;
|
|
2724
|
+
const nextFormat = nextSelection.format;
|
|
2725
|
+
const isCollapsed = nextSelection.isCollapsed();
|
|
2585
2726
|
let nextAnchorNode = anchorDOM;
|
|
2586
2727
|
let nextFocusNode = focusDOM;
|
|
2728
|
+
let anchorFormatChanged = false;
|
|
2587
2729
|
|
|
2588
2730
|
if (anchor.type === 'text') {
|
|
2589
2731
|
nextAnchorNode = getDOMTextNode(anchorDOM);
|
|
2732
|
+
anchorFormatChanged = anchor.getNode().getFormat() !== nextFormat;
|
|
2590
2733
|
}
|
|
2591
2734
|
|
|
2592
2735
|
if (focus.type === 'text') {
|
|
@@ -2597,20 +2740,31 @@ function reconcileSelection(prevSelection, nextSelection, editor, domSelection)
|
|
|
2597
2740
|
|
|
2598
2741
|
if (nextAnchorNode === null || nextFocusNode === null) {
|
|
2599
2742
|
return;
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
if (isCollapsed && (prevSelection === null || anchorFormatChanged || prevSelection.format !== nextFormat)) {
|
|
2746
|
+
markCollapsedSelectionFormat(nextFormat, nextAnchorOffset, anchorKey, performance.now());
|
|
2600
2747
|
} // Diff against the native DOM selection to ensure we don't do
|
|
2601
|
-
// an unnecessary selection update.
|
|
2748
|
+
// an unnecessary selection update. We also skip this check if
|
|
2749
|
+
// we're moving selection to within an element, as this can
|
|
2750
|
+
// sometimes be problematic around scrolling.
|
|
2602
2751
|
|
|
2603
2752
|
|
|
2604
2753
|
if (anchorOffset === nextAnchorOffset && focusOffset === nextFocusOffset && anchorDOMNode === nextAnchorNode && focusDOMNode === nextFocusNode && // Badly interpreted range selection when collapsed - #1482
|
|
2605
|
-
!(domSelection.type === 'Range' &&
|
|
2754
|
+
!(domSelection.type === 'Range' && isCollapsed)) {
|
|
2606
2755
|
// If the root element does not have focus, ensure it has focus
|
|
2607
2756
|
if (rootElement !== null && (activeElement === null || !rootElement.contains(activeElement))) {
|
|
2608
2757
|
rootElement.focus({
|
|
2609
2758
|
preventScroll: true
|
|
2610
2759
|
});
|
|
2611
|
-
}
|
|
2760
|
+
} // In Safari/iOS if we have selection on an element, then we also
|
|
2761
|
+
// need to additionally set the DOM selection, otherwise a selectionchange
|
|
2762
|
+
// event will not fire.
|
|
2612
2763
|
|
|
2613
|
-
|
|
2764
|
+
|
|
2765
|
+
if (!(IS_IOS || IS_SAFARI) || anchor.type !== 'element') {
|
|
2766
|
+
return;
|
|
2767
|
+
}
|
|
2614
2768
|
} // Apply the updated selection to the DOM. Note: this will trigger
|
|
2615
2769
|
// a "selectionchange" event, although it will be asynchronous.
|
|
2616
2770
|
|
|
@@ -2741,7 +2895,7 @@ function $normalizeAllDirtyTextNodes(editorState, editor) {
|
|
|
2741
2895
|
for (const nodeKey of dirtyLeaves) {
|
|
2742
2896
|
const node = nodeMap.get(nodeKey);
|
|
2743
2897
|
|
|
2744
|
-
if ($isTextNode(node) && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2898
|
+
if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2745
2899
|
$normalizeTextNode(node);
|
|
2746
2900
|
}
|
|
2747
2901
|
}
|
|
@@ -2777,7 +2931,7 @@ function $applyAllTransforms(editorState, editor) {
|
|
|
2777
2931
|
for (const nodeKey of untransformedDirtyLeaves) {
|
|
2778
2932
|
const node = nodeMap.get(nodeKey);
|
|
2779
2933
|
|
|
2780
|
-
if ($isTextNode(node) && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2934
|
+
if ($isTextNode(node) && node.isAttached() && node.isSimpleText() && !node.isUnmergeable()) {
|
|
2781
2935
|
$normalizeTextNode(node);
|
|
2782
2936
|
}
|
|
2783
2937
|
|
|
@@ -2903,8 +3057,9 @@ function handleDEVOnlyPendingUpdateGuarantees(pendingEditorState) {
|
|
|
2903
3057
|
function commitPendingUpdates(editor) {
|
|
2904
3058
|
const pendingEditorState = editor._pendingEditorState;
|
|
2905
3059
|
const rootElement = editor._rootElement;
|
|
3060
|
+
const headless = editor._headless;
|
|
2906
3061
|
|
|
2907
|
-
if (rootElement === null || pendingEditorState === null) {
|
|
3062
|
+
if (rootElement === null && !headless || pendingEditorState === null) {
|
|
2908
3063
|
return;
|
|
2909
3064
|
}
|
|
2910
3065
|
|
|
@@ -2925,10 +3080,12 @@ function commitPendingUpdates(editor) {
|
|
|
2925
3080
|
editor._updating = true;
|
|
2926
3081
|
|
|
2927
3082
|
try {
|
|
2928
|
-
|
|
3083
|
+
if (!headless && rootElement !== null) {
|
|
3084
|
+
const mutatedNodes = updateEditorState(rootElement, currentEditorState, pendingEditorState, currentSelection, pendingSelection, needsUpdate, editor);
|
|
2929
3085
|
|
|
2930
|
-
|
|
2931
|
-
|
|
3086
|
+
if (mutatedNodes !== null) {
|
|
3087
|
+
triggerMutationListeners(editor, currentEditorState, pendingEditorState, mutatedNodes);
|
|
3088
|
+
}
|
|
2932
3089
|
}
|
|
2933
3090
|
} catch (error) {
|
|
2934
3091
|
// Report errors
|
|
@@ -3095,9 +3252,9 @@ function triggerDeferredUpdateCallbacks(editor) {
|
|
|
3095
3252
|
}
|
|
3096
3253
|
}
|
|
3097
3254
|
|
|
3098
|
-
function processNestedUpdates(editor) {
|
|
3255
|
+
function processNestedUpdates(editor, initialSkipTransforms) {
|
|
3099
3256
|
const queuedUpdates = editor._updates;
|
|
3100
|
-
let skipTransforms = false; // Updates might grow as we process them, we so we'll need
|
|
3257
|
+
let skipTransforms = initialSkipTransforms || false; // Updates might grow as we process them, we so we'll need
|
|
3101
3258
|
// to handle each update as we go until the updates array is
|
|
3102
3259
|
// empty.
|
|
3103
3260
|
|
|
@@ -3169,13 +3326,13 @@ function beginUpdate(editor, updateFn, options) {
|
|
|
3169
3326
|
activeEditor = editor;
|
|
3170
3327
|
|
|
3171
3328
|
try {
|
|
3172
|
-
if (editorStateWasCloned) {
|
|
3329
|
+
if (editorStateWasCloned && !editor._headless) {
|
|
3173
3330
|
pendingEditorState._selection = internalCreateSelection(editor);
|
|
3174
3331
|
}
|
|
3175
3332
|
|
|
3176
3333
|
const startingCompositionKey = editor._compositionKey;
|
|
3177
3334
|
updateFn();
|
|
3178
|
-
skipTransforms = processNestedUpdates(editor);
|
|
3335
|
+
skipTransforms = processNestedUpdates(editor, skipTransforms);
|
|
3179
3336
|
applySelectionTransforms(pendingEditorState, editor);
|
|
3180
3337
|
|
|
3181
3338
|
if (editor._dirtyType !== NO_DIRTY_NODES) {
|
|
@@ -3506,6 +3663,8 @@ function initMutationObserver(editor) {
|
|
|
3506
3663
|
|
|
3507
3664
|
class Point {
|
|
3508
3665
|
constructor(key, offset, type) {
|
|
3666
|
+
// $FlowFixMe: is temporarily null
|
|
3667
|
+
this._selection = null;
|
|
3509
3668
|
this.key = key;
|
|
3510
3669
|
this.offset = offset;
|
|
3511
3670
|
this.type = type;
|
|
@@ -3536,10 +3695,6 @@ class Point {
|
|
|
3536
3695
|
return aNode.isBefore(bNode);
|
|
3537
3696
|
}
|
|
3538
3697
|
|
|
3539
|
-
getCharacterOffset() {
|
|
3540
|
-
return this.type === 'text' ? this.offset : 0;
|
|
3541
|
-
}
|
|
3542
|
-
|
|
3543
3698
|
getNode() {
|
|
3544
3699
|
const key = this.key;
|
|
3545
3700
|
const node = $getNodeByKey(key);
|
|
@@ -3554,7 +3709,7 @@ class Point {
|
|
|
3554
3709
|
}
|
|
3555
3710
|
|
|
3556
3711
|
set(key, offset, type) {
|
|
3557
|
-
const selection =
|
|
3712
|
+
const selection = this._selection;
|
|
3558
3713
|
const oldKey = this.key;
|
|
3559
3714
|
this.key = key;
|
|
3560
3715
|
this.offset = offset;
|
|
@@ -3566,6 +3721,7 @@ class Point {
|
|
|
3566
3721
|
}
|
|
3567
3722
|
|
|
3568
3723
|
if (selection !== null && (selection.anchor === this || selection.focus === this)) {
|
|
3724
|
+
selection._cachedNodes = null;
|
|
3569
3725
|
selection.dirty = true;
|
|
3570
3726
|
}
|
|
3571
3727
|
}
|
|
@@ -3642,6 +3798,7 @@ class NodeSelection {
|
|
|
3642
3798
|
constructor(objects) {
|
|
3643
3799
|
this.dirty = false;
|
|
3644
3800
|
this._nodes = objects;
|
|
3801
|
+
this._cachedNodes = null;
|
|
3645
3802
|
}
|
|
3646
3803
|
|
|
3647
3804
|
is(selection) {
|
|
@@ -3658,18 +3815,24 @@ class NodeSelection {
|
|
|
3658
3815
|
this.dirty = true;
|
|
3659
3816
|
|
|
3660
3817
|
this._nodes.add(key);
|
|
3818
|
+
|
|
3819
|
+
this._cachedNodes = null;
|
|
3661
3820
|
}
|
|
3662
3821
|
|
|
3663
3822
|
delete(key) {
|
|
3664
3823
|
this.dirty = true;
|
|
3665
3824
|
|
|
3666
3825
|
this._nodes.delete(key);
|
|
3826
|
+
|
|
3827
|
+
this._cachedNodes = null;
|
|
3667
3828
|
}
|
|
3668
3829
|
|
|
3669
3830
|
clear() {
|
|
3670
3831
|
this.dirty = true;
|
|
3671
3832
|
|
|
3672
3833
|
this._nodes.clear();
|
|
3834
|
+
|
|
3835
|
+
this._cachedNodes = null;
|
|
3673
3836
|
}
|
|
3674
3837
|
|
|
3675
3838
|
has(key) {
|
|
@@ -3691,6 +3854,12 @@ class NodeSelection {
|
|
|
3691
3854
|
}
|
|
3692
3855
|
|
|
3693
3856
|
getNodes() {
|
|
3857
|
+
const cachedNodes = this._cachedNodes;
|
|
3858
|
+
|
|
3859
|
+
if (cachedNodes !== null) {
|
|
3860
|
+
return cachedNodes;
|
|
3861
|
+
}
|
|
3862
|
+
|
|
3694
3863
|
const objects = this._nodes;
|
|
3695
3864
|
const nodes = [];
|
|
3696
3865
|
|
|
@@ -3702,6 +3871,10 @@ class NodeSelection {
|
|
|
3702
3871
|
}
|
|
3703
3872
|
}
|
|
3704
3873
|
|
|
3874
|
+
if (!isCurrentlyReadOnlyMode()) {
|
|
3875
|
+
this._cachedNodes = nodes;
|
|
3876
|
+
}
|
|
3877
|
+
|
|
3705
3878
|
return nodes;
|
|
3706
3879
|
}
|
|
3707
3880
|
|
|
@@ -3721,13 +3894,14 @@ function $isRangeSelection(x) {
|
|
|
3721
3894
|
return x instanceof RangeSelection;
|
|
3722
3895
|
}
|
|
3723
3896
|
class GridSelection {
|
|
3724
|
-
constructor(gridKey,
|
|
3897
|
+
constructor(gridKey, anchor, focus) {
|
|
3725
3898
|
this.gridKey = gridKey;
|
|
3726
|
-
this.
|
|
3727
|
-
this.
|
|
3728
|
-
this.focusCellKey = focusCellKey;
|
|
3729
|
-
this.focus = $createPoint(focusCellKey, 0, 'element');
|
|
3899
|
+
this.anchor = anchor;
|
|
3900
|
+
this.focus = focus;
|
|
3730
3901
|
this.dirty = false;
|
|
3902
|
+
this._cachedNodes = null;
|
|
3903
|
+
anchor._selection = this;
|
|
3904
|
+
focus._selection = this;
|
|
3731
3905
|
}
|
|
3732
3906
|
|
|
3733
3907
|
is(selection) {
|
|
@@ -3735,18 +3909,19 @@ class GridSelection {
|
|
|
3735
3909
|
return false;
|
|
3736
3910
|
}
|
|
3737
3911
|
|
|
3738
|
-
return this.gridKey === selection.gridKey && this.
|
|
3912
|
+
return this.gridKey === selection.gridKey && this.anchor.is(this.focus);
|
|
3739
3913
|
}
|
|
3740
3914
|
|
|
3741
3915
|
set(gridKey, anchorCellKey, focusCellKey) {
|
|
3742
3916
|
this.dirty = true;
|
|
3743
3917
|
this.gridKey = gridKey;
|
|
3744
|
-
this.
|
|
3745
|
-
this.
|
|
3918
|
+
this.anchor.key = anchorCellKey;
|
|
3919
|
+
this.focus.key = focusCellKey;
|
|
3920
|
+
this._cachedNodes = null;
|
|
3746
3921
|
}
|
|
3747
3922
|
|
|
3748
3923
|
clone() {
|
|
3749
|
-
return new GridSelection(this.gridKey, this.
|
|
3924
|
+
return new GridSelection(this.gridKey, this.anchor, this.focus);
|
|
3750
3925
|
}
|
|
3751
3926
|
|
|
3752
3927
|
isCollapsed() {
|
|
@@ -3757,6 +3932,10 @@ class GridSelection {
|
|
|
3757
3932
|
return this.focus.isBefore(this.anchor);
|
|
3758
3933
|
}
|
|
3759
3934
|
|
|
3935
|
+
getCharacterOffsets() {
|
|
3936
|
+
return getCharacterOffsets(this);
|
|
3937
|
+
}
|
|
3938
|
+
|
|
3760
3939
|
extract() {
|
|
3761
3940
|
return this.getNodes();
|
|
3762
3941
|
}
|
|
@@ -3768,7 +3947,7 @@ class GridSelection {
|
|
|
3768
3947
|
}
|
|
3769
3948
|
|
|
3770
3949
|
getShape() {
|
|
3771
|
-
const anchorCellNode = $getNodeByKey(this.
|
|
3950
|
+
const anchorCellNode = $getNodeByKey(this.anchor.key);
|
|
3772
3951
|
|
|
3773
3952
|
if (!anchorCellNode) {
|
|
3774
3953
|
throw Error(`getNodes: expected to find AnchorNode`);
|
|
@@ -3776,7 +3955,7 @@ class GridSelection {
|
|
|
3776
3955
|
|
|
3777
3956
|
const anchorCellNodeIndex = anchorCellNode.getIndexWithinParent();
|
|
3778
3957
|
const anchorCelRoweIndex = anchorCellNode.getParentOrThrow().getIndexWithinParent();
|
|
3779
|
-
const focusCellNode = $getNodeByKey(this.
|
|
3958
|
+
const focusCellNode = $getNodeByKey(this.focus.key);
|
|
3780
3959
|
|
|
3781
3960
|
if (!focusCellNode) {
|
|
3782
3961
|
throw Error(`getNodes: expected to find FocusNode`);
|
|
@@ -3797,7 +3976,13 @@ class GridSelection {
|
|
|
3797
3976
|
}
|
|
3798
3977
|
|
|
3799
3978
|
getNodes() {
|
|
3800
|
-
const
|
|
3979
|
+
const cachedNodes = this._cachedNodes;
|
|
3980
|
+
|
|
3981
|
+
if (cachedNodes !== null) {
|
|
3982
|
+
return cachedNodes;
|
|
3983
|
+
}
|
|
3984
|
+
|
|
3985
|
+
const nodesSet = new Set();
|
|
3801
3986
|
const {
|
|
3802
3987
|
fromX,
|
|
3803
3988
|
fromY,
|
|
@@ -3812,12 +3997,12 @@ class GridSelection {
|
|
|
3812
3997
|
}
|
|
3813
3998
|
}
|
|
3814
3999
|
|
|
3815
|
-
|
|
4000
|
+
nodesSet.add(gridNode);
|
|
3816
4001
|
const gridRowNodes = gridNode.getChildren();
|
|
3817
4002
|
|
|
3818
4003
|
for (let r = fromY; r <= toY; r++) {
|
|
3819
4004
|
const gridRowNode = gridRowNodes[r];
|
|
3820
|
-
|
|
4005
|
+
nodesSet.add(gridRowNode);
|
|
3821
4006
|
|
|
3822
4007
|
if (!$isGridRowNode(gridRowNode)) {
|
|
3823
4008
|
{
|
|
@@ -3836,12 +4021,12 @@ class GridSelection {
|
|
|
3836
4021
|
}
|
|
3837
4022
|
}
|
|
3838
4023
|
|
|
3839
|
-
|
|
4024
|
+
nodesSet.add(gridCellNode);
|
|
3840
4025
|
const children = gridCellNode.getChildren();
|
|
3841
4026
|
|
|
3842
4027
|
while (children.length > 0) {
|
|
3843
4028
|
const child = children.shift();
|
|
3844
|
-
|
|
4029
|
+
nodesSet.add(child);
|
|
3845
4030
|
|
|
3846
4031
|
if ($isElementNode(child)) {
|
|
3847
4032
|
children.unshift(...child.getChildren());
|
|
@@ -3850,7 +4035,13 @@ class GridSelection {
|
|
|
3850
4035
|
}
|
|
3851
4036
|
}
|
|
3852
4037
|
|
|
3853
|
-
|
|
4038
|
+
const nodes = Array.from(nodesSet);
|
|
4039
|
+
|
|
4040
|
+
if (!isCurrentlyReadOnlyMode()) {
|
|
4041
|
+
this._cachedNodes = nodes;
|
|
4042
|
+
}
|
|
4043
|
+
|
|
4044
|
+
return nodes;
|
|
3854
4045
|
}
|
|
3855
4046
|
|
|
3856
4047
|
getTextContent() {
|
|
@@ -3874,6 +4065,9 @@ class RangeSelection {
|
|
|
3874
4065
|
this.focus = focus;
|
|
3875
4066
|
this.dirty = false;
|
|
3876
4067
|
this.format = format;
|
|
4068
|
+
this._cachedNodes = null;
|
|
4069
|
+
anchor._selection = this;
|
|
4070
|
+
focus._selection = this;
|
|
3877
4071
|
}
|
|
3878
4072
|
|
|
3879
4073
|
is(selection) {
|
|
@@ -3893,6 +4087,12 @@ class RangeSelection {
|
|
|
3893
4087
|
}
|
|
3894
4088
|
|
|
3895
4089
|
getNodes() {
|
|
4090
|
+
const cachedNodes = this._cachedNodes;
|
|
4091
|
+
|
|
4092
|
+
if (cachedNodes !== null) {
|
|
4093
|
+
return cachedNodes;
|
|
4094
|
+
}
|
|
4095
|
+
|
|
3896
4096
|
const anchor = this.anchor;
|
|
3897
4097
|
const focus = this.focus;
|
|
3898
4098
|
let firstNode = anchor.getNode();
|
|
@@ -3906,20 +4106,29 @@ class RangeSelection {
|
|
|
3906
4106
|
lastNode = lastNode.getDescendantByIndex(focus.offset);
|
|
3907
4107
|
}
|
|
3908
4108
|
|
|
4109
|
+
let nodes;
|
|
4110
|
+
|
|
3909
4111
|
if (firstNode.is(lastNode)) {
|
|
3910
|
-
if ($isElementNode(firstNode)) {
|
|
3911
|
-
|
|
4112
|
+
if ($isElementNode(firstNode) && (firstNode.getChildrenSize() > 0 || firstNode.excludeFromCopy())) {
|
|
4113
|
+
nodes = [];
|
|
4114
|
+
} else {
|
|
4115
|
+
nodes = [firstNode];
|
|
3912
4116
|
}
|
|
4117
|
+
} else {
|
|
4118
|
+
nodes = firstNode.getNodesBetween(lastNode);
|
|
4119
|
+
}
|
|
3913
4120
|
|
|
3914
|
-
|
|
4121
|
+
if (!isCurrentlyReadOnlyMode()) {
|
|
4122
|
+
this._cachedNodes = nodes;
|
|
3915
4123
|
}
|
|
3916
4124
|
|
|
3917
|
-
return
|
|
4125
|
+
return nodes;
|
|
3918
4126
|
}
|
|
3919
4127
|
|
|
3920
4128
|
setTextNodeRange(anchorNode, anchorOffset, focusNode, focusOffset) {
|
|
3921
4129
|
$setPointValues(this.anchor, anchorNode.__key, anchorOffset, 'text');
|
|
3922
4130
|
$setPointValues(this.focus, focusNode.__key, focusOffset, 'text');
|
|
4131
|
+
this._cachedNodes = null;
|
|
3923
4132
|
this.dirty = true;
|
|
3924
4133
|
}
|
|
3925
4134
|
|
|
@@ -3935,8 +4144,7 @@ class RangeSelection {
|
|
|
3935
4144
|
const anchor = this.anchor;
|
|
3936
4145
|
const focus = this.focus;
|
|
3937
4146
|
const isBefore = anchor.isBefore(focus);
|
|
3938
|
-
const anchorOffset =
|
|
3939
|
-
const focusOffset = focus.getCharacterOffset();
|
|
4147
|
+
const [anchorOffset, focusOffset] = getCharacterOffsets(this);
|
|
3940
4148
|
let textContent = '';
|
|
3941
4149
|
let prevWasElement = true;
|
|
3942
4150
|
|
|
@@ -3992,12 +4200,14 @@ class RangeSelection {
|
|
|
3992
4200
|
const [anchorPoint, focusPoint] = resolvedSelectionPoints;
|
|
3993
4201
|
$setPointValues(this.anchor, anchorPoint.key, anchorPoint.offset, anchorPoint.type);
|
|
3994
4202
|
$setPointValues(this.focus, focusPoint.key, focusPoint.offset, focusPoint.type);
|
|
4203
|
+
this._cachedNodes = null;
|
|
3995
4204
|
}
|
|
3996
4205
|
|
|
3997
4206
|
clone() {
|
|
3998
4207
|
const anchor = this.anchor;
|
|
3999
4208
|
const focus = this.focus;
|
|
4000
|
-
|
|
4209
|
+
const selection = new RangeSelection($createPoint(anchor.key, anchor.offset, anchor.type), $createPoint(focus.key, focus.offset, focus.type), this.format);
|
|
4210
|
+
return selection;
|
|
4001
4211
|
}
|
|
4002
4212
|
|
|
4003
4213
|
toggleFormat(format) {
|
|
@@ -4064,11 +4274,13 @@ class RangeSelection {
|
|
|
4064
4274
|
const firstNodeText = firstNode.getTextContent();
|
|
4065
4275
|
const firstNodeTextLength = firstNodeText.length;
|
|
4066
4276
|
const firstNodeParent = firstNode.getParentOrThrow();
|
|
4277
|
+
const lastIndex = selectedNodesLength - 1;
|
|
4278
|
+
let lastNode = selectedNodes[lastIndex];
|
|
4067
4279
|
|
|
4068
4280
|
if (this.isCollapsed() && startOffset === firstNodeTextLength && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextAfter() || !firstNodeParent.canInsertTextAfter())) {
|
|
4069
4281
|
let nextSibling = firstNode.getNextSibling();
|
|
4070
4282
|
|
|
4071
|
-
if (!$isTextNode(nextSibling) || $
|
|
4283
|
+
if (!$isTextNode(nextSibling) || $isTokenOrInertOrSegmented(nextSibling)) {
|
|
4072
4284
|
nextSibling = $createTextNode();
|
|
4073
4285
|
|
|
4074
4286
|
if (!firstNodeParent.canInsertTextAfter()) {
|
|
@@ -4088,7 +4300,7 @@ class RangeSelection {
|
|
|
4088
4300
|
} else if (this.isCollapsed() && startOffset === 0 && (firstNode.isSegmented() || firstNode.isToken() || !firstNode.canInsertTextBefore() || !firstNodeParent.canInsertTextBefore())) {
|
|
4089
4301
|
let prevSibling = firstNode.getPreviousSibling();
|
|
4090
4302
|
|
|
4091
|
-
if (!$isTextNode(prevSibling) || $
|
|
4303
|
+
if (!$isTextNode(prevSibling) || $isTokenOrInertOrSegmented(prevSibling)) {
|
|
4092
4304
|
prevSibling = $createTextNode();
|
|
4093
4305
|
|
|
4094
4306
|
if (!firstNodeParent.canInsertTextBefore()) {
|
|
@@ -4109,6 +4321,19 @@ class RangeSelection {
|
|
|
4109
4321
|
const textNode = $createTextNode(firstNode.getTextContent());
|
|
4110
4322
|
firstNode.replace(textNode);
|
|
4111
4323
|
firstNode = textNode;
|
|
4324
|
+
} else if (!this.isCollapsed() && text !== '') {
|
|
4325
|
+
// When the firstNode or lastNode parents are elements that
|
|
4326
|
+
// do not allow text to be inserted before or after, we first
|
|
4327
|
+
// clear the content. Then we normalize selection, then insert
|
|
4328
|
+
// the new content.
|
|
4329
|
+
const lastNodeParent = lastNode.getParent();
|
|
4330
|
+
|
|
4331
|
+
if (!firstNodeParent.canInsertTextBefore() || !firstNodeParent.canInsertTextAfter() || $isElementNode(lastNodeParent) && (!lastNodeParent.canInsertTextBefore() || !lastNodeParent.canInsertTextAfter())) {
|
|
4332
|
+
this.insertText('');
|
|
4333
|
+
normalizeSelectionPointsForBoundaries(this.anchor, this.focus, null);
|
|
4334
|
+
this.insertText(text);
|
|
4335
|
+
return;
|
|
4336
|
+
}
|
|
4112
4337
|
}
|
|
4113
4338
|
|
|
4114
4339
|
if (selectedNodesLength === 1) {
|
|
@@ -4157,11 +4382,24 @@ class RangeSelection {
|
|
|
4157
4382
|
this.anchor.offset -= text.length;
|
|
4158
4383
|
}
|
|
4159
4384
|
} else {
|
|
4160
|
-
const
|
|
4161
|
-
|
|
4162
|
-
|
|
4385
|
+
const markedNodeKeysForKeep = new Set([...firstNode.getParentKeys(), ...lastNode.getParentKeys()]); // We have to get the parent elements before the next section,
|
|
4386
|
+
// as in that section we might mutate the lastNode.
|
|
4387
|
+
|
|
4163
4388
|
const firstElement = $isElementNode(firstNode) ? firstNode : firstNode.getParentOrThrow();
|
|
4164
|
-
|
|
4389
|
+
let lastElement = $isElementNode(lastNode) ? lastNode : lastNode.getParentOrThrow();
|
|
4390
|
+
let lastElementChild = lastNode; // If the last element is inline, we should instead look at getting
|
|
4391
|
+
// the nodes of its parent, rather than itself. This behavior will
|
|
4392
|
+
// then better match how text node insertions work. We will need to
|
|
4393
|
+
// also update the last element's child accordingly as we do this.
|
|
4394
|
+
|
|
4395
|
+
if (!firstElement.is(lastElement) && lastElement.isInline()) {
|
|
4396
|
+
// Keep traversing till we have a non-inline element parent.
|
|
4397
|
+
do {
|
|
4398
|
+
lastElementChild = lastElement;
|
|
4399
|
+
lastElement = lastElement.getParentOrThrow();
|
|
4400
|
+
} while (lastElement.isInline());
|
|
4401
|
+
} // Handle mutations to the last node.
|
|
4402
|
+
|
|
4165
4403
|
|
|
4166
4404
|
if (endPoint.type === 'text' && (endOffset !== 0 || lastNode.getTextContent() === '') || endPoint.type === 'element' && lastNode.getIndexWithinParent() < endOffset) {
|
|
4167
4405
|
if ($isTextNode(lastNode) && !$isTokenOrInert(lastNode) && endOffset !== lastNode.getTextContentSize()) {
|
|
@@ -4174,7 +4412,13 @@ class RangeSelection {
|
|
|
4174
4412
|
lastNode = lastNode.spliceText(0, endOffset, '');
|
|
4175
4413
|
markedNodeKeysForKeep.add(lastNode.__key);
|
|
4176
4414
|
} else {
|
|
4177
|
-
lastNode.
|
|
4415
|
+
const lastNodeParent = lastNode.getParentOrThrow();
|
|
4416
|
+
|
|
4417
|
+
if (!lastNodeParent.canBeEmpty() && lastNodeParent.getChildrenSize() === 1) {
|
|
4418
|
+
lastNodeParent.remove();
|
|
4419
|
+
} else {
|
|
4420
|
+
lastNode.remove();
|
|
4421
|
+
}
|
|
4178
4422
|
}
|
|
4179
4423
|
} else {
|
|
4180
4424
|
markedNodeKeysForKeep.add(lastNode.__key);
|
|
@@ -4185,48 +4429,50 @@ class RangeSelection {
|
|
|
4185
4429
|
|
|
4186
4430
|
const lastNodeChildren = lastElement.getChildren();
|
|
4187
4431
|
const selectedNodesSet = new Set(selectedNodes);
|
|
4188
|
-
const firstAndLastElementsAreEqual = firstElement.is(lastElement); //
|
|
4189
|
-
//
|
|
4432
|
+
const firstAndLastElementsAreEqual = firstElement.is(lastElement); // We choose a target to insert all nodes after. In the case of having
|
|
4433
|
+
// and inline starting parent element with a starting node that has no
|
|
4434
|
+
// siblings, we should insert after the starting parent element, otherwise
|
|
4435
|
+
// we will incorrectly merge into the starting parent element.
|
|
4436
|
+
// TODO: should we keep on traversing parents if we're inside another
|
|
4437
|
+
// nested inline element?
|
|
4190
4438
|
|
|
4191
|
-
|
|
4192
|
-
firstElement.append(lastElement);
|
|
4193
|
-
} else {
|
|
4194
|
-
for (let i = lastNodeChildren.length - 1; i >= 0; i--) {
|
|
4195
|
-
const lastNodeChild = lastNodeChildren[i];
|
|
4439
|
+
const insertionTarget = firstElement.isInline() && firstNode.getNextSibling() === null ? firstElement : firstNode;
|
|
4196
4440
|
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
}
|
|
4441
|
+
for (let i = lastNodeChildren.length - 1; i >= 0; i--) {
|
|
4442
|
+
const lastNodeChild = lastNodeChildren[i];
|
|
4200
4443
|
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4444
|
+
if (lastNodeChild.is(firstNode) || $isElementNode(lastNodeChild) && lastNodeChild.isParentOf(firstNode)) {
|
|
4445
|
+
break;
|
|
4446
|
+
}
|
|
4447
|
+
|
|
4448
|
+
if (lastNodeChild.isAttached()) {
|
|
4449
|
+
if (!selectedNodesSet.has(lastNodeChild) || lastNodeChild.is(lastElementChild)) {
|
|
4450
|
+
if (!firstAndLastElementsAreEqual) {
|
|
4451
|
+
insertionTarget.insertAfter(lastNodeChild);
|
|
4208
4452
|
}
|
|
4453
|
+
} else {
|
|
4454
|
+
lastNodeChild.remove();
|
|
4209
4455
|
}
|
|
4210
4456
|
}
|
|
4457
|
+
}
|
|
4211
4458
|
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4459
|
+
if (!firstAndLastElementsAreEqual) {
|
|
4460
|
+
// Check if we have already moved out all the nodes of the
|
|
4461
|
+
// last parent, and if so, traverse the parent tree and mark
|
|
4462
|
+
// them all as being able to deleted too.
|
|
4463
|
+
let parent = lastElement;
|
|
4464
|
+
let lastRemovedParent = null;
|
|
4218
4465
|
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4466
|
+
while (parent !== null) {
|
|
4467
|
+
const children = parent.getChildren();
|
|
4468
|
+
const childrenLength = children.length;
|
|
4222
4469
|
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
}
|
|
4227
|
-
|
|
4228
|
-
parent = parent.getParent();
|
|
4470
|
+
if (childrenLength === 0 || children[childrenLength - 1].is(lastRemovedParent)) {
|
|
4471
|
+
markedNodeKeysForKeep.delete(parent.__key);
|
|
4472
|
+
lastRemovedParent = parent;
|
|
4229
4473
|
}
|
|
4474
|
+
|
|
4475
|
+
parent = parent.getParent();
|
|
4230
4476
|
}
|
|
4231
4477
|
} // Ensure we do splicing after moving of nodes, as splicing
|
|
4232
4478
|
// can have side-effects (in the case of hashtags).
|
|
@@ -4283,10 +4529,9 @@ class RangeSelection {
|
|
|
4283
4529
|
|
|
4284
4530
|
const anchor = this.anchor;
|
|
4285
4531
|
const focus = this.focus;
|
|
4286
|
-
const firstNodeText = firstNode.getTextContent();
|
|
4287
|
-
const firstNodeTextLength = firstNodeText.length;
|
|
4288
4532
|
const focusOffset = focus.offset;
|
|
4289
4533
|
let firstNextFormat = 0;
|
|
4534
|
+
let firstNodeTextLength = firstNode.getTextContent().length;
|
|
4290
4535
|
|
|
4291
4536
|
for (let i = 0; i < selectedNodes.length; i++) {
|
|
4292
4537
|
const selectedNode = selectedNodes[i];
|
|
@@ -4306,13 +4551,18 @@ class RangeSelection {
|
|
|
4306
4551
|
// first node so we don't want to include it in the formatting change.
|
|
4307
4552
|
|
|
4308
4553
|
if (startOffset === firstNode.getTextContentSize()) {
|
|
4309
|
-
|
|
4554
|
+
let nextSibling = firstNode.getNextSibling();
|
|
4555
|
+
|
|
4556
|
+
if ($isElementNode(nextSibling) && nextSibling.isInline()) {
|
|
4557
|
+
nextSibling = nextSibling.getFirstChild();
|
|
4558
|
+
}
|
|
4310
4559
|
|
|
4311
4560
|
if ($isTextNode(nextSibling)) {
|
|
4312
4561
|
// we basically make the second node the firstNode, changing offsets accordingly
|
|
4313
4562
|
anchorOffset = 0;
|
|
4314
4563
|
startOffset = 0;
|
|
4315
4564
|
firstNode = nextSibling;
|
|
4565
|
+
firstNodeTextLength = nextSibling.getTextContent().length;
|
|
4316
4566
|
firstNextFormat = firstNode.getFormatFlags(formatType, null);
|
|
4317
4567
|
}
|
|
4318
4568
|
} // This is the case where we only selected a single node
|
|
@@ -4458,7 +4708,7 @@ class RangeSelection {
|
|
|
4458
4708
|
for (let i = 0; i < nodes.length; i++) {
|
|
4459
4709
|
const node = nodes[i];
|
|
4460
4710
|
|
|
4461
|
-
if ($isElementNode(node)) {
|
|
4711
|
+
if ($isElementNode(node) && !node.isInline()) {
|
|
4462
4712
|
// -----
|
|
4463
4713
|
// Heuristics for the replacment or merging of elements
|
|
4464
4714
|
// -----
|
|
@@ -4554,7 +4804,7 @@ class RangeSelection {
|
|
|
4554
4804
|
|
|
4555
4805
|
didReplaceOrMerge = false;
|
|
4556
4806
|
|
|
4557
|
-
if ($isElementNode(target)) {
|
|
4807
|
+
if ($isElementNode(target) && !target.isInline()) {
|
|
4558
4808
|
lastNodeInserted = node;
|
|
4559
4809
|
|
|
4560
4810
|
if ($isDecoratorNode(node) && node.isTopLevel()) {
|
|
@@ -4588,7 +4838,7 @@ class RangeSelection {
|
|
|
4588
4838
|
target = target.insertAfter(node);
|
|
4589
4839
|
}
|
|
4590
4840
|
}
|
|
4591
|
-
} else if (!$isElementNode(node) || $isDecoratorNode(target) && target.isTopLevel()) {
|
|
4841
|
+
} else if (!$isElementNode(node) || $isElementNode(node) && node.isInline() || $isDecoratorNode(target) && target.isTopLevel()) {
|
|
4592
4842
|
lastNodeInserted = node;
|
|
4593
4843
|
target = target.insertAfter(node);
|
|
4594
4844
|
} else {
|
|
@@ -4738,7 +4988,17 @@ class RangeSelection {
|
|
|
4738
4988
|
const nodesToMoveLength = nodesToMove.length;
|
|
4739
4989
|
|
|
4740
4990
|
if (anchorOffset === 0 && nodesToMoveLength > 0 && currentElement.isInline()) {
|
|
4741
|
-
currentElement.getParentOrThrow()
|
|
4991
|
+
const parent = currentElement.getParentOrThrow();
|
|
4992
|
+
const newElement = parent.insertNewAfter(this);
|
|
4993
|
+
|
|
4994
|
+
if ($isElementNode(newElement)) {
|
|
4995
|
+
const children = parent.getChildren();
|
|
4996
|
+
|
|
4997
|
+
for (let i = 0; i < children.length; i++) {
|
|
4998
|
+
newElement.append(children[i]);
|
|
4999
|
+
}
|
|
5000
|
+
}
|
|
5001
|
+
|
|
4742
5002
|
return;
|
|
4743
5003
|
}
|
|
4744
5004
|
|
|
@@ -4812,6 +5072,10 @@ class RangeSelection {
|
|
|
4812
5072
|
}
|
|
4813
5073
|
}
|
|
4814
5074
|
|
|
5075
|
+
getCharacterOffsets() {
|
|
5076
|
+
return getCharacterOffsets(this);
|
|
5077
|
+
}
|
|
5078
|
+
|
|
4815
5079
|
extract() {
|
|
4816
5080
|
const selectedNodes = this.getNodes();
|
|
4817
5081
|
const selectedNodesLength = selectedNodes.length;
|
|
@@ -4820,8 +5084,7 @@ class RangeSelection {
|
|
|
4820
5084
|
const focus = this.focus;
|
|
4821
5085
|
let firstNode = selectedNodes[0];
|
|
4822
5086
|
let lastNode = selectedNodes[lastIndex];
|
|
4823
|
-
const anchorOffset =
|
|
4824
|
-
const focusOffset = focus.getCharacterOffset();
|
|
5087
|
+
const [anchorOffset, focusOffset] = getCharacterOffsets(this);
|
|
4825
5088
|
|
|
4826
5089
|
if (selectedNodesLength === 0) {
|
|
4827
5090
|
return [];
|
|
@@ -4899,6 +5162,16 @@ class RangeSelection {
|
|
|
4899
5162
|
anchor.set(elementKey, offset, 'element');
|
|
4900
5163
|
}
|
|
4901
5164
|
|
|
5165
|
+
return;
|
|
5166
|
+
} else {
|
|
5167
|
+
const siblingKey = sibling.__key;
|
|
5168
|
+
const offset = isBackward ? sibling.getTextContent().length : 0;
|
|
5169
|
+
focus.set(siblingKey, offset, 'text');
|
|
5170
|
+
|
|
5171
|
+
if (collapse) {
|
|
5172
|
+
anchor.set(siblingKey, offset, 'text');
|
|
5173
|
+
}
|
|
5174
|
+
|
|
4902
5175
|
return;
|
|
4903
5176
|
}
|
|
4904
5177
|
}
|
|
@@ -4916,7 +5189,8 @@ class RangeSelection {
|
|
|
4916
5189
|
const range = domSelection.getRangeAt(0); // Apply the DOM selection to our Lexical selection.
|
|
4917
5190
|
// $FlowFixMe[incompatible-call]
|
|
4918
5191
|
|
|
4919
|
-
this.applyDOMRange(range);
|
|
5192
|
+
this.applyDOMRange(range);
|
|
5193
|
+
this.dirty = true; // Because a range works on start and end, we might need to flip
|
|
4920
5194
|
// the anchor and focus points to match what the DOM has, not what
|
|
4921
5195
|
// the range has specifically.
|
|
4922
5196
|
|
|
@@ -5001,6 +5275,29 @@ function $isNodeSelection(x) {
|
|
|
5001
5275
|
return x instanceof NodeSelection;
|
|
5002
5276
|
}
|
|
5003
5277
|
|
|
5278
|
+
function getCharacterOffset(point) {
|
|
5279
|
+
const offset = point.offset;
|
|
5280
|
+
|
|
5281
|
+
if (point.type === 'text') {
|
|
5282
|
+
return offset;
|
|
5283
|
+
} // $FlowFixMe: cast
|
|
5284
|
+
|
|
5285
|
+
|
|
5286
|
+
const parent = point.getNode();
|
|
5287
|
+
return offset === parent.getChildrenSize() ? parent.getTextContent().length : 0;
|
|
5288
|
+
}
|
|
5289
|
+
|
|
5290
|
+
function getCharacterOffsets(selection) {
|
|
5291
|
+
const anchor = selection.anchor;
|
|
5292
|
+
const focus = selection.focus;
|
|
5293
|
+
|
|
5294
|
+
if (anchor.type === 'element' && focus.type === 'element' && anchor.key === focus.key && anchor.offset === focus.offset) {
|
|
5295
|
+
return [0, 0];
|
|
5296
|
+
}
|
|
5297
|
+
|
|
5298
|
+
return [getCharacterOffset(anchor), getCharacterOffset(focus)];
|
|
5299
|
+
}
|
|
5300
|
+
|
|
5004
5301
|
function $swapPoints(selection) {
|
|
5005
5302
|
const focus = selection.focus;
|
|
5006
5303
|
const anchor = selection.anchor;
|
|
@@ -5009,6 +5306,7 @@ function $swapPoints(selection) {
|
|
|
5009
5306
|
const anchorType = anchor.type;
|
|
5010
5307
|
$setPointValues(anchor, focus.key, focus.offset, focus.type);
|
|
5011
5308
|
$setPointValues(focus, anchorKey, anchorOffset, anchorType);
|
|
5309
|
+
selection._cachedNodes = null;
|
|
5012
5310
|
}
|
|
5013
5311
|
|
|
5014
5312
|
function $moveNativeSelection(domSelection, alter, direction, granularity) {
|
|
@@ -5048,7 +5346,7 @@ function $updateCaretSelectionForUnicodeCharacter(selection, isBackward) {
|
|
|
5048
5346
|
function $removeSegment(node, isBackward, offset) {
|
|
5049
5347
|
const textNode = node;
|
|
5050
5348
|
const textContent = textNode.getTextContent();
|
|
5051
|
-
const split = textContent.split(
|
|
5349
|
+
const split = textContent.split(/(?=\s)/g);
|
|
5052
5350
|
const splitLength = split.length;
|
|
5053
5351
|
let segmentOffset = 0;
|
|
5054
5352
|
let restoreOffset = 0;
|
|
@@ -5070,7 +5368,7 @@ function $removeSegment(node, isBackward, offset) {
|
|
|
5070
5368
|
}
|
|
5071
5369
|
}
|
|
5072
5370
|
|
|
5073
|
-
const nextTextContent = split.join('
|
|
5371
|
+
const nextTextContent = split.join('').trim();
|
|
5074
5372
|
|
|
5075
5373
|
if (nextTextContent === '') {
|
|
5076
5374
|
textNode.remove();
|
|
@@ -5169,6 +5467,78 @@ function internalResolveSelectionPoint(dom, offset, lastPoint) {
|
|
|
5169
5467
|
return $createPoint(resolvedNode.__key, resolvedOffset, 'text');
|
|
5170
5468
|
}
|
|
5171
5469
|
|
|
5470
|
+
function resolveSelectionPointOnBoundary(point, isBackward, isCollapsed) {
|
|
5471
|
+
const offset = point.offset;
|
|
5472
|
+
const node = point.getNode();
|
|
5473
|
+
|
|
5474
|
+
if (offset === 0) {
|
|
5475
|
+
const prevSibling = node.getPreviousSibling();
|
|
5476
|
+
const parent = node.getParent();
|
|
5477
|
+
|
|
5478
|
+
if (!isBackward) {
|
|
5479
|
+
if ($isElementNode(prevSibling) && !isCollapsed && prevSibling.isInline()) {
|
|
5480
|
+
point.key = prevSibling.__key;
|
|
5481
|
+
point.offset = prevSibling.getChildrenSize(); // $FlowFixMe: intentional
|
|
5482
|
+
|
|
5483
|
+
point.type = 'element';
|
|
5484
|
+
} else if ($isTextNode(prevSibling) && !prevSibling.isInert()) {
|
|
5485
|
+
point.key = prevSibling.__key;
|
|
5486
|
+
point.offset = prevSibling.getTextContent().length;
|
|
5487
|
+
}
|
|
5488
|
+
} else if ((isCollapsed || !isBackward) && prevSibling === null && $isElementNode(parent) && parent.isInline()) {
|
|
5489
|
+
const parentSibling = parent.getPreviousSibling();
|
|
5490
|
+
|
|
5491
|
+
if ($isTextNode(parentSibling)) {
|
|
5492
|
+
point.key = parentSibling.__key;
|
|
5493
|
+
point.offset = parentSibling.getTextContent().length;
|
|
5494
|
+
}
|
|
5495
|
+
}
|
|
5496
|
+
} else if (offset === node.getTextContent().length) {
|
|
5497
|
+
const nextSibling = node.getNextSibling();
|
|
5498
|
+
const parent = node.getParent();
|
|
5499
|
+
|
|
5500
|
+
if (isBackward && $isElementNode(nextSibling) && nextSibling.isInline()) {
|
|
5501
|
+
point.key = nextSibling.__key;
|
|
5502
|
+
point.offset = 0; // $FlowFixMe: intentional
|
|
5503
|
+
|
|
5504
|
+
point.type = 'element';
|
|
5505
|
+
} else if ((isCollapsed || isBackward) && nextSibling === null && $isElementNode(parent) && parent.isInline() && !parent.canInsertTextAfter()) {
|
|
5506
|
+
const parentSibling = parent.getNextSibling();
|
|
5507
|
+
|
|
5508
|
+
if ($isTextNode(parentSibling)) {
|
|
5509
|
+
point.key = parentSibling.__key;
|
|
5510
|
+
point.offset = 0;
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
}
|
|
5514
|
+
}
|
|
5515
|
+
|
|
5516
|
+
function normalizeSelectionPointsForBoundaries(anchor, focus, lastSelection) {
|
|
5517
|
+
if (anchor.type === 'text' && focus.type === 'text') {
|
|
5518
|
+
const isBackward = anchor.isBefore(focus);
|
|
5519
|
+
const isCollapsed = anchor.is(focus); // Attempt to normalize the offset to the previous sibling if we're at the
|
|
5520
|
+
// start of a text node and the sibling is a text node or inline element.
|
|
5521
|
+
|
|
5522
|
+
resolveSelectionPointOnBoundary(anchor, isBackward, isCollapsed);
|
|
5523
|
+
resolveSelectionPointOnBoundary(focus, !isBackward, isCollapsed);
|
|
5524
|
+
|
|
5525
|
+
if (isCollapsed) {
|
|
5526
|
+
focus.key = anchor.key;
|
|
5527
|
+
focus.offset = anchor.offset;
|
|
5528
|
+
focus.type = anchor.type;
|
|
5529
|
+
}
|
|
5530
|
+
|
|
5531
|
+
const editor = getActiveEditor();
|
|
5532
|
+
|
|
5533
|
+
if (editor.isComposing() && editor._compositionKey !== anchor.key && $isRangeSelection(lastSelection)) {
|
|
5534
|
+
const lastAnchor = lastSelection.anchor;
|
|
5535
|
+
const lastFocus = lastSelection.focus;
|
|
5536
|
+
$setPointValues(anchor, lastAnchor.key, lastAnchor.offset, lastAnchor.type);
|
|
5537
|
+
$setPointValues(focus, lastFocus.key, lastFocus.offset, lastFocus.type);
|
|
5538
|
+
}
|
|
5539
|
+
}
|
|
5540
|
+
}
|
|
5541
|
+
|
|
5172
5542
|
function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focusOffset, editor, lastSelection) {
|
|
5173
5543
|
if (anchorDOM === null || focusDOM === null || !isSelectionWithinEditor(editor, anchorDOM, focusDOM)) {
|
|
5174
5544
|
return null;
|
|
@@ -5186,46 +5556,19 @@ function internalResolveSelectionPoints(anchorDOM, anchorOffset, focusDOM, focus
|
|
|
5186
5556
|
return null;
|
|
5187
5557
|
}
|
|
5188
5558
|
|
|
5189
|
-
if (resolvedAnchorPoint.type === '
|
|
5190
|
-
const
|
|
5191
|
-
const
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
const resolvedAnchorOffset = resolvedAnchorPoint.offset;
|
|
5195
|
-
const resolvedFocusOffset = resolvedFocusPoint.offset;
|
|
5196
|
-
|
|
5197
|
-
if (resolvedAnchorNode === resolvedFocusNode && resolvedAnchorOffset === resolvedFocusOffset) {
|
|
5198
|
-
if (anchorOffset === 0) {
|
|
5199
|
-
const prevSibling = resolvedAnchorNode.getPreviousSibling();
|
|
5200
|
-
|
|
5201
|
-
if ($isTextNode(prevSibling) && !prevSibling.isInert()) {
|
|
5202
|
-
const offset = prevSibling.getTextContentSize();
|
|
5203
|
-
const key = prevSibling.__key;
|
|
5204
|
-
resolvedAnchorPoint.key = key;
|
|
5205
|
-
resolvedFocusPoint.key = key;
|
|
5206
|
-
resolvedAnchorPoint.offset = offset;
|
|
5207
|
-
resolvedFocusPoint.offset = offset;
|
|
5208
|
-
}
|
|
5209
|
-
}
|
|
5210
|
-
} else {
|
|
5211
|
-
if (resolvedAnchorOffset === textContentSize) {
|
|
5212
|
-
const nextSibling = resolvedAnchorNode.getNextSibling();
|
|
5559
|
+
if (resolvedAnchorPoint.type === 'element' && resolvedFocusPoint.type === 'element') {
|
|
5560
|
+
const anchorNode = getNodeFromDOM(anchorDOM);
|
|
5561
|
+
const focusNode = getNodeFromDOM(focusDOM); // Ensure if we're selecting the content of a decorator that we
|
|
5562
|
+
// return null for this point, as it's not in the controlled scope
|
|
5563
|
+
// of Lexical.
|
|
5213
5564
|
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
resolvedAnchorPoint.offset = 0;
|
|
5217
|
-
}
|
|
5218
|
-
}
|
|
5565
|
+
if ($isDecoratorNode(anchorNode) && $isDecoratorNode(focusNode)) {
|
|
5566
|
+
return null;
|
|
5219
5567
|
}
|
|
5568
|
+
} // Handle normalization of selection when it is at the boundaries.
|
|
5220
5569
|
|
|
5221
|
-
if (editor.isComposing() && editor._compositionKey !== resolvedAnchorPoint.key && $isRangeSelection(lastSelection)) {
|
|
5222
|
-
const lastAnchor = lastSelection.anchor;
|
|
5223
|
-
const lastFocus = lastSelection.focus;
|
|
5224
|
-
$setPointValues(resolvedAnchorPoint, lastAnchor.key, lastAnchor.offset, lastAnchor.type);
|
|
5225
|
-
$setPointValues(resolvedFocusPoint, lastFocus.key, lastFocus.offset, lastFocus.type);
|
|
5226
|
-
}
|
|
5227
|
-
}
|
|
5228
5570
|
|
|
5571
|
+
normalizeSelectionPointsForBoundaries(resolvedAnchorPoint, resolvedFocusPoint, lastSelection);
|
|
5229
5572
|
return [resolvedAnchorPoint, resolvedFocusPoint];
|
|
5230
5573
|
} // This is used to make a selection when the existing
|
|
5231
5574
|
// selection is null, i.e. forcing selection on the editor
|
|
@@ -5248,7 +5591,9 @@ function $createEmptyObjectSelection() {
|
|
|
5248
5591
|
return new NodeSelection(new Set());
|
|
5249
5592
|
}
|
|
5250
5593
|
function $createEmptyGridSelection() {
|
|
5251
|
-
|
|
5594
|
+
const anchor = $createPoint('root', 0, 'element');
|
|
5595
|
+
const focus = $createPoint('root', 0, 'element');
|
|
5596
|
+
return new GridSelection('root', anchor, focus);
|
|
5252
5597
|
}
|
|
5253
5598
|
|
|
5254
5599
|
function getActiveEventType() {
|
|
@@ -5327,7 +5672,7 @@ function internalCreateSelectionFromParse(parsedSelection) {
|
|
|
5327
5672
|
} else if (parsedSelection.type === 'node') {
|
|
5328
5673
|
return new NodeSelection(new Set(parsedSelection.nodes));
|
|
5329
5674
|
} else if (parsedSelection.type === 'grid') {
|
|
5330
|
-
return new GridSelection(parsedSelection.gridKey, parsedSelection.
|
|
5675
|
+
return new GridSelection(parsedSelection.gridKey, $createPoint(parsedSelection.anchor.key, parsedSelection.anchor.offset, parsedSelection.anchor.type), $createPoint(parsedSelection.focus.key, parsedSelection.focus.offset, parsedSelection.focus.type));
|
|
5331
5676
|
}
|
|
5332
5677
|
}
|
|
5333
5678
|
|
|
@@ -5669,8 +6014,7 @@ class LexicalNode {
|
|
|
5669
6014
|
return false;
|
|
5670
6015
|
}
|
|
5671
6016
|
|
|
5672
|
-
const
|
|
5673
|
-
const isSelected = selectedNodeKeys.has(this.__key);
|
|
6017
|
+
const isSelected = selection.getNodes().some(n => n.__key === this.__key);
|
|
5674
6018
|
|
|
5675
6019
|
if ($isTextNode(this)) {
|
|
5676
6020
|
return isSelected;
|
|
@@ -6024,11 +6368,6 @@ class LexicalNode {
|
|
|
6024
6368
|
const editor = getActiveEditor();
|
|
6025
6369
|
const dirtyLeaves = editor._dirtyLeaves;
|
|
6026
6370
|
return dirtyLeaves !== null && dirtyLeaves.has(this.__key);
|
|
6027
|
-
} // TODO remove this and move to TextNode
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
isComposing() {
|
|
6031
|
-
return this.__key === $getCompositionKey();
|
|
6032
6371
|
}
|
|
6033
6372
|
|
|
6034
6373
|
getLatest() {
|
|
@@ -6054,6 +6393,11 @@ class LexicalNode {
|
|
|
6054
6393
|
const latestNode = this.getLatest();
|
|
6055
6394
|
const parent = latestNode.__parent;
|
|
6056
6395
|
const cloneNotNeeded = editor._cloneNotNeeded;
|
|
6396
|
+
const selection = $getSelection();
|
|
6397
|
+
|
|
6398
|
+
if (selection !== null) {
|
|
6399
|
+
selection._cachedNodes = null;
|
|
6400
|
+
}
|
|
6057
6401
|
|
|
6058
6402
|
if (cloneNotNeeded.has(key)) {
|
|
6059
6403
|
// Transforms clear the dirty node set on each iteration to keep track on newly dirty nodes
|
|
@@ -6084,34 +6428,29 @@ class LexicalNode {
|
|
|
6084
6428
|
nodeMap.set(key, mutableNode); // $FlowFixMe this is LexicalNode
|
|
6085
6429
|
|
|
6086
6430
|
return mutableNode;
|
|
6087
|
-
}
|
|
6088
|
-
|
|
6431
|
+
}
|
|
6089
6432
|
|
|
6090
6433
|
getTextContent(includeInert, includeDirectionless) {
|
|
6091
6434
|
return '';
|
|
6092
|
-
}
|
|
6093
|
-
|
|
6435
|
+
}
|
|
6094
6436
|
|
|
6095
6437
|
getTextContentSize(includeInert, includeDirectionless) {
|
|
6096
6438
|
return this.getTextContent(includeInert, includeDirectionless).length;
|
|
6097
6439
|
} // View
|
|
6098
|
-
// $FlowFixMe: Revise typings for EditorContext
|
|
6099
6440
|
|
|
6100
6441
|
|
|
6101
6442
|
createDOM(config, editor) {
|
|
6102
6443
|
{
|
|
6103
6444
|
throw Error(`createDOM: base method not extended`);
|
|
6104
6445
|
}
|
|
6105
|
-
}
|
|
6106
|
-
|
|
6446
|
+
}
|
|
6107
6447
|
|
|
6108
6448
|
updateDOM( // $FlowFixMe: TODO
|
|
6109
6449
|
prevNode, dom, config) {
|
|
6110
6450
|
{
|
|
6111
6451
|
throw Error(`updateDOM: base method not extended`);
|
|
6112
6452
|
}
|
|
6113
|
-
}
|
|
6114
|
-
|
|
6453
|
+
}
|
|
6115
6454
|
|
|
6116
6455
|
exportDOM(editor) {
|
|
6117
6456
|
if ($isDecoratorNode(this)) {
|
|
@@ -6428,6 +6767,12 @@ class ElementNode extends LexicalNode {
|
|
|
6428
6767
|
return dirtyElements !== null && dirtyElements.has(this.__key);
|
|
6429
6768
|
}
|
|
6430
6769
|
|
|
6770
|
+
isLastChild() {
|
|
6771
|
+
const self = this.getLatest();
|
|
6772
|
+
const parent = self.getParentOrThrow();
|
|
6773
|
+
return parent.getLastChild() === self;
|
|
6774
|
+
}
|
|
6775
|
+
|
|
6431
6776
|
getAllTextNodes(includeInert) {
|
|
6432
6777
|
const textNodes = [];
|
|
6433
6778
|
const self = this.getLatest();
|
|
@@ -6562,7 +6907,7 @@ class ElementNode extends LexicalNode {
|
|
|
6562
6907
|
textContent += child.getTextContent(includeInert, includeDirectionless);
|
|
6563
6908
|
|
|
6564
6909
|
if ($isElementNode(child) && i !== childrenLength - 1 && !child.isInline()) {
|
|
6565
|
-
textContent +=
|
|
6910
|
+
textContent += DOUBLE_LINE_BREAK;
|
|
6566
6911
|
}
|
|
6567
6912
|
}
|
|
6568
6913
|
|
|
@@ -6791,6 +7136,10 @@ class ElementNode extends LexicalNode {
|
|
|
6791
7136
|
return false;
|
|
6792
7137
|
}
|
|
6793
7138
|
|
|
7139
|
+
canIndent() {
|
|
7140
|
+
return true;
|
|
7141
|
+
}
|
|
7142
|
+
|
|
6794
7143
|
collapseAtStart(selection) {
|
|
6795
7144
|
return false;
|
|
6796
7145
|
}
|
|
@@ -6831,6 +7180,10 @@ class ElementNode extends LexicalNode {
|
|
|
6831
7180
|
return false;
|
|
6832
7181
|
}
|
|
6833
7182
|
|
|
7183
|
+
extractWithChild(child, selection, destination) {
|
|
7184
|
+
return false;
|
|
7185
|
+
}
|
|
7186
|
+
|
|
6834
7187
|
}
|
|
6835
7188
|
function $isElementNode(node) {
|
|
6836
7189
|
return node instanceof ElementNode;
|
|
@@ -7011,8 +7364,16 @@ class EditorState {
|
|
|
7011
7364
|
nodes: Array.from(selection._nodes),
|
|
7012
7365
|
type: 'node'
|
|
7013
7366
|
} : $isGridSelection(selection) ? {
|
|
7014
|
-
|
|
7015
|
-
|
|
7367
|
+
anchor: {
|
|
7368
|
+
key: selection.anchor.key,
|
|
7369
|
+
offset: selection.anchor.offset,
|
|
7370
|
+
type: selection.anchor.type
|
|
7371
|
+
},
|
|
7372
|
+
focus: {
|
|
7373
|
+
key: selection.focus.key,
|
|
7374
|
+
offset: selection.focus.offset,
|
|
7375
|
+
type: selection.focus.type
|
|
7376
|
+
},
|
|
7016
7377
|
gridKey: selection.gridKey,
|
|
7017
7378
|
type: 'grid'
|
|
7018
7379
|
} : null
|
|
@@ -7259,6 +7620,10 @@ class TextNode extends LexicalNode {
|
|
|
7259
7620
|
return self.__mode === IS_TOKEN;
|
|
7260
7621
|
}
|
|
7261
7622
|
|
|
7623
|
+
isComposing() {
|
|
7624
|
+
return this.__key === $getCompositionKey();
|
|
7625
|
+
}
|
|
7626
|
+
|
|
7262
7627
|
isSegmented() {
|
|
7263
7628
|
const self = this.getLatest();
|
|
7264
7629
|
return self.__mode === IS_SEGMENTED;
|
|
@@ -7302,7 +7667,6 @@ class TextNode extends LexicalNode {
|
|
|
7302
7667
|
const format = self.__format;
|
|
7303
7668
|
return toggleTextFormatType(format, type, alignWithFormat);
|
|
7304
7669
|
} // View
|
|
7305
|
-
// $FlowFixMe: Revise typings for EditorContext
|
|
7306
7670
|
|
|
7307
7671
|
|
|
7308
7672
|
createDOM(config) {
|
|
@@ -7327,8 +7691,7 @@ class TextNode extends LexicalNode {
|
|
|
7327
7691
|
}
|
|
7328
7692
|
|
|
7329
7693
|
return dom;
|
|
7330
|
-
}
|
|
7331
|
-
|
|
7694
|
+
}
|
|
7332
7695
|
|
|
7333
7696
|
updateDOM(prevNode, dom, config) {
|
|
7334
7697
|
const nextText = this.__text;
|
|
@@ -7540,7 +7903,8 @@ class TextNode extends LexicalNode {
|
|
|
7540
7903
|
}
|
|
7541
7904
|
|
|
7542
7905
|
const updatedText = text.slice(0, index) + newText + text.slice(index + delCount);
|
|
7543
|
-
|
|
7906
|
+
writableSelf.__text = updatedText;
|
|
7907
|
+
return writableSelf;
|
|
7544
7908
|
}
|
|
7545
7909
|
|
|
7546
7910
|
canInsertTextBefore() {
|
|
@@ -7705,10 +8069,12 @@ class TextNode extends LexicalNode {
|
|
|
7705
8069
|
}
|
|
7706
8070
|
}
|
|
7707
8071
|
|
|
7708
|
-
const
|
|
8072
|
+
const targetText = target.__text;
|
|
8073
|
+
const newText = isBefore ? targetText + text : text + targetText;
|
|
7709
8074
|
this.setTextContent(newText);
|
|
8075
|
+
const writableSelf = this.getWritable();
|
|
7710
8076
|
target.remove();
|
|
7711
|
-
return
|
|
8077
|
+
return writableSelf;
|
|
7712
8078
|
}
|
|
7713
8079
|
|
|
7714
8080
|
isTextEntity() {
|
|
@@ -7982,7 +8348,6 @@ function createEditor(editorConfig) {
|
|
|
7982
8348
|
const config = editorConfig || {};
|
|
7983
8349
|
const namespace = config.namespace || createUID();
|
|
7984
8350
|
const theme = config.theme || {};
|
|
7985
|
-
const context = config.context || {};
|
|
7986
8351
|
const parentEditor = config.parentEditor || null;
|
|
7987
8352
|
const disableEvents = config.disableEvents || false;
|
|
7988
8353
|
const editorState = createEmptyEditorState();
|
|
@@ -8004,8 +8369,6 @@ function createEditor(editorConfig) {
|
|
|
8004
8369
|
|
|
8005
8370
|
|
|
8006
8371
|
const editor = new LexicalEditor(editorState, parentEditor, registeredNodes, {
|
|
8007
|
-
// $FlowFixMe: we use our internal type to simpify the generics
|
|
8008
|
-
context,
|
|
8009
8372
|
disableEvents,
|
|
8010
8373
|
namespace,
|
|
8011
8374
|
theme
|
|
@@ -8066,6 +8429,7 @@ class LexicalEditor {
|
|
|
8066
8429
|
this._onError = onError;
|
|
8067
8430
|
this._htmlConversions = htmlConversions;
|
|
8068
8431
|
this._readOnly = false;
|
|
8432
|
+
this._headless = false;
|
|
8069
8433
|
}
|
|
8070
8434
|
|
|
8071
8435
|
isComposing() {
|
|
@@ -8288,8 +8652,8 @@ class LexicalEditor {
|
|
|
8288
8652
|
commitPendingUpdates(this);
|
|
8289
8653
|
}
|
|
8290
8654
|
|
|
8291
|
-
parseEditorState(
|
|
8292
|
-
const parsedEditorState = JSON.parse(
|
|
8655
|
+
parseEditorState(maybeStringifiedEditorState) {
|
|
8656
|
+
const parsedEditorState = typeof maybeStringifiedEditorState === 'string' ? JSON.parse(maybeStringifiedEditorState) : maybeStringifiedEditorState;
|
|
8293
8657
|
return parseEditorState(parsedEditorState, this);
|
|
8294
8658
|
}
|
|
8295
8659
|
|
|
@@ -8364,7 +8728,7 @@ class LexicalEditor {
|
|
|
8364
8728
|
*
|
|
8365
8729
|
*
|
|
8366
8730
|
*/
|
|
8367
|
-
const VERSION = '0.2.
|
|
8731
|
+
const VERSION = '0.2.7';
|
|
8368
8732
|
|
|
8369
8733
|
/**
|
|
8370
8734
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -8455,6 +8819,7 @@ exports.CUT_COMMAND = CUT_COMMAND;
|
|
|
8455
8819
|
exports.DELETE_CHARACTER_COMMAND = DELETE_CHARACTER_COMMAND;
|
|
8456
8820
|
exports.DELETE_LINE_COMMAND = DELETE_LINE_COMMAND;
|
|
8457
8821
|
exports.DELETE_WORD_COMMAND = DELETE_WORD_COMMAND;
|
|
8822
|
+
exports.DRAGEND_COMMAND = DRAGEND_COMMAND;
|
|
8458
8823
|
exports.DRAGSTART_COMMAND = DRAGSTART_COMMAND;
|
|
8459
8824
|
exports.DROP_COMMAND = DROP_COMMAND;
|
|
8460
8825
|
exports.DecoratorNode = DecoratorNode;
|
|
@@ -8478,7 +8843,9 @@ exports.KEY_DELETE_COMMAND = KEY_DELETE_COMMAND;
|
|
|
8478
8843
|
exports.KEY_ENTER_COMMAND = KEY_ENTER_COMMAND;
|
|
8479
8844
|
exports.KEY_ESCAPE_COMMAND = KEY_ESCAPE_COMMAND;
|
|
8480
8845
|
exports.KEY_MODIFIER_COMMAND = KEY_MODIFIER_COMMAND;
|
|
8846
|
+
exports.KEY_SPACE_COMMAND = KEY_SPACE_COMMAND;
|
|
8481
8847
|
exports.KEY_TAB_COMMAND = KEY_TAB_COMMAND;
|
|
8848
|
+
exports.LineBreakNode = LineBreakNode;
|
|
8482
8849
|
exports.OUTDENT_CONTENT_COMMAND = OUTDENT_CONTENT_COMMAND;
|
|
8483
8850
|
exports.PASTE_COMMAND = PASTE_COMMAND;
|
|
8484
8851
|
exports.ParagraphNode = ParagraphNode;
|