roosterjs-content-model-plugins 9.34.0 → 9.35.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.
Files changed (40) hide show
  1. package/lib/autoFormat/link/createLink.js +1 -2
  2. package/lib/autoFormat/link/createLink.js.map +1 -1
  3. package/lib/edit/deleteSteps/deleteParagraphStyle.js +20 -5
  4. package/lib/edit/deleteSteps/deleteParagraphStyle.js.map +1 -1
  5. package/lib/edit/handleKeyboardEventCommon.js +17 -0
  6. package/lib/edit/handleKeyboardEventCommon.js.map +1 -1
  7. package/lib/imageEdit/ImageEditPlugin.js +7 -2
  8. package/lib/imageEdit/ImageEditPlugin.js.map +1 -1
  9. package/lib/imageEdit/utils/applyChange.d.ts +2 -1
  10. package/lib/imageEdit/utils/applyChange.js +7 -7
  11. package/lib/imageEdit/utils/applyChange.js.map +1 -1
  12. package/lib/imageEdit/utils/checkEditInfoState.js +1 -2
  13. package/lib/imageEdit/utils/checkEditInfoState.js.map +1 -1
  14. package/lib-amd/autoFormat/link/createLink.js +1 -2
  15. package/lib-amd/autoFormat/link/createLink.js.map +1 -1
  16. package/lib-amd/edit/deleteSteps/deleteParagraphStyle.js +20 -6
  17. package/lib-amd/edit/deleteSteps/deleteParagraphStyle.js.map +1 -1
  18. package/lib-amd/edit/handleKeyboardEventCommon.js +17 -0
  19. package/lib-amd/edit/handleKeyboardEventCommon.js.map +1 -1
  20. package/lib-amd/imageEdit/ImageEditPlugin.js +7 -2
  21. package/lib-amd/imageEdit/ImageEditPlugin.js.map +1 -1
  22. package/lib-amd/imageEdit/utils/applyChange.d.ts +2 -1
  23. package/lib-amd/imageEdit/utils/applyChange.js +7 -7
  24. package/lib-amd/imageEdit/utils/applyChange.js.map +1 -1
  25. package/lib-amd/imageEdit/utils/checkEditInfoState.js +1 -2
  26. package/lib-amd/imageEdit/utils/checkEditInfoState.js.map +1 -1
  27. package/lib-mjs/autoFormat/link/createLink.js +1 -2
  28. package/lib-mjs/autoFormat/link/createLink.js.map +1 -1
  29. package/lib-mjs/edit/deleteSteps/deleteParagraphStyle.js +20 -5
  30. package/lib-mjs/edit/deleteSteps/deleteParagraphStyle.js.map +1 -1
  31. package/lib-mjs/edit/handleKeyboardEventCommon.js +18 -1
  32. package/lib-mjs/edit/handleKeyboardEventCommon.js.map +1 -1
  33. package/lib-mjs/imageEdit/ImageEditPlugin.js +7 -2
  34. package/lib-mjs/imageEdit/ImageEditPlugin.js.map +1 -1
  35. package/lib-mjs/imageEdit/utils/applyChange.d.ts +2 -1
  36. package/lib-mjs/imageEdit/utils/applyChange.js +7 -7
  37. package/lib-mjs/imageEdit/utils/applyChange.js.map +1 -1
  38. package/lib-mjs/imageEdit/utils/checkEditInfoState.js +1 -2
  39. package/lib-mjs/imageEdit/utils/checkEditInfoState.js.map +1 -1
  40. package/package.json +5 -5
@@ -12,8 +12,7 @@ function createLink(editor, autoLinkOptions) {
12
12
  (0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(editor, function (_model, segment, paragraph) {
13
13
  var promotedSegment = null;
14
14
  if (segment.link) {
15
- links.push(segment.link);
16
- return true;
15
+ return false;
17
16
  }
18
17
  else if ((promotedSegment = (0, roosterjs_content_model_api_1.promoteLink)(segment, paragraph, autoLinkOptions)) &&
19
18
  promotedSegment.link) {
@@ -1 +1 @@
1
- {"version":3,"file":"createLink.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/link/createLink.ts"],"names":[],"mappings":";;;AAAA,2EAA2D;AAC3D,2EAAkG;AAQlG;;GAEG;AACH,SAAgB,UAAU,CAAC,MAAe,EAAE,eAAgC;IACxE,IAAI,UAAU,GAAgB,IAAI,CAAC;IACnC,IAAM,KAAK,GAAuB,EAAE,CAAC;IAErC,IAAA,oEAAsC,EAClC,MAAM,EACN,UAAC,MAAM,EAAE,OAAO,EAAE,SAAS;QACvB,IAAI,eAAe,GAA4B,IAAI,CAAC;QAEpD,IAAI,OAAO,CAAC,IAAI,EAAE;YACd,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAEzB,OAAO,IAAI,CAAC;SACf;aAAM,IACH,CAAC,eAAe,GAAG,IAAA,yCAAW,EAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;YACpE,eAAe,CAAC,IAAI,EACtB;YACE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAEjC,OAAO,IAAI,CAAC;SACf;aAAM;YACH,OAAO,KAAK,CAAC;SAChB;IACL,CAAC,EACD;QACI,YAAY,EAAE,0CAAY,CAAC,QAAQ;QACnC,aAAa,EAAE,UAAC,YAAY,EAAE,IAAI;YAC9B,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,YAAgC,CAAC,IAAI,CAAC,EAAE;gBACrE,UAAU,GAAG,IAAI,CAAC;aACrB;QACL,CAAC;QACD,aAAa,EAAE,cAAM,OAAA,UAAU,EAAV,CAAU;KAClC,CACJ,CAAC;AACN,CAAC;AAlCD,gCAkCC","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { formatTextSegmentBeforeSelectionMarker, promoteLink } from 'roosterjs-content-model-api';\nimport type {\n ContentModelLink,\n IEditor,\n ContentModelText,\n AutoLinkOptions,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function createLink(editor: IEditor, autoLinkOptions: AutoLinkOptions) {\n let anchorNode: Node | null = null;\n const links: ContentModelLink[] = [];\n\n formatTextSegmentBeforeSelectionMarker(\n editor,\n (_model, segment, paragraph) => {\n let promotedSegment: ContentModelText | null = null;\n\n if (segment.link) {\n links.push(segment.link);\n\n return true;\n } else if (\n (promotedSegment = promoteLink(segment, paragraph, autoLinkOptions)) &&\n promotedSegment.link\n ) {\n links.push(promotedSegment.link);\n\n return true;\n } else {\n return false;\n }\n },\n {\n changeSource: ChangeSource.AutoLink,\n onNodeCreated: (modelElement, node) => {\n if (!anchorNode && links.indexOf(modelElement as ContentModelLink) >= 0) {\n anchorNode = node;\n }\n },\n getChangeData: () => anchorNode,\n }\n );\n}\n"]}
1
+ {"version":3,"file":"createLink.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/link/createLink.ts"],"names":[],"mappings":";;;AAAA,2EAA2D;AAC3D,2EAAkG;AAQlG;;GAEG;AACH,SAAgB,UAAU,CAAC,MAAe,EAAE,eAAgC;IACxE,IAAI,UAAU,GAAgB,IAAI,CAAC;IACnC,IAAM,KAAK,GAAuB,EAAE,CAAC;IAErC,IAAA,oEAAsC,EAClC,MAAM,EACN,UAAC,MAAM,EAAE,OAAO,EAAE,SAAS;QACvB,IAAI,eAAe,GAA4B,IAAI,CAAC;QAEpD,IAAI,OAAO,CAAC,IAAI,EAAE;YACd,OAAO,KAAK,CAAC;SAChB;aAAM,IACH,CAAC,eAAe,GAAG,IAAA,yCAAW,EAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;YACpE,eAAe,CAAC,IAAI,EACtB;YACE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAEjC,OAAO,IAAI,CAAC;SACf;aAAM;YACH,OAAO,KAAK,CAAC;SAChB;IACL,CAAC,EACD;QACI,YAAY,EAAE,0CAAY,CAAC,QAAQ;QACnC,aAAa,EAAE,UAAC,YAAY,EAAE,IAAI;YAC9B,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,YAAgC,CAAC,IAAI,CAAC,EAAE;gBACrE,UAAU,GAAG,IAAI,CAAC;aACrB;QACL,CAAC;QACD,aAAa,EAAE,cAAM,OAAA,UAAU,EAAV,CAAU;KAClC,CACJ,CAAC;AACN,CAAC;AAhCD,gCAgCC","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { formatTextSegmentBeforeSelectionMarker, promoteLink } from 'roosterjs-content-model-api';\nimport type {\n ContentModelLink,\n IEditor,\n ContentModelText,\n AutoLinkOptions,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function createLink(editor: IEditor, autoLinkOptions: AutoLinkOptions) {\n let anchorNode: Node | null = null;\n const links: ContentModelLink[] = [];\n\n formatTextSegmentBeforeSelectionMarker(\n editor,\n (_model, segment, paragraph) => {\n let promotedSegment: ContentModelText | null = null;\n\n if (segment.link) {\n return false;\n } else if (\n (promotedSegment = promoteLink(segment, paragraph, autoLinkOptions)) &&\n promotedSegment.link\n ) {\n links.push(promotedSegment.link);\n\n return true;\n } else {\n return false;\n }\n },\n {\n changeSource: ChangeSource.AutoLink,\n onNodeCreated: (modelElement, node) => {\n if (!anchorNode && links.indexOf(modelElement as ContentModelLink) >= 0) {\n anchorNode = node;\n }\n },\n getChangeData: () => anchorNode,\n }\n );\n}\n"]}
@@ -1,20 +1,35 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.deleteParagraphStyle = void 0;
4
+ var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
4
5
  /**
5
6
  * @internal
6
7
  */
7
8
  var deleteParagraphStyle = function (context) {
8
9
  if (context.deleteResult === 'nothingToDelete') {
9
10
  var insertPoint = context.insertPoint;
10
- var paragraph = insertPoint.paragraph;
11
+ var paragraph = insertPoint.paragraph, path = insertPoint.path;
12
+ var group = path[0];
13
+ var parentGroup = path[1];
11
14
  // If the paragraph is empty, we will delete any style in it
12
15
  // This is to ensure the paragraph style is reset to default when there is no content in the paragraph
13
16
  if (paragraph.segments.every(function (s) { return s.segmentType === 'SelectionMarker' || s.segmentType === 'Br'; }) &&
14
- paragraph.segments.filter(function (s) { return s.segmentType === 'Br'; }).length <= 1 &&
15
- Object.keys(paragraph.format).length > 0) {
16
- paragraph.format = {};
17
- context.deleteResult = 'range';
17
+ paragraph.segments.filter(function (s) { return s.segmentType === 'Br'; }).length <= 1) {
18
+ if (Object.keys(paragraph.format).length > 0) {
19
+ paragraph.format = {};
20
+ context.deleteResult = 'range';
21
+ }
22
+ else if (group.blocks.length == 1 &&
23
+ group.blocks[0] == paragraph &&
24
+ parentGroup &&
25
+ (group.blockGroupType == 'FormatContainer' ||
26
+ group.blockGroupType == 'ListItem' ||
27
+ group.blockGroupType == 'General')) {
28
+ // Still has nothing to delete, try to unwrap parent container
29
+ (0, roosterjs_content_model_dom_1.unwrapBlock)(parentGroup, group);
30
+ path.shift();
31
+ context.deleteResult = 'range';
32
+ }
18
33
  }
19
34
  }
20
35
  };
@@ -1 +1 @@
1
- {"version":3,"file":"deleteParagraphStyle.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteParagraphStyle.ts"],"names":[],"mappings":";;;AAEA;;GAEG;AACI,IAAM,oBAAoB,GAAwB,UAAA,OAAO;IAC5D,IAAI,OAAO,CAAC,YAAY,KAAK,iBAAiB,EAAE;QACpC,IAAA,WAAW,GAAK,OAAO,YAAZ,CAAa;QACxB,IAAA,SAAS,GAAK,WAAW,UAAhB,CAAiB;QAElC,4DAA4D;QAC5D,sGAAsG;QACtG,IACI,SAAS,CAAC,QAAQ,CAAC,KAAK,CACpB,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,WAAW,KAAK,iBAAiB,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI,EAA7D,CAA6D,CACrE;YACD,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,WAAW,KAAK,IAAI,EAAtB,CAAsB,CAAC,CAAC,MAAM,IAAI,CAAC;YAClE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAC1C;YACE,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC;YACtB,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC;SAClC;KACJ;AACL,CAAC,CAAC;AAlBW,QAAA,oBAAoB,wBAkB/B","sourcesContent":["import type { DeleteSelectionStep } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport const deleteParagraphStyle: DeleteSelectionStep = context => {\n if (context.deleteResult === 'nothingToDelete') {\n const { insertPoint } = context;\n const { paragraph } = insertPoint;\n\n // If the paragraph is empty, we will delete any style in it\n // This is to ensure the paragraph style is reset to default when there is no content in the paragraph\n if (\n paragraph.segments.every(\n s => s.segmentType === 'SelectionMarker' || s.segmentType === 'Br'\n ) &&\n paragraph.segments.filter(s => s.segmentType === 'Br').length <= 1 &&\n Object.keys(paragraph.format).length > 0\n ) {\n paragraph.format = {};\n context.deleteResult = 'range';\n }\n }\n};\n"]}
1
+ {"version":3,"file":"deleteParagraphStyle.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/edit/deleteSteps/deleteParagraphStyle.ts"],"names":[],"mappings":";;;AAAA,2EAA0D;AAG1D;;GAEG;AACI,IAAM,oBAAoB,GAAwB,UAAA,OAAO;IAC5D,IAAI,OAAO,CAAC,YAAY,KAAK,iBAAiB,EAAE;QACpC,IAAA,WAAW,GAAK,OAAO,YAAZ,CAAa;QACxB,IAAA,SAAS,GAAW,WAAW,UAAtB,EAAE,IAAI,GAAK,WAAW,KAAhB,CAAiB;QACxC,IAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACtB,IAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAE5B,4DAA4D;QAC5D,sGAAsG;QACtG,IACI,SAAS,CAAC,QAAQ,CAAC,KAAK,CACpB,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,WAAW,KAAK,iBAAiB,IAAI,CAAC,CAAC,WAAW,KAAK,IAAI,EAA7D,CAA6D,CACrE;YACD,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,UAAA,CAAC,IAAI,OAAA,CAAC,CAAC,WAAW,KAAK,IAAI,EAAtB,CAAsB,CAAC,CAAC,MAAM,IAAI,CAAC,EACpE;YACE,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE;gBAC1C,SAAS,CAAC,MAAM,GAAG,EAAE,CAAC;gBACtB,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC;aAClC;iBAAM,IACH,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC;gBACxB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,SAAS;gBAC5B,WAAW;gBACX,CAAC,KAAK,CAAC,cAAc,IAAI,iBAAiB;oBACtC,KAAK,CAAC,cAAc,IAAI,UAAU;oBAClC,KAAK,CAAC,cAAc,IAAI,SAAS,CAAC,EACxC;gBACE,8DAA8D;gBAC9D,IAAA,yCAAW,EAAC,WAAW,EAAE,KAAK,CAAC,CAAC;gBAEhC,IAAI,CAAC,KAAK,EAAE,CAAC;gBACb,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC;aAClC;SACJ;KACJ;AACL,CAAC,CAAC;AAlCW,QAAA,oBAAoB,wBAkC/B","sourcesContent":["import { unwrapBlock } from 'roosterjs-content-model-dom';\nimport type { DeleteSelectionStep } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport const deleteParagraphStyle: DeleteSelectionStep = context => {\n if (context.deleteResult === 'nothingToDelete') {\n const { insertPoint } = context;\n const { paragraph, path } = insertPoint;\n const group = path[0];\n const parentGroup = path[1];\n\n // If the paragraph is empty, we will delete any style in it\n // This is to ensure the paragraph style is reset to default when there is no content in the paragraph\n if (\n paragraph.segments.every(\n s => s.segmentType === 'SelectionMarker' || s.segmentType === 'Br'\n ) &&\n paragraph.segments.filter(s => s.segmentType === 'Br').length <= 1\n ) {\n if (Object.keys(paragraph.format).length > 0) {\n paragraph.format = {};\n context.deleteResult = 'range';\n } else if (\n group.blocks.length == 1 &&\n group.blocks[0] == paragraph &&\n parentGroup &&\n (group.blockGroupType == 'FormatContainer' ||\n group.blockGroupType == 'ListItem' ||\n group.blockGroupType == 'General')\n ) {\n // Still has nothing to delete, try to unwrap parent container\n unwrapBlock(parentGroup, group);\n\n path.shift();\n context.deleteResult = 'range';\n }\n }\n }\n};\n"]}
@@ -24,6 +24,7 @@ function handleKeyboardEventResult(editor, model, rawEvent, result, context) {
24
24
  // We have deleted what we need from content model, no need to let browser keep handling the event
25
25
  rawEvent.preventDefault();
26
26
  (0, roosterjs_content_model_dom_1.normalizeContentModel)(model);
27
+ deleteEmptyBlockGroups(model);
27
28
  if (result == 'range') {
28
29
  // A range is about to be deleted, so add an undo snapshot immediately
29
30
  context.skipUndoSnapshot = false;
@@ -52,4 +53,20 @@ function shouldDeleteAllSegmentsBefore(rawEvent) {
52
53
  return rawEvent.metaKey && !rawEvent.altKey;
53
54
  }
54
55
  exports.shouldDeleteAllSegmentsBefore = shouldDeleteAllSegmentsBefore;
56
+ function deleteEmptyBlockGroups(group) {
57
+ var modified = false;
58
+ for (var i = group.blocks.length - 1; i >= 0; i--) {
59
+ var block = group.blocks[i];
60
+ if (block.blockType == 'BlockGroup') {
61
+ deleteEmptyBlockGroups(block);
62
+ if (block.blocks.length == 0) {
63
+ (0, roosterjs_content_model_dom_1.mutateBlock)(group).blocks.splice(i, 1);
64
+ modified = true;
65
+ }
66
+ }
67
+ }
68
+ if (modified) {
69
+ group.blocks.forEach(roosterjs_content_model_dom_1.setParagraphNotImplicit);
70
+ }
71
+ }
55
72
  //# sourceMappingURL=handleKeyboardEventCommon.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"handleKeyboardEventCommon.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/handleKeyboardEventCommon.ts"],"names":[],"mappings":";;;AAAA,2EAAoE;AAQpE;;;GAGG;AACH,SAAgB,yBAAyB,CACrC,MAAe,EACf,KAAmC,EACnC,QAAuB,EACvB,MAAoB,EACpB,OAAkC;IAElC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC;IAEhC,QAAQ,MAAM,EAAE;QACZ,KAAK,YAAY;YACb,kHAAkH;YAClH,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;YAE/B,6GAA6G;YAC7G,OAAO,KAAK,CAAC;QAEjB,KAAK,iBAAiB;YAClB,sFAAsF;YACtF,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC;QAEjB,KAAK,OAAO,CAAC;QACb,KAAK,YAAY;YACb,kGAAkG;YAClG,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,IAAA,mDAAqB,EAAC,KAAK,CAAC,CAAC;YAE7B,IAAI,MAAM,IAAI,OAAO,EAAE;gBACnB,sEAAsE;gBACtE,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC;aACpC;YAED,6GAA6G;YAC7G,oHAAoH;YACpH,MAAM,CAAC,YAAY,CAAC,uBAAuB,EAAE;gBACzC,QAAQ,UAAA;aACX,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;KACnB;AACL,CAAC;AA1CD,8DA0CC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,QAAuB,EAAE,KAAc;IACpE,OAAO,CACH,CAAC,KAAK,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC/C,CAAC,CAAC,KAAK,IAAI,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CACnD,CAAC;AACN,CAAC;AALD,4CAKC;AAED;;GAEG;AACH,SAAgB,6BAA6B,CAAC,QAAuB;IACjE,OAAO,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAChD,CAAC;AAFD,sEAEC","sourcesContent":["import { normalizeContentModel } from 'roosterjs-content-model-dom';\nimport type {\n DeleteResult,\n FormatContentModelContext,\n IEditor,\n ReadonlyContentModelDocument,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * @return True means content is changed, so need to rewrite content model to editor. Otherwise false\n */\nexport function handleKeyboardEventResult(\n editor: IEditor,\n model: ReadonlyContentModelDocument,\n rawEvent: KeyboardEvent,\n result: DeleteResult,\n context: FormatContentModelContext\n): boolean {\n context.skipUndoSnapshot = true;\n context.clearModelCache = false;\n\n switch (result) {\n case 'notDeleted':\n // We have not delete anything, we will let browser handle this event, so that current cached model may be invalid\n context.clearModelCache = true;\n\n // Return false here since we didn't do any change to Content Model, so no need to rewrite with Content Model\n return false;\n\n case 'nothingToDelete':\n // We known there is nothing to delete, no need to let browser keep handling the event\n rawEvent.preventDefault();\n return false;\n\n case 'range':\n case 'singleChar':\n // We have deleted what we need from content model, no need to let browser keep handling the event\n rawEvent.preventDefault();\n normalizeContentModel(model);\n\n if (result == 'range') {\n // A range is about to be deleted, so add an undo snapshot immediately\n context.skipUndoSnapshot = false;\n }\n\n // Trigger an event to let plugins know the content is about to be changed by Content Model keyboard editing.\n // So plugins can do proper handling. e.g. UndoPlugin can decide whether take a snapshot before this change happens.\n editor.triggerEvent('beforeKeyboardEditing', {\n rawEvent,\n });\n\n return true;\n }\n}\n\n/**\n * @internal\n */\nexport function shouldDeleteWord(rawEvent: KeyboardEvent, isMac: boolean) {\n return (\n (isMac && rawEvent.altKey && !rawEvent.metaKey) ||\n (!isMac && rawEvent.ctrlKey && !rawEvent.altKey)\n );\n}\n\n/**\n * @internal\n */\nexport function shouldDeleteAllSegmentsBefore(rawEvent: KeyboardEvent) {\n return rawEvent.metaKey && !rawEvent.altKey;\n}\n"]}
1
+ {"version":3,"file":"handleKeyboardEventCommon.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/edit/handleKeyboardEventCommon.ts"],"names":[],"mappings":";;;AAAA,2EAIqC;AASrC;;;GAGG;AACH,SAAgB,yBAAyB,CACrC,MAAe,EACf,KAAmC,EACnC,QAAuB,EACvB,MAAoB,EACpB,OAAkC;IAElC,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;IAChC,OAAO,CAAC,eAAe,GAAG,KAAK,CAAC;IAEhC,QAAQ,MAAM,EAAE;QACZ,KAAK,YAAY;YACb,kHAAkH;YAClH,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC;YAE/B,6GAA6G;YAC7G,OAAO,KAAK,CAAC;QAEjB,KAAK,iBAAiB;YAClB,sFAAsF;YACtF,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC;QAEjB,KAAK,OAAO,CAAC;QACb,KAAK,YAAY;YACb,kGAAkG;YAClG,QAAQ,CAAC,cAAc,EAAE,CAAC;YAC1B,IAAA,mDAAqB,EAAC,KAAK,CAAC,CAAC;YAC7B,sBAAsB,CAAC,KAAK,CAAC,CAAC;YAE9B,IAAI,MAAM,IAAI,OAAO,EAAE;gBACnB,sEAAsE;gBACtE,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC;aACpC;YAED,6GAA6G;YAC7G,oHAAoH;YACpH,MAAM,CAAC,YAAY,CAAC,uBAAuB,EAAE;gBACzC,QAAQ,UAAA;aACX,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;KACnB;AACL,CAAC;AA3CD,8DA2CC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,QAAuB,EAAE,KAAc;IACpE,OAAO,CACH,CAAC,KAAK,IAAI,QAAQ,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;QAC/C,CAAC,CAAC,KAAK,IAAI,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CACnD,CAAC;AACN,CAAC;AALD,4CAKC;AAED;;GAEG;AACH,SAAgB,6BAA6B,CAAC,QAAuB;IACjE,OAAO,QAAQ,CAAC,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;AAChD,CAAC;AAFD,sEAEC;AAED,SAAS,sBAAsB,CAAC,KAAqC;IACjE,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;QAC/C,IAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAE9B,IAAI,KAAK,CAAC,SAAS,IAAI,YAAY,EAAE;YACjC,sBAAsB,CAAC,KAAK,CAAC,CAAC;YAE9B,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE;gBAC1B,IAAA,yCAAW,EAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACvC,QAAQ,GAAG,IAAI,CAAC;aACnB;SACJ;KACJ;IAED,IAAI,QAAQ,EAAE;QACV,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,qDAAuB,CAAC,CAAC;KACjD;AACL,CAAC","sourcesContent":["import {\n mutateBlock,\n normalizeContentModel,\n setParagraphNotImplicit,\n} from 'roosterjs-content-model-dom';\nimport type {\n DeleteResult,\n FormatContentModelContext,\n IEditor,\n ReadonlyContentModelBlockGroup,\n ReadonlyContentModelDocument,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * @return True means content is changed, so need to rewrite content model to editor. Otherwise false\n */\nexport function handleKeyboardEventResult(\n editor: IEditor,\n model: ReadonlyContentModelDocument,\n rawEvent: KeyboardEvent,\n result: DeleteResult,\n context: FormatContentModelContext\n): boolean {\n context.skipUndoSnapshot = true;\n context.clearModelCache = false;\n\n switch (result) {\n case 'notDeleted':\n // We have not delete anything, we will let browser handle this event, so that current cached model may be invalid\n context.clearModelCache = true;\n\n // Return false here since we didn't do any change to Content Model, so no need to rewrite with Content Model\n return false;\n\n case 'nothingToDelete':\n // We known there is nothing to delete, no need to let browser keep handling the event\n rawEvent.preventDefault();\n return false;\n\n case 'range':\n case 'singleChar':\n // We have deleted what we need from content model, no need to let browser keep handling the event\n rawEvent.preventDefault();\n normalizeContentModel(model);\n deleteEmptyBlockGroups(model);\n\n if (result == 'range') {\n // A range is about to be deleted, so add an undo snapshot immediately\n context.skipUndoSnapshot = false;\n }\n\n // Trigger an event to let plugins know the content is about to be changed by Content Model keyboard editing.\n // So plugins can do proper handling. e.g. UndoPlugin can decide whether take a snapshot before this change happens.\n editor.triggerEvent('beforeKeyboardEditing', {\n rawEvent,\n });\n\n return true;\n }\n}\n\n/**\n * @internal\n */\nexport function shouldDeleteWord(rawEvent: KeyboardEvent, isMac: boolean) {\n return (\n (isMac && rawEvent.altKey && !rawEvent.metaKey) ||\n (!isMac && rawEvent.ctrlKey && !rawEvent.altKey)\n );\n}\n\n/**\n * @internal\n */\nexport function shouldDeleteAllSegmentsBefore(rawEvent: KeyboardEvent) {\n return rawEvent.metaKey && !rawEvent.altKey;\n}\n\nfunction deleteEmptyBlockGroups(group: ReadonlyContentModelBlockGroup) {\n let modified = false;\n\n for (let i = group.blocks.length - 1; i >= 0; i--) {\n const block = group.blocks[i];\n\n if (block.blockType == 'BlockGroup') {\n deleteEmptyBlockGroups(block);\n\n if (block.blocks.length == 0) {\n mutateBlock(group).blocks.splice(i, 1);\n modified = true;\n }\n }\n }\n\n if (modified) {\n group.blocks.forEach(setParagraphNotImplicit);\n }\n}\n"]}
@@ -267,12 +267,14 @@ var ImageEditPlugin = /** @class */ (function () {
267
267
  var _this = this;
268
268
  var editingImageModel;
269
269
  var selection = editor.getDOMSelection();
270
- editor.formatContentModel(function (model) {
270
+ editor.formatContentModel(function (model, context) {
271
271
  var editingImage = (0, getSelectedImage_1.getSelectedImage)(model);
272
272
  var previousSelectedImage = isApiOperation
273
273
  ? editingImage
274
274
  : (0, findEditingImage_1.findEditingImage)(model);
275
275
  var result = false;
276
+ // Skip adding undo snapshot for now. If we detect any changes later, we will reset it
277
+ context.skipUndoSnapshot = 'SkipAll';
276
278
  if (shouldSelectImage ||
277
279
  (previousSelectedImage === null || previousSelectedImage === void 0 ? void 0 : previousSelectedImage.image) != (editingImage === null || editingImage === void 0 ? void 0 : editingImage.image) ||
278
280
  (previousSelectedImage === null || previousSelectedImage === void 0 ? void 0 : previousSelectedImage.image.format.imageState) == findEditingImage_1.EDITING_MARKER ||
@@ -285,7 +287,10 @@ var ImageEditPlugin = /** @class */ (function () {
285
287
  imageEditInfo_1 &&
286
288
  clonedImage_1) {
287
289
  (0, roosterjs_content_model_dom_1.mutateSegment)(previousSelectedImage.paragraph, previousSelectedImage.image, function (image) {
288
- (0, applyChange_1.applyChange)(editor, selectedImage_1, image, imageEditInfo_1, lastSrc_1, _this.wasImageResized || _this.isCropMode, clonedImage_1);
290
+ var changeState = (0, applyChange_1.applyChange)(editor, selectedImage_1, image, imageEditInfo_1, lastSrc_1, _this.wasImageResized || _this.isCropMode, clonedImage_1);
291
+ if (_this.wasImageResized || changeState == 'FullyChanged') {
292
+ context.skipUndoSnapshot = false;
293
+ }
289
294
  image.isSelected = shouldSelectImage;
290
295
  image.isSelectedAsImageSelection = shouldSelectImage;
291
296
  image.format.imageState = undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"ImageEditPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { applyChange } from './utils/applyChange';\nimport { canRegenerateImage } from './utils/canRegenerateImage';\nimport { checkIfImageWasResized, isASmallImage } from './utils/imageEditUtils';\nimport { createImageWrapper } from './utils/createImageWrapper';\nimport { Cropper } from './Cropper/cropperContext';\nimport { EDITING_MARKER, findEditingImage } from './utils/findEditingImage';\nimport { filterInnerResizerHandles } from './utils/filterInnerResizerHandles';\nimport { getDropAndDragHelpers } from './utils/getDropAndDragHelpers';\nimport { getHTMLImageOptions } from './utils/getHTMLImageOptions';\nimport { getSelectedImage } from './utils/getSelectedImage';\nimport { getSelectedImageMetadata, updateImageEditInfo } from './utils/updateImageEditInfo';\nimport { ImageEditElementClass } from './types/ImageEditElementClass';\nimport { normalizeImageSelection } from './utils/normalizeImageSelection';\nimport { Resizer } from './Resizer/resizerContext';\nimport { Rotator } from './Rotator/rotatorContext';\nimport { updateHandleCursor } from './utils/updateHandleCursor';\nimport { updateRotateHandle } from './Rotator/updateRotateHandle';\nimport { updateWrapper } from './utils/updateWrapper';\nimport {\n ChangeSource,\n getSafeIdSelector,\n getSelectedParagraphs,\n isElementOfType,\n isNodeOfType,\n mutateBlock,\n mutateSegment,\n setImageState,\n unwrap,\n} from 'roosterjs-content-model-dom';\nimport type { DragAndDropHelper } from '../pluginUtils/DragAndDrop/DragAndDropHelper';\nimport type { DragAndDropContext } from './types/DragAndDropContext';\nimport type { ImageHtmlOptions } from './types/ImageHtmlOptions';\nimport type { ImageEditOptions } from './types/ImageEditOptions';\nimport type {\n ContentChangedEvent,\n ContentModelImage,\n EditorPlugin,\n IEditor,\n ImageEditOperation,\n ImageEditor,\n ImageMetadataFormat,\n KeyDownEvent,\n MouseDownEvent,\n MouseUpEvent,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\nconst DefaultOptions: Partial<ImageEditOptions> = {\n borderColor: '#DB626C',\n minWidth: 10,\n minHeight: 10,\n preserveRatio: true,\n disableRotate: false,\n disableSideResize: false,\n onSelectState: ['resize', 'rotate'],\n};\n\nconst MouseRightButton = 2;\nconst DRAG_ID = '_dragging';\nconst IMAGE_EDIT_CLASS = 'imageEdit';\nconst IMAGE_EDIT_CLASS_CARET = 'imageEditCaretColor';\nconst IMAGE_EDIT_FORMAT_EVENT = 'ImageEditEvent';\n\n/**\n * ImageEdit plugin handles the following image editing features:\n * - Resize image\n * - Crop image\n * - Rotate image\n * - Flip image\n */\nexport class ImageEditPlugin implements ImageEditor, EditorPlugin {\n protected editor: IEditor | null = null;\n private shadowSpan: HTMLSpanElement | null = null;\n private selectedImage: HTMLImageElement | null = null;\n protected wrapper: HTMLSpanElement | null = null;\n protected imageEditInfo: ImageMetadataFormat | null = null;\n private imageHTMLOptions: ImageHtmlOptions | null = null;\n private dndHelpers: DragAndDropHelper<DragAndDropContext, any>[] = [];\n private clonedImage: HTMLImageElement | null = null;\n private lastSrc: string | null = null;\n private wasImageResized: boolean = false;\n private isCropMode: boolean = false;\n private resizers: HTMLDivElement[] = [];\n private rotators: HTMLDivElement[] = [];\n private croppers: HTMLDivElement[] = [];\n private zoomScale: number = 1;\n private disposer: (() => void) | null = null;\n protected isEditing = false;\n protected options: ImageEditOptions;\n\n constructor(options?: ImageEditOptions) {\n this.options = { ...DefaultOptions, ...options };\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'ImageEdit';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n this.disposer = editor.attachDomEvent({\n blur: {\n beforeDispatch: () => {\n if (this.isEditing && this.editor && !this.editor.isDisposed()) {\n this.applyFormatWithContentModel(\n this.editor,\n this.isCropMode,\n true /* shouldSelectImage */\n );\n }\n },\n },\n dragstart: {\n beforeDispatch: ev => {\n if (this.editor) {\n const target = ev.target as Node;\n if (this.isImageSelection(target)) {\n target.id = target.id + DRAG_ID;\n }\n }\n },\n },\n dragend: {\n beforeDispatch: ev => {\n if (this.editor) {\n const target = ev.target as Node;\n if (this.isImageSelection(target) && target.id.includes(DRAG_ID)) {\n target.id = target.id.replace(DRAG_ID, '').trim();\n }\n }\n },\n },\n });\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n if (this.disposer) {\n this.disposer();\n this.disposer = null;\n }\n this.isEditing = false;\n this.cleanInfo();\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor) {\n return;\n }\n switch (event.eventType) {\n case 'mouseDown':\n this.mouseDownHandler(this.editor, event);\n break;\n case 'mouseUp':\n this.mouseUpHandler(this.editor, event);\n break;\n case 'keyDown':\n this.keyDownHandler(this.editor, event);\n break;\n case 'contentChanged':\n this.contentChangedHandler(this.editor, event);\n break;\n case 'extractContentWithDom':\n this.removeImageEditing(event.clonedRoot);\n break;\n case 'beforeLogicalRootChange':\n this.handleBeforeLogicalRootChange();\n break;\n }\n }\n\n private handleBeforeLogicalRootChange() {\n if (this.isEditing && this.editor && !this.editor.isDisposed()) {\n this.applyFormatWithContentModel(\n this.editor,\n this.isCropMode,\n false /* shouldSelectImage */\n );\n this.removeImageWrapper();\n this.cleanInfo();\n }\n }\n\n private removeImageEditing(clonedRoot: HTMLElement) {\n const images = clonedRoot.querySelectorAll('img');\n images.forEach(image => {\n if (image.dataset.editingInfo) {\n delete image.dataset.editingInfo;\n }\n });\n }\n\n private isImageSelection(target: Node): target is HTMLElement {\n return (\n isNodeOfType(target, 'ELEMENT_NODE') &&\n (isElementOfType(target, 'img') ||\n !!(\n isElementOfType(target, 'span') &&\n target.firstElementChild &&\n isNodeOfType(target.firstElementChild, 'ELEMENT_NODE') &&\n isElementOfType(target.firstElementChild, 'img')\n ))\n );\n }\n\n private mouseUpHandler(editor: IEditor, event: MouseUpEvent) {\n const selection = editor.getDOMSelection();\n if ((selection && selection.type == 'image') || this.isEditing) {\n const shouldSelectImage =\n this.isImageSelection(event.rawEvent.target as Node) &&\n event.rawEvent.button === MouseRightButton;\n this.applyFormatWithContentModel(editor, this.isCropMode, shouldSelectImage);\n }\n }\n\n private mouseDownHandler(editor: IEditor, event: MouseDownEvent) {\n if (\n this.isEditing &&\n this.isImageSelection(event.rawEvent.target as Node) &&\n event.rawEvent.button !== MouseRightButton &&\n !this.isCropMode\n ) {\n this.applyFormatWithContentModel(\n editor,\n this.isCropMode,\n this.shadowSpan === event.rawEvent.target\n );\n }\n }\n\n private onDropHandler(editor: IEditor) {\n const selection = editor.getDOMSelection();\n if (selection?.type == 'image') {\n editor.formatContentModel(model => {\n const imageDragged = findEditingImage(model, selection.image.id);\n const imageDropped = findEditingImage(\n model,\n selection.image.id.replace(DRAG_ID, '').trim()\n );\n if (imageDragged && imageDropped) {\n const draggedIndex = imageDragged.paragraph.segments.indexOf(\n imageDragged.image\n );\n mutateBlock(imageDragged.paragraph).segments.splice(draggedIndex, 1);\n const segment = imageDropped.image;\n const paragraph = imageDropped.paragraph;\n mutateSegment(paragraph, segment, image => {\n image.isSelected = true;\n image.isSelectedAsImageSelection = true;\n });\n\n return true;\n }\n return false;\n });\n }\n }\n\n private keyDownHandler(editor: IEditor, event: KeyDownEvent) {\n if (this.isEditing) {\n if (\n event.rawEvent.key === 'Escape' ||\n event.rawEvent.key === 'Delete' ||\n event.rawEvent.key === 'Backspace'\n ) {\n if (event.rawEvent.key === 'Escape') {\n this.removeImageWrapper();\n }\n this.cleanInfo();\n } else {\n if (event.rawEvent.key == 'Enter' && this.isCropMode) {\n event.rawEvent.preventDefault();\n }\n this.applyFormatWithContentModel(\n editor,\n this.isCropMode,\n true /** should selectImage */,\n false /* isApiOperation */\n );\n }\n }\n }\n\n private setContentHandler(editor: IEditor) {\n const selection = editor.getDOMSelection();\n if (selection?.type == 'image') {\n this.cleanInfo();\n setImageState(selection.image, '');\n this.isEditing = false;\n this.isCropMode = false;\n }\n }\n\n private formatEventHandler(event: ContentChangedEvent) {\n if (this.isEditing && event.formatApiName !== IMAGE_EDIT_FORMAT_EVENT) {\n this.cleanInfo();\n this.isEditing = false;\n this.isCropMode = false;\n }\n }\n\n private contentChangedHandler(editor: IEditor, event: ContentChangedEvent) {\n switch (event.source) {\n case ChangeSource.SetContent:\n this.setContentHandler(editor);\n break;\n case ChangeSource.Format:\n this.formatEventHandler(event);\n break;\n case ChangeSource.Drop:\n this.onDropHandler(editor);\n break;\n }\n }\n\n /**\n * EXPOSED FOR TESTING PURPOSE ONLY\n */\n protected applyFormatWithContentModel(\n editor: IEditor,\n isCropMode: boolean,\n shouldSelectImage: boolean,\n isApiOperation?: boolean\n ) {\n let editingImageModel: ContentModelImage | undefined;\n const selection = editor.getDOMSelection();\n\n editor.formatContentModel(\n model => {\n const editingImage = getSelectedImage(model);\n const previousSelectedImage = isApiOperation\n ? editingImage\n : findEditingImage(model);\n let result = false;\n\n if (\n shouldSelectImage ||\n previousSelectedImage?.image != editingImage?.image ||\n previousSelectedImage?.image.format.imageState == EDITING_MARKER ||\n isApiOperation\n ) {\n const { lastSrc, selectedImage, imageEditInfo, clonedImage } = this;\n if (\n (this.isEditing || isApiOperation) &&\n previousSelectedImage &&\n lastSrc &&\n selectedImage &&\n imageEditInfo &&\n clonedImage\n ) {\n mutateSegment(\n previousSelectedImage.paragraph,\n previousSelectedImage.image,\n image => {\n applyChange(\n editor,\n selectedImage,\n image,\n imageEditInfo,\n lastSrc,\n this.wasImageResized || this.isCropMode,\n clonedImage\n );\n\n image.isSelected = shouldSelectImage;\n image.isSelectedAsImageSelection = shouldSelectImage;\n image.format.imageState = undefined;\n\n if (selection?.type == 'range' && !selection.range.collapsed) {\n const selectedParagraphs = getSelectedParagraphs(model, true);\n const isImageInRange = selectedParagraphs.some(paragraph =>\n paragraph.segments.includes(image)\n );\n if (isImageInRange) {\n image.isSelected = true;\n }\n }\n }\n );\n\n if (shouldSelectImage) {\n normalizeImageSelection(previousSelectedImage);\n }\n\n this.cleanInfo();\n result = true;\n }\n\n this.isEditing = false;\n this.isCropMode = false;\n\n if (\n editingImage &&\n selection?.type == 'image' &&\n !shouldSelectImage &&\n !isApiOperation\n ) {\n this.isEditing = true;\n this.isCropMode = isCropMode;\n mutateSegment(editingImage.paragraph, editingImage.image, image => {\n editingImageModel = image;\n this.imageEditInfo = updateImageEditInfo(image, selection.image);\n image.format.imageState = 'isEditing';\n });\n\n result = true;\n }\n }\n\n return result;\n },\n {\n onNodeCreated: (model, node) => {\n if (\n !isApiOperation &&\n editingImageModel &&\n editingImageModel == model &&\n editingImageModel.format.imageState == EDITING_MARKER &&\n isNodeOfType(node, 'ELEMENT_NODE') &&\n isElementOfType(node, 'img')\n ) {\n if (isCropMode) {\n this.startCropMode(editor, node);\n } else {\n this.startRotateAndResize(editor, node);\n }\n }\n },\n apiName: IMAGE_EDIT_FORMAT_EVENT,\n },\n {\n tryGetFromCache: true,\n }\n );\n }\n\n private startEditing(\n editor: IEditor,\n image: HTMLImageElement,\n apiOperation: ImageEditOperation[]\n ) {\n if (!this.imageEditInfo) {\n this.imageEditInfo = getSelectedImageMetadata(editor, image);\n }\n\n if (\n (this.imageEditInfo.widthPx == 0 || this.imageEditInfo.heightPx == 0) &&\n !image.complete\n ) {\n // Image dimensions are zero and loading is incomplete, wait for image to load.\n image.onload = () => {\n this.updateImageDimensionsIfZero(image);\n this.startEditingInternal(editor, image, apiOperation);\n image.onload = null;\n image.onerror = null;\n };\n image.onerror = () => {\n image.onload = null;\n image.onerror = null;\n };\n } else {\n this.updateImageDimensionsIfZero(image);\n this.startEditingInternal(editor, image, apiOperation);\n }\n }\n\n private updateImageDimensionsIfZero(image: HTMLImageElement) {\n if (this.imageEditInfo?.widthPx === 0 || this.imageEditInfo?.heightPx === 0) {\n this.imageEditInfo.widthPx = image.clientWidth;\n this.imageEditInfo.heightPx = image.clientHeight;\n }\n }\n\n private startEditingInternal(\n editor: IEditor,\n image: HTMLImageElement,\n apiOperation: ImageEditOperation[]\n ) {\n if (!this.imageEditInfo) {\n this.imageEditInfo = getSelectedImageMetadata(editor, image);\n }\n this.imageHTMLOptions = getHTMLImageOptions(editor, this.options, this.imageEditInfo);\n this.lastSrc = image.getAttribute('src');\n\n const {\n resizers,\n rotators,\n wrapper,\n shadowSpan,\n imageClone,\n croppers,\n } = createImageWrapper(\n editor,\n image,\n this.options,\n this.imageEditInfo,\n this.imageHTMLOptions,\n apiOperation\n );\n this.shadowSpan = shadowSpan;\n this.selectedImage = image;\n this.wrapper = wrapper;\n this.clonedImage = imageClone;\n this.wasImageResized = checkIfImageWasResized(image);\n this.resizers = resizers;\n this.rotators = rotators;\n this.croppers = croppers;\n this.zoomScale = editor.getDOMHelper().calculateZoomScale();\n\n editor.setEditorStyle(IMAGE_EDIT_CLASS, `outline-style:none!important;`, [\n `span:has(>img${getSafeIdSelector(this.selectedImage.id)})`,\n ]);\n\n editor.setEditorStyle(IMAGE_EDIT_CLASS_CARET, `caret-color: transparent;`);\n }\n\n public startRotateAndResize(editor: IEditor, image: HTMLImageElement) {\n if (this.imageEditInfo) {\n this.startEditing(editor, image, ['resize', 'rotate']);\n if (this.selectedImage && this.imageEditInfo && this.wrapper && this.clonedImage) {\n const isMobileOrTable = !!editor.getEnvironment().isMobileOrTablet;\n this.dndHelpers = [\n ...getDropAndDragHelpers(\n this.wrapper,\n this.imageEditInfo,\n this.options,\n ImageEditElementClass.ResizeHandle,\n Resizer,\n () => {\n if (\n this.imageEditInfo &&\n this.selectedImage &&\n this.wrapper &&\n this.clonedImage\n ) {\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n this.resizers\n );\n this.wasImageResized = true;\n }\n },\n this.zoomScale,\n isMobileOrTable\n ),\n ...getDropAndDragHelpers(\n this.wrapper,\n this.imageEditInfo,\n this.options,\n ImageEditElementClass.RotateHandle,\n Rotator,\n () => {\n if (\n this.imageEditInfo &&\n this.selectedImage &&\n this.wrapper &&\n this.clonedImage\n ) {\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper\n );\n this.updateRotateHandleState(\n editor,\n this.selectedImage,\n this.wrapper,\n this.rotators,\n this.imageEditInfo?.angleRad,\n !!this.options?.disableSideResize\n );\n this.updateResizeHandleDirection(\n this.resizers,\n this.imageEditInfo.angleRad\n );\n }\n },\n this.zoomScale,\n isMobileOrTable\n ),\n ];\n\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n this.resizers\n );\n\n this.updateRotateHandleState(\n editor,\n this.selectedImage,\n this.wrapper,\n this.rotators,\n this.imageEditInfo?.angleRad,\n !!this.options?.disableSideResize\n );\n }\n }\n }\n\n private updateResizeHandleDirection(resizers: HTMLDivElement[], angleRad: number | undefined) {\n const resizeHandles = filterInnerResizerHandles(resizers);\n if (angleRad !== undefined) {\n updateHandleCursor(resizeHandles, angleRad);\n }\n }\n\n private updateRotateHandleState(\n editor: IEditor,\n image: HTMLImageElement,\n wrapper: HTMLSpanElement,\n rotators: HTMLDivElement[],\n angleRad: number | undefined,\n disableSideResize: boolean\n ) {\n const viewport = editor.getVisibleViewport();\n const smallImage = isASmallImage(image.width, image.height);\n if (viewport && rotators && rotators.length > 0) {\n const rotator = rotators[0];\n const rotatorHandle = rotator.firstElementChild;\n if (\n isNodeOfType(rotatorHandle, 'ELEMENT_NODE') &&\n isElementOfType(rotatorHandle, 'div')\n ) {\n updateRotateHandle(\n viewport,\n angleRad ?? 0,\n wrapper,\n rotator,\n rotatorHandle,\n smallImage,\n disableSideResize\n );\n }\n }\n }\n\n public isOperationAllowed(operation: ImageEditOperation): boolean {\n return (\n operation === 'resize' ||\n operation === 'rotate' ||\n operation === 'flip' ||\n operation === 'crop'\n );\n }\n\n public canRegenerateImage(image: HTMLImageElement): boolean {\n return canRegenerateImage(image);\n }\n\n private startCropMode(editor: IEditor, image: HTMLImageElement) {\n if (this.imageEditInfo) {\n this.startEditing(editor, image, ['crop']);\n if (this.imageEditInfo && this.selectedImage && this.wrapper && this.clonedImage) {\n this.dndHelpers = [\n ...getDropAndDragHelpers(\n this.wrapper,\n this.imageEditInfo,\n this.options,\n ImageEditElementClass.CropHandle,\n Cropper,\n () => {\n if (\n this.imageEditInfo &&\n this.selectedImage &&\n this.wrapper &&\n this.clonedImage\n ) {\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n undefined,\n this.croppers\n );\n this.isCropMode = true;\n }\n },\n this.zoomScale,\n !!editor.getEnvironment().isMobileOrTablet\n ),\n ];\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n undefined,\n this.croppers\n );\n }\n }\n }\n\n public cropImage() {\n if (!this.editor) {\n return;\n }\n if (!this.editor.getEnvironment().isSafari) {\n this.editor.focus(); // Safari will keep the selection when click crop, then the focus() call should not be called\n }\n const selection = this.editor.getDOMSelection();\n if (selection?.type == 'image') {\n this.applyFormatWithContentModel(\n this.editor,\n true /* isCropMode */,\n false /* shouldSelectImage */\n );\n }\n }\n\n private editImage(\n editor: IEditor,\n image: HTMLImageElement,\n apiOperation: ImageEditOperation[],\n operation: (imageEditInfo: ImageMetadataFormat) => void\n ) {\n this.startEditing(editor, image, apiOperation);\n if (!this.selectedImage || !this.imageEditInfo || !this.wrapper || !this.clonedImage) {\n return;\n }\n\n operation(this.imageEditInfo);\n\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper\n );\n\n this.applyFormatWithContentModel(\n editor,\n false /* isCrop */,\n true /* shouldSelect*/,\n true /* isApiOperation */\n );\n }\n\n /**\n * Exported for testing purpose only\n */\n public cleanInfo() {\n this.editor?.setEditorStyle(IMAGE_EDIT_CLASS, null);\n this.editor?.setEditorStyle(IMAGE_EDIT_CLASS_CARET, null);\n this.selectedImage = null;\n this.shadowSpan = null;\n this.wrapper = null;\n this.imageEditInfo = null;\n this.imageHTMLOptions = null;\n this.dndHelpers.forEach(helper => helper.dispose());\n this.dndHelpers = [];\n this.clonedImage = null;\n this.lastSrc = null;\n this.wasImageResized = false;\n this.isCropMode = false;\n this.resizers = [];\n this.rotators = [];\n this.croppers = [];\n }\n\n private removeImageWrapper() {\n let image: HTMLImageElement | null = null;\n if (this.shadowSpan && this.shadowSpan.parentElement) {\n if (\n this.shadowSpan.firstElementChild &&\n isNodeOfType(this.shadowSpan.firstElementChild, 'ELEMENT_NODE') &&\n isElementOfType(this.shadowSpan.firstElementChild, 'img')\n ) {\n image = this.shadowSpan.firstElementChild;\n }\n unwrap(this.shadowSpan);\n this.shadowSpan = null;\n this.wrapper = null;\n }\n\n return image;\n }\n\n public flipImage(direction: 'horizontal' | 'vertical') {\n const selection = this.editor?.getDOMSelection();\n if (!this.editor || !selection || selection.type !== 'image') {\n return;\n }\n const image = selection.image;\n if (this.editor) {\n this.editImage(this.editor, image, ['flip'], imageEditInfo => {\n const angleRad = imageEditInfo.angleRad || 0;\n const isInVerticalPostion =\n (angleRad >= Math.PI / 2 && angleRad < (3 * Math.PI) / 4) ||\n (angleRad <= -Math.PI / 2 && angleRad > (-3 * Math.PI) / 4);\n if (isInVerticalPostion) {\n if (direction === 'horizontal') {\n imageEditInfo.flippedVertical = !imageEditInfo.flippedVertical;\n } else {\n imageEditInfo.flippedHorizontal = !imageEditInfo.flippedHorizontal;\n }\n } else {\n if (direction === 'vertical') {\n imageEditInfo.flippedVertical = !imageEditInfo.flippedVertical;\n } else {\n imageEditInfo.flippedHorizontal = !imageEditInfo.flippedHorizontal;\n }\n }\n });\n }\n }\n\n public rotateImage(angleRad: number) {\n const selection = this.editor?.getDOMSelection();\n if (!this.editor || !selection || selection.type !== 'image') {\n return;\n }\n const image = selection.image;\n if (this.editor) {\n this.editImage(this.editor, image, [], imageEditInfo => {\n imageEditInfo.angleRad = (imageEditInfo.angleRad || 0) + angleRad;\n });\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ImageEditPlugin.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-plugins/lib/imageEdit/ImageEditPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { applyChange } from './utils/applyChange';\nimport { canRegenerateImage } from './utils/canRegenerateImage';\nimport { checkIfImageWasResized, isASmallImage } from './utils/imageEditUtils';\nimport { createImageWrapper } from './utils/createImageWrapper';\nimport { Cropper } from './Cropper/cropperContext';\nimport { EDITING_MARKER, findEditingImage } from './utils/findEditingImage';\nimport { filterInnerResizerHandles } from './utils/filterInnerResizerHandles';\nimport { getDropAndDragHelpers } from './utils/getDropAndDragHelpers';\nimport { getHTMLImageOptions } from './utils/getHTMLImageOptions';\nimport { getSelectedImage } from './utils/getSelectedImage';\nimport { getSelectedImageMetadata, updateImageEditInfo } from './utils/updateImageEditInfo';\nimport { ImageEditElementClass } from './types/ImageEditElementClass';\nimport { normalizeImageSelection } from './utils/normalizeImageSelection';\nimport { Resizer } from './Resizer/resizerContext';\nimport { Rotator } from './Rotator/rotatorContext';\nimport { updateHandleCursor } from './utils/updateHandleCursor';\nimport { updateRotateHandle } from './Rotator/updateRotateHandle';\nimport { updateWrapper } from './utils/updateWrapper';\nimport {\n ChangeSource,\n getSafeIdSelector,\n getSelectedParagraphs,\n isElementOfType,\n isNodeOfType,\n mutateBlock,\n mutateSegment,\n setImageState,\n unwrap,\n} from 'roosterjs-content-model-dom';\nimport type { DragAndDropHelper } from '../pluginUtils/DragAndDrop/DragAndDropHelper';\nimport type { DragAndDropContext } from './types/DragAndDropContext';\nimport type { ImageHtmlOptions } from './types/ImageHtmlOptions';\nimport type { ImageEditOptions } from './types/ImageEditOptions';\nimport type {\n ContentChangedEvent,\n ContentModelImage,\n EditorPlugin,\n IEditor,\n ImageEditOperation,\n ImageEditor,\n ImageMetadataFormat,\n KeyDownEvent,\n MouseDownEvent,\n MouseUpEvent,\n PluginEvent,\n} from 'roosterjs-content-model-types';\n\nconst DefaultOptions: Partial<ImageEditOptions> = {\n borderColor: '#DB626C',\n minWidth: 10,\n minHeight: 10,\n preserveRatio: true,\n disableRotate: false,\n disableSideResize: false,\n onSelectState: ['resize', 'rotate'],\n};\n\nconst MouseRightButton = 2;\nconst DRAG_ID = '_dragging';\nconst IMAGE_EDIT_CLASS = 'imageEdit';\nconst IMAGE_EDIT_CLASS_CARET = 'imageEditCaretColor';\nconst IMAGE_EDIT_FORMAT_EVENT = 'ImageEditEvent';\n\n/**\n * ImageEdit plugin handles the following image editing features:\n * - Resize image\n * - Crop image\n * - Rotate image\n * - Flip image\n */\nexport class ImageEditPlugin implements ImageEditor, EditorPlugin {\n protected editor: IEditor | null = null;\n private shadowSpan: HTMLSpanElement | null = null;\n private selectedImage: HTMLImageElement | null = null;\n protected wrapper: HTMLSpanElement | null = null;\n protected imageEditInfo: ImageMetadataFormat | null = null;\n private imageHTMLOptions: ImageHtmlOptions | null = null;\n private dndHelpers: DragAndDropHelper<DragAndDropContext, any>[] = [];\n private clonedImage: HTMLImageElement | null = null;\n private lastSrc: string | null = null;\n private wasImageResized: boolean = false;\n private isCropMode: boolean = false;\n private resizers: HTMLDivElement[] = [];\n private rotators: HTMLDivElement[] = [];\n private croppers: HTMLDivElement[] = [];\n private zoomScale: number = 1;\n private disposer: (() => void) | null = null;\n protected isEditing = false;\n protected options: ImageEditOptions;\n\n constructor(options?: ImageEditOptions) {\n this.options = { ...DefaultOptions, ...options };\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'ImageEdit';\n }\n\n /**\n * The first method that editor will call to a plugin when editor is initializing.\n * It will pass in the editor instance, plugin should take this chance to save the\n * editor reference so that it can call to any editor method or format API later.\n * @param editor The editor object\n */\n initialize(editor: IEditor) {\n this.editor = editor;\n this.disposer = editor.attachDomEvent({\n blur: {\n beforeDispatch: () => {\n if (this.isEditing && this.editor && !this.editor.isDisposed()) {\n this.applyFormatWithContentModel(\n this.editor,\n this.isCropMode,\n true /* shouldSelectImage */\n );\n }\n },\n },\n dragstart: {\n beforeDispatch: ev => {\n if (this.editor) {\n const target = ev.target as Node;\n if (this.isImageSelection(target)) {\n target.id = target.id + DRAG_ID;\n }\n }\n },\n },\n dragend: {\n beforeDispatch: ev => {\n if (this.editor) {\n const target = ev.target as Node;\n if (this.isImageSelection(target) && target.id.includes(DRAG_ID)) {\n target.id = target.id.replace(DRAG_ID, '').trim();\n }\n }\n },\n },\n });\n }\n\n /**\n * The last method that editor will call to a plugin before it is disposed.\n * Plugin can take this chance to clear the reference to editor. After this method is\n * called, plugin should not call to any editor method since it will result in error.\n */\n dispose() {\n if (this.disposer) {\n this.disposer();\n this.disposer = null;\n }\n this.isEditing = false;\n this.cleanInfo();\n this.editor = null;\n }\n\n /**\n * Core method for a plugin. Once an event happens in editor, editor will call this\n * method of each plugin to handle the event as long as the event is not handled\n * exclusively by another plugin.\n * @param event The event to handle:\n */\n onPluginEvent(event: PluginEvent) {\n if (!this.editor) {\n return;\n }\n switch (event.eventType) {\n case 'mouseDown':\n this.mouseDownHandler(this.editor, event);\n break;\n case 'mouseUp':\n this.mouseUpHandler(this.editor, event);\n break;\n case 'keyDown':\n this.keyDownHandler(this.editor, event);\n break;\n case 'contentChanged':\n this.contentChangedHandler(this.editor, event);\n break;\n case 'extractContentWithDom':\n this.removeImageEditing(event.clonedRoot);\n break;\n case 'beforeLogicalRootChange':\n this.handleBeforeLogicalRootChange();\n break;\n }\n }\n\n private handleBeforeLogicalRootChange() {\n if (this.isEditing && this.editor && !this.editor.isDisposed()) {\n this.applyFormatWithContentModel(\n this.editor,\n this.isCropMode,\n false /* shouldSelectImage */\n );\n this.removeImageWrapper();\n this.cleanInfo();\n }\n }\n\n private removeImageEditing(clonedRoot: HTMLElement) {\n const images = clonedRoot.querySelectorAll('img');\n images.forEach(image => {\n if (image.dataset.editingInfo) {\n delete image.dataset.editingInfo;\n }\n });\n }\n\n private isImageSelection(target: Node): target is HTMLElement {\n return (\n isNodeOfType(target, 'ELEMENT_NODE') &&\n (isElementOfType(target, 'img') ||\n !!(\n isElementOfType(target, 'span') &&\n target.firstElementChild &&\n isNodeOfType(target.firstElementChild, 'ELEMENT_NODE') &&\n isElementOfType(target.firstElementChild, 'img')\n ))\n );\n }\n\n private mouseUpHandler(editor: IEditor, event: MouseUpEvent) {\n const selection = editor.getDOMSelection();\n if ((selection && selection.type == 'image') || this.isEditing) {\n const shouldSelectImage =\n this.isImageSelection(event.rawEvent.target as Node) &&\n event.rawEvent.button === MouseRightButton;\n this.applyFormatWithContentModel(editor, this.isCropMode, shouldSelectImage);\n }\n }\n\n private mouseDownHandler(editor: IEditor, event: MouseDownEvent) {\n if (\n this.isEditing &&\n this.isImageSelection(event.rawEvent.target as Node) &&\n event.rawEvent.button !== MouseRightButton &&\n !this.isCropMode\n ) {\n this.applyFormatWithContentModel(\n editor,\n this.isCropMode,\n this.shadowSpan === event.rawEvent.target\n );\n }\n }\n\n private onDropHandler(editor: IEditor) {\n const selection = editor.getDOMSelection();\n if (selection?.type == 'image') {\n editor.formatContentModel(model => {\n const imageDragged = findEditingImage(model, selection.image.id);\n const imageDropped = findEditingImage(\n model,\n selection.image.id.replace(DRAG_ID, '').trim()\n );\n if (imageDragged && imageDropped) {\n const draggedIndex = imageDragged.paragraph.segments.indexOf(\n imageDragged.image\n );\n mutateBlock(imageDragged.paragraph).segments.splice(draggedIndex, 1);\n const segment = imageDropped.image;\n const paragraph = imageDropped.paragraph;\n mutateSegment(paragraph, segment, image => {\n image.isSelected = true;\n image.isSelectedAsImageSelection = true;\n });\n\n return true;\n }\n return false;\n });\n }\n }\n\n private keyDownHandler(editor: IEditor, event: KeyDownEvent) {\n if (this.isEditing) {\n if (\n event.rawEvent.key === 'Escape' ||\n event.rawEvent.key === 'Delete' ||\n event.rawEvent.key === 'Backspace'\n ) {\n if (event.rawEvent.key === 'Escape') {\n this.removeImageWrapper();\n }\n this.cleanInfo();\n } else {\n if (event.rawEvent.key == 'Enter' && this.isCropMode) {\n event.rawEvent.preventDefault();\n }\n this.applyFormatWithContentModel(\n editor,\n this.isCropMode,\n true /** should selectImage */,\n false /* isApiOperation */\n );\n }\n }\n }\n\n private setContentHandler(editor: IEditor) {\n const selection = editor.getDOMSelection();\n if (selection?.type == 'image') {\n this.cleanInfo();\n setImageState(selection.image, '');\n this.isEditing = false;\n this.isCropMode = false;\n }\n }\n\n private formatEventHandler(event: ContentChangedEvent) {\n if (this.isEditing && event.formatApiName !== IMAGE_EDIT_FORMAT_EVENT) {\n this.cleanInfo();\n this.isEditing = false;\n this.isCropMode = false;\n }\n }\n\n private contentChangedHandler(editor: IEditor, event: ContentChangedEvent) {\n switch (event.source) {\n case ChangeSource.SetContent:\n this.setContentHandler(editor);\n break;\n case ChangeSource.Format:\n this.formatEventHandler(event);\n break;\n case ChangeSource.Drop:\n this.onDropHandler(editor);\n break;\n }\n }\n\n /**\n * EXPOSED FOR TESTING PURPOSE ONLY\n */\n protected applyFormatWithContentModel(\n editor: IEditor,\n isCropMode: boolean,\n shouldSelectImage: boolean,\n isApiOperation?: boolean\n ) {\n let editingImageModel: ContentModelImage | undefined;\n const selection = editor.getDOMSelection();\n\n editor.formatContentModel(\n (model, context) => {\n const editingImage = getSelectedImage(model);\n const previousSelectedImage = isApiOperation\n ? editingImage\n : findEditingImage(model);\n let result = false;\n\n // Skip adding undo snapshot for now. If we detect any changes later, we will reset it\n context.skipUndoSnapshot = 'SkipAll';\n\n if (\n shouldSelectImage ||\n previousSelectedImage?.image != editingImage?.image ||\n previousSelectedImage?.image.format.imageState == EDITING_MARKER ||\n isApiOperation\n ) {\n const { lastSrc, selectedImage, imageEditInfo, clonedImage } = this;\n if (\n (this.isEditing || isApiOperation) &&\n previousSelectedImage &&\n lastSrc &&\n selectedImage &&\n imageEditInfo &&\n clonedImage\n ) {\n mutateSegment(\n previousSelectedImage.paragraph,\n previousSelectedImage.image,\n image => {\n const changeState = applyChange(\n editor,\n selectedImage,\n image,\n imageEditInfo,\n lastSrc,\n this.wasImageResized || this.isCropMode,\n clonedImage\n );\n\n if (this.wasImageResized || changeState == 'FullyChanged') {\n context.skipUndoSnapshot = false;\n }\n\n image.isSelected = shouldSelectImage;\n image.isSelectedAsImageSelection = shouldSelectImage;\n image.format.imageState = undefined;\n\n if (selection?.type == 'range' && !selection.range.collapsed) {\n const selectedParagraphs = getSelectedParagraphs(model, true);\n const isImageInRange = selectedParagraphs.some(paragraph =>\n paragraph.segments.includes(image)\n );\n if (isImageInRange) {\n image.isSelected = true;\n }\n }\n }\n );\n\n if (shouldSelectImage) {\n normalizeImageSelection(previousSelectedImage);\n }\n\n this.cleanInfo();\n result = true;\n }\n\n this.isEditing = false;\n this.isCropMode = false;\n\n if (\n editingImage &&\n selection?.type == 'image' &&\n !shouldSelectImage &&\n !isApiOperation\n ) {\n this.isEditing = true;\n this.isCropMode = isCropMode;\n mutateSegment(editingImage.paragraph, editingImage.image, image => {\n editingImageModel = image;\n this.imageEditInfo = updateImageEditInfo(image, selection.image);\n image.format.imageState = 'isEditing';\n });\n\n result = true;\n }\n }\n\n return result;\n },\n {\n onNodeCreated: (model, node) => {\n if (\n !isApiOperation &&\n editingImageModel &&\n editingImageModel == model &&\n editingImageModel.format.imageState == EDITING_MARKER &&\n isNodeOfType(node, 'ELEMENT_NODE') &&\n isElementOfType(node, 'img')\n ) {\n if (isCropMode) {\n this.startCropMode(editor, node);\n } else {\n this.startRotateAndResize(editor, node);\n }\n }\n },\n apiName: IMAGE_EDIT_FORMAT_EVENT,\n },\n {\n tryGetFromCache: true,\n }\n );\n }\n\n private startEditing(\n editor: IEditor,\n image: HTMLImageElement,\n apiOperation: ImageEditOperation[]\n ) {\n if (!this.imageEditInfo) {\n this.imageEditInfo = getSelectedImageMetadata(editor, image);\n }\n\n if (\n (this.imageEditInfo.widthPx == 0 || this.imageEditInfo.heightPx == 0) &&\n !image.complete\n ) {\n // Image dimensions are zero and loading is incomplete, wait for image to load.\n image.onload = () => {\n this.updateImageDimensionsIfZero(image);\n this.startEditingInternal(editor, image, apiOperation);\n image.onload = null;\n image.onerror = null;\n };\n image.onerror = () => {\n image.onload = null;\n image.onerror = null;\n };\n } else {\n this.updateImageDimensionsIfZero(image);\n this.startEditingInternal(editor, image, apiOperation);\n }\n }\n\n private updateImageDimensionsIfZero(image: HTMLImageElement) {\n if (this.imageEditInfo?.widthPx === 0 || this.imageEditInfo?.heightPx === 0) {\n this.imageEditInfo.widthPx = image.clientWidth;\n this.imageEditInfo.heightPx = image.clientHeight;\n }\n }\n\n private startEditingInternal(\n editor: IEditor,\n image: HTMLImageElement,\n apiOperation: ImageEditOperation[]\n ) {\n if (!this.imageEditInfo) {\n this.imageEditInfo = getSelectedImageMetadata(editor, image);\n }\n this.imageHTMLOptions = getHTMLImageOptions(editor, this.options, this.imageEditInfo);\n this.lastSrc = image.getAttribute('src');\n\n const {\n resizers,\n rotators,\n wrapper,\n shadowSpan,\n imageClone,\n croppers,\n } = createImageWrapper(\n editor,\n image,\n this.options,\n this.imageEditInfo,\n this.imageHTMLOptions,\n apiOperation\n );\n this.shadowSpan = shadowSpan;\n this.selectedImage = image;\n this.wrapper = wrapper;\n this.clonedImage = imageClone;\n this.wasImageResized = checkIfImageWasResized(image);\n this.resizers = resizers;\n this.rotators = rotators;\n this.croppers = croppers;\n this.zoomScale = editor.getDOMHelper().calculateZoomScale();\n\n editor.setEditorStyle(IMAGE_EDIT_CLASS, `outline-style:none!important;`, [\n `span:has(>img${getSafeIdSelector(this.selectedImage.id)})`,\n ]);\n\n editor.setEditorStyle(IMAGE_EDIT_CLASS_CARET, `caret-color: transparent;`);\n }\n\n public startRotateAndResize(editor: IEditor, image: HTMLImageElement) {\n if (this.imageEditInfo) {\n this.startEditing(editor, image, ['resize', 'rotate']);\n if (this.selectedImage && this.imageEditInfo && this.wrapper && this.clonedImage) {\n const isMobileOrTable = !!editor.getEnvironment().isMobileOrTablet;\n this.dndHelpers = [\n ...getDropAndDragHelpers(\n this.wrapper,\n this.imageEditInfo,\n this.options,\n ImageEditElementClass.ResizeHandle,\n Resizer,\n () => {\n if (\n this.imageEditInfo &&\n this.selectedImage &&\n this.wrapper &&\n this.clonedImage\n ) {\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n this.resizers\n );\n this.wasImageResized = true;\n }\n },\n this.zoomScale,\n isMobileOrTable\n ),\n ...getDropAndDragHelpers(\n this.wrapper,\n this.imageEditInfo,\n this.options,\n ImageEditElementClass.RotateHandle,\n Rotator,\n () => {\n if (\n this.imageEditInfo &&\n this.selectedImage &&\n this.wrapper &&\n this.clonedImage\n ) {\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper\n );\n this.updateRotateHandleState(\n editor,\n this.selectedImage,\n this.wrapper,\n this.rotators,\n this.imageEditInfo?.angleRad,\n !!this.options?.disableSideResize\n );\n this.updateResizeHandleDirection(\n this.resizers,\n this.imageEditInfo.angleRad\n );\n }\n },\n this.zoomScale,\n isMobileOrTable\n ),\n ];\n\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n this.resizers\n );\n\n this.updateRotateHandleState(\n editor,\n this.selectedImage,\n this.wrapper,\n this.rotators,\n this.imageEditInfo?.angleRad,\n !!this.options?.disableSideResize\n );\n }\n }\n }\n\n private updateResizeHandleDirection(resizers: HTMLDivElement[], angleRad: number | undefined) {\n const resizeHandles = filterInnerResizerHandles(resizers);\n if (angleRad !== undefined) {\n updateHandleCursor(resizeHandles, angleRad);\n }\n }\n\n private updateRotateHandleState(\n editor: IEditor,\n image: HTMLImageElement,\n wrapper: HTMLSpanElement,\n rotators: HTMLDivElement[],\n angleRad: number | undefined,\n disableSideResize: boolean\n ) {\n const viewport = editor.getVisibleViewport();\n const smallImage = isASmallImage(image.width, image.height);\n if (viewport && rotators && rotators.length > 0) {\n const rotator = rotators[0];\n const rotatorHandle = rotator.firstElementChild;\n if (\n isNodeOfType(rotatorHandle, 'ELEMENT_NODE') &&\n isElementOfType(rotatorHandle, 'div')\n ) {\n updateRotateHandle(\n viewport,\n angleRad ?? 0,\n wrapper,\n rotator,\n rotatorHandle,\n smallImage,\n disableSideResize\n );\n }\n }\n }\n\n public isOperationAllowed(operation: ImageEditOperation): boolean {\n return (\n operation === 'resize' ||\n operation === 'rotate' ||\n operation === 'flip' ||\n operation === 'crop'\n );\n }\n\n public canRegenerateImage(image: HTMLImageElement): boolean {\n return canRegenerateImage(image);\n }\n\n private startCropMode(editor: IEditor, image: HTMLImageElement) {\n if (this.imageEditInfo) {\n this.startEditing(editor, image, ['crop']);\n if (this.imageEditInfo && this.selectedImage && this.wrapper && this.clonedImage) {\n this.dndHelpers = [\n ...getDropAndDragHelpers(\n this.wrapper,\n this.imageEditInfo,\n this.options,\n ImageEditElementClass.CropHandle,\n Cropper,\n () => {\n if (\n this.imageEditInfo &&\n this.selectedImage &&\n this.wrapper &&\n this.clonedImage\n ) {\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n undefined,\n this.croppers\n );\n this.isCropMode = true;\n }\n },\n this.zoomScale,\n !!editor.getEnvironment().isMobileOrTablet\n ),\n ];\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper,\n undefined,\n this.croppers\n );\n }\n }\n }\n\n public cropImage() {\n if (!this.editor) {\n return;\n }\n if (!this.editor.getEnvironment().isSafari) {\n this.editor.focus(); // Safari will keep the selection when click crop, then the focus() call should not be called\n }\n const selection = this.editor.getDOMSelection();\n if (selection?.type == 'image') {\n this.applyFormatWithContentModel(\n this.editor,\n true /* isCropMode */,\n false /* shouldSelectImage */\n );\n }\n }\n\n private editImage(\n editor: IEditor,\n image: HTMLImageElement,\n apiOperation: ImageEditOperation[],\n operation: (imageEditInfo: ImageMetadataFormat) => void\n ) {\n this.startEditing(editor, image, apiOperation);\n if (!this.selectedImage || !this.imageEditInfo || !this.wrapper || !this.clonedImage) {\n return;\n }\n\n operation(this.imageEditInfo);\n\n updateWrapper(\n this.imageEditInfo,\n this.options,\n this.selectedImage,\n this.clonedImage,\n this.wrapper\n );\n\n this.applyFormatWithContentModel(\n editor,\n false /* isCrop */,\n true /* shouldSelect*/,\n true /* isApiOperation */\n );\n }\n\n /**\n * Exported for testing purpose only\n */\n public cleanInfo() {\n this.editor?.setEditorStyle(IMAGE_EDIT_CLASS, null);\n this.editor?.setEditorStyle(IMAGE_EDIT_CLASS_CARET, null);\n this.selectedImage = null;\n this.shadowSpan = null;\n this.wrapper = null;\n this.imageEditInfo = null;\n this.imageHTMLOptions = null;\n this.dndHelpers.forEach(helper => helper.dispose());\n this.dndHelpers = [];\n this.clonedImage = null;\n this.lastSrc = null;\n this.wasImageResized = false;\n this.isCropMode = false;\n this.resizers = [];\n this.rotators = [];\n this.croppers = [];\n }\n\n private removeImageWrapper() {\n let image: HTMLImageElement | null = null;\n if (this.shadowSpan && this.shadowSpan.parentElement) {\n if (\n this.shadowSpan.firstElementChild &&\n isNodeOfType(this.shadowSpan.firstElementChild, 'ELEMENT_NODE') &&\n isElementOfType(this.shadowSpan.firstElementChild, 'img')\n ) {\n image = this.shadowSpan.firstElementChild;\n }\n unwrap(this.shadowSpan);\n this.shadowSpan = null;\n this.wrapper = null;\n }\n\n return image;\n }\n\n public flipImage(direction: 'horizontal' | 'vertical') {\n const selection = this.editor?.getDOMSelection();\n if (!this.editor || !selection || selection.type !== 'image') {\n return;\n }\n const image = selection.image;\n if (this.editor) {\n this.editImage(this.editor, image, ['flip'], imageEditInfo => {\n const angleRad = imageEditInfo.angleRad || 0;\n const isInVerticalPostion =\n (angleRad >= Math.PI / 2 && angleRad < (3 * Math.PI) / 4) ||\n (angleRad <= -Math.PI / 2 && angleRad > (-3 * Math.PI) / 4);\n if (isInVerticalPostion) {\n if (direction === 'horizontal') {\n imageEditInfo.flippedVertical = !imageEditInfo.flippedVertical;\n } else {\n imageEditInfo.flippedHorizontal = !imageEditInfo.flippedHorizontal;\n }\n } else {\n if (direction === 'vertical') {\n imageEditInfo.flippedVertical = !imageEditInfo.flippedVertical;\n } else {\n imageEditInfo.flippedHorizontal = !imageEditInfo.flippedHorizontal;\n }\n }\n });\n }\n }\n\n public rotateImage(angleRad: number) {\n const selection = this.editor?.getDOMSelection();\n if (!this.editor || !selection || selection.type !== 'image') {\n return;\n }\n const image = selection.image;\n if (this.editor) {\n this.editImage(this.editor, image, [], imageEditInfo => {\n imageEditInfo.angleRad = (imageEditInfo.angleRad || 0) + angleRad;\n });\n }\n }\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import type { ImageEditInfoState } from './checkEditInfoState';
1
2
  import type { ContentModelImage, IEditor, ImageMetadataFormat } from 'roosterjs-content-model-types';
2
3
  /**
3
4
  * @internal
@@ -9,4 +10,4 @@ import type { ContentModelImage, IEditor, ImageMetadataFormat } from 'roosterjs-
9
10
  * @param wasResizedOrCropped if the image was resized or cropped apply the new image dimensions
10
11
  * @param editingImage (optional) Image in editing state
11
12
  */
12
- export declare function applyChange(editor: IEditor, image: HTMLImageElement, contentModelImage: ContentModelImage, editInfo: ImageMetadataFormat, previousSrc: string, wasResizedOrCropped: boolean, editingImage?: HTMLImageElement): void;
13
+ export declare function applyChange(editor: IEditor, image: HTMLImageElement, contentModelImage: ContentModelImage, editInfo: ImageMetadataFormat, previousSrc: string, wasResizedOrCropped: boolean, editingImage?: HTMLImageElement): ImageEditInfoState;
@@ -60,14 +60,14 @@ function applyChange(editor, image, contentModelImage, editInfo, previousSrc, wa
60
60
  }
61
61
  // Write back the change to image, and set its new size
62
62
  var generatedImageSize = (0, generateImageSize_1.getGeneratedImageSize)(editInfo);
63
- if (!generatedImageSize) {
64
- return;
65
- }
66
- contentModelImage.src = newSrc;
67
- if (wasResizedOrCropped || state == 'FullyChanged') {
68
- contentModelImage.format.width = generatedImageSize.targetWidth + 'px';
69
- contentModelImage.format.height = generatedImageSize.targetHeight + 'px';
63
+ if (generatedImageSize) {
64
+ contentModelImage.src = newSrc;
65
+ if (wasResizedOrCropped || state == 'FullyChanged') {
66
+ contentModelImage.format.width = generatedImageSize.targetWidth + 'px';
67
+ contentModelImage.format.height = generatedImageSize.targetHeight + 'px';
68
+ }
70
69
  }
70
+ return state;
71
71
  }
72
72
  exports.applyChange = applyChange;
73
73
  //# sourceMappingURL=applyChange.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"applyChange.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/imageEdit/utils/applyChange.ts"],"names":[],"mappings":";;;AAAA,2DAA0D;AAC1D,qDAAoD;AACpD,yDAA4D;AAC5D,6DAA4D;AAO5D;;;;;;;;;GASG;AACH,SAAgB,WAAW,CACvB,MAAe,EACf,KAAuB,EACvB,iBAAoC,EACpC,QAA6B,EAC7B,WAAmB,EACnB,mBAA4B,EAC5B,YAA+B;;IAE/B,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAM,YAAY,GAAG,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,KAAK,CAAC;IAC3C,IAAM,YAAY,GAAG,MAAA,IAAA,yCAAmB,EAAC,iBAAiB,EAAE,YAAY,CAAC,mCAAI,SAAS,CAAC;IACvF,IAAM,KAAK,GAAG,IAAA,uCAAkB,EAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEzD,QAAQ,KAAK,EAAE;QACX,KAAK,YAAY;YACb,qFAAqF;YACrF,MAAM,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,CAAC;YAC5B,MAAM;QACV,KAAK,cAAc;YACf,+FAA+F;YAC/F,4DAA4D;YAC5D,MAAM,GAAG,WAAW,CAAC;YACrB,MAAM;QACV,KAAK,cAAc;YACf,8FAA8F;YAC9F,MAAM,GAAG,IAAA,iCAAe,EAAC,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC1D,MAAM;KACb;IAED,IAAM,UAAU,GAAG,MAAM,IAAI,WAAW,CAAC;IAEzC,IAAI,UAAU,EAAE;QACZ,yGAAyG;QACzG,sFAAsF;QACtF,IAAM,OAAK,GAAG,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE;YAC3C,KAAK,EAAE,KAAK;YACZ,WAAW,EAAE,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG;YACtC,WAAW,aAAA;YACX,MAAM,QAAA;SACT,CAAC,CAAC;QACH,MAAM,GAAG,OAAK,CAAC,MAAM,CAAC;KACzB;IAED,IAAI,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE;QACxB,6GAA6G;QAC7G,uDAAuD;QACvD,IAAA,yCAAmB,EAAC,iBAAiB,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;KAC9D;SAAM;QACH,wGAAwG;QACxG,gBAAgB;QAChB,IAAA,yCAAmB,EAAC,iBAAiB,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;KAClE;IAED,uDAAuD;IACvD,IAAM,kBAAkB,GAAG,IAAA,yCAAqB,EAAC,QAAQ,CAAC,CAAC;IAC3D,IAAI,CAAC,kBAAkB,EAAE;QACrB,OAAO;KACV;IAED,iBAAiB,CAAC,GAAG,GAAG,MAAM,CAAC;IAE/B,IAAI,mBAAmB,IAAI,KAAK,IAAI,cAAc,EAAE;QAChD,iBAAiB,CAAC,MAAM,CAAC,KAAK,GAAG,kBAAkB,CAAC,WAAW,GAAG,IAAI,CAAC;QACvE,iBAAiB,CAAC,MAAM,CAAC,MAAM,GAAG,kBAAkB,CAAC,YAAY,GAAG,IAAI,CAAC;KAC5E;AACL,CAAC;AAlED,kCAkEC","sourcesContent":["import { checkEditInfoState } from './checkEditInfoState';\nimport { generateDataURL } from './generateDataURL';\nimport { getGeneratedImageSize } from './generateImageSize';\nimport { updateImageEditInfo } from './updateImageEditInfo';\nimport type {\n ContentModelImage,\n IEditor,\n ImageMetadataFormat,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Apply changes from the edit info of an image, write result to the image\n * @param editor The editor object that contains the image\n * @param image The image to apply the change\n * @param editInfo Edit info that contains the changed information of the image\n * @param previousSrc Last src value of the image before the change was made\n * @param wasResizedOrCropped if the image was resized or cropped apply the new image dimensions\n * @param editingImage (optional) Image in editing state\n */\nexport function applyChange(\n editor: IEditor,\n image: HTMLImageElement,\n contentModelImage: ContentModelImage,\n editInfo: ImageMetadataFormat,\n previousSrc: string,\n wasResizedOrCropped: boolean,\n editingImage?: HTMLImageElement\n) {\n let newSrc = '';\n const imageEditing = editingImage ?? image;\n const initEditInfo = updateImageEditInfo(contentModelImage, imageEditing) ?? undefined;\n const state = checkEditInfoState(editInfo, initEditInfo);\n\n switch (state) {\n case 'ResizeOnly':\n // For resize only case, no need to generate a new image, just reuse the original one\n newSrc = editInfo.src || '';\n break;\n case 'SameWithLast':\n // For SameWithLast case, image may be resized but the content is still the same with last one,\n // so no need to create a new image, but just reuse last one\n newSrc = previousSrc;\n break;\n case 'FullyChanged':\n // For other cases (cropped, rotated, ...) we need to create a new image to reflect the change\n newSrc = generateDataURL(editingImage ?? image, editInfo);\n break;\n }\n\n const srcChanged = newSrc != previousSrc;\n\n if (srcChanged) {\n // If the src is changed, fire an EditImage event so that plugins knows that a new image is used, and can\n // replace the new src with some other string and it will be used and set to the image\n const event = editor.triggerEvent('editImage', {\n image: image,\n originalSrc: editInfo.src || image.src,\n previousSrc,\n newSrc,\n });\n newSrc = event.newSrc;\n }\n\n if (newSrc == editInfo.src) {\n // If newSrc is the same with original one, it means there is only size change, but no rotation, no cropping,\n // so we don't need to keep edit info, we can delete it\n updateImageEditInfo(contentModelImage, imageEditing, null);\n } else {\n // Otherwise, save the new edit info to the image so that next time when we edit the same image, we know\n // the edit info\n updateImageEditInfo(contentModelImage, imageEditing, editInfo);\n }\n\n // Write back the change to image, and set its new size\n const generatedImageSize = getGeneratedImageSize(editInfo);\n if (!generatedImageSize) {\n return;\n }\n\n contentModelImage.src = newSrc;\n\n if (wasResizedOrCropped || state == 'FullyChanged') {\n contentModelImage.format.width = generatedImageSize.targetWidth + 'px';\n contentModelImage.format.height = generatedImageSize.targetHeight + 'px';\n }\n}\n"]}
1
+ {"version":3,"file":"applyChange.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/imageEdit/utils/applyChange.ts"],"names":[],"mappings":";;;AAAA,2DAA0D;AAC1D,qDAAoD;AACpD,yDAA4D;AAC5D,6DAA4D;AAQ5D;;;;;;;;;GASG;AACH,SAAgB,WAAW,CACvB,MAAe,EACf,KAAuB,EACvB,iBAAoC,EACpC,QAA6B,EAC7B,WAAmB,EACnB,mBAA4B,EAC5B,YAA+B;;IAE/B,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAM,YAAY,GAAG,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,KAAK,CAAC;IAC3C,IAAM,YAAY,GAAG,MAAA,IAAA,yCAAmB,EAAC,iBAAiB,EAAE,YAAY,CAAC,mCAAI,SAAS,CAAC;IACvF,IAAM,KAAK,GAAG,IAAA,uCAAkB,EAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IAEzD,QAAQ,KAAK,EAAE;QACX,KAAK,YAAY;YACb,qFAAqF;YACrF,MAAM,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,CAAC;YAC5B,MAAM;QACV,KAAK,cAAc;YACf,+FAA+F;YAC/F,4DAA4D;YAC5D,MAAM,GAAG,WAAW,CAAC;YACrB,MAAM;QACV,KAAK,cAAc;YACf,8FAA8F;YAC9F,MAAM,GAAG,IAAA,iCAAe,EAAC,YAAY,aAAZ,YAAY,cAAZ,YAAY,GAAI,KAAK,EAAE,QAAQ,CAAC,CAAC;YAC1D,MAAM;KACb;IAED,IAAM,UAAU,GAAG,MAAM,IAAI,WAAW,CAAC;IAEzC,IAAI,UAAU,EAAE;QACZ,yGAAyG;QACzG,sFAAsF;QACtF,IAAM,OAAK,GAAG,MAAM,CAAC,YAAY,CAAC,WAAW,EAAE;YAC3C,KAAK,EAAE,KAAK;YACZ,WAAW,EAAE,QAAQ,CAAC,GAAG,IAAI,KAAK,CAAC,GAAG;YACtC,WAAW,aAAA;YACX,MAAM,QAAA;SACT,CAAC,CAAC;QACH,MAAM,GAAG,OAAK,CAAC,MAAM,CAAC;KACzB;IAED,IAAI,MAAM,IAAI,QAAQ,CAAC,GAAG,EAAE;QACxB,6GAA6G;QAC7G,uDAAuD;QACvD,IAAA,yCAAmB,EAAC,iBAAiB,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;KAC9D;SAAM;QACH,wGAAwG;QACxG,gBAAgB;QAChB,IAAA,yCAAmB,EAAC,iBAAiB,EAAE,YAAY,EAAE,QAAQ,CAAC,CAAC;KAClE;IAED,uDAAuD;IACvD,IAAM,kBAAkB,GAAG,IAAA,yCAAqB,EAAC,QAAQ,CAAC,CAAC;IAE3D,IAAI,kBAAkB,EAAE;QACpB,iBAAiB,CAAC,GAAG,GAAG,MAAM,CAAC;QAE/B,IAAI,mBAAmB,IAAI,KAAK,IAAI,cAAc,EAAE;YAChD,iBAAiB,CAAC,MAAM,CAAC,KAAK,GAAG,kBAAkB,CAAC,WAAW,GAAG,IAAI,CAAC;YACvE,iBAAiB,CAAC,MAAM,CAAC,MAAM,GAAG,kBAAkB,CAAC,YAAY,GAAG,IAAI,CAAC;SAC5E;KACJ;IAED,OAAO,KAAK,CAAC;AACjB,CAAC;AAnED,kCAmEC","sourcesContent":["import { checkEditInfoState } from './checkEditInfoState';\nimport { generateDataURL } from './generateDataURL';\nimport { getGeneratedImageSize } from './generateImageSize';\nimport { updateImageEditInfo } from './updateImageEditInfo';\nimport type { ImageEditInfoState } from './checkEditInfoState';\nimport type {\n ContentModelImage,\n IEditor,\n ImageMetadataFormat,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Apply changes from the edit info of an image, write result to the image\n * @param editor The editor object that contains the image\n * @param image The image to apply the change\n * @param editInfo Edit info that contains the changed information of the image\n * @param previousSrc Last src value of the image before the change was made\n * @param wasResizedOrCropped if the image was resized or cropped apply the new image dimensions\n * @param editingImage (optional) Image in editing state\n */\nexport function applyChange(\n editor: IEditor,\n image: HTMLImageElement,\n contentModelImage: ContentModelImage,\n editInfo: ImageMetadataFormat,\n previousSrc: string,\n wasResizedOrCropped: boolean,\n editingImage?: HTMLImageElement\n): ImageEditInfoState {\n let newSrc = '';\n const imageEditing = editingImage ?? image;\n const initEditInfo = updateImageEditInfo(contentModelImage, imageEditing) ?? undefined;\n const state = checkEditInfoState(editInfo, initEditInfo);\n\n switch (state) {\n case 'ResizeOnly':\n // For resize only case, no need to generate a new image, just reuse the original one\n newSrc = editInfo.src || '';\n break;\n case 'SameWithLast':\n // For SameWithLast case, image may be resized but the content is still the same with last one,\n // so no need to create a new image, but just reuse last one\n newSrc = previousSrc;\n break;\n case 'FullyChanged':\n // For other cases (cropped, rotated, ...) we need to create a new image to reflect the change\n newSrc = generateDataURL(editingImage ?? image, editInfo);\n break;\n }\n\n const srcChanged = newSrc != previousSrc;\n\n if (srcChanged) {\n // If the src is changed, fire an EditImage event so that plugins knows that a new image is used, and can\n // replace the new src with some other string and it will be used and set to the image\n const event = editor.triggerEvent('editImage', {\n image: image,\n originalSrc: editInfo.src || image.src,\n previousSrc,\n newSrc,\n });\n newSrc = event.newSrc;\n }\n\n if (newSrc == editInfo.src) {\n // If newSrc is the same with original one, it means there is only size change, but no rotation, no cropping,\n // so we don't need to keep edit info, we can delete it\n updateImageEditInfo(contentModelImage, imageEditing, null);\n } else {\n // Otherwise, save the new edit info to the image so that next time when we edit the same image, we know\n // the edit info\n updateImageEditInfo(contentModelImage, imageEditing, editInfo);\n }\n\n // Write back the change to image, and set its new size\n const generatedImageSize = getGeneratedImageSize(editInfo);\n\n if (generatedImageSize) {\n contentModelImage.src = newSrc;\n\n if (wasResizedOrCropped || state == 'FullyChanged') {\n contentModelImage.format.width = generatedImageSize.targetWidth + 'px';\n contentModelImage.format.height = generatedImageSize.targetHeight + 'px';\n }\n }\n\n return state;\n}\n"]}
@@ -33,8 +33,7 @@ function checkEditInfoState(editInfo, compareTo) {
33
33
  return 'ResizeOnly';
34
34
  }
35
35
  else if (compareTo &&
36
- ROTATE_KEYS.every(function (key) { return areSameNumber(editInfo[key], 0); }) &&
37
- ROTATE_KEYS.every(function (key) { return areSameNumber(compareTo[key], 0); }) &&
36
+ ROTATE_KEYS.every(function (key) { return areSameNumber(editInfo[key], compareTo[key]); }) &&
38
37
  CROP_KEYS.every(function (key) { return areSameNumber(editInfo[key], compareTo[key]); }) &&
39
38
  compareTo.flippedHorizontal === editInfo.flippedHorizontal &&
40
39
  compareTo.flippedVertical === editInfo.flippedVertical) {
@@ -1 +1 @@
1
- {"version":3,"file":"checkEditInfoState.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/imageEdit/utils/checkEditInfoState.ts"],"names":[],"mappings":";;;;AAOA,IAAM,WAAW,GAAwC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACjF,IAAM,WAAW,GAAwC,CAAC,UAAU,CAAC,CAAC;AACtE,IAAM,SAAS,GAAsC;IACjD,aAAa;IACb,cAAc;IACd,YAAY;IACZ,eAAe;CAClB,CAAC;AACF,IAAM,gBAAgB,iFACf,WAAW,+BACX,SAAS,SACf,CAAC;AACF,IAAM,QAAQ,iFAAO,gBAAgB,+BAAK,WAAW,SAAC,CAAC;AAmCvD;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAC9B,QAA6B,EAC7B,SAA+B;IAE/B,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAA,GAAG,IAAI,OAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAxB,CAAwB,CAAC,EAAE;QAC9E,OAAO,SAAS,CAAC;KACpB;SAAM,IACH,gBAAgB,CAAC,KAAK,CAAC,UAAA,GAAG,IAAI,OAAA,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAA/B,CAA+B,CAAC;QAC9D,CAAC,QAAQ,CAAC,iBAAiB;QAC3B,CAAC,QAAQ,CAAC,eAAe;QACzB,CAAC,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ,CAAC,CAAC,EACzE;QACE,OAAO,YAAY,CAAC;KACvB;SAAM,IACH,SAAS;QACT,WAAW,CAAC,KAAK,CAAC,UAAA,GAAG,IAAI,OAAA,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAA/B,CAA+B,CAAC;QACzD,WAAW,CAAC,KAAK,CAAC,UAAA,GAAG,IAAI,OAAA,aAAa,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAhC,CAAgC,CAAC;QAC1D,SAAS,CAAC,KAAK,CAAC,UAAA,GAAG,IAAI,OAAA,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAA5C,CAA4C,CAAC;QACpE,SAAS,CAAC,iBAAiB,KAAK,QAAQ,CAAC,iBAAiB;QAC1D,SAAS,CAAC,eAAe,KAAK,QAAQ,CAAC,eAAe,EACxD;QACE,OAAO,cAAc,CAAC;KACzB;SAAM;QACH,OAAO,cAAc,CAAC;KACzB;AACL,CAAC;AAzBD,gDAyBC;AAED,SAAS,QAAQ,CAAC,CAAM;IACpB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,EAAW,EAAE,EAAW;IAC3C,OAAO,EAAE,IAAI,SAAS,IAAI,EAAE,IAAI,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;AAC1E,CAAC","sourcesContent":["import type {\n ImageCropMetadataFormat,\n ImageMetadataFormat,\n ImageResizeMetadataFormat,\n ImageRotateMetadataFormat,\n} from 'roosterjs-content-model-types';\n\nconst RESIZE_KEYS: (keyof ImageResizeMetadataFormat)[] = ['widthPx', 'heightPx'];\nconst ROTATE_KEYS: (keyof ImageRotateMetadataFormat)[] = ['angleRad'];\nconst CROP_KEYS: (keyof ImageCropMetadataFormat)[] = [\n 'leftPercent',\n 'rightPercent',\n 'topPercent',\n 'bottomPercent',\n];\nconst ROTATE_CROP_KEYS: (keyof ImageRotateMetadataFormat | keyof ImageCropMetadataFormat)[] = [\n ...ROTATE_KEYS,\n ...CROP_KEYS,\n];\nconst ALL_KEYS = [...ROTATE_CROP_KEYS, ...RESIZE_KEYS];\n\n/**\n * @internal\n * State of an edit info object for image editing.\n * It is returned by checkEditInfoState() function\n */\nexport type ImageEditInfoState =\n /**\n * Invalid edit info. It means the given edit info object is either null,\n * or not all its member are of correct type\n */\n | 'Invalid'\n\n /**\n * The edit info shows that it is only potentially edited by resizing action.\n * Image is not rotated or cropped, or event not changed at all.\n */\n | 'ResizeOnly'\n\n /**\n * When compare with another edit info, this value can be returned when both current\n * edit info and the other one are not been rotated, and they have same cropping\n * percentages. So that they can share the same image src, only width and height\n * need to be adjusted.\n */\n | 'SameWithLast'\n\n /**\n * When this value is returned, it means the image is edited by either cropping or\n * rotation, or both. Image source can't be reused, need to generate a new image src\n * data uri.\n */\n | 'FullyChanged';\n\n/**\n * @internal\n * Check the state of an edit info\n * @param editInfo The edit info to check\n * @param compareTo An optional edit info to compare to\n * @returns If the source edit info is not valid (wrong type, missing field, ...), returns Invalid.\n * If the source edit info doesn't contain any rotation or cropping, returns ResizeOnly\n * If the compare edit info exists, and both of them don't contain rotation, and the have same cropping values,\n * returns SameWithLast. Otherwise, returns FullyChanged\n */\nexport function checkEditInfoState(\n editInfo: ImageMetadataFormat,\n compareTo?: ImageMetadataFormat\n): ImageEditInfoState {\n if (!editInfo || !editInfo.src || ALL_KEYS.some(key => !isNumber(editInfo[key]))) {\n return 'Invalid';\n } else if (\n ROTATE_CROP_KEYS.every(key => areSameNumber(editInfo[key], 0)) &&\n !editInfo.flippedHorizontal &&\n !editInfo.flippedVertical &&\n (!compareTo || (compareTo && editInfo.angleRad === compareTo.angleRad))\n ) {\n return 'ResizeOnly';\n } else if (\n compareTo &&\n ROTATE_KEYS.every(key => areSameNumber(editInfo[key], 0)) &&\n ROTATE_KEYS.every(key => areSameNumber(compareTo[key], 0)) &&\n CROP_KEYS.every(key => areSameNumber(editInfo[key], compareTo[key])) &&\n compareTo.flippedHorizontal === editInfo.flippedHorizontal &&\n compareTo.flippedVertical === editInfo.flippedVertical\n ) {\n return 'SameWithLast';\n } else {\n return 'FullyChanged';\n }\n}\n\nfunction isNumber(o: any): o is number {\n return typeof o === 'number';\n}\n\nfunction areSameNumber(n1?: number, n2?: number) {\n return n1 != undefined && n2 != undefined && Math.abs(n1 - n2) < 1e-3;\n}\n"]}
1
+ {"version":3,"file":"checkEditInfoState.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/imageEdit/utils/checkEditInfoState.ts"],"names":[],"mappings":";;;;AAOA,IAAM,WAAW,GAAwC,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACjF,IAAM,WAAW,GAAwC,CAAC,UAAU,CAAC,CAAC;AACtE,IAAM,SAAS,GAAsC;IACjD,aAAa;IACb,cAAc;IACd,YAAY;IACZ,eAAe;CAClB,CAAC;AACF,IAAM,gBAAgB,iFACf,WAAW,+BACX,SAAS,SACf,CAAC;AACF,IAAM,QAAQ,iFAAO,gBAAgB,+BAAK,WAAW,SAAC,CAAC;AAmCvD;;;;;;;;;GASG;AACH,SAAgB,kBAAkB,CAC9B,QAA6B,EAC7B,SAA+B;IAE/B,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,CAAC,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,UAAA,GAAG,IAAI,OAAA,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAxB,CAAwB,CAAC,EAAE;QAC9E,OAAO,SAAS,CAAC;KACpB;SAAM,IACH,gBAAgB,CAAC,KAAK,CAAC,UAAA,GAAG,IAAI,OAAA,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAA/B,CAA+B,CAAC;QAC9D,CAAC,QAAQ,CAAC,iBAAiB;QAC3B,CAAC,QAAQ,CAAC,eAAe;QACzB,CAAC,CAAC,SAAS,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,KAAK,SAAS,CAAC,QAAQ,CAAC,CAAC,EACzE;QACE,OAAO,YAAY,CAAC;KACvB;SAAM,IACH,SAAS;QACT,WAAW,CAAC,KAAK,CAAC,UAAA,GAAG,IAAI,OAAA,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAA5C,CAA4C,CAAC;QACtE,SAAS,CAAC,KAAK,CAAC,UAAA,GAAG,IAAI,OAAA,aAAa,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,EAA5C,CAA4C,CAAC;QACpE,SAAS,CAAC,iBAAiB,KAAK,QAAQ,CAAC,iBAAiB;QAC1D,SAAS,CAAC,eAAe,KAAK,QAAQ,CAAC,eAAe,EACxD;QACE,OAAO,cAAc,CAAC;KACzB;SAAM;QACH,OAAO,cAAc,CAAC;KACzB;AACL,CAAC;AAxBD,gDAwBC;AAED,SAAS,QAAQ,CAAC,CAAM;IACpB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,EAAW,EAAE,EAAW;IAC3C,OAAO,EAAE,IAAI,SAAS,IAAI,EAAE,IAAI,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC;AAC1E,CAAC","sourcesContent":["import type {\n ImageCropMetadataFormat,\n ImageMetadataFormat,\n ImageResizeMetadataFormat,\n ImageRotateMetadataFormat,\n} from 'roosterjs-content-model-types';\n\nconst RESIZE_KEYS: (keyof ImageResizeMetadataFormat)[] = ['widthPx', 'heightPx'];\nconst ROTATE_KEYS: (keyof ImageRotateMetadataFormat)[] = ['angleRad'];\nconst CROP_KEYS: (keyof ImageCropMetadataFormat)[] = [\n 'leftPercent',\n 'rightPercent',\n 'topPercent',\n 'bottomPercent',\n];\nconst ROTATE_CROP_KEYS: (keyof ImageRotateMetadataFormat | keyof ImageCropMetadataFormat)[] = [\n ...ROTATE_KEYS,\n ...CROP_KEYS,\n];\nconst ALL_KEYS = [...ROTATE_CROP_KEYS, ...RESIZE_KEYS];\n\n/**\n * @internal\n * State of an edit info object for image editing.\n * It is returned by checkEditInfoState() function\n */\nexport type ImageEditInfoState =\n /**\n * Invalid edit info. It means the given edit info object is either null,\n * or not all its member are of correct type\n */\n | 'Invalid'\n\n /**\n * The edit info shows that it is only potentially edited by resizing action.\n * Image is not rotated or cropped, or event not changed at all.\n */\n | 'ResizeOnly'\n\n /**\n * When compare with another edit info, this value can be returned when both current\n * edit info and the other one are not been rotated, and they have same cropping\n * percentages. So that they can share the same image src, only width and height\n * need to be adjusted.\n */\n | 'SameWithLast'\n\n /**\n * When this value is returned, it means the image is edited by either cropping or\n * rotation, or both. Image source can't be reused, need to generate a new image src\n * data uri.\n */\n | 'FullyChanged';\n\n/**\n * @internal\n * Check the state of an edit info\n * @param editInfo The edit info to check\n * @param compareTo An optional edit info to compare to\n * @returns If the source edit info is not valid (wrong type, missing field, ...), returns Invalid.\n * If the source edit info doesn't contain any rotation or cropping, returns ResizeOnly\n * If the compare edit info exists, and both of them don't contain rotation, and the have same cropping values,\n * returns SameWithLast. Otherwise, returns FullyChanged\n */\nexport function checkEditInfoState(\n editInfo: ImageMetadataFormat,\n compareTo?: ImageMetadataFormat\n): ImageEditInfoState {\n if (!editInfo || !editInfo.src || ALL_KEYS.some(key => !isNumber(editInfo[key]))) {\n return 'Invalid';\n } else if (\n ROTATE_CROP_KEYS.every(key => areSameNumber(editInfo[key], 0)) &&\n !editInfo.flippedHorizontal &&\n !editInfo.flippedVertical &&\n (!compareTo || (compareTo && editInfo.angleRad === compareTo.angleRad))\n ) {\n return 'ResizeOnly';\n } else if (\n compareTo &&\n ROTATE_KEYS.every(key => areSameNumber(editInfo[key], compareTo[key])) &&\n CROP_KEYS.every(key => areSameNumber(editInfo[key], compareTo[key])) &&\n compareTo.flippedHorizontal === editInfo.flippedHorizontal &&\n compareTo.flippedVertical === editInfo.flippedVertical\n ) {\n return 'SameWithLast';\n } else {\n return 'FullyChanged';\n }\n}\n\nfunction isNumber(o: any): o is number {\n return typeof o === 'number';\n}\n\nfunction areSameNumber(n1?: number, n2?: number) {\n return n1 != undefined && n2 != undefined && Math.abs(n1 - n2) < 1e-3;\n}\n"]}
@@ -11,8 +11,7 @@ define(["require", "exports", "roosterjs-content-model-dom", "roosterjs-content-
11
11
  (0, roosterjs_content_model_api_1.formatTextSegmentBeforeSelectionMarker)(editor, function (_model, segment, paragraph) {
12
12
  var promotedSegment = null;
13
13
  if (segment.link) {
14
- links.push(segment.link);
15
- return true;
14
+ return false;
16
15
  }
17
16
  else if ((promotedSegment = (0, roosterjs_content_model_api_1.promoteLink)(segment, paragraph, autoLinkOptions)) &&
18
17
  promotedSegment.link) {
@@ -1 +1 @@
1
- {"version":3,"file":"createLink.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/link/createLink.ts"],"names":[],"mappings":";;;;IASA;;OAEG;IACH,SAAgB,UAAU,CAAC,MAAe,EAAE,eAAgC;QACxE,IAAI,UAAU,GAAgB,IAAI,CAAC;QACnC,IAAM,KAAK,GAAuB,EAAE,CAAC;QAErC,IAAA,oEAAsC,EAClC,MAAM,EACN,UAAC,MAAM,EAAE,OAAO,EAAE,SAAS;YACvB,IAAI,eAAe,GAA4B,IAAI,CAAC;YAEpD,IAAI,OAAO,CAAC,IAAI,EAAE;gBACd,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAEzB,OAAO,IAAI,CAAC;aACf;iBAAM,IACH,CAAC,eAAe,GAAG,IAAA,yCAAW,EAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;gBACpE,eAAe,CAAC,IAAI,EACtB;gBACE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;gBAEjC,OAAO,IAAI,CAAC;aACf;iBAAM;gBACH,OAAO,KAAK,CAAC;aAChB;QACL,CAAC,EACD;YACI,YAAY,EAAE,0CAAY,CAAC,QAAQ;YACnC,aAAa,EAAE,UAAC,YAAY,EAAE,IAAI;gBAC9B,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,YAAgC,CAAC,IAAI,CAAC,EAAE;oBACrE,UAAU,GAAG,IAAI,CAAC;iBACrB;YACL,CAAC;YACD,aAAa,EAAE,cAAM,OAAA,UAAU,EAAV,CAAU;SAClC,CACJ,CAAC;IACN,CAAC;IAlCD,gCAkCC","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { formatTextSegmentBeforeSelectionMarker, promoteLink } from 'roosterjs-content-model-api';\nimport type {\n ContentModelLink,\n IEditor,\n ContentModelText,\n AutoLinkOptions,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function createLink(editor: IEditor, autoLinkOptions: AutoLinkOptions) {\n let anchorNode: Node | null = null;\n const links: ContentModelLink[] = [];\n\n formatTextSegmentBeforeSelectionMarker(\n editor,\n (_model, segment, paragraph) => {\n let promotedSegment: ContentModelText | null = null;\n\n if (segment.link) {\n links.push(segment.link);\n\n return true;\n } else if (\n (promotedSegment = promoteLink(segment, paragraph, autoLinkOptions)) &&\n promotedSegment.link\n ) {\n links.push(promotedSegment.link);\n\n return true;\n } else {\n return false;\n }\n },\n {\n changeSource: ChangeSource.AutoLink,\n onNodeCreated: (modelElement, node) => {\n if (!anchorNode && links.indexOf(modelElement as ContentModelLink) >= 0) {\n anchorNode = node;\n }\n },\n getChangeData: () => anchorNode,\n }\n );\n}\n"]}
1
+ {"version":3,"file":"createLink.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-plugins/lib/autoFormat/link/createLink.ts"],"names":[],"mappings":";;;;IASA;;OAEG;IACH,SAAgB,UAAU,CAAC,MAAe,EAAE,eAAgC;QACxE,IAAI,UAAU,GAAgB,IAAI,CAAC;QACnC,IAAM,KAAK,GAAuB,EAAE,CAAC;QAErC,IAAA,oEAAsC,EAClC,MAAM,EACN,UAAC,MAAM,EAAE,OAAO,EAAE,SAAS;YACvB,IAAI,eAAe,GAA4B,IAAI,CAAC;YAEpD,IAAI,OAAO,CAAC,IAAI,EAAE;gBACd,OAAO,KAAK,CAAC;aAChB;iBAAM,IACH,CAAC,eAAe,GAAG,IAAA,yCAAW,EAAC,OAAO,EAAE,SAAS,EAAE,eAAe,CAAC,CAAC;gBACpE,eAAe,CAAC,IAAI,EACtB;gBACE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;gBAEjC,OAAO,IAAI,CAAC;aACf;iBAAM;gBACH,OAAO,KAAK,CAAC;aAChB;QACL,CAAC,EACD;YACI,YAAY,EAAE,0CAAY,CAAC,QAAQ;YACnC,aAAa,EAAE,UAAC,YAAY,EAAE,IAAI;gBAC9B,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC,OAAO,CAAC,YAAgC,CAAC,IAAI,CAAC,EAAE;oBACrE,UAAU,GAAG,IAAI,CAAC;iBACrB;YACL,CAAC;YACD,aAAa,EAAE,cAAM,OAAA,UAAU,EAAV,CAAU;SAClC,CACJ,CAAC;IACN,CAAC;IAhCD,gCAgCC","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { formatTextSegmentBeforeSelectionMarker, promoteLink } from 'roosterjs-content-model-api';\nimport type {\n ContentModelLink,\n IEditor,\n ContentModelText,\n AutoLinkOptions,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n */\nexport function createLink(editor: IEditor, autoLinkOptions: AutoLinkOptions) {\n let anchorNode: Node | null = null;\n const links: ContentModelLink[] = [];\n\n formatTextSegmentBeforeSelectionMarker(\n editor,\n (_model, segment, paragraph) => {\n let promotedSegment: ContentModelText | null = null;\n\n if (segment.link) {\n return false;\n } else if (\n (promotedSegment = promoteLink(segment, paragraph, autoLinkOptions)) &&\n promotedSegment.link\n ) {\n links.push(promotedSegment.link);\n\n return true;\n } else {\n return false;\n }\n },\n {\n changeSource: ChangeSource.AutoLink,\n onNodeCreated: (modelElement, node) => {\n if (!anchorNode && links.indexOf(modelElement as ContentModelLink) >= 0) {\n anchorNode = node;\n }\n },\n getChangeData: () => anchorNode,\n }\n );\n}\n"]}
@@ -1,4 +1,4 @@
1
- define(["require", "exports"], function (require, exports) {
1
+ define(["require", "exports", "roosterjs-content-model-dom"], function (require, exports, roosterjs_content_model_dom_1) {
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.deleteParagraphStyle = void 0;
@@ -8,14 +8,28 @@ define(["require", "exports"], function (require, exports) {
8
8
  var deleteParagraphStyle = function (context) {
9
9
  if (context.deleteResult === 'nothingToDelete') {
10
10
  var insertPoint = context.insertPoint;
11
- var paragraph = insertPoint.paragraph;
11
+ var paragraph = insertPoint.paragraph, path = insertPoint.path;
12
+ var group = path[0];
13
+ var parentGroup = path[1];
12
14
  // If the paragraph is empty, we will delete any style in it
13
15
  // This is to ensure the paragraph style is reset to default when there is no content in the paragraph
14
16
  if (paragraph.segments.every(function (s) { return s.segmentType === 'SelectionMarker' || s.segmentType === 'Br'; }) &&
15
- paragraph.segments.filter(function (s) { return s.segmentType === 'Br'; }).length <= 1 &&
16
- Object.keys(paragraph.format).length > 0) {
17
- paragraph.format = {};
18
- context.deleteResult = 'range';
17
+ paragraph.segments.filter(function (s) { return s.segmentType === 'Br'; }).length <= 1) {
18
+ if (Object.keys(paragraph.format).length > 0) {
19
+ paragraph.format = {};
20
+ context.deleteResult = 'range';
21
+ }
22
+ else if (group.blocks.length == 1 &&
23
+ group.blocks[0] == paragraph &&
24
+ parentGroup &&
25
+ (group.blockGroupType == 'FormatContainer' ||
26
+ group.blockGroupType == 'ListItem' ||
27
+ group.blockGroupType == 'General')) {
28
+ // Still has nothing to delete, try to unwrap parent container
29
+ (0, roosterjs_content_model_dom_1.unwrapBlock)(parentGroup, group);
30
+ path.shift();
31
+ context.deleteResult = 'range';
32
+ }
19
33
  }
20
34
  }
21
35
  };