nakarte

Source code of https://map.sikmir.ru (fork)
git clone git://git.sikmir.ru/nakarte
Log | Files | Refs | LICENSE

commit 9388cdd1458be0663c56059efcfbea8125b001ff
parent 400232b800cb8f183d5524109bf9cafa643c8192
Author: myadzel <myadzel@gmail.com>
Date:   Fri,  5 Dec 2025 17:52:48 +0100

Layers control: allow user change layers hotkeys

Fixes: #1361

Diffstat:
Msrc/lib/leaflet.control.layers.configure/index.js | 78+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
Msrc/lib/leaflet.control.layers.configure/style.css | 18+++++++++++++++++-
Msrc/lib/leaflet.control.layers.hotkeys/index.js | 18+++++++++++-------
3 files changed, 101 insertions(+), 13 deletions(-)

diff --git a/src/lib/leaflet.control.layers.configure/index.js b/src/lib/leaflet.control.layers.configure/index.js @@ -19,6 +19,13 @@ class LayersConfigDialog { this.initWindow(); } + allLayers() { + return [ + ...([].concat(...this.builtInLayers.map((group) => group.layers))), + ...this.customLayers + ]; + } + initWindow() { const container = this.window = L.DomUtil.create('div', 'leaflet-layers-dialog-wrapper'); @@ -32,10 +39,12 @@ class LayersConfigDialog { <!-- ko foreach: layerGroups --> <div class="section-header" data-bind="html: group"></div> <!-- ko foreach: layers --> - <label> + <label class="layer-label"> <input type="checkbox" data-bind="checked: enabled"/> <span data-bind="text: title"> </span> + <input type="text" class="hotkey-input" size="1" maxlength="1" + data-bind="value: hotkey, event: {keypress: $root.validateHotkeyAndDisplayError.bind($root, event, hotkey)}"/> </label> <!-- /ko --> <!-- /ko --> @@ -68,6 +77,7 @@ class LayersConfigDialog { group.layers.map((l) => ({ title: l.title, enabled: ko.observable(l.enabled), + hotkey: ko.observable(l.layer.hotkey), origLayer: l, })) ), @@ -80,6 +90,7 @@ class LayersConfigDialog { this.customLayers.map((l) => ({ title: l.title, enabled: ko.observable(l.enabled), + hotkey: ko.observable(l.layer.hotkey), origLayer: l, })) ), @@ -91,6 +102,7 @@ class LayersConfigDialog { for (const group of this.layerGroups()) { for (const layer of group.layers()) { layer.origLayer.enabled = layer.enabled(); + layer.origLayer.layer.hotkey = layer.hotkey(); } } } @@ -125,6 +137,46 @@ class LayersConfigDialog { } } } + + validateHotkeyAndDisplayError(e, hotkey) { + const isValid = this.validateHotkey(e, hotkey); + + if (!isValid) { + setTimeout(() => { + e.target.value = ''; + }, 0); + } + + e.target.setAttribute('data-error', !isValid); + + return isValid; + } + + validateHotkey(e, hotkey) { + const hotkeys = this.allLayers().map((layer) => layer.layer.hotkey).filter((layer) => layer); + + const codeRegexp = /^Key|Digit/u; + + if (!codeRegexp.test(e.code)) { + return false; + } + + let value = e.code.replace(codeRegexp, ''); + + setTimeout(() => { + e.target.value = value; + }, 0); + + if (hotkey && hotkeys.includes(value)) { + return value === hotkey; + } + + if (!hotkey) { + return !hotkeys.includes(value); + } + + return true; + } } function enableConfig(control, {layers, customLayersOrder}) { @@ -198,7 +250,21 @@ function enableConfig(control, {layers, customLayersOrder}) { safeLocalStorage.setItem('leafletLayersSettings', JSON.stringify(settings)); }, - loadSettings: function() { + getLayerDefaultHotkey: function(layer) { + const layerOptions = layer?.layer.options; + if (!layerOptions) { + return null; + } + if (layerOptions.hotkey) { + return layerOptions.hotkey; + } + if (layerOptions.code?.length === 1) { + return layerOptions.code; + } + return null; + }, + + loadSettings: function() { this.migrateSetting(); // load settings from storage const serialized = safeLocalStorage.getItem('leafletLayersSettings'); @@ -240,6 +306,7 @@ function enableConfig(control, {layers, customLayersOrder}) { // if storage is empty enable only default layers // if new default layer appears it will be enabled layer.enabled = layerSettings.enabled ?? layer.isDefault; + layer.layer.hotkey = layerSettings.hotkey || this.getLayerDefaultHotkey(layer); } this.updateLayers(); }, @@ -331,6 +398,7 @@ function enableConfig(control, {layers, customLayersOrder}) { code: layer.layer.options.code, isCustom: layer.isCustom, enabled: layer.enabled, + hotkey: layer.layer.hotkey, }); } const settings = {layers: layersSettings}; @@ -548,7 +616,7 @@ function enableConfig(control, {layers, customLayersOrder}) { caption: 'Save', callback: (fieldValues) => this.onCustomLayerChangeClicked(layer, fieldValues), }, - {caption: 'Delete', callback: () => this.onCustomLayerDeletelClicked(layer)}, + {caption: 'Delete', callback: () => this.onCustomLayerDeleteClicked(layer)}, {caption: 'Cancel', callback: () => this.onCustomLayerCancelClicked()} ], layer.fieldValues ); @@ -572,8 +640,8 @@ function enableConfig(control, {layers, customLayersOrder}) { const layerPos = this._customLayers.indexOf(layer); this._customLayers.remove(layer); - const newLayer = this.createCustomLayer(newFieldValues); + newLayer.layer.hotkey = layer.layer.hotkey; this._customLayers.splice(layerPos, 0, newLayer); const newLayerVisible = ( this._map.hasLayer(layer.layer) && @@ -591,7 +659,7 @@ function enableConfig(control, {layers, customLayersOrder}) { this.hideCustomLayerForm(); }, - onCustomLayerDeletelClicked: function(layer) { + onCustomLayerDeleteClicked: function(layer) { this._map.removeLayer(layer.layer); this._customLayers.remove(layer); this.updateLayers(); diff --git a/src/lib/leaflet.control.layers.configure/style.css b/src/lib/leaflet.control.layers.configure/style.css @@ -66,7 +66,7 @@ white-space: nowrap; } -.leaflet-layers-config-window label { +.leaflet-layers-config-window .layer-label { display: block; } @@ -163,3 +163,19 @@ font-size: 10px; color: #777; } + +.leaflet-layers-config-window .hotkey-input { + color: #999; + border: 1px solid transparent; + font-size: 9px; +} + +.leaflet-layers-config-window .hotkey-input:focus, +.leaflet-layers-config-window .layer-label:hover .hotkey-input { + border-color: #999; +} + +.leaflet-layers-config-window .hotkey-input:focus[data-error=true] { + border-color: red !important; + transition: border-color 2s 0s; +} diff --git a/src/lib/leaflet.control.layers.hotkeys/index.js b/src/lib/leaflet.control.layers.hotkeys/index.js @@ -2,16 +2,20 @@ import L from 'leaflet'; import './style.css'; function getLayerHotkey(layer) { - if (!layer || !layer.options) { + if (!layer) { return null; } - let hotkey = layer.options.hotkey; - if (hotkey) { - return hotkey; + if (layer.hotkey) { + return layer.hotkey; } - hotkey = layer.options.code; - if (hotkey && hotkey.length === 1) { - return hotkey; + if (!layer.options) { + return null; + } + if (layer.options.hotkey) { + return layer.options.hotkey; + } + if (layer.options.code?.length === 1) { + return layer.options.code; } return null; }