Merge pull request #314 from rkflx/pr/add-and-fix-shortcuts
Add more keyboard shortcuts and fix various shortcut related issues
This commit is contained in:
commit
77f1b5f0af
17 changed files with 433 additions and 107 deletions
41
index.html
41
index.html
|
|
@ -29,7 +29,7 @@
|
||||||
>
|
>
|
||||||
<div class="collapse navbar-collapse" id="collapsingNavbar">
|
<div class="collapse navbar-collapse" id="collapsingNavbar">
|
||||||
<div class="navbar-nav">
|
<div class="navbar-nav">
|
||||||
<form class="form-inline">
|
<form class="form-inline" id="profile-alternative-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<select class="selectpicker show-tick" data-width="250px" id="profile-alternative" multiple>
|
<select class="selectpicker show-tick" data-width="250px" id="profile-alternative" multiple>
|
||||||
<optgroup label="Profile" data-max-options="1" data-icon="fa-bicycle" id="profile">
|
<optgroup label="Profile" data-max-options="1" data-icon="fa-bicycle" id="profile">
|
||||||
|
|
@ -61,6 +61,8 @@
|
||||||
role="button"
|
role="button"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
|
data-i18n="[title]navbar.export-tooltip"
|
||||||
|
title="Export route"
|
||||||
>
|
>
|
||||||
<span class="fa fa-lg fa-cloud-download" aria-hidden="true"> </span>
|
<span class="fa fa-lg fa-cloud-download" aria-hidden="true"> </span>
|
||||||
<span data-i18n="navbar.export">Export</span>
|
<span data-i18n="navbar.export">Export</span>
|
||||||
|
|
@ -76,6 +78,8 @@
|
||||||
id="navbarLoadDropdown"
|
id="navbarLoadDropdown"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
|
data-i18n="[title]navbar.load.tooltip"
|
||||||
|
title="Load route"
|
||||||
>
|
>
|
||||||
<span class="fa fa-lg fa-cloud-upload" aria-hidden="true"> </span>
|
<span class="fa fa-lg fa-cloud-upload" aria-hidden="true"> </span>
|
||||||
<span data-i18n="navbar.load.title">Load</span>
|
<span data-i18n="navbar.load.title">Load</span>
|
||||||
|
|
@ -107,7 +111,11 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-item">
|
<div
|
||||||
|
class="nav-item"
|
||||||
|
data-i18n="[title]about.tooltip"
|
||||||
|
title="Show more information about BRouter-Web"
|
||||||
|
>
|
||||||
<a class="nav-link" href="#" data-toggle="modal" data-target="#about"
|
<a class="nav-link" href="#" data-toggle="modal" data-target="#about"
|
||||||
><span class="fa fa-lg fa-info-circle" aria-hidden="true"></span
|
><span class="fa fa-lg fa-info-circle" aria-hidden="true"></span
|
||||||
><span data-i18n="navbar.about">About</span></a
|
><span data-i18n="navbar.about">About</span></a
|
||||||
|
|
@ -698,7 +706,12 @@
|
||||||
<div id="sidebarTabs" class="leaflet-sidebar-tabs collapsed">
|
<div id="sidebarTabs" class="leaflet-sidebar-tabs collapsed">
|
||||||
<ul role="tablist">
|
<ul role="tablist">
|
||||||
<li>
|
<li>
|
||||||
<a href="#tab_layers_control" role="tab" data-i18n="[title]sidebar.layers.title" title="Layers">
|
<a
|
||||||
|
href="#tab_layers_control"
|
||||||
|
role="tab"
|
||||||
|
data-i18n="[title]sidebar.layers.tooltip"
|
||||||
|
title="Select layers"
|
||||||
|
>
|
||||||
<!--
|
<!--
|
||||||
https://github.com/feathericons/feather/blob/0dc2bf5c9d01759e47485d9498aefc02cac1d845/icons/layers.svg
|
https://github.com/feathericons/feather/blob/0dc2bf5c9d01759e47485d9498aefc02cac1d845/icons/layers.svg
|
||||||
MIT License: https://github.com/feathericons/feather/blob/master/LICENSE
|
MIT License: https://github.com/feathericons/feather/blob/master/LICENSE
|
||||||
|
|
@ -722,7 +735,11 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li hidden>
|
<li hidden>
|
||||||
<a href="#tab_itinerary" role="tab" data-i18n="[title]sidebar.itinerary.title" title="Itinerary"
|
<a
|
||||||
|
href="#tab_itinerary"
|
||||||
|
role="tab"
|
||||||
|
data-i18n="[title]sidebar.itinerary.tooltip"
|
||||||
|
title="Show Itinerary"
|
||||||
><i class="fa fa-map-signs"></i
|
><i class="fa fa-map-signs"></i
|
||||||
></a>
|
></a>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -730,18 +747,26 @@
|
||||||
<a
|
<a
|
||||||
href="#tab_profile"
|
href="#tab_profile"
|
||||||
role="tab"
|
role="tab"
|
||||||
data-i18n="[title]sidebar.customize-profile.title"
|
data-i18n="[title]sidebar.customize-profile.tooltip"
|
||||||
title="Customize profile"
|
title="Customize profile"
|
||||||
><i class="fa fa-wrench"></i
|
><i class="fa fa-wrench"></i
|
||||||
></a>
|
></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#tab_data" role="tab" data-i18n="[title]sidebar.data.title" title="Data"
|
<a
|
||||||
|
href="#tab_data"
|
||||||
|
role="tab"
|
||||||
|
data-i18n="[title]sidebar.data.tooltip"
|
||||||
|
title="Show detailed route data table"
|
||||||
><i class="fa fa-table"></i
|
><i class="fa fa-table"></i
|
||||||
></a>
|
></a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="#tab_statistics" role="tab" data-i18n="[title]sidebar.analysis.title" title="Analysis"
|
<a
|
||||||
|
href="#tab_statistics"
|
||||||
|
role="tab"
|
||||||
|
data-i18n="[title]sidebar.analysis.tooltip"
|
||||||
|
title="Analyse route"
|
||||||
><i class="fa fa-pie-chart"></i
|
><i class="fa fa-pie-chart"></i
|
||||||
></a>
|
></a>
|
||||||
</li>
|
</li>
|
||||||
|
|
@ -1048,6 +1073,8 @@
|
||||||
id="elevation-btn"
|
id="elevation-btn"
|
||||||
aria-expanded="false"
|
aria-expanded="false"
|
||||||
aria-label="Toggle elevation chart"
|
aria-label="Toggle elevation chart"
|
||||||
|
data-i18n="[title]footer.elevation-chart"
|
||||||
|
title="Toggle elevation chart"
|
||||||
>
|
>
|
||||||
<span class="fa fa-area-chart"></span>
|
<span class="fa fa-area-chart"></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
18
js/Map.js
18
js/Map.js
|
|
@ -2,6 +2,12 @@ BR.Map = {
|
||||||
initMap: function() {
|
initMap: function() {
|
||||||
var map, layersControl;
|
var map, layersControl;
|
||||||
|
|
||||||
|
L.setOptions(this, {
|
||||||
|
shortcut: {
|
||||||
|
locate: 76 // char code for 'l'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
BR.keys = BR.keys || {};
|
BR.keys = BR.keys || {};
|
||||||
|
|
||||||
var maxZoom = 19;
|
var maxZoom = 19;
|
||||||
|
|
@ -96,7 +102,7 @@ BR.Map = {
|
||||||
|
|
||||||
var secureContext = 'isSecureContext' in window ? isSecureContext : location.protocol === 'https:';
|
var secureContext = 'isSecureContext' in window ? isSecureContext : location.protocol === 'https:';
|
||||||
if (secureContext) {
|
if (secureContext) {
|
||||||
L.control
|
var locationControl = L.control
|
||||||
.locate({
|
.locate({
|
||||||
strings: {
|
strings: {
|
||||||
title: i18next.t('map.locate-me')
|
title: i18next.t('map.locate-me')
|
||||||
|
|
@ -105,6 +111,16 @@ BR.Map = {
|
||||||
iconLoading: 'fa fa-spinner fa-pulse'
|
iconLoading: 'fa fa-spinner fa-pulse'
|
||||||
})
|
})
|
||||||
.addTo(map);
|
.addTo(map);
|
||||||
|
L.DomEvent.addListener(
|
||||||
|
document,
|
||||||
|
'keydown',
|
||||||
|
function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.locate) {
|
||||||
|
locationControl.start();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
L.control.scale().addTo(map);
|
L.control.scale().addTo(map);
|
||||||
|
|
|
||||||
30
js/Util.js
30
js/Util.js
|
|
@ -67,5 +67,35 @@ BR.Util = {
|
||||||
}
|
}
|
||||||
$el.remove();
|
$el.remove();
|
||||||
return env;
|
return env;
|
||||||
|
},
|
||||||
|
|
||||||
|
keyboardShortcutsAllowed: function(keyEvent) {
|
||||||
|
// Skip auto-repeating key events
|
||||||
|
if (keyEvent.repeat) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suppress shortcut handling when a text or number input field is focussed
|
||||||
|
if (
|
||||||
|
document.activeElement.type == 'number' ||
|
||||||
|
document.activeElement.type == 'text' ||
|
||||||
|
document.activeElement.type == 'textarea'
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only allow shortcuts without modifiers for now, to prevent triggering map functions
|
||||||
|
// when browser shortcuts are triggered (e.g. Ctrl+P for print should not add a POI)
|
||||||
|
if (keyEvent.ctrlKey || keyEvent.metaKey || keyEvent.altKey) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do not allow shortcuts triggering actions behind Bootstrap's
|
||||||
|
// modal dialogs or when dropdown menus are opened
|
||||||
|
if ($('.modal.show').length || $('.dropdown.show').length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
BR.Export = L.Class.extend({
|
BR.Export = L.Class.extend({
|
||||||
latLngs: [],
|
latLngs: [],
|
||||||
|
|
||||||
|
options: {
|
||||||
|
shortcut: {
|
||||||
|
export: 88 // char code for 'x'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
initialize: function(router, pois) {
|
initialize: function(router, pois) {
|
||||||
this.router = router;
|
this.router = router;
|
||||||
this.pois = pois;
|
this.pois = pois;
|
||||||
|
|
@ -20,6 +26,8 @@ BR.Export = L.Class.extend({
|
||||||
this.exportButton.on('click', L.bind(this._generateTrackname, this));
|
this.exportButton.on('click', L.bind(this._generateTrackname, this));
|
||||||
L.DomUtil.get('submitExport').onclick = L.bind(this._export, this);
|
L.DomUtil.get('submitExport').onclick = L.bind(this._export, this);
|
||||||
|
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
|
|
||||||
this.update([]);
|
this.update([]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -116,6 +124,17 @@ BR.Export = L.Class.extend({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (
|
||||||
|
BR.Util.keyboardShortcutsAllowed(e) &&
|
||||||
|
e.keyCode === this.options.shortcut.export &&
|
||||||
|
!this.exportButton.hasClass('disabled')
|
||||||
|
) {
|
||||||
|
this._generateTrackname();
|
||||||
|
$('#export').modal('show');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,23 +52,13 @@ BR.OpacitySlider = L.Class.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
_keydownListener: function(e) {
|
_keydownListener: function(e) {
|
||||||
// Suppress shortcut handling when a text input field is focussed
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.muteKeyCode) {
|
||||||
if (document.activeElement.type == 'text' || document.activeElement.type == 'textarea') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.keyCode === this.options.muteKeyCode && !e.repeat) {
|
|
||||||
this.options.callback(0);
|
this.options.callback(0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_keyupListener: function(e) {
|
_keyupListener: function(e) {
|
||||||
// Suppress shortcut handling when a text input field is focussed
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.muteKeyCode) {
|
||||||
if (document.activeElement.type == 'text' || document.activeElement.type == 'textarea') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.keyCode === this.options.muteKeyCode && !e.repeat) {
|
|
||||||
this.options.callback(this.input.val() / 100);
|
this.options.callback(this.input.val() / 100);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,10 @@
|
||||||
BR.RoutingOptions = L.Evented.extend({
|
BR.RoutingOptions = L.Evented.extend({
|
||||||
|
options: {
|
||||||
|
shortcut: {
|
||||||
|
switch: 71 // char code for 'g'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
initialize: function() {
|
initialize: function() {
|
||||||
$('#profile-alternative').on('changed.bs.select', this._getChangeHandler());
|
$('#profile-alternative').on('changed.bs.select', this._getChangeHandler());
|
||||||
|
|
||||||
|
|
@ -15,6 +21,8 @@ BR.RoutingOptions = L.Evented.extend({
|
||||||
profiles_list.children[0].value = 'Custom';
|
profiles_list.children[0].value = 'Custom';
|
||||||
// <custom> profile is empty at start, select next one
|
// <custom> profile is empty at start, select next one
|
||||||
profiles_list.children[1].selected = true;
|
profiles_list.children[1].selected = true;
|
||||||
|
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
refreshUI: function() {
|
refreshUI: function() {
|
||||||
|
|
@ -37,6 +45,10 @@ BR.RoutingOptions = L.Evented.extend({
|
||||||
custom.disabled = true;
|
custom.disabled = true;
|
||||||
}
|
}
|
||||||
$('.selectpicker').selectpicker('refresh');
|
$('.selectpicker').selectpicker('refresh');
|
||||||
|
|
||||||
|
// append shortcut text to tooltip
|
||||||
|
var button = $('#profile-alternative-form button')[0];
|
||||||
|
button.title = button.title + i18next.t('navbar.profile-tooltip');
|
||||||
},
|
},
|
||||||
|
|
||||||
getOptions: function() {
|
getOptions: function() {
|
||||||
|
|
@ -105,5 +117,13 @@ BR.RoutingOptions = L.Evented.extend({
|
||||||
return L.bind(function(evt) {
|
return L.bind(function(evt) {
|
||||||
this.fire('update', { options: this.getOptions() });
|
this.fire('update', { options: this.getOptions() });
|
||||||
}, this);
|
}, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.switch) {
|
||||||
|
if (!$('#profile-alternative-form .dropdown').hasClass('show')) {
|
||||||
|
$('#profile-alternative-form button').click();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
30
js/index.js
30
js/index.js
|
|
@ -46,6 +46,7 @@
|
||||||
|
|
||||||
search = new BR.Search();
|
search = new BR.Search();
|
||||||
map.addControl(search);
|
map.addControl(search);
|
||||||
|
$('#map .leaflet-control-geocoder > button')[0].title = i18next.t('map.geocoder');
|
||||||
|
|
||||||
router = L.bRouter(); //brouterCgi dummyRouter
|
router = L.bRouter(); //brouterCgi dummyRouter
|
||||||
|
|
||||||
|
|
@ -83,7 +84,7 @@
|
||||||
var deletePointButton = L.easyButton(
|
var deletePointButton = L.easyButton(
|
||||||
'<span><i class="fa fa-caret-left"></i><i class="fa fa-map-marker" style="margin-left: 1px; color: gray;"></i></span>',
|
'<span><i class="fa fa-caret-left"></i><i class="fa fa-map-marker" style="margin-left: 1px; color: gray;"></i></span>',
|
||||||
function() {
|
function() {
|
||||||
routing.removeWaypoint(routing.getLast(), function(err, data) {});
|
routing.deleteLastPoint();
|
||||||
},
|
},
|
||||||
i18next.t('map.delete-last-point')
|
i18next.t('map.delete-last-point')
|
||||||
);
|
);
|
||||||
|
|
@ -91,6 +92,29 @@
|
||||||
deleteRouteButton = L.easyButton(
|
deleteRouteButton = L.easyButton(
|
||||||
'fa-trash-o',
|
'fa-trash-o',
|
||||||
function() {
|
function() {
|
||||||
|
clearRoute();
|
||||||
|
},
|
||||||
|
i18next.t('map.clear-route-tooltip')
|
||||||
|
);
|
||||||
|
|
||||||
|
L.DomEvent.addListener(
|
||||||
|
document,
|
||||||
|
'keydown',
|
||||||
|
function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && !$('.modal.show').length) {
|
||||||
|
if (e.keyCode === 8) {
|
||||||
|
// char code for 'backspace'
|
||||||
|
clearRoute();
|
||||||
|
} else if (e.keyCode === 72) {
|
||||||
|
// char code for 'h'
|
||||||
|
$('#about').modal('show');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
|
function clearRoute() {
|
||||||
bootbox.prompt({
|
bootbox.prompt({
|
||||||
size: 'small',
|
size: 'small',
|
||||||
title: i18next.t('map.clear-route'),
|
title: i18next.t('map.clear-route'),
|
||||||
|
|
@ -126,9 +150,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
i18next.t('map.clear-route')
|
|
||||||
);
|
|
||||||
|
|
||||||
function updateRoute(evt) {
|
function updateRoute(evt) {
|
||||||
router.setOptions(evt.options);
|
router.setOptions(evt.options);
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@ BR.Elevation = L.Control.Elevation.extend({
|
||||||
bottom: 30,
|
bottom: 30,
|
||||||
left: 60
|
left: 60
|
||||||
},
|
},
|
||||||
theme: 'steelblue-theme'
|
theme: 'steelblue-theme',
|
||||||
|
shortcut: {
|
||||||
|
toggle: 69 // char code for 'e'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onAdd: function(map) {
|
onAdd: function(map) {
|
||||||
|
|
@ -30,6 +33,8 @@ BR.Elevation = L.Control.Elevation.extend({
|
||||||
L.DomEvent.on(this._container, 'mouseup', this._dragEndHandler, this);
|
L.DomEvent.on(this._container, 'mouseup', this._dragEndHandler, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
|
|
||||||
return container;
|
return container;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -64,5 +69,11 @@ BR.Elevation = L.Control.Elevation.extend({
|
||||||
|
|
||||||
layer.on('mouseout', this._hidePositionMarker.bind(this));
|
layer.on('mouseout', this._hidePositionMarker.bind(this));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.toggle) {
|
||||||
|
$('#elevation-btn').click();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,13 @@
|
||||||
BR.NogoAreas = L.Control.extend({
|
BR.NogoAreas = L.Control.extend({
|
||||||
|
options: {
|
||||||
|
shortcut: {
|
||||||
|
draw: {
|
||||||
|
enable: 78, // char code for 'n'
|
||||||
|
disable: 27 // char code for 'ESC'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
statics: {
|
statics: {
|
||||||
MSG_BUTTON: 'Draw no-go area (circle)',
|
MSG_BUTTON: 'Draw no-go area (circle)',
|
||||||
MSG_BUTTON_CANCEL: 'Cancel drawing no-go area',
|
MSG_BUTTON_CANCEL: 'Cancel drawing no-go area',
|
||||||
|
|
@ -48,28 +57,32 @@ BR.NogoAreas = L.Control.extend({
|
||||||
featuresLayer: this.drawnItems
|
featuresLayer: this.drawnItems
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.startDrawing = function(control) {
|
||||||
|
// initial radius of 0 to detect click, see DeletableCircleEditor.onDrawingMouseUp
|
||||||
|
var opts = L.extend({ radius: 0 }, self.style);
|
||||||
|
editTools.startCircle(null, opts);
|
||||||
|
|
||||||
|
control.state('cancel-no-go-create');
|
||||||
|
};
|
||||||
|
|
||||||
|
this.stopDrawing = function(control) {
|
||||||
|
editTools.stopDrawing();
|
||||||
|
control.state('no-go-create');
|
||||||
|
};
|
||||||
|
|
||||||
this.button = L.easyButton({
|
this.button = L.easyButton({
|
||||||
states: [
|
states: [
|
||||||
{
|
{
|
||||||
stateName: BR.NogoAreas.STATE_CREATE,
|
stateName: BR.NogoAreas.STATE_CREATE,
|
||||||
icon: 'fa-ban',
|
icon: 'fa-ban',
|
||||||
title: BR.NogoAreas.MSG_BUTTON,
|
title: BR.NogoAreas.MSG_BUTTON,
|
||||||
onClick: function(control) {
|
onClick: this.startDrawing
|
||||||
// initial radius of 0 to detect click, see DeletableCircleEditor.onDrawingMouseUp
|
|
||||||
var opts = L.extend({ radius: 0 }, self.style);
|
|
||||||
editTools.startCircle(null, opts);
|
|
||||||
|
|
||||||
control.state('cancel-no-go-create');
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
stateName: BR.NogoAreas.STATE_CANCEL,
|
stateName: BR.NogoAreas.STATE_CANCEL,
|
||||||
icon: 'fa-ban active',
|
icon: 'fa-ban active',
|
||||||
title: BR.NogoAreas.MSG_BUTTON_CANCEL,
|
title: BR.NogoAreas.MSG_BUTTON_CANCEL,
|
||||||
onClick: function(control) {
|
onClick: this.stopDrawing
|
||||||
editTools.stopDrawing();
|
|
||||||
control.state('no-go-create');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
@ -78,6 +91,8 @@ BR.NogoAreas = L.Control.extend({
|
||||||
// events firing in Chrome mobile while L.Map.Tap enabled for circle drawing
|
// events firing in Chrome mobile while L.Map.Tap enabled for circle drawing
|
||||||
L.DomEvent.addListener(this.button.button, 'pointerdown', L.DomEvent.stop);
|
L.DomEvent.addListener(this.button.button, 'pointerdown', L.DomEvent.stop);
|
||||||
|
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
|
|
||||||
this.editTools.on(
|
this.editTools.on(
|
||||||
'editable:drawing:end',
|
'editable:drawing:end',
|
||||||
function(e) {
|
function(e) {
|
||||||
|
|
@ -124,6 +139,20 @@ BR.NogoAreas = L.Control.extend({
|
||||||
return L.DomUtil.create('div');
|
return L.DomUtil.create('div');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (!BR.Util.keyboardShortcutsAllowed(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (e.keyCode === this.options.shortcut.draw.disable && this.button.state() === BR.NogoAreas.STATE_CANCEL) {
|
||||||
|
this.stopDrawing(this.button);
|
||||||
|
} else if (
|
||||||
|
e.keyCode === this.options.shortcut.draw.enable &&
|
||||||
|
this.button.state() === BR.NogoAreas.STATE_CREATE
|
||||||
|
) {
|
||||||
|
this.startDrawing(this.button);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
displayUploadError: function(message) {
|
displayUploadError: function(message) {
|
||||||
$('#nogoError').text(message ? message : '');
|
$('#nogoError').text(message ? message : '');
|
||||||
$('#nogoError').css('display', message ? 'block' : 'none');
|
$('#nogoError').css('display', message ? 'block' : 'none');
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,9 @@ BR.PoiMarkers = L.Control.extend({
|
||||||
self.draw(false);
|
self.draw(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
var container = new L.DomUtil.create('div');
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
// keys not working when map container does not have focus, use document instead
|
|
||||||
L.DomEvent.removeListener(container, 'keyup', this._keyupListener);
|
|
||||||
L.DomEvent.addListener(document, 'keyup', this._keyupListener, this);
|
|
||||||
|
|
||||||
|
var container = new L.DomUtil.create('div');
|
||||||
return container;
|
return container;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -62,9 +60,8 @@ BR.PoiMarkers = L.Control.extend({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_keyupListener: function(e) {
|
_keydownListener: function(e) {
|
||||||
// Suppress shortcut handling when a text input field is focussed
|
if (!BR.Util.keyboardShortcutsAllowed(e)) {
|
||||||
if (document.activeElement.type == 'text' || document.activeElement.type == 'textarea') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (e.keyCode === this.options.shortcut.draw.disable) {
|
if (e.keyCode === this.options.shortcut.draw.disable) {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,14 @@ BR.Routing = L.Routing.extend({
|
||||||
textFunction: function(distance) {
|
textFunction: function(distance) {
|
||||||
return distance / 1000;
|
return distance / 1000;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
shortcut: {
|
||||||
|
draw: {
|
||||||
|
enable: 68, // char code for 'd'
|
||||||
|
disable: 27 // char code for 'ESC'
|
||||||
|
},
|
||||||
|
reverse: 82, // char code for 'r'
|
||||||
|
deleteLastPoint: 90 // char code for 'z'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -163,8 +171,7 @@ BR.Routing = L.Routing.extend({
|
||||||
this._draw
|
this._draw
|
||||||
);
|
);
|
||||||
|
|
||||||
// keys not working when map container does not have focus, use document instead
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
L.DomEvent.removeListener(this._container, 'keyup', this._keyupListener);
|
|
||||||
L.DomEvent.addListener(document, 'keyup', this._keyupListener, this);
|
L.DomEvent.addListener(document, 'keyup', this._keyupListener, this);
|
||||||
|
|
||||||
// enable drawing mode
|
// enable drawing mode
|
||||||
|
|
@ -336,16 +343,26 @@ BR.Routing = L.Routing.extend({
|
||||||
return segments;
|
return segments;
|
||||||
},
|
},
|
||||||
|
|
||||||
_keyupListener: function(e) {
|
_keydownListener: function(e) {
|
||||||
// Suppress shortcut handling when a text input field is focussed
|
if (!BR.Util.keyboardShortcutsAllowed(e)) {
|
||||||
if (document.activeElement.type == 'text' || document.activeElement.type == 'textarea') {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// add 'esc' to disable drawing
|
if (e.keyCode === this.options.shortcut.draw.disable) {
|
||||||
if (e.keyCode === 27) {
|
|
||||||
this._draw.disable();
|
this._draw.disable();
|
||||||
} else {
|
} else if (e.keyCode === this.options.shortcut.draw.enable) {
|
||||||
L.Routing.prototype._keyupListener.call(this, e);
|
this._draw.enable();
|
||||||
|
} else if (e.keyCode === this.options.shortcut.reverse) {
|
||||||
|
this.reverse();
|
||||||
|
} else if (e.keyCode === this.options.shortcut.deleteLastPoint) {
|
||||||
|
this.deleteLastPoint();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_keyupListener: function(e) {
|
||||||
|
// Prevent Leaflet from triggering drawing a second time on keyup,
|
||||||
|
// since this is already done in _keydownListener
|
||||||
|
if (e.keyCode === this.options.shortcut.draw.enable) {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -360,6 +377,12 @@ BR.Routing = L.Routing.extend({
|
||||||
this.setWaypoints(waypoints);
|
this.setWaypoints(waypoints);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
deleteLastPoint: function() {
|
||||||
|
if ((lastPoint = this.getLast())) {
|
||||||
|
this.removeWaypoint(lastPoint, function(err, data) {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_removeDistanceMarkers: function() {
|
_removeDistanceMarkers: function() {
|
||||||
if (this._map && this._distanceMarkers) {
|
if (this._map && this._distanceMarkers) {
|
||||||
this._map.removeLayer(this._distanceMarkers);
|
this._map.removeLayer(this._distanceMarkers);
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
BR.RoutingPathQuality = L.Control.extend({
|
BR.RoutingPathQuality = L.Control.extend({
|
||||||
|
options: {
|
||||||
|
shortcut: {
|
||||||
|
toggle: 67, // char code for 'c'
|
||||||
|
muteKeyCode: 77 // char code for 'm'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
initialize: function(map, layersControl, options) {
|
initialize: function(map, layersControl, options) {
|
||||||
L.setOptions(this, options);
|
L.setOptions(this, options);
|
||||||
|
|
||||||
|
|
@ -78,6 +85,7 @@ BR.RoutingPathQuality = L.Control.extend({
|
||||||
this.selectedProvider = this._initialProvider;
|
this.selectedProvider = this._initialProvider;
|
||||||
|
|
||||||
this._active = false;
|
this._active = false;
|
||||||
|
this._muted = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
onAdd: function(map) {
|
onAdd: function(map) {
|
||||||
|
|
@ -133,6 +141,11 @@ BR.RoutingPathQuality = L.Control.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.options.shortcut.muteKeyCode || this.options.shortcut.toggle) {
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
|
L.DomEvent.addListener(document, 'keyup', this._keyupListener, this);
|
||||||
|
}
|
||||||
|
|
||||||
this.routingPathButton = new L.easyButton({
|
this.routingPathButton = new L.easyButton({
|
||||||
states: states
|
states: states
|
||||||
}).addTo(map);
|
}).addTo(map);
|
||||||
|
|
@ -177,6 +190,26 @@ BR.RoutingPathQuality = L.Control.extend({
|
||||||
this._routingSegments.addLayer(layers[i]);
|
this._routingSegments.addLayer(layers[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (!BR.Util.keyboardShortcutsAllowed(e)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this._active && e.keyCode === this.options.shortcut.muteKeyCode) {
|
||||||
|
this._muted = true;
|
||||||
|
this._deactivate(this.routingPathButton);
|
||||||
|
}
|
||||||
|
if (!this._muted && e.keyCode === this.options.shortcut.toggle) {
|
||||||
|
this.routingPathButton.button.click();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_keyupListener: function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && this._muted && e.keyCode === this.options.shortcut.muteKeyCode) {
|
||||||
|
this._muted = false;
|
||||||
|
this._activate(this.routingPathButton);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,21 @@ BR.Search = L.Control.Geocoder.extend({
|
||||||
}),
|
}),
|
||||||
sizeInMeters: 800
|
sizeInMeters: 800
|
||||||
}),
|
}),
|
||||||
position: 'topleft'
|
position: 'topleft',
|
||||||
|
shortcut: {
|
||||||
|
search: 70 // char code for 'f'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function(options) {
|
||||||
|
L.Control.Geocoder.prototype.initialize.call(this, options);
|
||||||
|
L.setOptions(this, {
|
||||||
|
// i18next.t will only return 'undefined' if it is called in a static context
|
||||||
|
// (e.g. when added directly to "options:" above), so we have to call it here
|
||||||
|
placeholder: i18next.t('map.geocoder-placeholder')
|
||||||
|
});
|
||||||
|
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
markGeocode: function(result) {
|
markGeocode: function(result) {
|
||||||
|
|
@ -29,5 +43,12 @@ BR.Search = L.Control.Geocoder.extend({
|
||||||
if (this._geocodeMarker) {
|
if (this._geocodeMarker) {
|
||||||
this._map.removeLayer(this._geocodeMarker);
|
this._map.removeLayer(this._geocodeMarker);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.search) {
|
||||||
|
$('#map .leaflet-control-geocoder')[0].dispatchEvent(new MouseEvent('mousedown'));
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,10 @@ BR.Sidebar = L.Control.Sidebar.extend({
|
||||||
autopan: false,
|
autopan: false,
|
||||||
defaultTabId: '',
|
defaultTabId: '',
|
||||||
|
|
||||||
|
shortcut: {
|
||||||
|
toggleTabs: 84 // char code for 't'
|
||||||
|
},
|
||||||
|
|
||||||
// Tabs to be notified when shown or hidden
|
// Tabs to be notified when shown or hidden
|
||||||
// (tab div id -> object implementing show/hide methods)
|
// (tab div id -> object implementing show/hide methods)
|
||||||
listeningTabs: {}
|
listeningTabs: {}
|
||||||
|
|
@ -17,6 +21,8 @@ BR.Sidebar = L.Control.Sidebar.extend({
|
||||||
L.Control.Sidebar.prototype.initialize.call(this, id, options);
|
L.Control.Sidebar.prototype.initialize.call(this, id, options);
|
||||||
|
|
||||||
this.oldTab = null;
|
this.oldTab = null;
|
||||||
|
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
},
|
},
|
||||||
|
|
||||||
addTo: function(map) {
|
addTo: function(map) {
|
||||||
|
|
@ -34,6 +40,15 @@ BR.Sidebar = L.Control.Sidebar.extend({
|
||||||
this
|
this
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.recentTab = this.options.defaultTabId;
|
||||||
|
this.on(
|
||||||
|
'content',
|
||||||
|
function(tab) {
|
||||||
|
this.recentTab = tab.id;
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
this._rememberTabState();
|
this._rememberTabState();
|
||||||
|
|
||||||
if (L.Browser.touch && BR.Browser.touchScreenDetectable && !BR.Browser.touchScreen) {
|
if (L.Browser.touch && BR.Browser.touchScreenDetectable && !BR.Browser.touchScreen) {
|
||||||
|
|
@ -103,6 +118,30 @@ BR.Sidebar = L.Control.Sidebar.extend({
|
||||||
|
|
||||||
_storeActiveTab: function(e) {
|
_storeActiveTab: function(e) {
|
||||||
localStorage.setItem(this.storageId, e.id || '');
|
localStorage.setItem(this.storageId, e.id || '');
|
||||||
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.toggleTabs) {
|
||||||
|
if ($('#sidebarTabs > ul > li[class=active]').length) {
|
||||||
|
// sidebar is currently open
|
||||||
|
if (e.shiftKey) {
|
||||||
|
// try to find next tab
|
||||||
|
var nextTab = $('#sidebarTabs > ul > li[class=active] ~ li:not([hidden]) > a');
|
||||||
|
if (!nextTab.length) {
|
||||||
|
// wrap around to first tab
|
||||||
|
nextTab = $('#sidebarTabs > ul > li:not([hidden]) > a');
|
||||||
|
}
|
||||||
|
// switch to next or first tab
|
||||||
|
this.open(nextTab.attr('href').slice(1));
|
||||||
|
} else {
|
||||||
|
// close current tab
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// sidebar is currently closed, open recent or default tab
|
||||||
|
this.open(this.recentTab);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ BR.tracksLoader = function(map, layersControl, routing) {
|
||||||
},
|
},
|
||||||
addToMap: false,
|
addToMap: false,
|
||||||
// File size limit in kb (default: 1024) ?
|
// File size limit in kb (default: 1024) ?
|
||||||
fileSizeLimit: 1024
|
fileSizeLimit: 1024,
|
||||||
|
shortcut: {
|
||||||
|
open: 79 // char code for 'o'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_initContainer: function() {
|
_initContainer: function() {
|
||||||
|
|
@ -31,6 +34,8 @@ BR.tracksLoader = function(map, layersControl, routing) {
|
||||||
var fileInput;
|
var fileInput;
|
||||||
var container = L.DomUtil.get('navbarLoadTracksContainer');
|
var container = L.DomUtil.get('navbarLoadTracksContainer');
|
||||||
|
|
||||||
|
L.DomEvent.addListener(document, 'keydown', this._keydownListener, this);
|
||||||
|
|
||||||
// Create an invisible file input
|
// Create an invisible file input
|
||||||
fileInput = L.DomUtil.create('input', 'hidden', container);
|
fileInput = L.DomUtil.create('input', 'hidden', container);
|
||||||
fileInput.type = 'file';
|
fileInput.type = 'file';
|
||||||
|
|
@ -62,6 +67,16 @@ BR.tracksLoader = function(map, layersControl, routing) {
|
||||||
var dummy = L.DomUtil.create('div');
|
var dummy = L.DomUtil.create('div');
|
||||||
dummy.hidden = true;
|
dummy.hidden = true;
|
||||||
return dummy;
|
return dummy;
|
||||||
|
},
|
||||||
|
|
||||||
|
_keydownListener: function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.open) {
|
||||||
|
if (e.shiftKey) {
|
||||||
|
$('#loadNogos').modal('show');
|
||||||
|
} else {
|
||||||
|
$('#navbarLoadTracks')[0].click();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var tracksLoaderControl = new TracksLoader();
|
var tracksLoaderControl = new TracksLoader();
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,12 @@ BR.stravaSegments = function(map, layersControl) {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
L.setOptions(this, {
|
||||||
|
shortcut: {
|
||||||
|
toggleLayer: 83 // char code for 's'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// hide strava buttons when layer is inactive
|
// hide strava buttons when layer is inactive
|
||||||
var toggleStravaControl = function() {
|
var toggleStravaControl = function() {
|
||||||
var stravaBar = stravaControl.runningButton.button.parentElement;
|
var stravaBar = stravaControl.runningButton.button.parentElement;
|
||||||
|
|
@ -24,5 +30,20 @@ BR.stravaSegments = function(map, layersControl) {
|
||||||
toggleStravaControl();
|
toggleStravaControl();
|
||||||
stravaControl.stravaLayer.on('add remove', toggleStravaControl);
|
stravaControl.stravaLayer.on('add remove', toggleStravaControl);
|
||||||
|
|
||||||
|
L.DomEvent.addListener(
|
||||||
|
document,
|
||||||
|
'keydown',
|
||||||
|
function(e) {
|
||||||
|
if (BR.Util.keyboardShortcutsAllowed(e) && e.keyCode === this.options.shortcut.toggleLayer) {
|
||||||
|
if (map.hasLayer(stravaControl.stravaLayer)) {
|
||||||
|
map.removeLayer(stravaControl.stravaLayer);
|
||||||
|
} else {
|
||||||
|
map.addLayer(stravaControl.stravaLayer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this
|
||||||
|
);
|
||||||
|
|
||||||
return stravaControl;
|
return stravaControl;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@
|
||||||
"description": "Online service of the BRouter routing engine. For the offline Android app and more information see <a href=\"https://brouter.de/\" target=\"_blank\">brouter.de</a>",
|
"description": "Online service of the BRouter routing engine. For the offline Android app and more information see <a href=\"https://brouter.de/\" target=\"_blank\">brouter.de</a>",
|
||||||
"details": "<i><a href=\"{{privacyPolicyUrl}}\" target=\"_blank\">Privacy Policy</a></i>, \n<i><a href=\"https://github.com/nrenner/brouter-web#credits-and-licenses\" target=\"_blank\">Credits</a></i>,\n<i><a href=\"https://github.com/nrenner/brouter-web/blob/master/CHANGELOG.md\" target=\"_blank\">Changelog</a></i> and\n<i><a href=\"https://github.com/nrenner/brouter-web#readme\" target=\"_blank\">more info</a></i> on the client.",
|
"details": "<i><a href=\"{{privacyPolicyUrl}}\" target=\"_blank\">Privacy Policy</a></i>, \n<i><a href=\"https://github.com/nrenner/brouter-web#credits-and-licenses\" target=\"_blank\">Credits</a></i>,\n<i><a href=\"https://github.com/nrenner/brouter-web/blob/master/CHANGELOG.md\" target=\"_blank\">Changelog</a></i> and\n<i><a href=\"https://github.com/nrenner/brouter-web#readme\" target=\"_blank\">more info</a></i> on the client.",
|
||||||
"support": "General discussions/questions, support",
|
"support": "General discussions/questions, support",
|
||||||
"title": "About"
|
"title": "About",
|
||||||
|
"tooltip": "Show more information about Brouter-Web (H key)"
|
||||||
},
|
},
|
||||||
"credits": {
|
"credits": {
|
||||||
"brouter": "BRouter",
|
"brouter": "BRouter",
|
||||||
|
|
@ -41,6 +42,7 @@
|
||||||
"ascend": "Ascend",
|
"ascend": "Ascend",
|
||||||
"cost": "Cost",
|
"cost": "Cost",
|
||||||
"distance": "Distance",
|
"distance": "Distance",
|
||||||
|
"elevation-chart": "Toggle elevation chart (E key)",
|
||||||
"energy-per-100km": "Energy per 100 km",
|
"energy-per-100km": "Energy per 100 km",
|
||||||
"hours": "hours",
|
"hours": "hours",
|
||||||
"hours-abbrev": "h",
|
"hours-abbrev": "h",
|
||||||
|
|
@ -80,9 +82,10 @@
|
||||||
"attribution-osm-long": "OpenStreetMap contributors",
|
"attribution-osm-long": "OpenStreetMap contributors",
|
||||||
"attribution-osm-short": "OpenStreetMap",
|
"attribution-osm-short": "OpenStreetMap",
|
||||||
"clear-route": "Clear route data",
|
"clear-route": "Clear route data",
|
||||||
|
"clear-route-tooltip": "Clear route data (Backspace key)",
|
||||||
"copyright": "Copyright",
|
"copyright": "Copyright",
|
||||||
"cycling": "Cycling",
|
"cycling": "Cycling",
|
||||||
"delete-last-point": "Delete last point",
|
"delete-last-point": "Delete last point (Z key)",
|
||||||
"delete-nogo-areas": "Delete all no-go areas",
|
"delete-nogo-areas": "Delete all no-go areas",
|
||||||
"delete-pois": "Delete all points of interest",
|
"delete-pois": "Delete all points of interest",
|
||||||
"delete-route": "Delete route",
|
"delete-route": "Delete route",
|
||||||
|
|
@ -91,6 +94,8 @@
|
||||||
"draw-route-start": "Draw route (D key)",
|
"draw-route-start": "Draw route (D key)",
|
||||||
"draw-route-stop": "Stop drawing route (ESC key)",
|
"draw-route-stop": "Stop drawing route (ESC key)",
|
||||||
"enter-poi-name": "Enter Point of Interest name",
|
"enter-poi-name": "Enter Point of Interest name",
|
||||||
|
"geocoder": "Search (F key)",
|
||||||
|
"geocoder-placeholder": "Search…",
|
||||||
"hikebike-hillshading": "Hillshading",
|
"hikebike-hillshading": "Hillshading",
|
||||||
"hiking": "Hiking",
|
"hiking": "Hiking",
|
||||||
"layer": {
|
"layer": {
|
||||||
|
|
@ -110,25 +115,25 @@
|
||||||
"topo": "OpenTopoMap"
|
"topo": "OpenTopoMap"
|
||||||
},
|
},
|
||||||
"loading": "Loading…",
|
"loading": "Loading…",
|
||||||
"locate-me": "Show me where I am",
|
"locate-me": "Show me where I am (L key)",
|
||||||
"nogo": {
|
"nogo": {
|
||||||
"cancel": "Cancel drawing no-go area",
|
"cancel": "Cancel drawing no-go area (ESC key)",
|
||||||
"click-drag": "Click and drag to draw circle",
|
"click-drag": "Click and drag to draw circle",
|
||||||
"draw": "Draw no-go area (circle)",
|
"draw": "Draw circular no-go area (N key)",
|
||||||
"edit": "Click to edit",
|
"edit": "Click to edit",
|
||||||
"help": "□ = move / resize, <span class=\"fa fa-trash-o\"></span> = delete,<br>click circle to quit editing"
|
"help": "□ = move / resize, <span class=\"fa fa-trash-o\"></span> = delete,<br>click circle to quit editing"
|
||||||
},
|
},
|
||||||
"opacity-slider": "Set transparency of route track and markers. Press and hold the 'M' key to temporarily hide the planned route.",
|
"opacity-slider": "Set transparency of route track and markers\n(Hold M key to mute temporarily)",
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"privacy": "Privacy",
|
"privacy": "Privacy",
|
||||||
"reverse-route": "Reverse route",
|
"reverse-route": "Reverse route (R key)",
|
||||||
"route-quality-altitude": "Altitude coding",
|
"route-quality-altitude": "Altitude coding (C key to toggle)",
|
||||||
"route-quality-cost": "Cost coding",
|
"route-quality-cost": "Cost coding (C key to toggle)",
|
||||||
"route-quality-incline": "Incline coding",
|
"route-quality-incline": "Incline coding (C key to toggle)",
|
||||||
"strava-biking": "Show Strava biking segments",
|
"strava-biking": "Show Strava biking segments\n(S key to toggle layer, click to reload for current area)",
|
||||||
"strava-running": "Show Strava running segments",
|
"strava-running": "Show Strava running segments\n(S key to toggle layer, click to reload for current area)",
|
||||||
"zoomInTitle": "Zoom in",
|
"zoomInTitle": "Zoom in (+ key)",
|
||||||
"zoomOutTitle": "Zoom out"
|
"zoomOutTitle": "Zoom out (- key)"
|
||||||
},
|
},
|
||||||
"modal": {
|
"modal": {
|
||||||
"close": "Close"
|
"close": "Close"
|
||||||
|
|
@ -142,9 +147,11 @@
|
||||||
"third": "3rd alternative"
|
"third": "3rd alternative"
|
||||||
},
|
},
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
|
"export-tooltip": "Export route (X key)",
|
||||||
"load": {
|
"load": {
|
||||||
"nogos": "No-go areas",
|
"nogos": "No-go areas",
|
||||||
"title": "Load",
|
"title": "Load",
|
||||||
|
"tooltip": "Load tracks (O key)\nLoad No-go areas (Shift+O)",
|
||||||
"tracks": "Tracks"
|
"tracks": "Tracks"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
|
|
@ -168,7 +175,8 @@
|
||||||
"trekking-steep": "Trekking bike (steep)",
|
"trekking-steep": "Trekking bike (steep)",
|
||||||
"vm-forum-liegerad-schnell": "Recumbent bike (fast)",
|
"vm-forum-liegerad-schnell": "Recumbent bike (fast)",
|
||||||
"vm-forum-velomobil-schnell": "Velomobile (fast)"
|
"vm-forum-velomobil-schnell": "Velomobile (fast)"
|
||||||
}
|
},
|
||||||
|
"profile-tooltip": "\n(G key to switch)"
|
||||||
},
|
},
|
||||||
"sidebar": {
|
"sidebar": {
|
||||||
"analysis": {
|
"analysis": {
|
||||||
|
|
@ -183,17 +191,21 @@
|
||||||
"total_known": "Total Known:",
|
"total_known": "Total Known:",
|
||||||
"unknown": "Unknown"
|
"unknown": "Unknown"
|
||||||
},
|
},
|
||||||
"title": "Analysis"
|
"title": "Analysis",
|
||||||
|
"tooltip": "Analyse route\n(T key to toggle, Shift+T to switch to next tab)"
|
||||||
},
|
},
|
||||||
"customize-profile": {
|
"customize-profile": {
|
||||||
"title": "Customize profile"
|
"title": "Customize profile",
|
||||||
|
"tooltip": "Customize profile\n(T key to toggle, Shift+T to switch to next tab)"
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"sync-map": "Synchronize map",
|
"sync-map": "Synchronize map",
|
||||||
"title": "Data"
|
"title": "Data",
|
||||||
|
"tooltip": "Show detailed route data table\n(T key to toggle, Shift+T to switch to next tab)"
|
||||||
},
|
},
|
||||||
"itinerary": {
|
"itinerary": {
|
||||||
"title": "Itinerary"
|
"title": "Itinerary",
|
||||||
|
"tooltip": "Show itinerary\n(T key to toggle, Shift+T to switch to next tab)"
|
||||||
},
|
},
|
||||||
"layers": {
|
"layers": {
|
||||||
"category": {
|
"category": {
|
||||||
|
|
@ -219,7 +231,8 @@
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"type": "Type"
|
"type": "Type"
|
||||||
},
|
},
|
||||||
"title": "Layers"
|
"title": "Layers",
|
||||||
|
"tooltip": "Select layers\n(T key to toggle, Shift+T to switch to next tab)"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"apply": "Apply",
|
"apply": "Apply",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue