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

View File

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

View File

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

View File

@ -1,3 +1,13 @@
declare module '*.png'; declare module '*.png';
declare module '*.svg'; 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 ReactGA from 'react-ga';
import EditorPage from './components/editor-page'; import EditorPage from './components/editor-page';
import AppConfig from './classes/app-config'; import AppConfig from './classes/app-config';
import withSessionExpirationHandling from './components/HOCs/withSessionExpirationHandling'; import withSessionExpirationHandling from './components/hocs/withSessionExpirationHandling';
declare module '@mui/styles/defaultTheme' { declare module '@mui/styles/defaultTheme' {
@ -39,12 +39,7 @@ const queryClient = new QueryClient({
const App = (): ReactElement => { const App = (): ReactElement => {
const locale = AppI18n.getBrowserLocale(); const locale = AppI18n.getBrowserLocale();
const EnhacedEditorPage = withSessionExpirationHandling(EditorPage);
// global variables set server-side
const istTryMode = global.memoryPersistence;
const mapId = parseInt(global.mapId, 10);
const EditorPageComponent = withSessionExpirationHandling(EditorPage);
return locale.message ? ( return locale.message ? (
<Provider store={store}> <Provider store={store}>
@ -86,10 +81,10 @@ const App = (): ReactElement => {
component={withSessionExpirationHandling(MapsPage)} component={withSessionExpirationHandling(MapsPage)}
/> />
<Route exact path="/c/maps/:id/edit"> <Route exact path="/c/maps/:id/edit">
<EditorPageComponent isTryMode={istTryMode} mapId={mapId} /> <EnhacedEditorPage isTryMode={false} />
</Route> </Route>
<Route exact path="/c/maps/:id/try"> <Route exact path="/c/maps/:id/try">
<EditorPageComponent isTryMode={istTryMode} mapId={mapId} /> <EnhacedEditorPage isTryMode={true} />
</Route> </Route>
</Switch> </Switch>
</Router> </Router>

View File

@ -21,6 +21,11 @@ class _AppConfig {
recaptcha2SiteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI' recaptcha2SiteKey: '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI'
} }
isDevelopEnv(): boolean {
const config = this.getInstance();
return config.clientType === 'mock';
}
private getInstance(): Config { private getInstance(): Config {
// Config can be inserted in the html page to define the global properties ... // Config can be inserted in the html page to define the global properties ...
// eslint-disable-next-line @typescript-eslint/no-explicit-any // 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 Editor from '@wisemapping/editor';
import AppI18n from '../../classes/app-i18n'; import AppI18n from '../../classes/app-i18n';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { hotkeysEnabled } from '../../redux/editorSlice'; import { hotkeys } from '../../redux/editorSlice';
import ReactGA from 'react-ga'; import ReactGA from 'react-ga';
import Client from '../../classes/client'; import Client from '../../classes/client';
import { activeInstance } from '../../redux/clientSlice'; import { activeInstance } from '../../redux/clientSlice';
import { PersistenceManager } from '@wisemapping/mindplot'; import { PersistenceManager } from '@wisemapping/mindplot';
import EditorOptionsBulder from './EditorOptiosBuider';
export type EditorPropsType = { export type EditorPropsType = {
mapId: number;
isTryMode: boolean; isTryMode: boolean;
}; };
const EditorPage = ({ mapId, ...props }: EditorPropsType): React.ReactElement => { const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => {
const [activeDialog, setActiveDialog] = React.useState<ActionType | null>(null); const [activeDialog, setActiveDialog] = React.useState<ActionType | null>(null);
const hotkeys = useSelector(hotkeysEnabled); const hotkeysEnabled = useSelector(hotkeys);
const userLocale = AppI18n.getUserLocale(); const userLocale = AppI18n.getUserLocale();
const client: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const [persistenceManager, setPersistenceManager] = React.useState<PersistenceManager>(); const [persistenceManager, setPersistenceManager] = React.useState<PersistenceManager>();
@ -29,25 +29,26 @@ const EditorPage = ({ mapId, ...props }: EditorPropsType): React.ReactElement =>
return () => client.removePersistenceManager(); return () => client.removePersistenceManager();
}, []); }, []);
if (!persistenceManager) { // As temporal hack, editor properties are propagated from global variables...
// persistenceManager must be ready for the editor to work const { mapId, options } = EditorOptionsBulder.build(userLocale.code, hotkeysEnabled, isTryMode);
return null; return persistenceManager ? (
} <>
return <> <Editor onAction={setActiveDialog}
<Editor {...props} onAction={setActiveDialog} options={options}
locale={userLocale.code} hotkeys={hotkeys} persistenceManager={persistenceManager}
persistenceManager={persistenceManager} /> mapId={mapId} />
{ {
activeDialog && activeDialog &&
<ActionDispatcher <ActionDispatcher
action={activeDialog} action={activeDialog}
onClose={() => setActiveDialog(null)} onClose={() => setActiveDialog(null)}
mapsId={[mapId]} mapsId={[mapId]}
fromEditor fromEditor
/> />
} }
</> </>) : <></>
} }
export default EditorPage; 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; return state.editor.hotkeysEnabled;
}; };