mirror of
https://github.com/laurent22/joplin.git
synced 2025-01-23 18:53:36 +02:00
Chore: Refactor EventManager to use stronger types (#10272)
This commit is contained in:
parent
9713034f18
commit
58ca1a938b
@ -125,8 +125,7 @@ function NoteEditor(props: NoteEditorProps) {
|
|||||||
return async function() {
|
return async function() {
|
||||||
const note = await formNoteToNote(formNote);
|
const note = await formNoteToNote(formNote);
|
||||||
reg.logger().debug('Saving note...', note);
|
reg.logger().debug('Saving note...', note);
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
const savedNote = await Note.save(note);
|
||||||
const savedNote: any = await Note.save(note);
|
|
||||||
|
|
||||||
setFormNote((prev: FormNote) => {
|
setFormNote((prev: FormNote) => {
|
||||||
return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false };
|
return { ...prev, user_updated_time: savedNote.user_updated_time, hasChanged: false };
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
const fastDeepEqual = require('fast-deep-equal');
|
const fastDeepEqual = require('fast-deep-equal');
|
||||||
|
import { EventEmitter } from 'events';
|
||||||
const events = require('events');
|
import type { State as AppState } from './reducer';
|
||||||
|
|
||||||
export enum EventName {
|
export enum EventName {
|
||||||
ResourceCreate = 'resourceCreate',
|
ResourceCreate = 'resourceCreate',
|
||||||
@ -20,30 +20,34 @@ export enum EventName {
|
|||||||
NoteResourceIndexed = 'noteResourceIndexed',
|
NoteResourceIndexed = 'noteResourceIndexed',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code from before rule was applied
|
||||||
|
export type EventListenerCallback = (...args: any[])=> void;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code from before rule was applied
|
||||||
|
type AppStateChangeCallback = (event: { value: any })=> void;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partial refactor of old code from before rule was applied
|
||||||
|
type FilterObject = any;
|
||||||
|
export type FilterHandler = (object: FilterObject)=> FilterObject;
|
||||||
|
|
||||||
export class EventManager {
|
export class EventManager {
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
private emitter_: EventEmitter;
|
||||||
private emitter_: any;
|
private appStatePrevious_: Record<string, AppState[keyof AppState]>;
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
|
||||||
private appStatePrevious_: any;
|
|
||||||
private appStateWatchedProps_: string[];
|
private appStateWatchedProps_: string[];
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
private appStateListeners_: Record<string, AppStateChangeCallback[]>;
|
||||||
private appStateListeners_: any;
|
|
||||||
|
|
||||||
public constructor() {
|
public constructor() {
|
||||||
this.reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public reset() {
|
public reset() {
|
||||||
this.emitter_ = new events.EventEmitter();
|
this.emitter_ = new EventEmitter();
|
||||||
|
|
||||||
this.appStatePrevious_ = {};
|
this.appStatePrevious_ = {};
|
||||||
this.appStateWatchedProps_ = [];
|
this.appStateWatchedProps_ = [];
|
||||||
this.appStateListeners_ = {};
|
this.appStateListeners_ = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public on(eventName: EventName, callback: EventListenerCallback) {
|
||||||
public on(eventName: EventName, callback: Function) {
|
|
||||||
return this.emitter_.on(eventName, callback);
|
return this.emitter_.on(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,23 +56,19 @@ export class EventManager {
|
|||||||
return this.emitter_.emit(eventName, object);
|
return this.emitter_.emit(eventName, object);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public removeListener(eventName: string, callback: EventListenerCallback) {
|
||||||
public removeListener(eventName: string, callback: Function) {
|
|
||||||
return this.emitter_.removeListener(eventName, callback);
|
return this.emitter_.removeListener(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public off(eventName: EventName, callback: EventListenerCallback) {
|
||||||
public off(eventName: EventName, callback: Function) {
|
|
||||||
return this.removeListener(eventName, callback);
|
return this.removeListener(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public filterOn(filterName: string, callback: FilterHandler) {
|
||||||
public filterOn(filterName: string, callback: Function) {
|
|
||||||
return this.emitter_.on(`filter:${filterName}`, callback);
|
return this.emitter_.on(`filter:${filterName}`, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public filterOff(filterName: string, callback: FilterHandler) {
|
||||||
public filterOff(filterName: string, callback: Function) {
|
|
||||||
return this.removeListener(`filter:${filterName}`, callback);
|
return this.removeListener(`filter:${filterName}`, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,8 +95,7 @@ export class EventManager {
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public appStateOn(propName: string, callback: AppStateChangeCallback) {
|
||||||
public appStateOn(propName: string, callback: Function) {
|
|
||||||
if (!this.appStateListeners_[propName]) {
|
if (!this.appStateListeners_[propName]) {
|
||||||
this.appStateListeners_[propName] = [];
|
this.appStateListeners_[propName] = [];
|
||||||
this.appStateWatchedProps_.push(propName);
|
this.appStateWatchedProps_.push(propName);
|
||||||
@ -105,8 +104,7 @@ export class EventManager {
|
|||||||
this.appStateListeners_[propName].push(callback);
|
this.appStateListeners_[propName].push(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public appStateOff(propName: string, callback: AppStateChangeCallback) {
|
||||||
public appStateOff(propName: string, callback: Function) {
|
|
||||||
if (!this.appStateListeners_[propName]) {
|
if (!this.appStateListeners_[propName]) {
|
||||||
throw new Error('EventManager: Trying to unregister a state prop watch for a non-watched prop (1)');
|
throw new Error('EventManager: Trying to unregister a state prop watch for a non-watched prop (1)');
|
||||||
}
|
}
|
||||||
@ -117,10 +115,10 @@ export class EventManager {
|
|||||||
this.appStateListeners_[propName].splice(idx, 1);
|
this.appStateListeners_[propName].splice(idx, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
private stateValue_(state: AppState, propName: string) {
|
||||||
private stateValue_(state: any, propName: string) {
|
|
||||||
const parts = propName.split('.');
|
const parts = propName.split('.');
|
||||||
let s = state;
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Partially refactored old code from before rule was applied.
|
||||||
|
let s: any = state;
|
||||||
for (const p of parts) {
|
for (const p of parts) {
|
||||||
if (!(p in s)) throw new Error(`Invalid state property path: ${propName}`);
|
if (!(p in s)) throw new Error(`Invalid state property path: ${propName}`);
|
||||||
s = s[p];
|
s = s[p];
|
||||||
@ -131,8 +129,7 @@ export class EventManager {
|
|||||||
// This function works by keeping a copy of the watched props and, whenever this function
|
// This function works by keeping a copy of the watched props and, whenever this function
|
||||||
// is called, comparing the previous and new values and emitting events if they have changed.
|
// is called, comparing the previous and new values and emitting events if they have changed.
|
||||||
// The appStateEmit function should be called from a middleware.
|
// The appStateEmit function should be called from a middleware.
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
public appStateEmit(state: AppState) {
|
||||||
public appStateEmit(state: any) {
|
|
||||||
if (!this.appStateWatchedProps_.length) return;
|
if (!this.appStateWatchedProps_.length) return;
|
||||||
|
|
||||||
for (const propName of this.appStateWatchedProps_) {
|
for (const propName of this.appStateWatchedProps_) {
|
||||||
@ -157,8 +154,7 @@ export class EventManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
public once(eventName: string, callback: EventListenerCallback) {
|
||||||
public once(eventName: string, callback: any) {
|
|
||||||
return this.emitter_.once(eventName, callback);
|
return this.emitter_.once(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { State } from '../reducer';
|
import { State } from '../reducer';
|
||||||
import eventManager, { EventName } from '../eventManager';
|
import eventManager, { EventListenerCallback, EventName } from '../eventManager';
|
||||||
import BaseService from './BaseService';
|
import BaseService from './BaseService';
|
||||||
import shim from '../shim';
|
import shim from '../shim';
|
||||||
import WhenClause from './WhenClause';
|
import WhenClause from './WhenClause';
|
||||||
@ -57,6 +57,16 @@ export interface Command {
|
|||||||
runtime?: CommandRuntime;
|
runtime?: CommandRuntime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CommandSpec {
|
||||||
|
declaration: CommandDeclaration;
|
||||||
|
runtime: ()=> CommandRuntime;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ComponentCommandSpec<ComponentType> {
|
||||||
|
declaration: CommandDeclaration;
|
||||||
|
runtime: (component: ComponentType)=> CommandRuntime;
|
||||||
|
}
|
||||||
|
|
||||||
interface Commands {
|
interface Commands {
|
||||||
[key: string]: Command;
|
[key: string]: Command;
|
||||||
}
|
}
|
||||||
@ -114,13 +124,11 @@ export default class CommandService extends BaseService {
|
|||||||
this.stateToWhenClauseContext_ = stateToWhenClauseContext;
|
this.stateToWhenClauseContext_ = stateToWhenClauseContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public on(eventName: EventName, callback: EventListenerCallback) {
|
||||||
public on(eventName: EventName, callback: Function) {
|
|
||||||
eventManager.on(eventName, callback);
|
eventManager.on(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public off(eventName: EventName, callback: EventListenerCallback) {
|
||||||
public off(eventName: EventName, callback: Function) {
|
|
||||||
eventManager.off(eventName, callback);
|
eventManager.off(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,29 +212,26 @@ export default class CommandService extends BaseService {
|
|||||||
command.runtime = runtime;
|
command.runtime = runtime;
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
public registerCommands(commands: CommandSpec[]) {
|
||||||
public registerCommands(commands: any[]) {
|
|
||||||
for (const command of commands) {
|
for (const command of commands) {
|
||||||
CommandService.instance().registerRuntime(command.declaration.name, command.runtime());
|
CommandService.instance().registerRuntime(command.declaration.name, command.runtime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
public unregisterCommands(commands: CommandSpec[]) {
|
||||||
public unregisterCommands(commands: any[]) {
|
|
||||||
for (const command of commands) {
|
for (const command of commands) {
|
||||||
CommandService.instance().unregisterRuntime(command.declaration.name);
|
CommandService.instance().unregisterRuntime(command.declaration.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
public componentRegisterCommands<ComponentType>(component: ComponentType, commands: ComponentCommandSpec<ComponentType>[]) {
|
||||||
public componentRegisterCommands(component: any, commands: any[]) {
|
|
||||||
for (const command of commands) {
|
for (const command of commands) {
|
||||||
CommandService.instance().registerRuntime(command.declaration.name, command.runtime(component));
|
CommandService.instance().registerRuntime(command.declaration.name, command.runtime(component));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
|
||||||
public componentUnregisterCommands(commands: any[]) {
|
public componentUnregisterCommands(commands: ComponentCommandSpec<any>[]) {
|
||||||
for (const command of commands) {
|
for (const command of commands) {
|
||||||
CommandService.instance().unregisterRuntime(command.declaration.name);
|
CommandService.instance().unregisterRuntime(command.declaration.name);
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import eventManager, { EventName } from '../eventManager';
|
import eventManager, { EventListenerCallback, EventName } from '../eventManager';
|
||||||
import shim from '../shim';
|
import shim from '../shim';
|
||||||
import { _ } from '../locale';
|
import { _ } from '../locale';
|
||||||
import keysRegExp from './KeymapService_keysRegExp';
|
import keysRegExp from './KeymapService_keysRegExp';
|
||||||
@ -415,13 +415,11 @@ export default class KeymapService extends BaseService {
|
|||||||
return parts.join('+');
|
return parts.join('+');
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public on(eventName: EventName, callback: EventListenerCallback) {
|
||||||
public on(eventName: EventName, callback: Function) {
|
|
||||||
eventManager.on(eventName, callback);
|
eventManager.on(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public off(eventName: EventName, callback: EventListenerCallback) {
|
||||||
public off(eventName: EventName, callback: Function) {
|
|
||||||
eventManager.off(eventName, callback);
|
eventManager.off(eventName, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/* eslint-disable multiline-comment-style */
|
/* eslint-disable multiline-comment-style */
|
||||||
|
|
||||||
import eventManager from '../../../eventManager';
|
import eventManager, { FilterHandler } from '../../../eventManager';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ignore
|
* @ignore
|
||||||
@ -9,13 +10,11 @@ import eventManager from '../../../eventManager';
|
|||||||
* so for now disable filters.
|
* so for now disable filters.
|
||||||
*/
|
*/
|
||||||
export default class JoplinFilters {
|
export default class JoplinFilters {
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public async on(name: string, callback: FilterHandler) {
|
||||||
public async on(name: string, callback: Function) {
|
|
||||||
eventManager.filterOn(name, callback);
|
eventManager.filterOn(name, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public async off(name: string, callback: FilterHandler) {
|
||||||
public async off(name: string, callback: Function) {
|
|
||||||
eventManager.filterOff(name, callback);
|
eventManager.filterOff(name, callback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,9 +44,28 @@ interface ResourceChangeEvent {
|
|||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ItemChangeHandler = (event: ItemChangeEvent)=> void;
|
interface NoteContentChangeEvent {
|
||||||
type SyncStartHandler = (event: SyncStartEvent)=> void;
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- No plugin-api-accessible Note type defined.
|
||||||
type ResourceChangeHandler = (event: ResourceChangeEvent)=> void;
|
note: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NoteSelectionChangeEvent {
|
||||||
|
value: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface NoteAlarmTriggerEvent {
|
||||||
|
noteId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SyncCompleteEvent {
|
||||||
|
withErrors: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
type WorkspaceEventHandler<EventType> = (event: EventType)=> void;
|
||||||
|
|
||||||
|
type ItemChangeHandler = WorkspaceEventHandler<ItemChangeEvent>;
|
||||||
|
type SyncStartHandler = WorkspaceEventHandler<SyncStartEvent>;
|
||||||
|
type ResourceChangeHandler = WorkspaceEventHandler<ResourceChangeEvent>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The workspace service provides access to all the parts of Joplin that
|
* The workspace service provides access to all the parts of Joplin that
|
||||||
@ -71,7 +90,7 @@ export default class JoplinWorkspace {
|
|||||||
* Called when a new note or notes are selected.
|
* Called when a new note or notes are selected.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
||||||
public async onNoteSelectionChange(callback: Function): Promise<Disposable> {
|
public async onNoteSelectionChange(callback: WorkspaceEventHandler<NoteSelectionChangeEvent>): Promise<Disposable> {
|
||||||
eventManager.appStateOn('selectedNoteIds', callback);
|
eventManager.appStateOn('selectedNoteIds', callback);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@ -87,8 +106,7 @@ export default class JoplinWorkspace {
|
|||||||
* Called when the content of a note changes.
|
* Called when the content of a note changes.
|
||||||
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
|
* @deprecated Use `onNoteChange()` instead, which is reliably triggered whenever the note content, or any note property changes.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public async onNoteContentChange(callback: WorkspaceEventHandler<NoteContentChangeEvent>) {
|
||||||
public async onNoteContentChange(callback: Function) {
|
|
||||||
eventManager.on(EventName.NoteContentChange, callback);
|
eventManager.on(EventName.NoteContentChange, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,8 +139,7 @@ export default class JoplinWorkspace {
|
|||||||
/**
|
/**
|
||||||
* Called when an alarm associated with a to-do is triggered.
|
* Called when an alarm associated with a to-do is triggered.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public async onNoteAlarmTrigger(handler: WorkspaceEventHandler<NoteAlarmTriggerEvent>): Promise<Disposable> {
|
||||||
public async onNoteAlarmTrigger(handler: Function): Promise<Disposable> {
|
|
||||||
return makeListener(eventManager, EventName.NoteAlarmTrigger, handler);
|
return makeListener(eventManager, EventName.NoteAlarmTrigger, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,8 +153,7 @@ export default class JoplinWorkspace {
|
|||||||
/**
|
/**
|
||||||
* Called when the synchronisation process has finished.
|
* Called when the synchronisation process has finished.
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
public async onSyncComplete(callback: WorkspaceEventHandler<SyncCompleteEvent>): Promise<Disposable> {
|
||||||
public async onSyncComplete(callback: Function): Promise<Disposable> {
|
|
||||||
return makeListener(eventManager, EventName.SyncComplete, callback);
|
return makeListener(eventManager, EventName.SyncComplete, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { EventManager, EventName } from '../../../eventManager';
|
import { EventListenerCallback, EventManager, EventName } from '../../../eventManager';
|
||||||
import { Disposable } from '../api/types';
|
import { Disposable } from '../api/types';
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
|
export default function(eventManager: EventManager, eventName: EventName, callback: EventListenerCallback): Disposable {
|
||||||
export default function(eventManager: EventManager, eventName: EventName, callback: Function): Disposable {
|
|
||||||
eventManager.on(eventName, callback);
|
eventManager.on(eventName, callback);
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user