roosterjs 9.22.0 → 9.23.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");
@@ -10303,6 +10305,7 @@ var CachePlugin = /** @class */ (function () {
10303
10305
  domIndexer: new domIndexerImpl_1.DomIndexerImpl(option.experimentalFeatures &&
10304
10306
  option.experimentalFeatures.indexOf('PersistCache') >= 0),
10305
10307
  textMutationObserver: (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation),
10308
+ paragraphMap: (0, ParagraphMapImpl_1.createParagraphMap)(),
10306
10309
  };
10307
10310
  }
10308
10311
  /**
@@ -10385,10 +10388,13 @@ var CachePlugin = /** @class */ (function () {
10385
10388
  }
10386
10389
  };
10387
10390
  CachePlugin.prototype.invalidateCache = function () {
10388
- var _a;
10391
+ var _a, _b;
10389
10392
  if (!((_a = this.editor) === null || _a === void 0 ? void 0 : _a.isInShadowEdit())) {
10390
10393
  this.state.cachedModel = undefined;
10391
10394
  this.state.cachedSelection = undefined;
10395
+ // Clear paragraph indexer to prevent stale references to old paragraphs
10396
+ // It will be rebuild next time when we create a new Content Model
10397
+ (_b = this.state.paragraphMap) === null || _b === void 0 ? void 0 : _b.clear();
10392
10398
  }
10393
10399
  };
10394
10400
  CachePlugin.prototype.updateCachedModel = function (editor, forceUpdate) {
@@ -10432,6 +10438,84 @@ function createCachePlugin(option, contentDiv) {
10432
10438
  exports.createCachePlugin = createCachePlugin;
10433
10439
 
10434
10440
 
10441
+ /***/ }),
10442
+
10443
+ /***/ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts":
10444
+ /*!****************************************************************************************!*\
10445
+ !*** ./packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts ***!
10446
+ \****************************************************************************************/
10447
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
10448
+
10449
+ "use strict";
10450
+
10451
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
10452
+ exports.createParagraphMap = void 0;
10453
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
10454
+ var idPrefix = 'paragraph';
10455
+ var ParagraphMapImpl = /** @class */ (function () {
10456
+ function ParagraphMapImpl() {
10457
+ this.nextId = 0;
10458
+ this.paragraphMap = {};
10459
+ ParagraphMapImpl.prefixNum++;
10460
+ }
10461
+ ParagraphMapImpl.prototype.assignMarkerToModel = function (element, paragraph) {
10462
+ var marker = (0, roosterjs_content_model_dom_1.getParagraphMarker)(element);
10463
+ var paragraphWithMarker = paragraph;
10464
+ if (marker) {
10465
+ paragraphWithMarker._marker = marker;
10466
+ this.paragraphMap[marker] = paragraph;
10467
+ }
10468
+ else {
10469
+ paragraphWithMarker._marker = this.generateId();
10470
+ this.applyMarkerToDom(element, paragraph);
10471
+ }
10472
+ };
10473
+ ParagraphMapImpl.prototype.applyMarkerToDom = function (element, paragraph) {
10474
+ var paragraphWithMarker = paragraph;
10475
+ if (!paragraphWithMarker._marker) {
10476
+ paragraphWithMarker._marker = this.generateId();
10477
+ }
10478
+ var marker = paragraphWithMarker._marker;
10479
+ if (marker) {
10480
+ (0, roosterjs_content_model_dom_1.setParagraphMarker)(element, marker);
10481
+ this.paragraphMap[marker] = paragraph;
10482
+ }
10483
+ };
10484
+ /**
10485
+ * Get paragraph using a previously marked paragraph
10486
+ * @param markedParagraph The previously marked paragraph to get
10487
+ */
10488
+ ParagraphMapImpl.prototype.getParagraphFromMarker = function (markerParagraph) {
10489
+ var marker = markerParagraph._marker;
10490
+ return marker ? this.paragraphMap[marker] || null : null;
10491
+ };
10492
+ ParagraphMapImpl.prototype.clear = function () {
10493
+ this.paragraphMap = {};
10494
+ };
10495
+ //#region For test code only
10496
+ ParagraphMapImpl.prototype._reset = function () {
10497
+ ParagraphMapImpl.prefixNum = 0;
10498
+ this.nextId = 0;
10499
+ };
10500
+ ParagraphMapImpl.prototype._getMap = function () {
10501
+ return this.paragraphMap;
10502
+ };
10503
+ //#endregion
10504
+ ParagraphMapImpl.prototype.generateId = function () {
10505
+ return idPrefix + "_" + ParagraphMapImpl.prefixNum + "_" + this.nextId++;
10506
+ };
10507
+ ParagraphMapImpl.prefixNum = 0;
10508
+ return ParagraphMapImpl;
10509
+ }());
10510
+ /**
10511
+ * @internal
10512
+ */
10513
+ function createParagraphMap() {
10514
+ return new ParagraphMapImpl();
10515
+ }
10516
+ exports.createParagraphMap = createParagraphMap;
10517
+
10518
+
10435
10519
  /***/ }),
10436
10520
 
10437
10521
  /***/ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts":
@@ -16191,6 +16275,7 @@ var SegmentDecoratorTags = ['A', 'CODE'];
16191
16275
  * @internal
16192
16276
  */
16193
16277
  function blockProcessor(group, element, context, segmentFormat) {
16278
+ var _a;
16194
16279
  var decorator = context.blockDecorator.tagName ? context.blockDecorator : undefined;
16195
16280
  var isSegmentDecorator = SegmentDecoratorTags.indexOf(element.tagName) >= 0;
16196
16281
  (0, parseFormat_1.parseFormat)(element, context.formatParsers.block, context.blockFormat, context);
@@ -16203,6 +16288,7 @@ function blockProcessor(group, element, context, segmentFormat) {
16203
16288
  });
16204
16289
  if (!isSegmentDecorator) {
16205
16290
  var paragraph = (0, createParagraph_1.createParagraph)(false /*isImplicit*/, blockFormat, segmentFormat, decorator);
16291
+ (_a = context.paragraphMap) === null || _a === void 0 ? void 0 : _a.assignMarkerToModel(element, paragraph);
16206
16292
  (0, addBlock_1.addBlock)(group, paragraph);
16207
16293
  }
16208
16294
  context.elementProcessors.child(group, element, context);
@@ -16921,6 +17007,8 @@ function shouldUseFormatContainer(element, context) {
16921
17007
 
16922
17008
  Object.defineProperty(exports, "__esModule", ({ value: true }));
16923
17009
  exports.linkProcessor = void 0;
17010
+ var addSegment_1 = __webpack_require__(/*! ../../modelApi/common/addSegment */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/addSegment.ts");
17011
+ var createText_1 = __webpack_require__(/*! ../../modelApi/creators/createText */ "./packages/roosterjs-content-model-dom/lib/modelApi/creators/createText.ts");
16924
17012
  var knownElementProcessor_1 = __webpack_require__(/*! ./knownElementProcessor */ "./packages/roosterjs-content-model-dom/lib/domToModel/processors/knownElementProcessor.ts");
16925
17013
  var parseFormat_1 = __webpack_require__(/*! ../utils/parseFormat */ "./packages/roosterjs-content-model-dom/lib/domToModel/utils/parseFormat.ts");
16926
17014
  var stackFormat_1 = __webpack_require__(/*! ../utils/stackFormat */ "./packages/roosterjs-content-model-dom/lib/domToModel/utils/stackFormat.ts");
@@ -16928,15 +17016,32 @@ var stackFormat_1 = __webpack_require__(/*! ../utils/stackFormat */ "./packages/
16928
17016
  * @internal
16929
17017
  */
16930
17018
  var linkProcessor = function (group, element, context) {
16931
- if (element.hasAttribute('href')) {
16932
- (0, stackFormat_1.stackFormat)(context, { link: 'linkDefault' }, function () {
17019
+ var name = element.getAttribute('name');
17020
+ var href = element.getAttribute('href');
17021
+ if (name || href) {
17022
+ var isAnchor_1 = !!name && !href;
17023
+ var option = {
17024
+ // For anchor (name without ref), no need to add other styles
17025
+ // For link (href exists), add default link styles
17026
+ link: isAnchor_1 ? 'empty' : 'linkDefault',
17027
+ };
17028
+ (0, stackFormat_1.stackFormat)(context, option, function () {
16933
17029
  (0, parseFormat_1.parseFormat)(element, context.formatParsers.link, context.link.format, context);
16934
17030
  (0, parseFormat_1.parseFormat)(element, context.formatParsers.dataset, context.link.dataset, context);
16935
- (0, knownElementProcessor_1.knownElementProcessor)(group, element, context);
17031
+ if (isAnchor_1 && !element.firstChild) {
17032
+ // Empty anchor, need to make sure it has some child in model
17033
+ (0, addSegment_1.addSegment)(group, (0, createText_1.createText)('', context.segmentFormat, {
17034
+ dataset: context.link.dataset,
17035
+ format: context.link.format,
17036
+ }));
17037
+ }
17038
+ else {
17039
+ (0, knownElementProcessor_1.knownElementProcessor)(group, element, context);
17040
+ }
16936
17041
  });
16937
17042
  }
16938
17043
  else {
16939
- // A tag without href, can be treated as normal SPAN tag
17044
+ // A tag without name or href, can be treated as normal SPAN tag
16940
17045
  (0, knownElementProcessor_1.knownElementProcessor)(group, element, context);
16941
17046
  }
16942
17047
  };
@@ -18175,6 +18280,104 @@ function getSafeIdSelector(id) {
18175
18280
  exports.getSafeIdSelector = getSafeIdSelector;
18176
18281
 
18177
18282
 
18283
+ /***/ }),
18284
+
18285
+ /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts":
18286
+ /*!**********************************************************************************************!*\
18287
+ !*** ./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts ***!
18288
+ \**********************************************************************************************/
18289
+ /***/ ((__unused_webpack_module, exports) => {
18290
+
18291
+ "use strict";
18292
+
18293
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
18294
+ exports.setHiddenProperty = exports.getHiddenProperty = void 0;
18295
+ /**
18296
+ * @internal
18297
+ */
18298
+ function getHiddenProperty(node, key) {
18299
+ var nodeWithHiddenProperty = node;
18300
+ var hiddenProperty = nodeWithHiddenProperty.__roosterjsHiddenProperty;
18301
+ return hiddenProperty ? hiddenProperty[key] : undefined;
18302
+ }
18303
+ exports.getHiddenProperty = getHiddenProperty;
18304
+ /**
18305
+ * @internal
18306
+ */
18307
+ function setHiddenProperty(node, key, value) {
18308
+ var nodeWithHiddenProperty = node;
18309
+ var hiddenProperty = nodeWithHiddenProperty.__roosterjsHiddenProperty || {};
18310
+ hiddenProperty[key] = value;
18311
+ nodeWithHiddenProperty.__roosterjsHiddenProperty = hiddenProperty;
18312
+ }
18313
+ exports.setHiddenProperty = setHiddenProperty;
18314
+
18315
+
18316
+ /***/ }),
18317
+
18318
+ /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/paragraphMarker.ts":
18319
+ /*!***********************************************************************************************!*\
18320
+ !*** ./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/paragraphMarker.ts ***!
18321
+ \***********************************************************************************************/
18322
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
18323
+
18324
+ "use strict";
18325
+
18326
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
18327
+ exports.setParagraphMarker = exports.getParagraphMarker = void 0;
18328
+ var hiddenProperty_1 = __webpack_require__(/*! ./hiddenProperty */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts");
18329
+ /**
18330
+ * Get paragraph marker from element. This is used to mark the end of a paragraph in a block element.
18331
+ */
18332
+ function getParagraphMarker(element) {
18333
+ return (0, hiddenProperty_1.getHiddenProperty)(element, 'paragraphMarker');
18334
+ }
18335
+ exports.getParagraphMarker = getParagraphMarker;
18336
+ /**
18337
+ * Set paragraph marker to element. This is used to mark the end of a paragraph in a block element.
18338
+ */
18339
+ function setParagraphMarker(element, marker) {
18340
+ (0, hiddenProperty_1.setHiddenProperty)(element, 'paragraphMarker', marker);
18341
+ }
18342
+ exports.setParagraphMarker = setParagraphMarker;
18343
+
18344
+
18345
+ /***/ }),
18346
+
18347
+ /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts":
18348
+ /*!***********************************************************************************************!*\
18349
+ !*** ./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts ***!
18350
+ \***********************************************************************************************/
18351
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
18352
+
18353
+ "use strict";
18354
+
18355
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
18356
+ exports.isLinkUndeletable = exports.setLinkUndeletable = void 0;
18357
+ var hiddenProperty_1 = __webpack_require__(/*! ./hiddenProperty */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/hiddenProperty.ts");
18358
+ var UndeletableLinkKey = 'undeletable';
18359
+ /**
18360
+ * Set a hidden property on a link element to indicate whether it is undeletable or not.
18361
+ * This is used to prevent the link from being deleted when the user tries to delete it.
18362
+ * @param a The link element to set the property on
18363
+ * @param undeletable Whether the link is undeletable or not
18364
+ */
18365
+ function setLinkUndeletable(a, undeletable) {
18366
+ (0, hiddenProperty_1.setHiddenProperty)(a, UndeletableLinkKey, undeletable);
18367
+ }
18368
+ exports.setLinkUndeletable = setLinkUndeletable;
18369
+ /**
18370
+ * Check if a link element is undeletable or not.
18371
+ * This is used to determine if the link can be deleted when the user tries to delete it.
18372
+ * @param a The link element to check
18373
+ * @returns True if the link is undeletable, false otherwise
18374
+ */
18375
+ function isLinkUndeletable(a) {
18376
+ return !!(0, hiddenProperty_1.getHiddenProperty)(a, UndeletableLinkKey);
18377
+ }
18378
+ exports.isLinkUndeletable = isLinkUndeletable;
18379
+
18380
+
18178
18381
  /***/ }),
18179
18382
 
18180
18383
  /***/ "./packages/roosterjs-content-model-dom/lib/domUtils/isElementOfType.ts":
@@ -19665,6 +19868,7 @@ var textAlignFormatHandler_1 = __webpack_require__(/*! ./block/textAlignFormatHa
19665
19868
  var textColorFormatHandler_1 = __webpack_require__(/*! ./segment/textColorFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/textColorFormatHandler.ts");
19666
19869
  var textColorOnTableCellFormatHandler_1 = __webpack_require__(/*! ./table/textColorOnTableCellFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/table/textColorOnTableCellFormatHandler.ts");
19667
19870
  var textIndentFormatHandler_1 = __webpack_require__(/*! ./block/textIndentFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/block/textIndentFormatHandler.ts");
19871
+ var undeletableLinkFormatHandler_1 = __webpack_require__(/*! ./segment/undeletableLinkFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/undeletableLinkFormatHandler.ts");
19668
19872
  var underlineFormatHandler_1 = __webpack_require__(/*! ./segment/underlineFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/underlineFormatHandler.ts");
19669
19873
  var verticalAlignFormatHandler_1 = __webpack_require__(/*! ./common/verticalAlignFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/common/verticalAlignFormatHandler.ts");
19670
19874
  var whiteSpaceFormatHandler_1 = __webpack_require__(/*! ./block/whiteSpaceFormatHandler */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/block/whiteSpaceFormatHandler.ts");
@@ -19703,6 +19907,7 @@ var defaultFormatHandlerMap = {
19703
19907
  textColor: textColorFormatHandler_1.textColorFormatHandler,
19704
19908
  textColorOnTableCell: textColorOnTableCellFormatHandler_1.textColorOnTableCellFormatHandler,
19705
19909
  textIndent: textIndentFormatHandler_1.textIndentFormatHandler,
19910
+ undeletableLink: undeletableLinkFormatHandler_1.undeletableLinkFormatHandler,
19706
19911
  underline: underlineFormatHandler_1.underlineFormatHandler,
19707
19912
  verticalAlign: verticalAlignFormatHandler_1.verticalAlignFormatHandler,
19708
19913
  whiteSpace: whiteSpaceFormatHandler_1.whiteSpaceFormatHandler,
@@ -19808,6 +20013,7 @@ exports.defaultFormatKeysPerCategory = {
19808
20013
  'border',
19809
20014
  'size',
19810
20015
  'textAlign',
20016
+ 'undeletableLink',
19811
20017
  ],
19812
20018
  segmentUnderLink: ['textColor'],
19813
20019
  code: ['fontFamily', 'display'],
@@ -20296,8 +20502,10 @@ exports.linkFormatHandler = {
20296
20502
  }
20297
20503
  },
20298
20504
  apply: function (format, element) {
20299
- if ((0, isElementOfType_1.isElementOfType)(element, 'a') && format.href) {
20300
- element.href = format.href;
20505
+ if ((0, isElementOfType_1.isElementOfType)(element, 'a') && (format.href || format.name)) {
20506
+ if (format.href) {
20507
+ element.href = format.href;
20508
+ }
20301
20509
  if (format.name) {
20302
20510
  element.name = format.name;
20303
20511
  }
@@ -20435,6 +20643,37 @@ exports.textColorFormatHandler = {
20435
20643
  };
20436
20644
 
20437
20645
 
20646
+ /***/ }),
20647
+
20648
+ /***/ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/undeletableLinkFormatHandler.ts":
20649
+ /*!*********************************************************************************************************!*\
20650
+ !*** ./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/undeletableLinkFormatHandler.ts ***!
20651
+ \*********************************************************************************************************/
20652
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
20653
+
20654
+ "use strict";
20655
+
20656
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
20657
+ exports.undeletableLinkFormatHandler = void 0;
20658
+ var isElementOfType_1 = __webpack_require__(/*! ../../domUtils/isElementOfType */ "./packages/roosterjs-content-model-dom/lib/domUtils/isElementOfType.ts");
20659
+ var undeletableLink_1 = __webpack_require__(/*! ../../domUtils/hiddenProperties/undeletableLink */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts");
20660
+ /**
20661
+ * @internal
20662
+ */
20663
+ exports.undeletableLinkFormatHandler = {
20664
+ parse: function (format, element) {
20665
+ if ((0, isElementOfType_1.isElementOfType)(element, 'a') && (0, undeletableLink_1.isLinkUndeletable)(element)) {
20666
+ format.undeletable = true;
20667
+ }
20668
+ },
20669
+ apply: function (format, element) {
20670
+ if (format.undeletable && (0, isElementOfType_1.isElementOfType)(element, 'a')) {
20671
+ (0, undeletableLink_1.setLinkUndeletable)(element, true);
20672
+ }
20673
+ },
20674
+ };
20675
+
20676
+
20438
20677
  /***/ }),
20439
20678
 
20440
20679
  /***/ "./packages/roosterjs-content-model-dom/lib/formatHandlers/segment/underlineFormatHandler.ts":
@@ -20928,9 +21167,10 @@ exports.shouldSetValue = shouldSetValue;
20928
21167
  "use strict";
20929
21168
 
20930
21169
  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;
21170
+ 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;
21171
+ 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;
21172
+ 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;
21173
+ exports.EmptySegmentFormat = void 0;
20934
21174
  var domToContentModel_1 = __webpack_require__(/*! ./domToModel/domToContentModel */ "./packages/roosterjs-content-model-dom/lib/domToModel/domToContentModel.ts");
20935
21175
  Object.defineProperty(exports, "domToContentModel", ({ enumerable: true, get: function () { return domToContentModel_1.domToContentModel; } }));
20936
21176
  var contentModelToDom_1 = __webpack_require__(/*! ./modelToDom/contentModelToDom */ "./packages/roosterjs-content-model-dom/lib/modelToDom/contentModelToDom.ts");
@@ -20992,6 +21232,9 @@ var isWhiteSpacePreserved_1 = __webpack_require__(/*! ./domUtils/isWhiteSpacePre
20992
21232
  Object.defineProperty(exports, "isWhiteSpacePreserved", ({ enumerable: true, get: function () { return isWhiteSpacePreserved_1.isWhiteSpacePreserved; } }));
20993
21233
  var normalizeRect_1 = __webpack_require__(/*! ./domUtils/normalizeRect */ "./packages/roosterjs-content-model-dom/lib/domUtils/normalizeRect.ts");
20994
21234
  Object.defineProperty(exports, "normalizeRect", ({ enumerable: true, get: function () { return normalizeRect_1.normalizeRect; } }));
21235
+ var undeletableLink_1 = __webpack_require__(/*! ./domUtils/hiddenProperties/undeletableLink */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/undeletableLink.ts");
21236
+ Object.defineProperty(exports, "setLinkUndeletable", ({ enumerable: true, get: function () { return undeletableLink_1.setLinkUndeletable; } }));
21237
+ Object.defineProperty(exports, "isLinkUndeletable", ({ enumerable: true, get: function () { return undeletableLink_1.isLinkUndeletable; } }));
20995
21238
  var createBr_1 = __webpack_require__(/*! ./modelApi/creators/createBr */ "./packages/roosterjs-content-model-dom/lib/modelApi/creators/createBr.ts");
20996
21239
  Object.defineProperty(exports, "createBr", ({ enumerable: true, get: function () { return createBr_1.createBr; } }));
20997
21240
  var createListItem_1 = __webpack_require__(/*! ./modelApi/creators/createListItem */ "./packages/roosterjs-content-model-dom/lib/modelApi/creators/createListItem.ts");
@@ -21107,6 +21350,9 @@ var extractClipboardItems_1 = __webpack_require__(/*! ./domUtils/event/extractCl
21107
21350
  Object.defineProperty(exports, "extractClipboardItems", ({ enumerable: true, get: function () { return extractClipboardItems_1.extractClipboardItems; } }));
21108
21351
  var cacheGetEventData_1 = __webpack_require__(/*! ./domUtils/event/cacheGetEventData */ "./packages/roosterjs-content-model-dom/lib/domUtils/event/cacheGetEventData.ts");
21109
21352
  Object.defineProperty(exports, "cacheGetEventData", ({ enumerable: true, get: function () { return cacheGetEventData_1.cacheGetEventData; } }));
21353
+ var paragraphMarker_1 = __webpack_require__(/*! ./domUtils/hiddenProperties/paragraphMarker */ "./packages/roosterjs-content-model-dom/lib/domUtils/hiddenProperties/paragraphMarker.ts");
21354
+ Object.defineProperty(exports, "setParagraphMarker", ({ enumerable: true, get: function () { return paragraphMarker_1.setParagraphMarker; } }));
21355
+ Object.defineProperty(exports, "getParagraphMarker", ({ enumerable: true, get: function () { return paragraphMarker_1.getParagraphMarker; } }));
21110
21356
  var isBlockGroupOfType_1 = __webpack_require__(/*! ./modelApi/typeCheck/isBlockGroupOfType */ "./packages/roosterjs-content-model-dom/lib/modelApi/typeCheck/isBlockGroupOfType.ts");
21111
21357
  Object.defineProperty(exports, "isBlockGroupOfType", ({ enumerable: true, get: function () { return isBlockGroupOfType_1.isBlockGroupOfType; } }));
21112
21358
  var iterateSelections_1 = __webpack_require__(/*! ./modelApi/selection/iterateSelections */ "./packages/roosterjs-content-model-dom/lib/modelApi/selection/iterateSelections.ts");
@@ -21251,7 +21497,7 @@ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.m
21251
21497
  * @internal
21252
21498
  */
21253
21499
  function addLink(segment, link) {
21254
- if (link.format.href) {
21500
+ if (link.format.href || link.format.name) {
21255
21501
  segment.link = {
21256
21502
  format: (0, tslib_1.__assign)({}, link.format),
21257
21503
  dataset: (0, tslib_1.__assign)({}, link.dataset),
@@ -21480,10 +21726,11 @@ exports.isBlockGroupEmpty = isBlockGroupEmpty;
21480
21726
  /**
21481
21727
  * @internal
21482
21728
  */
21483
- function isSegmentEmpty(segment) {
21729
+ function isSegmentEmpty(segment, treatAnchorAsNotEmpty) {
21730
+ var _a;
21484
21731
  switch (segment.segmentType) {
21485
21732
  case 'Text':
21486
- return !segment.text;
21733
+ return !segment.text && (!treatAnchorAsNotEmpty || !((_a = segment.link) === null || _a === void 0 ? void 0 : _a.format.name));
21487
21734
  default:
21488
21735
  return false;
21489
21736
  }
@@ -21769,7 +22016,7 @@ function normalizeParagraphStyle(paragraph) {
21769
22016
  }
21770
22017
  function removeEmptySegments(block) {
21771
22018
  for (var j = block.segments.length - 1; j >= 0; j--) {
21772
- if ((0, isEmpty_1.isSegmentEmpty)(block.segments[j])) {
22019
+ if ((0, isEmpty_1.isSegmentEmpty)(block.segments[j], true /*treatAnchorAsNotEmpty*/)) {
21773
22020
  (0, mutate_1.mutateBlock)(block).segments.splice(j, 1);
21774
22021
  }
21775
22022
  }
@@ -23163,6 +23410,7 @@ function deleteExpandedSelection(model, formatContext) {
23163
23410
  deleteResult: 'notDeleted',
23164
23411
  insertPoint: null,
23165
23412
  formatContext: formatContext,
23413
+ undeletableSegments: [],
23166
23414
  };
23167
23415
  (0, iterateSelections_1.iterateSelections)(model, function (path, tableContext, readonlyBlock, readonlySegments) {
23168
23416
  // Set paragraph, format and index for default position where we will put cursor to.
@@ -23179,6 +23427,7 @@ function deleteExpandedSelection(model, formatContext) {
23179
23427
  paragraph = block_1;
23180
23428
  insertMarkerIndex = indexes[0];
23181
23429
  markerFormat = (0, getSegmentTextFormat_1.getSegmentTextFormat)(segments[0], true /*includingBIU*/);
23430
+ var isFirstDeletingParagraph_1 = !context.lastParagraph;
23182
23431
  context.lastParagraph = paragraph;
23183
23432
  context.lastTableContext = tableContext;
23184
23433
  segments.forEach(function (segment, i) {
@@ -23189,7 +23438,8 @@ function deleteExpandedSelection(model, formatContext) {
23189
23438
  // because this is possible a collapsed selection, then it will be handled later
23190
23439
  context.insertPoint = createInsertPoint(segment, block_1, path, tableContext);
23191
23440
  }
23192
- else if ((0, deleteSegment_1.deleteSegment)(block_1, segment, context.formatContext)) {
23441
+ 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
23442
+ )) {
23193
23443
  context.deleteResult = 'range';
23194
23444
  }
23195
23445
  });
@@ -23264,9 +23514,10 @@ var stringUtil_1 = __webpack_require__(/*! ../../domUtils/stringUtil */ "./packa
23264
23514
  * @param readonlySegmentToDelete The segment to delete
23265
23515
  * @param context @optional Context object provided by formatContentModel API
23266
23516
  * @param direction @optional Whether this is deleting forward or backward. This is only used for deleting entity.
23517
+ * @param undeletableSegments @optional When passed, if this segment is undeletable, it will be added to this array instead of being deleted.
23267
23518
  * If not specified, only selected entity will be deleted
23268
23519
  */
23269
- function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, direction) {
23520
+ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, direction, undeletableSegments) {
23270
23521
  var _a = (0, tslib_1.__read)((0, mutate_1.mutateSegment)(readonlyParagraph, readonlySegmentToDelete), 3), paragraph = _a[0], segmentToDelete = _a[1], index = _a[2];
23271
23522
  var segments = paragraph.segments;
23272
23523
  var preserveWhiteSpace = (0, isWhiteSpacePreserved_1.isWhiteSpacePreserved)(paragraph.format.whiteSpace);
@@ -23279,7 +23530,7 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23279
23530
  case 'Br':
23280
23531
  case 'Image':
23281
23532
  case 'SelectionMarker':
23282
- segments.splice(index, 1);
23533
+ removeSegment(segments, index, direction, undeletableSegments);
23283
23534
  return true;
23284
23535
  case 'Entity':
23285
23536
  var operation = segmentToDelete.isSelected
@@ -23290,7 +23541,7 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23290
23541
  ? 'removeFromEnd'
23291
23542
  : undefined;
23292
23543
  if (operation !== undefined) {
23293
- segments.splice(index, 1);
23544
+ removeSegment(segments, index, direction, undeletableSegments);
23294
23545
  context === null || context === void 0 ? void 0 : context.deletedEntities.push({
23295
23546
  entity: segmentToDelete,
23296
23547
  operation: operation,
@@ -23298,26 +23549,25 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23298
23549
  }
23299
23550
  return true;
23300
23551
  case 'Text':
23301
- var text = segmentToDelete.text;
23302
- if (text.length == 0 || segmentToDelete.isSelected) {
23303
- segments.splice(index, 1);
23552
+ if (segmentToDelete.text.length == 0 || segmentToDelete.isSelected) {
23553
+ segmentToDelete.text = '';
23554
+ removeSegment(segments, index, direction, undeletableSegments);
23304
23555
  }
23305
23556
  else if (direction) {
23557
+ var text = segmentToDelete.text;
23306
23558
  text = (0, deleteSingleChar_1.deleteSingleChar)(text, isForward); // isForward ? text.substring(1) : text.substring(0, text.length - 1);
23307
23559
  if (!preserveWhiteSpace) {
23308
23560
  text = (0, stringUtil_1.normalizeText)(text, isForward);
23309
23561
  }
23562
+ segmentToDelete.text = text;
23310
23563
  if (text == '') {
23311
- segments.splice(index, 1);
23312
- }
23313
- else {
23314
- segmentToDelete.text = text;
23564
+ removeSegment(segments, index, direction, undeletableSegments);
23315
23565
  }
23316
23566
  }
23317
23567
  return true;
23318
23568
  case 'General':
23319
23569
  if (segmentToDelete.isSelected) {
23320
- segments.splice(index, 1);
23570
+ removeSegment(segments, index, direction, undeletableSegments);
23321
23571
  return true;
23322
23572
  }
23323
23573
  else {
@@ -23328,6 +23578,42 @@ function deleteSegment(readonlyParagraph, readonlySegmentToDelete, context, dire
23328
23578
  }
23329
23579
  }
23330
23580
  exports.deleteSegment = deleteSegment;
23581
+ function removeSegment(segments, index, direction, undeletableSegments) {
23582
+ var _a;
23583
+ var segment = segments.splice(index, 1)[0];
23584
+ if ((_a = segment.link) === null || _a === void 0 ? void 0 : _a.format.undeletable) {
23585
+ // Segment is not deletable, but at least we should unselect it
23586
+ delete segment.isSelected;
23587
+ if (undeletableSegments) {
23588
+ // For undeletable segments, if an undeletableSegments array is passed in,
23589
+ // put it into this array after we delete it, so caller knows that we have deleted some undeletable segments
23590
+ // and do proper handling
23591
+ undeletableSegments.push(segment);
23592
+ }
23593
+ else {
23594
+ // Otherwise, we need to reinsert it back to the segments array to keep the model consistent.
23595
+ // We need to find the right place to insert it back based on the direction of deletion
23596
+ var insertIndex = void 0;
23597
+ switch (direction) {
23598
+ case 'forward':
23599
+ insertIndex =
23600
+ index > 0 && segments[index - 1].segmentType == 'SelectionMarker'
23601
+ ? index - 1
23602
+ : index;
23603
+ break;
23604
+ case 'backward':
23605
+ insertIndex =
23606
+ index < segments.length && segments[index].segmentType == 'SelectionMarker'
23607
+ ? index + 1
23608
+ : index;
23609
+ break;
23610
+ default:
23611
+ insertIndex = index;
23612
+ }
23613
+ segments.splice(insertIndex, 0, segment);
23614
+ }
23615
+ }
23616
+ }
23331
23617
  function normalizePreviousSegment(paragraph, segments, currentIndex) {
23332
23618
  var _a;
23333
23619
  var index = currentIndex - 1;
@@ -23375,8 +23661,8 @@ function deleteSelection(model, additionalSteps, formatContext) {
23375
23661
  exports.deleteSelection = deleteSelection;
23376
23662
  // If we end up with multiple paragraphs impacted, we need to merge them
23377
23663
  function mergeParagraphAfterDelete(context) {
23378
- var _a;
23379
- var insertPoint = context.insertPoint, deleteResult = context.deleteResult, lastParagraph = context.lastParagraph, lastTableContext = context.lastTableContext;
23664
+ var _a, _b;
23665
+ var insertPoint = context.insertPoint, deleteResult = context.deleteResult, lastParagraph = context.lastParagraph, lastTableContext = context.lastTableContext, undeletableSegments = context.undeletableSegments;
23380
23666
  if (insertPoint &&
23381
23667
  deleteResult != 'notDeleted' &&
23382
23668
  deleteResult != 'nothingToDelete' &&
@@ -23384,7 +23670,11 @@ function mergeParagraphAfterDelete(context) {
23384
23670
  lastParagraph != insertPoint.paragraph &&
23385
23671
  lastTableContext == insertPoint.tableContext) {
23386
23672
  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));
23673
+ var mutableInsertingParagraph = (0, mutate_1.mutateBlock)(insertPoint.paragraph);
23674
+ if (undeletableSegments) {
23675
+ (_a = mutableLastParagraph.segments).unshift.apply(_a, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(undeletableSegments), false));
23676
+ }
23677
+ (_b = mutableInsertingParagraph.segments).push.apply(_b, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(mutableLastParagraph.segments), false));
23388
23678
  mutableLastParagraph.segments = [];
23389
23679
  }
23390
23680
  }
@@ -26544,7 +26834,7 @@ var handleParagraph = function (doc, parent, paragraph, context, refNode) {
26544
26834
  }
26545
26835
  else {
26546
26836
  (0, stackFormat_1.stackFormat)(context, ((_a = paragraph.decorator) === null || _a === void 0 ? void 0 : _a.tagName) || null, function () {
26547
- var _a, _b, _c, _d;
26837
+ var _a, _b, _c, _d, _e;
26548
26838
  var needParagraphWrapper = !paragraph.isImplicit ||
26549
26839
  !!paragraph.decorator ||
26550
26840
  ((0, getObjectKeys_1.getObjectKeys)(paragraph.format).length > 0 &&
@@ -26582,6 +26872,7 @@ var handleParagraph = function (doc, parent, paragraph, context, refNode) {
26582
26872
  (0, applyFormat_1.applyFormat)(container, context.formatAppliers.block, paragraph.format, context);
26583
26873
  (0, applyFormat_1.applyFormat)(container, context.formatAppliers.container, paragraph.format, context);
26584
26874
  (0, applyFormat_1.applyFormat)(container, context.formatAppliers.segmentOnBlock, formatOnWrapper, context);
26875
+ (_c = context.paragraphMap) === null || _c === void 0 ? void 0 : _c.applyMarkerToDom(container, paragraph);
26585
26876
  }
26586
26877
  else {
26587
26878
  handleSegments();
@@ -26595,8 +26886,8 @@ var handleParagraph = function (doc, parent, paragraph, context, refNode) {
26595
26886
  // to make sure the value is correct.
26596
26887
  refNode = container.nextSibling;
26597
26888
  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);
26889
+ (_d = context.onNodeCreated) === null || _d === void 0 ? void 0 : _d.call(context, paragraph, container);
26890
+ (_e = context.domIndexer) === null || _e === void 0 ? void 0 : _e.onParagraph(container);
26600
26891
  }
26601
26892
  if (needParagraphWrapper) {
26602
26893
  if (context.allowCacheElement) {
@@ -29446,19 +29737,40 @@ function shouldDeleteWithContentModel(selection, rawEvent, handleExpandedSelecti
29446
29737
  }
29447
29738
  else {
29448
29739
  var range = selection.range;
29740
+ var startContainer = range.startContainer;
29741
+ var startOffset = range.startOffset;
29449
29742
  // 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') &&
29743
+ return !((0, roosterjs_content_model_dom_1.isNodeOfType)(startContainer, 'TEXT_NODE') &&
29451
29744
  !(0, roosterjs_content_model_dom_1.isModifierKey)(rawEvent) &&
29452
- (canDeleteBefore(rawEvent, range) || canDeleteAfter(rawEvent, range)));
29745
+ (canDeleteBefore(rawEvent, startContainer, startOffset) ||
29746
+ canDeleteAfter(rawEvent, startContainer, startOffset)));
29453
29747
  }
29454
29748
  }
29455
- function canDeleteBefore(rawEvent, range) {
29456
- return rawEvent.key == 'Backspace' && range.startOffset > 1;
29749
+ function canDeleteBefore(rawEvent, text, offset) {
29750
+ var _a, _b;
29751
+ if (rawEvent.key != 'Backspace' || offset <= 1) {
29752
+ return false;
29753
+ }
29754
+ var length = (_b = (_a = text.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
29755
+ if (offset == length) {
29756
+ // At the end of text, need to check if next segment is deletable
29757
+ var nextSibling = text.nextSibling;
29758
+ var isNextSiblingUndeletable = (0, roosterjs_content_model_dom_1.isNodeOfType)(nextSibling, 'ELEMENT_NODE') &&
29759
+ (0, roosterjs_content_model_dom_1.isElementOfType)(nextSibling, 'a') &&
29760
+ (0, roosterjs_content_model_dom_1.isLinkUndeletable)(nextSibling) &&
29761
+ !nextSibling.firstChild;
29762
+ // If next sibling is undeletable, we cannot let browser handle it since it will remove the anchor
29763
+ // So we return false here to let Content Model handle it
29764
+ return !isNextSiblingUndeletable;
29765
+ }
29766
+ else {
29767
+ // In middle of text, we can safely let browser handle deletion
29768
+ return true;
29769
+ }
29457
29770
  }
29458
- function canDeleteAfter(rawEvent, range) {
29771
+ function canDeleteAfter(rawEvent, text, offset) {
29459
29772
  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);
29773
+ 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
29774
  }
29463
29775
 
29464
29776
 
@@ -30022,6 +30334,122 @@ function splitParagraph(insertPoint) {
30022
30334
  exports.splitParagraph = splitParagraph;
30023
30335
 
30024
30336
 
30337
+ /***/ }),
30338
+
30339
+ /***/ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts":
30340
+ /*!*********************************************************************************************!*\
30341
+ !*** ./packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts ***!
30342
+ \*********************************************************************************************/
30343
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
30344
+
30345
+ "use strict";
30346
+
30347
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
30348
+ exports.HiddenPropertyPlugin = void 0;
30349
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30350
+ var fixupHiddenProperties_1 = __webpack_require__(/*! ./fixupHiddenProperties */ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts");
30351
+ /**
30352
+ * HiddenPropertyPlugin helps editor to maintain hidden properties in DOM after editor content is reset using HTML
30353
+ */
30354
+ var HiddenPropertyPlugin = /** @class */ (function () {
30355
+ /**
30356
+ * Construct a new instance of FormatPlugin class
30357
+ * @param option The editor option
30358
+ */
30359
+ function HiddenPropertyPlugin(option) {
30360
+ this.option = option;
30361
+ this.editor = null;
30362
+ }
30363
+ /**
30364
+ * Get name of this plugin
30365
+ */
30366
+ HiddenPropertyPlugin.prototype.getName = function () {
30367
+ return 'HiddenProperty';
30368
+ };
30369
+ /**
30370
+ * The first method that editor will call to a plugin when editor is initializing.
30371
+ * It will pass in the editor instance, plugin should take this chance to save the
30372
+ * editor reference so that it can call to any editor method or format API later.
30373
+ * @param editor The editor object
30374
+ */
30375
+ HiddenPropertyPlugin.prototype.initialize = function (editor) {
30376
+ this.editor = editor;
30377
+ };
30378
+ /**
30379
+ * The last method that editor will call to a plugin before it is disposed.
30380
+ * Plugin can take this chance to clear the reference to editor. After this method is
30381
+ * called, plugin should not call to any editor method since it will result in error.
30382
+ */
30383
+ HiddenPropertyPlugin.prototype.dispose = function () {
30384
+ this.editor = null;
30385
+ };
30386
+ /**
30387
+ * Core method for a plugin. Once an event happens in editor, editor will call this
30388
+ * method of each plugin to handle the event as long as the event is not handled
30389
+ * exclusively by another plugin.
30390
+ * @param event The event to handle:
30391
+ */
30392
+ HiddenPropertyPlugin.prototype.onPluginEvent = function (event) {
30393
+ if (!this.editor) {
30394
+ return;
30395
+ }
30396
+ if (event.eventType == 'contentChanged' && event.source == roosterjs_content_model_dom_1.ChangeSource.SetContent) {
30397
+ (0, fixupHiddenProperties_1.fixupHiddenProperties)(this.editor, this.option);
30398
+ }
30399
+ };
30400
+ return HiddenPropertyPlugin;
30401
+ }());
30402
+ exports.HiddenPropertyPlugin = HiddenPropertyPlugin;
30403
+
30404
+
30405
+ /***/ }),
30406
+
30407
+ /***/ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts":
30408
+ /*!**********************************************************************************************!*\
30409
+ !*** ./packages/roosterjs-content-model-plugins/lib/hiddenProperty/fixupHiddenProperties.ts ***!
30410
+ \**********************************************************************************************/
30411
+ /***/ ((__unused_webpack_module, exports, __webpack_require__) => {
30412
+
30413
+ "use strict";
30414
+
30415
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
30416
+ exports.fixupHiddenProperties = void 0;
30417
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30418
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30419
+ /**
30420
+ * @internal
30421
+ * Maintain hidden properties in DOM after editor content is reset using HTML
30422
+ * This includes:
30423
+ * 1. Undeletable property
30424
+ */
30425
+ function fixupHiddenProperties(editor, options) {
30426
+ if (options.undeletableLinkChecker) {
30427
+ checkUndeletable(editor, options.undeletableLinkChecker);
30428
+ }
30429
+ // Add more hidden properties checkers here
30430
+ }
30431
+ exports.fixupHiddenProperties = fixupHiddenProperties;
30432
+ function checkUndeletable(editor, checker) {
30433
+ var e_1, _a;
30434
+ var anchors = editor.getDOMHelper().queryElements('a');
30435
+ try {
30436
+ 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()) {
30437
+ var a = anchors_1_1.value;
30438
+ if (checker(a)) {
30439
+ (0, roosterjs_content_model_dom_1.setLinkUndeletable)(a, true);
30440
+ }
30441
+ }
30442
+ }
30443
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
30444
+ finally {
30445
+ try {
30446
+ if (anchors_1_1 && !anchors_1_1.done && (_a = anchors_1.return)) _a.call(anchors_1);
30447
+ }
30448
+ finally { if (e_1) throw e_1.error; }
30449
+ }
30450
+ }
30451
+
30452
+
30025
30453
  /***/ }),
30026
30454
 
30027
30455
  /***/ "./packages/roosterjs-content-model-plugins/lib/hyperlink/HyperlinkPlugin.ts":
@@ -32379,7 +32807,7 @@ exports.updateWrapper = updateWrapper;
32379
32807
  "use strict";
32380
32808
 
32381
32809
  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;
32810
+ 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
32811
  var TableEditPlugin_1 = __webpack_require__(/*! ./tableEdit/TableEditPlugin */ "./packages/roosterjs-content-model-plugins/lib/tableEdit/TableEditPlugin.ts");
32384
32812
  Object.defineProperty(exports, "TableEditPlugin", ({ enumerable: true, get: function () { return TableEditPlugin_1.TableEditPlugin; } }));
32385
32813
  var PastePlugin_1 = __webpack_require__(/*! ./paste/PastePlugin */ "./packages/roosterjs-content-model-plugins/lib/paste/PastePlugin.ts");
@@ -32424,6 +32852,8 @@ var CustomReplacePlugin_1 = __webpack_require__(/*! ./customReplace/CustomReplac
32424
32852
  Object.defineProperty(exports, "CustomReplacePlugin", ({ enumerable: true, get: function () { return CustomReplacePlugin_1.CustomReplacePlugin; } }));
32425
32853
  var ImageEditPlugin_1 = __webpack_require__(/*! ./imageEdit/ImageEditPlugin */ "./packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts");
32426
32854
  Object.defineProperty(exports, "ImageEditPlugin", ({ enumerable: true, get: function () { return ImageEditPlugin_1.ImageEditPlugin; } }));
32855
+ var HiddenPropertyPlugin_1 = __webpack_require__(/*! ./hiddenProperty/HiddenPropertyPlugin */ "./packages/roosterjs-content-model-plugins/lib/hiddenProperty/HiddenPropertyPlugin.ts");
32856
+ Object.defineProperty(exports, "HiddenPropertyPlugin", ({ enumerable: true, get: function () { return HiddenPropertyPlugin_1.HiddenPropertyPlugin; } }));
32427
32857
 
32428
32858
 
32429
32859
  /***/ }),