ckeditor5-blazor 1.10.0 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ckeditor5-blazor",
3
- "version": "1.10.0",
3
+ "version": "1.10.2",
4
4
  "description": "CKEditor 5 integration for Blazor",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -128,6 +128,7 @@ export class EditableComponentElement extends HTMLElement {
128
128
  return () => {
129
129
  editor.model.document.off('change:data', debouncedSync);
130
130
 
131
+ /* v8 ignore else -- @preserve */
131
132
  if (editor.state !== 'destroyed' && rootName) {
132
133
  const root = editor.model.document.getRoot(rootName);
133
134
 
@@ -1,6 +1,5 @@
1
1
  import type { WaitForInteractiveResult } from '../../shared';
2
2
  import type { EditorId, EditorLanguage, EditorPreset } from './typings';
3
- import type { Editor } from 'ckeditor5';
4
3
 
5
4
  import {
6
5
  isEmptyObject,
@@ -37,9 +36,9 @@ import {
37
36
  */
38
37
  export class EditorComponentElement extends HTMLElement {
39
38
  /**
40
- * The promise that resolves to the editor instance.
39
+ * Stops observing the editor registry and immediately runs any pending cleanup.
41
40
  */
42
- private editorPromise: Promise<Editor> | null = null;
41
+ private unmountEffect: VoidFunction | null = null;
43
42
 
44
43
  /**
45
44
  * Wait result for the interactive attribute.
@@ -76,27 +75,52 @@ export class EditorComponentElement extends HTMLElement {
76
75
 
77
76
  try {
78
77
  this.style.display = 'block';
79
- this.editorPromise = this.createEditor();
80
78
 
81
- const editor = await this.editorPromise;
79
+ const editor = await this.createEditor();
80
+ const editorContext = unwrapEditorContext(editor);
81
+ const watchdog = unwrapEditorWatchdog(editor);
82
82
 
83
83
  // Do not even try to broadcast about the registration of the editor
84
84
  // if hook was immediately destroyed.
85
85
  /* v8 ignore else -- @preserve */
86
86
  if (this.isConnected) {
87
- EditorsRegistry.the.register(editorId, editor);
87
+ // Run some stuff that have to be reinitialized every-time editor is being restarted.
88
+ const unmountDestroyWatchers = EditorsRegistry.the.mountEffect(editorId, (editor) => {
89
+ // Enforce deregistration of the editor when it's being destroyed by watchdog.
90
+ editor.once('destroy', () => {
91
+ // Let's handle case when watchdog (or context watchdog) destroyed editor "externally"
92
+ // user might also manually kill the editor using `.destroy()` method.
93
+ // Keep pending callbacks though. Someone might register new callbacks just before calling `.destroy()`.
94
+ EditorsRegistry.the.unregister(editorId, false);
95
+ }, { priority: 'highest' });
96
+ });
88
97
 
89
- editor.once('destroy', () => {
90
- if (EditorsRegistry.the.hasItem(editorId)) {
91
- EditorsRegistry.the.unregister(editorId);
98
+ this.unmountEffect = async () => {
99
+ // If for some reason editor not fired `destroy`, enforce deregistration.
100
+ EditorsRegistry.the.unregister(editorId);
101
+ unmountDestroyWatchers();
102
+
103
+ if (editorContext) {
104
+ // If context is present, make sure it's not in unmounting phase, as it'll kill the editors.
105
+ // If it's being destroyed, don't do anything, as the context will take care of it.
106
+ if (editorContext.state !== 'unavailable') {
107
+ await editorContext.context.remove(editorContext.editorContextId);
108
+ }
92
109
  }
93
- });
110
+ else if (watchdog) {
111
+ await watchdog.destroy();
112
+ }
113
+ else {
114
+ await editor.destroy();
115
+ }
116
+ };
117
+
118
+ EditorsRegistry.the.register(editorId, editor);
94
119
  }
95
120
  }
96
121
  catch (error: any) {
97
122
  /* v8 ignore start -- @preserve */
98
123
  console.error(`Error initializing CKEditor5 instance with ID "${editorId}":`, error);
99
- this.editorPromise = null;
100
124
  EditorsRegistry.the.error(editorId, error);
101
125
  /* v8 ignore end */
102
126
  }
@@ -107,41 +131,9 @@ export class EditorComponentElement extends HTMLElement {
107
131
  * This is important to prevent memory leaks and ensure that the editor is properly cleaned up.
108
132
  */
109
133
  async disconnectedCallback() {
110
- // Disconnect the observer if present.
111
134
  this.interactiveWait?.disconnect();
112
-
113
- // Let's hide the element during destruction to prevent flickering.
114
135
  this.style.display = 'none';
115
-
116
- // Let's wait for the mounted promise to resolve before proceeding with destruction.
117
- try {
118
- const editor = await this.editorPromise;
119
-
120
- /* v8 ignore next -- @preserve */
121
- if (!editor) {
122
- return;
123
- }
124
-
125
- const editorContext = unwrapEditorContext(editor);
126
- const watchdog = unwrapEditorWatchdog(editor);
127
-
128
- if (editorContext) {
129
- // If context is present, make sure it's not in unmounting phase, as it'll kill the editors.
130
- // If it's being destroyed, don't do anything, as the context will take care of it.
131
- if (editorContext.state !== 'unavailable') {
132
- await editorContext.context.remove(editorContext.editorContextId);
133
- }
134
- }
135
- else if (watchdog) {
136
- await watchdog.destroy();
137
- }
138
- else {
139
- await editor.destroy();
140
- }
141
- }
142
- finally {
143
- this.editorPromise = null;
144
- }
136
+ this.unmountEffect?.();
145
137
  }
146
138
 
147
139
  /**
@@ -136,9 +136,9 @@ export function createEditorBlazorInterop(element: HTMLElement, interop: DotNetI
136
136
  return;
137
137
  }
138
138
 
139
- const editor = await EditorsRegistry.the.waitFor(editorId);
140
-
141
- installImageUploadAdapter(editor, interop);
139
+ EditorsRegistry.the.mountEffect(editorId, (editor) => {
140
+ installImageUploadAdapter(editor, interop);
141
+ });
142
142
  },
143
143
  };
144
144
  }