roosterjs 9.52.0 → 9.54.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.
@@ -8019,6 +8019,15 @@ function formatInsertPointWithContentModel(editor, insertPoint, callback, option
8019
8019
  textWithSelection: getShadowTextProcessor(bundle),
8020
8020
  },
8021
8021
  tryGetFromCache: false,
8022
+ // When an element carries "container level" styles such as margin or padding, we first
8023
+ // wrap it in a FormatContainer. After all its child nodes are processed, we decide whether
8024
+ // to keep the FormatContainer or fall back to a plain paragraph when it only wraps a single
8025
+ // paragraph. However, formatInsertPointWithContentModel persists the Content Model group path
8026
+ // during processing so the later formatting callback can still use it (see the
8027
+ // DomToModelContextWithPath interface below). If the FormatContainer falls back to a paragraph,
8028
+ // it is removed from the model and the persisted path becomes invalid. To keep the path valid,
8029
+ // we skip the fallback check here and always keep the FormatContainer when one is needed.
8030
+ skipFormatContainerFallbackCheck: true,
8022
8031
  });
8023
8032
  }
8024
8033
  exports.formatInsertPointWithContentModel = formatInsertPointWithContentModel;
@@ -9056,9 +9065,12 @@ function getContentForCopy(editor, isCut, event) {
9056
9065
  rawEvent: event,
9057
9066
  isCut: isCut,
9058
9067
  }).clonedRoot;
9068
+ // Build the text content from the (possibly modified) cloned root DOM tree so that any
9069
+ // changes made by beforeCutCopy event handlers are reflected in the plain text result as well
9070
+ var textModel = (0, roosterjs_content_model_dom_1.domToContentModel)(clonedRoot, (0, roosterjs_content_model_dom_1.createDomToModelContext)());
9059
9071
  return {
9060
9072
  htmlContent: clonedRoot,
9061
- textContent: (0, roosterjs_content_model_dom_1.contentModelToText)(pasteModel),
9073
+ textContent: (0, roosterjs_content_model_dom_1.contentModelToText)(textModel),
9062
9074
  };
9063
9075
  }
9064
9076
  }
@@ -9926,6 +9938,7 @@ var announce = function (core, announceData) {
9926
9938
  var textToAnnounce = formatString(template || text, formatStrings);
9927
9939
  if (!core.lifecycle.announceContainer) {
9928
9940
  core.lifecycle.announceContainer = (0, createAriaLiveElement_1.createAriaLiveElement)(core.physicalRoot.ownerDocument);
9941
+ core.domHelper.appendToRoot(core.lifecycle.announceContainer);
9929
9942
  }
9930
9943
  if (textToAnnounce && core.lifecycle.announceContainer) {
9931
9944
  var announceContainer = core.lifecycle.announceContainer;
@@ -10099,6 +10112,9 @@ var createContentModel = function (core, option, selectionOverride) {
10099
10112
  var domToModelContext = option
10100
10113
  ? (0, roosterjs_content_model_dom_1.createDomToModelContext)(editorContext, settings.builtIn, settings.customized, option)
10101
10114
  : (0, roosterjs_content_model_dom_1.createDomToModelContextWithConfig)(settings.calculated, editorContext);
10115
+ if (option === null || option === void 0 ? void 0 : option.skipFormatContainerFallbackCheck) {
10116
+ domToModelContext.skipFormatContainerFallbackCheck = true;
10117
+ }
10102
10118
  if (selection) {
10103
10119
  domToModelContext.selection = selection;
10104
10120
  }
@@ -10417,16 +10433,19 @@ var getDOMSelection = function (core) {
10417
10433
  exports.getDOMSelection = getDOMSelection;
10418
10434
  function getNewSelection(core) {
10419
10435
  var _a;
10436
+ var range = core.domHelper.getSelectionRange();
10437
+ if (!range || !core.logicalRoot.contains(range.commonAncestorContainer)) {
10438
+ return null;
10439
+ }
10420
10440
  var selection = (_a = core.logicalRoot.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
10421
- var range = selection && selection.rangeCount > 0 ? selection.getRangeAt(0) : null;
10422
- return selection && range && core.logicalRoot.contains(range.commonAncestorContainer)
10423
- ? {
10424
- type: 'range',
10425
- range: range,
10426
- isReverted: selection.focusNode != range.endContainer ||
10427
- selection.focusOffset != range.endOffset,
10428
- }
10429
- : null;
10441
+ var isReverted = selection
10442
+ ? selection.focusNode != range.endContainer || selection.focusOffset != range.endOffset
10443
+ : false;
10444
+ return {
10445
+ type: 'range',
10446
+ range: range,
10447
+ isReverted: isReverted,
10448
+ };
10430
10449
  }
10431
10450
 
10432
10451
 
@@ -10870,43 +10889,6 @@ var setContentModel = function (core, model, option, onNodeCreated, isInitializi
10870
10889
  exports.setContentModel = setContentModel;
10871
10890
 
10872
10891
 
10873
- /***/ },
10874
-
10875
- /***/ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/addRangeToSelection.ts"
10876
- /*!**************************************************************************************************!*\
10877
- !*** ./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/addRangeToSelection.ts ***!
10878
- \**************************************************************************************************/
10879
- (__unused_webpack_module, exports, __webpack_require__) {
10880
-
10881
- "use strict";
10882
-
10883
- Object.defineProperty(exports, "__esModule", ({ value: true }));
10884
- exports.addRangeToSelection = void 0;
10885
- var areSameSelections_1 = __webpack_require__(/*! ../../corePlugin/cache/areSameSelections */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts");
10886
- /**
10887
- * @internal
10888
- */
10889
- function addRangeToSelection(doc, range, isReverted) {
10890
- var _a;
10891
- if (isReverted === void 0) { isReverted = false; }
10892
- var selection = (_a = doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
10893
- if (selection) {
10894
- var currentRange = selection.rangeCount > 0 && selection.getRangeAt(0);
10895
- if (currentRange && (0, areSameSelections_1.areSameRanges)(currentRange, range)) {
10896
- return;
10897
- }
10898
- selection.removeAllRanges();
10899
- if (!isReverted) {
10900
- selection.addRange(range);
10901
- }
10902
- else {
10903
- selection.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
10904
- }
10905
- }
10906
- }
10907
- exports.addRangeToSelection = addRangeToSelection;
10908
-
10909
-
10910
10892
  /***/ },
10911
10893
 
10912
10894
  /***/ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/findLastedCoInMergedCell.ts"
@@ -11008,7 +10990,6 @@ exports.findTableCellElement = findTableCellElement;
11008
10990
 
11009
10991
  Object.defineProperty(exports, "__esModule", ({ value: true }));
11010
10992
  exports.setDOMSelection = void 0;
11011
- var addRangeToSelection_1 = __webpack_require__(/*! ./addRangeToSelection */ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/addRangeToSelection.ts");
11012
10993
  var areSameSelections_1 = __webpack_require__(/*! ../../corePlugin/cache/areSameSelections */ "./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts");
11013
10994
  var ensureUniqueId_1 = __webpack_require__(/*! ../setEditorStyle/ensureUniqueId */ "./packages/roosterjs-content-model-core/lib/coreApi/setEditorStyle/ensureUniqueId.ts");
11014
10995
  var findLastedCoInMergedCell_1 = __webpack_require__(/*! ./findLastedCoInMergedCell */ "./packages/roosterjs-content-model-core/lib/coreApi/setDOMSelection/findLastedCoInMergedCell.ts");
@@ -11034,7 +11015,6 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11034
11015
  // We are applying a new selection, so we don't need to apply cached selection in DOMEventPlugin.
11035
11016
  // Set skipReselectOnFocus to skip this behavior
11036
11017
  var skipReselectOnFocus = core.selection.skipReselectOnFocus;
11037
- var doc = core.physicalRoot.ownerDocument;
11038
11018
  var isDarkMode = core.lifecycle.isDarkMode;
11039
11019
  core.selection.skipReselectOnFocus = true;
11040
11020
  core.api.setEditorStyle(core, DOM_SELECTION_CSS_KEY, null /*cssRule*/);
@@ -11050,7 +11030,7 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11050
11030
  : core.selection.imageSelectionBorderColor;
11051
11031
  core.api.setEditorStyle(core, DOM_SELECTION_CSS_KEY, "outline-style:solid!important; outline-color:" + (imageSelectionColor || DEFAULT_SELECTION_BORDER_COLOR) + "!important;", [(0, roosterjs_content_model_dom_1.getSafeIdSelector)((0, ensureUniqueId_1.ensureUniqueId)(image, IMAGE_ID))]);
11052
11032
  core.api.setEditorStyle(core, HIDE_SELECTION_CSS_KEY, TRANSPARENT_SELECTION_CSS_RULE, [SELECTION_SELECTOR]);
11053
- setRangeSelection(doc, image, false /* collapse */);
11033
+ setRangeSelection(core, image, false /* collapse */);
11054
11034
  break;
11055
11035
  case 'table':
11056
11036
  var table = selection.table, firstColumn = selection.firstColumn, firstRow = selection.firstRow, lastColumn = selection.lastColumn, lastRow = selection.lastRow;
@@ -11087,11 +11067,11 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11087
11067
  (0, toggleCaret_1.toggleCaret)(core, true /* hide */);
11088
11068
  var nodeToSelect = ((_a = firstCell.cell) === null || _a === void 0 ? void 0 : _a.firstElementChild) || firstCell.cell;
11089
11069
  if (nodeToSelect) {
11090
- setRangeSelection(doc, nodeToSelect || undefined, true /* collapse */);
11070
+ setRangeSelection(core, nodeToSelect || undefined, true /* collapse */);
11091
11071
  }
11092
11072
  break;
11093
11073
  case 'range':
11094
- (0, addRangeToSelection_1.addRangeToSelection)(doc, selection.range, selection.isReverted);
11074
+ core.domHelper.setSelectionRange(selection.range, selection.isReverted);
11095
11075
  core.selection.selection = core.domHelper.hasFocus() ? null : selection;
11096
11076
  break;
11097
11077
  default:
@@ -11111,9 +11091,10 @@ var setDOMSelection = function (core, selection, skipSelectionChangedEvent) {
11111
11091
  }
11112
11092
  };
11113
11093
  exports.setDOMSelection = setDOMSelection;
11114
- function setRangeSelection(doc, element, collapse) {
11094
+ function setRangeSelection(core, element, collapse) {
11115
11095
  var _a;
11116
- if (element && doc.contains(element)) {
11096
+ if (element && core.domHelper.isNodeInEditor(element)) {
11097
+ var doc = core.physicalRoot.ownerDocument;
11117
11098
  var range = doc.createRange();
11118
11099
  var isReverted = undefined;
11119
11100
  range.selectNode(element);
@@ -11129,7 +11110,7 @@ function setRangeSelection(doc, element, collapse) {
11129
11110
  selection.focusOffset != range_1.endOffset;
11130
11111
  }
11131
11112
  }
11132
- (0, addRangeToSelection_1.addRangeToSelection)(doc, range, isReverted);
11113
+ core.domHelper.setSelectionRange(range, isReverted);
11133
11114
  }
11134
11115
  }
11135
11116
 
@@ -11316,9 +11297,9 @@ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-mo
11316
11297
  */
11317
11298
  function ensureUniqueId(element, idPrefix) {
11318
11299
  idPrefix = element.id || idPrefix;
11319
- var doc = element.ownerDocument;
11300
+ var root = element.getRootNode();
11320
11301
  var i = 0;
11321
- while (!element.id || doc.querySelectorAll((0, roosterjs_content_model_dom_1.getSafeIdSelector)(element.id)).length > 1) {
11302
+ while (!element.id || root.querySelectorAll((0, roosterjs_content_model_dom_1.getSafeIdSelector)(element.id)).length > 1) {
11322
11303
  element.id = idPrefix + '_' + i++;
11323
11304
  }
11324
11305
  return element.id;
@@ -11351,7 +11332,7 @@ var setEditorStyle = function (core, key, cssRule, subSelectors, maxRuleLength)
11351
11332
  if (!styleElement && cssRule) {
11352
11333
  var doc = core.physicalRoot.ownerDocument;
11353
11334
  styleElement = doc.createElement('style');
11354
- doc.head.appendChild(styleElement);
11335
+ core.domHelper.appendToRoot(styleElement);
11355
11336
  styleElement.dataset.roosterjsStyleKey = key;
11356
11337
  core.lifecycle.styleElements[key] = styleElement;
11357
11338
  }
@@ -11605,6 +11586,11 @@ var CachePlugin = /** @class */ (function () {
11605
11586
  _this.invalidateCache();
11606
11587
  }
11607
11588
  break;
11589
+ case 'attribute':
11590
+ if (!_this.state.domIndexer.reconcileImageAttribute(mutation.element, mutation.attributeName)) {
11591
+ _this.invalidateCache();
11592
+ }
11593
+ break;
11608
11594
  case 'unknown':
11609
11595
  _this.invalidateCache();
11610
11596
  break;
@@ -11829,12 +11815,13 @@ exports.createParagraphMap = createParagraphMap;
11829
11815
  /*!*****************************************************************************************!*\
11830
11816
  !*** ./packages/roosterjs-content-model-core/lib/corePlugin/cache/areSameSelections.ts ***!
11831
11817
  \*****************************************************************************************/
11832
- (__unused_webpack_module, exports) {
11818
+ (__unused_webpack_module, exports, __webpack_require__) {
11833
11819
 
11834
11820
  "use strict";
11835
11821
 
11836
11822
  Object.defineProperty(exports, "__esModule", ({ value: true }));
11837
- exports.areSameRanges = exports.areSameTableSelections = exports.areSameSelections = void 0;
11823
+ exports.areSameTableSelections = exports.areSameSelections = void 0;
11824
+ var areSameRanges_1 = __webpack_require__(/*! ../../utils/areSameRanges */ "./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts");
11838
11825
  /**
11839
11826
  * @internal
11840
11827
  * Check if the given selections are the same
@@ -11860,7 +11847,7 @@ function areSameSelections(sel1, sel2) {
11860
11847
  range1.endOffset == end.offset);
11861
11848
  }
11862
11849
  else {
11863
- return areSameRanges(range1, sel2.range);
11850
+ return (0, areSameRanges_1.areSameRanges)(range1, sel2.range);
11864
11851
  }
11865
11852
  }
11866
11853
  else {
@@ -11879,7 +11866,6 @@ var TableSelectionKeys = [
11879
11866
  'firstRow',
11880
11867
  'lastRow',
11881
11868
  ];
11882
- var RangeKeys = ['startContainer', 'endContainer', 'startOffset', 'endOffset'];
11883
11869
  /**
11884
11870
  * @internal
11885
11871
  */
@@ -11887,13 +11873,6 @@ function areSameTableSelections(t1, t2) {
11887
11873
  return areSame(t1, t2, TableSelectionKeys);
11888
11874
  }
11889
11875
  exports.areSameTableSelections = areSameTableSelections;
11890
- /**
11891
- * @internal
11892
- */
11893
- function areSameRanges(r1, r2) {
11894
- return areSame(r1, r2, RangeKeys);
11895
- }
11896
- exports.areSameRanges = areSameRanges;
11897
11876
  function isCacheSelection(sel) {
11898
11877
  return !!sel.start;
11899
11878
  }
@@ -12071,7 +12050,13 @@ var DomIndexerImpl = /** @class */ (function () {
12071
12050
  }
12072
12051
  else {
12073
12052
  var marker1 = this.reconcileNodeSelection(startContainer, startOffset);
12074
- var marker2 = this.reconcileNodeSelection(endContainer, endOffset);
12053
+ // Pass marker1 to the second call so its adjacent-marker cleanup
12054
+ // does not consume the SelectionMarker we just inserted. Without
12055
+ // this guard, when marker1 lands directly next to endContainer's
12056
+ // segment in paragraph.segments (e.g. startOffset == startContainer
12057
+ // text length), the second splice would absorb marker1 and leave
12058
+ // setSelection with a dangling reference. See issue #3341.
12059
+ var marker2 = this.reconcileNodeSelection(endContainer, endOffset, undefined, undefined, marker1);
12075
12060
  if (marker1 && marker2) {
12076
12061
  if (newSelection.isReverted) {
12077
12062
  model.hasRevertedRangeSelection = true;
@@ -12137,6 +12122,33 @@ var DomIndexerImpl = /** @class */ (function () {
12137
12122
  return false;
12138
12123
  }
12139
12124
  };
12125
+ DomIndexerImpl.prototype.reconcileImageAttribute = function (element, attributeName) {
12126
+ var _a, _b;
12127
+ if ((0, roosterjs_content_model_dom_1.isElementOfType)(element, 'img')) {
12128
+ var image = (_a = getIndexedSegmentItem(element)) === null || _a === void 0 ? void 0 : _a.segments[0];
12129
+ if ((image === null || image === void 0 ? void 0 : image.segmentType) == 'Image') {
12130
+ if (attributeName == 'src') {
12131
+ // Use getAttribute('src') instead of retrieving src directly, in case the src
12132
+ // has port and may be stripped by browser. This matches imageProcessor.
12133
+ image.src = (_b = element.getAttribute('src')) !== null && _b !== void 0 ? _b : '';
12134
+ return true;
12135
+ }
12136
+ else if (attributeName.indexOf('data-') == 0) {
12137
+ // A data-* attribute may be added, modified or removed. Rebuild the whole
12138
+ // dataset from DOM to keep it in sync, the same way imageProcessor builds it.
12139
+ var dataset_1 = image.dataset;
12140
+ (0, roosterjs_content_model_dom_1.getObjectKeys)(dataset_1).forEach(function (key) {
12141
+ delete dataset_1[key];
12142
+ });
12143
+ (0, roosterjs_content_model_dom_1.getObjectKeys)(element.dataset).forEach(function (key) {
12144
+ dataset_1[key] = element.dataset[key] || '';
12145
+ });
12146
+ return true;
12147
+ }
12148
+ }
12149
+ }
12150
+ return false;
12151
+ };
12140
12152
  DomIndexerImpl.prototype.onBlockEntityDelimiter = function (node, entity, parent) {
12141
12153
  if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'ELEMENT_NODE') && (0, roosterjs_content_model_dom_1.isEntityDelimiter)(node) && node.firstChild) {
12142
12154
  var indexedDelimiter = node.firstChild;
@@ -12147,10 +12159,10 @@ var DomIndexerImpl = /** @class */ (function () {
12147
12159
  var start = selection.start, end = selection.end;
12148
12160
  return start.node == end.node && start.offset == end.offset;
12149
12161
  };
12150
- DomIndexerImpl.prototype.reconcileNodeSelection = function (node, offset, defaultFormat, selectionMarker) {
12162
+ DomIndexerImpl.prototype.reconcileNodeSelection = function (node, offset, defaultFormat, selectionMarker, preserveMarker) {
12151
12163
  if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'TEXT_NODE')) {
12152
12164
  if (isIndexedSegment(node)) {
12153
- return this.reconcileTextSelection(node, offset, undefined, selectionMarker);
12165
+ return this.reconcileTextSelection(node, offset, undefined, selectionMarker, preserveMarker);
12154
12166
  }
12155
12167
  else if (isIndexedDelimiter(node)) {
12156
12168
  return this.reconcileDelimiterSelection(node, defaultFormat);
@@ -12180,7 +12192,7 @@ var DomIndexerImpl = /** @class */ (function () {
12180
12192
  }
12181
12193
  return marker;
12182
12194
  };
12183
- DomIndexerImpl.prototype.reconcileTextSelection = function (textNode, startOffset, endOffset, selectionMarker) {
12195
+ DomIndexerImpl.prototype.reconcileTextSelection = function (textNode, startOffset, endOffset, selectionMarker, preserveMarker) {
12184
12196
  var _a;
12185
12197
  var _b, _c, _d, _e, _f, _g;
12186
12198
  var _h = textNode.__roosterjsContentModel, paragraph = _h.paragraph, segments = _h.segments;
@@ -12233,11 +12245,13 @@ var DomIndexerImpl = /** @class */ (function () {
12233
12245
  var lastIndex = paragraph.segments.indexOf(last);
12234
12246
  if (firstIndex >= 0 && lastIndex >= 0) {
12235
12247
  while (firstIndex > 0 &&
12236
- paragraph.segments[firstIndex - 1].segmentType == 'SelectionMarker') {
12248
+ paragraph.segments[firstIndex - 1].segmentType == 'SelectionMarker' &&
12249
+ paragraph.segments[firstIndex - 1] !== preserveMarker) {
12237
12250
  firstIndex--;
12238
12251
  }
12239
12252
  while (lastIndex < paragraph.segments.length - 1 &&
12240
- paragraph.segments[lastIndex + 1].segmentType == 'SelectionMarker') {
12253
+ paragraph.segments[lastIndex + 1].segmentType == 'SelectionMarker' &&
12254
+ paragraph.segments[lastIndex + 1] !== preserveMarker) {
12241
12255
  lastIndex++;
12242
12256
  }
12243
12257
  (_a = paragraph.segments).splice.apply(_a, (0, tslib_1.__spreadArray)([firstIndex, lastIndex - firstIndex + 1], (0, tslib_1.__read)(newSegments), false));
@@ -12450,6 +12464,16 @@ var TextMutationObserverImpl = /** @class */ (function () {
12450
12464
  (0, roosterjs_content_model_dom_1.isNodeOfType)(target, 'ELEMENT_NODE')) {
12451
12465
  _this.onMutation({ type: 'elementId', element: target });
12452
12466
  }
12467
+ else if (mutation.attributeName &&
12468
+ (0, roosterjs_content_model_dom_1.isNodeOfType)(target, 'ELEMENT_NODE') &&
12469
+ (mutation.attributeName == 'src' ||
12470
+ mutation.attributeName.indexOf('data-') == 0)) {
12471
+ _this.onMutation({
12472
+ type: 'attribute',
12473
+ element: target,
12474
+ attributeName: mutation.attributeName,
12475
+ });
12476
+ }
12453
12477
  else {
12454
12478
  // We cannot handle attributes changes on editor content for now
12455
12479
  canHandle = false;
@@ -14355,6 +14379,7 @@ var LifecyclePlugin = /** @class */ (function () {
14355
14379
  delete this.state.rewriteFromModel;
14356
14380
  // Initialize the Announce container.
14357
14381
  this.state.announceContainer = (0, createAriaLiveElement_1.createAriaLiveElement)(editor.getDocument());
14382
+ editor.getDOMHelper().appendToRoot(this.state.announceContainer);
14358
14383
  };
14359
14384
  /**
14360
14385
  * Dispose this plugin
@@ -14548,20 +14573,23 @@ var SelectionPlugin = /** @class */ (function () {
14548
14573
  }
14549
14574
  };
14550
14575
  this.onSelectionChange = function () {
14551
- var _a;
14576
+ var _a, _b;
14552
14577
  if (((_a = _this.editor) === null || _a === void 0 ? void 0 : _a.hasFocus()) && !_this.editor.isInShadowEdit()) {
14553
14578
  var newSelection = _this.editor.getDOMSelection();
14579
+ var domHelper = _this.editor.getDOMHelper();
14554
14580
  //If am image selection changed to a wider range due a keyboard event, we should update the selection
14555
- var selection = _this.editor.getDocument().getSelection();
14556
- if (selection && selection.focusNode) {
14557
- var image = (0, isSingleImageInSelection_1.isSingleImageInSelection)(selection);
14581
+ var range = domHelper.getSelectionRange();
14582
+ if (range) {
14583
+ var image = (0, isSingleImageInSelection_1.isSingleImageInSelection)(range);
14558
14584
  if ((newSelection === null || newSelection === void 0 ? void 0 : newSelection.type) == 'image' && !image) {
14559
- var range = selection.getRangeAt(0);
14585
+ var sel = (_b = _this.editor.getDocument().defaultView) === null || _b === void 0 ? void 0 : _b.getSelection();
14586
+ var isReverted = sel
14587
+ ? sel.focusNode != range.endContainer || sel.focusOffset != range.endOffset
14588
+ : false;
14560
14589
  _this.editor.setDOMSelection({
14561
14590
  type: 'range',
14562
14591
  range: range,
14563
- isReverted: selection.focusNode != range.endContainer ||
14564
- selection.focusOffset != range.endOffset,
14592
+ isReverted: isReverted,
14565
14593
  });
14566
14594
  }
14567
14595
  else if ((newSelection === null || newSelection === void 0 ? void 0 : newSelection.type) !== 'image' && image) {
@@ -15950,10 +15978,23 @@ exports.Editor = Editor;
15950
15978
 
15951
15979
  Object.defineProperty(exports, "__esModule", ({ value: true }));
15952
15980
  exports.createDOMHelper = void 0;
15981
+ var areSameRanges_1 = __webpack_require__(/*! ../../utils/areSameRanges */ "./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts");
15953
15982
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
15983
+ function isSelectionWithComposedRanges(sel) {
15984
+ return 'getComposedRanges' in sel;
15985
+ }
15986
+ function isShadowRoot(node) {
15987
+ return 'host' in node;
15988
+ }
15954
15989
  var DOMHelperImpl = /** @class */ (function () {
15955
15990
  function DOMHelperImpl(contentDiv, options) {
15991
+ var _a;
15956
15992
  this.contentDiv = contentDiv;
15993
+ var rootNode = contentDiv.getRootNode();
15994
+ this.shadowRoot = (options === null || options === void 0 ? void 0 : options.useShadowDom) && isShadowRoot(rootNode) ? rootNode : null;
15995
+ this.doc = contentDiv.ownerDocument;
15996
+ var sel = (_a = this.doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
15997
+ this.useComposedRanges = !!(this.shadowRoot && sel && 'getComposedRanges' in sel);
15957
15998
  }
15958
15999
  DOMHelperImpl.prototype.queryElements = function (selector) {
15959
16000
  return (0, roosterjs_content_model_dom_1.toArray)(this.contentDiv.querySelectorAll(selector));
@@ -16015,7 +16056,9 @@ var DOMHelperImpl = /** @class */ (function () {
16015
16056
  return this.contentDiv;
16016
16057
  };
16017
16058
  DOMHelperImpl.prototype.hasFocus = function () {
16018
- var activeElement = this.contentDiv.ownerDocument.activeElement;
16059
+ var activeElement = this.shadowRoot
16060
+ ? this.shadowRoot.activeElement
16061
+ : this.doc.activeElement;
16019
16062
  return !!(activeElement && this.contentDiv.contains(activeElement));
16020
16063
  };
16021
16064
  /**
@@ -16082,6 +16125,51 @@ var DOMHelperImpl = /** @class */ (function () {
16082
16125
  DOMHelperImpl.prototype.getRangesByText = function (text, matchCase, wholeWord) {
16083
16126
  return (0, roosterjs_content_model_dom_1.getRangesByText)(this.contentDiv, text, matchCase, wholeWord, true /*editableOnly*/);
16084
16127
  };
16128
+ DOMHelperImpl.prototype.getSelectionRange = function () {
16129
+ var _a;
16130
+ var sel = (_a = this.doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
16131
+ if (!sel) {
16132
+ return null;
16133
+ }
16134
+ if (this.useComposedRanges && this.shadowRoot && isSelectionWithComposedRanges(sel)) {
16135
+ var staticRanges = sel.getComposedRanges({
16136
+ shadowRoots: [this.shadowRoot],
16137
+ });
16138
+ if ((staticRanges === null || staticRanges === void 0 ? void 0 : staticRanges.length) > 0) {
16139
+ var sr = staticRanges[0];
16140
+ var range = this.doc.createRange();
16141
+ range.setStart(sr.startContainer, sr.startOffset);
16142
+ range.setEnd(sr.endContainer, sr.endOffset);
16143
+ return range;
16144
+ }
16145
+ return null;
16146
+ }
16147
+ return sel.rangeCount > 0 ? sel.getRangeAt(0) : null;
16148
+ };
16149
+ DOMHelperImpl.prototype.setSelectionRange = function (range, isReverted) {
16150
+ var _a;
16151
+ if (isReverted === void 0) { isReverted = false; }
16152
+ var sel = (_a = this.doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
16153
+ var currentRange = this.getSelectionRange();
16154
+ if (!sel || (currentRange && (0, areSameRanges_1.areSameRanges)(range, currentRange))) {
16155
+ return;
16156
+ }
16157
+ var startContainer = range.startContainer, startOffset = range.startOffset, endContainer = range.endContainer, endOffset = range.endOffset;
16158
+ if (!isReverted) {
16159
+ sel.setBaseAndExtent(startContainer, startOffset, endContainer, endOffset);
16160
+ }
16161
+ else {
16162
+ sel.setBaseAndExtent(endContainer, endOffset, startContainer, startOffset);
16163
+ }
16164
+ };
16165
+ DOMHelperImpl.prototype.appendToRoot = function (element) {
16166
+ if (this.shadowRoot) {
16167
+ this.shadowRoot.appendChild(element);
16168
+ }
16169
+ else {
16170
+ this.doc.body.appendChild(element);
16171
+ }
16172
+ };
16085
16173
  return DOMHelperImpl;
16086
16174
  }());
16087
16175
  /**
@@ -16198,7 +16286,10 @@ function createEditorCore(contentDiv, options) {
16198
16286
  corePlugins.lifecycle,
16199
16287
  ], false), environment: createEditorEnvironment(contentDiv, options), darkColorHandler: (0, DarkColorHandlerImpl_1.createDarkColorHandler)(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors, options.generateColorKey), trustedHTMLHandler: options.trustedHTMLHandler && !(0, domCreator_1.isDOMCreator)(options.trustedHTMLHandler)
16200
16288
  ? options.trustedHTMLHandler
16201
- : (0, domCreator_1.createTrustedHTMLHandler)(domCreator), domCreator: domCreator, domHelper: (0, DOMHelperImpl_1.createDOMHelper)(contentDiv) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler, onFixUpModel: options.onFixUpModel, experimentalFeatures: options.experimentalFeatures ? (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(options.experimentalFeatures), false) : [] });
16289
+ : (0, domCreator_1.createTrustedHTMLHandler)(domCreator), domCreator: domCreator, domHelper: (0, DOMHelperImpl_1.createDOMHelper)(contentDiv, {
16290
+ useShadowDom: !!options.experimentalFeatures &&
16291
+ options.experimentalFeatures.indexOf('ShadowDom') >= 0,
16292
+ }) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler, onFixUpModel: options.onFixUpModel, experimentalFeatures: options.experimentalFeatures ? (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(options.experimentalFeatures), false) : [] });
16202
16293
  }
16203
16294
  exports.createEditorCore = createEditorCore;
16204
16295
  function createEditorEnvironment(contentDiv, options) {
@@ -16356,6 +16447,8 @@ var containerSizeFormatParser = function (format, element) {
16356
16447
  if (element.tagName == 'DIV' || element.tagName == 'P') {
16357
16448
  delete format.width;
16358
16449
  delete format.height;
16450
+ delete format.maxHeight;
16451
+ delete format.maxWidth;
16359
16452
  }
16360
16453
  };
16361
16454
  exports.containerSizeFormatParser = containerSizeFormatParser;
@@ -16652,6 +16745,29 @@ var pasteWhiteSpaceFormatParser = function (format, element, context, defaultSty
16652
16745
  exports.pasteWhiteSpaceFormatParser = pasteWhiteSpaceFormatParser;
16653
16746
 
16654
16747
 
16748
+ /***/ },
16749
+
16750
+ /***/ "./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts"
16751
+ /*!**************************************************************************!*\
16752
+ !*** ./packages/roosterjs-content-model-core/lib/utils/areSameRanges.ts ***!
16753
+ \**************************************************************************/
16754
+ (__unused_webpack_module, exports) {
16755
+
16756
+ "use strict";
16757
+
16758
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
16759
+ exports.areSameRanges = void 0;
16760
+ var RangeKeys = ['startContainer', 'endContainer', 'startOffset', 'endOffset'];
16761
+ /**
16762
+ * @internal
16763
+ * Check if two ranges have the same start and end positions.
16764
+ */
16765
+ function areSameRanges(r1, r2) {
16766
+ return RangeKeys.every(function (k) { return r1[k] == r2[k]; });
16767
+ }
16768
+ exports.areSameRanges = areSameRanges;
16769
+
16770
+
16655
16771
  /***/ },
16656
16772
 
16657
16773
  /***/ "./packages/roosterjs-content-model-core/lib/utils/createAriaLiveElement.ts"
@@ -16677,7 +16793,6 @@ function createAriaLiveElement(document) {
16677
16793
  div.style.whiteSpace = 'nowrap';
16678
16794
  div.style.width = '1px';
16679
16795
  div.ariaLive = 'assertive';
16680
- document.body.appendChild(div);
16681
16796
  return div;
16682
16797
  }
16683
16798
  exports.createAriaLiveElement = createAriaLiveElement;
@@ -18075,7 +18190,9 @@ var formatContainerProcessorInternal = function (group, element, context, forceF
18075
18190
  if (element.style.fontSize && parseInt(element.style.fontSize) == 0) {
18076
18191
  formatContainer.zeroFontSize = true;
18077
18192
  }
18078
- if (shouldFallbackToParagraph(formatContainer) && !forceFormatContainer) {
18193
+ if (!context.skipFormatContainerFallbackCheck &&
18194
+ shouldFallbackToParagraph(formatContainer) &&
18195
+ !forceFormatContainer) {
18079
18196
  // For DIV container that only has one paragraph child, container style can be merged into paragraph
18080
18197
  // and no need to have this container
18081
18198
  var paragraph = formatContainer.blocks[0];
@@ -21168,11 +21285,13 @@ exports.directionFormatHandler = {
21168
21285
  format.direction = dir == 'rtl' ? 'rtl' : 'ltr';
21169
21286
  }
21170
21287
  },
21171
- apply: function (format, element) {
21288
+ apply: function (format, element, context) {
21172
21289
  if (format.direction) {
21173
21290
  element.style.direction = format.direction;
21174
21291
  }
21175
- if (format.direction == 'rtl' && (0, isElementOfType_1.isElementOfType)(element, 'table')) {
21292
+ if (format.direction == 'rtl' &&
21293
+ (0, isElementOfType_1.isElementOfType)(element, 'table') &&
21294
+ context.implicitFormat.direction != 'rtl') {
21176
21295
  element.style.justifySelf = 'flex-end';
21177
21296
  }
21178
21297
  },
@@ -21709,6 +21828,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
21709
21828
  exports.borderFormatHandler = void 0;
21710
21829
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
21711
21830
  var borderKeys_1 = __webpack_require__(/*! ../utils/borderKeys */ "./packages/roosterjs-content-model-dom/lib/formatHandlers/utils/borderKeys.ts");
21831
+ var borderValues_1 = __webpack_require__(/*! ../../domUtils/style/borderValues */ "./packages/roosterjs-content-model-dom/lib/domUtils/style/borderValues.ts");
21712
21832
  // This array needs to match BorderKeys array
21713
21833
  var BorderWidthKeys = [
21714
21834
  'borderTopWidth',
@@ -21737,7 +21857,17 @@ exports.borderFormatHandler = {
21737
21857
  width = '0px';
21738
21858
  }
21739
21859
  if (value && width != defaultWidth) {
21740
- format[key] = value == 'none' ? '' : value;
21860
+ var result = value;
21861
+ if (result.includes('initial')) {
21862
+ // Remove 'initial' from the last part (color) of the border value
21863
+ // since browsers ignore it when setting the inline style property
21864
+ var border = (0, borderValues_1.extractBorderValues)(value);
21865
+ if (border.color === 'initial') {
21866
+ border.color = '';
21867
+ }
21868
+ result = (0, borderValues_1.combineBorderValue)(border);
21869
+ }
21870
+ format[key] = result == 'none' ? '' : result;
21741
21871
  }
21742
21872
  });
21743
21873
  var borderRadius = element.style.borderRadius;
@@ -24139,6 +24269,7 @@ var createText_1 = __webpack_require__(/*! ../creators/createText */ "./packages
24139
24269
  var ensureParagraph_1 = __webpack_require__(/*! ./ensureParagraph */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/ensureParagraph.ts");
24140
24270
  var hasSpacesOnly_1 = __webpack_require__(/*! ./hasSpacesOnly */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/hasSpacesOnly.ts");
24141
24271
  var isWhiteSpacePreserved_1 = __webpack_require__(/*! ../../domUtils/isWhiteSpacePreserved */ "./packages/roosterjs-content-model-dom/lib/domUtils/isWhiteSpacePreserved.ts");
24272
+ var stripInvisibleUnicode_1 = __webpack_require__(/*! ./stripInvisibleUnicode */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/stripInvisibleUnicode.ts");
24142
24273
  /**
24143
24274
  * Add a new text segment to current paragraph
24144
24275
  * @param group Current BlockGroup that the paragraph belong to
@@ -24154,7 +24285,11 @@ function addTextSegment(group, text, context) {
24154
24285
  if (!(0, hasSpacesOnly_1.hasSpacesOnly)(text) ||
24155
24286
  ((_a = paragraph === null || paragraph === void 0 ? void 0 : paragraph.segments.length) !== null && _a !== void 0 ? _a : 0) > 0 ||
24156
24287
  (0, isWhiteSpacePreserved_1.isWhiteSpacePreserved)(paragraph === null || paragraph === void 0 ? void 0 : paragraph.format.whiteSpace)) {
24157
- textModel = (0, createText_1.createText)(text, context.segmentFormat);
24288
+ var filteredText = context.experimentalFeatures &&
24289
+ context.experimentalFeatures.indexOf('FilterInvisibleUnicode') > -1
24290
+ ? (0, stripInvisibleUnicode_1.stripInvisibleUnicode)(text)
24291
+ : text;
24292
+ textModel = (0, createText_1.createText)(filteredText, context.segmentFormat);
24158
24293
  if (context.isInSelection) {
24159
24294
  textModel.isSelected = true;
24160
24295
  }
@@ -24789,6 +24924,34 @@ function normalizeSegmentFormat(format, environment) {
24789
24924
  exports.normalizeSegmentFormat = normalizeSegmentFormat;
24790
24925
 
24791
24926
 
24927
+ /***/ },
24928
+
24929
+ /***/ "./packages/roosterjs-content-model-dom/lib/modelApi/common/stripInvisibleUnicode.ts"
24930
+ /*!*******************************************************************************************!*\
24931
+ !*** ./packages/roosterjs-content-model-dom/lib/modelApi/common/stripInvisibleUnicode.ts ***!
24932
+ \*******************************************************************************************/
24933
+ (__unused_webpack_module, exports) {
24934
+
24935
+ "use strict";
24936
+
24937
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
24938
+ exports.stripInvisibleUnicode = void 0;
24939
+ // According to https://embracethered.com/blog/posts/2024/hiding-and-finding-text-with-unicode-tags/
24940
+ // there are some invisible unicode characters in the range of U+E0000 to U+EFFFF, which are used for hiding text in HTML.
24941
+ // We need to strip them out before processing the pasted content, otherwise they will be treated as normal text and cause unexpected behavior.
24942
+ var INVISIBLE_UNICODE_REGEX = /[\u{E0000}-\u{EFFFF}]/gu;
24943
+ /**
24944
+ * @internal
24945
+ * Strip invisible unicode characters from the given string
24946
+ * @param value The string to be processed
24947
+ * @returns The string with invisible unicode characters removed
24948
+ */
24949
+ function stripInvisibleUnicode(value) {
24950
+ return value.replace(INVISIBLE_UNICODE_REGEX, '');
24951
+ }
24952
+ exports.stripInvisibleUnicode = stripInvisibleUnicode;
24953
+
24954
+
24792
24955
  /***/ },
24793
24956
 
24794
24957
  /***/ "./packages/roosterjs-content-model-dom/lib/modelApi/common/unwrapBlock.ts"
@@ -25247,16 +25410,25 @@ exports.createParagraphDecorator = createParagraphDecorator;
25247
25410
 
25248
25411
  Object.defineProperty(exports, "__esModule", ({ value: true }));
25249
25412
  exports.createSelectionMarker = void 0;
25250
- var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
25413
+ var EmptySegmentFormat_1 = __webpack_require__(/*! ../../constants/EmptySegmentFormat */ "./packages/roosterjs-content-model-dom/lib/constants/EmptySegmentFormat.ts");
25414
+ var getObjectKeys_1 = __webpack_require__(/*! ../../domUtils/getObjectKeys */ "./packages/roosterjs-content-model-dom/lib/domUtils/getObjectKeys.ts");
25251
25415
  /**
25252
25416
  * Create a ContentModelSelectionMarker model
25253
25417
  * @param format @optional The format of this model
25254
25418
  */
25255
25419
  function createSelectionMarker(format) {
25420
+ var filteredFormat = {};
25421
+ if (format) {
25422
+ (0, getObjectKeys_1.getObjectKeys)(EmptySegmentFormat_1.EmptySegmentFormat).forEach(function (key) {
25423
+ if (key in format) {
25424
+ filteredFormat[key] = format[key];
25425
+ }
25426
+ });
25427
+ }
25256
25428
  return {
25257
25429
  segmentType: 'SelectionMarker',
25258
25430
  isSelected: true,
25259
- format: (0, tslib_1.__assign)({}, format),
25431
+ format: filteredFormat,
25260
25432
  };
25261
25433
  }
25262
25434
  exports.createSelectionMarker = createSelectionMarker;
@@ -28557,6 +28729,7 @@ function internalIterateSelections(path, callback, option, table, treatAllAsSele
28557
28729
 
28558
28730
  Object.defineProperty(exports, "__esModule", ({ value: true }));
28559
28731
  exports.setSelection = void 0;
28732
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
28560
28733
  var isGeneralSegment_1 = __webpack_require__(/*! ../typeCheck/isGeneralSegment */ "./packages/roosterjs-content-model-dom/lib/modelApi/typeCheck/isGeneralSegment.ts");
28561
28734
  var mutate_1 = __webpack_require__(/*! ../common/mutate */ "./packages/roosterjs-content-model-dom/lib/modelApi/common/mutate.ts");
28562
28735
  /**
@@ -28594,6 +28767,7 @@ function setSelectionToBlockGroup(group, isInSelection, start, end) {
28594
28767
  });
28595
28768
  }
28596
28769
  function setSelectionToBlock(block, isInSelection, start, end) {
28770
+ var _a;
28597
28771
  switch (block.blockType) {
28598
28772
  case 'BlockGroup':
28599
28773
  return setSelectionToBlockGroup(block, isInSelection, start, end);
@@ -28614,16 +28788,31 @@ function setSelectionToBlock(block, isInSelection, start, end) {
28614
28788
  return isInSelection;
28615
28789
  });
28616
28790
  case 'Paragraph':
28617
- var segmentsToDelete_1 = [];
28791
+ var state_1 = {
28792
+ segmentsToDelete: [],
28793
+ boundaryMarkers: [],
28794
+ hasSelectedNonMarker: false,
28795
+ };
28618
28796
  block.segments.forEach(function (segment, i) {
28619
28797
  isInSelection = handleSelection(isInSelection, segment, start, end, function (isInSelection) {
28620
- return setSelectionToSegment(block, segment, isInSelection, segmentsToDelete_1, start, end, i);
28798
+ return setSelectionToSegment(block, segment, isInSelection, state_1, start, end, i);
28621
28799
  });
28622
28800
  });
28623
- if (segmentsToDelete_1.length > 0) {
28801
+ if (state_1.hasSelectedNonMarker) {
28802
+ // This paragraph contains a real (non-marker) selected segment, so any leading/trailing
28803
+ // selection marker of the range is redundant within this paragraph and can be removed.
28804
+ // We only do this within the same paragraph: a boundary marker at a paragraph edge must be
28805
+ // kept to distinguish "selection starts at the beginning of this line" from "selection
28806
+ // starts at the end of the previous line".
28807
+ (_a = state_1.segmentsToDelete).push.apply(_a, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(state_1.boundaryMarkers), false));
28808
+ }
28809
+ if (state_1.segmentsToDelete.length > 0) {
28624
28810
  var mutablePara = (0, mutate_1.mutateBlock)(block);
28625
28811
  var index = void 0;
28626
- while ((index = segmentsToDelete_1.pop()) !== undefined) {
28812
+ // Sort ascending so the pop()-based splice below always removes the highest index first,
28813
+ // keeping the remaining indices valid (boundary markers may sit before queued deletions).
28814
+ state_1.segmentsToDelete.sort(function (a, b) { return a - b; });
28815
+ while ((index = state_1.segmentsToDelete.pop()) !== undefined) {
28627
28816
  if (index >= 0) {
28628
28817
  mutablePara.segments.splice(index, 1);
28629
28818
  }
@@ -28672,14 +28861,23 @@ function findCell(table, cell) {
28672
28861
  : -1;
28673
28862
  return { row: row, col: col };
28674
28863
  }
28675
- function setSelectionToSegment(paragraph, segment, isInSelection, segmentsToDelete, start, end, i) {
28864
+ function setSelectionToSegment(paragraph, segment, isInSelection, state, start, end, i) {
28865
+ if (segment.segmentType != 'SelectionMarker' && isInSelection) {
28866
+ state.hasSelectedNonMarker = true;
28867
+ }
28676
28868
  switch (segment.segmentType) {
28677
28869
  case 'SelectionMarker':
28678
28870
  if (!isInSelection || (segment != start && segment != end)) {
28679
28871
  // Delete the selection marker when
28680
28872
  // 1. It is not in selection any more. Or
28681
28873
  // 2. It is in middle of selection, so no need to have it
28682
- segmentsToDelete.push(i);
28874
+ state.segmentsToDelete.push(i);
28875
+ }
28876
+ else {
28877
+ // It is a leading/trailing selection marker of a range selection. Keep it for now, but
28878
+ // remember it so it can be removed later if this same paragraph also contains a real
28879
+ // (non-marker) selected segment, in which case the marker is redundant.
28880
+ state.boundaryMarkers.push(i);
28683
28881
  }
28684
28882
  return isInSelection;
28685
28883
  case 'General':
@@ -29120,7 +29318,7 @@ var handleBlockGroupChildren = function (doc, parent, group, context) {
29120
29318
  (_a = context.domIndexer) === null || _a === void 0 ? void 0 : _a.onBlockEntity(childBlock, group);
29121
29319
  }
29122
29320
  });
29123
- cleanUpNodeStack(listFormat.nodeStack, context);
29321
+ cleanUpNodeStack(listFormat.nodeStack, context, parent);
29124
29322
  // Remove all rest node if any since they don't appear in content model
29125
29323
  (0, cleanUpRestNodes_1.cleanUpRestNodes)(refNode, context.rewriteFromModel);
29126
29324
  }
@@ -29129,7 +29327,7 @@ var handleBlockGroupChildren = function (doc, parent, group, context) {
29129
29327
  }
29130
29328
  };
29131
29329
  exports.handleBlockGroupChildren = handleBlockGroupChildren;
29132
- function cleanUpNodeStack(nodeStack, context) {
29330
+ function cleanUpNodeStack(nodeStack, context, leavingParent) {
29133
29331
  var _a, _b;
29134
29332
  if (nodeStack.length > 0) {
29135
29333
  // Clear list stack, only run to nodeStack[1] because nodeStack[0] is the parent node
@@ -29137,6 +29335,13 @@ function cleanUpNodeStack(nodeStack, context) {
29137
29335
  var node = (_b = (_a = nodeStack.pop()) === null || _a === void 0 ? void 0 : _a.refNode) !== null && _b !== void 0 ? _b : null;
29138
29336
  (0, cleanUpRestNodes_1.cleanUpRestNodes)(node, context.rewriteFromModel);
29139
29337
  }
29338
+ if (leavingParent && nodeStack[0].node == leavingParent) {
29339
+ // When leaving a parent node that is the same with the root of node stack
29340
+ // It means the whole list node stack is being invalidated, so we clear it
29341
+ while (nodeStack.length > 0) {
29342
+ nodeStack.pop();
29343
+ }
29344
+ }
29140
29345
  }
29141
29346
  }
29142
29347
 
@@ -29331,14 +29536,16 @@ var handleFormatContainer = function (doc, parent, container, context, refNode)
29331
29536
  (0, applyFormat_1.applyFormat)(containerNode_1, context.formatAppliers.segmentOnBlock, container.format, context);
29332
29537
  (0, applyFormat_1.applyFormat)(containerNode_1, context.formatAppliers.container, container.format, context);
29333
29538
  });
29334
- if (container.tagName == 'pre') {
29335
- (0, stackFormat_1.stackFormat)(context, PreChildFormat, function () {
29539
+ (0, stackFormat_1.stackFormat)(context, container.format.direction ? { direction: container.format.direction } : null, function () {
29540
+ if (container.tagName == 'pre') {
29541
+ (0, stackFormat_1.stackFormat)(context, PreChildFormat, function () {
29542
+ context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
29543
+ });
29544
+ }
29545
+ else {
29336
29546
  context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
29337
- });
29338
- }
29339
- else {
29340
- context.modelHandlers.blockGroupChildren(doc, containerNode_1, container, context);
29341
- }
29547
+ }
29548
+ });
29342
29549
  element = containerNode_1;
29343
29550
  }
29344
29551
  if (element) {
@@ -29628,7 +29835,9 @@ var handleListItem = function (doc, parent, listItem, context, refNode) {
29628
29835
  // Need to apply listItemElement formats after applying metadata since the list numbers value relies on the result of metadata handling
29629
29836
  (0, applyFormat_1.applyFormat)(li, context.formatAppliers.listItemElement, listItem.format, context);
29630
29837
  (0, stackFormat_1.stackFormat)(context, listItem.formatHolder.format, function () {
29631
- context.modelHandlers.blockGroupChildren(doc, li, listItem, context);
29838
+ (0, stackFormat_1.stackFormat)(context, listItem.format.direction ? { direction: listItem.format.direction } : null, function () {
29839
+ context.modelHandlers.blockGroupChildren(doc, li, listItem, context);
29840
+ });
29632
29841
  });
29633
29842
  }
29634
29843
  else {
@@ -30000,7 +30209,9 @@ var handleTable = function (doc, parent, table, context, refNode) {
30000
30209
  (0, applyFormat_1.applyFormat)(td_1, context.formatAppliers.tableCellBorder, cell.format, context);
30001
30210
  (0, applyFormat_1.applyFormat)(td_1, context.formatAppliers.dataset, cell.dataset, context);
30002
30211
  }
30003
- context.modelHandlers.blockGroupChildren(doc, td_1, cell, context);
30212
+ (0, stackFormat_1.stackFormat)(context, cell.format.direction ? { direction: cell.format.direction } : null, function () {
30213
+ context.modelHandlers.blockGroupChildren(doc, td_1, cell, context);
30214
+ });
30004
30215
  });
30005
30216
  (_f = context.onNodeCreated) === null || _f === void 0 ? void 0 : _f.call(context, cell, td_1);
30006
30217
  }
@@ -30519,40 +30730,17 @@ exports.MarkdownHeadings = {
30519
30730
  "use strict";
30520
30731
 
30521
30732
  Object.defineProperty(exports, "__esModule", ({ value: true }));
30522
- exports.convertContentModelToMarkdown = exports.convertMarkdownToContentModel = void 0;
30733
+ exports.MarkdownPastePlugin = exports.isPastedContentMarkdown = exports.isContentMarkdown = exports.convertContentModelToMarkdown = exports.convertMarkdownToContentModel = void 0;
30523
30734
  var convertMarkdownToContentModel_1 = __webpack_require__(/*! ./markdownToModel/convertMarkdownToContentModel */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts");
30524
30735
  Object.defineProperty(exports, "convertMarkdownToContentModel", ({ enumerable: true, get: function () { return convertMarkdownToContentModel_1.convertMarkdownToContentModel; } }));
30525
30736
  var convertContentModelToMarkdown_1 = __webpack_require__(/*! ./modelToMarkdown/convertContentModelToMarkdown */ "./packages/roosterjs-content-model-markdown/lib/modelToMarkdown/convertContentModelToMarkdown.ts");
30526
30737
  Object.defineProperty(exports, "convertContentModelToMarkdown", ({ enumerable: true, get: function () { return convertContentModelToMarkdown_1.convertContentModelToMarkdown; } }));
30527
-
30528
-
30529
- /***/ },
30530
-
30531
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyLink.ts"
30532
- /*!*********************************************************************************************!*\
30533
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyLink.ts ***!
30534
- \*********************************************************************************************/
30535
- (__unused_webpack_module, exports) {
30536
-
30537
- "use strict";
30538
-
30539
- Object.defineProperty(exports, "__esModule", ({ value: true }));
30540
- exports.applyLink = void 0;
30541
- /**
30542
- * @internal
30543
- */
30544
- function applyLink(textSegment, text, url) {
30545
- textSegment.text = text;
30546
- textSegment.link = {
30547
- dataset: {},
30548
- format: {
30549
- href: url,
30550
- underline: true,
30551
- },
30552
- };
30553
- return textSegment;
30554
- }
30555
- exports.applyLink = applyLink;
30738
+ var isContentMarkdown_1 = __webpack_require__(/*! ./publicApi/isContentMarkdown */ "./packages/roosterjs-content-model-markdown/lib/publicApi/isContentMarkdown.ts");
30739
+ Object.defineProperty(exports, "isContentMarkdown", ({ enumerable: true, get: function () { return isContentMarkdown_1.isContentMarkdown; } }));
30740
+ var isPastedContentMarkdown_1 = __webpack_require__(/*! ./publicApi/isPastedContentMarkdown */ "./packages/roosterjs-content-model-markdown/lib/publicApi/isPastedContentMarkdown.ts");
30741
+ Object.defineProperty(exports, "isPastedContentMarkdown", ({ enumerable: true, get: function () { return isPastedContentMarkdown_1.isPastedContentMarkdown; } }));
30742
+ var MarkdownPastePlugin_1 = __webpack_require__(/*! ./plugins/MarkdownPastePlugin */ "./packages/roosterjs-content-model-markdown/lib/plugins/MarkdownPastePlugin.ts");
30743
+ Object.defineProperty(exports, "MarkdownPastePlugin", ({ enumerable: true, get: function () { return MarkdownPastePlugin_1.MarkdownPastePlugin; } }));
30556
30744
 
30557
30745
 
30558
30746
  /***/ },
@@ -30569,46 +30757,39 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
30569
30757
  exports.applySegmentFormatting = void 0;
30570
30758
  var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30571
30759
  var adjustHeading_1 = __webpack_require__(/*! ../utils/adjustHeading */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/adjustHeading.ts");
30572
- var applyLink_1 = __webpack_require__(/*! ./applyLink */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyLink.ts");
30573
- var applyTextFormatting_1 = __webpack_require__(/*! ./applyTextFormatting */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyTextFormatting.ts");
30574
30760
  var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30575
- var createImageSegment_1 = __webpack_require__(/*! ../creators/createImageSegment */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createImageSegment.ts");
30576
- var splitParagraphSegments_1 = __webpack_require__(/*! ../utils/splitParagraphSegments */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/splitParagraphSegments.ts");
30761
+ var parseInlineSegments_1 = __webpack_require__(/*! ../utils/parseInlineSegments */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/parseInlineSegments.ts");
30577
30762
  /**
30578
30763
  * @internal
30579
30764
  */
30580
30765
  function applySegmentFormatting(text, paragraph, decorator) {
30581
- var e_1, _a, _b;
30766
+ var e_1, _a;
30582
30767
  if (text.length === 0) {
30583
30768
  var br = (0, roosterjs_content_model_dom_1.createBr)();
30584
30769
  paragraph.segments.push(br);
30585
30770
  }
30586
30771
  else {
30587
- var textSegments = (0, splitParagraphSegments_1.splitParagraphSegments)(text);
30772
+ var segments = [];
30773
+ (0, parseInlineSegments_1.parseInlineSegments)(text, segments);
30774
+ // Apply heading adjustment to the first text-bearing segment, if any.
30775
+ var headingAdjusted = false;
30588
30776
  try {
30589
- for (var textSegments_1 = (0, tslib_1.__values)(textSegments), textSegments_1_1 = textSegments_1.next(); !textSegments_1_1.done; textSegments_1_1 = textSegments_1.next()) {
30590
- var segment = textSegments_1_1.value;
30591
- var formattedSegment = (0, roosterjs_content_model_dom_1.createText)(segment.text);
30592
- if (segment.type === 'image') {
30593
- var image = (0, createImageSegment_1.createImageSegment)(segment.text, segment.url);
30594
- paragraph.segments.push(image);
30595
- }
30596
- else {
30597
- if (segment.type === 'link') {
30598
- (0, applyLink_1.applyLink)(formattedSegment, segment.text, segment.url);
30599
- }
30600
- var segmentWithAdjustedHeading = (0, adjustHeading_1.adjustHeading)(formattedSegment, decorator);
30601
- if (segmentWithAdjustedHeading) {
30602
- var formattedSegments = (0, applyTextFormatting_1.applyTextFormatting)(formattedSegment);
30603
- (_b = paragraph.segments).push.apply(_b, (0, tslib_1.__spreadArray)([], (0, tslib_1.__read)(formattedSegments), false));
30777
+ for (var segments_1 = (0, tslib_1.__values)(segments), segments_1_1 = segments_1.next(); !segments_1_1.done; segments_1_1 = segments_1.next()) {
30778
+ var segment = segments_1_1.value;
30779
+ if (!headingAdjusted && segment.segmentType === 'Text') {
30780
+ var adjusted = (0, adjustHeading_1.adjustHeading)(segment, decorator);
30781
+ headingAdjusted = true;
30782
+ if (!adjusted) {
30783
+ continue;
30604
30784
  }
30605
30785
  }
30786
+ paragraph.segments.push(segment);
30606
30787
  }
30607
30788
  }
30608
30789
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
30609
30790
  finally {
30610
30791
  try {
30611
- if (textSegments_1_1 && !textSegments_1_1.done && (_a = textSegments_1.return)) _a.call(textSegments_1);
30792
+ if (segments_1_1 && !segments_1_1.done && (_a = segments_1.return)) _a.call(segments_1);
30612
30793
  }
30613
30794
  finally { if (e_1) throw e_1.error; }
30614
30795
  }
@@ -30620,199 +30801,57 @@ exports.applySegmentFormatting = applySegmentFormatting;
30620
30801
 
30621
30802
  /***/ },
30622
30803
 
30623
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyTextFormatting.ts"
30624
- /*!*******************************************************************************************************!*\
30625
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/appliers/applyTextFormatting.ts ***!
30626
- \*******************************************************************************************************/
30804
+ /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts"
30805
+ /*!********************************************************************************************************!*\
30806
+ !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts ***!
30807
+ \********************************************************************************************************/
30627
30808
  (__unused_webpack_module, exports, __webpack_require__) {
30628
30809
 
30629
30810
  "use strict";
30630
30811
 
30631
30812
  Object.defineProperty(exports, "__esModule", ({ value: true }));
30632
- exports.applyTextFormatting = void 0;
30633
- var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
30634
- var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
30813
+ exports.convertMarkdownToContentModel = void 0;
30814
+ var markdownProcessor_1 = __webpack_require__(/*! ./processor/markdownProcessor */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/processor/markdownProcessor.ts");
30815
+ function convertMarkdownToContentModel(text, splitLinesPatternOrOptions) {
30816
+ var _a;
30817
+ var options = (_a = (typeof splitLinesPatternOrOptions === 'string'
30818
+ ? {
30819
+ splitLinesPattern: splitLinesPatternOrOptions,
30820
+ }
30821
+ : splitLinesPatternOrOptions)) !== null && _a !== void 0 ? _a : {};
30822
+ return (0, markdownProcessor_1.markdownProcessor)(text, options);
30823
+ }
30824
+ exports.convertMarkdownToContentModel = convertMarkdownToContentModel;
30825
+
30826
+
30827
+ /***/ },
30828
+
30829
+ /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createBlockGroupFromMarkdown.ts"
30830
+ /*!****************************************************************************************************************!*\
30831
+ !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createBlockGroupFromMarkdown.ts ***!
30832
+ \****************************************************************************************************************/
30833
+ (__unused_webpack_module, exports, __webpack_require__) {
30834
+
30835
+ "use strict";
30836
+
30837
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
30838
+ exports.createBlockGroupFromMarkdown = void 0;
30839
+ var createBlockQuoteFromMarkdown_1 = __webpack_require__(/*! ./createBlockQuoteFromMarkdown */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createBlockQuoteFromMarkdown.ts");
30840
+ var createListFromMarkdown_1 = __webpack_require__(/*! ./createListFromMarkdown */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createListFromMarkdown.ts");
30841
+ var MarkdownBlockGroupType = {
30842
+ unordered_list: 'ListItem',
30843
+ ordered_list: 'ListItem',
30844
+ blockquote: 'FormatContainer',
30845
+ };
30635
30846
  /**
30636
30847
  * @internal
30637
30848
  */
30638
- function applyTextFormatting(textSegment) {
30639
- var text = textSegment.text;
30640
- // Quick check: if the text contains only formatting markers, return original
30641
- if (isOnlyFormattingMarkers(text)) {
30642
- return [textSegment];
30643
- }
30644
- var textSegments = [];
30645
- var currentState = { bold: false, italic: false, strikethrough: false };
30646
- var currentText = '';
30647
- var i = 0;
30648
- while (i < text.length) {
30649
- var marker = parseMarkerAt(text, i);
30650
- if (marker) {
30651
- // Check if this marker should be treated as formatting or as literal text
30652
- if (shouldToggleFormatting(text, i, marker, currentState)) {
30653
- // If we have accumulated text, create a segment for it
30654
- if (currentText.length > 0) {
30655
- textSegments.push(createFormattedSegment(currentText, textSegment.format, currentState, textSegment.link));
30656
- currentText = '';
30657
- }
30658
- // Toggle the formatting state
30659
- toggleFormatting(currentState, marker.type);
30660
- // Skip the marker characters
30661
- i += marker.length;
30662
- }
30663
- else {
30664
- // Treat as regular text if marker is not valid in this context
30665
- currentText += text[i];
30666
- i++;
30667
- }
30668
- }
30669
- else {
30670
- // Regular character, add to current text
30671
- currentText += text[i];
30672
- i++;
30673
- }
30674
- }
30675
- // Add any remaining text as a final segment
30676
- if (currentText.length > 0) {
30677
- textSegments.push(createFormattedSegment(currentText, textSegment.format, currentState, textSegment.link));
30678
- }
30679
- // If no meaningful formatting was applied, return the original segment
30680
- if (textSegments.length === 0 ||
30681
- (textSegments.length === 1 && textSegments[0].text === textSegment.text)) {
30682
- return [textSegment];
30683
- }
30684
- return textSegments;
30685
- }
30686
- exports.applyTextFormatting = applyTextFormatting;
30687
- function isOnlyFormattingMarkers(text) {
30688
- // Remove all potential formatting markers and see if anything remains
30689
- var remaining = text;
30690
- remaining = remaining.replace(/\*\*/g, ''); // Remove **
30691
- remaining = remaining.replace(/~~/g, ''); // Remove ~~
30692
- remaining = remaining.replace(/\*/g, ''); // Remove *
30693
- // If nothing remains after removing all markers, it was only markers
30694
- return remaining.length === 0;
30695
- }
30696
- function parseMarkerAt(text, index) {
30697
- var remaining = text.substring(index);
30698
- if (remaining.startsWith('~~')) {
30699
- return { type: 'strikethrough', length: 2 };
30700
- }
30701
- if (remaining.startsWith('**')) {
30702
- return { type: 'bold', length: 2 };
30849
+ function createBlockGroupFromMarkdown(text, patternName, options, group) {
30850
+ if (MarkdownBlockGroupType[patternName] === 'ListItem') {
30851
+ return (0, createListFromMarkdown_1.createListFromMarkdown)(text, patternName === 'ordered_list' ? 'OL' : 'UL', options);
30703
30852
  }
30704
- if (remaining.startsWith('*')) {
30705
- return { type: 'italic', length: 1 };
30706
- }
30707
- return null;
30708
- }
30709
- function shouldToggleFormatting(text, index, marker, currentState) {
30710
- var nextChar = index + marker.length < text.length ? text.charAt(index + marker.length) : '';
30711
- var isCurrentlyActive = getCurrentFormatState(currentState, marker.type);
30712
- if (isCurrentlyActive) {
30713
- // We're currently in this format, so any marker can close it
30714
- return true;
30715
- }
30716
- else {
30717
- // We're not in this format, so this marker would open it
30718
- // Opening markers must be followed by non-whitespace
30719
- return nextChar.length > 0 && !isWhitespace(nextChar);
30720
- }
30721
- }
30722
- function isWhitespace(char) {
30723
- return /\s/.test(char);
30724
- }
30725
- function toggleFormatting(state, type) {
30726
- switch (type) {
30727
- case 'bold':
30728
- state.bold = !state.bold;
30729
- break;
30730
- case 'italic':
30731
- state.italic = !state.italic;
30732
- break;
30733
- case 'strikethrough':
30734
- state.strikethrough = !state.strikethrough;
30735
- break;
30736
- }
30737
- }
30738
- function getCurrentFormatState(state, type) {
30739
- switch (type) {
30740
- case 'bold':
30741
- return state.bold;
30742
- case 'italic':
30743
- return state.italic;
30744
- case 'strikethrough':
30745
- return state.strikethrough;
30746
- }
30747
- }
30748
- function createFormattedSegment(text, baseFormat, state, link) {
30749
- var format = (0, tslib_1.__assign)({}, baseFormat);
30750
- if (state.bold) {
30751
- format.fontWeight = 'bold';
30752
- }
30753
- if (state.italic) {
30754
- format.italic = true;
30755
- }
30756
- if (state.strikethrough) {
30757
- format.strikethrough = true;
30758
- }
30759
- return (0, roosterjs_content_model_dom_1.createText)(text, format, link);
30760
- }
30761
-
30762
-
30763
- /***/ },
30764
-
30765
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts"
30766
- /*!********************************************************************************************************!*\
30767
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts ***!
30768
- \********************************************************************************************************/
30769
- (__unused_webpack_module, exports, __webpack_require__) {
30770
-
30771
- "use strict";
30772
-
30773
- Object.defineProperty(exports, "__esModule", ({ value: true }));
30774
- exports.convertMarkdownToContentModel = void 0;
30775
- var markdownProcessor_1 = __webpack_require__(/*! ./processor/markdownProcessor */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/processor/markdownProcessor.ts");
30776
- function convertMarkdownToContentModel(text, splitLinesPatternOrOptions) {
30777
- var _a;
30778
- var options = (_a = (typeof splitLinesPatternOrOptions === 'string'
30779
- ? {
30780
- splitLinesPattern: splitLinesPatternOrOptions,
30781
- }
30782
- : splitLinesPatternOrOptions)) !== null && _a !== void 0 ? _a : {};
30783
- return (0, markdownProcessor_1.markdownProcessor)(text, options);
30784
- }
30785
- exports.convertMarkdownToContentModel = convertMarkdownToContentModel;
30786
-
30787
-
30788
- /***/ },
30789
-
30790
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createBlockGroupFromMarkdown.ts"
30791
- /*!****************************************************************************************************************!*\
30792
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createBlockGroupFromMarkdown.ts ***!
30793
- \****************************************************************************************************************/
30794
- (__unused_webpack_module, exports, __webpack_require__) {
30795
-
30796
- "use strict";
30797
-
30798
- Object.defineProperty(exports, "__esModule", ({ value: true }));
30799
- exports.createBlockGroupFromMarkdown = void 0;
30800
- var createBlockQuoteFromMarkdown_1 = __webpack_require__(/*! ./createBlockQuoteFromMarkdown */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createBlockQuoteFromMarkdown.ts");
30801
- var createListFromMarkdown_1 = __webpack_require__(/*! ./createListFromMarkdown */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createListFromMarkdown.ts");
30802
- var MarkdownBlockGroupType = {
30803
- unordered_list: 'ListItem',
30804
- ordered_list: 'ListItem',
30805
- blockquote: 'FormatContainer',
30806
- };
30807
- /**
30808
- * @internal
30809
- */
30810
- function createBlockGroupFromMarkdown(text, patternName, options, group) {
30811
- if (MarkdownBlockGroupType[patternName] === 'ListItem') {
30812
- return (0, createListFromMarkdown_1.createListFromMarkdown)(text, patternName === 'ordered_list' ? 'OL' : 'UL', options);
30813
- }
30814
- else {
30815
- return (0, createBlockQuoteFromMarkdown_1.createBlockQuoteFromMarkdown)(text, options, group);
30853
+ else {
30854
+ return (0, createBlockQuoteFromMarkdown_1.createBlockQuoteFromMarkdown)(text, options, group);
30816
30855
  }
30817
30856
  }
30818
30857
  exports.createBlockGroupFromMarkdown = createBlockGroupFromMarkdown;
@@ -31357,29 +31396,154 @@ exports.isMarkdownTable = isMarkdownTable;
31357
31396
 
31358
31397
  /***/ },
31359
31398
 
31360
- /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/splitParagraphSegments.ts"
31361
- /*!*******************************************************************************************************!*\
31362
- !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/splitParagraphSegments.ts ***!
31363
- \*******************************************************************************************************/
31364
- (__unused_webpack_module, exports) {
31399
+ /***/ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/parseInlineSegments.ts"
31400
+ /*!****************************************************************************************************!*\
31401
+ !*** ./packages/roosterjs-content-model-markdown/lib/markdownToModel/utils/parseInlineSegments.ts ***!
31402
+ \****************************************************************************************************/
31403
+ (__unused_webpack_module, exports, __webpack_require__) {
31365
31404
 
31366
31405
  "use strict";
31367
31406
 
31368
31407
  Object.defineProperty(exports, "__esModule", ({ value: true }));
31369
- exports.splitParagraphSegments = void 0;
31370
- // Matches markdown links and images in a string.
31371
- // Group 1 (full link): [text](url) e.g. [Click here](https://example.com)
31372
- // Group 2: link text e.g. "Click here"
31373
- // Group 3: link url e.g. "https://example.com"
31374
- // Group 4 (full image): ![alt](url) e.g. ![Logo](https://example.com/logo.png)
31375
- // Group 5: alt text e.g. "Logo"
31376
- // Group 6: image url e.g. "https://example.com/logo.png"
31377
- var linkRegex = /(\[([^\[]+)\]\(([^\)]+)\))|(\!\[([^\[]+)\]\(([^\)]+)\))/g;
31378
- var isValidUrl = function (url) {
31408
+ exports.parseInlineSegments = void 0;
31409
+ var createImageSegment_1 = __webpack_require__(/*! ../creators/createImageSegment */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/creators/createImageSegment.ts");
31410
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
31411
+ // Matches a markdown link [text](url) anchored at the start of the input.
31412
+ var linkPattern = /^\[([^\[\]]+)\]\(([^\)]+)\)/;
31413
+ // Matches a markdown image ![alt](url) anchored at the start of the input.
31414
+ var imagePattern = /^!\[([^\[\]]+)\]\(([^\)]+)\)/;
31415
+ /**
31416
+ * @internal
31417
+ * Parse a markdown inline string into Content Model segments. Supports bold/italic/
31418
+ * strikethrough markers, links, and images, and keeps formatting state active across
31419
+ * link boundaries (e.g. **[link](url)**).
31420
+ */
31421
+ function parseInlineSegments(text, segments, state, link) {
31422
+ if (state === void 0) { state = { bold: false, italic: false, strikethrough: false }; }
31423
+ var buffer = '';
31424
+ var i = 0;
31425
+ var flushBuffer = function () {
31426
+ if (buffer.length > 0) {
31427
+ segments.push(createFormattedSegment(buffer, state, link));
31428
+ buffer = '';
31429
+ }
31430
+ };
31431
+ while (i < text.length) {
31432
+ var remaining = text.substring(i);
31433
+ // Escaped character: a backslash followed by an ASCII punctuation character emits
31434
+ // that character literally (e.g. "\*" -> "*") and is never treated as a marker.
31435
+ if (text[i] === '\\' && i + 1 < text.length && isEscapable(text[i + 1])) {
31436
+ buffer += text[i + 1];
31437
+ i += 2;
31438
+ continue;
31439
+ }
31440
+ // Image: ![alt](url)
31441
+ var imgMatch = imagePattern.exec(remaining);
31442
+ if (imgMatch && isValidUrl(imgMatch[2])) {
31443
+ flushBuffer();
31444
+ segments.push((0, createImageSegment_1.createImageSegment)(imgMatch[1], imgMatch[2]));
31445
+ i += imgMatch[0].length;
31446
+ continue;
31447
+ }
31448
+ // Link: [text](url) — keep outer formatting state active inside the link
31449
+ var linkMatch = linkPattern.exec(remaining);
31450
+ if (linkMatch && isValidUrl(linkMatch[2])) {
31451
+ flushBuffer();
31452
+ var innerLink = {
31453
+ dataset: {},
31454
+ format: { href: linkMatch[2], underline: true },
31455
+ };
31456
+ parseInlineSegments(linkMatch[1], segments, state, innerLink);
31457
+ i += linkMatch[0].length;
31458
+ continue;
31459
+ }
31460
+ // Formatting marker
31461
+ var marker = parseMarkerAt(text, i);
31462
+ if (marker && shouldToggleFormatting(text, i, marker, state)) {
31463
+ flushBuffer();
31464
+ toggleFormatting(state, marker.type);
31465
+ i += marker.length;
31466
+ continue;
31467
+ }
31468
+ buffer += text[i];
31469
+ i++;
31470
+ }
31471
+ flushBuffer();
31472
+ }
31473
+ exports.parseInlineSegments = parseInlineSegments;
31474
+ function parseMarkerAt(text, index) {
31475
+ var remaining = text.substring(index);
31476
+ if (remaining.startsWith('~~')) {
31477
+ return { type: 'strikethrough', length: 2 };
31478
+ }
31479
+ if (remaining.startsWith('**')) {
31480
+ return { type: 'bold', length: 2 };
31481
+ }
31482
+ if (remaining.startsWith('*')) {
31483
+ return { type: 'italic', length: 1 };
31484
+ }
31485
+ return null;
31486
+ }
31487
+ function shouldToggleFormatting(text, index, marker, currentState) {
31488
+ var isCurrentlyActive = getCurrentFormatState(currentState, marker.type);
31489
+ if (isCurrentlyActive) {
31490
+ return true;
31491
+ }
31492
+ // Opening marker must be followed by a non-whitespace character.
31493
+ var nextIndex = index + marker.length;
31494
+ var nextChar = nextIndex < text.length ? text.charAt(nextIndex) : '';
31495
+ if (nextChar.length === 0 || isWhitespace(nextChar)) {
31496
+ return false;
31497
+ }
31498
+ return true;
31499
+ }
31500
+ function isWhitespace(char) {
31501
+ return /\s/.test(char);
31502
+ }
31503
+ function isEscapable(char) {
31504
+ // Per CommonMark, any ASCII punctuation character may be backslash-escaped.
31505
+ return /[!"#$%&'()*+,\-./:;<=>?@[\\\]^_`{|}~]/.test(char);
31506
+ }
31507
+ function toggleFormatting(state, type) {
31508
+ switch (type) {
31509
+ case 'bold':
31510
+ state.bold = !state.bold;
31511
+ break;
31512
+ case 'italic':
31513
+ state.italic = !state.italic;
31514
+ break;
31515
+ case 'strikethrough':
31516
+ state.strikethrough = !state.strikethrough;
31517
+ break;
31518
+ }
31519
+ }
31520
+ function getCurrentFormatState(state, type) {
31521
+ switch (type) {
31522
+ case 'bold':
31523
+ return state.bold;
31524
+ case 'italic':
31525
+ return state.italic;
31526
+ case 'strikethrough':
31527
+ return state.strikethrough;
31528
+ }
31529
+ }
31530
+ function createFormattedSegment(text, state, link) {
31531
+ var format = {};
31532
+ if (state.bold) {
31533
+ format.fontWeight = 'bold';
31534
+ }
31535
+ if (state.italic) {
31536
+ format.italic = true;
31537
+ }
31538
+ if (state.strikethrough) {
31539
+ format.strikethrough = true;
31540
+ }
31541
+ return (0, roosterjs_content_model_dom_1.createText)(text, format, link);
31542
+ }
31543
+ function isValidUrl(url) {
31379
31544
  if (!url) {
31380
31545
  return false;
31381
31546
  }
31382
- // Accept common non-http schemes and relative paths
31383
31547
  if (url.startsWith('data:') ||
31384
31548
  url.startsWith('blob:') ||
31385
31549
  url.startsWith('/') ||
@@ -31394,51 +31558,7 @@ var isValidUrl = function (url) {
31394
31558
  catch (_) {
31395
31559
  return false;
31396
31560
  }
31397
- };
31398
- function pushText(result, text) {
31399
- var last = result[result.length - 1];
31400
- if (last && last.type === 'text') {
31401
- last.text += text;
31402
- }
31403
- else {
31404
- result.push({ type: 'text', text: text, url: '' });
31405
- }
31406
31561
  }
31407
- /**
31408
- * @internal
31409
- */
31410
- function splitParagraphSegments(text) {
31411
- var result = [];
31412
- var lastIndex = 0;
31413
- var match = null;
31414
- while ((match = linkRegex.exec(text)) !== null) {
31415
- if (match.index > lastIndex) {
31416
- pushText(result, text.slice(lastIndex, match.index));
31417
- }
31418
- if (match[2] && match[3]) {
31419
- if (isValidUrl(match[3])) {
31420
- result.push({ type: 'link', text: match[2], url: match[3] });
31421
- }
31422
- else {
31423
- pushText(result, match[0]);
31424
- }
31425
- }
31426
- else if (match[5] && match[6]) {
31427
- if (isValidUrl(match[6])) {
31428
- result.push({ type: 'image', text: match[5], url: match[6] });
31429
- }
31430
- else {
31431
- pushText(result, match[0]);
31432
- }
31433
- }
31434
- lastIndex = linkRegex.lastIndex;
31435
- }
31436
- if (lastIndex < text.length) {
31437
- pushText(result, text.slice(lastIndex));
31438
- }
31439
- return result;
31440
- }
31441
- exports.splitParagraphSegments = splitParagraphSegments;
31442
31562
 
31443
31563
 
31444
31564
  /***/ },
@@ -31699,20 +31819,30 @@ function createMarkdownParagraph(paragraph, context) {
31699
31819
  }
31700
31820
  exports.createMarkdownParagraph = createMarkdownParagraph;
31701
31821
  function textProcessor(text) {
31702
- var markdownString = text.text;
31703
- if (text.link) {
31704
- markdownString = "[" + text.text + "](" + text.link.format.href + ")";
31705
- }
31706
- if (text.format.fontWeight == 'bold') {
31707
- markdownString = "**" + markdownString + "**";
31822
+ var _a = text.format, fontWeight = _a.fontWeight, italic = _a.italic, strikethrough = _a.strikethrough;
31823
+ var hasInlineFormat = fontWeight == 'bold' || italic || strikethrough;
31824
+ if (!hasInlineFormat) {
31825
+ return text.link ? "[" + text.text + "](" + text.link.format.href + ")" : text.text;
31826
+ }
31827
+ // Move leading/trailing whitespace outside the markers so the emitted
31828
+ // markdown is valid (CommonMark requires emphasis markers to hug
31829
+ // non-whitespace), e.g. "world " with <b> => " " + "**world**".
31830
+ var match = /^(\s*)([\s\S]*?)(\s*)$/.exec(text.text);
31831
+ var _b = (0, tslib_1.__read)(match ? match : ['', '', text.text, ''], 4), leading = _b[1], core = _b[2], trailing = _b[3];
31832
+ if (!core) {
31833
+ return text.text;
31834
+ }
31835
+ var inner = text.link ? "[" + core + "](" + text.link.format.href + ")" : core;
31836
+ if (fontWeight == 'bold') {
31837
+ inner = "**" + inner + "**";
31838
+ }
31839
+ if (strikethrough) {
31840
+ inner = "~~" + inner + "~~";
31708
31841
  }
31709
- if (text.format.strikethrough) {
31710
- markdownString = "~~" + markdownString + "~~";
31711
- }
31712
- if (text.format.italic) {
31713
- markdownString = "*" + markdownString + "*";
31842
+ if (italic) {
31843
+ inner = "*" + inner + "*";
31714
31844
  }
31715
- return markdownString;
31845
+ return "" + leading + inner + trailing;
31716
31846
  }
31717
31847
 
31718
31848
 
@@ -31877,6 +32007,252 @@ function modelProcessor(model, newLine) {
31877
32007
  exports.modelProcessor = modelProcessor;
31878
32008
 
31879
32009
 
32010
+ /***/ },
32011
+
32012
+ /***/ "./packages/roosterjs-content-model-markdown/lib/plugins/MarkdownPastePlugin.ts"
32013
+ /*!**************************************************************************************!*\
32014
+ !*** ./packages/roosterjs-content-model-markdown/lib/plugins/MarkdownPastePlugin.ts ***!
32015
+ \**************************************************************************************/
32016
+ (__unused_webpack_module, exports, __webpack_require__) {
32017
+
32018
+ "use strict";
32019
+
32020
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
32021
+ exports.MarkdownPastePlugin = void 0;
32022
+ var roosterjs_content_model_dom_1 = __webpack_require__(/*! roosterjs-content-model-dom */ "./packages/roosterjs-content-model-dom/lib/index.ts");
32023
+ var convertMarkdownToContentModel_1 = __webpack_require__(/*! ../markdownToModel/convertMarkdownToContentModel */ "./packages/roosterjs-content-model-markdown/lib/markdownToModel/convertMarkdownToContentModel.ts");
32024
+ var isPastedContentMarkdown_1 = __webpack_require__(/*! ../publicApi/isPastedContentMarkdown */ "./packages/roosterjs-content-model-markdown/lib/publicApi/isPastedContentMarkdown.ts");
32025
+ var DefaultOptions = {
32026
+ autoConversion: false,
32027
+ };
32028
+ /**
32029
+ * Markdown paste plugin. Handles the BeforePaste event and, when the pasted content
32030
+ * can be interpreted as markdown, converts the plain text into a Content Model and
32031
+ * pastes it as rich markdown content instead of the original clipboard HTML.
32032
+ */
32033
+ var MarkdownPastePlugin = /** @class */ (function () {
32034
+ /**
32035
+ * Construct a new instance of MarkdownPastePlugin
32036
+ * @param options Options to control the markdown paste behavior
32037
+ */
32038
+ function MarkdownPastePlugin(options) {
32039
+ this.editor = null;
32040
+ this.options = options !== null && options !== void 0 ? options : DefaultOptions;
32041
+ }
32042
+ /**
32043
+ * Get name of this plugin
32044
+ */
32045
+ MarkdownPastePlugin.prototype.getName = function () {
32046
+ return 'MarkdownPaste';
32047
+ };
32048
+ /**
32049
+ * The first method that editor will call to a plugin when editor is initializing.
32050
+ * It will pass in the editor instance, plugin should take this chance to save the
32051
+ * editor reference so that it can call to any editor method or format API later.
32052
+ * @param editor The editor object
32053
+ */
32054
+ MarkdownPastePlugin.prototype.initialize = function (editor) {
32055
+ this.editor = editor;
32056
+ };
32057
+ /**
32058
+ * The last method that editor will call to a plugin before it is disposed.
32059
+ * Plugin can take this chance to clear the reference to editor. After this method is
32060
+ * called, plugin should not call to any editor method since it will result in error.
32061
+ */
32062
+ MarkdownPastePlugin.prototype.dispose = function () {
32063
+ this.editor = null;
32064
+ };
32065
+ /**
32066
+ * Core method for a plugin. Once an event happens in editor, editor will call this
32067
+ * method of each plugin to handle the event as long as the event is not handled
32068
+ * exclusively by another plugin.
32069
+ * @param event The event to handle:
32070
+ */
32071
+ MarkdownPastePlugin.prototype.onPluginEvent = function (event) {
32072
+ if (!this.editor || event.eventType != 'beforePaste') {
32073
+ return;
32074
+ }
32075
+ var shouldConvert = event.pasteType === 'asMarkdown' || this.options.autoConversion;
32076
+ if (shouldConvert && (0, isPastedContentMarkdown_1.isPastedContentMarkdown)(this.editor, event.clipboardData)) {
32077
+ convertPastedTextToMarkdown(this.editor, event.fragment, event.clipboardData.text);
32078
+ }
32079
+ };
32080
+ return MarkdownPastePlugin;
32081
+ }());
32082
+ exports.MarkdownPastePlugin = MarkdownPastePlugin;
32083
+ function convertPastedTextToMarkdown(editor, fragment, text) {
32084
+ var model = (0, convertMarkdownToContentModel_1.convertMarkdownToContentModel)(text, {
32085
+ emptyLine: 'merge',
32086
+ });
32087
+ while (fragment.firstChild) {
32088
+ fragment.removeChild(fragment.firstChild);
32089
+ }
32090
+ (0, roosterjs_content_model_dom_1.contentModelToDom)(editor.getDocument(), fragment, model, (0, roosterjs_content_model_dom_1.createModelToDomContext)());
32091
+ }
32092
+
32093
+
32094
+ /***/ },
32095
+
32096
+ /***/ "./packages/roosterjs-content-model-markdown/lib/publicApi/isContentMarkdown.ts"
32097
+ /*!**************************************************************************************!*\
32098
+ !*** ./packages/roosterjs-content-model-markdown/lib/publicApi/isContentMarkdown.ts ***!
32099
+ \**************************************************************************************/
32100
+ (__unused_webpack_module, exports, __webpack_require__) {
32101
+
32102
+ "use strict";
32103
+
32104
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
32105
+ exports.isContentMarkdown = void 0;
32106
+ var tslib_1 = __webpack_require__(/*! tslib */ "./node_modules/tslib/tslib.es6.mjs");
32107
+ // Block-level markdown patterns. A line that matches any of these is considered markdown.
32108
+ var BlockPatterns = [
32109
+ /^#{1,6}\s.+/,
32110
+ /^\s*>\s.+/,
32111
+ /^\s*[\*\-\+]\s.+/,
32112
+ /^\s*\d+\.\s.+/,
32113
+ /^---+$/,
32114
+ /^\s*\|.*\|\s*$/, // table row: "| a | b |"
32115
+ ];
32116
+ // Inline markdown patterns. The text contains markdown if any of these match anywhere.
32117
+ var InlinePatterns = [
32118
+ /!\[[^\[\]]+\]\([^\)\s]+\)/,
32119
+ /\[[^\[\]]+\]\([^\)\s]+\)/,
32120
+ /\*\*[^\s*][^*]*\*\*/,
32121
+ /(^|[^*])\*[^\s*][^*]*\*([^*]|$)/,
32122
+ /~~[^\s~][^~]*~~/, // strikethrough: ~~text~~
32123
+ ];
32124
+ /**
32125
+ * Detect whether the given plain text contains any markdown markup.
32126
+ * Recognizes block-level patterns (headings, blockquotes, lists, horizontal rules, tables)
32127
+ * and inline patterns (bold, italic, strikethrough, links, images).
32128
+ * @param text The plain text to check.
32129
+ * @returns True if the text contains any markdown markup, false otherwise.
32130
+ */
32131
+ function isContentMarkdown(text) {
32132
+ var e_1, _a, e_2, _b, e_3, _c;
32133
+ if (!text || !text.trim()) {
32134
+ return false;
32135
+ }
32136
+ var lines = text.split(/\r\n|\r|\n/);
32137
+ try {
32138
+ for (var lines_1 = (0, tslib_1.__values)(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
32139
+ var line = lines_1_1.value;
32140
+ try {
32141
+ for (var BlockPatterns_1 = (e_2 = void 0, (0, tslib_1.__values)(BlockPatterns)), BlockPatterns_1_1 = BlockPatterns_1.next(); !BlockPatterns_1_1.done; BlockPatterns_1_1 = BlockPatterns_1.next()) {
32142
+ var pattern = BlockPatterns_1_1.value;
32143
+ if (pattern.test(line)) {
32144
+ return true;
32145
+ }
32146
+ }
32147
+ }
32148
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
32149
+ finally {
32150
+ try {
32151
+ if (BlockPatterns_1_1 && !BlockPatterns_1_1.done && (_b = BlockPatterns_1.return)) _b.call(BlockPatterns_1);
32152
+ }
32153
+ finally { if (e_2) throw e_2.error; }
32154
+ }
32155
+ }
32156
+ }
32157
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
32158
+ finally {
32159
+ try {
32160
+ if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
32161
+ }
32162
+ finally { if (e_1) throw e_1.error; }
32163
+ }
32164
+ try {
32165
+ for (var InlinePatterns_1 = (0, tslib_1.__values)(InlinePatterns), InlinePatterns_1_1 = InlinePatterns_1.next(); !InlinePatterns_1_1.done; InlinePatterns_1_1 = InlinePatterns_1.next()) {
32166
+ var pattern = InlinePatterns_1_1.value;
32167
+ if (pattern.test(text)) {
32168
+ return true;
32169
+ }
32170
+ }
32171
+ }
32172
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
32173
+ finally {
32174
+ try {
32175
+ if (InlinePatterns_1_1 && !InlinePatterns_1_1.done && (_c = InlinePatterns_1.return)) _c.call(InlinePatterns_1);
32176
+ }
32177
+ finally { if (e_3) throw e_3.error; }
32178
+ }
32179
+ return false;
32180
+ }
32181
+ exports.isContentMarkdown = isContentMarkdown;
32182
+
32183
+
32184
+ /***/ },
32185
+
32186
+ /***/ "./packages/roosterjs-content-model-markdown/lib/publicApi/isPastedContentMarkdown.ts"
32187
+ /*!********************************************************************************************!*\
32188
+ !*** ./packages/roosterjs-content-model-markdown/lib/publicApi/isPastedContentMarkdown.ts ***!
32189
+ \********************************************************************************************/
32190
+ (__unused_webpack_module, exports, __webpack_require__) {
32191
+
32192
+ "use strict";
32193
+
32194
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
32195
+ exports.isPastedContentMarkdown = void 0;
32196
+ var isContentMarkdown_1 = __webpack_require__(/*! ./isContentMarkdown */ "./packages/roosterjs-content-model-markdown/lib/publicApi/isContentMarkdown.ts");
32197
+ // Tags that are considered "thin wrappers", which only add structure (such as line breaks)
32198
+ // around the plain text without applying any real formatting to its content.
32199
+ var ThinWrapperTags = new Set(['DIV', 'P', 'BR', 'SPAN']);
32200
+ var AllowedAttributes = new Set(['class', 'style']);
32201
+ /**
32202
+ * Detect whether the given clipboard content can be interpreted as markdown.
32203
+ * @param editor The editor instance.
32204
+ * @param clipboardData The clipboard data to check.
32205
+ * @returns True if the content can be interpreted as markdown, false otherwise.
32206
+ */
32207
+ function isPastedContentMarkdown(editor, clipboardData) {
32208
+ var text = clipboardData.text, rawHtml = clipboardData.rawHtml;
32209
+ if (!text || !text.trim()) {
32210
+ return false;
32211
+ }
32212
+ if ((0, isContentMarkdown_1.isContentMarkdown)(text)) {
32213
+ if (!rawHtml) {
32214
+ return true;
32215
+ }
32216
+ var doc = editor.getDocument();
32217
+ var trustedHTMLHandler = editor.getDOMCreator();
32218
+ var fragment = parseHtmlToFragment(rawHtml, doc, trustedHTMLHandler);
32219
+ return isThinWrapperOfPlainText(fragment, text);
32220
+ }
32221
+ return false;
32222
+ }
32223
+ exports.isPastedContentMarkdown = isPastedContentMarkdown;
32224
+ function isThinWrapperOfPlainText(fragment, text) {
32225
+ var elements = fragment.querySelectorAll('*');
32226
+ for (var i = 0; i < elements.length; i++) {
32227
+ var element = elements[i];
32228
+ if (!ThinWrapperTags.has(element.tagName)) {
32229
+ return false;
32230
+ }
32231
+ for (var j = 0; j < element.attributes.length; j++) {
32232
+ var attr = element.attributes[j];
32233
+ if (!AllowedAttributes.has(attr.name) && !attr.name.startsWith('data-')) {
32234
+ return false;
32235
+ }
32236
+ }
32237
+ }
32238
+ return removeWhitespace(fragment.textContent || '') === removeWhitespace(text);
32239
+ }
32240
+ function removeWhitespace(text) {
32241
+ return text.replace(/\s/g, '');
32242
+ }
32243
+ function parseHtmlToFragment(html, doc, trustedHTMLHandler) {
32244
+ var parsedDoc = trustedHTMLHandler.htmlToDOM(html);
32245
+ var fragment = doc.createDocumentFragment();
32246
+ var body = parsedDoc === null || parsedDoc === void 0 ? void 0 : parsedDoc.body;
32247
+ if (body) {
32248
+ while (body.firstChild) {
32249
+ fragment.appendChild(body.firstChild);
32250
+ }
32251
+ }
32252
+ return fragment;
32253
+ }
32254
+
32255
+
31880
32256
  /***/ },
31881
32257
 
31882
32258
  /***/ "./packages/roosterjs-content-model-plugins/lib/announce/AnnouncePlugin.ts"