roosterjs 8.9.0 → 8.10.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
@@ -3106,7 +3106,7 @@ exports.default = setDirection;
3106
3106
  "use strict";
3107
3107
 
3108
3108
  Object.defineProperty(exports, "__esModule", { value: true });
3109
- var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts");
3109
+ var applyListItemWrap_1 = __webpack_require__(/*! ../utils/applyListItemWrap */ "./packages/roosterjs-editor-api/lib/utils/applyListItemWrap.ts");
3110
3110
  /**
3111
3111
  * Set font name at selection
3112
3112
  * @param editor The editor instance
@@ -3114,11 +3114,9 @@ var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ ".
3114
3114
  * Currently there's no validation to the string, if the passed string is invalid, it won't take affect
3115
3115
  */
3116
3116
  function setFontName(editor, fontName) {
3117
- fontName = fontName.trim();
3118
3117
  // The browser provided execCommand creates a HTML <font> tag with face attribute. <font> is not HTML5 standard
3119
- // (http://www.w3schools.com/tags/tag_font.asp). Use applyInlineStyle which gives flexibility on applying inline style
3120
- // for here, we use CSS font-family style
3121
- applyInlineStyle_1.default(editor, function (element, isInnerNode) {
3118
+ // (http://www.w3schools.com/tags/tag_font.asp).
3119
+ applyListItemWrap_1.default(editor, 'font-family', function (element, isInnerNode) {
3122
3120
  element.style.fontFamily = isInnerNode ? '' : fontName;
3123
3121
  });
3124
3122
  }
@@ -3137,7 +3135,7 @@ exports.default = setFontName;
3137
3135
  "use strict";
3138
3136
 
3139
3137
  Object.defineProperty(exports, "__esModule", { value: true });
3140
- var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts");
3138
+ var applyListItemWrap_1 = __webpack_require__(/*! ../utils/applyListItemWrap */ "./packages/roosterjs-editor-api/lib/utils/applyListItemWrap.ts");
3141
3139
  var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts");
3142
3140
  /**
3143
3141
  * Set font size at selection
@@ -3146,11 +3144,9 @@ var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./
3146
3144
  * Currently there's no validation to the string, if the passed string is invalid, it won't take affect
3147
3145
  */
3148
3146
  function setFontSize(editor, fontSize) {
3149
- fontSize = fontSize.trim();
3150
3147
  // The browser provided execCommand only accepts 1-7 point value. In addition, it uses HTML <font> tag with size attribute.
3151
- // <font> is not HTML5 standard (http://www.w3schools.com/tags/tag_font.asp). Use applyInlineStyle which gives flexibility on applying inline style
3152
- // for here, we use CSS font-size style
3153
- applyInlineStyle_1.default(editor, function (element, isInnerNode) {
3148
+ // <font> is not HTML5 standard (http://www.w3schools.com/tags/tag_font.asp).
3149
+ applyListItemWrap_1.default(editor, 'font-size', function (element, isInnerNode) {
3154
3150
  element.style.fontSize = isInnerNode ? '' : fontSize;
3155
3151
  var lineHeight = roosterjs_editor_dom_1.getComputedStyle(element, 'line-height');
3156
3152
  if (lineHeight != 'normal') {
@@ -3310,7 +3306,7 @@ exports.default = setOrderedListNumbering;
3310
3306
  "use strict";
3311
3307
 
3312
3308
  Object.defineProperty(exports, "__esModule", { value: true });
3313
- var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts");
3309
+ var applyListItemWrap_1 = __webpack_require__(/*! ../utils/applyListItemWrap */ "./packages/roosterjs-editor-api/lib/utils/applyListItemWrap.ts");
3314
3310
  var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts");
3315
3311
  /**
3316
3312
  * Set text color at selection
@@ -3324,7 +3320,7 @@ var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./
3324
3320
  * @param shouldApplyInlineStyle Optional callback function to be invoked to verify if the current element should have the inline Style applied
3325
3321
  */
3326
3322
  function setTextColor(editor, color, shouldApplyInlineStyle) {
3327
- applyInlineStyle_1.default(editor, function (element, isInnerNode) {
3323
+ applyListItemWrap_1.default(editor, 'color', function (element, isInnerNode) {
3328
3324
  if (!shouldApplyInlineStyle || shouldApplyInlineStyle(element)) {
3329
3325
  roosterjs_editor_dom_1.setColor(element, isInnerNode ? '' : color, false /*isBackground*/, editor.isDarkMode());
3330
3326
  }
@@ -4012,6 +4008,54 @@ function applyInlineStyle(editor, callback) {
4012
4008
  exports.default = applyInlineStyle;
4013
4009
 
4014
4010
 
4011
+ /***/ }),
4012
+
4013
+ /***/ "./packages/roosterjs-editor-api/lib/utils/applyListItemWrap.ts":
4014
+ /*!**********************************************************************!*\
4015
+ !*** ./packages/roosterjs-editor-api/lib/utils/applyListItemWrap.ts ***!
4016
+ \**********************************************************************/
4017
+ /*! no static exports found */
4018
+ /***/ (function(module, exports, __webpack_require__) {
4019
+
4020
+ "use strict";
4021
+
4022
+ Object.defineProperty(exports, "__esModule", { value: true });
4023
+ var applyInlineStyle_1 = __webpack_require__(/*! ../utils/applyInlineStyle */ "./packages/roosterjs-editor-api/lib/utils/applyInlineStyle.ts");
4024
+ var roosterjs_editor_dom_1 = __webpack_require__(/*! roosterjs-editor-dom */ "./packages/roosterjs-editor-dom/lib/index.ts");
4025
+ /**
4026
+ * @internal
4027
+ * Set the List Item Style when all inner inline element have the same style
4028
+ * @param editor The editor instance
4029
+ * @param styleName Name of the style to apply to the list item
4030
+ * @param formatCallback callback to apply the style to each element
4031
+ */
4032
+ function applyListItemStyleWrap(editor, styleName, formatCallback) {
4033
+ var parentNodes = [];
4034
+ applyInlineStyle_1.default(editor, function (element, isInnerNode) {
4035
+ formatCallback(element, isInnerNode);
4036
+ var parent = editor.getElementAtCursor('LI', element);
4037
+ if (parent && parentNodes.indexOf(parent) === -1) {
4038
+ parentNodes.push(parent);
4039
+ }
4040
+ });
4041
+ applyStyleToListItems(parentNodes, [styleName]);
4042
+ }
4043
+ exports.default = applyListItemStyleWrap;
4044
+ /**
4045
+ * @internal
4046
+ * Checks if the parent element is a List Item, if it is, apply the style elements to the list item
4047
+ * @param parentNodes parentNodes to apply the style
4048
+ * @param styles styles to apply to the List Item Element
4049
+ */
4050
+ function applyStyleToListItems(parentNodes, styles) {
4051
+ parentNodes.forEach(function (node) {
4052
+ if (roosterjs_editor_dom_1.safeInstanceOf(node, 'HTMLLIElement')) {
4053
+ roosterjs_editor_dom_1.setListItemStyle(node, styles);
4054
+ }
4055
+ });
4056
+ }
4057
+
4058
+
4015
4059
  /***/ }),
4016
4060
 
4017
4061
  /***/ "./packages/roosterjs-editor-api/lib/utils/blockFormat.ts":
@@ -5872,6 +5916,12 @@ var ALLOWED_CSS_CLASSES = [
5872
5916
  ENTITY_TYPE_CSS_REGEX,
5873
5917
  ENTITY_READONLY_CSS_REGEX,
5874
5918
  ];
5919
+ var REMOVE_ENTITY_OPERATIONS = [
5920
+ 6 /* Overwrite */,
5921
+ 7 /* PartialOverwrite */,
5922
+ 4 /* RemoveFromStart */,
5923
+ 5 /* RemoveFromEnd */,
5924
+ ];
5875
5925
  /**
5876
5926
  * @internal
5877
5927
  * Entity Plugin helps handle all operations related to an entity and generate entity specified events
@@ -5888,9 +5938,28 @@ var EntityPlugin = /** @class */ (function () {
5888
5938
  _this.checkRemoveEntityForRange(event);
5889
5939
  }
5890
5940
  };
5941
+ this.workaroundShadowDOMIssueForChrome = function () {
5942
+ var cache = {};
5943
+ _this.cacheShadowEntities(cache);
5944
+ _this.editor.runAsync(function () {
5945
+ Object.keys(cache).forEach(function (id) {
5946
+ var entity = roosterjs_editor_dom_1.getEntityFromElement(cache[id]);
5947
+ var newWrapper = _this.editor.queryElements(roosterjs_editor_dom_1.getEntitySelector(entity.type, entity.id))[0];
5948
+ if (newWrapper != entity.wrapper) {
5949
+ _this.triggerEvent(entity.wrapper, 10 /* RemoveShadowRoot */);
5950
+ _this.setIsEntityKnown(entity.wrapper, false /*isKnown*/);
5951
+ if (newWrapper) {
5952
+ roosterjs_editor_dom_1.moveChildNodes(newWrapper, entity.wrapper);
5953
+ _this.createShadowRoot(newWrapper, entity.wrapper.shadowRoot);
5954
+ _this.setIsEntityKnown(newWrapper, true /*isKnown*/);
5955
+ }
5956
+ }
5957
+ });
5958
+ });
5959
+ };
5891
5960
  this.state = {
5892
- clickingPoint: null,
5893
5961
  knownEntityElements: [],
5962
+ shadowEntityCache: {},
5894
5963
  };
5895
5964
  }
5896
5965
  /**
@@ -5905,6 +5974,27 @@ var EntityPlugin = /** @class */ (function () {
5905
5974
  */
5906
5975
  EntityPlugin.prototype.initialize = function (editor) {
5907
5976
  this.editor = editor;
5977
+ // Workaround an issue for Chrome that when Delete or Backsapce, shadow DOM may be lost in editor
5978
+ if (roosterjs_editor_dom_1.Browser.isChrome || roosterjs_editor_dom_1.Browser.isSafari) {
5979
+ this.editor.addContentEditFeature({
5980
+ keys: [8 /* BACKSPACE */, 46 /* DELETE */],
5981
+ shouldHandleEvent: function () { return true; },
5982
+ handleEvent: this.workaroundShadowDOMIssueForChrome,
5983
+ });
5984
+ }
5985
+ };
5986
+ /**
5987
+ * Check if the plugin should handle the given event exclusively.
5988
+ * Handle an event exclusively means other plugin will not receive this event in
5989
+ * onPluginEvent method.
5990
+ * If two plugins will return true in willHandleEventExclusively() for the same event,
5991
+ * the final result depends on the order of the plugins are added into editor
5992
+ * @param event The event to check
5993
+ */
5994
+ EntityPlugin.prototype.willHandleEventExclusively = function (event) {
5995
+ var _a;
5996
+ return (event.eventType == 1 /* KeyPress */ &&
5997
+ !!((_a = event.rawEvent.target) === null || _a === void 0 ? void 0 : _a.shadowRoot));
5908
5998
  };
5909
5999
  /**
5910
6000
  * Dispose this plugin
@@ -5912,7 +6002,6 @@ var EntityPlugin = /** @class */ (function () {
5912
6002
  EntityPlugin.prototype.dispose = function () {
5913
6003
  this.editor = null;
5914
6004
  this.state.knownEntityElements = [];
5915
- this.state.clickingPoint = null;
5916
6005
  };
5917
6006
  /**
5918
6007
  * Get plugin state object
@@ -5926,11 +6015,8 @@ var EntityPlugin = /** @class */ (function () {
5926
6015
  */
5927
6016
  EntityPlugin.prototype.onPluginEvent = function (event) {
5928
6017
  switch (event.eventType) {
5929
- case 5 /* MouseDown */:
5930
- this.handleMouseDownEvent(event.rawEvent);
5931
- break;
5932
6018
  case 6 /* MouseUp */:
5933
- this.handleMouseUpEvent(event.rawEvent);
6019
+ this.handleMouseUpEvent(event);
5934
6020
  break;
5935
6021
  case 0 /* KeyDown */:
5936
6022
  this.handleKeyDownEvent(event.rawEvent);
@@ -5941,13 +6027,13 @@ var EntityPlugin = /** @class */ (function () {
5941
6027
  }
5942
6028
  break;
5943
6029
  case 10 /* BeforePaste */:
5944
- this.handleBeforePasteEvent(event.fragment, event.sanitizingOption);
6030
+ this.handleBeforePasteEvent(event.sanitizingOption);
5945
6031
  break;
5946
6032
  case 7 /* ContentChanged */:
5947
- this.handleContentChangedEvent(event.source == "SetContent" /* SetContent */);
6033
+ this.handleContentChangedEvent(event);
5948
6034
  break;
5949
6035
  case 11 /* EditorReady */:
5950
- this.handleContentChangedEvent(true /*resetAll*/);
6036
+ this.handleContentChangedEvent();
5951
6037
  break;
5952
6038
  case 8 /* ExtractContentWithDom */:
5953
6039
  this.handleExtractContentWithDomEvent(event.clonedRoot);
@@ -5955,6 +6041,12 @@ var EntityPlugin = /** @class */ (function () {
5955
6041
  case 16 /* ContextMenu */:
5956
6042
  this.handleContextMenuEvent(event.rawEvent);
5957
6043
  break;
6044
+ case 20 /* BeforeSetContent */:
6045
+ this.handleBeforeSetContentEvent();
6046
+ break;
6047
+ case 15 /* EntityOperation */:
6048
+ this.handleEntityOperationEvent(event);
6049
+ break;
5958
6050
  }
5959
6051
  };
5960
6052
  EntityPlugin.prototype.handleContextMenuEvent = function (event) {
@@ -5965,63 +6057,83 @@ var EntityPlugin = /** @class */ (function () {
5965
6057
  this.triggerEvent(entityElement, 2 /* ContextMenu */, event);
5966
6058
  }
5967
6059
  };
5968
- EntityPlugin.prototype.handleMouseDownEvent = function (event) {
5969
- var target = event.target, pageX = event.pageX, pageY = event.pageY;
5970
- var node = target;
5971
- var entityElement = node && this.editor.getElementAtCursor(roosterjs_editor_dom_1.getEntitySelector(), node);
5972
- if (entityElement && !entityElement.isContentEditable) {
5973
- event.preventDefault();
5974
- this.state.clickingPoint = { pageX: pageX, pageY: pageY };
5975
- }
5976
- };
5977
6060
  EntityPlugin.prototype.handleMouseUpEvent = function (event) {
5978
- var target = event.target, pageX = event.pageX, pageY = event.pageY;
5979
- var node = target;
6061
+ var rawEvent = event.rawEvent, isClicking = event.isClicking;
6062
+ var node = rawEvent.target;
5980
6063
  var entityElement;
5981
- if (this.state.clickingPoint &&
5982
- this.state.clickingPoint.pageX == pageX &&
5983
- this.state.clickingPoint.pageY == pageY &&
6064
+ if (isClicking &&
5984
6065
  node &&
5985
6066
  !!(entityElement = this.editor.getElementAtCursor(roosterjs_editor_dom_1.getEntitySelector(), node))) {
5986
- event.preventDefault();
5987
- this.triggerEvent(entityElement, 1 /* Click */, event);
6067
+ this.triggerEvent(entityElement, 1 /* Click */, rawEvent);
5988
6068
  workaroundSelectionIssueForIE(this.editor);
5989
6069
  }
5990
- this.state.clickingPoint = null;
5991
6070
  };
5992
6071
  EntityPlugin.prototype.handleKeyDownEvent = function (event) {
5993
6072
  if (roosterjs_editor_dom_1.isCharacterValue(event) ||
5994
6073
  event.which == 8 /* BACKSPACE */ ||
5995
- event.which == 46 /* DELETE */) {
6074
+ event.which == 46 /* DELETE */ ||
6075
+ event.which == 13 /* ENTER */) {
5996
6076
  var range = this.editor.getSelectionRange();
5997
6077
  if (range && !range.collapsed) {
5998
6078
  this.checkRemoveEntityForRange(event);
5999
6079
  }
6000
6080
  }
6001
6081
  };
6002
- EntityPlugin.prototype.handleBeforePasteEvent = function (fragment, sanitizingOption) {
6082
+ EntityPlugin.prototype.handleBeforePasteEvent = function (sanitizingOption) {
6003
6083
  var range = this.editor.getSelectionRange();
6004
6084
  if (!range.collapsed) {
6005
6085
  this.checkRemoveEntityForRange(null /*rawEvent*/);
6006
6086
  }
6007
6087
  roosterjs_editor_dom_1.arrayPush(sanitizingOption.additionalAllowedCssClasses, ALLOWED_CSS_CLASSES);
6008
6088
  };
6009
- EntityPlugin.prototype.handleContentChangedEvent = function (resetAll) {
6089
+ EntityPlugin.prototype.handleBeforeSetContentEvent = function () {
6090
+ this.cacheShadowEntities(this.state.shadowEntityCache);
6091
+ };
6092
+ EntityPlugin.prototype.handleContentChangedEvent = function (event) {
6010
6093
  var _this = this;
6011
- this.state.knownEntityElements = resetAll
6012
- ? []
6013
- : this.state.knownEntityElements.filter(function (node) { return _this.editor.contains(node); });
6014
- var allId = this.state.knownEntityElements
6094
+ // 1. find removed entities
6095
+ for (var i = this.state.knownEntityElements.length - 1; i >= 0; i--) {
6096
+ var element = this.state.knownEntityElements[i];
6097
+ if (!this.editor.contains(element)) {
6098
+ this.setIsEntityKnown(element, false /*isKnown*/);
6099
+ if (element.shadowRoot) {
6100
+ this.triggerEvent(element, 10 /* RemoveShadowRoot */);
6101
+ }
6102
+ }
6103
+ }
6104
+ // 2. collect all new entities
6105
+ var knownIds = this.state.knownEntityElements
6015
6106
  .map(function (e) { var _a; return (_a = roosterjs_editor_dom_1.getEntityFromElement(e)) === null || _a === void 0 ? void 0 : _a.id; })
6016
6107
  .filter(function (x) { return !!x; });
6017
- this.editor.queryElements(roosterjs_editor_dom_1.getEntitySelector(), function (element) {
6018
- if (_this.state.knownEntityElements.indexOf(element) < 0) {
6019
- _this.state.knownEntityElements.push(element);
6020
- var entity = roosterjs_editor_dom_1.getEntityFromElement(element);
6021
- _this.hydrateEntity(entity, allId);
6022
- }
6108
+ var newEntities = (event === null || event === void 0 ? void 0 : event.source) == "InsertEntity" /* InsertEntity */ && event.data
6109
+ ? [event.data]
6110
+ : this.getExistingEntities().filter(function (_a) {
6111
+ var wrapper = _a.wrapper;
6112
+ return !_this.isEntityKnown(wrapper);
6113
+ });
6114
+ // 3. Add new entities to known entity list, and hydrate
6115
+ newEntities.forEach(function (entity) {
6116
+ var wrapper = entity.wrapper, type = entity.type, id = entity.id, isReadonly = entity.isReadonly;
6117
+ entity.id = _this.ensureUniqueId(type, id, knownIds);
6118
+ roosterjs_editor_dom_1.commitEntity(wrapper, type, isReadonly, entity.id); // Use entity.id here because it is newly updated
6119
+ _this.handleNewEntity(entity);
6120
+ });
6121
+ Object.keys(this.state.shadowEntityCache).forEach(function (id) {
6122
+ _this.triggerEvent(_this.state.shadowEntityCache[id], 6 /* Overwrite */);
6123
+ delete _this.state.shadowEntityCache[id];
6023
6124
  });
6024
6125
  };
6126
+ EntityPlugin.prototype.handleEntityOperationEvent = function (event) {
6127
+ var _this = this;
6128
+ var _a;
6129
+ if (REMOVE_ENTITY_OPERATIONS.indexOf(event.operation) >= 0) {
6130
+ (_a = this.cancelAsyncRun) === null || _a === void 0 ? void 0 : _a.call(this);
6131
+ this.cancelAsyncRun = this.editor.runAsync(function () {
6132
+ _this.cancelAsyncRun = null;
6133
+ _this.handleContentChangedEvent();
6134
+ });
6135
+ }
6136
+ };
6025
6137
  EntityPlugin.prototype.handleExtractContentWithDomEvent = function (root) {
6026
6138
  var _this = this;
6027
6139
  roosterjs_editor_dom_1.toArray(root.querySelectorAll(roosterjs_editor_dom_1.getEntitySelector())).forEach(function (element) {
@@ -6051,8 +6163,71 @@ var EntityPlugin = /** @class */ (function () {
6051
6163
  });
6052
6164
  }
6053
6165
  };
6054
- EntityPlugin.prototype.hydrateEntity = function (entity, knownIds) {
6055
- var id = entity.id, type = entity.type, wrapper = entity.wrapper, isReadonly = entity.isReadonly;
6166
+ EntityPlugin.prototype.triggerEvent = function (element, operation, rawEvent, contentForShadowEntity) {
6167
+ var entity = element && roosterjs_editor_dom_1.getEntityFromElement(element);
6168
+ if (entity) {
6169
+ this.editor.triggerPluginEvent(15 /* EntityOperation */, {
6170
+ operation: operation,
6171
+ rawEvent: rawEvent,
6172
+ entity: entity,
6173
+ contentForShadowEntity: contentForShadowEntity,
6174
+ });
6175
+ }
6176
+ };
6177
+ EntityPlugin.prototype.handleNewEntity = function (entity) {
6178
+ var wrapper = entity.wrapper;
6179
+ var fragment = this.editor.getDocument().createDocumentFragment();
6180
+ var cache = this.state.shadowEntityCache[entity.id];
6181
+ delete this.state.shadowEntityCache[entity.id];
6182
+ if (cache === null || cache === void 0 ? void 0 : cache.shadowRoot) {
6183
+ roosterjs_editor_dom_1.moveChildNodes(fragment, cache.shadowRoot);
6184
+ }
6185
+ this.triggerEvent(wrapper, 0 /* NewEntity */, undefined /*rawEvent*/, fragment);
6186
+ // If there is element to hydrate for shadow entity, craete shadow root and mount these elements to shadow root
6187
+ // Then trigger AddShadowRoot so that plugins can do further actions
6188
+ if (fragment.firstChild) {
6189
+ if (wrapper.shadowRoot) {
6190
+ roosterjs_editor_dom_1.moveChildNodes(wrapper.shadowRoot, fragment);
6191
+ }
6192
+ else {
6193
+ this.createShadowRoot(wrapper, fragment);
6194
+ }
6195
+ }
6196
+ else if (wrapper.shadowRoot) {
6197
+ // If no elements to hydrate, remove existing shadow root by cloning a new node
6198
+ this.triggerEvent(wrapper, 10 /* RemoveShadowRoot */);
6199
+ var newWrapper = wrapper.cloneNode();
6200
+ roosterjs_editor_dom_1.moveChildNodes(newWrapper, wrapper);
6201
+ this.editor.replaceNode(wrapper, newWrapper);
6202
+ entity.wrapper = newWrapper;
6203
+ }
6204
+ this.setIsEntityKnown(entity.wrapper, true /*isKnown*/);
6205
+ };
6206
+ EntityPlugin.prototype.getExistingEntities = function (shadowEntityOnly) {
6207
+ return this.editor
6208
+ .queryElements(roosterjs_editor_dom_1.getEntitySelector())
6209
+ .map(roosterjs_editor_dom_1.getEntityFromElement)
6210
+ .filter(function (x) { return !!x && (!shadowEntityOnly || !!x.wrapper.shadowRoot); });
6211
+ };
6212
+ EntityPlugin.prototype.createShadowRoot = function (wrapper, shadowContentContainer) {
6213
+ if (wrapper.attachShadow) {
6214
+ var shadowRoot = wrapper.attachShadow({
6215
+ mode: 'open',
6216
+ delegatesFocus: true,
6217
+ });
6218
+ wrapper.contentEditable = 'false';
6219
+ this.triggerEvent(wrapper, 9 /* AddShadowRoot */);
6220
+ roosterjs_editor_dom_1.moveChildNodes(shadowRoot, shadowContentContainer);
6221
+ return shadowRoot;
6222
+ }
6223
+ };
6224
+ EntityPlugin.prototype.cacheShadowEntities = function (cache) {
6225
+ this.getExistingEntities(true /*shadowEntityOnly*/).forEach(function (_a) {
6226
+ var wrapper = _a.wrapper, id = _a.id;
6227
+ cache[id] = wrapper;
6228
+ });
6229
+ };
6230
+ EntityPlugin.prototype.ensureUniqueId = function (type, id, knownIds) {
6056
6231
  var match = ENTITY_ID_REGEX.exec(id);
6057
6232
  var baseId = (match ? id.substr(0, id.length - match[0].length) : id) || type;
6058
6233
  // Make sure entity id is unique
@@ -6064,19 +6239,20 @@ var EntityPlugin = /** @class */ (function () {
6064
6239
  break;
6065
6240
  }
6066
6241
  }
6067
- roosterjs_editor_dom_1.commitEntity(wrapper, type, isReadonly, newId);
6068
- this.triggerEvent(wrapper, 0 /* NewEntity */);
6242
+ return newId;
6069
6243
  };
6070
- EntityPlugin.prototype.triggerEvent = function (element, operation, rawEvent) {
6071
- var entity = element && roosterjs_editor_dom_1.getEntityFromElement(element);
6072
- if (entity) {
6073
- this.editor.triggerPluginEvent(15 /* EntityOperation */, {
6074
- operation: operation,
6075
- rawEvent: rawEvent,
6076
- entity: entity,
6077
- });
6244
+ EntityPlugin.prototype.setIsEntityKnown = function (wrapper, isKnown) {
6245
+ var index = this.state.knownEntityElements.indexOf(wrapper);
6246
+ if (isKnown && index < 0) {
6247
+ this.state.knownEntityElements.push(wrapper);
6248
+ }
6249
+ else if (!isKnown && index >= 0) {
6250
+ this.state.knownEntityElements.splice(index, 1);
6078
6251
  }
6079
6252
  };
6253
+ EntityPlugin.prototype.isEntityKnown = function (wrapper) {
6254
+ return this.state.knownEntityElements.indexOf(wrapper) >= 0;
6255
+ };
6080
6256
  return EntityPlugin;
6081
6257
  }());
6082
6258
  exports.default = EntityPlugin;
@@ -6088,13 +6264,10 @@ var workaroundSelectionIssueForIE = roosterjs_editor_dom_1.Browser.isIE
6088
6264
  ? function (editor) {
6089
6265
  editor.runAsync(function (editor) {
6090
6266
  var workaroundButton = editor.getCustomData('ENTITY_IE_FOCUS_BUTTON', function () {
6091
- var button = editor.getDocument().createElement('button');
6092
- button.style.overflow = 'hidden';
6093
- button.style.position = 'fixed';
6094
- button.style.width = '0';
6095
- button.style.height = '0';
6096
- button.style.left = '0';
6097
- button.style.top = '-1000px';
6267
+ var button = roosterjs_editor_dom_1.createElement({
6268
+ tag: 'button',
6269
+ style: 'overflow:hidden;position:fixed;width:0;height:0;top:-1000px',
6270
+ }, editor.getDocument());
6098
6271
  button.onblur = function () {
6099
6272
  button.style.display = 'none';
6100
6273
  };
@@ -6104,13 +6277,7 @@ var workaroundSelectionIssueForIE = roosterjs_editor_dom_1.Browser.isIE
6104
6277
  return button;
6105
6278
  });
6106
6279
  workaroundButton.style.display = '';
6107
- var range = editor.getDocument().createRange();
6108
- range.setStart(workaroundButton, 0);
6109
- try {
6110
- window.getSelection().removeAllRanges();
6111
- window.getSelection().addRange(range);
6112
- }
6113
- catch (_a) { }
6280
+ roosterjs_editor_dom_1.addRangeToSelection(roosterjs_editor_dom_1.createRange(workaroundButton, 0));
6114
6281
  });
6115
6282
  }
6116
6283
  : function () { };
@@ -7313,15 +7480,19 @@ var Editor = /** @class */ (function () {
7313
7480
  /**
7314
7481
  * Run a callback function asynchronously
7315
7482
  * @param callback The callback function to run
7483
+ * @returns a function to cancel this async run
7316
7484
  */
7317
7485
  Editor.prototype.runAsync = function (callback) {
7318
7486
  var _this = this;
7319
7487
  var win = this.core.contentDiv.ownerDocument.defaultView || window;
7320
- win.requestAnimationFrame(function () {
7488
+ var handle = win.requestAnimationFrame(function () {
7321
7489
  if (!_this.isDisposed() && callback) {
7322
7490
  callback(_this);
7323
7491
  }
7324
7492
  });
7493
+ return function () {
7494
+ win.cancelAnimationFrame(handle);
7495
+ };
7325
7496
  };
7326
7497
  /**
7327
7498
  * Set DOM attribute of editor content DIV
@@ -9883,6 +10054,8 @@ exports.createElement = createElement_1.default;
9883
10054
  exports.KnownCreateElementData = createElement_1.KnownCreateElementData;
9884
10055
  var moveChildNodes_1 = __webpack_require__(/*! ./utils/moveChildNodes */ "./packages/roosterjs-editor-dom/lib/utils/moveChildNodes.ts");
9885
10056
  exports.moveChildNodes = moveChildNodes_1.default;
10057
+ var setListItemStyle_1 = __webpack_require__(/*! ./utils/setListItemStyle */ "./packages/roosterjs-editor-dom/lib/utils/setListItemStyle.ts");
10058
+ exports.setListItemStyle = setListItemStyle_1.default;
9886
10059
  var VTable_1 = __webpack_require__(/*! ./table/VTable */ "./packages/roosterjs-editor-dom/lib/table/VTable.ts");
9887
10060
  exports.VTable = VTable_1.default;
9888
10061
  var VList_1 = __webpack_require__(/*! ./list/VList */ "./packages/roosterjs-editor-dom/lib/list/VList.ts");
@@ -11054,6 +11227,7 @@ var getTagOfNode_1 = __webpack_require__(/*! ../utils/getTagOfNode */ "./package
11054
11227
  var isBlockElement_1 = __webpack_require__(/*! ../utils/isBlockElement */ "./packages/roosterjs-editor-dom/lib/utils/isBlockElement.ts");
11055
11228
  var moveChildNodes_1 = __webpack_require__(/*! ../utils/moveChildNodes */ "./packages/roosterjs-editor-dom/lib/utils/moveChildNodes.ts");
11056
11229
  var safeInstanceOf_1 = __webpack_require__(/*! ../utils/safeInstanceOf */ "./packages/roosterjs-editor-dom/lib/utils/safeInstanceOf.ts");
11230
+ var setListItemStyle_1 = __webpack_require__(/*! ../utils/setListItemStyle */ "./packages/roosterjs-editor-dom/lib/utils/setListItemStyle.ts");
11057
11231
  var toArray_1 = __webpack_require__(/*! ../utils/toArray */ "./packages/roosterjs-editor-dom/lib/utils/toArray.ts");
11058
11232
  var unwrap_1 = __webpack_require__(/*! ../utils/unwrap */ "./packages/roosterjs-editor-dom/lib/utils/unwrap.ts");
11059
11233
  var wrap_1 = __webpack_require__(/*! ../utils/wrap */ "./packages/roosterjs-editor-dom/lib/utils/wrap.ts");
@@ -11231,7 +11405,14 @@ var VListItem = /** @class */ (function () {
11231
11405
  // 3. Add current node into deepest list element
11232
11406
  listStack[listStack.length - 1].appendChild(this.node);
11233
11407
  this.node.style.display = this.dummy ? 'block' : null;
11234
- // 4. If this is not a list item now, need to unwrap the LI node and do proper handling
11408
+ // 4. Inherit styles of the childelement to the li, so we are able to apply the styles to the ::marker
11409
+ if (this.listTypes.length > 1) {
11410
+ if (!(this.node.style.fontSize || this.node.style.color || this.node.style.fontFamily)) {
11411
+ var stylesToInherit = ['font-size', 'font-family', 'color'];
11412
+ setListItemStyle_1.default(this.node, stylesToInherit);
11413
+ }
11414
+ }
11415
+ // 5. If this is not a list item now, need to unwrap the LI node and do proper handling
11235
11416
  if (this.listTypes.length <= 1) {
11236
11417
  wrapIfNotBlockNode(getTagOfNode_1.default(this.node) == 'LI' ? getChildrenAndUnwrap(this.node) : [this.node], true /*checkFirst*/, true /*checkLast*/);
11237
11418
  }
@@ -14991,6 +15172,65 @@ function setColor(element, color, isBackgroundColor, isDarkMode) {
14991
15172
  exports.default = setColor;
14992
15173
 
14993
15174
 
15175
+ /***/ }),
15176
+
15177
+ /***/ "./packages/roosterjs-editor-dom/lib/utils/setListItemStyle.ts":
15178
+ /*!*********************************************************************!*\
15179
+ !*** ./packages/roosterjs-editor-dom/lib/utils/setListItemStyle.ts ***!
15180
+ \*********************************************************************/
15181
+ /*! no static exports found */
15182
+ /***/ (function(module, exports, __webpack_require__) {
15183
+
15184
+ "use strict";
15185
+
15186
+ Object.defineProperty(exports, "__esModule", { value: true });
15187
+ var ContentTraverser_1 = __webpack_require__(/*! ../contentTraverser/ContentTraverser */ "./packages/roosterjs-editor-dom/lib/contentTraverser/ContentTraverser.ts");
15188
+ var findClosestElementAncestor_1 = __webpack_require__(/*! ./findClosestElementAncestor */ "./packages/roosterjs-editor-dom/lib/utils/findClosestElementAncestor.ts");
15189
+ var getStyles_1 = __webpack_require__(/*! ../style/getStyles */ "./packages/roosterjs-editor-dom/lib/style/getStyles.ts");
15190
+ var safeInstanceOf_1 = __webpack_require__(/*! ./safeInstanceOf */ "./packages/roosterjs-editor-dom/lib/utils/safeInstanceOf.ts");
15191
+ var setStyles_1 = __webpack_require__(/*! ../style/setStyles */ "./packages/roosterjs-editor-dom/lib/style/setStyles.ts");
15192
+ /**
15193
+ * Set the Style of a List Item provided, with the styles that the inline child elements have
15194
+ * If the child inline elements have different styles, it will not modify the styles of the list item
15195
+ * @param element the LI Element to set the styles
15196
+ * @param styles The styles that should be applied to the element.
15197
+ */
15198
+ function setListItemStyle(element, styles) {
15199
+ var elementsStyles = getInlineChildElementsStyle(element);
15200
+ var stylesToApply = getStyles_1.default(element);
15201
+ styles.forEach(function (styleName) {
15202
+ var styleValues = elementsStyles.map(function (style) {
15203
+ return style[styleName] !== undefined ? style[styleName] : '';
15204
+ });
15205
+ if (styleValues &&
15206
+ (styleValues.length == 1 || new Set(styleValues).size == 1) &&
15207
+ styleValues[0]) {
15208
+ stylesToApply[styleName] = styleValues[0];
15209
+ }
15210
+ });
15211
+ setStyles_1.default(element, stylesToApply);
15212
+ }
15213
+ exports.default = setListItemStyle;
15214
+ function getInlineChildElementsStyle(element) {
15215
+ var result = [];
15216
+ var contentTraverser = ContentTraverser_1.default.createBodyTraverser(element);
15217
+ var currentInlineElement;
15218
+ while (contentTraverser.currentInlineElement != currentInlineElement) {
15219
+ currentInlineElement = contentTraverser.currentInlineElement;
15220
+ var currentNode = currentInlineElement.getContainerNode();
15221
+ currentNode = findClosestElementAncestor_1.default(currentNode);
15222
+ if (safeInstanceOf_1.default(currentNode, 'HTMLElement')) {
15223
+ var childStyle = getStyles_1.default(currentNode);
15224
+ if (childStyle) {
15225
+ result.push(childStyle);
15226
+ }
15227
+ }
15228
+ contentTraverser.getNextInlineElement();
15229
+ }
15230
+ return result;
15231
+ }
15232
+
15233
+
14994
15234
  /***/ }),
14995
15235
 
14996
15236
  /***/ "./packages/roosterjs-editor-dom/lib/utils/shouldSkipNode.ts":
@@ -15906,6 +16146,7 @@ function cacheGetNeighborEntityElement(event, editor, isNext, collapseOnly, oper
15906
16146
  if (collapseOnly && !range.collapsed) {
15907
16147
  return null;
15908
16148
  }
16149
+ range.commonAncestorContainer.normalize();
15909
16150
  var pos = roosterjs_editor_dom_1.Position.getEnd(range).normalize();
15910
16151
  var isAtBeginOrEnd = pos.offset == 0 || pos.isAtEnd;
15911
16152
  var entityNode = null;
@@ -16087,27 +16328,29 @@ var AutoBullet = {
16087
16328
  editor.insertContent('&nbsp;');
16088
16329
  event.rawEvent.preventDefault();
16089
16330
  editor.addUndoSnapshot(function () {
16331
+ var _a;
16090
16332
  var regions;
16091
16333
  var searcher = editor.getContentSearcherOfCursor();
16092
16334
  var textBeforeCursor = searcher.getSubStringBefore(4);
16093
- var rangeToDelete = searcher.getRangeFromText(textBeforeCursor, true /*exactMatch*/);
16094
- if (!rangeToDelete) {
16335
+ var textRange = searcher.getRangeFromText(textBeforeCursor, true /*exactMatch*/);
16336
+ if (!textRange) {
16095
16337
  // no op if the range can't be found
16096
16338
  }
16097
16339
  else if (textBeforeCursor.indexOf('*') == 0 ||
16098
16340
  textBeforeCursor.indexOf('-') == 0) {
16099
- prepareAutoBullet(editor, rangeToDelete);
16341
+ prepareAutoBullet(editor, textRange);
16100
16342
  roosterjs_editor_api_1.toggleBullet(editor);
16101
16343
  }
16102
16344
  else if (isAListPattern(textBeforeCursor)) {
16103
- prepareAutoBullet(editor, rangeToDelete);
16345
+ prepareAutoBullet(editor, textRange);
16104
16346
  roosterjs_editor_api_1.toggleNumbering(editor);
16105
16347
  }
16106
16348
  else if ((regions = editor.getSelectedRegions()) && regions.length == 1) {
16107
16349
  var num = parseInt(textBeforeCursor);
16108
- prepareAutoBullet(editor, rangeToDelete);
16350
+ prepareAutoBullet(editor, textRange);
16109
16351
  roosterjs_editor_api_1.toggleNumbering(editor, num);
16110
16352
  }
16353
+ (_a = searcher.getRangeFromText(textBeforeCursor, true /*exactMatch*/)) === null || _a === void 0 ? void 0 : _a.deleteContents();
16111
16354
  }, null /*changeSource*/, true /*canUndoByBackspace*/);
16112
16355
  },
16113
16356
  };
@@ -16152,7 +16395,6 @@ function getCacheNextSibiling(event, editor) {
16152
16395
  return element;
16153
16396
  }
16154
16397
  function prepareAutoBullet(editor, range) {
16155
- range.deleteContents();
16156
16398
  var block = editor.getBlockElementAtNode(range.startContainer);
16157
16399
  var endNode = block === null || block === void 0 ? void 0 : block.getEndNode();
16158
16400
  if (endNode && roosterjs_editor_dom_1.getTagOfNode(endNode) != 'BR' && (block === null || block === void 0 ? void 0 : block.getTextContent().trim()) === '') {
@@ -17426,7 +17668,6 @@ var ImageEdit = /** @class */ (function () {
17426
17668
  var img = wrapper === null || wrapper === void 0 ? void 0 : wrapper.querySelector('img');
17427
17669
  if (img && parent) {
17428
17670
  img.style.position = '';
17429
- img.style.maxWidth = '100%';
17430
17671
  img.style.margin = null;
17431
17672
  img.style.textAlign = null;
17432
17673
  parent.insertBefore(img, wrapper);
@@ -17485,6 +17726,7 @@ var ImageEdit = /** @class */ (function () {
17485
17726
  if ((context === null || context === void 0 ? void 0 : context.elementClass) == "r_resizeH" /* ResizeHandle */) {
17486
17727
  var clientWidth = wrapper.clientWidth;
17487
17728
  var clientHeight = wrapper.clientHeight;
17729
+ _this.wasResized = true;
17488
17730
  Resizer_1.doubleCheckResize(_this.editInfo, _this.options.preserveRatio, clientWidth, clientHeight);
17489
17731
  _this.updateWrapper();
17490
17732
  }
@@ -17595,7 +17837,7 @@ var ImageEdit = /** @class */ (function () {
17595
17837
  // When there is image in editing, clean up any cached objects and elements
17596
17838
  this.clearDndHelpers();
17597
17839
  // Apply the changes, and add undo snapshot if necessary
17598
- if (applyChange_1.default(this.editor, this.image, this.editInfo, this.lastSrc)) {
17840
+ if (applyChange_1.default(this.editor, this.image, this.editInfo, this.lastSrc, this.wasResized)) {
17599
17841
  this.editor.addUndoSnapshot(function () { return _this.image; }, "ImageResize" /* ImageResize */);
17600
17842
  }
17601
17843
  // Remove editing wrapper
@@ -17616,6 +17858,8 @@ var ImageEdit = /** @class */ (function () {
17616
17858
  this.image = image;
17617
17859
  // Get initial edit info
17618
17860
  this.editInfo = editInfo_1.getEditInfoFromImage(image);
17861
+ //Check if the image was resized by the user
17862
+ this.wasResized = checkIfImageWasResized(this.image);
17619
17863
  operation =
17620
17864
  (canRegenerateImage_1.default(image) ? operation : 3 /* Resize */) &
17621
17865
  this.allowedOperations;
@@ -17748,6 +17992,28 @@ function updateHandleCursor(handles, angleRad) {
17748
17992
  handle.style.cursor = rotateHandles(handle, angleRad) + "-resize";
17749
17993
  });
17750
17994
  }
17995
+ /**
17996
+ * Check if the current image was resized by the user
17997
+ * @param image the current image
17998
+ * @returns if the user resized the image, returns true, otherwise, returns false
17999
+ */
18000
+ function checkIfImageWasResized(image) {
18001
+ var width = image.width, height = image.height, style = image.style;
18002
+ if (style.maxWidth === 'initial' &&
18003
+ (isFixedNumberValue(style.height) ||
18004
+ isFixedNumberValue(style.width) ||
18005
+ isFixedNumberValue(width) ||
18006
+ isFixedNumberValue(height))) {
18007
+ return true;
18008
+ }
18009
+ else {
18010
+ return false;
18011
+ }
18012
+ }
18013
+ function isFixedNumberValue(value) {
18014
+ var numberValue = typeof value === 'string' ? parseInt(value) : value;
18015
+ return !isNaN(numberValue);
18016
+ }
17751
18017
 
17752
18018
 
17753
18019
  /***/ }),
@@ -17882,7 +18148,7 @@ function resizeByPercentage(editor, image, percentage, minWidth, minHeight) {
17882
18148
  editInfo.widthPx = Math.max(width, minWidth);
17883
18149
  editInfo.heightPx = Math.max(height, minHeight);
17884
18150
  editor.addUndoSnapshot(function () {
17885
- applyChange_1.default(editor, image, editInfo, lastSrc_1);
18151
+ applyChange_1.default(editor, image, editInfo, lastSrc_1, true /*wasResized*/);
17886
18152
  }, "ImageResize" /* ImageResize */);
17887
18153
  }
17888
18154
  });
@@ -17929,7 +18195,7 @@ var editInfo_1 = __webpack_require__(/*! ./editInfo */ "./packages/roosterjs-edi
17929
18195
  * @param previousSrc Last src value of the image before the change was made
17930
18196
  * @returns True if the image is changed, otherwise false
17931
18197
  */
17932
- function applyChange(editor, image, editInfo, previousSrc) {
18198
+ function applyChange(editor, image, editInfo, previousSrc, wasResized) {
17933
18199
  var newSrc = '';
17934
18200
  var initEditInfo = editInfo_1.getEditInfoFromImage(image);
17935
18201
  var state = checkEditInfoState_1.default(editInfo, initEditInfo);
@@ -17973,15 +18239,32 @@ function applyChange(editor, image, editInfo, previousSrc) {
17973
18239
  // Write back the change to image, and set its new size
17974
18240
  var _a = getGeneratedImageSize_1.default(editInfo), targetWidth = _a.targetWidth, targetHeight = _a.targetHeight;
17975
18241
  image.src = newSrc;
17976
- image.style.width = targetWidth + 'px';
17977
- image.style.height = targetHeight + 'px';
17978
- image.width = targetWidth;
17979
- image.height = targetHeight;
18242
+ setImageSize(image, wasResized, targetWidth, targetHeight);
17980
18243
  return (srcChanged ||
17981
18244
  editInfo.widthPx != initEditInfo.widthPx ||
17982
18245
  editInfo.heightPx != initEditInfo.heightPx);
17983
18246
  }
17984
18247
  exports.default = applyChange;
18248
+ /**
18249
+ * @param img The current image.
18250
+ * @param wasResized the current resize state of the image
18251
+ */
18252
+ function setImageSize(image, wasResized, targetWidth, targetHeight) {
18253
+ if (wasResized) {
18254
+ image.style.maxWidth = 'initial';
18255
+ image.width = targetWidth;
18256
+ image.height = targetHeight;
18257
+ image.style.width = targetWidth + 'px';
18258
+ image.style.height = targetHeight + 'px';
18259
+ }
18260
+ else {
18261
+ image.style.maxWidth = '100%';
18262
+ image.style.height = 'initial';
18263
+ image.style.width = 'initial';
18264
+ image.removeAttribute('height');
18265
+ image.removeAttribute('width');
18266
+ }
18267
+ }
17985
18268
 
17986
18269
 
17987
18270
  /***/ }),