mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-12-22 03:33:48 +01:00
Merged in ray-develop (pull request #51)
Ray develop * reset zoom and toolbar fixes * lang fixes * dialog enhancements * comments * tooltip for zoom and fit commented * merge develop into ray develop * rules for ignoring some linebreaks in eslint * comments in .eslintrc * brackets around ifs * playground fixes, comments removed, semi-colon at bottom of editor removed, root container size now defined with css Approved-by: Paulo Veiga
This commit is contained in:
parent
b48d55ebca
commit
0f4a8ee087
3
.gitignore
vendored
3
.gitignore
vendored
@ -52,3 +52,6 @@ Thumbs.db
|
||||
.vscode
|
||||
|
||||
*/test/playground/dist
|
||||
|
||||
# visual code local workspaces
|
||||
wisemapping-frontend.code-workspace
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "all",
|
||||
"tabWidth": 2,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"printWidth": 100
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: '3'
|
||||
services:
|
||||
e2e:
|
||||
image: cypress/included:9.7.0
|
||||
image: cypress/included:10.2.0
|
||||
container_name: wisemapping-integration-tests
|
||||
entrypoint: '/bin/sh -c "yarn install && yarn bootstrap && yarn build && yarn test:integration"'
|
||||
working_dir: /e2e
|
||||
|
@ -1,7 +1,7 @@
|
||||
version: '3'
|
||||
services:
|
||||
e2e:
|
||||
image: cypress/included:9.7.0
|
||||
image: cypress/included:10.2.0
|
||||
container_name: wisemapping-integration-tests
|
||||
entrypoint: '/bin/sh -c "yarn bootstrap && yarn build && yarn test:integration"'
|
||||
working_dir: /e2e
|
||||
|
@ -4,5 +4,6 @@
|
||||
],
|
||||
"version": "1.0.0",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true
|
||||
"useWorkspaces": true,
|
||||
"useNx": false
|
||||
}
|
||||
|
17
package.json
17
package.json
@ -45,5 +45,20 @@
|
||||
"homepage": "http://localhost:8080/react",
|
||||
"license": "https://wisemapping.atlassian.net/wiki/spaces/WS/pages/524357/WiseMapping+Public+License+Version+1.0+WPL",
|
||||
"version": "0.4.0",
|
||||
"dependencies": {}
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged",
|
||||
"pre-push": "yarn lint && yarn test:unit"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.{ts,tsx}": [
|
||||
"prettier --write"
|
||||
]
|
||||
},
|
||||
"eslintConfig": {
|
||||
"rules": {
|
||||
"implicit-arrow-linebreak": "off"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
43
packages/editor/images/close-dialog-icon.svg
Normal file
43
packages/editor/images/close-dialog-icon.svg
Normal file
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 26 26" style="enable-background:new 0 0 26 26;" xml:space="preserve">
|
||||
<g>
|
||||
<path style="fill:#030104;" d="M21.125,0H4.875C2.182,0,0,2.182,0,4.875v16.25C0,23.818,2.182,26,4.875,26h16.25
|
||||
C23.818,26,26,23.818,26,21.125V4.875C26,2.182,23.818,0,21.125,0z M18.78,17.394l-1.388,1.387c-0.254,0.255-0.67,0.255-0.924,0
|
||||
L13,15.313L9.533,18.78c-0.255,0.255-0.67,0.255-0.925-0.002L7.22,17.394c-0.253-0.256-0.253-0.669,0-0.926l3.468-3.467
|
||||
L7.221,9.534c-0.254-0.256-0.254-0.672,0-0.925l1.388-1.388c0.255-0.257,0.671-0.257,0.925,0L13,10.689l3.468-3.468
|
||||
c0.255-0.257,0.671-0.257,0.924,0l1.388,1.386c0.254,0.255,0.254,0.671,0.001,0.927l-3.468,3.467l3.468,3.467
|
||||
C19.033,16.725,19.033,17.138,18.78,17.394z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.1 KiB |
@ -4,6 +4,18 @@
|
||||
},
|
||||
"editor.try-welcome-description": {
|
||||
"defaultMessage": "Melden Sie sich an, um kostenlos eine unbegrenzte Anzahl von Mindmaps zu erstellen, zu teilen und zu veröffentlichen."
|
||||
},
|
||||
"editor.try-welcome-mobile": {
|
||||
"defaultMessage": "Diese Edition zeigt einige der Mindmap-Funktionen!"
|
||||
},
|
||||
"editor.try-welcome-description-mobile": {
|
||||
"defaultMessage": "Melden Sie sich an, um kostenlos eine unbegrenzte Anzahl von Mindmaps zu erstellen, zu teilen und zu veröffentlichen. Eingeschränkte Funktionen der Mindmap-Edition werden auf Mobilgeräten unterstützt. Verwenden Sie den Desktop-Browser für vollständige Editorfunktionen."
|
||||
},
|
||||
"editor.edit-mobile": {
|
||||
"defaultMessage": "Hinweis für Mobilgeräte."
|
||||
},
|
||||
"editor.edit-description-mobile": {
|
||||
"defaultMessage": "Eingeschränkte Funktionen der Mindmap-Edition werden auf Mobilgeräten unterstützt. Verwenden Sie den Desktop-Browser für vollständige Editorfunktionen."
|
||||
},
|
||||
"login.signup": {
|
||||
"defaultMessage": "Anmeldung"
|
||||
|
@ -4,6 +4,18 @@
|
||||
},
|
||||
"editor.try-welcome-description": {
|
||||
"defaultMessage": "Sign Up to start creating, sharing and publishing unlimited number of mindmaps for free."
|
||||
},
|
||||
"editor.try-welcome-mobile": {
|
||||
"defaultMessage": "This edition space showcases some of the mindmap capabilities!"
|
||||
},
|
||||
"editor.try-welcome-description-mobile": {
|
||||
"defaultMessage": "Sign Up to start creating, sharing and publishing unlimited number of mindmaps for free. Limited mindmap edition capabilties are supported in Mobile devices. Use Desktop browser for full editor capabilies."
|
||||
},
|
||||
"editor.edit-mobile": {
|
||||
"defaultMessage": "Note for mobile devices."
|
||||
},
|
||||
"editor.edit-description-mobile": {
|
||||
"defaultMessage": "Limited mindmap edition capabilities are supported in Mobile devices. Use Desktop browser for full editor capabilities."
|
||||
},
|
||||
"login.signup": {
|
||||
"defaultMessage": "Sign Up"
|
||||
|
@ -4,6 +4,18 @@
|
||||
},
|
||||
"editor.try-welcome-description": {
|
||||
"defaultMessage": "Registrate para comenzar a crear, compartir y publicar una cantidad ilimitada de mapas mentales de forma gratuita."
|
||||
},
|
||||
"editor.try-welcome-mobile": {
|
||||
"defaultMessage": "¡Este espacio de edición muestra algunas de las capacidades de mapas mentales!"
|
||||
},
|
||||
"editor.try-welcome-description-mobile": {
|
||||
"defaultMessage": "Registrate para comenzar a crear, compartir y publicar una cantidad ilimitada de mapas mentales de forma gratuita. En dispositivos móbiles las funciones son limitadas. Use la versión de escritorio para tener las funciones completas."
|
||||
},
|
||||
"editor.edit-mobile": {
|
||||
"defaultMessage": "Nota para dispositivos móbiles."
|
||||
},
|
||||
"editor.edit-description-mobile": {
|
||||
"defaultMessage": "En dispositivos móbiles las funciones son limitadas. Use la versión de escritorio para tener las funciones completas."
|
||||
},
|
||||
"login.signup": {
|
||||
"defaultMessage": "Crear cuenta"
|
||||
|
@ -1,9 +1,21 @@
|
||||
{
|
||||
"editor.try-welcome": {
|
||||
"defaultMessage": "Cet espace d'édition présente certaines des fonctionnalités de l'éditeur de cartes mentales !"
|
||||
"defaultMessage": "Cet espace d'édition présente certaines des fonctionnalités de l'éditeur de cartes mentales!"
|
||||
},
|
||||
"editor.try-welcome-description": {
|
||||
"defaultMessage": "Inscrivez-vous pour commencer à créer, partager et publier gratuitement un nombre illimité de cartes mentales."
|
||||
},
|
||||
"editor.try-welcome-mobile": {
|
||||
"defaultMessage": "Cet espace d'édition présente certaines des fonctionnalités des cartes mentales!"
|
||||
},
|
||||
"editor.try-welcome-description-mobile": {
|
||||
"defaultMessage": "Inscrivez-vous pour commencer à créer, partager et publier gratuitement un nombre illimité de cartes mentales. Les capacités d'édition limitées de mindmap sont prises en charge dans les appareils mobiles. Utilisez le navigateur de bureau pour bénéficier de toutes les fonctionnalités de l'éditeur."
|
||||
},
|
||||
"editor.edit-mobile": {
|
||||
"defaultMessage": "Remarque pour les appareils mobiles."
|
||||
},
|
||||
"editor.edit-description-mobile": {
|
||||
"defaultMessage": "Les capacités d'édition limitées de mindmap sont prises en charge dans les appareils mobiles. Utilisez le navigateur de bureau pour bénéficier de toutes les fonctionnalités de l'éditeur."
|
||||
},
|
||||
"login.signup": {
|
||||
"defaultMessage": "S'inscrire"
|
||||
|
@ -4,6 +4,18 @@
|
||||
},
|
||||
"editor.try-welcome-description": {
|
||||
"defaultMessage": "Чтобы получить бесплатный неограниченный доступ — нужна только регистрация."
|
||||
},
|
||||
"editor.try-welcome-mobile": {
|
||||
"defaultMessage": "В этом издании демонстрируются некоторые возможности ментальных карт!"
|
||||
},
|
||||
"editor.try-welcome-description-mobile": {
|
||||
"defaultMessage": "Зарегистрируйтесь, чтобы начать создавать, делиться и публиковать неограниченное количество ментальных карт бесплатно. Возможности ограниченной версии Mindmap поддерживаются на мобильных устройствах. Используйте настольный браузер для полных возможностей редактора."
|
||||
},
|
||||
"editor.edit-mobile": {
|
||||
"defaultMessage": "Примечание для мобильных устройств."
|
||||
},
|
||||
"editor.edit-description-mobile": {
|
||||
"defaultMessage": "Возможности ограниченной версии Mindmap поддерживаются на мобильных устройствах. Используйте настольный браузер для полных возможностей редактора."
|
||||
},
|
||||
"login.signup": {
|
||||
"defaultMessage": "Регистрация"
|
||||
|
@ -5,6 +5,18 @@
|
||||
"editor.try-welcome-description": {
|
||||
"defaultMessage": "注册后可以免费创建、分享和发布无限数量的思维导图。"
|
||||
},
|
||||
"editor.try-welcome-mobile": {
|
||||
"defaultMessage": "这个版本空间展示了一些思维导图功能!"
|
||||
},
|
||||
"editor.try-welcome-description-mobile": {
|
||||
"defaultMessage": "注册以开始免费创建、共享和发布无限数量的思维导图。 移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
|
||||
},
|
||||
"editor.edit-mobile": {
|
||||
"defaultMessage": "移动设备注意事项."
|
||||
},
|
||||
"editor.edit-description-mobile": {
|
||||
"defaultMessage": "移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
|
||||
},
|
||||
"login.signup": {
|
||||
"defaultMessage": "注册"
|
||||
},
|
||||
|
@ -61,7 +61,9 @@ class Menu extends IMenu {
|
||||
this._addButton('position', false, false, () => {
|
||||
designer.zoomToFit();
|
||||
});
|
||||
Menu._registerTooltip('position', $msg('CENTER_POSITION'));
|
||||
// Disabled because this tooltip overflows the screen and makes the button un-clickeable
|
||||
// This should be enabled when migrating to material-ui
|
||||
//Menu._registerTooltip('position', $msg('CENTER_POSITION'));
|
||||
|
||||
// Edition actions ...
|
||||
if (!readOnly) {
|
||||
@ -181,7 +183,9 @@ class Menu extends IMenu {
|
||||
designer.changeBorderColor(hex);
|
||||
},
|
||||
};
|
||||
this._toolbarElems.push(new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl));
|
||||
this._toolbarElems.push(
|
||||
new ColorPalettePanel('topicBorder', borderColorModel, widgetsBaseUrl),
|
||||
);
|
||||
Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR'));
|
||||
|
||||
const fontColorModel = {
|
||||
@ -271,12 +275,10 @@ class Menu extends IMenu {
|
||||
});
|
||||
Menu._registerTooltip('fontItalic', $msg('FONT_ITALIC'), $msg('CTRL') + ' + I');
|
||||
|
||||
|
||||
if (!readOnly) {
|
||||
// Register action on save ...
|
||||
const saveElem = $('#save');
|
||||
this._addButton('save', false, false,
|
||||
() => {
|
||||
this._addButton('save', false, false, () => {
|
||||
this.save(saveElem, designer, true);
|
||||
});
|
||||
Menu._registerTooltip('save', $msg('SAVE'), $msg('CTRL') + ' + S');
|
||||
@ -290,13 +292,11 @@ class Menu extends IMenu {
|
||||
});
|
||||
|
||||
// Autosave on a fixed period of time ...
|
||||
setInterval(
|
||||
() => {
|
||||
setInterval(() => {
|
||||
if (this.isSaveRequired()) {
|
||||
this.save(saveElem, designer, false);
|
||||
}
|
||||
}, 10000,
|
||||
);
|
||||
}, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
@ -394,10 +394,14 @@ class Menu extends IMenu {
|
||||
// Register Events ...
|
||||
let result = null;
|
||||
if ($(`#${buttonId}`)) {
|
||||
const button = new ToolbarItem(buttonId, ((event) => {
|
||||
const button = new ToolbarItem(
|
||||
buttonId,
|
||||
(event) => {
|
||||
fn(event);
|
||||
this.clear();
|
||||
}), { topicAction: isTopic, relAction: isRelationship });
|
||||
},
|
||||
{ topicAction: isTopic, relAction: isRelationship },
|
||||
);
|
||||
|
||||
this._toolbarElems.push(button);
|
||||
result = button;
|
||||
@ -409,7 +413,8 @@ class Menu extends IMenu {
|
||||
if ($(`#${buttonId}`)) {
|
||||
let tooltip = text;
|
||||
if (shortcut) {
|
||||
const platformedShortcut = navigator.appVersion.indexOf('Mac') !== -1
|
||||
const platformedShortcut =
|
||||
navigator.appVersion.indexOf('Mac') !== -1
|
||||
? shortcut.replace('meta+', '⌘')
|
||||
: shortcut.replace('meta+', 'ctrl+');
|
||||
tooltip = `${tooltip} (${platformedShortcut})`;
|
||||
|
@ -5,6 +5,18 @@
|
||||
"value": "Teilen"
|
||||
}
|
||||
],
|
||||
"editor.edit-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Eingeschränkte Funktionen der Mindmap-Edition werden auf Mobilgeräten unterstützt. Verwenden Sie den Desktop-Browser für vollständige Editorfunktionen."
|
||||
}
|
||||
],
|
||||
"editor.edit-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Hinweis für Mobilgeräte."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -17,6 +29,18 @@
|
||||
"value": "Melden Sie sich an, um kostenlos eine unbegrenzte Anzahl von Mindmaps zu erstellen, zu teilen und zu veröffentlichen."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Melden Sie sich an, um kostenlos eine unbegrenzte Anzahl von Mindmaps zu erstellen, zu teilen und zu veröffentlichen. Eingeschränkte Funktionen der Mindmap-Edition werden auf Mobilgeräten unterstützt. Verwenden Sie den Desktop-Browser für vollständige Editorfunktionen."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Diese Edition zeigt einige der Mindmap-Funktionen!"
|
||||
}
|
||||
],
|
||||
"login.signup": [
|
||||
{
|
||||
"type": 0,
|
||||
|
@ -5,6 +5,18 @@
|
||||
"value": "Share"
|
||||
}
|
||||
],
|
||||
"editor.edit-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Limited mindmap edition capabilities are supported in Mobile devices. Use Desktop browser for full editor capabilities."
|
||||
}
|
||||
],
|
||||
"editor.edit-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Note for mobile devices."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -17,6 +29,18 @@
|
||||
"value": "Sign Up to start creating, sharing and publishing unlimited number of mindmaps for free."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Sign Up to start creating, sharing and publishing unlimited number of mindmaps for free. Limited mindmap edition capabilties are supported in Mobile devices. Use Desktop browser for full editor capabilies."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "This edition space showcases some of the mindmap capabilities!"
|
||||
}
|
||||
],
|
||||
"login.signup": [
|
||||
{
|
||||
"type": 0,
|
||||
|
@ -5,6 +5,18 @@
|
||||
"value": "Compartir"
|
||||
}
|
||||
],
|
||||
"editor.edit-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "En dispositivos móbiles las funciones son limitadas. Use la versión de escritorio para tener las funciones completas."
|
||||
}
|
||||
],
|
||||
"editor.edit-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Nota para dispositivos móbiles."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -17,6 +29,18 @@
|
||||
"value": "Registrate para comenzar a crear, compartir y publicar una cantidad ilimitada de mapas mentales de forma gratuita."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Registrate para comenzar a crear, compartir y publicar una cantidad ilimitada de mapas mentales de forma gratuita. En dispositivos móbiles las funciones son limitadas. Use la versión de escritorio para tener las funciones completas."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "¡Este espacio de edición muestra algunas de las capacidades de mapas mentales!"
|
||||
}
|
||||
],
|
||||
"login.signup": [
|
||||
{
|
||||
"type": 0,
|
||||
|
@ -5,10 +5,22 @@
|
||||
"value": "Partager"
|
||||
}
|
||||
],
|
||||
"editor.edit-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Les capacités d'édition limitées de mindmap sont prises en charge dans les appareils mobiles. Utilisez le navigateur de bureau pour bénéficier de toutes les fonctionnalités de l'éditeur."
|
||||
}
|
||||
],
|
||||
"editor.edit-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Remarque pour les appareils mobiles."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Cet espace d'édition présente certaines des fonctionnalités de l'éditeur de cartes mentales !"
|
||||
"value": "Cet espace d'édition présente certaines des fonctionnalités de l'éditeur de cartes mentales!"
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-description": [
|
||||
@ -17,6 +29,18 @@
|
||||
"value": "Inscrivez-vous pour commencer à créer, partager et publier gratuitement un nombre illimité de cartes mentales."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Inscrivez-vous pour commencer à créer, partager et publier gratuitement un nombre illimité de cartes mentales. Les capacités d'édition limitées de mindmap sont prises en charge dans les appareils mobiles. Utilisez le navigateur de bureau pour bénéficier de toutes les fonctionnalités de l'éditeur."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Cet espace d'édition présente certaines des fonctionnalités des cartes mentales!"
|
||||
}
|
||||
],
|
||||
"login.signup": [
|
||||
{
|
||||
"type": 0,
|
||||
|
@ -5,6 +5,18 @@
|
||||
"value": "Поделиться"
|
||||
}
|
||||
],
|
||||
"editor.edit-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Возможности ограниченной версии Mindmap поддерживаются на мобильных устройствах. Используйте настольный браузер для полных возможностей редактора."
|
||||
}
|
||||
],
|
||||
"editor.edit-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Примечание для мобильных устройств."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -17,6 +29,18 @@
|
||||
"value": "Чтобы получить бесплатный неограниченный доступ — нужна только регистрация."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Зарегистрируйтесь, чтобы начать создавать, делиться и публиковать неограниченное количество ментальных карт бесплатно. Возможности ограниченной версии Mindmap поддерживаются на мобильных устройствах. Используйте настольный браузер для полных возможностей редактора."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "В этом издании демонстрируются некоторые возможности ментальных карт!"
|
||||
}
|
||||
],
|
||||
"login.signup": [
|
||||
{
|
||||
"type": 0,
|
||||
|
@ -5,6 +5,18 @@
|
||||
"value": "分享"
|
||||
}
|
||||
],
|
||||
"editor.edit-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
|
||||
}
|
||||
],
|
||||
"editor.edit-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "移动设备注意事项."
|
||||
}
|
||||
],
|
||||
"editor.try-welcome": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -17,6 +29,18 @@
|
||||
"value": "注册后可以免费创建、分享和发布无限数量的思维导图。"
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-description-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "注册以开始免费创建、共享和发布无限数量的思维导图。 移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
|
||||
}
|
||||
],
|
||||
"editor.try-welcome-mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "这个版本空间展示了一些思维导图功能!"
|
||||
}
|
||||
],
|
||||
"login.signup": [
|
||||
{
|
||||
"type": 0,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { StyledLogo, Notifier } from './styled';
|
||||
import { useIntl } from 'react-intl';
|
||||
|
||||
@ -6,22 +6,54 @@ import KeyboardSvg from '../../../images/keyboard.svg';
|
||||
import AddSvg from '../../../images/add.svg';
|
||||
import MinusSvg from '../../../images/minus.svg';
|
||||
import CenterFocusSvg from '../../../images/center_focus.svg';
|
||||
import CloseDialogSvg from '../../../images/close-dialog-icon.svg';
|
||||
|
||||
import ActionButton from '../action-button';
|
||||
import { EditorRenderMode } from '@wisemapping/mindplot';
|
||||
|
||||
export type FooterPropsType = {
|
||||
editorMode: EditorRenderMode;
|
||||
isMobile: boolean;
|
||||
};
|
||||
|
||||
const Footer = ({ editorMode }: FooterPropsType): React.ReactElement => {
|
||||
const Footer = ({ editorMode, isMobile }: FooterPropsType): React.ReactElement => {
|
||||
const intl = useIntl();
|
||||
const [dialogClass, setDialogClass] = useState('tryInfoPanel');
|
||||
|
||||
var titleKey = undefined;
|
||||
var descriptionKey = undefined;
|
||||
var showSignupButton = undefined;
|
||||
|
||||
if (editorMode !== 'viewonly' && editorMode !== 'showcase' && isMobile) {
|
||||
titleKey = 'editor.edit-mobile';
|
||||
descriptionKey = 'editor.edit-description-mobile';
|
||||
showSignupButton = false;
|
||||
}
|
||||
if (editorMode === 'showcase' && isMobile) {
|
||||
titleKey = 'editor.try-welcome-mobile';
|
||||
descriptionKey = 'editor.edit-description-mobile';
|
||||
showSignupButton = true;
|
||||
}
|
||||
if (editorMode === 'showcase' && !isMobile) {
|
||||
titleKey = 'editor.try-welcome';
|
||||
descriptionKey = 'editor.try-welcome-description';
|
||||
showSignupButton = true;
|
||||
}
|
||||
|
||||
// if the toolbar is present, the alert must not overlap
|
||||
var alertTopAdjustmentStyle =
|
||||
editorMode !== 'viewonly' && !isMobile
|
||||
? 'tryInfoPanelWithToolbar'
|
||||
: 'tryInfoPanelWithoutToolbar';
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="floating-panel">
|
||||
{!isMobile && (
|
||||
<div id="keyboardShortcuts" className="buttonExtOn">
|
||||
<img src={KeyboardSvg} />
|
||||
</div>
|
||||
)}
|
||||
<div id="zoom-button">
|
||||
<button id="zoom-plus">
|
||||
<img src={AddSvg} />
|
||||
@ -38,15 +70,31 @@ const Footer = ({ editorMode }: FooterPropsType): React.ReactElement => {
|
||||
</div>
|
||||
<StyledLogo id="bottom-logo"></StyledLogo>
|
||||
<Notifier id="headerNotifier"></Notifier>
|
||||
{editorMode === 'showcase' && (
|
||||
<div id="tryInfoPanel">
|
||||
<p>{intl.formatMessage({ id: 'editor.try-welcome' })}</p>
|
||||
<p>{intl.formatMessage({ id: 'editor.try-welcome-description' })}</p>
|
||||
{titleKey && (
|
||||
<div className={dialogClass + ' ' + alertTopAdjustmentStyle}>
|
||||
<div className="tryInfoPanelInner">
|
||||
<div className="closeButton">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
setDialogClass('tryInfoPanelClosed');
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<img src={CloseDialogSvg} />
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
{intl.formatMessage({ id: titleKey })} {intl.formatMessage({ id: descriptionKey })}
|
||||
</p>
|
||||
{showSignupButton && (
|
||||
<a href="/c/registration">
|
||||
<ActionButton>
|
||||
{intl.formatMessage({ id: 'login.signup', defaultMessage: 'Sign Up' })}
|
||||
</ActionButton>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
@ -9,6 +9,19 @@ html {
|
||||
font-size: initial;
|
||||
}
|
||||
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
min-width: 100vw;
|
||||
min-height: 100vh;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.mindplot-root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
div#mindplot {
|
||||
position: relative;
|
||||
top: 50px;
|
||||
@ -201,21 +214,69 @@ div#shotcuts > img{
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div#tryInfoPanel {
|
||||
.tryInfoPanel {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
text-align: center;
|
||||
top: 80px;
|
||||
left: 20px;
|
||||
width: 200px;
|
||||
padding: 20px;
|
||||
font-size: 15px;
|
||||
border-radius: 9px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: white;
|
||||
border: solid 2px #ffa800;
|
||||
margin: auto;
|
||||
width: 99%;
|
||||
border-radius: 9px;
|
||||
width: 96%;
|
||||
}
|
||||
|
||||
#tryInfoPanel > p {
|
||||
justify-content: center;
|
||||
padding-bottom: 20px;
|
||||
@media (min-width: 600px) {
|
||||
.tryInfoPanel {
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.tryInfoPanel {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.tryInfoPanel .tryInfoPanelInner {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.tryInfoPanel .tryInfoPanelInner .closeButton {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.tryInfoPanel .tryInfoPanelInner .closeButton button {
|
||||
cursor: pointer;
|
||||
border-style: hidden;
|
||||
background-color: transparent;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.tryInfoPanel .tryInfoPanelInner .closeButton button img {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
filter: invert(73%) sepia(21%) saturate(4699%) hue-rotate(357deg) brightness(98%) contrast(108%);
|
||||
}
|
||||
|
||||
.tryInfoPanelWithToolbar {
|
||||
top: 55px;
|
||||
}
|
||||
|
||||
.tryInfoPanelWithoutToolbar {
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
.tryInfoPanelClosed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tryInfoPanel > p {
|
||||
justify-content: center;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import Toolbar, { ToolbarActionType } from './components/toolbar';
|
||||
import Footer from './components/footer';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
@ -22,14 +22,14 @@ declare global {
|
||||
}
|
||||
|
||||
export type EditorOptions = {
|
||||
mode: EditorRenderMode,
|
||||
locale: string,
|
||||
zoom?: number,
|
||||
locked?: boolean,
|
||||
mode: EditorRenderMode;
|
||||
locale: string;
|
||||
zoom?: number;
|
||||
locked?: boolean;
|
||||
lockedMsg?: string;
|
||||
mapTitle: string;
|
||||
enableKeyboardEvents: boolean;
|
||||
}
|
||||
};
|
||||
|
||||
export type EditorProps = {
|
||||
mapId: string;
|
||||
@ -39,13 +39,8 @@ export type EditorProps = {
|
||||
onLoad?: (designer: Designer) => void;
|
||||
};
|
||||
|
||||
const Editor = ({
|
||||
mapId,
|
||||
options,
|
||||
persistenceManager,
|
||||
onAction,
|
||||
onLoad,
|
||||
}: EditorProps) => {
|
||||
const Editor = ({ mapId, options, persistenceManager, onAction, onLoad }: EditorProps) => {
|
||||
const [isMobile, setIsMobile] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
// Change page title ...
|
||||
@ -63,6 +58,8 @@ const Editor = ({
|
||||
const mindmap = instance.load(mapId);
|
||||
designer.loadMap(mindmap);
|
||||
|
||||
setIsMobile(checkMobile());
|
||||
|
||||
if (options.locked) {
|
||||
$notify(options.lockedMsg, false);
|
||||
}
|
||||
@ -76,7 +73,22 @@ const Editor = ({
|
||||
}
|
||||
}, [options.enableKeyboardEvents]);
|
||||
|
||||
const onLoadDesigner = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager): Designer => {
|
||||
const checkMobile = () => {
|
||||
const check =
|
||||
/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|ipad|iris|kindle|Android|Silk|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(
|
||||
navigator.userAgent.toLowerCase(),
|
||||
) ||
|
||||
/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(
|
||||
navigator.userAgent.toLowerCase().substring(0, 4),
|
||||
);
|
||||
return check;
|
||||
};
|
||||
|
||||
const onLoadDesigner = (
|
||||
mapId: string,
|
||||
options: EditorOptions,
|
||||
persistenceManager: PersistenceManager,
|
||||
): Designer => {
|
||||
const buildOptions = DesignerOptionsBuilder.buildOptions({
|
||||
persistenceManager,
|
||||
mode: options.mode,
|
||||
@ -90,7 +102,12 @@ const Editor = ({
|
||||
const result = buildDesigner(buildOptions);
|
||||
|
||||
// Register toolbar event ...
|
||||
if (options.mode === 'edition-owner' || options.mode === 'edition-editor' || options.mode === 'edition-viewer' || options.mode === 'showcase') {
|
||||
if (
|
||||
options.mode === 'edition-owner' ||
|
||||
options.mode === 'edition-editor' ||
|
||||
options.mode === 'edition-viewer' ||
|
||||
options.mode === 'showcase'
|
||||
) {
|
||||
const menu = new Menu(designer, 'toolbar');
|
||||
|
||||
// If a node has focus, focus can be move to another node using the keys.
|
||||
@ -99,24 +116,26 @@ const Editor = ({
|
||||
};
|
||||
}
|
||||
return result;
|
||||
|
||||
};
|
||||
|
||||
const locale = options.locale;
|
||||
const msg = I18nMsg.loadLocaleData(locale);
|
||||
const mindplotStyle = (options.mode === 'viewonly') ? { top: 0 } : { top: 'inherit' };
|
||||
const mindplotStyle = options.mode === 'viewonly' ? { top: 0 } : { top: 'inherit' };
|
||||
// if the Toolbar is not hidden before the variable 'isMobile' is defined, it appears intermittently when the page loads
|
||||
// if the Toolbar is not rendered, Menu.ts cant find buttons for create event listeners
|
||||
// so, with this hack the Toolbar is rendered but no visible until the variable 'isMobile' is defined
|
||||
const toolbarContainerStyle = isMobile === undefined ? { display: 'none' } : { display: 'block' };
|
||||
return (
|
||||
<IntlProvider locale={locale} messages={msg}>
|
||||
{(options.mode !== 'viewonly') &&
|
||||
<Toolbar
|
||||
editorMode={options.mode}
|
||||
onAction={onAction}
|
||||
/>
|
||||
}
|
||||
<div style={toolbarContainerStyle}>
|
||||
{options.mode !== 'viewonly' && !isMobile && (
|
||||
<Toolbar editorMode={options.mode} onAction={onAction} />
|
||||
)}
|
||||
</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} isMobile={isMobile} />
|
||||
</IntlProvider>
|
||||
);
|
||||
}
|
||||
};
|
||||
export default Editor;
|
||||
|
@ -10,6 +10,10 @@
|
||||
font-family: Arial !important;
|
||||
}
|
||||
|
||||
.section {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tbody tr td:first-child {
|
||||
width: 20%;
|
||||
}
|
||||
@ -21,10 +25,30 @@
|
||||
<h1>@wisemapping/editor - Playground</h1>
|
||||
<p>You will find here a set of examples that shows how you can use integrate WiseMapping Editor</p>
|
||||
<div>
|
||||
<p><span class="section">View Mode:</span>Simple integration to load and render mindaps in read only mode.</p>
|
||||
<ul>
|
||||
<li><a href="/viewmode.html">View mode:</a> Simple integration to load and render mindaps in read
|
||||
only mode</li>
|
||||
<li><a href="/editor.html">Editor mode:</a> Example on how mindplot can be used for mindmap edition. Browser local storage is used for persistance.</li>
|
||||
<li><a href="/viewmode.html?id=welcome">Welcome</a></li>
|
||||
<li><a href="/viewmode.html?id=sample1">Sample 1</a></li>
|
||||
<li><a href="/viewmode.html?id=sample2">Sample 2</a></li>
|
||||
<li><a href="/viewmode.html?id=sample3">Sample 3</a></li>
|
||||
<li><a href="/viewmode.html?id=sample4">Sample 4</a></li>
|
||||
<li><a href="/viewmode.html?id=sample5">Sample 5</a></li>
|
||||
<li><a href="/viewmode.html?id=sample6">Sample 6</a></li>
|
||||
<li><a href="/viewmode.html?id=sample7">Sample 7</a></li>
|
||||
<li><a href="/viewmode.html?id=sample8">Sample 8</a></li>
|
||||
<li><a href="/viewmode.html?id=img-support">Image support</a></li>
|
||||
<li><a href="/viewmode.html?id=error-on-load">Error on load</a></li>
|
||||
<li><a href="/viewmode.html?id=complex">Complex</a></li>
|
||||
<li><a href="/viewmode.html?id=huge">Huge</a></li>
|
||||
<li><a href="/viewmode.html?id=icon-sample">Icon Sample</a></li>
|
||||
</ul>
|
||||
<p><span class="section">Editor Mode:</span>Example on how mindplot can be used for mindmap edition. Browser local storage is used for persistance.</p>
|
||||
<ul>
|
||||
<li><a href="/editor.html">Sample</a></li>
|
||||
</ul>
|
||||
<p><span class="section">Showcase Mode:</span>When an user wants to try the editor without creating an account.</p>
|
||||
<ul>
|
||||
<li><a href="/showcase.html">Sample</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
|
@ -20,7 +20,7 @@ div#footer-logo {
|
||||
}
|
||||
|
||||
#floating-panel {
|
||||
bottom: 80px;
|
||||
bottom: 20px;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<div id="root" class="mindplot-root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,17 @@
|
||||
<!DOCTYPE HTML>
|
||||
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>WiseMapping - Editor </title>
|
||||
<meta name="viewport" content="initial-scale=1">
|
||||
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
|
||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root" class="mindplot-root"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -4,35 +4,14 @@
|
||||
|
||||
<head>
|
||||
<title>WiseMapping - View Mode </title>
|
||||
<meta name="viewport" content="initial-scale=1">
|
||||
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
|
||||
<link rel="icon" href="images/favicon.ico" type="image/x-icon">
|
||||
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="root" onselectstart="return false;"></div>
|
||||
<div id="footer">
|
||||
<div id="footer-logo"><img src="../images/logo-small.svg" /></div>
|
||||
<div id="footer-desc">
|
||||
<p>The following example showcase rendering of mindmaps in read-only.</p>
|
||||
<p>Select one map to render from the gallery: <select id="map-select">
|
||||
<option value="welcome">welcome</option>
|
||||
<option value="sample1">sample1</option>
|
||||
<option value="sample2">sample2</option>
|
||||
<option value="sample3">sample3</option>
|
||||
<option value="sample4">sample4</option>
|
||||
<option value="sample5">sample5</option>
|
||||
<option value="sample6">sample6</option>
|
||||
<option value="sample7">sample7</option>
|
||||
<option value="sample8">sample8</option>
|
||||
<option value="img-support">img-support</option>
|
||||
<option value="error-on-load">error-on-load</option>
|
||||
<option value="complex">complex</option>
|
||||
<option value="huge">huge</option>
|
||||
<option value="icon-sample">icon-sample</option>
|
||||
</select>
|
||||
</p>
|
||||
</div>
|
||||
<div id="root" class="mindplot-root" onselectstart="return false;"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
52
packages/editor/test/playground/map-render/js/showcase.tsx
Normal file
52
packages/editor/test/playground/map-render/js/showcase.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright [2021] [wisemapping]
|
||||
*
|
||||
* Licensed under WiseMapping Public License, Version 1.0 (the "License").
|
||||
* It is basically the Apache License, Version 2.0 (the "License") plus the
|
||||
* "powered by wisemapping" text requirement on every single page;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the license at
|
||||
*
|
||||
* http://www.wisemapping.org/license
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Editor, { EditorOptions } from '../../../../src/index';
|
||||
import { LocalStorageManager, Designer } from '@wisemapping/mindplot';
|
||||
|
||||
const initialization = (designer: Designer) => {
|
||||
designer.addEvent('loadSuccess', () => {
|
||||
const elem = document.getElementById('mindplot');
|
||||
if (elem) {
|
||||
elem.classList.add('ready');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const persistence = new LocalStorageManager('samples/{id}.wxml', false, false);
|
||||
const mapId = 'welcome';
|
||||
const options: EditorOptions = {
|
||||
zoom: 0.8,
|
||||
locked: false,
|
||||
mapTitle: 'Develop WiseMapping',
|
||||
mode: 'showcase',
|
||||
locale: 'en',
|
||||
enableKeyboardEvents: true,
|
||||
};
|
||||
|
||||
ReactDOM.render(
|
||||
<Editor
|
||||
mapId={mapId}
|
||||
options={options}
|
||||
persistenceManager={persistence}
|
||||
onAction={(action) => console.log('action called:', action)}
|
||||
onLoad={initialization}
|
||||
/>,
|
||||
document.getElementById('root'),
|
||||
);
|
@ -10,6 +10,7 @@ const playgroundConfig = {
|
||||
entry: {
|
||||
viewmode: path.resolve(__dirname, './test/playground/map-render/js/viewmode'),
|
||||
editor: path.resolve(__dirname, './test/playground/map-render/js/editor'),
|
||||
showcase: path.resolve(__dirname, './test/playground/map-render/js/showcase'),
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'test/playground/dist'),
|
||||
@ -47,6 +48,11 @@ const playgroundConfig = {
|
||||
filename: 'editor.html',
|
||||
template: 'test/playground/map-render/html/editor.html',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
chunks: ['showcase'],
|
||||
filename: 'showcase.html',
|
||||
template: 'test/playground/map-render/html/showcase.html',
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
|
@ -22,6 +22,21 @@
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
// ignore errores when a line finishes with (setting this value to 0 ignores all errors)
|
||||
"operator-linebreak": [
|
||||
"error", "after", {
|
||||
"overrides": {
|
||||
"+": "ignore",
|
||||
"-": "ignore",
|
||||
":": "ignore",
|
||||
"*": "ignore",
|
||||
"?": "ignore",
|
||||
">": "ignore",
|
||||
"||": "ignore",
|
||||
"&&": "ignore"
|
||||
}
|
||||
}
|
||||
],
|
||||
"no-underscore-dangle": "off",
|
||||
"no-plusplus": "off",
|
||||
"no-param-reassign": "off",
|
||||
@ -44,7 +59,8 @@
|
||||
"ts": "never",
|
||||
"tsx": "never"
|
||||
}
|
||||
]
|
||||
],
|
||||
"implicit-arrow-linebreak": "off"
|
||||
},
|
||||
"settings": {
|
||||
"import/resolver": {
|
||||
|
@ -82,7 +82,6 @@ class Designer extends Events {
|
||||
super();
|
||||
$assert(options, 'options must be defined');
|
||||
$assert(options.zoom, 'zoom must be defined');
|
||||
$assert(options.containerSize, 'size must be defined');
|
||||
$assert(divElement, 'divElement must be defined');
|
||||
|
||||
// Set up i18n location ...
|
||||
@ -91,10 +90,10 @@ class Designer extends Events {
|
||||
|
||||
this._options = options;
|
||||
|
||||
// Set full div elem render area ...
|
||||
if (options.containerSize) {
|
||||
divElement.css(options.containerSize);
|
||||
}
|
||||
// Set full div elem render area.The component must fill container size
|
||||
// container is responsible for location and size
|
||||
divElement.css('width', '100%');
|
||||
divElement.css('height', '100%');
|
||||
|
||||
// Dispatcher manager ...
|
||||
const commandContext = new CommandContext(this);
|
||||
@ -138,14 +137,18 @@ class Designer extends Events {
|
||||
|
||||
private _registerWheelEvents(): void {
|
||||
const zoomFactor = 1.02;
|
||||
document.addEventListener('wheel', (event: WheelEvent) => {
|
||||
document.addEventListener(
|
||||
'wheel',
|
||||
(event: WheelEvent) => {
|
||||
if (event.deltaX > 0 || event.deltaY > 0) {
|
||||
this.zoomOut(zoomFactor);
|
||||
} else {
|
||||
this.zoomIn(zoomFactor);
|
||||
}
|
||||
event.preventDefault();
|
||||
}, { passive: false });
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
}
|
||||
|
||||
getActionDispatcher(): StandaloneActionDispatcher {
|
||||
@ -187,8 +190,7 @@ class Designer extends Events {
|
||||
screenManager.addEvent('dblclick', (event: MouseEvent) => {
|
||||
if (workspace.isWorkspaceEventsEnabled()) {
|
||||
const mousePos = screenManager.getWorkspaceMousePosition(event);
|
||||
const centralTopic: CentralTopic = me.getModel()
|
||||
.getCentralTopic();
|
||||
const centralTopic: CentralTopic = me.getModel().getCentralTopic();
|
||||
|
||||
const model = me._createChildModel(centralTopic, mousePos);
|
||||
this._actionDispatcher.addTopics([model], [centralTopic.getId()]);
|
||||
@ -704,9 +706,7 @@ class Designer extends Events {
|
||||
const targetTopic = dmodel.findTopicById(targetTopicId);
|
||||
$assert(
|
||||
targetTopic,
|
||||
`targetTopic could not be found:${targetTopicId},${dmodel
|
||||
.getTopics()
|
||||
.map((e) => e.getId())}`,
|
||||
`targetTopic could not be found:${targetTopicId},${dmodel.getTopics().map((e) => e.getId())}`,
|
||||
);
|
||||
|
||||
// Build relationship line ....
|
||||
@ -797,16 +797,14 @@ class Designer extends Events {
|
||||
}
|
||||
|
||||
changeFontFamily(font: string) {
|
||||
const topicsIds = this.getModel()
|
||||
.filterTopicsIds();
|
||||
const topicsIds = this.getModel().filterTopicsIds();
|
||||
if (topicsIds.length > 0) {
|
||||
this._actionDispatcher.changeFontFamilyToTopic(topicsIds, font);
|
||||
}
|
||||
}
|
||||
|
||||
changeFontStyle(): void {
|
||||
const topicsIds = this.getModel()
|
||||
.filterTopicsIds();
|
||||
const topicsIds = this.getModel().filterTopicsIds();
|
||||
if (topicsIds.length > 0) {
|
||||
this._actionDispatcher.changeFontStyleToTopic(topicsIds);
|
||||
}
|
||||
@ -815,8 +813,7 @@ class Designer extends Events {
|
||||
changeFontColor(color: string) {
|
||||
$assert(color, 'color can not be null');
|
||||
|
||||
const topicsIds = this.getModel()
|
||||
.filterTopicsIds();
|
||||
const topicsIds = this.getModel().filterTopicsIds();
|
||||
|
||||
if (topicsIds.length > 0) {
|
||||
this._actionDispatcher.changeFontColorToTopic(topicsIds, color);
|
||||
@ -851,9 +848,8 @@ class Designer extends Events {
|
||||
}
|
||||
|
||||
changeTopicShape(shape: string) {
|
||||
const validateFunc = (topic: Topic) => !(
|
||||
topic.getType() === 'CentralTopic' && shape === TopicShape.LINE
|
||||
);
|
||||
const validateFunc = (topic: Topic) =>
|
||||
!(topic.getType() === 'CentralTopic' && shape === TopicShape.LINE);
|
||||
|
||||
const validateError = 'Central Topic shape can not be changed to line figure.';
|
||||
const topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
|
||||
@ -872,9 +868,13 @@ class Designer extends Events {
|
||||
addIconType(iconType: string): void {
|
||||
const topicsIds = this.getModel().filterTopicsIds();
|
||||
if (topicsIds.length > 0) {
|
||||
this._actionDispatcher.addFeatureToTopic(topicsIds[0], TopicFeatureFactory.Icon.id as FeatureType, {
|
||||
this._actionDispatcher.addFeatureToTopic(
|
||||
topicsIds[0],
|
||||
TopicFeatureFactory.Icon.id as FeatureType,
|
||||
{
|
||||
id: iconType,
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,37 +18,25 @@
|
||||
import { $assert } from '@wisemapping/core-js';
|
||||
import EditorRenderMode from './EditorRenderMode';
|
||||
import PersistenceManager from './PersistenceManager';
|
||||
import SizeType from './SizeType';
|
||||
|
||||
export type DesignerOptions = {
|
||||
zoom: number,
|
||||
containerSize?: SizeType,
|
||||
mode: EditorRenderMode,
|
||||
mapId?: string,
|
||||
container: string,
|
||||
persistenceManager?: PersistenceManager,
|
||||
saveOnLoad?: boolean,
|
||||
locale?: string,
|
||||
zoom: number;
|
||||
mode: EditorRenderMode;
|
||||
mapId?: string;
|
||||
container: string;
|
||||
persistenceManager?: PersistenceManager;
|
||||
saveOnLoad?: boolean;
|
||||
locale?: string;
|
||||
};
|
||||
|
||||
class OptionsBuilder {
|
||||
static buildOptions(options: DesignerOptions): DesignerOptions {
|
||||
$assert(options.persistenceManager, 'persistence must be defined');
|
||||
|
||||
let { containerSize } = options;
|
||||
if (options.containerSize == null) {
|
||||
// If it has not been defined, use browser size ...
|
||||
containerSize = {
|
||||
width: window.screen.width,
|
||||
height: window.screen.height,
|
||||
};
|
||||
}
|
||||
|
||||
const defaultOptions: DesignerOptions = {
|
||||
mode: 'edition-owner',
|
||||
zoom: 0.85,
|
||||
saveOnLoad: true,
|
||||
containerSize,
|
||||
container: 'mindplot',
|
||||
locale: 'en',
|
||||
};
|
||||
|
@ -16,15 +16,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
$assert,
|
||||
$defined,
|
||||
} from '@wisemapping/core-js';
|
||||
import {
|
||||
Group,
|
||||
ElementClass,
|
||||
Point,
|
||||
} from '@wisemapping/web2d';
|
||||
import { $assert, $defined } from '@wisemapping/core-js';
|
||||
import { Group, ElementClass, Point } from '@wisemapping/web2d';
|
||||
import IconGroupRemoveTip from './IconGroupRemoveTip';
|
||||
import Icon from './Icon';
|
||||
import SizeType from './SizeType';
|
||||
@ -102,7 +95,10 @@ class IconGroup {
|
||||
|
||||
icon.setGroup(this);
|
||||
icons.push(icon);
|
||||
this._icons = icons.sort((a, b) => ORDER_BY_TYPE.get(a.getModel().getType()) - ORDER_BY_TYPE.get(b.getModel().getType()));
|
||||
this._icons = icons.sort(
|
||||
(a, b) =>
|
||||
ORDER_BY_TYPE.get(a.getModel().getType()) - ORDER_BY_TYPE.get(b.getModel().getType()),
|
||||
);
|
||||
|
||||
// Add all the nodes back ...
|
||||
this._resize(this._icons.length);
|
||||
@ -185,10 +181,7 @@ class IconGroup {
|
||||
|
||||
private _positionIcon(icon: Icon, order: number) {
|
||||
const iconSize = Icon.SIZE + IconGroup.ICON_PADDING * 2;
|
||||
icon.getImage().setPosition(
|
||||
iconSize * order + IconGroup.ICON_PADDING,
|
||||
IconGroup.ICON_PADDING,
|
||||
);
|
||||
icon.getImage().setPosition(iconSize * order + IconGroup.ICON_PADDING, IconGroup.ICON_PADDING);
|
||||
}
|
||||
|
||||
static ICON_PADDING = 5;
|
||||
|
@ -21,7 +21,7 @@ import { Point } from '@wisemapping/web2d';
|
||||
class ScreenManager {
|
||||
private _divContainer: JQuery;
|
||||
|
||||
private _padding: { x: number; y: number; };
|
||||
private _padding: { x: number; y: number };
|
||||
|
||||
private _clickEvents;
|
||||
|
||||
@ -34,20 +34,23 @@ class ScreenManager {
|
||||
|
||||
// Ignore default click event propagation. Prevent 'click' event on drag.
|
||||
this._clickEvents = [];
|
||||
this._divContainer.bind('click', (event: { stopPropagation: () => void; }) => {
|
||||
this._divContainer.bind('click', (event: { stopPropagation: () => void }) => {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
this._divContainer.bind('dblclick', (event: { stopPropagation: () => void; preventDefault: () => void; }) => {
|
||||
this._divContainer.bind(
|
||||
'dblclick',
|
||||
(event: { stopPropagation: () => void; preventDefault: () => void }) => {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current visibile area in the browser.
|
||||
*/
|
||||
getVisibleBrowserSize(): { width: number, height: number } {
|
||||
getVisibleBrowserSize(): { width: number; height: number } {
|
||||
return {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight - Number.parseInt(this._divContainer.css('top'), 10),
|
||||
@ -82,10 +85,31 @@ class ScreenManager {
|
||||
}
|
||||
}
|
||||
|
||||
getWorkspaceMousePosition(event: MouseEvent) {
|
||||
private mouseEvents = ['mousedown', 'mouseup', 'mousemove', 'dblclick', 'click'];
|
||||
|
||||
private tocuchEvents = ['touchstart', 'touchend', 'touchmove'];
|
||||
|
||||
// the received type was changed from MouseEvent to "any", because we must support touch events
|
||||
getWorkspaceMousePosition(event: any) {
|
||||
let x;
|
||||
let y;
|
||||
|
||||
if (this.mouseEvents.includes(event.type)) {
|
||||
// Retrieve current mouse position.
|
||||
let x = event.clientX;
|
||||
let y = event.clientY;
|
||||
x = event.clientX;
|
||||
y = event.clientY;
|
||||
} else if (this.tocuchEvents.includes(event.type)) {
|
||||
x = event.touches[0].clientX;
|
||||
y = event.touches[0].clientY;
|
||||
}
|
||||
|
||||
// if value is zero assert throws error
|
||||
if (x !== 0) {
|
||||
$assert(x, `clientX can not be null, eventType= ${event.type}`);
|
||||
}
|
||||
if (y !== 0) {
|
||||
$assert(y, `clientY can not be null, eventType= ${event.type}`);
|
||||
}
|
||||
|
||||
// Adjust the deviation of the container positioning ...
|
||||
const containerPosition = this.getContainer().position();
|
||||
|
@ -130,11 +130,19 @@ class Workspace {
|
||||
setZoom(zoom: number, center = false): void {
|
||||
this._zoom = zoom;
|
||||
const workspace = this._workspace;
|
||||
const newVisibleAreaSize = this._screenManager.getVisibleBrowserSize();
|
||||
|
||||
// Update coord scale...
|
||||
const newCoordWidth = zoom * this._containerSize.width;
|
||||
const newCoordHeight = zoom * this._containerSize.height;
|
||||
const divContainer = this._screenManager.getContainer();
|
||||
const containerWidth = divContainer.width();
|
||||
const containerHeight = divContainer.height();
|
||||
const newVisibleAreaSize = { width: containerWidth, height: containerHeight };
|
||||
|
||||
// - svg must fit container size
|
||||
const svgElement = divContainer.find('svg');
|
||||
svgElement.attr('width', containerWidth);
|
||||
svgElement.attr('height', containerHeight);
|
||||
// - svg viewPort must fit container size with zoom adjustment
|
||||
const newCoordWidth = containerWidth * this._zoom;
|
||||
const newCoordHeight = containerHeight * this._zoom;
|
||||
|
||||
let coordOriginX: number;
|
||||
let coordOriginY: number;
|
||||
@ -222,11 +230,14 @@ class Workspace {
|
||||
wasDragged = true;
|
||||
};
|
||||
screenManager.addEvent('mousemove', workspace._mouseMoveListener);
|
||||
screenManager.addEvent('touchmove', workspace._mouseMoveListener);
|
||||
|
||||
// Register mouse up listeners ...
|
||||
workspace._mouseUpListener = () => {
|
||||
screenManager.removeEvent('mousemove', workspace._mouseMoveListener);
|
||||
screenManager.removeEvent('mouseup', workspace._mouseUpListener);
|
||||
screenManager.removeEvent('touchmove', workspace._mouseUpListener);
|
||||
screenManager.removeEvent('touchend', workspace._mouseMoveListener);
|
||||
workspace._mouseUpListener = null;
|
||||
workspace._mouseMoveListener = null;
|
||||
window.document.body.style.cursor = 'default';
|
||||
@ -241,12 +252,14 @@ class Workspace {
|
||||
}
|
||||
};
|
||||
screenManager.addEvent('mouseup', workspace._mouseUpListener);
|
||||
screenManager.addEvent('touchend', workspace._mouseUpListener);
|
||||
}
|
||||
} else {
|
||||
workspace._mouseUpListener();
|
||||
}
|
||||
};
|
||||
screenManager.addEvent('mousedown', mouseDownListener);
|
||||
screenManager.addEvent('touchstart', mouseDownListener);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,9 +45,9 @@ abstract class AbstractBasicSorter extends ChildrenSorterStrategy {
|
||||
} else {
|
||||
let childrenHeight = 0;
|
||||
|
||||
children.forEach(((child) => {
|
||||
children.forEach((child) => {
|
||||
childrenHeight += this._computeChildrenHeight(treeSet, child, heightCache);
|
||||
}));
|
||||
});
|
||||
|
||||
result = Math.max(height, childrenHeight);
|
||||
}
|
||||
|
@ -34,14 +34,8 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
// If it is a dragged node...
|
||||
if (node) {
|
||||
$assert($defined(position), 'position cannot be null for predict in dragging');
|
||||
const nodeDirection = this._getRelativeDirection(
|
||||
rootNode.getPosition(),
|
||||
node.getPosition(),
|
||||
);
|
||||
const positionDirection = this._getRelativeDirection(
|
||||
rootNode.getPosition(),
|
||||
position,
|
||||
);
|
||||
const nodeDirection = this._getRelativeDirection(rootNode.getPosition(), node.getPosition());
|
||||
const positionDirection = this._getRelativeDirection(rootNode.getPosition(), position);
|
||||
const siblings = graph.getSiblings(node);
|
||||
|
||||
const sameParent = parent === graph.getParent(node);
|
||||
@ -50,7 +44,8 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
}
|
||||
}
|
||||
|
||||
let right; let left;
|
||||
let right;
|
||||
let left;
|
||||
if (!position) {
|
||||
right = this._getChildrenForOrder(parent, graph, 0);
|
||||
left = this._getChildrenForOrder(parent, graph, 1);
|
||||
@ -58,19 +53,16 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
// Filter nodes on one side..
|
||||
let order;
|
||||
if (position) {
|
||||
order = position.x > rootNode.getPosition().x
|
||||
? 0
|
||||
: 1;
|
||||
order = position.x > rootNode.getPosition().x ? 0 : 1;
|
||||
} else {
|
||||
order = right.length - left.length > 0
|
||||
? 1
|
||||
: 0;
|
||||
order = right.length - left.length > 0 ? 1 : 0;
|
||||
}
|
||||
const direction = order % 2 === 0 ? 1 : -1;
|
||||
|
||||
// Exclude the dragged node (if set)
|
||||
const children = this._getChildrenForOrder(parent, graph, order)
|
||||
.filter((child) => child !== node);
|
||||
const children = this._getChildrenForOrder(parent, graph, order).filter(
|
||||
(child) => child !== node,
|
||||
);
|
||||
|
||||
// No children?
|
||||
if (children.length === 0) {
|
||||
@ -78,10 +70,9 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
order,
|
||||
{
|
||||
x:
|
||||
parent.getPosition().x
|
||||
+ direction
|
||||
* (parent.getSize().width / 2
|
||||
+ BalancedSorter.INTERNODE_HORIZONTAL_PADDING * 2),
|
||||
parent.getPosition().x +
|
||||
direction *
|
||||
(parent.getSize().width / 2 + BalancedSorter.INTERNODE_HORIZONTAL_PADDING * 2),
|
||||
y: parent.getPosition().y,
|
||||
},
|
||||
];
|
||||
@ -94,7 +85,8 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
children.forEach((child, index) => {
|
||||
const cpos = child.getPosition();
|
||||
if (newestPosition.y > cpos.y) {
|
||||
const yOffset = child === last
|
||||
const yOffset =
|
||||
child === last
|
||||
? child.getSize().height + BalancedSorter.INTERNODE_VERTICAL_PADDING * 2
|
||||
: (children[index + 1].getPosition().y - child.getPosition().y) / 2;
|
||||
result = [child.getOrder() + 2, { x: cpos.x, y: cpos.y + yOffset }];
|
||||
@ -109,9 +101,9 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
{
|
||||
x: first.getPosition().x,
|
||||
y:
|
||||
first.getPosition().y
|
||||
- first.getSize().height
|
||||
- BalancedSorter.INTERNODE_VERTICAL_PADDING * 2,
|
||||
first.getPosition().y -
|
||||
first.getSize().height -
|
||||
BalancedSorter.INTERNODE_VERTICAL_PADDING * 2,
|
||||
},
|
||||
];
|
||||
}
|
||||
@ -202,10 +194,11 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
}
|
||||
|
||||
const yOffset = ysum + heights[i].height / 2;
|
||||
const xOffset = direction
|
||||
* (node.getSize().width / 2
|
||||
+ heights[i].width / 2
|
||||
+ +BalancedSorter.INTERNODE_HORIZONTAL_PADDING);
|
||||
const xOffset =
|
||||
direction *
|
||||
(node.getSize().width / 2 +
|
||||
heights[i].width / 2 +
|
||||
+BalancedSorter.INTERNODE_HORIZONTAL_PADDING);
|
||||
|
||||
$assert(!Number.isNaN(xOffset), 'xOffset can not be null');
|
||||
$assert(!Number.isNaN(yOffset), 'yOffset can not be null');
|
||||
@ -226,9 +219,9 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
const order = i === 0 && factor === 1 ? 1 : factor * i;
|
||||
$assert(
|
||||
children[i].getOrder() === order,
|
||||
`Missing order elements. Missing order: ${i * factor
|
||||
}. Parent:${node.getId()
|
||||
},Node:${children[i].getId()}`,
|
||||
`Missing order elements. Missing order: ${
|
||||
i * factor
|
||||
}. Parent:${node.getId()},Node:${children[i].getId()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -242,8 +235,9 @@ class BalancedSorter extends AbstractBasicSorter {
|
||||
}
|
||||
|
||||
protected _getChildrenForOrder(parent: Node, graph: RootedTreeSet, order: number) {
|
||||
return this._getSortedChildren(graph, parent)
|
||||
.filter((child) => child.getOrder() % 2 === order % 2);
|
||||
return this._getSortedChildren(graph, parent).filter(
|
||||
(child) => child.getOrder() % 2 === order % 2,
|
||||
);
|
||||
}
|
||||
|
||||
protected _getVerticalPadding(): number {
|
||||
|
@ -119,8 +119,9 @@ class LinkEditor extends BootstrapDialog {
|
||||
* @return {Boolean} true if the url is valid
|
||||
*/
|
||||
private checkURL(url: string): boolean {
|
||||
const regex = /^(http|https):\/\/[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i;
|
||||
return (regex.test(url));
|
||||
const regex =
|
||||
/^(http|https):\/\/[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i;
|
||||
return regex.test(url);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,7 +130,7 @@ class LinkEditor extends BootstrapDialog {
|
||||
*/
|
||||
private hasProtocol(url: string): boolean {
|
||||
const regex = /^(http|https):\/\//i;
|
||||
return (regex.test(url));
|
||||
return regex.test(url);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,7 +35,8 @@ class LinkIconTooltip extends FloatingTip {
|
||||
placement: 'bottom',
|
||||
title: $msg('LINK'),
|
||||
trigger: 'manual',
|
||||
template: '<div id="linkPopover" class="popover" onmouseover="jQuery(this).mouseleave(function() {jQuery(this).fadeOut(200); });" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
|
||||
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>',
|
||||
destroyOnExit: true,
|
||||
});
|
||||
}
|
||||
|
@ -33,17 +33,11 @@ import DesignerKeyboard from './components/DesignerKeyboard';
|
||||
import EditorRenderMode from './components/EditorRenderMode';
|
||||
import ImageIcon from './components/ImageIcon';
|
||||
|
||||
import {
|
||||
buildDesigner,
|
||||
} from './components/DesignerBuilder';
|
||||
import { buildDesigner } from './components/DesignerBuilder';
|
||||
|
||||
import {
|
||||
$notify,
|
||||
} from './components/widget/ToolbarNotifier';
|
||||
import { $notify } from './components/widget/ToolbarNotifier';
|
||||
|
||||
import {
|
||||
$msg,
|
||||
} from './components/Messages';
|
||||
import { $msg } from './components/Messages';
|
||||
|
||||
// This hack is required to initialize Bootstrap. In future, this should be removed.
|
||||
const globalAny: any = global;
|
||||
|
@ -16,11 +16,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import jquery from 'jquery';
|
||||
import {
|
||||
} from './components/widget/ToolbarNotifier';
|
||||
import {
|
||||
buildDesigner,
|
||||
} from './components/DesignerBuilder';
|
||||
import {} from './components/widget/ToolbarNotifier';
|
||||
import { buildDesigner } from './components/DesignerBuilder';
|
||||
import PersistenceManager from './components/PersistenceManager';
|
||||
import LocalStorageManager from './components/LocalStorageManager';
|
||||
import DesignerOptionsBuilder from './components/DesignerOptionsBuilder';
|
||||
@ -43,16 +40,14 @@ const persistence: PersistenceManager = new LocalStorageManager(
|
||||
const params = new URLSearchParams(window.location.search.substring(1));
|
||||
|
||||
const zoomParam = Number.parseFloat(params.get('zoom'));
|
||||
const options = DesignerOptionsBuilder.buildOptions(
|
||||
{
|
||||
const options = DesignerOptionsBuilder.buildOptions({
|
||||
persistenceManager: persistence,
|
||||
mode: 'viewonly',
|
||||
mapId: global.mapId,
|
||||
container: 'mindplot',
|
||||
zoom: zoomParam || global.userOptions.zoom,
|
||||
locale: global.locale,
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
// Build designer ...
|
||||
const designer = buildDesigner(options);
|
||||
|
@ -19,7 +19,6 @@ import EditorPage from './components/editor-page';
|
||||
import AppConfig from './classes/app-config';
|
||||
import withSessionExpirationHandling from './components/HOCs/withSessionExpirationHandling';
|
||||
|
||||
|
||||
declare module '@mui/styles/defaultTheme' {
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface DefaultTheme extends Theme {}
|
||||
@ -29,10 +28,9 @@ declare module '@mui/styles/defaultTheme' {
|
||||
ReactGA.initialize([
|
||||
{
|
||||
trackingId: AppConfig.getGoogleAnalyticsAccount(),
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
queries: {
|
||||
@ -62,27 +60,14 @@ const App = (): ReactElement => {
|
||||
<Route exact path="/">
|
||||
<Redirect to="/c/login" />
|
||||
</Route>
|
||||
<Route path="/c/login"
|
||||
component={LoginPage}
|
||||
/>
|
||||
<Route path="/c/login" component={LoginPage} />
|
||||
<Route path="/c/registration" component={RegistationPage} />
|
||||
<Route path="/c/registration-success" component={RegistrationSuccessPage} />
|
||||
<Route path="/c/forgot-password" component={ForgotPasswordPage} />
|
||||
<Route path="/c/forgot-password-success" component={ForgotPasswordSuccessPage} />
|
||||
<Route
|
||||
path="/c/registration"
|
||||
component={RegistationPage}
|
||||
/>
|
||||
<Route
|
||||
path="/c/registration-success"
|
||||
component={RegistrationSuccessPage}
|
||||
/>
|
||||
<Route
|
||||
path="/c/forgot-password"
|
||||
component={ForgotPasswordPage}
|
||||
/>
|
||||
<Route
|
||||
path="/c/forgot-password-success"
|
||||
component={ForgotPasswordSuccessPage}
|
||||
/>
|
||||
<Route
|
||||
exact path="/c/maps/"
|
||||
exact
|
||||
path="/c/maps/"
|
||||
component={withSessionExpirationHandling(MapsPage)}
|
||||
/>
|
||||
<Route exact path="/c/maps/:id/edit">
|
||||
|
@ -23,7 +23,7 @@ function withSessionExpirationHandling<T>(Component: ComponentType<T>) {
|
||||
return (
|
||||
<>
|
||||
<ClientHealthSentinel />
|
||||
<Component {...hocProps} />;
|
||||
<Component {...hocProps} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -43,7 +43,6 @@ import LabelDeleteConfirm from './maps-list/label-delete-confirm';
|
||||
import ReactGA from 'react-ga4';
|
||||
import { withStyles } from '@mui/styles';
|
||||
|
||||
|
||||
export type Filter = GenericFilter | LabelFilter;
|
||||
|
||||
export interface GenericFilter {
|
||||
@ -72,11 +71,14 @@ const MapsPage = (): ReactElement => {
|
||||
const userLocale = AppI18n.getUserLocale();
|
||||
|
||||
const cache = createIntlCache();
|
||||
const intl = createIntl({
|
||||
const intl = createIntl(
|
||||
{
|
||||
defaultLocale: userLocale.code,
|
||||
locale: Locales.EN.code,
|
||||
messages: userLocale.message
|
||||
}, cache)
|
||||
messages: userLocale.message,
|
||||
},
|
||||
cache,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = intl.formatMessage({
|
||||
@ -143,7 +145,7 @@ const MapsPage = (): ReactElement => {
|
||||
filter: { type: 'label', label: l },
|
||||
label: l.title,
|
||||
icon: <LabelTwoTone style={{ color: l.color ? l.color : 'inherit' }} />,
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
return (
|
||||
@ -249,10 +251,7 @@ const MapsPage = (): ReactElement => {
|
||||
})}
|
||||
</List>
|
||||
|
||||
<div
|
||||
style={{ position: 'absolute', bottom: '10px', left: '20px' }}
|
||||
key="power-by"
|
||||
>
|
||||
<div style={{ position: 'absolute', bottom: '10px', left: '20px' }} key="power-by">
|
||||
<Link href="http://www.wisemapping.org/">
|
||||
<img src={poweredByIcon} alt="Powered By WiseMapping" />
|
||||
</Link>
|
||||
@ -263,14 +262,16 @@ const MapsPage = (): ReactElement => {
|
||||
<MapsList filter={filter} />
|
||||
</main>
|
||||
</div>
|
||||
{labelToDelete && <LabelDeleteConfirm
|
||||
{labelToDelete && (
|
||||
<LabelDeleteConfirm
|
||||
onClose={() => setLabelToDelete(null)}
|
||||
onConfirm={() => {
|
||||
handleLabelDelete(labelToDelete);
|
||||
setLabelToDelete(null);
|
||||
}}
|
||||
label={labels.find(l => l.id === labelToDelete)}
|
||||
/>}
|
||||
label={labels.find((l) => l.id === labelToDelete)}
|
||||
/>
|
||||
)}
|
||||
</IntlProvider>
|
||||
);
|
||||
};
|
||||
@ -287,22 +288,22 @@ interface ListItemProps {
|
||||
// https://stackoverflow.com/questions/61486061/how-to-set-selected-and-hover-color-of-listitem-in-mui
|
||||
const CustomListItem = withStyles({
|
||||
root: {
|
||||
"&$selected": {
|
||||
backgroundColor: "rgb(210, 140, 5)",
|
||||
color: "white",
|
||||
"& .MuiListItemIcon-root": {
|
||||
color: "white"
|
||||
}
|
||||
},
|
||||
"&$selected:hover": {
|
||||
backgroundColor: "rgb(210, 140, 5)",
|
||||
color: "white",
|
||||
"& .MuiListItemIcon-root": {
|
||||
color: "white"
|
||||
}
|
||||
'&$selected': {
|
||||
backgroundColor: 'rgb(210, 140, 5)',
|
||||
color: 'white',
|
||||
'& .MuiListItemIcon-root': {
|
||||
color: 'white',
|
||||
},
|
||||
},
|
||||
selected: {}
|
||||
'&$selected:hover': {
|
||||
backgroundColor: 'rgb(210, 140, 5)',
|
||||
color: 'white',
|
||||
'& .MuiListItemIcon-root': {
|
||||
color: 'white',
|
||||
},
|
||||
},
|
||||
},
|
||||
selected: {},
|
||||
})(ListItemButton);
|
||||
|
||||
const StyleListItem = (props: ListItemProps) => {
|
||||
@ -324,7 +325,7 @@ const StyleListItem = (props: ListItemProps) => {
|
||||
|
||||
const handleOnDelete = (
|
||||
event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
|
||||
filter: Filter
|
||||
filter: Filter,
|
||||
) => {
|
||||
event.stopPropagation();
|
||||
if (!onDeleteLabel) {
|
||||
@ -343,7 +344,8 @@ const StyleListItem = (props: ListItemProps) => {
|
||||
edge="end"
|
||||
aria-label="delete"
|
||||
onClick={(e) => handleOnDelete(e, filter)}
|
||||
size="large">
|
||||
size="large"
|
||||
>
|
||||
<DeleteOutlineTwoTone color="secondary" />
|
||||
</IconButton>
|
||||
</ListItemSecondaryAction>
|
||||
|
Loading…
Reference in New Issue
Block a user