mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-15 19:47:57 +01:00
Merged feature/remove_actions into master
* Migration to TS * Change to typescript * Fix css style issue due to bootstrap. * Fix eslit errors * Remove print button on try
This commit is contained in:
parent
165142a0f5
commit
2c4d937ffa
20
packages/editor/src/bootstrap-fixes.css
vendored
Normal file
20
packages/editor/src/bootstrap-fixes.css
vendored
Normal 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;
|
||||||
|
}
|
10
packages/editor/src/bootstrap-prefix.min.css
vendored
Normal file
10
packages/editor/src/bootstrap-prefix.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
7
packages/editor/src/bootstrap.min.css
vendored
7
packages/editor/src/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@ -43,12 +43,12 @@ export default function Toolbar({
|
|||||||
}: 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>
|
||||||
{editorMode === 'edition' && (
|
{(editorMode === 'edition-editor' || editorMode === 'edition-owner') && (
|
||||||
<div id="persist" className="buttonContainer">
|
<div id="persist" className="buttonContainer">
|
||||||
<ToolbarButton id="save" className="buttonOn">
|
<ToolbarButton id="save" className="buttonOn">
|
||||||
<img src={SaveSvg} />
|
<img src={SaveSvg} />
|
||||||
@ -112,29 +112,15 @@ export default function Toolbar({
|
|||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
</div>
|
</div>
|
||||||
<div id="separator" className="buttonContainer"></div>
|
<div id="separator" className="buttonContainer"></div>
|
||||||
{editorMode === 'edition' && (
|
<ToolbarRightContainer>
|
||||||
<ToolbarRightContainer>
|
<ToolbarButton
|
||||||
<ToolbarButton
|
id="export"
|
||||||
id="export"
|
className="buttonOn"
|
||||||
className="buttonOn"
|
onClick={() => onAction('export')}
|
||||||
onClick={() => onAction('export')}
|
>
|
||||||
>
|
<img src={ExportSvg} />
|
||||||
<img src={ExportSvg} />
|
</ToolbarButton>
|
||||||
</ToolbarButton>
|
{(editorMode === 'edition-owner' || editorMode === 'edition-editor' || editorMode === 'edition-viewer') && (
|
||||||
<ToolbarButton
|
|
||||||
id="publishIt"
|
|
||||||
className="buttonOn"
|
|
||||||
onClick={() => onAction('publish')}
|
|
||||||
>
|
|
||||||
<img src={PublicSvg} />
|
|
||||||
</ToolbarButton>
|
|
||||||
<ToolbarButton
|
|
||||||
id="history"
|
|
||||||
className="buttonOn"
|
|
||||||
onClick={() => onAction('history')}
|
|
||||||
>
|
|
||||||
<img src={HistorySvg} />
|
|
||||||
</ToolbarButton>
|
|
||||||
<ToolbarButton
|
<ToolbarButton
|
||||||
id="print"
|
id="print"
|
||||||
className="buttonOn"
|
className="buttonOn"
|
||||||
@ -142,14 +128,37 @@ export default function Toolbar({
|
|||||||
>
|
>
|
||||||
<img src={PrintSvg} />
|
<img src={PrintSvg} />
|
||||||
</ToolbarButton>
|
</ToolbarButton>
|
||||||
|
)}
|
||||||
|
{editorMode === 'edition-owner' && (
|
||||||
|
<>
|
||||||
|
<ToolbarButton
|
||||||
|
id="history"
|
||||||
|
className="buttonOn"
|
||||||
|
onClick={() => onAction('history')}
|
||||||
|
>
|
||||||
|
<img src={HistorySvg} />
|
||||||
|
</ToolbarButton>
|
||||||
|
<ToolbarButton
|
||||||
|
id="publishIt"
|
||||||
|
className="buttonOn"
|
||||||
|
onClick={() => onAction('publish')}
|
||||||
|
>
|
||||||
|
<img src={PublicSvg} />
|
||||||
|
</ToolbarButton>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{(editorMode === 'edition-owner' || editorMode === 'edition-editor') && (
|
||||||
<ToolbarButton id="account">
|
<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>
|
||||||
);
|
);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,6 @@ import {
|
|||||||
} from '@wisemapping/mindplot';
|
} from '@wisemapping/mindplot';
|
||||||
import './global-styled.css';
|
import './global-styled.css';
|
||||||
import I18nMsg from './classes/i18n-msg';
|
import I18nMsg from './classes/i18n-msg';
|
||||||
import Messages from '@wisemapping/mindplot/src/components/Messages';
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
// used in mindplot
|
// used in mindplot
|
||||||
@ -100,7 +99,8 @@ const Editor = ({
|
|||||||
onAction={onAction}
|
onAction={onAction}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div id="mindplot" style={mindplotStyle}></div>
|
<div id="mindplot" style={mindplotStyle} className="wise-editor"></div>
|
||||||
|
<div id="mindplot-tooltips" className="wise-editor"></div>
|
||||||
<Footer editorMode={options.mode} />
|
<Footer editorMode={options.mode} />
|
||||||
</IntlProvider >
|
</IntlProvider >
|
||||||
);
|
);
|
||||||
|
@ -36,7 +36,7 @@ const options: EditorOptions = {
|
|||||||
zoom: 0.8,
|
zoom: 0.8,
|
||||||
locked: false,
|
locked: false,
|
||||||
mapTitle: "Develop Mindnap",
|
mapTitle: "Develop Mindnap",
|
||||||
mode: 'edition',
|
mode: 'edition-owner',
|
||||||
locale: 'en',
|
locale: 'en',
|
||||||
enableKeyboardEvents: true
|
enableKeyboardEvents: true
|
||||||
};
|
};
|
||||||
|
2
packages/mindplot/src/@types/custom.d.ts
vendored
2
packages/mindplot/src/@types/custom.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
declare module "*.svg" {
|
declare module '*.svg' {
|
||||||
const content: any;
|
const content: any;
|
||||||
export default content;
|
export default content;
|
||||||
}
|
}
|
@ -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;
|
|
@ -41,20 +41,15 @@ class CommandContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
findTopics(topicIds: number[]): Topic[] {
|
findTopics(topicIds: number[]): Topic[] {
|
||||||
$assert($defined(topicIds), 'topicsIds can not be null');
|
|
||||||
const topicsIds = Array.isArray(topicIds) ? topicIds : [topicIds];
|
const topicsIds = Array.isArray(topicIds) ? topicIds : [topicIds];
|
||||||
const designerTopics = this._designer.getModel().getTopics();
|
const designerTopics = this._designer.getModel().getTopics();
|
||||||
const result = designerTopics.filter((topic) => topicsIds.includes(topic.getId()));
|
const result = designerTopics.filter((topic) => topicsIds.includes(topic.getId()));
|
||||||
|
|
||||||
if (result.length !== topicsIds.length) {
|
if (result.length !== topicsIds.length) {
|
||||||
const ids = designerTopics.map((topic) => topic.getId());
|
const ids = designerTopics.map((topic) => topic.getId());
|
||||||
$assert(
|
throw new Error(`Could not find topic. Result:${result
|
||||||
result.length === topicsIds.length,
|
} Filter Criteria:${topicsIds
|
||||||
`Could not find topic. Result:${result
|
} Current Topics: [${ids}])`);
|
||||||
} Filter Criteria:${topicsIds
|
|
||||||
} Current Topics: [${ids
|
|
||||||
}]`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -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,
|
||||||
});
|
});
|
||||||
|
@ -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() {
|
||||||
|
@ -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';
|
||||||
@ -225,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 ...
|
||||||
@ -606,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');
|
||||||
}
|
}
|
||||||
@ -695,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();
|
||||||
|
|
||||||
@ -744,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
|
||||||
@ -771,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();
|
||||||
@ -840,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);
|
||||||
@ -849,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) {
|
||||||
@ -859,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) {
|
||||||
@ -895,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) {
|
||||||
@ -908,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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ export function buildDesigner(options: DesignerOptions): Designer {
|
|||||||
PersistenceManager.init(persistence);
|
PersistenceManager.init(persistence);
|
||||||
|
|
||||||
// Register toolbar event ...
|
// Register toolbar event ...
|
||||||
if (options.mode === 'edition' || options.mode === 'showcase') {
|
if (options.mode === 'edition-owner' || options.mode === 'edition-editor' || options.mode === 'showcase') {
|
||||||
const menu = new Menu(designer, 'toolbar');
|
const menu = new Menu(designer, 'toolbar');
|
||||||
|
|
||||||
// If a node has focus, focus can be move to another node using the keys.
|
// If a node has focus, focus can be move to another node using the keys.
|
||||||
|
@ -46,7 +46,7 @@ class OptionsBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const defaultOptions: DesignerOptions = {
|
const defaultOptions: DesignerOptions = {
|
||||||
mode: 'edition',
|
mode: 'edition-owner',
|
||||||
zoom: 0.85,
|
zoom: 0.85,
|
||||||
saveOnLoad: true,
|
saveOnLoad: true,
|
||||||
containerSize,
|
containerSize,
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
const PIVOT_SIZE = { width: 50, height: 6 };
|
|
||||||
|
|
||||||
export default {
|
|
||||||
PIVOT_SIZE,
|
|
||||||
};
|
|
@ -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`;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,2 +1,2 @@
|
|||||||
type EditorRenderMode = 'viewonly' | 'edition' | 'showcase';
|
type EditorRenderMode = 'viewonly' | 'edition-owner' | 'edition-editor' | 'edition-viewer' | 'showcase';
|
||||||
export default EditorRenderMode;
|
export default EditorRenderMode;
|
||||||
|
@ -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.apply(this, args);
|
||||||
fn.delay(delay, this, args);
|
|
||||||
} else {
|
|
||||||
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);
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
|
||||||
};
|
|
@ -27,8 +27,11 @@ import FeatureModel from './model/FeatureModel';
|
|||||||
|
|
||||||
class NoteIcon extends Icon {
|
class NoteIcon extends Icon {
|
||||||
private _linksModel: NoteModel;
|
private _linksModel: NoteModel;
|
||||||
|
|
||||||
private _topic: Topic;
|
private _topic: Topic;
|
||||||
|
|
||||||
private _readOnly: boolean;
|
private _readOnly: boolean;
|
||||||
|
|
||||||
private _tip: FloatingTip;
|
private _tip: FloatingTip;
|
||||||
|
|
||||||
constructor(topic: Topic, noteModel: NoteModel, readOnly: boolean) {
|
constructor(topic: Topic, noteModel: NoteModel, readOnly: boolean) {
|
||||||
@ -55,7 +58,6 @@ class NoteIcon extends Icon {
|
|||||||
}
|
}
|
||||||
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 +90,6 @@ class NoteIcon extends Icon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static IMAGE_URL = NotesImage;
|
static IMAGE_URL = NotesImage;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NoteIcon;
|
export default NoteIcon;
|
||||||
|
@ -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) {
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
elements.forEach((elem) => {
|
||||||
const me = this;
|
elem.setVisibility(!value, 250);
|
||||||
fade.addEvent('complete', () => {
|
|
||||||
// Set focus on the parent node ...
|
|
||||||
if (value) {
|
|
||||||
me.setOnFocus(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set focus in false for all the children ...
|
|
||||||
elements.forEach((elem) => {
|
|
||||||
if (elem.setOnFocus) {
|
|
||||||
elem.setOnFocus(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
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();
|
||||||
|
27
packages/mindplot/src/components/TopicFactory.ts
Normal file
27
packages/mindplot/src/components/TopicFactory.ts
Normal 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;
|
@ -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');
|
||||||
|
@ -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);
|
||||||
|
@ -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]);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
@ -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;
|
||||||
}
|
}
|
@ -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);
|
||||||
}
|
}
|
@ -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)) {
|
||||||
|
@ -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() {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import fadeEffect from './FadeEffect';
|
|
||||||
import shape from './Shape';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
FadeEffect: fadeEffect,
|
|
||||||
Shape: shape,
|
|
||||||
};
|
|
@ -27,7 +27,7 @@ const defaultOptions = {
|
|||||||
title: '',
|
title: '',
|
||||||
content: '',
|
content: '',
|
||||||
delay: 0,
|
delay: 0,
|
||||||
container: false,
|
container: '#mindplot-tooltips',
|
||||||
destroyOnExit: false,
|
destroyOnExit: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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>',
|
||||||
|
@ -39,170 +39,145 @@ class Menu extends IMenu {
|
|||||||
|
|
||||||
// Create panels ...
|
// Create panels ...
|
||||||
const designerModel = designer.getModel();
|
const designerModel = designer.getModel();
|
||||||
|
const fontFamilyModel = {
|
||||||
const fontFamilyBtn = $('#fontFamily');
|
getValue() {
|
||||||
if (fontFamilyBtn) {
|
const nodes = designerModel.filterSelectedTopics();
|
||||||
const fontFamilyModel = {
|
let result = null;
|
||||||
getValue() {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
const nodes = designerModel.filterSelectedTopics();
|
const fontFamily = nodes[i].getFontFamily();
|
||||||
let result = null;
|
if (result != null && result !== fontFamily) {
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
result = null;
|
||||||
const fontFamily = nodes[i].getFontFamily();
|
break;
|
||||||
if (result != null && result !== fontFamily) {
|
|
||||||
result = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = fontFamily;
|
|
||||||
}
|
}
|
||||||
return result;
|
result = fontFamily;
|
||||||
},
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
setValue(value: string) {
|
setValue(value: string) {
|
||||||
designer.changeFontFamily(value);
|
designer.changeFontFamily(value);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
this._toolbarElems.push(new FontFamilyPanel('fontFamily', fontFamilyModel));
|
this._toolbarElems.push(new FontFamilyPanel('fontFamily', fontFamilyModel));
|
||||||
Menu._registerTooltip('fontFamily', $msg('FONT_FAMILY'));
|
Menu._registerTooltip('fontFamily', $msg('FONT_FAMILY'));
|
||||||
}
|
|
||||||
|
|
||||||
const fontSizeBtn = $('#fontSize');
|
const fontSizeModel = {
|
||||||
if (fontSizeBtn) {
|
getValue(): number {
|
||||||
const fontSizeModel = {
|
const nodes = designerModel.filterSelectedTopics();
|
||||||
getValue(): number {
|
|
||||||
const nodes = designerModel.filterSelectedTopics();
|
|
||||||
|
|
||||||
let result = null;
|
let result = null;
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
const fontSize = nodes[i].getFontSize();
|
const fontSize = nodes[i].getFontSize();
|
||||||
if (result != null && result !== fontSize) {
|
if (result != null && result !== fontSize) {
|
||||||
result = null;
|
result = null;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
result = fontSize;
|
|
||||||
}
|
}
|
||||||
return result;
|
result = fontSize;
|
||||||
},
|
}
|
||||||
setValue(value: number) {
|
return result;
|
||||||
designer.changeFontSize(value);
|
},
|
||||||
},
|
setValue(value: number) {
|
||||||
};
|
designer.changeFontSize(value);
|
||||||
this._toolbarElems.push(new FontSizePanel('fontSize', fontSizeModel));
|
},
|
||||||
Menu._registerTooltip('fontSize', $msg('FONT_SIZE'));
|
};
|
||||||
}
|
this._toolbarElems.push(new FontSizePanel('fontSize', fontSizeModel));
|
||||||
|
Menu._registerTooltip('fontSize', $msg('FONT_SIZE'));
|
||||||
|
|
||||||
const topicShapeBtn = $('#topicShape');
|
const topicShapeModel = {
|
||||||
if (topicShapeBtn) {
|
getValue() {
|
||||||
const topicShapeModel = {
|
const nodes = designerModel.filterSelectedTopics();
|
||||||
getValue() {
|
let result = null;
|
||||||
const nodes = designerModel.filterSelectedTopics();
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
let result = null;
|
const shapeType = nodes[i].getShapeType();
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
if (result != null && result !== shapeType) {
|
||||||
const shapeType = nodes[i].getShapeType();
|
result = null;
|
||||||
if (result != null && result !== shapeType) {
|
break;
|
||||||
result = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = shapeType;
|
|
||||||
}
|
}
|
||||||
return result;
|
result = shapeType;
|
||||||
},
|
}
|
||||||
setValue(value: string) {
|
return result;
|
||||||
designer.changeTopicShape(value);
|
},
|
||||||
},
|
setValue(value: string) {
|
||||||
};
|
designer.changeTopicShape(value);
|
||||||
this._toolbarElems.push(new TopicShapePanel('topicShape', topicShapeModel));
|
},
|
||||||
Menu._registerTooltip('topicShape', $msg('TOPIC_SHAPE'));
|
};
|
||||||
}
|
this._toolbarElems.push(new TopicShapePanel('topicShape', topicShapeModel));
|
||||||
|
Menu._registerTooltip('topicShape', $msg('TOPIC_SHAPE'));
|
||||||
|
|
||||||
const topicIconBtn = $('#topicIcon');
|
// Create icon panel dialog ...
|
||||||
if (topicIconBtn) {
|
const topicIconModel = {
|
||||||
// Create icon panel dialog ...
|
getValue() {
|
||||||
const topicIconModel = {
|
return null;
|
||||||
getValue() {
|
},
|
||||||
return null;
|
setValue(value: string) {
|
||||||
},
|
designer.addIconType(value);
|
||||||
setValue(value: string) {
|
},
|
||||||
designer.addIconType(value);
|
};
|
||||||
},
|
this._toolbarElems.push(new IconPanel('topicIcon', topicIconModel));
|
||||||
};
|
Menu._registerTooltip('topicIcon', $msg('TOPIC_ICON'));
|
||||||
this._toolbarElems.push(new IconPanel('topicIcon', topicIconModel));
|
|
||||||
Menu._registerTooltip('topicIcon', $msg('TOPIC_ICON'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Topic color item ...
|
const topicColorModel = {
|
||||||
const topicColorBtn = $('#topicColor');
|
getValue() {
|
||||||
if (topicColorBtn) {
|
const nodes = designerModel.filterSelectedTopics();
|
||||||
const topicColorModel = {
|
let result = null;
|
||||||
getValue() {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
const nodes = designerModel.filterSelectedTopics();
|
const color = nodes[i].getBackgroundColor();
|
||||||
let result = null;
|
if (result != null && result !== color) {
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
result = null;
|
||||||
const color = nodes[i].getBackgroundColor();
|
break;
|
||||||
if (result != null && result !== color) {
|
|
||||||
result = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = color;
|
|
||||||
}
|
}
|
||||||
return result;
|
result = color;
|
||||||
},
|
}
|
||||||
setValue(hex: string) {
|
return result;
|
||||||
designer.changeBackgroundColor(hex);
|
},
|
||||||
},
|
setValue(hex: string) {
|
||||||
};
|
designer.changeBackgroundColor(hex);
|
||||||
this._toolbarElems.push(new ColorPalettePanel('topicColor', topicColorModel, widgetsBaseUrl));
|
},
|
||||||
Menu._registerTooltip('topicColor', $msg('TOPIC_COLOR'));
|
};
|
||||||
}
|
this._toolbarElems.push(new ColorPalettePanel('topicColor', topicColorModel, widgetsBaseUrl));
|
||||||
|
Menu._registerTooltip('topicColor', $msg('TOPIC_COLOR'));
|
||||||
|
|
||||||
// Border color item ...
|
const borderColorModel = {
|
||||||
const topicBorderBtn = $('#topicBorder');
|
getValue() {
|
||||||
if (topicBorderBtn) {
|
const nodes = designerModel.filterSelectedTopics();
|
||||||
const borderColorModel = {
|
let result = null;
|
||||||
getValue() {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
const nodes = designerModel.filterSelectedTopics();
|
const color = nodes[i].getBorderColor();
|
||||||
let result = null;
|
if (result != null && result !== color) {
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
result = null;
|
||||||
const color = nodes[i].getBorderColor();
|
break;
|
||||||
if (result != null && result !== color) {
|
|
||||||
result = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = color;
|
|
||||||
}
|
}
|
||||||
return result;
|
result = color;
|
||||||
},
|
}
|
||||||
setValue(hex: string) {
|
return result;
|
||||||
designer.changeBorderColor(hex);
|
},
|
||||||
},
|
setValue(hex: string) {
|
||||||
};
|
designer.changeBorderColor(hex);
|
||||||
this._toolbarElems.push(new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl));
|
},
|
||||||
Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR'));
|
};
|
||||||
}
|
this._toolbarElems.push(new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl));
|
||||||
|
Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR'));
|
||||||
|
|
||||||
// Font color item ...
|
const fontColorModel = {
|
||||||
const fontColorBtn = $('#fontColor');
|
getValue() {
|
||||||
if (fontColorBtn) {
|
let result = null;
|
||||||
const fontColorModel = {
|
const nodes = designerModel.filterSelectedTopics();
|
||||||
getValue() {
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
let result = null;
|
const color = nodes[i].getFontColor();
|
||||||
const nodes = designerModel.filterSelectedTopics();
|
if (result != null && result !== color) {
|
||||||
for (let i = 0; i < nodes.length; i++) {
|
result = null;
|
||||||
const color = nodes[i].getFontColor();
|
break;
|
||||||
if (result != null && result !== color) {
|
|
||||||
result = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
result = color;
|
|
||||||
}
|
}
|
||||||
return result;
|
result = color;
|
||||||
},
|
}
|
||||||
setValue(hex) {
|
return result;
|
||||||
designer.changeFontColor(hex);
|
},
|
||||||
},
|
setValue(hex) {
|
||||||
};
|
designer.changeFontColor(hex);
|
||||||
this._toolbarElems.push(new ColorPalettePanel('fontColor', fontColorModel, baseUrl));
|
},
|
||||||
Menu._registerTooltip('fontColor', $msg('FONT_COLOR'));
|
};
|
||||||
}
|
this._toolbarElems.push(new ColorPalettePanel('fontColor', fontColorModel, baseUrl));
|
||||||
|
Menu._registerTooltip('fontColor', $msg('FONT_COLOR'));
|
||||||
|
|
||||||
Menu._registerTooltip('export', $msg('EXPORT'));
|
Menu._registerTooltip('export', $msg('EXPORT'));
|
||||||
|
|
||||||
@ -315,14 +290,6 @@ class Menu extends IMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const discardElem = $('#discard');
|
|
||||||
if (discardElem.length !== 0) {
|
|
||||||
this._addButton('discard', false, false, () => {
|
|
||||||
this.discardChanges(designer);
|
|
||||||
});
|
|
||||||
Menu._registerTooltip('discard', $msg('DISCARD_CHANGES'));
|
|
||||||
}
|
|
||||||
|
|
||||||
const shareElem = $('#shareIt');
|
const shareElem = $('#shareIt');
|
||||||
if (shareElem.length !== 0) {
|
if (shareElem.length !== 0) {
|
||||||
Menu._registerTooltip('shareIt', $msg('COLLABORATE'));
|
Menu._registerTooltip('shareIt', $msg('COLLABORATE'));
|
||||||
@ -350,14 +317,12 @@ class Menu extends IMenu {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const backTolist = $('#backToList');
|
const backTolist = $('#backToList');
|
||||||
if (backTolist.length !== 0) {
|
backTolist.bind('click', (event) => {
|
||||||
backTolist.bind('click', (event) => {
|
event.stopPropagation();
|
||||||
event.stopPropagation();
|
window.location.href = '/c/maps/';
|
||||||
window.location.href = '/c/maps/';
|
return false;
|
||||||
return false;
|
});
|
||||||
});
|
Menu._registerTooltip('backToList', $msg('BACK_TO_MAP_LIST'));
|
||||||
Menu._registerTooltip('backToList', $msg('BACK_TO_MAP_LIST'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account dialog ...
|
// Account dialog ...
|
||||||
const accountSettings = $('#account');
|
const accountSettings = $('#account');
|
||||||
@ -367,9 +332,9 @@ class Menu extends IMenu {
|
|||||||
});
|
});
|
||||||
this._toolbarElems.push(new AccountSettingsPanel('account'));
|
this._toolbarElems.push(new AccountSettingsPanel('account'));
|
||||||
Menu._registerTooltip('account', `${global.accountEmail}`);
|
Menu._registerTooltip('account', `${global.accountEmail}`);
|
||||||
}
|
|
||||||
|
|
||||||
this._registerEvents(designer);
|
this._registerEvents(designer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _registerEvents(designer: Designer) {
|
private _registerEvents(designer: Designer) {
|
||||||
|
@ -161,12 +161,12 @@ class ElementClass {
|
|||||||
setStroke(width, style, color, opacity) {
|
setStroke(width, style, color, opacity) {
|
||||||
if (
|
if (
|
||||||
style != null
|
style != null
|
||||||
&& style !== undefined
|
&& style !== undefined
|
||||||
&& style !== 'dash'
|
&& style !== 'dash'
|
||||||
&& style !== 'dot'
|
&& style !== 'dot'
|
||||||
&& style !== 'solid'
|
&& style !== 'solid'
|
||||||
&& style !== 'longdash'
|
&& style !== 'longdash'
|
||||||
&& style !== 'dashdot'
|
&& style !== 'dashdot'
|
||||||
) {
|
) {
|
||||||
throw new Error(`Unsupported stroke style: '${style}'`);
|
throw new Error(`Unsupported stroke style: '${style}'`);
|
||||||
}
|
}
|
||||||
@ -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() {
|
||||||
|
@ -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() {
|
||||||
|
@ -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>
|
||||||
|
@ -225,15 +225,14 @@ 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);
|
||||||
});
|
});
|
||||||
|
|
||||||
let isVisible = true;
|
rect.addEvent('mouseout', () => {
|
||||||
const executer = function () {
|
rect.setVisibility(true, 500);
|
||||||
isVisible = !isVisible;
|
});
|
||||||
rect.setVisibility(isVisible);
|
|
||||||
};
|
// executer.periodical(100);
|
||||||
// executer.periodical(100);
|
|
||||||
workspace.addItAsChildTo($('#visibility'));
|
workspace.addItAsChildTo($('#visibility'));
|
||||||
};
|
};
|
||||||
visibilityTest();
|
visibilityTest();
|
||||||
|
@ -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} />
|
||||||
|
@ -611,12 +611,12 @@ export default class RestClient implements Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
buildPersistenceManager(editorMode: EditorRenderMode ): PersistenceManager {
|
buildPersistenceManager(editorMode: EditorRenderMode): PersistenceManager {
|
||||||
if (this.persistenceManager) {
|
if (this.persistenceManager) {
|
||||||
return this.persistenceManager;
|
return this.persistenceManager;
|
||||||
}
|
}
|
||||||
let persistence: PersistenceManager;
|
let persistence: PersistenceManager;
|
||||||
if (editorMode === 'edition') {
|
if (editorMode === 'edition-owner' || editorMode === 'edition-editor') {
|
||||||
persistence = new RESTPersistenceManager({
|
persistence = new RESTPersistenceManager({
|
||||||
documentUrl: '/c/restful/maps/{id}/document',
|
documentUrl: '/c/restful/maps/{id}/document',
|
||||||
revertUrl: '/c/restful/maps/{id}/history/latest',
|
revertUrl: '/c/restful/maps/{id}/history/latest',
|
||||||
@ -645,13 +645,15 @@ export default class RestClient implements Client {
|
|||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private parseResponseOnError = (response: any): ErrorInfo => {
|
private parseResponseOnError = (response: any): ErrorInfo => {
|
||||||
console.error("Backend error=>");
|
console.error(`Performing backend action error: ${JSON.stringify(response)}`);
|
||||||
console.error(response.data);
|
|
||||||
|
|
||||||
let result: ErrorInfo | undefined;
|
let result: ErrorInfo | undefined;
|
||||||
if (response) {
|
if (response) {
|
||||||
const status: number = response.status;
|
const status: number = response.status;
|
||||||
const data = response.data;
|
const data = response.data;
|
||||||
|
console.error(`Status Code: ${status}`);
|
||||||
|
console.error(`Status Data: ${response.data}`);
|
||||||
|
console.error(`Status Message: ${response.message}`);
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 401:
|
case 401:
|
||||||
|
@ -1,25 +1,16 @@
|
|||||||
import { EditorOptions } from '@wisemapping/editor';
|
import { EditorOptions } from '@wisemapping/editor';
|
||||||
|
import { EditorRenderMode } from '@wisemapping/mindplot';
|
||||||
import AppConfig from '../../classes/app-config';
|
import AppConfig from '../../classes/app-config';
|
||||||
|
|
||||||
export default class EditorOptionsBulder {
|
export default class EditorOptionsBulder {
|
||||||
static build(locale: string, hotkeys: boolean, isTryMode: boolean): { options: EditorOptions, mapId: number } {
|
static build(locale: string, mode: EditorRenderMode, hotkeys: boolean): EditorOptions {
|
||||||
|
|
||||||
let options: EditorOptions = {
|
let options: EditorOptions = {
|
||||||
enableKeyboardEvents: hotkeys,
|
enableKeyboardEvents: hotkeys,
|
||||||
locale: locale,
|
locale: locale,
|
||||||
|
mode: mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isTryMode) {
|
|
||||||
// Sent to try mode ...
|
|
||||||
options.mode = 'showcase';
|
|
||||||
} else if (global.mindmapLocked) {
|
|
||||||
// Map locked, open for view mode ...
|
|
||||||
options.mode = 'viewonly';
|
|
||||||
} else {
|
|
||||||
options.mode = 'edition';
|
|
||||||
}
|
|
||||||
|
|
||||||
let mapId: number;
|
|
||||||
if (!AppConfig.isDevelopEnv()) {
|
if (!AppConfig.isDevelopEnv()) {
|
||||||
options = {
|
options = {
|
||||||
zoom: (global.userOptions?.zoom != undefined
|
zoom: (global.userOptions?.zoom != undefined
|
||||||
@ -30,7 +21,6 @@ export default class EditorOptionsBulder {
|
|||||||
mapTitle: global.mapTitle,
|
mapTitle: global.mapTitle,
|
||||||
...options
|
...options
|
||||||
}
|
}
|
||||||
mapId = global.mapId;
|
|
||||||
} else {
|
} else {
|
||||||
// Running in a development mode.
|
// Running in a development mode.
|
||||||
console.log('Running editor in development mode');
|
console.log('Running editor in development mode');
|
||||||
@ -40,8 +30,11 @@ export default class EditorOptionsBulder {
|
|||||||
mapTitle: "Develop Mindnap",
|
mapTitle: "Develop Mindnap",
|
||||||
...options
|
...options
|
||||||
}
|
}
|
||||||
mapId = 666;
|
|
||||||
}
|
}
|
||||||
return { options, mapId };
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
static loadMapId(): number {
|
||||||
|
return !AppConfig.isDevelopEnv() ? global.mapId : 555;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,13 +2,14 @@ import React, { useEffect } from 'react';
|
|||||||
import ActionDispatcher from '../maps-page/action-dispatcher';
|
import ActionDispatcher from '../maps-page/action-dispatcher';
|
||||||
import { ActionType } from '../maps-page/action-chooser';
|
import { ActionType } from '../maps-page/action-chooser';
|
||||||
import Editor from '@wisemapping/editor';
|
import Editor from '@wisemapping/editor';
|
||||||
|
import { EditorRenderMode, PersistenceManager } from '@wisemapping/mindplot';
|
||||||
|
|
||||||
import AppI18n from '../../classes/app-i18n';
|
import AppI18n from '../../classes/app-i18n';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { hotkeysEnabled } from '../../redux/editorSlice';
|
import { hotkeysEnabled } from '../../redux/editorSlice';
|
||||||
import ReactGA from 'react-ga';
|
import ReactGA from 'react-ga';
|
||||||
import Client from '../../classes/client';
|
import Client from '../../classes/client';
|
||||||
import { activeInstance, fetchAccount } from '../../redux/clientSlice';
|
import { activeInstance, fetchAccount, fetchMapById } from '../../redux/clientSlice';
|
||||||
import { PersistenceManager } from '@wisemapping/mindplot';
|
|
||||||
import EditorOptionsBulder from './EditorOptionsBuider';
|
import EditorOptionsBulder from './EditorOptionsBuider';
|
||||||
|
|
||||||
export type EditorPropsType = {
|
export type EditorPropsType = {
|
||||||
@ -20,16 +21,43 @@ const EditorPage = ({ isTryMode }: EditorPropsType): React.ReactElement => {
|
|||||||
const hotkey = useSelector(hotkeysEnabled);
|
const hotkey = useSelector(hotkeysEnabled);
|
||||||
const userLocale = AppI18n.getUserLocale();
|
const userLocale = AppI18n.getUserLocale();
|
||||||
const client: Client = useSelector(activeInstance);
|
const client: Client = useSelector(activeInstance);
|
||||||
const { mapId, options } = EditorOptionsBulder.build(userLocale.code, hotkey, isTryMode);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
ReactGA.pageview(window.location.pathname + window.location.search);
|
ReactGA.pageview(window.location.pathname + window.location.search);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const findEditorMode = (isTryMode: boolean, mapId: number): EditorRenderMode | null => {
|
||||||
|
let result: EditorRenderMode = null;
|
||||||
|
if (isTryMode) {
|
||||||
|
result = 'showcase';
|
||||||
|
} else if (global.mindmapLocked) {
|
||||||
|
result = 'viewonly';
|
||||||
|
} else {
|
||||||
|
const fetchResult = fetchMapById(mapId);
|
||||||
|
if (!fetchResult.isLoading) {
|
||||||
|
if (fetchResult.error) {
|
||||||
|
throw new Error(`User coild not be loaded: ${JSON.stringify(fetchResult.error)}`);
|
||||||
|
}
|
||||||
|
result = fetchResult.map.role === 'owner' ? 'edition-owner' : 'edition-editor';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// What is the role ?
|
||||||
|
const mapId = EditorOptionsBulder.loadMapId();
|
||||||
|
const mode = findEditorMode(isTryMode, mapId);
|
||||||
|
|
||||||
// Account settings can be null and editor cannot be initilized multiple times. This creates problems
|
// Account settings can be null and editor cannot be initilized multiple times. This creates problems
|
||||||
// at the i18n resource loading.
|
// at the i18n resource loading.
|
||||||
const persistence = client.buildPersistenceManager(options.mode);
|
const isAccountLoaded = mode === 'showcase' || fetchAccount;
|
||||||
const loadCompleted = persistence && (options.mode === 'showcase' || fetchAccount());
|
const loadCompleted = mode && isAccountLoaded;
|
||||||
|
|
||||||
|
let options, persistence: PersistenceManager;
|
||||||
|
if (loadCompleted) {
|
||||||
|
options = EditorOptionsBulder.build(userLocale.code, mode, hotkey);
|
||||||
|
persistence = client.buildPersistenceManager(mode);
|
||||||
|
}
|
||||||
|
|
||||||
return loadCompleted ? (
|
return loadCompleted ? (
|
||||||
<>
|
<>
|
||||||
|
Loading…
Reference in New Issue
Block a user