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. * limitations under the License.
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import { $msg } from '../Messages'; import { $msg } from '@wisemapping/mindplot/src/components/Messages';
import PersistenceManager from '../PersistenceManager'; import PersistenceManager from '@wisemapping/mindplot/src/components/PersistenceManager';
import { $notify } from './ToolbarNotifier'; import { $notify } from '@wisemapping/mindplot/src/components/widget/ToolbarNotifier';
import { $notifyModal } from './ModalDialogNotifier'; import { $notifyModal } from '../menu/ModalDialogNotifier';
import Designer from '../Designer'; import Designer from '@wisemapping/mindplot/src/components/Designer';
import ToolbarItem from './ToolbarItem'; import ToolbarItem from '../menu/ToolbarItem';
class IMenu { class IMenu {
private _designer: Designer; private _designer: Designer;

View File

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

View File

@ -15,8 +15,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import BootstrapDialog from '../libraries/bootstrap/BootstrapDialog'; import BootstrapDialog from '../bootstrap/BootstrapDialog';
import { $msg } from '../Messages'; import { $msg } from '@wisemapping/mindplot';
class KeyboardShortcutDialog extends BootstrapDialog { class KeyboardShortcutDialog extends BootstrapDialog {
constructor() { constructor() {

View File

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

View File

@ -17,8 +17,7 @@
* limitations under the License. * limitations under the License.
*/ */
import $ from 'jquery'; import $ from 'jquery';
import { $msg } from '../Messages'; import { Designer } from '@wisemapping/mindplot';
import IMenu from './IMenu';
import FontFamilyPanel from './FontFamilyPanel'; import FontFamilyPanel from './FontFamilyPanel';
import FontSizePanel from './FontSizePanel'; import FontSizePanel from './FontSizePanel';
import TopicShapePanel from './TopicShapePanel'; import TopicShapePanel from './TopicShapePanel';
@ -28,7 +27,8 @@ import ToolbarItem from './ToolbarItem';
import KeyboardShortcutTooltip from './KeyboardShortcutTooltip'; import KeyboardShortcutTooltip from './KeyboardShortcutTooltip';
import KeyboardShortcutDialog from './KeyboardShortcutDialog'; import KeyboardShortcutDialog from './KeyboardShortcutDialog';
import AccountSettingsPanel from './AccountSettingsPanel'; import AccountSettingsPanel from './AccountSettingsPanel';
import Designer from '../Designer'; import IMenu from './IMenu';
import { $msg } from '@wisemapping/mindplot';
class Menu extends IMenu { class Menu extends IMenu {
constructor(designer: Designer, containerId: string, readOnly = false, baseUrl = '') { constructor(designer: Designer, containerId: string, readOnly = false, baseUrl = '') {
@ -39,9 +39,6 @@ class Menu extends IMenu {
// Create panels ... // Create panels ...
const designerModel = designer.getModel(); const designerModel = designer.getModel();
const fontFamilyBtn = $('#fontFamily');
if (fontFamilyBtn) {
const fontFamilyModel = { const fontFamilyModel = {
getValue() { getValue() {
const nodes = designerModel.filterSelectedTopics(); const nodes = designerModel.filterSelectedTopics();
@ -63,10 +60,7 @@ class Menu extends IMenu {
}; };
this._toolbarElems.push(new FontFamilyPanel('fontFamily', fontFamilyModel)); this._toolbarElems.push(new FontFamilyPanel('fontFamily', fontFamilyModel));
Menu._registerTooltip('fontFamily', $msg('FONT_FAMILY')); Menu._registerTooltip('fontFamily', $msg('FONT_FAMILY'));
}
const fontSizeBtn = $('#fontSize');
if (fontSizeBtn) {
const fontSizeModel = { const fontSizeModel = {
getValue(): number { getValue(): number {
const nodes = designerModel.filterSelectedTopics(); const nodes = designerModel.filterSelectedTopics();
@ -88,10 +82,7 @@ class Menu extends IMenu {
}; };
this._toolbarElems.push(new FontSizePanel('fontSize', fontSizeModel)); this._toolbarElems.push(new FontSizePanel('fontSize', fontSizeModel));
Menu._registerTooltip('fontSize', $msg('FONT_SIZE')); Menu._registerTooltip('fontSize', $msg('FONT_SIZE'));
}
const topicShapeBtn = $('#topicShape');
if (topicShapeBtn) {
const topicShapeModel = { const topicShapeModel = {
getValue() { getValue() {
const nodes = designerModel.filterSelectedTopics(); const nodes = designerModel.filterSelectedTopics();
@ -112,10 +103,7 @@ class Menu extends IMenu {
}; };
this._toolbarElems.push(new TopicShapePanel('topicShape', topicShapeModel)); this._toolbarElems.push(new TopicShapePanel('topicShape', topicShapeModel));
Menu._registerTooltip('topicShape', $msg('TOPIC_SHAPE')); Menu._registerTooltip('topicShape', $msg('TOPIC_SHAPE'));
}
const topicIconBtn = $('#topicIcon');
if (topicIconBtn) {
// Create icon panel dialog ... // Create icon panel dialog ...
const topicIconModel = { const topicIconModel = {
getValue() { getValue() {
@ -127,11 +115,7 @@ class Menu extends IMenu {
}; };
this._toolbarElems.push(new IconPanel('topicIcon', topicIconModel)); this._toolbarElems.push(new IconPanel('topicIcon', topicIconModel));
Menu._registerTooltip('topicIcon', $msg('TOPIC_ICON')); Menu._registerTooltip('topicIcon', $msg('TOPIC_ICON'));
}
// Topic color item ...
const topicColorBtn = $('#topicColor');
if (topicColorBtn) {
const topicColorModel = { const topicColorModel = {
getValue() { getValue() {
const nodes = designerModel.filterSelectedTopics(); const nodes = designerModel.filterSelectedTopics();
@ -152,11 +136,7 @@ class Menu extends IMenu {
}; };
this._toolbarElems.push(new ColorPalettePanel('topicColor', topicColorModel, widgetsBaseUrl)); this._toolbarElems.push(new ColorPalettePanel('topicColor', topicColorModel, widgetsBaseUrl));
Menu._registerTooltip('topicColor', $msg('TOPIC_COLOR')); Menu._registerTooltip('topicColor', $msg('TOPIC_COLOR'));
}
// Border color item ...
const topicBorderBtn = $('#topicBorder');
if (topicBorderBtn) {
const borderColorModel = { const borderColorModel = {
getValue() { getValue() {
const nodes = designerModel.filterSelectedTopics(); const nodes = designerModel.filterSelectedTopics();
@ -177,11 +157,7 @@ class Menu extends IMenu {
}; };
this._toolbarElems.push(new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl)); this._toolbarElems.push(new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl));
Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR')); Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR'));
}
// Font color item ...
const fontColorBtn = $('#fontColor');
if (fontColorBtn) {
const fontColorModel = { const fontColorModel = {
getValue() { getValue() {
let result = null; let result = null;
@ -202,7 +178,6 @@ class Menu extends IMenu {
}; };
this._toolbarElems.push(new ColorPalettePanel('fontColor', fontColorModel, baseUrl)); this._toolbarElems.push(new ColorPalettePanel('fontColor', fontColorModel, baseUrl));
Menu._registerTooltip('fontColor', $msg('FONT_COLOR')); Menu._registerTooltip('fontColor', $msg('FONT_COLOR'));
}
Menu._registerTooltip('export', $msg('EXPORT')); Menu._registerTooltip('export', $msg('EXPORT'));
@ -315,14 +290,6 @@ class Menu extends IMenu {
} }
} }
const discardElem = $('#discard');
if (discardElem.length !== 0) {
this._addButton('discard', false, false, () => {
this.discardChanges(designer);
});
Menu._registerTooltip('discard', $msg('DISCARD_CHANGES'));
}
const shareElem = $('#shareIt'); const shareElem = $('#shareIt');
if (shareElem.length !== 0) { if (shareElem.length !== 0) {
Menu._registerTooltip('shareIt', $msg('COLLABORATE')); Menu._registerTooltip('shareIt', $msg('COLLABORATE'));
@ -350,14 +317,12 @@ class Menu extends IMenu {
} }
const backTolist = $('#backToList'); const backTolist = $('#backToList');
if (backTolist.length !== 0) {
backTolist.bind('click', (event) => { backTolist.bind('click', (event) => {
event.stopPropagation(); event.stopPropagation();
window.location.href = '/c/maps/'; window.location.href = '/c/maps/';
return false; return false;
}); });
Menu._registerTooltip('backToList', $msg('BACK_TO_MAP_LIST')); Menu._registerTooltip('backToList', $msg('BACK_TO_MAP_LIST'));
}
// Account dialog ... // Account dialog ...
const accountSettings = $('#account'); const accountSettings = $('#account');
@ -367,10 +332,10 @@ class Menu extends IMenu {
}); });
this._toolbarElems.push(new AccountSettingsPanel('account')); this._toolbarElems.push(new AccountSettingsPanel('account'));
Menu._registerTooltip('account', `${global.accountEmail}`); Menu._registerTooltip('account', `${global.accountEmail}`);
}
this._registerEvents(designer); this._registerEvents(designer);
} }
}
private _registerEvents(designer: Designer) { private _registerEvents(designer: Designer) {
// Register on close events ... // Register on close events ...

View File

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

View File

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

View File

@ -17,7 +17,7 @@
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import ToolbarItem from './ToolbarItem'; import ToolbarItem from './ToolbarItem';
import FloatingTip from './FloatingTip'; import FloatingTip from '@wisemapping/mindplot/src/components/widget/FloatingTip';
class ToolbarPaneItem extends ToolbarItem { class ToolbarPaneItem extends ToolbarItem {
constructor(buttonId, model, delayInit) { 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 MinusSvg from '../../../images/minus.svg';
import CenterFocusSvg from '../../../images/center_focus.svg'; import CenterFocusSvg from '../../../images/center_focus.svg';
import ActionButton from '../action-button'; import ActionButton from '../action-button';
import { EditorRenderMode } from '@wisemapping/mindplot';
export type FooterPropsType = { export type FooterPropsType = {
showTryPanel?: boolean; editorMode: EditorRenderMode;
}; };
const Footer = ({ showTryPanel }: FooterPropsType): React.ReactElement => { const Footer = ({ editorMode }: FooterPropsType): React.ReactElement => {
const intl = useIntl(); const intl = useIntl();
return ( return (
@ -37,7 +38,7 @@ const Footer = ({ showTryPanel }: FooterPropsType): React.ReactElement => {
</div> </div>
<StyledLogo id="bottom-logo"></StyledLogo> <StyledLogo id="bottom-logo"></StyledLogo>
<Notifier id="headerNotifier"></Notifier> <Notifier id="headerNotifier"></Notifier>
{showTryPanel && ( {editorMode === 'showcase' && (
<div id="tryInfoPanel"> <div id="tryInfoPanel">
<p>{intl.formatMessage({ id: 'editor.try-welcome' })}</p> <p>{intl.formatMessage({ id: 'editor.try-welcome' })}</p>
<p>{intl.formatMessage({ id: 'editor.try-welcome-description' })}</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 { HeaderContainer, ToolbarButton, ToolbarButtonExt, ToolbarRightContainer } from './styled';
import ActionButton from '../action-button'; import ActionButton from '../action-button';
import { EditorRenderMode } from '@wisemapping/mindplot';
export type ToolbarActionType = 'export' | 'publish' | 'history' | 'print' | 'share'; export type ToolbarActionType = 'export' | 'publish' | 'history' | 'print' | 'share';
export type ToolbarPropsType = { export type ToolbarPropsType = {
isTryMode: boolean; editorMode: EditorRenderMode;
onAction: (action: ToolbarActionType) => void; onAction: (action: ToolbarActionType) => void;
}; };
export default function Toolbar({ export default function Toolbar({
isTryMode: isTryMode, editorMode: editorMode,
onAction, onAction,
}: ToolbarPropsType): React.ReactElement { }: ToolbarPropsType): React.ReactElement {
const intl = useIntl(); const intl = useIntl();
return ( return (
<HeaderContainer> <HeaderContainer className="wise-editor">
<div id="toolbar"> <div id="toolbar">
<div id="backToList"> <div id="backToList">
<img src={BackIconSvg} /> <img src={BackIconSvg} />
</div> </div>
{!isTryMode && ( {(editorMode === 'edition-editor' || editorMode === 'edition-owner') && (
<div id="persist" className="buttonContainer"> <div id="persist" className="buttonContainer">
<ToolbarButton id="save" className="buttonOn"> <ToolbarButton id="save" className="buttonOn">
<img src={SaveSvg} /> <img src={SaveSvg} />
@ -111,7 +112,6 @@ export default function Toolbar({
</ToolbarButton> </ToolbarButton>
</div> </div>
<div id="separator" className="buttonContainer"></div> <div id="separator" className="buttonContainer"></div>
{!isTryMode && (
<ToolbarRightContainer> <ToolbarRightContainer>
<ToolbarButton <ToolbarButton
id="export" id="export"
@ -120,13 +120,17 @@ export default function Toolbar({
> >
<img src={ExportSvg} /> <img src={ExportSvg} />
</ToolbarButton> </ToolbarButton>
{(editorMode === 'edition-owner' || editorMode === 'edition-editor' || editorMode === 'edition-viewer') && (
<ToolbarButton <ToolbarButton
id="publishIt" id="print"
className="buttonOn" className="buttonOn"
onClick={() => onAction('publish')} onClick={() => onAction('print')}
> >
<img src={PublicSvg} /> <img src={PrintSvg} />
</ToolbarButton> </ToolbarButton>
)}
{editorMode === 'edition-owner' && (
<>
<ToolbarButton <ToolbarButton
id="history" id="history"
className="buttonOn" className="buttonOn"
@ -135,20 +139,26 @@ export default function Toolbar({
<img src={HistorySvg} /> <img src={HistorySvg} />
</ToolbarButton> </ToolbarButton>
<ToolbarButton <ToolbarButton
id="print" id="publishIt"
className="buttonOn" className="buttonOn"
onClick={() => onAction('print')} onClick={() => onAction('publish')}
> >
<img src={PrintSvg} /> <img src={PublicSvg} />
</ToolbarButton> </ToolbarButton>
</>
)}
{(editorMode === 'edition-owner' || editorMode === 'edition-editor') && (
<ToolbarButton id="account"> <ToolbarButton id="account">
<img src={AccountSvg} /> <img src={AccountSvg} />
</ToolbarButton> </ToolbarButton>
)}
{editorMode === 'edition-owner' && (
<ActionButton onClick={() => onAction('share')}> <ActionButton onClick={() => onAction('share')}>
{intl.formatMessage({ id: 'action.share', defaultMessage: 'Share' })} {intl.formatMessage({ id: 'action.share', defaultMessage: 'Share' })}
</ActionButton> </ActionButton>
</ToolbarRightContainer>
)} )}
</ToolbarRightContainer>
</div> </div>
</HeaderContainer> </HeaderContainer>
); );

View File

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

View File

@ -9,14 +9,11 @@ import {
DesignerOptionsBuilder, DesignerOptionsBuilder,
Designer, Designer,
DesignerKeyboard, DesignerKeyboard,
EditorRenderMode,
} from '@wisemapping/mindplot'; } 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 './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 { declare global {
// used in mindplot // used in mindplot
@ -25,7 +22,7 @@ declare global {
} }
export type EditorOptions = { export type EditorOptions = {
mode: EditorModeType, mode: EditorRenderMode,
locale: string, locale: string,
zoom?: number, zoom?: number,
locked?: boolean, locked?: boolean,
@ -37,61 +34,38 @@ export type EditorOptions = {
export type EditorProps = { export type EditorProps = {
mapId: string; mapId: string;
options: EditorOptions; options: EditorOptions;
onAction: (action: ToolbarActionType) => void;
persistenceManager: PersistenceManager; persistenceManager: PersistenceManager;
initCallback?: (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager) => void; onAction: (action: ToolbarActionType) => void;
}; onLoad?: (designer: Designer) => 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);
}
}; };
const Editor = ({ const Editor = ({
mapId, mapId,
options, options,
persistenceManager, persistenceManager,
initCallback = defaultCallback,
onAction, onAction,
onLoad,
}: EditorProps) => { }: EditorProps) => {
useEffect(() => { 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(() => { useEffect(() => {
@ -102,15 +76,47 @@ const Editor = ({
} }
}, [options.enableKeyboardEvents]); }, [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 ( return (
<IntlProvider locale={options.locale} messages={loadLocaleData(options.locale)}> <IntlProvider locale={locale} messages={msg}>
{(options.mode !== 'viewonly') &&
<Toolbar <Toolbar
isTryMode={options.mode === 'showcase'} editorMode={options.mode}
onAction={onAction} onAction={onAction}
/> />
<div id="mindplot"></div> }
<Footer showTryPanel={options.mode === 'showcase'} /> <div id="mindplot" style={mindplotStyle} className="wise-editor"></div>
</IntlProvider> <div id="mindplot-tooltips" className="wise-editor"></div>
<Footer editorMode={options.mode} />
</IntlProvider >
); );
} }
export default Editor; 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 React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import Editor, { EditorOptions } from '../../../../src/index'; 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', () => { designer.addEvent('loadSuccess', () => {
const elem = document.getElementById('mindplot'); const elem = document.getElementById('mindplot');
if (elem) { if (elem) {
elem.classList.add('ready'); elem.classList.add('ready');
} }
}); });
// Load map from XML file persisted on disk...
const persistence = PersistenceManager.getInstance();
const mindmap = persistence.load(mapId);
designer.loadMap(mindmap);
}; };
const persistence = new LocalStorageManager('samples/{id}.wxml', false); const persistence = new LocalStorageManager('samples/{id}.wxml', false);
@ -32,7 +36,7 @@ const options: EditorOptions = {
zoom: 0.8, zoom: 0.8,
locked: false, locked: false,
mapTitle: "Develop Mindnap", mapTitle: "Develop Mindnap",
mode: 'edition', mode: 'edition-owner',
locale: 'en', locale: 'en',
enableKeyboardEvents: true enableKeyboardEvents: true
}; };
@ -43,7 +47,7 @@ ReactDOM.render(
options={options} options={options}
persistenceManager={persistence} persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)} onAction={(action) => console.log('action called:', action)}
initCallback={initialization} onLoad={initialization}
/>, />,
document.getElementById('root'), document.getElementById('root'),
); );

View File

@ -2,18 +2,10 @@ import '../css/viewmode.css';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import Editor, { EditorOptions } from '../../../../src/index'; 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', () => { designer.addEvent('loadSuccess', () => {
const elem = document.getElementById('mindplot'); const elem = document.getElementById('mindplot');
if (elem) { 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 // Obtain map id from query param
@ -61,7 +48,7 @@ ReactDOM.render(
options={options} options={options}
persistenceManager={persistence} persistenceManager={persistence}
onAction={(action) => console.log('action called:', action)} onAction={(action) => console.log('action called:', action)}
initCallback={initialization} onLoad={initialization}
/>, />,
document.getElementById('root'), document.getElementById('root'),
); );

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -16,41 +16,50 @@
* limitations under the License. * limitations under the License.
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import ActionDispatcher from './ActionDispatcher';
import Command from './Command';
import CommandContext from './CommandContext';
import DesignerUndoManager from './DesignerUndoManager'; import DesignerUndoManager from './DesignerUndoManager';
import EventBus from './layout/EventBus'; import EventBus from './layout/EventBus';
class DesignerActionRunner { 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'); $assert(commandContext, 'commandContext can not be null');
this._undoManager = new DesignerUndoManager(); this._undoManager = new DesignerUndoManager();
this._context = commandContext; this._context = commandContext;
this._notifier = notifier; this._actionDisplatcher = notifier;
} }
execute(command) { execute(command: Command): void {
$assert(command, 'command can not be null'); $assert(command, 'command can not be null');
command.execute(this._context); command.execute(this._context);
this._undoManager.enqueue(command); this._undoManager.enqueue(command);
this.fireChangeEvent(); this.fireChangeEvent();
EventBus.instance.fireEvent(EventBus.events.DoLayout); EventBus.instance.fireEvent('forceLayout');
} }
undo() { undo(): void {
this._undoManager.execUndo(this._context); this._undoManager.execUndo(this._context);
this.fireChangeEvent(); this.fireChangeEvent();
EventBus.instance.fireEvent(EventBus.events.DoLayout); EventBus.instance.fireEvent('forceLayout');
} }
redo() { redo(): void {
this._undoManager.execRedo(this._context); this._undoManager.execRedo(this._context);
this.fireChangeEvent(); this.fireChangeEvent();
EventBus.instance.fireEvent(EventBus.events.DoLayout); EventBus.instance.fireEvent('forceLayout');
} }
fireChangeEvent() { fireChangeEvent(): void {
const event = this._undoManager.buildEvent(); 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 $ from 'jquery';
import PersistenceManager from './PersistenceManager'; import PersistenceManager from './PersistenceManager';
import Designer from './Designer'; import Designer from './Designer';
import Menu from './widget/Menu';
import { DesignerOptions } from './DesignerOptionsBuilder'; import { DesignerOptions } from './DesignerOptionsBuilder';
let designer: Designer; let designer: Designer;
@ -30,25 +29,12 @@ export function buildDesigner(options: DesignerOptions): Designer {
// Register load events ... // Register load events ...
designer = new Designer(options, divContainer); designer = new Designer(options, divContainer);
designer.addEvent('loadSuccess', () => {
console.log('Map loadded successfully');
});
// Configure default persistence manager ... // Configure default persistence manager ...
const persistence = options.persistenceManager; const persistence = options.persistenceManager;
$assert(persistence, 'persistence must be defined'); $assert(persistence, 'persistence must be defined');
PersistenceManager.init(persistence); 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; return designer;
} }

View File

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

View File

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

View File

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

View File

@ -15,7 +15,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import { Point, ElementClass } from '@wisemapping/web2d'; import { Point, ElementClass } from '@wisemapping/web2d';
import ActionDispatcher from './ActionDispatcher'; import ActionDispatcher from './ActionDispatcher';
@ -27,12 +27,19 @@ import Workspace from './Workspace';
class DragTopic { class DragTopic {
private _elem2d: ElementClass; private _elem2d: ElementClass;
private _order: number | null; private _order: number | null;
private _draggedNode: NodeGraph; private _draggedNode: NodeGraph;
private _layoutManager: LayoutManager; private _layoutManager: LayoutManager;
private _position: any;
private _position: Point;
private _isInWorkspace: boolean; private _isInWorkspace: boolean;
static _dragPivot: any;
static _dragPivot: DragPivot = new DragPivot();
constructor(dragShape: ElementClass, draggedNode: NodeGraph, layoutManger: LayoutManager) { constructor(dragShape: ElementClass, draggedNode: NodeGraph, layoutManger: LayoutManager) {
$assert(dragShape, 'Rect can not be null.'); $assert(dragShape, 'Rect can not be null.');
$assert(draggedNode, 'draggedNode can not be null.'); $assert(draggedNode, 'draggedNode can not be null.');
@ -46,13 +53,13 @@ class DragTopic {
this._isInWorkspace = false; this._isInWorkspace = false;
} }
setOrder(order: number) { setOrder(order: number): void {
this._order = order; this._order = order;
} }
setPosition(x: number, y: number) { setPosition(x: number, y: number): void {
// Update drag shadow position .... // Update drag shadow position ....
let position = { x, y }; const position = { x, y };
this._position.setValue(position.x, position.y); this._position.setValue(position.x, position.y);
// Elements are positioned in the center. // Elements are positioned in the center.
@ -104,11 +111,7 @@ class DragTopic {
$assert(parent, 'Parent connection node can not be null.'); $assert(parent, 'Parent connection node can not be null.');
// Where it should be connected ? // Where it should be connected ?
const predict = this._layoutManager.predict(
// @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(
parent.getId(), parent.getId(),
this._draggedNode.getId(), this._draggedNode.getId(),
this.getPosition(), this.getPosition(),
@ -154,8 +157,8 @@ class DragTopic {
} }
} }
_getDragPivot(): DragPivot { private _getDragPivot(): DragPivot {
return DragTopic.__getDragPivot(); return DragTopic._dragPivot;
} }
getPosition(): Point { getPosition(): Point {
@ -206,18 +209,9 @@ class DragTopic {
static init(workspace: Workspace) { static init(workspace: Workspace) {
$assert(workspace, 'workspace can not be null'); $assert(workspace, 'workspace can not be null');
const pivot = DragTopic.__getDragPivot(); const pivot = DragTopic._dragPivot;
workspace.append(pivot); workspace.append(pivot);
};
static __getDragPivot() {
let result = DragTopic._dragPivot;
if (!$defined(result)) {
result = new DragPivot();
DragTopic._dragPivot = result;
} }
return result;
};
} }
export default DragTopic; 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 { class EditorProperties {
private _zoom: number;
constructor() { constructor() {
this._zoom = 0; this._zoom = 0;
this._position = 0;
} }
setZoom(zoom) { setZoom(zoom: number) {
this._zoom = zoom; this._zoom = zoom;
} }
getZoom() { getZoom(): number {
return this._zoom; return this._zoom;
} }
asProperties() { asProperties(): string {
return `zoom=${this._zoom}\n`; 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 { class Events {
private $events; private _handlerByType;
constructor() { constructor() {
this.$events = {}; this._handlerByType = {};
} }
static _removeOn(string: string) { static _normalizeEventName(string: string) {
return string.replace(/^on([A-Z])/, (full, first) => first.toLowerCase()); return string.replace(/^on([A-Z])/, (_full, first) => first.toLowerCase());
} }
addEvent(typeName: string, fn?, internal?: boolean): Events { addEvent(typeName: string, fn?, internal?: boolean): Events {
const type = Events._removeOn(typeName); const type = Events._normalizeEventName(typeName);
// Add function had not been added yet // 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)) { if (!funByType.includes(fn)) {
funByType.push(fn); funByType.push(fn);
this.$events[type] = funByType; this._handlerByType[type] = funByType;
} }
// Mark reference ... // Mark reference ...
@ -42,25 +42,21 @@ class Events {
return this; return this;
} }
fireEvent(typeName: string, eventArgs?, delay?: boolean): Events { fireEvent(typeName: string, eventArgs?): Events {
const type = Events._removeOn(typeName); const type = Events._normalizeEventName(typeName);
const events = this.$events[type]; const events = this._handlerByType[type];
if (!events) return this; if (!events) return this;
const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs]; const args = Array.isArray(eventArgs) ? eventArgs : [eventArgs];
events.forEach(((fn) => { events.forEach(((fn) => {
if (delay) {
fn.delay(delay, this, args);
} else {
fn.apply(this, args); fn.apply(this, args);
}
})); }));
return this; return this;
} }
removeEvent(typeName: string, fn?): Events { removeEvent(typeName: string, fn?): Events {
const type = Events._removeOn(typeName); const type = Events._normalizeEventName(typeName);
const events = this.$events[type]; const events = this._handlerByType[type];
if (events && !fn.internal) { if (events && !fn.internal) {
const index = events.indexOf(fn); const index = events.indexOf(fn);
if (index !== -1) events.splice(index, 1); if (index !== -1) events.splice(index, 1);

View File

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

View File

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

View File

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

View File

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

View File

@ -144,7 +144,13 @@ class MultilineTextEditor extends Events {
const topicId = this._topic.getId(); const topicId = this._topic.getId();
const actionDispatcher = ActionDispatcher.getInstance(); const actionDispatcher = ActionDispatcher.getInstance();
try {
actionDispatcher.changeTextToTopic([topicId], text); 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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,12 +20,14 @@ import ES from './es';
import EN from './en'; import EN from './en';
import DE from './de'; import DE from './de';
import FR from './fr'; import FR from './fr';
import RU from './ru';
const Bundle = { const Bundle = {
es: ES, es: ES,
en: EN, en: EN,
de: DE, de: DE,
fr: FR, fr: FR,
ru: RU,
}; };
export default Bundle; 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] * Copyright [2021] [wisemapping]
* *
* Licensed under WiseMapping Public License, Version 1.0 (the "License"). * Licensed under WiseMapping Public License, Version 1.0 (the "License").
@ -17,22 +15,26 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import RootedTreeSet from './RootedTreeSet';
import Node from './Node';
import PositionType from '../PositionType';
abstract class ChildrenSorterStrategy { 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; export default ChildrenSorterStrategy;

View File

@ -17,25 +17,22 @@
*/ */
import Events from '../Events'; import Events from '../Events';
export type EventType = 'topicResize' | 'topicMoved' | 'childShrinked' | 'topicConnected' | 'topicAdded' | 'topicRemoved' | 'forceLayout' | 'topicDisconect';
class EventBus extends Events { 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; export default EventBus;

View File

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

View File

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

View File

@ -28,31 +28,20 @@ class RootedTreeSet {
this._rootNodes = []; this._rootNodes = [];
} }
/**
* @param root
* @throws will throw an error if root is null or undefined
*/
setRoot(root: Node) { setRoot(root: Node) {
$assert(root, 'root can not be null'); $assert(root, 'root can not be null');
this._rootNodes.push(this._decodate(root)); this._rootNodes.push(this._decodate(root));
} }
/** getter */ getTreeRoots(): Node[] {
getTreeRoots() {
return this._rootNodes; return this._rootNodes;
} }
_decodate(node: Node) { _decodate(node: Node): Node {
node._children = []; node._children = [];
return node; 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) { add(node: Node) {
$assert(node, 'node can not be null'); $assert(node, 'node can not be null');
if (this.find(node.getId(), false)) { if (this.find(node.getId(), false)) {

View File

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

View File

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

View File

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

View File

@ -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: '', title: '',
content: '', content: '',
delay: 0, delay: 0,
container: false, container: '#mindplot-tooltips',
destroyOnExit: false, destroyOnExit: false,
}; };
class FloatingTip extends Events { class FloatingTip extends Events {
private options;
private element;
constructor(element, options) { constructor(element, options) {
super();
const opts = { ...defaultOptions, ...options }; const opts = { ...defaultOptions, ...options };
super(element, opts);
this.setOptions(opts); this.setOptions(opts);
this.element = element; this.element = element;
this._createPopover(); this._createPopover();

View File

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

View File

@ -31,7 +31,6 @@ class LinkIconTooltip extends FloatingTip {
}, },
html: true, html: true,
placement: 'bottom', placement: 'bottom',
container: 'body',
title: $msg('LINK'), title: $msg('LINK'),
trigger: 'manual', 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>', 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 { $assert } from '@wisemapping/core-js';
import $ from 'jquery'; import $ from 'jquery';
import BootstrapDialog from '../libraries/bootstrap/BootstrapDialog'; import BootstrapDialog from '../../../../editor/src/classes/bootstrap/BootstrapDialog';
import { $msg } from '../Messages'; import { $msg } from '../Messages';
class NoteEditor extends BootstrapDialog { class NoteEditor extends BootstrapDialog {

View File

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

View File

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

View File

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

View File

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

View File

@ -255,8 +255,8 @@ class ElementClass {
this.peer.setFill(null, opacity); this.peer.setFill(null, opacity);
} }
setVisibility(isVisible) { setVisibility(value, fade) {
this.peer.setVisibility(isVisible); this.peer.setVisibility(value, fade);
} }
isVisible() { isVisible() {

View File

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

View File

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

View File

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

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", "name": "@wisemapping/webapp",
"version": "5.0.7", "version": "5.0.8",
"main": "app.jsx", "main": "app.jsx",
"scripts": { "scripts": {
"start": "webpack serve --config webpack.dev.js ", "start": "webpack serve --config webpack.dev.js ",

View File

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

View File

@ -2,6 +2,7 @@ import { fetchAccount } from './../../redux/clientSlice';
import 'dayjs/locale/fr'; import 'dayjs/locale/fr';
import 'dayjs/locale/en'; import 'dayjs/locale/en';
import 'dayjs/locale/es'; import 'dayjs/locale/es';
import 'dayjs/locale/ru';
export class Locale { export class Locale {
code: LocaleCode; 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 = { export const Locales = {
EN: new Locale('en', 'English', require('./../../compiled-lang/en.json')), // eslint-disable-line 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 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 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 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 => { export const localeFromStr = (code: string): Locale => {
const locales: Locale[] = Object.values(Locales); 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, { import Client, {
AccountInfo, AccountInfo,
BasicMapInfo, BasicMapInfo,
@ -130,8 +130,8 @@ class CacheDecoratorClient implements Client {
return this.client.revertHistory(id, cid); return this.client.revertHistory(id, cid);
} }
buildPersistenceManager(isTryMode: boolean): PersistenceManager { buildPersistenceManager(mode: EditorRenderMode): PersistenceManager {
return this.client.buildPersistenceManager(isTryMode); return this.client.buildPersistenceManager(mode);
} }
removePersistenceManager(): void { removePersistenceManager(): void {

View File

@ -1,4 +1,4 @@
import { Mindmap, PersistenceManager } from '@wisemapping/mindplot'; import { EditorRenderMode, Mindmap, PersistenceManager } from '@wisemapping/mindplot';
import { Locale, LocaleCode } from '../app-i18n'; import { Locale, LocaleCode } from '../app-i18n';
export type NewUser = { export type NewUser = {
@ -109,7 +109,7 @@ interface Client {
fetchMindmap(id: number): Mindmap; fetchMindmap(id: number): Mindmap;
buildPersistenceManager(isTryMode: boolean): PersistenceManager; buildPersistenceManager(mode: EditorRenderMode): PersistenceManager;
removePersistenceManager(): void; removePersistenceManager(): void;
onSessionExpired(callback?: () => void): () => void; onSessionExpired(callback?: () => void): () => void;

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