From d05d0fb19692e743154801d09c11884bbd4532bd Mon Sep 17 00:00:00 2001 From: Eric NGUYEN Date: Mon, 17 Oct 2022 19:17:46 +0200 Subject: [PATCH] Refactor App and Editor events --- src/Components/App/App.tsx | 34 +--- .../Editor/Actions/ContextMenuActions.ts | 112 +++++++++++- src/Components/Editor/Editor.tsx | 172 +----------------- src/Events/AppEvents.ts | 33 ++++ src/Events/EditorEvents.ts | 61 ++++++- 5 files changed, 209 insertions(+), 203 deletions(-) diff --git a/src/Components/App/App.tsx b/src/Components/App/App.tsx index 8e493b4..88eb9ee 100644 --- a/src/Components/App/App.tsx +++ b/src/Components/App/App.tsx @@ -1,5 +1,5 @@ import React, { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react'; -import { events as EVENTS } from '../../Events/AppEvents'; +import { events as EVENTS, UseCustomEvents } from '../../Events/AppEvents'; import { MainMenu } from '../MainMenu/MainMenu'; import { ContainerModel, IContainerModel } from '../../Interfaces/IContainerModel'; import { Editor } from '../Editor/Editor'; @@ -41,38 +41,6 @@ function UseHTTPGETStatePreloading( }); }; -function UseCustomEvents( - root: Element | Document, - appRef: React.RefObject, - setEditor: (newState: IEditorState) => void, - setLoaded: (loaded: boolean) => void -): void { - useEffect(() => { - const funcs = new Map void>(); - for (const event of EVENTS) { - function Func(eventInitDict?: CustomEventInit): void { - return event.func( - root, - setEditor, - setLoaded, - eventInitDict - ); - } - appRef.current?.addEventListener(event.name, Func); - funcs.set(event.name, Func); - } - return () => { - for (const event of EVENTS) { - const func = funcs.get(event.name); - if (func === undefined) { - continue; - } - appRef.current?.removeEventListener(event.name, func); - } - }; - }); -} - export function App(props: IAppProps): JSX.Element { const [isLoaded, setLoaded] = useState(false); const appRef = useRef(null); diff --git a/src/Components/Editor/Actions/ContextMenuActions.ts b/src/Components/Editor/Actions/ContextMenuActions.ts index 21c8ac0..7135bf2 100644 --- a/src/Components/Editor/Actions/ContextMenuActions.ts +++ b/src/Components/Editor/Actions/ContextMenuActions.ts @@ -1,4 +1,5 @@ import Swal from 'sweetalert2'; +import { Dispatch, SetStateAction } from 'react'; import { AddMethod } from '../../../Enums/AddMethod'; import { IAction } from '../../../Interfaces/IAction'; import { IConfiguration } from '../../../Interfaces/IConfiguration'; @@ -6,13 +7,122 @@ import { IContainerModel } from '../../../Interfaces/IContainerModel'; import { IHistoryState } from '../../../Interfaces/IHistoryState'; import { ISetContainerListRequest } from '../../../Interfaces/ISetContainerListRequest'; import { ISetContainerListResponse } from '../../../Interfaces/ISetContainerListResponse'; +import { DISABLE_API } from '../../../utils/default'; import { FindContainerById } from '../../../utils/itertools'; import { SetContainerList } from '../../API/api'; +import { IMenuAction } from '../../Menu/Menu'; import { GetCurrentHistoryState } from '../Editor'; import { AddContainers } from './AddContainer'; import { DeleteContainer } from './ContainerOperations'; +import { DeleteSymbol } from './SymbolOperations'; -export function GetAction( +export function InitActions( + menuActions: Map, + configuration: IConfiguration, + history: IHistoryState[], + historyCurrentStep: number, + setNewHistory: (newHistory: IHistoryState[]) => void, + setHistoryCurrentStep: Dispatch> +): void { + menuActions.set( + '', + [ + { + text: 'Undo', + title: 'Undo last action', + shortcut: 'Ctrl+Z', + action: () => { + if (historyCurrentStep <= 0) { + return; + } + setHistoryCurrentStep(historyCurrentStep - 1); + } + }, + { + text: 'Redo', + title: 'Redo last action', + shortcut: 'Ctrl+Y', + action: () => { + if (historyCurrentStep >= history.length - 1) { + return; + } + setHistoryCurrentStep(historyCurrentStep + 1); + } + } + ] + ); + + menuActions.set( + 'elements-sidebar-row', + [{ + text: 'Delete', + title: 'Delete the container', + shortcut: 'Suppr', + action: (target: HTMLElement) => { + const id = target.id; + const newHistory = DeleteContainer( + id, + history, + historyCurrentStep + ); + setNewHistory(newHistory); + } + }] + ); + + menuActions.set( + 'symbols-sidebar-row', + [{ + text: 'Delete', + title: 'Delete the container', + shortcut: 'Suppr', + action: (target: HTMLElement) => { + const id = target.id; + const newHistory = DeleteSymbol( + id, + history, + historyCurrentStep + ); + setNewHistory(newHistory); + } + }] + ); + + // API Actions + if (DISABLE_API) { + return; + } + + for (const availableContainer of configuration.AvailableContainers) { + if (availableContainer.Actions === undefined || availableContainer.Actions === null) { + continue; + } + + for (const action of availableContainer.Actions) { + if (menuActions.get(availableContainer.Type) === undefined) { + menuActions.set(availableContainer.Type, []); + } + + const currentState = GetCurrentHistoryState(history, historyCurrentStep); + const newAction: IMenuAction = { + text: action.Label, + title: action.Description, + action: GetAction( + action, + currentState, + configuration, + history, + historyCurrentStep, + setNewHistory + ) + }; + + menuActions.get(availableContainer.Type)?.push(newAction); + } + } +} + +function GetAction( action: IAction, currentState: IHistoryState, configuration: IConfiguration, diff --git a/src/Components/Editor/Editor.tsx b/src/Components/Editor/Editor.tsx index 5309f8f..7707608 100644 --- a/src/Components/Editor/Editor.tsx +++ b/src/Components/Editor/Editor.tsx @@ -6,13 +6,12 @@ import { UI } from '../UI/UI'; import { SelectContainer, DeleteContainer, OnPropertyChange } from './Actions/ContainerOperations'; import { SaveEditorAsJSON, SaveEditorAsSVG } from './Actions/Save'; import { OnKey } from './Actions/Shortcuts'; -import { events as EVENTS } from '../../Events/EditorEvents'; -import { IEditorState } from '../../Interfaces/IEditorState'; -import { DISABLE_API, MAX_HISTORY } from '../../utils/default'; +import { UseCustomEvents, UseEditorListener } from '../../Events/EditorEvents'; +import { MAX_HISTORY } from '../../utils/default'; import { AddSymbol, OnPropertyChange as OnSymbolPropertyChange, DeleteSymbol, SelectSymbol } from './Actions/SymbolOperations'; import { FindContainerById } from '../../utils/itertools'; -import { IMenuAction, Menu } from '../Menu/Menu'; -import { GetAction } from './Actions/ContextMenuActions'; +import { Menu } from '../Menu/Menu'; +import { InitActions } from './Actions/ContextMenuActions'; import { AddContainerToSelectedContainer, AddContainer } from './Actions/AddContainer'; interface IEditorProps { @@ -22,112 +21,6 @@ interface IEditorProps { historyCurrentStep: number } -function InitActions( - menuActions: Map, - configuration: IConfiguration, - history: IHistoryState[], - historyCurrentStep: number, - setNewHistory: (newHistory: IHistoryState[]) => void, - setHistoryCurrentStep: Dispatch> -): void { - menuActions.set( - '', - [ - { - text: 'Undo', - title: 'Undo last action', - shortcut: 'Ctrl+Z', - action: () => { - if (historyCurrentStep <= 0) { - return; - } - setHistoryCurrentStep(historyCurrentStep - 1); - } - }, - { - text: 'Redo', - title: 'Redo last action', - shortcut: 'Ctrl+Y', - action: () => { - if (historyCurrentStep >= history.length - 1) { - return; - } - setHistoryCurrentStep(historyCurrentStep + 1); - } - } - ] - ); - - menuActions.set( - 'elements-sidebar-row', - [{ - text: 'Delete', - title: 'Delete the container', - shortcut: 'Suppr', - action: (target: HTMLElement) => { - const id = target.id; - const newHistory = DeleteContainer( - id, - history, - historyCurrentStep - ); - setNewHistory(newHistory); - } - }] - ); - - menuActions.set( - 'symbols-sidebar-row', - [{ - text: 'Delete', - title: 'Delete the container', - shortcut: 'Suppr', - action: (target: HTMLElement) => { - const id = target.id; - const newHistory = DeleteSymbol( - id, - history, - historyCurrentStep - ); - setNewHistory(newHistory); - } - }] - ); - - // API Actions - if (DISABLE_API) { - return; - } - - for (const availableContainer of configuration.AvailableContainers) { - if (availableContainer.Actions === undefined || availableContainer.Actions === null) { - continue; - } - - for (const action of availableContainer.Actions) { - if (menuActions.get(availableContainer.Type) === undefined) { - menuActions.set(availableContainer.Type, []); - } - - const currentState = GetCurrentHistoryState(history, historyCurrentStep); - const newAction: IMenuAction = { - text: action.Label, - title: action.Description, - action: GetAction( - action, - currentState, - configuration, - history, - historyCurrentStep, - setNewHistory - ) - }; - - menuActions.get(availableContainer.Type)?.push(newAction); - } - } -} - function UseShortcuts( history: IHistoryState[], historyCurrentStep: number, @@ -152,63 +45,6 @@ function UseShortcuts( }); } -function UseCustomEvents( - root: Element | Document, - history: IHistoryState[], - historyCurrentStep: number, - configuration: IConfiguration, - editorRef: React.RefObject, - setNewHistory: (newHistory: IHistoryState[], historyCurrentStep?: number) => void -): void { - useEffect(() => { - const editorState: IEditorState = { - history, - historyCurrentStep, - configuration - }; - - const funcs = new Map void>(); - for (const event of EVENTS) { - function Func(eventInitDict?: CustomEventInit): void { - return event.func( - root, - editorState, - setNewHistory, - eventInitDict - ); - } - editorRef.current?.addEventListener(event.name, Func); - funcs.set(event.name, Func); - } - return () => { - for (const event of EVENTS) { - const func = funcs.get(event.name); - if (func === undefined) { - continue; - } - editorRef.current?.removeEventListener(event.name, func); - } - }; - }); -} - -function UseEditorListener( - root: Element | Document, - history: IHistoryState[], - historyCurrentStep: number, - configuration: IConfiguration -): void { - useEffect(() => { - const editorState: IEditorState = { - history, - historyCurrentStep, - configuration - }; - const event = new CustomEvent('editorListener', { detail: editorState }); - root.dispatchEvent(event); - }); -} - /** * Return a macro function to use both setHistory * and setHistoryCurrentStep at the same time diff --git a/src/Events/AppEvents.ts b/src/Events/AppEvents.ts index 3aabbee..6ba07ad 100644 --- a/src/Events/AppEvents.ts +++ b/src/Events/AppEvents.ts @@ -1,3 +1,4 @@ +import { useEffect } from 'react'; import { IConfiguration } from '../Interfaces/IConfiguration'; import { IEditorState } from '../Interfaces/IEditorState'; import { IHistoryState } from '../Interfaces/IHistoryState'; @@ -22,6 +23,38 @@ export const events: IAppEvent[] = [ { name: 'getDefaultEditorState', func: GetDefaultEditorState } ]; +export function UseCustomEvents( + root: Element | Document, + appRef: React.RefObject, + setEditor: (newState: IEditorState) => void, + setLoaded: (loaded: boolean) => void +): void { + useEffect(() => { + const funcs = new Map void>(); + for (const event of events) { + function Func(eventInitDict?: CustomEventInit): void { + return event.func( + root, + setEditor, + setLoaded, + eventInitDict + ); + } + appRef.current?.addEventListener(event.name, Func); + funcs.set(event.name, Func); + } + return () => { + for (const event of events) { + const func = funcs.get(event.name); + if (func === undefined) { + continue; + } + appRef.current?.removeEventListener(event.name, func); + } + }; + }); +} + function SetEditor( root: Element | Document, setEditor: (newState: IEditorState) => void, diff --git a/src/Events/EditorEvents.ts b/src/Events/EditorEvents.ts index c572bda..5cb644a 100644 --- a/src/Events/EditorEvents.ts +++ b/src/Events/EditorEvents.ts @@ -1,11 +1,13 @@ +import { useEffect } from 'react'; import { AddContainer as AddContainerAction, AddContainerToSelectedContainer as AddContainerToSelectedContainerAction } from '../Components/Editor/Actions/AddContainer'; import { DeleteContainer as DeleteContainerAction, SelectContainer as SelectContainerAction } from '../Components/Editor/Actions/ContainerOperations'; import { AddSymbol as AddSymbolAction, DeleteSymbol as DeleteSymbolAction, SelectSymbol as SelectSymbolAction } from '../Components/Editor/Actions/SymbolOperations'; import { GetCurrentHistory } from '../Components/Editor/Editor'; +import { IConfiguration } from '../Interfaces/IConfiguration'; import { IEditorState } from '../Interfaces/IEditorState'; import { IHistoryState } from '../Interfaces/IHistoryState'; import { FindContainerById } from '../utils/itertools'; -import { GetCircularReplacer, ReviveHistory as ReviveHistoryAction } from '../utils/saveload'; +import { GetCircularReplacer } from '../utils/saveload'; export interface IEditorEvent { name: string @@ -34,6 +36,63 @@ export const events: IEditorEvent[] = [ { name: 'deleteSymbol', func: DeleteSymbol } ]; +export function UseCustomEvents( + root: Element | Document, + history: IHistoryState[], + historyCurrentStep: number, + configuration: IConfiguration, + editorRef: React.RefObject, + setNewHistory: (newHistory: IHistoryState[], historyCurrentStep?: number) => void +): void { + useEffect(() => { + const editorState: IEditorState = { + history, + historyCurrentStep, + configuration + }; + + const funcs = new Map void>(); + for (const event of events) { + function Func(eventInitDict?: CustomEventInit): void { + return event.func( + root, + editorState, + setNewHistory, + eventInitDict + ); + } + editorRef.current?.addEventListener(event.name, Func); + funcs.set(event.name, Func); + } + return () => { + for (const event of events) { + const func = funcs.get(event.name); + if (func === undefined) { + continue; + } + editorRef.current?.removeEventListener(event.name, func); + } + }; + }); +} + +export function UseEditorListener( + root: Element | Document, + history: IHistoryState[], + historyCurrentStep: number, + configuration: IConfiguration +): void { + useEffect(() => { + const editorState: IEditorState = { + history, + historyCurrentStep, + configuration + }; + const event = new CustomEvent('editorListener', { detail: editorState }); + root.dispatchEvent(event); + }); +} + function GetEditorState(root: Element | Document, editorState: IEditorState): void { const customEvent = new CustomEvent('getEditorState', { detail: structuredClone(editorState) });