Merged in editor-actions-by-mode (pull request #63)

Editor actions by mode

* Toolbar configuration for all EditorRenderMode and locked maps

* fix unlock
This commit is contained in:
Gonzalo Martinez 2022-10-07 01:58:24 +00:00 committed by Paulo Veiga
parent f3a11f2eb1
commit c6f04742d8
7 changed files with 218 additions and 113 deletions

View File

@ -105,6 +105,7 @@ export const ToolbarSubmenu = (props: {
>
<div style={{ display: 'flex' }} onScroll={(e) => e.stopPropagation()}>
{props.configuration.options?.map((o, i) => {
if (o?.visible === false) return null;
if (!o?.render) {
return (
<ToolbarMenuItem

View File

@ -38,7 +38,7 @@ export interface ToolbarOptionConfiguration {
*/
useClickToClose?: boolean;
/**
* if false the nmenu entry or button is not visible. Entries with custom render will ignore this property
* if false the nmenu entry or button is not visible. Also custom render will be ignored.
*/
visible?: boolean;
}

View File

@ -33,7 +33,7 @@ import Box from '@mui/material/Box';
import LogoTextBlackSvg from '../../../images/logo-text-black.svg';
import Palette from '@mui/icons-material/Square';
import SquareOutlined from '@mui/icons-material/SquareOutlined';
import { $msg, Designer, EditorRenderMode } from '@wisemapping/mindplot';
import { $msg, Designer } from '@wisemapping/mindplot';
import { ToolbarOptionConfiguration } from './ToolbarOptionConfigurationInterface';
import { SwitchValueDirection, NodePropertyValueModelBuilder } from './ToolbarValueModelBuilder';
import {
@ -354,9 +354,14 @@ export function buildEditorAppBarConfiguration(
designer: Designer,
onAction: (type: ToolbarActionType) => void,
save: () => void,
editorMode: EditorRenderMode,
isMobile: boolean,
showOnlyCommonActions: boolean,
showAccessChangeActions: boolean,
showMapEntityActions: boolean,
showMindMapNodesActions: boolean,
showPersistenceActions: boolean,
): ToolbarOptionConfiguration[] {
if (!designer) return [];
let commonConfiguration = [
{
icon: <ArrowBackIosNewOutlinedIcon />,
@ -366,104 +371,106 @@ export function buildEditorAppBarConfiguration(
{
render: () => <img src={LogoTextBlackSvg} />,
},
];
if (editorMode === 'viewonly' || editorMode === 'showcase' || isMobile)
return commonConfiguration;
if (!designer) return [];
const isEditor =
editorMode === 'edition-owner' ||
editorMode === 'edition-editor' ||
editorMode === 'edition-viewer';
if (isEditor) {
return [
...commonConfiguration,
{
render: () => (
<Tooltip title={designer.getMindmap().getCentralTopic().getText()}>
<Typography
className="truncated"
variant="body1"
component="div"
sx={{ marginX: '1.5rem' }}
>
{designer.getMindmap().getCentralTopic().getText()}
</Typography>
</Tooltip>
),
},
null,
{
render: () => (
<UndoAndRedoButton
configuration={{
icon: <UndoOutlinedIcon />,
tooltip: $msg('UNDO') + ' (' + $msg('CTRL') + ' + Z)',
onClick: () => designer.undo(),
}}
disabledCondition={(event) => event.undoSteps > 0}
></UndoAndRedoButton>
),
},
{
render: () => (
<UndoAndRedoButton
configuration={{
icon: <RedoOutlinedIcon />,
tooltip: $msg('REDO') + ' (' + $msg('CTRL') + ' + Shift + Z)',
onClick: () => designer.redo(),
}}
disabledCondition={(event) => event.redoSteps > 0}
></UndoAndRedoButton>
),
},
null,
{
icon: <RestoreOutlinedIcon />,
tooltip: $msg('HISTORY'),
onClick: () => onAction('history'),
},
{
icon: <SaveOutlinedIcon />,
tooltip: $msg('SAVE') + ' (' + $msg('CTRL') + ' + S)',
onClick: save,
},
{
render: () => <Typography component="div" sx={{ flexGrow: 1 }} />,
},
{
icon: <PrintOutlinedIcon />,
tooltip: $msg('PRINT'),
onClick: () => onAction('print'),
},
{
icon: <FileDownloadOutlinedIcon />,
tooltip: $msg('EXPORT'),
onClick: () => onAction('export'),
},
{
icon: <CloudUploadOutlinedIcon />,
onClick: () => onAction('publish'),
tooltip: $msg('PUBLISH'),
disabled: () => editorMode !== 'edition-owner',
},
{
render: () => (
<Button
variant="contained"
onClick={() => onAction('share')}
disabled={editorMode !== 'edition-owner'}
{
render: () => (
<Tooltip title={designer.getMindmap().getCentralTopic().getText()}>
<Typography
className="truncated"
variant="body1"
component="div"
sx={{ marginX: '1.5rem' }}
>
{$msg('COLLABORATE')}
</Button>
),
},
{
icon: <HelpOutlineOutlinedIcon />,
onClick: () => onAction('info'),
tooltip: $msg('MAP_INFO'),
},
];
}
{designer.getMindmap().getCentralTopic().getText()}
</Typography>
</Tooltip>
),
},
];
const exportConfiguration = {
icon: <FileDownloadOutlinedIcon />,
tooltip: $msg('EXPORT'),
onClick: () => onAction('export'),
};
const helpConfiguration = {
icon: <HelpOutlineOutlinedIcon />,
onClick: () => onAction('info'),
tooltip: $msg('MAP_INFO'),
};
const appBarDivisor = {
render: () => <Typography component="div" sx={{ flexGrow: 1 }} />,
};
if (showOnlyCommonActions)
return [...commonConfiguration, appBarDivisor, exportConfiguration, helpConfiguration];
return [
...commonConfiguration,
null,
{
render: () => (
<UndoAndRedoButton
configuration={{
icon: <UndoOutlinedIcon />,
tooltip: $msg('UNDO') + ' (' + $msg('CTRL') + ' + Z)',
onClick: () => designer.undo(),
}}
disabledCondition={(event) => event.undoSteps > 0}
></UndoAndRedoButton>
),
visible: showMindMapNodesActions,
},
{
render: () => (
<UndoAndRedoButton
configuration={{
icon: <RedoOutlinedIcon />,
tooltip: $msg('REDO') + ' (' + $msg('CTRL') + ' + Shift + Z)',
onClick: () => designer.redo(),
}}
disabledCondition={(event) => event.redoSteps > 0}
></UndoAndRedoButton>
),
visible: showMindMapNodesActions,
},
null,
{
icon: <RestoreOutlinedIcon />,
tooltip: $msg('HISTORY'),
onClick: () => onAction('history'),
visible: showPersistenceActions,
},
{
icon: <SaveOutlinedIcon />,
tooltip: $msg('SAVE') + ' (' + $msg('CTRL') + ' + S)',
onClick: save,
visible: showPersistenceActions,
},
appBarDivisor,
{
icon: <PrintOutlinedIcon />,
tooltip: $msg('PRINT'),
onClick: () => onAction('print'),
visible: showMapEntityActions,
},
exportConfiguration,
{
icon: <CloudUploadOutlinedIcon />,
onClick: () => onAction('publish'),
tooltip: $msg('PUBLISH'),
disabled: () => !showAccessChangeActions,
},
{
render: () => (
<Button
variant="contained"
onClick={() => onAction('share')}
disabled={!showAccessChangeActions}
>
{$msg('COLLABORATE')}
</Button>
),
},
helpConfiguration,
];
}

View File

@ -96,10 +96,15 @@ const Editor = ({
const [mindplotComponent, setMindplotComponent]: [MindplotWebComponent | undefined, Function] =
useState();
const editMode =
options.mode === 'edition-owner' ||
options.mode === 'edition-editor' ||
options.mode === 'edition-viewer';
const {
editMode,
showOnlyCommonActions,
showAccessChangeActions,
showMapEntityActions,
showMindMapNodesActions,
showPersistenceActions,
} = getToolsVisibilityConfiguration(options, isMobile);
const editorTheme: Theme = theme ? theme : defaultEditorTheme;
const [toolbarsRerenderSwitch, setToolbarsRerenderSwitch] = useState(0);
const toolbarConfiguration = useRef([]);
@ -200,12 +205,24 @@ const Editor = ({
() => {
mindplotComponent.save(true);
},
options.mode,
isMobile,
showOnlyCommonActions,
showAccessChangeActions,
showMapEntityActions,
showMindMapNodesActions,
showPersistenceActions,
);
menubarConfiguration.push({
render: () => accountConfiguration,
});
if (options.mode !== 'showcase') {
menubarConfiguration.push({
render: () => accountConfiguration,
});
}
useEffect(() => {
return () => {
mindplotComponent.unlockMap();
};
}, []);
// if the Toolbar is not hidden before the variable 'isMobile' is defined, it appears intermittently when the page loads
// if the Toolbar is not rendered, Menu.ts cant find buttons for create event listeners
// so, with this hack the Toolbar is rendered but no visible until the variable 'isMobile' is defined
@ -225,7 +242,7 @@ const Editor = ({
>
{widgetManager.getEditorContent()}
</Popover>
{editMode && !isMobile && (
{showMindMapNodesActions && (
<Toolbar
configurations={toolbarConfiguration.current}
rerender={toolbarsRerenderSwitch}
@ -252,3 +269,20 @@ const Editor = ({
);
};
export default Editor;
function getToolsVisibilityConfiguration(options: EditorOptions, isMobile: any) {
const editMode = options.mode === 'edition-owner' || options.mode === 'edition-editor';
const showcaseMode = options.mode === 'showcase';
const showMindMapNodesActions = (editMode || showcaseMode) && !isMobile && !options.locked;
const showMapEntityActions = editMode && !isMobile;
const showAccessChangeActions = options.mode === 'edition-owner' && !isMobile;
const showPersistenceActions = editMode && !isMobile && !options.locked;
const showOnlyCommonActions = options.mode === 'viewonly' || isMobile;
return {
editMode,
showOnlyCommonActions,
showAccessChangeActions,
showMapEntityActions,
showMindMapNodesActions,
showPersistenceActions,
};
}

View File

@ -50,6 +50,10 @@
<ul>
<li><a href="/showcase.html">Sample</a></li>
</ul>
<p><span class="section">Editor Mode (locked):</span>Example on how mindplot can be used for mindmap edition. Browser local storage is used for persistance.</p>
<ul>
<li><a href="/editorlocked.html">Sample</a></li>
</ul>
</div>
</body>

View File

@ -0,0 +1,53 @@
/*
* Copyright [2021] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
* It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the license at
*
* http://www.wisemapping.org/license
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import ReactDOM from 'react-dom';
import Editor, { EditorOptions } from '../../../../src/index';
import { LocalStorageManager, Designer } from '@wisemapping/mindplot';
const initialization = (designer: Designer) => {
designer.addEvent('loadSuccess', () => {
const elem = document.getElementById('mindmap-comp');
if (elem) {
elem.classList.add('ready');
}
});
};
const persistence = new LocalStorageManager('samples/{id}.wxml', false, false);
const mapId = 'welcome';
const options: EditorOptions = {
zoom: 0.8,
locked: true,
lockedMsg: 'Blockeado',
mapTitle: 'Develop WiseMapping',
mode: 'edition-editor',
locale: 'en',
enableKeyboardEvents: true,
};
ReactDOM.render(
<Editor
mapId={mapId}
options={options}
persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)}
onLoad={initialization}
/>,
document.getElementById('root'),
);

View File

@ -11,6 +11,7 @@ const playgroundConfig = {
viewmode: path.resolve(__dirname, './test/playground/map-render/js/viewmode'),
editor: path.resolve(__dirname, './test/playground/map-render/js/editor'),
showcase: path.resolve(__dirname, './test/playground/map-render/js/showcase'),
editorlocked: path.resolve(__dirname, './test/playground/map-render/js/editorlocked'),
},
output: {
path: path.resolve(__dirname, 'test/playground/dist'),
@ -53,6 +54,11 @@ const playgroundConfig = {
filename: 'showcase.html',
template: 'test/playground/map-render/html/showcase.html',
}),
new HtmlWebpackPlugin({
chunks: ['editorlocked'],
filename: 'editorlocked.html',
template: 'test/playground/map-render/html/editor.html',
}),
],
};