@ckeditor/ckeditor5-watchdog
Advanced tools
Comparing version 0.0.0-nightly-20230720.0 to 0.0.0-nightly-20230721.0
{ | ||
"name": "@ckeditor/ckeditor5-watchdog", | ||
"version": "0.0.0-nightly-20230720.0", | ||
"version": "0.0.0-nightly-20230721.0", | ||
"description": "A watchdog feature for CKEditor 5 editors. It keeps a CKEditor 5 editor instance running.", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -130,3 +130,3 @@ /** | ||
/** | ||
* Returns the editor data. | ||
* Gets all data that is required to reinitialize editor instance. | ||
*/ | ||
@@ -146,2 +146,16 @@ private _getData; | ||
} | ||
export type EditorData = { | ||
roots: Record<string, { | ||
content: string; | ||
attributes: string; | ||
}>; | ||
markers: Record<string, { | ||
rangeJSON: { | ||
start: any; | ||
end: any; | ||
}; | ||
usingOperation: boolean; | ||
affectsData: boolean; | ||
}>; | ||
}; | ||
/** | ||
@@ -148,0 +162,0 @@ * Fired after the watchdog restarts the error in case of a crash. |
@@ -93,9 +93,17 @@ /** | ||
.then(() => { | ||
const existingRoots = Object.keys(this._data.roots).reduce((acc, rootName) => { | ||
acc[rootName] = ''; | ||
return acc; | ||
}, {}); | ||
const updatedConfig = { | ||
...this._config, | ||
extraPlugins: this._config.extraPlugins || [], | ||
_watchdogInitialData: this._data | ||
}; | ||
updatedConfig.extraPlugins.push(EditorWatchdogInitPlugin); | ||
if (typeof this._elementOrData === 'string') { | ||
return this.create(this._data, this._config, this._config.context); | ||
return this.create(existingRoots, updatedConfig, updatedConfig.context); | ||
} | ||
else { | ||
const updatedConfig = Object.assign({}, this._config, { | ||
initialData: this._data | ||
}); | ||
updatedConfig.initialData = existingRoots; | ||
return this.create(this._elementOrData, updatedConfig, updatedConfig.context); | ||
@@ -186,8 +194,27 @@ } | ||
/** | ||
* Returns the editor data. | ||
* Gets all data that is required to reinitialize editor instance. | ||
*/ | ||
_getData() { | ||
const data = {}; | ||
for (const rootName of this._editor.model.document.getRootNames()) { | ||
data[rootName] = this._editor.data.get({ rootName }); | ||
const editor = this.editor; | ||
const rootNames = editor.model.document.getRootNames(); | ||
const data = { | ||
roots: {}, | ||
markers: {} | ||
}; | ||
rootNames.forEach(rootName => { | ||
const root = editor.model.document.getRoot(rootName); | ||
data.roots[rootName] = { | ||
content: JSON.stringify(Array.from(root.getChildren())), | ||
attributes: JSON.stringify(Array.from(root.getAttributes())) | ||
}; | ||
}); | ||
for (const marker of editor.model.markers) { | ||
if (!marker._affectsData) { | ||
continue; | ||
} | ||
data.markers[marker.name] = { | ||
rangeJSON: marker.getRange().toJSON(), | ||
usingOperation: marker._managedUsingOperations, | ||
affectsData: marker._affectsData | ||
}; | ||
} | ||
@@ -220,1 +247,76 @@ return data; | ||
} | ||
/** | ||
* Internal plugin that is used to stop the default editor initialization and restoring the editor state | ||
* based on the `editor.config._watchdogInitialData` data. | ||
*/ | ||
class EditorWatchdogInitPlugin { | ||
constructor(editor) { | ||
this.editor = editor; | ||
this._data = editor.config.get('_watchdogInitialData'); | ||
} | ||
/** | ||
* @inheritDoc | ||
*/ | ||
init() { | ||
// Stops the default editor initialization and use the saved data to restore the editor state. | ||
// Some of data could not be initialize as a config properties. It is important to keep the data | ||
// in the same form as it was before the restarting. | ||
this.editor.data.on('init', evt => { | ||
evt.stop(); | ||
this.editor.model.enqueueChange({ isUndoable: true }, writer => { | ||
this._restoreEditorData(writer); | ||
}); | ||
this.editor.data.fire('ready'); | ||
// Keep priority `'high' - 1` to be sure that RTC initialization will be first. | ||
}, { priority: 1000 - 1 }); | ||
} | ||
/** | ||
* Creates a model node (element or text) based on provided JSON. | ||
*/ | ||
_createNode(writer, jsonNode) { | ||
if ('name' in jsonNode) { | ||
// If child has name property, it is an Element. | ||
const element = writer.createElement(jsonNode.name, jsonNode.attributes); | ||
if (jsonNode.children) { | ||
for (const child of jsonNode.children) { | ||
element._appendChild(this._createNode(writer, child)); | ||
} | ||
} | ||
return element; | ||
} | ||
else { | ||
// Otherwise, it is a Text node. | ||
return writer.createText(jsonNode.data, jsonNode.attributes); | ||
} | ||
} | ||
/** | ||
* Restores the editor by setting the document data, roots attributes and markers. | ||
*/ | ||
_restoreEditorData(writer) { | ||
const editor = this.editor; | ||
Object.entries(this._data.roots).forEach(([rootName, { content, attributes }]) => { | ||
const parsedNodes = JSON.parse(content); | ||
const parsedAttributes = JSON.parse(attributes); | ||
const rootElement = editor.model.document.getRoot(rootName); | ||
for (const [key, value] of parsedAttributes) { | ||
writer.setAttribute(key, value, rootElement); | ||
} | ||
for (const child of parsedNodes) { | ||
const node = this._createNode(writer, child); | ||
writer.insert(node, rootElement, 'end'); | ||
} | ||
}); | ||
Object.entries(this._data.markers).forEach(([markerName, markerOptions]) => { | ||
const { document } = editor.model; | ||
const { rangeJSON: { start, end }, ...options } = markerOptions; | ||
const root = document.getRoot(start.root); | ||
const startPosition = writer.createPositionFromPath(root, start.path, start.stickiness); | ||
const endPosition = writer.createPositionFromPath(root, end.path, end.stickiness); | ||
const range = writer.createRange(startPosition, endPosition); | ||
writer.addMarker(markerName, { | ||
range, | ||
...options | ||
}); | ||
}); | ||
} | ||
} |
@@ -11,1 +11,2 @@ /** | ||
export { default as Watchdog } from './watchdog'; | ||
import './augmentation'; |
@@ -11,1 +11,2 @@ /** | ||
export { default as Watchdog } from './watchdog'; | ||
import './augmentation'; |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
75471
19
1850