Merged PR 392: Events: Fix needing to use setTimeout for callbacks
This commit is contained in:
parent
6792d5e105
commit
460669987d
8 changed files with 182 additions and 88 deletions
|
@ -9,16 +9,20 @@ import { GetDefaultEditorState as GetDefaultEditorStateAction } from '../utils/d
|
|||
import { Revive, ReviveHistory as ReviveHistoryAction } from '../utils/saveload';
|
||||
|
||||
interface IAppEventParams {
|
||||
root: Element | Document
|
||||
languageContext: ILanguage
|
||||
setEditor: (newState: IEditorState) => void
|
||||
setAppState: (appState: AppState) => void
|
||||
eventInitDict?: CustomEventInit
|
||||
}
|
||||
|
||||
export interface WrappedCustomEvent {
|
||||
event: CustomEvent
|
||||
runAfterRender: boolean
|
||||
}
|
||||
|
||||
export interface IAppEvent {
|
||||
name: string
|
||||
func: (params: IAppEventParams) => void
|
||||
func: (params: IAppEventParams) => WrappedCustomEvent
|
||||
}
|
||||
|
||||
export const events: IAppEvent[] = [
|
||||
|
@ -33,6 +37,7 @@ export const events: IAppEvent[] = [
|
|||
];
|
||||
|
||||
export function UseCustomEvents(
|
||||
callbackQueue: React.RefObject<CustomEvent[]>,
|
||||
root: Element | Document,
|
||||
appRef: React.RefObject<HTMLDivElement>,
|
||||
languageContext: ILanguage,
|
||||
|
@ -49,13 +54,21 @@ export function UseCustomEvents(
|
|||
const funcs = new Map<string, () => void>();
|
||||
for (const event of events) {
|
||||
function Func(eventInitDict?: CustomEventInit): void {
|
||||
event.func({
|
||||
root,
|
||||
console.debug(`RUN INITIAL FUNCTION: ${event.name}`);
|
||||
const customEvent = event.func({
|
||||
languageContext,
|
||||
setEditor,
|
||||
setAppState,
|
||||
eventInitDict
|
||||
});
|
||||
|
||||
if (customEvent.runAfterRender) {
|
||||
console.debug(`ADDING CALLBACK TO QUEUE: ${customEvent.event.type}`);
|
||||
callbackQueue.current?.push(customEvent.event);
|
||||
} else {
|
||||
console.debug(`EXECUTING CALLBACK IMMEDIATELY: ${customEvent.event.type}`);
|
||||
root.dispatchEvent(customEvent.event);
|
||||
}
|
||||
}
|
||||
current.addEventListener(event.name, Func);
|
||||
funcs.set(event.name, Func);
|
||||
|
@ -70,89 +83,127 @@ export function UseCustomEvents(
|
|||
}
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (callbackQueue.current === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbackQueue.current.length > 0) {
|
||||
const callback = callbackQueue.current.shift();
|
||||
|
||||
if (callback === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug(`RUNNING CALLBACK FROM QUEUE: ${callback.type}`);
|
||||
root.dispatchEvent(callback);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
function SetEditor({
|
||||
root,
|
||||
setEditor,
|
||||
setAppState,
|
||||
eventInitDict
|
||||
}: IAppEventParams): void {
|
||||
}: IAppEventParams): WrappedCustomEvent {
|
||||
const editor: IEditorState = eventInitDict?.detail;
|
||||
setEditor(editor);
|
||||
setAppState(AppState.Loading);
|
||||
const customEvent = new CustomEvent<IEditorState>('setEditor', { detail: editor });
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent<IEditorState>('setEditor', { detail: editor });
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function SetAppState({
|
||||
setAppState,
|
||||
eventInitDict
|
||||
}: IAppEventParams): void {
|
||||
}: IAppEventParams): WrappedCustomEvent {
|
||||
const appState: AppState = eventInitDict?.detail;
|
||||
setAppState(appState);
|
||||
return {
|
||||
event: new CustomEvent('setAppState'),
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function ReviveEditorState({
|
||||
root,
|
||||
eventInitDict
|
||||
}: IAppEventParams): void {
|
||||
}: IAppEventParams): WrappedCustomEvent {
|
||||
const anEditorState: IEditorState = eventInitDict?.detail;
|
||||
Revive(anEditorState);
|
||||
const customEvent = new CustomEvent<IEditorState>('reviveEditorState', { detail: anEditorState });
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent<IEditorState>('reviveEditorState', { detail: anEditorState });
|
||||
return {
|
||||
event,
|
||||
runAfterRender: false
|
||||
};
|
||||
}
|
||||
|
||||
function ReviveHistory({
|
||||
root,
|
||||
eventInitDict
|
||||
}: IAppEventParams): void {
|
||||
}: IAppEventParams): WrappedCustomEvent {
|
||||
const history: IHistoryState[] = eventInitDict?.detail;
|
||||
ReviveHistoryAction(history);
|
||||
const customEvent = new CustomEvent<IHistoryState[]>('reviveHistory', { detail: history });
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent<IHistoryState[]>('reviveHistory', { detail: history });
|
||||
return {
|
||||
event,
|
||||
runAfterRender: false
|
||||
};
|
||||
}
|
||||
|
||||
function GetDefaultEditorState({
|
||||
root,
|
||||
eventInitDict
|
||||
}: IAppEventParams): void {
|
||||
}: IAppEventParams): WrappedCustomEvent {
|
||||
const configuration: IConfiguration = eventInitDict?.detail;
|
||||
const editorState = GetDefaultEditorStateAction(configuration);
|
||||
const customEvent = new CustomEvent<IEditorState>('getDefaultEditorState', { detail: editorState });
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent<IEditorState>('getDefaultEditorState', { detail: editorState });
|
||||
return {
|
||||
event,
|
||||
runAfterRender: false
|
||||
};
|
||||
}
|
||||
|
||||
function AddLanguage({
|
||||
root,
|
||||
eventInitDict
|
||||
}: IAppEventParams): void {
|
||||
}: IAppEventParams): WrappedCustomEvent {
|
||||
const language: ILanguage = eventInitDict?.detail.language;
|
||||
const option: string = eventInitDict?.detail.option;
|
||||
languageOptions[language.language] = option;
|
||||
translations[language.language] = language.dictionary;
|
||||
const customEvent = new CustomEvent('addLanguage');
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent('addLanguage');
|
||||
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function SetLanguage({
|
||||
root,
|
||||
languageContext,
|
||||
eventInitDict
|
||||
}: IAppEventParams): void {
|
||||
}: IAppEventParams): WrappedCustomEvent {
|
||||
const language: string = eventInitDict?.detail;
|
||||
let success = false;
|
||||
if (languageContext.languageChange !== undefined) {
|
||||
languageContext.languageChange(language);
|
||||
success = true;
|
||||
}
|
||||
const customEvent = new CustomEvent<boolean>('setLanguage', { detail: success });
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent<boolean>('setLanguage', { detail: success });
|
||||
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function GetLanguages({
|
||||
root
|
||||
}: IAppEventParams): void {
|
||||
function GetLanguages(): WrappedCustomEvent {
|
||||
const customEvent = new CustomEvent<Record<string, Record<string, string>>>('getLanguages', { detail: translations });
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event: customEvent,
|
||||
runAfterRender: false
|
||||
};
|
||||
}
|
||||
|
|
|
@ -15,16 +15,16 @@ import { type IEditorState } from '../Interfaces/IEditorState';
|
|||
import { type IHistoryState } from '../Interfaces/IHistoryState';
|
||||
import { FindContainerById } from '../utils/itertools';
|
||||
import { GetCircularReplacer } from '../utils/saveload';
|
||||
import { type WrappedCustomEvent } from './AppEvents';
|
||||
|
||||
interface IEditorEventParams {
|
||||
root: Element | Document
|
||||
editorState: IEditorState
|
||||
setNewHistory: (newHistory: IHistoryState[], historyCurrentStep?: number) => void
|
||||
eventInitDict?: CustomEventInit
|
||||
}
|
||||
export interface IEditorEvent {
|
||||
name: string
|
||||
func: (params: IEditorEventParams) => void
|
||||
func: (params: IEditorEventParams) => WrappedCustomEvent
|
||||
}
|
||||
|
||||
export const events: IEditorEvent[] = [
|
||||
|
@ -41,6 +41,7 @@ export const events: IEditorEvent[] = [
|
|||
];
|
||||
|
||||
export function UseCustomEvents(
|
||||
callbackQueue: React.RefObject<CustomEvent[]>,
|
||||
root: Element | Document,
|
||||
history: IHistoryState[],
|
||||
historyCurrentStep: number,
|
||||
|
@ -64,12 +65,17 @@ export function UseCustomEvents(
|
|||
|
||||
for (const event of events) {
|
||||
function Func(eventInitDict?: CustomEventInit): void {
|
||||
event.func({
|
||||
root,
|
||||
const customEvent = event.func({
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
});
|
||||
|
||||
if (customEvent.runAfterRender) {
|
||||
callbackQueue.current?.push(customEvent.event);
|
||||
} else {
|
||||
root.dispatchEvent(customEvent.event);
|
||||
}
|
||||
}
|
||||
current?.addEventListener(event.name, Func);
|
||||
funcs.set(event.name, Func);
|
||||
|
@ -84,6 +90,22 @@ export function UseCustomEvents(
|
|||
}
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (callbackQueue.current === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (callbackQueue.current.length > 0) {
|
||||
const callback = callbackQueue.current.shift();
|
||||
|
||||
if (callback === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
root.dispatchEvent(callback);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function UseEditorListener(
|
||||
|
@ -104,74 +126,83 @@ export function UseEditorListener(
|
|||
}
|
||||
|
||||
function GetEditorState({
|
||||
root,
|
||||
editorState
|
||||
}: IEditorEventParams): void {
|
||||
const customEvent = new CustomEvent<IEditorState>('getEditorState', { detail: structuredClone(editorState) });
|
||||
root.dispatchEvent(customEvent);
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const event = new CustomEvent<IEditorState>('getEditorState', { detail: structuredClone(editorState) });
|
||||
return {
|
||||
event,
|
||||
runAfterRender: false
|
||||
};
|
||||
}
|
||||
|
||||
function GetEditorStateAsString({
|
||||
root,
|
||||
editorState
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const spaces = import.meta.env.DEV
|
||||
? 4
|
||||
: 0;
|
||||
const data = JSON.stringify(editorState, GetCircularReplacer(), spaces);
|
||||
const customEvent = new CustomEvent<string>('getEditorStateAsString', { detail: data });
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent<string>('getEditorStateAsString', { detail: data });
|
||||
return {
|
||||
event,
|
||||
runAfterRender: false
|
||||
};
|
||||
}
|
||||
|
||||
function SetHistory({
|
||||
root,
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const history: IHistoryState[] = eventInitDict?.detail.history;
|
||||
const historyCurrentStep: number | undefined = eventInitDict?.detail.historyCurrentStep;
|
||||
setNewHistory(history, historyCurrentStep);
|
||||
const customEvent = new CustomEvent<IEditorState>('setHistory', { detail: editorState });
|
||||
root.dispatchEvent(customEvent);
|
||||
const event = new CustomEvent<IEditorState>('setHistory', { detail: editorState });
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function GetCurrentHistoryState({
|
||||
root,
|
||||
editorState
|
||||
}: IEditorEventParams): void {
|
||||
const customEvent = new CustomEvent<IHistoryState>(
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const event = new CustomEvent<IHistoryState>(
|
||||
'getCurrentHistoryState',
|
||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) }
|
||||
);
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function AppendNewState({
|
||||
root,
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const state: IHistoryState = eventInitDict?.detail.state;
|
||||
const history = GetCurrentHistory(editorState.history, editorState.historyCurrentStep);
|
||||
|
||||
history.push(state);
|
||||
setNewHistory(history);
|
||||
|
||||
const customEvent = new CustomEvent<IHistoryState>(
|
||||
const event = new CustomEvent<IHistoryState>(
|
||||
'appendNewState',
|
||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) }
|
||||
);
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function AddContainer({
|
||||
root,
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const {
|
||||
index,
|
||||
type,
|
||||
|
@ -189,19 +220,21 @@ function AddContainer({
|
|||
);
|
||||
setNewHistory(newHistory);
|
||||
|
||||
const customEvent = new CustomEvent<IHistoryState>(
|
||||
const event = new CustomEvent<IHistoryState>(
|
||||
'addContainer',
|
||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) }
|
||||
);
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function AppendContainer({
|
||||
root,
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const {
|
||||
type,
|
||||
parentId
|
||||
|
@ -222,19 +255,21 @@ function AppendContainer({
|
|||
);
|
||||
setNewHistory(newHistory);
|
||||
|
||||
const customEvent = new CustomEvent<IHistoryState>(
|
||||
const event = new CustomEvent<IHistoryState>(
|
||||
'appendContainerToSelectedContainer',
|
||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) }
|
||||
);
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function DeleteContainer({
|
||||
root,
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const {
|
||||
containerId
|
||||
} = eventInitDict?.detail;
|
||||
|
@ -248,19 +283,21 @@ function DeleteContainer({
|
|||
);
|
||||
setNewHistory(newHistory);
|
||||
|
||||
const customEvent = new CustomEvent<IHistoryState>(
|
||||
const event = new CustomEvent<IHistoryState>(
|
||||
'deleteContainer',
|
||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) }
|
||||
);
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function AddSymbol({
|
||||
root,
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const {
|
||||
name
|
||||
} = eventInitDict?.detail;
|
||||
|
@ -275,19 +312,21 @@ function AddSymbol({
|
|||
);
|
||||
setNewHistory(newHistory);
|
||||
|
||||
const customEvent = new CustomEvent<IHistoryState>(
|
||||
const event = new CustomEvent<IHistoryState>(
|
||||
'AddSymbol',
|
||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) }
|
||||
);
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
||||
function DeleteSymbol({
|
||||
root,
|
||||
editorState,
|
||||
setNewHistory,
|
||||
eventInitDict
|
||||
}: IEditorEventParams): void {
|
||||
}: IEditorEventParams): WrappedCustomEvent {
|
||||
const {
|
||||
symbolId
|
||||
} = eventInitDict?.detail;
|
||||
|
@ -300,9 +339,12 @@ function DeleteSymbol({
|
|||
);
|
||||
setNewHistory(newHistory);
|
||||
|
||||
const customEvent = new CustomEvent<IHistoryState>(
|
||||
const event = new CustomEvent<IHistoryState>(
|
||||
'DeleteSymbol',
|
||||
{ detail: structuredClone(editorState.history[editorState.historyCurrentStep]) }
|
||||
);
|
||||
root.dispatchEvent(customEvent);
|
||||
return {
|
||||
event,
|
||||
runAfterRender: true
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue