roosterjs-content-model-core 9.22.0 → 9.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/coreApi/createEditorContext/createEditorContext.js +1 -1
- package/lib/coreApi/createEditorContext/createEditorContext.js.map +1 -1
- package/lib/coreApi/formatContentModel/formatContentModel.js +1 -0
- package/lib/coreApi/formatContentModel/formatContentModel.js.map +1 -1
- package/lib/corePlugin/cache/CachePlugin.js +14 -8
- package/lib/corePlugin/cache/CachePlugin.js.map +1 -1
- package/lib/corePlugin/cache/ParagraphMapImpl.d.ts +14 -0
- package/lib/corePlugin/cache/ParagraphMapImpl.js +68 -0
- package/lib/corePlugin/cache/ParagraphMapImpl.js.map +1 -0
- package/lib-amd/coreApi/createEditorContext/createEditorContext.js +1 -1
- package/lib-amd/coreApi/createEditorContext/createEditorContext.js.map +1 -1
- package/lib-amd/coreApi/formatContentModel/formatContentModel.js +1 -0
- package/lib-amd/coreApi/formatContentModel/formatContentModel.js.map +1 -1
- package/lib-amd/corePlugin/cache/CachePlugin.js +14 -9
- package/lib-amd/corePlugin/cache/CachePlugin.js.map +1 -1
- package/lib-amd/corePlugin/cache/ParagraphMapImpl.d.ts +14 -0
- package/lib-amd/corePlugin/cache/ParagraphMapImpl.js +69 -0
- package/lib-amd/corePlugin/cache/ParagraphMapImpl.js.map +1 -0
- package/lib-mjs/coreApi/createEditorContext/createEditorContext.js +1 -1
- package/lib-mjs/coreApi/createEditorContext/createEditorContext.js.map +1 -1
- package/lib-mjs/coreApi/formatContentModel/formatContentModel.js +1 -0
- package/lib-mjs/coreApi/formatContentModel/formatContentModel.js.map +1 -1
- package/lib-mjs/corePlugin/cache/CachePlugin.js +14 -8
- package/lib-mjs/corePlugin/cache/CachePlugin.js.map +1 -1
- package/lib-mjs/corePlugin/cache/ParagraphMapImpl.d.ts +14 -0
- package/lib-mjs/corePlugin/cache/ParagraphMapImpl.js +64 -0
- package/lib-mjs/corePlugin/cache/ParagraphMapImpl.js.map +1 -0
- package/package.json +3 -3
|
@@ -11,7 +11,7 @@ var createEditorContext = function (core, saveIndex) {
|
|
|
11
11
|
var _a, _b;
|
|
12
12
|
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, logicalRoot = core.logicalRoot, cache = core.cache, domHelper = core.domHelper;
|
|
13
13
|
saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;
|
|
14
|
-
var context = (0, tslib_1.__assign)({ isDarkMode: lifecycle.isDarkMode, defaultFormat: format.defaultFormat, pendingFormat: (_a = format.pendingFormat) !== null && _a !== void 0 ? _a : undefined, darkColorHandler: darkColorHandler, addDelimiterForEntity: true, allowCacheElement: true, domIndexer: saveIndex ? cache.domIndexer : undefined, zoomScale: domHelper.calculateZoomScale(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [] }, (0, getRootComputedStyleForContext_1.getRootComputedStyleForContext)(logicalRoot.ownerDocument));
|
|
14
|
+
var context = (0, tslib_1.__assign)({ isDarkMode: lifecycle.isDarkMode, defaultFormat: format.defaultFormat, pendingFormat: (_a = format.pendingFormat) !== null && _a !== void 0 ? _a : undefined, darkColorHandler: darkColorHandler, addDelimiterForEntity: true, allowCacheElement: true, domIndexer: saveIndex ? cache.domIndexer : undefined, zoomScale: domHelper.calculateZoomScale(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [], paragraphMap: core.cache.paragraphMap }, (0, getRootComputedStyleForContext_1.getRootComputedStyleForContext)(logicalRoot.ownerDocument));
|
|
15
15
|
if (core.domHelper.isRightToLeft()) {
|
|
16
16
|
context.isRootRtl = true;
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createEditorContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/createEditorContext/createEditorContext.ts"],"names":[],"mappings":";;;;AAAA,mFAAkF;AAGlF;;;GAGG;AACI,IAAM,mBAAmB,GAAwB,UAAC,IAAI,EAAE,SAAS;;IAC5D,IAAA,SAAS,GAA8D,IAAI,UAAlE,EAAE,MAAM,GAAsD,IAAI,OAA1D,EAAE,gBAAgB,GAAoC,IAAI,iBAAxC,EAAE,WAAW,GAAuB,IAAI,YAA3B,EAAE,KAAK,GAAgB,IAAI,MAApB,EAAE,SAAS,GAAK,IAAI,UAAT,CAAU;IAEpF,SAAS,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;IAE5D,IAAM,OAAO,2BACT,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,aAAa,EAAE,MAAA,MAAM,CAAC,aAAa,mCAAI,SAAS,EAChD,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,IAAI,EAC3B,iBAAiB,EAAE,IAAI,EACvB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EACpD,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,EACzC,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"createEditorContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/createEditorContext/createEditorContext.ts"],"names":[],"mappings":";;;;AAAA,mFAAkF;AAGlF;;;GAGG;AACI,IAAM,mBAAmB,GAAwB,UAAC,IAAI,EAAE,SAAS;;IAC5D,IAAA,SAAS,GAA8D,IAAI,UAAlE,EAAE,MAAM,GAAsD,IAAI,OAA1D,EAAE,gBAAgB,GAAoC,IAAI,iBAAxC,EAAE,WAAW,GAAuB,IAAI,YAA3B,EAAE,KAAK,GAAgB,IAAI,MAApB,EAAE,SAAS,GAAK,IAAI,UAAT,CAAU;IAEpF,SAAS,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;IAE5D,IAAM,OAAO,2BACT,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,aAAa,EAAE,MAAA,MAAM,CAAC,aAAa,mCAAI,SAAS,EAChD,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,IAAI,EAC3B,iBAAiB,EAAE,IAAI,EACvB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EACpD,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,EACzC,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,EAAE,EACrD,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,IAClC,IAAA,+DAA8B,EAAC,WAAW,CAAC,aAAa,CAAC,CAC/D,CAAC;IAEF,IAAI,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE;QAChC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;KAC5B;IAED,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC;AAxBW,QAAA,mBAAmB,uBAwB9B","sourcesContent":["import { getRootComputedStyleForContext } from './getRootComputedStyleForContext';\nimport type { EditorContext, CreateEditorContext } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Create a EditorContext object used by ContentModel API\n */\nexport const createEditorContext: CreateEditorContext = (core, saveIndex) => {\n const { lifecycle, format, darkColorHandler, logicalRoot, cache, domHelper } = core;\n\n saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;\n\n const context: EditorContext = {\n isDarkMode: lifecycle.isDarkMode,\n defaultFormat: format.defaultFormat,\n pendingFormat: format.pendingFormat ?? undefined,\n darkColorHandler: darkColorHandler,\n addDelimiterForEntity: true,\n allowCacheElement: true,\n domIndexer: saveIndex ? cache.domIndexer : undefined,\n zoomScale: domHelper.calculateZoomScale(),\n experimentalFeatures: core.experimentalFeatures ?? [],\n paragraphMap: core.cache.paragraphMap,\n ...getRootComputedStyleForContext(logicalRoot.ownerDocument),\n };\n\n if (core.domHelper.isRightToLeft()) {\n context.isRootRtl = true;\n }\n\n return context;\n};\n"]}
|
|
@@ -23,6 +23,7 @@ var formatContentModel = function (core, formatter, options, domToModelOptions)
|
|
|
23
23
|
deletedEntities: [],
|
|
24
24
|
rawEvent: rawEvent,
|
|
25
25
|
newImages: [],
|
|
26
|
+
paragraphIndexer: core.cache.paragraphMap,
|
|
26
27
|
};
|
|
27
28
|
var hasFocus = core.domHelper.hasFocus();
|
|
28
29
|
var changed = formatter(model, context);
|
|
@@ -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 };\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 };\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"]}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createCachePlugin = void 0;
|
|
4
4
|
var areSameSelections_1 = require("./areSameSelections");
|
|
5
|
+
var ParagraphMapImpl_1 = require("./ParagraphMapImpl");
|
|
5
6
|
var textMutationObserver_1 = require("./textMutationObserver");
|
|
6
7
|
var domIndexerImpl_1 = require("./domIndexerImpl");
|
|
7
8
|
var updateCache_1 = require("./updateCache");
|
|
@@ -47,13 +48,15 @@ var CachePlugin = /** @class */ (function () {
|
|
|
47
48
|
_this.updateCachedModel(_this.editor);
|
|
48
49
|
}
|
|
49
50
|
};
|
|
50
|
-
this.state =
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
51
|
+
this.state = {};
|
|
52
|
+
if (!option.disableCache) {
|
|
53
|
+
this.state.domIndexer = new domIndexerImpl_1.DomIndexerImpl(option.experimentalFeatures &&
|
|
54
|
+
option.experimentalFeatures.indexOf('PersistCache') >= 0);
|
|
55
|
+
this.state.textMutationObserver = (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation);
|
|
56
|
+
}
|
|
57
|
+
if (option.enableParagraphMap) {
|
|
58
|
+
this.state.paragraphMap = (0, ParagraphMapImpl_1.createParagraphMap)();
|
|
59
|
+
}
|
|
57
60
|
}
|
|
58
61
|
/**
|
|
59
62
|
* Get name of this plugin
|
|
@@ -135,10 +138,13 @@ var CachePlugin = /** @class */ (function () {
|
|
|
135
138
|
}
|
|
136
139
|
};
|
|
137
140
|
CachePlugin.prototype.invalidateCache = function () {
|
|
138
|
-
var _a;
|
|
141
|
+
var _a, _b;
|
|
139
142
|
if (!((_a = this.editor) === null || _a === void 0 ? void 0 : _a.isInShadowEdit())) {
|
|
140
143
|
this.state.cachedModel = undefined;
|
|
141
144
|
this.state.cachedSelection = undefined;
|
|
145
|
+
// Clear paragraph indexer to prevent stale references to old paragraphs
|
|
146
|
+
// It will be rebuild next time when we create a new Content Model
|
|
147
|
+
(_b = this.state.paragraphMap) === null || _b === void 0 ? void 0 : _b.clear();
|
|
142
148
|
}
|
|
143
149
|
};
|
|
144
150
|
CachePlugin.prototype.updateCachedModel = function (editor, forceUpdate) {
|
|
@@ -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 { 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 = option.disableCache\n ? {}\n : {\n domIndexer: new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 0\n ),\n textMutationObserver: createTextMutationObserver(contentDiv, this.onMutation),\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 }\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\n if (!option.disableCache) {\n this.state.domIndexer = new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 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"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ParagraphIndexer, ParagraphMap, ReadonlyContentModelParagraph } from 'roosterjs-content-model-types';
|
|
2
|
+
/**
|
|
3
|
+
* @internal, used by test code only
|
|
4
|
+
*/
|
|
5
|
+
export interface ParagraphMapReset {
|
|
6
|
+
_reset(): void;
|
|
7
|
+
_getMap(): {
|
|
8
|
+
[key: string]: ReadonlyContentModelParagraph;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function createParagraphMap(): ParagraphMap & ParagraphIndexer;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createParagraphMap = void 0;
|
|
4
|
+
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
|
|
5
|
+
var idPrefix = 'paragraph';
|
|
6
|
+
var ParagraphMapImpl = /** @class */ (function () {
|
|
7
|
+
function ParagraphMapImpl() {
|
|
8
|
+
this.nextId = 0;
|
|
9
|
+
this.paragraphMap = {};
|
|
10
|
+
ParagraphMapImpl.prefixNum++;
|
|
11
|
+
}
|
|
12
|
+
ParagraphMapImpl.prototype.assignMarkerToModel = function (element, paragraph) {
|
|
13
|
+
var marker = (0, roosterjs_content_model_dom_1.getParagraphMarker)(element);
|
|
14
|
+
var paragraphWithMarker = paragraph;
|
|
15
|
+
if (marker) {
|
|
16
|
+
paragraphWithMarker._marker = marker;
|
|
17
|
+
this.paragraphMap[marker] = paragraph;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
paragraphWithMarker._marker = this.generateId();
|
|
21
|
+
this.applyMarkerToDom(element, paragraph);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
ParagraphMapImpl.prototype.applyMarkerToDom = function (element, paragraph) {
|
|
25
|
+
var paragraphWithMarker = paragraph;
|
|
26
|
+
if (!paragraphWithMarker._marker) {
|
|
27
|
+
paragraphWithMarker._marker = this.generateId();
|
|
28
|
+
}
|
|
29
|
+
var marker = paragraphWithMarker._marker;
|
|
30
|
+
if (marker) {
|
|
31
|
+
(0, roosterjs_content_model_dom_1.setParagraphMarker)(element, marker);
|
|
32
|
+
this.paragraphMap[marker] = paragraph;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Get paragraph using a previously marked paragraph
|
|
37
|
+
* @param markedParagraph The previously marked paragraph to get
|
|
38
|
+
*/
|
|
39
|
+
ParagraphMapImpl.prototype.getParagraphFromMarker = function (markerParagraph) {
|
|
40
|
+
var marker = markerParagraph._marker;
|
|
41
|
+
return marker ? this.paragraphMap[marker] || null : null;
|
|
42
|
+
};
|
|
43
|
+
ParagraphMapImpl.prototype.clear = function () {
|
|
44
|
+
this.paragraphMap = {};
|
|
45
|
+
};
|
|
46
|
+
//#region For test code only
|
|
47
|
+
ParagraphMapImpl.prototype._reset = function () {
|
|
48
|
+
ParagraphMapImpl.prefixNum = 0;
|
|
49
|
+
this.nextId = 0;
|
|
50
|
+
};
|
|
51
|
+
ParagraphMapImpl.prototype._getMap = function () {
|
|
52
|
+
return this.paragraphMap;
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
ParagraphMapImpl.prototype.generateId = function () {
|
|
56
|
+
return idPrefix + "_" + ParagraphMapImpl.prefixNum + "_" + this.nextId++;
|
|
57
|
+
};
|
|
58
|
+
ParagraphMapImpl.prefixNum = 0;
|
|
59
|
+
return ParagraphMapImpl;
|
|
60
|
+
}());
|
|
61
|
+
/**
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
function createParagraphMap() {
|
|
65
|
+
return new ParagraphMapImpl();
|
|
66
|
+
}
|
|
67
|
+
exports.createParagraphMap = createParagraphMap;
|
|
68
|
+
//# sourceMappingURL=ParagraphMapImpl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParagraphMapImpl.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts"],"names":[],"mappings":";;;AAAA,2EAAqF;AAqBrF,IAAM,QAAQ,GAAG,WAAW,CAAC;AAE7B;IAKI;QAHQ,WAAM,GAAG,CAAC,CAAC;QACX,iBAAY,GAAqD,EAAE,CAAC;QAGxE,gBAAgB,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,8CAAmB,GAAnB,UAAoB,OAAoB,EAAE,SAAgC;QACtE,IAAM,MAAM,GAAG,IAAA,gDAAkB,EAAC,OAAO,CAAC,CAAC;QAC3C,IAAM,mBAAmB,GAAG,SAAgC,CAAC;QAE7D,IAAI,MAAM,EAAE;YACR,mBAAmB,CAAC,OAAO,GAAG,MAAM,CAAC;YAErC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;SACzC;aAAM;YACH,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAEhD,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;SAC7C;IACL,CAAC;IAED,2CAAgB,GAAhB,UAAiB,OAAoB,EAAE,SAAgC;QACnE,IAAM,mBAAmB,GAAG,SAAgC,CAAC;QAE7D,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;YAC9B,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;SACnD;QAED,IAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC;QAE3C,IAAI,MAAM,EAAE;YACR,IAAA,gDAAkB,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAEpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;SACzC;IACL,CAAC;IAED;;;OAGG;IACH,iDAAsB,GAAtB,UACI,eAA8C;QAE9C,IAAM,MAAM,GAAI,eAAuC,CAAC,OAAO,CAAC;QAEhE,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IAED,gCAAK,GAAL;QACI,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,4BAA4B;IAC5B,iCAAM,GAAN;QACI,gBAAgB,CAAC,SAAS,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACpB,CAAC;IAED,kCAAO,GAAP;QACI,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IACD,YAAY;IAEJ,qCAAU,GAAlB;QACI,OAAU,QAAQ,SAAI,gBAAgB,CAAC,SAAS,SAAI,IAAI,CAAC,MAAM,EAAI,CAAC;IACxE,CAAC;IApEc,0BAAS,GAAG,CAAC,CAAC;IAqEjC,uBAAC;CAAA,AAtED,IAsEC;AAED;;GAEG;AACH,SAAgB,kBAAkB;IAC9B,OAAO,IAAI,gBAAgB,EAAE,CAAC;AAClC,CAAC;AAFD,gDAEC","sourcesContent":["import { getParagraphMarker, setParagraphMarker } from 'roosterjs-content-model-dom';\nimport type {\n ContentModelParagraph,\n ContentModelParagraphCommon,\n ParagraphIndexer,\n ParagraphMap,\n ReadonlyContentModelParagraph,\n} from 'roosterjs-content-model-types';\n\ninterface ParagraphWithMarker extends ContentModelParagraphCommon {\n _marker?: string;\n}\n\n/**\n * @internal, used by test code only\n */\nexport interface ParagraphMapReset {\n _reset(): void;\n _getMap(): { [key: string]: ReadonlyContentModelParagraph };\n}\n\nconst idPrefix = 'paragraph';\n\nclass ParagraphMapImpl implements ParagraphMap, ParagraphIndexer, ParagraphMapReset {\n private static prefixNum = 0;\n private nextId = 0;\n private paragraphMap: { [key: string]: ReadonlyContentModelParagraph } = {};\n\n constructor() {\n ParagraphMapImpl.prefixNum++;\n }\n\n assignMarkerToModel(element: HTMLElement, paragraph: ContentModelParagraph): void {\n const marker = getParagraphMarker(element);\n const paragraphWithMarker = paragraph as ParagraphWithMarker;\n\n if (marker) {\n paragraphWithMarker._marker = marker;\n\n this.paragraphMap[marker] = paragraph;\n } else {\n paragraphWithMarker._marker = this.generateId();\n\n this.applyMarkerToDom(element, paragraph);\n }\n }\n\n applyMarkerToDom(element: HTMLElement, paragraph: ContentModelParagraph): void {\n const paragraphWithMarker = paragraph as ParagraphWithMarker;\n\n if (!paragraphWithMarker._marker) {\n paragraphWithMarker._marker = this.generateId();\n }\n\n const marker = paragraphWithMarker._marker;\n\n if (marker) {\n setParagraphMarker(element, marker);\n\n this.paragraphMap[marker] = paragraph;\n }\n }\n\n /**\n * Get paragraph using a previously marked paragraph\n * @param markedParagraph The previously marked paragraph to get\n */\n getParagraphFromMarker(\n markerParagraph: ReadonlyContentModelParagraph\n ): ReadonlyContentModelParagraph | null {\n const marker = (markerParagraph as ParagraphWithMarker)._marker;\n\n return marker ? this.paragraphMap[marker] || null : null;\n }\n\n clear() {\n this.paragraphMap = {};\n }\n\n //#region For test code only\n _reset() {\n ParagraphMapImpl.prefixNum = 0;\n this.nextId = 0;\n }\n\n _getMap() {\n return this.paragraphMap;\n }\n //#endregion\n\n private generateId() {\n return `${idPrefix}_${ParagraphMapImpl.prefixNum}_${this.nextId++}`;\n }\n}\n\n/**\n * @internal\n */\nexport function createParagraphMap(): ParagraphMap & ParagraphIndexer {\n return new ParagraphMapImpl();\n}\n"]}
|
|
@@ -10,7 +10,7 @@ define(["require", "exports", "tslib", "./getRootComputedStyleForContext"], func
|
|
|
10
10
|
var _a, _b;
|
|
11
11
|
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, logicalRoot = core.logicalRoot, cache = core.cache, domHelper = core.domHelper;
|
|
12
12
|
saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;
|
|
13
|
-
var context = (0, tslib_1.__assign)({ isDarkMode: lifecycle.isDarkMode, defaultFormat: format.defaultFormat, pendingFormat: (_a = format.pendingFormat) !== null && _a !== void 0 ? _a : undefined, darkColorHandler: darkColorHandler, addDelimiterForEntity: true, allowCacheElement: true, domIndexer: saveIndex ? cache.domIndexer : undefined, zoomScale: domHelper.calculateZoomScale(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [] }, (0, getRootComputedStyleForContext_1.getRootComputedStyleForContext)(logicalRoot.ownerDocument));
|
|
13
|
+
var context = (0, tslib_1.__assign)({ isDarkMode: lifecycle.isDarkMode, defaultFormat: format.defaultFormat, pendingFormat: (_a = format.pendingFormat) !== null && _a !== void 0 ? _a : undefined, darkColorHandler: darkColorHandler, addDelimiterForEntity: true, allowCacheElement: true, domIndexer: saveIndex ? cache.domIndexer : undefined, zoomScale: domHelper.calculateZoomScale(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [], paragraphMap: core.cache.paragraphMap }, (0, getRootComputedStyleForContext_1.getRootComputedStyleForContext)(logicalRoot.ownerDocument));
|
|
14
14
|
if (core.domHelper.isRightToLeft()) {
|
|
15
15
|
context.isRootRtl = true;
|
|
16
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createEditorContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/createEditorContext/createEditorContext.ts"],"names":[],"mappings":";;;;IAGA;;;OAGG;IACI,IAAM,mBAAmB,GAAwB,UAAC,IAAI,EAAE,SAAS;;QAC5D,IAAA,SAAS,GAA8D,IAAI,UAAlE,EAAE,MAAM,GAAsD,IAAI,OAA1D,EAAE,gBAAgB,GAAoC,IAAI,iBAAxC,EAAE,WAAW,GAAuB,IAAI,YAA3B,EAAE,KAAK,GAAgB,IAAI,MAApB,EAAE,SAAS,GAAK,IAAI,UAAT,CAAU;QAEpF,SAAS,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;QAE5D,IAAM,OAAO,2BACT,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,aAAa,EAAE,MAAA,MAAM,CAAC,aAAa,mCAAI,SAAS,EAChD,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,IAAI,EAC3B,iBAAiB,EAAE,IAAI,EACvB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EACpD,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,EACzC,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"createEditorContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/createEditorContext/createEditorContext.ts"],"names":[],"mappings":";;;;IAGA;;;OAGG;IACI,IAAM,mBAAmB,GAAwB,UAAC,IAAI,EAAE,SAAS;;QAC5D,IAAA,SAAS,GAA8D,IAAI,UAAlE,EAAE,MAAM,GAAsD,IAAI,OAA1D,EAAE,gBAAgB,GAAoC,IAAI,iBAAxC,EAAE,WAAW,GAAuB,IAAI,YAA3B,EAAE,KAAK,GAAgB,IAAI,MAApB,EAAE,SAAS,GAAK,IAAI,UAAT,CAAU;QAEpF,SAAS,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;QAE5D,IAAM,OAAO,2BACT,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,aAAa,EAAE,MAAA,MAAM,CAAC,aAAa,mCAAI,SAAS,EAChD,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,IAAI,EAC3B,iBAAiB,EAAE,IAAI,EACvB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EACpD,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,EACzC,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,EAAE,EACrD,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,IAClC,IAAA,+DAA8B,EAAC,WAAW,CAAC,aAAa,CAAC,CAC/D,CAAC;QAEF,IAAI,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE;YAChC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;SAC5B;QAED,OAAO,OAAO,CAAC;IACnB,CAAC,CAAC;IAxBW,QAAA,mBAAmB,uBAwB9B","sourcesContent":["import { getRootComputedStyleForContext } from './getRootComputedStyleForContext';\nimport type { EditorContext, CreateEditorContext } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Create a EditorContext object used by ContentModel API\n */\nexport const createEditorContext: CreateEditorContext = (core, saveIndex) => {\n const { lifecycle, format, darkColorHandler, logicalRoot, cache, domHelper } = core;\n\n saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;\n\n const context: EditorContext = {\n isDarkMode: lifecycle.isDarkMode,\n defaultFormat: format.defaultFormat,\n pendingFormat: format.pendingFormat ?? undefined,\n darkColorHandler: darkColorHandler,\n addDelimiterForEntity: true,\n allowCacheElement: true,\n domIndexer: saveIndex ? cache.domIndexer : undefined,\n zoomScale: domHelper.calculateZoomScale(),\n experimentalFeatures: core.experimentalFeatures ?? [],\n paragraphMap: core.cache.paragraphMap,\n ...getRootComputedStyleForContext(logicalRoot.ownerDocument),\n };\n\n if (core.domHelper.isRightToLeft()) {\n context.isRootRtl = true;\n }\n\n return context;\n};\n"]}
|
|
@@ -21,6 +21,7 @@ define(["require", "exports", "tslib", "roosterjs-content-model-dom", "./scrollC
|
|
|
21
21
|
deletedEntities: [],
|
|
22
22
|
rawEvent: rawEvent,
|
|
23
23
|
newImages: [],
|
|
24
|
+
paragraphIndexer: core.cache.paragraphMap,
|
|
24
25
|
};
|
|
25
26
|
var hasFocus = core.domHelper.hasFocus();
|
|
26
27
|
var changed = formatter(model, context);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formatContentModel.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/formatContentModel/formatContentModel.ts"],"names":[],"mappings":";;;;IAWA;;;;;;;;;OASG;IACI,IAAM,kBAAkB,GAAuB,UAClD,IAAI,EACJ,SAAS,EACT,OAAO,EACP,iBAAiB;;QAEX,IAAA,KACF,OAAO,IAAI,EAAE,EADT,aAAa,mBAAA,EAAE,QAAQ,cAAA,EAAE,iBAAiB,uBAAA,EAAuB,MAAM,yBAC9D,CAAC;QAClB,IAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;QACtF,IAAM,OAAO,GAA8B;YACvC,WAAW,EAAE,EAAE;YACf,eAAe,EAAE,EAAE;YACnB,QAAQ,UAAA;YACR,SAAS,EAAE,EAAE;SAChB,CAAC;QAEF,IAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;QAE3C,IAAM,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClC,IAAA,gBAAgB,GAAwD,OAAO,iBAA/D,EAAE,eAAe,GAAuC,OAAO,gBAA9C,EAAE,YAAY,GAAyB,OAAO,aAAhC,EAAE,kBAAkB,GAAK,OAAO,mBAAZ,CAAa;QAExF,IAAI,OAAO,EAAE;YACT,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;YACpC,IAAM,iBAAiB,GACnB,CAAC,CAAC,gBAAgB,IAAI,gBAAgB,IAAI,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;YACxE,IAAM,oBAAoB,GACtB,CAAC,gBAAgB,KAAK,IAAI,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC;YACrF,IAAI,SAAS,SAA0B,CAAC;YAExC,IAAI,iBAAiB,EAAE;gBACnB,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAE1B,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;aACtE;YAED,IAAI;gBACA,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAE5B,SAAS;oBACL,MAAA,IAAI,CAAC,GAAG,CAAC,eAAe,CACpB,IAAI,EACJ,KAAK,EACL,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,4EAA4E;oBAC9H,aAAa,CAChB,mCAAI,SAAS,CAAC;gBAEnB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;gBAE9C,IAAI,MAAM,IAAI,CAAC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,IAAI,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,CAAC,EAAE;oBACtE,IAAA,yCAAmB,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC;iBACxC;gBAED,IAAM,SAAS,GAAwB;oBACnC,SAAS,EAAE,gBAAgB;oBAC3B,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;oBACjD,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;oBAClD,MAAM,EAAE,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAAY,KAAI,0CAAY,CAAC,MAAM;oBACpD,IAAI,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa,+CAAtB,OAAO,CAAmB;oBAChC,aAAa,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO;oBAC/B,eAAe,EAAE,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC;iBACzD,CAAC;gBAEF,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;gBAE3D,IAAI,kBAAkB,IAAI,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,EAAE;oBAClD,IAAI,CAAC,IAAI,CAAC,uBAAuB,GAAG;wBAChC,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,cAAc;wBACpC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,WAAW;qBACtC,CAAC;iBACL;gBAED,IAAI,iBAAiB,EAAE;oBACnB,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,sBAAsB,EAAE,YAAY,CAAC,CAAC;iBAC9E;gBAED,IAAI,oBAAoB,EAAE;oBACtB,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,GAAG,IAAI,CAAC;iBACnD;aACJ;oBAAS;gBACN,IAAI,CAAC,QAAQ,EAAE;oBACX,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;iBAC9B;aACJ;SACJ;aAAM;YACH,IAAI,eAAe,EAAE;gBACjB,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC;gBACnC,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,SAAS,CAAC;aAC1C;YAED,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;SACtE;QAED,IAAI,OAAO,CAAC,YAAY,EAAE;YACtB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;SACjD;IACL,CAAC,CAAC;IA/FW,QAAA,kBAAkB,sBA+F7B;IAEF,SAAS,YAAY,CAAC,IAAgB,EAAE,OAAkC;QACtE,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9B,IAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;YAC9C,IAAM,eAAe,GAAG,EAAE,CAAC;YAC3B,IAAM,UAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;YAClD,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,UAAA,KAAK;gBAC3B,KAAK,CAAC,MAAM,CAAC,QAAQ,GAAM,UAAQ,OAAI,CAAC;YAC5C,CAAC,CAAC,CAAC;SACN;IACL,CAAC;IAED,SAAS,mBAAmB,CACxB,IAAgB,EAChB,OAAkC,EAClC,SAA+B;;QAE/B,IAAM,aAAa,GACf,OAAO,CAAC,gBAAgB,IAAI,UAAU;YAClC,CAAC,CAAC,MAAA,IAAI,CAAC,MAAM,CAAC,aAAa,0CAAE,MAAM;YACnC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;QACnC,IAAM,sBAAsB,GACxB,OAAO,CAAC,yBAAyB,IAAI,UAAU;YAC3C,CAAC,CAAC,MAAA,IAAI,CAAC,MAAM,CAAC,aAAa,0CAAE,eAAe;YAC5C,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC;QAE5C,IACI,CAAC,aAAa,IAAI,sBAAsB,CAAC;YACzC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO;YAC1B,SAAS,CAAC,KAAK,CAAC,SAAS,EAC3B;YACE,IAAI,CAAC,MAAM,CAAC,aAAa,GAAG;gBACxB,MAAM,EAAE,aAAa,CAAC,CAAC,2BAAM,aAAa,EAAG,CAAC,CAAC,SAAS;gBACxD,eAAe,EAAE,sBAAsB,CAAC,CAAC,2BAAM,sBAAsB,EAAG,CAAC,CAAC,SAAS;gBACnF,WAAW,EAAE;oBACT,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,cAAc;oBACpC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,WAAW;iBACtC;aACJ,CAAC;SACL;IACL,CAAC;IAED,SAAS,kBAAkB,CACvB,OAAkC,EAClC,QAAgB;QAEhB,OAAO,OAAO,CAAC,yBAAyB;YACpC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,OAAO,CAAC,WAAW;iBACd,GAAG,CACA,UAAC,MAAM,IAAoB,OAAA,CAAC;gBACxB,MAAM,QAAA;gBACN,SAAS,EAAE,WAAW;gBACtB,QAAQ,UAAA;aACX,CAAC,EAJyB,CAIzB,CACL;iBACA,MAAM,CACH,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,UAAA,KAAK,IAAI,OAAA,CAAC;gBAClC,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,QAAQ,UAAA;aACX,CAAC,EAJmC,CAInC,CAAC,CACN,CAAC;IAChB,CAAC","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 };\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":";;;;IAWA;;;;;;;;;OASG;IACI,IAAM,kBAAkB,GAAuB,UAClD,IAAI,EACJ,SAAS,EACT,OAAO,EACP,iBAAiB;;QAEX,IAAA,KACF,OAAO,IAAI,EAAE,EADT,aAAa,mBAAA,EAAE,QAAQ,cAAA,EAAE,iBAAiB,uBAAA,EAAuB,MAAM,yBAC9D,CAAC;QAClB,IAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,EAAE,iBAAiB,CAAC,CAAC;QACtF,IAAM,OAAO,GAA8B;YACvC,WAAW,EAAE,EAAE;YACf,eAAe,EAAE,EAAE;YACnB,QAAQ,UAAA;YACR,SAAS,EAAE,EAAE;YACb,gBAAgB,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY;SAC5C,CAAC;QAEF,IAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;QAE3C,IAAM,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAClC,IAAA,gBAAgB,GAAwD,OAAO,iBAA/D,EAAE,eAAe,GAAuC,OAAO,gBAA9C,EAAE,YAAY,GAAyB,OAAO,aAAhC,EAAE,kBAAkB,GAAK,OAAO,mBAAZ,CAAa;QAExF,IAAI,OAAO,EAAE;YACT,IAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;YACpC,IAAM,iBAAiB,GACnB,CAAC,CAAC,gBAAgB,IAAI,gBAAgB,IAAI,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC;YACxE,IAAM,oBAAoB,GACtB,CAAC,gBAAgB,KAAK,IAAI,IAAI,gBAAgB,IAAI,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAC;YACrF,IAAI,SAAS,SAA0B,CAAC;YAExC,IAAI,iBAAiB,EAAE;gBACnB,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAE1B,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;aACtE;YAED,IAAI;gBACA,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;gBAE5B,SAAS;oBACL,MAAA,IAAI,CAAC,GAAG,CAAC,eAAe,CACpB,IAAI,EACJ,KAAK,EACL,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,EAAE,4EAA4E;oBAC9H,aAAa,CAChB,mCAAI,SAAS,CAAC;gBAEnB,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;gBAE9C,IAAI,MAAM,IAAI,CAAC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,IAAI,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,CAAC,EAAE;oBACtE,IAAA,yCAAmB,EAAC,IAAI,EAAE,SAAS,CAAC,CAAC;iBACxC;gBAED,IAAM,SAAS,GAAwB;oBACnC,SAAS,EAAE,gBAAgB;oBAC3B,YAAY,EAAE,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;oBACjD,SAAS,EAAE,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS;oBAClD,MAAM,EAAE,CAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,YAAY,KAAI,0CAAY,CAAC,MAAM;oBACpD,IAAI,EAAE,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,aAAa,+CAAtB,OAAO,CAAmB;oBAChC,aAAa,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,OAAO;oBAC/B,eAAe,EAAE,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC;iBACzD,CAAC;gBAEF,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;gBAE3D,IAAI,kBAAkB,IAAI,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO,EAAE;oBAClD,IAAI,CAAC,IAAI,CAAC,uBAAuB,GAAG;wBAChC,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,cAAc;wBACpC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,WAAW;qBACtC,CAAC;iBACL;gBAED,IAAI,iBAAiB,EAAE;oBACnB,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,CAAC,sBAAsB,EAAE,YAAY,CAAC,CAAC;iBAC9E;gBAED,IAAI,oBAAoB,EAAE;oBACtB,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,aAAa,GAAG,IAAI,CAAC;iBACnD;aACJ;oBAAS;gBACN,IAAI,CAAC,QAAQ,EAAE;oBACX,IAAI,CAAC,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;iBAC9B;aACJ;SACJ;aAAM;YACH,IAAI,eAAe,EAAE;gBACjB,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,SAAS,CAAC;gBACnC,IAAI,CAAC,KAAK,CAAC,eAAe,GAAG,SAAS,CAAC;aAC1C;YAED,mBAAmB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC;SACtE;QAED,IAAI,OAAO,CAAC,YAAY,EAAE;YACtB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;SACjD;IACL,CAAC,CAAC;IAhGW,QAAA,kBAAkB,sBAgG7B;IAEF,SAAS,YAAY,CAAC,IAAgB,EAAE,OAAkC;QACtE,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE;YAC9B,IAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;YAC9C,IAAM,eAAe,GAAG,EAAE,CAAC;YAC3B,IAAM,UAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,eAAe,CAAC,CAAC;YAClD,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,UAAA,KAAK;gBAC3B,KAAK,CAAC,MAAM,CAAC,QAAQ,GAAM,UAAQ,OAAI,CAAC;YAC5C,CAAC,CAAC,CAAC;SACN;IACL,CAAC;IAED,SAAS,mBAAmB,CACxB,IAAgB,EAChB,OAAkC,EAClC,SAA+B;;QAE/B,IAAM,aAAa,GACf,OAAO,CAAC,gBAAgB,IAAI,UAAU;YAClC,CAAC,CAAC,MAAA,IAAI,CAAC,MAAM,CAAC,aAAa,0CAAE,MAAM;YACnC,CAAC,CAAC,OAAO,CAAC,gBAAgB,CAAC;QACnC,IAAM,sBAAsB,GACxB,OAAO,CAAC,yBAAyB,IAAI,UAAU;YAC3C,CAAC,CAAC,MAAA,IAAI,CAAC,MAAM,CAAC,aAAa,0CAAE,eAAe;YAC5C,CAAC,CAAC,OAAO,CAAC,yBAAyB,CAAC;QAE5C,IACI,CAAC,aAAa,IAAI,sBAAsB,CAAC;YACzC,CAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,IAAI,KAAI,OAAO;YAC1B,SAAS,CAAC,KAAK,CAAC,SAAS,EAC3B;YACE,IAAI,CAAC,MAAM,CAAC,aAAa,GAAG;gBACxB,MAAM,EAAE,aAAa,CAAC,CAAC,2BAAM,aAAa,EAAG,CAAC,CAAC,SAAS;gBACxD,eAAe,EAAE,sBAAsB,CAAC,CAAC,2BAAM,sBAAsB,EAAG,CAAC,CAAC,SAAS;gBACnF,WAAW,EAAE;oBACT,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,cAAc;oBACpC,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,WAAW;iBACtC;aACJ,CAAC;SACL;IACL,CAAC;IAED,SAAS,kBAAkB,CACvB,OAAkC,EAClC,QAAgB;QAEhB,OAAO,OAAO,CAAC,yBAAyB;YACpC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,OAAO,CAAC,WAAW;iBACd,GAAG,CACA,UAAC,MAAM,IAAoB,OAAA,CAAC;gBACxB,MAAM,QAAA;gBACN,SAAS,EAAE,WAAW;gBACtB,QAAQ,UAAA;aACX,CAAC,EAJyB,CAIzB,CACL;iBACA,MAAM,CACH,OAAO,CAAC,eAAe,CAAC,GAAG,CAAC,UAAA,KAAK,IAAI,OAAA,CAAC;gBAClC,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,QAAQ,UAAA;aACX,CAAC,EAJmC,CAInC,CAAC,CACN,CAAC;IAChB,CAAC","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,4 +1,4 @@
|
|
|
1
|
-
define(["require", "exports", "./areSameSelections", "./textMutationObserver", "./domIndexerImpl", "./updateCache"], function (require, exports, areSameSelections_1, textMutationObserver_1, domIndexerImpl_1, updateCache_1) {
|
|
1
|
+
define(["require", "exports", "./areSameSelections", "./ParagraphMapImpl", "./textMutationObserver", "./domIndexerImpl", "./updateCache"], function (require, exports, areSameSelections_1, ParagraphMapImpl_1, textMutationObserver_1, domIndexerImpl_1, updateCache_1) {
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.createCachePlugin = void 0;
|
|
@@ -44,13 +44,15 @@ define(["require", "exports", "./areSameSelections", "./textMutationObserver", "
|
|
|
44
44
|
_this.updateCachedModel(_this.editor);
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
|
-
this.state =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
this.state = {};
|
|
48
|
+
if (!option.disableCache) {
|
|
49
|
+
this.state.domIndexer = new domIndexerImpl_1.DomIndexerImpl(option.experimentalFeatures &&
|
|
50
|
+
option.experimentalFeatures.indexOf('PersistCache') >= 0);
|
|
51
|
+
this.state.textMutationObserver = (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation);
|
|
52
|
+
}
|
|
53
|
+
if (option.enableParagraphMap) {
|
|
54
|
+
this.state.paragraphMap = (0, ParagraphMapImpl_1.createParagraphMap)();
|
|
55
|
+
}
|
|
54
56
|
}
|
|
55
57
|
/**
|
|
56
58
|
* Get name of this plugin
|
|
@@ -132,10 +134,13 @@ define(["require", "exports", "./areSameSelections", "./textMutationObserver", "
|
|
|
132
134
|
}
|
|
133
135
|
};
|
|
134
136
|
CachePlugin.prototype.invalidateCache = function () {
|
|
135
|
-
var _a;
|
|
137
|
+
var _a, _b;
|
|
136
138
|
if (!((_a = this.editor) === null || _a === void 0 ? void 0 : _a.isInShadowEdit())) {
|
|
137
139
|
this.state.cachedModel = undefined;
|
|
138
140
|
this.state.cachedSelection = undefined;
|
|
141
|
+
// Clear paragraph indexer to prevent stale references to old paragraphs
|
|
142
|
+
// It will be rebuild next time when we create a new Content Model
|
|
143
|
+
(_b = this.state.paragraphMap) === null || _b === void 0 ? void 0 : _b.clear();
|
|
139
144
|
}
|
|
140
145
|
};
|
|
141
146
|
CachePlugin.prototype.updateCachedModel = function (editor, forceUpdate) {
|
|
@@ -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 { 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 = option.disableCache\n ? {}\n : {\n domIndexer: new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 0\n ),\n textMutationObserver: createTextMutationObserver(contentDiv, this.onMutation),\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 }\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\n if (!option.disableCache) {\n this.state.domIndexer = new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 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"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ParagraphIndexer, ParagraphMap, ReadonlyContentModelParagraph } from 'roosterjs-content-model-types';
|
|
2
|
+
/**
|
|
3
|
+
* @internal, used by test code only
|
|
4
|
+
*/
|
|
5
|
+
export interface ParagraphMapReset {
|
|
6
|
+
_reset(): void;
|
|
7
|
+
_getMap(): {
|
|
8
|
+
[key: string]: ReadonlyContentModelParagraph;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function createParagraphMap(): ParagraphMap & ParagraphIndexer;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
define(["require", "exports", "roosterjs-content-model-dom"], function (require, exports, roosterjs_content_model_dom_1) {
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.createParagraphMap = void 0;
|
|
5
|
+
var idPrefix = 'paragraph';
|
|
6
|
+
var ParagraphMapImpl = /** @class */ (function () {
|
|
7
|
+
function ParagraphMapImpl() {
|
|
8
|
+
this.nextId = 0;
|
|
9
|
+
this.paragraphMap = {};
|
|
10
|
+
ParagraphMapImpl.prefixNum++;
|
|
11
|
+
}
|
|
12
|
+
ParagraphMapImpl.prototype.assignMarkerToModel = function (element, paragraph) {
|
|
13
|
+
var marker = (0, roosterjs_content_model_dom_1.getParagraphMarker)(element);
|
|
14
|
+
var paragraphWithMarker = paragraph;
|
|
15
|
+
if (marker) {
|
|
16
|
+
paragraphWithMarker._marker = marker;
|
|
17
|
+
this.paragraphMap[marker] = paragraph;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
paragraphWithMarker._marker = this.generateId();
|
|
21
|
+
this.applyMarkerToDom(element, paragraph);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
ParagraphMapImpl.prototype.applyMarkerToDom = function (element, paragraph) {
|
|
25
|
+
var paragraphWithMarker = paragraph;
|
|
26
|
+
if (!paragraphWithMarker._marker) {
|
|
27
|
+
paragraphWithMarker._marker = this.generateId();
|
|
28
|
+
}
|
|
29
|
+
var marker = paragraphWithMarker._marker;
|
|
30
|
+
if (marker) {
|
|
31
|
+
(0, roosterjs_content_model_dom_1.setParagraphMarker)(element, marker);
|
|
32
|
+
this.paragraphMap[marker] = paragraph;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Get paragraph using a previously marked paragraph
|
|
37
|
+
* @param markedParagraph The previously marked paragraph to get
|
|
38
|
+
*/
|
|
39
|
+
ParagraphMapImpl.prototype.getParagraphFromMarker = function (markerParagraph) {
|
|
40
|
+
var marker = markerParagraph._marker;
|
|
41
|
+
return marker ? this.paragraphMap[marker] || null : null;
|
|
42
|
+
};
|
|
43
|
+
ParagraphMapImpl.prototype.clear = function () {
|
|
44
|
+
this.paragraphMap = {};
|
|
45
|
+
};
|
|
46
|
+
//#region For test code only
|
|
47
|
+
ParagraphMapImpl.prototype._reset = function () {
|
|
48
|
+
ParagraphMapImpl.prefixNum = 0;
|
|
49
|
+
this.nextId = 0;
|
|
50
|
+
};
|
|
51
|
+
ParagraphMapImpl.prototype._getMap = function () {
|
|
52
|
+
return this.paragraphMap;
|
|
53
|
+
};
|
|
54
|
+
//#endregion
|
|
55
|
+
ParagraphMapImpl.prototype.generateId = function () {
|
|
56
|
+
return idPrefix + "_" + ParagraphMapImpl.prefixNum + "_" + this.nextId++;
|
|
57
|
+
};
|
|
58
|
+
ParagraphMapImpl.prefixNum = 0;
|
|
59
|
+
return ParagraphMapImpl;
|
|
60
|
+
}());
|
|
61
|
+
/**
|
|
62
|
+
* @internal
|
|
63
|
+
*/
|
|
64
|
+
function createParagraphMap() {
|
|
65
|
+
return new ParagraphMapImpl();
|
|
66
|
+
}
|
|
67
|
+
exports.createParagraphMap = createParagraphMap;
|
|
68
|
+
});
|
|
69
|
+
//# sourceMappingURL=ParagraphMapImpl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParagraphMapImpl.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts"],"names":[],"mappings":";;;;IAqBA,IAAM,QAAQ,GAAG,WAAW,CAAC;IAE7B;QAKI;YAHQ,WAAM,GAAG,CAAC,CAAC;YACX,iBAAY,GAAqD,EAAE,CAAC;YAGxE,gBAAgB,CAAC,SAAS,EAAE,CAAC;QACjC,CAAC;QAED,8CAAmB,GAAnB,UAAoB,OAAoB,EAAE,SAAgC;YACtE,IAAM,MAAM,GAAG,IAAA,gDAAkB,EAAC,OAAO,CAAC,CAAC;YAC3C,IAAM,mBAAmB,GAAG,SAAgC,CAAC;YAE7D,IAAI,MAAM,EAAE;gBACR,mBAAmB,CAAC,OAAO,GAAG,MAAM,CAAC;gBAErC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;aACzC;iBAAM;gBACH,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;gBAEhD,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;aAC7C;QACL,CAAC;QAED,2CAAgB,GAAhB,UAAiB,OAAoB,EAAE,SAAgC;YACnE,IAAM,mBAAmB,GAAG,SAAgC,CAAC;YAE7D,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;gBAC9B,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;aACnD;YAED,IAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC;YAE3C,IAAI,MAAM,EAAE;gBACR,IAAA,gDAAkB,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC;gBAEpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;aACzC;QACL,CAAC;QAED;;;WAGG;QACH,iDAAsB,GAAtB,UACI,eAA8C;YAE9C,IAAM,MAAM,GAAI,eAAuC,CAAC,OAAO,CAAC;YAEhE,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC7D,CAAC;QAED,gCAAK,GAAL;YACI,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;QAC3B,CAAC;QAED,4BAA4B;QAC5B,iCAAM,GAAN;YACI,gBAAgB,CAAC,SAAS,GAAG,CAAC,CAAC;YAC/B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACpB,CAAC;QAED,kCAAO,GAAP;YACI,OAAO,IAAI,CAAC,YAAY,CAAC;QAC7B,CAAC;QACD,YAAY;QAEJ,qCAAU,GAAlB;YACI,OAAU,QAAQ,SAAI,gBAAgB,CAAC,SAAS,SAAI,IAAI,CAAC,MAAM,EAAI,CAAC;QACxE,CAAC;QApEc,0BAAS,GAAG,CAAC,CAAC;QAqEjC,uBAAC;KAAA,AAtED,IAsEC;IAED;;OAEG;IACH,SAAgB,kBAAkB;QAC9B,OAAO,IAAI,gBAAgB,EAAE,CAAC;IAClC,CAAC;IAFD,gDAEC","sourcesContent":["import { getParagraphMarker, setParagraphMarker } from 'roosterjs-content-model-dom';\nimport type {\n ContentModelParagraph,\n ContentModelParagraphCommon,\n ParagraphIndexer,\n ParagraphMap,\n ReadonlyContentModelParagraph,\n} from 'roosterjs-content-model-types';\n\ninterface ParagraphWithMarker extends ContentModelParagraphCommon {\n _marker?: string;\n}\n\n/**\n * @internal, used by test code only\n */\nexport interface ParagraphMapReset {\n _reset(): void;\n _getMap(): { [key: string]: ReadonlyContentModelParagraph };\n}\n\nconst idPrefix = 'paragraph';\n\nclass ParagraphMapImpl implements ParagraphMap, ParagraphIndexer, ParagraphMapReset {\n private static prefixNum = 0;\n private nextId = 0;\n private paragraphMap: { [key: string]: ReadonlyContentModelParagraph } = {};\n\n constructor() {\n ParagraphMapImpl.prefixNum++;\n }\n\n assignMarkerToModel(element: HTMLElement, paragraph: ContentModelParagraph): void {\n const marker = getParagraphMarker(element);\n const paragraphWithMarker = paragraph as ParagraphWithMarker;\n\n if (marker) {\n paragraphWithMarker._marker = marker;\n\n this.paragraphMap[marker] = paragraph;\n } else {\n paragraphWithMarker._marker = this.generateId();\n\n this.applyMarkerToDom(element, paragraph);\n }\n }\n\n applyMarkerToDom(element: HTMLElement, paragraph: ContentModelParagraph): void {\n const paragraphWithMarker = paragraph as ParagraphWithMarker;\n\n if (!paragraphWithMarker._marker) {\n paragraphWithMarker._marker = this.generateId();\n }\n\n const marker = paragraphWithMarker._marker;\n\n if (marker) {\n setParagraphMarker(element, marker);\n\n this.paragraphMap[marker] = paragraph;\n }\n }\n\n /**\n * Get paragraph using a previously marked paragraph\n * @param markedParagraph The previously marked paragraph to get\n */\n getParagraphFromMarker(\n markerParagraph: ReadonlyContentModelParagraph\n ): ReadonlyContentModelParagraph | null {\n const marker = (markerParagraph as ParagraphWithMarker)._marker;\n\n return marker ? this.paragraphMap[marker] || null : null;\n }\n\n clear() {\n this.paragraphMap = {};\n }\n\n //#region For test code only\n _reset() {\n ParagraphMapImpl.prefixNum = 0;\n this.nextId = 0;\n }\n\n _getMap() {\n return this.paragraphMap;\n }\n //#endregion\n\n private generateId() {\n return `${idPrefix}_${ParagraphMapImpl.prefixNum}_${this.nextId++}`;\n }\n}\n\n/**\n * @internal\n */\nexport function createParagraphMap(): ParagraphMap & ParagraphIndexer {\n return new ParagraphMapImpl();\n}\n"]}
|
|
@@ -8,7 +8,7 @@ export var createEditorContext = function (core, saveIndex) {
|
|
|
8
8
|
var _a, _b;
|
|
9
9
|
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, logicalRoot = core.logicalRoot, cache = core.cache, domHelper = core.domHelper;
|
|
10
10
|
saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;
|
|
11
|
-
var context = __assign({ isDarkMode: lifecycle.isDarkMode, defaultFormat: format.defaultFormat, pendingFormat: (_a = format.pendingFormat) !== null && _a !== void 0 ? _a : undefined, darkColorHandler: darkColorHandler, addDelimiterForEntity: true, allowCacheElement: true, domIndexer: saveIndex ? cache.domIndexer : undefined, zoomScale: domHelper.calculateZoomScale(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [] }, getRootComputedStyleForContext(logicalRoot.ownerDocument));
|
|
11
|
+
var context = __assign({ isDarkMode: lifecycle.isDarkMode, defaultFormat: format.defaultFormat, pendingFormat: (_a = format.pendingFormat) !== null && _a !== void 0 ? _a : undefined, darkColorHandler: darkColorHandler, addDelimiterForEntity: true, allowCacheElement: true, domIndexer: saveIndex ? cache.domIndexer : undefined, zoomScale: domHelper.calculateZoomScale(), experimentalFeatures: (_b = core.experimentalFeatures) !== null && _b !== void 0 ? _b : [], paragraphMap: core.cache.paragraphMap }, getRootComputedStyleForContext(logicalRoot.ownerDocument));
|
|
12
12
|
if (core.domHelper.isRightToLeft()) {
|
|
13
13
|
context.isRootRtl = true;
|
|
14
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createEditorContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/createEditorContext/createEditorContext.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC;AAGlF;;;GAGG;AACH,MAAM,CAAC,IAAM,mBAAmB,GAAwB,UAAC,IAAI,EAAE,SAAS;;IAC5D,IAAA,SAAS,GAA8D,IAAI,UAAlE,EAAE,MAAM,GAAsD,IAAI,OAA1D,EAAE,gBAAgB,GAAoC,IAAI,iBAAxC,EAAE,WAAW,GAAuB,IAAI,YAA3B,EAAE,KAAK,GAAgB,IAAI,MAApB,EAAE,SAAS,GAAK,IAAI,UAAT,CAAU;IAEpF,SAAS,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;IAE5D,IAAM,OAAO,cACT,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,aAAa,EAAE,MAAA,MAAM,CAAC,aAAa,mCAAI,SAAS,EAChD,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,IAAI,EAC3B,iBAAiB,EAAE,IAAI,EACvB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EACpD,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,EACzC,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"createEditorContext.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/coreApi/createEditorContext/createEditorContext.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC;AAGlF;;;GAGG;AACH,MAAM,CAAC,IAAM,mBAAmB,GAAwB,UAAC,IAAI,EAAE,SAAS;;IAC5D,IAAA,SAAS,GAA8D,IAAI,UAAlE,EAAE,MAAM,GAAsD,IAAI,OAA1D,EAAE,gBAAgB,GAAoC,IAAI,iBAAxC,EAAE,WAAW,GAAuB,IAAI,YAA3B,EAAE,KAAK,GAAgB,IAAI,MAApB,EAAE,SAAS,GAAK,IAAI,UAAT,CAAU;IAEpF,SAAS,GAAG,SAAS,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC;IAE5D,IAAM,OAAO,cACT,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,aAAa,EAAE,MAAM,CAAC,aAAa,EACnC,aAAa,EAAE,MAAA,MAAM,CAAC,aAAa,mCAAI,SAAS,EAChD,gBAAgB,EAAE,gBAAgB,EAClC,qBAAqB,EAAE,IAAI,EAC3B,iBAAiB,EAAE,IAAI,EACvB,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,EACpD,SAAS,EAAE,SAAS,CAAC,kBAAkB,EAAE,EACzC,oBAAoB,EAAE,MAAA,IAAI,CAAC,oBAAoB,mCAAI,EAAE,EACrD,YAAY,EAAE,IAAI,CAAC,KAAK,CAAC,YAAY,IAClC,8BAA8B,CAAC,WAAW,CAAC,aAAa,CAAC,CAC/D,CAAC;IAEF,IAAI,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,EAAE;QAChC,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;KAC5B;IAED,OAAO,OAAO,CAAC;AACnB,CAAC,CAAC","sourcesContent":["import { getRootComputedStyleForContext } from './getRootComputedStyleForContext';\nimport type { EditorContext, CreateEditorContext } from 'roosterjs-content-model-types';\n\n/**\n * @internal\n * Create a EditorContext object used by ContentModel API\n */\nexport const createEditorContext: CreateEditorContext = (core, saveIndex) => {\n const { lifecycle, format, darkColorHandler, logicalRoot, cache, domHelper } = core;\n\n saveIndex = saveIndex && !core.lifecycle.shadowEditFragment;\n\n const context: EditorContext = {\n isDarkMode: lifecycle.isDarkMode,\n defaultFormat: format.defaultFormat,\n pendingFormat: format.pendingFormat ?? undefined,\n darkColorHandler: darkColorHandler,\n addDelimiterForEntity: true,\n allowCacheElement: true,\n domIndexer: saveIndex ? cache.domIndexer : undefined,\n zoomScale: domHelper.calculateZoomScale(),\n experimentalFeatures: core.experimentalFeatures ?? [],\n paragraphMap: core.cache.paragraphMap,\n ...getRootComputedStyleForContext(logicalRoot.ownerDocument),\n };\n\n if (core.domHelper.isRightToLeft()) {\n context.isRootRtl = true;\n }\n\n return context;\n};\n"]}
|
|
@@ -20,6 +20,7 @@ export var formatContentModel = function (core, formatter, options, domToModelOp
|
|
|
20
20
|
deletedEntities: [],
|
|
21
21
|
rawEvent: rawEvent,
|
|
22
22
|
newImages: [],
|
|
23
|
+
paragraphIndexer: core.cache.paragraphMap,
|
|
23
24
|
};
|
|
24
25
|
var hasFocus = core.domHelper.hasFocus();
|
|
25
26
|
var changed = formatter(model, context);
|
|
@@ -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 };\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 };\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,4 +1,5 @@
|
|
|
1
1
|
import { areSameSelections } from './areSameSelections';
|
|
2
|
+
import { createParagraphMap } from './ParagraphMapImpl';
|
|
2
3
|
import { createTextMutationObserver } from './textMutationObserver';
|
|
3
4
|
import { DomIndexerImpl } from './domIndexerImpl';
|
|
4
5
|
import { updateCache } from './updateCache';
|
|
@@ -44,13 +45,15 @@ var CachePlugin = /** @class */ (function () {
|
|
|
44
45
|
_this.updateCachedModel(_this.editor);
|
|
45
46
|
}
|
|
46
47
|
};
|
|
47
|
-
this.state =
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
48
|
+
this.state = {};
|
|
49
|
+
if (!option.disableCache) {
|
|
50
|
+
this.state.domIndexer = new DomIndexerImpl(option.experimentalFeatures &&
|
|
51
|
+
option.experimentalFeatures.indexOf('PersistCache') >= 0);
|
|
52
|
+
this.state.textMutationObserver = createTextMutationObserver(contentDiv, this.onMutation);
|
|
53
|
+
}
|
|
54
|
+
if (option.enableParagraphMap) {
|
|
55
|
+
this.state.paragraphMap = createParagraphMap();
|
|
56
|
+
}
|
|
54
57
|
}
|
|
55
58
|
/**
|
|
56
59
|
* Get name of this plugin
|
|
@@ -132,10 +135,13 @@ var CachePlugin = /** @class */ (function () {
|
|
|
132
135
|
}
|
|
133
136
|
};
|
|
134
137
|
CachePlugin.prototype.invalidateCache = function () {
|
|
135
|
-
var _a;
|
|
138
|
+
var _a, _b;
|
|
136
139
|
if (!((_a = this.editor) === null || _a === void 0 ? void 0 : _a.isInShadowEdit())) {
|
|
137
140
|
this.state.cachedModel = undefined;
|
|
138
141
|
this.state.cachedSelection = undefined;
|
|
142
|
+
// Clear paragraph indexer to prevent stale references to old paragraphs
|
|
143
|
+
// It will be rebuild next time when we create a new Content Model
|
|
144
|
+
(_b = this.state.paragraphMap) === null || _b === void 0 ? void 0 : _b.clear();
|
|
139
145
|
}
|
|
140
146
|
};
|
|
141
147
|
CachePlugin.prototype.updateCachedModel = function (editor, forceUpdate) {
|
|
@@ -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 { 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 = option.disableCache\n ? {}\n : {\n domIndexer: new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 0\n ),\n textMutationObserver: createTextMutationObserver(contentDiv, this.onMutation),\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 }\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\n if (!option.disableCache) {\n this.state.domIndexer = new DomIndexerImpl(\n option.experimentalFeatures &&\n option.experimentalFeatures.indexOf('PersistCache') >= 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"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ParagraphIndexer, ParagraphMap, ReadonlyContentModelParagraph } from 'roosterjs-content-model-types';
|
|
2
|
+
/**
|
|
3
|
+
* @internal, used by test code only
|
|
4
|
+
*/
|
|
5
|
+
export interface ParagraphMapReset {
|
|
6
|
+
_reset(): void;
|
|
7
|
+
_getMap(): {
|
|
8
|
+
[key: string]: ReadonlyContentModelParagraph;
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* @internal
|
|
13
|
+
*/
|
|
14
|
+
export declare function createParagraphMap(): ParagraphMap & ParagraphIndexer;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { getParagraphMarker, setParagraphMarker } from 'roosterjs-content-model-dom';
|
|
2
|
+
var idPrefix = 'paragraph';
|
|
3
|
+
var ParagraphMapImpl = /** @class */ (function () {
|
|
4
|
+
function ParagraphMapImpl() {
|
|
5
|
+
this.nextId = 0;
|
|
6
|
+
this.paragraphMap = {};
|
|
7
|
+
ParagraphMapImpl.prefixNum++;
|
|
8
|
+
}
|
|
9
|
+
ParagraphMapImpl.prototype.assignMarkerToModel = function (element, paragraph) {
|
|
10
|
+
var marker = getParagraphMarker(element);
|
|
11
|
+
var paragraphWithMarker = paragraph;
|
|
12
|
+
if (marker) {
|
|
13
|
+
paragraphWithMarker._marker = marker;
|
|
14
|
+
this.paragraphMap[marker] = paragraph;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
paragraphWithMarker._marker = this.generateId();
|
|
18
|
+
this.applyMarkerToDom(element, paragraph);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
ParagraphMapImpl.prototype.applyMarkerToDom = function (element, paragraph) {
|
|
22
|
+
var paragraphWithMarker = paragraph;
|
|
23
|
+
if (!paragraphWithMarker._marker) {
|
|
24
|
+
paragraphWithMarker._marker = this.generateId();
|
|
25
|
+
}
|
|
26
|
+
var marker = paragraphWithMarker._marker;
|
|
27
|
+
if (marker) {
|
|
28
|
+
setParagraphMarker(element, marker);
|
|
29
|
+
this.paragraphMap[marker] = paragraph;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Get paragraph using a previously marked paragraph
|
|
34
|
+
* @param markedParagraph The previously marked paragraph to get
|
|
35
|
+
*/
|
|
36
|
+
ParagraphMapImpl.prototype.getParagraphFromMarker = function (markerParagraph) {
|
|
37
|
+
var marker = markerParagraph._marker;
|
|
38
|
+
return marker ? this.paragraphMap[marker] || null : null;
|
|
39
|
+
};
|
|
40
|
+
ParagraphMapImpl.prototype.clear = function () {
|
|
41
|
+
this.paragraphMap = {};
|
|
42
|
+
};
|
|
43
|
+
//#region For test code only
|
|
44
|
+
ParagraphMapImpl.prototype._reset = function () {
|
|
45
|
+
ParagraphMapImpl.prefixNum = 0;
|
|
46
|
+
this.nextId = 0;
|
|
47
|
+
};
|
|
48
|
+
ParagraphMapImpl.prototype._getMap = function () {
|
|
49
|
+
return this.paragraphMap;
|
|
50
|
+
};
|
|
51
|
+
//#endregion
|
|
52
|
+
ParagraphMapImpl.prototype.generateId = function () {
|
|
53
|
+
return idPrefix + "_" + ParagraphMapImpl.prefixNum + "_" + this.nextId++;
|
|
54
|
+
};
|
|
55
|
+
ParagraphMapImpl.prefixNum = 0;
|
|
56
|
+
return ParagraphMapImpl;
|
|
57
|
+
}());
|
|
58
|
+
/**
|
|
59
|
+
* @internal
|
|
60
|
+
*/
|
|
61
|
+
export function createParagraphMap() {
|
|
62
|
+
return new ParagraphMapImpl();
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=ParagraphMapImpl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ParagraphMapImpl.js","sourceRoot":"","sources":["../../../../../packages/roosterjs-content-model-core/lib/corePlugin/cache/ParagraphMapImpl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAqBrF,IAAM,QAAQ,GAAG,WAAW,CAAC;AAE7B;IAKI;QAHQ,WAAM,GAAG,CAAC,CAAC;QACX,iBAAY,GAAqD,EAAE,CAAC;QAGxE,gBAAgB,CAAC,SAAS,EAAE,CAAC;IACjC,CAAC;IAED,8CAAmB,GAAnB,UAAoB,OAAoB,EAAE,SAAgC;QACtE,IAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAM,mBAAmB,GAAG,SAAgC,CAAC;QAE7D,IAAI,MAAM,EAAE;YACR,mBAAmB,CAAC,OAAO,GAAG,MAAM,CAAC;YAErC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;SACzC;aAAM;YACH,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAEhD,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;SAC7C;IACL,CAAC;IAED,2CAAgB,GAAhB,UAAiB,OAAoB,EAAE,SAAgC;QACnE,IAAM,mBAAmB,GAAG,SAAgC,CAAC;QAE7D,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE;YAC9B,mBAAmB,CAAC,OAAO,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;SACnD;QAED,IAAM,MAAM,GAAG,mBAAmB,CAAC,OAAO,CAAC;QAE3C,IAAI,MAAM,EAAE;YACR,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAEpC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;SACzC;IACL,CAAC;IAED;;;OAGG;IACH,iDAAsB,GAAtB,UACI,eAA8C;QAE9C,IAAM,MAAM,GAAI,eAAuC,CAAC,OAAO,CAAC;QAEhE,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC7D,CAAC;IAED,gCAAK,GAAL;QACI,IAAI,CAAC,YAAY,GAAG,EAAE,CAAC;IAC3B,CAAC;IAED,4BAA4B;IAC5B,iCAAM,GAAN;QACI,gBAAgB,CAAC,SAAS,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACpB,CAAC;IAED,kCAAO,GAAP;QACI,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IACD,YAAY;IAEJ,qCAAU,GAAlB;QACI,OAAU,QAAQ,SAAI,gBAAgB,CAAC,SAAS,SAAI,IAAI,CAAC,MAAM,EAAI,CAAC;IACxE,CAAC;IApEc,0BAAS,GAAG,CAAC,CAAC;IAqEjC,uBAAC;CAAA,AAtED,IAsEC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAC9B,OAAO,IAAI,gBAAgB,EAAE,CAAC;AAClC,CAAC","sourcesContent":["import { getParagraphMarker, setParagraphMarker } from 'roosterjs-content-model-dom';\nimport type {\n ContentModelParagraph,\n ContentModelParagraphCommon,\n ParagraphIndexer,\n ParagraphMap,\n ReadonlyContentModelParagraph,\n} from 'roosterjs-content-model-types';\n\ninterface ParagraphWithMarker extends ContentModelParagraphCommon {\n _marker?: string;\n}\n\n/**\n * @internal, used by test code only\n */\nexport interface ParagraphMapReset {\n _reset(): void;\n _getMap(): { [key: string]: ReadonlyContentModelParagraph };\n}\n\nconst idPrefix = 'paragraph';\n\nclass ParagraphMapImpl implements ParagraphMap, ParagraphIndexer, ParagraphMapReset {\n private static prefixNum = 0;\n private nextId = 0;\n private paragraphMap: { [key: string]: ReadonlyContentModelParagraph } = {};\n\n constructor() {\n ParagraphMapImpl.prefixNum++;\n }\n\n assignMarkerToModel(element: HTMLElement, paragraph: ContentModelParagraph): void {\n const marker = getParagraphMarker(element);\n const paragraphWithMarker = paragraph as ParagraphWithMarker;\n\n if (marker) {\n paragraphWithMarker._marker = marker;\n\n this.paragraphMap[marker] = paragraph;\n } else {\n paragraphWithMarker._marker = this.generateId();\n\n this.applyMarkerToDom(element, paragraph);\n }\n }\n\n applyMarkerToDom(element: HTMLElement, paragraph: ContentModelParagraph): void {\n const paragraphWithMarker = paragraph as ParagraphWithMarker;\n\n if (!paragraphWithMarker._marker) {\n paragraphWithMarker._marker = this.generateId();\n }\n\n const marker = paragraphWithMarker._marker;\n\n if (marker) {\n setParagraphMarker(element, marker);\n\n this.paragraphMap[marker] = paragraph;\n }\n }\n\n /**\n * Get paragraph using a previously marked paragraph\n * @param markedParagraph The previously marked paragraph to get\n */\n getParagraphFromMarker(\n markerParagraph: ReadonlyContentModelParagraph\n ): ReadonlyContentModelParagraph | null {\n const marker = (markerParagraph as ParagraphWithMarker)._marker;\n\n return marker ? this.paragraphMap[marker] || null : null;\n }\n\n clear() {\n this.paragraphMap = {};\n }\n\n //#region For test code only\n _reset() {\n ParagraphMapImpl.prefixNum = 0;\n this.nextId = 0;\n }\n\n _getMap() {\n return this.paragraphMap;\n }\n //#endregion\n\n private generateId() {\n return `${idPrefix}_${ParagraphMapImpl.prefixNum}_${this.nextId++}`;\n }\n}\n\n/**\n * @internal\n */\nexport function createParagraphMap(): ParagraphMap & ParagraphIndexer {\n return new ParagraphMapImpl();\n}\n"]}
|
package/package.json
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
"description": "Core editor for roosterjs",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"tslib": "^2.3.1",
|
|
6
|
-
"roosterjs-content-model-dom": "^9.
|
|
7
|
-
"roosterjs-content-model-types": "^9.
|
|
6
|
+
"roosterjs-content-model-dom": "^9.24.0",
|
|
7
|
+
"roosterjs-content-model-types": "^9.24.0"
|
|
8
8
|
},
|
|
9
|
-
"version": "9.
|
|
9
|
+
"version": "9.24.0",
|
|
10
10
|
"main": "./lib/index.js",
|
|
11
11
|
"typings": "./lib/index.d.ts",
|
|
12
12
|
"module": "./lib-mjs/index.js",
|