roosterjs 9.1.0 → 9.3.0

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/dist/rooster.js CHANGED
@@ -2095,7 +2095,7 @@ exports["default"] = getDarkColor;
2095
2095
 
2096
2096
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2097
2097
  exports.formatTextSegmentBeforeSelectionMarker = exports.formatSegmentWithContentModel = exports.formatParagraphWithContentModel = exports.formatImageWithContentModel = exports.formatTableWithContentModel = exports.clearSelectedCells = exports.insertTableColumn = exports.insertTableRow = exports.insertEntity = exports.toggleCode = exports.setParagraphMargin = exports.adjustImageSelection = exports.setImageAltText = exports.adjustLinkSelection = exports.removeLink = exports.insertLink = exports.clearFormat = exports.getFormatState = exports.changeImage = exports.setImageBoxShadow = exports.setImageBorder = exports.setSpacing = exports.toggleBlockQuote = exports.setHeadingLevel = exports.setDirection = exports.setAlignment = exports.setIndentation = exports.setListStartNumber = exports.setListStyle = exports.insertImage = exports.changeCapitalization = exports.applySegmentFormat = exports.changeFontSize = exports.setTextColor = exports.setFontSize = exports.setFontName = exports.setBackgroundColor = exports.toggleSuperscript = exports.toggleSubscript = exports.toggleStrikethrough = exports.toggleUnderline = exports.toggleItalic = exports.toggleBold = exports.toggleNumbering = exports.toggleBullet = exports.applyTableBorderFormat = exports.editTable = exports.setTableCellShade = exports.formatTable = exports.insertTable = void 0;
2098
- exports.matchLink = exports.setModelIndentation = exports.findListItemsInSameThread = exports.setModelListStartNumber = exports.setModelListStyle = exports.setListType = void 0;
2098
+ exports.getListAnnounceData = exports.matchLink = exports.setModelIndentation = exports.findListItemsInSameThread = exports.setModelListStartNumber = exports.setModelListStyle = exports.setListType = exports.formatInsertPointWithContentModel = void 0;
2099
2099
  var insertTable_1 = __webpack_require__(/*! ./publicApi/table/insertTable */ "./packages/roosterjs-content-model-api/lib/publicApi/table/insertTable.ts");
2100
2100
  Object.defineProperty(exports, "insertTable", ({ enumerable: true, get: function () { return insertTable_1.insertTable; } }));
2101
2101
  var formatTable_1 = __webpack_require__(/*! ./publicApi/table/formatTable */ "./packages/roosterjs-content-model-api/lib/publicApi/table/formatTable.ts");
@@ -2196,6 +2196,8 @@ var formatSegmentWithContentModel_1 = __webpack_require__(/*! ./publicApi/utils/
2196
2196
  Object.defineProperty(exports, "formatSegmentWithContentModel", ({ enumerable: true, get: function () { return formatSegmentWithContentModel_1.formatSegmentWithContentModel; } }));
2197
2197
  var formatTextSegmentBeforeSelectionMarker_1 = __webpack_require__(/*! ./publicApi/utils/formatTextSegmentBeforeSelectionMarker */ "./packages/roosterjs-content-model-api/lib/publicApi/utils/formatTextSegmentBeforeSelectionMarker.ts");
2198
2198
  Object.defineProperty(exports, "formatTextSegmentBeforeSelectionMarker", ({ enumerable: true, get: function () { return formatTextSegmentBeforeSelectionMarker_1.formatTextSegmentBeforeSelectionMarker; } }));
2199
+ var formatInsertPointWithContentModel_1 = __webpack_require__(/*! ./publicApi/utils/formatInsertPointWithContentModel */ "./packages/roosterjs-content-model-api/lib/publicApi/utils/formatInsertPointWithContentModel.ts");
2200
+ Object.defineProperty(exports, "formatInsertPointWithContentModel", ({ enumerable: true, get: function () { return formatInsertPointWithContentModel_1.formatInsertPointWithContentModel; } }));
2199
2201
  var setListType_1 = __webpack_require__(/*! ./modelApi/list/setListType */ "./packages/roosterjs-content-model-api/lib/modelApi/list/setListType.ts");
2200
2202
  Object.defineProperty(exports, "setListType", ({ enumerable: true, get: function () { return setListType_1.setListType; } }));
2201
2203
  var setModelListStyle_1 = __webpack_require__(/*! ./modelApi/list/setModelListStyle */ "./packages/roosterjs-content-model-api/lib/modelApi/list/setModelListStyle.ts");
@@ -2208,6 +2210,8 @@ var setModelIndentation_1 = __webpack_require__(/*! ./modelApi/block/setModelInd
2208
2210
  Object.defineProperty(exports, "setModelIndentation", ({ enumerable: true, get: function () { return setModelIndentation_1.setModelIndentation; } }));
2209
2211
  var matchLink_1 = __webpack_require__(/*! ./modelApi/link/matchLink */ "./packages/roosterjs-content-model-api/lib/modelApi/link/matchLink.ts");
2210
2212
  Object.defineProperty(exports, "matchLink", ({ enumerable: true, get: function () { return matchLink_1.matchLink; } }));
2213
+ var getListAnnounceData_1 = __webpack_require__(/*! ./modelApi/list/getListAnnounceData */ "./packages/roosterjs-content-model-api/lib/modelApi/list/getListAnnounceData.ts");
2214
+ Object.defineProperty(exports, "getListAnnounceData", ({ enumerable: true, get: function () { return getListAnnounceData_1.getListAnnounceData; } }));
2211
2215
 
2212
2216
 
2213
2217
  /***/ }),
@@ -2374,7 +2378,9 @@ function setProperty(format, key, value) {
2374
2378
 
2375
2379
  Object.defineProperty(exports, "__esModule", ({ value: true }));
2376
2380
  exports.setModelIndentation = void 0;
2381
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
2377
2382
  var findListItemsInSameThread_1 = __webpack_require__(/*! ../list/findListItemsInSameThread */ "./packages/roosterjs-content-model-api/lib/modelApi/list/findListItemsInSameThread.ts");
2383
+ var getListAnnounceData_1 = __webpack_require__(/*! ../list/getListAnnounceData */ "./packages/roosterjs-content-model-api/lib/modelApi/list/getListAnnounceData.ts");
2378
2384
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
2379
2385
  var IndentStepInPixel = 40;
2380
2386
  /**
@@ -2383,7 +2389,7 @@ var IndentStepInPixel = 40;
2383
2389
  * @param length The length of indentation in pixel, default value is 40
2384
2390
  * Set indentation for selected list items or paragraphs
2385
2391
  */
2386
- function setModelIndentation(model, indentation, length) {
2392
+ function setModelIndentation(model, indentation, length, context) {
2387
2393
  if (length === void 0) { length = IndentStepInPixel; }
2388
2394
  var paragraphOrListItem = (0, roosterjs_content_model_dom_1.getOperationalBlocks)(model, ['ListItem'], ['TableCell']);
2389
2395
  var isIndent = indentation == 'indent';
@@ -2430,6 +2436,9 @@ function setModelIndentation(model, indentation, length) {
2430
2436
  else {
2431
2437
  block.levels.pop();
2432
2438
  }
2439
+ if (block.levels.length > 0 && context) {
2440
+ context.announceData = (0, getListAnnounceData_1.getListAnnounceData)((0, tslib_1.__spreadArray)([block], (0, tslib_1.__read)(path), false));
2441
+ }
2433
2442
  }
2434
2443
  }
2435
2444
  else if (block) {
@@ -3130,9 +3139,9 @@ exports.findListItemsInSameThread = void 0;
3130
3139
  * @param currentItem The current list item
3131
3140
  * Search for all list items in the same thread as the current list item
3132
3141
  */
3133
- function findListItemsInSameThread(model, currentItem) {
3142
+ function findListItemsInSameThread(group, currentItem) {
3134
3143
  var items = [];
3135
- findListItems(model, items);
3144
+ findListItems(group, items);
3136
3145
  return filterListItems(items, currentItem);
3137
3146
  }
3138
3147
  exports.findListItemsInSameThread = findListItemsInSameThread;
@@ -3200,7 +3209,9 @@ function filterListItems(items, currentItem) {
3200
3209
  break;
3201
3210
  }
3202
3211
  }
3203
- else if (!isOrderedList || startNumberOverride) {
3212
+ else if (!isOrderedList ||
3213
+ startNumberOverride ||
3214
+ item.levels.length < currentItem.levels.length) {
3204
3215
  break;
3205
3216
  }
3206
3217
  }
@@ -3218,7 +3229,9 @@ function filterListItems(items, currentItem) {
3218
3229
  if (areListTypesCompatible(items, currentIndex, i) && !startNumberOverride) {
3219
3230
  result.push(item);
3220
3231
  }
3221
- else if (!isOrderedList || startNumberOverride) {
3232
+ else if (!isOrderedList ||
3233
+ startNumberOverride ||
3234
+ item.levels.length < currentItem.levels.length) {
3222
3235
  break;
3223
3236
  }
3224
3237
  }
@@ -3238,6 +3251,85 @@ function hasStartNumberOverride(item, levelLength) {
3238
3251
  }
3239
3252
 
3240
3253
 
3254
+ /***/ }),
3255
+
3256
+ /***/ "./packages/roosterjs-content-model-api/lib/modelApi/list/getListAnnounceData.ts":
3257
+ /*!***************************************************************************************!*\
3258
+ !*** ./packages/roosterjs-content-model-api/lib/modelApi/list/getListAnnounceData.ts ***!
3259
+ \***************************************************************************************/
3260
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
3261
+
3262
+ "use strict";
3263
+
3264
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
3265
+ exports.getListAnnounceData = void 0;
3266
+ var findListItemsInSameThread_1 = __webpack_require__(/*! ./findListItemsInSameThread */ "./packages/roosterjs-content-model-api/lib/modelApi/list/findListItemsInSameThread.ts");
3267
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
3268
+ /**
3269
+ * Get announce data for list item
3270
+ * @param path Content model path that include the list item
3271
+ * @returns Announce data of current list item if any, or null
3272
+ */
3273
+ function getListAnnounceData(path) {
3274
+ var index = (0, roosterjs_content_model_dom_1.getClosestAncestorBlockGroupIndex)(path, ['ListItem'], ['TableCell']);
3275
+ if (index >= 0) {
3276
+ var listItem = path[index];
3277
+ var level = listItem.levels[listItem.levels.length - 1];
3278
+ if (level.format.displayForDummyItem) {
3279
+ return null;
3280
+ }
3281
+ else if (level.listType == 'OL') {
3282
+ var listNumber = getListNumber(path, listItem);
3283
+ var metadata = (0, roosterjs_content_model_dom_1.updateListMetadata)(level);
3284
+ var listStyle = (0, roosterjs_content_model_dom_1.getAutoListStyleType)('OL', metadata !== null && metadata !== void 0 ? metadata : {}, listItem.levels.length - 1, level.format.listStyleType);
3285
+ return listStyle === undefined
3286
+ ? null
3287
+ : {
3288
+ defaultStrings: 'announceListItemNumbering',
3289
+ formatStrings: [(0, roosterjs_content_model_dom_1.getOrderedListNumberStr)(listStyle, listNumber)],
3290
+ };
3291
+ }
3292
+ else {
3293
+ return {
3294
+ defaultStrings: 'announceListItemBullet',
3295
+ };
3296
+ }
3297
+ }
3298
+ else {
3299
+ return null;
3300
+ }
3301
+ }
3302
+ exports.getListAnnounceData = getListAnnounceData;
3303
+ function getListNumber(path, listItem) {
3304
+ var _a, _b;
3305
+ var items = (0, findListItemsInSameThread_1.findListItemsInSameThread)(path[path.length - 1], listItem);
3306
+ var listNumber = 0;
3307
+ for (var i = 0; i < items.length; i++) {
3308
+ var item = items[i];
3309
+ if (listNumber == 0 && item.levels.length == listItem.levels.length) {
3310
+ listNumber = (_b = (_a = item.levels[item.levels.length - 1]) === null || _a === void 0 ? void 0 : _a.format.startNumberOverride) !== null && _b !== void 0 ? _b : 1;
3311
+ }
3312
+ if (item == listItem) {
3313
+ // Found current item, so break and return
3314
+ break;
3315
+ }
3316
+ else if (item.levels.length < listItem.levels.length) {
3317
+ // Found upper level item, reset list number
3318
+ listNumber = 0;
3319
+ }
3320
+ else if (item.levels.length > listItem.levels.length) {
3321
+ // Found deeper level item, skip
3322
+ continue;
3323
+ }
3324
+ else if (!item.levels[item.levels.length - 1].format.displayForDummyItem) {
3325
+ // Save level, and is not dummy, number plus one
3326
+ listNumber++;
3327
+ }
3328
+ }
3329
+ return listNumber;
3330
+ }
3331
+
3332
+
3241
3333
  /***/ }),
3242
3334
 
3243
3335
  /***/ "./packages/roosterjs-content-model-api/lib/modelApi/list/setListType.ts":
@@ -4992,6 +5084,8 @@ function insertImageWithSrc(editor, src) {
4992
5084
  (0, roosterjs_content_model_dom_1.mergeModel)(model, doc, context, {
4993
5085
  mergeFormat: 'mergeAll',
4994
5086
  });
5087
+ image.isSelected = true;
5088
+ (0, roosterjs_content_model_dom_1.setSelection)(model, image);
4995
5089
  return true;
4996
5090
  }, {
4997
5091
  apiName: 'insertImage',
@@ -6304,6 +6398,7 @@ var alignTableCell_1 = __webpack_require__(/*! ../../modelApi/table/alignTableCe
6304
6398
  */
6305
6399
  function editTable(editor, operation) {
6306
6400
  editor.focus();
6401
+ fixUpSafariSelection(editor);
6307
6402
  (0, formatTableWithContentModel_1.formatTableWithContentModel)(editor, 'editTable', function (tableModel) {
6308
6403
  switch (operation) {
6309
6404
  case 'alignCellLeft':
@@ -6359,6 +6454,22 @@ function editTable(editor, operation) {
6359
6454
  });
6360
6455
  }
6361
6456
  exports.editTable = editTable;
6457
+ // In safari, when open context menu under a table, it may expand the range selection to the beginning of next table cell.
6458
+ // So we make a workaround here to collapse the selection when need, to avoid unexpected table editing behavior
6459
+ // (e.g. insert two columns but actually need one only)
6460
+ function fixUpSafariSelection(editor) {
6461
+ if (editor.getEnvironment().isSafari) {
6462
+ var selection = editor.getDOMSelection();
6463
+ if ((selection === null || selection === void 0 ? void 0 : selection.type) == 'range' && !selection.range.collapsed) {
6464
+ selection.range.collapse(true /*toStart*/);
6465
+ editor.setDOMSelection({
6466
+ type: 'range',
6467
+ range: selection.range,
6468
+ isReverted: false,
6469
+ });
6470
+ }
6471
+ }
6472
+ }
6362
6473
 
6363
6474
 
6364
6475
  /***/ }),
@@ -6555,7 +6666,11 @@ exports.formatInsertPointWithContentModel = void 0;
6555
6666
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
6556
6667
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
6557
6668
  /**
6558
- * @internal
6669
+ * Format content model at a given insert point with a callback function
6670
+ * @param editor The editor object
6671
+ * @param insertPoint The insert point to format
6672
+ * @param callback The callback function to format the content model
6673
+ * @param options Options to control the behavior of the formatting
6559
6674
  */
6560
6675
  function formatInsertPointWithContentModel(editor, insertPoint, callback, options) {
6561
6676
  var bundle = {
@@ -6740,7 +6855,8 @@ function formatSegmentWithContentModel(editor, apiName, toggleStyleCallback, seg
6740
6855
  segmentAndParagraphs[0][0].segmentType == 'SelectionMarker';
6741
6856
  if (isCollapsedSelection) {
6742
6857
  var para_1 = segmentAndParagraphs[0][1];
6743
- segmentAndParagraphs = (0, adjustWordSelection_1.adjustWordSelection)(model, segmentAndParagraphs[0][0]).map(function (x) { return [x, para_1]; });
6858
+ var path_1 = segmentAndParagraphs[0][2];
6859
+ segmentAndParagraphs = (0, adjustWordSelection_1.adjustWordSelection)(model, segmentAndParagraphs[0][0]).map(function (x) { return [x, para_1, path_1]; });
6744
6860
  if (segmentAndParagraphs.length > 1) {
6745
6861
  isCollapsedSelection = false;
6746
6862
  }
@@ -6842,8 +6958,10 @@ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-mo
6842
6958
  * Invoke a callback to format the text segment before the selection marker using Content Model
6843
6959
  * @param editor The editor object
6844
6960
  * @param callback The callback to format the text segment.
6961
+ * @returns True if the segment before cursor is found and callback is called, otherwise false
6845
6962
  */
6846
- function formatTextSegmentBeforeSelectionMarker(editor, callback) {
6963
+ function formatTextSegmentBeforeSelectionMarker(editor, callback, options) {
6964
+ var result = false;
6847
6965
  editor.formatContentModel(function (model, context) {
6848
6966
  var selectedSegmentsAndParagraphs = (0, roosterjs_content_model_dom_1.getSelectedSegmentsAndParagraphs)(model, false /*includeFormatHolder*/);
6849
6967
  if (selectedSegmentsAndParagraphs.length > 0 && selectedSegmentsAndParagraphs[0][1]) {
@@ -6853,12 +6971,14 @@ function formatTextSegmentBeforeSelectionMarker(editor, callback) {
6853
6971
  if (marker.segmentType === 'SelectionMarker' && markerIndex > 0) {
6854
6972
  var previousSegment = paragraph.segments[markerIndex - 1];
6855
6973
  if (previousSegment && previousSegment.segmentType === 'Text') {
6974
+ result = true;
6856
6975
  return callback(model, previousSegment, paragraph, marker.format, context);
6857
6976
  }
6858
6977
  }
6859
6978
  }
6860
6979
  return false;
6861
- });
6980
+ }, options);
6981
+ return result;
6862
6982
  }
6863
6983
  exports.formatTextSegmentBeforeSelectionMarker = formatTextSegmentBeforeSelectionMarker;
6864
6984
 
@@ -7417,16 +7537,7 @@ function isCssVariable(value) {
7417
7537
  Object.defineProperty(exports, "__esModule", ({ value: true }));
7418
7538
  exports.exportContent = void 0;
7419
7539
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
7420
- /**
7421
- * Export string content of editor
7422
- * @param editor The editor to get content from
7423
- * @param mode Mode of content to export. It supports:
7424
- * - HTML: Export HTML content. If there are entities, this will cause EntityOperation event with option = 'replaceTemporaryContent' to get a dehydrated entity
7425
- * - PlainText: Export plain text content
7426
- * - PlainTextFast: Export plain text using editor's textContent property directly
7427
- * @param options @optional Options for Model to DOM conversion
7428
- */
7429
- function exportContent(editor, mode, options) {
7540
+ function exportContent(editor, mode, optionsOrCallbacks) {
7430
7541
  if (mode === void 0) { mode = 'HTML'; }
7431
7542
  if (mode == 'PlainTextFast') {
7432
7543
  return editor.getDOMHelper().getTextContent();
@@ -7434,12 +7545,12 @@ function exportContent(editor, mode, options) {
7434
7545
  else {
7435
7546
  var model = editor.getContentModelCopy('clean');
7436
7547
  if (mode == 'PlainText') {
7437
- return (0, roosterjs_content_model_dom_1.contentModelToText)(model);
7548
+ return (0, roosterjs_content_model_dom_1.contentModelToText)(model, undefined /*separator*/, optionsOrCallbacks);
7438
7549
  }
7439
7550
  else {
7440
7551
  var doc = editor.getDocument();
7441
7552
  var div = doc.createElement('div');
7442
- (0, roosterjs_content_model_dom_1.contentModelToDom)(doc, div, model, (0, roosterjs_content_model_dom_1.createModelToDomContext)(undefined /*editorContext*/, options));
7553
+ (0, roosterjs_content_model_dom_1.contentModelToDom)(doc, div, model, (0, roosterjs_content_model_dom_1.createModelToDomContext)(undefined /*editorContext*/, optionsOrCallbacks));
7443
7554
  editor.triggerEvent('extractContentWithDom', { clonedRoot: div }, true /*broadcast*/);
7444
7555
  return div.innerHTML;
7445
7556
  }
@@ -7645,6 +7756,7 @@ function mergePasteContent(editor, eventResult, clipboardData) {
7645
7756
  }, {
7646
7757
  changeSource: roosterjs_content_model_dom_1.ChangeSource.Paste,
7647
7758
  getChangeData: function () { return clipboardData; },
7759
+ scrollCaretIntoView: true,
7648
7760
  apiName: 'paste',
7649
7761
  });
7650
7762
  }
@@ -7692,7 +7804,10 @@ function paste(editor, clipboardData, pasteType) {
7692
7804
  editor.focus();
7693
7805
  var trustedHTMLHandler = editor.getTrustedHTMLHandler();
7694
7806
  if (!clipboardData.modelBeforePaste) {
7695
- clipboardData.modelBeforePaste = (0, mergePasteContent_1.cloneModelForPaste)(editor.getContentModelCopy('connected'));
7807
+ editor.formatContentModel(function (model) {
7808
+ clipboardData.modelBeforePaste = (0, mergePasteContent_1.cloneModelForPaste)(model);
7809
+ return false;
7810
+ });
7696
7811
  }
7697
7812
  // 1. Prepare variables
7698
7813
  var doc = createDOMFromHtml(clipboardData.rawHtml, trustedHTMLHandler);
@@ -8127,6 +8242,69 @@ function getPath(node, offset, rootNode) {
8127
8242
  exports.getPath = getPath;
8128
8243
 
8129
8244
 
8245
+ /***/ }),
8246
+
8247
+ /***/ "./packages/roosterjs-content-model-core/lib/coreApi/announce/announce.ts":
8248
+ /*!********************************************************************************!*\
8249
+ !*** ./packages/roosterjs-content-model-core/lib/coreApi/announce/announce.ts ***!
8250
+ \********************************************************************************/
8251
+ /***/ ((__unused_webpack_module, exports) => {
8252
+
8253
+ "use strict";
8254
+
8255
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
8256
+ exports.announce = void 0;
8257
+ /**
8258
+ * @internal
8259
+ * Announce the given data
8260
+ * @param core The EditorCore object
8261
+ * @param announceData Data to announce
8262
+ */
8263
+ var announce = function (core, announceData) {
8264
+ var _a;
8265
+ var text = announceData.text, defaultStrings = announceData.defaultStrings, _b = announceData.formatStrings, formatStrings = _b === void 0 ? [] : _b;
8266
+ var announcerStringGetter = core.lifecycle.announcerStringGetter;
8267
+ var template = defaultStrings && (announcerStringGetter === null || announcerStringGetter === void 0 ? void 0 : announcerStringGetter(defaultStrings));
8268
+ var textToAnnounce = formatString(template || text, formatStrings);
8269
+ if (textToAnnounce) {
8270
+ var announceContainer = core.lifecycle.announceContainer;
8271
+ if (!announceContainer || textToAnnounce == announceContainer.textContent) {
8272
+ (_a = announceContainer === null || announceContainer === void 0 ? void 0 : announceContainer.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(announceContainer);
8273
+ announceContainer = createAriaLiveElement(core.physicalRoot.ownerDocument);
8274
+ core.lifecycle.announceContainer = announceContainer;
8275
+ }
8276
+ if (announceContainer) {
8277
+ announceContainer.textContent = textToAnnounce;
8278
+ }
8279
+ }
8280
+ };
8281
+ exports.announce = announce;
8282
+ function formatString(text, formatStrings) {
8283
+ if (text == undefined) {
8284
+ return text;
8285
+ }
8286
+ text = text.replace(/\{(\d+)\}/g, function (_, sub) {
8287
+ var index = parseInt(sub);
8288
+ var replace = formatStrings[index];
8289
+ return replace !== null && replace !== void 0 ? replace : '';
8290
+ });
8291
+ return text;
8292
+ }
8293
+ function createAriaLiveElement(document) {
8294
+ var div = document.createElement('div');
8295
+ div.style.clip = 'rect(0px, 0px, 0px, 0px)';
8296
+ div.style.clipPath = 'inset(100%)';
8297
+ div.style.height = '1px';
8298
+ div.style.overflow = 'hidden';
8299
+ div.style.position = 'absolute';
8300
+ div.style.whiteSpace = 'nowrap';
8301
+ div.style.width = '1px';
8302
+ div.ariaLive = 'assertive';
8303
+ document.body.appendChild(div);
8304
+ return div;
8305
+ }
8306
+
8307
+
8130
8308
  /***/ }),
8131
8309
 
8132
8310
  /***/ "./packages/roosterjs-content-model-core/lib/coreApi/attachDomEvent/attachDomEvent.ts":
@@ -8186,6 +8364,7 @@ exports.attachDomEvent = attachDomEvent;
8186
8364
  Object.defineProperty(exports, "__esModule", ({ value: true }));
8187
8365
  exports.coreApiMap = void 0;
8188
8366
  var addUndoSnapshot_1 = __webpack_require__(/*! ./addUndoSnapshot/addUndoSnapshot */ "./packages/roosterjs-content-model-core/lib/coreApi/addUndoSnapshot/addUndoSnapshot.ts");
8367
+ var announce_1 = __webpack_require__(/*! ./announce/announce */ "./packages/roosterjs-content-model-core/lib/coreApi/announce/announce.ts");
8189
8368
  var attachDomEvent_1 = __webpack_require__(/*! ./attachDomEvent/attachDomEvent */ "./packages/roosterjs-content-model-core/lib/coreApi/attachDomEvent/attachDomEvent.ts");
8190
8369
  var createContentModel_1 = __webpack_require__(/*! ./createContentModel/createContentModel */ "./packages/roosterjs-content-model-core/lib/coreApi/createContentModel/createContentModel.ts");
8191
8370
  var createEditorContext_1 = __webpack_require__(/*! ./createEditorContext/createEditorContext */ "./packages/roosterjs-content-model-core/lib/coreApi/createEditorContext/createEditorContext.ts");
@@ -8220,6 +8399,7 @@ exports.coreApiMap = {
8220
8399
  switchShadowEdit: switchShadowEdit_1.switchShadowEdit,
8221
8400
  getVisibleViewport: getVisibleViewport_1.getVisibleViewport,
8222
8401
  setEditorStyle: setEditorStyle_1.setEditorStyle,
8402
+ announce: announce_1.announce,
8223
8403
  };
8224
8404
 
8225
8405
 
@@ -8248,34 +8428,33 @@ var createContentModel = function (core, option, selectionOverride) {
8248
8428
  var _a;
8249
8429
  // Flush all mutations if any, so that we can get an up-to-date Content Model
8250
8430
  (_a = core.cache.textMutationObserver) === null || _a === void 0 ? void 0 : _a.flushMutations();
8251
- var cachedModel = selectionOverride || (option && !option.tryGetFromCache) ? null : core.cache.cachedModel;
8252
- if (cachedModel && core.lifecycle.shadowEditFragment) {
8253
- // When in shadow edit, use a cloned model so we won't pollute the cached one
8254
- cachedModel = (0, roosterjs_content_model_dom_1.cloneModel)(cachedModel, { includeCachedElement: true });
8431
+ if (!selectionOverride && (!option || option.tryGetFromCache)) {
8432
+ var cachedModel = core.cache.cachedModel;
8433
+ if (cachedModel) {
8434
+ // When in shadow edit, use a cloned model so we won't pollute the cached one
8435
+ return core.lifecycle.shadowEditFragment
8436
+ ? (0, roosterjs_content_model_dom_1.cloneModel)(cachedModel, { includeCachedElement: true })
8437
+ : cachedModel;
8438
+ }
8255
8439
  }
8256
- if (cachedModel) {
8257
- return cachedModel;
8440
+ var selection = selectionOverride == 'none'
8441
+ ? undefined
8442
+ : selectionOverride || core.api.getDOMSelection(core) || undefined;
8443
+ var saveIndex = !option && !selectionOverride;
8444
+ var editorContext = core.api.createEditorContext(core, saveIndex);
8445
+ var settings = core.environment.domToModelSettings;
8446
+ var domToModelContext = option
8447
+ ? (0, roosterjs_content_model_dom_1.createDomToModelContext)(editorContext, settings.builtIn, settings.customized, option)
8448
+ : (0, roosterjs_content_model_dom_1.createDomToModelContextWithConfig)(settings.calculated, editorContext);
8449
+ if (selection) {
8450
+ domToModelContext.selection = selection;
8258
8451
  }
8259
- else {
8260
- var selection = selectionOverride == 'none'
8261
- ? undefined
8262
- : selectionOverride || core.api.getDOMSelection(core) || undefined;
8263
- var saveIndex = !option && !selectionOverride;
8264
- var editorContext = core.api.createEditorContext(core, saveIndex);
8265
- var settings = core.environment.domToModelSettings;
8266
- var domToModelContext = option
8267
- ? (0, roosterjs_content_model_dom_1.createDomToModelContext)(editorContext, settings.builtIn, settings.customized, option)
8268
- : (0, roosterjs_content_model_dom_1.createDomToModelContextWithConfig)(settings.calculated, editorContext);
8269
- if (selection) {
8270
- domToModelContext.selection = selection;
8271
- }
8272
- var model = (0, roosterjs_content_model_dom_1.domToContentModel)(core.logicalRoot, domToModelContext);
8273
- if (saveIndex) {
8274
- core.cache.cachedModel = model;
8275
- (0, updateCachedSelection_1.updateCachedSelection)(core.cache, selection);
8276
- }
8277
- return model;
8452
+ var model = (0, roosterjs_content_model_dom_1.domToContentModel)(core.logicalRoot, domToModelContext);
8453
+ if (saveIndex) {
8454
+ core.cache.cachedModel = model;
8455
+ (0, updateCachedSelection_1.updateCachedSelection)(core.cache, selection);
8278
8456
  }
8457
+ return model;
8279
8458
  };
8280
8459
  exports.createContentModel = createContentModel;
8281
8460
 
@@ -8303,17 +8482,12 @@ var createEditorContext = function (core, saveIndex) {
8303
8482
  var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, logicalRoot = core.logicalRoot, cache = core.cache, domHelper = core.domHelper;
8304
8483
  saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;
8305
8484
  var context = (0, tslib_1.__assign)({ isDarkMode: lifecycle.isDarkMode, defaultFormat: format.defaultFormat, pendingFormat: (_a = format.pendingFormat) !== null && _a !== void 0 ? _a : undefined, darkColorHandler: darkColorHandler, addDelimiterForEntity: true, allowCacheElement: true, domIndexer: saveIndex ? cache.domIndexer : undefined, zoomScale: domHelper.calculateZoomScale() }, (0, getRootComputedStyleForContext_1.getRootComputedStyleForContext)(logicalRoot.ownerDocument));
8306
- checkRootRtl(logicalRoot, context);
8485
+ if (core.domHelper.isRightToLeft()) {
8486
+ context.isRootRtl = true;
8487
+ }
8307
8488
  return context;
8308
8489
  };
8309
8490
  exports.createEditorContext = createEditorContext;
8310
- function checkRootRtl(element, context) {
8311
- var _a;
8312
- var style = (_a = element === null || element === void 0 ? void 0 : element.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(element);
8313
- if ((style === null || style === void 0 ? void 0 : style.direction) == 'rtl') {
8314
- context.isRootRtl = true;
8315
- }
8316
- }
8317
8491
 
8318
8492
 
8319
8493
  /***/ }),
@@ -8400,7 +8574,7 @@ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-mo
8400
8574
  */
8401
8575
  var formatContentModel = function (core, formatter, options, domToModelOptions) {
8402
8576
  var _a;
8403
- var _b = options || {}, apiName = _b.apiName, onNodeCreated = _b.onNodeCreated, getChangeData = _b.getChangeData, changeSource = _b.changeSource, rawEvent = _b.rawEvent, selectionOverride = _b.selectionOverride;
8577
+ var _b = options || {}, apiName = _b.apiName, onNodeCreated = _b.onNodeCreated, getChangeData = _b.getChangeData, changeSource = _b.changeSource, rawEvent = _b.rawEvent, selectionOverride = _b.selectionOverride, scrollCaretIntoView = _b.scrollCaretIntoView;
8404
8578
  var model = core.api.createContentModel(core, domToModelOptions, selectionOverride);
8405
8579
  var context = {
8406
8580
  newEntities: [],
@@ -8425,6 +8599,11 @@ var formatContentModel = function (core, formatter, options, domToModelOptions)
8425
8599
  (_a = core.api.setContentModel(core, model, hasFocus ? undefined : { ignoreSelection: true }, // If editor did not have focus before format, do not set focus after format
8426
8600
  onNodeCreated)) !== null && _a !== void 0 ? _a : undefined;
8427
8601
  handlePendingFormat(core, context, selection);
8602
+ if (selection && scrollCaretIntoView) {
8603
+ var selectionRoot = (0, roosterjs_content_model_dom_1.getSelectionRootNode)(selection);
8604
+ var rootElement = selectionRoot && core.domHelper.findClosestElementAncestor(selectionRoot);
8605
+ rootElement === null || rootElement === void 0 ? void 0 : rootElement.scrollIntoView();
8606
+ }
8428
8607
  var eventData = {
8429
8608
  eventType: 'contentChanged',
8430
8609
  contentModel: clearModelCache ? undefined : model,
@@ -8461,19 +8640,19 @@ var formatContentModel = function (core, formatter, options, domToModelOptions)
8461
8640
  }
8462
8641
  handlePendingFormat(core, context, core.api.getDOMSelection(core));
8463
8642
  }
8643
+ if (context.announceData) {
8644
+ core.api.announce(core, context.announceData);
8645
+ }
8464
8646
  };
8465
8647
  exports.formatContentModel = formatContentModel;
8466
8648
  function handleImages(core, context) {
8467
8649
  if (context.newImages.length > 0) {
8468
- var viewport = core.api.getVisibleViewport(core);
8469
- if (viewport) {
8470
- var left = viewport.left, right = viewport.right;
8471
- var minMaxImageSize = 10;
8472
- var maxWidth_1 = Math.max(right - left, minMaxImageSize);
8473
- context.newImages.forEach(function (image) {
8474
- image.format.maxWidth = maxWidth_1 + "px";
8475
- });
8476
- }
8650
+ var width = core.domHelper.getClientWidth();
8651
+ var minMaxImageSize = 10;
8652
+ var maxWidth_1 = Math.max(width, minMaxImageSize);
8653
+ context.newImages.forEach(function (image) {
8654
+ image.format.maxWidth = maxWidth_1 + "px";
8655
+ });
8477
8656
  }
8478
8657
  }
8479
8658
  function handlePendingFormat(core, context, selection) {
@@ -8693,7 +8872,6 @@ exports.restoreSnapshotColors = restoreSnapshotColors;
8693
8872
  Object.defineProperty(exports, "__esModule", ({ value: true }));
8694
8873
  exports.restoreSnapshotHTML = void 0;
8695
8874
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
8696
- var BlockEntityContainer = '_E_EBlockEntityContainer';
8697
8875
  /**
8698
8876
  * @internal
8699
8877
  */
@@ -8745,22 +8923,19 @@ function tryGetEntityElement(entityMap, node) {
8745
8923
  var format = (0, roosterjs_content_model_dom_1.parseEntityFormat)(node);
8746
8924
  result = getEntityWrapperForReuse(entityMap, format.id);
8747
8925
  }
8748
- else if (isBlockEntityContainer(node)) {
8926
+ else if ((0, roosterjs_content_model_dom_1.isBlockEntityContainer)(node)) {
8749
8927
  result = tryGetEntityFromContainer(node, entityMap);
8750
8928
  }
8751
8929
  }
8752
8930
  return result;
8753
8931
  }
8754
- function isBlockEntityContainer(node) {
8755
- return node.classList.contains(BlockEntityContainer);
8756
- }
8757
8932
  function tryGetEntityFromContainer(element, entityMap) {
8758
8933
  var _a;
8759
8934
  for (var node = element.firstChild; node; node = node.nextSibling) {
8760
8935
  if ((0, roosterjs_content_model_dom_1.isEntityElement)(node) && (0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'ELEMENT_NODE')) {
8761
8936
  var format = (0, roosterjs_content_model_dom_1.parseEntityFormat)(node);
8762
8937
  var parent_1 = (_a = getEntityWrapperForReuse(entityMap, format.id)) === null || _a === void 0 ? void 0 : _a.parentElement;
8763
- return (0, roosterjs_content_model_dom_1.isNodeOfType)(parent_1, 'ELEMENT_NODE') && isBlockEntityContainer(parent_1)
8938
+ return (0, roosterjs_content_model_dom_1.isNodeOfType)(parent_1, 'ELEMENT_NODE') && (0, roosterjs_content_model_dom_1.isBlockEntityContainer)(parent_1)
8764
8939
  ? parent_1
8765
8940
  : null;
8766
8941
  }
@@ -9121,7 +9296,7 @@ var TABLE_ID = 'table';
9121
9296
  var DEFAULT_SELECTION_BORDER_COLOR = '#DB626C';
9122
9297
  var TABLE_CSS_RULE = 'background-color:#C6C6C6!important;';
9123
9298
  var CARET_CSS_RULE = 'caret-color: transparent';
9124
- var TRANSPARENT_SELECTION_CSS_RULE = 'background-color: transparent !important';
9299
+ var TRANSPARENT_SELECTION_CSS_RULE = 'background-color: transparent !important;';
9125
9300
  var SELECTION_SELECTOR = '*::selection';
9126
9301
  /**
9127
9302
  * @internal
@@ -9139,9 +9314,12 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
9139
9314
  try {
9140
9315
  switch (selection === null || selection === void 0 ? void 0 : selection.type) {
9141
9316
  case 'image':
9142
- var image = selection.image;
9143
- core.selection.selection = selection;
9144
- core.api.setEditorStyle(core, DOM_SELECTION_CSS_KEY, "outline-style:auto!important; outline-color:" + (core.selection.imageSelectionBorderColor || DEFAULT_SELECTION_BORDER_COLOR) + "!important;", ["#" + (0, ensureUniqueId_1.ensureUniqueId)(image, IMAGE_ID)]);
9317
+ var image = ensureImageHasSpanParent(selection.image);
9318
+ core.selection.selection = {
9319
+ type: 'image',
9320
+ image: image,
9321
+ };
9322
+ core.api.setEditorStyle(core, DOM_SELECTION_CSS_KEY, "outline-style:auto!important; outline-color:" + (core.selection.imageSelectionBorderColor || DEFAULT_SELECTION_BORDER_COLOR) + "!important;", ["span:has(>img#" + (0, ensureUniqueId_1.ensureUniqueId)(image, IMAGE_ID) + ")"]);
9145
9323
  core.api.setEditorStyle(core, HIDE_SELECTION_CSS_KEY, TRANSPARENT_SELECTION_CSS_RULE, [SELECTION_SELECTOR]);
9146
9324
  setRangeSelection(doc, image, false /* collapse */);
9147
9325
  break;
@@ -9272,6 +9450,18 @@ function setRangeSelection(doc, element, collapse) {
9272
9450
  (0, addRangeToSelection_1.addRangeToSelection)(doc, range, isReverted);
9273
9451
  }
9274
9452
  }
9453
+ function ensureImageHasSpanParent(image) {
9454
+ var parent = image.parentElement;
9455
+ if (parent &&
9456
+ (0, roosterjs_content_model_dom_1.isNodeOfType)(parent, 'ELEMENT_NODE') &&
9457
+ (0, roosterjs_content_model_dom_1.isElementOfType)(parent, 'span') &&
9458
+ parent.firstChild == image &&
9459
+ parent.lastChild == image) {
9460
+ return image;
9461
+ }
9462
+ (0, roosterjs_content_model_dom_1.wrap)(image.ownerDocument, image, 'span');
9463
+ return image;
9464
+ }
9275
9465
 
9276
9466
 
9277
9467
  /***/ }),
@@ -9812,11 +10002,15 @@ function reconcileSelection(model, newSelection, oldSelection) {
9812
10002
  var newRange = newSelection.range;
9813
10003
  if (newRange) {
9814
10004
  var startContainer = newRange.startContainer, startOffset = newRange.startOffset, endContainer = newRange.endContainer, endOffset = newRange.endOffset, collapsed = newRange.collapsed;
10005
+ delete model.hasRevertedRangeSelection;
9815
10006
  if (collapsed) {
9816
10007
  return !!reconcileNodeSelection(startContainer, startOffset);
9817
10008
  }
9818
10009
  else if (startContainer == endContainer &&
9819
10010
  (0, roosterjs_content_model_dom_1.isNodeOfType)(startContainer, 'TEXT_NODE')) {
10011
+ if (newSelection.isReverted) {
10012
+ model.hasRevertedRangeSelection = true;
10013
+ }
9820
10014
  return (isIndexedSegment(startContainer) &&
9821
10015
  !!reconcileTextSelection(startContainer, startOffset, endOffset));
9822
10016
  }
@@ -9824,6 +10018,9 @@ function reconcileSelection(model, newSelection, oldSelection) {
9824
10018
  var marker1 = reconcileNodeSelection(startContainer, startOffset);
9825
10019
  var marker2 = reconcileNodeSelection(endContainer, endOffset);
9826
10020
  if (marker1 && marker2) {
10021
+ if (newSelection.isReverted) {
10022
+ model.hasRevertedRangeSelection = true;
10023
+ }
9827
10024
  (0, roosterjs_content_model_dom_1.setSelection)(model, marker1, marker2);
9828
10025
  return true;
9829
10026
  }
@@ -10287,8 +10484,8 @@ var CopyPastePlugin = /** @class */ (function () {
10287
10484
  return;
10288
10485
  }
10289
10486
  cleanUpAndRestoreSelection(tempDiv_1);
10290
- _this.editor.focus();
10291
10487
  _this.editor.setDOMSelection(selection);
10488
+ _this.editor.focus();
10292
10489
  if (isCut) {
10293
10490
  _this.editor.formatContentModel(function (model, context) {
10294
10491
  if ((0, roosterjs_content_model_dom_1.deleteSelection)(model, [deleteEmptyList_1.deleteEmptyList], context)
@@ -10955,6 +11152,123 @@ function createEntityPlugin() {
10955
11152
  exports.createEntityPlugin = createEntityPlugin;
10956
11153
 
10957
11154
 
11155
+ /***/ }),
11156
+
11157
+ /***/ "./packages/roosterjs-content-model-core/lib/corePlugin/entity/adjustSelectionAroundEntity.ts":
11158
+ /*!****************************************************************************************************!*\
11159
+ !*** ./packages/roosterjs-content-model-core/lib/corePlugin/entity/adjustSelectionAroundEntity.ts ***!
11160
+ \****************************************************************************************************/
11161
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
11162
+
11163
+ "use strict";
11164
+
11165
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
11166
+ exports.adjustSelectionAroundEntity = void 0;
11167
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
11168
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
11169
+ /**
11170
+ * @internal
11171
+ */
11172
+ function adjustSelectionAroundEntity(editor, key, shiftKey) {
11173
+ var _a;
11174
+ var selection = editor.isDisposed() ? null : editor.getDOMSelection();
11175
+ if (!selection || selection.type != 'range') {
11176
+ return;
11177
+ }
11178
+ var range = selection.range, isReverted = selection.isReverted;
11179
+ var anchorNode = isReverted ? range.startContainer : range.endContainer;
11180
+ var offset = isReverted ? range.startOffset : range.endOffset;
11181
+ var delimiter = (0, roosterjs_content_model_dom_1.isNodeOfType)(anchorNode, 'ELEMENT_NODE')
11182
+ ? anchorNode
11183
+ : anchorNode.parentElement;
11184
+ var isRtl = delimiter &&
11185
+ ((_a = editor.getDocument().defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(delimiter).direction) == 'rtl';
11186
+ var movingBefore = (key == 'ArrowLeft') != !!isRtl;
11187
+ if (delimiter &&
11188
+ (((0, roosterjs_content_model_dom_1.isEntityDelimiter)(delimiter, !movingBefore) &&
11189
+ ((movingBefore && offset == 0) || (!movingBefore && offset == 1))) ||
11190
+ (0, roosterjs_content_model_dom_1.isBlockEntityContainer)(delimiter))) {
11191
+ editor.formatContentModel(function (model) {
11192
+ var _a, _b;
11193
+ var allSel = (0, roosterjs_content_model_dom_1.getSelectedSegmentsAndParagraphs)(model, false /*includingFormatHolder*/, true /*includingEntity*/);
11194
+ var sel = allSel[isReverted ? 0 : allSel.length - 1];
11195
+ var index = (_b = (_a = sel === null || sel === void 0 ? void 0 : sel[1]) === null || _a === void 0 ? void 0 : _a.segments.indexOf(sel[0])) !== null && _b !== void 0 ? _b : -1;
11196
+ if (sel && sel[1] && index >= 0) {
11197
+ var _c = (0, tslib_1.__read)(sel, 3), segment = _c[0], paragraph = _c[1], path = _c[2];
11198
+ var isShrinking = shiftKey && !range.collapsed && movingBefore != !!isReverted;
11199
+ var entitySegment = isShrinking
11200
+ ? segment
11201
+ : paragraph.segments[movingBefore ? index - 1 : index + 1];
11202
+ var pairedDelimiter = findPairedDelimiter(entitySegment, path, paragraph, movingBefore);
11203
+ if (pairedDelimiter) {
11204
+ var newRange = getNewRange(range, isShrinking, movingBefore, pairedDelimiter, shiftKey);
11205
+ editor.setDOMSelection({
11206
+ type: 'range',
11207
+ range: newRange,
11208
+ isReverted: newRange.collapsed ? false : isReverted,
11209
+ });
11210
+ }
11211
+ }
11212
+ return false;
11213
+ });
11214
+ }
11215
+ }
11216
+ exports.adjustSelectionAroundEntity = adjustSelectionAroundEntity;
11217
+ function getNewRange(originalRange, isShrinking, movingBefore, pairedDelimiter, shiftKey) {
11218
+ var newRange = originalRange.cloneRange();
11219
+ if (isShrinking) {
11220
+ if (movingBefore) {
11221
+ newRange.setEndBefore(pairedDelimiter);
11222
+ }
11223
+ else {
11224
+ newRange.setStartAfter(pairedDelimiter);
11225
+ }
11226
+ }
11227
+ else {
11228
+ if (movingBefore) {
11229
+ newRange.setStartBefore(pairedDelimiter);
11230
+ }
11231
+ else {
11232
+ newRange.setEndAfter(pairedDelimiter);
11233
+ }
11234
+ if (!shiftKey) {
11235
+ if (movingBefore) {
11236
+ newRange.setEndBefore(pairedDelimiter);
11237
+ }
11238
+ else {
11239
+ newRange.setStartAfter(pairedDelimiter);
11240
+ }
11241
+ }
11242
+ }
11243
+ return newRange;
11244
+ }
11245
+ function findPairedDelimiter(entitySegment, path, paragraph, movingBefore) {
11246
+ var entity = null;
11247
+ if ((entitySegment === null || entitySegment === void 0 ? void 0 : entitySegment.segmentType) == 'Entity') {
11248
+ // Inline entity
11249
+ entity = entitySegment;
11250
+ }
11251
+ else {
11252
+ // Block entity
11253
+ var blocks = path[0].blocks;
11254
+ var paraIndex = blocks.indexOf(paragraph);
11255
+ var entityBlock = paraIndex >= 0 ? blocks[movingBefore ? paraIndex - 1 : paraIndex + 1] : null;
11256
+ if ((entityBlock === null || entityBlock === void 0 ? void 0 : entityBlock.blockType) == 'Entity') {
11257
+ entity = entityBlock;
11258
+ }
11259
+ }
11260
+ var pairedDelimiter = entity
11261
+ ? movingBefore
11262
+ ? entity.wrapper.previousElementSibling
11263
+ : entity.wrapper.nextElementSibling
11264
+ : null;
11265
+ return (0, roosterjs_content_model_dom_1.isNodeOfType)(pairedDelimiter, 'ELEMENT_NODE') &&
11266
+ (0, roosterjs_content_model_dom_1.isEntityDelimiter)(pairedDelimiter, movingBefore)
11267
+ ? pairedDelimiter
11268
+ : null;
11269
+ }
11270
+
11271
+
10958
11272
  /***/ }),
10959
11273
 
10960
11274
  /***/ "./packages/roosterjs-content-model-core/lib/corePlugin/entity/entityDelimiterUtils.ts":
@@ -10968,6 +11282,7 @@ exports.createEntityPlugin = createEntityPlugin;
10968
11282
  Object.defineProperty(exports, "__esModule", ({ value: true }));
10969
11283
  exports.handleEnterInlineEntity = exports.handleKeyDownInBlockDelimiter = exports.handleDelimiterKeyDownEvent = exports.handleCompositionEndEvent = exports.handleDelimiterContentChangedEvent = exports.preventTypeInDelimiter = void 0;
10970
11284
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
11285
+ var adjustSelectionAroundEntity_1 = __webpack_require__(/*! ./adjustSelectionAroundEntity */ "./packages/roosterjs-content-model-core/lib/corePlugin/entity/adjustSelectionAroundEntity.ts");
10971
11286
  var normalizePos_1 = __webpack_require__(/*! ../selection/normalizePos */ "./packages/roosterjs-content-model-core/lib/corePlugin/selection/normalizePos.ts");
10972
11287
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
10973
11288
  var DelimiterBefore = 'entityDelimiterBefore';
@@ -10976,8 +11291,6 @@ var DelimiterSelector = '.' + DelimiterAfter + ',.' + DelimiterBefore;
10976
11291
  var ZeroWidthSpace = '\u200B';
10977
11292
  var EntityInfoName = '_Entity';
10978
11293
  var InlineEntitySelector = 'span.' + EntityInfoName;
10979
- var BlockEntityContainer = '_E_EBlockEntityContainer';
10980
- var BlockEntityContainerSelector = '.' + BlockEntityContainer;
10981
11294
  /**
10982
11295
  * @internal exported only for unit test
10983
11296
  */
@@ -11119,61 +11432,86 @@ exports.handleCompositionEndEvent = handleCompositionEndEvent;
11119
11432
  function handleDelimiterKeyDownEvent(editor, event) {
11120
11433
  var _a;
11121
11434
  var selection = editor.getDOMSelection();
11122
- var rawEvent = event.rawEvent;
11123
11435
  if (!selection || selection.type != 'range') {
11124
11436
  return;
11125
11437
  }
11126
- var isEnter = rawEvent.key === 'Enter';
11127
- var helper = editor.getDOMHelper();
11128
- if (selection.range.collapsed && ((0, roosterjs_content_model_dom_1.isCharacterValue)(rawEvent) || isEnter)) {
11129
- var helper_1 = editor.getDOMHelper();
11130
- var node_1 = getFocusedElement(selection);
11131
- if (node_1 && (0, roosterjs_content_model_dom_1.isEntityDelimiter)(node_1) && helper_1.isNodeInEditor(node_1)) {
11132
- var blockEntityContainer = node_1.closest(BlockEntityContainerSelector);
11133
- if (blockEntityContainer && helper_1.isNodeInEditor(blockEntityContainer)) {
11134
- var isAfter = node_1.classList.contains(DelimiterAfter);
11135
- if (isAfter) {
11136
- selection.range.setStartAfter(blockEntityContainer);
11137
- }
11138
- else {
11139
- selection.range.setStartBefore(blockEntityContainer);
11140
- }
11141
- selection.range.collapse(true /* toStart */);
11142
- if (isEnter) {
11143
- event.rawEvent.preventDefault();
11438
+ var rawEvent = event.rawEvent;
11439
+ var range = selection.range;
11440
+ var key = rawEvent.key;
11441
+ switch (key) {
11442
+ case 'Enter':
11443
+ if (range.collapsed) {
11444
+ handleInputOnDelimiter(editor, range, getFocusedElement(selection), rawEvent);
11445
+ }
11446
+ else {
11447
+ var helper = editor.getDOMHelper();
11448
+ var entity = (0, roosterjs_content_model_dom_1.findClosestEntityWrapper)(range.startContainer, helper);
11449
+ if (entity &&
11450
+ (0, roosterjs_content_model_dom_1.isNodeOfType)(entity, 'ELEMENT_NODE') &&
11451
+ helper.isNodeInEditor(entity)) {
11452
+ triggerEntityEventOnEnter(editor, entity, rawEvent);
11144
11453
  }
11145
- editor.formatContentModel(exports.handleKeyDownInBlockDelimiter, {
11146
- selectionOverride: {
11147
- type: 'range',
11148
- isReverted: false,
11149
- range: selection.range,
11150
- },
11454
+ }
11455
+ break;
11456
+ case 'ArrowLeft':
11457
+ case 'ArrowRight':
11458
+ if (!rawEvent.altKey && !rawEvent.ctrlKey && !rawEvent.metaKey) {
11459
+ // Handle in async so focus is already moved, this makes us easier to check if we should adjust the selection
11460
+ (_a = editor.getDocument().defaultView) === null || _a === void 0 ? void 0 : _a.requestAnimationFrame(function () {
11461
+ (0, adjustSelectionAroundEntity_1.adjustSelectionAroundEntity)(editor, key, rawEvent.shiftKey);
11151
11462
  });
11152
11463
  }
11464
+ break;
11465
+ default:
11466
+ if ((0, roosterjs_content_model_dom_1.isCharacterValue)(rawEvent) && range.collapsed) {
11467
+ handleInputOnDelimiter(editor, range, getFocusedElement(selection), rawEvent);
11468
+ }
11469
+ break;
11470
+ }
11471
+ }
11472
+ exports.handleDelimiterKeyDownEvent = handleDelimiterKeyDownEvent;
11473
+ function handleInputOnDelimiter(editor, range, focusedNode, rawEvent) {
11474
+ var _a;
11475
+ var helper = editor.getDOMHelper();
11476
+ if (focusedNode && (0, roosterjs_content_model_dom_1.isEntityDelimiter)(focusedNode) && helper.isNodeInEditor(focusedNode)) {
11477
+ var blockEntityContainer = (0, roosterjs_content_model_dom_1.findClosestBlockEntityContainer)(focusedNode, helper);
11478
+ var isEnter = rawEvent.key === 'Enter';
11479
+ if (blockEntityContainer && helper.isNodeInEditor(blockEntityContainer)) {
11480
+ var isAfter = focusedNode.classList.contains(DelimiterAfter);
11481
+ if (isAfter) {
11482
+ range.setStartAfter(blockEntityContainer);
11483
+ }
11153
11484
  else {
11154
- if (isEnter) {
11155
- event.rawEvent.preventDefault();
11156
- editor.formatContentModel(exports.handleEnterInlineEntity);
11157
- }
11158
- else {
11159
- editor.takeSnapshot();
11160
- (_a = editor
11161
- .getDocument()
11162
- .defaultView) === null || _a === void 0 ? void 0 : _a.requestAnimationFrame(function () {
11163
- return preventTypeInDelimiter(node_1, editor);
11164
- });
11165
- }
11485
+ range.setStartBefore(blockEntityContainer);
11166
11486
  }
11487
+ range.collapse(true /* toStart */);
11488
+ if (isEnter) {
11489
+ rawEvent.preventDefault();
11490
+ }
11491
+ editor.formatContentModel(exports.handleKeyDownInBlockDelimiter, {
11492
+ selectionOverride: {
11493
+ type: 'range',
11494
+ isReverted: false,
11495
+ range: range,
11496
+ },
11497
+ });
11167
11498
  }
11168
- }
11169
- else if (isEnter) {
11170
- var entity = (0, roosterjs_content_model_dom_1.findClosestEntityWrapper)(selection.range.startContainer, helper);
11171
- if (entity && (0, roosterjs_content_model_dom_1.isNodeOfType)(entity, 'ELEMENT_NODE') && helper.isNodeInEditor(entity)) {
11172
- triggerEntityEventOnEnter(editor, entity, rawEvent);
11499
+ else {
11500
+ if (isEnter) {
11501
+ rawEvent.preventDefault();
11502
+ editor.formatContentModel(exports.handleEnterInlineEntity);
11503
+ }
11504
+ else {
11505
+ editor.takeSnapshot();
11506
+ (_a = editor
11507
+ .getDocument()
11508
+ .defaultView) === null || _a === void 0 ? void 0 : _a.requestAnimationFrame(function () {
11509
+ return preventTypeInDelimiter(focusedNode, editor);
11510
+ });
11511
+ }
11173
11512
  }
11174
11513
  }
11175
11514
  }
11176
- exports.handleDelimiterKeyDownEvent = handleDelimiterKeyDownEvent;
11177
11515
  /**
11178
11516
  * @internal Exported Only for unit test
11179
11517
  * @returns
@@ -11668,6 +12006,7 @@ var LifecyclePlugin = /** @class */ (function () {
11668
12006
  isDarkMode: !!options.inDarkMode,
11669
12007
  shadowEditFragment: null,
11670
12008
  styleElements: {},
12009
+ announcerStringGetter: options.announcerStringGetter,
11671
12010
  };
11672
12011
  }
11673
12012
  /**
@@ -11695,7 +12034,7 @@ var LifecyclePlugin = /** @class */ (function () {
11695
12034
  */
11696
12035
  LifecyclePlugin.prototype.dispose = function () {
11697
12036
  var _this = this;
11698
- var _a;
12037
+ var _a, _b;
11699
12038
  (_a = this.editor) === null || _a === void 0 ? void 0 : _a.triggerEvent('beforeDispose', {}, true /*broadcast*/);
11700
12039
  (0, roosterjs_content_model_dom_1.getObjectKeys)(this.state.styleElements).forEach(function (key) {
11701
12040
  var _a;
@@ -11703,6 +12042,11 @@ var LifecyclePlugin = /** @class */ (function () {
11703
12042
  (_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.removeChild(element);
11704
12043
  delete _this.state.styleElements[key];
11705
12044
  });
12045
+ var announceContainer = this.state.announceContainer;
12046
+ if (announceContainer) {
12047
+ (_b = announceContainer.parentElement) === null || _b === void 0 ? void 0 : _b.removeChild(announceContainer);
12048
+ delete this.state.announceContainer;
12049
+ }
11706
12050
  if (this.disposer) {
11707
12051
  this.disposer();
11708
12052
  this.disposer = null;
@@ -12086,14 +12430,14 @@ var SelectionPlugin = /** @class */ (function () {
12086
12430
  return rawEvent.shiftKey ? 'TabLeft' : 'TabRight';
12087
12431
  };
12088
12432
  SelectionPlugin.prototype.handleSelectionInTable = function (key) {
12089
- var _a, _b, _c, _d;
12433
+ var _a, _b, _c, _d, _e, _f;
12090
12434
  if (!this.editor || !this.state.tableSelection) {
12091
12435
  return;
12092
12436
  }
12093
12437
  var selection = this.editor.getDOMSelection();
12094
12438
  var domHelper = this.editor.getDOMHelper();
12095
12439
  if ((selection === null || selection === void 0 ? void 0 : selection.type) == 'range') {
12096
- var _e = selection.range, collapsed = _e.collapsed, startContainer = _e.startContainer, endContainer = _e.endContainer, commonAncestorContainer = _e.commonAncestorContainer, isReverted = selection.isReverted;
12440
+ var _g = selection.range, collapsed = _g.collapsed, startContainer = _g.startContainer, endContainer = _g.endContainer, commonAncestorContainer = _g.commonAncestorContainer, isReverted = selection.isReverted;
12097
12441
  var start = isReverted ? endContainer : startContainer;
12098
12442
  var end = isReverted ? startContainer : endContainer;
12099
12443
  var tableSel = this.parseTableSelection(commonAncestorContainer, start, domHelper);
@@ -12101,7 +12445,7 @@ var SelectionPlugin = /** @class */ (function () {
12101
12445
  return;
12102
12446
  }
12103
12447
  var lastCo = (0, findCoordinate_1.findCoordinate)(tableSel === null || tableSel === void 0 ? void 0 : tableSel.parsedTable, end, domHelper);
12104
- var _f = this.state.tableSelection, parsedTable = _f.parsedTable, oldCo = _f.firstCo, table = _f.table;
12448
+ var _h = this.state.tableSelection, parsedTable = _h.parsedTable, oldCo = _h.firstCo, table = _h.table;
12105
12449
  if (lastCo && tableSel.table == table) {
12106
12450
  if (lastCo.col != oldCo.col && (key == Up || key == Down)) {
12107
12451
  var change = key == Up ? -1 : 1;
@@ -12139,6 +12483,8 @@ var SelectionPlugin = /** @class */ (function () {
12139
12483
  var cell = parsedTable[row][col];
12140
12484
  if (typeof cell != 'string') {
12141
12485
  this.setRangeSelectionInTable(cell, 0, this.editor);
12486
+ lastCo.row = row;
12487
+ lastCo.col = col;
12142
12488
  break;
12143
12489
  }
12144
12490
  }
@@ -12146,6 +12492,13 @@ var SelectionPlugin = /** @class */ (function () {
12146
12492
  else {
12147
12493
  this.state.tableSelection = null;
12148
12494
  }
12495
+ if (collapsed &&
12496
+ (lastCo.col != oldCo.col || lastCo.row != oldCo.row) &&
12497
+ lastCo.row >= 0 &&
12498
+ lastCo.row == parsedTable.length - 1 &&
12499
+ lastCo.col == ((_e = parsedTable[lastCo.row]) === null || _e === void 0 ? void 0 : _e.length) - 1) {
12500
+ (_f = this.editor) === null || _f === void 0 ? void 0 : _f.announce({ defaultStrings: 'announceOnFocusLastCell' });
12501
+ }
12149
12502
  }
12150
12503
  if (!collapsed && lastCo) {
12151
12504
  this.state.tableSelection = tableSel;
@@ -12659,6 +13012,11 @@ var UndoPlugin = /** @class */ (function () {
12659
13012
  case 'beforeKeyboardEditing':
12660
13013
  this.onBeforeKeyboardEditing(event.rawEvent);
12661
13014
  break;
13015
+ case 'mouseDown':
13016
+ if (this.state.snapshotsManager.hasNewContent) {
13017
+ this.addUndoSnapshot();
13018
+ }
13019
+ break;
12662
13020
  }
12663
13021
  };
12664
13022
  UndoPlugin.prototype.onKeyDown = function (editor, evt) {
@@ -12856,9 +13214,6 @@ var Editor = /** @class */ (function () {
12856
13214
  /**
12857
13215
  * Create Content Model from DOM tree in this editor
12858
13216
  * @param mode What kind of Content Model we want. Currently we support the following values:
12859
- * - connected: Returns a connect Content Model object. "Connected" means if there is any entity inside editor, the returned Content Model will
12860
- * contain the same wrapper element for entity. This option should only be used in some special cases. In most cases we should use "disconnected"
12861
- * to get a fully disconnected Content Model so that any change to the model will not impact editor content.
12862
13217
  * - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.
12863
13218
  * If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.
12864
13219
  * If editor is in dark mode, the cloned entity will be converted back to light mode.
@@ -12868,10 +13223,7 @@ var Editor = /** @class */ (function () {
12868
13223
  Editor.prototype.getContentModelCopy = function (mode) {
12869
13224
  var core = this.getCore();
12870
13225
  switch (mode) {
12871
- case 'connected':
12872
- return core.api.createContentModel(core, {
12873
- tryGetFromCache: true, // Pass an option here to force disable save index
12874
- });
13226
+ case 'connected': // Get a connected model is deprecated. Now we will always return disconnected model
12875
13227
  case 'disconnected':
12876
13228
  return (0, roosterjs_content_model_dom_1.cloneModel)(core.api.createContentModel(core, {
12877
13229
  processorOverride: {
@@ -13098,6 +13450,14 @@ var Editor = /** @class */ (function () {
13098
13450
  var core = this.getCore();
13099
13451
  core.api.setEditorStyle(core, key, cssRule, subSelectors);
13100
13452
  };
13453
+ /**
13454
+ * Announce the given data
13455
+ * @param announceData Data to announce
13456
+ */
13457
+ Editor.prototype.announce = function (announceData) {
13458
+ var core = this.getCore();
13459
+ core.api.announce(core, announceData);
13460
+ };
13101
13461
  /**
13102
13462
  * @returns the current EditorCore object
13103
13463
  * @throws a standard Error if there's no core object
@@ -13178,6 +13538,26 @@ var DOMHelperImpl = /** @class */ (function () {
13178
13538
  var activeElement = this.contentDiv.ownerDocument.activeElement;
13179
13539
  return !!(activeElement && this.contentDiv.contains(activeElement));
13180
13540
  };
13541
+ /**
13542
+ * Check if the root element is in RTL mode
13543
+ */
13544
+ DOMHelperImpl.prototype.isRightToLeft = function () {
13545
+ var _a;
13546
+ var contentDiv = this.contentDiv;
13547
+ var style = (_a = contentDiv.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(contentDiv);
13548
+ return (style === null || style === void 0 ? void 0 : style.direction) == 'rtl';
13549
+ };
13550
+ /**
13551
+ * Get the width of the editable area of the editor content div
13552
+ */
13553
+ DOMHelperImpl.prototype.getClientWidth = function () {
13554
+ var _a;
13555
+ var contentDiv = this.contentDiv;
13556
+ var style = (_a = contentDiv.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getComputedStyle(contentDiv);
13557
+ var paddingLeft = (0, roosterjs_content_model_dom_1.parseValueWithUnit)(style === null || style === void 0 ? void 0 : style.paddingLeft);
13558
+ var paddingRight = (0, roosterjs_content_model_dom_1.parseValueWithUnit)(style === null || style === void 0 ? void 0 : style.paddingRight);
13559
+ return this.contentDiv.clientWidth - (paddingLeft + paddingRight);
13560
+ };
13181
13561
  return DOMHelperImpl;
13182
13562
  }());
13183
13563
  /**
@@ -13468,94 +13848,23 @@ exports.containerSizeFormatParser = containerSizeFormatParser;
13468
13848
 
13469
13849
  Object.defineProperty(exports, "__esModule", ({ value: true }));
13470
13850
  exports.listLevelMetadataApplier = exports.listItemMetadataApplier = void 0;
13471
- var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
13472
13851
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
13473
- var DefaultOrderedListStyles = ['decimal', 'lower-alpha', 'lower-roman'];
13474
- var DefaultUnorderedListStyles = ['disc', 'circle', 'square'];
13475
13852
  var OrderedMapPlaceholderRegex = /\$\{(\w+)\}/;
13476
- var CharCodeOfA = 65;
13477
- var RomanValues = {
13478
- M: 1000,
13479
- CM: 900,
13480
- D: 500,
13481
- CD: 400,
13482
- C: 100,
13483
- XC: 90,
13484
- L: 50,
13485
- XL: 40,
13486
- X: 10,
13487
- IX: 9,
13488
- V: 5,
13489
- IV: 4,
13490
- I: 1,
13491
- };
13492
- function getOrderedListStyleValue(template, listNumber) {
13493
- return template
13494
- ? template.replace(OrderedMapPlaceholderRegex, function (_, subStr) {
13495
- switch (subStr) {
13496
- case 'Number':
13497
- return listNumber + '';
13498
- case 'LowerAlpha':
13499
- return convertDecimalsToAlpha(listNumber, true /*isLowerCase*/);
13500
- case 'UpperAlpha':
13501
- return convertDecimalsToAlpha(listNumber, false /*isLowerCase*/);
13502
- case 'LowerRoman':
13503
- return convertDecimalsToRoman(listNumber, true /*isLowerCase*/);
13504
- case 'UpperRoman':
13505
- return convertDecimalsToRoman(listNumber, false /*isLowerCase*/);
13506
- }
13507
- return '';
13508
- })
13509
- : undefined;
13510
- }
13511
- function convertDecimalsToAlpha(decimal, isLowerCase) {
13512
- var alpha = '';
13513
- decimal--;
13514
- while (decimal >= 0) {
13515
- alpha = String.fromCharCode((decimal % 26) + CharCodeOfA) + alpha;
13516
- decimal = Math.floor(decimal / 26) - 1;
13853
+ function getListStyleValue(listType, listStyleType, listNumber) {
13854
+ if (listType == 'OL') {
13855
+ var numberStr = (0, roosterjs_content_model_dom_1.getOrderedListNumberStr)(listStyleType, listNumber !== null && listNumber !== void 0 ? listNumber : 1);
13856
+ var template = roosterjs_content_model_dom_1.OrderedListStyleMap[listStyleType];
13857
+ return template ? template.replace(OrderedMapPlaceholderRegex, numberStr) : undefined;
13858
+ }
13859
+ else {
13860
+ return roosterjs_content_model_dom_1.UnorderedListStyleMap[listStyleType];
13517
13861
  }
13518
- return isLowerCase ? alpha.toLowerCase() : alpha;
13519
13862
  }
13520
- function convertDecimalsToRoman(decimal, isLowerCase) {
13521
- var e_1, _a;
13522
- var romanValue = '';
13523
- try {
13524
- for (var _b = (0, tslib_1.__values)((0, roosterjs_content_model_dom_1.getObjectKeys)(RomanValues)), _c = _b.next(); !_c.done; _c = _b.next()) {
13525
- var i = _c.value;
13526
- var timesRomanCharAppear = Math.floor(decimal / RomanValues[i]);
13527
- decimal = decimal - timesRomanCharAppear * RomanValues[i];
13528
- romanValue = romanValue + i.repeat(timesRomanCharAppear);
13529
- }
13530
- }
13531
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
13532
- finally {
13533
- try {
13534
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
13535
- }
13536
- finally { if (e_1) throw e_1.error; }
13537
- }
13538
- return isLowerCase ? romanValue.toLocaleLowerCase() : romanValue;
13539
- }
13540
- function shouldApplyToItem(listStyleType) {
13541
- return listStyleType.indexOf('"') >= 0;
13542
- }
13543
- function getRawListStyleType(listType, metadata, depth) {
13544
- var orderedStyleType = metadata.orderedStyleType, unorderedStyleType = metadata.unorderedStyleType, applyListStyleFromLevel = metadata.applyListStyleFromLevel;
13545
- if (listType == 'OL') {
13546
- return typeof orderedStyleType == 'number'
13547
- ? roosterjs_content_model_dom_1.OrderedListStyleMap[orderedStyleType]
13548
- : applyListStyleFromLevel
13549
- ? DefaultOrderedListStyles[depth % DefaultOrderedListStyles.length]
13550
- : undefined;
13551
- }
13552
- else {
13553
- return typeof unorderedStyleType == 'number'
13554
- ? roosterjs_content_model_dom_1.UnorderedListStyleMap[unorderedStyleType]
13555
- : applyListStyleFromLevel
13556
- ? DefaultUnorderedListStyles[depth % DefaultUnorderedListStyles.length]
13557
- : undefined;
13558
- }
13863
+ function shouldApplyToItem(listStyleType, listType) {
13864
+ var style = listType == 'OL'
13865
+ ? roosterjs_content_model_dom_1.OrderedListStyleMap[listStyleType]
13866
+ : roosterjs_content_model_dom_1.UnorderedListStyleMap[listStyleType];
13867
+ return (style === null || style === void 0 ? void 0 : style.indexOf('"')) >= 0;
13559
13868
  }
13560
13869
  /**
13561
13870
  * @internal
@@ -13567,13 +13876,10 @@ exports.listItemMetadataApplier = {
13567
13876
  var depth = context.listFormat.nodeStack.length - 2; // Minus two for the parent element and convert length to index
13568
13877
  if (depth >= 0) {
13569
13878
  var listType = (_a = context.listFormat.nodeStack[depth + 1].listType) !== null && _a !== void 0 ? _a : 'OL';
13570
- var listStyleType = getRawListStyleType(listType, metadata !== null && metadata !== void 0 ? metadata : {}, depth);
13571
- if (listStyleType) {
13572
- if (shouldApplyToItem(listStyleType)) {
13573
- format.listStyleType =
13574
- listType == 'OL'
13575
- ? getOrderedListStyleValue(listStyleType, context.listFormat.threadItemCounts[depth])
13576
- : listStyleType;
13879
+ var listStyleType = (0, roosterjs_content_model_dom_1.getAutoListStyleType)(listType, metadata !== null && metadata !== void 0 ? metadata : {}, depth);
13880
+ if (listStyleType !== undefined) {
13881
+ if (shouldApplyToItem(listStyleType, listType)) {
13882
+ format.listStyleType = getListStyleValue(listType, listStyleType, context.listFormat.threadItemCounts[depth]);
13577
13883
  }
13578
13884
  else {
13579
13885
  delete format.listStyleType;
@@ -13592,10 +13898,13 @@ exports.listLevelMetadataApplier = {
13592
13898
  var depth = context.listFormat.nodeStack.length - 2; // Minus two for the parent element and convert length to index
13593
13899
  if (depth >= 0) {
13594
13900
  var listType = (_a = context.listFormat.nodeStack[depth + 1].listType) !== null && _a !== void 0 ? _a : 'OL';
13595
- var listStyleType = getRawListStyleType(listType, metadata !== null && metadata !== void 0 ? metadata : {}, depth);
13596
- if (listStyleType) {
13597
- if (!shouldApplyToItem(listStyleType)) {
13598
- format.listStyleType = listStyleType;
13901
+ var listStyleType = (0, roosterjs_content_model_dom_1.getAutoListStyleType)(listType, metadata !== null && metadata !== void 0 ? metadata : {}, depth);
13902
+ if (listStyleType !== undefined) {
13903
+ if (!shouldApplyToItem(listStyleType, listType)) {
13904
+ var listStyleTypeFormat = getListStyleValue(listType, listStyleType, context.listFormat.threadItemCounts[depth]);
13905
+ if (listStyleTypeFormat) {
13906
+ format.listStyleType = listStyleTypeFormat;
13907
+ }
13599
13908
  }
13600
13909
  else {
13601
13910
  delete format.listStyleType;
@@ -14161,6 +14470,10 @@ exports.ChangeSource = {
14161
14470
  * Data of this event will be the key code number
14162
14471
  */
14163
14472
  Keyboard: 'Keyboard',
14473
+ /**
14474
+ * Content changed by auto format
14475
+ */
14476
+ AutoFormat: 'AutoFormat',
14164
14477
  };
14165
14478
 
14166
14479
 
@@ -14651,7 +14964,11 @@ var normalizeContentModel_1 = __webpack_require__(/*! ../modelApi/common/normali
14651
14964
  * @returns A ContentModelDocument object that contains all the models created from the give root element
14652
14965
  */
14653
14966
  function domToContentModel(root, context) {
14967
+ var _a;
14654
14968
  var model = (0, createContentModelDocument_1.createContentModelDocument)(context.defaultFormat);
14969
+ if (((_a = context.selection) === null || _a === void 0 ? void 0 : _a.type) == 'range' && context.selection.isReverted) {
14970
+ model.hasRevertedRangeSelection = true;
14971
+ }
14655
14972
  context.elementProcessors.child(model, root, context);
14656
14973
  (0, normalizeContentModel_1.normalizeContentModel)(model);
14657
14974
  return model;
@@ -16249,19 +16566,22 @@ function stackFormatInternal(format, processType) {
16249
16566
  "use strict";
16250
16567
 
16251
16568
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16252
- exports.addDelimiters = exports.isEntityDelimiter = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.findClosestEntityWrapper = exports.isEntityElement = void 0;
16569
+ exports.addDelimiters = exports.isBlockEntityContainer = exports.isEntityDelimiter = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.findClosestBlockEntityContainer = exports.findClosestEntityWrapper = exports.isEntityElement = void 0;
16253
16570
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
16254
16571
  var applyFormat_1 = __webpack_require__(/*! ../modelToDom/utils/applyFormat */ "./packages/roosterjs-content-model-dom/lib/modelToDom/utils/applyFormat.ts");
16255
16572
  var isElementOfType_1 = __webpack_require__(/*! ./isElementOfType */ "./packages/roosterjs-content-model-dom/lib/domUtils/isElementOfType.ts");
16256
16573
  var isNodeOfType_1 = __webpack_require__(/*! ./isNodeOfType */ "./packages/roosterjs-content-model-dom/lib/domUtils/isNodeOfType.ts");
16257
16574
  var toArray_1 = __webpack_require__(/*! ./toArray */ "./packages/roosterjs-content-model-dom/lib/domUtils/toArray.ts");
16258
16575
  var ENTITY_INFO_NAME = '_Entity';
16576
+ var ENTITY_INFO_SELECTOR = '.' + ENTITY_INFO_NAME;
16259
16577
  var ENTITY_TYPE_PREFIX = '_EType_';
16260
16578
  var ENTITY_ID_PREFIX = '_EId_';
16261
16579
  var ENTITY_READONLY_PREFIX = '_EReadonly_';
16262
16580
  var ZERO_WIDTH_SPACE = '\u200B';
16263
16581
  var DELIMITER_BEFORE = 'entityDelimiterBefore';
16264
16582
  var DELIMITER_AFTER = 'entityDelimiterAfter';
16583
+ var BLOCK_ENTITY_CONTAINER = '_E_EBlockEntityContainer';
16584
+ var BLOCK_ENTITY_CONTAINER_SELECTOR = '.' + BLOCK_ENTITY_CONTAINER;
16265
16585
  /**
16266
16586
  * Check if the given DOM Node is an entity wrapper element
16267
16587
  */
@@ -16275,9 +16595,19 @@ exports.isEntityElement = isEntityElement;
16275
16595
  * @param domHelper The DOM helper to use
16276
16596
  */
16277
16597
  function findClosestEntityWrapper(startNode, domHelper) {
16278
- return domHelper.findClosestElementAncestor(startNode, "." + ENTITY_INFO_NAME);
16598
+ return domHelper.findClosestElementAncestor(startNode, ENTITY_INFO_SELECTOR);
16279
16599
  }
16280
16600
  exports.findClosestEntityWrapper = findClosestEntityWrapper;
16601
+ /**
16602
+ * Find the closest block entity wrapper element from a given DOM node
16603
+ * @param node The node to start looking for entity container
16604
+ * @param domHelper The DOM helper
16605
+ * @returns
16606
+ */
16607
+ function findClosestBlockEntityContainer(node, domHelper) {
16608
+ return domHelper.findClosestElementAncestor(node, BLOCK_ENTITY_CONTAINER_SELECTOR);
16609
+ }
16610
+ exports.findClosestBlockEntityContainer = findClosestBlockEntityContainer;
16281
16611
  /**
16282
16612
  * Get all entity wrapper elements under the given root element
16283
16613
  * @param root The root element to query from
@@ -16339,15 +16669,27 @@ exports.generateEntityClassNames = generateEntityClassNames;
16339
16669
  /**
16340
16670
  * Checks whether the node provided is a Entity delimiter
16341
16671
  * @param node the node to check
16672
+ * @param isBefore True to match delimiter before entity only, false to match delimiter after entity, or undefined means match both
16342
16673
  * @return true if it is a delimiter
16343
16674
  */
16344
- function isEntityDelimiter(element) {
16675
+ function isEntityDelimiter(element, isBefore) {
16676
+ var matchBefore = isBefore === undefined || isBefore;
16677
+ var matchAfter = isBefore === undefined || !isBefore;
16345
16678
  return ((0, isElementOfType_1.isElementOfType)(element, 'span') &&
16346
- (element.classList.contains(DELIMITER_AFTER) ||
16347
- element.classList.contains(DELIMITER_BEFORE)) &&
16679
+ ((matchAfter && element.classList.contains(DELIMITER_AFTER)) ||
16680
+ (matchBefore && element.classList.contains(DELIMITER_BEFORE))) &&
16348
16681
  element.textContent === ZERO_WIDTH_SPACE);
16349
16682
  }
16350
16683
  exports.isEntityDelimiter = isEntityDelimiter;
16684
+ /**
16685
+ * Check if the given element is a container element of block entity
16686
+ * @param element The element to check
16687
+ * @returns True if the element is a block entity container, otherwise false
16688
+ */
16689
+ function isBlockEntityContainer(element) {
16690
+ return (0, isElementOfType_1.isElementOfType)(element, 'div') && element.classList.contains(BLOCK_ENTITY_CONTAINER);
16691
+ }
16692
+ exports.isBlockEntityContainer = isBlockEntityContainer;
16351
16693
  /**
16352
16694
  * Adds delimiters to the element provided. If the delimiters already exists, will not be added
16353
16695
  * @param element the node to add the delimiters
@@ -19241,9 +19583,9 @@ exports.shouldSetValue = shouldSetValue;
19241
19583
  "use strict";
19242
19584
 
19243
19585
  Object.defineProperty(exports, "__esModule", ({ value: true }));
19244
- exports.addBlock = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = exports.createParagraphDecorator = exports.createContentModelDocument = exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.normalizeRect = exports.isWhiteSpacePreserved = exports.reuseCachedElement = exports.isEntityDelimiter = exports.addDelimiters = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.findClosestEntityWrapper = exports.isEntityElement = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.updateMetadata = exports.buildSelectionMarker = exports.isBlockElement = exports.areSameFormats = exports.parseFormat = exports.getRegularSelectionOffsets = exports.tableProcessor = exports.entityProcessor = exports.processChildNode = exports.handleRegularSelection = exports.childProcessor = exports.contentModelToText = exports.contentModelToDom = exports.domToContentModel = void 0;
19245
- exports.hasSelectionInSegment = exports.hasSelectionInBlock = exports.getSelectedCells = exports.getSelectedSegmentsAndParagraphs = exports.getSelectedSegments = exports.getSelectedParagraphs = exports.getOperationalBlocks = exports.getFirstSelectedTable = exports.getFirstSelectedListItem = exports.iterateSelections = exports.getClosestAncestorBlockGroupIndex = exports.isBlockGroupOfType = exports.cacheGetEventData = exports.extractClipboardItems = exports.transformColor = exports.readFile = exports.parseTableCells = exports.normalizeText = exports.isSpace = exports.isPunctuation = exports.extractBorderValues = exports.combineBorderValue = exports.isCursorMovingKey = exports.isModifierKey = exports.isCharacterValue = exports.getSelectionRootNode = exports.isBold = exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.setParagraphNotImplicit = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = exports.normalizeParagraph = exports.addTextSegment = exports.addLink = exports.addCode = void 0;
19246
- exports.UnorderedListStyleMap = exports.OrderedListStyleMap = exports.TableBorderFormat = exports.NumberingListType = exports.BulletListType = exports.ChangeSource = exports.ListMetadataDefinition = exports.updateListMetadata = exports.updateTableMetadata = exports.updateTableCellMetadata = exports.updateImageMetadata = exports.getSegmentTextFormat = exports.getListStyleTypeFromString = exports.retrieveModelFormatState = exports.setTableCellBackgroundColor = exports.MIN_ALLOWED_TABLE_CELL_WIDTH = exports.normalizeTable = exports.applyTableFormat = exports.deleteBlock = exports.deleteSegment = exports.deleteSelection = exports.mergeModel = exports.cloneModel = exports.setSelection = exports.hasSelectionInBlockGroup = void 0;
19586
+ exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = exports.createParagraphDecorator = exports.createContentModelDocument = exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.normalizeRect = exports.isWhiteSpacePreserved = exports.reuseCachedElement = exports.findClosestBlockEntityContainer = exports.isBlockEntityContainer = exports.isEntityDelimiter = exports.addDelimiters = exports.generateEntityClassNames = exports.parseEntityFormat = exports.getAllEntityWrappers = exports.findClosestEntityWrapper = exports.isEntityElement = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.updateMetadata = exports.buildSelectionMarker = exports.isBlockElement = exports.areSameFormats = exports.parseFormat = exports.getRegularSelectionOffsets = exports.tableProcessor = exports.entityProcessor = exports.processChildNode = exports.handleRegularSelection = exports.childProcessor = exports.contentModelToText = exports.contentModelToDom = exports.domToContentModel = void 0;
19587
+ exports.getSelectedSegments = exports.getSelectedParagraphs = exports.getOperationalBlocks = exports.getFirstSelectedTable = exports.getFirstSelectedListItem = exports.iterateSelections = exports.getClosestAncestorBlockGroupIndex = exports.isBlockGroupOfType = exports.cacheGetEventData = exports.extractClipboardItems = exports.transformColor = exports.readFile = exports.parseTableCells = exports.normalizeText = exports.isSpace = exports.isPunctuation = exports.extractBorderValues = exports.combineBorderValue = exports.isCursorMovingKey = exports.isModifierKey = exports.isCharacterValue = exports.getSelectionRootNode = exports.isBold = exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.getAutoListStyleType = exports.getOrderedListNumberStr = exports.setParagraphNotImplicit = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = exports.normalizeParagraph = exports.addTextSegment = exports.addLink = exports.addCode = exports.addBlock = exports.createEmptyModel = void 0;
19588
+ exports.UnorderedListStyleMap = exports.OrderedListStyleMap = exports.TableBorderFormat = exports.NumberingListType = exports.BulletListType = exports.ChangeSource = exports.ListMetadataDefinition = exports.updateListMetadata = exports.updateTableMetadata = exports.updateTableCellMetadata = exports.updateImageMetadata = exports.getSegmentTextFormat = exports.getListStyleTypeFromString = exports.retrieveModelFormatState = exports.setTableCellBackgroundColor = exports.MIN_ALLOWED_TABLE_CELL_WIDTH = exports.normalizeTable = exports.applyTableFormat = exports.deleteBlock = exports.deleteSegment = exports.deleteSelection = exports.mergeModel = exports.cloneModel = exports.setSelection = exports.hasSelectionInBlockGroup = exports.hasSelectionInSegment = exports.hasSelectionInBlock = exports.getSelectedCells = exports.getSelectedSegmentsAndParagraphs = void 0;
19247
19589
  var domToContentModel_1 = __webpack_require__(/*! ./domToModel/domToContentModel */ "./packages/roosterjs-content-model-dom/lib/domToModel/domToContentModel.ts");
19248
19590
  Object.defineProperty(exports, "domToContentModel", ({ enumerable: true, get: function () { return domToContentModel_1.domToContentModel; } }));
19249
19591
  var contentModelToDom_1 = __webpack_require__(/*! ./modelToDom/contentModelToDom */ "./packages/roosterjs-content-model-dom/lib/modelToDom/contentModelToDom.ts");
@@ -19292,6 +19634,8 @@ Object.defineProperty(exports, "parseEntityFormat", ({ enumerable: true, get: fu
19292
19634
  Object.defineProperty(exports, "generateEntityClassNames", ({ enumerable: true, get: function () { return entityUtils_1.generateEntityClassNames; } }));
19293
19635
  Object.defineProperty(exports, "addDelimiters", ({ enumerable: true, get: function () { return entityUtils_1.addDelimiters; } }));
19294
19636
  Object.defineProperty(exports, "isEntityDelimiter", ({ enumerable: true, get: function () { return entityUtils_1.isEntityDelimiter; } }));
19637
+ Object.defineProperty(exports, "isBlockEntityContainer", ({ enumerable: true, get: function () { return entityUtils_1.isBlockEntityContainer; } }));
19638
+ Object.defineProperty(exports, "findClosestBlockEntityContainer", ({ enumerable: true, get: function () { return entityUtils_1.findClosestBlockEntityContainer; } }));
19295
19639
  var reuseCachedElement_1 = __webpack_require__(/*! ./domUtils/reuseCachedElement */ "./packages/roosterjs-content-model-dom/lib/domUtils/reuseCachedElement.ts");
19296
19640
  Object.defineProperty(exports, "reuseCachedElement", ({ enumerable: true, get: function () { return reuseCachedElement_1.reuseCachedElement; } }));
19297
19641
  var isWhiteSpacePreserved_1 = __webpack_require__(/*! ./domUtils/isWhiteSpacePreserved */ "./packages/roosterjs-content-model-dom/lib/domUtils/isWhiteSpacePreserved.ts");
@@ -19356,6 +19700,10 @@ var normalizeSegment_1 = __webpack_require__(/*! ./modelApi/common/normalizeSegm
19356
19700
  Object.defineProperty(exports, "normalizeSingleSegment", ({ enumerable: true, get: function () { return normalizeSegment_1.normalizeSingleSegment; } }));
19357
19701
  var setParagraphNotImplicit_1 = __webpack_require__(/*! ./modelApi/block/setParagraphNotImplicit */ "./packages/roosterjs-content-model-dom/lib/modelApi/block/setParagraphNotImplicit.ts");
19358
19702
  Object.defineProperty(exports, "setParagraphNotImplicit", ({ enumerable: true, get: function () { return setParagraphNotImplicit_1.setParagraphNotImplicit; } }));
19703
+ var getOrderedListNumberStr_1 = __webpack_require__(/*! ./modelApi/list/getOrderedListNumberStr */ "./packages/roosterjs-content-model-dom/lib/modelApi/list/getOrderedListNumberStr.ts");
19704
+ Object.defineProperty(exports, "getOrderedListNumberStr", ({ enumerable: true, get: function () { return getOrderedListNumberStr_1.getOrderedListNumberStr; } }));
19705
+ var getAutoListStyleType_1 = __webpack_require__(/*! ./modelApi/list/getAutoListStyleType */ "./packages/roosterjs-content-model-dom/lib/modelApi/list/getAutoListStyleType.ts");
19706
+ Object.defineProperty(exports, "getAutoListStyleType", ({ enumerable: true, get: function () { return getAutoListStyleType_1.getAutoListStyleType; } }));
19359
19707
  var parseValueWithUnit_1 = __webpack_require__(/*! ./formatHandlers/utils/parseValueWithUnit */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/utils/parseValueWithUnit.ts");
19360
19708
  Object.defineProperty(exports, "parseValueWithUnit", ({ enumerable: true, get: function () { return parseValueWithUnit_1.parseValueWithUnit; } }));
19361
19709
  var borderFormatHandler_1 = __webpack_require__(/*! ./formatHandlers/common/borderFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/common/borderFormatHandler.ts");
@@ -22372,6 +22720,175 @@ function calculateLightness(color) {
22372
22720
  }
22373
22721
 
22374
22722
 
22723
+ /***/ }),
22724
+
22725
+ /***/ "./packages/roosterjs-content-model-dom/lib/modelApi/list/getAutoListStyleType.ts":
22726
+ /*!****************************************************************************************!*\
22727
+ !*** ./packages/roosterjs-content-model-dom/lib/modelApi/list/getAutoListStyleType.ts ***!
22728
+ \****************************************************************************************/
22729
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
22730
+
22731
+ "use strict";
22732
+
22733
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
22734
+ exports.getAutoListStyleType = void 0;
22735
+ var BulletListType_1 = __webpack_require__(/*! ../../constants/BulletListType */ "./packages/roosterjs-content-model-dom/lib/constants/BulletListType.ts");
22736
+ var NumberingListType_1 = __webpack_require__(/*! ../../constants/NumberingListType */ "./packages/roosterjs-content-model-dom/lib/constants/NumberingListType.ts");
22737
+ var DefaultOrderedListStyles = [
22738
+ NumberingListType_1.NumberingListType.Decimal,
22739
+ NumberingListType_1.NumberingListType.LowerAlpha,
22740
+ NumberingListType_1.NumberingListType.LowerRoman,
22741
+ ];
22742
+ var DefaultUnorderedListStyles = [
22743
+ BulletListType_1.BulletListType.Disc,
22744
+ BulletListType_1.BulletListType.Circle,
22745
+ BulletListType_1.BulletListType.Square,
22746
+ ];
22747
+ var OrderedListStyleRevertMap = {
22748
+ 'lower-alpha': NumberingListType_1.NumberingListType.LowerAlpha,
22749
+ 'lower-latin': NumberingListType_1.NumberingListType.LowerAlpha,
22750
+ 'upper-alpha': NumberingListType_1.NumberingListType.UpperAlpha,
22751
+ 'upper-latin': NumberingListType_1.NumberingListType.UpperAlpha,
22752
+ 'lower-roman': NumberingListType_1.NumberingListType.LowerRoman,
22753
+ 'upper-roman': NumberingListType_1.NumberingListType.UpperRoman,
22754
+ };
22755
+ var UnorderedListStyleRevertMap = {
22756
+ disc: BulletListType_1.BulletListType.Disc,
22757
+ circle: BulletListType_1.BulletListType.Circle,
22758
+ square: BulletListType_1.BulletListType.Square,
22759
+ };
22760
+ /**
22761
+ * Get automatic list style of a list item according to its lis type and metadata.
22762
+ * @param listType The list type, either OL or UL
22763
+ * @param metadata Metadata of this list item from list item model
22764
+ * @param depth Depth of list level, start from 0
22765
+ * @param existingStyleType Existing list style type in format, if any
22766
+ * @returns A number to represent list style type.
22767
+ * This will be the value of either NumberingListType (when listType is OL) or BulletListType (when listType is UL).
22768
+ * When there is a specified list style in its metadata, return this value, otherwise
22769
+ * When specified "applyListStyleFromLevel" in metadata, calculate auto list type from its depth, otherwise
22770
+ * When there is already listStyleType in list level format, find a related style type index, otherwise
22771
+ * return undefined
22772
+ */
22773
+ function getAutoListStyleType(listType, metadata, depth, existingStyleType) {
22774
+ var orderedStyleType = metadata.orderedStyleType, unorderedStyleType = metadata.unorderedStyleType, applyListStyleFromLevel = metadata.applyListStyleFromLevel;
22775
+ if (listType == 'OL') {
22776
+ return typeof orderedStyleType == 'number'
22777
+ ? orderedStyleType
22778
+ : applyListStyleFromLevel
22779
+ ? DefaultOrderedListStyles[depth % DefaultOrderedListStyles.length]
22780
+ : existingStyleType
22781
+ ? OrderedListStyleRevertMap[existingStyleType]
22782
+ : undefined;
22783
+ }
22784
+ else {
22785
+ return typeof unorderedStyleType == 'number'
22786
+ ? unorderedStyleType
22787
+ : applyListStyleFromLevel
22788
+ ? DefaultUnorderedListStyles[depth % DefaultUnorderedListStyles.length]
22789
+ : existingStyleType
22790
+ ? UnorderedListStyleRevertMap[existingStyleType]
22791
+ : undefined;
22792
+ }
22793
+ }
22794
+ exports.getAutoListStyleType = getAutoListStyleType;
22795
+
22796
+
22797
+ /***/ }),
22798
+
22799
+ /***/ "./packages/roosterjs-content-model-dom/lib/modelApi/list/getOrderedListNumberStr.ts":
22800
+ /*!*******************************************************************************************!*\
22801
+ !*** ./packages/roosterjs-content-model-dom/lib/modelApi/list/getOrderedListNumberStr.ts ***!
22802
+ \*******************************************************************************************/
22803
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
22804
+
22805
+ "use strict";
22806
+
22807
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
22808
+ exports.getOrderedListNumberStr = void 0;
22809
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
22810
+ var getObjectKeys_1 = __webpack_require__(/*! ../../domUtils/getObjectKeys */ "./packages/roosterjs-content-model-dom/lib/domUtils/getObjectKeys.ts");
22811
+ var NumberingListType_1 = __webpack_require__(/*! ../../constants/NumberingListType */ "./packages/roosterjs-content-model-dom/lib/constants/NumberingListType.ts");
22812
+ var CharCodeOfA = 65;
22813
+ var RomanValues = {
22814
+ M: 1000,
22815
+ CM: 900,
22816
+ D: 500,
22817
+ CD: 400,
22818
+ C: 100,
22819
+ XC: 90,
22820
+ L: 50,
22821
+ XL: 40,
22822
+ X: 10,
22823
+ IX: 9,
22824
+ V: 5,
22825
+ IV: 4,
22826
+ I: 1,
22827
+ };
22828
+ /**
22829
+ * Get the list number for a list item according to list style type and its index number
22830
+ * @param styleType The list style number, should be a value of NumberingListType type
22831
+ * @param listNumber List number, start from 1
22832
+ * @returns A string for this list item. For example, when pass in NumberingListType.LowerAlpha and 2, it returns "b"
22833
+ */
22834
+ function getOrderedListNumberStr(styleType, listNumber) {
22835
+ switch (styleType) {
22836
+ case NumberingListType_1.NumberingListType.LowerAlpha:
22837
+ case NumberingListType_1.NumberingListType.LowerAlphaDash:
22838
+ case NumberingListType_1.NumberingListType.LowerAlphaDoubleParenthesis:
22839
+ case NumberingListType_1.NumberingListType.LowerAlphaParenthesis:
22840
+ return convertDecimalsToAlpha(listNumber, true /*isLowerCase*/);
22841
+ case NumberingListType_1.NumberingListType.UpperAlpha:
22842
+ case NumberingListType_1.NumberingListType.UpperAlphaDash:
22843
+ case NumberingListType_1.NumberingListType.UpperAlphaDoubleParenthesis:
22844
+ case NumberingListType_1.NumberingListType.UpperAlphaParenthesis:
22845
+ return convertDecimalsToAlpha(listNumber, false /*isLowerCase*/);
22846
+ case NumberingListType_1.NumberingListType.LowerRoman:
22847
+ case NumberingListType_1.NumberingListType.LowerRomanDash:
22848
+ case NumberingListType_1.NumberingListType.LowerRomanDoubleParenthesis:
22849
+ case NumberingListType_1.NumberingListType.LowerRomanParenthesis:
22850
+ return convertDecimalsToRoman(listNumber, true /*isLowerCase*/);
22851
+ case NumberingListType_1.NumberingListType.UpperRoman:
22852
+ case NumberingListType_1.NumberingListType.UpperRomanDash:
22853
+ case NumberingListType_1.NumberingListType.UpperRomanDoubleParenthesis:
22854
+ case NumberingListType_1.NumberingListType.UpperRomanParenthesis:
22855
+ return convertDecimalsToRoman(listNumber, false /*isLowerCase*/);
22856
+ default:
22857
+ return listNumber + '';
22858
+ }
22859
+ }
22860
+ exports.getOrderedListNumberStr = getOrderedListNumberStr;
22861
+ function convertDecimalsToAlpha(decimal, isLowerCase) {
22862
+ var alpha = '';
22863
+ decimal--;
22864
+ while (decimal >= 0) {
22865
+ alpha = String.fromCharCode((decimal % 26) + CharCodeOfA) + alpha;
22866
+ decimal = Math.floor(decimal / 26) - 1;
22867
+ }
22868
+ return isLowerCase ? alpha.toLowerCase() : alpha;
22869
+ }
22870
+ function convertDecimalsToRoman(decimal, isLowerCase) {
22871
+ var e_1, _a;
22872
+ var romanValue = '';
22873
+ try {
22874
+ for (var _b = (0, tslib_1.__values)((0, getObjectKeys_1.getObjectKeys)(RomanValues)), _c = _b.next(); !_c.done; _c = _b.next()) {
22875
+ var i = _c.value;
22876
+ var timesRomanCharAppear = Math.floor(decimal / RomanValues[i]);
22877
+ decimal = decimal - timesRomanCharAppear * RomanValues[i];
22878
+ romanValue = romanValue + i.repeat(timesRomanCharAppear);
22879
+ }
22880
+ }
22881
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
22882
+ finally {
22883
+ try {
22884
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
22885
+ }
22886
+ finally { if (e_1) throw e_1.error; }
22887
+ }
22888
+ return isLowerCase ? romanValue.toLocaleLowerCase() : romanValue;
22889
+ }
22890
+
22891
+
22375
22892
  /***/ }),
22376
22893
 
22377
22894
  /***/ "./packages/roosterjs-content-model-dom/lib/modelApi/metadata/definitionCreators.ts":
@@ -22768,17 +23285,19 @@ var iterateSelections_1 = __webpack_require__(/*! ./iterateSelections */ "./pack
22768
23285
  * @param model The Content Model to get selection from
22769
23286
  * @param includingFormatHolder True means also include format holder as segment from list item, in that case paragraph will be null
22770
23287
  */
22771
- function getSelectedSegmentsAndParagraphs(model, includingFormatHolder) {
23288
+ function getSelectedSegmentsAndParagraphs(model, includingFormatHolder, includingEntity) {
22772
23289
  var selections = collectSelections(model, {
22773
23290
  includeListFormatHolder: includingFormatHolder ? 'allSegments' : 'never',
22774
23291
  });
22775
23292
  var result = [];
22776
23293
  selections.forEach(function (_a) {
22777
- var segments = _a.segments, block = _a.block;
23294
+ var segments = _a.segments, block = _a.block, path = _a.path;
22778
23295
  if (segments && ((includingFormatHolder && !block) || (block === null || block === void 0 ? void 0 : block.blockType) == 'Paragraph')) {
22779
23296
  segments.forEach(function (segment) {
22780
- if (segment.segmentType != 'Entity' || !segment.entityFormat.isReadonly) {
22781
- result.push([segment, (block === null || block === void 0 ? void 0 : block.blockType) == 'Paragraph' ? block : null]);
23297
+ if (includingEntity ||
23298
+ segment.segmentType != 'Entity' ||
23299
+ !segment.entityFormat.isReadonly) {
23300
+ result.push([segment, (block === null || block === void 0 ? void 0 : block.blockType) == 'Paragraph' ? block : null, path]);
22782
23301
  }
22783
23302
  });
22784
23303
  }
@@ -22814,15 +23333,15 @@ function getSelectedParagraphs(model) {
22814
23333
  exports.getSelectedParagraphs = getSelectedParagraphs;
22815
23334
  /**
22816
23335
  * Get an array of block group - block pair that is of the expected block group type from selection
22817
- * @param model The Content Model to get selection from
23336
+ * @param group The root block group to search
22818
23337
  * @param blockGroupTypes The expected block group types
22819
23338
  * @param stopTypes Block group types that will stop searching when hit
22820
23339
  * @param deepFirst True means search in deep first, otherwise wide first
22821
23340
  */
22822
- function getOperationalBlocks(model, blockGroupTypes, stopTypes, deepFirst) {
23341
+ function getOperationalBlocks(group, blockGroupTypes, stopTypes, deepFirst) {
22823
23342
  var result = [];
22824
23343
  var findSequence = deepFirst ? blockGroupTypes.map(function (type) { return [type]; }) : [blockGroupTypes];
22825
- var selections = collectSelections(model, {
23344
+ var selections = collectSelections(group, {
22826
23345
  includeListFormatHolder: 'never',
22827
23346
  contentUnderSelectedTableCell: 'ignoreForTable', // When whole table is selected, we treat the table as a single block
22828
23347
  });
@@ -22900,9 +23419,9 @@ function getFirstSelectedListItem(model) {
22900
23419
  return listItem;
22901
23420
  }
22902
23421
  exports.getFirstSelectedListItem = getFirstSelectedListItem;
22903
- function collectSelections(model, option) {
23422
+ function collectSelections(group, option) {
22904
23423
  var selections = [];
22905
- (0, iterateSelections_1.iterateSelections)(model, function (path, tableContext, block, segments) {
23424
+ (0, iterateSelections_1.iterateSelections)(group, function (path, tableContext, block, segments) {
22906
23425
  selections.push({
22907
23426
  path: path,
22908
23427
  tableContext: tableContext,
@@ -23443,6 +23962,9 @@ var toArray_1 = __webpack_require__(/*! ../domUtils/toArray */ "./packages/roost
23443
23962
  function contentModelToDom(doc, root, model, context) {
23444
23963
  context.modelHandlers.blockGroupChildren(doc, root, model, context);
23445
23964
  var range = extractSelectionRange(doc, context);
23965
+ if (model.hasRevertedRangeSelection && (range === null || range === void 0 ? void 0 : range.type) == 'range') {
23966
+ range.isReverted = true;
23967
+ }
23446
23968
  root.normalize();
23447
23969
  return range;
23448
23970
  }
@@ -24632,7 +25154,8 @@ function removeUnnecessarySpan(root) {
24632
25154
  for (var child = root.firstChild; child;) {
24633
25155
  if ((0, isNodeOfType_1.isNodeOfType)(child, 'ELEMENT_NODE') &&
24634
25156
  child.tagName == 'SPAN' &&
24635
- child.attributes.length == 0) {
25157
+ child.attributes.length == 0 &&
25158
+ !isImageSpan(child)) {
24636
25159
  var node = child;
24637
25160
  var refNode = child.nextSibling;
24638
25161
  child = child.nextSibling;
@@ -24649,6 +25172,11 @@ function removeUnnecessarySpan(root) {
24649
25172
  }
24650
25173
  }
24651
25174
  exports.removeUnnecessarySpan = removeUnnecessarySpan;
25175
+ var isImageSpan = function (child) {
25176
+ return ((0, isNodeOfType_1.isNodeOfType)(child.firstChild, 'ELEMENT_NODE') &&
25177
+ child.firstChild.tagName == 'IMG' &&
25178
+ child.firstChild == child.lastChild);
25179
+ };
24652
25180
 
24653
25181
 
24654
25182
  /***/ }),
@@ -24787,65 +25315,84 @@ exports.stackFormat = stackFormat;
24787
25315
  Object.defineProperty(exports, "__esModule", ({ value: true }));
24788
25316
  exports.contentModelToText = void 0;
24789
25317
  var TextForHR = '________________________________________';
25318
+ var defaultCallbacks = {
25319
+ onDivider: function (divider) { return (divider.tagName == 'hr' ? TextForHR : ''); },
25320
+ onEntityBlock: function () { return ''; },
25321
+ onEntitySegment: function (entity) { var _a; return (_a = entity.wrapper.textContent) !== null && _a !== void 0 ? _a : ''; },
25322
+ onGeneralSegment: function (segment) { var _a; return (_a = segment.element.textContent) !== null && _a !== void 0 ? _a : ''; },
25323
+ onImage: function () { return ' '; },
25324
+ onText: function (text) { return text.text; },
25325
+ onParagraph: function () { return true; },
25326
+ onTable: function () { return true; },
25327
+ onBlockGroup: function () { return true; },
25328
+ };
24790
25329
  /**
24791
25330
  * Convert Content Model to plain text
24792
25331
  * @param model The source Content Model
24793
25332
  * @param [separator='\r\n'] The separator string used for connect lines
25333
+ * @param callbacks Callbacks to customize the behavior of contentModelToText function
24794
25334
  */
24795
- function contentModelToText(model, separator) {
25335
+ function contentModelToText(model, separator, callbacks) {
24796
25336
  if (separator === void 0) { separator = '\r\n'; }
24797
25337
  var textArray = [];
24798
- contentModelToTextArray(model, textArray);
25338
+ var fullCallbacks = Object.assign({}, defaultCallbacks, callbacks);
25339
+ contentModelToTextArray(model, textArray, fullCallbacks);
24799
25340
  return textArray.join(separator);
24800
25341
  }
24801
25342
  exports.contentModelToText = contentModelToText;
24802
- function contentModelToTextArray(group, textArray) {
24803
- group.blocks.forEach(function (block) {
24804
- switch (block.blockType) {
24805
- case 'Paragraph':
24806
- var text_1 = '';
24807
- block.segments.forEach(function (segment) {
24808
- switch (segment.segmentType) {
24809
- case 'Br':
25343
+ function contentModelToTextArray(group, textArray, callbacks) {
25344
+ if (callbacks.onBlockGroup(group)) {
25345
+ group.blocks.forEach(function (block) {
25346
+ switch (block.blockType) {
25347
+ case 'Paragraph':
25348
+ if (callbacks.onParagraph(block)) {
25349
+ var text_1 = '';
25350
+ block.segments.forEach(function (segment) {
25351
+ switch (segment.segmentType) {
25352
+ case 'Br':
25353
+ textArray.push(text_1);
25354
+ text_1 = '';
25355
+ break;
25356
+ case 'Entity':
25357
+ text_1 += callbacks.onEntitySegment(segment);
25358
+ break;
25359
+ case 'General':
25360
+ text_1 += callbacks.onGeneralSegment(segment);
25361
+ break;
25362
+ case 'Text':
25363
+ text_1 += callbacks.onText(segment);
25364
+ break;
25365
+ case 'Image':
25366
+ text_1 += callbacks.onImage(segment);
25367
+ break;
25368
+ }
25369
+ });
25370
+ if (text_1) {
24810
25371
  textArray.push(text_1);
24811
- text_1 = '';
24812
- break;
24813
- case 'Entity':
24814
- text_1 += segment.wrapper.textContent || '';
24815
- break;
24816
- case 'General':
24817
- text_1 += segment.element.textContent || '';
24818
- break;
24819
- case 'Text':
24820
- text_1 += segment.text;
24821
- break;
24822
- case 'Image':
24823
- text_1 += ' ';
24824
- break;
25372
+ }
24825
25373
  }
24826
- });
24827
- if (text_1) {
24828
- textArray.push(text_1);
24829
- }
24830
- break;
24831
- case 'Divider':
24832
- textArray.push(block.tagName == 'hr' ? TextForHR : '');
24833
- break;
24834
- case 'Entity':
24835
- textArray.push('');
24836
- break;
24837
- case 'Table':
24838
- block.rows.forEach(function (row) {
24839
- return row.cells.forEach(function (cell) {
24840
- contentModelToTextArray(cell, textArray);
24841
- });
24842
- });
24843
- break;
24844
- case 'BlockGroup':
24845
- contentModelToTextArray(block, textArray);
24846
- break;
24847
- }
24848
- });
25374
+ break;
25375
+ case 'Divider':
25376
+ textArray.push(callbacks.onDivider(block));
25377
+ break;
25378
+ case 'Entity':
25379
+ textArray.push(callbacks.onEntityBlock(block));
25380
+ break;
25381
+ case 'Table':
25382
+ if (callbacks.onTable(block)) {
25383
+ block.rows.forEach(function (row) {
25384
+ return row.cells.forEach(function (cell) {
25385
+ contentModelToTextArray(cell, textArray, callbacks);
25386
+ });
25387
+ });
25388
+ }
25389
+ break;
25390
+ case 'BlockGroup':
25391
+ contentModelToTextArray(block, textArray, callbacks);
25392
+ break;
25393
+ }
25394
+ });
25395
+ }
24849
25396
  }
24850
25397
 
24851
25398
 
@@ -24861,11 +25408,14 @@ function contentModelToTextArray(group, textArray) {
24861
25408
 
24862
25409
  Object.defineProperty(exports, "__esModule", ({ value: true }));
24863
25410
  exports.AutoFormatPlugin = void 0;
25411
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
24864
25412
  var createLink_1 = __webpack_require__(/*! ./link/createLink */ "./packages/roosterjs-content-model-plugins/lib/autoFormat/link/createLink.ts");
24865
25413
  var createLinkAfterSpace_1 = __webpack_require__(/*! ./link/createLinkAfterSpace */ "./packages/roosterjs-content-model-plugins/lib/autoFormat/link/createLinkAfterSpace.ts");
24866
25414
  var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-model-api */ "./packages/roosterjs-content-model-api/lib/index.ts");
24867
25415
  var keyboardListTrigger_1 = __webpack_require__(/*! ./list/keyboardListTrigger */ "./packages/roosterjs-content-model-plugins/lib/autoFormat/list/keyboardListTrigger.ts");
25416
+ var transformFraction_1 = __webpack_require__(/*! ./numbers/transformFraction */ "./packages/roosterjs-content-model-plugins/lib/autoFormat/numbers/transformFraction.ts");
24868
25417
  var transformHyphen_1 = __webpack_require__(/*! ./hyphen/transformHyphen */ "./packages/roosterjs-content-model-plugins/lib/autoFormat/hyphen/transformHyphen.ts");
25418
+ var transformOrdinals_1 = __webpack_require__(/*! ./numbers/transformOrdinals */ "./packages/roosterjs-content-model-plugins/lib/autoFormat/numbers/transformOrdinals.ts");
24869
25419
  var unlink_1 = __webpack_require__(/*! ./link/unlink */ "./packages/roosterjs-content-model-plugins/lib/autoFormat/link/unlink.ts");
24870
25420
  /**
24871
25421
  * @internal
@@ -24876,6 +25426,8 @@ var DefaultOptions = {
24876
25426
  autoUnlink: false,
24877
25427
  autoLink: false,
24878
25428
  autoHyphen: false,
25429
+ autoFraction: false,
25430
+ autoOrdinals: false,
24879
25431
  };
24880
25432
  /**
24881
25433
  * Auto Format plugin handles auto formatting, such as transforming * characters into a bullet list.
@@ -24889,6 +25441,8 @@ var AutoFormatPlugin = /** @class */ (function () {
24889
25441
  * - autoLink: A boolean that enables or disables automatic hyperlink creation when pasting or typing content. Defaults to false.
24890
25442
  * - autoUnlink: A boolean that enables or disables automatic hyperlink removal when pressing backspace. Defaults to false.
24891
25443
  * - autoHyphen: A boolean that enables or disables automatic hyphen transformation. Defaults to false.
25444
+ * - autoFraction: A boolean that enables or disables automatic fraction transformation. Defaults to false.
25445
+ * - autoOrdinals: A boolean that enables or disables automatic ordinal number transformation. Defaults to false.
24892
25446
  */
24893
25447
  function AutoFormatPlugin(options) {
24894
25448
  if (options === void 0) { options = DefaultOptions; }
@@ -24949,20 +25503,40 @@ var AutoFormatPlugin = /** @class */ (function () {
24949
25503
  selection.range.collapsed) {
24950
25504
  switch (rawEvent.data) {
24951
25505
  case ' ':
25506
+ var formatOptions_1 = {
25507
+ changeSource: '',
25508
+ apiName: '',
25509
+ };
24952
25510
  (0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(editor, function (model, previousSegment, paragraph, _markerFormat, context) {
24953
- var _a = _this.options, autoBullet = _a.autoBullet, autoNumbering = _a.autoNumbering, autoLink = _a.autoLink, autoHyphen = _a.autoHyphen;
25511
+ var _a = _this.options, autoBullet = _a.autoBullet, autoNumbering = _a.autoNumbering, autoLink = _a.autoLink, autoHyphen = _a.autoHyphen, autoFraction = _a.autoFraction, autoOrdinals = _a.autoOrdinals;
24954
25512
  var shouldHyphen = false;
24955
25513
  var shouldLink = false;
25514
+ var shouldList = false;
25515
+ var shouldFraction = false;
25516
+ var shouldOrdinals = false;
25517
+ if (autoBullet || autoNumbering) {
25518
+ shouldList = (0, keyboardListTrigger_1.keyboardListTrigger)(model, paragraph, context, autoBullet, autoNumbering);
25519
+ }
24956
25520
  if (autoLink) {
24957
25521
  shouldLink = (0, createLinkAfterSpace_1.createLinkAfterSpace)(previousSegment, paragraph, context);
24958
25522
  }
24959
25523
  if (autoHyphen) {
24960
25524
  shouldHyphen = (0, transformHyphen_1.transformHyphen)(previousSegment, paragraph, context);
24961
25525
  }
24962
- return ((0, keyboardListTrigger_1.keyboardListTrigger)(model, paragraph, context, autoBullet, autoNumbering) ||
25526
+ if (autoFraction) {
25527
+ shouldFraction = (0, transformFraction_1.transformFraction)(previousSegment, paragraph, context);
25528
+ }
25529
+ if (autoOrdinals) {
25530
+ shouldOrdinals = (0, transformOrdinals_1.transformOrdinals)(previousSegment, paragraph, context);
25531
+ }
25532
+ formatOptions_1.apiName = getApiName(shouldList, shouldHyphen);
25533
+ formatOptions_1.changeSource = getChangeSource(shouldList, shouldHyphen, shouldLink);
25534
+ return (shouldList ||
24963
25535
  shouldHyphen ||
24964
- shouldLink);
24965
- });
25536
+ shouldLink ||
25537
+ shouldFraction ||
25538
+ shouldOrdinals);
25539
+ }, formatOptions_1);
24966
25540
  break;
24967
25541
  }
24968
25542
  }
@@ -24988,6 +25562,16 @@ var AutoFormatPlugin = /** @class */ (function () {
24988
25562
  return AutoFormatPlugin;
24989
25563
  }());
24990
25564
  exports.AutoFormatPlugin = AutoFormatPlugin;
25565
+ var getApiName = function (shouldList, shouldHyphen) {
25566
+ return shouldList ? 'autoToggleList' : shouldHyphen ? 'autoHyphen' : '';
25567
+ };
25568
+ var getChangeSource = function (shouldList, shouldHyphen, shouldLink) {
25569
+ return shouldList || shouldHyphen
25570
+ ? roosterjs_content_model_dom_1.ChangeSource.AutoFormat
25571
+ : shouldLink
25572
+ ? roosterjs_content_model_dom_1.ChangeSource.AutoLink
25573
+ : '';
25574
+ };
24991
25575
 
24992
25576
 
24993
25577
  /***/ }),
@@ -25066,6 +25650,8 @@ function createLink(editor) {
25066
25650
  return true;
25067
25651
  }
25068
25652
  return false;
25653
+ }, {
25654
+ changeSource: roosterjs_content_model_dom_1.ChangeSource.AutoLink,
25069
25655
  });
25070
25656
  }
25071
25657
  exports.createLink = createLink;
@@ -25480,15 +26066,13 @@ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-mo
25480
26066
  function keyboardListTrigger(model, paragraph, context, shouldSearchForBullet, shouldSearchForNumbering) {
25481
26067
  if (shouldSearchForBullet === void 0) { shouldSearchForBullet = true; }
25482
26068
  if (shouldSearchForNumbering === void 0) { shouldSearchForNumbering = true; }
25483
- if (shouldSearchForBullet || shouldSearchForNumbering) {
25484
- var listStyleType = (0, getListTypeStyle_1.getListTypeStyle)(model, shouldSearchForBullet, shouldSearchForNumbering);
25485
- if (listStyleType) {
25486
- paragraph.segments.splice(0, 1);
25487
- var listType = listStyleType.listType, styleType = listStyleType.styleType, index = listStyleType.index;
25488
- triggerList(model, listType, styleType, index);
25489
- context.canUndoByBackspace = true;
25490
- return true;
25491
- }
26069
+ var listStyleType = (0, getListTypeStyle_1.getListTypeStyle)(model, shouldSearchForBullet, shouldSearchForNumbering);
26070
+ if (listStyleType) {
26071
+ paragraph.segments.splice(0, 1);
26072
+ var listType = listStyleType.listType, styleType = listStyleType.styleType, index = listStyleType.index;
26073
+ triggerList(model, listType, styleType, index);
26074
+ context.canUndoByBackspace = true;
26075
+ return true;
25492
26076
  }
25493
26077
  return false;
25494
26078
  }
@@ -25509,6 +26093,85 @@ var triggerList = function (model, listType, styleType, index) {
25509
26093
  };
25510
26094
 
25511
26095
 
26096
+ /***/ }),
26097
+
26098
+ /***/ "./packages/roosterjs-content-model-plugins/lib/autoFormat/numbers/transformFraction.ts":
26099
+ /*!**********************************************************************************************!*\
26100
+ !*** ./packages/roosterjs-content-model-plugins/lib/autoFormat/numbers/transformFraction.ts ***!
26101
+ \**********************************************************************************************/
26102
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
26103
+
26104
+ "use strict";
26105
+
26106
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
26107
+ exports.transformFraction = void 0;
26108
+ var splitTextSegment_1 = __webpack_require__(/*! ../../pluginUtils/splitTextSegment */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/splitTextSegment.ts");
26109
+ var FRACTIONS = {
26110
+ '1/2': '½',
26111
+ '1/4': '¼',
26112
+ '3/4': '¾',
26113
+ };
26114
+ /**
26115
+ * @internal
26116
+ */
26117
+ function transformFraction(previousSegment, paragraph, context) {
26118
+ var _a;
26119
+ var fraction = (_a = previousSegment.text.split(' ').pop()) === null || _a === void 0 ? void 0 : _a.trim();
26120
+ if (fraction && FRACTIONS[fraction]) {
26121
+ var textLength = previousSegment.text.length - 1;
26122
+ var textIndex = textLength - fraction.length;
26123
+ var textSegment = (0, splitTextSegment_1.splitTextSegment)(previousSegment, paragraph, textIndex, textLength);
26124
+ textSegment.text = FRACTIONS[fraction];
26125
+ context.canUndoByBackspace = true;
26126
+ return true;
26127
+ }
26128
+ return false;
26129
+ }
26130
+ exports.transformFraction = transformFraction;
26131
+
26132
+
26133
+ /***/ }),
26134
+
26135
+ /***/ "./packages/roosterjs-content-model-plugins/lib/autoFormat/numbers/transformOrdinals.ts":
26136
+ /*!**********************************************************************************************!*\
26137
+ !*** ./packages/roosterjs-content-model-plugins/lib/autoFormat/numbers/transformOrdinals.ts ***!
26138
+ \**********************************************************************************************/
26139
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
26140
+
26141
+ "use strict";
26142
+
26143
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
26144
+ exports.transformOrdinals = void 0;
26145
+ var splitTextSegment_1 = __webpack_require__(/*! ../../pluginUtils/splitTextSegment */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/splitTextSegment.ts");
26146
+ var getOrdinal = function (value) {
26147
+ var ORDINALS = {
26148
+ 1: 'st',
26149
+ 2: 'nd',
26150
+ 3: 'rd',
26151
+ };
26152
+ return ORDINALS[value] || 'th';
26153
+ };
26154
+ /**
26155
+ * @internal
26156
+ */
26157
+ function transformOrdinals(previousSegment, paragraph, context) {
26158
+ var _a;
26159
+ var value = (_a = previousSegment.text.split(' ').pop()) === null || _a === void 0 ? void 0 : _a.trim();
26160
+ if (value) {
26161
+ var ordinal = value.substring(value.length - 2);
26162
+ var ordinalValue = parseInt(value);
26163
+ if (ordinalValue && getOrdinal(ordinalValue) === ordinal) {
26164
+ var ordinalSegment = (0, splitTextSegment_1.splitTextSegment)(previousSegment, paragraph, previousSegment.text.length - 3, previousSegment.text.length - 1);
26165
+ ordinalSegment.format.superOrSubScriptSequence = 'super';
26166
+ context.canUndoByBackspace = true;
26167
+ return true;
26168
+ }
26169
+ }
26170
+ return false;
26171
+ }
26172
+ exports.transformOrdinals = transformOrdinals;
26173
+
26174
+
25512
26175
  /***/ }),
25513
26176
 
25514
26177
  /***/ "./packages/roosterjs-content-model-plugins/lib/contextMenuBase/ContextMenuPluginBase.ts":
@@ -25605,8 +26268,105 @@ exports.ContextMenuPluginBase = ContextMenuPluginBase;
25605
26268
 
25606
26269
  /***/ }),
25607
26270
 
25608
- /***/ "./packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts":
25609
- /*!*************************************************************************!*\
26271
+ /***/ "./packages/roosterjs-content-model-plugins/lib/customReplace/CustomReplacePlugin.ts":
26272
+ /*!*******************************************************************************************!*\
26273
+ !*** ./packages/roosterjs-content-model-plugins/lib/customReplace/CustomReplacePlugin.ts ***!
26274
+ \*******************************************************************************************/
26275
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
26276
+
26277
+ "use strict";
26278
+
26279
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
26280
+ exports.CustomReplacePlugin = void 0;
26281
+ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-model-api */ "./packages/roosterjs-content-model-api/lib/index.ts");
26282
+ /**
26283
+ * CustomReplacePlugin is a plugin that allows you to replace a string with another string in the editor.
26284
+ */
26285
+ var CustomReplacePlugin = /** @class */ (function () {
26286
+ /**
26287
+ * @param customReplacements Custom replacement rules.
26288
+ * Ex: [{ stringToReplace: ':)', replacementString: '🙂', replacementHandler: replaceEmojis }]
26289
+ */
26290
+ function CustomReplacePlugin(customReplacements) {
26291
+ this.customReplacements = customReplacements;
26292
+ this.editor = null;
26293
+ this.triggerKeys = [];
26294
+ }
26295
+ /**
26296
+ * Get name of this plugin
26297
+ */
26298
+ CustomReplacePlugin.prototype.getName = function () {
26299
+ return 'CustomReplace';
26300
+ };
26301
+ /**
26302
+ * The first method that editor will call to a plugin when editor is initializing.
26303
+ * It will pass in the editor instance, plugin should take this chance to save the
26304
+ * editor reference so that it can call to any editor method or format API later.
26305
+ * @param editor The editor object
26306
+ */
26307
+ CustomReplacePlugin.prototype.initialize = function (editor) {
26308
+ this.editor = editor;
26309
+ this.triggerKeys = this.customReplacements.map(function (replacement) {
26310
+ return replacement.stringToReplace.slice(-1);
26311
+ });
26312
+ };
26313
+ /**
26314
+ * The last method that editor will call to a plugin before it is disposed.
26315
+ * Plugin can take this chance to clear the reference to editor. After this method is
26316
+ * called, plugin should not call to any editor method since it will result in error.
26317
+ */
26318
+ CustomReplacePlugin.prototype.dispose = function () {
26319
+ this.editor = null;
26320
+ };
26321
+ /**
26322
+ * Core method for a plugin. Once an event happens in editor, editor will call this
26323
+ * method of each plugin to handle the event as long as the event is not handled
26324
+ * exclusively by another plugin.
26325
+ * @param event The event to handle:
26326
+ */
26327
+ CustomReplacePlugin.prototype.onPluginEvent = function (event) {
26328
+ if (this.editor) {
26329
+ switch (event.eventType) {
26330
+ case 'input':
26331
+ this.handleEditorInputEvent(this.editor, event);
26332
+ break;
26333
+ }
26334
+ }
26335
+ };
26336
+ CustomReplacePlugin.prototype.handleEditorInputEvent = function (editor, event) {
26337
+ var _this = this;
26338
+ var rawEvent = event.rawEvent;
26339
+ var selection = editor.getDOMSelection();
26340
+ var key = rawEvent.data;
26341
+ if (this.customReplacements.length > 0 &&
26342
+ rawEvent.inputType === 'insertText' &&
26343
+ selection &&
26344
+ selection.type === 'range' &&
26345
+ selection.range.collapsed &&
26346
+ key &&
26347
+ this.triggerKeys.indexOf(key) > -1) {
26348
+ (0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(editor, function (_model, previousSegment, paragraph, _markerFormat, context) {
26349
+ var replaced = _this.customReplacements.some(function (_a) {
26350
+ var stringToReplace = _a.stringToReplace, replacementString = _a.replacementString, replacementHandler = _a.replacementHandler;
26351
+ return replacementHandler(previousSegment, stringToReplace, replacementString, paragraph);
26352
+ });
26353
+ if (replaced) {
26354
+ context.canUndoByBackspace = true;
26355
+ return true;
26356
+ }
26357
+ return false;
26358
+ });
26359
+ }
26360
+ };
26361
+ return CustomReplacePlugin;
26362
+ }());
26363
+ exports.CustomReplacePlugin = CustomReplacePlugin;
26364
+
26365
+
26366
+ /***/ }),
26367
+
26368
+ /***/ "./packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts":
26369
+ /*!*************************************************************************!*\
25610
26370
  !*** ./packages/roosterjs-content-model-plugins/lib/edit/EditPlugin.ts ***!
25611
26371
  \*************************************************************************/
25612
26372
  /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
@@ -25687,11 +26447,18 @@ var EditPlugin = /** @class */ (function () {
25687
26447
  if (!rawEvent.defaultPrevented && !event.handledByEditFeature) {
25688
26448
  switch (rawEvent.key) {
25689
26449
  case 'Backspace':
25690
- case 'Delete':
25691
26450
  // Use our API to handle BACKSPACE/DELETE key.
25692
26451
  // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache
25693
26452
  (0, keyboardDelete_1.keyboardDelete)(editor, rawEvent);
25694
26453
  break;
26454
+ case 'Delete':
26455
+ // Use our API to handle BACKSPACE/DELETE key.
26456
+ // No need to clear cache here since if we rely on browser's behavior, there will be Input event and its handler will reconcile cache
26457
+ // And leave it to browser when shift key is pressed so that browser will trigger cut event
26458
+ if (!event.rawEvent.shiftKey) {
26459
+ (0, keyboardDelete_1.keyboardDelete)(editor, rawEvent);
26460
+ }
26461
+ break;
25695
26462
  case 'Tab':
25696
26463
  (0, keyboardTab_1.keyboardTab)(editor, rawEvent);
25697
26464
  break;
@@ -25708,6 +26475,8 @@ var EditPlugin = /** @class */ (function () {
25708
26475
  }
25709
26476
  };
25710
26477
  EditPlugin.prototype.handleBeforeInputEvent = function (editor, rawEvent) {
26478
+ var _this = this;
26479
+ var _a, _b;
25711
26480
  // Some Android IMEs doesn't fire correct keydown event for BACKSPACE/DELETE key
25712
26481
  // Here we translate input event to BACKSPACE/DELETE keydown event to be compatible with existing logic
25713
26482
  if (!this.shouldHandleNextInputEvent ||
@@ -25735,6 +26504,15 @@ var EditPlugin = /** @class */ (function () {
25735
26504
  }
25736
26505
  if (handled) {
25737
26506
  rawEvent.preventDefault();
26507
+ // Restore the selection to avoid the cursor jump issue
26508
+ // See: https://issues.chromium.org/issues/330596261
26509
+ var selection_1 = editor.getDOMSelection();
26510
+ var doc = (_a = this.editor) === null || _a === void 0 ? void 0 : _a.getDocument();
26511
+ (_b = doc === null || doc === void 0 ? void 0 : doc.defaultView) === null || _b === void 0 ? void 0 : _b.requestAnimationFrame(function () {
26512
+ if (_this.editor) {
26513
+ _this.editor.setDOMSelection(selection_1);
26514
+ }
26515
+ });
25738
26516
  }
25739
26517
  };
25740
26518
  return EditPlugin;
@@ -26266,6 +27044,7 @@ exports.shouldDeleteAllSegmentsBefore = shouldDeleteAllSegmentsBefore;
26266
27044
  Object.defineProperty(exports, "__esModule", ({ value: true }));
26267
27045
  exports.handleEnterOnList = void 0;
26268
27046
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
27047
+ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-model-api */ "./packages/roosterjs-content-model-api/lib/index.ts");
26269
27048
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
26270
27049
  /**
26271
27050
  * @internal
@@ -26312,7 +27091,12 @@ var handleEnterOnList = function (context) {
26312
27091
  listItem_1.levels.pop();
26313
27092
  }
26314
27093
  else {
26315
- createNewListItem(context, listItem_1, listParent);
27094
+ var newListItem = createNewListItem(context, listItem_1, listParent);
27095
+ if (context.formatContext) {
27096
+ context.formatContext.announceData = (0, roosterjs_content_model_api_1.getListAnnounceData)((0, tslib_1.__spreadArray)([
27097
+ newListItem
27098
+ ], (0, tslib_1.__read)(path.slice(index + 1)), false));
27099
+ }
26316
27100
  }
26317
27101
  }
26318
27102
  rawEvent === null || rawEvent === void 0 ? void 0 : rawEvent.preventDefault();
@@ -26338,6 +27122,7 @@ var createNewListItem = function (context, listItem, listParent) {
26338
27122
  insertPoint.paragraph = newParagraph;
26339
27123
  context.lastParagraph = newParagraph;
26340
27124
  listParent.blocks.splice(listIndex + 1, 0, newListItem);
27125
+ return newListItem;
26341
27126
  };
26342
27127
  var createNewListLevel = function (listItem) {
26343
27128
  return listItem.levels.map(function (level) {
@@ -26398,6 +27183,7 @@ function keyboardDelete(editor, rawEvent) {
26398
27183
  rawEvent: rawEvent,
26399
27184
  changeSource: roosterjs_content_model_dom_1.ChangeSource.Keyboard,
26400
27185
  getChangeData: function () { return rawEvent.which; },
27186
+ scrollCaretIntoView: true,
26401
27187
  apiName: rawEvent.key == 'Delete' ? 'handleDeleteKey' : 'handleBackspaceKey',
26402
27188
  });
26403
27189
  }
@@ -26490,6 +27276,7 @@ function keyboardInput(editor, rawEvent) {
26490
27276
  return false;
26491
27277
  }
26492
27278
  }, {
27279
+ scrollCaretIntoView: true,
26493
27280
  rawEvent: rawEvent,
26494
27281
  });
26495
27282
  return true;
@@ -26543,8 +27330,8 @@ function keyboardTab(editor, rawEvent) {
26543
27330
  var selection = editor.getDOMSelection();
26544
27331
  switch (selection === null || selection === void 0 ? void 0 : selection.type) {
26545
27332
  case 'range':
26546
- editor.formatContentModel(function (model) {
26547
- return handleTab(model, rawEvent);
27333
+ editor.formatContentModel(function (model, context) {
27334
+ return handleTab(model, rawEvent, context);
26548
27335
  }, {
26549
27336
  apiName: 'handleTabKey',
26550
27337
  });
@@ -26566,7 +27353,7 @@ exports.keyboardTab = keyboardTab;
26566
27353
  * - If it is a paragraph, call handleTabOnParagraph to handle the tab key.
26567
27354
  * - If it is a list item, call handleTabOnList to handle the tab key.
26568
27355
  */
26569
- function handleTab(model, rawEvent) {
27356
+ function handleTab(model, rawEvent, context) {
26570
27357
  var blocks = (0, roosterjs_content_model_dom_1.getOperationalBlocks)(model, ['ListItem', 'TableCell'], []);
26571
27358
  var block = blocks.length > 0 ? blocks[0].block : undefined;
26572
27359
  if (blocks.length > 1) {
@@ -26578,10 +27365,10 @@ function handleTab(model, rawEvent) {
26578
27365
  return (0, handleTabOnTableCell_1.handleTabOnTableCell)(model, block, rawEvent);
26579
27366
  }
26580
27367
  else if ((block === null || block === void 0 ? void 0 : block.blockType) === 'Paragraph') {
26581
- return (0, handleTabOnParagraph_1.handleTabOnParagraph)(model, block, rawEvent);
27368
+ return (0, handleTabOnParagraph_1.handleTabOnParagraph)(model, block, rawEvent, context);
26582
27369
  }
26583
27370
  else if ((0, roosterjs_content_model_dom_1.isBlockGroupOfType)(block, 'ListItem')) {
26584
- return (0, handleTabOnList_1.handleTabOnList)(model, block, rawEvent);
27371
+ return (0, handleTabOnList_1.handleTabOnList)(model, block, rawEvent, context);
26585
27372
  }
26586
27373
  return false;
26587
27374
  }
@@ -26606,15 +27393,15 @@ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-mo
26606
27393
  * 2. Otherwise call handleTabOnParagraph.
26607
27394
  * @internal
26608
27395
  */
26609
- function handleTabOnList(model, listItem, rawEvent) {
27396
+ function handleTabOnList(model, listItem, rawEvent, context) {
26610
27397
  var selectedParagraph = findSelectedParagraph(listItem);
26611
27398
  if (!isMarkerAtStartOfBlock(listItem) &&
26612
27399
  selectedParagraph.length == 1 &&
26613
27400
  selectedParagraph[0].blockType === 'Paragraph') {
26614
- return (0, handleTabOnParagraph_1.handleTabOnParagraph)(model, selectedParagraph[0], rawEvent);
27401
+ return (0, handleTabOnParagraph_1.handleTabOnParagraph)(model, selectedParagraph[0], rawEvent, context);
26615
27402
  }
26616
27403
  else {
26617
- (0, roosterjs_content_model_api_1.setModelIndentation)(model, rawEvent.shiftKey ? 'outdent' : 'indent');
27404
+ (0, roosterjs_content_model_api_1.setModelIndentation)(model, rawEvent.shiftKey ? 'outdent' : 'indent', undefined /*length*/, context);
26618
27405
  rawEvent.preventDefault();
26619
27406
  return true;
26620
27407
  }
@@ -26662,7 +27449,7 @@ var space = ' ';
26662
27449
  * 4. When the selection is not collapsed, replace the selected range with a 4 space.
26663
27450
  * 5. When the selection is not collapsed, but all segments are selected, call setModelIndention function to outdent the whole paragraph
26664
27451
  */
26665
- function handleTabOnParagraph(model, paragraph, rawEvent) {
27452
+ function handleTabOnParagraph(model, paragraph, rawEvent, context) {
26666
27453
  var selectedSegments = paragraph.segments.filter(function (segment) { return segment.isSelected; });
26667
27454
  var isCollapsed = selectedSegments.length === 1 && selectedSegments[0].segmentType === 'SelectionMarker';
26668
27455
  var isAllSelected = paragraph.segments.every(function (segment) { return segment.isSelected; });
@@ -26674,7 +27461,7 @@ function handleTabOnParagraph(model, paragraph, rawEvent) {
26674
27461
  (isRtl && (!marginRight || marginRight == '0px')))) {
26675
27462
  return false;
26676
27463
  }
26677
- (0, roosterjs_content_model_api_1.setModelIndentation)(model, rawEvent.shiftKey ? 'outdent' : 'indent');
27464
+ (0, roosterjs_content_model_api_1.setModelIndentation)(model, rawEvent.shiftKey ? 'outdent' : 'indent', undefined /*length*/, context);
26678
27465
  }
26679
27466
  else {
26680
27467
  if (!isCollapsed) {
@@ -26989,7 +27776,7 @@ var HyperlinkPlugin = /** @class */ (function () {
26989
27776
  */
26990
27777
  HyperlinkPlugin.prototype.onPluginEvent = function (event) {
26991
27778
  var _this = this;
26992
- var _a, _b;
27779
+ var _a, _b, _c;
26993
27780
  var matchedLink;
26994
27781
  if (event.eventType == 'keyDown') {
26995
27782
  var selection = (_a = this.editor) === null || _a === void 0 ? void 0 : _a.getDOMSelection();
@@ -27034,6 +27821,9 @@ var HyperlinkPlugin = /** @class */ (function () {
27034
27821
  }
27035
27822
  });
27036
27823
  }
27824
+ else if (event.eventType == 'contentChanged') {
27825
+ (_c = this.domHelper) === null || _c === void 0 ? void 0 : _c.setDomAttribute('title', null /*value*/);
27826
+ }
27037
27827
  };
27038
27828
  HyperlinkPlugin.prototype.runWithHyperlink = function (node, callback) {
27039
27829
  var _a;
@@ -27062,7 +27852,7 @@ exports.HyperlinkPlugin = HyperlinkPlugin;
27062
27852
  "use strict";
27063
27853
 
27064
27854
  Object.defineProperty(exports, "__esModule", ({ value: true }));
27065
- exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.WatermarkPlugin = exports.ContextMenuPluginBase = exports.ShortcutPlugin = exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoMacOS = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = exports.AutoFormatPlugin = exports.EditPlugin = exports.PastePlugin = exports.TableEditPlugin = void 0;
27855
+ exports.getDOMInsertPointRect = exports.CustomReplacePlugin = exports.PickerPlugin = exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.WatermarkPlugin = exports.ContextMenuPluginBase = exports.ShortcutPlugin = exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoMacOS = exports.ShortcutRedoAlt = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = exports.AutoFormatPlugin = exports.EditPlugin = exports.PastePlugin = exports.TableEditPlugin = void 0;
27066
27856
  var TableEditPlugin_1 = __webpack_require__(/*! ./tableEdit/TableEditPlugin */ "./packages/roosterjs-content-model-plugins/lib/tableEdit/TableEditPlugin.ts");
27067
27857
  Object.defineProperty(exports, "TableEditPlugin", ({ enumerable: true, get: function () { return TableEditPlugin_1.TableEditPlugin; } }));
27068
27858
  var PastePlugin_1 = __webpack_require__(/*! ./paste/PastePlugin */ "./packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts");
@@ -27079,6 +27869,7 @@ Object.defineProperty(exports, "ShortcutClearFormat", ({ enumerable: true, get:
27079
27869
  Object.defineProperty(exports, "ShortcutUndo", ({ enumerable: true, get: function () { return shortcuts_1.ShortcutUndo; } }));
27080
27870
  Object.defineProperty(exports, "ShortcutUndo2", ({ enumerable: true, get: function () { return shortcuts_1.ShortcutUndo2; } }));
27081
27871
  Object.defineProperty(exports, "ShortcutRedo", ({ enumerable: true, get: function () { return shortcuts_1.ShortcutRedo; } }));
27872
+ Object.defineProperty(exports, "ShortcutRedoAlt", ({ enumerable: true, get: function () { return shortcuts_1.ShortcutRedoAlt; } }));
27082
27873
  Object.defineProperty(exports, "ShortcutRedoMacOS", ({ enumerable: true, get: function () { return shortcuts_1.ShortcutRedoMacOS; } }));
27083
27874
  Object.defineProperty(exports, "ShortcutBullet", ({ enumerable: true, get: function () { return shortcuts_1.ShortcutBullet; } }));
27084
27875
  Object.defineProperty(exports, "ShortcutNumbering", ({ enumerable: true, get: function () { return shortcuts_1.ShortcutNumbering; } }));
@@ -27096,6 +27887,12 @@ var MarkdownPlugin_1 = __webpack_require__(/*! ./markdown/MarkdownPlugin */ "./p
27096
27887
  Object.defineProperty(exports, "MarkdownPlugin", ({ enumerable: true, get: function () { return MarkdownPlugin_1.MarkdownPlugin; } }));
27097
27888
  var HyperlinkPlugin_1 = __webpack_require__(/*! ./hyperlink/HyperlinkPlugin */ "./packages/roosterjs-content-model-plugins/lib/hyperlink/HyperlinkPlugin.ts");
27098
27889
  Object.defineProperty(exports, "HyperlinkPlugin", ({ enumerable: true, get: function () { return HyperlinkPlugin_1.HyperlinkPlugin; } }));
27890
+ var PickerPlugin_1 = __webpack_require__(/*! ./picker/PickerPlugin */ "./packages/roosterjs-content-model-plugins/lib/picker/PickerPlugin.ts");
27891
+ Object.defineProperty(exports, "PickerPlugin", ({ enumerable: true, get: function () { return PickerPlugin_1.PickerPlugin; } }));
27892
+ var CustomReplacePlugin_1 = __webpack_require__(/*! ./customReplace/CustomReplacePlugin */ "./packages/roosterjs-content-model-plugins/lib/customReplace/CustomReplacePlugin.ts");
27893
+ Object.defineProperty(exports, "CustomReplacePlugin", ({ enumerable: true, get: function () { return CustomReplacePlugin_1.CustomReplacePlugin; } }));
27894
+ var getDOMInsertPointRect_1 = __webpack_require__(/*! ./pluginUtils/Rect/getDOMInsertPointRect */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/Rect/getDOMInsertPointRect.ts");
27895
+ Object.defineProperty(exports, "getDOMInsertPointRect", ({ enumerable: true, get: function () { return getDOMInsertPointRect_1.getDOMInsertPointRect; } }));
27099
27896
 
27100
27897
 
27101
27898
  /***/ }),
@@ -27332,16 +28129,18 @@ function setFormat(editor, character, format, codeFormat) {
27332
28129
  var firstCharIndex = previousSegment.text
27333
28130
  .substring(0, lastCharIndex - 1)
27334
28131
  .lastIndexOf(character);
27335
- var formattedText = (0, splitTextSegment_1.splitTextSegment)(previousSegment, paragraph, firstCharIndex, lastCharIndex);
27336
- formattedText.text = formattedText.text.replace(character, '').slice(0, -1);
27337
- formattedText.format = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, formattedText.format), format);
27338
- if (codeFormat) {
27339
- formattedText.code = {
27340
- format: codeFormat,
27341
- };
28132
+ if (lastCharIndex - firstCharIndex > 2) {
28133
+ var formattedText = (0, splitTextSegment_1.splitTextSegment)(previousSegment, paragraph, firstCharIndex, lastCharIndex);
28134
+ formattedText.text = formattedText.text.replace(character, '').slice(0, -1);
28135
+ formattedText.format = (0, tslib_1.__assign)((0, tslib_1.__assign)({}, formattedText.format), format);
28136
+ if (codeFormat) {
28137
+ formattedText.code = {
28138
+ format: codeFormat,
28139
+ };
28140
+ }
28141
+ context.canUndoByBackspace = true;
28142
+ return true;
27342
28143
  }
27343
- context.canUndoByBackspace = true;
27344
- return true;
27345
28144
  }
27346
28145
  }
27347
28146
  return false;
@@ -28718,6 +29517,343 @@ function setProcessor(domToModelOption, entry, processorOverride) {
28718
29517
  exports.setProcessor = setProcessor;
28719
29518
 
28720
29519
 
29520
+ /***/ }),
29521
+
29522
+ /***/ "./packages/roosterjs-content-model-plugins/lib/picker/PickerHelperImpl.ts":
29523
+ /*!*********************************************************************************!*\
29524
+ !*** ./packages/roosterjs-content-model-plugins/lib/picker/PickerHelperImpl.ts ***!
29525
+ \*********************************************************************************/
29526
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
29527
+
29528
+ "use strict";
29529
+
29530
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
29531
+ exports.PickerHelperImpl = void 0;
29532
+ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-model-api */ "./packages/roosterjs-content-model-api/lib/index.ts");
29533
+ var getQueryString_1 = __webpack_require__(/*! ./getQueryString */ "./packages/roosterjs-content-model-plugins/lib/picker/getQueryString.ts");
29534
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
29535
+ /**
29536
+ * @internal
29537
+ */
29538
+ var PickerHelperImpl = /** @class */ (function () {
29539
+ function PickerHelperImpl(editor, handler, triggerCharacter) {
29540
+ this.editor = editor;
29541
+ this.handler = handler;
29542
+ this.triggerCharacter = triggerCharacter;
29543
+ this.direction = null;
29544
+ }
29545
+ /**
29546
+ * Replace the query string with a given Content Model.
29547
+ * This is used for commit a change from picker and insert the committed content into editor.
29548
+ * @param model The Content Model to insert
29549
+ * @param options Options for formatting content model
29550
+ * @param canUndoByBackspace Whether this change can be undone using Backspace key
29551
+ */
29552
+ PickerHelperImpl.prototype.replaceQueryString = function (model, options, canUndoByBackspace) {
29553
+ var _this = this;
29554
+ this.editor.focus();
29555
+ (0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(this.editor, function (target, previousSegment, paragraph, _, context) {
29556
+ var potentialSegments = [];
29557
+ var queryString = (0, getQueryString_1.getQueryString)(_this.triggerCharacter, paragraph, previousSegment, potentialSegments);
29558
+ if (queryString) {
29559
+ potentialSegments.forEach(function (x) { return (x.isSelected = true); });
29560
+ (0, roosterjs_content_model_dom_1.mergeModel)(target, model, context);
29561
+ context.canUndoByBackspace = canUndoByBackspace;
29562
+ return true;
29563
+ }
29564
+ else {
29565
+ return false;
29566
+ }
29567
+ }, options);
29568
+ };
29569
+ /**
29570
+ * Notify Picker Plugin that picker is closed from the handler code, so picker plugin can quit the suggesting state
29571
+ */
29572
+ PickerHelperImpl.prototype.closePicker = function () {
29573
+ var _a, _b;
29574
+ if (this.direction) {
29575
+ this.direction = null;
29576
+ (_b = (_a = this.handler).onClosePicker) === null || _b === void 0 ? void 0 : _b.call(_a);
29577
+ }
29578
+ };
29579
+ return PickerHelperImpl;
29580
+ }());
29581
+ exports.PickerHelperImpl = PickerHelperImpl;
29582
+
29583
+
29584
+ /***/ }),
29585
+
29586
+ /***/ "./packages/roosterjs-content-model-plugins/lib/picker/PickerPlugin.ts":
29587
+ /*!*****************************************************************************!*\
29588
+ !*** ./packages/roosterjs-content-model-plugins/lib/picker/PickerPlugin.ts ***!
29589
+ \*****************************************************************************/
29590
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
29591
+
29592
+ "use strict";
29593
+
29594
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
29595
+ exports.PickerPlugin = void 0;
29596
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
29597
+ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-model-api */ "./packages/roosterjs-content-model-api/lib/index.ts");
29598
+ var getQueryString_1 = __webpack_require__(/*! ./getQueryString */ "./packages/roosterjs-content-model-plugins/lib/picker/getQueryString.ts");
29599
+ var PickerHelperImpl_1 = __webpack_require__(/*! ./PickerHelperImpl */ "./packages/roosterjs-content-model-plugins/lib/picker/PickerHelperImpl.ts");
29600
+ /**
29601
+ * PickerPlugin represents a plugin of editor which can handle picker related behaviors, including
29602
+ * - Show picker when special trigger key is pressed
29603
+ * - Hide picker
29604
+ * - Change selection in picker by Up/Down/Left/Right
29605
+ * - Apply selected item in picker
29606
+ *
29607
+ * PickerPlugin doesn't provide any UI, it just wraps related DOM events and invoke callback functions.
29608
+ */
29609
+ var PickerPlugin = /** @class */ (function () {
29610
+ /**
29611
+ * Construct a new instance of PickerPlugin class
29612
+ * @param triggerCharacter The character to trigger a picker to be shown
29613
+ * @param handler Picker handler for receiving picker state change events
29614
+ */
29615
+ function PickerPlugin(triggerCharacter, handler) {
29616
+ this.triggerCharacter = triggerCharacter;
29617
+ this.handler = handler;
29618
+ this.isMac = false;
29619
+ this.lastQueryString = '';
29620
+ this.helper = null;
29621
+ }
29622
+ /**
29623
+ * Get a friendly name
29624
+ */
29625
+ PickerPlugin.prototype.getName = function () {
29626
+ return 'Picker';
29627
+ };
29628
+ /**
29629
+ * Initialize this plugin. This should only be called from Editor
29630
+ * @param editor Editor instance
29631
+ */
29632
+ PickerPlugin.prototype.initialize = function (editor) {
29633
+ this.isMac = !!editor.getEnvironment().isMac;
29634
+ this.helper = new PickerHelperImpl_1.PickerHelperImpl(editor, this.handler, this.triggerCharacter);
29635
+ this.handler.onInitialize(this.helper);
29636
+ };
29637
+ /**
29638
+ * Dispose this plugin
29639
+ */
29640
+ PickerPlugin.prototype.dispose = function () {
29641
+ this.handler.onDispose();
29642
+ this.helper = null;
29643
+ };
29644
+ /**
29645
+ * Check if the plugin should handle the given event exclusively.
29646
+ * Handle an event exclusively means other plugin will not receive this event in
29647
+ * onPluginEvent method.
29648
+ * If two plugins will return true in willHandleEventExclusively() for the same event,
29649
+ * the final result depends on the order of the plugins are added into editor
29650
+ * @param event The event to check
29651
+ */
29652
+ PickerPlugin.prototype.willHandleEventExclusively = function (event) {
29653
+ var _a;
29654
+ return (!!((_a = this.helper) === null || _a === void 0 ? void 0 : _a.direction) &&
29655
+ event.eventType == 'keyDown' &&
29656
+ ((0, roosterjs_content_model_dom_1.isCursorMovingKey)(event.rawEvent) ||
29657
+ event.rawEvent.key == 'Enter' ||
29658
+ event.rawEvent.key == 'Tab' ||
29659
+ event.rawEvent.key == 'Escape'));
29660
+ };
29661
+ /**
29662
+ * Handle events triggered from editor
29663
+ * @param event PluginEvent object
29664
+ */
29665
+ PickerPlugin.prototype.onPluginEvent = function (event) {
29666
+ if (!this.helper) {
29667
+ return;
29668
+ }
29669
+ switch (event.eventType) {
29670
+ case 'contentChanged':
29671
+ if (this.helper.direction) {
29672
+ if (event.source == roosterjs_content_model_dom_1.ChangeSource.SetContent) {
29673
+ this.helper.closePicker();
29674
+ }
29675
+ else {
29676
+ this.onSuggestingInput(this.helper);
29677
+ }
29678
+ }
29679
+ break;
29680
+ case 'keyDown':
29681
+ if (this.helper.direction) {
29682
+ this.onSuggestingKeyDown(this.helper, event.rawEvent);
29683
+ }
29684
+ break;
29685
+ case 'input':
29686
+ if (this.helper.direction) {
29687
+ this.onSuggestingInput(this.helper);
29688
+ }
29689
+ else {
29690
+ this.onInput(this.helper, event.rawEvent);
29691
+ }
29692
+ break;
29693
+ case 'mouseUp':
29694
+ if (this.helper.direction) {
29695
+ this.helper.closePicker();
29696
+ }
29697
+ break;
29698
+ }
29699
+ };
29700
+ PickerPlugin.prototype.onSuggestingKeyDown = function (helper, event) {
29701
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
29702
+ switch (event.key) {
29703
+ case 'ArrowLeft':
29704
+ case 'ArrowRight':
29705
+ if (helper.direction == 'horizontal' || helper.direction == 'both') {
29706
+ var isIncrement = event.key == 'ArrowRight';
29707
+ if (helper.editor.getDOMHelper().isRightToLeft()) {
29708
+ isIncrement = !isIncrement;
29709
+ }
29710
+ (_b = (_a = this.handler).onSelectionChanged) === null || _b === void 0 ? void 0 : _b.call(_a, isIncrement ? 'next' : 'previous');
29711
+ }
29712
+ event.preventDefault();
29713
+ break;
29714
+ case 'ArrowUp':
29715
+ case 'ArrowDown':
29716
+ {
29717
+ var isIncrement = event.key == 'ArrowDown';
29718
+ if (helper.direction != 'horizontal') {
29719
+ (_d = (_c = this.handler).onSelectionChanged) === null || _d === void 0 ? void 0 : _d.call(_c, helper.direction == 'both'
29720
+ ? isIncrement
29721
+ ? 'nextRow'
29722
+ : 'previousRow'
29723
+ : isIncrement
29724
+ ? 'next'
29725
+ : 'previous');
29726
+ }
29727
+ }
29728
+ event.preventDefault();
29729
+ break;
29730
+ case 'PageUp':
29731
+ case 'PageDown':
29732
+ (_f = (_e = this.handler).onSelectionChanged) === null || _f === void 0 ? void 0 : _f.call(_e, event.key == 'PageDown' ? 'nextPage' : 'previousPage');
29733
+ event.preventDefault();
29734
+ break;
29735
+ case 'Home':
29736
+ case 'End':
29737
+ var hasCtrl = this.isMac ? event.metaKey : event.ctrlKey;
29738
+ (_h = (_g = this.handler).onSelectionChanged) === null || _h === void 0 ? void 0 : _h.call(_g, event.key == 'Home'
29739
+ ? hasCtrl
29740
+ ? 'first'
29741
+ : 'firstInRow'
29742
+ : hasCtrl
29743
+ ? 'last'
29744
+ : 'lastInRow');
29745
+ event.preventDefault();
29746
+ break;
29747
+ case 'Escape':
29748
+ helper.closePicker();
29749
+ event.preventDefault();
29750
+ break;
29751
+ case 'Enter':
29752
+ case 'Tab':
29753
+ (_k = (_j = this.handler).onSelect) === null || _k === void 0 ? void 0 : _k.call(_j);
29754
+ event.preventDefault();
29755
+ break;
29756
+ }
29757
+ };
29758
+ PickerPlugin.prototype.onSuggestingInput = function (helper) {
29759
+ var _this = this;
29760
+ if (!(0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(helper.editor, function (_, segment, paragraph) {
29761
+ var _a, _b;
29762
+ var newQueryString = (0, getQueryString_1.getQueryString)(_this.triggerCharacter, paragraph, segment).replace(/[\u0020\u00A0]/g, ' ');
29763
+ var oldQueryString = _this.lastQueryString;
29764
+ if (newQueryString &&
29765
+ ((newQueryString.length >= oldQueryString.length &&
29766
+ newQueryString.indexOf(oldQueryString) == 0) ||
29767
+ (newQueryString.length < oldQueryString.length &&
29768
+ oldQueryString.indexOf(newQueryString) == 0))) {
29769
+ _this.lastQueryString = newQueryString;
29770
+ (_b = (_a = _this.handler).onQueryStringChanged) === null || _b === void 0 ? void 0 : _b.call(_a, newQueryString);
29771
+ }
29772
+ else {
29773
+ helper.closePicker();
29774
+ }
29775
+ return false;
29776
+ })) {
29777
+ helper.closePicker();
29778
+ }
29779
+ };
29780
+ PickerPlugin.prototype.onInput = function (helper, event) {
29781
+ var _this = this;
29782
+ if (event.inputType == 'insertText' && event.data == this.triggerCharacter) {
29783
+ (0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(helper.editor, function (_, segment) {
29784
+ if (segment.text.endsWith(_this.triggerCharacter)) {
29785
+ var charBeforeTrigger = segment.text[segment.text.length - 2];
29786
+ if (!charBeforeTrigger ||
29787
+ !charBeforeTrigger.trim() ||
29788
+ (0, roosterjs_content_model_dom_1.isPunctuation)(charBeforeTrigger)) {
29789
+ var selection = helper.editor.getDOMSelection();
29790
+ var pos = (selection === null || selection === void 0 ? void 0 : selection.type) == 'range' && selection.range.collapsed
29791
+ ? {
29792
+ node: selection.range.startContainer,
29793
+ offset: selection.range.startOffset,
29794
+ }
29795
+ : null;
29796
+ if (pos) {
29797
+ _this.lastQueryString = _this.triggerCharacter;
29798
+ helper.direction = _this.handler.onTrigger(_this.lastQueryString, pos);
29799
+ }
29800
+ }
29801
+ }
29802
+ return false;
29803
+ });
29804
+ }
29805
+ };
29806
+ return PickerPlugin;
29807
+ }());
29808
+ exports.PickerPlugin = PickerPlugin;
29809
+
29810
+
29811
+ /***/ }),
29812
+
29813
+ /***/ "./packages/roosterjs-content-model-plugins/lib/picker/getQueryString.ts":
29814
+ /*!*******************************************************************************!*\
29815
+ !*** ./packages/roosterjs-content-model-plugins/lib/picker/getQueryString.ts ***!
29816
+ \*******************************************************************************/
29817
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
29818
+
29819
+ "use strict";
29820
+
29821
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
29822
+ exports.getQueryString = void 0;
29823
+ var splitTextSegment_1 = __webpack_require__(/*! ../pluginUtils/splitTextSegment */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/splitTextSegment.ts");
29824
+ /**
29825
+ * @internal
29826
+ */
29827
+ function getQueryString(triggerCharacter, paragraph, previousSegment, splittedSegmentResult) {
29828
+ var result = '';
29829
+ var i = paragraph.segments.indexOf(previousSegment);
29830
+ for (; i >= 0; i--) {
29831
+ var segment = paragraph.segments[i];
29832
+ if (segment.segmentType != 'Text') {
29833
+ result = '';
29834
+ break;
29835
+ }
29836
+ var index = segment.text.lastIndexOf(triggerCharacter);
29837
+ if (index >= 0) {
29838
+ result = segment.text.substring(index) + result;
29839
+ splittedSegmentResult === null || splittedSegmentResult === void 0 ? void 0 : splittedSegmentResult.unshift(index > 0
29840
+ ? (0, splitTextSegment_1.splitTextSegment)(segment, paragraph, index, segment.text.length)
29841
+ : segment);
29842
+ break;
29843
+ }
29844
+ else {
29845
+ result = segment.text + result;
29846
+ splittedSegmentResult === null || splittedSegmentResult === void 0 ? void 0 : splittedSegmentResult.unshift(segment);
29847
+ }
29848
+ }
29849
+ if (i < 0) {
29850
+ result = '';
29851
+ }
29852
+ return result;
29853
+ }
29854
+ exports.getQueryString = getQueryString;
29855
+
29856
+
28721
29857
  /***/ }),
28722
29858
 
28723
29859
  /***/ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/CreateElement/createElement.ts":
@@ -28911,6 +30047,73 @@ var DragAndDropHelper = /** @class */ (function () {
28911
30047
  exports.DragAndDropHelper = DragAndDropHelper;
28912
30048
 
28913
30049
 
30050
+ /***/ }),
30051
+
30052
+ /***/ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/Rect/getDOMInsertPointRect.ts":
30053
+ /*!************************************************************************************************!*\
30054
+ !*** ./packages/roosterjs-content-model-plugins/lib/pluginUtils/Rect/getDOMInsertPointRect.ts ***!
30055
+ \************************************************************************************************/
30056
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
30057
+
30058
+ "use strict";
30059
+
30060
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
30061
+ exports.getDOMInsertPointRect = void 0;
30062
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30063
+ /**
30064
+ * Get bounding rect of the given DOM insert point
30065
+ * @param doc The document object
30066
+ * @param pos The input DOM insert point
30067
+ */
30068
+ function getDOMInsertPointRect(doc, pos) {
30069
+ var _a;
30070
+ var node = pos.node, offset = pos.offset;
30071
+ var range = doc.createRange();
30072
+ range.setStart(node, offset);
30073
+ // 1) try to get rect using range.getBoundingClientRect()
30074
+ var rect = (0, roosterjs_content_model_dom_1.normalizeRect)(range.getBoundingClientRect());
30075
+ if (rect) {
30076
+ return rect;
30077
+ }
30078
+ // 2) try to get rect using range.getClientRects
30079
+ while (node.lastChild) {
30080
+ if (offset == node.childNodes.length) {
30081
+ node = node.lastChild;
30082
+ offset = node.childNodes.length;
30083
+ }
30084
+ else {
30085
+ node = node.childNodes[offset];
30086
+ offset = 0;
30087
+ }
30088
+ }
30089
+ var rects = range.getClientRects && range.getClientRects();
30090
+ rect = rects && rects.length == 1 ? (0, roosterjs_content_model_dom_1.normalizeRect)(rects[0]) : null;
30091
+ if (rect) {
30092
+ return rect;
30093
+ }
30094
+ // 3) if node is text node, try inserting a SPAN and get the rect of SPAN for others
30095
+ if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'TEXT_NODE')) {
30096
+ var span = node.ownerDocument.createElement('span');
30097
+ span.textContent = '\u200b';
30098
+ range.insertNode(span);
30099
+ rect = (0, roosterjs_content_model_dom_1.normalizeRect)(span.getBoundingClientRect());
30100
+ (_a = span.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(span);
30101
+ if (rect) {
30102
+ return rect;
30103
+ }
30104
+ }
30105
+ // 4) try getBoundingClientRect on element
30106
+ if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'ELEMENT_NODE') && node.getBoundingClientRect) {
30107
+ rect = (0, roosterjs_content_model_dom_1.normalizeRect)(node.getBoundingClientRect());
30108
+ if (rect) {
30109
+ return rect;
30110
+ }
30111
+ }
30112
+ return null;
30113
+ }
30114
+ exports.getDOMInsertPointRect = getDOMInsertPointRect;
30115
+
30116
+
28914
30117
  /***/ }),
28915
30118
 
28916
30119
  /***/ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/Rect/getIntersectedRect.ts":
@@ -29025,6 +30228,7 @@ var defaultShortcuts = [
29025
30228
  shortcuts_1.ShortcutUndo,
29026
30229
  shortcuts_1.ShortcutUndo2,
29027
30230
  shortcuts_1.ShortcutRedo,
30231
+ shortcuts_1.ShortcutRedoAlt,
29028
30232
  shortcuts_1.ShortcutRedoMacOS,
29029
30233
  shortcuts_1.ShortcutBullet,
29030
30234
  shortcuts_1.ShortcutNumbering,
@@ -29144,7 +30348,7 @@ exports.ShortcutPlugin = ShortcutPlugin;
29144
30348
  "use strict";
29145
30349
 
29146
30350
  Object.defineProperty(exports, "__esModule", ({ value: true }));
29147
- exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoMacOS = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = void 0;
30351
+ exports.ShortcutOutdentList = exports.ShortcutIndentList = exports.ShortcutDecreaseFont = exports.ShortcutIncreaseFont = exports.ShortcutNumbering = exports.ShortcutBullet = exports.ShortcutRedoAlt = exports.ShortcutRedoMacOS = exports.ShortcutRedo = exports.ShortcutUndo2 = exports.ShortcutUndo = exports.ShortcutClearFormat = exports.ShortcutUnderline = exports.ShortcutItalic = exports.ShortcutBold = void 0;
29148
30352
  var roosterjs_content_model_core_1 = __webpack_require__(/*! roosterjs-content-model-core */ "./packages/roosterjs-content-model-core/lib/index.ts");
29149
30353
  var setShortcutIndentationCommand_1 = __webpack_require__(/*! ./utils/setShortcutIndentationCommand */ "./packages/roosterjs-content-model-plugins/lib/shortcut/utils/setShortcutIndentationCommand.ts");
29150
30354
  var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-model-api */ "./packages/roosterjs-content-model-api/lib/index.ts");
@@ -29258,6 +30462,7 @@ exports.ShortcutRedo = {
29258
30462
  environment: 'nonMac',
29259
30463
  };
29260
30464
  /**
30465
+ * @deprecated
29261
30466
  * Shortcut command for Redo 2
29262
30467
  * Windows: N/A
29263
30468
  * MacOS: Meta + Shift + Z
@@ -29271,6 +30476,19 @@ exports.ShortcutRedoMacOS = {
29271
30476
  onClick: function (editor) { return (0, roosterjs_content_model_core_1.redo)(editor); },
29272
30477
  environment: 'mac',
29273
30478
  };
30479
+ /**
30480
+ * Shortcut command for Redo 3
30481
+ * Windows: Ctrl + Shift + Z
30482
+ * MacOS: Meta + Shift + Z
30483
+ */
30484
+ exports.ShortcutRedoAlt = {
30485
+ shortcutKey: {
30486
+ modifierKey: 'ctrl',
30487
+ shiftKey: true,
30488
+ which: 90 /* Z */,
30489
+ },
30490
+ onClick: function (editor) { return (0, roosterjs_content_model_core_1.redo)(editor); },
30491
+ };
29274
30492
  /**
29275
30493
  * Shortcut command for Bullet List
29276
30494
  * Windows: Ctrl + . (Period)
@@ -29375,12 +30593,12 @@ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-mo
29375
30593
  * @internal
29376
30594
  */
29377
30595
  function setShortcutIndentationCommand(editor, operation) {
29378
- editor.formatContentModel(function (model) {
30596
+ editor.formatContentModel(function (model, context) {
29379
30597
  var listItem = (0, roosterjs_content_model_dom_1.getFirstSelectedListItem)(model);
29380
30598
  if (listItem &&
29381
30599
  listItem.blocks[0].blockType == 'Paragraph' &&
29382
30600
  listItem.blocks[0].segments[0].segmentType == 'SelectionMarker') {
29383
- (0, roosterjs_content_model_api_1.setModelIndentation)(model, operation);
30601
+ (0, roosterjs_content_model_api_1.setModelIndentation)(model, operation, undefined /*length*/, context);
29384
30602
  return true;
29385
30603
  }
29386
30604
  return false;
@@ -29413,10 +30631,14 @@ var TableEditPlugin = /** @class */ (function () {
29413
30631
  * @param anchorContainerSelector An optional selector string to specify the container to host the plugin.
29414
30632
  * The container must not be affected by transform: scale(), otherwise the position calculation will be wrong.
29415
30633
  * If not specified, the plugin will be inserted in document.body
30634
+ * @param onTableEditorCreated An optional callback to customize the Table Editors elements when created.
30635
+ * @param disableFeatures An optional array of TableEditFeatures to disable
29416
30636
  */
29417
- function TableEditPlugin(anchorContainerSelector) {
30637
+ function TableEditPlugin(anchorContainerSelector, onTableEditorCreated, disableFeatures) {
29418
30638
  var _this = this;
29419
30639
  this.anchorContainerSelector = anchorContainerSelector;
30640
+ this.onTableEditorCreated = onTableEditorCreated;
30641
+ this.disableFeatures = disableFeatures;
29420
30642
  this.editor = null;
29421
30643
  this.onMouseMoveDisposer = null;
29422
30644
  this.tableRectMap = null;
@@ -29494,6 +30716,7 @@ var TableEditPlugin = /** @class */ (function () {
29494
30716
  this.disposeTableEditor();
29495
30717
  this.editor = null;
29496
30718
  this.onMouseMoveDisposer = null;
30719
+ this.onTableEditorCreated = undefined;
29497
30720
  };
29498
30721
  /**
29499
30722
  * Handle events triggered from editor
@@ -29524,7 +30747,7 @@ var TableEditPlugin = /** @class */ (function () {
29524
30747
  var container = this.anchorContainerSelector
29525
30748
  ? this.editor.getDocument().querySelector(this.anchorContainerSelector)
29526
30749
  : undefined;
29527
- this.tableEditor = new TableEditor_1.TableEditor(this.editor, table, this.invalidateTableRects, (0, roosterjs_content_model_dom_1.isNodeOfType)(container, 'ELEMENT_NODE') ? container : undefined, event === null || event === void 0 ? void 0 : event.currentTarget);
30750
+ this.tableEditor = new TableEditor_1.TableEditor(this.editor, table, this.invalidateTableRects, (0, roosterjs_content_model_dom_1.isNodeOfType)(container, 'ELEMENT_NODE') ? container : undefined, event === null || event === void 0 ? void 0 : event.currentTarget, this.onTableEditorCreated, this.disableFeatures);
29528
30751
  }
29529
30752
  };
29530
30753
  TableEditPlugin.prototype.disposeTableEditor = function () {
@@ -29609,7 +30832,7 @@ var TOP_OR_SIDE;
29609
30832
  * When set a different current table or change current TD, we need to update these areas
29610
30833
  */
29611
30834
  var TableEditor = /** @class */ (function () {
29612
- function TableEditor(editor, table, onChanged, anchorContainer, contentDiv) {
30835
+ function TableEditor(editor, table, onChanged, anchorContainer, contentDiv, onTableEditorCreated, disableFeatures) {
29613
30836
  var _this = this;
29614
30837
  var _a;
29615
30838
  this.editor = editor;
@@ -29617,6 +30840,8 @@ var TableEditor = /** @class */ (function () {
29617
30840
  this.onChanged = onChanged;
29618
30841
  this.anchorContainer = anchorContainer;
29619
30842
  this.contentDiv = contentDiv;
30843
+ this.onTableEditorCreated = onTableEditorCreated;
30844
+ this.disableFeatures = disableFeatures;
29620
30845
  // 1, 2 - Insert a column or a row
29621
30846
  this.horizontalInserter = null;
29622
30847
  this.verticalInserter = null;
@@ -29628,6 +30853,20 @@ var TableEditor = /** @class */ (function () {
29628
30853
  // 6 - Move as well as select whole table
29629
30854
  this.tableMover = null;
29630
30855
  this.range = null;
30856
+ this.onEditorCreated = function (featureType, element) {
30857
+ var _a;
30858
+ var disposer = (_a = _this.onTableEditorCreated) === null || _a === void 0 ? void 0 : _a.call(_this, featureType, element);
30859
+ var onMouseOut = element && _this.getOnMouseOut(element);
30860
+ if (onMouseOut) {
30861
+ element.addEventListener('mouseout', onMouseOut);
30862
+ }
30863
+ return function () {
30864
+ disposer === null || disposer === void 0 ? void 0 : disposer();
30865
+ if (onMouseOut) {
30866
+ element.removeEventListener('mouseout', onMouseOut);
30867
+ }
30868
+ };
30869
+ };
29631
30870
  this.onFinishEditing = function () {
29632
30871
  _this.editor.focus();
29633
30872
  if (_this.range) {
@@ -29647,6 +30886,16 @@ var TableEditor = /** @class */ (function () {
29647
30886
  _this.disposeTableResizer();
29648
30887
  _this.onStartResize();
29649
30888
  };
30889
+ this.onStartTableMove = function () {
30890
+ _this.isCurrentlyEditing = true;
30891
+ _this.disposeTableResizer();
30892
+ _this.disposeTableInserter();
30893
+ _this.disposeCellResizers();
30894
+ };
30895
+ this.onEndTableMove = function () {
30896
+ _this.disposeTableMover();
30897
+ return _this.onFinishEditing();
30898
+ };
29650
30899
  this.onInserted = function () {
29651
30900
  _this.disposeTableResizer();
29652
30901
  _this.onFinishEditing();
@@ -29656,14 +30905,16 @@ var TableEditor = /** @class */ (function () {
29656
30905
  * @param table the table to select
29657
30906
  */
29658
30907
  this.onSelect = function (table) {
30908
+ var _a, _b;
29659
30909
  _this.editor.focus();
29660
30910
  if (table) {
30911
+ var parsedTable = (0, roosterjs_content_model_dom_1.parseTableCells)(table);
29661
30912
  var selection = {
29662
30913
  table: table,
29663
30914
  firstRow: 0,
29664
30915
  firstColumn: 0,
29665
- lastRow: table.rows.length - 1,
29666
- lastColumn: table.rows[table.rows.length - 1].cells.length - 1,
30916
+ lastRow: parsedTable.length - 1,
30917
+ lastColumn: ((_b = (_a = parsedTable[0]) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1,
29667
30918
  type: 'table',
29668
30919
  };
29669
30920
  _this.editor.setDOMSelection(selection);
@@ -29675,7 +30926,8 @@ var TableEditor = /** @class */ (function () {
29675
30926
  ev.relatedTarget != feature &&
29676
30927
  (0, roosterjs_content_model_dom_1.isNodeOfType)(_this.contentDiv, 'ELEMENT_NODE') &&
29677
30928
  (0, roosterjs_content_model_dom_1.isNodeOfType)(ev.relatedTarget, 'ELEMENT_NODE') &&
29678
- !(_this.contentDiv == ev.relatedTarget)) {
30929
+ !(_this.contentDiv == ev.relatedTarget) &&
30930
+ !_this.isEditing()) {
29679
30931
  _this.dispose();
29680
30932
  }
29681
30933
  };
@@ -29709,7 +30961,6 @@ var TableEditor = /** @class */ (function () {
29709
30961
  var _a;
29710
30962
  // Get whole table rect
29711
30963
  var tableRect = (0, roosterjs_content_model_dom_1.normalizeRect)(this.table.getBoundingClientRect());
29712
- //console.log('>>>tableRect', tableRect);
29713
30964
  if (!tableRect) {
29714
30965
  return;
29715
30966
  }
@@ -29747,7 +30998,8 @@ var TableEditor = /** @class */ (function () {
29747
30998
  if (i === 0 && topOrSide == 0 /* top */) {
29748
30999
  var center = (tdRect.left + tdRect.right) / 2;
29749
31000
  var isOnRightHalf = this.isRTL ? x < center : x > center;
29750
- this.setInserterTd(isOnRightHalf ? td : tr.cells[j - 1], false /*isHorizontal*/);
31001
+ !this.isFeatureDisabled('VerticalTableInserter') &&
31002
+ this.setInserterTd(isOnRightHalf ? td : tr.cells[j - 1], false /*isHorizontal*/);
29751
31003
  }
29752
31004
  else if (j === 0 && topOrSide == 1 /* side */) {
29753
31005
  var tdAbove = (_a = this.table.rows[i - 1]) === null || _a === void 0 ? void 0 : _a.cells[0];
@@ -29759,14 +31011,15 @@ var TableEditor = /** @class */ (function () {
29759
31011
  : this.isRTL
29760
31012
  ? tdAboveRect.right === tdRect.right
29761
31013
  : tdAboveRect.left === tdRect.left;
29762
- this.setInserterTd(y < (tdRect.top + tdRect.bottom) / 2 && isTdNotAboveMerged
29763
- ? tdAbove
29764
- : td, true /*isHorizontal*/);
31014
+ !this.isFeatureDisabled('HorizontalTableInserter') &&
31015
+ this.setInserterTd(y < (tdRect.top + tdRect.bottom) / 2 && isTdNotAboveMerged
31016
+ ? tdAbove
31017
+ : td, true /*isHorizontal*/);
29765
31018
  }
29766
31019
  else {
29767
31020
  this.setInserterTd(null);
29768
31021
  }
29769
- this.setResizingTd(td);
31022
+ !this.isFeatureDisabled('CellResizer') && this.setResizingTd(td);
29770
31023
  //Cell found
29771
31024
  break;
29772
31025
  }
@@ -29779,11 +31032,13 @@ var TableEditor = /** @class */ (function () {
29779
31032
  this.setEditorFeatures();
29780
31033
  };
29781
31034
  TableEditor.prototype.setEditorFeatures = function () {
29782
- if (!this.tableMover) {
29783
- this.tableMover = (0, TableMover_1.createTableMover)(this.table, this.editor, this.isRTL, this.onSelect, this.getOnMouseOut, this.contentDiv, this.anchorContainer);
31035
+ var disableSelector = this.isFeatureDisabled('TableSelector');
31036
+ var disableMovement = this.isFeatureDisabled('TableMover');
31037
+ if (!this.tableMover && !(disableSelector && disableMovement)) {
31038
+ this.tableMover = (0, TableMover_1.createTableMover)(this.table, this.editor, this.isRTL, disableSelector ? function () { } : this.onSelect, this.onStartTableMove, this.onEndTableMove, this.contentDiv, this.anchorContainer, this.onEditorCreated, disableMovement);
29784
31039
  }
29785
- if (!this.tableResizer) {
29786
- this.tableResizer = (0, TableResizer_1.createTableResizer)(this.table, this.editor, this.isRTL, this.onStartTableResize, this.onFinishEditing, this.contentDiv, this.anchorContainer);
31040
+ if (!this.tableResizer && !this.isFeatureDisabled('TableResizer')) {
31041
+ this.tableResizer = (0, TableResizer_1.createTableResizer)(this.table, this.editor, this.isRTL, this.onStartTableResize, this.onFinishEditing, this.contentDiv, this.anchorContainer, this.onTableEditorCreated);
29787
31042
  }
29788
31043
  };
29789
31044
  TableEditor.prototype.setResizingTd = function (td) {
@@ -29805,7 +31060,7 @@ var TableEditor = /** @class */ (function () {
29805
31060
  this.disposeTableInserter();
29806
31061
  }
29807
31062
  if (!this.horizontalInserter && !this.verticalInserter && td) {
29808
- var newInserter = (0, TableInserter_1.createTableInserter)(this.editor, td, this.table, this.isRTL, !!isHorizontal, this.onInserted, this.getOnMouseOut, this.anchorContainer);
31063
+ var newInserter = (0, TableInserter_1.createTableInserter)(this.editor, td, this.table, this.isRTL, !!isHorizontal, this.onInserted, this.anchorContainer, this.onEditorCreated);
29809
31064
  if (isHorizontal) {
29810
31065
  this.horizontalInserter = newInserter;
29811
31066
  }
@@ -29854,6 +31109,10 @@ var TableEditor = /** @class */ (function () {
29854
31109
  }
29855
31110
  this.editor.takeSnapshot();
29856
31111
  };
31112
+ TableEditor.prototype.isFeatureDisabled = function (feature) {
31113
+ var _a;
31114
+ return (_a = this.disableFeatures) === null || _a === void 0 ? void 0 : _a.includes(feature);
31115
+ };
29857
31116
  return TableEditor;
29858
31117
  }());
29859
31118
  exports.TableEditor = TableEditor;
@@ -29870,12 +31129,20 @@ exports.TableEditor = TableEditor;
29870
31129
  "use strict";
29871
31130
 
29872
31131
  Object.defineProperty(exports, "__esModule", ({ value: true }));
29873
- exports.createCellResizer = void 0;
31132
+ exports.createCellResizer = exports.VERTICAL_RESIZER_ID = exports.HORIZONTAL_RESIZER_ID = void 0;
29874
31133
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
29875
31134
  var createElement_1 = __webpack_require__(/*! ../../../pluginUtils/CreateElement/createElement */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/CreateElement/createElement.ts");
29876
31135
  var DragAndDropHelper_1 = __webpack_require__(/*! ../../../pluginUtils/DragAndDrop/DragAndDropHelper */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/DragAndDrop/DragAndDropHelper.ts");
29877
31136
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
29878
31137
  var CELL_RESIZER_WIDTH = 4;
31138
+ /**
31139
+ * @internal
31140
+ */
31141
+ exports.HORIZONTAL_RESIZER_ID = 'horizontalResizer';
31142
+ /**
31143
+ * @internal
31144
+ */
31145
+ exports.VERTICAL_RESIZER_ID = 'verticalResizer';
29879
31146
  /**
29880
31147
  * @internal
29881
31148
  */
@@ -30017,7 +31284,7 @@ function setHorizontalPosition(context, trigger) {
30017
31284
  var td = context.td;
30018
31285
  var rect = (0, roosterjs_content_model_dom_1.normalizeRect)(td.getBoundingClientRect());
30019
31286
  if (rect) {
30020
- trigger.id = 'horizontalResizer';
31287
+ trigger.id = exports.HORIZONTAL_RESIZER_ID;
30021
31288
  trigger.style.top = rect.bottom - CELL_RESIZER_WIDTH + 'px';
30022
31289
  trigger.style.left = rect.left + 'px';
30023
31290
  trigger.style.width = rect.right - rect.left + 'px';
@@ -30028,7 +31295,7 @@ function setVerticalPosition(context, trigger) {
30028
31295
  var td = context.td, isRTL = context.isRTL;
30029
31296
  var rect = (0, roosterjs_content_model_dom_1.normalizeRect)(td.getBoundingClientRect());
30030
31297
  if (rect) {
30031
- trigger.id = 'verticalResizer';
31298
+ trigger.id = exports.VERTICAL_RESIZER_ID;
30032
31299
  trigger.style.top = rect.top + 'px';
30033
31300
  trigger.style.left = (isRTL ? rect.left : rect.right) - CELL_RESIZER_WIDTH + 1 + 'px';
30034
31301
  trigger.style.width = CELL_RESIZER_WIDTH + 'px';
@@ -30052,13 +31319,13 @@ exports.disposeTableEditFeature = void 0;
30052
31319
  /**
30053
31320
  * @internal
30054
31321
  */
30055
- function disposeTableEditFeature(resizer) {
31322
+ function disposeTableEditFeature(feature) {
30056
31323
  var _a, _b, _c;
30057
- if (resizer) {
30058
- (_b = (_a = resizer.div) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(resizer.div);
30059
- resizer.div = null;
30060
- (_c = resizer.featureHandler) === null || _c === void 0 ? void 0 : _c.dispose();
30061
- resizer.featureHandler = null;
31324
+ if (feature) {
31325
+ (_a = feature.featureHandler) === null || _a === void 0 ? void 0 : _a.dispose();
31326
+ feature.featureHandler = null;
31327
+ (_c = (_b = feature.div) === null || _b === void 0 ? void 0 : _b.parentNode) === null || _c === void 0 ? void 0 : _c.removeChild(feature.div);
31328
+ feature.div = null;
30062
31329
  }
30063
31330
  }
30064
31331
  exports.disposeTableEditFeature = disposeTableEditFeature;
@@ -30075,7 +31342,7 @@ exports.disposeTableEditFeature = disposeTableEditFeature;
30075
31342
  "use strict";
30076
31343
 
30077
31344
  Object.defineProperty(exports, "__esModule", ({ value: true }));
30078
- exports.createTableInserter = void 0;
31345
+ exports.createTableInserter = exports.VERTICAL_INSERTER_ID = exports.HORIZONTAL_INSERTER_ID = void 0;
30079
31346
  var createElement_1 = __webpack_require__(/*! ../../../pluginUtils/CreateElement/createElement */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/CreateElement/createElement.ts");
30080
31347
  var getIntersectedRect_1 = __webpack_require__(/*! ../../../pluginUtils/Rect/getIntersectedRect */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/Rect/getIntersectedRect.ts");
30081
31348
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
@@ -30087,7 +31354,15 @@ var INSERTER_BORDER_SIZE = 1;
30087
31354
  /**
30088
31355
  * @internal
30089
31356
  */
30090
- function createTableInserter(editor, td, table, isRTL, isHorizontal, onInsert, getOnMouseOut, anchorContainer) {
31357
+ exports.HORIZONTAL_INSERTER_ID = 'horizontalInserter';
31358
+ /**
31359
+ * @internal
31360
+ */
31361
+ exports.VERTICAL_INSERTER_ID = 'verticalInserter';
31362
+ /**
31363
+ * @internal
31364
+ */
31365
+ function createTableInserter(editor, td, table, isRTL, isHorizontal, onInsert, anchorContainer, onTableEditorCreated) {
30091
31366
  var tdRect = (0, roosterjs_content_model_dom_1.normalizeRect)(td.getBoundingClientRect());
30092
31367
  var viewPort = editor.getVisibleViewport();
30093
31368
  var tableRect = table && viewPort ? (0, getIntersectedRect_1.getIntersectedRect)([table], [viewPort]) : null;
@@ -30098,7 +31373,7 @@ function createTableInserter(editor, td, table, isRTL, isHorizontal, onInsert, g
30098
31373
  var div = (0, createElement_1.createElement)(createElementData, document_1);
30099
31374
  if (isHorizontal) {
30100
31375
  // tableRect.left/right is used because the Inserter is always intended to be on the side
30101
- div.id = 'horizontalInserter';
31376
+ div.id = exports.HORIZONTAL_INSERTER_ID;
30102
31377
  div.style.left = (isRTL
30103
31378
  ? tableRect.right
30104
31379
  : tableRect.left - (INSERTER_SIDE_LENGTH - 1 + 2 * INSERTER_BORDER_SIZE)) + "px";
@@ -30106,21 +31381,21 @@ function createTableInserter(editor, td, table, isRTL, isHorizontal, onInsert, g
30106
31381
  div.firstChild.style.width = tableRect.right - tableRect.left + "px";
30107
31382
  }
30108
31383
  else {
30109
- div.id = 'verticalInserter';
31384
+ div.id = exports.VERTICAL_INSERTER_ID;
30110
31385
  div.style.left = (isRTL ? tdRect.left - 8 : tdRect.right - 8) + "px";
30111
31386
  // tableRect.top is used because the Inserter is always intended to be on top
30112
31387
  div.style.top = tableRect.top - (INSERTER_SIDE_LENGTH - 1 + 2 * INSERTER_BORDER_SIZE) + "px";
30113
31388
  div.firstChild.style.height = tableRect.bottom - tableRect.top + "px";
30114
31389
  }
30115
31390
  (anchorContainer || document_1.body).appendChild(div);
30116
- var handler = new TableInsertHandler(div, td, table, isHorizontal, editor, onInsert, getOnMouseOut);
31391
+ var handler = new TableInsertHandler(div, td, table, isHorizontal, editor, onInsert, onTableEditorCreated);
30117
31392
  return { div: div, featureHandler: handler, node: td };
30118
31393
  }
30119
31394
  return null;
30120
31395
  }
30121
31396
  exports.createTableInserter = createTableInserter;
30122
31397
  var TableInsertHandler = /** @class */ (function () {
30123
- function TableInsertHandler(div, td, table, isHorizontal, editor, onInsert, getOnMouseOut) {
31398
+ function TableInsertHandler(div, td, table, isHorizontal, editor, onInsert, onTableEditorCreated) {
30124
31399
  var _this = this;
30125
31400
  this.div = div;
30126
31401
  this.td = td;
@@ -30155,15 +31430,13 @@ var TableInsertHandler = /** @class */ (function () {
30155
31430
  _this.onInsert();
30156
31431
  };
30157
31432
  this.div.addEventListener('click', this.insertTd);
30158
- this.onMouseOutEvent = getOnMouseOut(div);
30159
- this.div.addEventListener('mouseout', this.onMouseOutEvent);
31433
+ this.disposer = onTableEditorCreated === null || onTableEditorCreated === void 0 ? void 0 : onTableEditorCreated(isHorizontal ? 'HorizontalTableInserter' : 'VerticalTableInserter', div);
30160
31434
  }
30161
31435
  TableInsertHandler.prototype.dispose = function () {
31436
+ var _a;
30162
31437
  this.div.removeEventListener('click', this.insertTd);
30163
- if (this.onMouseOutEvent) {
30164
- this.div.removeEventListener('mouseout', this.onMouseOutEvent);
30165
- }
30166
- this.onMouseOutEvent = null;
31438
+ (_a = this.disposer) === null || _a === void 0 ? void 0 : _a.call(this);
31439
+ this.disposer = undefined;
30167
31440
  };
30168
31441
  return TableInsertHandler;
30169
31442
  }());
@@ -30198,19 +31471,24 @@ function getInsertElementData(isHorizontal, isDark, isRTL, backgroundColor) {
30198
31471
  "use strict";
30199
31472
 
30200
31473
  Object.defineProperty(exports, "__esModule", ({ value: true }));
30201
- exports.createTableMover = void 0;
31474
+ exports.onDragEnd = exports.onDragging = exports.onDragStart = exports.createTableMover = exports.TABLE_MOVER_ID = void 0;
30202
31475
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30203
31476
  var createElement_1 = __webpack_require__(/*! ../../../pluginUtils/CreateElement/createElement */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/CreateElement/createElement.ts");
30204
31477
  var DragAndDropHelper_1 = __webpack_require__(/*! ../../../pluginUtils/DragAndDrop/DragAndDropHelper */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/DragAndDrop/DragAndDropHelper.ts");
31478
+ var roosterjs_content_model_api_1 = __webpack_require__(/*! roosterjs-content-model-api */ "./packages/roosterjs-content-model-api/lib/index.ts");
30205
31479
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30206
31480
  var TABLE_MOVER_LENGTH = 12;
30207
- var TABLE_MOVER_ID = '_Table_Mover';
30208
31481
  /**
30209
31482
  * @internal
31483
+ */
31484
+ exports.TABLE_MOVER_ID = '_Table_Mover';
31485
+ var TABLE_MOVER_STYLE_KEY = '_TableMoverCursorStyle';
31486
+ /**
31487
+ * @internal
31488
+ * Allows user to move table to another position
30210
31489
  * Contains the function to select whole table
30211
- * Moving behavior not implemented yet
30212
31490
  */
30213
- function createTableMover(table, editor, isRTL, onFinishDragging, getOnMouseOut, contentDiv, anchorContainer) {
31491
+ function createTableMover(table, editor, isRTL, onFinishDragging, onStart, onEnd, contentDiv, anchorContainer, onTableEditorCreated, disableMovement) {
30214
31492
  var rect = (0, roosterjs_content_model_dom_1.normalizeRect)(table.getBoundingClientRect());
30215
31493
  if (!isTableTopVisible(editor, rect, contentDiv)) {
30216
31494
  return null;
@@ -30219,10 +31497,10 @@ function createTableMover(table, editor, isRTL, onFinishDragging, getOnMouseOut,
30219
31497
  var document = table.ownerDocument;
30220
31498
  var createElementData = {
30221
31499
  tag: 'div',
30222
- style: 'position: fixed; cursor: all-scroll; user-select: none; border: 1px solid #808080',
31500
+ style: 'position: fixed; cursor: move; user-select: none; border: 1px solid #808080',
30223
31501
  };
30224
31502
  var div = (0, createElement_1.createElement)(createElementData, document);
30225
- div.id = TABLE_MOVER_ID;
31503
+ div.id = exports.TABLE_MOVER_ID;
30226
31504
  div.style.width = TABLE_MOVER_LENGTH + "px";
30227
31505
  div.style.height = TABLE_MOVER_LENGTH + "px";
30228
31506
  (anchorContainer || document.body).appendChild(div);
@@ -30231,35 +31509,36 @@ function createTableMover(table, editor, isRTL, onFinishDragging, getOnMouseOut,
30231
31509
  zoomScale: zoomScale,
30232
31510
  rect: rect,
30233
31511
  isRTL: isRTL,
31512
+ editor: editor,
31513
+ div: div,
31514
+ onFinishDragging: onFinishDragging,
31515
+ onStart: onStart,
31516
+ onEnd: onEnd,
31517
+ disableMovement: disableMovement,
30234
31518
  };
30235
31519
  setDivPosition(context, div);
30236
- var onDragEnd = function (context, event) {
30237
- if (event.target == div) {
30238
- onFinishDragging(context.table);
30239
- }
30240
- return false;
30241
- };
30242
- var featureHandler = new TableMoverFeature(div, context, setDivPosition, {
30243
- onDragEnd: onDragEnd,
30244
- }, context.zoomScale, getOnMouseOut);
30245
- return { div: div, featureHandler: featureHandler, node: table };
31520
+ var featureHandler = new TableMoverFeature(div, context, function () { }, disableMovement
31521
+ ? { onDragEnd: onDragEnd }
31522
+ : {
31523
+ onDragStart: onDragStart,
31524
+ onDragging: onDragging,
31525
+ onDragEnd: onDragEnd,
31526
+ }, context.zoomScale, onTableEditorCreated, editor.getEnvironment().isMobileOrTablet);
31527
+ return { node: table, div: div, featureHandler: featureHandler };
30246
31528
  }
30247
31529
  exports.createTableMover = createTableMover;
30248
31530
  var TableMoverFeature = /** @class */ (function (_super) {
30249
31531
  (0, tslib_1.__extends)(TableMoverFeature, _super);
30250
- function TableMoverFeature(div, context, onSubmit, handler, zoomScale, getOnMouseOut, forceMobile, container) {
31532
+ function TableMoverFeature(div, context, onSubmit, handler, zoomScale, onTableEditorCreated, forceMobile) {
30251
31533
  var _this = _super.call(this, div, context, onSubmit, handler, zoomScale, forceMobile) || this;
30252
- _this.div = div;
30253
- _this.onMouseOut = getOnMouseOut(div);
30254
- div.addEventListener('mouseout', _this.onMouseOut);
31534
+ _this.disposer = onTableEditorCreated === null || onTableEditorCreated === void 0 ? void 0 : onTableEditorCreated('TableMover', div);
30255
31535
  return _this;
30256
31536
  }
30257
31537
  TableMoverFeature.prototype.dispose = function () {
31538
+ var _a;
31539
+ (_a = this.disposer) === null || _a === void 0 ? void 0 : _a.call(this);
31540
+ this.disposer = undefined;
30258
31541
  _super.prototype.dispose.call(this);
30259
- if (this.onMouseOut) {
30260
- this.div.removeEventListener('mouseout', this.onMouseOut);
30261
- }
30262
- this.onMouseOut = null;
30263
31542
  };
30264
31543
  return TableMoverFeature;
30265
31544
  }(DragAndDropHelper_1.DragAndDropHelper));
@@ -30278,6 +31557,188 @@ function isTableTopVisible(editor, rect, contentDiv) {
30278
31557
  }
30279
31558
  return true;
30280
31559
  }
31560
+ function setTableMoverCursor(editor, state, type) {
31561
+ var _a;
31562
+ editor === null || editor === void 0 ? void 0 : editor.setEditorStyle(TABLE_MOVER_STYLE_KEY, state ? (_a = 'cursor: ' + type) !== null && _a !== void 0 ? _a : 'move' : null);
31563
+ }
31564
+ // Get insertion point from coordinate.
31565
+ function getNodePositionFromEvent(editor, x, y) {
31566
+ var doc = editor.getDocument();
31567
+ var domHelper = editor.getDOMHelper();
31568
+ if (doc.caretRangeFromPoint) {
31569
+ // Chrome, Edge, Safari, Opera
31570
+ var range = doc.caretRangeFromPoint(x, y);
31571
+ if (range && domHelper.isNodeInEditor(range.startContainer)) {
31572
+ return { node: range.startContainer, offset: range.startOffset };
31573
+ }
31574
+ }
31575
+ if ('caretPositionFromPoint' in doc) {
31576
+ // Firefox
31577
+ var pos = doc.caretPositionFromPoint(x, y);
31578
+ if (pos && domHelper.isNodeInEditor(pos.offsetNode)) {
31579
+ return { node: pos.offsetNode, offset: pos.offset };
31580
+ }
31581
+ }
31582
+ if (doc.elementFromPoint) {
31583
+ // Fallback
31584
+ var element = doc.elementFromPoint(x, y);
31585
+ if (element && domHelper.isNodeInEditor(element)) {
31586
+ return { node: element, offset: 0 };
31587
+ }
31588
+ }
31589
+ return null;
31590
+ }
31591
+ /**
31592
+ * @internal
31593
+ * Exported for testing
31594
+ */
31595
+ function onDragStart(context) {
31596
+ var _a;
31597
+ context.onStart();
31598
+ var editor = context.editor, table = context.table, div = context.div;
31599
+ setTableMoverCursor(editor, true, 'move');
31600
+ // Create table outline rectangle
31601
+ var trect = table.getBoundingClientRect();
31602
+ var createElementData = {
31603
+ tag: 'div',
31604
+ style: 'position: fixed; user-select: none; border: 1px solid #808080',
31605
+ };
31606
+ var tableRect = (0, createElement_1.createElement)(createElementData, document);
31607
+ tableRect.style.width = trect.width + "px";
31608
+ tableRect.style.height = trect.height + "px";
31609
+ tableRect.style.top = trect.top + "px";
31610
+ tableRect.style.left = trect.left + "px";
31611
+ (_a = div.parentNode) === null || _a === void 0 ? void 0 : _a.appendChild(tableRect);
31612
+ // Get current selection
31613
+ var initialSelection = editor.getDOMSelection();
31614
+ // Select first cell of the table
31615
+ editor.setDOMSelection({
31616
+ type: 'table',
31617
+ firstColumn: 0,
31618
+ firstRow: 0,
31619
+ lastColumn: 0,
31620
+ lastRow: 0,
31621
+ table: table,
31622
+ });
31623
+ // Get the table content model
31624
+ var _b = (0, tslib_1.__read)((0, roosterjs_content_model_dom_1.getFirstSelectedTable)(editor.getContentModelCopy('disconnected')), 1), cmTable = _b[0];
31625
+ // Restore selection
31626
+ editor.setDOMSelection(initialSelection);
31627
+ return {
31628
+ cmTable: cmTable,
31629
+ initialSelection: initialSelection,
31630
+ tableRect: tableRect,
31631
+ };
31632
+ }
31633
+ exports.onDragStart = onDragStart;
31634
+ /**
31635
+ * @internal
31636
+ * Exported for testing
31637
+ */
31638
+ function onDragging(context, event, initValue) {
31639
+ var tableRect = initValue.tableRect;
31640
+ var editor = context.editor;
31641
+ // Move table outline rectangle
31642
+ tableRect.style.top = event.clientY + TABLE_MOVER_LENGTH + "px";
31643
+ tableRect.style.left = event.clientX + TABLE_MOVER_LENGTH + "px";
31644
+ var pos = getNodePositionFromEvent(editor, event.clientX, event.clientY);
31645
+ if (pos) {
31646
+ var range = editor.getDocument().createRange();
31647
+ range.setStart(pos.node, pos.offset);
31648
+ range.collapse(true);
31649
+ editor.setDOMSelection({ type: 'range', range: range, isReverted: false });
31650
+ return true;
31651
+ }
31652
+ return false;
31653
+ }
31654
+ exports.onDragging = onDragging;
31655
+ /**
31656
+ * @internal
31657
+ * Exported for testing
31658
+ */
31659
+ function onDragEnd(context, event, initValue) {
31660
+ var _a, _b;
31661
+ var editor = context.editor, table = context.table, selectWholeTable = context.onFinishDragging, disableMovement = context.disableMovement;
31662
+ var element = event.target;
31663
+ // Remove table outline rectangle
31664
+ initValue === null || initValue === void 0 ? void 0 : initValue.tableRect.remove();
31665
+ // Reset cursor
31666
+ setTableMoverCursor(editor, false);
31667
+ if (element == context.div) {
31668
+ // Table mover was only clicked, select whole table
31669
+ selectWholeTable(table);
31670
+ context.onEnd();
31671
+ return true;
31672
+ }
31673
+ else {
31674
+ // Check if table was dragged on itself, element is not in editor, or movement is disabled
31675
+ if (table.contains(element) ||
31676
+ !editor.getDOMHelper().isNodeInEditor(element) ||
31677
+ disableMovement) {
31678
+ editor.setDOMSelection((_a = initValue === null || initValue === void 0 ? void 0 : initValue.initialSelection) !== null && _a !== void 0 ? _a : null);
31679
+ context.onEnd();
31680
+ return false;
31681
+ }
31682
+ var insertionSuccess_1 = false;
31683
+ // Get position to insert table
31684
+ var insertPosition = getNodePositionFromEvent(editor, event.clientX, event.clientY);
31685
+ if (insertPosition) {
31686
+ // Move table to new position
31687
+ (0, roosterjs_content_model_api_1.formatInsertPointWithContentModel)(editor, insertPosition, function (model, context, ip) {
31688
+ var _a;
31689
+ // Remove old table
31690
+ var _b = (0, tslib_1.__read)((0, roosterjs_content_model_dom_1.getFirstSelectedTable)(model), 2), oldTable = _b[0], path = _b[1];
31691
+ if (oldTable) {
31692
+ var index = path[0].blocks.indexOf(oldTable);
31693
+ path[0].blocks.splice(index, 1);
31694
+ }
31695
+ if (ip && (initValue === null || initValue === void 0 ? void 0 : initValue.cmTable)) {
31696
+ // Insert new table
31697
+ var doc = (0, roosterjs_content_model_dom_1.createContentModelDocument)();
31698
+ doc.blocks.push(initValue.cmTable);
31699
+ insertionSuccess_1 = !!(0, roosterjs_content_model_dom_1.mergeModel)(model, doc, context, {
31700
+ mergeFormat: 'none',
31701
+ insertPosition: ip,
31702
+ });
31703
+ if (insertionSuccess_1) {
31704
+ // After mergeModel, the new table should be selected
31705
+ var finalTable = (_a = (0, roosterjs_content_model_dom_1.getFirstSelectedTable)(model)[0]) !== null && _a !== void 0 ? _a : initValue.cmTable;
31706
+ if (finalTable) {
31707
+ // Add selection marker to the first cell of the table
31708
+ var FirstCell = finalTable.rows[0].cells[0];
31709
+ var markerParagraph = FirstCell === null || FirstCell === void 0 ? void 0 : FirstCell.blocks[0];
31710
+ if ((markerParagraph === null || markerParagraph === void 0 ? void 0 : markerParagraph.blockType) == 'Paragraph') {
31711
+ var marker = (0, roosterjs_content_model_dom_1.createSelectionMarker)(model.format);
31712
+ markerParagraph.segments.unshift(marker);
31713
+ (0, roosterjs_content_model_dom_1.setParagraphNotImplicit)(markerParagraph);
31714
+ (0, roosterjs_content_model_dom_1.setSelection)(FirstCell, marker);
31715
+ }
31716
+ }
31717
+ }
31718
+ return insertionSuccess_1;
31719
+ }
31720
+ }, {
31721
+ // Select first cell of the old table
31722
+ selectionOverride: {
31723
+ type: 'table',
31724
+ firstColumn: 0,
31725
+ firstRow: 0,
31726
+ lastColumn: 0,
31727
+ lastRow: 0,
31728
+ table: table,
31729
+ },
31730
+ apiName: 'TableMover',
31731
+ });
31732
+ }
31733
+ else {
31734
+ // No movement, restore initial selection
31735
+ editor.setDOMSelection((_b = initValue === null || initValue === void 0 ? void 0 : initValue.initialSelection) !== null && _b !== void 0 ? _b : null);
31736
+ }
31737
+ context.onEnd();
31738
+ return insertionSuccess_1;
31739
+ }
31740
+ }
31741
+ exports.onDragEnd = onDragEnd;
30281
31742
 
30282
31743
 
30283
31744
  /***/ }),
@@ -30291,16 +31752,20 @@ function isTableTopVisible(editor, rect, contentDiv) {
30291
31752
  "use strict";
30292
31753
 
30293
31754
  Object.defineProperty(exports, "__esModule", ({ value: true }));
30294
- exports.createTableResizer = void 0;
31755
+ exports.createTableResizer = exports.TABLE_RESIZER_ID = void 0;
31756
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30295
31757
  var createElement_1 = __webpack_require__(/*! ../../../pluginUtils/CreateElement/createElement */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/CreateElement/createElement.ts");
30296
31758
  var DragAndDropHelper_1 = __webpack_require__(/*! ../../../pluginUtils/DragAndDrop/DragAndDropHelper */ "./packages/roosterjs-content-model-plugins/lib/pluginUtils/DragAndDrop/DragAndDropHelper.ts");
30297
31759
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30298
31760
  var TABLE_RESIZER_LENGTH = 12;
30299
- var TABLE_RESIZER_ID = '_Table_Resizer';
30300
31761
  /**
30301
31762
  * @internal
30302
31763
  */
30303
- function createTableResizer(table, editor, isRTL, onStart, onEnd, contentDiv, anchorContainer) {
31764
+ exports.TABLE_RESIZER_ID = '_Table_Resizer';
31765
+ /**
31766
+ * @internal
31767
+ */
31768
+ function createTableResizer(table, editor, isRTL, onStart, onEnd, contentDiv, anchorContainer, onTableEditorCreated) {
30304
31769
  var rect = (0, roosterjs_content_model_dom_1.normalizeRect)(table.getBoundingClientRect());
30305
31770
  if (!isTableBottomVisible(editor, rect, contentDiv)) {
30306
31771
  return null;
@@ -30312,7 +31777,7 @@ function createTableResizer(table, editor, isRTL, onStart, onEnd, contentDiv, an
30312
31777
  style: "position: fixed; cursor: " + (isRTL ? 'ne' : 'nw') + "-resize; user-select: none; border: 1px solid #808080",
30313
31778
  };
30314
31779
  var div = (0, createElement_1.createElement)(createElementData, document);
30315
- div.id = TABLE_RESIZER_ID;
31780
+ div.id = exports.TABLE_RESIZER_ID;
30316
31781
  div.style.width = TABLE_RESIZER_LENGTH + "px";
30317
31782
  div.style.height = TABLE_RESIZER_LENGTH + "px";
30318
31783
  (anchorContainer || document.body).appendChild(div);
@@ -30327,15 +31792,30 @@ function createTableResizer(table, editor, isRTL, onStart, onEnd, contentDiv, an
30327
31792
  contentDiv: contentDiv,
30328
31793
  };
30329
31794
  setDivPosition(context, div);
30330
- var featureHandler = new DragAndDropHelper_1.DragAndDropHelper(div, context, hideResizer, // Resizer is hidden while dragging only
31795
+ var featureHandler = new TableResizer(div, context, hideResizer, // Resizer is hidden while dragging only
30331
31796
  {
30332
31797
  onDragStart: onDragStart,
30333
31798
  onDragging: onDragging,
30334
31799
  onDragEnd: onDragEnd,
30335
- }, zoomScale, editor.getEnvironment().isMobileOrTablet);
31800
+ }, zoomScale, editor.getEnvironment().isMobileOrTablet, onTableEditorCreated);
30336
31801
  return { node: table, div: div, featureHandler: featureHandler };
30337
31802
  }
30338
31803
  exports.createTableResizer = createTableResizer;
31804
+ var TableResizer = /** @class */ (function (_super) {
31805
+ (0, tslib_1.__extends)(TableResizer, _super);
31806
+ function TableResizer(trigger, context, onSubmit, handler, zoomScale, forceMobile, onTableEditorCreated) {
31807
+ var _this = _super.call(this, trigger, context, onSubmit, handler, zoomScale, forceMobile) || this;
31808
+ _this.disposer = onTableEditorCreated === null || onTableEditorCreated === void 0 ? void 0 : onTableEditorCreated('TableResizer', trigger);
31809
+ return _this;
31810
+ }
31811
+ TableResizer.prototype.dispose = function () {
31812
+ var _a;
31813
+ (_a = this.disposer) === null || _a === void 0 ? void 0 : _a.call(this);
31814
+ this.disposer = undefined;
31815
+ _super.prototype.dispose.call(this);
31816
+ };
31817
+ return TableResizer;
31818
+ }(DragAndDropHelper_1.DragAndDropHelper));
30339
31819
  function onDragStart(context, event) {
30340
31820
  context.onStart();
30341
31821
  var editor = context.editor, table = context.table;
@@ -30521,7 +32001,8 @@ var WatermarkPlugin = /** @class */ (function () {
30521
32001
  if (!editor) {
30522
32002
  return;
30523
32003
  }
30524
- if (event.eventType == 'input' && event.rawEvent.inputType == 'insertText') {
32004
+ if ((event.eventType == 'input' && event.rawEvent.inputType == 'insertText') ||
32005
+ event.eventType == 'compositionEnd') {
30525
32006
  // When input text, editor must not be empty, so we can do hide watermark now without checking content model
30526
32007
  this.showHide(editor, false /*isEmpty*/);
30527
32008
  }
@@ -30602,6 +32083,10 @@ function isModelEmptyFast(model) {
30602
32083
  })) {
30603
32084
  return false; // Has meaningful segments, it is not empty
30604
32085
  }
32086
+ else if ((firstBlock.format.marginRight && parseFloat(firstBlock.format.marginRight) > 0) ||
32087
+ (firstBlock.format.marginLeft && parseFloat(firstBlock.format.marginLeft) > 0)) {
32088
+ return false; // Has margin (indentation is changed), it is not empty
32089
+ }
30605
32090
  else {
30606
32091
  return firstBlock.segments.filter(function (x) { return x.segmentType == 'Br'; }).length <= 1; // If there are more than one BR, it is not empty, otherwise it is empty
30607
32092
  }