Skip to content

Commit ae5ccd9

Browse files
Don't require onActivationCheck to be provided in .create & fix related
issue
1 parent 641fdad commit ae5ccd9

File tree

2 files changed

+47
-25
lines changed

2 files changed

+47
-25
lines changed

packages/generator-joplin/generators/app/templates/api/JoplinViewsEditor.d.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ import { ActivationCheckCallback, ViewHandle, UpdateCallback } from './types';
33
export interface EditorPluginProps {
44
/** The ID of the window to show the editor plugin. Use `undefined` for the main window. */
55
windowId: string | undefined;
6-
/**
7-
* Called to determine whether the custom editor supports the current note.
8-
*/
9-
onActivationCheck: ActivationCheckCallback;
106
}
117
export interface SaveEditorContentProps {
128
/**
@@ -62,6 +58,7 @@ export default class JoplinViewsEditors {
6258
private store;
6359
private plugin;
6460
private activationCheckHandlers_;
61+
private unhandledActivationCheck_;
6562
constructor(plugin: Plugin, store: any);
6663
private controller;
6764
/**

packages/lib/services/plugins/api/JoplinViewsEditor.ts

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,6 @@ import { ActivationCheckCallback, EditorActivationCheckFilterObject, FilterHandl
1111
export interface EditorPluginProps {
1212
/** The ID of the window to show the editor plugin. Use `undefined` for the main window. */
1313
windowId: string|undefined;
14-
/**
15-
* Called to determine whether the custom editor supports the current note.
16-
*/
17-
onActivationCheck: ActivationCheckCallback;
1814
}
1915

2016
export interface SaveEditorContentProps {
@@ -31,6 +27,8 @@ export interface SaveEditorContentProps {
3127
body: string;
3228
}
3329

30+
type ActivationCheckSlice = Pick<EditorActivationCheckFilterObject, 'effectiveNoteId'|'windowId'|'activatedEditors'>;
31+
3432
/**
3533
* Allows creating alternative note editors. You can create a view to handle loading and saving the
3634
* note, and do your own rendering.
@@ -74,6 +72,7 @@ export default class JoplinViewsEditors {
7472
private store: any;
7573
private plugin: Plugin;
7674
private activationCheckHandlers_: Record<string, FilterHandler<EditorActivationCheckFilterObject>> = {};
75+
private unhandledActivationCheck_: Map<string, ActivationCheckSlice> = new Map();
7776

7877
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
7978
public constructor(plugin: Plugin, store: any) {
@@ -92,19 +91,40 @@ export default class JoplinViewsEditors {
9291
id: string,
9392
options: EditorPluginProps = {
9493
windowId: undefined,
95-
onActivationCheck: async ()=>false,
9694
},
9795
): Promise<ViewHandle> {
9896
const windowId = options.windowId ?? defaultWindowId;
9997
const handle = createViewHandle(this.plugin, `${id}-${windowId}`);
10098

101-
const controller = new WebviewController(handle, this.plugin.id, this.store, this.plugin.baseDir, ContainerType.Editor, windowId);
102-
this.plugin.addViewController(controller);
103-
// Restore the last open/closed state for the editor
104-
controller.setOpened(Setting.value('plugins.shownEditorViewIds').includes(handle));
99+
const initializeController = () => {
100+
const controller = new WebviewController(handle, this.plugin.id, this.store, this.plugin.baseDir, ContainerType.Editor, windowId);
101+
this.plugin.addViewController(controller);
102+
// Restore the last open/closed state for the editor
103+
controller.setOpened(Setting.value('plugins.shownEditorViewIds').includes(handle));
104+
};
105+
// Register the activation check handler early to handle the case where the editorActivationCheck
106+
// event is fired **before** an activation check handler is registered through the API.
107+
const registerActivationCheckHandler = () => {
108+
const onActivationCheck: FilterHandler<EditorActivationCheckFilterObject> = async object => {
109+
if (this.activationCheckHandlers_[handle]) {
110+
return this.activationCheckHandlers_[handle](object);
111+
} else {
112+
this.unhandledActivationCheck_.set(handle, {
113+
...object,
114+
});
115+
return object;
116+
}
117+
};
118+
eventManager.filterOn('editorActivationCheck', onActivationCheck);
119+
this.plugin.addOnUnloadListener(() => {
120+
eventManager.filterOff('editorActivationCheck', onActivationCheck);
121+
this.unhandledActivationCheck_.delete(handle);
122+
});
123+
};
124+
125+
initializeController();
126+
registerActivationCheckHandler();
105127

106-
// Call onActivationCheck immediately to prevent race conditions.
107-
await this.onActivationCheck(handle, options.onActivationCheck);
108128
return handle;
109129
}
110130

@@ -147,26 +167,31 @@ export default class JoplinViewsEditors {
147167
* `true`, otherwise return `false`.
148168
*/
149169
public async onActivationCheck(handle: ViewHandle, callback: ActivationCheckCallback): Promise<void> {
150-
const handler: FilterHandler<EditorActivationCheckFilterObject> = async (object) => {
151-
const isCorrectWindow = object.windowId === this.controller(handle).parentWindowId;
152-
const isActive = isCorrectWindow && await callback({
153-
noteId: object.effectiveNoteId,
154-
windowId: object.windowId,
170+
const isActive = async ({ windowId, effectiveNoteId }: ActivationCheckSlice) => {
171+
const isCorrectWindow = windowId === this.controller(handle).parentWindowId;
172+
const active = isCorrectWindow && await callback({
173+
noteId: effectiveNoteId,
174+
windowId: windowId,
155175
});
176+
return active;
177+
};
178+
const handler = async (object: ActivationCheckSlice) => {
156179
object.activatedEditors.push({
157180
pluginId: this.plugin.id,
158181
viewId: handle,
159-
isActive: isActive,
182+
isActive: await isActive(object),
160183
});
161184
return object;
162185
};
163186

164187
this.activationCheckHandlers_[handle] = handler;
165188

166-
eventManager.filterOn('editorActivationCheck', this.activationCheckHandlers_[handle]);
167-
this.plugin.addOnUnloadListener(() => {
168-
eventManager.filterOff('editorActivationCheck', this.activationCheckHandlers_[handle]);
169-
});
189+
// Handle the case where an activation check was done before the onActivationCheck handler was registered.
190+
if (this.unhandledActivationCheck_.has(handle)) {
191+
const activationCheckObject = this.unhandledActivationCheck_.get(handle);
192+
this.unhandledActivationCheck_.delete(handle);
193+
this.controller(handle).setActive(await isActive(activationCheckObject));
194+
}
170195
}
171196

172197
/**

0 commit comments

Comments
 (0)