Clean up editor global variables.

This commit is contained in:
Paulo Gustavo Veiga 2022-02-21 21:37:00 -08:00
parent 591c9470e7
commit eb4e6e3e71
14 changed files with 248 additions and 185 deletions

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import Toolbar, { ToolbarActionType } from './components/toolbar';
import Footer from './components/footer';
import { IntlProvider } from 'react-intl';
@ -15,35 +15,31 @@ import ES from './compiled-lang/es.json';
import EN from './compiled-lang/en.json';
import DE from './compiled-lang/de.json';
import './global-styled.css';
import { EditorModeType } from '@wisemapping/mindplot/src/components/DesignerOptionsBuilder';
declare global {
var memoryPersistence: boolean;
var readOnly: boolean;
var lockTimestamp: string;
var lockSession: string;
var historyId: string;
var isAuth: boolean;
var mapId: number;
var userOptions: { zoom: string | number } | null;
var locale: string;
var mindmapLocked: boolean;
var mindmapLockedMsg: string;
var mapTitle: string;
// used in mindplot
var designer: Designer;
var accountEmail: string;
}
export type EditorPropsType = {
initCallback?: (locale: string, persistenceManager: PersistenceManager) => void;
mapId?: number;
isTryMode: boolean;
readOnlyMode: boolean;
locale?: string;
export type EditorOptions = {
mode: EditorModeType,
locale: string,
zoom?: number,
locked?: boolean,
lockedMsg?: string;
mapTitle: string;
enableKeyboardEvents: boolean;
}
export type EditorProps = {
mapId: string;
options: EditorOptions;
onAction: (action: ToolbarActionType) => void;
hotkeys?: boolean;
persistenceManager: PersistenceManager;
initCallback?: (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => void;
};
const loadLocaleData = (locale: string) => {
@ -61,68 +57,60 @@ const loadLocaleData = (locale: string) => {
}
}
const initMindplot = (locale: string, persistenceManager: PersistenceManager) => {
const defaultCallback = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => {
// Change page title ...
document.title = `${global.mapTitle} | WiseMapping `;
document.title = `${options.mapTitle} | WiseMapping `;
const params = new URLSearchParams(window.location.search.substring(1));
const zoomParam = Number.parseFloat(params.get('zoom'));
const options = DesignerOptionsBuilder.buildOptions({
const buildOptions = DesignerOptionsBuilder.buildOptions({
persistenceManager,
readOnly: Boolean(global.readOnly || false),
mapId: String(global.mapId),
mode: options.mode,
mapId: mapId,
container: 'mindplot',
zoom:
zoomParam ||
(global.userOptions?.zoom != undefined
? Number.parseFloat(global.userOptions.zoom as string)
: 0.8),
locale: locale,
zoom: options.zoom,
locale: options.locale,
});
// Build designer ...
const designer = buildDesigner(options);
const designer = buildDesigner(buildOptions);
// Load map from XML file persisted on disk...
const instance = PersistenceManager.getInstance();
const mindmap = instance.load(String(global.mapId));
const mindmap = instance.load(mapId);
designer.loadMap(mindmap);
if (global.mindmapLocked) {
$notify(global.mindmapLockedMsg);
if (options.locked) {
$notify(options.lockedMsg);
}
};
const Editor = ({
initCallback = initMindplot,
mapId,
isTryMode: isTryMode,
locale = 'en',
onAction,
hotkeys = true,
options,
persistenceManager,
}: EditorPropsType): React.ReactElement => {
React.useEffect(() => {
initCallback(locale, persistenceManager);
initCallback = defaultCallback,
onAction,
}: EditorProps) => {
useEffect(() => {
initCallback(mapId, options, persistenceManager);
}, []);
React.useEffect(() => {
if (hotkeys) {
useEffect(() => {
if (options.enableKeyboardEvents) {
console.log("options.enableKeyboardEvents"+options.enableKeyboardEvents)
DesignerKeyboard.resume();
} else {
DesignerKeyboard.pause();
}
}, [hotkeys]);
}, [options.enableKeyboardEvents]);
return (
<IntlProvider locale={locale} messages={loadLocaleData(locale)}>
<IntlProvider locale={options.locale} messages={loadLocaleData(options.locale)}>
<Toolbar
isTryMode={isTryMode}
isTryMode={options.mode === 'showcase'}
onAction={onAction}
/>
<div id="mindplot"></div>
<Footer showTryPanel={isTryMode} />
<Footer showTryPanel={options.mode === 'showcase'} />
</IntlProvider>
);
}

View File

@ -1,43 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Editor from '../../../../src/index';
import { buildDesigner, LocalStorageManager, PersistenceManager, DesignerOptionsBuilder } from '@wisemapping/mindplot';
global.accountName = 'Test User';
global.accountEmail = 'test@example.com';
global.memoryPersistence = false;
global.readOnly = false;
global.mapId = 'welcome';
global.locale = 'en';
const initialization = () => {
const p = new LocalStorageManager('samples/{id}.wxml');
const options = DesignerOptionsBuilder.buildOptions({
persistenceManager: p
});
const designer = buildDesigner(options);
designer.addEvent('loadSuccess', () => {
// Hack for automation testing ...
document.getElementById('mindplot').classList.add('ready');
});
// Load map from XML file persisted on disk...
const mapId = 'welcome';
const persistence = PersistenceManager.getInstance();
const mindmap = persistence.load(mapId);
designer.loadMap(mindmap);
}
ReactDOM.render(
<Editor
mapId={global.mapId}
memoryPersistence={global.memoryPersistence}
readOnlyMode={global.readOnly}
locale={global.locale}
onAction={(action) => console.log('action called:', action)}
initCallback={initialization}
/>,
document.getElementById('root'),
);

View File

@ -0,0 +1,49 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Editor, { EditorOptions } from '../../../../src/index';
import { buildDesigner, LocalStorageManager, PersistenceManager, DesignerOptionsBuilder } from '@wisemapping/mindplot';
const initialization = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => {
const designerOptions = DesignerOptionsBuilder.buildOptions({
persistenceManager: persistenceManager,
zoom: options.zoom ? options.zoom : 0.8,
mode: options.mode,
container: 'mindplot'
});
const designer = buildDesigner(designerOptions);
designer.addEvent('loadSuccess', () => {
const elem = document.getElementById('mindplot');
if (elem) {
elem.classList.add('ready');
}
});
// Load map from XML file persisted on disk...
const persistence = PersistenceManager.getInstance();
const mindmap = persistence.load(mapId);
designer.loadMap(mindmap);
};
const persistence = new LocalStorageManager('samples/{id}.wxml', false);
const mapId = 'welcome';
const options: EditorOptions = {
zoom: 0.8,
locked: false,
mapTitle: "Develop Mindnap",
mode: 'edition',
locale: 'en',
enableKeyboardEvents: true
};
ReactDOM.render(
<Editor
mapId={mapId}
options={options}
persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)}
initCallback={initialization}
/>,
document.getElementById('root'),
);

View File

@ -1,49 +0,0 @@
import '../css/viewmode.css';
import React from 'react';
import ReactDOM from 'react-dom';
import Editor from '../../../../src/index';
import { buildDesigner, LocalStorageManager, PersistenceManager, DesignerOptionsBuilder } from '@wisemapping/mindplot';
const initialization = () => {
const p = new LocalStorageManager('samples/{id}.wxml');
const options = DesignerOptionsBuilder.buildOptions({ persistenceManager: p, readOnly: true, saveOnLoad: false });
// Obtain map id from query param
const params = new URLSearchParams(window.location.search.substring(1));
const mapId = params.get('id') || 'welcome';
const designer = buildDesigner(options);
designer.addEvent('loadSuccess', () => {
document.getElementById('mindplot').classList.add('ready');
});
// Load map from XML file persisted on disk...
const persistence = PersistenceManager.getInstance();
const mindmap = persistence.load(mapId);
designer.loadMap(mindmap);
// Code for selector of map.
const mapSelectElem = document.getElementById('map-select');
mapSelectElem.addEventListener('change', (e) => {
const selectMap = e.target.value;
window.location = `${window.location.pathname}?id=${selectMap}`;
});
Array.from(mapSelectElem.options).forEach((option) => {
option.selected = option.value === mapId;
});
};
ReactDOM.render(
<Editor
mapId={global.mapId}
memoryPersistence={global.memoryPersistence}
readOnlyMode={global.readOnly}
locale={global.locale}
onAction={(action) => console.log('action called:', action)}
initCallback={initialization}
/>,
document.getElementById('root'),
);

View File

@ -0,0 +1,67 @@
import '../css/viewmode.css';
import React from 'react';
import ReactDOM from 'react-dom';
import Editor, { EditorOptions } from '../../../../src/index';
import { buildDesigner, LocalStorageManager, PersistenceManager, DesignerOptionsBuilder } from '@wisemapping/mindplot';
const initialization = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => {
const designerOptions = DesignerOptionsBuilder.buildOptions({
persistenceManager: persistenceManager,
zoom: options.zoom ? options.zoom : 0.8,
mode: options.mode,
container: 'mindplot'
});
const designer = buildDesigner(designerOptions);
designer.addEvent('loadSuccess', () => {
const elem = document.getElementById('mindplot');
if (elem) {
elem.classList.add('ready');
}
// Code for selector of map.
const mapSelectElem = document.getElementById('map-select') as HTMLSelectElement;
if (mapSelectElem) {
mapSelectElem.addEventListener('change', (e) => {
// @ts-ignore
const selectMap = e.target?.value;
window.location.href = `${window.location.pathname}?id=${selectMap}`;
});
Array.from(mapSelectElem.options).forEach((option) => {
option.selected = option.value === mapId;
});
}
});
// Load map from XML file persisted on disk...
const persistence = PersistenceManager.getInstance();
const mindmap = persistence.load(mapId);
designer.loadMap(mindmap);
};
// Obtain map id from query param
const params = new URLSearchParams(window.location.search.substring(1));
const mapId = params.get('id') || 'welcome';
const persistence = new LocalStorageManager('samples/{id}.wxml', false);
const options: EditorOptions = {
zoom: 0.8,
locked: false,
mapTitle: "Develop Mindnap",
mode: 'viewonly',
locale: 'en',
enableKeyboardEvents: true
};
ReactDOM.render(
<Editor
mapId={mapId}
options={options}
persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)}
initCallback={initialization}
/>,
document.getElementById('root'),
);

View File

@ -110,7 +110,7 @@ class Designer extends Events {
// Init Screen manager..
const screenManager = new ScreenManager(divElement);
this._workspace = new Workspace(screenManager, this._model.getZoom(), !!options.readOnly);
this._workspace = new Workspace(screenManager, this._model.getZoom(), options.mode === 'viewonly');
// Init layout manager ...
this._eventBussDispatcher = new EventBusDispatcher();
@ -626,7 +626,7 @@ class Designer extends Events {
}
isReadOnly(): boolean {
return Boolean(this._options?.readOnly);
return Boolean(this._options?.mode === 'viewonly');
}
nodeModelToTopic(nodeModel: NodeModel): Topic {

View File

@ -19,10 +19,12 @@ import { $assert } from '@wisemapping/core-js';
import PersistenceManager from './PersistenceManager';
import SizeType from './SizeType';
export type EditorModeType = 'viewonly' | 'edition' | 'showcase';
export type DesignerOptions = {
zoom: number,
containerSize?: SizeType,
readOnly?: boolean,
mode: EditorModeType,
mapId?: string,
container: string,
persistenceManager?: PersistenceManager,
@ -45,7 +47,7 @@ class OptionsBuilder {
}
const defaultOptions: DesignerOptions = {
readOnly: false,
mode: 'edition',
zoom: 0.85,
saveOnLoad: true,
containerSize,

View File

@ -57,7 +57,7 @@ const zoomParam = Number.parseFloat(params.get('zoom'));
const options = DesignerOptionsBuilder.buildOptions(
{
persistenceManager: persistence,
readOnly: Boolean(global.readOnly || false),
mode: 'viewonly',
mapId: global.mapId,
container: 'mindplot',
zoom: zoomParam || global.userOptions.zoom,

View File

@ -1,3 +1,13 @@
declare module '*.png';
declare module '*.svg';
declare module '*.wxml';
declare module '*.wxml';
declare global {
const lockTimestamp: string;
const lockSession: string;
const isAuth: boolean;
const mapId: number;
const userOptions: { zoom: string | number } | null;
const mindmapLocked: boolean;
const mindmapLockedMsg: string;
const mapTitle: string;
}

View File

@ -17,7 +17,7 @@ import { ThemeProvider, Theme, StyledEngineProvider } from '@mui/material/styles
import ReactGA from 'react-ga';
import EditorPage from './components/editor-page';
import AppConfig from './classes/app-config';
import withSessionExpirationHandling from './components/HOCs/withSessionExpirationHandling';
import withSessionExpirationHandling from './components/hocs/withSessionExpirationHandling';
declare module '@mui/styles/defaultTheme' {
@ -39,12 +39,7 @@ const queryClient = new QueryClient({
const App = (): ReactElement => {
const locale = AppI18n.getBrowserLocale();
// global variables set server-side
const istTryMode = global.memoryPersistence;
const mapId = parseInt(global.mapId, 10);
const EditorPageComponent = withSessionExpirationHandling(EditorPage);
const EnhacedEditorPage = withSessionExpirationHandling(EditorPage);
return locale.message ? (
<Provider store={store}>
@ -63,7 +58,7 @@ const App = (): ReactElement => {
<Redirect to="/c/login" />
</Route>
<Route path="/c/login"
component={LoginPage}
component={LoginPage}
/>
<Route
path="/c/registration"
@ -86,10 +81,10 @@ const App = (): ReactElement => {
component={withSessionExpirationHandling(MapsPage)}
/>
<Route exact path="/c/maps/:id/edit">
<EditorPageComponent isTryMode={istTryMode} mapId={mapId} />
<EnhacedEditorPage isTryMode={false} />
</Route>
<Route exact path="/c/maps/:id/try">
<EditorPageComponent isTryMode={istTryMode} mapId={mapId} />
<EnhacedEditorPage isTryMode={true} />
</Route>
</Switch>
</Router>

View File

@ -21,6 +21,11 @@ class _AppConfig {
recaptcha2SiteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
}
isDevelopEnv(): boolean {
const config = this.getInstance();
return config.clientType === 'mock';
}
private getInstance(): Config {
// Config can be inserted in the html page to define the global properties ...
// eslint-disable-next-line @typescript-eslint/no-explicit-any

View File

@ -0,0 +1,38 @@
import EditorOptions from '@wisemapping/editor';
import AppConfig from '../../classes/app-config';
export default class EditorOptionsBulder {
static build(locale: string, hotkeys: boolean, isTryMode: boolean): { options: EditorOptions, mapId: number } {
let options: EditorOptions = {
editorKeyboardEnabled: hotkeys,
locale: locale,
mode: isTryMode ? 'showcase' : 'editor',
};
let mapId: number;
if (!AppConfig.isDevelopEnv()) {
options = {
zoom: (global.userOptions?.zoom != undefined
? Number.parseFloat(global?.userOptions?.zoom as string)
: 0.8),
locked: global.mindmapLocked,
lockedMsg: global.mindmapLockedMsg,
mapTitle: global.mapTitle,
...options
}
mapId = global.mapId;
} else {
// Running in a development mode.
console.log('Running editor in development mode');
options = {
zoom: 0.8,
locked: false,
mapTitle: "Develop Mindnap",
...options
}
mapId = 666;
}
return { options, mapId };
}
}

View File

@ -4,20 +4,20 @@ import { ActionType } from '../maps-page/action-chooser';
import Editor from '@wisemapping/editor';
import AppI18n from '../../classes/app-i18n';
import { useSelector } from 'react-redux';
import { hotkeysEnabled } from '../../redux/editorSlice';
import { hotkeys } from '../../redux/editorSlice';
import ReactGA from 'react-ga';
import Client from '../../classes/client';
import { activeInstance } from '../../redux/clientSlice';
import { PersistenceManager } from '@wisemapping/mindplot';
import EditorOptionsBulder from './EditorOptiosBuider';
export type EditorPropsType = {
mapId: number;
isTryMode: boolean;
};
const EditorPage = ({ mapId, ...props }: EditorPropsType): React.ReactElement => {
const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => {
const [activeDialog, setActiveDialog] = React.useState<ActionType | null>(null);
const hotkeys = useSelector(hotkeysEnabled);
const hotkeysEnabled = useSelector(hotkeys);
const userLocale = AppI18n.getUserLocale();
const client: Client = useSelector(activeInstance);
const [persistenceManager, setPersistenceManager] = React.useState<PersistenceManager>();
@ -28,26 +28,27 @@ const EditorPage = ({ mapId, ...props }: EditorPropsType): React.ReactElement =>
setPersistenceManager(persistence);
return () => client.removePersistenceManager();
}, []);
if (!persistenceManager) {
// persistenceManager must be ready for the editor to work
return null;
}
return <>
<Editor {...props} onAction={setActiveDialog}
locale={userLocale.code} hotkeys={hotkeys}
persistenceManager={persistenceManager} />
{
activeDialog &&
<ActionDispatcher
action={activeDialog}
onClose={() => setActiveDialog(null)}
mapsId={[mapId]}
fromEditor
/>
}
</>
// As temporal hack, editor properties are propagated from global variables...
const { mapId, options } = EditorOptionsBulder.build(userLocale.code, hotkeysEnabled, isTryMode);
return persistenceManager ? (
<>
<Editor onAction={setActiveDialog}
options={options}
persistenceManager={persistenceManager}
mapId={mapId} />
{
activeDialog &&
<ActionDispatcher
action={activeDialog}
onClose={() => setActiveDialog(null)}
mapsId={[mapId]}
fromEditor
/>
}
</>) : <></>
}
export default EditorPage;

View File

@ -22,7 +22,7 @@ export const editorSlice = createSlice({
},
});
export const hotkeysEnabled = (state: RootState): boolean => {
export const hotkeys = (state: RootState): boolean => {
return state.editor.hotkeysEnabled;
};