Merge branch 'develop'

This commit is contained in:
Paulo Gustavo Veiga 2022-09-11 13:01:39 -07:00
commit 9bfb300b06
339 changed files with 32036 additions and 11750 deletions

3
.gitignore vendored
View File

@ -52,3 +52,6 @@ Thumbs.db
.vscode .vscode
*/test/playground/dist */test/playground/dist
# visual code local workspaces
wisemapping-frontend.code-workspace

View File

@ -1,6 +1,6 @@
{ {
"trailingComma": "es5", "trailingComma": "all",
"tabWidth": 4, "tabWidth": 2,
"semi": true, "semi": true,
"singleQuote": true, "singleQuote": true,
"printWidth": 100 "printWidth": 100

View File

@ -21,6 +21,7 @@ pipelines:
- yarn bootstrap - yarn bootstrap
- yarn build - yarn build
- yarn lint - yarn lint
- yarn test:unit
# - yarn test # - yarn test
artifacts: artifacts:
- packages/**/cypress/snapshots/**/__diff_output__/*.diff.png - packages/**/cypress/snapshots/**/__diff_output__/*.diff.png

View File

@ -0,0 +1 @@
../packages/webapp/dist/src_components_editor-page_index_tsx.bundle.js

View File

@ -0,0 +1 @@
../packages/webapp/dist/src_components_editor-page_index_tsx.bundle.js.map

View File

@ -0,0 +1 @@
../packages/webapp/dist/src_components_maps-page_action-dispatcher_index_tsx.bundle.js

View File

@ -0,0 +1 @@
../packages/webapp/dist/src_components_maps-page_action-dispatcher_index_tsx.bundle.js.map

View File

@ -0,0 +1 @@
../packages/webapp/dist/src_components_maps-page_index_tsx.bundle.js

View File

@ -0,0 +1 @@
../packages/webapp/dist/src_components_maps-page_index_tsx.bundle.js.map

View File

@ -1,7 +1,7 @@
version: '3' version: '3'
services: services:
e2e: e2e:
image: cypress/included:8.4.1 image: cypress/included:10.7.0
container_name: wisemapping-integration-tests container_name: wisemapping-integration-tests
entrypoint: '/bin/sh -c "yarn install && yarn bootstrap && yarn build && yarn test:integration"' entrypoint: '/bin/sh -c "yarn install && yarn bootstrap && yarn build && yarn test:integration"'
working_dir: /e2e working_dir: /e2e

View File

@ -1,7 +1,7 @@
version: '3' version: '3'
services: services:
e2e: e2e:
image: cypress/included:8.4.1 image: cypress/included:10.7.0
container_name: wisemapping-integration-tests container_name: wisemapping-integration-tests
entrypoint: '/bin/sh -c "yarn bootstrap && yarn build && yarn test:integration"' entrypoint: '/bin/sh -c "yarn bootstrap && yarn build && yarn test:integration"'
working_dir: /e2e working_dir: /e2e

View File

@ -4,5 +4,6 @@
], ],
"version": "1.0.0", "version": "1.0.0",
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true "useWorkspaces": true,
"useNx": false
} }

View File

@ -13,7 +13,7 @@
width: 100px; width: 100px;
height: 100px; height: 100px;
cursor: crosshair; cursor: crosshair;
background-image: url("../img/bootstrap-colorpicker/saturation.png"); background-image: url('../img/bootstrap-colorpicker/saturation.png');
} }
.colorpicker-saturation i { .colorpicker-saturation i {
@ -64,12 +64,12 @@
} }
.colorpicker-hue { .colorpicker-hue {
background-image: url("../img/bootstrap-colorpicker/hue.png"); background-image: url('../img/bootstrap-colorpicker/hue.png');
} }
.colorpicker-alpha { .colorpicker-alpha {
display: none; display: none;
background-image: url("../img/bootstrap-colorpicker/alpha.png"); background-image: url('../img/bootstrap-colorpicker/alpha.png');
} }
.colorpicker { .colorpicker {
@ -89,7 +89,7 @@
.colorpicker:after { .colorpicker:after {
display: table; display: table;
line-height: 0; line-height: 0;
content: ""; content: '';
} }
.colorpicker:after { .colorpicker:after {
@ -135,7 +135,7 @@
height: 10px; height: 10px;
margin-top: 5px; margin-top: 5px;
clear: both; clear: both;
background-image: url("../img/bootstrap-colorpicker/alpha.png"); background-image: url('../img/bootstrap-colorpicker/alpha.png');
background-position: 0 100%; background-position: 0 100%;
} }
@ -194,11 +194,11 @@
} }
.colorpicker.colorpicker-horizontal .colorpicker-hue { .colorpicker.colorpicker-horizontal .colorpicker-hue {
background-image: url("../img/bootstrap-colorpicker/hue-horizontal.png"); background-image: url('../img/bootstrap-colorpicker/hue-horizontal.png');
} }
.colorpicker.colorpicker-horizontal .colorpicker-alpha { .colorpicker.colorpicker-horizontal .colorpicker-alpha {
background-image: url("../img/bootstrap-colorpicker/alpha-horizontal.png"); background-image: url('../img/bootstrap-colorpicker/alpha-horizontal.png');
} }
.colorpicker.colorpicker-hidden { .colorpicker.colorpicker-hidden {

View File

@ -6,4 +6,180 @@
* Licensed under the Apache License v2.0 * Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0.txt * http://www.apache.org/licenses/LICENSE-2.0.txt
* *
*/.colorpicker-saturation{float:left;width:100px;height:100px;cursor:crosshair;background-image:url("../img/bootstrap-colorpicker/saturation.png")}.colorpicker-saturation i{position:absolute;top:0;left:0;display:block;width:5px;height:5px;margin:-4px 0 0 -4px;border:1px solid #000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-saturation i b{display:block;width:5px;height:5px;border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-hue,.colorpicker-alpha{float:left;width:15px;height:100px;margin-bottom:4px;margin-left:4px;cursor:row-resize}.colorpicker-hue i,.colorpicker-alpha i{position:absolute;top:0;left:0;display:block;width:100%;height:1px;margin-top:-1px;background:#000;border-top:1px solid #fff}.colorpicker-hue{background-image:url("../img/bootstrap-colorpicker/hue.png")}.colorpicker-alpha{display:none;background-image:url("../img/bootstrap-colorpicker/alpha.png")}.colorpicker{top:0;left:0;z-index:2500;min-width:130px;padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1}.colorpicker:before,.colorpicker:after{display:table;line-height:0;content:""}.colorpicker:after{clear:both}.colorpicker:before{position:absolute;top:-7px;left:6px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.colorpicker:after{position:absolute;top:-6px;left:7px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.colorpicker div{position:relative}.colorpicker.colorpicker-with-alpha{min-width:140px}.colorpicker.colorpicker-with-alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-image:url("../img/bootstrap-colorpicker/alpha.png");background-position:0 100%}.colorpicker-color div{height:10px}.colorpicker-element .input-group-addon i{display:block;width:16px;height:16px;cursor:pointer}.colorpicker.colorpicker-inline{position:relative;display:inline-block;float:none}.colorpicker.colorpicker-horizontal{width:110px;height:auto;min-width:110px}.colorpicker.colorpicker-horizontal .colorpicker-saturation{margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-color{width:100px}.colorpicker.colorpicker-horizontal .colorpicker-hue,.colorpicker.colorpicker-horizontal .colorpicker-alpha{float:left;width:100px;height:15px;margin-bottom:4px;margin-left:0;cursor:col-resize}.colorpicker.colorpicker-horizontal .colorpicker-hue i,.colorpicker.colorpicker-horizontal .colorpicker-alpha i{position:absolute;top:0;left:0;display:block;width:1px;height:15px;margin-top:0;background:#fff;border:0}.colorpicker.colorpicker-horizontal .colorpicker-hue{background-image:url("../img/bootstrap-colorpicker/hue-horizontal.png")}.colorpicker.colorpicker-horizontal .colorpicker-alpha{background-image:url("../img/bootstrap-colorpicker/alpha-horizontal.png")}.colorpicker.colorpicker-hidden{display:none}.colorpicker.colorpicker-visible{display:block}.colorpicker-inline.colorpicker-visible{display:inline-block} */
.colorpicker-saturation {
float: left;
width: 100px;
height: 100px;
cursor: crosshair;
background-image: url('../img/bootstrap-colorpicker/saturation.png');
}
.colorpicker-saturation i {
position: absolute;
top: 0;
left: 0;
display: block;
width: 5px;
height: 5px;
margin: -4px 0 0 -4px;
border: 1px solid #000;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.colorpicker-saturation i b {
display: block;
width: 5px;
height: 5px;
border: 1px solid #fff;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
.colorpicker-hue,
.colorpicker-alpha {
float: left;
width: 15px;
height: 100px;
margin-bottom: 4px;
margin-left: 4px;
cursor: row-resize;
}
.colorpicker-hue i,
.colorpicker-alpha i {
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
height: 1px;
margin-top: -1px;
background: #000;
border-top: 1px solid #fff;
}
.colorpicker-hue {
background-image: url('../img/bootstrap-colorpicker/hue.png');
}
.colorpicker-alpha {
display: none;
background-image: url('../img/bootstrap-colorpicker/alpha.png');
}
.colorpicker {
top: 0;
left: 0;
z-index: 2500;
min-width: 130px;
padding: 4px;
margin-top: 1px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
*zoom: 1;
}
.colorpicker:before,
.colorpicker:after {
display: table;
line-height: 0;
content: '';
}
.colorpicker:after {
clear: both;
}
.colorpicker:before {
position: absolute;
top: -7px;
left: 6px;
display: inline-block;
border-right: 7px solid transparent;
border-bottom: 7px solid #ccc;
border-left: 7px solid transparent;
border-bottom-color: rgba(0, 0, 0, 0.2);
content: '';
}
.colorpicker:after {
position: absolute;
top: -6px;
left: 7px;
display: inline-block;
border-right: 6px solid transparent;
border-bottom: 6px solid #fff;
border-left: 6px solid transparent;
content: '';
}
.colorpicker div {
position: relative;
}
.colorpicker.colorpicker-with-alpha {
min-width: 140px;
}
.colorpicker.colorpicker-with-alpha .colorpicker-alpha {
display: block;
}
.colorpicker-color {
height: 10px;
margin-top: 5px;
clear: both;
background-image: url('../img/bootstrap-colorpicker/alpha.png');
background-position: 0 100%;
}
.colorpicker-color div {
height: 10px;
}
.colorpicker-element .input-group-addon i {
display: block;
width: 16px;
height: 16px;
cursor: pointer;
}
.colorpicker.colorpicker-inline {
position: relative;
display: inline-block;
float: none;
}
.colorpicker.colorpicker-horizontal {
width: 110px;
height: auto;
min-width: 110px;
}
.colorpicker.colorpicker-horizontal .colorpicker-saturation {
margin-bottom: 4px;
}
.colorpicker.colorpicker-horizontal .colorpicker-color {
width: 100px;
}
.colorpicker.colorpicker-horizontal .colorpicker-hue,
.colorpicker.colorpicker-horizontal .colorpicker-alpha {
float: left;
width: 100px;
height: 15px;
margin-bottom: 4px;
margin-left: 0;
cursor: col-resize;
}
.colorpicker.colorpicker-horizontal .colorpicker-hue i,
.colorpicker.colorpicker-horizontal .colorpicker-alpha i {
position: absolute;
top: 0;
left: 0;
display: block;
width: 1px;
height: 15px;
margin-top: 0;
background: #fff;
border: 0;
}
.colorpicker.colorpicker-horizontal .colorpicker-hue {
background-image: url('../img/bootstrap-colorpicker/hue-horizontal.png');
}
.colorpicker.colorpicker-horizontal .colorpicker-alpha {
background-image: url('../img/bootstrap-colorpicker/alpha-horizontal.png');
}
.colorpicker.colorpicker-hidden {
display: none;
}
.colorpicker.colorpicker-visible {
display: block;
}
.colorpicker-inline.colorpicker-visible {
display: inline-block;
}

View File

@ -10,9 +10,9 @@
.btn-info, .btn-info,
.btn-warning, .btn-warning,
.btn-danger { .btn-danger {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
} }
.btn-default:active, .btn-default:active,
.btn-primary:active, .btn-primary:active,
@ -26,8 +26,8 @@
.btn-info.active, .btn-info.active,
.btn-warning.active, .btn-warning.active,
.btn-danger.active { .btn-danger.active {
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
} }
.btn:active, .btn:active,
.btn.active { .btn.active {
@ -145,8 +145,8 @@
} }
.thumbnail, .thumbnail,
.img-thumbnail { .img-thumbnail {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
} }
.dropdown-menu > li > a:hover, .dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus { .dropdown-menu > li > a:focus {
@ -172,20 +172,20 @@
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
background-repeat: repeat-x; background-repeat: repeat-x;
border-radius: 4px; border-radius: 4px;
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
} }
.navbar-default .navbar-nav > .active > a { .navbar-default .navbar-nav > .active > a {
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%); background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%); background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
background-repeat: repeat-x; background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
} }
.navbar-brand, .navbar-brand,
.navbar-nav > li > a { .navbar-nav > li > a {
text-shadow: 0 1px 0 rgba(255, 255, 255, .25); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
} }
.navbar-inverse { .navbar-inverse {
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
@ -199,12 +199,12 @@
background-image: linear-gradient(to bottom, #222 0%, #282828 100%); background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
background-repeat: repeat-x; background-repeat: repeat-x;
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
} }
.navbar-inverse .navbar-brand, .navbar-inverse .navbar-brand,
.navbar-inverse .navbar-nav > li > a { .navbar-inverse .navbar-nav > li > a {
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
} }
.navbar-static-top, .navbar-static-top,
.navbar-fixed-top, .navbar-fixed-top,
@ -212,9 +212,9 @@
border-radius: 0; border-radius: 0;
} }
.alert { .alert {
text-shadow: 0 1px 0 rgba(255, 255, 255, .2); text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
} }
.alert-success { .alert-success {
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
@ -282,8 +282,8 @@
} }
.list-group { .list-group {
border-radius: 4px; border-radius: 4px;
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
box-shadow: 0 1px 2px rgba(0, 0, 0, .075); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
} }
.list-group-item.active, .list-group-item.active,
.list-group-item.active:hover, .list-group-item.active:hover,
@ -296,8 +296,8 @@
border-color: #3278b3; border-color: #3278b3;
} }
.panel { .panel {
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
box-shadow: 0 1px 2px rgba(0, 0, 0, .05); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
} }
.panel-default > .panel-heading { .panel-default > .panel-heading {
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
@ -341,7 +341,7 @@
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
background-repeat: repeat-x; background-repeat: repeat-x;
border-color: #dcdcdc; border-color: #dcdcdc;
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
} }
/*# sourceMappingURL=bootstrap-theme.css.map */ /*# sourceMappingURL=bootstrap-theme.css.map */

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -4,7 +4,9 @@
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/ */
if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript requires jQuery'); } if (typeof jQuery === 'undefined') {
throw new Error("Bootstrap's JavaScript requires jQuery");
}
/* ======================================================================== /* ========================================================================
* Bootstrap: transition.js v3.1.1 * Bootstrap: transition.js v3.1.1
@ -39,10 +41,14 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// http://blog.alexmaccaw.com/css-transitions // http://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) { $.fn.emulateTransitionEnd = function (duration) {
let called = false; const let called = false;
$el = this; const $el = this;
$(this).one($.support.transition.end, () => { called = true; }); $(this).one($.support.transition.end, () => {
const callback = function () { if (!called) $($el).trigger($.support.transition.end); }; called = true;
});
const callback = function () {
if (!called) $($el).trigger($.support.transition.end);
};
setTimeout(callback, duration); setTimeout(callback, duration);
return this; return this;
}; };
@ -50,7 +56,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$(() => { $(() => {
$.support.transition = transitionEnd(); $.support.transition = transitionEnd();
}); });
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: alert.js v3.1.1 * Bootstrap: alert.js v3.1.1
@ -86,7 +92,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$parent = $this.hasClass('alert') ? $this : $this.parent(); $parent = $this.hasClass('alert') ? $this : $this.parent();
} }
$parent.trigger(e = $.Event('close.bs.alert')); $parent.trigger((e = $.Event('close.bs.alert')));
if (e.isDefaultPrevented()) return; if (e.isDefaultPrevented()) return;
@ -97,9 +103,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
} }
$.support.transition && $parent.hasClass('fade') $.support.transition && $parent.hasClass('fade')
? $parent ? $parent.one($.support.transition.end, removeElement).emulateTransitionEnd(150)
.one($.support.transition.end, removeElement)
.emulateTransitionEnd(150)
: removeElement(); : removeElement();
}; };
@ -132,7 +136,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// ============== // ==============
$(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close); $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close);
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: button.js v3.1.1 * Bootstrap: button.js v3.1.1
@ -169,7 +173,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$el[val](data[state] || this.options[state]); $el[val](data[state] || this.options[state]);
// push to event loop to allow forms to submit // push to event loop to allow forms to submit
setTimeout($.proxy(function () { setTimeout(
$.proxy(function () {
if (state == 'loadingText') { if (state == 'loadingText') {
this.isLoading = true; this.isLoading = true;
$el.addClass(d).attr(d, d); $el.addClass(d).attr(d, d);
@ -177,7 +182,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.isLoading = false; this.isLoading = false;
$el.removeClass(d).removeAttr(d); $el.removeClass(d).removeAttr(d);
} }
}, this), 0); }, this),
0,
);
}; };
Button.prototype.toggle = function () { Button.prototype.toggle = function () {
@ -233,7 +240,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$btn.button('toggle'); $btn.button('toggle');
e.preventDefault(); e.preventDefault();
}); });
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: carousel.js v3.1.1 * Bootstrap: carousel.js v3.1.1
@ -253,7 +260,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.options = options; this.options = options;
this.paused = this.sliding = this.interval = this.$active = this.$items = null; this.paused = this.sliding = this.interval = this.$active = this.$items = null;
this.options.pause == 'hover' && this.$element this.options.pause == 'hover' &&
this.$element
.on('mouseenter', $.proxy(this.pause, this)) .on('mouseenter', $.proxy(this.pause, this))
.on('mouseleave', $.proxy(this.cycle, this)); .on('mouseleave', $.proxy(this.cycle, this));
}; };
@ -269,9 +277,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.interval && clearInterval(this.interval); this.interval && clearInterval(this.interval);
this.options.interval this.options.interval &&
&& !this.paused !this.paused &&
&& (this.interval = setInterval($.proxy(this.next, this), this.options.interval)); (this.interval = setInterval($.proxy(this.next, this), this.options.interval));
return this; return this;
}; };
@ -287,9 +295,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const that = this; const that = this;
const activeIndex = this.getActiveIndex(); const activeIndex = this.getActiveIndex();
if (pos > (this.$items.length - 1) || pos < 0) return; if (pos > this.$items.length - 1 || pos < 0) return;
if (this.sliding) return this.$element.one('slid.bs.carousel', () => { that.to(pos); }); if (this.sliding)
return this.$element.one('slid.bs.carousel', () => {
that.to(pos);
});
if (activeIndex == pos) return this.pause().cycle(); if (activeIndex == pos) return this.pause().cycle();
return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])); return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]));
@ -331,7 +342,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$next = this.$element.find('.item')[fallback](); $next = this.$element.find('.item')[fallback]();
} }
if ($next.hasClass('active')) return this.sliding = false; if ($next.hasClass('active')) return (this.sliding = false);
const e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction }); const e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction });
this.$element.trigger(e); this.$element.trigger(e);
@ -359,7 +370,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$next.removeClass([type, direction].join(' ')).addClass('active'); $next.removeClass([type, direction].join(' ')).addClass('active');
$active.removeClass(['active', direction].join(' ')); $active.removeClass(['active', direction].join(' '));
that.sliding = false; that.sliding = false;
setTimeout(() => { that.$element.trigger('slid.bs.carousel'); }, 0); setTimeout(() => {
that.$element.trigger('slid.bs.carousel');
}, 0);
}) })
.emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000); .emulateTransitionEnd($active.css('transition-duration').slice(0, -1) * 1000);
} else { } else {
@ -383,7 +396,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return this.each(function () { return this.each(function () {
const $this = $(this); const $this = $(this);
let data = $this.data('bs.carousel'); let data = $this.data('bs.carousel');
const options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option === 'object' && option); const options = $.extend(
{},
Carousel.DEFAULTS,
$this.data(),
typeof option === 'object' && option,
);
const action = typeof option === 'string' ? option : options.slide; const action = typeof option === 'string' ? option : options.slide;
if (!data) $this.data('bs.carousel', (data = new Carousel(this, options))); if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)));
@ -407,16 +425,19 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// ================= // =================
$(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
const $this = $(this); let const $this = $(this);
href; let href;
const $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')); // strip for ie7 const $target = $(
$this.attr('data-target') ||
((href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')),
); // strip for ie7
const options = $.extend({}, $target.data(), $this.data()); const options = $.extend({}, $target.data(), $this.data());
let slideIndex = $this.attr('data-slide-to'); let slideIndex = $this.attr('data-slide-to');
if (slideIndex) options.interval = false; if (slideIndex) options.interval = false;
$target.carousel(options); $target.carousel(options);
if (slideIndex = $this.attr('data-slide-to')) { if ((slideIndex = $this.attr('data-slide-to'))) {
$target.data('bs.carousel').to(slideIndex); $target.data('bs.carousel').to(slideIndex);
} }
@ -429,7 +450,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$carousel.carousel($carousel.data()); $carousel.carousel($carousel.data());
}); });
}); });
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: collapse.js v3.1.1 * Bootstrap: collapse.js v3.1.1
@ -479,18 +500,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const dimension = this.dimension(); const dimension = this.dimension();
this.$element this.$element.removeClass('collapse').addClass('collapsing')[dimension](0);
.removeClass('collapse')
.addClass('collapsing')
[dimension](0);
this.transitioning = 1; this.transitioning = 1;
const complete = function () { const complete = function () {
this.$element this.$element.removeClass('collapsing').addClass('collapse in')[dimension]('auto');
.removeClass('collapsing')
.addClass('collapse in')
[dimension]('auto');
this.transitioning = 0; this.transitioning = 0;
this.$element.trigger('shown.bs.collapse'); this.$element.trigger('shown.bs.collapse');
}; };
@ -514,29 +529,20 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const dimension = this.dimension(); const dimension = this.dimension();
this.$element this.$element[dimension](this.$element[dimension]())[0].offsetHeight;
[dimension](this.$element[dimension]())
[0].offsetHeight;
this.$element this.$element.addClass('collapsing').removeClass('collapse').removeClass('in');
.addClass('collapsing')
.removeClass('collapse')
.removeClass('in');
this.transitioning = 1; this.transitioning = 1;
const complete = function () { const complete = function () {
this.transitioning = 0; this.transitioning = 0;
this.$element this.$element.trigger('hidden.bs.collapse').removeClass('collapsing').addClass('collapse');
.trigger('hidden.bs.collapse')
.removeClass('collapsing')
.addClass('collapse');
}; };
if (!$.support.transition) return complete.call(this); if (!$.support.transition) return complete.call(this);
this.$element this.$element[dimension](0)
[dimension](0)
.one($.support.transition.end, $.proxy(complete, this)) .one($.support.transition.end, $.proxy(complete, this))
.emulateTransitionEnd(350); .emulateTransitionEnd(350);
}; };
@ -554,7 +560,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return this.each(function () { return this.each(function () {
const $this = $(this); const $this = $(this);
let data = $this.data('bs.collapse'); let data = $this.data('bs.collapse');
const options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option === 'object' && option); const options = $.extend(
{},
Collapse.DEFAULTS,
$this.data(),
typeof option === 'object' && option,
);
if (!data && options.toggle && option == 'show') option = !option; if (!data && options.toggle && option == 'show') option = !option;
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options))); if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)));
@ -576,11 +587,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// ================= // =================
$(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) { $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
const $this = $(this); let const $this = $(this);
href; let href;
const target = $this.attr('data-target') const target =
|| e.preventDefault() $this.attr('data-target') ||
|| (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, ''); // strip for ie7 e.preventDefault() ||
((href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')); // strip for ie7
const $target = $(target); const $target = $(target);
const data = $target.data('bs.collapse'); const data = $target.data('bs.collapse');
const option = data ? 'toggle' : $this.data(); const option = data ? 'toggle' : $this.data();
@ -588,13 +600,17 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const $parent = parent && $(parent); const $parent = parent && $(parent);
if (!data || !data.transitioning) { if (!data || !data.transitioning) {
if ($parent) $parent.find(`[data-toggle=collapse][data-parent="${parent}"]`).not($this).addClass('collapsed'); if ($parent)
$parent
.find(`[data-toggle=collapse][data-parent="${parent}"]`)
.not($this)
.addClass('collapsed');
$this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed'); $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed');
} }
$target.collapse(option); $target.collapse(option);
}); });
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: dropdown.js v3.1.1 * Bootstrap: dropdown.js v3.1.1
@ -631,13 +647,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
} }
const relatedTarget = { relatedTarget: this }; const relatedTarget = { relatedTarget: this };
$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget)); $parent.trigger((e = $.Event('show.bs.dropdown', relatedTarget)));
if (e.isDefaultPrevented()) return; if (e.isDefaultPrevented()) return;
$parent $parent.toggleClass('open').trigger('shown.bs.dropdown', relatedTarget);
.toggleClass('open')
.trigger('shown.bs.dropdown', relatedTarget);
$this.focus(); $this.focus();
} }
@ -683,7 +697,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const $parent = getParent($(this)); const $parent = getParent($(this));
const relatedTarget = { relatedTarget: this }; const relatedTarget = { relatedTarget: this };
if (!$parent.hasClass('open')) return; if (!$parent.hasClass('open')) return;
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget)); $parent.trigger((e = $.Event('hide.bs.dropdown', relatedTarget)));
if (e.isDefaultPrevented()) return; if (e.isDefaultPrevented()) return;
$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget); $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget);
}); });
@ -732,10 +746,16 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$(document) $(document)
.on('click.bs.dropdown.data-api', clearMenus) .on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', (e) => { e.stopPropagation(); }) .on('click.bs.dropdown.data-api', '.dropdown form', (e) => {
e.stopPropagation();
})
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle) .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', `${toggle}, [role=menu], [role=listbox]`, Dropdown.prototype.keydown); .on(
}(jQuery)); 'keydown.bs.dropdown.data-api',
`${toggle}, [role=menu], [role=listbox]`,
Dropdown.prototype.keydown,
);
})(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: modal.js v3.1.1 * Bootstrap: modal.js v3.1.1
@ -755,11 +775,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$backdrop = this.isShown = null; this.$backdrop = this.isShown = null;
if (this.options.remote) { if (this.options.remote) {
this.$element this.$element.find('.modal-content').load(
.find('.modal-content') this.options.remote,
.load(this.options.remote, $.proxy(function () { $.proxy(function () {
this.$element.trigger('loaded.bs.modal'); this.$element.trigger('loaded.bs.modal');
}, this)); }, this),
);
} }
}; };
@ -794,24 +815,21 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
that.$element.appendTo(document.body); // don't move modals dom position that.$element.appendTo(document.body); // don't move modals dom position
} }
that.$element that.$element.show().scrollTop(0);
.show()
.scrollTop(0);
if (transition) { if (transition) {
that.$element[0].offsetWidth; // force reflow that.$element[0].offsetWidth; // force reflow
} }
that.$element that.$element.addClass('in').attr('aria-hidden', false);
.addClass('in')
.attr('aria-hidden', false);
that.enforceFocus(); that.enforceFocus();
const e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget }); const e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget });
transition transition
? that.$element.find('.modal-dialog') // wait for modal to slide in ? that.$element
.find('.modal-dialog') // wait for modal to slide in
.one($.support.transition.end, () => { .one($.support.transition.end, () => {
that.$element.focus().trigger(e); that.$element.focus().trigger(e);
}) })
@ -835,10 +853,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$(document).off('focusin.bs.modal'); $(document).off('focusin.bs.modal');
this.$element this.$element.removeClass('in').attr('aria-hidden', true).off('click.dismiss.bs.modal');
.removeClass('in')
.attr('aria-hidden', true)
.off('click.dismiss.bs.modal');
$.support.transition && this.$element.hasClass('fade') $.support.transition && this.$element.hasClass('fade')
? this.$element ? this.$element
@ -850,18 +865,24 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Modal.prototype.enforceFocus = function () { Modal.prototype.enforceFocus = function () {
$(document) $(document)
.off('focusin.bs.modal') // guard against infinite focus loop .off('focusin.bs.modal') // guard against infinite focus loop
.on('focusin.bs.modal', $.proxy(function (e) { .on(
'focusin.bs.modal',
$.proxy(function (e) {
if (this.$element[0] !== e.target && !this.$element.has(e.target).length) { if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
this.$element.focus(); this.$element.focus();
} }
}, this)); }, this),
);
}; };
Modal.prototype.escape = function () { Modal.prototype.escape = function () {
if (this.isShown && this.options.keyboard) { if (this.isShown && this.options.keyboard) {
this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) { this.$element.on(
'keyup.dismiss.bs.modal',
$.proxy(function (e) {
e.which == 27 && this.hide(); e.which == 27 && this.hide();
}, this)); }, this),
);
} else if (!this.isShown) { } else if (!this.isShown) {
this.$element.off('keyup.dismiss.bs.modal'); this.$element.off('keyup.dismiss.bs.modal');
} }
@ -887,15 +908,17 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (this.isShown && this.options.backdrop) { if (this.isShown && this.options.backdrop) {
const doAnimate = $.support.transition && animate; const doAnimate = $.support.transition && animate;
this.$backdrop = $(`<div class="modal-backdrop ${animate}" />`) this.$backdrop = $(`<div class="modal-backdrop ${animate}" />`).appendTo(document.body);
.appendTo(document.body);
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) { this.$element.on(
'click.dismiss.bs.modal',
$.proxy(function (e) {
if (e.target !== e.currentTarget) return; if (e.target !== e.currentTarget) return;
this.options.backdrop == 'static' this.options.backdrop == 'static'
? this.$element[0].focus.call(this.$element[0]) ? this.$element[0].focus.call(this.$element[0])
: this.hide.call(this); : this.hide.call(this);
}, this)); }, this),
);
if (doAnimate) this.$backdrop[0].offsetWidth; // force reflow if (doAnimate) this.$backdrop[0].offsetWidth; // force reflow
@ -904,17 +927,13 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (!callback) return; if (!callback) return;
doAnimate doAnimate
? this.$backdrop ? this.$backdrop.one($.support.transition.end, callback).emulateTransitionEnd(150)
.one($.support.transition.end, callback)
.emulateTransitionEnd(150)
: callback(); : callback();
} else if (!this.isShown && this.$backdrop) { } else if (!this.isShown && this.$backdrop) {
this.$backdrop.removeClass('in'); this.$backdrop.removeClass('in');
$.support.transition && this.$element.hasClass('fade') $.support.transition && this.$element.hasClass('fade')
? this.$backdrop ? this.$backdrop.one($.support.transition.end, callback).emulateTransitionEnd(150)
.one($.support.transition.end, callback)
.emulateTransitionEnd(150)
: callback(); : callback();
} else if (callback) { } else if (callback) {
callback(); callback();
@ -930,7 +949,12 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return this.each(function () { return this.each(function () {
const $this = $(this); const $this = $(this);
let data = $this.data('bs.modal'); let data = $this.data('bs.modal');
const options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option === 'object' && option); const options = $.extend(
{},
Modal.DEFAULTS,
$this.data(),
typeof option === 'object' && option,
);
if (!data) $this.data('bs.modal', (data = new Modal(this, options))); if (!data) $this.data('bs.modal', (data = new Modal(this, options)));
if (typeof option === 'string') data[option](_relatedTarget); if (typeof option === 'string') data[option](_relatedTarget);
@ -955,21 +979,25 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const $this = $(this); const $this = $(this);
const href = $this.attr('href'); const href = $this.attr('href');
const $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))); // strip for ie7 const $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))); // strip for ie7
const option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data()); const option = $target.data('bs.modal')
? 'toggle'
: $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data());
if ($this.is('a')) e.preventDefault(); if ($this.is('a')) e.preventDefault();
$target $target.modal(option, this).one('hide', () => {
.modal(option, this)
.one('hide', () => {
$this.is(':visible') && $this.focus(); $this.is(':visible') && $this.focus();
}); });
}); });
$(document) $(document)
.on('show.bs.modal', '.modal', () => { $(document.body).addClass('modal-open'); }) .on('show.bs.modal', '.modal', () => {
.on('hidden.bs.modal', '.modal', () => { $(document.body).removeClass('modal-open'); }); $(document.body).addClass('modal-open');
}(jQuery)); })
.on('hidden.bs.modal', '.modal', () => {
$(document.body).removeClass('modal-open');
});
})(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: tooltip.js v3.1.1 * Bootstrap: tooltip.js v3.1.1
@ -994,7 +1022,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
animation: true, animation: true,
placement: 'top', placement: 'top',
selector: false, selector: false,
template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', template:
'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
trigger: 'hover focus', trigger: 'hover focus',
title: '', title: '',
delay: 0, delay: 0,
@ -1010,7 +1039,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const triggers = this.options.trigger.split(' '); const triggers = this.options.trigger.split(' ');
for (let i = triggers.length; i--;) { for (let i = triggers.length; i--; ) {
const trigger = triggers[i]; const trigger = triggers[i];
if (trigger == 'click') { if (trigger == 'click') {
@ -1019,8 +1048,16 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'; const eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
const eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'; const eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
this.$element.on(`${eventIn}.${this.type}`, this.options.selector, $.proxy(this.enter, this)); this.$element.on(
this.$element.on(`${eventOut}.${this.type}`, this.options.selector, $.proxy(this.leave, this)); `${eventIn}.${this.type}`,
this.options.selector,
$.proxy(this.enter, this),
);
this.$element.on(
`${eventOut}.${this.type}`,
this.options.selector,
$.proxy(this.leave, this),
);
} }
} }
@ -1050,7 +1087,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const options = {}; const options = {};
const defaults = this.getDefaults(); const defaults = this.getDefaults();
this._options && $.each(this._options, (key, value) => { this._options &&
$.each(this._options, (key, value) => {
if (defaults[key] != value) options[key] = value; if (defaults[key] != value) options[key] = value;
}); });
@ -1058,8 +1096,10 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}; };
Tooltip.prototype.enter = function (obj) { Tooltip.prototype.enter = function (obj) {
const self = obj instanceof this.constructor const self =
? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data(`bs.${this.type}`); obj instanceof this.constructor
? obj
: $(obj.currentTarget)[this.type](this.getDelegateOptions()).data(`bs.${this.type}`);
clearTimeout(self.timeout); clearTimeout(self.timeout);
@ -1073,8 +1113,10 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}; };
Tooltip.prototype.leave = function (obj) { Tooltip.prototype.leave = function (obj) {
const self = obj instanceof this.constructor const self =
? obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data(`bs.${this.type}`); obj instanceof this.constructor
? obj
: $(obj.currentTarget)[this.type](this.getDelegateOptions()).data(`bs.${this.type}`);
clearTimeout(self.timeout); clearTimeout(self.timeout);
@ -1102,7 +1144,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (this.options.animation) $tip.addClass('fade'); if (this.options.animation) $tip.addClass('fade');
let placement = typeof this.options.placement === 'function' let placement =
typeof this.options.placement === 'function'
? this.options.placement.call(this, $tip[0], this.$element[0]) ? this.options.placement.call(this, $tip[0], this.$element[0])
: this.options.placement; : this.options.placement;
@ -1110,12 +1153,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const autoPlace = autoToken.test(placement); const autoPlace = autoToken.test(placement);
if (autoPlace) placement = placement.replace(autoToken, '') || 'top'; if (autoPlace) placement = placement.replace(autoToken, '') || 'top';
$tip $tip.detach().css({ top: 0, left: 0, display: 'block' }).addClass(placement);
.detach()
.css({ top: 0, left: 0, display: 'block' })
.addClass(placement);
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element); this.options.container
? $tip.appendTo(this.options.container)
: $tip.insertAfter(this.$element);
const pos = this.getPosition(); const pos = this.getPosition();
const actualWidth = $tip[0].offsetWidth; const actualWidth = $tip[0].offsetWidth;
@ -1126,19 +1168,24 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const orgPlacement = placement; const orgPlacement = placement;
const docScroll = document.documentElement.scrollTop || document.body.scrollTop; const docScroll = document.documentElement.scrollTop || document.body.scrollTop;
const parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth(); const parentWidth =
const parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight(); this.options.container == 'body' ? window.innerWidth : $parent.outerWidth();
const parentHeight =
this.options.container == 'body' ? window.innerHeight : $parent.outerHeight();
const parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left; const parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left;
placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' placement =
: placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight
: placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' ? 'top'
: placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' : placement == 'top' && pos.top - docScroll - actualHeight < 0
? 'bottom'
: placement == 'right' && pos.right + actualWidth > parentWidth
? 'left'
: placement == 'left' && pos.left - actualWidth < parentLeft
? 'right'
: placement; : placement;
$tip $tip.removeClass(orgPlacement).addClass(placement);
.removeClass(orgPlacement)
.addClass(placement);
} }
const calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight); const calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight);
@ -1151,9 +1198,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}; };
$.support.transition && this.$tip.hasClass('fade') $.support.transition && this.$tip.hasClass('fade')
? $tip ? $tip.one($.support.transition.end, complete).emulateTransitionEnd(150)
.one($.support.transition.end, complete)
.emulateTransitionEnd(150)
: complete(); : complete();
} }
}; };
@ -1177,14 +1222,21 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// $.fn.offset doesn't round pixel values // $.fn.offset doesn't round pixel values
// so we use setOffset directly with our own function B-0 // so we use setOffset directly with our own function B-0
$.offset.setOffset($tip[0], $.extend({ $.offset.setOffset(
$tip[0],
$.extend(
{
using(props) { using(props) {
$tip.css({ $tip.css({
top: Math.round(props.top), top: Math.round(props.top),
left: Math.round(props.left), left: Math.round(props.left),
}); });
}, },
}, offset), 0); },
offset,
),
0,
);
$tip.addClass('in'); $tip.addClass('in');
@ -1219,7 +1271,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}; };
Tooltip.prototype.replaceArrow = function (delta, dimension, position) { Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
this.arrow().css(position, delta ? (`${50 * (1 - delta / dimension)}%`) : ''); this.arrow().css(position, delta ? `${50 * (1 - delta / dimension)}%` : '');
}; };
Tooltip.prototype.setContent = function () { Tooltip.prototype.setContent = function () {
@ -1247,9 +1299,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$tip.removeClass('in'); $tip.removeClass('in');
$.support.transition && this.$tip.hasClass('fade') $.support.transition && this.$tip.hasClass('fade')
? $tip ? $tip.one($.support.transition.end, complete).emulateTransitionEnd(150)
.one($.support.transition.end, complete)
.emulateTransitionEnd(150)
: complete(); : complete();
this.hoverState = null; this.hoverState = null;
@ -1259,7 +1309,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Tooltip.prototype.fixTitle = function () { Tooltip.prototype.fixTitle = function () {
const $e = this.$element; const $e = this.$element;
if ($e.attr('title') || typeof ($e.attr('data-original-title')) !== 'string') { if ($e.attr('title') || typeof $e.attr('data-original-title') !== 'string') {
$e.attr('data-original-title', $e.attr('title') || '').attr('title', ''); $e.attr('data-original-title', $e.attr('title') || '').attr('title', '');
} }
}; };
@ -1270,17 +1320,29 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Tooltip.prototype.getPosition = function () { Tooltip.prototype.getPosition = function () {
const el = this.$element[0]; const el = this.$element[0];
return $.extend({}, (typeof el.getBoundingClientRect === 'function') ? el.getBoundingClientRect() : { return $.extend(
{},
typeof el.getBoundingClientRect === 'function'
? el.getBoundingClientRect()
: {
width: el.offsetWidth, width: el.offsetWidth,
height: el.offsetHeight, height: el.offsetHeight,
}, this.$element.offset()); },
this.$element.offset(),
);
}; };
Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } return placement == 'bottom'
: placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 }
: placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : placement == 'top'
/* placement == 'right' */ : { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }; ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 }
: placement == 'left'
? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth }
: /* placement == 'right' */ {
top: pos.top + pos.height / 2 - actualHeight / 2,
left: pos.left + pos.width,
};
}; };
Tooltip.prototype.getTitle = function () { Tooltip.prototype.getTitle = function () {
@ -1288,18 +1350,19 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const $e = this.$element; const $e = this.$element;
const o = this.options; const o = this.options;
title = $e.attr('data-original-title') title =
|| (typeof o.title === 'function' ? o.title.call($e[0]) : o.title); $e.attr('data-original-title') ||
(typeof o.title === 'function' ? o.title.call($e[0]) : o.title);
return title; return title;
}; };
Tooltip.prototype.tip = function () { Tooltip.prototype.tip = function () {
return this.$tip = this.$tip || $(this.options.template); return (this.$tip = this.$tip || $(this.options.template));
}; };
Tooltip.prototype.arrow = function () { Tooltip.prototype.arrow = function () {
return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'); return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'));
}; };
Tooltip.prototype.validate = function () { Tooltip.prototype.validate = function () {
@ -1323,7 +1386,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
}; };
Tooltip.prototype.toggle = function (e) { Tooltip.prototype.toggle = function (e) {
const self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data(`bs.${this.type}`) : this; const self = e
? $(e.currentTarget)[this.type](this.getDelegateOptions()).data(`bs.${this.type}`)
: this;
self.tip().hasClass('in') ? self.leave(self) : self.enter(self); self.tip().hasClass('in') ? self.leave(self) : self.enter(self);
}; };
@ -1358,7 +1423,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$.fn.tooltip = old; $.fn.tooltip = old;
return this; return this;
}; };
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: popover.js v3.1.1 * Bootstrap: popover.js v3.1.1
@ -1382,7 +1447,8 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
placement: 'right', placement: 'right',
trigger: 'click', trigger: 'click',
content: '', content: '',
template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>', template:
'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
}); });
// NOTE: POPOVER EXTENDS tooltip.js // NOTE: POPOVER EXTENDS tooltip.js
@ -1402,9 +1468,9 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const content = this.getContent(); const content = this.getContent();
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title); $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
$tip.find('.popover-content')[// we use append for html objects to maintain js events $tip
this.options.html ? (typeof content === 'string' ? 'html' : 'append') : 'text' .find('.popover-content') // we use append for html objects to maintain js events
](content); [this.options.html ? (typeof content === 'string' ? 'html' : 'append') : 'text'](content);
$tip.removeClass('fade top bottom left right in'); $tip.removeClass('fade top bottom left right in');
@ -1421,14 +1487,14 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const $e = this.$element; const $e = this.$element;
const o = this.options; const o = this.options;
return $e.attr('data-content') return (
|| (typeof o.content === 'function' $e.attr('data-content') ||
? o.content.call($e[0]) (typeof o.content === 'function' ? o.content.call($e[0]) : o.content)
: o.content); );
}; };
Popover.prototype.arrow = function () { Popover.prototype.arrow = function () {
return this.$arrow = this.$arrow || this.tip().find('.arrow'); return (this.$arrow = this.$arrow || this.tip().find('.arrow'));
}; };
Popover.prototype.tip = function () { Popover.prototype.tip = function () {
@ -1462,7 +1528,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$.fn.popover = old; $.fn.popover = old;
return this; return this;
}; };
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: scrollspy.js v3.1.1 * Bootstrap: scrollspy.js v3.1.1
@ -1484,9 +1550,11 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
this.$body = $('body'); this.$body = $('body');
this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process); this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process);
this.options = $.extend({}, ScrollSpy.DEFAULTS, options); this.options = $.extend({}, ScrollSpy.DEFAULTS, options);
this.selector = `${this.options.target this.selector = `${
|| ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7 this.options.target ||
|| ''} .nav li > a`; ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) || // strip for ie7
''
} .nav li > a`;
this.offsets = $([]); this.offsets = $([]);
this.targets = $([]); this.targets = $([]);
this.activeTarget = null; this.activeTarget = null;
@ -1513,10 +1581,18 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
const href = $el.data('target') || $el.attr('href'); const href = $el.data('target') || $el.attr('href');
const $href = /^#./.test(href) && $(href); const $href = /^#./.test(href) && $(href);
return ($href return (
&& $href.length ($href &&
&& $href.is(':visible') $href.length &&
&& [[$href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href]]) || null; $href.is(':visible') && [
[
$href[offsetMethod]().top +
(!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()),
href,
],
]) ||
null
);
}) })
.sort((a, b) => a[0] - b[0]) .sort((a, b) => a[0] - b[0])
.each(function () { .each(function () {
@ -1542,33 +1618,25 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
return activeTarget != (i = targets[0]) && this.activate(i); return activeTarget != (i = targets[0]) && this.activate(i);
} }
for (i = offsets.length; i--;) { for (i = offsets.length; i--; ) {
activeTarget != targets[i] activeTarget != targets[i] &&
&& scrollTop >= offsets[i] scrollTop >= offsets[i] &&
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1]) (!offsets[i + 1] || scrollTop <= offsets[i + 1]) &&
&& this.activate(targets[i]); this.activate(targets[i]);
} }
}; };
ScrollSpy.prototype.activate = function (target) { ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target; this.activeTarget = target;
$(this.selector) $(this.selector).parentsUntil(this.options.target, '.active').removeClass('active');
.parentsUntil(this.options.target, '.active')
.removeClass('active');
const selector = `${this.selector const selector = `${this.selector}[data-target="${target}"],${this.selector}[href="${target}"]`;
}[data-target="${target}"],${
this.selector}[href="${target}"]`;
let active = $(selector) let active = $(selector).parents('li').addClass('active');
.parents('li')
.addClass('active');
if (active.parent('.dropdown-menu').length) { if (active.parent('.dropdown-menu').length) {
active = active active = active.closest('li.dropdown').addClass('active');
.closest('li.dropdown')
.addClass('active');
} }
active.trigger('activate.bs.scrollspy'); active.trigger('activate.bs.scrollspy');
@ -1609,7 +1677,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$spy.scrollspy($spy.data()); $spy.scrollspy($spy.data());
}); });
}); });
}(jQuery)); })(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: tab.js v3.1.1 * Bootstrap: tab.js v3.1.1
@ -1661,15 +1729,10 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
Tab.prototype.activate = function (element, container, callback) { Tab.prototype.activate = function (element, container, callback) {
const $active = container.find('> .active'); const $active = container.find('> .active');
const transition = callback const transition = callback && $.support.transition && $active.hasClass('fade');
&& $.support.transition
&& $active.hasClass('fade');
function next() { function next() {
$active $active.removeClass('active').find('> .dropdown-menu > .active').removeClass('active');
.removeClass('active')
.find('> .dropdown-menu > .active')
.removeClass('active');
element.addClass('active'); element.addClass('active');
@ -1687,11 +1750,7 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
callback && callback(); callback && callback();
} }
transition transition ? $active.one($.support.transition.end, next).emulateTransitionEnd(150) : next();
? $active
.one($.support.transition.end, next)
.emulateTransitionEnd(150)
: next();
$active.removeClass('in'); $active.removeClass('in');
}; };
@ -1724,11 +1783,15 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
// TAB DATA-API // TAB DATA-API
// ============ // ============
$(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) { $(document).on(
'click.bs.tab.data-api',
'[data-toggle="tab"], [data-toggle="pill"]',
function (e) {
e.preventDefault(); e.preventDefault();
$(this).tab('show'); $(this).tab('show');
}); },
}(jQuery)); );
})(jQuery);
/* ======================================================================== /* ========================================================================
* Bootstrap: affix.js v3.1.1 * Bootstrap: affix.js v3.1.1
@ -1788,9 +1851,15 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
if (typeof offsetTop === 'function') offsetTop = offset.top(this.$element); if (typeof offsetTop === 'function') offsetTop = offset.top(this.$element);
if (typeof offsetBottom === 'function') offsetBottom = offset.bottom(this.$element); if (typeof offsetBottom === 'function') offsetBottom = offset.bottom(this.$element);
const affix = this.unpin != null && (scrollTop + this.unpin <= position.top) ? false const affix =
: offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' this.unpin != null && scrollTop + this.unpin <= position.top
: offsetTop != null && (scrollTop <= offsetTop) ? 'top' : false; ? false
: offsetBottom != null &&
position.top + this.$element.height() >= scrollHeight - offsetBottom
? 'bottom'
: offsetTop != null && scrollTop <= offsetTop
? 'top'
: false;
if (this.affixed === affix) return; if (this.affixed === affix) return;
if (this.unpin) this.$element.css('top', ''); if (this.unpin) this.$element.css('top', '');
@ -1857,4 +1926,4 @@ if (typeof jQuery === 'undefined') { throw new Error('Bootstrap\'s JavaScript re
$spy.affix(data); $spy.affix(data);
}); });
}); });
}(jQuery)); })(jQuery);

File diff suppressed because one or more lines are too long

View File

@ -8,105 +8,186 @@
* *
* Original idea by: * Original idea by:
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/ */
/* /*
* One small change is: now keys are passed by object { keys: '...' } * One small change is: now keys are passed by object { keys: '...' }
* Might be useful, when you want to pass some other data to your handler * Might be useful, when you want to pass some other data to your handler
*/ */
function initHotKeyPluggin(jQuery){ function initHotKeyPluggin(jQuery) {
jQuery.hotkeys = { jQuery.hotkeys = {
version: "0.8", version: '0.8',
specialKeys: { specialKeys: {
8: "backspace", 9: "tab", 10: "return", 13: "enter", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", 8: 'backspace',
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", 9: 'tab',
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", 10: 'return',
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", 13: 'enter',
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", 16: 'shift',
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", 17: 'ctrl',
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 186: ";", 191: "/", 18: 'alt',
220: "\\", 222: "'", 224: "meta" 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',
}, },
shiftNums: { shiftNums: {
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", '`': '~',
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", 1: '!',
".": ">", "/": "?", "\\": "|" 2: '@',
} 3: '#',
4: '$',
5: '%',
6: '^',
7: '&',
8: '*',
9: '(',
0: ')',
'-': '_',
'=': '+',
';': ': ',
"'": '"',
',': '<',
'.': '>',
'/': '?',
'\\': '|',
},
}; };
function keyHandler( handleObj ) { function keyHandler(handleObj) {
if ( typeof handleObj.data === "string" ) { if (typeof handleObj.data === 'string') {
handleObj.data = { keys: handleObj.data }; handleObj.data = { keys: handleObj.data };
} }
// Only care when a possible input has been specified // Only care when a possible input has been specified
if ( !handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== "string" ) { if (!handleObj.data || !handleObj.data.keys || typeof handleObj.data.keys !== 'string') {
return; return;
} }
var origHandler = handleObj.handler, var origHandler = handleObj.handler,
keys = handleObj.data.keys.toLowerCase().split(" "), keys = handleObj.data.keys.toLowerCase().split(' '),
textAcceptingInputTypes = ["text", "password", "number", "email", "url", "range", "date", "month", "week", "time", "datetime", "datetime-local", "search", "color", "tel"]; textAcceptingInputTypes = [
'text',
'password',
'number',
'email',
'url',
'range',
'date',
'month',
'week',
'time',
'datetime',
'datetime-local',
'search',
'color',
'tel',
];
handleObj.handler = function( event ) { handleObj.handler = function (event) {
// Don't fire in text-accepting inputs that we didn't directly bind to // Don't fire in text-accepting inputs that we didn't directly bind to
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || if (
jQuery.inArray(event.target.type, textAcceptingInputTypes) > -1 ) ) { this !== event.target &&
(/textarea|select/i.test(event.target.nodeName) ||
jQuery.inArray(event.target.type, textAcceptingInputTypes) > -1)
) {
return; return;
} }
var special = jQuery.hotkeys.specialKeys[ event.keyCode ], var special = jQuery.hotkeys.specialKeys[event.keyCode],
character = String.fromCharCode( event.which ).toLowerCase(), character = String.fromCharCode(event.which).toLowerCase(),
modif = "", possible = {}; modif = '',
possible = {};
// check combinations (alt|ctrl|shift+anything) // check combinations (alt|ctrl|shift+anything)
if ( event.altKey && special !== "alt" ) { if (event.altKey && special !== 'alt') {
modif += "alt+"; modif += 'alt+';
} }
if ( event.ctrlKey && special !== "ctrl" ) { if (event.ctrlKey && special !== 'ctrl') {
modif += "ctrl+"; modif += 'ctrl+';
} }
// TODO: Need to make sure this works consistently across platforms // TODO: Need to make sure this works consistently across platforms
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) { if (event.metaKey && !event.ctrlKey && special !== 'meta') {
modif += "meta+"; modif += 'meta+';
} }
if ( event.shiftKey && special !== "shift" ) { if (event.shiftKey && special !== 'shift') {
modif += "shift+"; modif += 'shift+';
} }
if ( special ) { if (special) {
possible[ modif + special ] = true; possible[modif + special] = true;
} }
if ( character ) { if (character) {
possible[ modif + character ] = true; possible[modif + character] = true;
possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; possible[modif + jQuery.hotkeys.shiftNums[character]] = true;
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$" // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
if ( modif === "shift+" ) { if (modif === 'shift+') {
possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; possible[jQuery.hotkeys.shiftNums[character]] = true;
} }
} }
for ( var i = 0, l = keys.length; i < l; i++ ) { for (var i = 0, l = keys.length; i < l; i++) {
if ( possible[ keys[i] ] ) { if (possible[keys[i]]) {
return origHandler.apply( this, arguments ); return origHandler.apply(this, arguments);
} }
} }
}; };
} }
jQuery.each([ "keydown", "keyup", "keypress" ], function() { jQuery.each(['keydown', 'keyup', 'keypress'], function () {
jQuery.event.special[ this ] = { add: keyHandler }; jQuery.event.special[this] = { add: keyHandler };
}); });
}
};
export default initHotKeyPluggin; export default initHotKeyPluggin;

View File

@ -0,0 +1,15 @@
// Passive event listeners
function registerTouchHandler(jQuery) {
jQuery.event.special.touchstart = {
setup: function (_, ns, handle) {
this.addEventListener("touchstart", handle, { passive: true });
}
};
jQuery.event.special.touchmove = {
setup: function (_, ns, handle) {
this.addEventListener("touchmove", handle, { passive: true });
}
};
}
export default registerTouchHandler;

View File

@ -45,5 +45,20 @@
"homepage": "http://localhost:8080/react", "homepage": "http://localhost:8080/react",
"license": "https://wisemapping.atlassian.net/wiki/spaces/WS/pages/524357/WiseMapping+Public+License+Version+1.0+WPL", "license": "https://wisemapping.atlassian.net/wiki/spaces/WS/pages/524357/WiseMapping+Public+License+Version+1.0+WPL",
"version": "0.4.0", "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"
}
}
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "@wisemapping/core-js", "name": "@wisemapping/core-js",
"version": "0.4.0", "version": "0.4.1",
"description": "WiseMapping - Core Common Libraries", "description": "WiseMapping - Core Common Libraries",
"homepage": "http://www.wisemapping.org/", "homepage": "http://www.wisemapping.org/",
"license": "MIT", "license": "MIT",
@ -21,12 +21,12 @@
}, },
"private": false, "private": false,
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.6", "@babel/core": "^7.18.13",
"@babel/preset-env": "^7.14.7", "@babel/preset-env": "^7.14.7",
"babel-loader": "^8.2.2", "babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0-alpha.0", "clean-webpack-plugin": "^4.0.0-alpha.0",
"core-js": "^3.15.2", "core-js": "^3.15.2",
"webpack": "^5.44.0", "webpack": "^5.74.0",
"webpack-cli": "^4.7.2", "webpack-cli": "^4.7.2",
"webpack-merge": "^5.8.0" "webpack-merge": "^5.8.0"
}, },

View File

@ -8,7 +8,7 @@ module.exports = {
publicPath: '', publicPath: '',
library: { library: {
type: 'umd', type: 'umd',
} },
}, },
target: 'web', target: 'web',
optimization: { optimization: {
@ -19,17 +19,17 @@ module.exports = {
{ {
use: 'babel-loader', use: 'babel-loader',
test: /.js$/, test: /.js$/,
exclude: [ exclude: [/node_modules/],
/node_modules/,
]
}, },
], ],
}, },
resolve: { resolve: {
extensions: ['.js'], extensions: ['.js'],
}, },
plugins: [new CleanWebpackPlugin({ plugins: [
new CleanWebpackPlugin({
dangerouslyAllowCleanPatternsOutsideProject: true, dangerouslyAllowCleanPatternsOutsideProject: true,
dry: false, dry: false,
})], }),
],
}; };

View File

@ -5,7 +5,7 @@ const common = require('./webpack.common');
const devConfig = { const devConfig = {
mode: 'development', mode: 'development',
plugins: [new HotModuleReplacementPlugin()], plugins: [new HotModuleReplacementPlugin()],
devtool: 'eval-source-map' devtool: 'eval-source-map',
}; };
module.exports = merge(common, devConfig); module.exports = merge(common, devConfig);

View File

@ -1,6 +1,7 @@
{ {
"video": false, "video": false,
"videoUploadOnPasses": false, "videoUploadOnPasses": false,
"baseUrl": "http://localhost:8081" "baseUrl": "http://localhost:8081",
"includeShadowDom": true
} }

View File

@ -1,21 +1,30 @@
context('Playground', () => { context('Playground', () => {
it('viewmode page should match its snapshot', () => { it('viewmode page should match its snapshot', () => {
['welcome', 'sample1', 'sample2', 'sample3', 'sample4', 'sample5', 'sample6', 'complex', 'img-support', 'icon-sample'].forEach((mapId) => { [
'welcome',
'sample1',
'sample2',
'sample3',
'sample4',
'sample5',
'sample6',
'complex',
'img-support',
'icon-sample',
].forEach((mapId) => {
cy.visit(`/viewmode.html?id=${mapId}`); cy.visit(`/viewmode.html?id=${mapId}`);
cy.get('#mindplot.ready').should('exist'); cy.get('#mindmap-comp.ready').should('exist');
cy.matchImageSnapshot(`viewmode-${mapId}`); cy.matchImageSnapshot(`viewmode-${mapId}`);
}); });
}); });
it('the playground container.html page should match its snapshot', () => { it('the playground showcase.html page should match its snapshot', () => {
cy.visit('/container.html'); cy.visit('/showcase.html');
cy.getIframeBody() cy.getIframeBody().find('#mindmap-comp.ready').should('exist');
.find('#mindplot.ready')
.should('exist');
cy.matchImageSnapshot('container'); cy.matchImageSnapshot('container');
}); });
it('the playground editor.html page should match its snapshot', () => { it('the playground editor.html page should match its snapshot', () => {
cy.visit('/editor.html'); cy.visit('/editor.html');
cy.get('#mindplot.ready').should('exist'); cy.get('#mindmap-comp.ready').should('exist');
// TODO: why is the editor appearing twice in the snapshot? // TODO: why is the editor appearing twice in the snapshot?
cy.matchImageSnapshot('editor'); cy.matchImageSnapshot('editor');
}); });

View File

@ -18,7 +18,6 @@ if (Cypress.env('imageSnaphots')) {
} }
// https://www.cypress.io/blog/2020/02/12/working-with-iframes-in-cypress/ // https://www.cypress.io/blog/2020/02/12/working-with-iframes-in-cypress/
Cypress.Commands.add('getIframeBody', () => cy Cypress.Commands.add('getIframeBody', () =>
.get('iframe') cy.get('iframe').its('0.contentDocument.body').should('not.be.empty').then(cy.wrap),
.its('0.contentDocument.body').should('not.be.empty') );
.then(cy.wrap));

View 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

View File

@ -4,6 +4,18 @@
}, },
"editor.try-welcome-description": { "editor.try-welcome-description": {
"defaultMessage": "Melden Sie sich an, um kostenlos eine unbegrenzte Anzahl von Mindmaps zu erstellen, zu teilen und zu veröffentlichen." "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": { "login.signup": {
"defaultMessage": "Anmeldung" "defaultMessage": "Anmeldung"

View File

@ -1,9 +1,21 @@
{ {
"editor.try-welcome": { "editor.try-welcome": {
"defaultMessage": "This edition space showcases some of the mindmap editor capabilities !" "defaultMessage": "This edition space showcases some of the mindmap editor capabilities!"
}, },
"editor.try-welcome-description": { "editor.try-welcome-description": {
"defaultMessage": "Sign Up to start creating, sharing and publishing unlimited number of mindmaps for free." "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": { "login.signup": {
"defaultMessage": "Sign Up" "defaultMessage": "Sign Up"

View File

@ -4,6 +4,18 @@
}, },
"editor.try-welcome-description": { "editor.try-welcome-description": {
"defaultMessage": "Registrate para comenzar a crear, compartir y publicar una cantidad ilimitada de mapas mentales de forma gratuita." "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": { "login.signup": {
"defaultMessage": "Crear cuenta" "defaultMessage": "Crear cuenta"

View File

@ -1,9 +1,21 @@
{ {
"editor.try-welcome": { "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": { "editor.try-welcome-description": {
"defaultMessage": "Inscrivez-vous pour commencer à créer, partager et publier gratuitement un nombre illimité de cartes mentales." "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": { "login.signup": {
"defaultMessage": "S'inscrire" "defaultMessage": "S'inscrire"

View File

@ -4,6 +4,18 @@
}, },
"editor.try-welcome-description": { "editor.try-welcome-description": {
"defaultMessage": "Чтобы получить бесплатный неограниченный доступ — нужна только регистрация." "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": { "login.signup": {
"defaultMessage": "Регистрация" "defaultMessage": "Регистрация"

View File

@ -5,6 +5,18 @@
"editor.try-welcome-description": { "editor.try-welcome-description": {
"defaultMessage": "注册后可以免费创建、分享和发布无限数量的思维导图。" "defaultMessage": "注册后可以免费创建、分享和发布无限数量的思维导图。"
}, },
"editor.try-welcome-mobile": {
"defaultMessage": "这个版本空间展示了一些思维导图功能!"
},
"editor.try-welcome-description-mobile": {
"defaultMessage": "注册以开始免费创建、共享和发布无限数量的思维导图。 移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
},
"editor.edit-mobile": {
"defaultMessage": "移动设备注意事项."
},
"editor.edit-description-mobile": {
"defaultMessage": "移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
},
"login.signup": { "login.signup": {
"defaultMessage": "注册" "defaultMessage": "注册"
}, },

View File

@ -1,6 +1,6 @@
{ {
"name": "@wisemapping/editor", "name": "@wisemapping/editor",
"version": "0.4.1", "version": "0.4.2",
"main": "dist/editor.bundle.js", "main": "dist/editor.bundle.js",
"scripts": { "scripts": {
"build": "webpack --config webpack.prod.js", "build": "webpack --config webpack.prod.js",
@ -16,11 +16,9 @@
"license": "MIT", "license": "MIT",
"private": false, "private": false,
"devDependencies": { "devDependencies": {
"@babel/preset-env": "^7.16.11", "@babel/preset-env": "^7.18.6",
"@babel/preset-react": "^7.16.7", "@babel/preset-react": "^7.18.6",
"@formatjs/cli": "^4.8.1", "@formatjs/cli": "^4.8.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"@typescript-eslint/eslint-plugin": "^4.8.1", "@typescript-eslint/eslint-plugin": "^4.8.1",
"@typescript-eslint/parser": "^4.8.1", "@typescript-eslint/parser": "^4.8.1",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
@ -38,18 +36,18 @@
"ts-loader": "^8.0.11", "ts-loader": "^8.0.11",
"ts-node": "^9.0.0", "ts-node": "^9.0.0",
"typescript": "^4.1.2", "typescript": "^4.1.2",
"webpack": "^5.67.0", "webpack": "^5.74.0",
"webpack-dev-server": "^4.7.3", "webpack-dev-server": "^4.7.3",
"webpack-merge": "^5.8.0" "webpack-merge": "^5.8.0"
}, },
"dependencies": { "dependencies": {
"@types/styled-components": "^5.1.4", "@wisemapping/mindplot": "^5.0.1"
"@wisemapping/mindplot": "^5.0.1",
"styled-components": "^5.2.1"
}, },
"peerDependencies": { "peerDependencies": {
"@types/styled-components": "^5.1.26",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-intl": "^5.24.3" "react-intl": "^5.24.3",
"styled-components": "^5.3.5"
} }
} }

View File

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

View File

@ -15,6 +15,6 @@
top: 0; top: 0;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: rgba(0,0,0,0.5); background: rgba(0, 0, 0, 0.5);
z-index: 1000; z-index: 1000;
} }

File diff suppressed because one or more lines are too long

View File

@ -75,9 +75,7 @@ class BootstrapDialog extends Options {
)}</button>`, )}</button>`,
); );
footer.append(this.acceptButton); footer.append(this.acceptButton);
this.acceptButton this.acceptButton.unbind('click').on('click', this.options.onEventData, this.onAcceptClick);
.unbind('click')
.on('click', this.options.onEventData, this.onAcceptClick);
} }
if (this.options.removeButton) { if (this.options.removeButton) {
this.removeButton = $( this.removeButton = $(
@ -114,7 +112,7 @@ class BootstrapDialog extends Options {
return header; return header;
} }
onAcceptClick() { onAcceptClick(event) {
throw new Error('Unsupported operation'); throw new Error('Unsupported operation');
} }
@ -122,7 +120,7 @@ class BootstrapDialog extends Options {
// Overwrite default behaviour ... // Overwrite default behaviour ...
} }
onRemoveClick() { onRemoveClick(event) {
throw new Error('Unsupported operation'); throw new Error('Unsupported operation');
} }

View File

@ -49,10 +49,7 @@ class BootstrapDialogRequest extends BootstrapDialog {
this._native.find('.modal-body').load(url, () => { this._native.find('.modal-body').load(url, () => {
me.acceptButton.unbind('click').click(() => { me.acceptButton.unbind('click').click(() => {
if ( if ($defined(global.submitDialogForm) && typeof global.submitDialogForm === 'function') {
$defined(global.submitDialogForm)
&& typeof global.submitDialogForm === 'function'
) {
global.submitDialogForm(); global.submitDialogForm();
} }
}); });

View File

@ -0,0 +1,90 @@
import {
WidgetManager,
Topic,
LinkModel,
LinkIcon,
NoteModel,
NoteIcon,
$msg,
} from '@wisemapping/mindplot';
import LinkIconTooltip from './LinkIconTooltip';
import LinkEditor from './LinkEditor';
import FloatingTip from './FloatingTip';
import NoteEditor from './NoteEditor';
import $ from 'jquery';
export default class BootstrapWidgetManager extends WidgetManager {
createTooltipForLink(topic: Topic, linkModel: LinkModel, linkIcon: LinkIcon) {
const htmlImage = linkIcon.getImage().peer;
const toolTip = new LinkIconTooltip(linkIcon);
linkIcon.addEvent('mouseleave', (event) => {
setTimeout(() => {
if (!$('#linkPopover:hover').length) {
toolTip.hide();
}
event.stopPropagation();
}, 100);
});
$(htmlImage._native).mouseenter(() => {
toolTip.show();
});
}
showEditorForLink(topic: Topic, linkModel: LinkModel, linkIcon: LinkIcon) {
const editorModel = {
getValue(): string {
return topic.getLinkValue();
},
setValue(value: string) {
topic.setLinkValue(value);
},
};
topic.closeEditors();
const editor = new LinkEditor(editorModel);
editor.show();
}
private _buildTooltipContentForNote(noteModel: NoteModel): JQuery {
if ($('body').find('#textPopoverNote').length === 1) {
const text = $('body').find('#textPopoverNote');
text.text(noteModel.getText());
return text;
}
const result = $('<div id="textPopoverNote"></div>').css({ padding: '5px' });
const text = $('<div></div>').text(noteModel.getText()).css({
'white-space': 'pre-wrap',
'word-wrap': 'break-word',
});
result.append(text);
return result;
}
createTooltipForNote(topic: Topic, noteModel: NoteModel, noteIcon: NoteIcon) {
const htmlImage = noteIcon.getImage().peer;
const me = this;
const toolTip = new FloatingTip($(htmlImage._native), {
title: $msg('NOTE'),
content() {
return me._buildTooltipContentForNote(noteModel);
},
html: true,
placement: 'bottom',
destroyOnExit: true,
});
}
showEditorForNote(topic: Topic, noteModel: NoteModel, noteIcon: NoteIcon) {
const editorModel = {
getValue(): string {
return topic.getNoteValue();
},
setValue(value: string) {
topic.setNoteValue(value);
},
};
topic.closeEditors();
const editor = new NoteEditor(editorModel);
editor.show();
}
}

View File

@ -16,7 +16,7 @@
* limitations under the License. * limitations under the License.
*/ */
import merge from 'lodash/merge'; import merge from 'lodash/merge';
import Events from '../Events'; import Events from '../menu/Events';
const defaultOptions = { const defaultOptions = {
animation: true, animation: true,
@ -73,7 +73,7 @@ class FloatingTip extends Events {
if (this.addEvent) { if (this.addEvent) {
Object.keys(options).forEach((option) => { Object.keys(options).forEach((option) => {
if (options[option] instanceof Function && (/^on[A-Z]/).test(option)) { if (options[option] instanceof Function && /^on[A-Z]/.test(option)) {
this.addEvent(option, options[option]); this.addEvent(option, options[option]);
delete options[option]; delete options[option];
} }

View File

@ -17,17 +17,20 @@
*/ */
import $ from 'jquery'; import $ from 'jquery';
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import { $msg } from '../Messages'; import { $msg } from '@wisemapping/mindplot';
import BootstrapDialog from './bootstrap/BootstrapDialog'; import BootstrapDialog from './BootstrapDialog';
interface LinkEditorModel {
getValue(): string;
setValue(value: string): void;
}
class LinkEditor extends BootstrapDialog { class LinkEditor extends BootstrapDialog {
/** private form: JQuery<HTMLElement>;
* @constructs
* @param model private formSubmitted: boolean;
* @throws will throw an error if model is null or undefined
* @extends BootstrapDialog constructor(model: LinkEditorModel) {
*/
constructor(model) {
$assert(model, 'model can not be null'); $assert(model, 'model can not be null');
super($msg('LINK'), { super($msg('LINK'), {
cancelButton: true, cancelButton: true,
@ -37,13 +40,12 @@ class LinkEditor extends BootstrapDialog {
errorMessage: true, errorMessage: true,
onEventData: { model }, onEventData: { model },
}); });
this._model = model;
this.css({ margin: '150px auto' }); this.css({ margin: '150px auto' });
const panel = this._buildPanel(model); const panel = this._buildPanel(model);
this.setContent(panel); this.setContent(panel);
} }
_buildPanel(model) { protected _buildPanel(model: LinkEditorModel) {
const result = $('<div></div>').css('padding-top', '5px'); const result = $('<div></div>').css('padding-top', '5px');
this.form = $('<form></form>').attr({ this.form = $('<form></form>').attr({
action: 'none', action: 'none',
@ -80,8 +82,9 @@ class LinkEditor extends BootstrapDialog {
}); });
openButton.html($msg('OPEN_LINK')).css('margin-left', '0px'); openButton.html($msg('OPEN_LINK')).css('margin-left', '0px');
openButton.click(() => { openButton.on('click', () => {
window.open(input.val(), '_blank', 'status=1,width=700,height=450,resize=1'); const value = input.val() as string;
window.open(value, '_blank', 'status=1,width=700,height=450,resize=1');
}); });
const spanControl = $('<span class="input-group-btn"></span>').append(openButton); const spanControl = $('<span class="input-group-btn"></span>').append(openButton);
@ -90,13 +93,13 @@ class LinkEditor extends BootstrapDialog {
this.form.append(section); this.form.append(section);
const me = this; const me = this;
this.form.unbind('submit').submit((event) => { this.form.off('submit').on('submit', (event) => {
event.preventDefault(); event.preventDefault();
let inputValue = input.val(); let inputValue = input.val() as string;
inputValue = this.hasProtocol(inputValue) ? inputValue : `https://${inputValue}`; inputValue = this.hasProtocol(inputValue) ? inputValue : `https://${inputValue}`;
if (me.checkURL(inputValue)) { if (me.checkURL(inputValue)) {
me.cleanError(); me.cleanError();
if (inputValue != null && $.trim(inputValue) !== '') { if (inputValue !== null && inputValue.trim() !== '') {
model.setValue(inputValue); model.setValue(inputValue);
} }
me.close(); me.close();
@ -115,18 +118,19 @@ class LinkEditor extends BootstrapDialog {
* checks whether the input is a valid url * checks whether the input is a valid url
* @return {Boolean} true if the url is valid * @return {Boolean} true if the url is valid
*/ */
checkURL(url) { 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; const regex =
return (regex.test(url)); /^(http|https):\/\/[a-z0-9]+([-.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?(\/.*)?$/i;
return regex.test(url);
} }
/** /**
* checks whether the input is a valid url * checks whether the input is a valid url
* @return {Boolean} true if the url is valid * @return {Boolean} true if the url is valid
*/ */
hasProtocol(url) { private hasProtocol(url: string): boolean {
const regex = /^(http|https):\/\//i; const regex = /^(http|https):\/\//i;
return (regex.test(url)); return regex.test(url);
} }
/** /**
@ -134,7 +138,7 @@ class LinkEditor extends BootstrapDialog {
* triggered when the user clicks the accept button - submits the url input * triggered when the user clicks the accept button - submits the url input
* @param event * @param event
*/ */
onAcceptClick(event) { onAcceptClick(event: Event): void {
this.formSubmitted = false; this.formSubmitted = false;
$('#linkFormId').trigger('submit'); $('#linkFormId').trigger('submit');
if (!this.formSubmitted) { if (!this.formSubmitted) {
@ -146,7 +150,7 @@ class LinkEditor extends BootstrapDialog {
* overrides parent method * overrides parent method
* sets the url input on focus * sets the url input on focus
*/ */
onDialogShown() { onDialogShown(): void {
$(this).find('#inputUrl').focus(); $(this).find('#inputUrl').focus();
} }

View File

@ -17,11 +17,13 @@
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import $ from 'jquery'; import $ from 'jquery';
import { $msg } from '../Messages'; import { LinkIcon } from '@wisemapping/mindplot';
import { LinkModel } from '@wisemapping/mindplot';
import { $msg } from '@wisemapping/mindplot';
import FloatingTip from './FloatingTip'; import FloatingTip from './FloatingTip';
class LinkIconTooltip extends FloatingTip { class LinkIconTooltip extends FloatingTip {
constructor(linkIcon) { constructor(linkIcon: LinkIcon) {
$assert(linkIcon, 'linkIcon can not be null'); $assert(linkIcon, 'linkIcon can not be null');
const nativeElement = $(linkIcon.getImage().peer._native); const nativeElement = $(linkIcon.getImage().peer._native);
super(nativeElement, { super(nativeElement, {
@ -33,52 +35,29 @@ class LinkIconTooltip extends FloatingTip {
placement: 'bottom', placement: 'bottom',
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>',
destroyOnExit: true, destroyOnExit: true,
}); });
} }
static _buildContent(linkIcon) { private static _buildContent(linkIcon: LinkIcon): JQuery<HTMLElement> {
const url = linkIcon.getModel().getUrl(); const model = linkIcon.getModel() as LinkModel;
const url = model.getUrl();
const linkText = `${url}`; const linkText = `${url}`;
const linkPreview = `https://free.pagepeeker.com/v2/thumbs.php?size=m&url=${url}`;
const result = $('<div></div>').css({ const result = $('<div></div>').css({
padding: '5px', padding: '5px',
width: '100%', width: '100%',
}); });
const text = $('<div id="linkPopoverUrl"></div>').text(linkText)
.css({
'white-space': 'pre-wrap',
'word-wrap': 'break-word',
});
result.append(text);
const imgContainer = $('<div></div>')
.css({
width: '100%',
textAlign: 'right',
'padding-bottom': '5px',
'padding-top': '5px',
});
const img = $('<img id="linkPopoverPreview">')
.prop('src', linkPreview)
.prop('img', url)
.prop('alt', url);
img.css('padding', '5px');
const link = $('<a id="linkPopoverAnchor"></a>').attr({ const link = $('<a id="linkPopoverAnchor"></a>').attr({
href: url, href: url,
alt: 'Open in new window ...', alt: 'Open in new window ...',
target: '_blank', target: '_blank',
}); });
link.append(img); link.html(linkText);
imgContainer.append(link); result.append(link);
result.append(imgContainer);
return result; return result;
} }
} }

View File

@ -18,10 +18,15 @@
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import $ from 'jquery'; import $ from 'jquery';
import BootstrapDialog from '../../../../editor/src/classes/bootstrap/BootstrapDialog'; import BootstrapDialog from '../../../../editor/src/classes/bootstrap/BootstrapDialog';
import { $msg } from '../Messages'; import { $msg } from '@wisemapping/mindplot';
interface NoteEditorModel {
getValue(): string;
setValue(value: string): void;
}
class NoteEditor extends BootstrapDialog { class NoteEditor extends BootstrapDialog {
constructor(model) { constructor(model: NoteEditorModel) {
$assert(model, 'model can not be null'); $assert(model, 'model can not be null');
super($msg('NOTE'), { super($msg('NOTE'), {
cancelButton: true, cancelButton: true,
@ -30,13 +35,12 @@ class NoteEditor extends BootstrapDialog {
removeButton: typeof model.getValue() !== 'undefined', removeButton: typeof model.getValue() !== 'undefined',
onEventData: { model }, onEventData: { model },
}); });
this._model = model;
this.css({ margin: '150px auto' }); this.css({ margin: '150px auto' });
const panel = this._buildPanel(model); const panel = this._buildPanel(model);
this.setContent(panel); this.setContent(panel);
} }
_buildPanel(model) { _buildPanel(model: NoteEditorModel) {
const result = $('<div></div>').css('padding-top', '5px'); const result = $('<div></div>').css('padding-top', '5px');
const form = $('<form></form>').attr({ const form = $('<form></form>').attr({
@ -68,20 +72,20 @@ class NoteEditor extends BootstrapDialog {
return result; return result;
} }
onAcceptClick(event) { onAcceptClick(event): void {
event.data.dialog._submitForm(event.data.model); event.data.dialog._submitForm(event.data.model);
} }
_submitForm(model) { _submitForm(model: NoteEditorModel) {
const textarea = this._native.find('textarea'); const textarea = this._native.find('textarea');
if (textarea.val()) { if (textarea.val()) {
model.setValue(textarea.val()); model.setValue(textarea.val() as string);
} }
this.close(); this.close();
} }
onDialogShown() { onDialogShown() {
$(this).find('textarea').focus(); $(this).find('textarea').trigger('focus');
} }
onRemoveClick(event) { onRemoveClick(event) {

View File

@ -5,7 +5,6 @@ import DE from './../../compiled-lang/de.json';
import RU from './../../compiled-lang/ru.json'; import RU from './../../compiled-lang/ru.json';
import ZH from './../../compiled-lang/zh.json'; import ZH from './../../compiled-lang/zh.json';
class I18nMsg { class I18nMsg {
static loadLocaleData(locale: string) { static loadLocaleData(locale: string) {
switch (locale) { switch (locale) {

View File

@ -96,26 +96,113 @@ export const buildHtml = () => {
const palettes = [ const palettes = [
{ {
id: ':3p', id: ':3p',
colors: [['(0, 0, 0)', '(68, 68, 68)', '(102, 102, 102)', '(153, 153, 153)', '(204, 204, 204)', '(238, 238, 238)', '(243, 243, 243)', '(254, 255, 255)']], colors: [
[
'(0, 0, 0)',
'(68, 68, 68)',
'(102, 102, 102)',
'(153, 153, 153)',
'(204, 204, 204)',
'(238, 238, 238)',
'(243, 243, 243)',
'(254, 255, 255)',
],
],
}, },
{ {
id: '3q', id: '3q',
colors: [['(255, 0, 0)', '(255, 153, 0)', '(255, 255, 0)', '(0, 255, 0)', '(0, 255, 255)', '(0, 0, 255)', '(153, 0, 255)', '(255, 0, 255)']], colors: [
[
'(255, 0, 0)',
'(255, 153, 0)',
'(255, 255, 0)',
'(0, 255, 0)',
'(0, 255, 255)',
'(0, 0, 255)',
'(153, 0, 255)',
'(255, 0, 255)',
],
],
}, },
{ {
id: '3r', id: '3r',
colors: [ colors: [
['(244, 204, 204)', '(252, 229, 205)', '(255, 242, 204)', '(217, 234, 211)', '(208, 224, 227)', '(207, 226, 243)', '(217, 210, 233)', '(234, 209, 220)'], [
['(234, 153, 153)', '(249, 203, 156)', '(255, 229, 153)', '(182, 215, 168)', '(162, 196, 201)', '(159, 197, 232)', '(180, 167, 214)', '(213, 166, 189)'], '(244, 204, 204)',
['(224, 102, 102)', '(246, 178, 107)', '(255, 217, 102)', '(147, 196, 125)', '(118, 165, 175)', '(111, 168, 220)', '(142, 124, 195)', '(194, 123, 160)'], '(252, 229, 205)',
['(204, 0, 0)', '(230, 145, 56)', '(241, 194, 50)', '(106, 168, 79)', '(69, 129, 142)', '(61, 133, 198)', '(103, 78, 167)', '(166, 77, 121)'], '(255, 242, 204)',
['(153, 0, 0)', '(180, 95, 6)', '(191, 144, 0)', '(56, 118, 29)', '(19, 79, 92)', '(11, 83, 148)', '(53, 28, 117)', '(116, 27, 71)'], '(217, 234, 211)',
['(102, 0, 0)', '(120, 63, 4)', '(127, 96, 0)', '(39, 78, 19)', '(12, 52, 61)', '(7, 55, 99)', '(32, 18, 77)', '(76, 17, 48)'], '(208, 224, 227)',
'(207, 226, 243)',
'(217, 210, 233)',
'(234, 209, 220)',
],
[
'(234, 153, 153)',
'(249, 203, 156)',
'(255, 229, 153)',
'(182, 215, 168)',
'(162, 196, 201)',
'(159, 197, 232)',
'(180, 167, 214)',
'(213, 166, 189)',
],
[
'(224, 102, 102)',
'(246, 178, 107)',
'(255, 217, 102)',
'(147, 196, 125)',
'(118, 165, 175)',
'(111, 168, 220)',
'(142, 124, 195)',
'(194, 123, 160)',
],
[
'(204, 0, 0)',
'(230, 145, 56)',
'(241, 194, 50)',
'(106, 168, 79)',
'(69, 129, 142)',
'(61, 133, 198)',
'(103, 78, 167)',
'(166, 77, 121)',
],
[
'(153, 0, 0)',
'(180, 95, 6)',
'(191, 144, 0)',
'(56, 118, 29)',
'(19, 79, 92)',
'(11, 83, 148)',
'(53, 28, 117)',
'(116, 27, 71)',
],
[
'(102, 0, 0)',
'(120, 63, 4)',
'(127, 96, 0)',
'(39, 78, 19)',
'(12, 52, 61)',
'(7, 55, 99)',
'(32, 18, 77)',
'(76, 17, 48)',
],
], ],
}, },
{ {
id: '2p', id: '2p',
colors: [['(255, 255, 255)', '(224, 229, 239)', '(80, 157, 192)', '(57, 113, 177)', '(2, 59, 185)', '(244, 184, 45)', '(241, 163, 39)', '(82, 92, 97)']], colors: [
[
'(255, 255, 255)',
'(224, 229, 239)',
'(80, 157, 192)',
'(57, 113, 177)',
'(2, 59, 185)',
'(244, 184, 45)',
'(241, 163, 39)',
'(82, 92, 97)',
],
],
}, },
]; ];

View File

@ -21,7 +21,8 @@ import ToolbarPaneItem from './ToolbarPaneItem';
import { buildHtml, css } from './ColorPaletteHtml'; import { buildHtml, css } from './ColorPaletteHtml';
// rgbToHex implementation from https://stackoverflow.com/a/3627747/58128 // rgbToHex implementation from https://stackoverflow.com/a/3627747/58128
export const rgb2hex = (rgb) => `#${rgb export const rgb2hex = (rgb) =>
`#${rgb
.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/) .match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/)
.slice(1) .slice(1)
.map((n) => parseInt(n, 10).toString(16).padStart(2, '0')) .map((n) => parseInt(n, 10).toString(16).padStart(2, '0'))
@ -71,9 +72,7 @@ class ColorPalettePanel extends ToolbarPaneItem {
const panelElem = this.getPanelElem(); const panelElem = this.getPanelElem();
// Clear selected cell based on the color ... // Clear selected cell based on the color ...
panelElem panelElem.find("td[class='palette-cell palette-cell-selected']").attr('class', 'palette-cell');
.find("td[class='palette-cell palette-cell-selected']")
.attr('class', 'palette-cell');
// Mark the cell as selected ... // Mark the cell as selected ...
const colorCells = panelElem.find('div[class=palette-colorswatch]'); const colorCells = panelElem.find('div[class=palette-colorswatch]');

View File

@ -48,9 +48,9 @@ class Events {
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) => {
fn.apply(this, args); fn.apply(this, args);
})); });
return this; return this;
} }

View File

@ -22,7 +22,20 @@ class FontFamilyPanel extends ListToolbarPanel {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
buildPanel() { buildPanel() {
const content = $("<div class='toolbarPanel' id='fontFamilyPanel'></div>"); const content = $("<div class='toolbarPanel' id='fontFamilyPanel'></div>");
const list = ['Arial', 'Baskerville', 'Tahoma', 'Limunari', 'Brush Script MT', 'Verdana', 'Times', 'Cursive', 'Fantasy', 'Perpetua', 'Brush Script', 'Copperplate'] const list = [
'Arial',
'Baskerville',
'Tahoma',
'Limunari',
'Brush Script MT',
'Verdana',
'Times',
'Cursive',
'Fantasy',
'Perpetua',
'Brush Script',
'Copperplate',
]
.sort() .sort()
.map((f) => `<div model="${f}" class="toolbarPanelLink" style="font-family:${f};">${f}</div>`) .map((f) => `<div model="${f}" class="toolbarPanelLink" style="font-family:${f};">${f}</div>`)
.join('\n'); .join('\n');

View File

@ -22,11 +22,12 @@ class FontSizePanel extends ListToolbarPanel {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
buildPanel() { buildPanel() {
const content = $("<div class='toolbarPanel' id='fontSizePanel'></div>"); const content = $("<div class='toolbarPanel' id='fontSizePanel'></div>");
content[0].innerHTML = '' content[0].innerHTML =
+ '<div id="small" model="6" style="font-size:8px">Small</div>' '' +
+ '<div id="normal" model="8" style="font-size:12px">Normal</div>' '<div id="small" model="6" style="font-size:8px">Small</div>' +
+ '<div id="large" model="10" style="font-size:15px">Large</div>' '<div id="normal" model="8" style="font-size:12px">Normal</div>' +
+ '<div id="huge" model="15" style="font-size:24px">Huge</div>'; '<div id="large" model="10" style="font-size:15px">Large</div>' +
'<div id="huge" model="15" style="font-size:24px">Huge</div>';
return content; return content;
} }

View File

@ -19,15 +19,16 @@ import $ from 'jquery';
import ToolbarPaneItem from './ToolbarPaneItem'; import ToolbarPaneItem from './ToolbarPaneItem';
import { ImageIcon } from '@wisemapping/mindplot'; import { ImageIcon } from '@wisemapping/mindplot';
class IconPanel extends ToolbarPaneItem { class IconPanel extends ToolbarPaneItem {
_updateSelectedItem() { _updateSelectedItem() {
return this.getPanelElem(); return this.getPanelElem();
} }
buildPanel() { buildPanel() {
const content = $('<div class="toolbarPanel" id="IconsPanel"></div>') const content = $('<div class="toolbarPanel" id="IconsPanel"></div>').css({
.css({ width: 295, height: 305 }); width: 295,
height: 305,
});
content.on('click', (event) => { content.on('click', (event) => {
event.stopPropagation(); event.stopPropagation();
}); });
@ -37,7 +38,7 @@ class IconPanel extends ToolbarPaneItem {
for (let i = 0; i < ImageIcon.prototype.ICON_FAMILIES.length; i += 1) { for (let i = 0; i < ImageIcon.prototype.ICON_FAMILIES.length; i += 1) {
const familyIcons = ImageIcon.prototype.ICON_FAMILIES[i].icons; const familyIcons = ImageIcon.prototype.ICON_FAMILIES[i].icons;
for (let j = 0; j < familyIcons.length; j += 1) { for (let j = 0; j < familyIcons.length; j += 1) {
if ((count % 12) === 0) { if (count % 12 === 0) {
familyContent = $('<div></div>'); familyContent = $('<div></div>');
content.append(familyContent); content.append(familyContent);
} }
@ -52,10 +53,10 @@ class IconPanel extends ToolbarPaneItem {
const panel = this; const panel = this;
const model = this.getModel(); const model = this.getModel();
img.on('click', ((event) => { img.on('click', (event) => {
model.setValue($(event.target).attr('id')); model.setValue($(event.target).attr('id'));
panel.hide(); panel.hide();
})); });
count += 1; count += 1;
} }

View File

@ -18,7 +18,6 @@
import BootstrapDialog from '../bootstrap/BootstrapDialog'; import BootstrapDialog from '../bootstrap/BootstrapDialog';
import { $msg } from '@wisemapping/mindplot'; import { $msg } from '@wisemapping/mindplot';
class KeyboardShortcutDialog extends BootstrapDialog { class KeyboardShortcutDialog extends BootstrapDialog {
constructor() { constructor() {
super($msg('SHORTCUTS'), { super($msg('SHORTCUTS'), {
@ -42,8 +41,8 @@ class KeyboardShortcutDialog extends BootstrapDialog {
<tbody> <tbody>
<tr> <tr>
<td>${$msg('SAVE_CHANGES')}</td> <td>${$msg('SAVE_CHANGES')}</td>
<td>Ctrl + s</td> <td>${$msg('CTRL')} + S</td>
<td> + s</td> <td> + S</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('CREATE_SIBLING_TOPIC')}</td> <td>${$msg('CREATE_SIBLING_TOPIC')}</td>
@ -52,12 +51,12 @@ class KeyboardShortcutDialog extends BootstrapDialog {
</tr> </tr>
<tr> <tr>
<td>${$msg('CREATE_CHILD_TOPIC')}</td> <td>${$msg('CREATE_CHILD_TOPIC')}</td>
<td>Insert / Tab</td> <td>${$msg('K_INSERT')} / Tab</td>
<td> + Enter / Tab</td> <td> + Enter / Tab</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('DELETE_TOPIC')}</td> <td>${$msg('DELETE_TOPIC')}</td>
<td>Delete</td> <td>${$msg('K_DELETE')}</td>
<td>Delete</td> <td>Delete</td>
</tr> </tr>
<tr> <tr>
@ -67,19 +66,19 @@ class KeyboardShortcutDialog extends BootstrapDialog {
</tr> </tr>
<tr> <tr>
<td>${$msg('MULTIPLE_LINES')}</td> <td>${$msg('MULTIPLE_LINES')}</td>
<td>Ctrl + Enter</td> <td>${$msg('CTRL')} + Enter</td>
<td> + Enter</td> <td> + Enter</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('COPY_AND_PASTE_TOPICS')}</td> <td>${$msg('COPY_AND_PASTE_TOPICS')}</td>
<td>Ctrl + c/Ctrl + v</td> <td>${$msg('CTRL')} + C / ${$msg('CTRL')} + V</td>
<td> + c/ + v</td> <td> + C / + V</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('COLLAPSE_CHILDREN')}</td> <td>${$msg('COLLAPSE_CHILDREN')}</td>
<td>Space bar</td> <td>${$msg('SPACE_BAR')}</td>
<td>Space bar</td> <td>${$msg('SPACE_BAR')}</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('TOPIC_NAVIGATION')}</td> <td>${$msg('TOPIC_NAVIGATION')}</td>
@ -88,23 +87,23 @@ class KeyboardShortcutDialog extends BootstrapDialog {
</tr> </tr>
<tr> <tr>
<td>${$msg('SELECT_MULTIPLE_NODES')}</td> <td>${$msg('SELECT_MULTIPLE_NODES')}</td>
<td>Ctrl + Mouse Click</td> <td>${$msg('CTRL')} + ${$msg('MOUSE_CLICK')}</td>
<td>Ctrl + Mouse Click</td> <td>${$msg('CTRL')} + ${$msg('MOUSE_CLICK')}</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('UNDO_EDITION')}</td> <td>${$msg('UNDO_EDITION')}</td>
<td>Ctrl + z</td> <td>${$msg('CTRL')} + Z</td>
<td> + z</td> <td> + Z</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('REDO_EDITION')}</td> <td>${$msg('REDO_EDITION')}</td>
<td>Ctrl + Shift + z</td> <td>${$msg('CTRL')} + Shift + Z</td>
<td> + Shift + z</td> <td> + Shift + Z</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('SELECT_ALL_TOPIC')}</td> <td>${$msg('SELECT_ALL_TOPIC')}</td>
<td>Ctrl + a</td> <td>${$msg('CTRL')} + A</td>
<td> + a</td> <td> + A</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('CANCEL_TEXT_CHANGES')}</td> <td>${$msg('CANCEL_TEXT_CHANGES')}</td>
@ -113,28 +112,28 @@ class KeyboardShortcutDialog extends BootstrapDialog {
</tr> </tr>
<tr> <tr>
<td>${$msg('DESELECT_ALL_TOPIC')}</td> <td>${$msg('DESELECT_ALL_TOPIC')}</td>
<td>Ctrl + Shift + a</td> <td>${$msg('CTRL')} + Shift + A</td>
<td> + Shift + a</td> <td> + Shift + A</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('CHANGE_TEXT_ITALIC')}</td> <td>${$msg('CHANGE_TEXT_ITALIC')}</td>
<td>Ctrl + i</td> <td>${$msg('CTRL')} + I</td>
<td> + i</td> <td> + I</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('CHANGE_TEXT_BOLD')}</td> <td>${$msg('CHANGE_TEXT_BOLD')}</td>
<td>Ctrl + b</td> <td>${$msg('CTRL')} + B</td>
<td> + b</td> <td> + B</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('TOPIC_NOTE')}</td> <td>${$msg('TOPIC_NOTE')}</td>
<td>Ctrl + k</td> <td>${$msg('CTRL')} + K</td>
<td> + k</td> <td> + K</td>
</tr> </tr>
<tr> <tr>
<td>${$msg('TOPIC_LINK')}</td> <td>${$msg('TOPIC_LINK')}</td>
<td>Ctrl + l</td> <td>${$msg('CTRL')} + L</td>
<td> + l</td> <td> + L</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -17,7 +17,7 @@
*/ */
import $ from 'jquery'; import $ from 'jquery';
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import FloatingTip from '@wisemapping/mindplot/src/components/widget/FloatingTip'; import FloatingTip from '../bootstrap/FloatingTip';
class KeyboardShortcutTooltip extends FloatingTip { class KeyboardShortcutTooltip extends FloatingTip {
constructor(buttonElem, text) { constructor(buttonElem, text) {
@ -36,7 +36,8 @@ class KeyboardShortcutTooltip extends FloatingTip {
html: true, html: true,
placement: 'bottom', placement: 'bottom',
className: 'keyboardShortcutTip', className: 'keyboardShortcutTip',
template: '<div class="popover popoverBlack" role="tooltip"><div class="arrow arrowBlack"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>', template:
'<div class="popover popoverBlack" role="tooltip"><div class="arrow arrowBlack"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>',
}); });
tipDiv.on('click', (e) => { tipDiv.on('click', (e) => {
tipDiv.trigger('mouseleave', e); tipDiv.trigger('mouseleave', e);

View File

@ -43,7 +43,9 @@ class ListToolbarPanel extends ToolbarPaneItem {
const menuElems = panelElem.find('div'); const menuElems = panelElem.find('div');
const value = this.getModel().getValue(); const value = this.getModel().getValue();
menuElems.each((index, elem) => { menuElems.each((index, elem) => {
const elemValue = $defined($(elem).attr('model')) ? $(elem).attr('model') : $(elem).attr('id'); const elemValue = $defined($(elem).attr('model'))
? $(elem).attr('model')
: $(elem).attr('id');
$assert(elemValue, 'elemValue can not be null'); $assert(elemValue, 'elemValue can not be null');
if (elemValue === value) $(elem).attr('class', 'toolbarPanelLinkSelectedLink'); if (elemValue === value) $(elem).attr('class', 'toolbarPanelLinkSelectedLink');
else $(elem).attr('class', 'toolbarPanelLink'); else $(elem).attr('class', 'toolbarPanelLink');

View File

@ -61,7 +61,9 @@ class Menu extends IMenu {
this._addButton('position', false, false, () => { this._addButton('position', false, false, () => {
designer.zoomToFit(); 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 ... // Edition actions ...
if (!readOnly) { if (!readOnly) {
@ -181,7 +183,9 @@ class Menu extends IMenu {
designer.changeBorderColor(hex); 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')); Menu._registerTooltip('topicBorder', $msg('TOPIC_BORDER_COLOR'));
const fontColorModel = { const fontColorModel = {
@ -211,7 +215,7 @@ class Menu extends IMenu {
if (undoButton) { if (undoButton) {
undoButton.disable(); undoButton.disable();
} }
Menu._registerTooltip('undoEdition', $msg('UNDO')); Menu._registerTooltip('undoEdition', $msg('UNDO'), $msg('CTRL') + ' + Z');
const redoButton = this._addButton('redoEdition', false, false, () => { const redoButton = this._addButton('redoEdition', false, false, () => {
designer.redo(); designer.redo();
@ -219,7 +223,7 @@ class Menu extends IMenu {
if (redoButton) { if (redoButton) {
redoButton.disable(); redoButton.disable();
} }
Menu._registerTooltip('redoEdition', $msg('REDO')); Menu._registerTooltip('redoEdition', $msg('REDO'), $msg('CTRL') + ' + Shift + Z');
if (redoButton && undoButton) { if (redoButton && undoButton) {
designer.addEvent('modelUpdate', (event) => { designer.addEvent('modelUpdate', (event) => {
@ -244,7 +248,7 @@ class Menu extends IMenu {
this._addButton('deleteTopic', true, true, () => { this._addButton('deleteTopic', true, true, () => {
designer.deleteSelectedEntities(); designer.deleteSelectedEntities();
}); });
Menu._registerTooltip('deleteTopic', $msg('TOPIC_DELETE')); Menu._registerTooltip('deleteTopic', $msg('TOPIC_DELETE'), $msg('K_DELETE'));
this._addButton('topicLink', true, false, () => { this._addButton('topicLink', true, false, () => {
designer.addLink(); designer.addLink();
@ -264,22 +268,20 @@ class Menu extends IMenu {
this._addButton('fontBold', true, false, () => { this._addButton('fontBold', true, false, () => {
designer.changeFontWeight(); designer.changeFontWeight();
}); });
Menu._registerTooltip('fontBold', $msg('FONT_BOLD'), 'meta+B'); Menu._registerTooltip('fontBold', $msg('FONT_BOLD'), $msg('CTRL') + ' + B');
this._addButton('fontItalic', true, false, () => { this._addButton('fontItalic', true, false, () => {
designer.changeFontStyle(); designer.changeFontStyle();
}); });
Menu._registerTooltip('fontItalic', $msg('FONT_ITALIC'), 'meta+I'); Menu._registerTooltip('fontItalic', $msg('FONT_ITALIC'), $msg('CTRL') + ' + I');
if (!readOnly) { if (!readOnly) {
// Register action on save ... // Register action on save ...
const saveElem = $('#save'); const saveElem = $('#save');
this._addButton('save', false, false, this._addButton('save', false, false, () => {
() => {
this.save(saveElem, designer, true); this.save(saveElem, designer, true);
}); });
Menu._registerTooltip('save', $msg('SAVE')); Menu._registerTooltip('save', $msg('SAVE'), $msg('CTRL') + ' + S');
// Register unload save ... // Register unload save ...
window.addEventListener('beforeunload', () => { window.addEventListener('beforeunload', () => {
@ -290,13 +292,11 @@ class Menu extends IMenu {
}); });
// Autosave on a fixed period of time ... // Autosave on a fixed period of time ...
setInterval( setInterval(() => {
() => {
if (this.isSaveRequired()) { if (this.isSaveRequired()) {
this.save(saveElem, designer, false); this.save(saveElem, designer, false);
} }
}, 10000, }, 10000);
);
} }
} }
@ -394,10 +394,14 @@ class Menu extends IMenu {
// Register Events ... // Register Events ...
let result = null; let result = null;
if ($(`#${buttonId}`)) { if ($(`#${buttonId}`)) {
const button = new ToolbarItem(buttonId, ((event) => { const button = new ToolbarItem(
buttonId,
(event) => {
fn(event); fn(event);
this.clear(); this.clear();
}), { topicAction: isTopic, relAction: isRelationship }); },
{ topicAction: isTopic, relAction: isRelationship },
);
this._toolbarElems.push(button); this._toolbarElems.push(button);
result = button; result = button;
@ -409,7 +413,8 @@ class Menu extends IMenu {
if ($(`#${buttonId}`)) { if ($(`#${buttonId}`)) {
let tooltip = text; let tooltip = text;
if (shortcut) { if (shortcut) {
const platformedShortcut = navigator.appVersion.indexOf('Mac') !== -1 const platformedShortcut =
navigator.appVersion.indexOf('Mac') !== -1
? shortcut.replace('meta+', '⌘') ? shortcut.replace('meta+', '⌘')
: shortcut.replace('meta+', 'ctrl+'); : shortcut.replace('meta+', 'ctrl+');
tooltip = `${tooltip} (${platformedShortcut})`; tooltip = `${tooltip} (${platformedShortcut})`;

View File

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

View File

@ -5,6 +5,18 @@
"value": "Teilen" "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": [ "editor.try-welcome": [
{ {
"type": 0, "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." "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": [ "login.signup": [
{ {
"type": 0, "type": 0,

View File

@ -5,10 +5,22 @@
"value": "Share" "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": [ "editor.try-welcome": [
{ {
"type": 0, "type": 0,
"value": "This edition space showcases some of the mindmap editor capabilities !" "value": "This edition space showcases some of the mindmap editor capabilities!"
} }
], ],
"editor.try-welcome-description": [ "editor.try-welcome-description": [
@ -17,6 +29,18 @@
"value": "Sign Up to start creating, sharing and publishing unlimited number of mindmaps for free." "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": [ "login.signup": [
{ {
"type": 0, "type": 0,

View File

@ -5,6 +5,18 @@
"value": "Compartir" "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": [ "editor.try-welcome": [
{ {
"type": 0, "type": 0,
@ -17,6 +29,18 @@
"value": "Registrate para comenzar a crear, compartir y publicar una cantidad ilimitada de mapas mentales de forma gratuita." "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": [ "login.signup": [
{ {
"type": 0, "type": 0,

View File

@ -5,10 +5,22 @@
"value": "Partager" "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": [ "editor.try-welcome": [
{ {
"type": 0, "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": [ "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." "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": [ "login.signup": [
{ {
"type": 0, "type": 0,

View File

@ -5,6 +5,18 @@
"value": "Поделиться" "value": "Поделиться"
} }
], ],
"editor.edit-description-mobile": [
{
"type": 0,
"value": "Возможности ограниченной версии Mindmap поддерживаются на мобильных устройствах. Используйте настольный браузер для полных возможностей редактора."
}
],
"editor.edit-mobile": [
{
"type": 0,
"value": "Примечание для мобильных устройств."
}
],
"editor.try-welcome": [ "editor.try-welcome": [
{ {
"type": 0, "type": 0,
@ -17,6 +29,18 @@
"value": "Чтобы получить бесплатный неограниченный доступ — нужна только регистрация." "value": "Чтобы получить бесплатный неограниченный доступ — нужна только регистрация."
} }
], ],
"editor.try-welcome-description-mobile": [
{
"type": 0,
"value": "Зарегистрируйтесь, чтобы начать создавать, делиться и публиковать неограниченное количество ментальных карт бесплатно. Возможности ограниченной версии Mindmap поддерживаются на мобильных устройствах. Используйте настольный браузер для полных возможностей редактора."
}
],
"editor.try-welcome-mobile": [
{
"type": 0,
"value": "В этом издании демонстрируются некоторые возможности ментальных карт!"
}
],
"login.signup": [ "login.signup": [
{ {
"type": 0, "type": 0,

View File

@ -5,6 +5,18 @@
"value": "分享" "value": "分享"
} }
], ],
"editor.edit-description-mobile": [
{
"type": 0,
"value": "移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
}
],
"editor.edit-mobile": [
{
"type": 0,
"value": "移动设备注意事项."
}
],
"editor.try-welcome": [ "editor.try-welcome": [
{ {
"type": 0, "type": 0,
@ -17,6 +29,18 @@
"value": "注册后可以免费创建、分享和发布无限数量的思维导图。" "value": "注册后可以免费创建、分享和发布无限数量的思维导图。"
} }
], ],
"editor.try-welcome-description-mobile": [
{
"type": 0,
"value": "注册以开始免费创建、共享和发布无限数量的思维导图。 移动设备支持有限的思维导图编辑功能。 使用桌面浏览器获得完整的编辑器功能。"
}
],
"editor.try-welcome-mobile": [
{
"type": 0,
"value": "这个版本空间展示了一些思维导图功能!"
}
],
"login.signup": [ "login.signup": [
{ {
"type": 0, "type": 0,

View File

@ -18,7 +18,9 @@ const ActionButton = styled.div`
display: inline-block; display: inline-block;
&:hover { &:hover {
transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
} }
`; `;

View File

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState } from 'react';
import { StyledLogo, Notifier } from './styled'; import { StyledLogo, Notifier } from './styled';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
@ -6,22 +6,54 @@ import KeyboardSvg from '../../../images/keyboard.svg';
import AddSvg from '../../../images/add.svg'; import AddSvg from '../../../images/add.svg';
import MinusSvg from '../../../images/minus.svg'; import MinusSvg from '../../../images/minus.svg';
import CenterFocusSvg from '../../../images/center_focus.svg'; import CenterFocusSvg from '../../../images/center_focus.svg';
import CloseDialogSvg from '../../../images/close-dialog-icon.svg';
import ActionButton from '../action-button'; import ActionButton from '../action-button';
import { EditorRenderMode } from '@wisemapping/mindplot'; import { EditorRenderMode } from '@wisemapping/mindplot';
export type FooterPropsType = { export type FooterPropsType = {
editorMode: EditorRenderMode; editorMode: EditorRenderMode;
isMobile: boolean;
}; };
const Footer = ({ editorMode }: FooterPropsType): React.ReactElement => { const Footer = ({ editorMode, isMobile }: FooterPropsType): React.ReactElement => {
const intl = useIntl(); 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 ( return (
<> <>
<div id="floating-panel"> <div id="floating-panel">
{!isMobile && (
<div id="keyboardShortcuts" className="buttonExtOn"> <div id="keyboardShortcuts" className="buttonExtOn">
<img src={KeyboardSvg} /> <img src={KeyboardSvg} />
</div> </div>
)}
<div id="zoom-button"> <div id="zoom-button">
<button id="zoom-plus"> <button id="zoom-plus">
<img src={AddSvg} /> <img src={AddSvg} />
@ -38,15 +70,31 @@ const Footer = ({ editorMode }: FooterPropsType): React.ReactElement => {
</div> </div>
<StyledLogo id="bottom-logo"></StyledLogo> <StyledLogo id="bottom-logo"></StyledLogo>
<Notifier id="headerNotifier"></Notifier> <Notifier id="headerNotifier"></Notifier>
{editorMode === 'showcase' && ( {titleKey && (
<div id="tryInfoPanel"> <div className={dialogClass + ' ' + alertTopAdjustmentStyle}>
<p>{intl.formatMessage({ id: 'editor.try-welcome' })}</p> <div className="tryInfoPanelInner">
<p>{intl.formatMessage({ id: 'editor.try-welcome-description' })}</p> <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"> <a href="/c/registration">
<ActionButton> <ActionButton>
{intl.formatMessage({ id: 'login.signup', defaultMessage: 'Sign Up' })} {intl.formatMessage({ id: 'login.signup', defaultMessage: 'Sign Up' })}
</ActionButton> </ActionButton>
</a> </a>
)}
</div>
</div> </div>
)} )}
</> </>

View File

@ -1,9 +1,9 @@
div#header { div#header {
width: 100%; width: 100%;
height:50px; height: 50px;
position: absolute; position: absolute;
top: 0; top: 0;
z-index:1000; z-index: 1000;
} }
div#headerNotifier { div#headerNotifier {
@ -33,13 +33,13 @@ div#toolbarRight {
display: inline; display: inline;
} }
#account >img { #account > img {
width: 36x; width: 36x;
height: 36px; height: 36px;
} }
#accountSettingsPanel{ #accountSettingsPanel {
padding:10px 10px; padding: 10px 10px;
} }
#share { #share {
@ -64,7 +64,8 @@ div#toolbarRight {
} }
.actionButton:hover { .actionButton:hover {
transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; transition: background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,
box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, border 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms;
} }
div#toolbar { div#toolbar {
@ -85,7 +86,7 @@ div#toolbar .buttonContainer {
border-left: 1px solid lightgray; border-left: 1px solid lightgray;
} }
div#mapName >span { div#mapName > span {
border-radius: 4px; border-radius: 4px;
float: left; float: left;
padding: 8px; padding: 8px;
@ -165,7 +166,7 @@ div#toolbar .buttonExtActive {
div#toolbar .buttonExtOn { div#toolbar .buttonExtOn {
opacity: 0.8; opacity: 0.8;
cursor: pointer cursor: pointer;
} }
div#toolbar .buttonExtOff { div#toolbar .buttonExtOff {

View File

@ -56,7 +56,9 @@ export default function Toolbar({
</ToolbarButton> </ToolbarButton>
</div> </div>
)} )}
{(editorMode === 'edition-editor' || editorMode === 'edition-owner' || editorMode === 'showcase') && ( {(editorMode === 'edition-editor' ||
editorMode === 'edition-owner' ||
editorMode === 'showcase') && (
<> <>
<div id="edit" className="buttonContainer"> <div id="edit" className="buttonContainer">
<ToolbarButton id="undoEdition" className="buttonOn"> <ToolbarButton id="undoEdition" className="buttonOn">
@ -118,36 +120,22 @@ export default function Toolbar({
</> </>
)} )}
<ToolbarRightContainer> <ToolbarRightContainer>
<ToolbarButton <ToolbarButton id="export" className="buttonOn" onClick={() => onAction('export')}>
id="export"
className="buttonOn"
onClick={() => onAction('export')}
>
<img src={ExportSvg} /> <img src={ExportSvg} />
</ToolbarButton> </ToolbarButton>
{(editorMode === 'edition-owner' || editorMode === 'edition-editor' || editorMode === 'edition-viewer') && ( {(editorMode === 'edition-owner' ||
<ToolbarButton editorMode === 'edition-editor' ||
id="print" editorMode === 'edition-viewer') && (
className="buttonOn" <ToolbarButton id="print" className="buttonOn" onClick={() => onAction('print')}>
onClick={() => onAction('print')}
>
<img src={PrintSvg} /> <img src={PrintSvg} />
</ToolbarButton> </ToolbarButton>
)} )}
<ToolbarButton <ToolbarButton id="info" className="buttonOn" onClick={() => onAction('info')}>
id="info"
className="buttonOn"
onClick={() => onAction('info')}
>
<img src={InfoSvg} /> <img src={InfoSvg} />
</ToolbarButton> </ToolbarButton>
{editorMode === 'edition-owner' && ( {editorMode === 'edition-owner' && (
<> <>
<ToolbarButton <ToolbarButton id="history" className="buttonOn" onClick={() => onAction('history')}>
id="history"
className="buttonOn"
onClick={() => onAction('history')}
>
<img src={HistorySvg} /> <img src={HistorySvg} />
</ToolbarButton> </ToolbarButton>
<ToolbarButton <ToolbarButton
@ -168,7 +156,6 @@ export default function Toolbar({
<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>

View File

@ -26,7 +26,7 @@ export const ToolbarButton = styled.div`
padding-left: 2px; padding-left: 2px;
margin-left: 3px; margin-left: 3px;
display: inline-block; display: inline-block;
`; `;
export const ToolbarButtonExt = styled(ToolbarButton)` export const ToolbarButtonExt = styled(ToolbarButton)`
width: 40px; width: 40px;

View File

@ -1,26 +1,25 @@
/********************************************************************************/ /********************************************************************************/
/* Header & Toolbar Styles */ /* Header & Toolbar Styles */
/********************************************************************************/ /********************************************************************************/
@import "bootstrap-prefix.min.css"; @import 'bootstrap-prefix.min.css';
@import "bootstrap-fixes.css"; @import 'bootstrap-fixes.css';
html { html {
/* avoid bootstrap overriding font-size and breaking Mui */ /* avoid bootstrap overriding font-size and breaking Mui */
font-size: initial; font-size: initial;
} }
div#mindplot { body {
position: relative; width: 100vw;
top: 50px; height: 100vh;
left: 0; min-width: 100vw;
min-height: 100vh;
margin: 0px;
}
.mindplot-root {
width: 100%; width: 100%;
height: 100%; height: 100%;
border: 0;
overflow: hidden;
opacity: 1;
background-color: #f2f2f2;
background-image: linear-gradient(#ebe9e7 1px, transparent 1px), linear-gradient(to right, #ebe9e7 1px, #f2f2f2 1px);
background-size: 50px 50px;
} }
.notesTip { .notesTip {
@ -111,7 +110,7 @@ div.shareModalDialog {
height: 20px; height: 20px;
margin-left: 4px; margin-left: 4px;
margin-top: 3px; margin-top: 3px;
cursor: pointer cursor: pointer;
} }
.panelIcon:hover { .panelIcon:hover {
@ -145,8 +144,13 @@ div#position {
background-position: center; background-position: center;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 40px 40px; background-size: 40px 40px;
background-color: #FFF; background-color: #fff;
border-radius: 8px; border-radius: 8px;
padding: 0;
}
#position-button>img {
vertical-align: middle;
} }
#zoom-button { #zoom-button {
@ -163,9 +167,16 @@ div#position {
background-size: 40px 40px; background-size: 40px 40px;
background-position: center; background-position: center;
cursor: pointer; cursor: pointer;
background-color: #FFF; background-color: #fff;
padding: 0;
} }
#zoom-plus,
#zoom-minus>img {
vertical-align: middle;
}
#zoom-plus { #zoom-plus {
border-radius: 8px 8px 0 0; border-radius: 8px 8px 0 0;
} }
@ -174,7 +185,7 @@ div#position {
border-radius: 0 0 8px 8px; border-radius: 0 0 8px 8px;
} }
div#shotcuts > img{ div#shotcuts>img {
margin: 20px 0; margin: 20px 0;
width: 40px; width: 40px;
height: 40px; height: 40px;
@ -201,21 +212,69 @@ div#shotcuts > img{
color: #ffffff; color: #ffffff;
} }
div#tryInfoPanel { .tryInfoPanel {
position: absolute; position: absolute;
margin: auto;
text-align: center; text-align: center;
top: 80px; left: 0;
left: 20px; right: 0;
width: 200px;
padding: 20px;
font-size: 15px;
border-radius: 9px;
background-color: white; background-color: white;
border: solid 2px #ffa800; border: solid 2px #ffa800;
margin: auto;
width: 99%;
border-radius: 9px;
width: 96%;
} }
#tryInfoPanel > p { @media (min-width: 600px) {
justify-content: center; .tryInfoPanel {
padding-bottom: 20px; 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;
} }

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import Toolbar, { ToolbarActionType } from './components/toolbar'; import Toolbar, { ToolbarActionType } from './components/toolbar';
import Footer from './components/footer'; import Footer from './components/footer';
import { IntlProvider } from 'react-intl'; import { IntlProvider } from 'react-intl';
@ -10,10 +10,23 @@ import {
Designer, Designer,
DesignerKeyboard, DesignerKeyboard,
EditorRenderMode, EditorRenderMode,
MindplotWebComponentInterface,
Mindmap,
MockPersistenceManager,
LocalStorageManager,
RESTPersistenceManager,
TextExporterFactory,
ImageExporterFactory,
Exporter,
Importer,
TextImporterFactory,
} 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 Menu from './classes/menu/Menu'; import Menu from './classes/menu/Menu';
import BootstrapWidgetManager from './classes/bootstrap/BootstrapWidgetManager';
require('../../../libraries/bootstrap/js/bootstrap.min');
declare global { declare global {
// used in mindplot // used in mindplot
@ -21,15 +34,40 @@ declare global {
var accountEmail: string; var accountEmail: string;
} }
declare global {
namespace JSX {
interface IntrinsicElements {
['mindplot-component']: MindplotWebComponentInterface;
}
}
}
export type EditorOptions = { export type EditorOptions = {
mode: EditorRenderMode, mode: EditorRenderMode;
locale: string, locale: string;
zoom?: number, zoom?: number;
locked?: boolean, locked?: boolean;
lockedMsg?: string; lockedMsg?: string;
mapTitle: string; mapTitle: string;
enableKeyboardEvents: boolean; enableKeyboardEvents: boolean;
} };
export {
PersistenceManager,
DesignerOptionsBuilder,
Designer,
DesignerKeyboard,
EditorRenderMode,
Mindmap,
MockPersistenceManager,
LocalStorageManager,
RESTPersistenceManager,
TextExporterFactory,
ImageExporterFactory,
Exporter,
Importer,
TextImporterFactory,
};
export type EditorProps = { export type EditorProps = {
mapId: string; mapId: string;
@ -39,29 +77,25 @@ export type EditorProps = {
onLoad?: (designer: Designer) => void; onLoad?: (designer: Designer) => void;
}; };
const Editor = ({ const Editor = ({ mapId, options, persistenceManager, onAction, onLoad }: EditorProps) => {
mapId, const [isMobile, setIsMobile] = useState(undefined);
options, const mindplotComponent: any = useRef();
persistenceManager,
onAction,
onLoad,
}: EditorProps) => {
useEffect(() => { useEffect(() => {
// Change page title ... // Change page title ...
document.title = `${options.mapTitle} | WiseMapping `; document.title = `${options.mapTitle} | WiseMapping `;
// Load mindmap ... // Load mindmap ...
const designer = onLoadDesigner(mapId, options, persistenceManager); const designer = onLoadDesigner(mapId, options, persistenceManager);
// Has extended actions been customized ... // Has extended actions been customized ...
if (onLoad) { if (onLoad) {
onLoad(designer); onLoad(designer);
} }
// Load mindmap ... mindplotComponent.current.loadMap(mapId);
const instance = PersistenceManager.getInstance();
const mindmap = instance.load(mapId); setIsMobile(checkMobile());
designer.loadMap(mindmap);
if (options.locked) { if (options.locked) {
$notify(options.lockedMsg, false); $notify(options.lockedMsg, false);
@ -76,21 +110,34 @@ const Editor = ({
} }
}, [options.enableKeyboardEvents]); }, [options.enableKeyboardEvents]);
const onLoadDesigner = (mapId: string, options: EditorOptions, persistenceManager: PersistenceManager): Designer => { const checkMobile = () => {
const buildOptions = DesignerOptionsBuilder.buildOptions({ const check =
persistenceManager, /(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(
mode: options.mode, navigator.userAgent.toLowerCase(),
mapId: mapId, ) ||
container: 'mindplot', /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(
zoom: options.zoom, navigator.userAgent.toLowerCase().substring(0, 4),
locale: options.locale, );
}); return check;
};
const onLoadDesigner = (
mapId: string,
options: EditorOptions,
persistenceManager: PersistenceManager,
): Designer => {
mindplotComponent.current.buildDesigner(persistenceManager, new BootstrapWidgetManager());
// Build designer ... // Build designer ...
const result = buildDesigner(buildOptions); const result = mindplotComponent.current && mindplotComponent.current.getDesigner();
// Register toolbar event ... // 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'); 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.
@ -99,24 +146,30 @@ const Editor = ({
}; };
} }
return result; return result;
}; };
const locale = options.locale; const locale = options.locale;
const msg = I18nMsg.loadLocaleData(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 ( return (
<IntlProvider locale={locale} messages={msg}> <IntlProvider locale={locale} messages={msg}>
{(options.mode !== 'viewonly') && <div style={toolbarContainerStyle}>
<Toolbar {options.mode !== 'viewonly' && !isMobile && (
editorMode={options.mode} <Toolbar editorMode={options.mode} onAction={onAction} />
onAction={onAction} )}
/> </div>
} <mindplot-component
<div id="mindplot" style={mindplotStyle} className="wise-editor"></div> ref={mindplotComponent}
id="mindmap-comp"
mode={options.mode}
></mindplot-component>
<div id="mindplot-tooltips" className="wise-editor"></div> <div id="mindplot-tooltips" className="wise-editor"></div>
<Footer editorMode={options.mode} /> <Footer editorMode={options.mode} isMobile={isMobile} />
</IntlProvider > </IntlProvider>
); );
} };
export default Editor; export default Editor;

View File

@ -10,6 +10,10 @@
font-family: Arial !important; font-family: Arial !important;
} }
.section {
font-weight: bold;
}
tbody tr td:first-child { tbody tr td:first-child {
width: 20%; width: 20%;
} }
@ -21,10 +25,30 @@
<h1>@wisemapping/editor - Playground</h1> <h1>@wisemapping/editor - Playground</h1>
<p>You will find here a set of examples that shows how you can use integrate WiseMapping Editor</p> <p>You will find here a set of examples that shows how you can use integrate WiseMapping Editor</p>
<div> <div>
<p><span class="section">View Mode:</span>Simple integration to load and render mindaps in read only mode.</p>
<ul> <ul>
<li><a href="/viewmode.html">View mode:</a> Simple integration to load and render mindaps in read <li><a href="/viewmode.html?id=welcome">Welcome</a></li>
only mode</li> <li><a href="/viewmode.html?id=sample1">Sample 1</a></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=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> </ul>
</div> </div>
</body> </body>

View File

@ -20,12 +20,12 @@ div#footer-logo {
} }
#floating-panel { #floating-panel {
bottom: 80px; bottom: 20px;
align-items: stretch; align-items: stretch;
} }
div#mindplot { div#mindplot {
top:0; top: 0;
} }
#toolbar { #toolbar {

View File

@ -11,7 +11,7 @@
</head> </head>
<body> <body>
<div id="root"></div> <div id="root" class="mindplot-root"></div>
</body> </body>
</html> </html>

View File

@ -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>

View File

@ -4,35 +4,14 @@
<head> <head>
<title>WiseMapping - View Mode </title> <title>WiseMapping - View Mode </title>
<meta name="viewport" content="initial-scale=1">
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<link rel="icon" href="images/favicon.ico" type="image/x-icon"> <link rel="icon" href="images/favicon.ico" type="image/x-icon">
<link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon"> <link rel="shortcut icon" href="images/favicon.ico" type="image/x-icon">
</head> </head>
<body> <body>
<div id="root" onselectstart="return false;"></div> <div id="root" class="mindplot-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> </div>
</body> </body>

View File

@ -21,9 +21,8 @@ import Editor, { EditorOptions } from '../../../../src/index';
import { LocalStorageManager, Designer } from '@wisemapping/mindplot'; import { LocalStorageManager, Designer } from '@wisemapping/mindplot';
const initialization = (designer: Designer) => { const initialization = (designer: Designer) => {
designer.addEvent('loadSuccess', () => { designer.addEvent('loadSuccess', () => {
const elem = document.getElementById('mindplot'); const elem = document.getElementById('mindmap-comp');
if (elem) { if (elem) {
elem.classList.add('ready'); elem.classList.add('ready');
} }
@ -35,10 +34,10 @@ const mapId = 'welcome';
const options: EditorOptions = { const options: EditorOptions = {
zoom: 0.8, zoom: 0.8,
locked: false, locked: false,
mapTitle: "Develop WiseMapping", mapTitle: 'Develop WiseMapping',
mode: 'edition-owner', mode: 'edition-owner',
locale: 'en', locale: 'en',
enableKeyboardEvents: true enableKeyboardEvents: true,
}; };
ReactDOM.render( ReactDOM.render(

View 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('mindmap-comp');
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'),
);

View File

@ -5,9 +5,8 @@ import Editor, { EditorOptions } from '../../../../src/index';
import { LocalStorageManager, Designer } from '@wisemapping/mindplot'; import { LocalStorageManager, Designer } from '@wisemapping/mindplot';
const initialization = (designer: Designer) => { const initialization = (designer: Designer) => {
designer.addEvent('loadSuccess', () => { designer.addEvent('loadSuccess', () => {
const elem = document.getElementById('mindplot'); const elem = document.getElementById('mindmap-comp');
if (elem) { if (elem) {
elem.classList.add('ready'); elem.classList.add('ready');
} }
@ -25,7 +24,6 @@ const initialization = (designer: Designer) => {
option.selected = option.value === mapId; option.selected = option.value === mapId;
}); });
} }
}); });
}; };
@ -36,10 +34,10 @@ const persistence = new LocalStorageManager('samples/{id}.wxml', false);
const options: EditorOptions = { const options: EditorOptions = {
zoom: 0.8, zoom: 0.8,
locked: false, locked: false,
mapTitle: "Develop WiseMapping", mapTitle: 'Develop WiseMapping',
mode: 'viewonly', mode: 'viewonly',
locale: 'en', locale: 'en',
enableKeyboardEvents: true enableKeyboardEvents: true,
}; };
ReactDOM.render( ReactDOM.render(

View File

@ -10,23 +10,23 @@ module.exports = {
}, },
}, },
stats: { stats: {
errorDetails: true errorDetails: true,
}, },
entry: { entry: {
"editor.bundle": path.join(__dirname, 'src', 'index.tsx') 'editor.bundle': path.join(__dirname, 'src', 'index.tsx'),
}, },
mode: 'development', mode: 'development',
devtool: 'source-map', devtool: 'source-map',
target: 'web', target: 'web',
resolve: { resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx'] extensions: ['.ts', '.tsx', '.js', '.jsx'],
}, },
module: { module: {
rules: [ rules: [
{ {
test: /\.tsx?$/, test: /\.tsx?$/,
use: 'ts-loader', use: 'ts-loader',
exclude: '/node_modules/' exclude: '/node_modules/',
}, },
{ {
test: /\.(png|jpe?g|gif|svg)$/, test: /\.(png|jpe?g|gif|svg)$/,
@ -36,14 +36,15 @@ module.exports = {
test: /\.(js|jsx)$/, test: /\.(js|jsx)$/,
exclude: /node_modules/, exclude: /node_modules/,
use: ['babel-loader'], use: ['babel-loader'],
}, { },
{
test: /\.css$/i, test: /\.css$/i,
loader: 'style-loader' loader: 'style-loader',
}, },
{ {
test: /\.css$/, test: /\.css$/,
loader: 'css-loader', loader: 'css-loader',
} },
], ],
}, },
}; };

View File

@ -10,6 +10,7 @@ const playgroundConfig = {
entry: { entry: {
viewmode: path.resolve(__dirname, './test/playground/map-render/js/viewmode'), viewmode: path.resolve(__dirname, './test/playground/map-render/js/viewmode'),
editor: path.resolve(__dirname, './test/playground/map-render/js/editor'), editor: path.resolve(__dirname, './test/playground/map-render/js/editor'),
showcase: path.resolve(__dirname, './test/playground/map-render/js/showcase'),
}, },
output: { output: {
path: path.resolve(__dirname, 'test/playground/dist'), path: path.resolve(__dirname, 'test/playground/dist'),
@ -47,6 +48,11 @@ const playgroundConfig = {
filename: 'editor.html', filename: 'editor.html',
template: 'test/playground/map-render/html/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',
}),
], ],
}; };

View File

@ -9,12 +9,10 @@ const prodConfig = {
}, },
externals: { externals: {
react: 'react', react: 'react',
"react-dom": 'react-dom', 'react-dom': 'react-dom',
"react-intl": 'react-intl', 'react-intl': 'react-intl',
}, },
plugins: [ plugins: [new CleanWebpackPlugin()],
new CleanWebpackPlugin(),
]
}; };
module.exports = merge(common, prodConfig); module.exports = merge(common, prodConfig);

View File

@ -22,6 +22,23 @@
"@typescript-eslint" "@typescript-eslint"
], ],
"rules": { "rules": {
// ignore errors 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",
"(": "ignore"
}
}
],
"object-curly-newline": "off",
"no-underscore-dangle": "off", "no-underscore-dangle": "off",
"no-plusplus": "off", "no-plusplus": "off",
"no-param-reassign": "off", "no-param-reassign": "off",
@ -44,7 +61,8 @@
"ts": "never", "ts": "never",
"tsx": "never" "tsx": "never"
} }
] ],
"implicit-arrow-linebreak": "off"
}, },
"settings": { "settings": {
"import/resolver": { "import/resolver": {

View File

@ -1,7 +1,78 @@
# WiseMapping Mindplot # WiseMapping Mindplot
WiseMapping Mindplot module is the core mind map rerendering of WiseMapping. This lighway library allows eithe edition and visualization of saves mindmaps. WiseMapping Mindplot module is the core mind map rerendering of WiseMapping. This lighway library allows eithe edition and visualization of saved mindmaps.
## Usage ## Usage
A WebComponent implementation for mindplot designer is available.
This component is registered as mindplot-component in customElements API. (see https://developer.mozilla.org/en-US/docs/Web/API/CustomElementRegistry/define)
For use it you need to import minplot.js and put in your DOM a <mindplot-component id="mindplot-comp"/> tag. In order to create a Designer on it you need to call its buildDesigner method. Maps can be loaded through loadMap method.
#### Code example
```
<!DOCTYPE html>
<html>
<head>
<script src='mindplot.js'></script>
</head>
<body>
<mindmap-comp id='mindmap-comp' mode="viewonly"></mindmap-comp>
<script>
var webComponent = document.getElementById('mindmap-comp');
webComponent.buildDesigner(persistence, widget);
webComponent.loadMap("1");
</script>
</body>
</html>
```
Optionaly you can use your own presistence manager and widget manager.
If you don't have special requirements you can use the defaults.
```
var persistence = new LocalStorageManager(
'map.xml',
false, false
);
var widget = new MyAwesomeWidgetManager();
// then build the designer with these params
webComponent.buildDesigner(persistence, widget);
```
## Usage with React framework
To use the web component in your JSX code, first you need to register it in the IntrinsicElements interface using provided MindplotWebComponentInterface
#### TypeScript example
```
import { MindplotWebComponentInterface } from '@wisemapping/mindplot';
declare global {
namespace JSX {
interface IntrinsicElements {
['mindplot-component']: MindplotWebComponentInterface;
}
}
}
const App = ()=>{
const mindplotComponent: any = useRef();
useEffect(()=>{
mindplotComponent.current.buildDesigner();
mindplotComponent.current.loadMap("map_id");
}, [])
return (<div>
<mindplot-component
ref={mindplotComponent}
id="mindmap-comp"
mode={options.mode}
></mindplot-component>
</div>);
}
```
Check out the examples located in `test/playground/map-render/js` for some hints on high level usage. You can browse them by running `yarn playground`. Check out the examples located in `test/playground/map-render/js` for some hints on high level usage. You can browse them by running `yarn playground`.

View File

@ -18,7 +18,6 @@ if (Cypress.env('imageSnaphots')) {
} }
// https://www.cypress.io/blog/2020/02/12/working-with-iframes-in-cypress/ // https://www.cypress.io/blog/2020/02/12/working-with-iframes-in-cypress/
Cypress.Commands.add('getIframeBody', () => cy Cypress.Commands.add('getIframeBody', () =>
.get('iframe') cy.get('iframe').its('0.contentDocument.body').should('not.be.empty').then(cy.wrap),
.its('0.contentDocument.body').should('not.be.empty') );
.then(cy.wrap));

View File

@ -1,6 +1,6 @@
{ {
"name": "@wisemapping/mindplot", "name": "@wisemapping/mindplot",
"version": "5.0.12", "version": "5.0.14",
"description": "WiseMapping - Mindplot Canvas Library", "description": "WiseMapping - Mindplot Canvas Library",
"homepage": "http://www.wisemapping.org/", "homepage": "http://www.wisemapping.org/",
"directories": { "directories": {
@ -41,7 +41,7 @@
"xml-formatter": "^2.6.1" "xml-formatter": "^2.6.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.6", "@babel/core": "^7.18.13",
"@babel/preset-env": "^7.14.7", "@babel/preset-env": "^7.14.7",
"@babel/preset-typescript": "^7.16.5", "@babel/preset-typescript": "^7.16.5",
"@babel/register": "^7.16.0", "@babel/register": "^7.16.0",
@ -71,7 +71,7 @@
"ts-jest": "^27.1.2", "ts-jest": "^27.1.2",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.6",
"ts-node": "^10.4.0", "ts-node": "^10.4.0",
"webpack": "^5.44.0", "webpack": "^5.74.0",
"webpack-bundle-analyzer": "^4.5.0", "webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.7.2", "webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2", "webpack-dev-server": "^3.11.2",

View File

@ -1,20 +1,20 @@
/* /*
* 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").
* It is basically the Apache License, Version 2.0 (the "License") plus the * It is basically the Apache License, Version 2.0 (the "License") plus the
* "powered by wisemapping" text requirement on every single page; * "powered by wisemapping" text requirement on every single page;
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the license at * You may obtain a copy of the license at
* *
* http://www.wisemapping.org/license * http://www.wisemapping.org/license
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* 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 { $defined } from '@wisemapping/core-js'; import { $defined } from '@wisemapping/core-js';
import CommandContext from './CommandContext'; import CommandContext from './CommandContext';

View File

@ -47,9 +47,9 @@ class CommandContext {
if (result.length !== topicsIds.length) { if (result.length !== topicsIds.length) {
const ids = designerTopics.map((topic) => topic.getId()); const ids = designerTopics.map((topic) => topic.getId());
throw new Error(`Could not find topic. Result:${result throw new Error(
} Filter Criteria:${topicsIds `Could not find topic. Result:${result} Filter Criteria:${topicsIds} Current Topics: [${ids}])`,
} Current Topics: [${ids}])`); );
} }
return result; return result;
} }

View File

@ -17,9 +17,7 @@
*/ */
import { $assert, $defined } from '@wisemapping/core-js'; import { $assert, $defined } from '@wisemapping/core-js';
import { import { Point, CurvedLine, PolyLine, Line } from '@wisemapping/web2d';
Point, CurvedLine, PolyLine, Line,
} from '@wisemapping/web2d';
import { TopicShape } from './model/INodeModel'; import { TopicShape } from './model/INodeModel';
import RelationshipModel from './model/RelationshipModel'; import RelationshipModel from './model/RelationshipModel';
import Topic from './Topic'; import Topic from './Topic';

View File

@ -56,6 +56,7 @@ import { DesignerOptions } from './DesignerOptionsBuilder';
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';
import WidgetManager from './WidgetManager';
class Designer extends Events { class Designer extends Events {
private _mindmap: Mindmap; private _mindmap: Mindmap;
@ -82,7 +83,6 @@ class Designer extends Events {
super(); super();
$assert(options, 'options must be defined'); $assert(options, 'options must be defined');
$assert(options.zoom, 'zoom must be defined'); $assert(options.zoom, 'zoom must be defined');
$assert(options.containerSize, 'size must be defined');
$assert(divElement, 'divElement must be defined'); $assert(divElement, 'divElement must be defined');
// Set up i18n location ... // Set up i18n location ...
@ -91,10 +91,10 @@ class Designer extends Events {
this._options = options; this._options = options;
// Set full div elem render area ... // Set full div elem render area.The component must fill container size
if (options.containerSize) { // container is responsible for location and size
divElement.css(options.containerSize); divElement.css('width', '100%');
} divElement.css('height', '100%');
// Dispatcher manager ... // Dispatcher manager ...
const commandContext = new CommandContext(this); const commandContext = new CommandContext(this);
@ -138,14 +138,18 @@ class Designer extends Events {
private _registerWheelEvents(): void { private _registerWheelEvents(): void {
const zoomFactor = 1.02; const zoomFactor = 1.02;
document.addEventListener('wheel', (event: WheelEvent) => { document.addEventListener(
'wheel',
(event: WheelEvent) => {
if (event.deltaX > 0 || event.deltaY > 0) { if (event.deltaX > 0 || event.deltaY > 0) {
this.zoomOut(zoomFactor); this.zoomOut(zoomFactor);
} else { } else {
this.zoomIn(zoomFactor); this.zoomIn(zoomFactor);
} }
event.preventDefault(); event.preventDefault();
}, { passive: false }); },
{ passive: false },
);
} }
getActionDispatcher(): StandaloneActionDispatcher { getActionDispatcher(): StandaloneActionDispatcher {
@ -187,8 +191,7 @@ class Designer extends Events {
screenManager.addEvent('dblclick', (event: MouseEvent) => { screenManager.addEvent('dblclick', (event: MouseEvent) => {
if (workspace.isWorkspaceEventsEnabled()) { if (workspace.isWorkspaceEventsEnabled()) {
const mousePos = screenManager.getWorkspaceMousePosition(event); const mousePos = screenManager.getWorkspaceMousePosition(event);
const centralTopic: CentralTopic = me.getModel() const centralTopic: CentralTopic = me.getModel().getCentralTopic();
.getCentralTopic();
const model = me._createChildModel(centralTopic, mousePos); const model = me._createChildModel(centralTopic, mousePos);
this._actionDispatcher.addTopics([model], [centralTopic.getId()]); this._actionDispatcher.addTopics([model], [centralTopic.getId()]);
@ -704,9 +707,7 @@ class Designer extends Events {
const targetTopic = dmodel.findTopicById(targetTopicId); const targetTopic = dmodel.findTopicById(targetTopicId);
$assert( $assert(
targetTopic, targetTopic,
`targetTopic could not be found:${targetTopicId},${dmodel `targetTopic could not be found:${targetTopicId},${dmodel.getTopics().map((e) => e.getId())}`,
.getTopics()
.map((e) => e.getId())}`,
); );
// Build relationship line .... // Build relationship line ....
@ -797,16 +798,14 @@ class Designer extends Events {
} }
changeFontFamily(font: string) { changeFontFamily(font: string) {
const topicsIds = this.getModel() const topicsIds = this.getModel().filterTopicsIds();
.filterTopicsIds();
if (topicsIds.length > 0) { if (topicsIds.length > 0) {
this._actionDispatcher.changeFontFamilyToTopic(topicsIds, font); this._actionDispatcher.changeFontFamilyToTopic(topicsIds, font);
} }
} }
changeFontStyle(): void { changeFontStyle(): void {
const topicsIds = this.getModel() const topicsIds = this.getModel().filterTopicsIds();
.filterTopicsIds();
if (topicsIds.length > 0) { if (topicsIds.length > 0) {
this._actionDispatcher.changeFontStyleToTopic(topicsIds); this._actionDispatcher.changeFontStyleToTopic(topicsIds);
} }
@ -815,8 +814,7 @@ class Designer extends Events {
changeFontColor(color: string) { changeFontColor(color: string) {
$assert(color, 'color can not be null'); $assert(color, 'color can not be null');
const topicsIds = this.getModel() const topicsIds = this.getModel().filterTopicsIds();
.filterTopicsIds();
if (topicsIds.length > 0) { if (topicsIds.length > 0) {
this._actionDispatcher.changeFontColorToTopic(topicsIds, color); this._actionDispatcher.changeFontColorToTopic(topicsIds, color);
@ -851,9 +849,8 @@ class Designer extends Events {
} }
changeTopicShape(shape: string) { changeTopicShape(shape: string) {
const validateFunc = (topic: Topic) => !( const validateFunc = (topic: Topic) =>
topic.getType() === 'CentralTopic' && shape === TopicShape.LINE !(topic.getType() === 'CentralTopic' && shape === TopicShape.LINE);
);
const validateError = 'Central Topic shape can not be changed to line figure.'; const validateError = 'Central Topic shape can not be changed to line figure.';
const topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError); const topicsIds = this.getModel().filterTopicsIds(validateFunc, validateError);
@ -872,9 +869,13 @@ class Designer extends Events {
addIconType(iconType: string): void { addIconType(iconType: string): void {
const topicsIds = this.getModel().filterTopicsIds(); const topicsIds = this.getModel().filterTopicsIds();
if (topicsIds.length > 0) { 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, id: iconType,
}); },
);
} }
} }
@ -882,7 +883,8 @@ class Designer extends Events {
const model = this.getModel(); const model = this.getModel();
const topic = model.selectedTopic(); const topic = model.selectedTopic();
if (topic) { if (topic) {
topic.showLinkEditor(); const manager = WidgetManager.getInstance();
manager.showEditorForLink(topic, null, null);
this.onObjectFocusEvent(); this.onObjectFocusEvent();
} }
} }
@ -891,7 +893,8 @@ class Designer extends Events {
const model = this.getModel(); const model = this.getModel();
const topic = model.selectedTopic(); const topic = model.selectedTopic();
if (topic) { if (topic) {
topic.showNoteEditor(); const manager = WidgetManager.getInstance();
manager.showEditorForNote(topic, null, null);
this.onObjectFocusEvent(); this.onObjectFocusEvent();
} }
} }

View File

@ -20,11 +20,12 @@ import $ from 'jquery';
import PersistenceManager from './PersistenceManager'; import PersistenceManager from './PersistenceManager';
import Designer from './Designer'; import Designer from './Designer';
import { DesignerOptions } from './DesignerOptionsBuilder'; import { DesignerOptions } from './DesignerOptionsBuilder';
import WidgetManager from './WidgetManager';
let designer: Designer; let designer: Designer;
export function buildDesigner(options: DesignerOptions): Designer { export function buildDesigner(options: DesignerOptions): Designer {
const divContainer = $(`#${options.container}`); const divContainer = options.divContainer ? $(options.divContainer) : $(`#${options.container}`);
$assert(divContainer, 'container could not be null'); $assert(divContainer, 'container could not be null');
// Register load events ... // Register load events ...
@ -34,7 +35,8 @@ export function buildDesigner(options: DesignerOptions): Designer {
const persistence = options.persistenceManager; const persistence = options.persistenceManager;
$assert(persistence, 'persistence must be defined'); $assert(persistence, 'persistence must be defined');
PersistenceManager.init(persistence); PersistenceManager.init(persistence);
const widgetManager = options.widgetManager ? options.widgetManager : new WidgetManager();
WidgetManager.init(widgetManager);
return designer; return designer;
} }

View File

@ -33,7 +33,22 @@ class DesignerKeyboard extends Keyboard {
private static _disabled: boolean; private static _disabled: boolean;
private static excludeFromEditor = ['Enter', 'CapsLock', 'Escape', 'F1', 'F3', 'F4', 'F5', 'F6', 'F7', 'F8', 'F9', 'F10', 'F11', 'F12']; private static excludeFromEditor = [
'Enter',
'CapsLock',
'Escape',
'F1',
'F3',
'F4',
'F5',
'F6',
'F7',
'F8',
'F9',
'F10',
'F11',
'F12',
];
constructor(designer: Designer) { constructor(designer: Designer) {
super(); super();
@ -53,9 +68,13 @@ class DesignerKeyboard extends Keyboard {
private _registerEvents(designer: Designer) { private _registerEvents(designer: Designer) {
// Try with the keyboard .. // Try with the keyboard ..
const model = designer.getModel(); const model = designer.getModel();
this.addShortcut(['backspace', 'del'], () => { designer.deleteSelectedEntities(); }); this.addShortcut(['backspace', 'del'], () => {
designer.deleteSelectedEntities();
});
this.addShortcut('space', () => { designer.shrinkSelectedBranch(); }); this.addShortcut('space', () => {
designer.shrinkSelectedBranch();
});
this.addShortcut('f2', () => { this.addShortcut('f2', () => {
const node = model.selectedTopic(); const node = model.selectedTopic();
@ -64,39 +83,68 @@ class DesignerKeyboard extends Keyboard {
} }
}); });
this.addShortcut(['insert', 'tab', 'meta+enter'], () => { designer.createChildForSelectedNode(); }); this.addShortcut(['insert', 'tab', 'meta+enter'], () => {
designer.createChildForSelectedNode();
});
this.addShortcut('enter', () => { designer.createSiblingForSelectedNode(); }); this.addShortcut('enter', () => {
designer.createSiblingForSelectedNode();
});
this.addShortcut(['ctrl+z', 'meta+z'], () => { designer.undo(); }); this.addShortcut(['ctrl+z', 'meta+z'], () => {
designer.undo();
});
this.addShortcut(['ctrl+shift+z', 'meta+shift+z'], () => { designer.redo(); }); this.addShortcut(['ctrl+shift+z', 'meta+shift+z'], () => {
designer.redo();
});
this.addShortcut(['ctrl+c', 'meta+c'], () => { designer.copyToClipboard(); }); this.addShortcut(['ctrl+c', 'meta+c'], () => {
designer.copyToClipboard();
});
this.addShortcut(['ctrl+l', 'meta+l'], () => { designer.addLink(); }); this.addShortcut(['ctrl+l', 'meta+l'], () => {
designer.addLink();
});
this.addShortcut(['ctrl+k', 'meta+k'], () => { designer.addNote(); }); this.addShortcut(['ctrl+k', 'meta+k'], () => {
designer.addNote();
});
this.addShortcut(['ctrl+v', 'meta+v'], () => { designer.pasteClipboard(); }); this.addShortcut(['ctrl+v', 'meta+v'], () => {
designer.pasteClipboard();
});
this.addShortcut(['ctrl+a', 'meta+a'], () => { designer.selectAll(); }); this.addShortcut(['ctrl+a', 'meta+a'], () => {
designer.selectAll();
});
this.addShortcut(['ctrl+b', 'meta+b'], () => { designer.changeFontWeight(); }); this.addShortcut(['ctrl+b', 'meta+b'], () => {
designer.changeFontWeight();
});
this.addShortcut(['ctrl+s', 'meta+s'], () => { $(document).find('#save').trigger('click'); }); this.addShortcut(['ctrl+s', 'meta+s'], () => {
$(document).find('#save').trigger('click');
});
this.addShortcut(['ctrl+i', 'meta+i'], () => { designer.changeFontStyle(); }); this.addShortcut(['ctrl+i', 'meta+i'], () => {
designer.changeFontStyle();
});
this.addShortcut(['ctrl+shift+a', 'meta+shift+a'], () => { designer.deselectAll(); }); this.addShortcut(['ctrl+shift+a', 'meta+shift+a'], () => {
designer.deselectAll();
});
this.addShortcut(['meta+=', 'ctrl+='], () => { designer.zoomIn(); }); this.addShortcut(['meta+=', 'ctrl+='], () => {
designer.zoomIn();
});
this.addShortcut(['meta+-', 'ctrl+-'], () => { designer.zoomOut(); }); this.addShortcut(['meta+-', 'ctrl+-'], () => {
designer.zoomOut();
});
const me = this; const me = this;
this.addShortcut( this.addShortcut('right', () => {
'right', () => {
const node = model.selectedTopic(); const node = model.selectedTopic();
if (node) { if (node) {
if (node.isCentralTopic()) { if (node.isCentralTopic()) {
@ -110,11 +158,9 @@ class DesignerKeyboard extends Keyboard {
const centralTopic = model.getCentralTopic(); const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic); me._goToNode(designer, centralTopic);
} }
}, });
);
this.addShortcut( this.addShortcut('left', () => {
'left', () => {
const node = model.selectedTopic(); const node = model.selectedTopic();
if (node) { if (node) {
if (node.isCentralTopic()) { if (node.isCentralTopic()) {
@ -128,11 +174,9 @@ class DesignerKeyboard extends Keyboard {
const centralTopic = model.getCentralTopic(); const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic); me._goToNode(designer, centralTopic);
} }
}, });
);
this.addShortcut( this.addShortcut('up', () => {
'up', () => {
const node = model.selectedTopic(); const node = model.selectedTopic();
if (node) { if (node) {
if (!node.isCentralTopic()) { if (!node.isCentralTopic()) {
@ -142,10 +186,8 @@ class DesignerKeyboard extends Keyboard {
const centralTopic = model.getCentralTopic(); const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic); me._goToNode(designer, centralTopic);
} }
}, });
); this.addShortcut('down', () => {
this.addShortcut(
'down', () => {
const node = model.selectedTopic(); const node = model.selectedTopic();
if (node) { if (node) {
if (!node.isCentralTopic()) { if (!node.isCentralTopic()) {
@ -155,12 +197,14 @@ class DesignerKeyboard extends Keyboard {
const centralTopic = model.getCentralTopic(); const centralTopic = model.getCentralTopic();
me._goToNode(designer, centralTopic); me._goToNode(designer, centralTopic);
} }
}, });
);
$(document).on('keypress', (event) => { $(document).on('keypress', (event) => {
// Needs to be ignored ? // Needs to be ignored ?
if (DesignerKeyboard.isDisabled() || DesignerKeyboard.excludeFromEditor.includes(event.code)) { if (
DesignerKeyboard.isDisabled() ||
DesignerKeyboard.excludeFromEditor.includes(event.code)
) {
return; return;
} }
@ -189,14 +233,14 @@ class DesignerKeyboard extends Keyboard {
const { x } = node.getPosition(); const { x } = node.getPosition();
let dist = null; let dist = null;
for (let i = 0; i < brothers.length; i++) { for (let i = 0; i < brothers.length; i++) {
const sameSide = (x * brothers[i].getPosition().x) >= 0; const sameSide = x * brothers[i].getPosition().x >= 0;
if (brothers[i] !== node && sameSide) { if (brothers[i] !== node && sameSide) {
const brother = brothers[i]; const brother = brothers[i];
const brotherY = brother.getPosition().y; const brotherY = brother.getPosition().y;
if (direction === 'DOWN' && brotherY > y) { if (direction === 'DOWN' && brotherY > y) {
let distancia = y - brotherY; let distancia = y - brotherY;
if (distancia < 0) { if (distancia < 0) {
distancia *= (-1); distancia *= -1;
} }
if (dist == null || dist > distancia) { if (dist == null || dist > distancia) {
dist = distancia; dist = distancia;
@ -205,7 +249,7 @@ class DesignerKeyboard extends Keyboard {
} else if (direction === 'UP' && brotherY < y) { } else if (direction === 'UP' && brotherY < y) {
let distance = y - brotherY; let distance = y - brotherY;
if (distance < 0) { if (distance < 0) {
distance *= (-1); distance *= -1;
} }
if (dist == null || dist > distance) { if (dist == null || dist > distance) {
dist = distance; dist = distance;

View File

@ -117,7 +117,7 @@ class DesignerModel extends Events {
selectedTopic(): Topic | undefined { selectedTopic(): Topic | undefined {
const topics = this.filterSelectedTopics(); const topics = this.filterSelectedTopics();
return (topics.length > 0) ? topics[0] : undefined; return topics.length > 0 ? topics[0] : undefined;
} }
findTopicById(id: number): Topic | undefined { findTopicById(id: number): Topic | undefined {

View File

@ -17,38 +17,29 @@
*/ */
import { $assert } from '@wisemapping/core-js'; import { $assert } from '@wisemapping/core-js';
import EditorRenderMode from './EditorRenderMode'; import EditorRenderMode from './EditorRenderMode';
import WidgetManager from './WidgetManager';
import PersistenceManager from './PersistenceManager'; import PersistenceManager from './PersistenceManager';
import SizeType from './SizeType';
export type DesignerOptions = { export type DesignerOptions = {
zoom: number, zoom: number;
containerSize?: SizeType, mode: EditorRenderMode;
mode: EditorRenderMode, mapId?: string;
mapId?: string, divContainer?: HTMLElement;
container: string, container: string;
persistenceManager?: PersistenceManager, persistenceManager?: PersistenceManager;
saveOnLoad?: boolean, widgetManager?: WidgetManager;
locale?: string, saveOnLoad?: boolean;
locale?: string;
}; };
class OptionsBuilder { class OptionsBuilder {
static buildOptions(options: DesignerOptions): DesignerOptions { static buildOptions(options: DesignerOptions): DesignerOptions {
$assert(options.persistenceManager, 'persistence must be defined'); $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 = { const defaultOptions: DesignerOptions = {
mode: 'edition-owner', mode: 'edition-owner',
zoom: 0.85, zoom: 0.85,
saveOnLoad: true, saveOnLoad: true,
containerSize,
container: 'mindplot', container: 'mindplot',
locale: 'en', locale: 'en',
}; };

View File

@ -85,7 +85,7 @@ class DesignerUndoManager {
result = false; result = false;
} else if (undoLength > 0) { } else if (undoLength > 0) {
const command = this._undoQueue[undoLength - 1]; const command = this._undoQueue[undoLength - 1];
result = (this._baseId !== command.getId()); result = this._baseId !== command.getId();
} }
return result; return result;
} }

View File

@ -83,7 +83,7 @@ class DragConnector {
// That's why i need to divide it by two... // That's why i need to divide it by two...
const txborder = tpos.x + (topic.getSize().width / 2) * Math.sign(sPos.x); const txborder = tpos.x + (topic.getSize().width / 2) * Math.sign(sPos.x);
const distance = (sPos.x - txborder) * Math.sign(sPos.x); const distance = (sPos.x - txborder) * Math.sign(sPos.x);
return distance > 0 && (distance < DragConnector.MAX_VERTICAL_CONNECTION_TOLERANCE); return distance > 0 && distance < DragConnector.MAX_VERTICAL_CONNECTION_TOLERANCE;
}); });
// Assign a priority based on the distance: // Assign a priority based on the distance:
@ -99,19 +99,34 @@ class DragConnector {
const av = me._isVerticallyAligned(a.getSize(), aPos, sPos); const av = me._isVerticallyAligned(a.getSize(), aPos, sPos);
const bv = me._isVerticallyAligned(b.getSize(), bPos, sPos); const bv = me._isVerticallyAligned(b.getSize(), bPos, sPos);
return me._proximityWeight(av, a, sPos, currentConnection) return (
- me._proximityWeight(bv, b, sPos, currentConnection); me._proximityWeight(av, a, sPos, currentConnection) -
me._proximityWeight(bv, b, sPos, currentConnection)
);
}); });
return topics; return topics;
} }
private _proximityWeight(isAligned: boolean, target: Topic, sPos: Point, currentConnection: Topic): number { private _proximityWeight(
isAligned: boolean,
target: Topic,
sPos: Point,
currentConnection: Topic,
): number {
const tPos = target.getPosition(); const tPos = target.getPosition();
return (isAligned ? 0 : 200) + Math.abs(tPos.x - sPos.x) return (
+ Math.abs(tPos.y - sPos.y) + (currentConnection === target ? 0 : 100); (isAligned ? 0 : 200) +
Math.abs(tPos.x - sPos.x) +
Math.abs(tPos.y - sPos.y) +
(currentConnection === target ? 0 : 100)
);
} }
private _isVerticallyAligned(targetSize: SizeType, targetPosition: Point, sourcePosition: Point): boolean { private _isVerticallyAligned(
targetSize: SizeType,
targetPosition: Point,
sourcePosition: Point,
): boolean {
return Math.abs(sourcePosition.y - targetPosition.y) < targetSize.height / 2; return Math.abs(sourcePosition.y - targetPosition.y) < targetSize.height / 2;
} }

View File

@ -59,14 +59,14 @@ class DragManager {
// Register mouse move listener ... // Register mouse move listener ...
const mouseMoveListener = dragManager._buildMouseMoveListener( const mouseMoveListener = dragManager._buildMouseMoveListener(
workspace, dragNode, dragManager, workspace,
dragNode,
dragManager,
); );
screen.addEvent('mousemove', mouseMoveListener); screen.addEvent('mousemove', mouseMoveListener);
// Register mouse up listeners ... // Register mouse up listeners ...
const mouseUpListener = dragManager._buildMouseUpListener( const mouseUpListener = dragManager._buildMouseUpListener(workspace, dragNode, dragManager);
workspace, dragNode, dragManager,
);
screen.addEvent('mouseup', mouseUpListener); screen.addEvent('mouseup', mouseUpListener);
// Change cursor. // Change cursor.

View File

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

View File

@ -17,7 +17,7 @@
*/ */
class Events { class Events {
private _handlerByType; protected _handlerByType;
constructor() { constructor() {
this._handlerByType = {}; this._handlerByType = {};
@ -48,9 +48,9 @@ class Events {
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) => {
fn.apply(this, args); fn.apply(this, args);
})); });
return this; return this;
} }

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