roosterjs 9.22.0 → 9.24.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
@@ -8944,7 +8944,7 @@ var createEditorContext = function (core, saveIndex) {
8944
8944
  var _a, _b;
8945
8945
  var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, logicalRoot = core.logicalRoot, cache = core.cache, domHelper = core.domHelper;
8946
8946
  saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;
8947
- 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(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [] }, (0, getRootComputedStyleForContext_1.getRootComputedStyleForContext)(logicalRoot.ownerDocument));
8947
+ 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(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [], paragraphMap: core.cache.paragraphMap }, (0, getRootComputedStyleForContext_1.getRootComputedStyleForContext)(logicalRoot.ownerDocument));
8948
8948
  if (core.domHelper.isRightToLeft()) {
8949
8949
  context.isRootRtl = true;
8950
8950
  }
@@ -9045,6 +9045,7 @@ var formatContentModel = function (core, formatter, options, domToModelOptions)
9045
9045
  deletedEntities: [],
9046
9046
  rawEvent: rawEvent,
9047
9047
  newImages: [],
9048
+ paragraphIndexer: core.cache.paragraphMap,
9048
9049
  };
9049
9050
  var hasFocus = core.domHelper.hasFocus();
9050
9051
  var changed = formatter(model, context);
@@ -10252,6 +10253,7 @@ function handledExclusively(event, plugin) {
10252
10253
  Object.defineProperty(exports, "__esModule", ({ value: true }));
10253
10254
  exports.createCachePlugin = void 0;
10254
10255
  var areSameSelections_1 = __webpack_require__(/*! ./areSameSelections */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts");
10256
+ var ParagraphMapImpl_1 = __webpack_require__(/*! ./ParagraphMapImpl */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts");
10255
10257
  var textMutationObserver_1 = __webpack_require__(/*! ./textMutationObserver */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/textMutationObserver.ts");
10256
10258
  var domIndexerImpl_1 = __webpack_require__(/*! ./domIndexerImpl */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/domIndexerImpl.ts");
10257
10259
  var updateCache_1 = __webpack_require__(/*! ./updateCache */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/updateCache.ts");
@@ -10297,13 +10299,15 @@ var CachePlugin = /** @class */ (function () {
10297
10299
  _this.updateCachedModel(_this.editor);
10298
10300
  }
10299
10301
  };
10300
- this.state = option.disableCache
10301
- ? {}
10302
- : {
10303
- domIndexer: new domIndexerImpl_1.DomIndexerImpl(option.experimentalFeatures &&
10304
- option.experimentalFeatures.indexOf('PersistCache') >= 0),
10305
- textMutationObserver: (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation),
10306
- };
10302
+ this.state = {};
10303
+ if (!option.disableCache) {
10304
+ this.state.domIndexer = new domIndexerImpl_1.DomIndexerImpl(option.experimentalFeatures &&
10305
+ option.experimentalFeatures.indexOf('PersistCache') >= 0);
10306
+ this.state.textMutationObserver = (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation);
10307
+ }
10308
+ if (option.enableParagraphMap) {
10309
+ this.state.paragraphMap = (0, ParagraphMapImpl_1.createParagraphMap)();
10310
+ }
10307
10311
  }
10308
10312
  /**
10309
10313
  * Get name of this plugin
@@ -10385,10 +10389,13 @@ var CachePlugin = /** @class */ (function () {
10385
10389
  }
10386
10390
  };
10387
10391
  CachePlugin.prototype.invalidateCache = function () {
10388
- var _a;
10392
+ var _a, _b;
10389
10393
  if (!((_a = this.editor) === null || _a === void 0 ? void 0 : _a.isInShadowEdit())) {
10390
10394
  this.state.cachedModel = undefined;
10391
10395
  this.state.cachedSelection = undefined;
10396
+ // Clear paragraph indexer to prevent stale references to old paragraphs
10397
+ // It will be rebuild next time when we create a new Content Model
10398
+ (_b = this.state.paragraphMap) === null || _b === void 0 ? void 0 : _b.clear();
10392
10399
  }
10393
10400
  };
10394
10401
  CachePlugin.prototype.updateCachedModel = function (editor, forceUpdate) {
@@ -10432,6 +10439,84 @@ function createCachePlugin(option, contentDiv) {
10432
10439
  exports.createCachePlugin = createCachePlugin;
10433
10440
 
10434
10441
 
10442
+ /***/ }),
10443
+
10444
+ /***/ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts":
10445
+ /*!****************************************************************************************!*\
10446
+ !*** ./packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts ***!
10447
+ \****************************************************************************************/
10448
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
10449
+
10450
+ "use strict";
10451
+
10452
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
10453
+ exports.createParagraphMap = void 0;
10454
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
10455
+ var idPrefix = 'paragraph';
10456
+ var ParagraphMapImpl = /** @class */ (function () {
10457
+ function ParagraphMapImpl() {
10458
+ this.nextId = 0;
10459
+ this.paragraphMap = {};
10460
+ ParagraphMapImpl.prefixNum++;
10461
+ }
10462
+ ParagraphMapImpl.prototype.assignMarkerToModel = function (element, paragraph) {
10463
+ var marker = (0, roosterjs_content_model_dom_1.getParagraphMarker)(element);
10464
+ var paragraphWithMarker = paragraph;
10465
+ if (marker) {
10466
+ paragraphWithMarker._marker = marker;
10467
+ this.paragraphMap[marker] = paragraph;
10468
+ }
10469
+ else {
10470
+ paragraphWithMarker._marker = this.generateId();
10471
+ this.applyMarkerToDom(element, paragraph);
10472
+ }
10473
+ };
10474
+ ParagraphMapImpl.prototype.applyMarkerToDom = function (element, paragraph) {
10475
+ var paragraphWithMarker = paragraph;
10476
+ if (!paragraphWithMarker._marker) {
10477
+ paragraphWithMarker._marker = this.generateId();
10478
+ }
10479
+ var marker = paragraphWithMarker._marker;
10480
+ if (marker) {
10481
+ (0, roosterjs_content_model_dom_1.setParagraphMarker)(element, marker);
10482
+ this.paragraphMap[marker] = paragraph;
10483
+ }
10484
+ };
10485
+ /**
10486
+ * Get paragraph using a previously marked paragraph
10487
+ * @param markedParagraph The previously marked paragraph to get
10488
+ */
10489
+ ParagraphMapImpl.prototype.getParagraphFromMarker = function (markerParagraph) {
10490
+ var marker = markerParagraph._marker;
10491
+ return marker ? this.paragraphMap[marker] || null : null;
10492
+ };
10493
+ ParagraphMapImpl.prototype.clear = function () {
10494
+ this.paragraphMap = {};
10495
+ };
10496
+ //#region For test code only
10497
+ ParagraphMapImpl.prototype._reset = function () {
10498
+ ParagraphMapImpl.prefixNum = 0;
10499
+ this.nextId = 0;
10500
+ };
10501
+ ParagraphMapImpl.prototype._getMap = function () {
10502
+ return this.paragraphMap;
10503
+ };
10504
+ //#endregion
10505
+ ParagraphMapImpl.prototype.generateId = function () {
10506
+ return idPrefix + "_" + ParagraphMapImpl.prefixNum + "_" + this.nextId++;
10507
+ };
10508
+ ParagraphMapImpl.prefixNum = 0;
10509
+ return ParagraphMapImpl;
10510
+ }());
10511
+ /**
10512
+ * @internal
10513
+ */
10514
+ function createParagraphMap() {
10515
+ return new ParagraphMapImpl();
10516
+ }
10517
+ exports.createParagraphMap = createParagraphMap;
10518
+
10519
+
10435
10520
  /***/ }),
10436
10521
 
10437
10522
  /***/ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts":
@@ -16191,6 +16276,7 @@ var SegmentDecoratorTags = ['A', 'CODE'];
16191
16276
  * @internal
16192
16277
  */
16193
16278
  function blockProcessor(group, element, context, segmentFormat) {
16279
+ var _a;
16194
16280
  var decorator = context.blockDecorator.tagName ? context.blockDecorator : undefined;
16195
16281
  var isSegmentDecorator = SegmentDecoratorTags.indexOf(element.tagName) >= 0;
16196
16282
  (0, parseFormat_1.parseFormat)(element, context.formatParsers.block, context.blockFormat, context);
@@ -16203,6 +16289,7 @@ function blockProcessor(group, element, context, segmentFormat) {
16203
16289
  });
16204
16290
  if (!isSegmentDecorator) {
16205
16291
  var paragraph = (0, createParagraph_1.createParagraph)(false /*isImplicit*/, blockFormat, segmentFormat, decorator);
16292
+ (_a = context.paragraphMap) === null || _a === void 0 ? void 0 : _a.assignMarkerToModel(element, paragraph);
16206
16293
  (0, addBlock_1.addBlock)(group, paragraph);
16207
16294
  }
16208
16295
  context.elementProcessors.child(group, element, context);
@@ -16921,6 +17008,8 @@ function shouldUseFormatContainer(element, context) {
16921
17008
 
16922
17009
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16923
17010
  exports.linkProcessor = void 0;
17011
+ var addSegment_1 = __webpack_require__(/*! ../../modelApi/common/addSegment */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/addSegment.ts");
17012
+ var createText_1 = __webpack_require__(/*! ../../modelApi/creators/createText */ "./packages/roosterjs-content-model-dom/lib/modelApi/creators/createText.ts");
16924
17013
  var knownElementProcessor_1 = __webpack_require__(/*! ./knownElementProcessor */ "./packages/roosterjs-content-model-dom/lib/domToModel/processors/knownElementProcessor.ts");
16925
17014
  var parseFormat_1 = __webpack_require__(/*! ../utils/parseFormat */ "./packages/roosterjs-content-model-dom/lib/domToModel/utils/parseFormat.ts");
16926
17015
  var stackFormat_1 = __webpack_require__(/*! ../utils/stackFormat */ "./packages/roosterjs-content-model-dom/lib/domToModel/utils/stackFormat.ts");
@@ -16928,15 +17017,36 @@ var stackFormat_1 = __webpack_require__(/*! ../utils/stackFormat */ "./packages/
16928
17017
  * @internal
16929
17018
  */
16930
17019
  var linkProcessor = function (group, element, context) {
16931
- if (element.hasAttribute('href')) {
16932
- (0, stackFormat_1.stackFormat)(context, { link: 'linkDefault' }, function () {
17020
+ var name = element.getAttribute('name');
17021
+ var href = element.getAttribute('href');
17022
+ if (name || href) {
17023
+ var isAnchor_1 = !!name && !href;
17024
+ var option = {
17025
+ // For anchor (name without ref), no need to add other styles
17026
+ // For link (href exists), add default link styles
17027
+ link: isAnchor_1 ? 'empty' : 'linkDefault',
17028
+ };
17029
+ (0, stackFormat_1.stackFormat)(context, option, function () {
16933
17030
  (0, parseFormat_1.parseFormat)(element, context.formatParsers.link, context.link.format, context);
16934
17031
  (0, parseFormat_1.parseFormat)(element, context.formatParsers.dataset, context.link.dataset, context);
16935
- (0, knownElementProcessor_1.knownElementProcessor)(group, element, context);
17032
+ if (isAnchor_1 && !element.firstChild) {
17033
+ // Empty anchor, need to make sure it has some child in model
17034
+ var emptyText = (0, createText_1.createText)('', context.segmentFormat, {
17035
+ dataset: context.link.dataset,
17036
+ format: context.link.format,
17037
+ });
17038
+ if (context.isInSelection) {
17039
+ emptyText.isSelected = true;
17040
+ }
17041
+ (0, addSegment_1.addSegment)(group, emptyText);
17042
+ }
17043
+ else {
17044
+ (0, knownElementProcessor_1.knownElementProcessor)(group, element, context);
17045
+ }
16936
17046
  });
16937
17047
  }
16938
17048
  else {
16939
- // A tag without href, can be treated as normal SPAN tag
17049
+ // A tag without name or href, can be treated as normal SPAN tag
16940
17050
  (0, knownElementProcessor_1.knownElementProcessor)(group, element, context);
16941
17051
  }
16942
17052
  };
@@ -18175,6 +18285,104 @@ function getSafeIdSelector(id) {
18175
18285
  exports.getSafeIdSelector = getSafeIdSelector;
18176
18286
 
18177
18287
 
18288
+ /***/ }),
18289
+
18290
+ /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts":
18291
+ /*!**********************************************************************************************!*\
18292
+ !*** ./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts ***!
18293
+ \**********************************************************************************************/
18294
+ /***/ ((__unused_webpack_module, exports) => {
18295
+
18296
+ "use strict";
18297
+
18298
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
18299
+ exports.setHiddenProperty = exports.getHiddenProperty = void 0;
18300
+ /**
18301
+ * @internal
18302
+ */
18303
+ function getHiddenProperty(node, key) {
18304
+ var nodeWithHiddenProperty = node;
18305
+ var hiddenProperty = nodeWithHiddenProperty.__roosterjsHiddenProperty;
18306
+ return hiddenProperty ? hiddenProperty[key] : undefined;
18307
+ }
18308
+ exports.getHiddenProperty = getHiddenProperty;
18309
+ /**
18310
+ * @internal
18311
+ */
18312
+ function setHiddenProperty(node, key, value) {
18313
+ var nodeWithHiddenProperty = node;
18314
+ var hiddenProperty = nodeWithHiddenProperty.__roosterjsHiddenProperty || {};
18315
+ hiddenProperty[key] = value;
18316
+ nodeWithHiddenProperty.__roosterjsHiddenProperty = hiddenProperty;
18317
+ }
18318
+ exports.setHiddenProperty = setHiddenProperty;
18319
+
18320
+
18321
+ /***/ }),
18322
+
18323
+ /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/paragraphMarker.ts":
18324
+ /*!***********************************************************************************************!*\
18325
+ !*** ./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/paragraphMarker.ts ***!
18326
+ \***********************************************************************************************/
18327
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
18328
+
18329
+ "use strict";
18330
+
18331
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
18332
+ exports.setParagraphMarker = exports.getParagraphMarker = void 0;
18333
+ var hiddenProperty_1 = __webpack_require__(/*! ./hiddenProperty */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts");
18334
+ /**
18335
+ * Get paragraph marker from element. This is used to mark the end of a paragraph in a block element.
18336
+ */
18337
+ function getParagraphMarker(element) {
18338
+ return (0, hiddenProperty_1.getHiddenProperty)(element, 'paragraphMarker');
18339
+ }
18340
+ exports.getParagraphMarker = getParagraphMarker;
18341
+ /**
18342
+ * Set paragraph marker to element. This is used to mark the end of a paragraph in a block element.
18343
+ */
18344
+ function setParagraphMarker(element, marker) {
18345
+ (0, hiddenProperty_1.setHiddenProperty)(element, 'paragraphMarker', marker);
18346
+ }
18347
+ exports.setParagraphMarker = setParagraphMarker;
18348
+
18349
+
18350
+ /***/ }),
18351
+
18352
+ /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts":
18353
+ /*!***********************************************************************************************!*\
18354
+ !*** ./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts ***!
18355
+ \***********************************************************************************************/
18356
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
18357
+
18358
+ "use strict";
18359
+
18360
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
18361
+ exports.isLinkUndeletable = exports.setLinkUndeletable = void 0;
18362
+ var hiddenProperty_1 = __webpack_require__(/*! ./hiddenProperty */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts");
18363
+ var UndeletableLinkKey = 'undeletable';
18364
+ /**
18365
+ * Set a hidden property on a link element to indicate whether it is undeletable or not.
18366
+ * This is used to prevent the link from being deleted when the user tries to delete it.
18367
+ * @param a The link element to set the property on
18368
+ * @param undeletable Whether the link is undeletable or not
18369
+ */
18370
+ function setLinkUndeletable(a, undeletable) {
18371
+ (0, hiddenProperty_1.setHiddenProperty)(a, UndeletableLinkKey, undeletable);
18372
+ }
18373
+ exports.setLinkUndeletable = setLinkUndeletable;
18374
+ /**
18375
+ * Check if a link element is undeletable or not.
18376
+ * This is used to determine if the link can be deleted when the user tries to delete it.
18377
+ * @param a The link element to check
18378
+ * @returns True if the link is undeletable, false otherwise
18379
+ */
18380
+ function isLinkUndeletable(a) {
18381
+ return !!(0, hiddenProperty_1.getHiddenProperty)(a, UndeletableLinkKey);
18382
+ }
18383
+ exports.isLinkUndeletable = isLinkUndeletable;
18384
+
18385
+
18178
18386
  /***/ }),
18179
18387
 
18180
18388
  /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/isElementOfType.ts":
@@ -19665,6 +19873,7 @@ var textAlignFormatHandler_1 = __webpack_require__(/*! ./block/textAlignFormatHa
19665
19873
  var textColorFormatHandler_1 = __webpack_require__(/*! ./segment/textColorFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/textColorFormatHandler.ts");
19666
19874
  var textColorOnTableCellFormatHandler_1 = __webpack_require__(/*! ./table/textColorOnTableCellFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/table/textColorOnTableCellFormatHandler.ts");
19667
19875
  var textIndentFormatHandler_1 = __webpack_require__(/*! ./block/textIndentFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/block/textIndentFormatHandler.ts");
19876
+ var undeletableLinkFormatHandler_1 = __webpack_require__(/*! ./segment/undeletableLinkFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/undeletableLinkFormatHandler.ts");
19668
19877
  var underlineFormatHandler_1 = __webpack_require__(/*! ./segment/underlineFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/underlineFormatHandler.ts");
19669
19878
  var verticalAlignFormatHandler_1 = __webpack_require__(/*! ./common/verticalAlignFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/common/verticalAlignFormatHandler.ts");
19670
19879
  var whiteSpaceFormatHandler_1 = __webpack_require__(/*! ./block/whiteSpaceFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/block/whiteSpaceFormatHandler.ts");
@@ -19703,6 +19912,7 @@ var defaultFormatHandlerMap = {
19703
19912
  textColor: textColorFormatHandler_1.textColorFormatHandler,
19704
19913
  textColorOnTableCell: textColorOnTableCellFormatHandler_1.textColorOnTableCellFormatHandler,
19705
19914
  textIndent: textIndentFormatHandler_1.textIndentFormatHandler,
19915
+ undeletableLink: undeletableLinkFormatHandler_1.undeletableLinkFormatHandler,
19706
19916
  underline: underlineFormatHandler_1.underlineFormatHandler,
19707
19917
  verticalAlign: verticalAlignFormatHandler_1.verticalAlignFormatHandler,
19708
19918
  whiteSpace: whiteSpaceFormatHandler_1.whiteSpaceFormatHandler,
@@ -19808,6 +20018,7 @@ exports.defaultFormatKeysPerCategory = {
19808
20018
  'border',
19809
20019
  'size',
19810
20020
  'textAlign',
20021
+ 'undeletableLink',
19811
20022
  ],
19812
20023
  segmentUnderLink: ['textColor'],
19813
20024
  code: ['fontFamily', 'display'],
@@ -20296,8 +20507,10 @@ exports.linkFormatHandler = {
20296
20507
  }
20297
20508
  },
20298
20509
  apply: function (format, element) {
20299
- if ((0, isElementOfType_1.isElementOfType)(element, 'a') && format.href) {
20300
- element.href = format.href;
20510
+ if ((0, isElementOfType_1.isElementOfType)(element, 'a') && (format.href || format.name)) {
20511
+ if (format.href) {
20512
+ element.href = format.href;
20513
+ }
20301
20514
  if (format.name) {
20302
20515
  element.name = format.name;
20303
20516
  }
@@ -20435,6 +20648,37 @@ exports.textColorFormatHandler = {
20435
20648
  };
20436
20649
 
20437
20650
 
20651
+ /***/ }),
20652
+
20653
+ /***/ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/undeletableLinkFormatHandler.ts":
20654
+ /*!*********************************************************************************************************!*\
20655
+ !*** ./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/undeletableLinkFormatHandler.ts ***!
20656
+ \*********************************************************************************************************/
20657
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
20658
+
20659
+ "use strict";
20660
+
20661
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
20662
+ exports.undeletableLinkFormatHandler = void 0;
20663
+ var isElementOfType_1 = __webpack_require__(/*! ../../domUtils/isElementOfType */ "./packages/roosterjs-content-model-dom/lib/domUtils/isElementOfType.ts");
20664
+ var undeletableLink_1 = __webpack_require__(/*! ../../domUtils/hiddenProperties/undeletableLink */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts");
20665
+ /**
20666
+ * @internal
20667
+ */
20668
+ exports.undeletableLinkFormatHandler = {
20669
+ parse: function (format, element) {
20670
+ if ((0, isElementOfType_1.isElementOfType)(element, 'a') && (0, undeletableLink_1.isLinkUndeletable)(element)) {
20671
+ format.undeletable = true;
20672
+ }
20673
+ },
20674
+ apply: function (format, element) {
20675
+ if (format.undeletable && (0, isElementOfType_1.isElementOfType)(element, 'a')) {
20676
+ (0, undeletableLink_1.setLinkUndeletable)(element, true);
20677
+ }
20678
+ },
20679
+ };
20680
+
20681
+
20438
20682
  /***/ }),
20439
20683
 
20440
20684
  /***/ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/underlineFormatHandler.ts":
@@ -20928,9 +21172,10 @@ exports.shouldSetValue = shouldSetValue;
20928
21172
  "use strict";
20929
21173
 
20930
21174
  Object.defineProperty(exports, "__esModule", ({ value: true }));
20931
- 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.unwrap = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getSafeIdSelector = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.getMetadata = 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;
20932
- exports.transformColor = exports.readFile = exports.parseTableCells = exports.normalizeText = exports.isSpace = exports.isPunctuation = exports.extractBorderValues = exports.combineBorderValue = exports.isCursorMovingKey = exports.isModifierKey = exports.isCharacterValue = exports.getDOMInsertPointRect = exports.getSelectionRootNode = exports.isBold = exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.defaultGenerateColorKey = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.getAutoListStyleType = exports.getOrderedListNumberStr = exports.setParagraphNotImplicit = exports.mergeTextSegments = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = exports.normalizeParagraph = exports.addTextSegment = exports.addLink = exports.addCode = exports.addBlock = exports.mutateSegment = exports.mutateSegments = exports.mutateBlock = exports.createTableRow = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = void 0;
20933
- exports.EmptySegmentFormat = exports.UnorderedListStyleMap = exports.OrderedListStyleMap = exports.TableBorderFormat = exports.NumberingListType = exports.BulletListType = exports.ChangeSource = exports.ListMetadataDefinition = exports.getListMetadata = exports.updateListMetadata = exports.getTableMetadata = exports.updateTableMetadata = exports.getTableCellMetadata = exports.updateTableCellMetadata = exports.getImageMetadata = exports.updateImageMetadata = exports.runEditSteps = exports.getClosestAncestorBlockGroupIndex = exports.getSegmentTextFormat = exports.getListStyleTypeFromString = exports.retrieveModelFormatState = exports.setTableCellBackgroundColor = exports.MIN_ALLOWED_TABLE_CELL_HEIGHT = exports.MIN_ALLOWED_TABLE_CELL_WIDTH = exports.normalizeTable = exports.setFirstColumnFormatBorders = exports.applyTableFormat = exports.deleteBlock = exports.deleteSegment = exports.deleteSelection = exports.mergeModel = exports.cloneModel = exports.setSelection = exports.hasSelectionInBlockGroup = exports.hasSelectionInSegment = exports.hasSelectionInBlock = exports.getSelectedCells = exports.getSelectedSegmentsAndParagraphs = exports.getSelectedSegments = exports.getSelectedParagraphs = exports.getOperationalBlocks = exports.getFirstSelectedTable = exports.getFirstSelectedListItem = exports.iterateSelections = exports.isBlockGroupOfType = exports.cacheGetEventData = exports.extractClipboardItems = void 0;
21175
+ exports.createParagraphDecorator = exports.createContentModelDocument = exports.createImage = exports.createText = exports.createTableCell = exports.createTable = exports.createSelectionMarker = exports.createParagraph = exports.createFormatContainer = exports.createListItem = exports.createBr = exports.isLinkUndeletable = exports.setLinkUndeletable = 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.unwrap = exports.wrap = exports.wrapAllChildNodes = exports.moveChildNodes = exports.toArray = exports.getSafeIdSelector = exports.getObjectKeys = exports.isElementOfType = exports.isNodeOfType = exports.hasMetadata = exports.getMetadata = 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;
21176
+ exports.parseTableCells = exports.normalizeText = exports.isSpace = exports.isPunctuation = exports.extractBorderValues = exports.combineBorderValue = exports.isCursorMovingKey = exports.isModifierKey = exports.isCharacterValue = exports.getDOMInsertPointRect = exports.getSelectionRootNode = exports.isBold = exports.createModelToDomConfig = exports.createModelToDomContextWithConfig = exports.createModelToDomContext = exports.createDomToModelConfig = exports.createDomToModelContextWithConfig = exports.createDomToModelContext = exports.defaultGenerateColorKey = exports.parseColor = exports.setColor = exports.getColor = exports.DeprecatedColors = exports.BorderKeys = exports.parseValueWithUnit = exports.getAutoListStyleType = exports.getOrderedListNumberStr = exports.setParagraphNotImplicit = exports.mergeTextSegments = exports.normalizeSingleSegment = exports.isEmpty = exports.addSegment = exports.unwrapBlock = exports.isGeneralSegment = exports.normalizeContentModel = exports.normalizeParagraph = exports.addTextSegment = exports.addLink = exports.addCode = exports.addBlock = exports.mutateSegment = exports.mutateSegments = exports.mutateBlock = exports.createTableRow = exports.createEmptyModel = exports.createListLevel = exports.createDivider = exports.createEntity = exports.createGeneralBlock = exports.createGeneralSegment = void 0;
21177
+ exports.UnorderedListStyleMap = exports.OrderedListStyleMap = exports.TableBorderFormat = exports.NumberingListType = exports.BulletListType = exports.ChangeSource = exports.ListMetadataDefinition = exports.getListMetadata = exports.updateListMetadata = exports.getTableMetadata = exports.updateTableMetadata = exports.getTableCellMetadata = exports.updateTableCellMetadata = exports.getImageMetadata = exports.updateImageMetadata = exports.runEditSteps = exports.getClosestAncestorBlockGroupIndex = exports.getSegmentTextFormat = exports.getListStyleTypeFromString = exports.retrieveModelFormatState = exports.setTableCellBackgroundColor = exports.MIN_ALLOWED_TABLE_CELL_HEIGHT = exports.MIN_ALLOWED_TABLE_CELL_WIDTH = exports.normalizeTable = exports.setFirstColumnFormatBorders = exports.applyTableFormat = exports.deleteBlock = exports.deleteSegment = exports.deleteSelection = exports.mergeModel = exports.cloneModel = exports.setSelection = exports.hasSelectionInBlockGroup = exports.hasSelectionInSegment = exports.hasSelectionInBlock = exports.getSelectedCells = exports.getSelectedSegmentsAndParagraphs = exports.getSelectedSegments = exports.getSelectedParagraphs = exports.getOperationalBlocks = exports.getFirstSelectedTable = exports.getFirstSelectedListItem = exports.iterateSelections = exports.isBlockGroupOfType = exports.getParagraphMarker = exports.setParagraphMarker = exports.cacheGetEventData = exports.extractClipboardItems = exports.transformColor = exports.readFile = void 0;
21178
+ exports.EmptySegmentFormat = void 0;
20934
21179
  var domToContentModel_1 = __webpack_require__(/*! ./domToModel/domToContentModel */ "./packages/roosterjs-content-model-dom/lib/domToModel/domToContentModel.ts");
20935
21180
  Object.defineProperty(exports, "domToContentModel", ({ enumerable: true, get: function () { return domToContentModel_1.domToContentModel; } }));
20936
21181
  var contentModelToDom_1 = __webpack_require__(/*! ./modelToDom/contentModelToDom */ "./packages/roosterjs-content-model-dom/lib/modelToDom/contentModelToDom.ts");
@@ -20992,6 +21237,9 @@ var isWhiteSpacePreserved_1 = __webpack_require__(/*! ./domUtils/isWhiteSpacePre
20992
21237
  Object.defineProperty(exports, "isWhiteSpacePreserved", ({ enumerable: true, get: function () { return isWhiteSpacePreserved_1.isWhiteSpacePreserved; } }));
20993
21238
  var normalizeRect_1 = __webpack_require__(/*! ./domUtils/normalizeRect */ "./packages/roosterjs-content-model-dom/lib/domUtils/normalizeRect.ts");
20994
21239
  Object.defineProperty(exports, "normalizeRect", ({ enumerable: true, get: function () { return normalizeRect_1.normalizeRect; } }));
21240
+ var undeletableLink_1 = __webpack_require__(/*! ./domUtils/hiddenProperties/undeletableLink */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts");
21241
+ Object.defineProperty(exports, "setLinkUndeletable", ({ enumerable: true, get: function () { return undeletableLink_1.setLinkUndeletable; } }));
21242
+ Object.defineProperty(exports, "isLinkUndeletable", ({ enumerable: true, get: function () { return undeletableLink_1.isLinkUndeletable; } }));
20995
21243
  var createBr_1 = __webpack_require__(/*! ./modelApi/creators/createBr */ "./packages/roosterjs-content-model-dom/lib/modelApi/creators/createBr.ts");
20996
21244
  Object.defineProperty(exports, "createBr", ({ enumerable: true, get: function () { return createBr_1.createBr; } }));
20997
21245
  var createListItem_1 = __webpack_require__(/*! ./modelApi/creators/createListItem */ "./packages/roosterjs-content-model-dom/lib/modelApi/creators/createListItem.ts");
@@ -21107,6 +21355,9 @@ var extractClipboardItems_1 = __webpack_require__(/*! ./domUtils/event/extractCl
21107
21355
  Object.defineProperty(exports, "extractClipboardItems", ({ enumerable: true, get: function () { return extractClipboardItems_1.extractClipboardItems; } }));
21108
21356
  var cacheGetEventData_1 = __webpack_require__(/*! ./domUtils/event/cacheGetEventData */ "./packages/roosterjs-content-model-dom/lib/domUtils/event/cacheGetEventData.ts");
21109
21357
  Object.defineProperty(exports, "cacheGetEventData", ({ enumerable: true, get: function () { return cacheGetEventData_1.cacheGetEventData; } }));
21358
+ var paragraphMarker_1 = __webpack_require__(/*! ./domUtils/hiddenProperties/paragraphMarker */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/paragraphMarker.ts");
21359
+ Object.defineProperty(exports, "setParagraphMarker", ({ enumerable: true, get: function () { return paragraphMarker_1.setParagraphMarker; } }));
21360
+ Object.defineProperty(exports, "getParagraphMarker", ({ enumerable: true, get: function () { return paragraphMarker_1.getParagraphMarker; } }));
21110
21361
  var isBlockGroupOfType_1 = __webpack_require__(/*! ./modelApi/typeCheck/isBlockGroupOfType */ "./packages/roosterjs-content-model-dom/lib/modelApi/typeCheck/isBlockGroupOfType.ts");
21111
21362
  Object.defineProperty(exports, "isBlockGroupOfType", ({ enumerable: true, get: function () { return isBlockGroupOfType_1.isBlockGroupOfType; } }));
21112
21363
  var iterateSelections_1 = __webpack_require__(/*! ./modelApi/selection/iterateSelections */ "./packages/roosterjs-content-model-dom/lib/modelApi/selection/iterateSelections.ts");
@@ -21251,7 +21502,7 @@ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.m
21251
21502
  * @internal
21252
21503
  */
21253
21504
  function addLink(segment, link) {
21254
- if (link.format.href) {
21505
+ if (link.format.href || link.format.name) {
21255
21506
  segment.link = {
21256
21507
  format: (0, tslib_1.__assign)({}, link.format),
21257
21508
  dataset: (0, tslib_1.__assign)({}, link.dataset),
@@ -21480,10 +21731,11 @@ exports.isBlockGroupEmpty = isBlockGroupEmpty;
21480
21731
  /**
21481
21732
  * @internal
21482
21733
  */
21483
- function isSegmentEmpty(segment) {
21734
+ function isSegmentEmpty(segment, treatAnchorAsNotEmpty) {
21735
+ var _a;
21484
21736
  switch (segment.segmentType) {
21485
21737
  case 'Text':
21486
- return !segment.text;
21738
+ return !segment.text && (!treatAnchorAsNotEmpty || !((_a = segment.link) === null || _a === void 0 ? void 0 : _a.format.name));
21487
21739
  default:
21488
21740
  return false;
21489
21741
  }
@@ -21769,7 +22021,7 @@ function normalizeParagraphStyle(paragraph) {
21769
22021
  }
21770
22022
  function removeEmptySegments(block) {
21771
22023
  for (var j = block.segments.length - 1; j >= 0; j--) {
21772
- if ((0, isEmpty_1.isSegmentEmpty)(block.segments[j])) {
22024
+ if ((0, isEmpty_1.isSegmentEmpty)(block.segments[j], true /*treatAnchorAsNotEmpty*/)) {
21773
22025
  (0, mutate_1.mutateBlock)(block).segments.splice(j, 1);
21774
22026
  }
21775
22027
  }
@@ -23163,6 +23415,7 @@ function deleteExpandedSelection(model, formatContext) {
23163
23415
  deleteResult: 'notDeleted',
23164
23416
  insertPoint: null,
23165
23417
  formatContext: formatContext,
23418
+ undeletableSegments: [],
23166
23419
  };
23167
23420
  (0, iterateSelections_1.iterateSelections)(model, function (path, tableContext, readonlyBlock, readonlySegments) {
23168
23421
  // Set paragraph, format and index for default position where we will put cursor to.
@@ -23179,6 +23432,7 @@ function deleteExpandedSelection(model, formatContext) {
23179
23432
  paragraph = block_1;
23180
23433
  insertMarkerIndex = indexes[0];
23181
23434
  markerFormat = (0, getSegmentTextFormat_1.getSegmentTextFormat)(segments[0], true /*includingBIU*/);
23435
+ var isFirstDeletingParagraph_1 = !context.lastParagraph;
23182
23436
  context.lastParagraph = paragraph;
23183
23437
  context.lastTableContext = tableContext;
23184
23438
  segments.forEach(function (segment, i) {
@@ -23189,7 +23443,8 @@ function deleteExpandedSelection(model, formatContext) {
23189
23443
  // because this is possible a collapsed selection, then it will be handled later
23190
23444
  context.insertPoint = createInsertPoint(segment, block_1, path, tableContext);
23191
23445
  }
23192
- else if ((0, deleteSegment_1.deleteSegment)(block_1, segment, context.formatContext)) {
23446
+ else if ((0, deleteSegment_1.deleteSegment)(block_1, segment, context.formatContext, undefined /*direction*/, isFirstDeletingParagraph_1 ? undefined : context.undeletableSegments // For first paragraph we can keep undeletable segments so no need to merge it later
23447
+ )) {
23193
23448
  context.deleteResult = 'range';
23194
23449
  }
23195
23450
  });
@@ -23264,9 +23519,10 @@ var stringUtil_1 = __webpack_require__(/*! ../../domUtils/stringUtil */ "./packa
23264
23519
  * @param readonlySegmentToDelete The segment to delete
23265
23520
  * @param context @optional Context object provided by formatContentModel API
23266
23521
  * @param direction @optional Whether this is deleting forward or backward. This is only used for deleting entity.
23522
+ * @param undeletableSegments @optional When passed, if this segment is undeletable, it will be added to this array instead of being deleted.
23267
23523
  * If not specified, only selected entity will be deleted
23268
23524
  */
23269
- function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, direction) {
23525
+ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, direction, undeletableSegments) {
23270
23526
  var _a = (0, tslib_1.__read)((0, mutate_1.mutateSegment)(readonlyParagraph, readonlySegmentToDelete), 3), paragraph = _a[0], segmentToDelete = _a[1], index = _a[2];
23271
23527
  var segments = paragraph.segments;
23272
23528
  var preserveWhiteSpace = (0, isWhiteSpacePreserved_1.isWhiteSpacePreserved)(paragraph.format.whiteSpace);
@@ -23279,7 +23535,7 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23279
23535
  case 'Br':
23280
23536
  case 'Image':
23281
23537
  case 'SelectionMarker':
23282
- segments.splice(index, 1);
23538
+ removeSegment(segments, index, direction, undeletableSegments);
23283
23539
  return true;
23284
23540
  case 'Entity':
23285
23541
  var operation = segmentToDelete.isSelected
@@ -23290,7 +23546,7 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23290
23546
  ? 'removeFromEnd'
23291
23547
  : undefined;
23292
23548
  if (operation !== undefined) {
23293
- segments.splice(index, 1);
23549
+ removeSegment(segments, index, direction, undeletableSegments);
23294
23550
  context === null || context === void 0 ? void 0 : context.deletedEntities.push({
23295
23551
  entity: segmentToDelete,
23296
23552
  operation: operation,
@@ -23298,26 +23554,25 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23298
23554
  }
23299
23555
  return true;
23300
23556
  case 'Text':
23301
- var text = segmentToDelete.text;
23302
- if (text.length == 0 || segmentToDelete.isSelected) {
23303
- segments.splice(index, 1);
23557
+ if (segmentToDelete.text.length == 0 || segmentToDelete.isSelected) {
23558
+ segmentToDelete.text = '';
23559
+ removeSegment(segments, index, direction, undeletableSegments);
23304
23560
  }
23305
23561
  else if (direction) {
23562
+ var text = segmentToDelete.text;
23306
23563
  text = (0, deleteSingleChar_1.deleteSingleChar)(text, isForward); // isForward ? text.substring(1) : text.substring(0, text.length - 1);
23307
23564
  if (!preserveWhiteSpace) {
23308
23565
  text = (0, stringUtil_1.normalizeText)(text, isForward);
23309
23566
  }
23567
+ segmentToDelete.text = text;
23310
23568
  if (text == '') {
23311
- segments.splice(index, 1);
23312
- }
23313
- else {
23314
- segmentToDelete.text = text;
23569
+ removeSegment(segments, index, direction, undeletableSegments);
23315
23570
  }
23316
23571
  }
23317
23572
  return true;
23318
23573
  case 'General':
23319
23574
  if (segmentToDelete.isSelected) {
23320
- segments.splice(index, 1);
23575
+ removeSegment(segments, index, direction, undeletableSegments);
23321
23576
  return true;
23322
23577
  }
23323
23578
  else {
@@ -23328,6 +23583,42 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23328
23583
  }
23329
23584
  }
23330
23585
  exports.deleteSegment = deleteSegment;
23586
+ function removeSegment(segments, index, direction, undeletableSegments) {
23587
+ var _a;
23588
+ var segment = segments.splice(index, 1)[0];
23589
+ if ((_a = segment.link) === null || _a === void 0 ? void 0 : _a.format.undeletable) {
23590
+ // Segment is not deletable, but at least we should unselect it
23591
+ delete segment.isSelected;
23592
+ if (undeletableSegments) {
23593
+ // For undeletable segments, if an undeletableSegments array is passed in,
23594
+ // put it into this array after we delete it, so caller knows that we have deleted some undeletable segments
23595
+ // and do proper handling
23596
+ undeletableSegments.push(segment);
23597
+ }
23598
+ else {
23599
+ // Otherwise, we need to reinsert it back to the segments array to keep the model consistent.
23600
+ // We need to find the right place to insert it back based on the direction of deletion
23601
+ var insertIndex = void 0;
23602
+ switch (direction) {
23603
+ case 'forward':
23604
+ insertIndex =
23605
+ index > 0 && segments[index - 1].segmentType == 'SelectionMarker'
23606
+ ? index - 1
23607
+ : index;
23608
+ break;
23609
+ case 'backward':
23610
+ insertIndex =
23611
+ index < segments.length && segments[index].segmentType == 'SelectionMarker'
23612
+ ? index + 1
23613
+ : index;
23614
+ break;
23615
+ default:
23616
+ insertIndex = index;
23617
+ }
23618
+ segments.splice(insertIndex, 0, segment);
23619
+ }
23620
+ }
23621
+ }
23331
23622
  function normalizePreviousSegment(paragraph, segments, currentIndex) {
23332
23623
  var _a;
23333
23624
  var index = currentIndex - 1;
@@ -23375,8 +23666,8 @@ function deleteSelection(model, additionalSteps, formatContext) {
23375
23666
  exports.deleteSelection = deleteSelection;
23376
23667
  // If we end up with multiple paragraphs impacted, we need to merge them
23377
23668
  function mergeParagraphAfterDelete(context) {
23378
- var _a;
23379
- var insertPoint = context.insertPoint, deleteResult = context.deleteResult, lastParagraph = context.lastParagraph, lastTableContext = context.lastTableContext;
23669
+ var _a, _b;
23670
+ var insertPoint = context.insertPoint, deleteResult = context.deleteResult, lastParagraph = context.lastParagraph, lastTableContext = context.lastTableContext, undeletableSegments = context.undeletableSegments;
23380
23671
  if (insertPoint &&
23381
23672
  deleteResult != 'notDeleted' &&
23382
23673
  deleteResult != 'nothingToDelete' &&
@@ -23384,7 +23675,11 @@ function mergeParagraphAfterDelete(context) {
23384
23675
  lastParagraph != insertPoint.paragraph &&
23385
23676
  lastTableContext == insertPoint.tableContext) {
23386
23677
  var mutableLastParagraph = (0, mutate_1.mutateBlock)(lastParagraph);
23387
- (_a = (0, mutate_1.mutateBlock)(insertPoint.paragraph).segments).push.apply(_a, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(mutableLastParagraph.segments), false));
23678
+ var mutableInsertingParagraph = (0, mutate_1.mutateBlock)(insertPoint.paragraph);
23679
+ if (undeletableSegments) {
23680
+ (_a = mutableLastParagraph.segments).unshift.apply(_a, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(undeletableSegments), false));
23681
+ }
23682
+ (_b = mutableInsertingParagraph.segments).push.apply(_b, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(mutableLastParagraph.segments), false));
23388
23683
  mutableLastParagraph.segments = [];
23389
23684
  }
23390
23685
  }
@@ -26544,7 +26839,7 @@ var handleParagraph = function (doc, parent, paragraph, context, refNode) {
26544
26839
  }
26545
26840
  else {
26546
26841
  (0, stackFormat_1.stackFormat)(context, ((_a = paragraph.decorator) === null || _a === void 0 ? void 0 : _a.tagName) || null, function () {
26547
- var _a, _b, _c, _d;
26842
+ var _a, _b, _c, _d, _e;
26548
26843
  var needParagraphWrapper = !paragraph.isImplicit ||
26549
26844
  !!paragraph.decorator ||
26550
26845
  ((0, getObjectKeys_1.getObjectKeys)(paragraph.format).length > 0 &&
@@ -26582,6 +26877,7 @@ var handleParagraph = function (doc, parent, paragraph, context, refNode) {
26582
26877
  (0, applyFormat_1.applyFormat)(container, context.formatAppliers.block, paragraph.format, context);
26583
26878
  (0, applyFormat_1.applyFormat)(container, context.formatAppliers.container, paragraph.format, context);
26584
26879
  (0, applyFormat_1.applyFormat)(container, context.formatAppliers.segmentOnBlock, formatOnWrapper, context);
26880
+ (_c = context.paragraphMap) === null || _c === void 0 ? void 0 : _c.applyMarkerToDom(container, paragraph);
26585
26881
  }
26586
26882
  else {
26587
26883
  handleSegments();
@@ -26595,8 +26891,8 @@ var handleParagraph = function (doc, parent, paragraph, context, refNode) {
26595
26891
  // to make sure the value is correct.
26596
26892
  refNode = container.nextSibling;
26597
26893
  if (container) {
26598
- (_c = context.onNodeCreated) === null || _c === void 0 ? void 0 : _c.call(context, paragraph, container);
26599
- (_d = context.domIndexer) === null || _d === void 0 ? void 0 : _d.onParagraph(container);
26894
+ (_d = context.onNodeCreated) === null || _d === void 0 ? void 0 : _d.call(context, paragraph, container);
26895
+ (_e = context.domIndexer) === null || _e === void 0 ? void 0 : _e.onParagraph(container);
26600
26896
  }
26601
26897
  if (needParagraphWrapper) {
26602
26898
  if (context.allowCacheElement) {
@@ -29446,19 +29742,40 @@ function shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelecti
29446
29742
  }
29447
29743
  else {
29448
29744
  var range = selection.range;
29745
+ var startContainer = range.startContainer;
29746
+ var startOffset = range.startOffset;
29449
29747
  // When selection is collapsed and is in middle of text node, no need to use Content Model to delete
29450
- return !((0, roosterjs_content_model_dom_1.isNodeOfType)(range.startContainer, 'TEXT_NODE') &&
29748
+ return !((0, roosterjs_content_model_dom_1.isNodeOfType)(startContainer, 'TEXT_NODE') &&
29451
29749
  !(0, roosterjs_content_model_dom_1.isModifierKey)(rawEvent) &&
29452
- (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range)));
29750
+ (canDeleteBefore(rawEvent, startContainer, startOffset) ||
29751
+ canDeleteAfter(rawEvent, startContainer, startOffset)));
29453
29752
  }
29454
29753
  }
29455
- function canDeleteBefore(rawEvent, range) {
29456
- return rawEvent.key == 'Backspace' && range.startOffset > 1;
29754
+ function canDeleteBefore(rawEvent, text, offset) {
29755
+ var _a, _b;
29756
+ if (rawEvent.key != 'Backspace' || offset <= 1) {
29757
+ return false;
29758
+ }
29759
+ var length = (_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
29760
+ if (offset == length) {
29761
+ // At the end of text, need to check if next segment is deletable
29762
+ var nextSibling = text.nextSibling;
29763
+ var isNextSiblingUndeletable = (0, roosterjs_content_model_dom_1.isNodeOfType)(nextSibling, 'ELEMENT_NODE') &&
29764
+ (0, roosterjs_content_model_dom_1.isElementOfType)(nextSibling, 'a') &&
29765
+ (0, roosterjs_content_model_dom_1.isLinkUndeletable)(nextSibling) &&
29766
+ !nextSibling.firstChild;
29767
+ // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor
29768
+ // So we return false here to let Content Model handle it
29769
+ return !isNextSiblingUndeletable;
29770
+ }
29771
+ else {
29772
+ // In middle of text, we can safely let browser handle deletion
29773
+ return true;
29774
+ }
29457
29775
  }
29458
- function canDeleteAfter(rawEvent, range) {
29776
+ function canDeleteAfter(rawEvent, text, offset) {
29459
29777
  var _a, _b;
29460
- return (rawEvent.key == 'Delete' &&
29461
- range.startOffset < ((_b = (_a = range.startContainer.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1);
29778
+ return rawEvent.key == 'Delete' && offset < ((_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) - 1;
29462
29779
  }
29463
29780
 
29464
29781
 
@@ -30022,6 +30339,122 @@ function splitParagraph(insertPoint) {
30022
30339
  exports.splitParagraph = splitParagraph;
30023
30340
 
30024
30341
 
30342
+ /***/ }),
30343
+
30344
+ /***/ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts":
30345
+ /*!*********************************************************************************************!*\
30346
+ !*** ./packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts ***!
30347
+ \*********************************************************************************************/
30348
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
30349
+
30350
+ "use strict";
30351
+
30352
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
30353
+ exports.HiddenPropertyPlugin = void 0;
30354
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30355
+ var fixupHiddenProperties_1 = __webpack_require__(/*! ./fixupHiddenProperties */ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts");
30356
+ /**
30357
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
30358
+ */
30359
+ var HiddenPropertyPlugin = /** @class */ (function () {
30360
+ /**
30361
+ * Construct a new instance of FormatPlugin class
30362
+ * @param option The editor option
30363
+ */
30364
+ function HiddenPropertyPlugin(option) {
30365
+ this.option = option;
30366
+ this.editor = null;
30367
+ }
30368
+ /**
30369
+ * Get name of this plugin
30370
+ */
30371
+ HiddenPropertyPlugin.prototype.getName = function () {
30372
+ return 'HiddenProperty';
30373
+ };
30374
+ /**
30375
+ * The first method that editor will call to a plugin when editor is initializing.
30376
+ * It will pass in the editor instance, plugin should take this chance to save the
30377
+ * editor reference so that it can call to any editor method or format API later.
30378
+ * @param editor The editor object
30379
+ */
30380
+ HiddenPropertyPlugin.prototype.initialize = function (editor) {
30381
+ this.editor = editor;
30382
+ };
30383
+ /**
30384
+ * The last method that editor will call to a plugin before it is disposed.
30385
+ * Plugin can take this chance to clear the reference to editor. After this method is
30386
+ * called, plugin should not call to any editor method since it will result in error.
30387
+ */
30388
+ HiddenPropertyPlugin.prototype.dispose = function () {
30389
+ this.editor = null;
30390
+ };
30391
+ /**
30392
+ * Core method for a plugin. Once an event happens in editor, editor will call this
30393
+ * method of each plugin to handle the event as long as the event is not handled
30394
+ * exclusively by another plugin.
30395
+ * @param event The event to handle:
30396
+ */
30397
+ HiddenPropertyPlugin.prototype.onPluginEvent = function (event) {
30398
+ if (!this.editor) {
30399
+ return;
30400
+ }
30401
+ if (event.eventType == 'contentChanged' && event.source == roosterjs_content_model_dom_1.ChangeSource.SetContent) {
30402
+ (0, fixupHiddenProperties_1.fixupHiddenProperties)(this.editor, this.option);
30403
+ }
30404
+ };
30405
+ return HiddenPropertyPlugin;
30406
+ }());
30407
+ exports.HiddenPropertyPlugin = HiddenPropertyPlugin;
30408
+
30409
+
30410
+ /***/ }),
30411
+
30412
+ /***/ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts":
30413
+ /*!**********************************************************************************************!*\
30414
+ !*** ./packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts ***!
30415
+ \**********************************************************************************************/
30416
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
30417
+
30418
+ "use strict";
30419
+
30420
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
30421
+ exports.fixupHiddenProperties = void 0;
30422
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30423
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30424
+ /**
30425
+ * @internal
30426
+ * Maintain hidden properties in DOM after editor content is reset using HTML
30427
+ * This includes:
30428
+ * 1. Undeletable property
30429
+ */
30430
+ function fixupHiddenProperties(editor, options) {
30431
+ if (options.undeletableLinkChecker) {
30432
+ checkUndeletable(editor, options.undeletableLinkChecker);
30433
+ }
30434
+ // Add more hidden properties checkers here
30435
+ }
30436
+ exports.fixupHiddenProperties = fixupHiddenProperties;
30437
+ function checkUndeletable(editor, checker) {
30438
+ var e_1, _a;
30439
+ var anchors = editor.getDOMHelper().queryElements('a');
30440
+ try {
30441
+ for (var anchors_1 = (0, tslib_1.__values)(anchors), anchors_1_1 = anchors_1.next(); !anchors_1_1.done; anchors_1_1 = anchors_1.next()) {
30442
+ var a = anchors_1_1.value;
30443
+ if (checker(a)) {
30444
+ (0, roosterjs_content_model_dom_1.setLinkUndeletable)(a, true);
30445
+ }
30446
+ }
30447
+ }
30448
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
30449
+ finally {
30450
+ try {
30451
+ if (anchors_1_1 && !anchors_1_1.done && (_a = anchors_1.return)) _a.call(anchors_1);
30452
+ }
30453
+ finally { if (e_1) throw e_1.error; }
30454
+ }
30455
+ }
30456
+
30457
+
30025
30458
  /***/ }),
30026
30459
 
30027
30460
  /***/ "./packages/roosterjs-content-model-plugins/lib/hyperlink/HyperlinkPlugin.ts":
@@ -32379,7 +32812,7 @@ exports.updateWrapper = updateWrapper;
32379
32812
  "use strict";
32380
32813
 
32381
32814
  Object.defineProperty(exports, "__esModule", ({ value: true }));
32382
- exports.ImageEditPlugin = exports.CustomReplacePlugin = exports.PickerPlugin = exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.isModelEmptyFast = 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.DefaultSanitizers = exports.PastePlugin = exports.TableEditPlugin = void 0;
32815
+ exports.HiddenPropertyPlugin = exports.ImageEditPlugin = exports.CustomReplacePlugin = exports.PickerPlugin = exports.HyperlinkPlugin = exports.MarkdownPlugin = exports.isModelEmptyFast = 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.DefaultSanitizers = exports.PastePlugin = exports.TableEditPlugin = void 0;
32383
32816
  var TableEditPlugin_1 = __webpack_require__(/*! ./tableEdit/TableEditPlugin */ "./packages/roosterjs-content-model-plugins/lib/tableEdit/TableEditPlugin.ts");
32384
32817
  Object.defineProperty(exports, "TableEditPlugin", ({ enumerable: true, get: function () { return TableEditPlugin_1.TableEditPlugin; } }));
32385
32818
  var PastePlugin_1 = __webpack_require__(/*! ./paste/PastePlugin */ "./packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts");
@@ -32424,6 +32857,8 @@ var CustomReplacePlugin_1 = __webpack_require__(/*! ./customReplace/CustomReplac
32424
32857
  Object.defineProperty(exports, "CustomReplacePlugin", ({ enumerable: true, get: function () { return CustomReplacePlugin_1.CustomReplacePlugin; } }));
32425
32858
  var ImageEditPlugin_1 = __webpack_require__(/*! ./imageEdit/ImageEditPlugin */ "./packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts");
32426
32859
  Object.defineProperty(exports, "ImageEditPlugin", ({ enumerable: true, get: function () { return ImageEditPlugin_1.ImageEditPlugin; } }));
32860
+ var HiddenPropertyPlugin_1 = __webpack_require__(/*! ./hiddenProperty/HiddenPropertyPlugin */ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts");
32861
+ Object.defineProperty(exports, "HiddenPropertyPlugin", ({ enumerable: true, get: function () { return HiddenPropertyPlugin_1.HiddenPropertyPlugin; } }));
32427
32862
 
32428
32863
 
32429
32864
  /***/ }),