Merged in feature/remove_actions (pull request #45)

Remove actions in toobar when user is not owner.

* Fix eslit errors
This commit is contained in:
Paulo Veiga 2022-03-05 16:10:03 +00:00
parent e9a23bb1e2
commit c6db14b99a
25 changed files with 270 additions and 278 deletions

View File

@ -48,7 +48,7 @@ export default function Toolbar({
<div id="backToList"> <div id="backToList">
<img src={BackIconSvg} /> <img src={BackIconSvg} />
</div> </div>
{editorMode === 'edition' && ( {(editorMode === 'edition-editor' || editorMode === 'edition-owner') && (
<div id="persist" className="buttonContainer"> <div id="persist" className="buttonContainer">
<ToolbarButton id="save" className="buttonOn"> <ToolbarButton id="save" className="buttonOn">
<img src={SaveSvg} /> <img src={SaveSvg} />
@ -112,44 +112,51 @@ export default function Toolbar({
</ToolbarButton> </ToolbarButton>
</div> </div>
<div id="separator" className="buttonContainer"></div> <div id="separator" className="buttonContainer"></div>
{editorMode === 'edition' && ( <ToolbarRightContainer>
<ToolbarRightContainer> <ToolbarButton
<ToolbarButton id="export"
id="export" className="buttonOn"
className="buttonOn" onClick={() => onAction('export')}
onClick={() => onAction('export')} >
> <img src={ExportSvg} />
<img src={ExportSvg} /> </ToolbarButton>
</ToolbarButton> <ToolbarButton
<ToolbarButton id="print"
id="publishIt" className="buttonOn"
className="buttonOn" onClick={() => onAction('print')}
onClick={() => onAction('publish')} >
> <img src={PrintSvg} />
<img src={PublicSvg} /> </ToolbarButton>
</ToolbarButton> {editorMode === 'edition-owner' && (
<ToolbarButton <>
id="history" <ToolbarButton
className="buttonOn" id="history"
onClick={() => onAction('history')} className="buttonOn"
> onClick={() => onAction('history')}
<img src={HistorySvg} /> >
</ToolbarButton> <img src={HistorySvg} />
<ToolbarButton </ToolbarButton>
id="print" <ToolbarButton
className="buttonOn" id="publishIt"
onClick={() => onAction('print')} className="buttonOn"
> onClick={() => onAction('publish')}
<img src={PrintSvg} /> >
</ToolbarButton> <img src={PublicSvg} />
<ToolbarButton id="account"> </ToolbarButton>
<img src={AccountSvg} /> </>
</ToolbarButton> )}
{(editorMode === 'edition-owner' || editorMode === 'edition-editor') && (
<ToolbarButton id="account">
<img src={AccountSvg} />
</ToolbarButton>
)}
{editorMode === 'edition-owner' && (
<ActionButton onClick={() => onAction('share')}> <ActionButton onClick={() => onAction('share')}>
{intl.formatMessage({ id: 'action.share', defaultMessage: 'Share' })} {intl.formatMessage({ id: 'action.share', defaultMessage: 'Share' })}
</ActionButton> </ActionButton>
</ToolbarRightContainer>
)} )}
</ToolbarRightContainer>
</div> </div>
</HeaderContainer> </HeaderContainer>
); );

View File

@ -13,7 +13,6 @@ import {
} from '@wisemapping/mindplot'; } from '@wisemapping/mindplot';
import './global-styled.css'; import './global-styled.css';
import I18nMsg from './classes/i18n-msg'; import I18nMsg from './classes/i18n-msg';
import Messages from '@wisemapping/mindplot/src/components/Messages';
declare global { declare global {
// used in mindplot // used in mindplot

View File

@ -36,7 +36,7 @@ const options: EditorOptions = {
zoom: 0.8, zoom: 0.8,
locked: false, locked: false,
mapTitle: "Develop Mindnap", mapTitle: "Develop Mindnap",
mode: 'edition', mode: 'edition-owner',
locale: 'en', locale: 'en',
enableKeyboardEvents: true enableKeyboardEvents: true
}; };

View File

@ -1,4 +1,4 @@
declare module "*.svg" { declare module '*.svg' {
const content: any; const content: any;
export default content; export default content;
} }

View File

@ -41,20 +41,15 @@ class CommandContext {
} }
findTopics(topicIds: number[]): Topic[] { findTopics(topicIds: number[]): Topic[] {
$assert($defined(topicIds), 'topicsIds can not be null');
const topicsIds = Array.isArray(topicIds) ? topicIds : [topicIds]; const topicsIds = Array.isArray(topicIds) ? topicIds : [topicIds];
const designerTopics = this._designer.getModel().getTopics(); const designerTopics = this._designer.getModel().getTopics();
const result = designerTopics.filter((topic) => topicsIds.includes(topic.getId())); const result = designerTopics.filter((topic) => topicsIds.includes(topic.getId()));
if (result.length !== topicsIds.length) { if (result.length !== topicsIds.length) {
const ids = designerTopics.map((topic) => topic.getId()); const ids = designerTopics.map((topic) => topic.getId());
$assert( throw new Error(`Could not find topic. Result:${result
result.length === topicsIds.length, } Filter Criteria:${topicsIds
`Could not find topic. Result:${result } Current Topics: [${ids}])`);
} Filter Criteria:${topicsIds
} Current Topics: [${ids
}]`,
);
} }
return result; return result;
} }

View File

@ -37,7 +37,7 @@ export function buildDesigner(options: DesignerOptions): Designer {
PersistenceManager.init(persistence); PersistenceManager.init(persistence);
// Register toolbar event ... // Register toolbar event ...
if (options.mode === 'edition' || options.mode === 'showcase') { if (options.mode === 'edition-owner' || options.mode === 'edition-editor' || options.mode === 'showcase') {
const menu = new Menu(designer, 'toolbar'); const menu = new Menu(designer, 'toolbar');
// If a node has focus, focus can be move to another node using the keys. // If a node has focus, focus can be move to another node using the keys.

View File

@ -46,7 +46,7 @@ class OptionsBuilder {
} }
const defaultOptions: DesignerOptions = { const defaultOptions: DesignerOptions = {
mode: 'edition', mode: 'edition-owner',
zoom: 0.85, zoom: 0.85,
saveOnLoad: true, saveOnLoad: true,
containerSize, containerSize,

View File

@ -1,2 +1,2 @@
type EditorRenderMode = 'viewonly' | 'edition' | 'showcase'; type EditorRenderMode = 'viewonly' | 'edition-owner' | 'edition-editor' | 'showcase';
export default EditorRenderMode; export default EditorRenderMode;

View File

@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
// eslint-disable-next-line max-classes-per-file
import { import {
$assert, $assert,
$defined, $defined,
@ -23,12 +23,11 @@ import {
import { import {
Group, Group,
ElementClass, ElementClass,
Point,
} from '@wisemapping/web2d'; } from '@wisemapping/web2d';
import IconGroupRemoveTip from './IconGroupRemoveTip'; import IconGroupRemoveTip from './IconGroupRemoveTip';
import { Point } from '@wisemapping/web2d';
import Icon from './Icon'; import Icon from './Icon';
import SizeType from './SizeType'; import SizeType from './SizeType';
import IconModel from './model/IconModel';
import FeatureModel from './model/FeatureModel'; import FeatureModel from './model/FeatureModel';
const ORDER_BY_TYPE = new Map<string, number>(); const ORDER_BY_TYPE = new Map<string, number>();
@ -38,10 +37,15 @@ ORDER_BY_TYPE.set('link', 2);
class IconGroup { class IconGroup {
private _icons: Icon[]; private _icons: Icon[];
private _group: any; private _group: any;
private _removeTip: IconGroupRemoveTip; private _removeTip: IconGroupRemoveTip;
private _iconSize: SizeType; private _iconSize: SizeType;
private _topicId: number; private _topicId: number;
constructor(topicId: number, iconSize: number) { constructor(topicId: number, iconSize: number) {
$assert($defined(topicId), 'topicId can not be null'); $assert($defined(topicId), 'topicId can not be null');
$assert($defined(iconSize), 'iconSize can not be null'); $assert($defined(iconSize), 'iconSize can not be null');
@ -59,7 +63,6 @@ class IconGroup {
this._removeTip = new IconGroupRemoveTip(this._group); this._removeTip = new IconGroupRemoveTip(this._group);
this.seIconSize(iconSize, iconSize); this.seIconSize(iconSize, iconSize);
this._registerListeners(); this._registerListeners();
} }
setPosition(x: number, y: number): void { setPosition(x: number, y: number): void {
@ -189,7 +192,6 @@ class IconGroup {
} }
static ICON_PADDING = 5; static ICON_PADDING = 5;
} }
export default IconGroup; export default IconGroup;

View File

@ -26,8 +26,11 @@ import FeatureModel from './model/FeatureModel';
class LinkIcon extends Icon { class LinkIcon extends Icon {
private _linksModel: FeatureModel; private _linksModel: FeatureModel;
private _topic: Topic; private _topic: Topic;
private _readOnly: boolean; private _readOnly: boolean;
private _tip: LinkIconTooltip; private _tip: LinkIconTooltip;
constructor(topic: Topic, linkModel: LinkModel, readOnly: boolean) { constructor(topic: Topic, linkModel: LinkModel, readOnly: boolean) {
@ -73,8 +76,8 @@ class LinkIcon extends Icon {
getModel(): FeatureModel { getModel(): FeatureModel {
return this._linksModel; return this._linksModel;
} }
static IMAGE_URL = LinksImage;
static IMAGE_URL = LinksImage;
} }
export default LinkIcon; export default LinkIcon;

View File

@ -27,8 +27,11 @@ import FeatureModel from './model/FeatureModel';
class NoteIcon extends Icon { class NoteIcon extends Icon {
private _linksModel: NoteModel; private _linksModel: NoteModel;
private _topic: Topic; private _topic: Topic;
private _readOnly: boolean; private _readOnly: boolean;
private _tip: FloatingTip; private _tip: FloatingTip;
constructor(topic: Topic, noteModel: NoteModel, readOnly: boolean) { constructor(topic: Topic, noteModel: NoteModel, readOnly: boolean) {
@ -87,7 +90,6 @@ class NoteIcon extends Icon {
} }
static IMAGE_URL = NotesImage; static IMAGE_URL = NotesImage;
} }
export default NoteIcon; export default NoteIcon;

View File

@ -110,8 +110,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
this.execute(command); this.execute(command);
} }
/** */ changeTextToTopic(topicsIds: number[], text: string): void {
changeTextToTopic(topicsIds: number[], text: string) {
$assert($defined(topicsIds), 'topicsIds can not be null'); $assert($defined(topicsIds), 'topicsIds can not be null');
const commandFunc = (topic: Topic, value: string) => { const commandFunc = (topic: Topic, value: string) => {

View File

@ -707,11 +707,10 @@ abstract class Topic extends NodeGraph {
// Do some fancy animation .... // Do some fancy animation ....
const elements = this._flatten2DElements(this); const elements = this._flatten2DElements(this);
elements.forEach((elem) => { elements.forEach((elem) => {
elem.setVisibility(!value, 250) elem.setVisibility(!value, 250);
}); });
EventBus.instance.fireEvent('childShrinked', model); EventBus.instance.fireEvent('childShrinked', model);
} }
getShrinkConnector(): ShirinkConnector | undefined { getShrinkConnector(): ShirinkConnector | undefined {
@ -893,7 +892,6 @@ abstract class Topic extends NodeGraph {
this._relationships.forEach((r) => r.redraw()); this._relationships.forEach((r) => r.redraw());
} }
/** */
setBranchVisibility(value: boolean): void { setBranchVisibility(value: boolean): void {
let current: Topic = this; let current: Topic = this;
let parent: Topic = this; let parent: Topic = this;
@ -904,7 +902,6 @@ abstract class Topic extends NodeGraph {
current.setVisibility(value); current.setVisibility(value);
} }
/** */
setVisibility(value: boolean, fade = 0): void { setVisibility(value: boolean, fade = 0): void {
this._setTopicVisibility(value, fade); this._setTopicVisibility(value, fade);
@ -961,8 +958,9 @@ abstract class Topic extends NodeGraph {
relationship.setVisibility( relationship.setVisibility(
value value
&& (targetParent == null || !targetParent.areChildrenShrunken()) && (targetParent == null || !targetParent.areChildrenShrunken())
&& (sourceParent == null || !sourceParent.areChildrenShrunken()) && (sourceParent == null || !sourceParent.areChildrenShrunken()),
, fade); fade,
);
}); });
} }

View File

@ -25,7 +25,7 @@ type CommandTypes = string | object | boolean | number;
class GenericFunctionCommand extends Command { class GenericFunctionCommand extends Command {
private _value: CommandTypes; private _value: CommandTypes;
private _topicsId: number[]; private _topicsIds: number[];
private _commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes; private _commandFunc: (topic: Topic, value: CommandTypes) => CommandTypes;
@ -39,7 +39,7 @@ class GenericFunctionCommand extends Command {
super(); super();
this._value = value; this._value = value;
this._topicsId = topicsIds; this._topicsIds = topicsIds;
this._commandFunc = commandFunc; this._commandFunc = commandFunc;
this._oldValues = []; this._oldValues = [];
} }
@ -49,7 +49,7 @@ class GenericFunctionCommand extends Command {
*/ */
execute(commandContext: CommandContext) { execute(commandContext: CommandContext) {
if (!this._applied) { if (!this._applied) {
const topics = commandContext.findTopics(this._topicsId); const topics = commandContext.findTopics(this._topicsIds);
if (topics != null) { if (topics != null) {
const me = this; const me = this;
@ -66,7 +66,7 @@ class GenericFunctionCommand extends Command {
undoExecute(commandContext: CommandContext): void { undoExecute(commandContext: CommandContext): void {
if (this._applied) { if (this._applied) {
const topics = commandContext.findTopics(this._topicsId); const topics = commandContext.findTopics(this._topicsIds);
topics.forEach(((topic: Topic, index: number) => { topics.forEach(((topic: Topic, index: number) => {
this._commandFunc(topic, this._oldValues[index]); this._commandFunc(topic, this._oldValues[index]);

View File

@ -15,9 +15,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import RootedTreeSet from "./RootedTreeSet"; import RootedTreeSet from './RootedTreeSet';
import Node from './Node'; import Node from './Node';
import PositionType from "../PositionType"; import PositionType from '../PositionType';
abstract class ChildrenSorterStrategy { abstract class ChildrenSorterStrategy {
abstract computeChildrenIdByHeights(treeSet: RootedTreeSet, node: Node); abstract computeChildrenIdByHeights(treeSet: RootedTreeSet, node: Node);

View File

@ -15,7 +15,6 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import $ from 'jquery';
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import Events from '../Events'; import Events from '../Events';
import RootedTreeSet from './RootedTreeSet'; import RootedTreeSet from './RootedTreeSet';

View File

@ -19,7 +19,7 @@ import { $assert } from '@wisemapping/core-js';
import FeatureType from './FeatureType'; import FeatureType from './FeatureType';
class FeatureModel { class FeatureModel {
static _next_id = 0; static _nextId = 0;
private _id: number; private _id: number;
@ -85,8 +85,8 @@ class FeatureModel {
} }
static _nextUUID(): number { static _nextUUID(): number {
const result = FeatureModel._next_id + 1; const result = FeatureModel._nextId + 1;
FeatureModel._next_id = result; FeatureModel._nextId = result;
return result; return result;
} }
} }

View File

@ -29,7 +29,7 @@ const parseJsObject = (str: string) => JSON.parse(str.replace(/(['"])?([a-z0-9A-
abstract class INodeModel { abstract class INodeModel {
static MAIN_TOPIC_TO_MAIN_TOPIC_DISTANCE = 220; static MAIN_TOPIC_TO_MAIN_TOPIC_DISTANCE = 220;
private static _next_uuid = 0; private static _nextUuid = 0;
protected _mindmap: Mindmap; protected _mindmap: Mindmap;
@ -49,9 +49,9 @@ abstract class INodeModel {
const newId = INodeModel._nextUUID(); const newId = INodeModel._nextUUID();
this.putProperty('id', newId); this.putProperty('id', newId);
} else { } else {
if (id > INodeModel._next_uuid) { if (id > INodeModel._nextUuid) {
$assert(Number.isFinite(id)); $assert(Number.isFinite(id));
INodeModel._next_uuid = id; INodeModel._nextUuid = id;
} }
this.putProperty('id', id); this.putProperty('id', id);
} }
@ -358,8 +358,8 @@ abstract class INodeModel {
abstract removeChild(child: INodeModel); abstract removeChild(child: INodeModel);
static _nextUUID(): number { static _nextUUID(): number {
INodeModel._next_uuid += 1; INodeModel._nextUuid += 1;
return INodeModel._next_uuid; return INodeModel._nextUuid;
} }
} }

View File

@ -20,7 +20,7 @@ import Point from '@wisemapping/web2d';
import ConnectionLine from '../ConnectionLine'; import ConnectionLine from '../ConnectionLine';
class RelationshipModel { class RelationshipModel {
static _next_uuid = 0; static _nextUuid = 0;
private _id: number; private _id: number;
@ -133,8 +133,8 @@ class RelationshipModel {
} }
static _nextUUID() { static _nextUUID() {
RelationshipModel._next_uuid += 1; RelationshipModel._nextUuid += 1;
return RelationshipModel._next_uuid; return RelationshipModel._nextUuid;
} }
} }

View File

@ -39,170 +39,145 @@ class Menu extends IMenu {
// Create panels ... // Create panels ...
const designerModel = designer.getModel(); const designerModel = designer.getModel();
const fontFamilyModel = {
const fontFamilyBtn = $('#fontFamily'); getValue() {
if (fontFamilyBtn) { const nodes = designerModel.filterSelectedTopics();
const fontFamilyModel = { let result = null;
getValue() { for (let i = 0; i < nodes.length; i++) {
const nodes = designerModel.filterSelectedTopics(); const fontFamily = nodes[i].getFontFamily();
let result = null; if (result != null && result !== fontFamily) {
for (let i = 0; i < nodes.length; i++) { result = null;
const fontFamily = nodes[i].getFontFamily(); break;
if (result != null && result !== fontFamily) {
result = null;
break;
}
result = fontFamily;
} }
return result; result = fontFamily;
}, }
return result;
},
setValue(value: string) { setValue(value: string) {
designer.changeFontFamily(value); designer.changeFontFamily(value);
}, },
}; };
this._toolbarElems.push(new FontFamilyPanel('fontFamily', fontFamilyModel)); this._toolbarElems.push(new FontFamilyPanel('fontFamily', fontFamilyModel));
Menu._registerTooltip('fontFamily', $msg('FONT_FAMILY')); Menu._registerTooltip('fontFamily', $msg('FONT_FAMILY'));
}
const fontSizeBtn = $('#fontSize'); const fontSizeModel = {
if (fontSizeBtn) { getValue(): number {
const fontSizeModel = { const nodes = designerModel.filterSelectedTopics();
getValue(): number {
const nodes = designerModel.filterSelectedTopics();
let result = null; let result = null;
for (let i = 0; i < nodes.length; i++) { for (let i = 0; i < nodes.length; i++) {
const fontSize = nodes[i].getFontSize(); const fontSize = nodes[i].getFontSize();
if (result != null && result !== fontSize) { if (result != null && result !== fontSize) {
result = null; result = null;
break; break;
}
result = fontSize;
} }
return result; result = fontSize;
}, }
setValue(value: number) { return result;
designer.changeFontSize(value); },
}, setValue(value: number) {
}; designer.changeFontSize(value);
this._toolbarElems.push(new FontSizePanel('fontSize', fontSizeModel)); },
Menu._registerTooltip('fontSize', $msg('FONT_SIZE')); };
} this._toolbarElems.push(new FontSizePanel('fontSize', fontSizeModel));
Menu._registerTooltip('fontSize', $msg('FONT_SIZE'));
const topicShapeBtn = $('#topicShape'); const topicShapeModel = {
if (topicShapeBtn) { getValue() {
const topicShapeModel = { const nodes = designerModel.filterSelectedTopics();
getValue() { let result = null;
const nodes = designerModel.filterSelectedTopics(); for (let i = 0; i < nodes.length; i++) {
let result = null; const shapeType = nodes[i].getShapeType();
for (let i = 0; i < nodes.length; i++) { if (result != null && result !== shapeType) {
const shapeType = nodes[i].getShapeType(); result = null;
if (result != null && result !== shapeType) { break;
result = null;
break;
}
result = shapeType;
} }
return result; result = shapeType;
}, }
setValue(value: string) { return result;
designer.changeTopicShape(value); },
}, setValue(value: string) {
}; designer.changeTopicShape(value);
this._toolbarElems.push(new TopicShapePanel('topicShape', topicShapeModel)); },
Menu._registerTooltip('topicShape', $msg('TOPIC_SHAPE')); };
} this._toolbarElems.push(new TopicShapePanel('topicShape', topicShapeModel));
Menu._registerTooltip('topicShape', $msg('TOPIC_SHAPE'));
const topicIconBtn = $('#topicIcon'); // Create icon panel dialog ...
if (topicIconBtn) { const topicIconModel = {
// Create icon panel dialog ... getValue() {
const topicIconModel = { return null;
getValue() { },
return null; setValue(value: string) {
}, designer.addIconType(value);
setValue(value: string) { },
designer.addIconType(value); };
}, this._toolbarElems.push(new IconPanel('topicIcon', topicIconModel));
}; Menu._registerTooltip('topicIcon', $msg('TOPIC_ICON'));
this._toolbarElems.push(new IconPanel('topicIcon', topicIconModel));
Menu._registerTooltip('topicIcon', $msg('TOPIC_ICON'));
}
// Topic color item ... const topicColorModel = {
const topicColorBtn = $('#topicColor'); getValue() {
if (topicColorBtn) { const nodes = designerModel.filterSelectedTopics();
const topicColorModel = { let result = null;
getValue() { for (let i = 0; i < nodes.length; i++) {
const nodes = designerModel.filterSelectedTopics(); const color = nodes[i].getBackgroundColor();
let result = null; if (result != null && result !== color) {
for (let i = 0; i < nodes.length; i++) { result = null;
const color = nodes[i].getBackgroundColor(); break;
if (result != null && result !== color) {
result = null;
break;
}
result = color;
} }
return result; result = color;
}, }
setValue(hex: string) { return result;
designer.changeBackgroundColor(hex); },
}, setValue(hex: string) {
}; designer.changeBackgroundColor(hex);
this._toolbarElems.push(new ColorPalettePanel('topicColor', topicColorModel, widgetsBaseUrl)); },
Menu._registerTooltip('topicColor', $msg('TOPIC_COLOR')); };
} this._toolbarElems.push(new ColorPalettePanel('topicColor', topicColorModel, widgetsBaseUrl));
Menu._registerTooltip('topicColor', $msg('TOPIC_COLOR'));
// Border color item ... const borderColorModel = {
const topicBorderBtn = $('#topicBorder'); getValue() {
if (topicBorderBtn) { const nodes = designerModel.filterSelectedTopics();
const borderColorModel = { let result = null;
getValue() { for (let i = 0; i < nodes.length; i++) {
const nodes = designerModel.filterSelectedTopics(); const color = nodes[i].getBorderColor();
let result = null; if (result != null && result !== color) {
for (let i = 0; i < nodes.length; i++) { result = null;
const color = nodes[i].getBorderColor(); break;
if (result != null && result !== color) {
result = null;
break;
}
result = color;
} }
return result; result = color;
}, }
setValue(hex: string) { return result;
designer.changeBorderColor(hex); },
}, setValue(hex: string) {
}; designer.changeBorderColor(hex);
this._toolbarElems.push(new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl)); },
Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR')); };
} this._toolbarElems.push(new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl));
Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR'));
// Font color item ... const fontColorModel = {
const fontColorBtn = $('#fontColor'); getValue() {
if (fontColorBtn) { let result = null;
const fontColorModel = { const nodes = designerModel.filterSelectedTopics();
getValue() { for (let i = 0; i < nodes.length; i++) {
let result = null; const color = nodes[i].getFontColor();
const nodes = designerModel.filterSelectedTopics(); if (result != null && result !== color) {
for (let i = 0; i < nodes.length; i++) { result = null;
const color = nodes[i].getFontColor(); break;
if (result != null && result !== color) {
result = null;
break;
}
result = color;
} }
return result; result = color;
}, }
setValue(hex) { return result;
designer.changeFontColor(hex); },
}, setValue(hex) {
}; designer.changeFontColor(hex);
this._toolbarElems.push(new ColorPalettePanel('fontColor', fontColorModel, baseUrl)); },
Menu._registerTooltip('fontColor', $msg('FONT_COLOR')); };
} this._toolbarElems.push(new ColorPalettePanel('fontColor', fontColorModel, baseUrl));
Menu._registerTooltip('fontColor', $msg('FONT_COLOR'));
Menu._registerTooltip('export', $msg('EXPORT')); Menu._registerTooltip('export', $msg('EXPORT'));
@ -315,14 +290,6 @@ class Menu extends IMenu {
} }
} }
const discardElem = $('#discard');
if (discardElem.length !== 0) {
this._addButton('discard', false, false, () => {
this.discardChanges(designer);
});
Menu._registerTooltip('discard', $msg('DISCARD_CHANGES'));
}
const shareElem = $('#shareIt'); const shareElem = $('#shareIt');
if (shareElem.length !== 0) { if (shareElem.length !== 0) {
Menu._registerTooltip('shareIt', $msg('COLLABORATE')); Menu._registerTooltip('shareIt', $msg('COLLABORATE'));
@ -350,14 +317,12 @@ class Menu extends IMenu {
} }
const backTolist = $('#backToList'); const backTolist = $('#backToList');
if (backTolist.length !== 0) { backTolist.bind('click', (event) => {
backTolist.bind('click', (event) => { event.stopPropagation();
event.stopPropagation(); window.location.href = '/c/maps/';
window.location.href = '/c/maps/'; return false;
return false; });
}); Menu._registerTooltip('backToList', $msg('BACK_TO_MAP_LIST'));
Menu._registerTooltip('backToList', $msg('BACK_TO_MAP_LIST'));
}
// Account dialog ... // Account dialog ...
const accountSettings = $('#account'); const accountSettings = $('#account');
@ -367,9 +332,9 @@ class Menu extends IMenu {
}); });
this._toolbarElems.push(new AccountSettingsPanel('account')); this._toolbarElems.push(new AccountSettingsPanel('account'));
Menu._registerTooltip('account', `${global.accountEmail}`); Menu._registerTooltip('account', `${global.accountEmail}`);
}
this._registerEvents(designer); this._registerEvents(designer);
}
} }
private _registerEvents(designer: Designer) { private _registerEvents(designer: Designer) {

View File

@ -81,7 +81,7 @@ const App = (): ReactElement => {
component={withSessionExpirationHandling(MapsPage)} component={withSessionExpirationHandling(MapsPage)}
/> />
<Route exact path="/c/maps/:id/edit"> <Route exact path="/c/maps/:id/edit">
<EnhacedEditorPage isTryMode={false} /> <EnhacedEditorPage isTryMode={false}/>
</Route> </Route>
<Route exact path="/c/maps/:id/try"> <Route exact path="/c/maps/:id/try">
<EnhacedEditorPage isTryMode={true} /> <EnhacedEditorPage isTryMode={true} />

View File

@ -611,12 +611,12 @@ export default class RestClient implements Client {
} }
} }
buildPersistenceManager(editorMode: EditorRenderMode ): PersistenceManager { buildPersistenceManager(editorMode: EditorRenderMode): PersistenceManager {
if (this.persistenceManager) { if (this.persistenceManager) {
return this.persistenceManager; return this.persistenceManager;
} }
let persistence: PersistenceManager; let persistence: PersistenceManager;
if (editorMode === 'edition') { if (editorMode === 'edition-owner' || editorMode === 'edition-editor') {
persistence = new RESTPersistenceManager({ persistence = new RESTPersistenceManager({
documentUrl: '/c/restful/maps/{id}/document', documentUrl: '/c/restful/maps/{id}/document',
revertUrl: '/c/restful/maps/{id}/history/latest', revertUrl: '/c/restful/maps/{id}/history/latest',
@ -645,13 +645,15 @@ export default class RestClient implements Client {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
private parseResponseOnError = (response: any): ErrorInfo => { private parseResponseOnError = (response: any): ErrorInfo => {
console.error("Backend error=>"); console.error(`Performing backend action error: ${JSON.stringify(response)}`);
console.error(response.data);
let result: ErrorInfo | undefined; let result: ErrorInfo | undefined;
if (response) { if (response) {
const status: number = response.status; const status: number = response.status;
const data = response.data; const data = response.data;
console.error(`Status Code: ${status}`);
console.error(`Status Data: ${response.data}`);
console.error(`Status Message: ${response.message}`);
switch (status) { switch (status) {
case 401: case 401:

View File

@ -1,25 +1,16 @@
import { EditorOptions } from '@wisemapping/editor'; import { EditorOptions } from '@wisemapping/editor';
import { EditorRenderMode } from '@wisemapping/mindplot';
import AppConfig from '../../classes/app-config'; import AppConfig from '../../classes/app-config';
export default class EditorOptionsBulder { export default class EditorOptionsBulder {
static build(locale: string, hotkeys: boolean, isTryMode: boolean): { options: EditorOptions, mapId: number } { static build(locale: string, mode: EditorRenderMode, hotkeys: boolean): EditorOptions {
let options: EditorOptions = { let options: EditorOptions = {
enableKeyboardEvents: hotkeys, enableKeyboardEvents: hotkeys,
locale: locale, locale: locale,
mode: mode,
}; };
if (isTryMode) {
// Sent to try mode ...
options.mode = 'showcase';
} else if (global.mindmapLocked) {
// Map locked, open for view mode ...
options.mode = 'viewonly';
} else {
options.mode = 'edition';
}
let mapId: number;
if (!AppConfig.isDevelopEnv()) { if (!AppConfig.isDevelopEnv()) {
options = { options = {
zoom: (global.userOptions?.zoom != undefined zoom: (global.userOptions?.zoom != undefined
@ -30,7 +21,6 @@ export default class EditorOptionsBulder {
mapTitle: global.mapTitle, mapTitle: global.mapTitle,
...options ...options
} }
mapId = global.mapId;
} else { } else {
// Running in a development mode. // Running in a development mode.
console.log('Running editor in development mode'); console.log('Running editor in development mode');
@ -40,8 +30,11 @@ export default class EditorOptionsBulder {
mapTitle: "Develop Mindnap", mapTitle: "Develop Mindnap",
...options ...options
} }
mapId = 666;
} }
return { options, mapId }; return options;
}
static loadMapId(): number {
return !AppConfig.isDevelopEnv() ? global.mapId : 555;
} }
} }

View File

@ -2,13 +2,14 @@ import React, { useEffect } from 'react';
import ActionDispatcher from '../maps-page/action-dispatcher'; import ActionDispatcher from '../maps-page/action-dispatcher';
import { ActionType } from '../maps-page/action-chooser'; import { ActionType } from '../maps-page/action-chooser';
import Editor from '@wisemapping/editor'; import Editor from '@wisemapping/editor';
import { EditorRenderMode, PersistenceManager } from '@wisemapping/mindplot';
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 { hotkeysEnabled } 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, fetchAccount } from '../../redux/clientSlice'; import { activeInstance, fetchAccount, fetchMapById } from '../../redux/clientSlice';
import { PersistenceManager } from '@wisemapping/mindplot';
import EditorOptionsBulder from './EditorOptionsBuider'; import EditorOptionsBulder from './EditorOptionsBuider';
export type EditorPropsType = { export type EditorPropsType = {
@ -20,16 +21,43 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => {
const hotkey = useSelector(hotkeysEnabled); const hotkey = useSelector(hotkeysEnabled);
const userLocale = AppI18n.getUserLocale(); const userLocale = AppI18n.getUserLocale();
const client: Client = useSelector(activeInstance); const client: Client = useSelector(activeInstance);
const { mapId, options } = EditorOptionsBulder.build(userLocale.code, hotkey, isTryMode);
useEffect(() => { useEffect(() => {
ReactGA.pageview(window.location.pathname + window.location.search); ReactGA.pageview(window.location.pathname + window.location.search);
}, []); }, []);
const findEditorMode = (isTryMode: boolean, mapId: number): EditorRenderMode | null => {
let result: EditorRenderMode = null;
if (isTryMode) {
result = 'showcase';
} else if (global.mindmapLocked) {
result = 'viewonly';
} else {
const fetchResult = fetchMapById(mapId);
if (!fetchResult.isLoading) {
if (fetchResult.error) {
throw new Error(`User coild not be loaded: ${JSON.stringify(fetchResult.error)}`);
}
result = fetchResult.map.role === 'owner' ? 'edition-owner' : 'edition-editor';
}
}
return result;
}
// What is the role ?
const mapId = EditorOptionsBulder.loadMapId();
const mode = findEditorMode(isTryMode, mapId);
// Account settings can be null and editor cannot be initilized multiple times. This creates problems // Account settings can be null and editor cannot be initilized multiple times. This creates problems
// at the i18n resource loading. // at the i18n resource loading.
const persistence = client.buildPersistenceManager(options.mode); const isAccountLoaded = mode === 'showcase' || fetchAccount;
const loadCompleted = persistence && (options.mode === 'showcase' || fetchAccount()); const loadCompleted = mode && isAccountLoaded;
let options, persistence: PersistenceManager;
if (loadCompleted) {
options = EditorOptionsBulder.build(userLocale.code, mode, hotkey);
persistence = client.buildPersistenceManager(mode);
}
return loadCompleted ? ( return loadCompleted ? (
<> <>