Socket
Socket
Sign inDemoInstall

roosterjs-content-model-core

Package Overview
Dependencies
Maintainers
1
Versions
38
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

roosterjs-content-model-core - npm Package Compare versions

Comparing version 0.24.0 to 0.25.0

lib-amd/corePlugin/ContextMenuPlugin.d.ts

10

lib-amd/coreApi/addUndoSnapshot.js

@@ -15,11 +15,13 @@ define(["require", "exports", "../utils/createSnapshotSelection"], function (require, exports, createSnapshotSelection_1) {

var addUndoSnapshot = function (core, canUndoByBackspace, entityStates) {
var lifecycle = core.lifecycle, api = core.api, contentDiv = core.contentDiv, undo = core.undo;
var lifecycle = core.lifecycle, contentDiv = core.contentDiv, undo = core.undo;
var snapshot = null;
if (!lifecycle.shadowEditFragment) {
var selection = api.getDOMSelection(core);
// Need to create snapshot selection before retrieve innerHTML since HTML can be changed during creating selection when normalize table
var selection = (0, createSnapshotSelection_1.createSnapshotSelection)(core);
var html = contentDiv.innerHTML;
snapshot = {
html: contentDiv.innerHTML,
html: html,
entityStates: entityStates,
isDarkMode: !!lifecycle.isDarkMode,
selection: (0, createSnapshotSelection_1.createSnapshotSelection)(contentDiv, selection),
selection: selection,
};

@@ -26,0 +28,0 @@ undo.snapshotsManager.addSnapshot(snapshot, !!canUndoByBackspace);

19

lib-amd/coreApi/createContentModel.js

@@ -13,2 +13,5 @@ define(["require", "exports", "../publicApi/model/cloneModel", "roosterjs-content-model-dom"], function (require, exports, cloneModel_1, roosterjs_content_model_dom_1) {

var createContentModel = function (core, option, selectionOverride) {
var _a;
// Flush all mutations if any, so that we can get an up-to-date Content Model
(_a = core.cache.textMutationObserver) === null || _a === void 0 ? void 0 : _a.flushMutations();
var cachedModel = selectionOverride ? null : core.cache.cachedModel;

@@ -24,4 +27,9 @@ if (cachedModel && core.lifecycle.shadowEditFragment) {

var selection = selectionOverride || core.api.getDOMSelection(core) || undefined;
var model = internalCreateContentModel(core, selection, option);
if (!option && !selectionOverride) {
var saveIndex = !option && !selectionOverride;
var editorContext = core.api.createEditorContext(core, saveIndex);
var domToModelContext = option
? (0, roosterjs_content_model_dom_1.createDomToModelContext)(editorContext, core.domToModelSettings.builtIn, core.domToModelSettings.customized, option)
: (0, roosterjs_content_model_dom_1.createDomToModelContextWithConfig)(core.domToModelSettings.calculated, editorContext);
var model = (0, roosterjs_content_model_dom_1.domToContentModel)(core.contentDiv, domToModelContext, selection);
if (saveIndex) {
core.cache.cachedModel = model;

@@ -34,10 +42,3 @@ core.cache.cachedSelection = selection;

exports.createContentModel = createContentModel;
function internalCreateContentModel(core, selection, option) {
var editorContext = core.api.createEditorContext(core);
var domToModelContext = option
? (0, roosterjs_content_model_dom_1.createDomToModelContext)(editorContext, core.domToModelSettings.builtIn, core.domToModelSettings.customized, option)
: (0, roosterjs_content_model_dom_1.createDomToModelContextWithConfig)(core.domToModelSettings.calculated, editorContext);
return (0, roosterjs_content_model_dom_1.domToContentModel)(core.contentDiv, domToModelContext, selection);
}
});
//# sourceMappingURL=createContentModel.js.map

@@ -9,5 +9,5 @@ define(["require", "exports"], function (require, exports) {

*/
var createEditorContext = function (core) {
var createEditorContext = function (core, saveIndex) {
var _a;
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, contentDiv = core.contentDiv, cache = core.cache;
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, contentDiv = core.contentDiv, cache = core.cache, domHelper = core.domHelper;
var context = {

@@ -20,17 +20,9 @@ isDarkMode: lifecycle.isDarkMode,

allowCacheElement: true,
domIndexer: cache.domIndexer,
domIndexer: saveIndex ? cache.domIndexer : undefined,
zoomScale: domHelper.calculateZoomScale(),
};
checkRootRtl(contentDiv, context);
checkZoomScale(contentDiv, context);
return context;
};
exports.createEditorContext = createEditorContext;
function checkZoomScale(element, context) {
var _a;
var originalWidth = ((_a = element === null || element === void 0 ? void 0 : element.getBoundingClientRect()) === null || _a === void 0 ? void 0 : _a.width) || 0;
var visualWidth = element.offsetWidth;
if (visualWidth > 0 && originalWidth > 0) {
context.zoomScale = Math.round((originalWidth / visualWidth) * 100) / 100;
}
}
function checkRootRtl(element, context) {

@@ -37,0 +29,0 @@ var _a;

@@ -9,6 +9,11 @@ define(["require", "exports"], function (require, exports) {

var getDOMSelection = function (core) {
var _a;
return core.lifecycle.shadowEditFragment
? null
: (_a = core.selection.selection) !== null && _a !== void 0 ? _a : getNewSelection(core);
if (core.lifecycle.shadowEditFragment) {
return null;
}
else {
var selection = core.selection.selection;
return selection && (selection.type != 'range' || !core.api.hasFocus(core))
? selection
: getNewSelection(core);
}
};

@@ -24,6 +29,16 @@ exports.getDOMSelection = getDOMSelection;

range: range,
isReverted: isSelectionReverted(selection),
}
: null;
}
function isSelectionReverted(selection) {
if (selection && selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
return (!range.collapsed &&
selection.focusNode != range.endContainer &&
selection.focusOffset != range.endOffset);
}
return false;
}
});
//# sourceMappingURL=getDOMSelection.js.map

@@ -1,2 +0,2 @@

define(["require", "exports", "../constants/ChangeSource", "../publicApi/model/cloneModel", "../utils/paste/convertInlineCss", "../utils/paste/createPasteFragment", "../utils/paste/generatePasteOptionFromPlugins", "../utils/paste/mergePasteContent", "../utils/paste/retrieveHtmlInfo"], function (require, exports, ChangeSource_1, cloneModel_1, convertInlineCss_1, createPasteFragment_1, generatePasteOptionFromPlugins_1, mergePasteContent_1, retrieveHtmlInfo_1) {
define(["require", "exports", "../publicApi/model/cloneModel", "../utils/paste/convertInlineCss", "../utils/paste/createPasteFragment", "../utils/paste/generatePasteOptionFromPlugins", "../utils/paste/mergePasteContent", "../utils/paste/retrieveHtmlInfo"], function (require, exports, cloneModel_1, convertInlineCss_1, createPasteFragment_1, generatePasteOptionFromPlugins_1, mergePasteContent_1, retrieveHtmlInfo_1) {
"use strict";

@@ -16,2 +16,3 @@ Object.defineProperty(exports, "__esModule", { value: true });

var paste = function (core, clipboardData, pasteType) {
var _a;
if (pasteType === void 0) { pasteType = 'normal'; }

@@ -25,24 +26,16 @@ core.api.focus(core);

}
core.api.formatContentModel(core, function (model, context) {
var _a;
// 1. Prepare variables
var doc = createDOMFromHtml(clipboardData.rawHtml, core.trustedHTMLHandler);
// 2. Handle HTML from clipboard
var htmlFromClipboard = (0, retrieveHtmlInfo_1.retrieveHtmlInfo)(doc, clipboardData);
// 3. Create target fragment
var sourceFragment = (0, createPasteFragment_1.createPasteFragment)(core.contentDiv.ownerDocument, clipboardData, pasteType, (_a = (clipboardData.rawHtml == clipboardData.html
? doc
: createDOMFromHtml(clipboardData.html, core.trustedHTMLHandler))) === null || _a === void 0 ? void 0 : _a.body);
// 4. Trigger BeforePaste event to allow plugins modify the fragment
var eventResult = (0, generatePasteOptionFromPlugins_1.generatePasteOptionFromPlugins)(core, clipboardData, sourceFragment, htmlFromClipboard, pasteType);
// 5. Convert global CSS to inline CSS
(0, convertInlineCss_1.convertInlineCss)(eventResult.fragment, htmlFromClipboard.globalCssRules);
// 6. Merge pasted content into main Content Model
(0, mergePasteContent_1.mergePasteContent)(model, context, eventResult, core.domToModelSettings.customized);
return true;
}, {
changeSource: ChangeSource_1.ChangeSource.Paste,
getChangeData: function () { return clipboardData; },
apiName: 'paste',
});
// 1. Prepare variables
var doc = createDOMFromHtml(clipboardData.rawHtml, core.trustedHTMLHandler);
// 2. Handle HTML from clipboard
var htmlFromClipboard = (0, retrieveHtmlInfo_1.retrieveHtmlInfo)(doc, clipboardData);
// 3. Create target fragment
var sourceFragment = (0, createPasteFragment_1.createPasteFragment)(core.contentDiv.ownerDocument, clipboardData, pasteType, (_a = (clipboardData.rawHtml == clipboardData.html
? doc
: createDOMFromHtml(clipboardData.html, core.trustedHTMLHandler))) === null || _a === void 0 ? void 0 : _a.body);
// 4. Trigger BeforePaste event to allow plugins modify the fragment
var eventResult = (0, generatePasteOptionFromPlugins_1.generatePasteOptionFromPlugins)(core, clipboardData, sourceFragment, htmlFromClipboard, pasteType);
// 5. Convert global CSS to inline CSS
(0, convertInlineCss_1.convertInlineCss)(eventResult.fragment, htmlFromClipboard.globalCssRules);
// 6. Merge pasted content into main Content Model
(0, mergePasteContent_1.mergePasteContent)(core, eventResult, clipboardData);
};

@@ -49,0 +42,0 @@ exports.paste = paste;

@@ -13,7 +13,9 @@ define(["require", "exports", "roosterjs-content-model-dom"], function (require, exports, roosterjs_content_model_dom_1) {

var setContentModel = function (core, model, option, onNodeCreated) {
var editorContext = core.api.createEditorContext(core);
var _a;
var editorContext = core.api.createEditorContext(core, true /*saveIndex*/);
var modelToDomContext = option
? (0, roosterjs_content_model_dom_1.createModelToDomContext)(editorContext, core.modelToDomSettings.builtIn, core.modelToDomSettings.customized, option)
: (0, roosterjs_content_model_dom_1.createModelToDomContextWithConfig)(core.modelToDomSettings.calculated, editorContext);
var selection = (0, roosterjs_content_model_dom_1.contentModelToDom)(core.contentDiv.ownerDocument, core.contentDiv, model, modelToDomContext, onNodeCreated);
modelToDomContext.onNodeCreated = onNodeCreated;
var selection = (0, roosterjs_content_model_dom_1.contentModelToDom)(core.contentDiv.ownerDocument, core.contentDiv, model, modelToDomContext);
if (!core.lifecycle.shadowEditFragment) {

@@ -24,5 +26,7 @@ core.cache.cachedSelection = selection || undefined;

}
else if (!selection || selection.type !== 'range') {
else {
core.selection.selection = selection;
}
// Clear pending mutations since we will use our latest model object to replace existing cache
(_a = core.cache.textMutationObserver) === null || _a === void 0 ? void 0 : _a.flushMutations();
core.cache.cachedModel = model;

@@ -29,0 +33,0 @@ }

@@ -40,3 +40,3 @@ define(["require", "exports", "../corePlugin/utils/addRangeToSelection", "roosterjs-content-model-dom", "../publicApi/domUtils/tableCellUtils"], function (require, exports, addRangeToSelection_1, roosterjs_content_model_dom_1, tableCellUtils_1) {

case 'range':
(0, addRangeToSelection_1.addRangeToSelection)(doc, selection.range);
(0, addRangeToSelection_1.addRangeToSelection)(doc, selection.range, selection.isReverted);
core.selection.selection = core.api.hasFocus(core) ? null : selection;

@@ -43,0 +43,0 @@ break;

@@ -12,3 +12,2 @@ define(["require", "exports", "../publicApi/selection/iterateSelections", "roosterjs-content-model-dom"], function (require, exports, iterateSelections_1, roosterjs_content_model_dom_1) {

var switchShadowEdit = function (editorCore, isOn) {
// TODO: Use strong-typed editor core object
var core = editorCore;

@@ -18,4 +17,2 @@ if (isOn != !!core.lifecycle.shadowEditFragment) {

var model = !core.cache.cachedModel ? core.api.createContentModel(core) : null;
// Fake object, not used in Content Model Editor, just to satisfy original editor code
// TODO: we can remove them once we have standalone Content Model Editor
var fragment = core.contentDiv.ownerDocument.createDocumentFragment();

@@ -22,0 +19,0 @@ var clonedRoot = core.contentDiv.cloneNode(true /*deep*/);

@@ -6,3 +6,4 @@ import type { ContentModelCachePluginState, PluginWithState, StandaloneEditorOptions } from 'roosterjs-content-model-types';

* @param option The editor option
* @param contentDiv The editor content DIV
*/
export declare function createContentModelCachePlugin(option: StandaloneEditorOptions): PluginWithState<ContentModelCachePluginState>;
export declare function createContentModelCachePlugin(option: StandaloneEditorOptions, contentDiv: HTMLDivElement): PluginWithState<ContentModelCachePluginState>;

@@ -1,2 +0,2 @@

define(["require", "exports", "./utils/areSameSelection", "./utils/contentModelDomIndexer", "../publicApi/domUtils/eventUtils"], function (require, exports, areSameSelection_1, contentModelDomIndexer_1, eventUtils_1) {
define(["require", "exports", "./utils/areSameSelection", "./utils/contentModelDomIndexer", "./utils/textMutationObserver"], function (require, exports, areSameSelection_1, contentModelDomIndexer_1, textMutationObserver_1) {
"use strict";

@@ -12,6 +12,17 @@ Object.defineProperty(exports, "__esModule", { value: true });

* @param option The editor option
* @param contentDiv The editor content DIV
*/
function ContentModelCachePlugin(option) {
function ContentModelCachePlugin(option, contentDiv) {
var _this = this;
this.editor = null;
this.onMutation = function (isTextChangeOnly) {
if (_this.editor) {
if (isTextChangeOnly) {
_this.updateCachedModel(_this.editor, true /*forceUpdate*/);
}
else {
_this.invalidateCache();
}
}
};
this.onNativeSelectionChange = function () {

@@ -23,5 +34,8 @@ var _a;

};
this.state = {
domIndexer: option.cacheModel ? contentModelDomIndexer_1.contentModelDomIndexer : undefined,
};
this.state = option.cacheModel
? {
domIndexer: contentModelDomIndexer_1.contentModelDomIndexer,
textMutationObserver: (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation),
}
: {};
}

@@ -41,5 +55,6 @@ /**

ContentModelCachePlugin.prototype.initialize = function (editor) {
// TODO: Later we may need a different interface for Content Model editor plugin
var _a;
this.editor = editor;
this.editor.getDocument().addEventListener('selectionchange', this.onNativeSelectionChange);
(_a = this.state.textMutationObserver) === null || _a === void 0 ? void 0 : _a.startObserving();
};

@@ -52,2 +67,4 @@ /**

ContentModelCachePlugin.prototype.dispose = function () {
var _a;
(_a = this.state.textMutationObserver) === null || _a === void 0 ? void 0 : _a.stopObserving();
if (this.editor) {

@@ -78,11 +95,8 @@ this.editor

case 'keyDown':
if (this.shouldClearCache(event)) {
case 'input':
if (!this.state.textMutationObserver) {
// When updating cache is not enabled, need to clear the cache to make sure other plugins can get an up-to-date content model
this.invalidateCache();
}
break;
case 'input':
{
this.updateCachedModel(this.editor, true /*forceUpdate*/);
}
break;
case 'selectionChanged':

@@ -92,12 +106,10 @@ this.updateCachedModel(this.editor);

case 'contentChanged':
{
var contentModel = event.contentModel, selection = event.selection;
if (contentModel && this.state.domIndexer) {
this.state.cachedModel = contentModel;
this.state.cachedSelection = selection;
}
else {
this.invalidateCache();
}
var contentModel = event.contentModel, selection = event.selection;
if (contentModel && this.state.domIndexer) {
this.state.cachedModel = contentModel;
this.state.cachedSelection = selection;
}
else {
this.invalidateCache();
}
break;

@@ -137,27 +149,2 @@ }

};
ContentModelCachePlugin.prototype.shouldClearCache = function (event) {
var _a;
var rawEvent = event.rawEvent, handledByEditFeature = event.handledByEditFeature;
// In these cases we can't update the model, so clear cache:
// 1. It is already handled by Content Edit Features
if (handledByEditFeature) {
return true;
}
// 2. Default behavior is prevented, which means other plugins has handled the event
if (rawEvent.defaultPrevented) {
return true;
}
// 3. ENTER key is pressed. ENTER key will create new paragraph, so need to update cache to reflect this change
// TODO: Handle ENTER key to better reuse content model
if (rawEvent.key == 'Enter') {
return true;
}
// 4. Current selection is image or table or expanded range selection, and is inputting some text
if ((((_a = this.state.cachedSelection) === null || _a === void 0 ? void 0 : _a.type) != 'range' ||
!this.state.cachedSelection.range.collapsed) &&
(0, eventUtils_1.isCharacterValue)(rawEvent)) {
return true;
}
return false;
};
return ContentModelCachePlugin;

@@ -169,5 +156,6 @@ }());

* @param option The editor option
* @param contentDiv The editor content DIV
*/
function createContentModelCachePlugin(option) {
return new ContentModelCachePlugin(option);
function createContentModelCachePlugin(option, contentDiv) {
return new ContentModelCachePlugin(option, contentDiv);
}

@@ -174,0 +162,0 @@ exports.createContentModelCachePlugin = createContentModelCachePlugin;

@@ -1,2 +0,2 @@

define(["require", "exports", "tslib", "./utils/addRangeToSelection", "../constants/ChangeSource", "../publicApi/model/cloneModel", "./utils/deleteEmptyList", "../publicApi/selection/deleteSelection", "../utils/extractClipboardItems", "../publicApi/table/getSelectedCells", "../publicApi/selection/iterateSelections", "../publicApi/color/transformColor", "roosterjs-content-model-dom"], function (require, exports, tslib_1, addRangeToSelection_1, ChangeSource_1, cloneModel_1, deleteEmptyList_1, deleteSelection_1, extractClipboardItems_1, getSelectedCells_1, iterateSelections_1, transformColor_1, roosterjs_content_model_dom_1) {
define(["require", "exports", "tslib", "./utils/addRangeToSelection", "../constants/ChangeSource", "./utils/deleteEmptyList", "../publicApi/selection/deleteSelection", "../utils/extractClipboardItems", "../publicApi/table/getSelectedCells", "../publicApi/selection/iterateSelections", "roosterjs-content-model-dom"], function (require, exports, tslib_1, addRangeToSelection_1, ChangeSource_1, deleteEmptyList_1, deleteSelection_1, extractClipboardItems_1, getSelectedCells_1, iterateSelections_1, roosterjs_content_model_dom_1) {
"use strict";

@@ -31,13 +31,2 @@ Object.defineProperty(exports, "__esModule", { value: true });

};
this.processEntityColor = function (node, type) {
if (type == 'cache' || !_this.editor) {
return undefined;
}
var result = node.cloneNode(true /*deep*/);
var colorHandler = _this.editor.getColorManager();
(0, transformColor_1.transformColor)(result, true /*includeSelf*/, 'darkToLight', colorHandler);
result.style.color = result.style.color || 'inherit';
result.style.backgroundColor = result.style.backgroundColor || 'inherit';
return result;
};
this.state = {

@@ -103,7 +92,3 @@ allowedCustomPasteType: option.allowedCustomPasteType || [],

if (selection && (selection.type != 'range' || !selection.range.collapsed)) {
var model = this.editor.createContentModel(undefined /* option */, selection);
var cacheProcessor = this.editor.isDarkMode() ? this.processEntityColor : false;
var pasteModel = (0, cloneModel_1.cloneModel)(model, {
includeCachedElement: cacheProcessor,
});
var pasteModel = this.editor.getContentModelCopy('disconnected');
if (selection.type === 'table') {

@@ -122,3 +107,5 @@ (0, iterateSelections_1.iterateSelections)(pasteModel, function (_, tableContext) {

var tempDiv_1 = this.getTempDiv(this.editor.getDocument());
var selectionForCopy = (0, roosterjs_content_model_dom_1.contentModelToDom)(tempDiv_1.ownerDocument, tempDiv_1, pasteModel, (0, roosterjs_content_model_dom_1.createModelToDomContext)(), exports.onNodeCreated);
var context = (0, roosterjs_content_model_dom_1.createModelToDomContext)();
context.onNodeCreated = exports.onNodeCreated;
var selectionForCopy = (0, roosterjs_content_model_dom_1.contentModelToDom)(tempDiv_1.ownerDocument, tempDiv_1, pasteModel, context);
var newRange = selectionForCopy

@@ -125,0 +112,0 @@ ? domSelectionToRange(doc, selectionForCopy)

@@ -39,3 +39,2 @@ define(["require", "exports", "tslib", "./utils/applyDefaultFormat", "./utils/applyPendingFormat", "roosterjs-content-model-dom", "../publicApi/domUtils/eventUtils"], function (require, exports, tslib_1, applyDefaultFormat_1, applyPendingFormat_1, roosterjs_content_model_dom_1, eventUtils_1) {

var _this = this;
// TODO: Later we may need a different interface for Content Model editor plugin
this.editor = editor;

@@ -42,0 +41,0 @@ this.hasDefaultFormat =

@@ -1,2 +0,2 @@

define(["require", "exports", "./ContentModelCachePlugin", "./ContentModelCopyPastePlugin", "./ContentModelFormatPlugin", "./DOMEventPlugin", "./EntityPlugin", "./LifecyclePlugin", "./SelectionPlugin", "./UndoPlugin"], function (require, exports, ContentModelCachePlugin_1, ContentModelCopyPastePlugin_1, ContentModelFormatPlugin_1, DOMEventPlugin_1, EntityPlugin_1, LifecyclePlugin_1, SelectionPlugin_1, UndoPlugin_1) {
define(["require", "exports", "./ContentModelCachePlugin", "./ContentModelCopyPastePlugin", "./ContentModelFormatPlugin", "./ContextMenuPlugin", "./DOMEventPlugin", "./EntityPlugin", "./LifecyclePlugin", "./SelectionPlugin", "./UndoPlugin"], function (require, exports, ContentModelCachePlugin_1, ContentModelCopyPastePlugin_1, ContentModelFormatPlugin_1, ContextMenuPlugin_1, DOMEventPlugin_1, EntityPlugin_1, LifecyclePlugin_1, SelectionPlugin_1, UndoPlugin_1) {
"use strict";

@@ -12,3 +12,3 @@ Object.defineProperty(exports, "__esModule", { value: true });

return {
cache: (0, ContentModelCachePlugin_1.createContentModelCachePlugin)(options),
cache: (0, ContentModelCachePlugin_1.createContentModelCachePlugin)(options, contentDiv),
format: (0, ContentModelFormatPlugin_1.createContentModelFormatPlugin)(options),

@@ -20,2 +20,3 @@ copyPaste: (0, ContentModelCopyPastePlugin_1.createContentModelCopyPastePlugin)(options),

selection: (0, SelectionPlugin_1.createSelectionPlugin)(options),
contextMenu: (0, ContextMenuPlugin_1.createContextMenuPlugin)(options),
undo: (0, UndoPlugin_1.createUndoPlugin)(options),

@@ -22,0 +23,0 @@ };

@@ -71,3 +71,3 @@ define(["require", "exports", "./utils/findAllEntities", "../publicApi/color/transformColor", "roosterjs-content-model-dom"], function (require, exports, findAllEntities_1, transformColor_1, roosterjs_content_model_dom_1) {

if (isClicking && this.editor) {
while (node && this.editor.isNodeInEditor(node)) {
while (node && this.editor.getDOMHelper().isNodeInEditor(node)) {
if ((0, roosterjs_content_model_dom_1.isEntityElement)(node)) {

@@ -128,3 +128,6 @@ this.triggerEvent(editor, node, 'click', rawEvent);

var result = [];
(0, findAllEntities_1.findAllEntities)(editor.createContentModel(), result);
editor.formatContentModel(function (model) {
(0, findAllEntities_1.findAllEntities)(model, result);
return false;
});
(0, roosterjs_content_model_dom_1.getObjectKeys)(this.state.entityMap).forEach(function (id) {

@@ -131,0 +134,0 @@ var entry = _this.state.entityMap[id];

@@ -19,8 +19,5 @@ define(["require", "exports", "../constants/ChangeSource", "roosterjs-content-model-dom"], function (require, exports, ChangeSource_1, roosterjs_content_model_dom_1) {

var _this = this;
var _a;
this.editor = null;
this.initializer = null;
this.disposer = null;
this.initialModel =
(_a = options.initialModel) !== null && _a !== void 0 ? _a : this.createInitModel(options.defaultSegmentFormat);
// Make the container editable and set its selection styles

@@ -60,6 +57,2 @@ if (contentDiv.getAttribute(ContentEditableAttributeName) === null) {

this.editor = editor;
this.editor.setContentModel(this.initialModel, { ignoreSelection: true });
// Initial model is only used once. After that we can just clean it up to make sure we don't cache anything useless
// including the cached DOM element inside the model.
this.initialModel = (0, roosterjs_content_model_dom_1.createContentModelDocument)();
// Set content DIV to be editable

@@ -110,9 +103,2 @@ (_a = this.initializer) === null || _a === void 0 ? void 0 : _a.call(this);

};
LifecyclePlugin.prototype.createInitModel = function (format) {
var model = (0, roosterjs_content_model_dom_1.createContentModelDocument)(format);
var paragraph = (0, roosterjs_content_model_dom_1.createParagraph)(false /*isImplicit*/, undefined /*blockFormat*/, format);
paragraph.segments.push((0, roosterjs_content_model_dom_1.createSelectionMarker)(format), (0, roosterjs_content_model_dom_1.createBr)(format));
model.blocks.push(paragraph);
return model;
};
return LifecyclePlugin;

@@ -119,0 +105,0 @@ }());

@@ -12,2 +12,3 @@ define(["require", "exports", "roosterjs-content-model-dom", "../publicApi/domUtils/eventUtils"], function (require, exports, roosterjs_content_model_dom_1, eventUtils_1) {

this.disposer = null;
this.isSafari = false;
this.onFocus = function () {

@@ -18,3 +19,3 @@ var _a, _b;

}
if (((_b = _this.state.selection) === null || _b === void 0 ? void 0 : _b.type) == 'range') {
if (((_b = _this.state.selection) === null || _b === void 0 ? void 0 : _b.type) == 'range' && !_this.isSafari) {
// Editor is focused, now we can get live selection. So no need to keep a selection if the selection type is range.

@@ -29,16 +30,17 @@ _this.state.selection = null;

};
this.onKeyDownDocument = function (event) {
if (event.key == 'Tab' && !event.defaultPrevented) {
_this.onBlur();
this.onSelectionChangeSafari = function () {
var _a;
if (((_a = _this.editor) === null || _a === void 0 ? void 0 : _a.hasFocus()) && !_this.editor.isInShadowEdit()) {
// Safari has problem to handle onBlur event. When blur, we cannot get the original selection from editor.
// So we always save a selection whenever editor has focus. Then after blur, we can still use this cached selection.
var newSelection = _this.editor.getDOMSelection();
if ((newSelection === null || newSelection === void 0 ? void 0 : newSelection.type) == 'range') {
_this.state.selection = newSelection;
}
}
};
this.onMouseDownDocument = function (event) {
if (_this.editor && !_this.editor.isNodeInEditor(event.target)) {
_this.onBlur();
}
};
this.state = {
selection: null,
selectionStyleNode: null,
imageSelectionBorderColor: options.imageSelectionBorderColor, // TODO: Move to Selection core plugin
imageSelectionBorderColor: options.imageSelectionBorderColor,
};

@@ -50,3 +52,2 @@ }

SelectionPlugin.prototype.initialize = function (editor) {
var _a;
this.editor = editor;

@@ -59,6 +60,5 @@ var doc = this.editor.getDocument();

var document = this.editor.getDocument();
if (env.isSafari) {
document.addEventListener('mousedown', this.onMouseDownDocument, true /*useCapture*/);
document.addEventListener('keydown', this.onKeyDownDocument);
(_a = document.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener('blur', this.onBlur);
this.isSafari = !!env.isSafari;
if (this.isSafari) {
document.addEventListener('selectionchange', this.onSelectionChangeSafari);
this.disposer = this.editor.attachDomEvent({ focus: { beforeDispatch: this.onFocus } });

@@ -75,4 +75,5 @@ }

var _a, _b;
(_a = this.editor) === null || _a === void 0 ? void 0 : _a.getDocument().removeEventListener('selectionchange', this.onSelectionChangeSafari);
if (this.state.selectionStyleNode) {
(_a = this.state.selectionStyleNode.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.state.selectionStyleNode);
(_b = this.state.selectionStyleNode.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.state.selectionStyleNode);
this.state.selectionStyleNode = null;

@@ -84,9 +85,3 @@ }

}
if (this.editor) {
var document_1 = this.editor.getDocument();
document_1.removeEventListener('mousedown', this.onMouseDownDocument, true /*useCapture*/);
document_1.removeEventListener('keydown', this.onKeyDownDocument);
(_b = document_1.defaultView) === null || _b === void 0 ? void 0 : _b.removeEventListener('blur', this.onBlur);
this.editor = null;
}
this.editor = null;
};

@@ -159,2 +154,3 @@ SelectionPlugin.prototype.getState = function () {

range: range,
isReverted: false,
});

@@ -161,0 +157,0 @@ }

/**
* @internal
*/
export declare function addRangeToSelection(doc: Document, range: Range): void;
export declare function addRangeToSelection(doc: Document, range: Range, isReverted?: boolean): void;

@@ -8,8 +8,14 @@ define(["require", "exports"], function (require, exports) {

*/
function addRangeToSelection(doc, range) {
function addRangeToSelection(doc, range, isReverted) {
var _a;
if (isReverted === void 0) { isReverted = false; }
var selection = (_a = doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
if (!isReverted) {
selection.addRange(range);
}
else {
selection.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
}
}

@@ -16,0 +22,0 @@ }

@@ -19,3 +19,3 @@ define(["require", "exports", "tslib", "../../publicApi/selection/deleteSelection", "roosterjs-content-model-dom"], function (require, exports, tslib_1, deleteSelection_1, roosterjs_content_model_dom_1) {

var node = posContainer;
while (node && editor.isNodeInEditor(node)) {
while (node && editor.getDOMHelper().isNodeInEditor(node)) {
if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'ELEMENT_NODE')) {

@@ -22,0 +22,0 @@ if ((_c = node.getAttribute) === null || _c === void 0 ? void 0 : _c.call(node, 'style')) {

@@ -1,2 +0,2 @@

define(["require", "exports", "tslib", "./DarkColorHandlerImpl", "../corePlugin/createStandaloneEditorCorePlugins", "./standaloneCoreApiMap", "./createStandaloneEditorDefaultSettings"], function (require, exports, tslib_1, DarkColorHandlerImpl_1, createStandaloneEditorCorePlugins_1, standaloneCoreApiMap_1, createStandaloneEditorDefaultSettings_1) {
define(["require", "exports", "tslib", "./DarkColorHandlerImpl", "./DOMHelperImpl", "../corePlugin/createStandaloneEditorCorePlugins", "./standaloneCoreApiMap", "./createStandaloneEditorDefaultSettings"], function (require, exports, tslib_1, DarkColorHandlerImpl_1, DOMHelperImpl_1, createStandaloneEditorCorePlugins_1, standaloneCoreApiMap_1, createStandaloneEditorDefaultSettings_1) {
"use strict";

@@ -12,3 +12,3 @@ Object.defineProperty(exports, "__esModule", { value: true });

function createStandaloneEditorCore(contentDiv, options) {
var _a, _b, _c;
var _a, _b;
var corePlugins = (0, createStandaloneEditorCorePlugins_1.createStandaloneEditorCorePlugins)(options, contentDiv);

@@ -24,4 +24,5 @@ return (0, tslib_1.__assign)((0, tslib_1.__assign)({ contentDiv: contentDiv, api: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, standaloneCoreApiMap_1.standaloneCoreApiMap), options.coreApiOverride), originalApi: (0, tslib_1.__assign)({}, standaloneCoreApiMap_1.standaloneCoreApiMap), plugins: (0, tslib_1.__spreadArray)((0, tslib_1.__spreadArray)([

corePlugins.undo,
corePlugins.contextMenu,
corePlugins.lifecycle,
], false), environment: createEditorEnvironment(contentDiv), darkColorHandler: (0, DarkColorHandlerImpl_1.createDarkColorHandler)(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors), trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler, domToModelSettings: (0, createStandaloneEditorDefaultSettings_1.createDomToModelSettings)(options), modelToDomSettings: (0, createStandaloneEditorDefaultSettings_1.createModelToDomSettings)(options) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler, zoomScale: ((_c = options.zoomScale) !== null && _c !== void 0 ? _c : -1) > 0 ? options.zoomScale : 1 });
], false), environment: createEditorEnvironment(contentDiv), darkColorHandler: (0, DarkColorHandlerImpl_1.createDarkColorHandler)(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors), trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler, domToModelSettings: (0, createStandaloneEditorDefaultSettings_1.createDomToModelSettings)(options), modelToDomSettings: (0, createStandaloneEditorDefaultSettings_1.createModelToDomSettings)(options), domHelper: (0, DOMHelperImpl_1.createDOMHelper)(contentDiv) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler });
}

@@ -58,2 +59,3 @@ exports.createStandaloneEditorCore = createStandaloneEditorCore;

selection: corePlugins.selection.getState(),
contextMenu: corePlugins.contextMenu.getState(),
undo: corePlugins.undo.getState(),

@@ -60,0 +62,0 @@ };

@@ -1,2 +0,2 @@

import type { ClipboardData, ContentModelDocument, ContentModelFormatter, ContentModelSegmentFormat, DarkColorHandler, DOMEventRecord, DOMSelection, DomToModelOption, EditorEnvironment, FormatWithContentModelOptions, IStandaloneEditor, ModelToDomOption, OnNodeCreated, PasteType, PluginEventData, PluginEventFromType, PluginEventType, Snapshot, SnapshotsManager, StandaloneEditorCore, StandaloneEditorOptions, TrustedHTMLHandler } from 'roosterjs-content-model-types';
import type { ClipboardData, ContentModelDocument, ContentModelFormatter, ContentModelSegmentFormat, DarkColorHandler, DOMEventRecord, DOMHelper, DOMSelection, EditorEnvironment, FormatWithContentModelOptions, IStandaloneEditor, PasteType, PluginEventData, PluginEventFromType, PluginEventType, Snapshot, SnapshotsManager, StandaloneEditorCore, StandaloneEditorOptions, TrustedHTMLHandler } from 'roosterjs-content-model-types';
/**

@@ -24,13 +24,14 @@ * The standalone editor class based on Content Model

* Create Content Model from DOM tree in this editor
* @param option The option to customize the behavior of DOM to Content Model conversion
* @param mode What kind of Content Model we want. Currently we support the following values:
* - connected: Returns a connect Content Model object. "Connected" means if there is any entity inside editor, the returned Content Model will
* contain the same wrapper element for entity. This option should only be used in some special cases. In most cases we should use "disconnected"
* to get a fully disconnected Content Model so that any change to the model will not impact editor content.
* - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.
* If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.
* If editor is in dark mode, the cloned entity will be converted back to light mode.
* - reduced: Returns a reduced Content Model that only contains the model of current selection. If there is already a up-to-date cached model, use it
* instead to improve performance. This is mostly used for retrieve current format state.
*/
createContentModel(option?: DomToModelOption, selectionOverride?: DOMSelection): ContentModelDocument;
getContentModelCopy(mode: 'connected' | 'disconnected' | 'reduced'): ContentModelDocument;
/**
* Set content with content model
* @param model The content model to set
* @param option Additional options to customize the behavior of Content Model to DOM conversion
* @param onNodeCreated An optional callback that will be called when a DOM node is created
*/
setContentModel(model: ContentModelDocument, option?: ModelToDomOption, onNodeCreated?: OnNodeCreated): DOMSelection | null;
/**
* Get current running environment, such as if editor is running on Mac

@@ -62,2 +63,6 @@ */

/**
* Get a DOM Helper object to help access DOM tree in editor
*/
getDOMHelper(): DOMHelper;
/**
* Add a single undo snapshot to undo stack

@@ -147,21 +152,2 @@ */

/**
* Check if the given DOM node is in editor
* @param node The node to check
*/
isNodeInEditor(node: Node): boolean;
/**
* Get current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @returns current zoom scale number
*/
getZoomScale(): number;
/**
* Set current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @param scale The new scale number to set. It should be positive number and no greater than 10, otherwise it will be ignored.
*/
setZoomScale(scale: number): void;
/**
* Get a function to convert HTML string to trusted HTML string.

@@ -178,2 +164,3 @@ * By default it will just return the input HTML directly. To override this behavior,

protected getCore(): StandaloneEditorCore;
private cloneOptionCallback;
}

@@ -1,2 +0,2 @@

define(["require", "exports", "tslib", "../constants/ChangeSource", "./createStandaloneEditorCore", "../publicApi/color/transformColor"], function (require, exports, tslib_1, ChangeSource_1, createStandaloneEditorCore_1, transformColor_1) {
define(["require", "exports", "tslib", "../constants/ChangeSource", "../publicApi/model/cloneModel", "roosterjs-content-model-dom", "./createStandaloneEditorCore", "../override/reducedModelChildProcessor", "../publicApi/color/transformColor"], function (require, exports, tslib_1, ChangeSource_1, cloneModel_1, roosterjs_content_model_dom_1, createStandaloneEditorCore_1, reducedModelChildProcessor_1, transformColor_1) {
"use strict";

@@ -17,6 +17,22 @@ Object.defineProperty(exports, "__esModule", { value: true });

if (options === void 0) { options = {}; }
var _a;
this.core = null;
this.cloneOptionCallback = function (node, type) {
if (type == 'cache') {
return undefined;
}
var result = node.cloneNode(true /*deep*/);
if (_this.isDarkMode()) {
var colorHandler = _this.getColorManager();
(0, transformColor_1.transformColor)(result, true /*includeSelf*/, 'darkToLight', colorHandler);
result.style.color = result.style.color || 'inherit';
result.style.backgroundColor = result.style.backgroundColor || 'inherit';
}
return result;
};
this.core = (0, createStandaloneEditorCore_1.createStandaloneEditorCore)(contentDiv, options);
onBeforeInitializePlugins === null || onBeforeInitializePlugins === void 0 ? void 0 : onBeforeInitializePlugins();
this.getCore().plugins.forEach(function (plugin) { return plugin.initialize(_this); });
var initialModel = (_a = options.initialModel) !== null && _a !== void 0 ? _a : (0, roosterjs_content_model_dom_1.createEmptyModel)(options.defaultSegmentFormat);
this.core.api.setContentModel(this.core, initialModel, { ignoreSelection: true });
this.core.plugins.forEach(function (plugin) { return plugin.initialize(_this); });
}

@@ -51,19 +67,34 @@ /**

* Create Content Model from DOM tree in this editor
* @param option The option to customize the behavior of DOM to Content Model conversion
* @param mode What kind of Content Model we want. Currently we support the following values:
* - connected: Returns a connect Content Model object. "Connected" means if there is any entity inside editor, the returned Content Model will
* contain the same wrapper element for entity. This option should only be used in some special cases. In most cases we should use "disconnected"
* to get a fully disconnected Content Model so that any change to the model will not impact editor content.
* - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.
* If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.
* If editor is in dark mode, the cloned entity will be converted back to light mode.
* - reduced: Returns a reduced Content Model that only contains the model of current selection. If there is already a up-to-date cached model, use it
* instead to improve performance. This is mostly used for retrieve current format state.
*/
StandaloneEditor.prototype.createContentModel = function (option, selectionOverride) {
StandaloneEditor.prototype.getContentModelCopy = function (mode) {
var core = this.getCore();
return core.api.createContentModel(core, option, selectionOverride);
switch (mode) {
case 'connected':
return core.api.createContentModel(core, {
processorOverride: {
table: roosterjs_content_model_dom_1.tableProcessor, // Use the original table processor to create Content Model with real table content but not just an entity
},
});
case 'disconnected':
return (0, cloneModel_1.cloneModel)(core.api.createContentModel(core), {
includeCachedElement: this.cloneOptionCallback,
});
case 'reduced':
return core.api.createContentModel(core, {
processorOverride: {
child: reducedModelChildProcessor_1.reducedModelChildProcessor,
},
});
}
};
/**
* Set content with content model
* @param model The content model to set
* @param option Additional options to customize the behavior of Content Model to DOM conversion
* @param onNodeCreated An optional callback that will be called when a DOM node is created
*/
StandaloneEditor.prototype.setContentModel = function (model, option, onNodeCreated) {
var core = this.getCore();
return core.api.setContentModel(core, model, option, onNodeCreated);
};
/**
* Get current running environment, such as if editor is running on Mac

@@ -109,2 +140,8 @@ */

/**
* Get a DOM Helper object to help access DOM tree in editor
*/
StandaloneEditor.prototype.getDOMHelper = function () {
return this.getCore().domHelper;
};
/**
* Add a single undo snapshot to undo stack

@@ -250,38 +287,2 @@ */

/**
* Check if the given DOM node is in editor
* @param node The node to check
*/
StandaloneEditor.prototype.isNodeInEditor = function (node) {
var core = this.getCore();
return core.contentDiv.contains(node);
};
/**
* Get current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @returns current zoom scale number
*/
StandaloneEditor.prototype.getZoomScale = function () {
return this.getCore().zoomScale;
};
/**
* Set current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @param scale The new scale number to set. It should be positive number and no greater than 10, otherwise it will be ignored.
*/
StandaloneEditor.prototype.setZoomScale = function (scale) {
var core = this.getCore();
if (scale > 0 && scale <= 10) {
var oldValue = core.zoomScale;
core.zoomScale = scale;
if (oldValue != scale) {
this.triggerEvent('zoomChanged', {
oldZoomScale: oldValue,
newZoomScale: scale,
}, true /*broadcast*/);
}
}
};
/**
* Get a function to convert HTML string to trusted HTML string.

@@ -288,0 +289,0 @@ * By default it will just return the input HTML directly. To override this behavior,

@@ -34,3 +34,3 @@ define(["require", "exports"], function (require, exports) {

else if (v && !result.color) {
result.color = v; // TODO: Do we need to use a regex to match all possible colors?
result.color = v;
}

@@ -37,0 +37,0 @@ });

@@ -15,2 +15,3 @@ define(["require", "exports"], function (require, exports) {

function deleteBlock(blocks, blockToDelete, replacement, context, direction) {
var _a;
var index = blocks.indexOf(blockToDelete);

@@ -31,2 +32,4 @@ switch (blockToDelete.blockType) {

if (operation !== undefined) {
var wrapper = blockToDelete.wrapper;
(_a = wrapper.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(wrapper);
replacement ? blocks.splice(index, 1, replacement) : blocks.splice(index, 1);

@@ -33,0 +36,0 @@ context === null || context === void 0 ? void 0 : context.deletedEntities.push({

@@ -14,2 +14,3 @@ define(["require", "exports", "../../modelApi/edit/deleteSingleChar", "roosterjs-content-model-dom", "../domUtils/stringUtil"], function (require, exports, deleteSingleChar_1, roosterjs_content_model_dom_1, stringUtil_1) {

function deleteSegment(paragraph, segmentToDelete, context, direction) {
var _a;
var segments = paragraph.segments;

@@ -38,2 +39,4 @@ var index = segments.indexOf(segmentToDelete);

if (operation !== undefined) {
var wrapper = segmentToDelete.wrapper;
(_a = wrapper.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(wrapper);
segments.splice(index, 1);

@@ -70,4 +73,2 @@ context === null || context === void 0 ? void 0 : context.deletedEntities.push({

else {
// No op if a general segment is not selected, let browser handle general segment
// TODO: Need to revisit this
return false;

@@ -74,0 +75,0 @@ }

@@ -15,4 +15,2 @@ define(["require", "exports", "tslib"], function (require, exports, tslib_1) {

if (!!((_a = block) === null || _a === void 0 ? void 0 : _a.cachedElement)) {
// TODO: This is a temporary solution. A better solution would be making all results from iterationSelection() to be readonly,
// use a util function to change it to be editable before edit them where we clear its cached element
delete block.cachedElement;

@@ -19,0 +17,0 @@ }

@@ -1,5 +0,5 @@

import type { DOMSelection, SnapshotSelection } from 'roosterjs-content-model-types';
import type { SnapshotSelection, StandaloneEditorCore } from 'roosterjs-content-model-types';
/**
* @internal
*/
export declare function createSnapshotSelection(contentDiv: HTMLElement, selection: DOMSelection | null): SnapshotSelection;
export declare function createSnapshotSelection(core: StandaloneEditorCore): SnapshotSelection;

@@ -8,3 +8,23 @@ define(["require", "exports", "roosterjs-content-model-dom"], function (require, exports, roosterjs_content_model_dom_1) {

*/
function createSnapshotSelection(contentDiv, selection) {
function createSnapshotSelection(core) {
var contentDiv = core.contentDiv, api = core.api;
var selection = api.getDOMSelection(core);
// Normalize tables to ensure they have TBODY element between TABLE and TR so that the selection path will include correct values
if ((selection === null || selection === void 0 ? void 0 : selection.type) == 'range') {
var _a = selection.range, startContainer = _a.startContainer, startOffset = _a.startOffset, endContainer = _a.endContainer, endOffset = _a.endOffset;
var isDOMChanged = normalizeTableTree(startContainer, contentDiv);
if (endContainer != startContainer) {
isDOMChanged = normalizeTableTree(endContainer, contentDiv) || isDOMChanged;
}
if (isDOMChanged) {
var newRange = contentDiv.ownerDocument.createRange();
newRange.setStart(startContainer, startOffset);
newRange.setEnd(endContainer, endOffset);
api.setDOMSelection(core, {
type: 'range',
range: newRange,
isReverted: !!selection.isReverted,
}, true /*skipSelectionChangedEvent*/);
}
}
switch (selection === null || selection === void 0 ? void 0 : selection.type) {

@@ -31,2 +51,3 @@ case 'image':

end: getPath(range.endContainer, range.endOffset, contentDiv),
isReverted: !!selection.isReverted,
};

@@ -38,2 +59,3 @@ default:

end: [],
isReverted: false,
};

@@ -95,3 +117,57 @@ }

}
function normalizeTableTree(startNode, root) {
var node = startNode;
var isDOMChanged = false;
while (node && root.contains(node)) {
if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'ELEMENT_NODE') && (0, roosterjs_content_model_dom_1.isElementOfType)(node, 'table')) {
isDOMChanged = normalizeTable(node) || isDOMChanged;
}
node = node.parentNode;
}
return isDOMChanged;
}
function normalizeTable(table) {
var _a;
var isDOMChanged = false;
var tbody = null;
for (var child = table.firstChild; child; child = child.nextSibling) {
var tag = (0, roosterjs_content_model_dom_1.isNodeOfType)(child, 'ELEMENT_NODE') ? child.tagName : null;
switch (tag) {
case 'TR':
if (!tbody) {
tbody = table.ownerDocument.createElement('tbody');
table.insertBefore(tbody, child);
}
tbody.appendChild(child);
child = tbody;
isDOMChanged = true;
break;
case 'TBODY':
if (tbody) {
(0, roosterjs_content_model_dom_1.moveChildNodes)(tbody, child, true /*keepExistingChildren*/);
(_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
child = tbody;
isDOMChanged = true;
}
else {
tbody = child;
}
break;
default:
tbody = null;
break;
}
}
var colgroups = table.querySelectorAll('colgroup');
var thead = table.querySelector('thead');
if (thead) {
colgroups.forEach(function (colgroup) {
if (!thead.contains(colgroup)) {
thead.appendChild(colgroup);
}
});
}
return isDOMChanged;
}
});
//# sourceMappingURL=createSnapshotSelection.js.map

@@ -1,5 +0,5 @@

import type { BeforePasteEvent, ContentModelDocument, DomToModelOption, FormatWithContentModelContext } from 'roosterjs-content-model-types';
import type { BeforePasteEvent, ClipboardData, StandaloneEditorCore } from 'roosterjs-content-model-types';
/**
* @internal
*/
export declare function mergePasteContent(model: ContentModelDocument, context: FormatWithContentModelContext, eventResult: BeforePasteEvent, defaultDomToModelOptions: DomToModelOption): void;
export declare function mergePasteContent(core: StandaloneEditorCore, eventResult: BeforePasteEvent, clipboardData: ClipboardData): void;

@@ -1,2 +0,2 @@

define(["require", "exports", "tslib", "../../override/containerSizeFormatParser", "roosterjs-content-model-dom", "../../override/pasteEntityProcessor", "../../override/pasteGeneralProcessor", "../../publicApi/domUtils/getSegmentTextFormat", "../../publicApi/selection/collectSelections", "../../publicApi/model/mergeModel", "../../override/pasteDisplayFormatParser", "../../override/pasteTextProcessor"], function (require, exports, tslib_1, containerSizeFormatParser_1, roosterjs_content_model_dom_1, pasteEntityProcessor_1, pasteGeneralProcessor_1, getSegmentTextFormat_1, collectSelections_1, mergeModel_1, pasteDisplayFormatParser_1, pasteTextProcessor_1) {
define(["require", "exports", "tslib", "../../constants/ChangeSource", "../../override/containerSizeFormatParser", "roosterjs-content-model-dom", "../../override/pasteEntityProcessor", "../../override/pasteGeneralProcessor", "../../publicApi/domUtils/getSegmentTextFormat", "../../publicApi/selection/collectSelections", "../../publicApi/model/mergeModel", "../../override/pasteDisplayFormatParser", "../../override/pasteTextProcessor"], function (require, exports, tslib_1, ChangeSource_1, containerSizeFormatParser_1, roosterjs_content_model_dom_1, pasteEntityProcessor_1, pasteGeneralProcessor_1, getSegmentTextFormat_1, collectSelections_1, mergeModel_1, pasteDisplayFormatParser_1, pasteTextProcessor_1) {
"use strict";

@@ -21,30 +21,39 @@ Object.defineProperty(exports, "__esModule", { value: true });

*/
function mergePasteContent(model, context, eventResult, defaultDomToModelOptions) {
function mergePasteContent(core, eventResult, clipboardData) {
var fragment = eventResult.fragment, domToModelOption = eventResult.domToModelOption, customizedMerge = eventResult.customizedMerge, pasteType = eventResult.pasteType;
var selectedSegment = (0, collectSelections_1.getSelectedSegments)(model, true /*includeFormatHolder*/)[0];
var domToModelContext = (0, roosterjs_content_model_dom_1.createDomToModelContext)(undefined /*editorContext*/, defaultDomToModelOptions, {
processorOverride: {
'#text': pasteTextProcessor_1.pasteTextProcessor,
entity: (0, pasteEntityProcessor_1.createPasteEntityProcessor)(domToModelOption),
'*': (0, pasteGeneralProcessor_1.createPasteGeneralProcessor)(domToModelOption),
},
formatParserOverride: {
display: pasteDisplayFormatParser_1.pasteDisplayFormatParser,
},
additionalFormatParsers: {
container: [containerSizeFormatParser_1.containerSizeFormatParser],
},
}, domToModelOption);
domToModelContext.segmentFormat = selectedSegment ? (0, getSegmentTextFormat_1.getSegmentTextFormat)(selectedSegment) : {};
var pasteModel = (0, roosterjs_content_model_dom_1.domToContentModel)(fragment, domToModelContext);
var mergeOption = {
mergeFormat: pasteType == 'mergeFormat' ? 'keepSourceEmphasisFormat' : 'none',
mergeTable: shouldMergeTable(pasteModel),
};
var insertPoint = customizedMerge
? customizedMerge(model, pasteModel)
: (0, mergeModel_1.mergeModel)(model, pasteModel, context, mergeOption);
if (insertPoint) {
context.newPendingFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, EmptySegmentFormat), model.format), insertPoint.marker.format);
}
core.api.formatContentModel(core, function (model, context) {
var selectedSegment = (0, collectSelections_1.getSelectedSegments)(model, true /*includeFormatHolder*/)[0];
var domToModelContext = (0, roosterjs_content_model_dom_1.createDomToModelContext)(undefined /*editorContext*/, core.domToModelSettings.customized, {
processorOverride: {
'#text': pasteTextProcessor_1.pasteTextProcessor,
entity: (0, pasteEntityProcessor_1.createPasteEntityProcessor)(domToModelOption),
'*': (0, pasteGeneralProcessor_1.createPasteGeneralProcessor)(domToModelOption),
},
formatParserOverride: {
display: pasteDisplayFormatParser_1.pasteDisplayFormatParser,
},
additionalFormatParsers: {
container: [containerSizeFormatParser_1.containerSizeFormatParser],
},
}, domToModelOption);
domToModelContext.segmentFormat = selectedSegment
? (0, getSegmentTextFormat_1.getSegmentTextFormat)(selectedSegment)
: {};
var pasteModel = (0, roosterjs_content_model_dom_1.domToContentModel)(fragment, domToModelContext);
var mergeOption = {
mergeFormat: pasteType == 'mergeFormat' ? 'keepSourceEmphasisFormat' : 'none',
mergeTable: shouldMergeTable(pasteModel),
};
var insertPoint = customizedMerge
? customizedMerge(model, pasteModel)
: (0, mergeModel_1.mergeModel)(model, pasteModel, context, mergeOption);
if (insertPoint) {
context.newPendingFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, EmptySegmentFormat), model.format), insertPoint.marker.format);
}
return true;
}, {
changeSource: ChangeSource_1.ChangeSource.Paste,
getChangeData: function () { return clipboardData; },
apiName: 'paste',
});
}

@@ -51,0 +60,0 @@ exports.mergePasteContent = mergePasteContent;

@@ -23,2 +23,3 @@ define(["require", "exports", "roosterjs-content-model-dom"], function (require, exports, roosterjs_content_model_dom_1) {

range: range,
isReverted: snapshotSelection.isReverted,
};

@@ -25,0 +26,0 @@ break;

@@ -12,11 +12,13 @@ import { createSnapshotSelection } from '../utils/createSnapshotSelection';

export var addUndoSnapshot = function (core, canUndoByBackspace, entityStates) {
var lifecycle = core.lifecycle, api = core.api, contentDiv = core.contentDiv, undo = core.undo;
var lifecycle = core.lifecycle, contentDiv = core.contentDiv, undo = core.undo;
var snapshot = null;
if (!lifecycle.shadowEditFragment) {
var selection = api.getDOMSelection(core);
// Need to create snapshot selection before retrieve innerHTML since HTML can be changed during creating selection when normalize table
var selection = createSnapshotSelection(core);
var html = contentDiv.innerHTML;
snapshot = {
html: contentDiv.innerHTML,
html: html,
entityStates: entityStates,
isDarkMode: !!lifecycle.isDarkMode,
selection: createSnapshotSelection(contentDiv, selection),
selection: selection,
};

@@ -23,0 +25,0 @@ undo.snapshotsManager.addSnapshot(snapshot, !!canUndoByBackspace);

@@ -11,2 +11,5 @@ import { cloneModel } from '../publicApi/model/cloneModel';

export var createContentModel = function (core, option, selectionOverride) {
var _a;
// Flush all mutations if any, so that we can get an up-to-date Content Model
(_a = core.cache.textMutationObserver) === null || _a === void 0 ? void 0 : _a.flushMutations();
var cachedModel = selectionOverride ? null : core.cache.cachedModel;

@@ -22,4 +25,9 @@ if (cachedModel && core.lifecycle.shadowEditFragment) {

var selection = selectionOverride || core.api.getDOMSelection(core) || undefined;
var model = internalCreateContentModel(core, selection, option);
if (!option && !selectionOverride) {
var saveIndex = !option && !selectionOverride;
var editorContext = core.api.createEditorContext(core, saveIndex);
var domToModelContext = option
? createDomToModelContext(editorContext, core.domToModelSettings.builtIn, core.domToModelSettings.customized, option)
: createDomToModelContextWithConfig(core.domToModelSettings.calculated, editorContext);
var model = domToContentModel(core.contentDiv, domToModelContext, selection);
if (saveIndex) {
core.cache.cachedModel = model;

@@ -31,9 +39,2 @@ core.cache.cachedSelection = selection;

};
function internalCreateContentModel(core, selection, option) {
var editorContext = core.api.createEditorContext(core);
var domToModelContext = option
? createDomToModelContext(editorContext, core.domToModelSettings.builtIn, core.domToModelSettings.customized, option)
: createDomToModelContextWithConfig(core.domToModelSettings.calculated, editorContext);
return domToContentModel(core.contentDiv, domToModelContext, selection);
}
//# sourceMappingURL=createContentModel.js.map

@@ -5,5 +5,5 @@ /**

*/
export var createEditorContext = function (core) {
export var createEditorContext = function (core, saveIndex) {
var _a;
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, contentDiv = core.contentDiv, cache = core.cache;
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, contentDiv = core.contentDiv, cache = core.cache, domHelper = core.domHelper;
var context = {

@@ -16,16 +16,8 @@ isDarkMode: lifecycle.isDarkMode,

allowCacheElement: true,
domIndexer: cache.domIndexer,
domIndexer: saveIndex ? cache.domIndexer : undefined,
zoomScale: domHelper.calculateZoomScale(),
};
checkRootRtl(contentDiv, context);
checkZoomScale(contentDiv, context);
return context;
};
function checkZoomScale(element, context) {
var _a;
var originalWidth = ((_a = element === null || element === void 0 ? void 0 : element.getBoundingClientRect()) === null || _a === void 0 ? void 0 : _a.width) || 0;
var visualWidth = element.offsetWidth;
if (visualWidth > 0 && originalWidth > 0) {
context.zoomScale = Math.round((originalWidth / visualWidth) * 100) / 100;
}
}
function checkRootRtl(element, context) {

@@ -32,0 +24,0 @@ var _a;

@@ -5,6 +5,11 @@ /**

export var getDOMSelection = function (core) {
var _a;
return core.lifecycle.shadowEditFragment
? null
: (_a = core.selection.selection) !== null && _a !== void 0 ? _a : getNewSelection(core);
if (core.lifecycle.shadowEditFragment) {
return null;
}
else {
var selection = core.selection.selection;
return selection && (selection.type != 'range' || !core.api.hasFocus(core))
? selection
: getNewSelection(core);
}
};

@@ -19,5 +24,15 @@ function getNewSelection(core) {

range: range,
isReverted: isSelectionReverted(selection),
}
: null;
}
function isSelectionReverted(selection) {
if (selection && selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
return (!range.collapsed &&
selection.focusNode != range.endContainer &&
selection.focusOffset != range.endOffset);
}
return false;
}
//# sourceMappingURL=getDOMSelection.js.map

@@ -1,2 +0,1 @@

import { ChangeSource } from '../constants/ChangeSource';
import { cloneModel } from '../publicApi/model/cloneModel';

@@ -19,2 +18,3 @@ import { convertInlineCss } from '../utils/paste/convertInlineCss';

export var paste = function (core, clipboardData, pasteType) {
var _a;
if (pasteType === void 0) { pasteType = 'normal'; }

@@ -28,24 +28,16 @@ core.api.focus(core);

}
core.api.formatContentModel(core, function (model, context) {
var _a;
// 1. Prepare variables
var doc = createDOMFromHtml(clipboardData.rawHtml, core.trustedHTMLHandler);
// 2. Handle HTML from clipboard
var htmlFromClipboard = retrieveHtmlInfo(doc, clipboardData);
// 3. Create target fragment
var sourceFragment = createPasteFragment(core.contentDiv.ownerDocument, clipboardData, pasteType, (_a = (clipboardData.rawHtml == clipboardData.html
? doc
: createDOMFromHtml(clipboardData.html, core.trustedHTMLHandler))) === null || _a === void 0 ? void 0 : _a.body);
// 4. Trigger BeforePaste event to allow plugins modify the fragment
var eventResult = generatePasteOptionFromPlugins(core, clipboardData, sourceFragment, htmlFromClipboard, pasteType);
// 5. Convert global CSS to inline CSS
convertInlineCss(eventResult.fragment, htmlFromClipboard.globalCssRules);
// 6. Merge pasted content into main Content Model
mergePasteContent(model, context, eventResult, core.domToModelSettings.customized);
return true;
}, {
changeSource: ChangeSource.Paste,
getChangeData: function () { return clipboardData; },
apiName: 'paste',
});
// 1. Prepare variables
var doc = createDOMFromHtml(clipboardData.rawHtml, core.trustedHTMLHandler);
// 2. Handle HTML from clipboard
var htmlFromClipboard = retrieveHtmlInfo(doc, clipboardData);
// 3. Create target fragment
var sourceFragment = createPasteFragment(core.contentDiv.ownerDocument, clipboardData, pasteType, (_a = (clipboardData.rawHtml == clipboardData.html
? doc
: createDOMFromHtml(clipboardData.html, core.trustedHTMLHandler))) === null || _a === void 0 ? void 0 : _a.body);
// 4. Trigger BeforePaste event to allow plugins modify the fragment
var eventResult = generatePasteOptionFromPlugins(core, clipboardData, sourceFragment, htmlFromClipboard, pasteType);
// 5. Convert global CSS to inline CSS
convertInlineCss(eventResult.fragment, htmlFromClipboard.globalCssRules);
// 6. Merge pasted content into main Content Model
mergePasteContent(core, eventResult, clipboardData);
};

@@ -52,0 +44,0 @@ function createDOMFromHtml(html, trustedHTMLHandler) {

@@ -10,7 +10,9 @@ import { contentModelToDom, createModelToDomContext, createModelToDomContextWithConfig, } from 'roosterjs-content-model-dom';

export var setContentModel = function (core, model, option, onNodeCreated) {
var editorContext = core.api.createEditorContext(core);
var _a;
var editorContext = core.api.createEditorContext(core, true /*saveIndex*/);
var modelToDomContext = option
? createModelToDomContext(editorContext, core.modelToDomSettings.builtIn, core.modelToDomSettings.customized, option)
: createModelToDomContextWithConfig(core.modelToDomSettings.calculated, editorContext);
var selection = contentModelToDom(core.contentDiv.ownerDocument, core.contentDiv, model, modelToDomContext, onNodeCreated);
modelToDomContext.onNodeCreated = onNodeCreated;
var selection = contentModelToDom(core.contentDiv.ownerDocument, core.contentDiv, model, modelToDomContext);
if (!core.lifecycle.shadowEditFragment) {

@@ -21,5 +23,7 @@ core.cache.cachedSelection = selection || undefined;

}
else if (!selection || selection.type !== 'range') {
else {
core.selection.selection = selection;
}
// Clear pending mutations since we will use our latest model object to replace existing cache
(_a = core.cache.textMutationObserver) === null || _a === void 0 ? void 0 : _a.flushMutations();
core.cache.cachedModel = model;

@@ -26,0 +30,0 @@ }

@@ -39,3 +39,3 @@ import { addRangeToSelection } from '../corePlugin/utils/addRangeToSelection';

case 'range':
addRangeToSelection(doc, selection.range);
addRangeToSelection(doc, selection.range, selection.isReverted);
core.selection.selection = core.api.hasFocus(core) ? null : selection;

@@ -42,0 +42,0 @@ break;

@@ -10,3 +10,2 @@ import { iterateSelections } from '../publicApi/selection/iterateSelections';

export var switchShadowEdit = function (editorCore, isOn) {
// TODO: Use strong-typed editor core object
var core = editorCore;

@@ -16,4 +15,2 @@ if (isOn != !!core.lifecycle.shadowEditFragment) {

var model = !core.cache.cachedModel ? core.api.createContentModel(core) : null;
// Fake object, not used in Content Model Editor, just to satisfy original editor code
// TODO: we can remove them once we have standalone Content Model Editor
var fragment = core.contentDiv.ownerDocument.createDocumentFragment();

@@ -20,0 +17,0 @@ var clonedRoot = core.contentDiv.cloneNode(true /*deep*/);

@@ -6,3 +6,4 @@ import type { ContentModelCachePluginState, PluginWithState, StandaloneEditorOptions } from 'roosterjs-content-model-types';

* @param option The editor option
* @param contentDiv The editor content DIV
*/
export declare function createContentModelCachePlugin(option: StandaloneEditorOptions): PluginWithState<ContentModelCachePluginState>;
export declare function createContentModelCachePlugin(option: StandaloneEditorOptions, contentDiv: HTMLDivElement): PluginWithState<ContentModelCachePluginState>;
import { areSameSelection } from './utils/areSameSelection';
import { contentModelDomIndexer } from './utils/contentModelDomIndexer';
import { isCharacterValue } from '../publicApi/domUtils/eventUtils';
import { createTextMutationObserver } from './utils/textMutationObserver';
/**

@@ -11,6 +11,17 @@ * ContentModel cache plugin manages cached Content Model, and refresh the cache when necessary

* @param option The editor option
* @param contentDiv The editor content DIV
*/
function ContentModelCachePlugin(option) {
function ContentModelCachePlugin(option, contentDiv) {
var _this = this;
this.editor = null;
this.onMutation = function (isTextChangeOnly) {
if (_this.editor) {
if (isTextChangeOnly) {
_this.updateCachedModel(_this.editor, true /*forceUpdate*/);
}
else {
_this.invalidateCache();
}
}
};
this.onNativeSelectionChange = function () {

@@ -22,5 +33,8 @@ var _a;

};
this.state = {
domIndexer: option.cacheModel ? contentModelDomIndexer : undefined,
};
this.state = option.cacheModel
? {
domIndexer: contentModelDomIndexer,
textMutationObserver: createTextMutationObserver(contentDiv, this.onMutation),
}
: {};
}

@@ -40,5 +54,6 @@ /**

ContentModelCachePlugin.prototype.initialize = function (editor) {
// TODO: Later we may need a different interface for Content Model editor plugin
var _a;
this.editor = editor;
this.editor.getDocument().addEventListener('selectionchange', this.onNativeSelectionChange);
(_a = this.state.textMutationObserver) === null || _a === void 0 ? void 0 : _a.startObserving();
};

@@ -51,2 +66,4 @@ /**

ContentModelCachePlugin.prototype.dispose = function () {
var _a;
(_a = this.state.textMutationObserver) === null || _a === void 0 ? void 0 : _a.stopObserving();
if (this.editor) {

@@ -77,11 +94,8 @@ this.editor

case 'keyDown':
if (this.shouldClearCache(event)) {
case 'input':
if (!this.state.textMutationObserver) {
// When updating cache is not enabled, need to clear the cache to make sure other plugins can get an up-to-date content model
this.invalidateCache();
}
break;
case 'input':
{
this.updateCachedModel(this.editor, true /*forceUpdate*/);
}
break;
case 'selectionChanged':

@@ -91,12 +105,10 @@ this.updateCachedModel(this.editor);

case 'contentChanged':
{
var contentModel = event.contentModel, selection = event.selection;
if (contentModel && this.state.domIndexer) {
this.state.cachedModel = contentModel;
this.state.cachedSelection = selection;
}
else {
this.invalidateCache();
}
var contentModel = event.contentModel, selection = event.selection;
if (contentModel && this.state.domIndexer) {
this.state.cachedModel = contentModel;
this.state.cachedSelection = selection;
}
else {
this.invalidateCache();
}
break;

@@ -136,27 +148,2 @@ }

};
ContentModelCachePlugin.prototype.shouldClearCache = function (event) {
var _a;
var rawEvent = event.rawEvent, handledByEditFeature = event.handledByEditFeature;
// In these cases we can't update the model, so clear cache:
// 1. It is already handled by Content Edit Features
if (handledByEditFeature) {
return true;
}
// 2. Default behavior is prevented, which means other plugins has handled the event
if (rawEvent.defaultPrevented) {
return true;
}
// 3. ENTER key is pressed. ENTER key will create new paragraph, so need to update cache to reflect this change
// TODO: Handle ENTER key to better reuse content model
if (rawEvent.key == 'Enter') {
return true;
}
// 4. Current selection is image or table or expanded range selection, and is inputting some text
if ((((_a = this.state.cachedSelection) === null || _a === void 0 ? void 0 : _a.type) != 'range' ||
!this.state.cachedSelection.range.collapsed) &&
isCharacterValue(rawEvent)) {
return true;
}
return false;
};
return ContentModelCachePlugin;

@@ -168,6 +155,7 @@ }());

* @param option The editor option
* @param contentDiv The editor content DIV
*/
export function createContentModelCachePlugin(option) {
return new ContentModelCachePlugin(option);
export function createContentModelCachePlugin(option, contentDiv) {
return new ContentModelCachePlugin(option, contentDiv);
}
//# sourceMappingURL=ContentModelCachePlugin.js.map
import { __assign } from "tslib";
import { addRangeToSelection } from './utils/addRangeToSelection';
import { ChangeSource } from '../constants/ChangeSource';
import { cloneModel } from '../publicApi/model/cloneModel';
import { deleteEmptyList } from './utils/deleteEmptyList';

@@ -10,3 +9,2 @@ import { deleteSelection } from '../publicApi/selection/deleteSelection';

import { iterateSelections } from '../publicApi/selection/iterateSelections';
import { transformColor } from '../publicApi/color/transformColor';
import { contentModelToDom, createModelToDomContext, isElementOfType, isNodeOfType, moveChildNodes, normalizeContentModel, toArray, wrap, } from 'roosterjs-content-model-dom';

@@ -39,13 +37,2 @@ /**

};
this.processEntityColor = function (node, type) {
if (type == 'cache' || !_this.editor) {
return undefined;
}
var result = node.cloneNode(true /*deep*/);
var colorHandler = _this.editor.getColorManager();
transformColor(result, true /*includeSelf*/, 'darkToLight', colorHandler);
result.style.color = result.style.color || 'inherit';
result.style.backgroundColor = result.style.backgroundColor || 'inherit';
return result;
};
this.state = {

@@ -111,7 +98,3 @@ allowedCustomPasteType: option.allowedCustomPasteType || [],

if (selection && (selection.type != 'range' || !selection.range.collapsed)) {
var model = this.editor.createContentModel(undefined /* option */, selection);
var cacheProcessor = this.editor.isDarkMode() ? this.processEntityColor : false;
var pasteModel = cloneModel(model, {
includeCachedElement: cacheProcessor,
});
var pasteModel = this.editor.getContentModelCopy('disconnected');
if (selection.type === 'table') {

@@ -130,3 +113,5 @@ iterateSelections(pasteModel, function (_, tableContext) {

var tempDiv_1 = this.getTempDiv(this.editor.getDocument());
var selectionForCopy = contentModelToDom(tempDiv_1.ownerDocument, tempDiv_1, pasteModel, createModelToDomContext(), onNodeCreated);
var context = createModelToDomContext();
context.onNodeCreated = onNodeCreated;
var selectionForCopy = contentModelToDom(tempDiv_1.ownerDocument, tempDiv_1, pasteModel, context);
var newRange = selectionForCopy

@@ -133,0 +118,0 @@ ? domSelectionToRange(doc, selectionForCopy)

@@ -40,3 +40,2 @@ import { __assign } from "tslib";

var _this = this;
// TODO: Later we may need a different interface for Content Model editor plugin
this.editor = editor;

@@ -43,0 +42,0 @@ this.hasDefaultFormat =

import { createContentModelCachePlugin } from './ContentModelCachePlugin';
import { createContentModelCopyPastePlugin } from './ContentModelCopyPastePlugin';
import { createContentModelFormatPlugin } from './ContentModelFormatPlugin';
import { createContextMenuPlugin } from './ContextMenuPlugin';
import { createDOMEventPlugin } from './DOMEventPlugin';

@@ -16,3 +17,3 @@ import { createEntityPlugin } from './EntityPlugin';

return {
cache: createContentModelCachePlugin(options),
cache: createContentModelCachePlugin(options, contentDiv),
format: createContentModelFormatPlugin(options),

@@ -24,2 +25,3 @@ copyPaste: createContentModelCopyPastePlugin(options),

selection: createSelectionPlugin(options),
contextMenu: createContextMenuPlugin(options),
undo: createUndoPlugin(options),

@@ -26,0 +28,0 @@ };

@@ -70,3 +70,3 @@ import { findAllEntities } from './utils/findAllEntities';

if (isClicking && this.editor) {
while (node && this.editor.isNodeInEditor(node)) {
while (node && this.editor.getDOMHelper().isNodeInEditor(node)) {
if (isEntityElement(node)) {

@@ -127,3 +127,6 @@ this.triggerEvent(editor, node, 'click', rawEvent);

var result = [];
findAllEntities(editor.createContentModel(), result);
editor.formatContentModel(function (model) {
findAllEntities(model, result);
return false;
});
getObjectKeys(this.state.entityMap).forEach(function (id) {

@@ -130,0 +133,0 @@ var entry = _this.state.entityMap[id];

import { ChangeSource } from '../constants/ChangeSource';
import { createBr, createContentModelDocument, createParagraph, createSelectionMarker, setColor, } from 'roosterjs-content-model-dom';
import { setColor } from 'roosterjs-content-model-dom';
var ContentEditableAttributeName = 'contenteditable';

@@ -17,8 +17,5 @@ var DefaultTextColor = '#000000';

var _this = this;
var _a;
this.editor = null;
this.initializer = null;
this.disposer = null;
this.initialModel =
(_a = options.initialModel) !== null && _a !== void 0 ? _a : this.createInitModel(options.defaultSegmentFormat);
// Make the container editable and set its selection styles

@@ -58,6 +55,2 @@ if (contentDiv.getAttribute(ContentEditableAttributeName) === null) {

this.editor = editor;
this.editor.setContentModel(this.initialModel, { ignoreSelection: true });
// Initial model is only used once. After that we can just clean it up to make sure we don't cache anything useless
// including the cached DOM element inside the model.
this.initialModel = createContentModelDocument();
// Set content DIV to be editable

@@ -108,9 +101,2 @@ (_a = this.initializer) === null || _a === void 0 ? void 0 : _a.call(this);

};
LifecyclePlugin.prototype.createInitModel = function (format) {
var model = createContentModelDocument(format);
var paragraph = createParagraph(false /*isImplicit*/, undefined /*blockFormat*/, format);
paragraph.segments.push(createSelectionMarker(format), createBr(format));
model.blocks.push(paragraph);
return model;
};
return LifecyclePlugin;

@@ -117,0 +103,0 @@ }());

@@ -10,2 +10,3 @@ import { isElementOfType, isNodeOfType, toArray } from 'roosterjs-content-model-dom';

this.disposer = null;
this.isSafari = false;
this.onFocus = function () {

@@ -16,3 +17,3 @@ var _a, _b;

}
if (((_b = _this.state.selection) === null || _b === void 0 ? void 0 : _b.type) == 'range') {
if (((_b = _this.state.selection) === null || _b === void 0 ? void 0 : _b.type) == 'range' && !_this.isSafari) {
// Editor is focused, now we can get live selection. So no need to keep a selection if the selection type is range.

@@ -27,16 +28,17 @@ _this.state.selection = null;

};
this.onKeyDownDocument = function (event) {
if (event.key == 'Tab' && !event.defaultPrevented) {
_this.onBlur();
this.onSelectionChangeSafari = function () {
var _a;
if (((_a = _this.editor) === null || _a === void 0 ? void 0 : _a.hasFocus()) && !_this.editor.isInShadowEdit()) {
// Safari has problem to handle onBlur event. When blur, we cannot get the original selection from editor.
// So we always save a selection whenever editor has focus. Then after blur, we can still use this cached selection.
var newSelection = _this.editor.getDOMSelection();
if ((newSelection === null || newSelection === void 0 ? void 0 : newSelection.type) == 'range') {
_this.state.selection = newSelection;
}
}
};
this.onMouseDownDocument = function (event) {
if (_this.editor && !_this.editor.isNodeInEditor(event.target)) {
_this.onBlur();
}
};
this.state = {
selection: null,
selectionStyleNode: null,
imageSelectionBorderColor: options.imageSelectionBorderColor, // TODO: Move to Selection core plugin
imageSelectionBorderColor: options.imageSelectionBorderColor,
};

@@ -48,3 +50,2 @@ }

SelectionPlugin.prototype.initialize = function (editor) {
var _a;
this.editor = editor;

@@ -57,6 +58,5 @@ var doc = this.editor.getDocument();

var document = this.editor.getDocument();
if (env.isSafari) {
document.addEventListener('mousedown', this.onMouseDownDocument, true /*useCapture*/);
document.addEventListener('keydown', this.onKeyDownDocument);
(_a = document.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener('blur', this.onBlur);
this.isSafari = !!env.isSafari;
if (this.isSafari) {
document.addEventListener('selectionchange', this.onSelectionChangeSafari);
this.disposer = this.editor.attachDomEvent({ focus: { beforeDispatch: this.onFocus } });

@@ -73,4 +73,5 @@ }

var _a, _b;
(_a = this.editor) === null || _a === void 0 ? void 0 : _a.getDocument().removeEventListener('selectionchange', this.onSelectionChangeSafari);
if (this.state.selectionStyleNode) {
(_a = this.state.selectionStyleNode.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.state.selectionStyleNode);
(_b = this.state.selectionStyleNode.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.state.selectionStyleNode);
this.state.selectionStyleNode = null;

@@ -82,9 +83,3 @@ }

}
if (this.editor) {
var document_1 = this.editor.getDocument();
document_1.removeEventListener('mousedown', this.onMouseDownDocument, true /*useCapture*/);
document_1.removeEventListener('keydown', this.onKeyDownDocument);
(_b = document_1.defaultView) === null || _b === void 0 ? void 0 : _b.removeEventListener('blur', this.onBlur);
this.editor = null;
}
this.editor = null;
};

@@ -157,2 +152,3 @@ SelectionPlugin.prototype.getState = function () {

range: range,
isReverted: false,
});

@@ -159,0 +155,0 @@ }

/**
* @internal
*/
export declare function addRangeToSelection(doc: Document, range: Range): void;
export declare function addRangeToSelection(doc: Document, range: Range, isReverted?: boolean): void;
/**
* @internal
*/
export function addRangeToSelection(doc, range) {
export function addRangeToSelection(doc, range, isReverted) {
var _a;
if (isReverted === void 0) { isReverted = false; }
var selection = (_a = doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
if (!isReverted) {
selection.addRange(range);
}
else {
selection.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
}
}
}
//# sourceMappingURL=addRangeToSelection.js.map

@@ -18,3 +18,3 @@ import { __assign } from "tslib";

var node = posContainer;
while (node && editor.isNodeInEditor(node)) {
while (node && editor.getDOMHelper().isNodeInEditor(node)) {
if (isNodeOfType(node, 'ELEMENT_NODE')) {

@@ -21,0 +21,0 @@ if ((_c = node.getAttribute) === null || _c === void 0 ? void 0 : _c.call(node, 'style')) {

import { __assign, __read, __spreadArray } from "tslib";
import { createDarkColorHandler } from './DarkColorHandlerImpl';
import { createDOMHelper } from './DOMHelperImpl';
import { createStandaloneEditorCorePlugins } from '../corePlugin/createStandaloneEditorCorePlugins';

@@ -13,3 +14,3 @@ import { standaloneCoreApiMap } from './standaloneCoreApiMap';

export function createStandaloneEditorCore(contentDiv, options) {
var _a, _b, _c;
var _a, _b;
var corePlugins = createStandaloneEditorCorePlugins(options, contentDiv);

@@ -25,4 +26,5 @@ return __assign(__assign({ contentDiv: contentDiv, api: __assign(__assign({}, standaloneCoreApiMap), options.coreApiOverride), originalApi: __assign({}, standaloneCoreApiMap), plugins: __spreadArray(__spreadArray([

corePlugins.undo,
corePlugins.contextMenu,
corePlugins.lifecycle,
], false), environment: createEditorEnvironment(contentDiv), darkColorHandler: createDarkColorHandler(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors), trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler, domToModelSettings: createDomToModelSettings(options), modelToDomSettings: createModelToDomSettings(options) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler, zoomScale: ((_c = options.zoomScale) !== null && _c !== void 0 ? _c : -1) > 0 ? options.zoomScale : 1 });
], false), environment: createEditorEnvironment(contentDiv), darkColorHandler: createDarkColorHandler(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors), trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler, domToModelSettings: createDomToModelSettings(options), modelToDomSettings: createModelToDomSettings(options), domHelper: createDOMHelper(contentDiv) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler });
}

@@ -57,2 +59,3 @@ function createEditorEnvironment(contentDiv) {

selection: corePlugins.selection.getState(),
contextMenu: corePlugins.contextMenu.getState(),
undo: corePlugins.undo.getState(),

@@ -59,0 +62,0 @@ };

@@ -1,2 +0,2 @@

import type { ClipboardData, ContentModelDocument, ContentModelFormatter, ContentModelSegmentFormat, DarkColorHandler, DOMEventRecord, DOMSelection, DomToModelOption, EditorEnvironment, FormatWithContentModelOptions, IStandaloneEditor, ModelToDomOption, OnNodeCreated, PasteType, PluginEventData, PluginEventFromType, PluginEventType, Snapshot, SnapshotsManager, StandaloneEditorCore, StandaloneEditorOptions, TrustedHTMLHandler } from 'roosterjs-content-model-types';
import type { ClipboardData, ContentModelDocument, ContentModelFormatter, ContentModelSegmentFormat, DarkColorHandler, DOMEventRecord, DOMHelper, DOMSelection, EditorEnvironment, FormatWithContentModelOptions, IStandaloneEditor, PasteType, PluginEventData, PluginEventFromType, PluginEventType, Snapshot, SnapshotsManager, StandaloneEditorCore, StandaloneEditorOptions, TrustedHTMLHandler } from 'roosterjs-content-model-types';
/**

@@ -24,13 +24,14 @@ * The standalone editor class based on Content Model

* Create Content Model from DOM tree in this editor
* @param option The option to customize the behavior of DOM to Content Model conversion
* @param mode What kind of Content Model we want. Currently we support the following values:
* - connected: Returns a connect Content Model object. "Connected" means if there is any entity inside editor, the returned Content Model will
* contain the same wrapper element for entity. This option should only be used in some special cases. In most cases we should use "disconnected"
* to get a fully disconnected Content Model so that any change to the model will not impact editor content.
* - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.
* If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.
* If editor is in dark mode, the cloned entity will be converted back to light mode.
* - reduced: Returns a reduced Content Model that only contains the model of current selection. If there is already a up-to-date cached model, use it
* instead to improve performance. This is mostly used for retrieve current format state.
*/
createContentModel(option?: DomToModelOption, selectionOverride?: DOMSelection): ContentModelDocument;
getContentModelCopy(mode: 'connected' | 'disconnected' | 'reduced'): ContentModelDocument;
/**
* Set content with content model
* @param model The content model to set
* @param option Additional options to customize the behavior of Content Model to DOM conversion
* @param onNodeCreated An optional callback that will be called when a DOM node is created
*/
setContentModel(model: ContentModelDocument, option?: ModelToDomOption, onNodeCreated?: OnNodeCreated): DOMSelection | null;
/**
* Get current running environment, such as if editor is running on Mac

@@ -62,2 +63,6 @@ */

/**
* Get a DOM Helper object to help access DOM tree in editor
*/
getDOMHelper(): DOMHelper;
/**
* Add a single undo snapshot to undo stack

@@ -147,21 +152,2 @@ */

/**
* Check if the given DOM node is in editor
* @param node The node to check
*/
isNodeInEditor(node: Node): boolean;
/**
* Get current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @returns current zoom scale number
*/
getZoomScale(): number;
/**
* Set current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @param scale The new scale number to set. It should be positive number and no greater than 10, otherwise it will be ignored.
*/
setZoomScale(scale: number): void;
/**
* Get a function to convert HTML string to trusted HTML string.

@@ -178,2 +164,3 @@ * By default it will just return the input HTML directly. To override this behavior,

protected getCore(): StandaloneEditorCore;
private cloneOptionCallback;
}
import { __assign } from "tslib";
import { ChangeSource } from '../constants/ChangeSource';
import { cloneModel } from '../publicApi/model/cloneModel';
import { createEmptyModel, tableProcessor } from 'roosterjs-content-model-dom';
import { createStandaloneEditorCore } from './createStandaloneEditorCore';
import { reducedModelChildProcessor } from '../override/reducedModelChildProcessor';
import { transformColor } from '../publicApi/color/transformColor';

@@ -17,6 +20,22 @@ /**

if (options === void 0) { options = {}; }
var _a;
this.core = null;
this.cloneOptionCallback = function (node, type) {
if (type == 'cache') {
return undefined;
}
var result = node.cloneNode(true /*deep*/);
if (_this.isDarkMode()) {
var colorHandler = _this.getColorManager();
transformColor(result, true /*includeSelf*/, 'darkToLight', colorHandler);
result.style.color = result.style.color || 'inherit';
result.style.backgroundColor = result.style.backgroundColor || 'inherit';
}
return result;
};
this.core = createStandaloneEditorCore(contentDiv, options);
onBeforeInitializePlugins === null || onBeforeInitializePlugins === void 0 ? void 0 : onBeforeInitializePlugins();
this.getCore().plugins.forEach(function (plugin) { return plugin.initialize(_this); });
var initialModel = (_a = options.initialModel) !== null && _a !== void 0 ? _a : createEmptyModel(options.defaultSegmentFormat);
this.core.api.setContentModel(this.core, initialModel, { ignoreSelection: true });
this.core.plugins.forEach(function (plugin) { return plugin.initialize(_this); });
}

@@ -51,19 +70,34 @@ /**

* Create Content Model from DOM tree in this editor
* @param option The option to customize the behavior of DOM to Content Model conversion
* @param mode What kind of Content Model we want. Currently we support the following values:
* - connected: Returns a connect Content Model object. "Connected" means if there is any entity inside editor, the returned Content Model will
* contain the same wrapper element for entity. This option should only be used in some special cases. In most cases we should use "disconnected"
* to get a fully disconnected Content Model so that any change to the model will not impact editor content.
* - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.
* If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.
* If editor is in dark mode, the cloned entity will be converted back to light mode.
* - reduced: Returns a reduced Content Model that only contains the model of current selection. If there is already a up-to-date cached model, use it
* instead to improve performance. This is mostly used for retrieve current format state.
*/
StandaloneEditor.prototype.createContentModel = function (option, selectionOverride) {
StandaloneEditor.prototype.getContentModelCopy = function (mode) {
var core = this.getCore();
return core.api.createContentModel(core, option, selectionOverride);
switch (mode) {
case 'connected':
return core.api.createContentModel(core, {
processorOverride: {
table: tableProcessor, // Use the original table processor to create Content Model with real table content but not just an entity
},
});
case 'disconnected':
return cloneModel(core.api.createContentModel(core), {
includeCachedElement: this.cloneOptionCallback,
});
case 'reduced':
return core.api.createContentModel(core, {
processorOverride: {
child: reducedModelChildProcessor,
},
});
}
};
/**
* Set content with content model
* @param model The content model to set
* @param option Additional options to customize the behavior of Content Model to DOM conversion
* @param onNodeCreated An optional callback that will be called when a DOM node is created
*/
StandaloneEditor.prototype.setContentModel = function (model, option, onNodeCreated) {
var core = this.getCore();
return core.api.setContentModel(core, model, option, onNodeCreated);
};
/**
* Get current running environment, such as if editor is running on Mac

@@ -109,2 +143,8 @@ */

/**
* Get a DOM Helper object to help access DOM tree in editor
*/
StandaloneEditor.prototype.getDOMHelper = function () {
return this.getCore().domHelper;
};
/**
* Add a single undo snapshot to undo stack

@@ -250,38 +290,2 @@ */

/**
* Check if the given DOM node is in editor
* @param node The node to check
*/
StandaloneEditor.prototype.isNodeInEditor = function (node) {
var core = this.getCore();
return core.contentDiv.contains(node);
};
/**
* Get current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @returns current zoom scale number
*/
StandaloneEditor.prototype.getZoomScale = function () {
return this.getCore().zoomScale;
};
/**
* Set current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @param scale The new scale number to set. It should be positive number and no greater than 10, otherwise it will be ignored.
*/
StandaloneEditor.prototype.setZoomScale = function (scale) {
var core = this.getCore();
if (scale > 0 && scale <= 10) {
var oldValue = core.zoomScale;
core.zoomScale = scale;
if (oldValue != scale) {
this.triggerEvent('zoomChanged', {
oldZoomScale: oldValue,
newZoomScale: scale,
}, true /*broadcast*/);
}
}
};
/**
* Get a function to convert HTML string to trusted HTML string.

@@ -288,0 +292,0 @@ * By default it will just return the input HTML directly. To override this behavior,

@@ -30,3 +30,3 @@ var BorderStyles = [

else if (v && !result.color) {
result.color = v; // TODO: Do we need to use a regex to match all possible colors?
result.color = v;
}

@@ -33,0 +33,0 @@ });

@@ -11,2 +11,3 @@ /**

export function deleteBlock(blocks, blockToDelete, replacement, context, direction) {
var _a;
var index = blocks.indexOf(blockToDelete);

@@ -27,2 +28,4 @@ switch (blockToDelete.blockType) {

if (operation !== undefined) {
var wrapper = blockToDelete.wrapper;
(_a = wrapper.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(wrapper);
replacement ? blocks.splice(index, 1, replacement) : blocks.splice(index, 1);

@@ -29,0 +32,0 @@ context === null || context === void 0 ? void 0 : context.deletedEntities.push({

@@ -13,2 +13,3 @@ import { deleteSingleChar } from '../../modelApi/edit/deleteSingleChar';

export function deleteSegment(paragraph, segmentToDelete, context, direction) {
var _a;
var segments = paragraph.segments;

@@ -37,2 +38,4 @@ var index = segments.indexOf(segmentToDelete);

if (operation !== undefined) {
var wrapper = segmentToDelete.wrapper;
(_a = wrapper.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(wrapper);
segments.splice(index, 1);

@@ -69,4 +72,2 @@ context === null || context === void 0 ? void 0 : context.deletedEntities.push({

else {
// No op if a general segment is not selected, let browser handle general segment
// TODO: Need to revisit this
return false;

@@ -73,0 +74,0 @@ }

@@ -12,4 +12,2 @@ import { __read, __spreadArray } from "tslib";

if (!!((_a = block) === null || _a === void 0 ? void 0 : _a.cachedElement)) {
// TODO: This is a temporary solution. A better solution would be making all results from iterationSelection() to be readonly,
// use a util function to change it to be editable before edit them where we clear its cached element
delete block.cachedElement;

@@ -16,0 +14,0 @@ }

@@ -1,5 +0,5 @@

import type { DOMSelection, SnapshotSelection } from 'roosterjs-content-model-types';
import type { SnapshotSelection, StandaloneEditorCore } from 'roosterjs-content-model-types';
/**
* @internal
*/
export declare function createSnapshotSelection(contentDiv: HTMLElement, selection: DOMSelection | null): SnapshotSelection;
export declare function createSnapshotSelection(core: StandaloneEditorCore): SnapshotSelection;

@@ -1,6 +0,26 @@

import { isNodeOfType } from 'roosterjs-content-model-dom';
import { isElementOfType, isNodeOfType, moveChildNodes } from 'roosterjs-content-model-dom';
/**
* @internal
*/
export function createSnapshotSelection(contentDiv, selection) {
export function createSnapshotSelection(core) {
var contentDiv = core.contentDiv, api = core.api;
var selection = api.getDOMSelection(core);
// Normalize tables to ensure they have TBODY element between TABLE and TR so that the selection path will include correct values
if ((selection === null || selection === void 0 ? void 0 : selection.type) == 'range') {
var _a = selection.range, startContainer = _a.startContainer, startOffset = _a.startOffset, endContainer = _a.endContainer, endOffset = _a.endOffset;
var isDOMChanged = normalizeTableTree(startContainer, contentDiv);
if (endContainer != startContainer) {
isDOMChanged = normalizeTableTree(endContainer, contentDiv) || isDOMChanged;
}
if (isDOMChanged) {
var newRange = contentDiv.ownerDocument.createRange();
newRange.setStart(startContainer, startOffset);
newRange.setEnd(endContainer, endOffset);
api.setDOMSelection(core, {
type: 'range',
range: newRange,
isReverted: !!selection.isReverted,
}, true /*skipSelectionChangedEvent*/);
}
}
switch (selection === null || selection === void 0 ? void 0 : selection.type) {

@@ -27,2 +47,3 @@ case 'image':

end: getPath(range.endContainer, range.endOffset, contentDiv),
isReverted: !!selection.isReverted,
};

@@ -34,2 +55,3 @@ default:

end: [],
isReverted: false,
};

@@ -90,2 +112,56 @@ }

}
function normalizeTableTree(startNode, root) {
var node = startNode;
var isDOMChanged = false;
while (node && root.contains(node)) {
if (isNodeOfType(node, 'ELEMENT_NODE') && isElementOfType(node, 'table')) {
isDOMChanged = normalizeTable(node) || isDOMChanged;
}
node = node.parentNode;
}
return isDOMChanged;
}
function normalizeTable(table) {
var _a;
var isDOMChanged = false;
var tbody = null;
for (var child = table.firstChild; child; child = child.nextSibling) {
var tag = isNodeOfType(child, 'ELEMENT_NODE') ? child.tagName : null;
switch (tag) {
case 'TR':
if (!tbody) {
tbody = table.ownerDocument.createElement('tbody');
table.insertBefore(tbody, child);
}
tbody.appendChild(child);
child = tbody;
isDOMChanged = true;
break;
case 'TBODY':
if (tbody) {
moveChildNodes(tbody, child, true /*keepExistingChildren*/);
(_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
child = tbody;
isDOMChanged = true;
}
else {
tbody = child;
}
break;
default:
tbody = null;
break;
}
}
var colgroups = table.querySelectorAll('colgroup');
var thead = table.querySelector('thead');
if (thead) {
colgroups.forEach(function (colgroup) {
if (!thead.contains(colgroup)) {
thead.appendChild(colgroup);
}
});
}
return isDOMChanged;
}
//# sourceMappingURL=createSnapshotSelection.js.map

@@ -1,5 +0,5 @@

import type { BeforePasteEvent, ContentModelDocument, DomToModelOption, FormatWithContentModelContext } from 'roosterjs-content-model-types';
import type { BeforePasteEvent, ClipboardData, StandaloneEditorCore } from 'roosterjs-content-model-types';
/**
* @internal
*/
export declare function mergePasteContent(model: ContentModelDocument, context: FormatWithContentModelContext, eventResult: BeforePasteEvent, defaultDomToModelOptions: DomToModelOption): void;
export declare function mergePasteContent(core: StandaloneEditorCore, eventResult: BeforePasteEvent, clipboardData: ClipboardData): void;
import { __assign } from "tslib";
import { ChangeSource } from '../../constants/ChangeSource';
import { containerSizeFormatParser } from '../../override/containerSizeFormatParser';

@@ -27,30 +28,39 @@ import { createDomToModelContext, domToContentModel } from 'roosterjs-content-model-dom';

*/
export function mergePasteContent(model, context, eventResult, defaultDomToModelOptions) {
export function mergePasteContent(core, eventResult, clipboardData) {
var fragment = eventResult.fragment, domToModelOption = eventResult.domToModelOption, customizedMerge = eventResult.customizedMerge, pasteType = eventResult.pasteType;
var selectedSegment = getSelectedSegments(model, true /*includeFormatHolder*/)[0];
var domToModelContext = createDomToModelContext(undefined /*editorContext*/, defaultDomToModelOptions, {
processorOverride: {
'#text': pasteTextProcessor,
entity: createPasteEntityProcessor(domToModelOption),
'*': createPasteGeneralProcessor(domToModelOption),
},
formatParserOverride: {
display: pasteDisplayFormatParser,
},
additionalFormatParsers: {
container: [containerSizeFormatParser],
},
}, domToModelOption);
domToModelContext.segmentFormat = selectedSegment ? getSegmentTextFormat(selectedSegment) : {};
var pasteModel = domToContentModel(fragment, domToModelContext);
var mergeOption = {
mergeFormat: pasteType == 'mergeFormat' ? 'keepSourceEmphasisFormat' : 'none',
mergeTable: shouldMergeTable(pasteModel),
};
var insertPoint = customizedMerge
? customizedMerge(model, pasteModel)
: mergeModel(model, pasteModel, context, mergeOption);
if (insertPoint) {
context.newPendingFormat = __assign(__assign(__assign({}, EmptySegmentFormat), model.format), insertPoint.marker.format);
}
core.api.formatContentModel(core, function (model, context) {
var selectedSegment = getSelectedSegments(model, true /*includeFormatHolder*/)[0];
var domToModelContext = createDomToModelContext(undefined /*editorContext*/, core.domToModelSettings.customized, {
processorOverride: {
'#text': pasteTextProcessor,
entity: createPasteEntityProcessor(domToModelOption),
'*': createPasteGeneralProcessor(domToModelOption),
},
formatParserOverride: {
display: pasteDisplayFormatParser,
},
additionalFormatParsers: {
container: [containerSizeFormatParser],
},
}, domToModelOption);
domToModelContext.segmentFormat = selectedSegment
? getSegmentTextFormat(selectedSegment)
: {};
var pasteModel = domToContentModel(fragment, domToModelContext);
var mergeOption = {
mergeFormat: pasteType == 'mergeFormat' ? 'keepSourceEmphasisFormat' : 'none',
mergeTable: shouldMergeTable(pasteModel),
};
var insertPoint = customizedMerge
? customizedMerge(model, pasteModel)
: mergeModel(model, pasteModel, context, mergeOption);
if (insertPoint) {
context.newPendingFormat = __assign(__assign(__assign({}, EmptySegmentFormat), model.format), insertPoint.marker.format);
}
return true;
}, {
changeSource: ChangeSource.Paste,
getChangeData: function () { return clipboardData; },
apiName: 'paste',
});
}

@@ -57,0 +67,0 @@ function shouldMergeTable(pasteModel) {

@@ -20,2 +20,3 @@ import { isNodeOfType } from 'roosterjs-content-model-dom';

range: range,
isReverted: snapshotSelection.isReverted,
};

@@ -22,0 +23,0 @@ break;

@@ -15,11 +15,13 @@ "use strict";

var addUndoSnapshot = function (core, canUndoByBackspace, entityStates) {
var lifecycle = core.lifecycle, api = core.api, contentDiv = core.contentDiv, undo = core.undo;
var lifecycle = core.lifecycle, contentDiv = core.contentDiv, undo = core.undo;
var snapshot = null;
if (!lifecycle.shadowEditFragment) {
var selection = api.getDOMSelection(core);
// Need to create snapshot selection before retrieve innerHTML since HTML can be changed during creating selection when normalize table
var selection = (0, createSnapshotSelection_1.createSnapshotSelection)(core);
var html = contentDiv.innerHTML;
snapshot = {
html: contentDiv.innerHTML,
html: html,
entityStates: entityStates,
isDarkMode: !!lifecycle.isDarkMode,
selection: (0, createSnapshotSelection_1.createSnapshotSelection)(contentDiv, selection),
selection: selection,
};

@@ -26,0 +28,0 @@ undo.snapshotsManager.addSnapshot(snapshot, !!canUndoByBackspace);

@@ -14,2 +14,5 @@ "use strict";

var createContentModel = function (core, option, selectionOverride) {
var _a;
// Flush all mutations if any, so that we can get an up-to-date Content Model
(_a = core.cache.textMutationObserver) === null || _a === void 0 ? void 0 : _a.flushMutations();
var cachedModel = selectionOverride ? null : core.cache.cachedModel;

@@ -25,4 +28,9 @@ if (cachedModel && core.lifecycle.shadowEditFragment) {

var selection = selectionOverride || core.api.getDOMSelection(core) || undefined;
var model = internalCreateContentModel(core, selection, option);
if (!option && !selectionOverride) {
var saveIndex = !option && !selectionOverride;
var editorContext = core.api.createEditorContext(core, saveIndex);
var domToModelContext = option
? (0, roosterjs_content_model_dom_1.createDomToModelContext)(editorContext, core.domToModelSettings.builtIn, core.domToModelSettings.customized, option)
: (0, roosterjs_content_model_dom_1.createDomToModelContextWithConfig)(core.domToModelSettings.calculated, editorContext);
var model = (0, roosterjs_content_model_dom_1.domToContentModel)(core.contentDiv, domToModelContext, selection);
if (saveIndex) {
core.cache.cachedModel = model;

@@ -35,9 +43,2 @@ core.cache.cachedSelection = selection;

exports.createContentModel = createContentModel;
function internalCreateContentModel(core, selection, option) {
var editorContext = core.api.createEditorContext(core);
var domToModelContext = option
? (0, roosterjs_content_model_dom_1.createDomToModelContext)(editorContext, core.domToModelSettings.builtIn, core.domToModelSettings.customized, option)
: (0, roosterjs_content_model_dom_1.createDomToModelContextWithConfig)(core.domToModelSettings.calculated, editorContext);
return (0, roosterjs_content_model_dom_1.domToContentModel)(core.contentDiv, domToModelContext, selection);
}
//# sourceMappingURL=createContentModel.js.map

@@ -8,5 +8,5 @@ "use strict";

*/
var createEditorContext = function (core) {
var createEditorContext = function (core, saveIndex) {
var _a;
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, contentDiv = core.contentDiv, cache = core.cache;
var lifecycle = core.lifecycle, format = core.format, darkColorHandler = core.darkColorHandler, contentDiv = core.contentDiv, cache = core.cache, domHelper = core.domHelper;
var context = {

@@ -19,17 +19,9 @@ isDarkMode: lifecycle.isDarkMode,

allowCacheElement: true,
domIndexer: cache.domIndexer,
domIndexer: saveIndex ? cache.domIndexer : undefined,
zoomScale: domHelper.calculateZoomScale(),
};
checkRootRtl(contentDiv, context);
checkZoomScale(contentDiv, context);
return context;
};
exports.createEditorContext = createEditorContext;
function checkZoomScale(element, context) {
var _a;
var originalWidth = ((_a = element === null || element === void 0 ? void 0 : element.getBoundingClientRect()) === null || _a === void 0 ? void 0 : _a.width) || 0;
var visualWidth = element.offsetWidth;
if (visualWidth > 0 && originalWidth > 0) {
context.zoomScale = Math.round((originalWidth / visualWidth) * 100) / 100;
}
}
function checkRootRtl(element, context) {

@@ -36,0 +28,0 @@ var _a;

@@ -8,6 +8,11 @@ "use strict";

var getDOMSelection = function (core) {
var _a;
return core.lifecycle.shadowEditFragment
? null
: (_a = core.selection.selection) !== null && _a !== void 0 ? _a : getNewSelection(core);
if (core.lifecycle.shadowEditFragment) {
return null;
}
else {
var selection = core.selection.selection;
return selection && (selection.type != 'range' || !core.api.hasFocus(core))
? selection
: getNewSelection(core);
}
};

@@ -23,5 +28,15 @@ exports.getDOMSelection = getDOMSelection;

range: range,
isReverted: isSelectionReverted(selection),
}
: null;
}
function isSelectionReverted(selection) {
if (selection && selection.rangeCount > 0) {
var range = selection.getRangeAt(0);
return (!range.collapsed &&
selection.focusNode != range.endContainer &&
selection.focusOffset != range.endOffset);
}
return false;
}
//# sourceMappingURL=getDOMSelection.js.map
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.paste = void 0;
var ChangeSource_1 = require("../constants/ChangeSource");
var cloneModel_1 = require("../publicApi/model/cloneModel");

@@ -22,2 +21,3 @@ var convertInlineCss_1 = require("../utils/paste/convertInlineCss");

var paste = function (core, clipboardData, pasteType) {
var _a;
if (pasteType === void 0) { pasteType = 'normal'; }

@@ -31,24 +31,16 @@ core.api.focus(core);

}
core.api.formatContentModel(core, function (model, context) {
var _a;
// 1. Prepare variables
var doc = createDOMFromHtml(clipboardData.rawHtml, core.trustedHTMLHandler);
// 2. Handle HTML from clipboard
var htmlFromClipboard = (0, retrieveHtmlInfo_1.retrieveHtmlInfo)(doc, clipboardData);
// 3. Create target fragment
var sourceFragment = (0, createPasteFragment_1.createPasteFragment)(core.contentDiv.ownerDocument, clipboardData, pasteType, (_a = (clipboardData.rawHtml == clipboardData.html
? doc
: createDOMFromHtml(clipboardData.html, core.trustedHTMLHandler))) === null || _a === void 0 ? void 0 : _a.body);
// 4. Trigger BeforePaste event to allow plugins modify the fragment
var eventResult = (0, generatePasteOptionFromPlugins_1.generatePasteOptionFromPlugins)(core, clipboardData, sourceFragment, htmlFromClipboard, pasteType);
// 5. Convert global CSS to inline CSS
(0, convertInlineCss_1.convertInlineCss)(eventResult.fragment, htmlFromClipboard.globalCssRules);
// 6. Merge pasted content into main Content Model
(0, mergePasteContent_1.mergePasteContent)(model, context, eventResult, core.domToModelSettings.customized);
return true;
}, {
changeSource: ChangeSource_1.ChangeSource.Paste,
getChangeData: function () { return clipboardData; },
apiName: 'paste',
});
// 1. Prepare variables
var doc = createDOMFromHtml(clipboardData.rawHtml, core.trustedHTMLHandler);
// 2. Handle HTML from clipboard
var htmlFromClipboard = (0, retrieveHtmlInfo_1.retrieveHtmlInfo)(doc, clipboardData);
// 3. Create target fragment
var sourceFragment = (0, createPasteFragment_1.createPasteFragment)(core.contentDiv.ownerDocument, clipboardData, pasteType, (_a = (clipboardData.rawHtml == clipboardData.html
? doc
: createDOMFromHtml(clipboardData.html, core.trustedHTMLHandler))) === null || _a === void 0 ? void 0 : _a.body);
// 4. Trigger BeforePaste event to allow plugins modify the fragment
var eventResult = (0, generatePasteOptionFromPlugins_1.generatePasteOptionFromPlugins)(core, clipboardData, sourceFragment, htmlFromClipboard, pasteType);
// 5. Convert global CSS to inline CSS
(0, convertInlineCss_1.convertInlineCss)(eventResult.fragment, htmlFromClipboard.globalCssRules);
// 6. Merge pasted content into main Content Model
(0, mergePasteContent_1.mergePasteContent)(core, eventResult, clipboardData);
};

@@ -55,0 +47,0 @@ exports.paste = paste;

@@ -13,7 +13,9 @@ "use strict";

var setContentModel = function (core, model, option, onNodeCreated) {
var editorContext = core.api.createEditorContext(core);
var _a;
var editorContext = core.api.createEditorContext(core, true /*saveIndex*/);
var modelToDomContext = option
? (0, roosterjs_content_model_dom_1.createModelToDomContext)(editorContext, core.modelToDomSettings.builtIn, core.modelToDomSettings.customized, option)
: (0, roosterjs_content_model_dom_1.createModelToDomContextWithConfig)(core.modelToDomSettings.calculated, editorContext);
var selection = (0, roosterjs_content_model_dom_1.contentModelToDom)(core.contentDiv.ownerDocument, core.contentDiv, model, modelToDomContext, onNodeCreated);
modelToDomContext.onNodeCreated = onNodeCreated;
var selection = (0, roosterjs_content_model_dom_1.contentModelToDom)(core.contentDiv.ownerDocument, core.contentDiv, model, modelToDomContext);
if (!core.lifecycle.shadowEditFragment) {

@@ -24,5 +26,7 @@ core.cache.cachedSelection = selection || undefined;

}
else if (!selection || selection.type !== 'range') {
else {
core.selection.selection = selection;
}
// Clear pending mutations since we will use our latest model object to replace existing cache
(_a = core.cache.textMutationObserver) === null || _a === void 0 ? void 0 : _a.flushMutations();
core.cache.cachedModel = model;

@@ -29,0 +33,0 @@ }

@@ -42,3 +42,3 @@ "use strict";

case 'range':
(0, addRangeToSelection_1.addRangeToSelection)(doc, selection.range);
(0, addRangeToSelection_1.addRangeToSelection)(doc, selection.range, selection.isReverted);
core.selection.selection = core.api.hasFocus(core) ? null : selection;

@@ -45,0 +45,0 @@ break;

@@ -13,3 +13,2 @@ "use strict";

var switchShadowEdit = function (editorCore, isOn) {
// TODO: Use strong-typed editor core object
var core = editorCore;

@@ -19,4 +18,2 @@ if (isOn != !!core.lifecycle.shadowEditFragment) {

var model = !core.cache.cachedModel ? core.api.createContentModel(core) : null;
// Fake object, not used in Content Model Editor, just to satisfy original editor code
// TODO: we can remove them once we have standalone Content Model Editor
var fragment = core.contentDiv.ownerDocument.createDocumentFragment();

@@ -23,0 +20,0 @@ var clonedRoot = core.contentDiv.cloneNode(true /*deep*/);

@@ -6,3 +6,4 @@ import type { ContentModelCachePluginState, PluginWithState, StandaloneEditorOptions } from 'roosterjs-content-model-types';

* @param option The editor option
* @param contentDiv The editor content DIV
*/
export declare function createContentModelCachePlugin(option: StandaloneEditorOptions): PluginWithState<ContentModelCachePluginState>;
export declare function createContentModelCachePlugin(option: StandaloneEditorOptions, contentDiv: HTMLDivElement): PluginWithState<ContentModelCachePluginState>;

@@ -6,3 +6,3 @@ "use strict";

var contentModelDomIndexer_1 = require("./utils/contentModelDomIndexer");
var eventUtils_1 = require("../publicApi/domUtils/eventUtils");
var textMutationObserver_1 = require("./utils/textMutationObserver");
/**

@@ -15,6 +15,17 @@ * ContentModel cache plugin manages cached Content Model, and refresh the cache when necessary

* @param option The editor option
* @param contentDiv The editor content DIV
*/
function ContentModelCachePlugin(option) {
function ContentModelCachePlugin(option, contentDiv) {
var _this = this;
this.editor = null;
this.onMutation = function (isTextChangeOnly) {
if (_this.editor) {
if (isTextChangeOnly) {
_this.updateCachedModel(_this.editor, true /*forceUpdate*/);
}
else {
_this.invalidateCache();
}
}
};
this.onNativeSelectionChange = function () {

@@ -26,5 +37,8 @@ var _a;

};
this.state = {
domIndexer: option.cacheModel ? contentModelDomIndexer_1.contentModelDomIndexer : undefined,
};
this.state = option.cacheModel
? {
domIndexer: contentModelDomIndexer_1.contentModelDomIndexer,
textMutationObserver: (0, textMutationObserver_1.createTextMutationObserver)(contentDiv, this.onMutation),
}
: {};
}

@@ -44,5 +58,6 @@ /**

ContentModelCachePlugin.prototype.initialize = function (editor) {
// TODO: Later we may need a different interface for Content Model editor plugin
var _a;
this.editor = editor;
this.editor.getDocument().addEventListener('selectionchange', this.onNativeSelectionChange);
(_a = this.state.textMutationObserver) === null || _a === void 0 ? void 0 : _a.startObserving();
};

@@ -55,2 +70,4 @@ /**

ContentModelCachePlugin.prototype.dispose = function () {
var _a;
(_a = this.state.textMutationObserver) === null || _a === void 0 ? void 0 : _a.stopObserving();
if (this.editor) {

@@ -81,11 +98,8 @@ this.editor

case 'keyDown':
if (this.shouldClearCache(event)) {
case 'input':
if (!this.state.textMutationObserver) {
// When updating cache is not enabled, need to clear the cache to make sure other plugins can get an up-to-date content model
this.invalidateCache();
}
break;
case 'input':
{
this.updateCachedModel(this.editor, true /*forceUpdate*/);
}
break;
case 'selectionChanged':

@@ -95,12 +109,10 @@ this.updateCachedModel(this.editor);

case 'contentChanged':
{
var contentModel = event.contentModel, selection = event.selection;
if (contentModel && this.state.domIndexer) {
this.state.cachedModel = contentModel;
this.state.cachedSelection = selection;
}
else {
this.invalidateCache();
}
var contentModel = event.contentModel, selection = event.selection;
if (contentModel && this.state.domIndexer) {
this.state.cachedModel = contentModel;
this.state.cachedSelection = selection;
}
else {
this.invalidateCache();
}
break;

@@ -140,27 +152,2 @@ }

};
ContentModelCachePlugin.prototype.shouldClearCache = function (event) {
var _a;
var rawEvent = event.rawEvent, handledByEditFeature = event.handledByEditFeature;
// In these cases we can't update the model, so clear cache:
// 1. It is already handled by Content Edit Features
if (handledByEditFeature) {
return true;
}
// 2. Default behavior is prevented, which means other plugins has handled the event
if (rawEvent.defaultPrevented) {
return true;
}
// 3. ENTER key is pressed. ENTER key will create new paragraph, so need to update cache to reflect this change
// TODO: Handle ENTER key to better reuse content model
if (rawEvent.key == 'Enter') {
return true;
}
// 4. Current selection is image or table or expanded range selection, and is inputting some text
if ((((_a = this.state.cachedSelection) === null || _a === void 0 ? void 0 : _a.type) != 'range' ||
!this.state.cachedSelection.range.collapsed) &&
(0, eventUtils_1.isCharacterValue)(rawEvent)) {
return true;
}
return false;
};
return ContentModelCachePlugin;

@@ -172,7 +159,8 @@ }());

* @param option The editor option
* @param contentDiv The editor content DIV
*/
function createContentModelCachePlugin(option) {
return new ContentModelCachePlugin(option);
function createContentModelCachePlugin(option, contentDiv) {
return new ContentModelCachePlugin(option, contentDiv);
}
exports.createContentModelCachePlugin = createContentModelCachePlugin;
//# sourceMappingURL=ContentModelCachePlugin.js.map

@@ -7,3 +7,2 @@ "use strict";

var ChangeSource_1 = require("../constants/ChangeSource");
var cloneModel_1 = require("../publicApi/model/cloneModel");
var deleteEmptyList_1 = require("./utils/deleteEmptyList");

@@ -14,3 +13,2 @@ var deleteSelection_1 = require("../publicApi/selection/deleteSelection");

var iterateSelections_1 = require("../publicApi/selection/iterateSelections");
var transformColor_1 = require("../publicApi/color/transformColor");
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");

@@ -43,13 +41,2 @@ /**

};
this.processEntityColor = function (node, type) {
if (type == 'cache' || !_this.editor) {
return undefined;
}
var result = node.cloneNode(true /*deep*/);
var colorHandler = _this.editor.getColorManager();
(0, transformColor_1.transformColor)(result, true /*includeSelf*/, 'darkToLight', colorHandler);
result.style.color = result.style.color || 'inherit';
result.style.backgroundColor = result.style.backgroundColor || 'inherit';
return result;
};
this.state = {

@@ -115,7 +102,3 @@ allowedCustomPasteType: option.allowedCustomPasteType || [],

if (selection && (selection.type != 'range' || !selection.range.collapsed)) {
var model = this.editor.createContentModel(undefined /* option */, selection);
var cacheProcessor = this.editor.isDarkMode() ? this.processEntityColor : false;
var pasteModel = (0, cloneModel_1.cloneModel)(model, {
includeCachedElement: cacheProcessor,
});
var pasteModel = this.editor.getContentModelCopy('disconnected');
if (selection.type === 'table') {

@@ -134,3 +117,5 @@ (0, iterateSelections_1.iterateSelections)(pasteModel, function (_, tableContext) {

var tempDiv_1 = this.getTempDiv(this.editor.getDocument());
var selectionForCopy = (0, roosterjs_content_model_dom_1.contentModelToDom)(tempDiv_1.ownerDocument, tempDiv_1, pasteModel, (0, roosterjs_content_model_dom_1.createModelToDomContext)(), exports.onNodeCreated);
var context = (0, roosterjs_content_model_dom_1.createModelToDomContext)();
context.onNodeCreated = exports.onNodeCreated;
var selectionForCopy = (0, roosterjs_content_model_dom_1.contentModelToDom)(tempDiv_1.ownerDocument, tempDiv_1, pasteModel, context);
var newRange = selectionForCopy

@@ -137,0 +122,0 @@ ? domSelectionToRange(doc, selectionForCopy)

@@ -43,3 +43,2 @@ "use strict";

var _this = this;
// TODO: Later we may need a different interface for Content Model editor plugin
this.editor = editor;

@@ -46,0 +45,0 @@ this.hasDefaultFormat =

@@ -7,2 +7,3 @@ "use strict";

var ContentModelFormatPlugin_1 = require("./ContentModelFormatPlugin");
var ContextMenuPlugin_1 = require("./ContextMenuPlugin");
var DOMEventPlugin_1 = require("./DOMEventPlugin");

@@ -20,3 +21,3 @@ var EntityPlugin_1 = require("./EntityPlugin");

return {
cache: (0, ContentModelCachePlugin_1.createContentModelCachePlugin)(options),
cache: (0, ContentModelCachePlugin_1.createContentModelCachePlugin)(options, contentDiv),
format: (0, ContentModelFormatPlugin_1.createContentModelFormatPlugin)(options),

@@ -28,2 +29,3 @@ copyPaste: (0, ContentModelCopyPastePlugin_1.createContentModelCopyPastePlugin)(options),

selection: (0, SelectionPlugin_1.createSelectionPlugin)(options),
contextMenu: (0, ContextMenuPlugin_1.createContextMenuPlugin)(options),
undo: (0, UndoPlugin_1.createUndoPlugin)(options),

@@ -30,0 +32,0 @@ };

@@ -73,3 +73,3 @@ "use strict";

if (isClicking && this.editor) {
while (node && this.editor.isNodeInEditor(node)) {
while (node && this.editor.getDOMHelper().isNodeInEditor(node)) {
if ((0, roosterjs_content_model_dom_1.isEntityElement)(node)) {

@@ -130,3 +130,6 @@ this.triggerEvent(editor, node, 'click', rawEvent);

var result = [];
(0, findAllEntities_1.findAllEntities)(editor.createContentModel(), result);
editor.formatContentModel(function (model) {
(0, findAllEntities_1.findAllEntities)(model, result);
return false;
});
(0, roosterjs_content_model_dom_1.getObjectKeys)(this.state.entityMap).forEach(function (id) {

@@ -133,0 +136,0 @@ var entry = _this.state.entityMap[id];

@@ -20,8 +20,5 @@ "use strict";

var _this = this;
var _a;
this.editor = null;
this.initializer = null;
this.disposer = null;
this.initialModel =
(_a = options.initialModel) !== null && _a !== void 0 ? _a : this.createInitModel(options.defaultSegmentFormat);
// Make the container editable and set its selection styles

@@ -61,6 +58,2 @@ if (contentDiv.getAttribute(ContentEditableAttributeName) === null) {

this.editor = editor;
this.editor.setContentModel(this.initialModel, { ignoreSelection: true });
// Initial model is only used once. After that we can just clean it up to make sure we don't cache anything useless
// including the cached DOM element inside the model.
this.initialModel = (0, roosterjs_content_model_dom_1.createContentModelDocument)();
// Set content DIV to be editable

@@ -111,9 +104,2 @@ (_a = this.initializer) === null || _a === void 0 ? void 0 : _a.call(this);

};
LifecyclePlugin.prototype.createInitModel = function (format) {
var model = (0, roosterjs_content_model_dom_1.createContentModelDocument)(format);
var paragraph = (0, roosterjs_content_model_dom_1.createParagraph)(false /*isImplicit*/, undefined /*blockFormat*/, format);
paragraph.segments.push((0, roosterjs_content_model_dom_1.createSelectionMarker)(format), (0, roosterjs_content_model_dom_1.createBr)(format));
model.blocks.push(paragraph);
return model;
};
return LifecyclePlugin;

@@ -120,0 +106,0 @@ }());

@@ -13,2 +13,3 @@ "use strict";

this.disposer = null;
this.isSafari = false;
this.onFocus = function () {

@@ -19,3 +20,3 @@ var _a, _b;

}
if (((_b = _this.state.selection) === null || _b === void 0 ? void 0 : _b.type) == 'range') {
if (((_b = _this.state.selection) === null || _b === void 0 ? void 0 : _b.type) == 'range' && !_this.isSafari) {
// Editor is focused, now we can get live selection. So no need to keep a selection if the selection type is range.

@@ -30,16 +31,17 @@ _this.state.selection = null;

};
this.onKeyDownDocument = function (event) {
if (event.key == 'Tab' && !event.defaultPrevented) {
_this.onBlur();
this.onSelectionChangeSafari = function () {
var _a;
if (((_a = _this.editor) === null || _a === void 0 ? void 0 : _a.hasFocus()) && !_this.editor.isInShadowEdit()) {
// Safari has problem to handle onBlur event. When blur, we cannot get the original selection from editor.
// So we always save a selection whenever editor has focus. Then after blur, we can still use this cached selection.
var newSelection = _this.editor.getDOMSelection();
if ((newSelection === null || newSelection === void 0 ? void 0 : newSelection.type) == 'range') {
_this.state.selection = newSelection;
}
}
};
this.onMouseDownDocument = function (event) {
if (_this.editor && !_this.editor.isNodeInEditor(event.target)) {
_this.onBlur();
}
};
this.state = {
selection: null,
selectionStyleNode: null,
imageSelectionBorderColor: options.imageSelectionBorderColor, // TODO: Move to Selection core plugin
imageSelectionBorderColor: options.imageSelectionBorderColor,
};

@@ -51,3 +53,2 @@ }

SelectionPlugin.prototype.initialize = function (editor) {
var _a;
this.editor = editor;

@@ -60,6 +61,5 @@ var doc = this.editor.getDocument();

var document = this.editor.getDocument();
if (env.isSafari) {
document.addEventListener('mousedown', this.onMouseDownDocument, true /*useCapture*/);
document.addEventListener('keydown', this.onKeyDownDocument);
(_a = document.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener('blur', this.onBlur);
this.isSafari = !!env.isSafari;
if (this.isSafari) {
document.addEventListener('selectionchange', this.onSelectionChangeSafari);
this.disposer = this.editor.attachDomEvent({ focus: { beforeDispatch: this.onFocus } });

@@ -76,4 +76,5 @@ }

var _a, _b;
(_a = this.editor) === null || _a === void 0 ? void 0 : _a.getDocument().removeEventListener('selectionchange', this.onSelectionChangeSafari);
if (this.state.selectionStyleNode) {
(_a = this.state.selectionStyleNode.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(this.state.selectionStyleNode);
(_b = this.state.selectionStyleNode.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.state.selectionStyleNode);
this.state.selectionStyleNode = null;

@@ -85,9 +86,3 @@ }

}
if (this.editor) {
var document_1 = this.editor.getDocument();
document_1.removeEventListener('mousedown', this.onMouseDownDocument, true /*useCapture*/);
document_1.removeEventListener('keydown', this.onKeyDownDocument);
(_b = document_1.defaultView) === null || _b === void 0 ? void 0 : _b.removeEventListener('blur', this.onBlur);
this.editor = null;
}
this.editor = null;
};

@@ -160,2 +155,3 @@ SelectionPlugin.prototype.getState = function () {

range: range,
isReverted: false,
});

@@ -162,0 +158,0 @@ }

/**
* @internal
*/
export declare function addRangeToSelection(doc: Document, range: Range): void;
export declare function addRangeToSelection(doc: Document, range: Range, isReverted?: boolean): void;

@@ -7,8 +7,14 @@ "use strict";

*/
function addRangeToSelection(doc, range) {
function addRangeToSelection(doc, range, isReverted) {
var _a;
if (isReverted === void 0) { isReverted = false; }
var selection = (_a = doc.defaultView) === null || _a === void 0 ? void 0 : _a.getSelection();
if (selection) {
selection.removeAllRanges();
selection.addRange(range);
if (!isReverted) {
selection.addRange(range);
}
else {
selection.setBaseAndExtent(range.endContainer, range.endOffset, range.startContainer, range.startOffset);
}
}

@@ -15,0 +21,0 @@ }

@@ -21,3 +21,3 @@ "use strict";

var node = posContainer;
while (node && editor.isNodeInEditor(node)) {
while (node && editor.getDOMHelper().isNodeInEditor(node)) {
if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'ELEMENT_NODE')) {

@@ -24,0 +24,0 @@ if ((_c = node.getAttribute) === null || _c === void 0 ? void 0 : _c.call(node, 'style')) {

@@ -6,2 +6,3 @@ "use strict";

var DarkColorHandlerImpl_1 = require("./DarkColorHandlerImpl");
var DOMHelperImpl_1 = require("./DOMHelperImpl");
var createStandaloneEditorCorePlugins_1 = require("../corePlugin/createStandaloneEditorCorePlugins");

@@ -17,3 +18,3 @@ var standaloneCoreApiMap_1 = require("./standaloneCoreApiMap");

function createStandaloneEditorCore(contentDiv, options) {
var _a, _b, _c;
var _a, _b;
var corePlugins = (0, createStandaloneEditorCorePlugins_1.createStandaloneEditorCorePlugins)(options, contentDiv);

@@ -29,4 +30,5 @@ return (0, tslib_1.__assign)((0, tslib_1.__assign)({ contentDiv: contentDiv, api: (0, tslib_1.__assign)((0, tslib_1.__assign)({}, standaloneCoreApiMap_1.standaloneCoreApiMap), options.coreApiOverride), originalApi: (0, tslib_1.__assign)({}, standaloneCoreApiMap_1.standaloneCoreApiMap), plugins: (0, tslib_1.__spreadArray)((0, tslib_1.__spreadArray)([

corePlugins.undo,
corePlugins.contextMenu,
corePlugins.lifecycle,
], false), environment: createEditorEnvironment(contentDiv), darkColorHandler: (0, DarkColorHandlerImpl_1.createDarkColorHandler)(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors), trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler, domToModelSettings: (0, createStandaloneEditorDefaultSettings_1.createDomToModelSettings)(options), modelToDomSettings: (0, createStandaloneEditorDefaultSettings_1.createModelToDomSettings)(options) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler, zoomScale: ((_c = options.zoomScale) !== null && _c !== void 0 ? _c : -1) > 0 ? options.zoomScale : 1 });
], false), environment: createEditorEnvironment(contentDiv), darkColorHandler: (0, DarkColorHandlerImpl_1.createDarkColorHandler)(contentDiv, (_b = options.getDarkColor) !== null && _b !== void 0 ? _b : getDarkColorFallback, options.knownColors), trustedHTMLHandler: options.trustedHTMLHandler || defaultTrustHtmlHandler, domToModelSettings: (0, createStandaloneEditorDefaultSettings_1.createDomToModelSettings)(options), modelToDomSettings: (0, createStandaloneEditorDefaultSettings_1.createModelToDomSettings)(options), domHelper: (0, DOMHelperImpl_1.createDOMHelper)(contentDiv) }, getPluginState(corePlugins)), { disposeErrorHandler: options.disposeErrorHandler });
}

@@ -63,2 +65,3 @@ exports.createStandaloneEditorCore = createStandaloneEditorCore;

selection: corePlugins.selection.getState(),
contextMenu: corePlugins.contextMenu.getState(),
undo: corePlugins.undo.getState(),

@@ -65,0 +68,0 @@ };

@@ -1,2 +0,2 @@

import type { ClipboardData, ContentModelDocument, ContentModelFormatter, ContentModelSegmentFormat, DarkColorHandler, DOMEventRecord, DOMSelection, DomToModelOption, EditorEnvironment, FormatWithContentModelOptions, IStandaloneEditor, ModelToDomOption, OnNodeCreated, PasteType, PluginEventData, PluginEventFromType, PluginEventType, Snapshot, SnapshotsManager, StandaloneEditorCore, StandaloneEditorOptions, TrustedHTMLHandler } from 'roosterjs-content-model-types';
import type { ClipboardData, ContentModelDocument, ContentModelFormatter, ContentModelSegmentFormat, DarkColorHandler, DOMEventRecord, DOMHelper, DOMSelection, EditorEnvironment, FormatWithContentModelOptions, IStandaloneEditor, PasteType, PluginEventData, PluginEventFromType, PluginEventType, Snapshot, SnapshotsManager, StandaloneEditorCore, StandaloneEditorOptions, TrustedHTMLHandler } from 'roosterjs-content-model-types';
/**

@@ -24,13 +24,14 @@ * The standalone editor class based on Content Model

* Create Content Model from DOM tree in this editor
* @param option The option to customize the behavior of DOM to Content Model conversion
* @param mode What kind of Content Model we want. Currently we support the following values:
* - connected: Returns a connect Content Model object. "Connected" means if there is any entity inside editor, the returned Content Model will
* contain the same wrapper element for entity. This option should only be used in some special cases. In most cases we should use "disconnected"
* to get a fully disconnected Content Model so that any change to the model will not impact editor content.
* - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.
* If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.
* If editor is in dark mode, the cloned entity will be converted back to light mode.
* - reduced: Returns a reduced Content Model that only contains the model of current selection. If there is already a up-to-date cached model, use it
* instead to improve performance. This is mostly used for retrieve current format state.
*/
createContentModel(option?: DomToModelOption, selectionOverride?: DOMSelection): ContentModelDocument;
getContentModelCopy(mode: 'connected' | 'disconnected' | 'reduced'): ContentModelDocument;
/**
* Set content with content model
* @param model The content model to set
* @param option Additional options to customize the behavior of Content Model to DOM conversion
* @param onNodeCreated An optional callback that will be called when a DOM node is created
*/
setContentModel(model: ContentModelDocument, option?: ModelToDomOption, onNodeCreated?: OnNodeCreated): DOMSelection | null;
/**
* Get current running environment, such as if editor is running on Mac

@@ -62,2 +63,6 @@ */

/**
* Get a DOM Helper object to help access DOM tree in editor
*/
getDOMHelper(): DOMHelper;
/**
* Add a single undo snapshot to undo stack

@@ -147,21 +152,2 @@ */

/**
* Check if the given DOM node is in editor
* @param node The node to check
*/
isNodeInEditor(node: Node): boolean;
/**
* Get current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @returns current zoom scale number
*/
getZoomScale(): number;
/**
* Set current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @param scale The new scale number to set. It should be positive number and no greater than 10, otherwise it will be ignored.
*/
setZoomScale(scale: number): void;
/**
* Get a function to convert HTML string to trusted HTML string.

@@ -178,2 +164,3 @@ * By default it will just return the input HTML directly. To override this behavior,

protected getCore(): StandaloneEditorCore;
private cloneOptionCallback;
}

@@ -6,3 +6,6 @@ "use strict";

var ChangeSource_1 = require("../constants/ChangeSource");
var cloneModel_1 = require("../publicApi/model/cloneModel");
var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");
var createStandaloneEditorCore_1 = require("./createStandaloneEditorCore");
var reducedModelChildProcessor_1 = require("../override/reducedModelChildProcessor");
var transformColor_1 = require("../publicApi/color/transformColor");

@@ -21,6 +24,22 @@ /**

if (options === void 0) { options = {}; }
var _a;
this.core = null;
this.cloneOptionCallback = function (node, type) {
if (type == 'cache') {
return undefined;
}
var result = node.cloneNode(true /*deep*/);
if (_this.isDarkMode()) {
var colorHandler = _this.getColorManager();
(0, transformColor_1.transformColor)(result, true /*includeSelf*/, 'darkToLight', colorHandler);
result.style.color = result.style.color || 'inherit';
result.style.backgroundColor = result.style.backgroundColor || 'inherit';
}
return result;
};
this.core = (0, createStandaloneEditorCore_1.createStandaloneEditorCore)(contentDiv, options);
onBeforeInitializePlugins === null || onBeforeInitializePlugins === void 0 ? void 0 : onBeforeInitializePlugins();
this.getCore().plugins.forEach(function (plugin) { return plugin.initialize(_this); });
var initialModel = (_a = options.initialModel) !== null && _a !== void 0 ? _a : (0, roosterjs_content_model_dom_1.createEmptyModel)(options.defaultSegmentFormat);
this.core.api.setContentModel(this.core, initialModel, { ignoreSelection: true });
this.core.plugins.forEach(function (plugin) { return plugin.initialize(_this); });
}

@@ -55,19 +74,34 @@ /**

* Create Content Model from DOM tree in this editor
* @param option The option to customize the behavior of DOM to Content Model conversion
* @param mode What kind of Content Model we want. Currently we support the following values:
* - connected: Returns a connect Content Model object. "Connected" means if there is any entity inside editor, the returned Content Model will
* contain the same wrapper element for entity. This option should only be used in some special cases. In most cases we should use "disconnected"
* to get a fully disconnected Content Model so that any change to the model will not impact editor content.
* - disconnected: Returns a disconnected clone of Content Model from editor which you can do any change on it and it won't impact the editor content.
* If there is any entity in editor, the returned object will contain cloned copy of entity wrapper element.
* If editor is in dark mode, the cloned entity will be converted back to light mode.
* - reduced: Returns a reduced Content Model that only contains the model of current selection. If there is already a up-to-date cached model, use it
* instead to improve performance. This is mostly used for retrieve current format state.
*/
StandaloneEditor.prototype.createContentModel = function (option, selectionOverride) {
StandaloneEditor.prototype.getContentModelCopy = function (mode) {
var core = this.getCore();
return core.api.createContentModel(core, option, selectionOverride);
switch (mode) {
case 'connected':
return core.api.createContentModel(core, {
processorOverride: {
table: roosterjs_content_model_dom_1.tableProcessor, // Use the original table processor to create Content Model with real table content but not just an entity
},
});
case 'disconnected':
return (0, cloneModel_1.cloneModel)(core.api.createContentModel(core), {
includeCachedElement: this.cloneOptionCallback,
});
case 'reduced':
return core.api.createContentModel(core, {
processorOverride: {
child: reducedModelChildProcessor_1.reducedModelChildProcessor,
},
});
}
};
/**
* Set content with content model
* @param model The content model to set
* @param option Additional options to customize the behavior of Content Model to DOM conversion
* @param onNodeCreated An optional callback that will be called when a DOM node is created
*/
StandaloneEditor.prototype.setContentModel = function (model, option, onNodeCreated) {
var core = this.getCore();
return core.api.setContentModel(core, model, option, onNodeCreated);
};
/**
* Get current running environment, such as if editor is running on Mac

@@ -113,2 +147,8 @@ */

/**
* Get a DOM Helper object to help access DOM tree in editor
*/
StandaloneEditor.prototype.getDOMHelper = function () {
return this.getCore().domHelper;
};
/**
* Add a single undo snapshot to undo stack

@@ -254,38 +294,2 @@ */

/**
* Check if the given DOM node is in editor
* @param node The node to check
*/
StandaloneEditor.prototype.isNodeInEditor = function (node) {
var core = this.getCore();
return core.contentDiv.contains(node);
};
/**
* Get current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @returns current zoom scale number
*/
StandaloneEditor.prototype.getZoomScale = function () {
return this.getCore().zoomScale;
};
/**
* Set current zoom scale, default value is 1
* When editor is put under a zoomed container, need to pass the zoom scale number using EditorOptions.zoomScale
* to let editor behave correctly especially for those mouse drag/drop behaviors
* @param scale The new scale number to set. It should be positive number and no greater than 10, otherwise it will be ignored.
*/
StandaloneEditor.prototype.setZoomScale = function (scale) {
var core = this.getCore();
if (scale > 0 && scale <= 10) {
var oldValue = core.zoomScale;
core.zoomScale = scale;
if (oldValue != scale) {
this.triggerEvent('zoomChanged', {
oldZoomScale: oldValue,
newZoomScale: scale,
}, true /*broadcast*/);
}
}
};
/**
* Get a function to convert HTML string to trusted HTML string.

@@ -292,0 +296,0 @@ * By default it will just return the input HTML directly. To override this behavior,

@@ -33,3 +33,3 @@ "use strict";

else if (v && !result.color) {
result.color = v; // TODO: Do we need to use a regex to match all possible colors?
result.color = v;
}

@@ -36,0 +36,0 @@ });

@@ -14,2 +14,3 @@ "use strict";

function deleteBlock(blocks, blockToDelete, replacement, context, direction) {
var _a;
var index = blocks.indexOf(blockToDelete);

@@ -30,2 +31,4 @@ switch (blockToDelete.blockType) {

if (operation !== undefined) {
var wrapper = blockToDelete.wrapper;
(_a = wrapper.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(wrapper);
replacement ? blocks.splice(index, 1, replacement) : blocks.splice(index, 1);

@@ -32,0 +35,0 @@ context === null || context === void 0 ? void 0 : context.deletedEntities.push({

@@ -16,2 +16,3 @@ "use strict";

function deleteSegment(paragraph, segmentToDelete, context, direction) {
var _a;
var segments = paragraph.segments;

@@ -40,2 +41,4 @@ var index = segments.indexOf(segmentToDelete);

if (operation !== undefined) {
var wrapper = segmentToDelete.wrapper;
(_a = wrapper.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(wrapper);
segments.splice(index, 1);

@@ -72,4 +75,2 @@ context === null || context === void 0 ? void 0 : context.deletedEntities.push({

else {
// No op if a general segment is not selected, let browser handle general segment
// TODO: Need to revisit this
return false;

@@ -76,0 +77,0 @@ }

@@ -15,4 +15,2 @@ "use strict";

if (!!((_a = block) === null || _a === void 0 ? void 0 : _a.cachedElement)) {
// TODO: This is a temporary solution. A better solution would be making all results from iterationSelection() to be readonly,
// use a util function to change it to be editable before edit them where we clear its cached element
delete block.cachedElement;

@@ -19,0 +17,0 @@ }

@@ -1,5 +0,5 @@

import type { DOMSelection, SnapshotSelection } from 'roosterjs-content-model-types';
import type { SnapshotSelection, StandaloneEditorCore } from 'roosterjs-content-model-types';
/**
* @internal
*/
export declare function createSnapshotSelection(contentDiv: HTMLElement, selection: DOMSelection | null): SnapshotSelection;
export declare function createSnapshotSelection(core: StandaloneEditorCore): SnapshotSelection;

@@ -8,3 +8,23 @@ "use strict";

*/
function createSnapshotSelection(contentDiv, selection) {
function createSnapshotSelection(core) {
var contentDiv = core.contentDiv, api = core.api;
var selection = api.getDOMSelection(core);
// Normalize tables to ensure they have TBODY element between TABLE and TR so that the selection path will include correct values
if ((selection === null || selection === void 0 ? void 0 : selection.type) == 'range') {
var _a = selection.range, startContainer = _a.startContainer, startOffset = _a.startOffset, endContainer = _a.endContainer, endOffset = _a.endOffset;
var isDOMChanged = normalizeTableTree(startContainer, contentDiv);
if (endContainer != startContainer) {
isDOMChanged = normalizeTableTree(endContainer, contentDiv) || isDOMChanged;
}
if (isDOMChanged) {
var newRange = contentDiv.ownerDocument.createRange();
newRange.setStart(startContainer, startOffset);
newRange.setEnd(endContainer, endOffset);
api.setDOMSelection(core, {
type: 'range',
range: newRange,
isReverted: !!selection.isReverted,
}, true /*skipSelectionChangedEvent*/);
}
}
switch (selection === null || selection === void 0 ? void 0 : selection.type) {

@@ -31,2 +51,3 @@ case 'image':

end: getPath(range.endContainer, range.endOffset, contentDiv),
isReverted: !!selection.isReverted,
};

@@ -38,2 +59,3 @@ default:

end: [],
isReverted: false,
};

@@ -95,2 +117,56 @@ }

}
function normalizeTableTree(startNode, root) {
var node = startNode;
var isDOMChanged = false;
while (node && root.contains(node)) {
if ((0, roosterjs_content_model_dom_1.isNodeOfType)(node, 'ELEMENT_NODE') && (0, roosterjs_content_model_dom_1.isElementOfType)(node, 'table')) {
isDOMChanged = normalizeTable(node) || isDOMChanged;
}
node = node.parentNode;
}
return isDOMChanged;
}
function normalizeTable(table) {
var _a;
var isDOMChanged = false;
var tbody = null;
for (var child = table.firstChild; child; child = child.nextSibling) {
var tag = (0, roosterjs_content_model_dom_1.isNodeOfType)(child, 'ELEMENT_NODE') ? child.tagName : null;
switch (tag) {
case 'TR':
if (!tbody) {
tbody = table.ownerDocument.createElement('tbody');
table.insertBefore(tbody, child);
}
tbody.appendChild(child);
child = tbody;
isDOMChanged = true;
break;
case 'TBODY':
if (tbody) {
(0, roosterjs_content_model_dom_1.moveChildNodes)(tbody, child, true /*keepExistingChildren*/);
(_a = child.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(child);
child = tbody;
isDOMChanged = true;
}
else {
tbody = child;
}
break;
default:
tbody = null;
break;
}
}
var colgroups = table.querySelectorAll('colgroup');
var thead = table.querySelector('thead');
if (thead) {
colgroups.forEach(function (colgroup) {
if (!thead.contains(colgroup)) {
thead.appendChild(colgroup);
}
});
}
return isDOMChanged;
}
//# sourceMappingURL=createSnapshotSelection.js.map

@@ -1,5 +0,5 @@

import type { BeforePasteEvent, ContentModelDocument, DomToModelOption, FormatWithContentModelContext } from 'roosterjs-content-model-types';
import type { BeforePasteEvent, ClipboardData, StandaloneEditorCore } from 'roosterjs-content-model-types';
/**
* @internal
*/
export declare function mergePasteContent(model: ContentModelDocument, context: FormatWithContentModelContext, eventResult: BeforePasteEvent, defaultDomToModelOptions: DomToModelOption): void;
export declare function mergePasteContent(core: StandaloneEditorCore, eventResult: BeforePasteEvent, clipboardData: ClipboardData): void;

@@ -5,2 +5,3 @@ "use strict";

var tslib_1 = require("tslib");
var ChangeSource_1 = require("../../constants/ChangeSource");
var containerSizeFormatParser_1 = require("../../override/containerSizeFormatParser");

@@ -31,30 +32,39 @@ var roosterjs_content_model_dom_1 = require("roosterjs-content-model-dom");

*/
function mergePasteContent(model, context, eventResult, defaultDomToModelOptions) {
function mergePasteContent(core, eventResult, clipboardData) {
var fragment = eventResult.fragment, domToModelOption = eventResult.domToModelOption, customizedMerge = eventResult.customizedMerge, pasteType = eventResult.pasteType;
var selectedSegment = (0, collectSelections_1.getSelectedSegments)(model, true /*includeFormatHolder*/)[0];
var domToModelContext = (0, roosterjs_content_model_dom_1.createDomToModelContext)(undefined /*editorContext*/, defaultDomToModelOptions, {
processorOverride: {
'#text': pasteTextProcessor_1.pasteTextProcessor,
entity: (0, pasteEntityProcessor_1.createPasteEntityProcessor)(domToModelOption),
'*': (0, pasteGeneralProcessor_1.createPasteGeneralProcessor)(domToModelOption),
},
formatParserOverride: {
display: pasteDisplayFormatParser_1.pasteDisplayFormatParser,
},
additionalFormatParsers: {
container: [containerSizeFormatParser_1.containerSizeFormatParser],
},
}, domToModelOption);
domToModelContext.segmentFormat = selectedSegment ? (0, getSegmentTextFormat_1.getSegmentTextFormat)(selectedSegment) : {};
var pasteModel = (0, roosterjs_content_model_dom_1.domToContentModel)(fragment, domToModelContext);
var mergeOption = {
mergeFormat: pasteType == 'mergeFormat' ? 'keepSourceEmphasisFormat' : 'none',
mergeTable: shouldMergeTable(pasteModel),
};
var insertPoint = customizedMerge
? customizedMerge(model, pasteModel)
: (0, mergeModel_1.mergeModel)(model, pasteModel, context, mergeOption);
if (insertPoint) {
context.newPendingFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, EmptySegmentFormat), model.format), insertPoint.marker.format);
}
core.api.formatContentModel(core, function (model, context) {
var selectedSegment = (0, collectSelections_1.getSelectedSegments)(model, true /*includeFormatHolder*/)[0];
var domToModelContext = (0, roosterjs_content_model_dom_1.createDomToModelContext)(undefined /*editorContext*/, core.domToModelSettings.customized, {
processorOverride: {
'#text': pasteTextProcessor_1.pasteTextProcessor,
entity: (0, pasteEntityProcessor_1.createPasteEntityProcessor)(domToModelOption),
'*': (0, pasteGeneralProcessor_1.createPasteGeneralProcessor)(domToModelOption),
},
formatParserOverride: {
display: pasteDisplayFormatParser_1.pasteDisplayFormatParser,
},
additionalFormatParsers: {
container: [containerSizeFormatParser_1.containerSizeFormatParser],
},
}, domToModelOption);
domToModelContext.segmentFormat = selectedSegment
? (0, getSegmentTextFormat_1.getSegmentTextFormat)(selectedSegment)
: {};
var pasteModel = (0, roosterjs_content_model_dom_1.domToContentModel)(fragment, domToModelContext);
var mergeOption = {
mergeFormat: pasteType == 'mergeFormat' ? 'keepSourceEmphasisFormat' : 'none',
mergeTable: shouldMergeTable(pasteModel),
};
var insertPoint = customizedMerge
? customizedMerge(model, pasteModel)
: (0, mergeModel_1.mergeModel)(model, pasteModel, context, mergeOption);
if (insertPoint) {
context.newPendingFormat = (0, tslib_1.__assign)((0, tslib_1.__assign)((0, tslib_1.__assign)({}, EmptySegmentFormat), model.format), insertPoint.marker.format);
}
return true;
}, {
changeSource: ChangeSource_1.ChangeSource.Paste,
getChangeData: function () { return clipboardData; },
apiName: 'paste',
});
}

@@ -61,0 +71,0 @@ exports.mergePasteContent = mergePasteContent;

@@ -23,2 +23,3 @@ "use strict";

range: range,
isReverted: snapshotSelection.isReverted,
};

@@ -25,0 +26,0 @@ break;

@@ -6,6 +6,6 @@ {

"tslib": "^2.3.1",
"roosterjs-content-model-dom": "^0.24.0",
"roosterjs-content-model-types": "^0.24.0"
"roosterjs-content-model-dom": "^0.25.0",
"roosterjs-content-model-types": "^0.25.0"
},
"version": "0.24.0",
"version": "0.25.0",
"main": "./lib/index.js",

@@ -12,0 +12,0 @@ "typings": "./lib/index.d.ts",

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc