qwc2 2025.11.19 → 2025.11.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/components/AppMenu.js +141 -204
  2. package/components/AttributeTableWidget.js +5 -0
  3. package/components/FeatureAttributesWindow.js +1 -2
  4. package/components/FullscreenSwitcher.js +3 -0
  5. package/components/Icon.js +6 -0
  6. package/components/ImportLayer.js +3 -9
  7. package/components/LayerInfoWindow.js +1 -2
  8. package/components/MapButton.js +2 -0
  9. package/components/NumericInputWindow.js +1 -2
  10. package/components/PickFeature.js +1 -1
  11. package/components/PluginsContainer.js +54 -9
  12. package/components/ResizeableWindow.js +18 -9
  13. package/components/SearchBox.js +117 -124
  14. package/components/ServiceInfoWindow.js +1 -2
  15. package/components/StandardApp.js +0 -1
  16. package/components/ThemeLayersListWindow.js +8 -7
  17. package/components/ThemeList.js +7 -2
  18. package/components/WindowManager.js +0 -1
  19. package/components/map/layers/VectorLayer.js +4 -2
  20. package/components/map3d/HeightProfile3D.js +0 -1
  21. package/components/map3d/Map3D.js +1 -1
  22. package/components/map3d/View3DSwitcher.js +2 -1
  23. package/components/map3d/drawtool/NumericInput3D.js +1 -2
  24. package/components/map3d/layers/VectorLayer3D.js +2 -2
  25. package/components/style/App.css +4 -0
  26. package/components/style/AppMenu.css +33 -48
  27. package/components/style/DefaultColorScheme.css +1 -0
  28. package/components/style/PickFeature.css +0 -6
  29. package/components/style/ResizeableWindow.css +0 -4
  30. package/components/style/SearchBox.css +0 -21
  31. package/components/widgets/ColorButton.js +7 -2
  32. package/components/widgets/ComboBox.js +18 -16
  33. package/components/widgets/EditableSelect.js +5 -10
  34. package/components/widgets/LayerCatalogWidget.js +66 -16
  35. package/components/widgets/MenuButton.js +16 -15
  36. package/components/widgets/PopupMenu.js +153 -13
  37. package/components/widgets/ToggleSwitch.js +5 -2
  38. package/components/widgets/style/ComboBox.css +7 -20
  39. package/components/widgets/style/EditableSelect.css +0 -2
  40. package/components/widgets/style/MenuButton.css +1 -17
  41. package/components/widgets/style/PopupMenu.css +20 -0
  42. package/package.json +1 -1
  43. package/plugins/AttributeTable.js +0 -1
  44. package/plugins/BackgroundSwitcher.js +104 -8
  45. package/plugins/Cyclomedia.js +1 -2
  46. package/plugins/FeatureForm.js +3 -6
  47. package/plugins/GeometryDigitizer.js +1 -2
  48. package/plugins/HeightProfile.js +2 -5
  49. package/plugins/Identify.js +2 -5
  50. package/plugins/LayerCatalog.js +2 -13
  51. package/plugins/LayerTree.js +30 -17
  52. package/plugins/MapLegend.js +1 -2
  53. package/plugins/ObjectList.js +0 -1
  54. package/plugins/Panoramax.js +1 -2
  55. package/plugins/Print.js +1 -2
  56. package/plugins/Routing.js +1 -2
  57. package/plugins/TimeManager.js +2 -5
  58. package/plugins/ValueTool.js +1 -2
  59. package/plugins/View3D.js +0 -1
  60. package/plugins/map/MeasurementSupport.js +2 -2
  61. package/plugins/map3d/Identify3D.js +1 -2
  62. package/plugins/map3d/Measure3D.js +21 -12
  63. package/plugins/style/BackgroundSwitcher.css +2 -1
  64. package/plugins/style/LayerTree.css +3 -18
  65. package/static/translations/ca-ES.json +29 -29
  66. package/static/translations/es-ES.json +34 -34
  67. package/utils/MapUtils.js +6 -0
  68. package/utils/MiscUtils.js +12 -0
@@ -1,13 +1,14 @@
1
1
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
3
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
4
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
5
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
2
6
  function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
3
7
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
8
  function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
5
9
  function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
6
10
  function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
7
11
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
8
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
9
- function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
10
- function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
11
12
  function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
12
13
  function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
13
14
  function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
@@ -58,7 +59,10 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
58
59
  _defineProperty(_this, "renderPlugins", function () {
59
60
  var device = ConfigUtils.isMobile() ? 'mobile' : 'desktop';
60
61
  var plugins = PluginStore.getPlugins();
61
- return _this.props.pluginsConfig.map(function (pluginConf) {
62
+ return _toConsumableArray(_this.props.pluginsConfig).sort(function (a, b) {
63
+ var _ref, _a$order;
64
+ return (_ref = (_a$order = a.order) !== null && _a$order !== void 0 ? _a$order : 0 - b.order) !== null && _ref !== void 0 ? _ref : 0;
65
+ }).map(function (pluginConf) {
62
66
  var _this$props$theme, _this$props$theme2, _pluginConf$key;
63
67
  var Plugin = plugins[pluginConf.name + "Plugin"];
64
68
  if (!Plugin) {
@@ -157,6 +161,47 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
157
161
  el.style.setProperty('--buttons-container-height', "".concat(height, "px"));
158
162
  }
159
163
  });
164
+ var mutationObserver = new MutationObserver(function (mutations) {
165
+ mutationObserver.disconnect();
166
+ var _iterator = _createForOfIteratorHelper(mutations),
167
+ _step;
168
+ try {
169
+ var _loop = function _loop() {
170
+ var m = _step.value;
171
+ if (m.type === "childList") {
172
+ // Reorder child nodes for natural tab focus order
173
+ var children = _toConsumableArray(el.children);
174
+ var slots = {};
175
+ children.forEach(function (child) {
176
+ if (child.dataset.subslot === undefined) {
177
+ var _slots$child$dataset$;
178
+ var subslot = ((_slots$child$dataset$ = slots[child.dataset.slot]) !== null && _slots$child$dataset$ !== void 0 ? _slots$child$dataset$ : 0) - 1;
179
+ slots[child.dataset.slot] = child.dataset.subslot = subslot;
180
+ child.style.order = 100 * parseInt(child.style.order, 10) + subslot;
181
+ }
182
+ });
183
+ children.sort(function (a, b) {
184
+ return b.style.order - a.style.order;
185
+ }).forEach(function (node) {
186
+ return el.appendChild(node);
187
+ });
188
+ }
189
+ };
190
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
191
+ _loop();
192
+ }
193
+ } catch (err) {
194
+ _iterator.e(err);
195
+ } finally {
196
+ _iterator.f();
197
+ }
198
+ mutationObserver.observe(el, {
199
+ childList: true
200
+ });
201
+ });
202
+ mutationObserver.observe(el, {
203
+ childList: true
204
+ });
160
205
  resizeObserver.observe(el);
161
206
  el.recomputeSpacers = function () {
162
207
  var slots = new Set();
@@ -173,7 +218,7 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
173
218
  var child = document.createElement("div");
174
219
  child.className = "map-buttons-spacer";
175
220
  child.dataset.spacer = 1;
176
- child.style.order = i;
221
+ child.style.order = 100 * i;
177
222
  el.appendChild(child);
178
223
  }
179
224
  }
@@ -210,14 +255,14 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
210
255
  }, /*#__PURE__*/React.createElement(BottomToolPortalContext.Provider, {
211
256
  value: this.state.bottomToolContainerRef
212
257
  }, haveRefs ? this.renderPlugins() : null, haveRefs ? this.props.children : null)))), /*#__PURE__*/React.createElement(WindowManager, null), /*#__PURE__*/React.createElement("div", {
213
- className: "map-container",
214
- ref: this.setMapContainerRef,
215
- style: mapContainerStyle
216
- }, /*#__PURE__*/React.createElement(ProcessNotifications, null)), /*#__PURE__*/React.createElement("div", {
217
258
  className: "map-buttons-container",
218
259
  ref: this.setButtonContainerRef,
219
260
  style: mapContainerStyle
220
261
  }), /*#__PURE__*/React.createElement("div", {
262
+ className: "map-container",
263
+ ref: this.setMapContainerRef,
264
+ style: mapContainerStyle
265
+ }, /*#__PURE__*/React.createElement(ProcessNotifications, null)), /*#__PURE__*/React.createElement("div", {
221
266
  className: "app-infos-container",
222
267
  ref: this.setAppInfosContainerRef,
223
268
  style: mapContainerStyle
@@ -46,11 +46,6 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
46
46
  _defineProperty(_this, "state", {
47
47
  geometry: null
48
48
  });
49
- _defineProperty(_this, "renderRole", function (role) {
50
- return React.Children.toArray(_this.props.children).find(function (child) {
51
- return child.props.role === role;
52
- });
53
- });
54
49
  _defineProperty(_this, "onClose", function (ev) {
55
50
  if (_this.state.externalWindow) {
56
51
  _this.state.externalWindow.removeEventListener('beforeunload', _this.props.onClose);
@@ -241,7 +236,10 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
241
236
  onResizeStop: _this.onResizeStop,
242
237
  ref: _this.initRnd
243
238
  }, /*#__PURE__*/React.createElement("div", {
244
- className: "resizeable-window-contents"
239
+ className: "resizeable-window-contents",
240
+ onFocus: function onFocus() {
241
+ return _this.props.raiseWindow(_this.id);
242
+ }
245
243
  }, _this.renderTitleBar(), /*#__PURE__*/React.createElement("div", {
246
244
  className: bodyclasses,
247
245
  onMouseDown: function onMouseDown() {
@@ -256,7 +254,7 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
256
254
  className: "resizeable-window-portal-container"
257
255
  }, /*#__PURE__*/React.createElement(portals.OutPortal, {
258
256
  node: _this.portalNode
259
- })) : _this.renderRole("body"))));
257
+ })) : _this.props.children)));
260
258
  });
261
259
  _defineProperty(_this, "setInitialSize", function (container) {
262
260
  if (!container) {
@@ -302,7 +300,7 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
302
300
  className: "resizeable-window-portal-container"
303
301
  }, /*#__PURE__*/React.createElement(portals.OutPortal, {
304
302
  node: _this.portalNode
305
- })) : _this.renderRole("body"))), _this.state.externalWindow.document.body);
303
+ })) : _this.props.children)), _this.state.externalWindow.document.body);
306
304
  });
307
305
  _defineProperty(_this, "initRnd", function (el) {
308
306
  if (el) {
@@ -456,6 +454,17 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
456
454
  _this.dragShield = null;
457
455
  _this.id = uuidv4();
458
456
  _this.portalNode = props.usePortal ? portals.createHtmlPortalNode() : null;
457
+ if (_this.portalNode) {
458
+ _this.portalNode.element.addEventListener('click', function () {
459
+ return _this.props.raiseWindow(_this.id);
460
+ });
461
+ _this.portalNode.element.addEventListener('focus', function () {
462
+ return _this.props.raiseWindow(_this.id);
463
+ });
464
+ _this.portalNode.element.addEventListener('focusin', function () {
465
+ return _this.props.raiseWindow(_this.id);
466
+ });
467
+ }
459
468
  return _this;
460
469
  }
461
470
  _inherits(ResizeableWindow, _React$Component);
@@ -513,7 +522,7 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
513
522
  return [this.portalNode ? /*#__PURE__*/React.createElement(portals.InPortal, {
514
523
  key: "InPortal",
515
524
  node: this.portalNode
516
- }, this.renderRole("body")) : null, this.state.externalWindow ? this.renderExternalWindow() : this.renderInternalWindowContainer()];
525
+ }, this.props.children) : null, this.state.externalWindow ? this.renderExternalWindow() : this.renderInternalWindowContainer()];
517
526
  }
518
527
  }]);
519
528
  }(React.Component);
@@ -67,6 +67,7 @@ import ButtonBar from './widgets/ButtonBar';
67
67
  import ComboBox from './widgets/ComboBox';
68
68
  import InputContainer from './widgets/InputContainer';
69
69
  import NumberInput from './widgets/NumberInput';
70
+ import PopupMenu from './widgets/PopupMenu';
70
71
  import Spinner from './widgets/Spinner';
71
72
  import './style/SearchBox.css';
72
73
  var SearchBox = /*#__PURE__*/function (_React$Component) {
@@ -149,7 +150,6 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
149
150
  }, LocaleUtils.tr("search.none")), _this.state.searchFilterRegions.map(function (group, gidx) {
150
151
  return [/*#__PURE__*/React.createElement("div", {
151
152
  "data-group-header": gidx,
152
- disabled: true,
153
153
  key: "group" + gidx
154
154
  }, group.name)].concat(_toConsumableArray(group.items.map(function (item, idx) {
155
155
  return /*#__PURE__*/React.createElement("div", {
@@ -243,23 +243,30 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
243
243
  if (!_this.state.resultsVisible) {
244
244
  return false;
245
245
  }
246
- var children = [_this.renderRecentResults(), _this.renderFilters(), _this.renderResults()];
246
+ var children = [_this.renderRecentResults(), _this.renderFilters(), _this.renderResults()].flat(Infinity);
247
247
  children = children.filter(function (child) {
248
248
  return !isEmpty(child);
249
249
  });
250
250
  if (isEmpty(children)) {
251
251
  if (isEmpty(_this.state.pendingSearches) && _this.state.searchResults.query_text) {
252
252
  children = /*#__PURE__*/React.createElement("div", {
253
- className: "searchbox-noresults"
253
+ className: "searchbox-noresults",
254
+ disabled: true,
255
+ key: "noresults"
254
256
  }, LocaleUtils.tr("search.noresults"));
255
257
  } else {
256
258
  return null;
257
259
  }
258
260
  }
259
- return /*#__PURE__*/React.createElement("div", {
261
+ return /*#__PURE__*/React.createElement(PopupMenu, {
262
+ anchor: _this.searchBox,
260
263
  className: "searchbox-results",
261
- onMouseDown: _this.setPreventBlur,
262
- ref: MiscUtils.setupKillTouchEvents
264
+ onClose: function onClose() {
265
+ return _this.setState({
266
+ resultsVisible: false
267
+ });
268
+ },
269
+ setMaxWidth: true
263
270
  }, children);
264
271
  });
265
272
  _defineProperty(_this, "renderRecentResults", function () {
@@ -269,69 +276,63 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
269
276
  if (isEmpty(recentSearches) || recentSearches.length === 1 && recentSearches[0].toLowerCase() === _this.state.searchText.toLowerCase()) {
270
277
  return null;
271
278
  }
272
- return /*#__PURE__*/React.createElement("div", {
273
- key: "recent"
274
- }, /*#__PURE__*/React.createElement("div", {
279
+ return [/*#__PURE__*/React.createElement("div", {
275
280
  className: "searchbox-results-section-title",
276
- onClick: function onClick() {
277
- return _this.toggleSection("recent");
278
- },
279
- onMouseDown: MiscUtils.killEvent
281
+ key: "recent",
282
+ onClick: function onClick(ev) {
283
+ return _this.toggleSection(ev, "recent");
284
+ }
280
285
  }, /*#__PURE__*/React.createElement(Icon, {
281
286
  icon: _this.isCollapsed("recent") ? "expand" : "collapse"
282
- }), LocaleUtils.tr("search.recent")), !_this.isCollapsed("recent") ? /*#__PURE__*/React.createElement("div", {
283
- className: "searchbox-results-section-body"
284
- }, recentSearches.map(function (entry, idx) {
287
+ }), LocaleUtils.tr("search.recent")), !_this.isCollapsed("recent") ? recentSearches.map(function (entry, idx) {
285
288
  return /*#__PURE__*/React.createElement("div", {
286
289
  className: "searchbox-result",
287
- key: "r" + idx,
290
+ key: "recent:" + idx,
288
291
  onClick: function onClick() {
289
292
  return _this.searchTextChanged(entry);
290
- },
291
- onMouseDown: MiscUtils.killEvent
293
+ }
292
294
  }, entry);
293
- })) : null);
295
+ }) : null];
294
296
  });
295
297
  _defineProperty(_this, "renderFilters", function () {
296
- return Object.entries(_this.state.searchResults).map(function (_ref3) {
298
+ var filters = Object.entries(_this.state.searchResults).reduce(function (res, _ref3) {
297
299
  var _ref4 = _slicedToArray(_ref3, 2),
298
300
  provider = _ref4[0],
299
301
  results = _ref4[1];
300
302
  if (isEmpty(results.result_counts) || results.result_counts.length < 2) {
301
- return null;
303
+ return res;
302
304
  }
303
- var collapsed = _this.isCollapsed('filter', false);
304
305
  var values = results.result_counts.map(function (entry) {
305
- return entry.filterword + ": " + _this.state.searchResults.query_text;
306
+ return [entry.filterword + ": " + _this.state.searchResults.query_text, provider];
306
307
  });
307
308
  values.sort(function (a, b) {
308
- return a.localeCompare(b);
309
+ return a[0].localeCompare(b[0]);
309
310
  });
311
+ return [].concat(_toConsumableArray(res), _toConsumableArray(values));
312
+ }, []);
313
+ if (isEmpty(filters)) {
314
+ return null;
315
+ }
316
+ var collapsed = _this.isCollapsed('filter', false);
317
+ return [/*#__PURE__*/React.createElement("div", {
318
+ className: "searchbox-results-section-title",
319
+ key: "filter",
320
+ onClick: function onClick(ev) {
321
+ return _this.toggleSection(ev, "filter");
322
+ }
323
+ }, /*#__PURE__*/React.createElement(Icon, {
324
+ icon: collapsed ? "expand" : "collapse"
325
+ }), LocaleUtils.tr("search.filter")), !collapsed ? filters.map(function (valProv, idx) {
310
326
  return /*#__PURE__*/React.createElement("div", {
311
- key: "filter"
312
- }, /*#__PURE__*/React.createElement("div", {
313
- className: "searchbox-results-section-title",
327
+ className: "searchbox-result",
328
+ key: "filter:" + idx,
314
329
  onClick: function onClick() {
315
- return _this.toggleSection("filter");
316
- },
317
- onMouseDown: MiscUtils.killEvent
318
- }, /*#__PURE__*/React.createElement(Icon, {
319
- icon: collapsed ? "expand" : "collapse"
320
- }), LocaleUtils.tr("search.filter")), !collapsed ? /*#__PURE__*/React.createElement("div", {
321
- className: "searchbox-results-section-body"
322
- }, values.map(function (value, idx) {
323
- return /*#__PURE__*/React.createElement("div", {
324
- className: "searchbox-result",
325
- key: "f" + idx,
326
- onClick: function onClick() {
327
- return _this.searchTextChanged(value, true, provider);
328
- },
329
- onMouseDown: MiscUtils.killEvent
330
- }, /*#__PURE__*/React.createElement("span", {
331
- className: "searchbox-result-label"
332
- }, value));
333
- })) : null);
334
- }).filter(Boolean);
330
+ return _this.searchTextChanged(valProv[0], true, valProv[1]);
331
+ }
332
+ }, /*#__PURE__*/React.createElement("span", {
333
+ className: "searchbox-result-label"
334
+ }, valProv[0]));
335
+ }) : null];
335
336
  });
336
337
  _defineProperty(_this, "renderResults", function () {
337
338
  var resultRenderers = _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, SearchResultType.PLACE, _this.renderPlaceResult), SearchResultType.THEMELAYER, _this.renderLayerResult), SearchResultType.EXTERNALLAYER, _this.renderLayerResult), SearchResultType.THEME, _this.renderThemeResult), SearchResultType.TASK, _this.renderTaskResult);
@@ -361,23 +362,21 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
361
362
  return {
362
363
  priority: priority * 1000000 + (group.priority || 0),
363
364
  title: (_group$title = group.title) !== null && _group$title !== void 0 ? _group$title : LocaleUtils.tr(group.titlemsgid),
364
- tree: /*#__PURE__*/React.createElement("div", {
365
- key: sectionId
366
- }, /*#__PURE__*/React.createElement("div", {
365
+ tree: [/*#__PURE__*/React.createElement("div", {
367
366
  className: "searchbox-results-section-title",
368
- onClick: function onClick() {
369
- return _this.toggleSection(sectionId);
370
- },
371
- onMouseDown: MiscUtils.killEvent
367
+ key: sectionId,
368
+ onClick: function onClick(ev) {
369
+ return _this.toggleSection(ev, sectionId);
370
+ }
372
371
  }, /*#__PURE__*/React.createElement(Icon, {
373
372
  icon: _this.isCollapsed(sectionId) ? "expand" : "collapse"
374
- }), /*#__PURE__*/React.createElement("span", null, (_group$title2 = group.title) !== null && _group$title2 !== void 0 ? _group$title2 : LocaleUtils.tr(group.titlemsgid))), !_this.isCollapsed(sectionId) ? /*#__PURE__*/React.createElement("div", {
375
- className: "searchbox-results-section-body"
376
- }, group.items.map(function (entry) {
373
+ }), /*#__PURE__*/React.createElement("span", null, (_group$title2 = group.title) !== null && _group$title2 !== void 0 ? _group$title2 : LocaleUtils.tr(group.titlemsgid))), !_this.isCollapsed(sectionId) ? [group.items.map(function (entry) {
377
374
  return renderer(provider, group, entry);
378
375
  }), moreLabel ? /*#__PURE__*/React.createElement("div", {
379
- className: "searchbox-more-results"
380
- }, moreLabel) : null) : null)
376
+ className: "searchbox-more-results",
377
+ disabled: true,
378
+ key: sectionId + ":more"
379
+ }, moreLabel) : null] : null].flat()
381
380
  };
382
381
  }));
383
382
  }, []).filter(Boolean);
@@ -399,10 +398,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
399
398
  className: "searchbox-result",
400
399
  key: key,
401
400
  onClick: function onClick() {
402
- _this.selectPlaceResult(provider, group, result);
403
- _this.blur();
404
- },
405
- onMouseDown: MiscUtils.killEvent
401
+ return _this.selectPlaceResult(provider, group, result);
402
+ }
406
403
  }, result.thumbnail ? /*#__PURE__*/React.createElement("img", {
407
404
  className: "searchbox-result-thumbnail",
408
405
  onError: function onError(ev) {
@@ -419,19 +416,20 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
419
416
  icon: "info-sign",
420
417
  onClick: function onClick(ev) {
421
418
  var _result$label2;
422
- MiscUtils.killEvent(ev);
423
- _this.openUrl(result.externalLink, result.target, (_result$label2 = result.label) !== null && _result$label2 !== void 0 ? _result$label2 : result.text);
419
+ return _this.openUrl(ev, result.externalLink, result.target, (_result$label2 = result.label) !== null && _result$label2 !== void 0 ? _result$label2 : result.text);
424
420
  }
425
421
  }) : null);
426
422
  });
427
423
  _defineProperty(_this, "renderLayerResult", function (provider, group, result) {
428
424
  var _result$label3, _result$layer;
429
425
  var parent = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
426
+ var level = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 0;
430
427
  var key = provider + ":" + group.id + ":" + result.id;
431
428
  var addThemes = ConfigUtils.getConfigProp("allowAddingOtherThemes", _this.props.theme);
432
429
  var icon = null;
433
430
  if (result.sublayers) {
434
- var toggleLayerGroup = function toggleLayerGroup() {
431
+ var toggleLayerGroup = function toggleLayerGroup(ev) {
432
+ MiscUtils.killEvent(ev);
435
433
  _this.setState(function (state) {
436
434
  return {
437
435
  expandedLayerGroup: state.expandedLayerGroup === key ? null : key
@@ -441,8 +439,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
441
439
  icon = /*#__PURE__*/React.createElement(Icon, {
442
440
  icon: _this.state.expandedLayerGroup === key ? "minus" : "plus",
443
441
  onClick: function onClick(ev) {
444
- MiscUtils.killEvent(ev);
445
- toggleLayerGroup();
442
+ return toggleLayerGroup(ev);
446
443
  }
447
444
  });
448
445
  } else if (result.thumbnail) {
@@ -455,15 +452,15 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
455
452
  });
456
453
  }
457
454
  var selectResult = result.theme ? _this.selectThemeResult : _this.selectLayerResult;
458
- return /*#__PURE__*/React.createElement("div", {
459
- key: key
460
- }, /*#__PURE__*/React.createElement("div", {
455
+ return [/*#__PURE__*/React.createElement("div", {
461
456
  className: "searchbox-result",
457
+ key: key,
462
458
  onClick: function onClick() {
463
- selectResult(provider, group, result);
464
- _this.blur();
459
+ return selectResult(provider, group, result);
465
460
  },
466
- onMouseDown: MiscUtils.killEvent
461
+ style: {
462
+ borderLeft: "".concat(level, "em solid transparent")
463
+ }
467
464
  }, icon, result.theme ? /*#__PURE__*/React.createElement(Icon, {
468
465
  className: "searchbox-result-openicon",
469
466
  icon: "open"
@@ -475,35 +472,34 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
475
472
  title: (_result$label3 = result.label) !== null && _result$label3 !== void 0 ? _result$label3 : result.text
476
473
  }), result.theme && addThemes ? /*#__PURE__*/React.createElement(Icon, {
477
474
  icon: "plus",
478
- onClick: function onClick(ev) {
479
- MiscUtils.killEvent(ev);
480
- _this.selectLayerResult(provider, group, result);
481
- _this.blur();
475
+ onClick: function onClick() {
476
+ return _this.selectLayerResult(provider, group, result);
482
477
  },
483
478
  title: LocaleUtils.tr("themeswitcher.addtotheme")
484
479
  }) : null, result.sublayers ? /*#__PURE__*/React.createElement(Icon, {
485
480
  icon: "group",
486
- onClick: function onClick(ev) {
487
- MiscUtils.killEvent(ev);
488
- _this.selectLayerResult(provider, group, result, true);
481
+ onClick: function onClick() {
482
+ return _this.selectLayerResult(provider, group, result, true);
489
483
  },
490
484
  title: LocaleUtils.tr("importlayer.asgroup")
491
485
  }) : null, result.info ? /*#__PURE__*/React.createElement(Icon, {
492
486
  icon: "info-sign",
493
487
  onClick: function onClick(ev) {
494
- MiscUtils.killEvent(ev);
495
- _this.toggleLayerInfo(provider, group, result, key, parent);
488
+ return _this.toggleLayerInfo(ev, provider, group, result, key, parent);
496
489
  }
497
490
  }) : null), _this.state.activeLayerInfo === key ? /*#__PURE__*/React.createElement("div", {
498
491
  className: "searchbox-result-abstract",
499
492
  dangerouslySetInnerHTML: {
500
493
  __html: MiscUtils.addLinkAnchors(DOMPurify.sanitize(((_result$layer = result.layer) === null || _result$layer === void 0 ? void 0 : _result$layer["abstract"]) || "")) || LocaleUtils.tr("search.nodescription")
494
+ },
495
+ disabled: true,
496
+ key: key + ":abstract",
497
+ style: {
498
+ borderLeft: "".concat(level, "em solid transparent")
501
499
  }
502
- }) : null, _this.state.expandedLayerGroup === key ? /*#__PURE__*/React.createElement("div", {
503
- className: "searchbox-result-group"
504
- }, result.sublayers.map(function (sublayer) {
505
- return _this.renderLayerResult(provider, group, sublayer, result.id);
506
- })) : null);
500
+ }) : null, _this.state.expandedLayerGroup === key ? result.sublayers.map(function (sublayer) {
501
+ return _this.renderLayerResult(provider, group, sublayer, result.id, level + 1);
502
+ }) : null].flat();
507
503
  });
508
504
  _defineProperty(_this, "renderThemeResult", function (provider, group, result) {
509
505
  var _result$label4;
@@ -512,10 +508,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
512
508
  className: "searchbox-result",
513
509
  key: provider + ":" + group.id + ":" + result.id,
514
510
  onClick: function onClick() {
515
- _this.selectThemeResult(provider, group, result);
516
- _this.blur();
517
- },
518
- onMouseDown: MiscUtils.killEvent
511
+ return _this.selectThemeResult(provider, group, result);
512
+ }
519
513
  }, result.thumbnail ? /*#__PURE__*/React.createElement("img", {
520
514
  className: "searchbox-result-thumbnail",
521
515
  onError: function onError(ev) {
@@ -534,9 +528,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
534
528
  }), result.theme && addThemes ? /*#__PURE__*/React.createElement(Icon, {
535
529
  icon: "plus",
536
530
  onClick: function onClick(ev) {
537
- MiscUtils.killEvent(ev);
538
- _this.addThemeLayers(result.layer);
539
- _this.blur();
531
+ return _this.addThemeLayers(result.layer);
540
532
  },
541
533
  title: LocaleUtils.tr("themeswitcher.addtotheme")
542
534
  }) : null);
@@ -546,10 +538,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
546
538
  className: "searchbox-result",
547
539
  key: provider + ":" + group.id + ":" + result.id,
548
540
  onClick: function onClick() {
549
- _this.selectTaskResult(provider, group, result);
550
- _this.blur();
551
- },
552
- onMouseDown: MiscUtils.killEvent
541
+ return _this.selectTaskResult(provider, group, result);
542
+ }
553
543
  }, result.task.icon ? /*#__PURE__*/React.createElement(Icon, {
554
544
  icon: result.task.icon
555
545
  }) : null, /*#__PURE__*/React.createElement("span", {
@@ -566,6 +556,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
566
556
  query_text: resultText
567
557
  }, provider, {
568
558
  results: [_objectSpread(_objectSpread({}, group), {}, {
559
+ resultCount: 1,
569
560
  items: [result]
570
561
  })],
571
562
  tot_result_count: 1
@@ -722,7 +713,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
722
713
  ev.target.style.display = 'none';
723
714
  }
724
715
  });
725
- _defineProperty(_this, "toggleLayerInfo", function (provider, group, result, key, parent) {
716
+ _defineProperty(_this, "toggleLayerInfo", function (ev, provider, group, result, key, parent) {
717
+ MiscUtils.killEvent(ev);
726
718
  var setResultLayerAndActiveInfo = function setResultLayerAndActiveInfo(layer) {
727
719
  // Embed returned layer into result item, so that layer info is read from item.layer.abstract
728
720
  _this.setState(function (state) {
@@ -779,14 +771,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
779
771
  }
780
772
  });
781
773
  });
782
- _defineProperty(_this, "setPreventBlur", function () {
783
- _this.preventBlur = true;
784
- setTimeout(function () {
785
- _this.preventBlur = false;
786
- return false;
787
- }, 100);
788
- });
789
- _defineProperty(_this, "toggleSection", function (key) {
774
+ _defineProperty(_this, "toggleSection", function (ev, key) {
775
+ MiscUtils.killEvent(ev);
790
776
  return _this.setState(function (state) {
791
777
  var _newCollapsedSections;
792
778
  var newCollapsedSections = _objectSpread({}, state.collapsedSections);
@@ -833,10 +819,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
833
819
  }, 250);
834
820
  });
835
821
  _defineProperty(_this, "onFocus", function () {
836
- _this.setState({
837
- resultsVisible: true
838
- });
839
- if (_this.searchBox) {
822
+ if (_this.searchBox && !_this.state.resultsVisible) {
840
823
  _this.searchBox.select();
841
824
  }
842
825
  if (isEmpty(_this.state.searchResults) && _this.props.theme) {
@@ -846,15 +829,11 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
846
829
  _this.toggleFilterOptions(false);
847
830
  }
848
831
  });
849
- _defineProperty(_this, "onBlur", function () {
850
- if (_this.preventBlur && _this.searchBox) {
851
- _this.searchBox.focus();
852
- } else {
832
+ _defineProperty(_this, "onKeyDown", function (ev) {
833
+ if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp') {
834
+ ev.preventDefault();
853
835
  _this.setState({
854
- resultsVisible: false,
855
- collapsedSections: {},
856
- expandedLayerGroup: null,
857
- activeLayerInfo: null
836
+ resultsVisible: true
858
837
  });
859
838
  }
860
839
  });
@@ -955,6 +934,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
955
934
  }
956
935
  }
957
936
  return {
937
+ resultsVisible: true,
958
938
  searchResults: searchResults,
959
939
  pendingSearches: newPendingSearches
960
940
  };
@@ -1130,7 +1110,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
1130
1110
  var y = 0.5 * (bbox[1] + bbox[3]);
1131
1111
  _this.props.zoomToPoint([x, y], zoom, _this.props.map.projection);
1132
1112
  });
1133
- _defineProperty(_this, "openUrl", function (url, target, title) {
1113
+ _defineProperty(_this, "openUrl", function (ev, url, target, title) {
1114
+ MiscUtils.killEvent(ev);
1134
1115
  if (target === "iframe") {
1135
1116
  target = ":iframedialog:externallinkiframe";
1136
1117
  }
@@ -1140,7 +1121,6 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
1140
1121
  });
1141
1122
  _this.searchBox = null;
1142
1123
  _this.searchTimeout = null;
1143
- _this.preventBlur = false;
1144
1124
  return _this;
1145
1125
  }
1146
1126
  _inherits(SearchBox, _React$Component);
@@ -1182,6 +1162,14 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
1182
1162
  if (!this.state.filterOptionsVisible && prevState.filterOptionsVisible) {
1183
1163
  this.searchTextChanged(this.state.searchText);
1184
1164
  }
1165
+ // Reset collapsed sections etc
1166
+ if (!this.state.resultsVisible && prevState.resultsVisible) {
1167
+ this.setState({
1168
+ collapsedSections: {},
1169
+ expandedLayerGroup: null,
1170
+ activeLayerInfo: null
1171
+ });
1172
+ }
1185
1173
  }
1186
1174
  }, {
1187
1175
  key: "render",
@@ -1202,11 +1190,16 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
1202
1190
  icon: "search",
1203
1191
  role: "prefix"
1204
1192
  }), /*#__PURE__*/React.createElement("input", {
1205
- onBlur: this.onBlur,
1206
1193
  onChange: function onChange(ev) {
1207
1194
  return _this3.searchTextChanged(ev.target.value);
1208
1195
  },
1196
+ onClick: function onClick() {
1197
+ return _this3.setState({
1198
+ resultsVisible: true
1199
+ });
1200
+ },
1209
1201
  onFocus: this.onFocus,
1202
+ onKeyDown: this.onKeyDown,
1210
1203
  placeholder: placeholder,
1211
1204
  ref: function ref(el) {
1212
1205
  _this3.searchBox = el;
@@ -85,8 +85,7 @@ var ServiceInfoWindow = /*#__PURE__*/function (_React$Component) {
85
85
  onClose: this.onClose,
86
86
  title: LocaleUtils.tr("serviceinfo.title")
87
87
  }, /*#__PURE__*/React.createElement("div", {
88
- className: "service-info-window-body",
89
- role: "body"
88
+ className: "service-info-window-body"
90
89
  }, /*#__PURE__*/React.createElement("h4", {
91
90
  className: "service-info-window-title"
92
91
  }, this.props.service.title), /*#__PURE__*/React.createElement("div", {