Socket
Socket
Sign inDemoInstall

@ckeditor/ckeditor5-watchdog

Package Overview
Dependencies
Maintainers
1
Versions
593
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ckeditor/ckeditor5-watchdog - npm Package Compare versions

Comparing version 0.0.0-nightly-20230726.0 to 0.0.0-nightly-20230727.0

2

package.json
{
"name": "@ckeditor/ckeditor5-watchdog",
"version": "0.0.0-nightly-20230726.0",
"version": "0.0.0-nightly-20230727.0",
"description": "A watchdog feature for CKEditor 5 editors. It keeps a CKEditor 5 editor instance running.",

@@ -5,0 +5,0 @@ "keywords": [

@@ -13,4 +13,4 @@ /**

*/
_watchdogInitialData?: EditorData | null;
_watchdogInitialData?: EditorData;
}
}

@@ -40,2 +40,10 @@ /**

/**
* Specifies whether the editor was initialized using document data (`true`) or HTML elements (`false`).
*/
private _initUsingData;
/**
* The latest record of the editor editable elements. Used to restart the editor.
*/
private _editables;
/**
* The editor configuration.

@@ -113,3 +121,3 @@ */

*/
create(elementOrData?: HTMLElement | string | Record<string, string>, config?: EditorConfig, context?: Context): Promise<unknown>;
create(elementOrData?: HTMLElement | string | Record<string, string> | Record<string, HTMLElement>, config?: EditorConfig, context?: Context): Promise<unknown>;
/**

@@ -136,2 +144,6 @@ * Destroys the watchdog and the current editor instance. It fires the callback

/**
* For each attached model root, returns its HTML editable element (if available).
*/
private _getEditables;
/**
* Traverses the error context and the current editor to find out whether these structures are connected

@@ -152,2 +164,3 @@ * to each other via properties.

attributes: string;
isLoaded: boolean;
}>;

@@ -162,2 +175,4 @@ markers: Record<string, {

}>;
commentThreads: string;
suggestions: string;
};

@@ -174,2 +189,2 @@ /**

};
export type EditorCreatorFunction<TEditor = Editor> = (elementOrData: HTMLElement | string | Record<string, string>, config: EditorConfig) => Promise<TEditor>;
export type EditorCreatorFunction<TEditor = Editor> = (elementOrData: HTMLElement | string | Record<string, string> | Record<string, HTMLElement>, config: EditorConfig) => Promise<TEditor>;

@@ -25,2 +25,10 @@ /**

this._editor = null;
/**
* Specifies whether the editor was initialized using document data (`true`) or HTML elements (`false`).
*/
this._initUsingData = true;
/**
* The latest record of the editor editable elements. Used to restart the editor.
*/
this._editables = {};
// this._editorClass = Editor;

@@ -94,18 +102,52 @@ this._throttledSave = throttle(this._save.bind(this), typeof watchdogConfig.saveInterval === 'number' ? watchdogConfig.saveInterval : 5000);

.then(() => {
const existingRoots = Object.keys(this._data.roots).reduce((acc, rootName) => {
acc[rootName] = '';
return acc;
}, {});
// Pre-process some data from the original editor config.
// Our goal here is to make sure that the restarted editor will be reinitialized with correct set of roots.
// We are not interested in any data set in config or in `.create()` first parameter. It will be replaced anyway.
// But we need to set them correctly to make sure that proper roots are created.
//
// Since a different set of roots will be created, `lazyRoots` and `rootsAttributes` properties must be managed too.
// Keys are root names, values are ''. Used when the editor was initialized by setting the first parameter to document data.
const existingRoots = {};
// Keeps lazy roots. They may be different when compared to initial config if some of the roots were loaded.
const lazyRoots = [];
// Roots attributes from the old config. Will be referred when setting new attributes.
const oldRootsAttributes = this._config.rootsAttributes || {};
// New attributes to be set. Is filled only for roots that still exist in the document.
const rootsAttributes = {};
// Traverse through the roots saved when the editor crashed and set up the discussed values.
for (const [rootName, rootData] of Object.entries(this._data.roots)) {
if (rootData.isLoaded) {
existingRoots[rootName] = '';
rootsAttributes[rootName] = oldRootsAttributes[rootName] || {};
}
else {
lazyRoots.push(rootName);
}
}
const updatedConfig = {
...this._config,
extraPlugins: this._config.extraPlugins || [],
lazyRoots,
rootsAttributes,
_watchdogInitialData: this._data
};
// Delete `initialData` as it is not needed. Data will be set by the watchdog based on `_watchdogInitialData`.
// First parameter of the editor `.create()` will be used to set up initial roots.
delete updatedConfig.initialData;
updatedConfig.extraPlugins.push(EditorWatchdogInitPlugin);
if (typeof this._elementOrData === 'string') {
if (this._initUsingData) {
return this.create(existingRoots, updatedConfig, updatedConfig.context);
}
else {
updatedConfig.initialData = existingRoots;
return this.create(this._elementOrData, updatedConfig, updatedConfig.context);
// Set correct editables to make sure that proper roots are created and linked with DOM elements.
// No need to set initial data, as it would be discarded anyway.
//
// If one element was initially set in `elementOrData`, then use that original element to restart the editor.
// This is for compatibility purposes with single-root editor types.
if (isElement(this._elementOrData)) {
return this.create(this._elementOrData, updatedConfig, updatedConfig.context);
}
else {
return this.create(this._editables, updatedConfig, updatedConfig.context);
}
}

@@ -129,2 +171,6 @@ })

this._elementOrData = elementOrData;
// Use document data in the first parameter of the editor `.create()` call only if it was used like this originally.
// Use document data if a string or object with strings was passed.
this._initUsingData = typeof elementOrData == 'string' ||
(Object.keys(elementOrData).length > 0 && typeof Object.values(elementOrData)[0] == 'string');
// Clone configuration because it might be shared within multiple watchdog instances. Otherwise,

@@ -141,2 +187,5 @@ // when an error occurs in one of these editors, the watchdog will restart all of them.

this._data = this._getData();
if (!this._initUsingData) {
this._editables = this._getEditables();
}
this.state = 'ready';

@@ -164,4 +213,3 @@ this._fire('stateChange');

this._stopErrorHandling();
// Save data if there is a remaining editor data change.
this._throttledSave.flush();
this._throttledSave.cancel();
const editor = this._editor;

@@ -184,2 +232,5 @@ this._editor = null;

this._data = this._getData();
if (!this._initUsingData) {
this._editables = this._getEditables();
}
this._lastDocumentVersion = version;

@@ -202,13 +253,19 @@ }

_getData() {
const editor = this.editor;
const rootNames = editor.model.document.getRootNames();
const editor = this._editor;
const roots = editor.model.document.roots.filter(root => root.isAttached() && root.rootName != '$graveyard');
const { plugins } = editor;
// `as any` to avoid linking from external private repo.
const commentsRepository = plugins.has('CommentsRepository') && plugins.get('CommentsRepository');
const trackChanges = plugins.has('TrackChanges') && plugins.get('TrackChanges');
const data = {
roots: {},
markers: {}
markers: {},
commentThreads: JSON.stringify([]),
suggestions: JSON.stringify([])
};
rootNames.forEach(rootName => {
const root = editor.model.document.getRoot(rootName);
data.roots[rootName] = {
roots.forEach(root => {
data.roots[root.rootName] = {
content: JSON.stringify(Array.from(root.getChildren())),
attributes: JSON.stringify(Array.from(root.getAttributes()))
attributes: JSON.stringify(Array.from(root.getAttributes())),
isLoaded: root._isLoaded
};

@@ -226,5 +283,24 @@ });

}
if (commentsRepository) {
data.commentThreads = JSON.stringify(commentsRepository.getCommentThreads({ toJSON: true, skipNotAttached: true }));
}
if (trackChanges) {
data.suggestions = JSON.stringify(trackChanges.getSuggestions({ toJSON: true, skipNotAttached: true }));
}
return data;
}
/**
* For each attached model root, returns its HTML editable element (if available).
*/
_getEditables() {
const editables = {};
for (const rootName of this.editor.model.document.getRootNames()) {
const editable = this.editor.ui.getEditableElement(rootName);
if (editable) {
editables[rootName] = editable;
}
}
return editables;
}
/**
* Traverses the error context and the current editor to find out whether these structures are connected

@@ -271,3 +347,4 @@ * to each other via properties.

evt.stop();
this.editor.model.enqueueChange({ isUndoable: true }, writer => {
this.editor.model.enqueueChange({ isUndoable: false }, writer => {
this._restoreCollaborationData();
this._restoreEditorData(writer);

@@ -328,2 +405,29 @@ });

}
/**
* Restores the editor collaboration data - comment threads and suggestions.
*/
_restoreCollaborationData() {
// `as any` to avoid linking from external private repo.
const parsedCommentThreads = JSON.parse(this._data.commentThreads);
const parsedSuggestions = JSON.parse(this._data.suggestions);
parsedCommentThreads.forEach(commentThreadData => {
const channelId = this.editor.config.get('collaboration.channelId');
const commentsRepository = this.editor.plugins.get('CommentsRepository');
if (commentsRepository.hasCommentThread(commentThreadData.threadId)) {
const commentThread = commentsRepository.getCommentThread(commentThreadData.threadId);
commentThread.remove();
}
commentsRepository.addCommentThread({ channelId, ...commentThreadData });
});
parsedSuggestions.forEach(suggestionData => {
const trackChangesEditing = this.editor.plugins.get('TrackChangesEditing');
if (trackChangesEditing.hasSuggestion(suggestionData.id)) {
const suggestion = trackChangesEditing.getSuggestion(suggestionData.id);
suggestion.attributes = suggestionData.attributes;
}
else {
trackChangesEditing.addSuggestionData(suggestionData);
}
});
}
}
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