roosterjs-content-model-core 9.34.0 → 9.35.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/coreApi/formatContentModel/formatContentModel.js +2 -0
- package/lib/coreApi/formatContentModel/formatContentModel.js.map +1 -1
- package/lib/corePlugin/cache/CachePlugin.js +14 -28
- package/lib/corePlugin/cache/CachePlugin.js.map +1 -1
- package/lib/corePlugin/undo/UndoPlugin.js +2 -5
- package/lib/corePlugin/undo/UndoPlugin.js.map +1 -1
- package/lib/editor/Editor.js +1 -0
- package/lib/editor/Editor.js.map +1 -1
- package/lib-amd/coreApi/formatContentModel/formatContentModel.js +2 -0
- package/lib-amd/coreApi/formatContentModel/formatContentModel.js.map +1 -1
- package/lib-amd/corePlugin/cache/CachePlugin.js +14 -28
- package/lib-amd/corePlugin/cache/CachePlugin.js.map +1 -1
- package/lib-amd/corePlugin/undo/UndoPlugin.js +2 -5
- package/lib-amd/corePlugin/undo/UndoPlugin.js.map +1 -1
- package/lib-amd/editor/Editor.js +1 -0
- package/lib-amd/editor/Editor.js.map +1 -1
- package/lib-mjs/coreApi/formatContentModel/formatContentModel.js +2 -0
- package/lib-mjs/coreApi/formatContentModel/formatContentModel.js.map +1 -1
- package/lib-mjs/corePlugin/cache/CachePlugin.js +14 -28
- package/lib-mjs/corePlugin/cache/CachePlugin.js.map +1 -1
- package/lib-mjs/corePlugin/undo/UndoPlugin.js +2 -5
- package/lib-mjs/corePlugin/undo/UndoPlugin.js.map +1 -1
- package/lib-mjs/editor/Editor.js +1 -0
- package/lib-mjs/editor/Editor.js.map +1 -1
- package/package.json +3 -3
|
@@ -54,6 +54,8 @@ var formatContentModel = function (core, formatter, options, domToModelOptions)
|
|
|
54
54
|
data: (_b = options === null || options === void 0 ? void 0 : options.getChangeData) === null || _b === void 0 ? void 0 : _b.call(options),
|
|
55
55
|
formatApiName: options === null || options === void 0 ? void 0 : options.apiName,
|
|
56
56
|
changedEntities: getChangedEntities(context, rawEvent),
|
|
57
|
+
skipUndo: !(shouldMarkNewContent || shouldAddSnapshot) ||
|
|
58
|
+
(options === null || options === void 0 ? void 0 : options.changeSource) == roosterjs_content_model_dom_1.ChangeSource.Keyboard, // Keyboard changes will be handled separately in undo plugin, so we need to skip handling it again
|
|
57
59
|
};
|
|
58
60
|
core.api.triggerEvent(core, eventData, true /*broadcast*/);
|
|
59
61
|
if (canUndoByBackspace && (selection === null || selection === void 0 ? void 0 : selection.type) == 'range') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatContentModel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { scrollCaretIntoView } from './scrollCaretIntoView';\nimport type {\n ChangedEntity,\n ContentChangedEvent,\n DOMSelection,\n FormatContentModel,\n FormatContentModelContext,\n EditorCore,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * The general API to do format change with Content Model\n * It will grab a Content Model for current editor content, and invoke a callback function\n * to do format change. Then according to the return value, write back the modified content model into editor.\n * If there is cached model, it will be used and updated.\n * @param core The EditorCore object\n * @param formatter Formatter function, see ContentModelFormatter\n * @param options More options, see FormatContentModelOptions\n */\nexport const formatContentModel: FormatContentModel = (\n core,\n formatter,\n options,\n domToModelOptions\n) => {\n const { onNodeCreated, rawEvent, selectionOverride, scrollCaretIntoView: scroll } =\n options || {};\n const model = core.api.createContentModel(core, domToModelOptions, selectionOverride);\n const context: FormatContentModelContext = {\n newEntities: [],\n deletedEntities: [],\n rawEvent,\n newImages: [],\n paragraphIndexer: core.cache.paragraphMap,\n };\n\n const hasFocus = core.domHelper.hasFocus();\n\n const changed = formatter(model, context);\n const { skipUndoSnapshot, clearModelCache, entityStates, canUndoByBackspace } = context;\n\n if (changed) {\n const isNested = core.undo.isNested;\n const shouldAddSnapshot =\n (!skipUndoSnapshot || skipUndoSnapshot == 'DoNotSkip') && !isNested;\n const shouldMarkNewContent =\n (skipUndoSnapshot === true || skipUndoSnapshot == 'MarkNewContent') && !isNested;\n let selection: DOMSelection | undefined;\n\n if (shouldAddSnapshot) {\n core.undo.isNested = true;\n\n core.api.addUndoSnapshot(core, !!canUndoByBackspace, entityStates);\n }\n\n try {\n handleImages(core, context);\n\n selection =\n core.api.setContentModel(\n core,\n model,\n hasFocus ? undefined : { ignoreSelection: true }, // If editor did not have focus before format, do not set focus after format\n onNodeCreated\n ) ?? undefined;\n\n handlePendingFormat(core, context, selection);\n\n if (scroll && (selection?.type == 'range' || selection?.type == 'image')) {\n scrollCaretIntoView(core, selection);\n }\n\n const eventData: ContentChangedEvent = {\n eventType: 'contentChanged',\n contentModel: clearModelCache ? undefined : model,\n selection: clearModelCache ? undefined : selection,\n source: options?.changeSource || ChangeSource.Format,\n data: options?.getChangeData?.(),\n formatApiName: options?.apiName,\n changedEntities: getChangedEntities(context, rawEvent),\n };\n\n core.api.triggerEvent(core, eventData, true /*broadcast*/);\n\n if (canUndoByBackspace && selection?.type == 'range') {\n core.undo.autoCompleteInsertPoint = {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n };\n }\n\n if (shouldAddSnapshot) {\n core.api.addUndoSnapshot(core, false /*canUndoByBackspace*/, entityStates);\n }\n\n if (shouldMarkNewContent) {\n core.undo.snapshotsManager.hasNewContent = true;\n }\n } finally {\n if (!isNested) {\n core.undo.isNested = false;\n }\n }\n } else {\n if (clearModelCache) {\n core.cache.cachedModel = undefined;\n core.cache.cachedSelection = undefined;\n }\n\n handlePendingFormat(core, context, core.api.getDOMSelection(core));\n }\n\n if (context.announceData) {\n core.api.announce(core, context.announceData);\n }\n};\n\nfunction handleImages(core: EditorCore, context: FormatContentModelContext) {\n if (context.newImages.length > 0) {\n const width = core.domHelper.getClientWidth();\n const minMaxImageSize = 10;\n const maxWidth = Math.max(width, minMaxImageSize);\n context.newImages.forEach(image => {\n image.format.maxWidth = `${maxWidth}px`;\n });\n }\n}\n\nfunction handlePendingFormat(\n core: EditorCore,\n context: FormatContentModelContext,\n selection?: DOMSelection | null\n) {\n const pendingFormat =\n context.newPendingFormat == 'preserve'\n ? core.format.pendingFormat?.format\n : context.newPendingFormat;\n const pendingParagraphFormat =\n context.newPendingParagraphFormat == 'preserve'\n ? core.format.pendingFormat?.paragraphFormat\n : context.newPendingParagraphFormat;\n\n if (\n (pendingFormat || pendingParagraphFormat) &&\n selection?.type == 'range' &&\n selection.range.collapsed\n ) {\n core.format.pendingFormat = {\n format: pendingFormat ? { ...pendingFormat } : undefined,\n paragraphFormat: pendingParagraphFormat ? { ...pendingParagraphFormat } : undefined,\n insertPoint: {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n },\n };\n }\n}\n\nfunction getChangedEntities(\n context: FormatContentModelContext,\n rawEvent?: Event\n): ChangedEntity[] | undefined {\n return context.autoDetectChangedEntities\n ? undefined\n : context.newEntities\n .map(\n (entity): ChangedEntity => ({\n entity,\n operation: 'newEntity',\n rawEvent,\n })\n )\n .concat(\n context.deletedEntities.map(entry => ({\n entity: entry.entity,\n operation: entry.operation,\n rawEvent,\n }))\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"formatContentModel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { scrollCaretIntoView } from './scrollCaretIntoView';\nimport type {\n ChangedEntity,\n ContentChangedEvent,\n DOMSelection,\n FormatContentModel,\n FormatContentModelContext,\n EditorCore,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * The general API to do format change with Content Model\n * It will grab a Content Model for current editor content, and invoke a callback function\n * to do format change. Then according to the return value, write back the modified content model into editor.\n * If there is cached model, it will be used and updated.\n * @param core The EditorCore object\n * @param formatter Formatter function, see ContentModelFormatter\n * @param options More options, see FormatContentModelOptions\n */\nexport const formatContentModel: FormatContentModel = (\n core,\n formatter,\n options,\n domToModelOptions\n) => {\n const { onNodeCreated, rawEvent, selectionOverride, scrollCaretIntoView: scroll } =\n options || {};\n const model = core.api.createContentModel(core, domToModelOptions, selectionOverride);\n const context: FormatContentModelContext = {\n newEntities: [],\n deletedEntities: [],\n rawEvent,\n newImages: [],\n paragraphIndexer: core.cache.paragraphMap,\n };\n\n const hasFocus = core.domHelper.hasFocus();\n\n const changed = formatter(model, context);\n const { skipUndoSnapshot, clearModelCache, entityStates, canUndoByBackspace } = context;\n\n if (changed) {\n const isNested = core.undo.isNested;\n const shouldAddSnapshot =\n (!skipUndoSnapshot || skipUndoSnapshot == 'DoNotSkip') && !isNested;\n const shouldMarkNewContent =\n (skipUndoSnapshot === true || skipUndoSnapshot == 'MarkNewContent') && !isNested;\n let selection: DOMSelection | undefined;\n\n if (shouldAddSnapshot) {\n core.undo.isNested = true;\n\n core.api.addUndoSnapshot(core, !!canUndoByBackspace, entityStates);\n }\n\n try {\n handleImages(core, context);\n\n selection =\n core.api.setContentModel(\n core,\n model,\n hasFocus ? undefined : { ignoreSelection: true }, // If editor did not have focus before format, do not set focus after format\n onNodeCreated\n ) ?? undefined;\n\n handlePendingFormat(core, context, selection);\n\n if (scroll && (selection?.type == 'range' || selection?.type == 'image')) {\n scrollCaretIntoView(core, selection);\n }\n\n const eventData: ContentChangedEvent = {\n eventType: 'contentChanged',\n contentModel: clearModelCache ? undefined : model,\n selection: clearModelCache ? undefined : selection,\n source: options?.changeSource || ChangeSource.Format,\n data: options?.getChangeData?.(),\n formatApiName: options?.apiName,\n changedEntities: getChangedEntities(context, rawEvent),\n skipUndo:\n !(shouldMarkNewContent || shouldAddSnapshot) ||\n options?.changeSource == ChangeSource.Keyboard, // Keyboard changes will be handled separately in undo plugin, so we need to skip handling it again\n };\n\n core.api.triggerEvent(core, eventData, true /*broadcast*/);\n\n if (canUndoByBackspace && selection?.type == 'range') {\n core.undo.autoCompleteInsertPoint = {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n };\n }\n\n if (shouldAddSnapshot) {\n core.api.addUndoSnapshot(core, false /*canUndoByBackspace*/, entityStates);\n }\n\n if (shouldMarkNewContent) {\n core.undo.snapshotsManager.hasNewContent = true;\n }\n } finally {\n if (!isNested) {\n core.undo.isNested = false;\n }\n }\n } else {\n if (clearModelCache) {\n core.cache.cachedModel = undefined;\n core.cache.cachedSelection = undefined;\n }\n\n handlePendingFormat(core, context, core.api.getDOMSelection(core));\n }\n\n if (context.announceData) {\n core.api.announce(core, context.announceData);\n }\n};\n\nfunction handleImages(core: EditorCore, context: FormatContentModelContext) {\n if (context.newImages.length > 0) {\n const width = core.domHelper.getClientWidth();\n const minMaxImageSize = 10;\n const maxWidth = Math.max(width, minMaxImageSize);\n context.newImages.forEach(image => {\n image.format.maxWidth = `${maxWidth}px`;\n });\n }\n}\n\nfunction handlePendingFormat(\n core: EditorCore,\n context: FormatContentModelContext,\n selection?: DOMSelection | null\n) {\n const pendingFormat =\n context.newPendingFormat == 'preserve'\n ? core.format.pendingFormat?.format\n : context.newPendingFormat;\n const pendingParagraphFormat =\n context.newPendingParagraphFormat == 'preserve'\n ? core.format.pendingFormat?.paragraphFormat\n : context.newPendingParagraphFormat;\n\n if (\n (pendingFormat || pendingParagraphFormat) &&\n selection?.type == 'range' &&\n selection.range.collapsed\n ) {\n core.format.pendingFormat = {\n format: pendingFormat ? { ...pendingFormat } : undefined,\n paragraphFormat: pendingParagraphFormat ? { ...pendingParagraphFormat } : undefined,\n insertPoint: {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n },\n };\n }\n}\n\nfunction getChangedEntities(\n context: FormatContentModelContext,\n rawEvent?: Event\n): ChangedEntity[] | undefined {\n return context.autoDetectChangedEntities\n ? undefined\n : context.newEntities\n .map(\n (entity): ChangedEntity => ({\n entity,\n operation: 'newEntity',\n rawEvent,\n })\n )\n .concat(\n context.deletedEntities.map(entry => ({\n entity: entry.entity,\n operation: entry.operation,\n rawEvent,\n }))\n );\n}\n"]}
|
|
@@ -19,11 +19,10 @@ var CachePlugin = /** @class */ (function () {
|
|
|
19
19
|
var _this = this;
|
|
20
20
|
this.editor = null;
|
|
21
21
|
this.onMutation = function (mutation) {
|
|
22
|
-
var _a, _b;
|
|
23
22
|
if (_this.editor) {
|
|
24
23
|
switch (mutation.type) {
|
|
25
24
|
case 'childList':
|
|
26
|
-
if (!
|
|
25
|
+
if (!_this.state.domIndexer.reconcileChildList(mutation.addedNodes, mutation.removedNodes)) {
|
|
27
26
|
_this.invalidateCache();
|
|
28
27
|
}
|
|
29
28
|
break;
|
|
@@ -32,7 +31,7 @@ var CachePlugin = /** @class */ (function () {
|
|
|
32
31
|
break;
|
|
33
32
|
case 'elementId':
|
|
34
33
|
var element = mutation.element;
|
|
35
|
-
if (!
|
|
34
|
+
if (!_this.state.domIndexer.reconcileElementId(element)) {
|
|
36
35
|
_this.invalidateCache();
|
|
37
36
|
}
|
|
38
37
|
break;
|
|
@@ -48,13 +47,12 @@ var CachePlugin = /** @class */ (function () {
|
|
|
48
47
|
_this.updateCachedModel(_this.editor);
|
|
49
48
|
}
|
|
50
49
|
};
|
|
51
|
-
this.state = {
|
|
52
|
-
|
|
53
|
-
this.state.domIndexer = new domIndexerImpl_1.DomIndexerImpl(option.experimentalFeatures &&
|
|
50
|
+
this.state = {
|
|
51
|
+
domIndexer: new domIndexerImpl_1.DomIndexerImpl(option.experimentalFeatures &&
|
|
54
52
|
option.experimentalFeatures.indexOf('PersistCache') >= 0, option.experimentalFeatures &&
|
|
55
|
-
option.experimentalFeatures.indexOf('KeepSelectionMarkerWhenEnteringTextNode') >= 0)
|
|
56
|
-
|
|
57
|
-
}
|
|
53
|
+
option.experimentalFeatures.indexOf('KeepSelectionMarkerWhenEnteringTextNode') >= 0),
|
|
54
|
+
textMutationObserver: (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation),
|
|
55
|
+
};
|
|
58
56
|
if (option.enableParagraphMap) {
|
|
59
57
|
this.state.paragraphMap = (0, ParagraphMapImpl_1.createParagraphMap)();
|
|
60
58
|
}
|
|
@@ -72,10 +70,9 @@ var CachePlugin = /** @class */ (function () {
|
|
|
72
70
|
* @param editor The editor object
|
|
73
71
|
*/
|
|
74
72
|
CachePlugin.prototype.initialize = function (editor) {
|
|
75
|
-
var _a;
|
|
76
73
|
this.editor = editor;
|
|
77
74
|
this.editor.getDocument().addEventListener('selectionchange', this.onNativeSelectionChange);
|
|
78
|
-
|
|
75
|
+
this.state.textMutationObserver.startObserving();
|
|
79
76
|
};
|
|
80
77
|
/**
|
|
81
78
|
* The last method that editor will call to a plugin before it is disposed.
|
|
@@ -83,8 +80,7 @@ var CachePlugin = /** @class */ (function () {
|
|
|
83
80
|
* called, plugin should not call to any editor method since it will result in error.
|
|
84
81
|
*/
|
|
85
82
|
CachePlugin.prototype.dispose = function () {
|
|
86
|
-
|
|
87
|
-
(_a = this.state.textMutationObserver) === null || _a === void 0 ? void 0 : _a.stopObserving();
|
|
83
|
+
this.state.textMutationObserver.stopObserving();
|
|
88
84
|
if (this.editor) {
|
|
89
85
|
this.editor
|
|
90
86
|
.getDocument()
|
|
@@ -111,25 +107,16 @@ var CachePlugin = /** @class */ (function () {
|
|
|
111
107
|
switch (event.eventType) {
|
|
112
108
|
case 'logicalRootChanged':
|
|
113
109
|
this.invalidateCache();
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
this.state.textMutationObserver.startObserving();
|
|
118
|
-
}
|
|
119
|
-
break;
|
|
120
|
-
case 'keyDown':
|
|
121
|
-
case 'input':
|
|
122
|
-
if (!this.state.textMutationObserver) {
|
|
123
|
-
// When updating cache is not enabled, need to clear the cache to make sure other plugins can get an up-to-date content model
|
|
124
|
-
this.invalidateCache();
|
|
125
|
-
}
|
|
110
|
+
this.state.textMutationObserver.stopObserving();
|
|
111
|
+
this.state.textMutationObserver = (0, textMutationObserver_1.createTextMutationObserver)(event.logicalRoot, this.onMutation);
|
|
112
|
+
this.state.textMutationObserver.startObserving();
|
|
126
113
|
break;
|
|
127
114
|
case 'selectionChanged':
|
|
128
115
|
this.updateCachedModel(this.editor);
|
|
129
116
|
break;
|
|
130
117
|
case 'contentChanged':
|
|
131
118
|
var contentModel = event.contentModel, selection = event.selection;
|
|
132
|
-
if (contentModel
|
|
119
|
+
if (contentModel) {
|
|
133
120
|
(0, updateCache_1.updateCache)(this.state, contentModel, selection);
|
|
134
121
|
}
|
|
135
122
|
else {
|
|
@@ -149,7 +136,6 @@ var CachePlugin = /** @class */ (function () {
|
|
|
149
136
|
}
|
|
150
137
|
};
|
|
151
138
|
CachePlugin.prototype.updateCachedModel = function (editor, forceUpdate) {
|
|
152
|
-
var _a;
|
|
153
139
|
if (editor.isInShadowEdit()) {
|
|
154
140
|
return;
|
|
155
141
|
}
|
|
@@ -164,7 +150,7 @@ var CachePlugin = /** @class */ (function () {
|
|
|
164
150
|
if (isSelectionChanged) {
|
|
165
151
|
if (!model ||
|
|
166
152
|
!newRangeEx ||
|
|
167
|
-
!
|
|
153
|
+
!this.state.domIndexer.reconcileSelection(model, newRangeEx, cachedSelection)) {
|
|
168
154
|
this.invalidateCache();
|
|
169
155
|
}
|
|
170
156
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CachePlugin.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/corePlugin/cache/CachePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameSelections } from './areSameSelections';\nimport { createParagraphMap } from './ParagraphMapImpl';\nimport { createTextMutationObserver } from './textMutationObserver';\nimport { DomIndexerImpl } from './domIndexerImpl';\nimport { updateCache } from './updateCache';\nimport type { Mutation } from './MutationType';\nimport type {\n CachePluginState,\n IEditor,\n PluginEvent,\n PluginWithState,\n EditorOptions,\n} from 'roosterjs-content-model-types';\n\n/**\n * ContentModel cache plugin manages cached Content Model, and refresh the cache when necessary\n */\nclass CachePlugin implements PluginWithState<CachePluginState> {\n private editor: IEditor | null = null;\n private state: CachePluginState;\n\n /**\n * Construct a new instance of CachePlugin class\n * @param option The editor option\n * @param contentDiv The editor content DIV\n */\n constructor(option: EditorOptions, contentDiv: HTMLDivElement) {\n this.state = {};\n\n if (!option.disableCache) {\n this.state.domIndexer = new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 0,\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf(\n 'KeepSelectionMarkerWhenEnteringTextNode'\n ) >= 0\n );\n this.state.textMutationObserver = createTextMutationObserver(\n contentDiv,\n this.onMutation\n );\n }\n\n if (option.enableParagraphMap) {\n this.state.paragraphMap = createParagraphMap();\n }\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Cache';\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.editor.getDocument().addEventListener('selectionchange', this.onNativeSelectionChange);\n\n this.state.textMutationObserver?.startObserving();\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 this.state.textMutationObserver?.stopObserving();\n\n if (this.editor) {\n this.editor\n .getDocument()\n .removeEventListener('selectionchange', this.onNativeSelectionChange);\n this.editor = null;\n }\n }\n\n /**\n * Get plugin state object\n */\n getState(): CachePluginState {\n return this.state;\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\n switch (event.eventType) {\n case 'logicalRootChanged':\n this.invalidateCache();\n\n if (this.state.textMutationObserver) {\n this.state.textMutationObserver.stopObserving();\n this.state.textMutationObserver = createTextMutationObserver(\n event.logicalRoot,\n this.onMutation\n );\n this.state.textMutationObserver.startObserving();\n }\n break;\n\n case 'keyDown':\n case 'input':\n if (!this.state.textMutationObserver) {\n // When updating cache is not enabled, need to clear the cache to make sure other plugins can get an up-to-date content model\n this.invalidateCache();\n }\n break;\n\n case 'selectionChanged':\n this.updateCachedModel(this.editor);\n break;\n\n case 'contentChanged':\n const { contentModel, selection } = event;\n\n if (contentModel && this.state.domIndexer) {\n updateCache(this.state, contentModel, selection);\n } else {\n this.invalidateCache();\n }\n\n break;\n }\n }\n\n private onMutation = (mutation: Mutation) => {\n if (this.editor) {\n switch (mutation.type) {\n case 'childList':\n if (\n !this.state.domIndexer?.reconcileChildList(\n mutation.addedNodes,\n mutation.removedNodes\n )\n ) {\n this.invalidateCache();\n }\n break;\n\n case 'text':\n this.updateCachedModel(this.editor, true /*forceUpdate*/);\n break;\n\n case 'elementId':\n const element = mutation.element;\n\n if (!this.state.domIndexer?.reconcileElementId(element)) {\n this.invalidateCache();\n }\n\n break;\n\n case 'unknown':\n this.invalidateCache();\n break;\n }\n }\n };\n\n private onNativeSelectionChange = () => {\n if (this.editor?.hasFocus()) {\n this.updateCachedModel(this.editor);\n }\n };\n\n private invalidateCache() {\n if (!this.editor?.isInShadowEdit()) {\n this.state.cachedModel = undefined;\n this.state.cachedSelection = undefined;\n\n // Clear paragraph indexer to prevent stale references to old paragraphs\n // It will be rebuild next time when we create a new Content Model\n this.state.paragraphMap?.clear();\n }\n }\n\n private updateCachedModel(editor: IEditor, forceUpdate?: boolean) {\n if (editor.isInShadowEdit()) {\n return;\n }\n\n const cachedSelection = this.state.cachedSelection;\n this.state.cachedSelection = undefined; // Clear it to force getDOMSelection() retrieve the latest selection range\n\n const newRangeEx = editor.getDOMSelection() || undefined;\n const model = this.state.cachedModel;\n const isSelectionChanged =\n forceUpdate ||\n !cachedSelection ||\n !newRangeEx ||\n !areSameSelections(newRangeEx, cachedSelection);\n\n if (isSelectionChanged) {\n if (\n !model ||\n !newRangeEx ||\n !this.state.domIndexer?.reconcileSelection(model, newRangeEx, cachedSelection)\n ) {\n this.invalidateCache();\n } else {\n updateCache(this.state, model, newRangeEx);\n }\n } else {\n this.state.cachedSelection = cachedSelection;\n }\n }\n}\n\n/**\n * @internal\n * Create a new instance of CachePlugin class.\n * @param option The editor option\n * @param contentDiv The editor content DIV\n */\nexport function createCachePlugin(\n option: EditorOptions,\n contentDiv: HTMLDivElement\n): PluginWithState<CachePluginState> {\n return new CachePlugin(option, contentDiv);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"CachePlugin.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/corePlugin/cache/CachePlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { areSameSelections } from './areSameSelections';\nimport { createParagraphMap } from './ParagraphMapImpl';\nimport { createTextMutationObserver } from './textMutationObserver';\nimport { DomIndexerImpl } from './domIndexerImpl';\nimport { updateCache } from './updateCache';\nimport type { Mutation } from './MutationType';\nimport type {\n CachePluginState,\n IEditor,\n PluginEvent,\n PluginWithState,\n EditorOptions,\n} from 'roosterjs-content-model-types';\n\n/**\n * ContentModel cache plugin manages cached Content Model, and refresh the cache when necessary\n */\nclass CachePlugin implements PluginWithState<CachePluginState> {\n private editor: IEditor | null = null;\n private state: CachePluginState;\n\n /**\n * Construct a new instance of CachePlugin class\n * @param option The editor option\n * @param contentDiv The editor content DIV\n */\n constructor(option: EditorOptions, contentDiv: HTMLDivElement) {\n this.state = {\n domIndexer: new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 0,\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf(\n 'KeepSelectionMarkerWhenEnteringTextNode'\n ) >= 0\n ),\n textMutationObserver: createTextMutationObserver(contentDiv, this.onMutation),\n };\n\n if (option.enableParagraphMap) {\n this.state.paragraphMap = createParagraphMap();\n }\n }\n\n /**\n * Get name of this plugin\n */\n getName() {\n return 'Cache';\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.editor.getDocument().addEventListener('selectionchange', this.onNativeSelectionChange);\n\n this.state.textMutationObserver.startObserving();\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 this.state.textMutationObserver.stopObserving();\n\n if (this.editor) {\n this.editor\n .getDocument()\n .removeEventListener('selectionchange', this.onNativeSelectionChange);\n this.editor = null;\n }\n }\n\n /**\n * Get plugin state object\n */\n getState(): CachePluginState {\n return this.state;\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\n switch (event.eventType) {\n case 'logicalRootChanged':\n this.invalidateCache();\n\n this.state.textMutationObserver.stopObserving();\n this.state.textMutationObserver = createTextMutationObserver(\n event.logicalRoot,\n this.onMutation\n );\n this.state.textMutationObserver.startObserving();\n break;\n\n case 'selectionChanged':\n this.updateCachedModel(this.editor);\n break;\n\n case 'contentChanged':\n const { contentModel, selection } = event;\n\n if (contentModel) {\n updateCache(this.state, contentModel, selection);\n } else {\n this.invalidateCache();\n }\n\n break;\n }\n }\n\n private onMutation = (mutation: Mutation) => {\n if (this.editor) {\n switch (mutation.type) {\n case 'childList':\n if (\n !this.state.domIndexer.reconcileChildList(\n mutation.addedNodes,\n mutation.removedNodes\n )\n ) {\n this.invalidateCache();\n }\n break;\n\n case 'text':\n this.updateCachedModel(this.editor, true /*forceUpdate*/);\n break;\n\n case 'elementId':\n const element = mutation.element;\n\n if (!this.state.domIndexer.reconcileElementId(element)) {\n this.invalidateCache();\n }\n\n break;\n\n case 'unknown':\n this.invalidateCache();\n break;\n }\n }\n };\n\n private onNativeSelectionChange = () => {\n if (this.editor?.hasFocus()) {\n this.updateCachedModel(this.editor);\n }\n };\n\n private invalidateCache() {\n if (!this.editor?.isInShadowEdit()) {\n this.state.cachedModel = undefined;\n this.state.cachedSelection = undefined;\n\n // Clear paragraph indexer to prevent stale references to old paragraphs\n // It will be rebuild next time when we create a new Content Model\n this.state.paragraphMap?.clear();\n }\n }\n\n private updateCachedModel(editor: IEditor, forceUpdate?: boolean) {\n if (editor.isInShadowEdit()) {\n return;\n }\n\n const cachedSelection = this.state.cachedSelection;\n this.state.cachedSelection = undefined; // Clear it to force getDOMSelection() retrieve the latest selection range\n\n const newRangeEx = editor.getDOMSelection() || undefined;\n const model = this.state.cachedModel;\n const isSelectionChanged =\n forceUpdate ||\n !cachedSelection ||\n !newRangeEx ||\n !areSameSelections(newRangeEx, cachedSelection);\n\n if (isSelectionChanged) {\n if (\n !model ||\n !newRangeEx ||\n !this.state.domIndexer.reconcileSelection(model, newRangeEx, cachedSelection)\n ) {\n this.invalidateCache();\n } else {\n updateCache(this.state, model, newRangeEx);\n }\n } else {\n this.state.cachedSelection = cachedSelection;\n }\n }\n}\n\n/**\n * @internal\n * Create a new instance of CachePlugin class.\n * @param option The editor option\n * @param contentDiv The editor content DIV\n */\nexport function createCachePlugin(\n option: EditorOptions,\n contentDiv: HTMLDivElement\n): PluginWithState<CachePluginState> {\n return new CachePlugin(option, contentDiv);\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createUndoPlugin = void 0;
|
|
4
|
-
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
5
4
|
var SnapshotsManagerImpl_1 = require("./SnapshotsManagerImpl");
|
|
5
|
+
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
6
6
|
var undo_1 = require("../../command/undo/undo");
|
|
7
7
|
var Backspace = 'Backspace';
|
|
8
8
|
var Delete = 'Delete';
|
|
@@ -179,10 +179,7 @@ var UndoPlugin = /** @class */ (function () {
|
|
|
179
179
|
this.state.snapshotsManager.hasNewContent = true;
|
|
180
180
|
};
|
|
181
181
|
UndoPlugin.prototype.onContentChanged = function (event) {
|
|
182
|
-
if (!
|
|
183
|
-
event.source == roosterjs_content_model_dom_1.ChangeSource.SwitchToDarkMode ||
|
|
184
|
-
event.source == roosterjs_content_model_dom_1.ChangeSource.SwitchToLightMode ||
|
|
185
|
-
event.source == roosterjs_content_model_dom_1.ChangeSource.Keyboard)) {
|
|
182
|
+
if (!this.state.isRestoring && !event.skipUndo) {
|
|
186
183
|
this.clearRedoForInput();
|
|
187
184
|
}
|
|
188
185
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UndoPlugin.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/corePlugin/undo/UndoPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeSource, isCursorMovingKey } from 'roosterjs-content-model-dom';\nimport { createSnapshotsManager } from './SnapshotsManagerImpl';\nimport { undo } from '../../command/undo/undo';\nimport type {\n ContentChangedEvent,\n IEditor,\n PluginEvent,\n PluginWithState,\n EditorOptions,\n UndoPluginState,\n} from 'roosterjs-content-model-types';\n\nconst Backspace = 'Backspace';\nconst Delete = 'Delete';\nconst Enter = 'Enter';\n\n/**\n * Provides snapshot based undo service for Editor\n */\nclass UndoPlugin implements PluginWithState<UndoPluginState> {\n private editor: IEditor | null = null;\n private state: UndoPluginState;\n\n /**\n * Construct a new instance of UndoPlugin\n * @param options The wrapper of the state object\n */\n constructor(options: EditorOptions) {\n this.state = {\n snapshotsManager: createSnapshotsManager(options.snapshots),\n isRestoring: false,\n isNested: false,\n autoCompleteInsertPoint: null,\n lastKeyPress: null,\n };\n }\n\n /**\n * Get a friendly name of this plugin\n */\n getName() {\n return 'Undo';\n }\n\n /**\n * Initialize this plugin. This should only be called from Editor\n * @param editor Editor instance\n */\n initialize(editor: IEditor): void {\n this.editor = editor;\n }\n\n /**\n * Dispose this plugin\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Get plugin state object\n */\n getState() {\n return this.state;\n }\n\n /**\n * Check if the plugin should handle the given event exclusively.\n * @param event The event to check\n */\n willHandleEventExclusively(event: PluginEvent) {\n return (\n !!this.editor &&\n event.eventType == 'keyDown' &&\n event.rawEvent.key == Backspace &&\n !event.rawEvent.ctrlKey &&\n this.canUndoAutoComplete(this.editor)\n );\n }\n\n /**\n * Handle events triggered from editor\n * @param event PluginEvent object\n */\n onPluginEvent(event: PluginEvent): void {\n if (!this.editor) {\n return;\n }\n\n switch (event.eventType) {\n case 'editorReady':\n const manager = this.state.snapshotsManager;\n const canUndo = manager.hasNewContent || manager.canMove(-1);\n const canRedo = manager.canMove(1);\n\n if (!canUndo && !canRedo) {\n // Only add initial snapshot when there is no existing snapshot\n // Otherwise preserved undo/redo state may be ruined\n this.addUndoSnapshot();\n }\n break;\n case 'keyDown':\n this.onKeyDown(this.editor, event.rawEvent);\n break;\n case 'keyPress':\n this.onKeyPress(this.editor, event.rawEvent);\n break;\n case 'compositionEnd':\n this.clearRedoForInput();\n this.addUndoSnapshot();\n break;\n case 'contentChanged':\n this.onContentChanged(event);\n break;\n case 'beforeKeyboardEditing':\n this.onBeforeKeyboardEditing(event.rawEvent);\n break;\n\n case 'mouseDown':\n if (this.state.snapshotsManager.hasNewContent) {\n this.addUndoSnapshot();\n }\n break;\n }\n }\n\n private onKeyDown(editor: IEditor, evt: KeyboardEvent): void {\n const { snapshotsManager } = this.state;\n\n // Handle backspace/delete when there is a selection to take a snapshot\n // since we want the state prior to deletion restorable\n // Ignore if keycombo is ALT+BACKSPACE\n if ((evt.key == Backspace && !evt.altKey) || evt.key == Delete) {\n if (evt.key == Backspace && !evt.ctrlKey && this.canUndoAutoComplete(editor)) {\n evt.preventDefault();\n undo(editor);\n this.state.autoCompleteInsertPoint = null;\n this.state.lastKeyPress = evt.key;\n } else if (!evt.defaultPrevented) {\n const selection = editor.getDOMSelection();\n\n // Add snapshot when\n // 1. Something has been selected (not collapsed), or\n // 2. It has a different key code from the last keyDown event (to prevent adding too many snapshot when keeping press the same key), or\n // 3. Ctrl/Meta key is pressed so that a whole word will be deleted\n if (\n selection &&\n (selection.type != 'range' ||\n !selection.range.collapsed ||\n this.state.lastKeyPress != evt.key ||\n this.isCtrlOrMetaPressed(editor, evt))\n ) {\n this.addUndoSnapshot();\n }\n\n // Since some content is deleted, always set hasNewContent to true so that we will take undo snapshot next time\n snapshotsManager.hasNewContent = true;\n this.state.lastKeyPress = evt.key;\n }\n } else if (isCursorMovingKey(evt)) {\n // PageUp, PageDown, Home, End, Left, Right, Up, Down\n if (snapshotsManager.hasNewContent) {\n this.addUndoSnapshot();\n }\n this.state.lastKeyPress = null;\n } else if (this.state.lastKeyPress == Backspace || this.state.lastKeyPress == Delete) {\n if (snapshotsManager.hasNewContent) {\n this.addUndoSnapshot();\n }\n }\n }\n\n private onKeyPress(editor: IEditor, evt: KeyboardEvent): void {\n if (evt.metaKey) {\n // if metaKey is pressed, simply return since no actual effect will be taken on the editor.\n // this is to prevent changing hasNewContent to true when meta + v to paste on Safari.\n return;\n }\n\n const selection = editor.getDOMSelection();\n\n if (\n (selection && (selection.type != 'range' || !selection.range.collapsed)) ||\n (evt.key == ' ' && this.state.lastKeyPress != ' ') ||\n evt.key == Enter\n ) {\n this.addUndoSnapshot();\n\n if (evt.key == Enter) {\n // Treat ENTER as new content so if there is no input after ENTER and undo,\n // we restore the snapshot before ENTER\n this.state.snapshotsManager.hasNewContent = true;\n }\n } else {\n this.clearRedoForInput();\n }\n\n this.state.lastKeyPress = evt.key;\n }\n\n private onBeforeKeyboardEditing(event: KeyboardEvent) {\n // For keyboard event (triggered from Content Model), we can get its keycode from event.data\n // And when user is keep pressing the same key, mark editor with \"hasNewContent\" so that next time user\n // do some other action or press a different key, we will add undo snapshot\n if (event.key != this.state.lastKeyPress) {\n this.addUndoSnapshot();\n }\n\n this.state.lastKeyPress = event.key;\n this.state.snapshotsManager.hasNewContent = true;\n }\n\n private onContentChanged(event: ContentChangedEvent) {\n if (\n !(\n this.state.isRestoring ||\n event.source == ChangeSource.SwitchToDarkMode ||\n event.source == ChangeSource.SwitchToLightMode ||\n event.source == ChangeSource.Keyboard\n )\n ) {\n this.clearRedoForInput();\n }\n }\n\n private clearRedoForInput() {\n this.state.snapshotsManager.clearRedo();\n this.state.lastKeyPress = null;\n this.state.snapshotsManager.hasNewContent = true;\n }\n\n private canUndoAutoComplete(editor: IEditor) {\n const selection = editor.getDOMSelection();\n\n return (\n this.state.snapshotsManager.canUndoAutoComplete() &&\n selection?.type == 'range' &&\n selection.range.collapsed &&\n selection.range.startContainer == this.state.autoCompleteInsertPoint?.node &&\n selection.range.startOffset == this.state.autoCompleteInsertPoint.offset\n );\n }\n\n private addUndoSnapshot() {\n this.editor?.takeSnapshot();\n this.state.autoCompleteInsertPoint = null;\n }\n\n private isCtrlOrMetaPressed(editor: IEditor, event: KeyboardEvent) {\n const env = editor.getEnvironment();\n\n return env.isMac ? event.metaKey : event.ctrlKey;\n }\n}\n\n/**\n * @internal\n * Create a new instance of UndoPlugin.\n * @param option The editor option\n */\nexport function createUndoPlugin(option: EditorOptions): PluginWithState<UndoPluginState> {\n return new UndoPlugin(option);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"UndoPlugin.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/corePlugin/undo/UndoPlugin.ts"],"names":[],"mappings":"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","sourcesContent":["import { createSnapshotsManager } from './SnapshotsManagerImpl';\nimport { isCursorMovingKey } from 'roosterjs-content-model-dom';\nimport { undo } from '../../command/undo/undo';\nimport type {\n ContentChangedEvent,\n IEditor,\n PluginEvent,\n PluginWithState,\n EditorOptions,\n UndoPluginState,\n} from 'roosterjs-content-model-types';\n\nconst Backspace = 'Backspace';\nconst Delete = 'Delete';\nconst Enter = 'Enter';\n\n/**\n * Provides snapshot based undo service for Editor\n */\nclass UndoPlugin implements PluginWithState<UndoPluginState> {\n private editor: IEditor | null = null;\n private state: UndoPluginState;\n\n /**\n * Construct a new instance of UndoPlugin\n * @param options The wrapper of the state object\n */\n constructor(options: EditorOptions) {\n this.state = {\n snapshotsManager: createSnapshotsManager(options.snapshots),\n isRestoring: false,\n isNested: false,\n autoCompleteInsertPoint: null,\n lastKeyPress: null,\n };\n }\n\n /**\n * Get a friendly name of this plugin\n */\n getName() {\n return 'Undo';\n }\n\n /**\n * Initialize this plugin. This should only be called from Editor\n * @param editor Editor instance\n */\n initialize(editor: IEditor): void {\n this.editor = editor;\n }\n\n /**\n * Dispose this plugin\n */\n dispose() {\n this.editor = null;\n }\n\n /**\n * Get plugin state object\n */\n getState() {\n return this.state;\n }\n\n /**\n * Check if the plugin should handle the given event exclusively.\n * @param event The event to check\n */\n willHandleEventExclusively(event: PluginEvent) {\n return (\n !!this.editor &&\n event.eventType == 'keyDown' &&\n event.rawEvent.key == Backspace &&\n !event.rawEvent.ctrlKey &&\n this.canUndoAutoComplete(this.editor)\n );\n }\n\n /**\n * Handle events triggered from editor\n * @param event PluginEvent object\n */\n onPluginEvent(event: PluginEvent): void {\n if (!this.editor) {\n return;\n }\n\n switch (event.eventType) {\n case 'editorReady':\n const manager = this.state.snapshotsManager;\n const canUndo = manager.hasNewContent || manager.canMove(-1);\n const canRedo = manager.canMove(1);\n\n if (!canUndo && !canRedo) {\n // Only add initial snapshot when there is no existing snapshot\n // Otherwise preserved undo/redo state may be ruined\n this.addUndoSnapshot();\n }\n break;\n case 'keyDown':\n this.onKeyDown(this.editor, event.rawEvent);\n break;\n case 'keyPress':\n this.onKeyPress(this.editor, event.rawEvent);\n break;\n case 'compositionEnd':\n this.clearRedoForInput();\n this.addUndoSnapshot();\n break;\n case 'contentChanged':\n this.onContentChanged(event);\n break;\n case 'beforeKeyboardEditing':\n this.onBeforeKeyboardEditing(event.rawEvent);\n break;\n\n case 'mouseDown':\n if (this.state.snapshotsManager.hasNewContent) {\n this.addUndoSnapshot();\n }\n break;\n }\n }\n\n private onKeyDown(editor: IEditor, evt: KeyboardEvent): void {\n const { snapshotsManager } = this.state;\n\n // Handle backspace/delete when there is a selection to take a snapshot\n // since we want the state prior to deletion restorable\n // Ignore if keycombo is ALT+BACKSPACE\n if ((evt.key == Backspace && !evt.altKey) || evt.key == Delete) {\n if (evt.key == Backspace && !evt.ctrlKey && this.canUndoAutoComplete(editor)) {\n evt.preventDefault();\n undo(editor);\n this.state.autoCompleteInsertPoint = null;\n this.state.lastKeyPress = evt.key;\n } else if (!evt.defaultPrevented) {\n const selection = editor.getDOMSelection();\n\n // Add snapshot when\n // 1. Something has been selected (not collapsed), or\n // 2. It has a different key code from the last keyDown event (to prevent adding too many snapshot when keeping press the same key), or\n // 3. Ctrl/Meta key is pressed so that a whole word will be deleted\n if (\n selection &&\n (selection.type != 'range' ||\n !selection.range.collapsed ||\n this.state.lastKeyPress != evt.key ||\n this.isCtrlOrMetaPressed(editor, evt))\n ) {\n this.addUndoSnapshot();\n }\n\n // Since some content is deleted, always set hasNewContent to true so that we will take undo snapshot next time\n snapshotsManager.hasNewContent = true;\n this.state.lastKeyPress = evt.key;\n }\n } else if (isCursorMovingKey(evt)) {\n // PageUp, PageDown, Home, End, Left, Right, Up, Down\n if (snapshotsManager.hasNewContent) {\n this.addUndoSnapshot();\n }\n this.state.lastKeyPress = null;\n } else if (this.state.lastKeyPress == Backspace || this.state.lastKeyPress == Delete) {\n if (snapshotsManager.hasNewContent) {\n this.addUndoSnapshot();\n }\n }\n }\n\n private onKeyPress(editor: IEditor, evt: KeyboardEvent): void {\n if (evt.metaKey) {\n // if metaKey is pressed, simply return since no actual effect will be taken on the editor.\n // this is to prevent changing hasNewContent to true when meta + v to paste on Safari.\n return;\n }\n\n const selection = editor.getDOMSelection();\n\n if (\n (selection && (selection.type != 'range' || !selection.range.collapsed)) ||\n (evt.key == ' ' && this.state.lastKeyPress != ' ') ||\n evt.key == Enter\n ) {\n this.addUndoSnapshot();\n\n if (evt.key == Enter) {\n // Treat ENTER as new content so if there is no input after ENTER and undo,\n // we restore the snapshot before ENTER\n this.state.snapshotsManager.hasNewContent = true;\n }\n } else {\n this.clearRedoForInput();\n }\n\n this.state.lastKeyPress = evt.key;\n }\n\n private onBeforeKeyboardEditing(event: KeyboardEvent) {\n // For keyboard event (triggered from Content Model), we can get its keycode from event.data\n // And when user is keep pressing the same key, mark editor with \"hasNewContent\" so that next time user\n // do some other action or press a different key, we will add undo snapshot\n if (event.key != this.state.lastKeyPress) {\n this.addUndoSnapshot();\n }\n\n this.state.lastKeyPress = event.key;\n this.state.snapshotsManager.hasNewContent = true;\n }\n\n private onContentChanged(event: ContentChangedEvent) {\n if (!this.state.isRestoring && !event.skipUndo) {\n this.clearRedoForInput();\n }\n }\n\n private clearRedoForInput() {\n this.state.snapshotsManager.clearRedo();\n this.state.lastKeyPress = null;\n this.state.snapshotsManager.hasNewContent = true;\n }\n\n private canUndoAutoComplete(editor: IEditor) {\n const selection = editor.getDOMSelection();\n\n return (\n this.state.snapshotsManager.canUndoAutoComplete() &&\n selection?.type == 'range' &&\n selection.range.collapsed &&\n selection.range.startContainer == this.state.autoCompleteInsertPoint?.node &&\n selection.range.startOffset == this.state.autoCompleteInsertPoint.offset\n );\n }\n\n private addUndoSnapshot() {\n this.editor?.takeSnapshot();\n this.state.autoCompleteInsertPoint = null;\n }\n\n private isCtrlOrMetaPressed(editor: IEditor, event: KeyboardEvent) {\n const env = editor.getEnvironment();\n\n return env.isMac ? event.metaKey : event.ctrlKey;\n }\n}\n\n/**\n * @internal\n * Create a new instance of UndoPlugin.\n * @param option The editor option\n */\nexport function createUndoPlugin(option: EditorOptions): PluginWithState<UndoPluginState> {\n return new UndoPlugin(option);\n}\n"]}
|
package/lib/editor/Editor.js
CHANGED
package/lib/editor/Editor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Editor.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-core/lib/editor/Editor.ts"],"names":[],"mappings":"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","sourcesContent":["import { createEditorCore } from './core/createEditorCore';\nimport {\n createEmptyModel,\n ChangeSource,\n cloneModel,\n transformColor,\n createDomToModelContextWithConfig,\n domToContentModel,\n} from 'roosterjs-content-model-dom';\nimport type {\n ContentModelDocument,\n ContentModelFormatter,\n ContentModelSegmentFormat,\n DarkColorHandler,\n DOMEventRecord,\n DOMHelper,\n DOMSelection,\n EditorEnvironment,\n FormatContentModelOptions,\n IEditor,\n PluginEventData,\n PluginEventFromType,\n PluginEventType,\n Snapshot,\n SnapshotsManager,\n EditorCore,\n EditorOptions,\n Rect,\n EntityState,\n CachedElementHandler,\n DomToModelOptionForCreateModel,\n AnnounceData,\n ExperimentalFeature,\n LegacyTrustedHTMLHandler,\n DOMCreator,\n} from 'roosterjs-content-model-types';\n\n/**\n * The main editor class based on Content Model\n */\nexport class Editor implements IEditor {\n private core: EditorCore | null = null;\n\n /**\n * Creates an instance of Editor\n * @param contentDiv The DIV HTML element which will be the container element of editor\n * @param options An optional options object to customize the editor\n */\n constructor(contentDiv: HTMLDivElement, options: EditorOptions = {}) {\n this.core = createEditorCore(contentDiv, options);\n\n const initialModel =\n options.initialModel ?? createEmptyModel(this.core.format.defaultFormat);\n\n this.core.api.setContentModel(\n this.core,\n initialModel,\n { ignoreSelection: true },\n undefined /*onNodeCreated*/,\n true /*isInitializing*/\n );\n this.core.plugins.forEach(plugin => plugin.initialize(this));\n }\n\n /**\n * Dispose this editor, dispose all plugins and custom data\n */\n dispose() {\n const core = this.getCore();\n\n for (let i = core.plugins.length - 1; i >= 0; i--) {\n const plugin = core.plugins[i];\n\n try {\n plugin.dispose();\n } catch (e) {\n // Cache the error and pass it out, then keep going since dispose should always succeed\n core.disposeErrorHandler?.(plugin, e as Error);\n }\n }\n\n core.darkColorHandler.reset();\n\n this.core = null;\n }\n\n /**\n * Get whether this editor is disposed\n * @returns True if editor is disposed, otherwise false\n */\n isDisposed(): boolean {\n return !this.core;\n }\n\n /**\n * Create Content Model from DOM tree in this editor\n * @param mode What kind of Content Model we want. Currently we support the following values:\n * - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.\n * If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.\n * If editor is in dark mode, the cloned entity will be converted back to light mode.\n * - clean: Similar with disconnected, this will return a disconnected model, the difference is \"clean\" mode will not include any selection info.\n * This is usually used for exporting content\n */\n getContentModelCopy(mode: 'connected' | 'disconnected' | 'clean'): ContentModelDocument {\n const core = this.getCore();\n\n switch (mode) {\n case 'connected': // Get a connected model is deprecated. Now we will always return disconnected model\n case 'disconnected':\n return cloneModel(\n core.api.createContentModel(core, {\n tryGetFromCache: false,\n }),\n {\n includeCachedElement: this.cloneOptionCallback,\n }\n );\n\n case 'clean':\n const domToModelContext = createDomToModelContextWithConfig(\n core.environment.domToModelSettings.calculated,\n core.api.createEditorContext(core, false /*saveIndex*/)\n );\n\n return cloneModel(domToContentModel(core.physicalRoot, domToModelContext), {\n includeCachedElement: this.cloneOptionCallback,\n });\n }\n }\n\n /**\n * Get current running environment, such as if editor is running on Mac\n */\n getEnvironment(): EditorEnvironment {\n return this.getCore().environment;\n }\n\n /**\n * Get current DOM selection\n */\n getDOMSelection(): DOMSelection | null {\n const core = this.getCore();\n\n return core.api.getDOMSelection(core);\n }\n\n /**\n * Set DOMSelection into editor content.\n * @param selection The selection to set\n */\n setDOMSelection(selection: DOMSelection | null) {\n const core = this.getCore();\n\n core.api.setDOMSelection(core, selection);\n }\n\n /**\n * Set a new logical root (most likely due to focus change)\n * @param logicalRoot The new logical root (has to be child of physicalRoot)\n */\n setLogicalRoot(logicalRoot: HTMLDivElement) {\n const core = this.getCore();\n\n core.api.setLogicalRoot(core, logicalRoot);\n }\n\n /**\n * The general API to do format change with Content Model\n * It will grab a Content Model for current editor content, and invoke a callback function\n * to do format change. Then according to the return value, write back the modified content model into editor.\n * If there is cached model, it will be used and updated.\n * @param formatter Formatter function, see ContentModelFormatter\n * @param options More options, see FormatContentModelOptions\n */\n formatContentModel(\n formatter: ContentModelFormatter,\n options?: FormatContentModelOptions,\n domToModelOptions?: DomToModelOptionForCreateModel\n ): void {\n const core = this.getCore();\n\n core.api.formatContentModel(core, formatter, options, domToModelOptions);\n }\n\n /**\n * Get pending format of editor if any, or return null\n */\n getPendingFormat(): ContentModelSegmentFormat | null {\n return this.getCore().format.pendingFormat?.format ?? null;\n }\n\n /**\n * Get a DOM Helper object to help access DOM tree in editor\n */\n getDOMHelper(): DOMHelper {\n return this.getCore().domHelper;\n }\n\n /**\n * Add a single undo snapshot to undo stack\n * @param entityState @optional State for entity if we want to add entity state for this snapshot\n */\n takeSnapshot(entityState?: EntityState): Snapshot | null {\n const core = this.getCore();\n\n return core.api.addUndoSnapshot(\n core,\n false /*canUndoByBackspace*/,\n entityState ? [entityState] : undefined\n );\n }\n\n /**\n * Restore an undo snapshot into editor\n * @param snapshot The snapshot to restore\n */\n restoreSnapshot(snapshot: Snapshot): void {\n const core = this.getCore();\n\n core.api.restoreUndoSnapshot(core, snapshot);\n }\n\n /**\n * Get document which contains this editor\n * @returns The HTML document which contains this editor\n */\n getDocument(): Document {\n return this.getCore().physicalRoot.ownerDocument;\n }\n\n /**\n * Focus to this editor, the selection was restored to where it was before, no unexpected scroll.\n */\n focus() {\n const core = this.getCore();\n core.api.focus(core);\n }\n\n /**\n * Check if focus is in editor now\n * @returns true if focus is in editor, otherwise false\n */\n hasFocus(): boolean {\n const core = this.getCore();\n return core.domHelper.hasFocus();\n }\n\n /**\n * Trigger an event to be dispatched to all plugins\n * @param eventType Type of the event\n * @param data data of the event with given type, this is the rest part of PluginEvent with the given type\n * @param broadcast indicates if the event needs to be dispatched to all plugins\n * True means to all, false means to allow exclusive handling from one plugin unless no one wants that\n * @returns the event object which is really passed into plugins. Some plugin may modify the event object so\n * the result of this function provides a chance to read the modified result\n */\n triggerEvent<T extends PluginEventType>(\n eventType: T,\n data: PluginEventData<T>,\n broadcast: boolean = false\n ): PluginEventFromType<T> {\n const core = this.getCore();\n const event = ({\n eventType,\n ...data,\n } as any) as PluginEventFromType<T>;\n core.api.triggerEvent(core, event, broadcast);\n\n return event;\n }\n\n /**\n * Attach a DOM event to the editor content DIV\n * @param eventMap A map from event name to its handler\n */\n attachDomEvent(eventMap: Record<string, DOMEventRecord>): () => void {\n const core = this.getCore();\n return core.api.attachDomEvent(core, eventMap);\n }\n\n /**\n * Get undo snapshots manager\n */\n getSnapshotsManager(): SnapshotsManager {\n const core = this.getCore();\n\n return core.undo.snapshotsManager;\n }\n\n /**\n * Check if the editor is in dark mode\n * @returns True if the editor is in dark mode, otherwise false\n */\n isDarkMode(): boolean {\n return this.getCore().lifecycle.isDarkMode;\n }\n\n /**\n * Set the dark mode state and transforms the content to match the new state.\n * @param isDarkMode The next status of dark mode. True if the editor should be in dark mode, false if not.\n */\n setDarkModeState(isDarkMode?: boolean) {\n const core = this.getCore();\n\n if (!!isDarkMode != core.lifecycle.isDarkMode) {\n transformColor(\n core.physicalRoot,\n false /*includeSelf*/,\n isDarkMode ? 'lightToDark' : 'darkToLight',\n core.darkColorHandler\n );\n\n core.lifecycle.isDarkMode = !!isDarkMode;\n\n core.api.triggerEvent(\n core,\n {\n eventType: 'contentChanged',\n source: isDarkMode\n ? ChangeSource.SwitchToDarkMode\n : ChangeSource.SwitchToLightMode,\n },\n true\n );\n }\n }\n\n /**\n * Check if editor is in Shadow Edit mode\n */\n isInShadowEdit() {\n return !!this.getCore().lifecycle.shadowEditFragment;\n }\n\n /**\n * Make the editor in \"Shadow Edit\" mode.\n * In Shadow Edit mode, all format change will finally be ignored.\n * This can be used for building a live preview feature for format button, to allow user\n * see format result without really apply it.\n * This function can be called repeated. If editor is already in shadow edit mode, we can still\n * use this function to do more shadow edit operation.\n */\n startShadowEdit() {\n const core = this.getCore();\n core.api.switchShadowEdit(core, true /*isOn*/);\n }\n\n /**\n * Leave \"Shadow Edit\" mode, all changes made during shadow edit will be discarded\n */\n stopShadowEdit() {\n const core = this.getCore();\n core.api.switchShadowEdit(core, false /*isOn*/);\n }\n\n /**\n * Get a color manager object for this editor.\n */\n getColorManager(): DarkColorHandler {\n return this.getCore().darkColorHandler;\n }\n\n /**\n * @deprecated\n * Get a function to convert HTML string to trusted HTML string.\n * By default it will just return the input HTML directly. To override this behavior,\n * pass your own trusted HTML handler to EditorOptions.trustedHTMLHandler\n * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types\n */\n getTrustedHTMLHandler(): LegacyTrustedHTMLHandler {\n return this.getCore().trustedHTMLHandler;\n }\n\n /**\n * Get a function to convert HTML string to a trust Document.\n * By default it will just convert the original HTML string into a Document object directly.\n * To override, pass your own trusted HTML handler to EditorOptions.trustedHTMLHandler\n * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types\n */\n getDOMCreator(): DOMCreator {\n return this.getCore().domCreator;\n }\n\n /**\n * Get the scroll container of the editor\n */\n getScrollContainer(): HTMLElement {\n return this.getCore().domEvent.scrollContainer;\n }\n\n /**\n * Retrieves the rect of the visible viewport of the editor.\n */\n getVisibleViewport(): Rect | null {\n return this.getCore().api.getVisibleViewport(this.getCore());\n }\n\n /**\n * Add CSS rules for editor\n * @param key A string to identify the CSS rule type. When set CSS rules with the same key again, existing rules with the same key will be replaced.\n * @param cssRule The CSS rule string, must be a valid CSS rule string, or browser may throw exception. Pass null to clear existing rules\n * @param subSelectors @optional If the rule is used for child element under editor, use this parameter to specify the child elements. Each item will be\n * combined with root selector together to build a separate rule.\n */\n setEditorStyle(\n key: string,\n cssRule: string | null,\n subSelectors?: 'before' | 'after' | string[]\n ): void {\n const core = this.getCore();\n\n core.api.setEditorStyle(core, key, cssRule, subSelectors);\n }\n\n /**\n * Announce the given data\n * @param announceData Data to announce\n */\n announce(announceData: AnnounceData): void {\n const core = this.getCore();\n\n core.api.announce(core, announceData);\n }\n\n /**\n * Check if a given feature is enabled\n * @param featureName The name of feature to check\n */\n isExperimentalFeatureEnabled(featureName: ExperimentalFeature | string): boolean {\n return this.getCore().experimentalFeatures.indexOf(featureName) >= 0;\n }\n\n /**\n * @returns the current EditorCore object\n * @throws a standard Error if there's no core object\n */\n protected getCore(): EditorCore {\n if (!this.core) {\n throw new Error('Editor is already disposed');\n }\n return this.core;\n }\n\n private cloneOptionCallback: CachedElementHandler = (node, type) => {\n if (type == 'cache') {\n return undefined;\n }\n\n const result = node.cloneNode(true /*deep*/) as HTMLElement;\n\n if (this.isDarkMode()) {\n const colorHandler = this.getColorManager();\n\n transformColor(result, true /*includeSelf*/, 'darkToLight', colorHandler);\n\n result.style.color = result.style.color || 'inherit';\n result.style.backgroundColor = result.style.backgroundColor || 'inherit';\n }\n\n return result;\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Editor.js","sourceRoot":"","sources":["../../../../packages/roosterjs-content-model-core/lib/editor/Editor.ts"],"names":[],"mappings":";;;;AAAA,4DAA2D;AAC3D,2EAOqC;AA6BrC;;GAEG;AACH;IAGI;;;;OAIG;IACH,gBAAY,UAA0B,EAAE,OAA2B;QAAnE,iBAcC;QAduC,wBAAA,EAAA,YAA2B;;QAP3D,SAAI,GAAsB,IAAI,CAAC;QAmZ/B,wBAAmB,GAAyB,UAAC,IAAI,EAAE,IAAI;YAC3D,IAAI,IAAI,IAAI,OAAO,EAAE;gBACjB,OAAO,SAAS,CAAC;aACpB;YAED,IAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAgB,CAAC;YAE5D,IAAI,KAAI,CAAC,UAAU,EAAE,EAAE;gBACnB,IAAM,YAAY,GAAG,KAAI,CAAC,eAAe,EAAE,CAAC;gBAE5C,IAAA,4CAAc,EAAC,MAAM,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,EAAE,YAAY,CAAC,CAAC;gBAE1E,MAAM,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,SAAS,CAAC;gBACrD,MAAM,CAAC,KAAK,CAAC,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,eAAe,IAAI,SAAS,CAAC;aAC5E;YAED,OAAO,MAAM,CAAC;QAClB,CAAC,CAAC;QA5ZE,IAAI,CAAC,IAAI,GAAG,IAAA,mCAAgB,EAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAElD,IAAM,YAAY,GACd,MAAA,OAAO,CAAC,YAAY,mCAAI,IAAA,8CAAgB,EAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC;QAE7E,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,eAAe,CACzB,IAAI,CAAC,IAAI,EACT,YAAY,EACZ,EAAE,eAAe,EAAE,IAAI,EAAE,EACzB,SAAS,CAAC,iBAAiB,EAC3B,IAAI,CAAC,kBAAkB,CAC1B,CAAC;QACF,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,UAAA,MAAM,IAAI,OAAA,MAAM,CAAC,UAAU,CAAC,KAAI,CAAC,EAAvB,CAAuB,CAAC,CAAC;IACjE,CAAC;IAED;;OAEG;IACH,wBAAO,GAAP;;QACI,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE;YAC/C,IAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAE/B,IAAI;gBACA,MAAM,CAAC,OAAO,EAAE,CAAC;aACpB;YAAC,OAAO,CAAC,EAAE;gBACR,uFAAuF;gBACvF,MAAA,IAAI,CAAC,mBAAmB,+CAAxB,IAAI,EAAuB,MAAM,EAAE,CAAU,CAAC,CAAC;aAClD;SACJ;QAED,IAAI,CAAC,gBAAgB,CAAC,KAAK,EAAE,CAAC;QAE9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACrB,CAAC;IAED;;;OAGG;IACH,2BAAU,GAAV;QACI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;IACtB,CAAC;IAED;;;;;;;;OAQG;IACH,oCAAmB,GAAnB,UAAoB,IAA4C;QAC5D,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,QAAQ,IAAI,EAAE;YACV,KAAK,WAAW,CAAC,CAAC,oFAAoF;YACtG,KAAK,cAAc;gBACf,OAAO,IAAA,wCAAU,EACb,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE;oBAC9B,eAAe,EAAE,KAAK;iBACzB,CAAC,EACF;oBACI,oBAAoB,EAAE,IAAI,CAAC,mBAAmB;iBACjD,CACJ,CAAC;YAEN,KAAK,OAAO;gBACR,IAAM,iBAAiB,GAAG,IAAA,+DAAiC,EACvD,IAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,UAAU,EAC9C,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,CAAC,CAC1D,CAAC;gBAEF,OAAO,IAAA,wCAAU,EAAC,IAAA,+CAAiB,EAAC,IAAI,CAAC,YAAY,EAAE,iBAAiB,CAAC,EAAE;oBACvE,oBAAoB,EAAE,IAAI,CAAC,mBAAmB;iBACjD,CAAC,CAAC;SACV;IACL,CAAC;IAED;;OAEG;IACH,+BAAc,GAAd;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,gCAAe,GAAf;QACI,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;IAC1C,CAAC;IAED;;;OAGG;IACH,gCAAe,GAAf,UAAgB,SAA8B;QAC1C,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACH,+BAAc,GAAd,UAAe,WAA2B;QACtC,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;OAOG;IACH,mCAAkB,GAAlB,UACI,SAAgC,EAChC,OAAmC,EACnC,iBAAkD;QAElD,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,iBAAiB,CAAC,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,iCAAgB,GAAhB;;QACI,OAAO,MAAA,MAAA,IAAI,CAAC,OAAO,EAAE,CAAC,MAAM,CAAC,aAAa,0CAAE,MAAM,mCAAI,IAAI,CAAC;IAC/D,CAAC;IAED;;OAEG;IACH,6BAAY,GAAZ;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC;IACpC,CAAC;IAED;;;OAGG;IACH,6BAAY,GAAZ,UAAa,WAAyB;QAClC,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,CAC3B,IAAI,EACJ,KAAK,CAAC,sBAAsB,EAC5B,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS,CAC1C,CAAC;IACN,CAAC;IAED;;;OAGG;IACH,gCAAe,GAAf,UAAgB,QAAkB;QAC9B,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IAED;;;OAGG;IACH,4BAAW,GAAX;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,YAAY,CAAC,aAAa,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,sBAAK,GAAL;QACI,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,yBAAQ,GAAR;QACI,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;IACrC,CAAC;IAED;;;;;;;;OAQG;IACH,6BAAY,GAAZ,UACI,SAAY,EACZ,IAAwB,EACxB,SAA0B;QAA1B,0BAAA,EAAA,iBAA0B;QAE1B,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,IAAM,KAAK,GAAI,wBACX,SAAS,WAAA,IACN,IAAI,CACwB,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;QAE9C,OAAO,KAAK,CAAC;IACjB,CAAC;IAED;;;OAGG;IACH,+BAAc,GAAd,UAAe,QAAwC;QACnD,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,oCAAmB,GAAnB;QACI,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,OAAO,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC;IACtC,CAAC;IAED;;;OAGG;IACH,2BAAU,GAAV;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,UAAU,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACH,iCAAgB,GAAhB,UAAiB,UAAoB;QACjC,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,IAAI,CAAC,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE;YAC3C,IAAA,4CAAc,EACV,IAAI,CAAC,YAAY,EACjB,KAAK,CAAC,eAAe,EACrB,UAAU,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,EAC1C,IAAI,CAAC,gBAAgB,CACxB,CAAC;YAEF,IAAI,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC;YAEzC,IAAI,CAAC,GAAG,CAAC,YAAY,CACjB,IAAI,EACJ;gBACI,SAAS,EAAE,gBAAgB;gBAC3B,MAAM,EAAE,UAAU;oBACd,CAAC,CAAC,0CAAY,CAAC,gBAAgB;oBAC/B,CAAC,CAAC,0CAAY,CAAC,iBAAiB;gBACpC,QAAQ,EAAE,IAAI;aACjB,EACD,IAAI,CACP,CAAC;SACL;IACL,CAAC;IAED;;OAEG;IACH,+BAAc,GAAd;QACI,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,kBAAkB,CAAC;IACzD,CAAC;IAED;;;;;;;OAOG;IACH,gCAAe,GAAf;QACI,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,+BAAc,GAAd;QACI,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,gCAAe,GAAf;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,gBAAgB,CAAC;IAC3C,CAAC;IAED;;;;;;OAMG;IACH,sCAAqB,GAArB;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,kBAAkB,CAAC;IAC7C,CAAC;IAED;;;;;OAKG;IACH,8BAAa,GAAb;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,UAAU,CAAC;IACrC,CAAC;IAED;;OAEG;IACH,mCAAkB,GAAlB;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,eAAe,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,mCAAkB,GAAlB;QACI,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IACjE,CAAC;IAED;;;;;;OAMG;IACH,+BAAc,GAAd,UACI,GAAW,EACX,OAAsB,EACtB,YAA4C;QAE5C,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC;IAC9D,CAAC;IAED;;;OAGG;IACH,yBAAQ,GAAR,UAAS,YAA0B;QAC/B,IAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAE5B,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IAC1C,CAAC;IAED;;;OAGG;IACH,6CAA4B,GAA5B,UAA6B,WAAyC;QAClE,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,oBAAoB,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IACzE,CAAC;IAED;;;OAGG;IACO,wBAAO,GAAjB;QACI,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YACZ,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;SACjD;QACD,OAAO,IAAI,CAAC,IAAI,CAAC;IACrB,CAAC;IAoBL,aAAC;AAAD,CAAC,AAtaD,IAsaC;AAtaY,wBAAM","sourcesContent":["import { createEditorCore } from './core/createEditorCore';\nimport {\n createEmptyModel,\n ChangeSource,\n cloneModel,\n transformColor,\n createDomToModelContextWithConfig,\n domToContentModel,\n} from 'roosterjs-content-model-dom';\nimport type {\n ContentModelDocument,\n ContentModelFormatter,\n ContentModelSegmentFormat,\n DarkColorHandler,\n DOMEventRecord,\n DOMHelper,\n DOMSelection,\n EditorEnvironment,\n FormatContentModelOptions,\n IEditor,\n PluginEventData,\n PluginEventFromType,\n PluginEventType,\n Snapshot,\n SnapshotsManager,\n EditorCore,\n EditorOptions,\n Rect,\n EntityState,\n CachedElementHandler,\n DomToModelOptionForCreateModel,\n AnnounceData,\n ExperimentalFeature,\n LegacyTrustedHTMLHandler,\n DOMCreator,\n} from 'roosterjs-content-model-types';\n\n/**\n * The main editor class based on Content Model\n */\nexport class Editor implements IEditor {\n private core: EditorCore | null = null;\n\n /**\n * Creates an instance of Editor\n * @param contentDiv The DIV HTML element which will be the container element of editor\n * @param options An optional options object to customize the editor\n */\n constructor(contentDiv: HTMLDivElement, options: EditorOptions = {}) {\n this.core = createEditorCore(contentDiv, options);\n\n const initialModel =\n options.initialModel ?? createEmptyModel(this.core.format.defaultFormat);\n\n this.core.api.setContentModel(\n this.core,\n initialModel,\n { ignoreSelection: true },\n undefined /*onNodeCreated*/,\n true /*isInitializing*/\n );\n this.core.plugins.forEach(plugin => plugin.initialize(this));\n }\n\n /**\n * Dispose this editor, dispose all plugins and custom data\n */\n dispose() {\n const core = this.getCore();\n\n for (let i = core.plugins.length - 1; i >= 0; i--) {\n const plugin = core.plugins[i];\n\n try {\n plugin.dispose();\n } catch (e) {\n // Cache the error and pass it out, then keep going since dispose should always succeed\n core.disposeErrorHandler?.(plugin, e as Error);\n }\n }\n\n core.darkColorHandler.reset();\n\n this.core = null;\n }\n\n /**\n * Get whether this editor is disposed\n * @returns True if editor is disposed, otherwise false\n */\n isDisposed(): boolean {\n return !this.core;\n }\n\n /**\n * Create Content Model from DOM tree in this editor\n * @param mode What kind of Content Model we want. Currently we support the following values:\n * - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.\n * If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.\n * If editor is in dark mode, the cloned entity will be converted back to light mode.\n * - clean: Similar with disconnected, this will return a disconnected model, the difference is \"clean\" mode will not include any selection info.\n * This is usually used for exporting content\n */\n getContentModelCopy(mode: 'connected' | 'disconnected' | 'clean'): ContentModelDocument {\n const core = this.getCore();\n\n switch (mode) {\n case 'connected': // Get a connected model is deprecated. Now we will always return disconnected model\n case 'disconnected':\n return cloneModel(\n core.api.createContentModel(core, {\n tryGetFromCache: false,\n }),\n {\n includeCachedElement: this.cloneOptionCallback,\n }\n );\n\n case 'clean':\n const domToModelContext = createDomToModelContextWithConfig(\n core.environment.domToModelSettings.calculated,\n core.api.createEditorContext(core, false /*saveIndex*/)\n );\n\n return cloneModel(domToContentModel(core.physicalRoot, domToModelContext), {\n includeCachedElement: this.cloneOptionCallback,\n });\n }\n }\n\n /**\n * Get current running environment, such as if editor is running on Mac\n */\n getEnvironment(): EditorEnvironment {\n return this.getCore().environment;\n }\n\n /**\n * Get current DOM selection\n */\n getDOMSelection(): DOMSelection | null {\n const core = this.getCore();\n\n return core.api.getDOMSelection(core);\n }\n\n /**\n * Set DOMSelection into editor content.\n * @param selection The selection to set\n */\n setDOMSelection(selection: DOMSelection | null) {\n const core = this.getCore();\n\n core.api.setDOMSelection(core, selection);\n }\n\n /**\n * Set a new logical root (most likely due to focus change)\n * @param logicalRoot The new logical root (has to be child of physicalRoot)\n */\n setLogicalRoot(logicalRoot: HTMLDivElement) {\n const core = this.getCore();\n\n core.api.setLogicalRoot(core, logicalRoot);\n }\n\n /**\n * The general API to do format change with Content Model\n * It will grab a Content Model for current editor content, and invoke a callback function\n * to do format change. Then according to the return value, write back the modified content model into editor.\n * If there is cached model, it will be used and updated.\n * @param formatter Formatter function, see ContentModelFormatter\n * @param options More options, see FormatContentModelOptions\n */\n formatContentModel(\n formatter: ContentModelFormatter,\n options?: FormatContentModelOptions,\n domToModelOptions?: DomToModelOptionForCreateModel\n ): void {\n const core = this.getCore();\n\n core.api.formatContentModel(core, formatter, options, domToModelOptions);\n }\n\n /**\n * Get pending format of editor if any, or return null\n */\n getPendingFormat(): ContentModelSegmentFormat | null {\n return this.getCore().format.pendingFormat?.format ?? null;\n }\n\n /**\n * Get a DOM Helper object to help access DOM tree in editor\n */\n getDOMHelper(): DOMHelper {\n return this.getCore().domHelper;\n }\n\n /**\n * Add a single undo snapshot to undo stack\n * @param entityState @optional State for entity if we want to add entity state for this snapshot\n */\n takeSnapshot(entityState?: EntityState): Snapshot | null {\n const core = this.getCore();\n\n return core.api.addUndoSnapshot(\n core,\n false /*canUndoByBackspace*/,\n entityState ? [entityState] : undefined\n );\n }\n\n /**\n * Restore an undo snapshot into editor\n * @param snapshot The snapshot to restore\n */\n restoreSnapshot(snapshot: Snapshot): void {\n const core = this.getCore();\n\n core.api.restoreUndoSnapshot(core, snapshot);\n }\n\n /**\n * Get document which contains this editor\n * @returns The HTML document which contains this editor\n */\n getDocument(): Document {\n return this.getCore().physicalRoot.ownerDocument;\n }\n\n /**\n * Focus to this editor, the selection was restored to where it was before, no unexpected scroll.\n */\n focus() {\n const core = this.getCore();\n core.api.focus(core);\n }\n\n /**\n * Check if focus is in editor now\n * @returns true if focus is in editor, otherwise false\n */\n hasFocus(): boolean {\n const core = this.getCore();\n return core.domHelper.hasFocus();\n }\n\n /**\n * Trigger an event to be dispatched to all plugins\n * @param eventType Type of the event\n * @param data data of the event with given type, this is the rest part of PluginEvent with the given type\n * @param broadcast indicates if the event needs to be dispatched to all plugins\n * True means to all, false means to allow exclusive handling from one plugin unless no one wants that\n * @returns the event object which is really passed into plugins. Some plugin may modify the event object so\n * the result of this function provides a chance to read the modified result\n */\n triggerEvent<T extends PluginEventType>(\n eventType: T,\n data: PluginEventData<T>,\n broadcast: boolean = false\n ): PluginEventFromType<T> {\n const core = this.getCore();\n const event = ({\n eventType,\n ...data,\n } as any) as PluginEventFromType<T>;\n core.api.triggerEvent(core, event, broadcast);\n\n return event;\n }\n\n /**\n * Attach a DOM event to the editor content DIV\n * @param eventMap A map from event name to its handler\n */\n attachDomEvent(eventMap: Record<string, DOMEventRecord>): () => void {\n const core = this.getCore();\n return core.api.attachDomEvent(core, eventMap);\n }\n\n /**\n * Get undo snapshots manager\n */\n getSnapshotsManager(): SnapshotsManager {\n const core = this.getCore();\n\n return core.undo.snapshotsManager;\n }\n\n /**\n * Check if the editor is in dark mode\n * @returns True if the editor is in dark mode, otherwise false\n */\n isDarkMode(): boolean {\n return this.getCore().lifecycle.isDarkMode;\n }\n\n /**\n * Set the dark mode state and transforms the content to match the new state.\n * @param isDarkMode The next status of dark mode. True if the editor should be in dark mode, false if not.\n */\n setDarkModeState(isDarkMode?: boolean) {\n const core = this.getCore();\n\n if (!!isDarkMode != core.lifecycle.isDarkMode) {\n transformColor(\n core.physicalRoot,\n false /*includeSelf*/,\n isDarkMode ? 'lightToDark' : 'darkToLight',\n core.darkColorHandler\n );\n\n core.lifecycle.isDarkMode = !!isDarkMode;\n\n core.api.triggerEvent(\n core,\n {\n eventType: 'contentChanged',\n source: isDarkMode\n ? ChangeSource.SwitchToDarkMode\n : ChangeSource.SwitchToLightMode,\n skipUndo: true,\n },\n true\n );\n }\n }\n\n /**\n * Check if editor is in Shadow Edit mode\n */\n isInShadowEdit() {\n return !!this.getCore().lifecycle.shadowEditFragment;\n }\n\n /**\n * Make the editor in \"Shadow Edit\" mode.\n * In Shadow Edit mode, all format change will finally be ignored.\n * This can be used for building a live preview feature for format button, to allow user\n * see format result without really apply it.\n * This function can be called repeated. If editor is already in shadow edit mode, we can still\n * use this function to do more shadow edit operation.\n */\n startShadowEdit() {\n const core = this.getCore();\n core.api.switchShadowEdit(core, true /*isOn*/);\n }\n\n /**\n * Leave \"Shadow Edit\" mode, all changes made during shadow edit will be discarded\n */\n stopShadowEdit() {\n const core = this.getCore();\n core.api.switchShadowEdit(core, false /*isOn*/);\n }\n\n /**\n * Get a color manager object for this editor.\n */\n getColorManager(): DarkColorHandler {\n return this.getCore().darkColorHandler;\n }\n\n /**\n * @deprecated\n * Get a function to convert HTML string to trusted HTML string.\n * By default it will just return the input HTML directly. To override this behavior,\n * pass your own trusted HTML handler to EditorOptions.trustedHTMLHandler\n * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types\n */\n getTrustedHTMLHandler(): LegacyTrustedHTMLHandler {\n return this.getCore().trustedHTMLHandler;\n }\n\n /**\n * Get a function to convert HTML string to a trust Document.\n * By default it will just convert the original HTML string into a Document object directly.\n * To override, pass your own trusted HTML handler to EditorOptions.trustedHTMLHandler\n * See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/trusted-types\n */\n getDOMCreator(): DOMCreator {\n return this.getCore().domCreator;\n }\n\n /**\n * Get the scroll container of the editor\n */\n getScrollContainer(): HTMLElement {\n return this.getCore().domEvent.scrollContainer;\n }\n\n /**\n * Retrieves the rect of the visible viewport of the editor.\n */\n getVisibleViewport(): Rect | null {\n return this.getCore().api.getVisibleViewport(this.getCore());\n }\n\n /**\n * Add CSS rules for editor\n * @param key A string to identify the CSS rule type. When set CSS rules with the same key again, existing rules with the same key will be replaced.\n * @param cssRule The CSS rule string, must be a valid CSS rule string, or browser may throw exception. Pass null to clear existing rules\n * @param subSelectors @optional If the rule is used for child element under editor, use this parameter to specify the child elements. Each item will be\n * combined with root selector together to build a separate rule.\n */\n setEditorStyle(\n key: string,\n cssRule: string | null,\n subSelectors?: 'before' | 'after' | string[]\n ): void {\n const core = this.getCore();\n\n core.api.setEditorStyle(core, key, cssRule, subSelectors);\n }\n\n /**\n * Announce the given data\n * @param announceData Data to announce\n */\n announce(announceData: AnnounceData): void {\n const core = this.getCore();\n\n core.api.announce(core, announceData);\n }\n\n /**\n * Check if a given feature is enabled\n * @param featureName The name of feature to check\n */\n isExperimentalFeatureEnabled(featureName: ExperimentalFeature | string): boolean {\n return this.getCore().experimentalFeatures.indexOf(featureName) >= 0;\n }\n\n /**\n * @returns the current EditorCore object\n * @throws a standard Error if there's no core object\n */\n protected getCore(): EditorCore {\n if (!this.core) {\n throw new Error('Editor is already disposed');\n }\n return this.core;\n }\n\n private cloneOptionCallback: CachedElementHandler = (node, type) => {\n if (type == 'cache') {\n return undefined;\n }\n\n const result = node.cloneNode(true /*deep*/) as HTMLElement;\n\n if (this.isDarkMode()) {\n const colorHandler = this.getColorManager();\n\n transformColor(result, true /*includeSelf*/, 'darkToLight', colorHandler);\n\n result.style.color = result.style.color || 'inherit';\n result.style.backgroundColor = result.style.backgroundColor || 'inherit';\n }\n\n return result;\n };\n}\n"]}
|
|
@@ -52,6 +52,8 @@ define(["require", "exports", "tslib", "roosterjs-content-model-dom", "./scrollC
|
|
|
52
52
|
data: (_b = options === null || options === void 0 ? void 0 : options.getChangeData) === null || _b === void 0 ? void 0 : _b.call(options),
|
|
53
53
|
formatApiName: options === null || options === void 0 ? void 0 : options.apiName,
|
|
54
54
|
changedEntities: getChangedEntities(context, rawEvent),
|
|
55
|
+
skipUndo: !(shouldMarkNewContent || shouldAddSnapshot) ||
|
|
56
|
+
(options === null || options === void 0 ? void 0 : options.changeSource) == roosterjs_content_model_dom_1.ChangeSource.Keyboard, // Keyboard changes will be handled separately in undo plugin, so we need to skip handling it again
|
|
55
57
|
};
|
|
56
58
|
core.api.triggerEvent(core, eventData, true /*broadcast*/);
|
|
57
59
|
if (canUndoByBackspace && (selection === null || selection === void 0 ? void 0 : selection.type) == 'range') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatContentModel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { scrollCaretIntoView } from './scrollCaretIntoView';\nimport type {\n ChangedEntity,\n ContentChangedEvent,\n DOMSelection,\n FormatContentModel,\n FormatContentModelContext,\n EditorCore,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * The general API to do format change with Content Model\n * It will grab a Content Model for current editor content, and invoke a callback function\n * to do format change. Then according to the return value, write back the modified content model into editor.\n * If there is cached model, it will be used and updated.\n * @param core The EditorCore object\n * @param formatter Formatter function, see ContentModelFormatter\n * @param options More options, see FormatContentModelOptions\n */\nexport const formatContentModel: FormatContentModel = (\n core,\n formatter,\n options,\n domToModelOptions\n) => {\n const { onNodeCreated, rawEvent, selectionOverride, scrollCaretIntoView: scroll } =\n options || {};\n const model = core.api.createContentModel(core, domToModelOptions, selectionOverride);\n const context: FormatContentModelContext = {\n newEntities: [],\n deletedEntities: [],\n rawEvent,\n newImages: [],\n paragraphIndexer: core.cache.paragraphMap,\n };\n\n const hasFocus = core.domHelper.hasFocus();\n\n const changed = formatter(model, context);\n const { skipUndoSnapshot, clearModelCache, entityStates, canUndoByBackspace } = context;\n\n if (changed) {\n const isNested = core.undo.isNested;\n const shouldAddSnapshot =\n (!skipUndoSnapshot || skipUndoSnapshot == 'DoNotSkip') && !isNested;\n const shouldMarkNewContent =\n (skipUndoSnapshot === true || skipUndoSnapshot == 'MarkNewContent') && !isNested;\n let selection: DOMSelection | undefined;\n\n if (shouldAddSnapshot) {\n core.undo.isNested = true;\n\n core.api.addUndoSnapshot(core, !!canUndoByBackspace, entityStates);\n }\n\n try {\n handleImages(core, context);\n\n selection =\n core.api.setContentModel(\n core,\n model,\n hasFocus ? undefined : { ignoreSelection: true }, // If editor did not have focus before format, do not set focus after format\n onNodeCreated\n ) ?? undefined;\n\n handlePendingFormat(core, context, selection);\n\n if (scroll && (selection?.type == 'range' || selection?.type == 'image')) {\n scrollCaretIntoView(core, selection);\n }\n\n const eventData: ContentChangedEvent = {\n eventType: 'contentChanged',\n contentModel: clearModelCache ? undefined : model,\n selection: clearModelCache ? undefined : selection,\n source: options?.changeSource || ChangeSource.Format,\n data: options?.getChangeData?.(),\n formatApiName: options?.apiName,\n changedEntities: getChangedEntities(context, rawEvent),\n };\n\n core.api.triggerEvent(core, eventData, true /*broadcast*/);\n\n if (canUndoByBackspace && selection?.type == 'range') {\n core.undo.autoCompleteInsertPoint = {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n };\n }\n\n if (shouldAddSnapshot) {\n core.api.addUndoSnapshot(core, false /*canUndoByBackspace*/, entityStates);\n }\n\n if (shouldMarkNewContent) {\n core.undo.snapshotsManager.hasNewContent = true;\n }\n } finally {\n if (!isNested) {\n core.undo.isNested = false;\n }\n }\n } else {\n if (clearModelCache) {\n core.cache.cachedModel = undefined;\n core.cache.cachedSelection = undefined;\n }\n\n handlePendingFormat(core, context, core.api.getDOMSelection(core));\n }\n\n if (context.announceData) {\n core.api.announce(core, context.announceData);\n }\n};\n\nfunction handleImages(core: EditorCore, context: FormatContentModelContext) {\n if (context.newImages.length > 0) {\n const width = core.domHelper.getClientWidth();\n const minMaxImageSize = 10;\n const maxWidth = Math.max(width, minMaxImageSize);\n context.newImages.forEach(image => {\n image.format.maxWidth = `${maxWidth}px`;\n });\n }\n}\n\nfunction handlePendingFormat(\n core: EditorCore,\n context: FormatContentModelContext,\n selection?: DOMSelection | null\n) {\n const pendingFormat =\n context.newPendingFormat == 'preserve'\n ? core.format.pendingFormat?.format\n : context.newPendingFormat;\n const pendingParagraphFormat =\n context.newPendingParagraphFormat == 'preserve'\n ? core.format.pendingFormat?.paragraphFormat\n : context.newPendingParagraphFormat;\n\n if (\n (pendingFormat || pendingParagraphFormat) &&\n selection?.type == 'range' &&\n selection.range.collapsed\n ) {\n core.format.pendingFormat = {\n format: pendingFormat ? { ...pendingFormat } : undefined,\n paragraphFormat: pendingParagraphFormat ? { ...pendingParagraphFormat } : undefined,\n insertPoint: {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n },\n };\n }\n}\n\nfunction getChangedEntities(\n context: FormatContentModelContext,\n rawEvent?: Event\n): ChangedEntity[] | undefined {\n return context.autoDetectChangedEntities\n ? undefined\n : context.newEntities\n .map(\n (entity): ChangedEntity => ({\n entity,\n operation: 'newEntity',\n rawEvent,\n })\n )\n .concat(\n context.deletedEntities.map(entry => ({\n entity: entry.entity,\n operation: entry.operation,\n rawEvent,\n }))\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"formatContentModel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts"],"names":[],"mappings":"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","sourcesContent":["import { ChangeSource } from 'roosterjs-content-model-dom';\nimport { scrollCaretIntoView } from './scrollCaretIntoView';\nimport type {\n ChangedEntity,\n ContentChangedEvent,\n DOMSelection,\n FormatContentModel,\n FormatContentModelContext,\n EditorCore,\n} from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * The general API to do format change with Content Model\n * It will grab a Content Model for current editor content, and invoke a callback function\n * to do format change. Then according to the return value, write back the modified content model into editor.\n * If there is cached model, it will be used and updated.\n * @param core The EditorCore object\n * @param formatter Formatter function, see ContentModelFormatter\n * @param options More options, see FormatContentModelOptions\n */\nexport const formatContentModel: FormatContentModel = (\n core,\n formatter,\n options,\n domToModelOptions\n) => {\n const { onNodeCreated, rawEvent, selectionOverride, scrollCaretIntoView: scroll } =\n options || {};\n const model = core.api.createContentModel(core, domToModelOptions, selectionOverride);\n const context: FormatContentModelContext = {\n newEntities: [],\n deletedEntities: [],\n rawEvent,\n newImages: [],\n paragraphIndexer: core.cache.paragraphMap,\n };\n\n const hasFocus = core.domHelper.hasFocus();\n\n const changed = formatter(model, context);\n const { skipUndoSnapshot, clearModelCache, entityStates, canUndoByBackspace } = context;\n\n if (changed) {\n const isNested = core.undo.isNested;\n const shouldAddSnapshot =\n (!skipUndoSnapshot || skipUndoSnapshot == 'DoNotSkip') && !isNested;\n const shouldMarkNewContent =\n (skipUndoSnapshot === true || skipUndoSnapshot == 'MarkNewContent') && !isNested;\n let selection: DOMSelection | undefined;\n\n if (shouldAddSnapshot) {\n core.undo.isNested = true;\n\n core.api.addUndoSnapshot(core, !!canUndoByBackspace, entityStates);\n }\n\n try {\n handleImages(core, context);\n\n selection =\n core.api.setContentModel(\n core,\n model,\n hasFocus ? undefined : { ignoreSelection: true }, // If editor did not have focus before format, do not set focus after format\n onNodeCreated\n ) ?? undefined;\n\n handlePendingFormat(core, context, selection);\n\n if (scroll && (selection?.type == 'range' || selection?.type == 'image')) {\n scrollCaretIntoView(core, selection);\n }\n\n const eventData: ContentChangedEvent = {\n eventType: 'contentChanged',\n contentModel: clearModelCache ? undefined : model,\n selection: clearModelCache ? undefined : selection,\n source: options?.changeSource || ChangeSource.Format,\n data: options?.getChangeData?.(),\n formatApiName: options?.apiName,\n changedEntities: getChangedEntities(context, rawEvent),\n skipUndo:\n !(shouldMarkNewContent || shouldAddSnapshot) ||\n options?.changeSource == ChangeSource.Keyboard, // Keyboard changes will be handled separately in undo plugin, so we need to skip handling it again\n };\n\n core.api.triggerEvent(core, eventData, true /*broadcast*/);\n\n if (canUndoByBackspace && selection?.type == 'range') {\n core.undo.autoCompleteInsertPoint = {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n };\n }\n\n if (shouldAddSnapshot) {\n core.api.addUndoSnapshot(core, false /*canUndoByBackspace*/, entityStates);\n }\n\n if (shouldMarkNewContent) {\n core.undo.snapshotsManager.hasNewContent = true;\n }\n } finally {\n if (!isNested) {\n core.undo.isNested = false;\n }\n }\n } else {\n if (clearModelCache) {\n core.cache.cachedModel = undefined;\n core.cache.cachedSelection = undefined;\n }\n\n handlePendingFormat(core, context, core.api.getDOMSelection(core));\n }\n\n if (context.announceData) {\n core.api.announce(core, context.announceData);\n }\n};\n\nfunction handleImages(core: EditorCore, context: FormatContentModelContext) {\n if (context.newImages.length > 0) {\n const width = core.domHelper.getClientWidth();\n const minMaxImageSize = 10;\n const maxWidth = Math.max(width, minMaxImageSize);\n context.newImages.forEach(image => {\n image.format.maxWidth = `${maxWidth}px`;\n });\n }\n}\n\nfunction handlePendingFormat(\n core: EditorCore,\n context: FormatContentModelContext,\n selection?: DOMSelection | null\n) {\n const pendingFormat =\n context.newPendingFormat == 'preserve'\n ? core.format.pendingFormat?.format\n : context.newPendingFormat;\n const pendingParagraphFormat =\n context.newPendingParagraphFormat == 'preserve'\n ? core.format.pendingFormat?.paragraphFormat\n : context.newPendingParagraphFormat;\n\n if (\n (pendingFormat || pendingParagraphFormat) &&\n selection?.type == 'range' &&\n selection.range.collapsed\n ) {\n core.format.pendingFormat = {\n format: pendingFormat ? { ...pendingFormat } : undefined,\n paragraphFormat: pendingParagraphFormat ? { ...pendingParagraphFormat } : undefined,\n insertPoint: {\n node: selection.range.startContainer,\n offset: selection.range.startOffset,\n },\n };\n }\n}\n\nfunction getChangedEntities(\n context: FormatContentModelContext,\n rawEvent?: Event\n): ChangedEntity[] | undefined {\n return context.autoDetectChangedEntities\n ? undefined\n : context.newEntities\n .map(\n (entity): ChangedEntity => ({\n entity,\n operation: 'newEntity',\n rawEvent,\n })\n )\n .concat(\n context.deletedEntities.map(entry => ({\n entity: entry.entity,\n operation: entry.operation,\n rawEvent,\n }))\n );\n}\n"]}
|