Merge branch 'develop' of https://bitbucket.org/wisemapping/wisemapping-frontend into feature/import-freemind-to-wisemapping

This commit is contained in:
Ezequiel-Vega 2022-03-07 13:27:35 -03:00
commit 0fcbf6d111
106 changed files with 2571 additions and 1274 deletions

View File

Before

Width:  |  Height:  |  Size: 281 B

After

Width:  |  Height:  |  Size: 281 B

View File

Before

Width:  |  Height:  |  Size: 172 B

After

Width:  |  Height:  |  Size: 172 B

View File

Before

Width:  |  Height:  |  Size: 247 B

After

Width:  |  Height:  |  Size: 247 B

View File

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 189 B

View File

@ -0,0 +1,14 @@
{
"editor.try-welcome": {
"defaultMessage": "Это демо-версия редактора, можно попробовать его в деле!"
},
"editor.try-welcome-description": {
"defaultMessage": "Чтобы получить бесплатный неограниченный доступ — нужна только регистрация."
},
"login.signup": {
"defaultMessage": "Регистрация"
},
"action.share": {
"defaultMessage": "Поделиться"
}
}

20
packages/editor/src/bootstrap-fixes.css vendored Normal file
View File

@ -0,0 +1,20 @@
/*
These are patches or hacks to avoid boostrap interfering with Mui styles
This file is meant to be removed when removing bootstrap
*/
/*
/* bootstrap modal */
.wise-editor .modal {
overflow: hidden;
}
.modal-backdrop {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0,0,0,0.5);
z-index: 1000;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,156 @@
/*
* 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 $ from 'jquery';
import Options from '@wisemapping/mindplot/src/components/Options';
import { $msg } from '@wisemapping/mindplot/src/components/Messages';
class BootstrapDialog extends Options {
constructor(title, options) {
super();
this.options = {
cancelButton: false,
closeButton: false,
acceptButton: true,
removeButton: false,
errorMessage: false,
onEventData: {},
};
this.setOptions(options);
this.options.onEventData.dialog = this;
this._native = $('<div class="modal fade" tabindex="-1"></div>').append(
'<div class="modal-dialog"></div>',
);
const content = $('<div class="modal-content"></div>');
const header = this._buildHeader(title);
if (header) {
content.append(header);
}
const body = $('<div class="modal-body"></div>');
if (this.options.errorMessage) {
const error = $('<div class="alert alert-danger"></div>');
error.hide();
body.append(error);
}
content.append(body);
const footer = this._buildFooter();
if (footer) {
content.append(footer);
}
this._native.find('.modal-dialog').append(content);
this._native.on('hidden.bs.modal', function remove() {
$(this).remove();
});
this._native.on('shown.bs.modal', this.onDialogShown);
this._native.appendTo('#mindplot-tooltips');
}
_buildFooter() {
let footer = null;
if (this.options.acceptButton || this.options.removeButton || this.options.cancelButton) {
footer = $('<div class="modal-footer" style="paddingTop:5;textAlign:center">');
}
if (this.options.acceptButton) {
this.acceptButton = $(
`<button type="button" class="btn btn-primary" id="acceptBtn" data-dismiss="modal">${$msg(
'ACCEPT',
)}</button>`,
);
footer.append(this.acceptButton);
this.acceptButton
.unbind('click')
.on('click', this.options.onEventData, this.onAcceptClick);
}
if (this.options.removeButton) {
this.removeButton = $(
`<button type="button" class="btn btn-secondary" id="removeBtn" data-dismiss="modal">${$msg(
'REMOVE',
)}</button>`,
);
footer.append(this.removeButton);
this.removeButton.on('click', this.options.onEventData, this.onRemoveClick);
}
if (this.options.cancelButton) {
footer.append(
`<button type="button" class="btn btn-secondary" data-dismiss="modal">${$msg(
'CANCEL',
)}</button>`,
);
}
return footer;
}
_buildHeader(title) {
let header = null;
if (this.options.closeButton || title) {
header = $('<div class="modal-header"></div>');
}
if (this.options.closeButton) {
header.append(
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>',
);
}
if (title) {
header.append(`<h2 class="modal-title">${title}</h2>`);
}
return header;
}
onAcceptClick() {
throw new Error('Unsupported operation');
}
onDialogShown() {
// Overwrite default behaviour ...
}
onRemoveClick() {
throw new Error('Unsupported operation');
}
show() {
this._native.modal();
}
setContent(content) {
const modalBody = this._native.find('.modal-body');
modalBody.append(content);
}
css(options) {
this._native.find('.modal-dialog').css(options);
}
close() {
this._native.modal('hide');
}
alertError(message) {
this._native.find('.alert-danger').text(message);
this._native.find('.alert-danger').show();
}
cleanError() {
this._native.find('.alert-danger').hide();
}
}
export default BootstrapDialog;

View File

@ -0,0 +1,26 @@
import FR from './../../compiled-lang/fr.json';
import ES from './../../compiled-lang/es.json';
import EN from './../../compiled-lang/en.json';
import DE from './../../compiled-lang/de.json';
import RU from './../../compiled-lang/ru.json';
class I18nMsg {
static loadLocaleData(locale: string) {
switch (locale) {
case 'fr':
return FR;
case 'en':
return EN;
case 'es':
return ES;
case 'de':
return DE;
case 'ru':
return RU;
default:
return EN;
}
}
}
export default I18nMsg;

View File

@ -0,0 +1,68 @@
/*
* 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.
*/
class Events {
private _handlerByType;
constructor() {
this._handlerByType = {};
}
static _normalizeEventName(string: string) {
return string.replace(/^on([A-Z])/, (_full, first) => first.toLowerCase());
}
addEvent(typeName: string, fn?, internal?: boolean): Events {
const type = Events._normalizeEventName(typeName);
// Add function had not been added yet
const funByType = this._handlerByType[type] ? this._handlerByType[type] : [];
if (!funByType.includes(fn)) {
funByType.push(fn);
this._handlerByType[type] = funByType;
}
// Mark reference ...
fn.internal = Boolean(internal);
return this;
}
fireEvent(typeName: string, eventArgs?): Events {
const type = Events._normalizeEventName(typeName);
const events = this._handlerByType[type];
if (!events) return this;
const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs];
events.forEach(((fn) => {
fn.apply(this, args);
}));
return this;
}
removeEvent(typeName: string, fn?): Events {
const type = Events._normalizeEventName(typeName);
const events = this._handlerByType[type];
if (events && !fn.internal) {
const index = events.indexOf(fn);
if (index !== -1) events.splice(index, 1);
}
return this;
}
}
export default Events;

View File

@ -16,12 +16,12 @@
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import { $msg } from '../Messages';
import PersistenceManager from '../PersistenceManager';
import { $notify } from './ToolbarNotifier';
import { $notifyModal } from './ModalDialogNotifier';
import Designer from '../Designer';
import ToolbarItem from './ToolbarItem';
import { $msg } from '@wisemapping/mindplot/src/components/Messages';
import PersistenceManager from '@wisemapping/mindplot/src/components/PersistenceManager';
import { $notify } from '@wisemapping/mindplot/src/components/widget/ToolbarNotifier';
import { $notifyModal } from '../menu/ModalDialogNotifier';
import Designer from '@wisemapping/mindplot/src/components/Designer';
import ToolbarItem from '../menu/ToolbarItem';
class IMenu {
private _designer: Designer;

View File

@ -17,7 +17,8 @@
*/
import $ from 'jquery';
import ToolbarPaneItem from './ToolbarPaneItem';
import ImageIcon from '../ImageIcon';
import { ImageIcon } from '@wisemapping/mindplot';
class IconPanel extends ToolbarPaneItem {
_updateSelectedItem() {

View File

@ -15,16 +15,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import BootstrapDialog from '../libraries/bootstrap/BootstrapDialog';
import { $msg } from '../Messages';
import BootstrapDialog from '../bootstrap/BootstrapDialog';
import { $msg } from '@wisemapping/mindplot';
class KeyboardShortcutDialog extends BootstrapDialog {
constructor() {
super($msg('SHORTCUTS'), {
closeButton: true,
acceptButton: false,
});
this.setContent(`<div id="keyboardTable">
constructor() {
super($msg('SHORTCUTS'), {
closeButton: true,
acceptButton: false,
});
this.setContent(`<div id="keyboardTable">
<table>
<colgroup>
<col width="40%"/>
@ -128,8 +129,8 @@ class KeyboardShortcutDialog extends BootstrapDialog {
</tbody>
</table>
</div>`);
this.show();
}
this.show();
}
}
export default KeyboardShortcutDialog;

View File

@ -17,7 +17,7 @@
*/
import $ from 'jquery';
import { $assert } from '@wisemapping/core-js';
import FloatingTip from './FloatingTip';
import FloatingTip from '@wisemapping/mindplot/src/components/widget/FloatingTip';
class KeyboardShortcutTooltip extends FloatingTip {
constructor(buttonElem, text) {

View File

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

View File

@ -16,7 +16,6 @@
*/
import { $assert } from '@wisemapping/core-js';
import $ from 'jquery';
import AlertImage from '../../../assets/images/alert-sign.png';
class ModalDialogNotifier {
show(message, title) {
@ -29,7 +28,6 @@ class ModalDialogNotifier {
<div class="modal-body">
</div>
<div class="alert alert-block alert-warning">
<img src="${AlertImage}">
<div style="display: inline-block" class="alert-content"></div>
</div>
<div class="modal-footer">

View File

@ -17,7 +17,7 @@
*/
import $ from 'jquery';
import { $assert } from '@wisemapping/core-js';
import Events from '../Events';
import Events from './Events';
class ToolbarItem extends Events {
constructor(buttonId, fn, options) {

View File

@ -17,7 +17,7 @@
*/
import { $assert } from '@wisemapping/core-js';
import ToolbarItem from './ToolbarItem';
import FloatingTip from './FloatingTip';
import FloatingTip from '@wisemapping/mindplot/src/components/widget/FloatingTip';
class ToolbarPaneItem extends ToolbarItem {
constructor(buttonId, model, delayInit) {

View File

@ -0,0 +1,26 @@
{
"action.share": [
{
"type": 0,
"value": "Поделиться"
}
],
"editor.try-welcome": [
{
"type": 0,
"value": "Это демо-версия редактора, можно попробовать его в деле!"
}
],
"editor.try-welcome-description": [
{
"type": 0,
"value": "Чтобы получить бесплатный неограниченный доступ — нужна только регистрация."
}
],
"login.signup": [
{
"type": 0,
"value": "Регистрация"
}
]
}

View File

@ -7,12 +7,13 @@ import AddSvg from '../../../images/add.svg';
import MinusSvg from '../../../images/minus.svg';
import CenterFocusSvg from '../../../images/center_focus.svg';
import ActionButton from '../action-button';
import { EditorRenderMode } from '@wisemapping/mindplot';
export type FooterPropsType = {
showTryPanel?: boolean;
editorMode: EditorRenderMode;
};
const Footer = ({ showTryPanel }: FooterPropsType): React.ReactElement => {
const Footer = ({ editorMode }: FooterPropsType): React.ReactElement => {
const intl = useIntl();
return (
@ -37,7 +38,7 @@ const Footer = ({ showTryPanel }: FooterPropsType): React.ReactElement => {
</div>
<StyledLogo id="bottom-logo"></StyledLogo>
<Notifier id="headerNotifier"></Notifier>
{showTryPanel && (
{editorMode === 'showcase' && (
<div id="tryInfoPanel">
<p>{intl.formatMessage({ id: 'editor.try-welcome' })}</p>
<p>{intl.formatMessage({ id: 'editor.try-welcome-description' })}</p>

View File

@ -28,26 +28,27 @@ import './global-styled.css';
import { HeaderContainer, ToolbarButton, ToolbarButtonExt, ToolbarRightContainer } from './styled';
import ActionButton from '../action-button';
import { EditorRenderMode } from '@wisemapping/mindplot';
export type ToolbarActionType = 'export' | 'publish' | 'history' | 'print' | 'share';
export type ToolbarPropsType = {
isTryMode: boolean;
editorMode: EditorRenderMode;
onAction: (action: ToolbarActionType) => void;
};
export default function Toolbar({
isTryMode: isTryMode,
editorMode: editorMode,
onAction,
}: ToolbarPropsType): React.ReactElement {
const intl = useIntl();
return (
<HeaderContainer>
<HeaderContainer className="wise-editor">
<div id="toolbar">
<div id="backToList">
<img src={BackIconSvg} />
</div>
{!isTryMode && (
{(editorMode === 'edition-editor' || editorMode === 'edition-owner') && (
<div id="persist" className="buttonContainer">
<ToolbarButton id="save" className="buttonOn">
<img src={SaveSvg} />
@ -111,29 +112,15 @@ export default function Toolbar({
</ToolbarButton>
</div>
<div id="separator" className="buttonContainer"></div>
{!isTryMode && (
<ToolbarRightContainer>
<ToolbarButton
id="export"
className="buttonOn"
onClick={() => onAction('export')}
>
<img src={ExportSvg} />
</ToolbarButton>
<ToolbarButton
id="publishIt"
className="buttonOn"
onClick={() => onAction('publish')}
>
<img src={PublicSvg} />
</ToolbarButton>
<ToolbarButton
id="history"
className="buttonOn"
onClick={() => onAction('history')}
>
<img src={HistorySvg} />
</ToolbarButton>
<ToolbarRightContainer>
<ToolbarButton
id="export"
className="buttonOn"
onClick={() => onAction('export')}
>
<img src={ExportSvg} />
</ToolbarButton>
{(editorMode === 'edition-owner' || editorMode === 'edition-editor' || editorMode === 'edition-viewer') && (
<ToolbarButton
id="print"
className="buttonOn"
@ -141,14 +128,37 @@ export default function Toolbar({
>
<img src={PrintSvg} />
</ToolbarButton>
)}
{editorMode === 'edition-owner' && (
<>
<ToolbarButton
id="history"
className="buttonOn"
onClick={() => onAction('history')}
>
<img src={HistorySvg} />
</ToolbarButton>
<ToolbarButton
id="publishIt"
className="buttonOn"
onClick={() => onAction('publish')}
>
<img src={PublicSvg} />
</ToolbarButton>
</>
)}
{(editorMode === 'edition-owner' || editorMode === 'edition-editor') && (
<ToolbarButton id="account">
<img src={AccountSvg} />
</ToolbarButton>
)}
{editorMode === 'edition-owner' && (
<ActionButton onClick={() => onAction('share')}>
{intl.formatMessage({ id: 'action.share', defaultMessage: 'Share' })}
</ActionButton>
</ToolbarRightContainer>
)}
)}
</ToolbarRightContainer>
</div>
</HeaderContainer>
);

View File

@ -1,7 +1,8 @@
/********************************************************************************/
/* Header & Toolbar Styles */
/********************************************************************************/
@import "bootstrap.min.css";
@import "bootstrap-prefix.min.css";
@import "bootstrap-fixes.css";
html {
/* avoid bootstrap overriding font-size and breaking Mui */
@ -129,7 +130,7 @@ div.shareModalDialog {
background-color: #efefef;
}
.popover {
.wise-editor .popover {
font-size: 13px;
max-width: none;
}
@ -217,9 +218,8 @@ div#tryInfoPanel {
margin: auto;
text-align: center;
top: 80px;
right: 20px;
left: 20px;
width: 200px;
height: 300px;
padding: 20px;
font-size: 15px;
border-radius: 9px;

View File

@ -9,14 +9,11 @@ import {
DesignerOptionsBuilder,
Designer,
DesignerKeyboard,
EditorRenderMode,
} from '@wisemapping/mindplot';
import FR from './compiled-lang/fr.json';
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';
import I18nMsg from './classes/i18n-msg';
import Menu from './classes/menu/Menu';
declare global {
// used in mindplot
@ -25,7 +22,7 @@ declare global {
}
export type EditorOptions = {
mode: EditorModeType,
mode: EditorRenderMode,
locale: string,
zoom?: number,
locked?: boolean,
@ -37,61 +34,38 @@ export type EditorOptions = {
export type EditorProps = {
mapId: string;
options: EditorOptions;
onAction: (action: ToolbarActionType) => void;
persistenceManager: PersistenceManager;
initCallback?: (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => void;
};
const loadLocaleData = (locale: string) => {
switch (locale) {
case 'fr':
return FR;
case 'en':
return EN;
case 'es':
return ES;
case 'de':
return DE;
default:
return EN;
}
}
const defaultCallback = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => {
// Change page title ...
document.title = `${options.mapTitle} | WiseMapping `;
const buildOptions = DesignerOptionsBuilder.buildOptions({
persistenceManager,
mode: options.mode,
mapId: mapId,
container: 'mindplot',
zoom: options.zoom,
locale: options.locale,
});
// Build designer ...
const designer = buildDesigner(buildOptions);
// Load map from XML file persisted on disk...
const instance = PersistenceManager.getInstance();
const mindmap = instance.load(mapId);
designer.loadMap(mindmap);
if (options.locked) {
$notify(options.lockedMsg);
}
onAction: (action: ToolbarActionType) => void;
onLoad?: (designer: Designer) => void;
};
const Editor = ({
mapId,
options,
persistenceManager,
initCallback = defaultCallback,
onAction,
onLoad,
}: EditorProps) => {
useEffect(() => {
initCallback(mapId, options, persistenceManager);
// Change page title ...
document.title = `${options.mapTitle} | WiseMapping `;
// Load mindmap ...
const designer = onLoadDesigner(mapId, options, persistenceManager);
// Has extended actions been customized ...
if (onLoad) {
onLoad(designer);
}
// Load mindmap ...
const instance = PersistenceManager.getInstance();
const mindmap = instance.load(mapId);
designer.loadMap(mindmap);
if (options.locked) {
$notify(options.lockedMsg, false);
}
}, []);
useEffect(() => {
@ -102,15 +76,47 @@ const Editor = ({
}
}, [options.enableKeyboardEvents]);
const onLoadDesigner = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager): Designer => {
const buildOptions = DesignerOptionsBuilder.buildOptions({
persistenceManager,
mode: options.mode,
mapId: mapId,
container: 'mindplot',
zoom: options.zoom,
locale: options.locale,
});
// Build designer ...
const result = buildDesigner(buildOptions);
// Register toolbar event ...
if (options.mode === 'edition-owner' || options.mode === 'edition-editor' || options.mode === 'showcase') {
const menu = new Menu(designer, 'toolbar');
// If a node has focus, focus can be move to another node using the keys.
designer.cleanScreen = () => {
menu.clear();
};
}
return result;
};
const locale = options.locale;
const msg = I18nMsg.loadLocaleData(locale);
const mindplotStyle = (options.mode === 'viewonly') ? { top: 0 } : { top: 'inherit' };
return (
<IntlProvider locale={options.locale} messages={loadLocaleData(options.locale)}>
<Toolbar
isTryMode={options.mode === 'showcase'}
onAction={onAction}
/>
<div id="mindplot"></div>
<Footer showTryPanel={options.mode === 'showcase'} />
</IntlProvider>
<IntlProvider locale={locale} messages={msg}>
{(options.mode !== 'viewonly') &&
<Toolbar
editorMode={options.mode}
onAction={onAction}
/>
}
<div id="mindplot" style={mindplotStyle} className="wise-editor"></div>
<div id="mindplot-tooltips" className="wise-editor"></div>
<Footer editorMode={options.mode} />
</IntlProvider >
);
}
export default Editor;

View File

@ -1,29 +1,33 @@
/*
* 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 { buildDesigner, LocalStorageManager, PersistenceManager, DesignerOptionsBuilder } from '@wisemapping/mindplot';
import { LocalStorageManager, Designer } from '@wisemapping/mindplot';
const initialization = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => {
const initialization = (designer: Designer) => {
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);
@ -32,7 +36,7 @@ const options: EditorOptions = {
zoom: 0.8,
locked: false,
mapTitle: "Develop Mindnap",
mode: 'edition',
mode: 'edition-owner',
locale: 'en',
enableKeyboardEvents: true
};
@ -43,7 +47,7 @@ ReactDOM.render(
options={options}
persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)}
initCallback={initialization}
onLoad={initialization}
/>,
document.getElementById('root'),
);

View File

@ -2,18 +2,10 @@ 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';
import { LocalStorageManager, Designer } from '@wisemapping/mindplot';
const initialization = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => {
const initialization = (designer: Designer) => {
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) {
@ -35,11 +27,6 @@ const initialization = (mapId: string, options: EditorOptions, persistenceManage
}
});
// 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
@ -61,7 +48,7 @@ ReactDOM.render(
options={options}
persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)}
initCallback={initialization}
onLoad={initialization}
/>,
document.getElementById('root'),
);

View File

@ -1,7 +1,7 @@
{
"include": [
"src/**/*"
],
, "../mindplot/src/components/widget/FloatingTip.ts" ],
"compilerOptions": {
"jsx": "react",
"outDir": "./dist/",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

@ -1,6 +1,6 @@
{
"name": "@wisemapping/mindplot",
"version": "5.0.7",
"version": "5.0.8",
"description": "WiseMapping - Mindplot Canvas Library",
"homepage": "http://www.wisemapping.org/",
"directories": {

View File

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

View File

@ -1,64 +0,0 @@
/*
* 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 Icon from './Icon';
class ActionIcon extends Icon {
constructor(topic, url) {
super(url);
this._node = topic;
}
getNode() {
return this._node;
}
setPosition(x, y) {
const size = this.getSize();
this.getImage().setPosition(x - size.width / 2, y - size.height / 2);
}
addEvent(event, fn) {
this.getImage().addEvent(event, fn);
}
addToGroup(group) {
group.append(this.getImage());
}
setVisibility(visible) {
this.getImage().setVisibility(visible);
}
isVisible() {
return this.getImage().isVisible();
}
setCursor(cursor) {
return this.getImage().setCursor(cursor);
}
moveToBack(cursor) {
return this.getImage().moveToBack(cursor);
}
moveToFront(cursor) {
return this.getImage().moveToFront(cursor);
}
}
export default ActionIcon;

View File

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

View File

@ -93,8 +93,8 @@ class ConnectionLine {
return line;
}
setVisibility(value: boolean): void {
this._line2d.setVisibility(value);
setVisibility(value: boolean, fade = 0): void {
this._line2d.setVisibility(value, fade);
}
isVisible() {

View File

@ -39,7 +39,7 @@ import Relationship from './Relationship';
import TopicEventDispatcher, { TopicEvent } from './TopicEventDispatcher';
import TopicFeatureFactory from './TopicFeature';
import { create } from './NodeGraphUtils';
import TopicFactory from './TopicFactory';
import EventBus from './layout/EventBus';
import EventBusDispatcher from './layout/EventBusDispatcher';
@ -53,7 +53,6 @@ import Mindmap from './model/Mindmap';
import NodeModel from './model/NodeModel';
import Topic from './Topic';
import { DesignerOptions } from './DesignerOptionsBuilder';
import MainTopic from './MainTopic';
import DragTopic from './DragTopic';
import CentralTopic from './CentralTopic';
import FeatureType from './model/FeatureType';
@ -87,6 +86,7 @@ class Designer extends Events {
$assert(divElement, 'divElement must be defined');
// Set up i18n location ...
console.log(`Editor location: ${options.locale}`);
Messages.init(options.locale);
this._options = options;
@ -224,9 +224,9 @@ class Designer extends Events {
return dragManager;
}
private _buildNodeGraph(model: NodeModel, readOnly: boolean): MainTopic {
private _buildNodeGraph(model: NodeModel, readOnly: boolean): Topic {
// Create node graph ...
const topic = create(model, { readOnly });
const topic = TopicFactory.create(model, { readOnly });
this.getModel().addTopic(topic);
const me = this;
// Add Topic events ...
@ -605,7 +605,7 @@ class Designer extends Events {
this.goToNode(centralTopic);
// Finally, sort the map ...
EventBus.instance.fireEvent(EventBus.events.DoLayout);
EventBus.instance.fireEvent('forceLayout');
this.fireEvent('loadSuccess');
}
@ -694,12 +694,6 @@ class Designer extends Events {
mindmap.deleteRelationship(rel.getModel());
}
/**
* @private
* @param {mindplot.model.RelationshipModel} model
* @return {mindplot.Relationship} the new relationship with events registered
* @throws will throw an error if the target topic cannot be found
*/
private _buildRelationshipShape(model: RelationshipModel): Relationship {
const dmodel = this.getModel();
@ -743,13 +737,9 @@ class Designer extends Events {
return result;
}
/**
* @param {mindplot.Topic} node the topic to remove
* removes the given topic and its children from Workspace, DesignerModel and NodeModel
*/
removeTopic(node) {
removeTopic(node: Topic): void {
if (!node.isCentralTopic()) {
const parent = node._parent;
const parent = node.getParent();
node.disconnect(this._workspace);
// remove children
@ -770,17 +760,13 @@ class Designer extends Events {
}
}
/**
* @private
*/
_resetEdition() {
private _resetEdition() {
const screenManager = this._workspace.getScreenManager();
screenManager.fireEvent('update');
screenManager.fireEvent('mouseup');
this._relPivot.dispose();
}
/** */
deleteSelectedEntities() {
// Is there some action in progress ?.
this._resetEdition();
@ -839,7 +825,7 @@ class Designer extends Events {
/** */
changeBackgroundColor(color: string) {
const validateFunc = (topic) => topic.getShapeType() !== TopicShape.LINE;
const validateFunc = (topic: Topic) => topic.getShapeType() !== TopicShape.LINE;
const validateError = 'Color can not be set to line topics.';
const topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
@ -848,9 +834,8 @@ class Designer extends Events {
}
}
/** */
changeBorderColor(color: string) {
const validateFunc = (topic) => topic.getShapeType() !== TopicShape.LINE;
const validateFunc = (topic: Topic) => topic.getShapeType() !== TopicShape.LINE;
const validateError = 'Color can not be set to line topics.';
const topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
if (topicsIds.length > 0) {
@ -858,7 +843,6 @@ class Designer extends Events {
}
}
/** */
changeFontSize(size: number) {
const topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) {
@ -894,11 +878,7 @@ class Designer extends Events {
}
}
/**
* lets the selected topic open the link editor where the user can define or modify an
* existing link
*/
addLink() {
addLink(): void {
const model = this.getModel();
const topic = model.selectedTopic();
if (topic) {
@ -907,8 +887,7 @@ class Designer extends Events {
}
}
/** */
addNote() {
addNote(): void {
const model = this.getModel();
const topic = model.selectedTopic();
if (topic) {

View File

@ -16,41 +16,50 @@
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import ActionDispatcher from './ActionDispatcher';
import Command from './Command';
import CommandContext from './CommandContext';
import DesignerUndoManager from './DesignerUndoManager';
import EventBus from './layout/EventBus';
class DesignerActionRunner {
constructor(commandContext, notifier) {
private _undoManager: DesignerUndoManager;
private _context: CommandContext;
private _actionDisplatcher: ActionDispatcher;
constructor(commandContext: CommandContext, notifier: ActionDispatcher) {
$assert(commandContext, 'commandContext can not be null');
this._undoManager = new DesignerUndoManager();
this._context = commandContext;
this._notifier = notifier;
this._actionDisplatcher = notifier;
}
execute(command) {
execute(command: Command): void {
$assert(command, 'command can not be null');
command.execute(this._context);
this._undoManager.enqueue(command);
this.fireChangeEvent();
EventBus.instance.fireEvent(EventBus.events.DoLayout);
EventBus.instance.fireEvent('forceLayout');
}
undo() {
undo(): void {
this._undoManager.execUndo(this._context);
this.fireChangeEvent();
EventBus.instance.fireEvent(EventBus.events.DoLayout);
EventBus.instance.fireEvent('forceLayout');
}
redo() {
redo(): void {
this._undoManager.execRedo(this._context);
this.fireChangeEvent();
EventBus.instance.fireEvent(EventBus.events.DoLayout);
EventBus.instance.fireEvent('forceLayout');
}
fireChangeEvent() {
fireChangeEvent(): void {
const event = this._undoManager.buildEvent();
this._notifier.fireEvent('modelUpdate', event);
this._actionDisplatcher.fireEvent('modelUpdate', event);
}
}

View File

@ -19,7 +19,6 @@ import { $assert } from '@wisemapping/core-js';
import $ from 'jquery';
import PersistenceManager from './PersistenceManager';
import Designer from './Designer';
import Menu from './widget/Menu';
import { DesignerOptions } from './DesignerOptionsBuilder';
let designer: Designer;
@ -30,25 +29,12 @@ export function buildDesigner(options: DesignerOptions): Designer {
// Register load events ...
designer = new Designer(options, divContainer);
designer.addEvent('loadSuccess', () => {
console.log('Map loadded successfully');
});
// Configure default persistence manager ...
const persistence = options.persistenceManager;
$assert(persistence, 'persistence must be defined');
PersistenceManager.init(persistence);
// Register toolbar event ...
if ($('#toolbar').length) {
const menu = new Menu(designer, 'toolbar');
// If a node has focus, focus can be move to another node using the keys.
designer.cleanScreen = () => {
menu.clear();
};
}
return designer;
}

View File

@ -16,15 +16,14 @@
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import EditorRenderMode from './EditorRenderMode';
import PersistenceManager from './PersistenceManager';
import SizeType from './SizeType';
export type EditorModeType = 'viewonly' | 'edition' | 'showcase';
export type DesignerOptions = {
zoom: number,
containerSize?: SizeType,
mode: EditorModeType,
mode: EditorRenderMode,
mapId?: string,
container: string,
persistenceManager?: PersistenceManager,
@ -47,7 +46,7 @@ class OptionsBuilder {
}
const defaultOptions: DesignerOptions = {
mode: 'edition',
mode: 'edition-owner',
zoom: 0.85,
saveOnLoad: true,
containerSize,

View File

@ -24,8 +24,6 @@ import Workspace from './Workspace';
class DragManager {
private _workspace: Workspace;
private _designerModel: Workspace;
private _isDragInProcess: boolean;
private _eventDispatcher: EventBusDispatcher;
@ -38,7 +36,6 @@ class DragManager {
constructor(workspace: Workspace, eventDispatcher: EventBusDispatcher) {
this._workspace = workspace;
this._designerModel = workspace;
this._listeners = {};
this._isDragInProcess = false;
this._eventDispatcher = eventDispatcher;
@ -68,7 +65,7 @@ class DragManager {
// Register mouse up listeners ...
const mouseUpListener = dragManager._buildMouseUpListener(
workspace, topic, dragNode, dragManager,
workspace, dragNode, dragManager,
);
screen.addEvent('mouseup', mouseUpListener);
@ -115,7 +112,7 @@ class DragManager {
return result;
}
protected _buildMouseUpListener(workspace: Workspace, topic: Topic, dragNode, dragManager: DragManager) {
protected _buildMouseUpListener(workspace: Workspace, dragNode, dragManager: DragManager) {
const screen = workspace.getScreenManager();
const me = this;
const result = (event: Event) => {
@ -149,13 +146,7 @@ class DragManager {
return result;
}
/**
* type:
* - startdragging.
* - dragging
* - enddragging
*/
addEvent(type: string, listener) {
addEvent(type: 'startdragging' | 'dragging' | 'enddragging', listener) {
this._listeners[type] = listener;
}
}

View File

@ -18,7 +18,6 @@
import { $assert, $defined } from '@wisemapping/core-js';
import { Point, CurvedLine, Rect } from '@wisemapping/web2d';
import DragTopicConfig from './DragTopicConfig';
import SizeType from './SizeType';
import Topic from './Topic';
import Shape from './util/Shape';
@ -43,7 +42,7 @@ class DragPivot {
constructor() {
this._position = new Point();
this._size = DragTopicConfig.PIVOT_SIZE;
this._size = DragPivot.DEFAULT_PIVOT_SIZE;
this._straightLine = this._buildStraightLine();
this._curvedLine = this._buildCurvedLine();
@ -251,6 +250,8 @@ class DragPivot {
this.setVisibility(false);
this._targetTopic = null;
}
static DEFAULT_PIVOT_SIZE = { width: 50, height: 6 };
}
export default DragPivot;

View File

@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { $assert, $defined } from '@wisemapping/core-js';
import { $assert } from '@wisemapping/core-js';
import { Point, ElementClass } from '@wisemapping/web2d';
import ActionDispatcher from './ActionDispatcher';
@ -27,12 +27,19 @@ import Workspace from './Workspace';
class DragTopic {
private _elem2d: ElementClass;
private _order: number | null;
private _draggedNode: NodeGraph;
private _layoutManager: LayoutManager;
private _position: any;
private _position: Point;
private _isInWorkspace: boolean;
static _dragPivot: any;
static _dragPivot: DragPivot = new DragPivot();
constructor(dragShape: ElementClass, draggedNode: NodeGraph, layoutManger: LayoutManager) {
$assert(dragShape, 'Rect can not be null.');
$assert(draggedNode, 'draggedNode can not be null.');
@ -46,13 +53,13 @@ class DragTopic {
this._isInWorkspace = false;
}
setOrder(order: number) {
setOrder(order: number): void {
this._order = order;
}
setPosition(x: number, y: number) {
setPosition(x: number, y: number): void {
// Update drag shadow position ....
let position = { x, y };
const position = { x, y };
this._position.setValue(position.x, position.y);
// Elements are positioned in the center.
@ -104,11 +111,7 @@ class DragTopic {
$assert(parent, 'Parent connection node can not be null.');
// Where it should be connected ?
// @todo: This is a hack for the access of the editor.
// It's required to review why this is needed forcing the declaration of a global variable.
const predict = global.designer._eventBussDispatcher._layoutManager.predict(
const predict = this._layoutManager.predict(
parent.getId(),
this._draggedNode.getId(),
this.getPosition(),
@ -154,8 +157,8 @@ class DragTopic {
}
}
_getDragPivot(): DragPivot {
return DragTopic.__getDragPivot();
private _getDragPivot(): DragPivot {
return DragTopic._dragPivot;
}
getPosition(): Point {
@ -206,18 +209,9 @@ class DragTopic {
static init(workspace: Workspace) {
$assert(workspace, 'workspace can not be null');
const pivot = DragTopic.__getDragPivot();
const pivot = DragTopic._dragPivot;
workspace.append(pivot);
};
static __getDragPivot() {
let result = DragTopic._dragPivot;
if (!$defined(result)) {
result = new DragPivot();
DragTopic._dragPivot = result;
}
return result;
};
}
}
export default DragTopic;

View File

@ -1,5 +0,0 @@
const PIVOT_SIZE = { width: 50, height: 6 };
export default {
PIVOT_SIZE,
};

View File

@ -17,20 +17,21 @@
*/
class EditorProperties {
private _zoom: number;
constructor() {
this._zoom = 0;
this._position = 0;
}
setZoom(zoom) {
setZoom(zoom: number) {
this._zoom = zoom;
}
getZoom() {
getZoom(): number {
return this._zoom;
}
asProperties() {
asProperties(): string {
return `zoom=${this._zoom}\n`;
}
}

View File

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

View File

@ -17,24 +17,24 @@
*/
class Events {
private $events;
private _handlerByType;
constructor() {
this.$events = {};
this._handlerByType = {};
}
static _removeOn(string: string) {
return string.replace(/^on([A-Z])/, (full, first) => first.toLowerCase());
static _normalizeEventName(string: string) {
return string.replace(/^on([A-Z])/, (_full, first) => first.toLowerCase());
}
addEvent(typeName: string, fn?, internal?: boolean): Events {
const type = Events._removeOn(typeName);
const type = Events._normalizeEventName(typeName);
// Add function had not been added yet
const funByType = this.$events[type] ? this.$events[type] : [];
const funByType = this._handlerByType[type] ? this._handlerByType[type] : [];
if (!funByType.includes(fn)) {
funByType.push(fn);
this.$events[type] = funByType;
this._handlerByType[type] = funByType;
}
// Mark reference ...
@ -42,25 +42,21 @@ class Events {
return this;
}
fireEvent(typeName: string, eventArgs?, delay?: boolean): Events {
const type = Events._removeOn(typeName);
const events = this.$events[type];
fireEvent(typeName: string, eventArgs?): Events {
const type = Events._normalizeEventName(typeName);
const events = this._handlerByType[type];
if (!events) return this;
const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs];
events.forEach(((fn) => {
if (delay) {
fn.delay(delay, this, args);
} else {
fn.apply(this, args);
}
fn.apply(this, args);
}));
return this;
}
removeEvent(typeName: string, fn?): Events {
const type = Events._removeOn(typeName);
const events = this.$events[type];
const type = Events._normalizeEventName(typeName);
const events = this._handlerByType[type];
if (events && !fn.internal) {
const index = events.indexOf(fn);
if (index !== -1) events.splice(index, 1);

View File

@ -16,14 +16,14 @@
* limitations under the License.
*/
import { $assert } from '@wisemapping/core-js';
import { Image } from '@wisemapping/web2d';
import { Image, Point } from '@wisemapping/web2d';
import IconGroup from './IconGroup';
import { Point } from '@wisemapping/web2d';
import SizeType from './SizeType';
import FeatureModel from './model/FeatureModel';
abstract class Icon {
protected _image: Image;
protected _group: IconGroup;
constructor(url: string) {

View File

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

View File

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

View File

@ -19,21 +19,23 @@ import { $defined } from '@wisemapping/core-js';
import Bundle from './lang/Bundle';
class Messages {
static init(locale) {
public static __bundle;
static init(locale: string) {
console.log(`Init designer message: ${locale}`);
let userLocale = $defined(locale) ? locale : 'en';
let bundle = Bundle[locale];
let bundle = Bundle[userLocale];
if (bundle == null && locale.indexOf('_') !== -1) {
// Try to locate without the specialization ...
userLocale = locale.substring(0, locale.indexOf('_'));
bundle = Bundle[locale];
bundle = Bundle[userLocale];
}
global.locale = userLocale;
Messages.__bundle = bundle || {};
this.__bundle = bundle;
}
}
const $msg = function $msg(key) {
const $msg = function $msg(key: string) {
if (!Messages.__bundle) {
Messages.init('en');
}

View File

@ -144,7 +144,13 @@ class MultilineTextEditor extends Events {
const topicId = this._topic.getId();
const actionDispatcher = ActionDispatcher.getInstance();
actionDispatcher.changeTextToTopic([topicId], text);
try {
actionDispatcher.changeTextToTopic([topicId], text);
} catch (e) {
// Hack: For some reasom, editor seems to end up connexted to a deleted node.
// More research required.
console.error(`Text could not be update -> ${JSON.stringify(e)}`);
}
}
}

View File

@ -161,7 +161,7 @@ abstract class NodeGraph {
createDragNode(layoutManager: LayoutManager) {
const dragShape = this._buildDragShape();
return new DragTopic(dragShape, this, layoutManager);
}

View File

@ -1,37 +0,0 @@
import { $assert } from '@wisemapping/core-js';
import CentralTopic from './CentralTopic';
import MainTopic from './MainTopic';
/**
* creates a new topic from the given node model
* @memberof mindplot.Nodegraph
* @param {mindplot.model.NodeModel} nodeModel
* @param {Object} options
* @throws will throw an error if nodeModel is null or undefined
* @throws will throw an error if the nodeModel's type is null or undefined
* @throws will throw an error if the node type cannot be recognized as either central or main
* topic type
* @return {mindplot.CentralTopic|mindplot.MainTopic} the new topic
*/
export const create = (nodeModel, options) => {
$assert(nodeModel, 'Model can not be null');
const type = nodeModel.getType();
$assert(type, 'Node model type can not be null');
let result;
if (type === 'CentralTopic') {
result = new CentralTopic(nodeModel, options);
} else if (type === 'MainTopic') {
result = new MainTopic(nodeModel, options);
} else {
$assert(false, `unsupported node type:${type}`);
}
return result;
};
export default {
create,
};

View File

@ -19,16 +19,19 @@ import { $assert } from '@wisemapping/core-js';
import $ from 'jquery';
import { $msg } from './Messages';
import Icon from './Icon';
import FloatingTip from './widget/FloatingTip';
import NotesImage from '../../assets/icons/notes.svg';
import Topic from './Topic';
import NoteModel from './model/NoteModel';
import FeatureModel from './model/FeatureModel';
import FloatingTip from './widget/FloatingTip';
class NoteIcon extends Icon {
private _linksModel: NoteModel;
private _topic: Topic;
private _readOnly: boolean;
private _tip: FloatingTip;
constructor(topic: Topic, noteModel: NoteModel, readOnly: boolean) {
@ -53,9 +56,9 @@ class NoteIcon extends Icon {
event.stopPropagation();
});
}
this._tip = new FloatingTip($(me.getImage().peer._native), {
title: $msg('NOTE'),
container: 'body',
// Content can also be a function of the target element!
content() {
return me._buildTooltipContent();
@ -88,7 +91,6 @@ class NoteIcon extends Icon {
}
static IMAGE_URL = NotesImage;
}
export default NoteIcon;

View File

@ -277,10 +277,10 @@ class Relationship extends ConnectionLine {
return this._isInWorkspace;
}
setVisibility(value: boolean) {
super.setVisibility(value);
setVisibility(value: boolean, fade = 0) {
super.setVisibility(value, fade);
if (this._showEndArrow) this._endArrow.setVisibility(this._showEndArrow);
this._startArrow.setVisibility(this._showStartArrow && value);
this._startArrow.setVisibility(this._showStartArrow && value, fade);
}
setOpacity(opacity: number) {

View File

@ -78,8 +78,8 @@ class ShirinkConnector {
this._isShrink = isShrink;
}
setVisibility(value: boolean): void {
this._ellipse.setVisibility(value);
setVisibility(value: boolean, fade = 0): void {
this._ellipse.setVisibility(value, fade);
}
setOpacity(opacity: number): void {

View File

@ -81,7 +81,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
const commandFunc = (topic: Topic, pos: Point) => {
const result = topic.getPosition();
EventBus.instance.fireEvent(EventBus.events.NodeMoveEvent, {
EventBus.instance.fireEvent('topicMoved', {
node: topic.getModel(),
position: pos,
});
@ -110,8 +110,7 @@ class StandaloneActionDispatcher extends ActionDispatcher {
this.execute(command);
}
/** */
changeTextToTopic(topicsIds: number[], text: string) {
changeTextToTopic(topicsIds: number[], text: string): void {
$assert($defined(topicsIds), 'topicsIds can not be null');
const commandFunc = (topic: Topic, value: string) => {
@ -252,7 +251,6 @@ class StandaloneActionDispatcher extends ActionDispatcher {
this.execute(command);
}
/** */
addFeatureToTopic(topicId: number, featureType: FeatureType, attributes) {
const command = new AddFeatureToTopicCommand(topicId, featureType, attributes);
this.execute(command);

View File

@ -28,7 +28,6 @@ import TopicStyle from './TopicStyle';
import TopicFeatureFactory from './TopicFeature';
import ConnectionLine from './ConnectionLine';
import IconGroup from './IconGroup';
import FadeEffect from './util/FadeEffect';
import EventBus from './layout/EventBus';
import ShirinkConnector from './ShrinkConnector';
import NoteEditor from './widget/NoteEditor';
@ -337,11 +336,6 @@ abstract class Topic extends NodeGraph {
return result;
}
/**
* assigns the new feature model to the topic's node model and adds the respective icon
* @param {mindplot.model.FeatureModel} featureModel
* @return {mindplot.Icon} the icon corresponding to the feature model
*/
addFeature(featureModel: FeatureModel): Icon {
const iconGroup = this.getOrBuildIconGroup();
this.closeEditors();
@ -350,7 +344,7 @@ abstract class Topic extends NodeGraph {
const model = this.getModel();
model.addFeature(featureModel);
const result = TopicFeatureFactory.createIcon(this, featureModel, this.isReadOnly());
const result: Icon = TopicFeatureFactory.createIcon(this, featureModel, this.isReadOnly());
iconGroup.addIcon(
result,
featureModel.getType() === TopicFeatureFactory.Icon.id && !this.isReadOnly(),
@ -360,7 +354,6 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
findFeatureById(id: number) {
const model = this.getModel();
return model.findFeatureById(id);
@ -431,7 +424,6 @@ abstract class Topic extends NodeGraph {
this.adjustShapes();
}
/** */
setFontSize(value: number, updateModel?: boolean) {
const textShape = this.getTextShape();
textShape.setSize(value);
@ -443,8 +435,7 @@ abstract class Topic extends NodeGraph {
this.adjustShapes();
}
/** */
setFontStyle(value, updateModel) {
setFontStyle(value: string, updateModel?: boolean) {
const textShape = this.getTextShape();
textShape.setStyle(value);
if ($defined(updateModel) && updateModel) {
@ -454,8 +445,7 @@ abstract class Topic extends NodeGraph {
this.adjustShapes();
}
/** */
setFontWeight(value, updateModel) {
setFontWeight(value: string, updateModel?: boolean) {
const textShape = this.getTextShape();
textShape.setWeight(value);
if ($defined(updateModel) && updateModel) {
@ -465,7 +455,6 @@ abstract class Topic extends NodeGraph {
this.adjustShapes();
}
/** */
getFontWeight() {
const model = this.getModel();
let result = model.getFontWeight();
@ -476,8 +465,7 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
getFontFamily() {
getFontFamily(): string {
const model = this.getModel();
let result = model.getFontFamily();
if (!$defined(result)) {
@ -487,8 +475,7 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
getFontColor() {
getFontColor(): string {
const model = this.getModel();
let result = model.getFontColor();
if (!$defined(result)) {
@ -498,8 +485,7 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
getFontStyle() {
getFontStyle(): string {
const model = this.getModel();
let result = model.getFontStyle();
if (!$defined(result)) {
@ -509,8 +495,7 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
getFontSize() {
getFontSize(): number {
const model = this.getModel();
let result = model.getFontSize();
if (!$defined(result)) {
@ -520,8 +505,7 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
setFontColor(value, updateModel) {
setFontColor(value: string, updateModel?: boolean) {
const textShape = this.getTextShape();
textShape.setColor(value);
if ($defined(updateModel) && updateModel) {
@ -530,7 +514,7 @@ abstract class Topic extends NodeGraph {
}
}
_setText(text: string, updateModel: boolean) {
private _setText(text: string, updateModel?: boolean) {
const textShape = this.getTextShape();
textShape.setText(text == null ? TopicStyle.defaultText(this) : text);
@ -540,7 +524,6 @@ abstract class Topic extends NodeGraph {
}
}
/** */
setText(text: string) {
// Avoid empty nodes ...
if (!text || $.trim(text).length === 0) {
@ -552,7 +535,6 @@ abstract class Topic extends NodeGraph {
this.adjustShapes();
}
/** */
getText(): string {
const model = this.getModel();
let result = model.getText();
@ -562,12 +544,11 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
setBackgroundColor(color: string) {
this._setBackgroundColor(color, true);
}
_setBackgroundColor(color: string, updateModel: boolean) {
private _setBackgroundColor(color: string, updateModel: boolean) {
const innerShape = this.getInnerShape();
innerShape.setFill(color);
@ -593,11 +574,11 @@ abstract class Topic extends NodeGraph {
}
/** */
setBorderColor(color: string) {
setBorderColor(color: string): void {
this._setBorderColor(color, true);
}
_setBorderColor(color: string, updateModel: boolean) {
private _setBorderColor(color: string, updateModel: boolean): void {
const innerShape = this.getInnerShape();
innerShape.setAttribute('strokeColor', color);
@ -612,8 +593,7 @@ abstract class Topic extends NodeGraph {
}
}
/** */
getBorderColor() {
getBorderColor(): string {
const model = this.getModel();
let result = model.getBorderColor();
if (!$defined(result)) {
@ -622,7 +602,7 @@ abstract class Topic extends NodeGraph {
return result;
}
_buildTopicShape() {
_buildTopicShape(): ElementClass {
const groupAttributes = {
width: 100,
height: 100,
@ -660,17 +640,17 @@ abstract class Topic extends NodeGraph {
group.setTestId(model.getId());
}
_registerDefaultListenersToElement(elem, topic) {
const mouseOver = function mouseOver(event) {
_registerDefaultListenersToElement(elem: ElementClass, topic: Topic) {
const mouseOver = function mouseOver() {
if (topic.isMouseEventsEnabled()) {
topic.handleMouseOver(event);
topic.handleMouseOver();
}
};
elem.addEvent('mouseover', mouseOver);
const outout = function outout(event) {
const outout = function outout() {
if (topic.isMouseEventsEnabled()) {
topic.handleMouseOut(event);
topic.handleMouseOut();
}
};
elem.addEvent('mouseout', outout);
@ -697,13 +677,12 @@ abstract class Topic extends NodeGraph {
}
/** */
areChildrenShrunken() {
areChildrenShrunken(): boolean {
const model = this.getModel();
return model.areChildrenShrunken() && !this.isCentralTopic();
}
/** */
isCollapsed() {
isCollapsed(): boolean {
let result = false;
let current = this.getParent();
@ -714,42 +693,27 @@ abstract class Topic extends NodeGraph {
return result;
}
/** */
setChildrenShrunken(value) {
setChildrenShrunken(value: boolean) {
// Update Model ...
const model = this.getModel();
model.setChildrenShrunken(value);
// Change render base on the state.
const shrinkConnector = this.getShrinkConnector();
if ($defined(shrinkConnector)) {
if (shrinkConnector) {
shrinkConnector.changeRender(value);
}
// Do some fancy animation ....
const elements = this._flatten2DElements(this);
const fade = new FadeEffect(elements, !value);
const me = this;
fade.addEvent('complete', () => {
// Set focus on the parent node ...
if (value) {
me.setOnFocus(true);
}
// Set focus in false for all the children ...
elements.forEach((elem) => {
if (elem.setOnFocus) {
elem.setOnFocus(false);
}
});
elements.forEach((elem) => {
elem.setVisibility(!value, 250);
});
fade.start();
EventBus.instance.fireEvent(EventBus.events.NodeShrinkEvent, model);
EventBus.instance.fireEvent('childShrinked', model);
}
/** */
getShrinkConnector(): ShirinkConnector {
getShrinkConnector(): ShirinkConnector | undefined {
let result = this._connector;
if (this._connector == null) {
this._connector = new ShirinkConnector(this);
@ -928,7 +892,6 @@ abstract class Topic extends NodeGraph {
this._relationships.forEach((r) => r.redraw());
}
/** */
setBranchVisibility(value: boolean): void {
let current: Topic = this;
let parent: Topic = this;
@ -939,20 +902,19 @@ abstract class Topic extends NodeGraph {
current.setVisibility(value);
}
/** */
setVisibility(value: boolean): void {
this._setTopicVisibility(value);
setVisibility(value: boolean, fade = 0): void {
this._setTopicVisibility(value, fade);
// Hide all children...
this._setChildrenVisibility(value);
this._setChildrenVisibility(value, fade);
// If there there are connection to the node, topic must be hidden.
this._setRelationshipLinesVisibility(value);
this._setRelationshipLinesVisibility(value, fade);
// If it's connected, the connection must be rendered.
const outgoingLine = this.getOutgoingLine();
if (outgoingLine) {
outgoingLine.setVisibility(value);
outgoingLine.setVisibility(value, fade);
}
}
@ -986,7 +948,7 @@ abstract class Topic extends NodeGraph {
return elem.isVisible();
}
private _setRelationshipLinesVisibility(value: boolean): void {
private _setRelationshipLinesVisibility(value: boolean, fade = 0): void {
this._relationships.forEach((relationship) => {
const sourceTopic = relationship.getSourceTopic();
const targetTopic = relationship.getTargetTopic();
@ -997,27 +959,28 @@ abstract class Topic extends NodeGraph {
value
&& (targetParent == null || !targetParent.areChildrenShrunken())
&& (sourceParent == null || !sourceParent.areChildrenShrunken()),
fade,
);
});
}
private _setTopicVisibility(value: boolean) {
private _setTopicVisibility(value: boolean, fade = 0) {
const elem = this.get2DElement();
elem.setVisibility(value);
elem.setVisibility(value, fade);
if (this.getIncomingLines().length > 0) {
const connector = this.getShrinkConnector();
if ($defined(connector)) {
connector.setVisibility(value);
connector.setVisibility(value, fade);
}
}
// Hide inner shape ...
this.getInnerShape().setVisibility(value);
this.getInnerShape().setVisibility(value, fade);
// Hide text shape ...
const textShape = this.getTextShape();
textShape.setVisibility(this.getShapeType() !== TopicShape.IMAGE ? value : false);
textShape.setVisibility(this.getShapeType() !== TopicShape.IMAGE ? value : false, fade);
}
/** */
@ -1033,14 +996,14 @@ abstract class Topic extends NodeGraph {
textShape.setOpacity(opacity);
}
private _setChildrenVisibility(isVisible: boolean) {
private _setChildrenVisibility(value: boolean, fade = 0) {
// Hide all children.
const children = this.getChildren();
const model = this.getModel();
const visibility = isVisible ? !model.areChildrenShrunken() : isVisible;
const visibility = value ? !model.areChildrenShrunken() : value;
children.forEach((child) => {
child.setVisibility(visibility);
child.setVisibility(visibility, fade);
const outgoingLine = child.getOutgoingLine();
outgoingLine.setVisibility(visibility);
});
@ -1081,7 +1044,7 @@ abstract class Topic extends NodeGraph {
this._updatePositionOnChangeSize(oldSize, roundedSize);
if (hasSizeChanged) {
EventBus.instance.fireEvent(EventBus.events.NodeResizeEvent, {
EventBus.instance.fireEvent('topicResize', {
node: this.getModel(),
size: roundedSize,
});
@ -1112,7 +1075,7 @@ abstract class Topic extends NodeGraph {
outgoingLine.removeFromWorkspace(workspace);
// Remove from workspace.
EventBus.instance.fireEvent(EventBus.events.NodeDisconnectEvent, this.getModel());
EventBus.instance.fireEvent('topicDisconect', this.getModel());
// Change text based on the current connection ...
const model = this.getModel();
@ -1195,7 +1158,7 @@ abstract class Topic extends NodeGraph {
// Fire connection event ...
if (this.isInWorkspace()) {
EventBus.instance.fireEvent(EventBus.events.NodeConnectEvent, {
EventBus.instance.fireEvent('topicConnected', {
parentNode: targetTopic.getModel(),
childNode: this.getModel(),
});
@ -1233,7 +1196,7 @@ abstract class Topic extends NodeGraph {
workspace.removeChild(line);
}
this._isInWorkspace = false;
EventBus.instance.fireEvent(EventBus.events.NodeRemoved, this.getModel());
EventBus.instance.fireEvent('topicRemoved', this.getModel());
}
addToWorkspace(workspace: Workspace) {
@ -1241,11 +1204,11 @@ abstract class Topic extends NodeGraph {
workspace.append(elem);
if (!this.isInWorkspace()) {
if (!this.isCentralTopic()) {
EventBus.instance.fireEvent(EventBus.events.NodeAdded, this.getModel());
EventBus.instance.fireEvent('topicAdded', this.getModel());
}
if (this.getModel().isConnected()) {
EventBus.instance.fireEvent(EventBus.events.NodeConnectEvent, {
EventBus.instance.fireEvent('topicConnected', {
parentNode: this.getOutgoingConnectedTopic().getModel(),
childNode: this.getModel(),
});
@ -1315,7 +1278,7 @@ abstract class Topic extends NodeGraph {
}
}
private _flatten2DElements(topic: Topic) {
private _flatten2DElements(topic: Topic): (Topic | Relationship)[] {
let result = [];
const children = topic.getChildren();

View File

@ -0,0 +1,27 @@
import { $assert } from '@wisemapping/core-js';
import CentralTopic from './CentralTopic';
import MainTopic from './MainTopic';
import NodeModel from './model/NodeModel';
import Topic from './Topic';
class TopicFactory {
static create(nodeModel: NodeModel, options: object): Topic {
$assert(nodeModel, 'Model can not be null');
const type = nodeModel.getType();
$assert(type, 'Node model type can not be null');
let result: Topic;
if (type === 'CentralTopic') {
result = new CentralTopic(nodeModel, options);
} else if (type === 'MainTopic') {
result = new MainTopic(nodeModel, options);
} else {
$assert(false, `unsupported node type:${type}`);
}
return result;
}
}
export default TopicFactory;

View File

@ -40,14 +40,6 @@ const TopicFeatureFactory = {
icon: NoteIcon,
},
/**
* @param {mindplot.Topic} topic
* @param {mindplot.model.FeatureModel} model
* @param {Boolean} readOnly true if the editor is running in read-only mode
* @throws will throw an error if topic is null or undefined
* @throws will throw an error if model is null or undefined
* @return {mindplot.Icon} a new instance of the icon subclass matching the topic feature
*/
createIcon(topic, model, readOnly) {
$assert(topic, 'topic can not be null');
$assert(model, 'model can not be null');

View File

@ -52,9 +52,6 @@ class AddFeatureToTopicCommand extends Command {
this._featureModel = null;
}
/**
* Overrides abstract parent method
*/
execute(commandContext: CommandContext) {
const topic = commandContext.findTopics([this._topicId])[0];
@ -66,10 +63,6 @@ class AddFeatureToTopicCommand extends Command {
topic.addFeature(this._featureModel);
}
/**
* Overrides abstract parent method
* @see {@link mindplot.Command.undoExecute}
*/
undoExecute(commandContext: CommandContext) {
const topic = commandContext.findTopics([this._topicId])[0];
topic.removeFeature(this._featureModel);

View File

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

View File

@ -20,12 +20,14 @@ import ES from './es';
import EN from './en';
import DE from './de';
import FR from './fr';
import RU from './ru';
const Bundle = {
es: ES,
en: EN,
de: DE,
fr: FR,
ru: RU,
};
export default Bundle;

View File

@ -1,80 +0,0 @@
ZOOM_IN = 'Ansicht vergrößern',
ZOOM_OUT = 'Ansicht verkleinern',
TOPIC_SHAPE = 'Themen Gestaltung',
TOPIC_ADD = 'Thema hinzufügen',
TOPIC_DELETE = 'Thema löschen',
TOPIC_ICON = 'Symbol hinzufügen',
TOPIC_LINK = 'Verbindung hinzufügen',
TOPIC_RELATIONSHIP = 'Beziehung',
TOPIC_COLOR = 'Themenfarbe',
TOPIC_BORDER_COLOR = 'Thema Randfarbe',
TOPIC_NOTE = 'Notiz hinzufügen',
FONT_FAMILY = 'Schrifttyp',
FONT_SIZE = 'Schriftgröße',
FONT_BOLD = 'Fette Schrift',
FONT_ITALIC = 'Kursive Schrift',
UNDO = 'Rückgängig machen',
REDO = 'Wiederholen',
INSERT = 'Einfügen',
SAVE = 'Sichern',
NOTE = 'Notiz',
ADD_TOPIC = 'Thema hinzufügen',
LOADING = 'Laden ...',
EXPORT = 'Exportieren',
PRINT = 'Drucken',
PUBLISH = 'Publizieren',
COLLABORATE = 'Mitbenutzen',
HISTORY = 'Historie',
DISCARD_CHANGES = 'Änderungen verwerfen',
FONT_COLOR = 'Textfarbe',
SAVING = 'Sichern ...',
SAVE_COMPLETE = 'Sichern abgeschlossen',
ZOOM_IN_ERROR = 'Zoom zu hoch.',
ZOOM_ERROR = 'Es kann nicht weiter vergrößert bzw. verkelinert werden.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED = 'Thema konnte nicht angelegt werden. Bitte wählen Sie nur ein Thema aus.',
ONE_TOPIC_MUST_BE_SELECTED = 'Thema konnte nicht angelegt werden. Es muss ein Thema ausgewählt werden.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE = 'Kinderknoten können nicht eingefaltet werden. Es muss ein Thema ausgewäht werden.',
SAVE_COULD_NOT_BE_COMPLETED = 'Sichern wurde nicht abgeschlossen. Versuchen Sie es später nocheinmal.',
UNEXPECTED_ERROR_LOADING = 'E tut uns Leid, ein unerwarteter Fehler ist aufgetreten.\nVersuchen Sie, den Editor neu zu laden. Falls das Problem erneut auftritt, bitte kontaktieren Sie uns unter support@wisemapping.com.',
MAIN_TOPIC = 'Hauptthema',
SUB_TOPIC = 'Unterthema',
ISOLATED_TOPIC = 'Isoliertes Thema',
CENTRAL_TOPIC = 'Zentrales Thema',
SHORTCUTS = 'Tastaturkürzel',
ENTITIES_COULD_NOT_BE_DELETED = 'Konnte das Thema oder die Beziehung nicht löschen. Es muss mindest ein Eintrag ausgewählt sein.',
AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED = 'Es muss mindestens ein Thema ausgewählt sein.',
CLIPBOARD_IS_EMPTY = 'Es gibt nichts zu kopieren. Die Zwischenablage ist leer.',
CENTRAL_TOPIC_CAN_NOT_BE_DELETED = 'Das zentrale Thema kann nicht gelöscht werden.',
RELATIONSHIP_COULD_NOT_BE_CREATED = 'Die Beziehung konnte nicht angelegt werden. Es muss erst ein Vater-Thema ausgewählt werden, um die Beziehung herzustellen.',
SELECTION_COPIED_TO_CLIPBOARD = 'Themen in der Zwischenablage',
WRITE_YOUR_TEXT_HERE = 'Schreiben Sie ihre Notiz hier ...',
REMOVE = 'Entfernen',
ACCEPT = 'Akzeptieren',
CANCEL = 'Abbrechen',
LINK = 'Verbindung',
OPEN_LINK = 'Öffne URL',
SESSION_EXPIRED = 'Ihre Sitzung ist abgelaufen, bitte melden Sie sich erneut an.',
URL_ERROR = 'URL nicht gültig',
ACTION = 'Aktion',
CREATE_SIBLING_TOPIC = 'Erzeuge ein Schwester Thema',
CREATE_CHILD_TOPIC = 'Eryeuge ein Unterthema',
DELETE_TOPIC = 'Lösche Thema',
EDIT_TOPIC_TEXT = 'Editiere Thematext',
JUST_START_TYPING = 'Einfach mit der Eingabe beginnen',
CANCEL_TEXT_CHANGES = 'Textänderungen abbrechen',
TOPIC_NAVIGATION = 'Themen Navigation',
ARROW_KEYS = 'Pfeiltasten',
SELECT_MULTIPLE_NODES = 'Wähle mehrfache Knoten aus',
UNDO_EDITION = 'Änderungen rückgängig machen',
REDO_EDITION = 'Änderung nochmal ausführen',
SELECT_ALL_TOPIC = 'Wähle alle Themen aus',
CHANGE_TEXT_BOLD = 'Ändere Text in fette Schrift',
SAVE_CHANGES = 'Änderungen sichern',
CHANGE_TEXT_ITALIC = 'Ändere Text in kursive Schrift',
DESELECT_ALL_TOPIC = 'Deselektiere alle Themen',
COLLAPSE_CHILDREN = 'Kindknoten zusammenklappen',
KEYBOARD_SHORTCUTS_MSG = 'Tastenkürzel helfen Zeit zu sparen und erlauben die Arbeit nur mit der Tatstatur, s.d. Sie niemals die Hand von der Tastatur nehmen müßen, um die Maus zu bedienen.',
COPY_AND_PASTE_TOPICS = 'Kopieren und Einsetzen von Themen',
MULTIPLE_LINES = 'Füge mehrer Textzeilen hinzu',
BACK_TO_MAP_LIST = 'Zurück zur Kartenliste',
KEYBOARD_SHOTCUTS = 'Tastaturkürzel',

View File

@ -1,80 +0,0 @@
ZOOM_IN = 'Zoom In',
ZOOM_OUT = 'Zoom Out',
TOPIC_SHAPE = 'Topic Shape',
TOPIC_ADD = 'Add Topic',
TOPIC_DELETE = 'Delete Topic',
TOPIC_ICON = 'Add Icon',
TOPIC_LINK = 'Add Link',
TOPIC_RELATIONSHIP = 'Relationship',
TOPIC_COLOR = 'Topic Color',
TOPIC_BORDER_COLOR = 'Topic Border Color',
TOPIC_NOTE = 'Add Note',
FONT_FAMILY = 'Font Type',
FONT_SIZE = 'Text Size',
FONT_BOLD = 'Text Bold',
FONT_ITALIC = 'Text Italic',
UNDO = 'Undo',
REDO = 'Redo',
INSERT = 'Insert',
SAVE = 'Save',
NOTE = 'Note',
ADD_TOPIC = 'Add Topic',
LOADING = 'Loading ...',
EXPORT = 'Export',
PRINT = 'Print',
PUBLISH = 'Publish',
COLLABORATE = 'Share',
HISTORY = 'History',
DISCARD_CHANGES = 'Discard Changes',
FONT_COLOR = 'Text Color',
SAVING = 'Saving ...',
SAVE_COMPLETE = 'Save Complete',
ZOOM_IN_ERROR = 'Zoom too high.',
ZOOM_ERROR = 'No more zoom can be applied.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED = 'Could not create a topic. Only one topic must be selected.',
ONE_TOPIC_MUST_BE_SELECTED = 'Could not create a topic. One topic must be selected.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE = 'Children can not be collapsed. One topic must be selected.',
SAVE_COULD_NOT_BE_COMPLETED = 'Save could not be completed, please try again latter.',
UNEXPECTED_ERROR_LOADING = "We're sorry, an unexpected error has occurred.\nTry again reloading the editor.If the problem persists, contact us to support@wisemapping.com.",
MAIN_TOPIC = 'Main Topic',
SUB_TOPIC = 'Sub Topic',
ISOLATED_TOPIC = 'Isolated Topic',
CENTRAL_TOPIC = 'Central Topic',
SHORTCUTS = 'Keyboard Shortcuts',
ENTITIES_COULD_NOT_BE_DELETED = 'Could not delete topic or relation. At least one map entity must be selected.',
AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED = 'At least one topic must be selected.',
CLIPBOARD_IS_EMPTY = 'Nothing to copy. Clipboard is empty.',
CENTRAL_TOPIC_CAN_NOT_BE_DELETED = 'Central topic can not be deleted.',
RELATIONSHIP_COULD_NOT_BE_CREATED = 'Relationship could not be created. A parent relationship topic must be selected first.',
SELECTION_COPIED_TO_CLIPBOARD = 'Topics copied to the clipboard',
WRITE_YOUR_TEXT_HERE = 'Write your note here ...',
REMOVE = 'Remove',
ACCEPT = 'Accept',
CANCEL = 'Cancel',
LINK = 'Link',
OPEN_LINK = 'Open URL',
SESSION_EXPIRED = 'Your session has expired, please log-in again.',
URL_ERROR = 'URL not valid',
ACTION = 'Action',
CREATE_SIBLING_TOPIC = 'Create Sibling Topic',
CREATE_CHILD_TOPIC = 'Create Child Topic',
DELETE_TOPIC = 'Delete Topic',
EDIT_TOPIC_TEXT = 'Edit Topic Text',
JUST_START_TYPING = 'Just start typing',
CANCEL_TEXT_CHANGES = 'Cancel Text Changes',
TOPIC_NAVIGATION = 'Topic Navigation',
ARROW_KEYS = 'Arrow Keys',
SELECT_MULTIPLE_NODES = 'Select Multiple Nodes',
UNDO_EDITION = 'Undo Edition',
REDO_EDITION = 'Redo Edition',
SELECT_ALL_TOPIC = 'Select All Topic',
CHANGE_TEXT_BOLD = 'Change Text Bold Type',
SAVE_CHANGES = 'Save Changes',
CHANGE_TEXT_ITALIC = 'Change Text Italic',
DESELECT_ALL_TOPIC = 'Deselect All Topic',
COLLAPSE_CHILDREN = 'Collapse Children',
KEYBOARD_SHORTCUTS_MSG = 'Keyboard shortcuts can help you save time by allowing you to never take your hands off the keyboard to use the mouse.',
COPY_AND_PASTE_TOPICS = 'Copy and Paste Topics',
MULTIPLE_LINES = 'Add multiple text lines',
BACK_TO_MAP_LIST = 'Back to Maps List',
KEYBOARD_SHOTCUTS = 'Keyboard Shorcuts',

View File

@ -1,80 +0,0 @@
ZOOM_IN = 'Acercar',
ZOOM_OUT = 'Alejar',
TOPIC_SHAPE = 'Forma del Tópico',
TOPIC_ADD = 'Agregar Tópico',
TOPIC_DELETE = 'Borrar Tópico',
TOPIC_ICON = 'Agregar Icono',
TOPIC_LINK = 'Agregar Enlace',
TOPIC_RELATIONSHIP = 'Relación',
TOPIC_COLOR = 'Color Tópico',
TOPIC_BORDER_COLOR = 'Color del Borde',
TOPIC_NOTE = 'Agregar Nota',
FONT_FAMILY = 'Tipo de Fuente',
FONT_SIZE = 'Tamaño de Texto',
FONT_BOLD = 'Negrita',
FONT_ITALIC = 'Italica',
UNDO = 'Rehacer',
REDO = 'Deshacer',
INSERT = 'Insertar',
SAVE = 'Guardar',
NOTE = 'Nota',
ADD_TOPIC = 'Agregar Tópico',
LOADING = 'Cargando ...',
EXPORT = 'Exportar',
PRINT = 'Imprimir',
PUBLISH = 'Publicar',
COLLABORATE = 'Compartir',
HISTORY = 'Historial',
DISCARD_CHANGES = 'Descartar Cambios',
FONT_COLOR = 'Color de Texto',
SAVING = 'Grabando ...',
SAVE_COMPLETE = 'Grabado Completo',
ZOOM_IN_ERROR = 'El zoom es muy alto.',
ZOOM_ERROR = 'No es posible aplicar mas zoom.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED = 'No ha sido posible crear un nuevo tópico. Sólo un tópico debe ser seleccionado.',
ONE_TOPIC_MUST_BE_SELECTED = 'No ha sido posible crear un nuevo tópico. Al menos un tópico debe ser seleccionado.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE = 'Tópicos hijos no pueden ser colapsados. Sólo un tópico debe ser seleccionado.',
SAVE_COULD_NOT_BE_COMPLETED = 'Grabación no pudo ser completada. Intentelo mas tarde.',
UNEXPECTED_ERROR_LOADING = 'Lo sentimos, un error inesperado ha ocurrido. Intentelo nuevamente recargando el editor. Si el problema persiste, contactenos a support@wisemapping.com.',
MAIN_TOPIC = 'Tópico Principal',
SUB_TOPIC = 'Tópico Secundario',
ISOLATED_TOPIC = 'Tópico Aislado',
CENTRAL_TOPIC = 'Tópico Central',
SHORTCUTS = 'Accesos directos',
ENTITIES_COULD_NOT_BE_DELETED = 'El tópico o la relación no pudo ser borrada. Debe selecionar al menos una.',
AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED = 'Al menos un tópico debe ser seleccionado.',
CLIPBOARD_IS_EMPTY = 'Nada que copiar. Clipboard está vacio.',
CENTRAL_TOPIC_CAN_NOT_BE_DELETED = 'El tópico central no puede ser borrado.',
RELATIONSHIP_COULD_NOT_BE_CREATED = 'La relación no pudo ser creada. Una relación padre debe ser seleccionada primero.',
SELECTION_COPIED_TO_CLIPBOARD = 'Tópicos copiados al clipboard',
WRITE_YOUR_TEXT_HERE = 'Escribe tu nota aquí ...',
REMOVE = 'Borrar',
ACCEPT = 'Aceptar',
CANCEL = 'Cancelar',
LINK = 'Enlace',
OPEN_LINK = 'Abrir Enlace',
SESSION_EXPIRED = 'Su session ha expirado. Por favor, ingrese nuevamente.',
URL_ERROR = 'URL no válida',
ACTION = 'Acción',
CREATE_SIBLING_TOPIC = 'Agregar Tópico Hermano',
CREATE_CHILD_TOPIC = 'Agregar Tópico Hijo',
DELETE_TOPIC = 'Borrar Tópico',
EDIT_TOPIC_TEXT = 'Editar Texto de Tópico',
JUST_START_TYPING = 'Comenza a escribir',
CANCEL_TEXT_CHANGES = 'Cancelar Edición de Texto',
TOPIC_NAVIGATION = 'Navegación Entre Tópicos',
ARROW_KEYS = 'Flechas Del Cursor',
SELECT_MULTIPLE_NODES = 'Selecciónar Multiples Tópicos',
UNDO_EDITION = 'Revertir Cambios',
REDO_EDITION = 'Rehacer Cambios',
SELECT_ALL_TOPIC = 'Seleccionar Todos los Tópicos',
CHANGE_TEXT_BOLD = 'Cambiar Texto a Negrita',
SAVE_CHANGES = 'Guardar los Cambios',
CHANGE_TEXT_ITALIC = 'Cambiar Texto a Italica',
DESELECT_ALL_TOPIC = 'Revertir Selección de Tópicos',
COLLAPSE_CHILDREN = 'Colapsar Hijos',
KEYBOARD_SHORTCUTS_MSG = 'Los accesos directos pueden ayudarte a salvar tiempo permitiéndote no sacar las manos del teclado para usar el mouse.',
COPY_AND_PASTE_TOPICS = 'Copier et coller les noeuds',
MULTIPLE_LINES = 'Ajouter plusieurs lignes de texte',
BACK_TO_MAP_LIST = 'Volver a la lista de mapas',
KEYBOARD_SHOTCUTS = 'Métodos abreviados de teclado',

View File

@ -1,80 +0,0 @@
ZOOM_IN = 'Agrandir affichage',
ZOOM_OUT = 'Réduire affichage',
TOPIC_SHAPE = 'Forme du noeud',
TOPIC_ADD = 'Ajouter un noeud',
TOPIC_DELETE = 'Supprimer le noeud',
TOPIC_ICON = 'Ajouter une icône',
TOPIC_LINK = 'Ajouter un lien',
TOPIC_RELATIONSHIP = 'Relation du noeud',
TOPIC_COLOR = 'Couleur du noeud',
TOPIC_BORDER_COLOR = 'Couleur de bordure du noeud',
TOPIC_NOTE = 'Ajouter une note',
FONT_FAMILY = 'Type de police',
FONT_SIZE = 'Taille de police',
FONT_BOLD = 'Caractères gras',
FONT_ITALIC = 'Caractères italiques',
UNDO = 'Annuler',
REDO = 'Refaire',
INSERT = 'Insérer',
SAVE = 'Enregistrer',
NOTE = 'Note',
ADD_TOPIC = 'Ajouter un noeud',
LOADING = 'Chargement ...',
EXPORT = 'Exporter',
PRINT = 'Imprimer',
PUBLISH = 'Publier',
COLLABORATE = 'Partager',
HISTORY = 'Historique',
DISCARD_CHANGES = 'Annuler les changements',
FONT_COLOR = 'Couleur de police',
SAVING = 'Enregistrement ...',
SAVE_COMPLETE = 'Enregistrement terminé',
ZOOM_IN_ERROR = 'Zoom trop grand.',
ZOOM_ERROR = 'Impossible de zoomer plus.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED = 'Impossible de créer un noeud. Un seul noeud doit être sélectionné.',
ONE_TOPIC_MUST_BE_SELECTED = 'Impossible de créer un noeud. Un noeud parent doit être sélectionné au préalable.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE = 'Un noeud enfant ne peut pas être réduit. Un noeud doit être sélectionné.',
SAVE_COULD_NOT_BE_COMPLETED = 'Enregistrement impossible. Essayer ultérieurement.',
UNEXPECTED_ERROR_LOADING = "Nous sommes désolés, une erreur vient de survenir.\nEssayez de recharger l'éditeur. Si le problème persiste, contactez-nous \= support@wisemapping.com.",
MAIN_TOPIC = 'Noeud titre principal',
SUB_TOPIC = 'Noeud sous-titre',
ISOLATED_TOPIC = 'Noeud isolé',
CENTRAL_TOPIC = 'Noeud racine',
SHORTCUTS = 'Raccourcis clavier',
ENTITIES_COULD_NOT_BE_DELETED = "Impossible d'effacer un noeud ou une relation. Au moins un objet de la carte doit être sélectionné.",
AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED = 'Au moins un objet de la carte doit être sélectionné.',
CLIPBOARD_IS_EMPTY = 'Rien à copier. Presse-papier vide.',
CENTRAL_TOPIC_CAN_NOT_BE_DELETED = 'Le noeud racine ne peut pas être effacé.',
RELATIONSHIP_COULD_NOT_BE_CREATED = 'Impossible de créer relation. Un noeud parent doit être sélectionné au préalable.',
SELECTION_COPIED_TO_CLIPBOARD = 'Noeuds sélectionnés copiés dans le presse-papiers.',
WRITE_YOUR_TEXT_HERE = 'Écrivez votre texte ici ...',
REMOVE = 'Supprimer',
ACCEPT = 'Accepter',
CANCEL = 'Annuler',
LINK = 'Lien',
OPEN_LINK = 'Ouvrir le lien',
SESSION_EXPIRED = 'Votre session a expiré, veuillez vous reconnecter.',
URL_ERROR = 'URL non valide',
ACTION = 'Action',
CREATE_SIBLING_TOPIC = 'Créer noeud même niveau',
CREATE_CHILD_TOPIC = 'Créer noeud enfant',
DELETE_TOPIC = 'Détruire noeud ',
EDIT_TOPIC_TEXT = 'Editer texte du noeud',
JUST_START_TYPING = 'Commencer saisie',
CANCEL_TEXT_CHANGES = 'Annuler changement texte',
TOPIC_NAVIGATION = 'Navigation sur les noeuds',
ARROW_KEYS = 'Touches flèches',
SELECT_MULTIPLE_NODES = 'Selection multiple de noeuds',
UNDO_EDITION = 'Annuler édition',
REDO_EDITION = 'Refaire édition',
SELECT_ALL_TOPIC = 'Sélection tous noeuds',
CHANGE_TEXT_BOLD = 'Caractères en gras',
SAVE_CHANGES = 'Enregistrer changements',
CHANGE_TEXT_ITALIC = 'Caractères en italique',
DESELECT_ALL_TOPIC = 'Deselection tous noeuds',
COLLAPSE_CHILDREN = 'Fermer enfants',
KEYBOARD_SHORTCUTS_MSG = 'Les raccourcis clavier vous font gagner du temps, en vous permettant de garder les mains sur le clavier sans utiliser la souris.',
COPY_AND_PASTE_TOPICS = 'Copier et coller les noeuds',
MULTIPLE_LINES = 'Ajouter plusieurs lignes de texte',
BACK_TO_MAP_LIST = 'Retour à la liste des cartes',
KEYBOARD_SHOTCUTS = "Raccourcis clavier",

View File

@ -0,0 +1,84 @@
const EN = {
ZOOM_IN: 'Zoom In',
ZOOM_OUT: 'Zoom Out',
TOPIC_SHAPE: 'Topic Shape',
TOPIC_ADD: 'Add Topic',
TOPIC_DELETE: 'Delete Topic',
TOPIC_ICON: 'Add Icon',
TOPIC_LINK: 'Add Link',
TOPIC_RELATIONSHIP: 'Relationship',
TOPIC_COLOR: 'Topic Color',
TOPIC_BORDER_COLOR: 'Topic Border Color',
TOPIC_NOTE: 'Add Note',
FONT_FAMILY: 'Font Type',
FONT_SIZE: 'Text Size',
FONT_BOLD: 'Text Bold',
FONT_ITALIC: 'Text Italic',
UNDO: 'Undo',
REDO: 'Redo',
INSERT: 'Insert',
SAVE: 'Save',
NOTE: 'Note',
ADD_TOPIC: 'Add Topic',
LOADING: 'Loading ...',
EXPORT: 'Export',
PRINT: 'Print',
PUBLISH: 'Publish',
COLLABORATE: 'Share',
HISTORY: 'History',
DISCARD_CHANGES: 'Discard Changes',
FONT_COLOR: 'Text Color',
SAVING: 'Saving ...',
SAVE_COMPLETE: 'Save Complete',
ZOOM_IN_ERROR: 'Zoom too high.',
ZOOM_ERROR: 'No more zoom can be applied.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED: 'Could not create a topic. Only one topic must be selected.',
ONE_TOPIC_MUST_BE_SELECTED: 'Could not create a topic. One topic must be selected.',
ONLY_ONE_TOPIC_MUST_BE_SELECTED_COLLAPSE: 'Children can not be collapsed. One topic must be selected.',
SAVE_COULD_NOT_BE_COMPLETED: 'Save could not be completed, please try again latter.',
UNEXPECTED_ERROR_LOADING: "We're sorry, an unexpected error has occurred.\nTry again reloading the editor.If the problem persists, contact us to support@wisemapping.com.",
MAIN_TOPIC: 'Main Topic',
SUB_TOPIC: 'Sub Topic',
ISOLATED_TOPIC: 'Isolated Topic',
CENTRAL_TOPIC: 'Central Topic',
SHORTCUTS: 'Keyboard Shortcuts',
ENTITIES_COULD_NOT_BE_DELETED: 'Could not delete topic or relation. At least one map entity must be selected.',
AT_LEAST_ONE_TOPIC_MUST_BE_SELECTED: 'At least one topic must be selected.',
CLIPBOARD_IS_EMPTY: 'Nothing to copy. Clipboard is empty.',
CENTRAL_TOPIC_CAN_NOT_BE_DELETED: 'Central topic can not be deleted.',
RELATIONSHIP_COULD_NOT_BE_CREATED: 'Relationship could not be created. A parent relationship topic must be selected first.',
SELECTION_COPIED_TO_CLIPBOARD: 'Topics copied to the clipboard',
WRITE_YOUR_TEXT_HERE: 'Write your note here ...',
REMOVE: 'Remove',
ACCEPT: 'Accept',
CANCEL: 'Cancel',
LINK: 'Link',
OPEN_LINK: 'Open URL',
SESSION_EXPIRED: 'Your session has expired, please log-in again.',
URL_ERROR: 'URL not valid',
ACTION: 'Action',
CREATE_SIBLING_TOPIC: 'Create Sibling Topic',
CREATE_CHILD_TOPIC: 'Create Child Topic',
DELETE_TOPIC: 'Delete Topic',
EDIT_TOPIC_TEXT: 'Edit Topic Text',
JUST_START_TYPING: 'Just start typing',
CANCEL_TEXT_CHANGES: 'Cancel Text Changes',
TOPIC_NAVIGATION: 'Topic Navigation',
ARROW_KEYS: 'Arrow Keys',
SELECT_MULTIPLE_NODES: 'Select Multiple Nodes',
UNDO_EDITION: 'Undo Edition',
REDO_EDITION: 'Redo Edition',
SELECT_ALL_TOPIC: 'Select All Topic',
CHANGE_TEXT_BOLD: 'Change Text Bold Type',
SAVE_CHANGES: 'Save Changes',
CHANGE_TEXT_ITALIC: 'Change Text Italic',
DESELECT_ALL_TOPIC: 'Deselect All Topic',
COLLAPSE_CHILDREN: 'Collapse Children',
KEYBOARD_SHORTCUTS_MSG: 'Keyboard shortcuts can help you save time by allowing you to never take your hands off the keyboard to use the mouse.',
COPY_AND_PASTE_TOPICS: 'Copy and Paste Topics',
MULTIPLE_LINES: 'Add multiple text lines',
BACK_TO_MAP_LIST: 'Back to Maps List',
KEYBOARD_SHOTCUTS: 'Keyboard Shorcuts',
};
export default EN;

View File

@ -1,6 +1,4 @@
/* eslint-disable no-unused-vars */
/* eslint-disable class-methods-use-this */
/*
/**
* Copyright [2021] [wisemapping]
*
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
@ -17,22 +15,26 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import RootedTreeSet from './RootedTreeSet';
import Node from './Node';
import PositionType from '../PositionType';
abstract class ChildrenSorterStrategy {
abstract computeChildrenIdByHeights(treeSet, node);
abstract computeChildrenIdByHeights(treeSet: RootedTreeSet, node: Node);
abstract computeOffsets(treeSet, node);
abstract computeOffsets(treeSet: RootedTreeSet, node: Node);
abstract insert(treeSet, parent, child, order);
abstract insert(treeSet: RootedTreeSet, parent: Node, child: Node, order: number);
abstract detach(treeSet, node);
abstract detach(treeSet: RootedTreeSet, node: Node);
abstract predict(treeSet, parent, node, position, free);
abstract predict(treeSet: RootedTreeSet, parent, node: Node, position: PositionType);
abstract verify(treeSet, node);
abstract verify(treeSet: RootedTreeSet, node: Node);
abstract getChildDirection(treeSet, node);
abstract getChildDirection(treeSet: RootedTreeSet, node: Node);
abstract toString();
abstract toString(): string;
}
export default ChildrenSorterStrategy;

View File

@ -17,25 +17,22 @@
*/
import Events from '../Events';
export type EventType = 'topicResize' | 'topicMoved' | 'childShrinked' | 'topicConnected' | 'topicAdded' | 'topicRemoved' | 'forceLayout' | 'topicDisconect';
class EventBus extends Events {
// eslint-disable-next-line no-use-before-define
static _instance: EventBus = new EventBus();
static get instance(): EventBus {
return this._instance;
}
fireEvent(type: EventType, eventArgs?: unknown[] | unknown): Events {
return super.fireEvent(type, eventArgs);
}
addEvent(type: EventType, fn?, internal?: boolean): Events {
return super.addEvent(type, fn, internal);
}
}
/**
* Enum for events
* @enum {String}
*/
EventBus.events = {
NodeResizeEvent: 'NodeResizeEvent',
NodeMoveEvent: 'NodeMoveEvent',
NodeShrinkEvent: 'NodeShrinkEvent',
NodeConnectEvent: 'NodeConnectEvent',
NodeDisconnectEvent: 'NodeDisconnectEvent',
NodeAdded: 'NodeAdded',
NodeRemoved: 'NodeRemoved',
DoLayout: 'DoLayout',
};
/** instance */
EventBus.instance = new EventBus();
export default EventBus;

View File

@ -15,59 +15,57 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import PositionType from '../PositionType';
import SizeType from '../SizeType';
import Topic from '../Topic';
import EventBus from './EventBus';
import LayoutManager from './LayoutManager';
class EventBusDispatcher {
private _layoutManager: LayoutManager;
constructor() {
this.registerBusEvents();
}
/**
* @param {mindplot.layout.LayoutManager} layoutManager
*/
setLayoutManager(layoutManager) {
setLayoutManager(layoutManager: LayoutManager) {
this._layoutManager = layoutManager;
}
/**
* register bus events
*/
registerBusEvents() {
EventBus.instance.addEvent(EventBus.events.NodeAdded, this._nodeAdded.bind(this));
EventBus.instance.addEvent(EventBus.events.NodeRemoved, this._nodeRemoved.bind(this));
EventBus.instance.addEvent(EventBus.events.NodeResizeEvent, this._nodeResizeEvent.bind(this));
EventBus.instance.addEvent(EventBus.events.NodeMoveEvent, this._nodeMoveEvent.bind(this));
EventBus.instance.addEvent(
EventBus.events.NodeDisconnectEvent, this._nodeDisconnectEvent.bind(this),
);
EventBus.instance.addEvent(EventBus.events.NodeConnectEvent, this._nodeConnectEvent.bind(this));
EventBus.instance.addEvent(EventBus.events.NodeShrinkEvent, this._nodeShrinkEvent.bind(this));
EventBus.instance.addEvent(EventBus.events.DoLayout, this._doLayout.bind(this));
EventBus.instance.addEvent('topicAdded', this._topicAdded.bind(this));
EventBus.instance.addEvent('topicRemoved', this._topicRemoved.bind(this));
EventBus.instance.addEvent('topicResize', this._topicResizeEvent.bind(this));
EventBus.instance.addEvent('topicMoved', this._topicMoved.bind(this));
EventBus.instance.addEvent('topicDisconect', this._topicDisconect.bind(this));
EventBus.instance.addEvent('topicConnected', this._topicConnected.bind(this));
EventBus.instance.addEvent('childShrinked', this._childShrinked.bind(this));
EventBus.instance.addEvent('forceLayout', this._forceLayout.bind(this));
}
_nodeResizeEvent(args) {
private _topicResizeEvent(args: { node: Topic, size: SizeType }) {
this._layoutManager.updateNodeSize(args.node.getId(), args.size);
}
_nodeMoveEvent(args) {
private _topicMoved(args: { node: Topic, position: PositionType }) {
this._layoutManager.moveNode(args.node.getId(), args.position);
}
_nodeDisconnectEvent(node) {
private _topicDisconect(node: Topic) {
this._layoutManager.disconnectNode(node.getId());
}
_nodeConnectEvent(args) {
private _topicConnected(args: { parentNode: Topic, childNode: Topic }) {
this._layoutManager.connectNode(
args.parentNode.getId(), args.childNode.getId(), args.childNode.getOrder(),
);
}
_nodeShrinkEvent(node) {
private _childShrinked(node: Topic) {
this._layoutManager.updateShrinkState(node.getId(), node.areChildrenShrunken());
}
_nodeAdded(node) {
private _topicAdded(node: Topic) {
// Central topic must not be added twice ...
if (node.getId() !== 0) {
this._layoutManager.addNode(node.getId(), { width: 10, height: 10 }, node.getPosition());
@ -75,21 +73,14 @@ class EventBusDispatcher {
}
}
_nodeRemoved(node) {
private _topicRemoved(node: Topic) {
this._layoutManager.removeNode(node.getId());
}
_doLayout() {
// (function() {
private _forceLayout() {
this._layoutManager.layout(true);
// console.log("---------");
// this._layoutManager.dump();
// console.log("---------");
// console.log("---------");
// }).delay(0, this);
}
/** @return layout manager */
getLayoutManager() {
return this._layoutManager;
}

View File

@ -15,15 +15,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import $ from 'jquery';
import { $assert, $defined } from '@wisemapping/core-js';
import Events from '../Events';
import RootedTreeSet from './RootedTreeSet';
import OriginalLayout from './OriginalLayout';
import ChangeEvent from './ChangeEvent';
import SizeType from '../SizeType';
import Node from './Node';
import PositionType from '../PositionType';
class LayoutManager extends Events {
constructor(rootNodeId, rootSize) {
private _treeSet: RootedTreeSet;
private _layout: OriginalLayout;
private _events: ChangeEvent[];
constructor(rootNodeId: number, rootSize: SizeType) {
super();
$assert($defined(rootNodeId), 'rootNodeId can not be null');
$assert(rootSize, 'rootSize can not be null');
@ -36,40 +44,22 @@ class LayoutManager extends Events {
this._events = [];
}
/**
* @param id
* @param size
* @throws will throw an error if id is null or undefined
*/
updateNodeSize(id, size) {
updateNodeSize(id: number, size: SizeType): void {
$assert($defined(id), 'id can not be null');
const node = this._treeSet.find(id);
node.setSize(size);
}
/**
* @param id
* @param value
* @throws will throw an error if id is null or undefined
* @throws will throw an error if value is null or undefined
* @return this
*/
updateShrinkState(id, value) {
updateShrinkState(id: number, value: boolean): void {
$assert($defined(id), 'id can not be null');
$assert($defined(value), 'value can not be null');
const node = this._treeSet.find(id);
node.setShrunken(value);
return this;
}
/**
* @param id
* @return {@link RootedTreeSet}.find(id)
*/
find(id) {
find(id: number): Node {
return this._treeSet.find(id);
}
@ -81,31 +71,17 @@ class LayoutManager extends Events {
* @throws will throw an error if the position's x property is null or undefined
* @throws will throw an error if the position's y property is null or undefined
*/
moveNode(id, position) {
moveNode(id: number, position: PositionType) {
$assert($defined(id), 'id cannot be null');
$assert($defined(position), 'position cannot be null');
$assert($defined(position.x), 'x can not be null');
$assert($defined(position.y), 'y can not be null');
const node = this._treeSet.find(id);
// @Todo: this should not be here. This is broking the isolated node support...
// node.setFree(true);
// node.setFreeDisplacement(
// {x:position.x - node.getPosition().x, y:position.y - node.getPosition().y}
// );
node.setPosition(position);
}
/**
* @param parentId
* @param childId
* @param order
* @throws will throw an error if parentId is null or undefined
* @throws will throw an error if childId is null or undefined
* @throws will throw an error if order is null or undefined
* @return this
*/
connectNode(parentId, childId, order) {
connectNode(parentId: number, childId: number, order: number) {
$assert($defined(parentId), 'parentId cannot be null');
$assert($defined(childId), 'childId cannot be null');
$assert($defined(order), 'order cannot be null');
@ -115,16 +91,9 @@ class LayoutManager extends Events {
return this;
}
/**
* @param id
* @throws will throw an error if id is null or undefined
* @return this
*/
disconnectNode(id) {
disconnectNode(id: number): void {
$assert($defined(id), 'id can not be null');
this._layout.disconnectNode(id);
return this;
}
/**
@ -134,7 +103,7 @@ class LayoutManager extends Events {
* @throws will throw an error if id is null or undefined
* @return this
*/
addNode(id, size, position) {
addNode(id: number, size: SizeType, position: PositionType) {
$assert($defined(id), 'id can not be null');
const result = this._layout.createNode(id, size, position, 'topic');
this._treeSet.add(result);
@ -142,13 +111,7 @@ class LayoutManager extends Events {
return this;
}
/**
* removes a node and its connection to parent if existing
* @param id
* @throws will throw an error if id is null or undefined
* @return this
*/
removeNode(id) {
removeNode(id: number) {
$assert($defined(id), 'id can not be null');
const node = this._treeSet.find(id);
@ -163,47 +126,31 @@ class LayoutManager extends Events {
return this;
}
/**
* @param {Number} parentId
* @param {Number=} nodeId
* @param {String=} position the position to use as mindplot.layout.Node.properties position
* property as '(x,y)'
* @param {Boolean=} free true specifies free node positioning
* @throws will throw an error if parentId is null or undefined
*/
predict(parentId, nodeId, position, free) {
predict(parentId: number, nodeId: number, position: PositionType): { order: number, position: PositionType } {
$assert($defined(parentId), 'parentId can not be null');
const parent = this._treeSet.find(parentId);
const node = nodeId ? this._treeSet.find(nodeId) : null;
const sorter = parent.getSorter();
const result = sorter.predict(this._treeSet, parent, node, position, free);
const result = sorter.predict(this._treeSet, parent, node, position);
return { order: result[0], position: result[1] };
}
/**
* logs dump to console
*/
dump() {
console.log(this._treeSet.dump());
}
/**
* @param containerId
* @param {width:Number, height:Number} size
* @throws will throw an error if containerId is null or undefined
* @return canvas
*/
plot(containerId, size = { width: 200, height: 200 }) {
plot(containerId: string, size = { width: 200, height: 200 }) {
// this method is only used from tests that include Raphael
if (!global.Raphael) {
if (!globalThis.Raphael) {
console.warn('Raphael.js not found, exiting plot()');
return null;
}
$assert(containerId, 'containerId cannot be null');
const squaresize = 10;
const canvas = global.Raphael(containerId, size.width, size.height);
const canvas = globalThis.Raphael(containerId, size.width, size.height);
canvas.drawGrid(
0,
0,
@ -217,40 +164,33 @@ class LayoutManager extends Events {
return canvas;
}
/**
* initializes the layout to be updated
* @param fireEvents
* @return this
*/
layout(fireEvents) {
layout(flush: boolean): LayoutManager {
// File repositioning ...
this._layout.layout();
// Collect changes ...
this._collectChanges();
this._collectChanges(this._treeSet.getTreeRoots());
if ($(fireEvents).length > 0 || fireEvents) {
if (flush) {
this._flushEvents();
}
return this;
}
_flushEvents() {
private _flushEvents() {
this._events.forEach(((event) => {
this.fireEvent('change', event);
}));
this._events = [];
}
_collectChanges(nodes) {
const nodesToCollect = nodes || this._treeSet.getTreeRoots();
nodesToCollect.forEach(((node) => {
private _collectChanges(nodes: Node[]) {
nodes.forEach(((node) => {
if (node.hasOrderChanged() || node.hasPositionChanged()) {
// Find or create a event ...
const id = node.getId();
let event = this._events.some((e) => e.id === id);
let event: ChangeEvent = this._events.find((e) => e.getId() === id);
if (!event) {
event = new ChangeEvent(id);
}

View File

@ -28,31 +28,20 @@ class RootedTreeSet {
this._rootNodes = [];
}
/**
* @param root
* @throws will throw an error if root is null or undefined
*/
setRoot(root: Node) {
$assert(root, 'root can not be null');
this._rootNodes.push(this._decodate(root));
}
/** getter */
getTreeRoots() {
getTreeRoots(): Node[] {
return this._rootNodes;
}
_decodate(node: Node) {
_decodate(node: Node): Node {
node._children = [];
return node;
}
/**
* @param {mindplot.model.NodeModel} node
* @throws will throw an error if node is null or undefined
* @throws will throw an error if node with id already exists
* @throws will throw an error if node has been added already
*/
add(node: Node) {
$assert(node, 'node can not be null');
if (this.find(node.getId(), false)) {

View File

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

View File

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

View File

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

View File

@ -1,7 +0,0 @@
import fadeEffect from './FadeEffect';
import shape from './Shape';
export default {
FadeEffect: fadeEffect,
Shape: shape,
};

View File

@ -27,14 +27,18 @@ const defaultOptions = {
title: '',
content: '',
delay: 0,
container: false,
container: '#mindplot-tooltips',
destroyOnExit: false,
};
class FloatingTip extends Events {
private options;
private element;
constructor(element, options) {
super();
const opts = { ...defaultOptions, ...options };
super(element, opts);
this.setOptions(opts);
this.element = element;
this._createPopover();

View File

@ -18,7 +18,7 @@
import $ from 'jquery';
import { $assert } from '@wisemapping/core-js';
import { $msg } from '../Messages';
import BootstrapDialog from '../libraries/bootstrap/BootstrapDialog';
import BootstrapDialog from './bootstrap/BootstrapDialog';
class LinkEditor extends BootstrapDialog {
/**

View File

@ -31,7 +31,6 @@ class LinkIconTooltip extends FloatingTip {
},
html: true,
placement: 'bottom',
container: 'body',
title: $msg('LINK'),
trigger: 'manual',
template: '<div id="linkPopover" class="popover" onmouseover="jQuery(this).mouseleave(function() {jQuery(this).fadeOut(200); });" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',

View File

@ -17,7 +17,7 @@
*/
import { $assert } from '@wisemapping/core-js';
import $ from 'jquery';
import BootstrapDialog from '../libraries/bootstrap/BootstrapDialog';
import BootstrapDialog from '../../../../editor/src/classes/bootstrap/BootstrapDialog';
import { $msg } from '../Messages';
class NoteEditor extends BootstrapDialog {

View File

@ -20,16 +20,17 @@ import { $assert } from '@wisemapping/core-js';
import $ from 'jquery';
class ToolbarNotifier {
get container() {
static get container() {
return $('#headerNotifier');
}
hide() {
static hide() {
this.container.hide();
}
logMessage(msg) {
static show(msg: string, fade: boolean) {
$assert(msg, 'msg can not be null');
// In case of print,embedded no message is displayed ....
if (this.container && this.container.length && !this.container.data('transitioning')) {
this.container.data('transitioning', true);
@ -37,15 +38,19 @@ class ToolbarNotifier {
this.container.css({
left: ($(window).width() - this.container.width()) / 2 - 9,
});
this.container.show().fadeOut(5000);
if (fade) {
this.container.show().fadeOut(5000);
} else {
this.container.show();
}
}
this.container.data('transitioning', false);
}
}
const toolbarNotifier = new ToolbarNotifier();
const $notify = (msg) => {
toolbarNotifier.logMessage(msg);
const $notify = (msg: string, fade = true) => {
ToolbarNotifier.show(msg, fade);
};
export { $notify };

View File

@ -59,6 +59,8 @@ class BootstrapDialog extends Options {
$(this).remove();
});
this._native.on('shown.bs.modal', this.onDialogShown);
this._native.appendTo('#mindplot-tooltips');
}
_buildFooter() {

View File

@ -23,20 +23,26 @@ import Designer from './components/Designer';
import LocalStorageManager from './components/LocalStorageManager';
import RESTPersistenceManager from './components/RestPersistenceManager';
import MockPersistenceManager from './components/MockPersistenceManager';
import Menu from './components/widget/Menu';
import DesignerOptionsBuilder from './components/DesignerOptionsBuilder';
import ImageExporterFactory from './components/export/ImageExporterFactory';
import TextExporterFactory from './components/export/TextExporterFactory';
import Exporter from './components/export/Exporter';
import DesignerKeyboard from './components/DesignerKeyboard';
import EditorRenderMode from './components/EditorRenderMode';
import ImageIcon from './components/ImageIcon';
import {
buildDesigner,
} from './components/DesignerBuilder';
import {
$notify,
} from './components/widget/ToolbarNotifier';
import {
$msg,
} from './components/Messages';
// This hack is required to initialize Bootstrap. In future, this should be removed.
const globalAny: any = global;
globalAny.jQuery = jquery;
@ -45,7 +51,6 @@ require('../../../libraries/bootstrap/js/bootstrap.min');
export {
Mindmap,
Designer,
Menu,
DesignerBuilder,
PersistenceManager,
RESTPersistenceManager,
@ -53,9 +58,12 @@ export {
LocalStorageManager,
DesignerOptionsBuilder,
buildDesigner,
EditorRenderMode,
TextExporterFactory,
ImageExporterFactory,
Exporter,
ImageIcon,
$notify,
$msg,
DesignerKeyboard,
};

View File

@ -15,7 +15,7 @@
},
"include": [
"src/**/*"
],
, "../editor/src/classes/menu/AccountSettingsPanel.js", "../editor/src/classes/menu/IMenu.ts", "../editor/src/classes/bootstrap" ],
"exclude": [
"node_modules"
]

View File

@ -161,12 +161,12 @@ class ElementClass {
setStroke(width, style, color, opacity) {
if (
style != null
&& style !== undefined
&& style !== 'dash'
&& style !== 'dot'
&& style !== 'solid'
&& style !== 'longdash'
&& style !== 'dashdot'
&& style !== undefined
&& style !== 'dash'
&& style !== 'dot'
&& style !== 'solid'
&& style !== 'longdash'
&& style !== 'dashdot'
) {
throw new Error(`Unsupported stroke style: '${style}'`);
}
@ -255,8 +255,8 @@ class ElementClass {
this.peer.setFill(null, opacity);
}
setVisibility(isVisible) {
this.peer.setVisibility(isVisible);
setVisibility(value, fade) {
this.peer.setVisibility(value, fade);
}
isVisible() {

View File

@ -181,11 +181,14 @@ class ElementPeer {
}
}
/*
* style='visibility: visible'
*/
setVisibility(isVisible) {
this._native.setAttribute('visibility', isVisible ? 'visible' : 'hidden');
setVisibility(value, fade) {
this._native.setAttribute('visibility', value ? 'visible' : 'hidden');
this._native.style.opacity = value ? 1 : 0;
if (fade) {
this._native.style.transition = `visibility ${fade}ms, opacity ${fade}ms`;
} else {
this._native.style.transition = null;
}
}
isVisible() {

View File

@ -66,7 +66,7 @@
</tr>
<tr>
<td>
Visibility.
Visibility with CSS Transition
</td>
<td>
<div id="visibility"></div>

View File

@ -225,15 +225,14 @@ const visibilityTest = () => {
rect.setPosition(120, 20);
workspace.append(rect);
rect.addEvent('mouseover', () => {
alert('Mouse Over');
rect.setVisibility(false, 500);
});
let isVisible = true;
const executer = function () {
isVisible = !isVisible;
rect.setVisibility(isVisible);
};
// executer.periodical(100);
rect.addEvent('mouseout', () => {
rect.setVisibility(true, 500);
});
// executer.periodical(100);
workspace.addItAsChildTo($('#visibility'));
};
visibilityTest();

View File

@ -0,0 +1,477 @@
{
"account.delete-warning": {
"defaultMessage": "Помните, что вы не сможете восстановить созданные вами майнд-карты. Вся информация будет удалена безвозвратно."
},
"accountinfo.button": {
"defaultMessage": "Сохранить"
},
"accountinfo.email": {
"defaultMessage": "Email"
},
"accountinfo.firstname": {
"defaultMessage": "Имя"
},
"accountinfo.lastname": {
"defaultMessage": "Фамилия"
},
"accountinfo.title": {
"defaultMessage": "Информация"
},
"action.cancel-button": {
"defaultMessage": "Отмена"
},
"action.close-button": {
"defaultMessage": "Закрыть"
},
"action.delete": {
"defaultMessage": "Удалить"
},
"action.delete-description": {
"defaultMessage": "Удаление майндкарты - необратимый процесс без возможности восстановления. Точно удалить майндкарту?."
},
"action.delete-title": {
"defaultMessage": "Удалить"
},
"action.duplicate": {
"defaultMessage": "Клонировать"
},
"action.export": {
"defaultMessage": "Экспорт"
},
"action.history": {
"defaultMessage": "История"
},
"action.history-description": {
"defaultMessage": "Список изменений за последние 90 дней."
},
"action.history-title": {
"defaultMessage": "История версий"
},
"action.import": {
"defaultMessage": "Импорт"
},
"action.info": {
"defaultMessage": "Инфо"
},
"action.label": {
"defaultMessage": "Добавить метку"
},
"action.new": {
"defaultMessage": "Новая майнд-карта"
},
"action.open": {
"defaultMessage": "Открыть"
},
"action.print": {
"defaultMessage": "Печать"
},
"action.publish": {
"defaultMessage": "Опубликовать"
},
"action.rename": {
"defaultMessage": "Переименовать"
},
"action.rename-description-placeholder": {
"defaultMessage": "Описание"
},
"action.rename-name-placeholder": {
"defaultMessage": "Имя"
},
"action.share": {
"defaultMessage": "Открыть доступ"
},
"changepwd.button": {
"defaultMessage": "Изменить"
},
"changepwd.confirm-password": {
"defaultMessage": "Подтвердить пароль"
},
"changepwd.description": {
"defaultMessage": "Укажите новый пароль вашей учетной записи."
},
"changepwd.password": {
"defaultMessage": "Пароль"
},
"changepwd.password-match": {
"defaultMessage": "Пароли не совпадают. Пожалуйста, попробуйте еще раз."
},
"changepwd.title": {
"defaultMessage": "Изменить пароль"
},
"common.wait": {
"defaultMessage": "Подождите..."
},
"create.button": {
"defaultMessage": "Создать"
},
"create.description": {
"defaultMessage": "Пожалуйста, укажите имя и описание."
},
"create.title": {
"defaultMessage": "Создание новой майнд-карты."
},
"deletem.title": {
"defaultMessage": "Все выбранные карты будут удалены"
},
"duplicate.title": {
"defaultMessage": "Клонировать"
},
"expired.description": {
"defaultMessage": "Время вашей сессии истекло. Пожалуйста, авторизуйтесь и попробуйте снова."
},
"expired.title": {
"defaultMessage": "Время вашей сессии истекло"
},
"export.desc": {
"defaultMessage": "Выгрузите эту карту в формате, который нужен - вставка в презентацию, отправка по почте, оффлайн работа."
},
"export.document": {
"defaultMessage": "Майнд-карта: Экспорт в различных форматах редакторов майнд-карт"
},
"export.document-label": {
"defaultMessage": "Документ: Экспорт в формате документа"
},
"export.image": {
"defaultMessage": "Рисунок: Экспорт рисунка вашей карты с учетом всех цветов и форм."
},
"export.title": {
"defaultMessage": "Экспорт"
},
"export.warning": {
"defaultMessage": "Экспорт рисунком (SVG,PNG,JPEG,PDF) доступен только из панели редактирования."
},
"footer.aboutus": {
"defaultMessage": "О Нас"
},
"footer.contactus": {
"defaultMessage": "Контакты"
},
"footer.faq": {
"defaultMessage": "F.A.Q."
},
"footer.faqandhelp": {
"defaultMessage": "Помощь & FAQ"
},
"footer.feedback": {
"defaultMessage": "Обратная связь"
},
"footer.opensource": {
"defaultMessage": "Open Source"
},
"footer.others": {
"defaultMessage": "Прочее"
},
"footer.termsandconditions": {
"defaultMessage": "Общие Правила"
},
"forgot.desc": {
"defaultMessage": "Мы отправим Вам e-mail для восстановления пароля."
},
"forgot.email": {
"defaultMessage": "Email"
},
"forgot.page-title": {
"defaultMessage": "Забыл пароль | WiseMapping"
},
"forgot.register": {
"defaultMessage": "Отправить"
},
"forgot.success.desc": {
"defaultMessage": "Мы отправили e-mail с инструкциями по восстановлению пароля. Вы должны получить его в течение пары минут."
},
"forgot.success.title": {
"defaultMessage": "Ваш временный пароль отправлен."
},
"forgot.title": {
"defaultMessage": "Установить новый пароль"
},
"forgotsuccess.page-title": {
"defaultMessage": "Пароль восстановлен | WiseMapping"
},
"header.donthaveaccount": {
"defaultMessage": "Нет аккаунта?"
},
"header.haveaccount": {
"defaultMessage": "Уже есть аккаунт?"
},
"help.support": {
"defaultMessage": "Поддержка"
},
"history.no-changes": {
"defaultMessage": "Нет доступных изменений"
},
"import.button": {
"defaultMessage": "Создать"
},
"import.description": {
"defaultMessage": "Можно импортировать FreeMind 1.0.1 и WiseMapping файлы. Выберите файл, который хотите импортировать."
},
"import.title": {
"defaultMessage": "Загрузить майнд-карту с компьютера"
},
"info.basic-info": {
"defaultMessage": "Основная информация"
},
"info.button": {
"defaultMessage": "Принять"
},
"info.creation-time": {
"defaultMessage": "Дата создания"
},
"info.creator": {
"defaultMessage": "Автор"
},
"info.description": {
"defaultMessage": "Описание"
},
"info.description-msg": {
"defaultMessage": "После публикация карта станет видима для любого, у кого есть ссылка."
},
"info.modified-time": {
"defaultMessage": "Последние изменения"
},
"info.modified-tny": {
"defaultMessage": "Последний редактировал"
},
"info.name": {
"defaultMessage": "Имя"
},
"info.public-visibility": {
"defaultMessage": "Доступ по ссылке"
},
"info.sharing": {
"defaultMessage": "Видимость"
},
"info.starred": {
"defaultMessage": "Важная"
},
"info.title": {
"defaultMessage": "Инфо"
},
"language.change": {
"defaultMessage": "Сменить язык"
},
"language.help": {
"defaultMessage": "Помочь переводить"
},
"login.desc": {
"defaultMessage": "Войдите в свой аккаунт"
},
"login.email": {
"defaultMessage": "Email"
},
"login.error": {
"defaultMessage": "Некорректный email или пароль."
},
"login.forgotpwd": {
"defaultMessage": "Забыли пароль?"
},
"login.hsqldbcofig": {
"defaultMessage": "Although HSQLDB is bundled with WiseMapping by default during the installation, we do not recommend this database for production use. Please consider using MySQL 5.7 instead. You can find more information how to configure MySQL",
"description": "Missing production database configured"
},
"login.page-title": {
"defaultMessage": "Вход | WiseMapping"
},
"login.password": {
"defaultMessage": "Пароль"
},
"login.remberme": {
"defaultMessage": "Запомнить меня"
},
"login.signin": {
"defaultMessage": "Вход"
},
"login.signup": {
"defaultMessage": "Регистрация"
},
"login.title": {
"defaultMessage": "Добро пожаловать!"
},
"login.userinactive": {
"defaultMessage": "Ваш аккаунт еще не активирован. Вам на почту придет сообщение о его активации. На связи!."
},
"map.creator": {
"defaultMessage": "Создатель"
},
"map.delete-selected": {
"defaultMessage": "Удалить выбранные"
},
"map.last-update": {
"defaultMessage": "Последнее изменение"
},
"map.more-actions": {
"defaultMessage": "Больше... "
},
"map.name": {
"defaultMessage": "Имя"
},
"map.tooltip-add": {
"defaultMessage": "Добавить метку выбранным"
},
"maps.choose-file": {
"defaultMessage": "Выберите файл"
},
"maps.create-tooltip": {
"defaultMessage": "Создать новую майнд-карту"
},
"maps.empty-result": {
"defaultMessage": "Нет карт, подходящих под условия фильтра."
},
"maps.import-desc": {
"defaultMessage": "Загрузить из других редакторов"
},
"maps.modified": {
"defaultMessage": "Изменена"
},
"maps.modified-by": {
"defaultMessage": "Редактор"
},
"maps.modified-by-desc": {
"defaultMessage": "Изменена {by} в {on}"
},
"maps.nav-all": {
"defaultMessage": "Все"
},
"maps.nav-onwned": {
"defaultMessage": "Созданные мной"
},
"maps.nav-public": {
"defaultMessage": "Публичные"
},
"maps.nav-shared": {
"defaultMessage": "В общем доступе"
},
"maps.nav-starred": {
"defaultMessage": "Отмеченные"
},
"maps.page-title": {
"defaultMessage": "Мои карты | WiseMapping"
},
"maps.revert": {
"defaultMessage": "Отменить"
},
"maps.search-action": {
"defaultMessage": "Поиск ..."
},
"maps.tooltip-open": {
"defaultMessage": "Открыть для редактирования"
},
"maps.tooltip-starred": {
"defaultMessage": "Отмеченные"
},
"maps.view": {
"defaultMessage": "Просмотр"
},
"menu.account": {
"defaultMessage": "Профиль"
},
"menu.change-password": {
"defaultMessage": "Сменить пароль"
},
"menu.signout": {
"defaultMessage": "Выход"
},
"publish.button": {
"defaultMessage": "Применить"
},
"publish.checkbox": {
"defaultMessage": "Включить общий доступ"
},
"publish.description": {
"defaultMessage": "После публикация карта станет видима для любого, у кого есть ссылка."
},
"publish.embedded": {
"defaultMessage": "Встроить"
},
"publish.embedded-msg": {
"defaultMessage": "Скопируйте этот код, чтобы встроить майнд-карту в ваш сайт:"
},
"publish.public-url": {
"defaultMessage": "Публичный URL"
},
"publish.public-url-msg": {
"defaultMessage": "Скопируйте ссылку, чтобы поделиться с коллегами доступом к карте:"
},
"publish.title": {
"defaultMessage": "Опубликовать"
},
"registation.success-title": {
"defaultMessage": "Успешная регистрация | WiseMapping"
},
"registration.desc": {
"defaultMessage": "Регистрация бесплатна и займет всего минуту"
},
"registration.email": {
"defaultMessage": "Email"
},
"registration.firstname": {
"defaultMessage": "Имя"
},
"registration.lastname": {
"defaultMessage": "Фамилия"
},
"registration.password": {
"defaultMessage": "Пароль"
},
"registration.register": {
"defaultMessage": "Регистрация"
},
"registration.success.desc": {
"defaultMessage": "Нажмите на кнопку 'Войти' и приступите к созданию майнд-карт."
},
"registration.termandconditions": {
"defaultMessage": "Правила: Пожалуйста, проверьте информацию учетной записи WiseMapping, которую вы указали, и ознакомьтесь с Правилами. По нажатию на кнопку 'Регистрация' вы соглашаетесь с Правилами и Политикой Конфиденциальности"
},
"registration.title": {
"defaultMessage": "Become a member"
},
"rename.description": {
"defaultMessage": "Пожалуйста, укажите новое имя и описание."
},
"rename.title": {
"defaultMessage": "Rename"
},
"resetpassword.success.title": {
"defaultMessage": "Аккаунт был успешно создан!"
},
"role.editor": {
"defaultMessage": "Редактор"
},
"role.owner": {
"defaultMessage": "Владелец"
},
"role.viewer": {
"defaultMessage": "Читатель"
},
"share.add-button": {
"defaultMessage": "Добавить"
},
"share.add-message": {
"defaultMessage": "Добавить сообщение"
},
"share.can-edit": {
"defaultMessage": "Редактирование"
},
"share.can-view": {
"defaultMessage": "Просмотр"
},
"share.delete": {
"defaultMessage": "Отозвать доступ"
},
"share.delete-description": {
"defaultMessage": "Пригласите людей для совместной работы над картой. Они получат письмо с приглашением."
},
"share.delete-title": {
"defaultMessage": "Общий доступ"
},
"share.message": {
"defaultMessage": "Сообщение"
},
"editor.try-welcome": {
"defaultMessage": "Здесь можно ознакомиться с возможностями нашего редактора майнд-карт на примерах и практике!"
},
"editor.try-welcome-description": {
"defaultMessage": "Зарегистрируйтесь, чтобы создавать, делиться и публиковать майнд-карты бесплатно и без ограничений!"
}
}

View File

@ -1,6 +1,6 @@
{
"name": "@wisemapping/webapp",
"version": "5.0.7",
"version": "5.0.8",
"main": "app.jsx",
"scripts": {
"start": "webpack serve --config webpack.dev.js ",

View File

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

View File

@ -2,6 +2,7 @@ import { fetchAccount } from './../../redux/clientSlice';
import 'dayjs/locale/fr';
import 'dayjs/locale/en';
import 'dayjs/locale/es';
import 'dayjs/locale/ru';
export class Locale {
code: LocaleCode;
@ -46,16 +47,18 @@ export default abstract class AppI18n {
}
}
export type LocaleCode = 'en' | 'es' | 'fr' | 'de';
export type LocaleCode = 'en' | 'es' | 'fr' | 'de' | 'ru';
export const Locales = {
EN: new Locale('en', 'English', require('./../../compiled-lang/en.json')), // eslint-disable-line
ES: new Locale('es', 'Español', require('./../../compiled-lang/es.json')), // eslint-disable-line
DE: new Locale('fr', 'Français', require('./../../compiled-lang/fr.json')), // eslint-disable-line
FR: new Locale('de', 'Deutsch', require('./../../compiled-lang/de.json')), // eslint-disable-line
RU: new Locale('ru', 'Pусский', require('./../../compiled-lang/ru.json')), // eslint-disable-line
};
export const localeFromStr = (code: string): Locale => {
const locales: Locale[] = Object.values(Locales);

View File

@ -1,4 +1,4 @@
import { Mindmap, PersistenceManager } from '@wisemapping/mindplot';
import { EditorRenderMode, Mindmap, PersistenceManager } from '@wisemapping/mindplot';
import Client, {
AccountInfo,
BasicMapInfo,
@ -130,8 +130,8 @@ class CacheDecoratorClient implements Client {
return this.client.revertHistory(id, cid);
}
buildPersistenceManager(isTryMode: boolean): PersistenceManager {
return this.client.buildPersistenceManager(isTryMode);
buildPersistenceManager(mode: EditorRenderMode): PersistenceManager {
return this.client.buildPersistenceManager(mode);
}
removePersistenceManager(): void {

Some files were not shown because too many files have changed in this diff Show More