2021-07-16 16:41:58 +02:00
|
|
|
/*
|
2021-12-25 23:39:34 +01:00
|
|
|
* Copyright [2021] [wisemapping]
|
2021-07-16 16:41:58 +02:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2021-12-05 18:25:16 +01:00
|
|
|
import $ from 'jquery';
|
2021-12-20 21:54:31 +01:00
|
|
|
import { $assert } from '@wisemapping/core-js';
|
2021-12-19 17:06:42 +01:00
|
|
|
import Keyboard from './Keyboard';
|
2022-02-04 07:19:18 +01:00
|
|
|
import { Designer } from '..';
|
|
|
|
import Topic from './Topic';
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-12-05 00:39:20 +01:00
|
|
|
class DesignerKeyboard extends Keyboard {
|
2022-02-04 07:19:18 +01:00
|
|
|
static _instance: any;
|
|
|
|
|
|
|
|
constructor(designer: Designer) {
|
|
|
|
super();
|
2021-10-05 02:05:34 +02:00
|
|
|
$assert(designer, 'designer can not be null');
|
|
|
|
this._registerEvents(designer);
|
2021-12-05 00:39:20 +01:00
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
private _registerEvents(designer: Designer) {
|
2021-10-05 02:05:34 +02:00
|
|
|
// Try with the keyboard ..
|
|
|
|
const model = designer.getModel();
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['backspace'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
designer.deleteSelectedEntities();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['space'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.shrinkSelectedBranch();
|
2022-02-06 03:20:42 +01:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2021-10-05 02:05:34 +02:00
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['f2'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
const node = model.selectedTopic();
|
|
|
|
if (node) {
|
2022-02-06 06:28:35 +01:00
|
|
|
node.showTextEditor(node.getText());
|
2021-10-05 02:05:34 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['del'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.deleteSelectedEntities();
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
|
|
|
['enter'], () => {
|
|
|
|
designer.createSiblingForSelectedNode();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['insert'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.createChildForSelectedNode();
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['tab'], (eventevent: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.createChildForSelectedNode();
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['meta+enter'], (eventevent: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
designer.createChildForSelectedNode();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+z', 'meta+z'], (event: Event) => {
|
|
|
|
event.preventDefault();
|
2021-10-05 02:05:34 +02:00
|
|
|
event.stopPropagation();
|
|
|
|
designer.undo();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+c', 'meta+c'], (event: Event) => {
|
|
|
|
event.preventDefault();
|
2021-10-05 02:05:34 +02:00
|
|
|
event.stopPropagation();
|
|
|
|
designer.copyToClipboard();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+v', 'meta+v'], (event: Event) => {
|
|
|
|
event.preventDefault();
|
2021-10-05 02:05:34 +02:00
|
|
|
event.stopPropagation();
|
|
|
|
designer.pasteClipboard();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+shift+z', 'meta+shift+z', 'ctrl+y', 'meta+y'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
designer.redo();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+a', 'meta+a'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
designer.selectAll();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+b', 'meta+b'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.changeFontWeight();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+s', 'meta+s'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
$(document).find('#save').trigger('click');
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+i', 'meta+i'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.changeFontStyle();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['ctrl+shift+a', 'meta+shift+a'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.deselectAll();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['meta+=', 'ctrl+='], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.zoomIn();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
['meta+-', 'ctrl+-'], (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
designer.zoomOut();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
const me = this;
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
'right', (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
const node = model.selectedTopic();
|
|
|
|
if (node) {
|
|
|
|
if (node.isCentralTopic()) {
|
|
|
|
me._goToSideChild(designer, node, 'RIGHT');
|
|
|
|
} else if (node.getPosition().x < 0) {
|
|
|
|
me._goToParent(designer, node);
|
|
|
|
} else if (!node.areChildrenShrunken()) {
|
|
|
|
me._goToChild(designer, node);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const centralTopic = model.getCentralTopic();
|
|
|
|
me._goToNode(designer, centralTopic);
|
|
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
'left', (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
const node = model.selectedTopic();
|
|
|
|
if (node) {
|
|
|
|
if (node.isCentralTopic()) {
|
|
|
|
me._goToSideChild(designer, node, 'LEFT');
|
|
|
|
} else if (node.getPosition().x > 0) {
|
|
|
|
me._goToParent(designer, node);
|
|
|
|
} else if (!node.areChildrenShrunken()) {
|
|
|
|
me._goToChild(designer, node);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const centralTopic = model.getCentralTopic();
|
|
|
|
me._goToNode(designer, centralTopic);
|
|
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
'up', (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
const node = model.selectedTopic();
|
|
|
|
if (node) {
|
|
|
|
if (!node.isCentralTopic()) {
|
|
|
|
me._goToBrother(designer, node, 'UP');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const centralTopic = model.getCentralTopic();
|
|
|
|
me._goToNode(designer, centralTopic);
|
|
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
this.addShortcut(
|
2022-02-06 03:20:42 +01:00
|
|
|
'down', (event: Event) => {
|
2021-10-05 02:05:34 +02:00
|
|
|
const node = model.selectedTopic();
|
|
|
|
if (node) {
|
|
|
|
if (!node.isCentralTopic()) {
|
|
|
|
me._goToBrother(designer, node, 'DOWN');
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const centralTopic = model.getCentralTopic();
|
|
|
|
me._goToNode(designer, centralTopic);
|
|
|
|
}
|
|
|
|
event.preventDefault();
|
|
|
|
event.stopPropagation();
|
|
|
|
},
|
|
|
|
);
|
|
|
|
const excludes = ['esc', 'escape', 'f1', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12'];
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
$(document).on('keypress', (event) => {
|
|
|
|
let keyCode;
|
|
|
|
// Firefox doesn't skip special keys for keypress event...
|
2021-12-14 18:06:09 +01:00
|
|
|
if (event.key && excludes.includes(event.key.toLowerCase())) {
|
2021-10-05 02:05:34 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Sometimes Firefox doesn't contain keyCode value
|
2021-12-19 18:07:01 +01:00
|
|
|
if (event.key && event.keyCode === 0) {
|
2021-10-05 02:05:34 +02:00
|
|
|
keyCode = event.charCode;
|
|
|
|
} else {
|
|
|
|
keyCode = event.keyCode;
|
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
const jq: any = $;
|
|
|
|
const specialKey = jq.hotkeys.specialKeys[keyCode];
|
|
|
|
if (['enter', 'capslock'].indexOf(specialKey) === -1 && !jq.hotkeys.shiftNums[keyCode]) {
|
2021-10-05 02:05:34 +02:00
|
|
|
const nodes = designer.getModel().filterSelectedTopics();
|
|
|
|
if (nodes.length > 0) {
|
|
|
|
// If a modifier is press, the key selected must be ignored.
|
|
|
|
const pressKey = String.fromCharCode(keyCode);
|
|
|
|
if (event.ctrlKey || event.altKey || event.metaKey) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nodes[0].showTextEditor(pressKey);
|
|
|
|
event.stopPropagation();
|
2021-07-16 16:41:58 +02:00
|
|
|
}
|
2021-10-05 02:05:34 +02:00
|
|
|
}
|
|
|
|
});
|
2021-12-05 00:39:20 +01:00
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
private _goToBrother(designer: Designer, node: Topic, direction) {
|
2021-10-05 02:05:34 +02:00
|
|
|
const parent = node.getParent();
|
|
|
|
if (parent) {
|
|
|
|
const brothers = parent.getChildren();
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
let target = node;
|
|
|
|
const { y } = node.getPosition();
|
|
|
|
const { x } = node.getPosition();
|
|
|
|
let dist = null;
|
|
|
|
for (let i = 0; i < brothers.length; i++) {
|
|
|
|
const sameSide = (x * brothers[i].getPosition().x) >= 0;
|
2021-12-05 00:39:20 +01:00
|
|
|
if (brothers[i] !== node && sameSide) {
|
2021-10-05 02:05:34 +02:00
|
|
|
const brother = brothers[i];
|
|
|
|
const brotherY = brother.getPosition().y;
|
2021-12-05 00:39:20 +01:00
|
|
|
if (direction === 'DOWN' && brotherY > y) {
|
2021-10-05 02:05:34 +02:00
|
|
|
let distancia = y - brotherY;
|
|
|
|
if (distancia < 0) {
|
|
|
|
distancia *= (-1);
|
2021-07-16 16:41:58 +02:00
|
|
|
}
|
2021-10-05 02:05:34 +02:00
|
|
|
if (dist == null || dist > distancia) {
|
|
|
|
dist = distancia;
|
|
|
|
target = brothers[i];
|
|
|
|
}
|
2021-12-05 00:39:20 +01:00
|
|
|
} else if (direction === 'UP' && brotherY < y) {
|
2021-10-05 02:05:34 +02:00
|
|
|
let distance = y - brotherY;
|
|
|
|
if (distance < 0) {
|
|
|
|
distance *= (-1);
|
|
|
|
}
|
|
|
|
if (dist == null || dist > distance) {
|
|
|
|
dist = distance;
|
|
|
|
target = brothers[i];
|
|
|
|
}
|
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
}
|
2021-10-05 02:05:34 +02:00
|
|
|
}
|
|
|
|
this._goToNode(designer, target);
|
|
|
|
}
|
2021-12-05 00:39:20 +01:00
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
private _goToSideChild(designer: Designer, node: Topic, side: 'LEFT' | 'RIGHT') {
|
2021-10-05 02:05:34 +02:00
|
|
|
const children = node.getChildren();
|
|
|
|
if (children.length > 0) {
|
|
|
|
let target = children[0];
|
|
|
|
let top = null;
|
|
|
|
for (let i = 0; i < children.length; i++) {
|
|
|
|
const child = children[i];
|
|
|
|
const childY = child.getPosition().y;
|
2021-12-05 00:39:20 +01:00
|
|
|
if (side === 'LEFT' && child.getPosition().x < 0) {
|
2021-10-05 02:05:34 +02:00
|
|
|
if (top == null || childY < top) {
|
|
|
|
target = child;
|
|
|
|
top = childY;
|
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
}
|
2021-12-05 00:39:20 +01:00
|
|
|
if (side === 'RIGHT' && child.getPosition().x > 0) {
|
2021-10-05 02:05:34 +02:00
|
|
|
if (top == null || childY < top) {
|
|
|
|
target = child;
|
|
|
|
top = childY;
|
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
}
|
2021-10-05 02:05:34 +02:00
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2021-10-05 02:05:34 +02:00
|
|
|
this._goToNode(designer, target);
|
|
|
|
}
|
2021-12-05 00:39:20 +01:00
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
private _goToParent(designer: Designer, node: Topic) {
|
2021-10-05 02:05:34 +02:00
|
|
|
const parent = node.getParent();
|
|
|
|
if (parent) {
|
|
|
|
this._goToNode(designer, parent);
|
2021-07-16 16:41:58 +02:00
|
|
|
}
|
2021-12-05 00:39:20 +01:00
|
|
|
}
|
2021-10-05 02:05:34 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
private _goToChild(designer, node) {
|
2021-10-05 02:05:34 +02:00
|
|
|
const children = node.getChildren();
|
|
|
|
if (children.length > 0) {
|
|
|
|
let target = children[0];
|
|
|
|
let top = target.getPosition().y;
|
|
|
|
for (let i = 0; i < children.length; i++) {
|
|
|
|
const child = children[i];
|
|
|
|
if (child.getPosition().y < top) {
|
|
|
|
top = child.getPosition().y;
|
|
|
|
target = child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this._goToNode(designer, target);
|
|
|
|
}
|
2021-12-05 00:39:20 +01:00
|
|
|
}
|
2021-10-05 02:05:34 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
private _goToNode(designer: Designer, node: Topic) {
|
2021-10-05 02:05:34 +02:00
|
|
|
// First deselect all the nodes ...
|
|
|
|
designer.deselectAll();
|
|
|
|
|
|
|
|
// Give focus to the selected node....
|
|
|
|
node.setOnFocus(true);
|
2021-12-05 00:39:20 +01:00
|
|
|
}
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
static register = function register(designer: Designer) {
|
|
|
|
this._instance = new DesignerKeyboard(designer);
|
|
|
|
};
|
2021-07-16 16:41:58 +02:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
static specialKeys = {
|
|
|
|
8: 'backspace',
|
|
|
|
9: 'tab',
|
|
|
|
10: 'return',
|
|
|
|
13: 'enter',
|
|
|
|
16: 'shift',
|
|
|
|
17: 'ctrl',
|
|
|
|
18: 'alt',
|
|
|
|
19: 'pause',
|
|
|
|
20: 'capslock',
|
|
|
|
27: 'esc',
|
|
|
|
32: 'space',
|
|
|
|
33: 'pageup',
|
|
|
|
34: 'pagedown',
|
|
|
|
35: 'end',
|
|
|
|
36: 'home',
|
|
|
|
37: 'left',
|
|
|
|
38: 'up',
|
|
|
|
39: 'right',
|
|
|
|
40: 'down',
|
|
|
|
45: 'insert',
|
|
|
|
46: 'del',
|
|
|
|
96: '0',
|
|
|
|
97: '1',
|
|
|
|
98: '2',
|
|
|
|
99: '3',
|
|
|
|
100: '4',
|
|
|
|
101: '5',
|
|
|
|
102: '6',
|
|
|
|
103: '7',
|
|
|
|
104: '8',
|
|
|
|
105: '9',
|
|
|
|
106: '*',
|
|
|
|
107: '+',
|
|
|
|
109: '-',
|
|
|
|
110: '.',
|
|
|
|
111: '/',
|
|
|
|
112: 'f1',
|
|
|
|
113: 'f2',
|
|
|
|
114: 'f3',
|
|
|
|
115: 'f4',
|
|
|
|
116: 'f5',
|
|
|
|
117: 'f6',
|
|
|
|
118: 'f7',
|
|
|
|
119: 'f8',
|
|
|
|
120: 'f9',
|
|
|
|
121: 'f10',
|
|
|
|
122: 'f11',
|
|
|
|
123: 'f12',
|
|
|
|
144: 'numlock',
|
|
|
|
145: 'scroll',
|
|
|
|
186: ';',
|
|
|
|
191: '/',
|
|
|
|
220: '\\',
|
|
|
|
222: "'",
|
|
|
|
224: 'meta',
|
|
|
|
};
|
2021-12-02 01:41:56 +01:00
|
|
|
|
2022-02-04 07:19:18 +01:00
|
|
|
static getInstance() {
|
|
|
|
return this._instance;
|
|
|
|
}
|
|
|
|
}
|
2021-12-02 01:41:56 +01:00
|
|
|
|
2021-07-16 16:41:58 +02:00
|
|
|
export default DesignerKeyboard;
|