qwc2 2025.12.15 → 2025.12.17

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 (50) hide show
  1. package/components/IdentifyViewer.js +89 -35
  2. package/components/ResizeableWindow.js +8 -0
  3. package/components/SearchBox.js +12 -5
  4. package/components/SideBar.js +4 -0
  5. package/components/style/IdentifyViewer.css +7 -5
  6. package/components/widgets/EditableSelect.js +2 -1
  7. package/components/widgets/LayerCatalogWidget.js +25 -14
  8. package/components/widgets/MenuButton.js +7 -2
  9. package/components/widgets/NavBar.js +4 -2
  10. package/components/widgets/PopupMenu.js +44 -13
  11. package/components/widgets/SearchWidget.js +39 -50
  12. package/components/widgets/style/SearchWidget.css +3 -19
  13. package/package.json +1 -1
  14. package/plugins/HeightProfile.js +4 -1
  15. package/plugins/Identify.js +4 -0
  16. package/plugins/LayerTree.js +5 -1
  17. package/plugins/Measure.js +5 -1
  18. package/plugins/Print.js +1 -1
  19. package/plugins/TopBar.js +2 -0
  20. package/plugins/map/MeasurementSupport.js +1 -0
  21. package/plugins/map/RedliningSupport.js +7 -5
  22. package/reducers/layers.js +18 -36
  23. package/reducers/measurement.js +2 -1
  24. package/scripts/wmts_config_generator.py +1 -1
  25. package/static/translations/bg-BG.json +6 -1
  26. package/static/translations/ca-ES.json +6 -1
  27. package/static/translations/cs-CZ.json +6 -1
  28. package/static/translations/de-CH.json +6 -1
  29. package/static/translations/de-DE.json +6 -1
  30. package/static/translations/en-US.json +6 -1
  31. package/static/translations/es-ES.json +6 -1
  32. package/static/translations/fi-FI.json +6 -1
  33. package/static/translations/fr-FR.json +7 -2
  34. package/static/translations/hu-HU.json +6 -1
  35. package/static/translations/it-IT.json +6 -1
  36. package/static/translations/ja-JP.json +6 -1
  37. package/static/translations/nl-NL.json +6 -1
  38. package/static/translations/no-NO.json +6 -1
  39. package/static/translations/pl-PL.json +6 -1
  40. package/static/translations/pt-BR.json +6 -1
  41. package/static/translations/pt-PT.json +6 -1
  42. package/static/translations/ro-RO.json +6 -1
  43. package/static/translations/ru-RU.json +6 -1
  44. package/static/translations/sv-SE.json +6 -1
  45. package/static/translations/tr-TR.json +6 -1
  46. package/static/translations/tsconfig.json +5 -0
  47. package/static/translations/uk-UA.json +6 -1
  48. package/utils/FeatureStyles.js +5 -2
  49. package/utils/MiscUtils.js +2 -1
  50. package/utils/VectorLayerUtils.js +4 -2
@@ -57,6 +57,7 @@ import VectorLayerUtils from '../utils/VectorLayerUtils';
57
57
  import Icon from './Icon';
58
58
  import NavBar from './widgets/NavBar';
59
59
  import Spinner from './widgets/Spinner';
60
+ import ToggleSwitch from './widgets/ToggleSwitch';
60
61
  import './style/IdentifyViewer.css';
61
62
  var EXCLUDE_PROPS = ['featurereport', 'displayfield', 'layername', 'layertitle', 'layerinfo', 'attribnames', 'clickPos', 'displayname', 'bbox'];
62
63
  var EXCLUDE_ATTRS = ['htmlContent', 'htmlContentInline'];
@@ -334,7 +335,9 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
334
335
  generatingReport: false,
335
336
  selectedLayer: '',
336
337
  compareEnabled: false,
337
- currentPage: 0
338
+ multiViewEnabled: false,
339
+ currentPage: 0,
340
+ pageSize: 1
338
341
  });
339
342
  _defineProperty(_this, "getCurrentResultFeature", function () {
340
343
  var _this$state$resultTre, _this$state$resultTre2, _this$state$resultTre3, _this$state$currentRe;
@@ -720,7 +723,13 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
720
723
  var selected = _this.state.selectedResults.has(key);
721
724
  return /*#__PURE__*/React.createElement("div", {
722
725
  className: resultClass,
723
- key: key
726
+ key: key,
727
+ onMouseEnter: function onMouseEnter() {
728
+ return _this.setHighlightedFeatures([feature]);
729
+ },
730
+ onMouseLeave: function onMouseLeave() {
731
+ return _this.setHighlightedFeatures(null);
732
+ }
724
733
  }, /*#__PURE__*/React.createElement("div", {
725
734
  className: "identify-result-title"
726
735
  }, _this.props.collapsible ? /*#__PURE__*/React.createElement(Icon, {
@@ -737,7 +746,8 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
737
746
  icon: selected ? "checked" : "unchecked",
738
747
  onClick: function onClick() {
739
748
  return _this.toggleSelectedResult(key);
740
- }
749
+ },
750
+ title: LocaleUtils.tr("identify.selectforcompare")
741
751
  }) : null, /*#__PURE__*/React.createElement("span", null, (_this.props.showLayerTitles ? feature.layertitle + ": " : "") + feature.displayname), zoomToFeatureButton, /*#__PURE__*/React.createElement(Icon, {
742
752
  icon: "info-sign",
743
753
  onClick: function onClick() {
@@ -761,6 +771,34 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
761
771
  };
762
772
  });
763
773
  });
774
+ _defineProperty(_this, "initBody", function (el) {
775
+ if (el) {
776
+ // HACK to trigger an additional repaint, since Safari/Chrome on iOS render the element cut off the first time
777
+ el.style.background = 'inherit';
778
+ var resizeObserver = new ResizeObserver(function (entries) {
779
+ var contentRectEntry = entries.find(function (entry) {
780
+ return entry.contentRect;
781
+ });
782
+ if (contentRectEntry) {
783
+ _this.computePageSize(contentRectEntry.contentRect);
784
+ }
785
+ });
786
+ resizeObserver.observe(el);
787
+ _this.bodyEl = el;
788
+ }
789
+ });
790
+ _defineProperty(_this, "computePageSize", function (rect) {
791
+ var s = 2 * _this.props.resultGridSize;
792
+ if (_this.state.multiViewEnabled && (rect.height >= s || rect.width >= s)) {
793
+ _this.setState({
794
+ pageSize: rect.height >= s && rect.width >= s ? 4 : 2
795
+ });
796
+ } else {
797
+ _this.setState({
798
+ pageSize: 1
799
+ });
800
+ }
801
+ });
764
802
  _defineProperty(_this, "renderToolbar", function (results) {
765
803
  var resultCount = results.length;
766
804
  var toggleButton = function toggleButton(key, icon, disabled) {
@@ -781,12 +819,12 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
781
819
  var infoLabel = null;
782
820
  if (_this.state.compareEnabled) {
783
821
  infoLabel = /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("identify.comparing", _this.state.selectedResults.size()));
784
- } else if (_this.props.resultDisplayMode !== 'paginated') {
822
+ } else {
785
823
  infoLabel = /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("identify.featurecount", resultCount));
786
824
  }
787
825
  var checkedPages = results.reduce(function (res, entry, idx) {
788
826
  if (_this.state.selectedResults.has(entry[0] + "$" + entry[1].id)) {
789
- return [].concat(_toConsumableArray(res), [idx]);
827
+ return [].concat(_toConsumableArray(res), [Math.floor(idx / _this.state.pageSize)]);
790
828
  }
791
829
  return res;
792
830
  }, []);
@@ -796,9 +834,9 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
796
834
  className: "identify-toolbar-spacer"
797
835
  }), infoLabel, /*#__PURE__*/React.createElement("span", {
798
836
  className: "identify-toolbar-spacer"
799
- }), _this.props.resultDisplayMode === 'paginated' ? /*#__PURE__*/React.createElement(NavBar, {
837
+ }), _this.props.resultDisplayMode === 'paginated' && !_this.state.compareEnabled ? /*#__PURE__*/React.createElement(NavBar, {
800
838
  currentPage: _this.state.currentPage,
801
- nPages: resultCount,
839
+ nPages: Math.ceil(resultCount / _this.state.pageSize),
802
840
  pageChanged: function pageChanged(page) {
803
841
  return _this.setState({
804
842
  currentPage: page
@@ -835,7 +873,14 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
835
873
  key: layer,
836
874
  value: layer
837
875
  }, _this.state.resultTree[layer][0].layertitle);
838
- }))))), exportEnabled ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("identify.export"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("div", {
876
+ }))))), _this.props.resultDisplayMode === 'paginated' ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("identify.multiview")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(ToggleSwitch, {
877
+ active: _this.state.multiViewEnabled,
878
+ onChange: function onChange(active) {
879
+ return _this.setState({
880
+ multiViewEnabled: active
881
+ });
882
+ }
883
+ }))) : null, exportEnabled ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("identify.export"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("div", {
839
884
  className: "controlgroup"
840
885
  }, /*#__PURE__*/React.createElement("select", {
841
886
  className: "controlgroup-expanditem",
@@ -1128,6 +1173,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1128
1173
  _this.resultsTreeRef = null;
1129
1174
  _this.currentResultElRef = null;
1130
1175
  _this.scrollIntoView = false;
1176
+ _this.bodyEl = null;
1131
1177
  _this.state.exportFormat = !Array.isArray(props.enableExport) ? 'geojson' : props.enableExport[0];
1132
1178
  return _this;
1133
1179
  }
@@ -1161,6 +1207,9 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1161
1207
  };
1162
1208
  });
1163
1209
  }
1210
+ if (this.state.multiViewEnabled !== prevState.multiViewEnabled) {
1211
+ this.computePageSize(this.bodyEl.getBoundingClientRect());
1212
+ }
1164
1213
  }
1165
1214
  }, {
1166
1215
  key: "componentWillUnmount",
@@ -1182,8 +1231,12 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1182
1231
  });
1183
1232
  }).flat();
1184
1233
  if (this.state.compareEnabled) {
1234
+ var style = {
1235
+ gridTemplateColumns: "repeat(auto-fit, minmax(".concat(this.resultGridSize / 2 - 2, "px, 1fr))")
1236
+ };
1185
1237
  body = /*#__PURE__*/React.createElement("div", {
1186
- className: "identify-compare-results"
1238
+ className: "identify-compare-results",
1239
+ style: style
1187
1240
  }, this.state.selectedResults.entries().map(function (key) {
1188
1241
  var _key$split3 = key.split("$"),
1189
1242
  _key$split4 = _slicedToArray(_key$split3, 2),
@@ -1205,37 +1258,36 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1205
1258
  layerid = _ref26[0],
1206
1259
  features = _ref26[1];
1207
1260
  return features.map(function (feature) {
1208
- return /*#__PURE__*/React.createElement("div", {
1209
- key: layerid + "$" + feature.id,
1210
- onMouseEnter: function onMouseEnter() {
1211
- return _this2.setHighlightedFeatures([feature]);
1212
- },
1213
- onMouseLeave: function onMouseLeave() {
1214
- return _this2.setHighlightedFeatures(null);
1215
- }
1216
- }, _this2.renderResultAttributes(layerid, feature, 'identify-result-frame'));
1261
+ return _this2.renderResultAttributes(layerid, feature, 'identify-result-frame');
1217
1262
  });
1218
1263
  }));
1219
- } else if (this.props.resultDisplayMode === 'paginated' && this.state.currentPage < flatResults.length) {
1220
- var _flatResults$this$sta = _slicedToArray(flatResults[this.state.currentPage], 2),
1221
- layerid = _flatResults$this$sta[0],
1222
- feature = _flatResults$this$sta[1];
1223
- body = /*#__PURE__*/React.createElement("div", {
1224
- className: "identify-flat-results-list",
1225
- onMouseEnter: function onMouseEnter() {
1226
- return _this2.setHighlightedFeatures([feature]);
1227
- },
1228
- onMouseLeave: function onMouseLeave() {
1229
- return _this2.setHighlightedFeatures(null);
1230
- }
1231
- }, this.renderResultAttributes(layerid, feature, 'identify-result-frame'));
1264
+ } else if (this.props.resultDisplayMode === 'paginated') {
1265
+ if (this.state.multiViewEnabled) {
1266
+ var results = flatResults.slice(this.state.currentPage * this.state.pageSize, (this.state.currentPage + 1) * this.state.pageSize);
1267
+ var _style = {
1268
+ gridTemplateColumns: "repeat(auto-fit, minmax(".concat(this.resultGridSize - 2, "px, 1fr))")
1269
+ };
1270
+ body = /*#__PURE__*/React.createElement("div", {
1271
+ className: "identify-compare-results",
1272
+ style: _style
1273
+ }, results.map(function (_ref27) {
1274
+ var _ref28 = _slicedToArray(_ref27, 2),
1275
+ layerid = _ref28[0],
1276
+ feature = _ref28[1];
1277
+ return _this2.renderResultAttributes(layerid, feature, 'identify-result-frame');
1278
+ }));
1279
+ } else if (this.state.currentPage < flatResults.length) {
1280
+ var _flatResults$this$sta = _slicedToArray(flatResults[this.state.currentPage], 2),
1281
+ layerid = _flatResults$this$sta[0],
1282
+ feature = _flatResults$this$sta[1];
1283
+ body = /*#__PURE__*/React.createElement("div", {
1284
+ className: "identify-flat-results-list"
1285
+ }, this.renderResultAttributes(layerid, feature, 'identify-result-frame'));
1286
+ }
1232
1287
  }
1233
- // "el.style.background='inherit'": HACK to trigger an additional repaint, since Safari/Chrome on iOS render the element cut off the first time
1234
1288
  return /*#__PURE__*/React.createElement("div", {
1235
1289
  className: "identify-body",
1236
- ref: function ref(el) {
1237
- if (el) el.style.background = 'inherit';
1238
- }
1290
+ ref: this.initBody
1239
1291
  }, body, flatResults.length > 0 ? this.renderToolbar(flatResults) : null);
1240
1292
  }
1241
1293
  }]);
@@ -1261,6 +1313,7 @@ _defineProperty(IdentifyViewer, "propTypes", {
1261
1313
  removeLayer: PropTypes.func,
1262
1314
  replaceImageUrls: PropTypes.bool,
1263
1315
  resultDisplayMode: PropTypes.string,
1316
+ resultGridSize: PropTypes.number,
1264
1317
  setActiveLayerInfo: PropTypes.func,
1265
1318
  showLayerSelector: PropTypes.bool,
1266
1319
  showLayerTitles: PropTypes.bool,
@@ -1278,6 +1331,7 @@ _defineProperty(IdentifyViewer, "defaultProps", {
1278
1331
  },
1279
1332
  enableAggregatedReports: true,
1280
1333
  resultDisplayMode: 'flat',
1334
+ resultGridSize: 200,
1281
1335
  showLayerTitles: true,
1282
1336
  showLayerSelector: true,
1283
1337
  highlightAllResults: true
@@ -306,6 +306,11 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
306
306
  if (el) {
307
307
  _this.rnd = el;
308
308
  _this.rnd.updatePosition(_this.state.geometry);
309
+ // Set focus to first focusable element
310
+ if (_this.props.visible) {
311
+ var _this$rnd$resizableEl, _this$rnd$resizableEl2, _this$rnd$resizableEl3;
312
+ (_this$rnd$resizableEl = _this.rnd.resizableElement) === null || _this$rnd$resizableEl === void 0 || (_this$rnd$resizableEl = _this$rnd$resizableEl.current) === null || _this$rnd$resizableEl === void 0 || (_this$rnd$resizableEl2 = _this$rnd$resizableEl.querySelector) === null || _this$rnd$resizableEl2 === void 0 || (_this$rnd$resizableEl2 = _this$rnd$resizableEl2.call(_this$rnd$resizableEl, '[tabindex="0"]')) === null || _this$rnd$resizableEl2 === void 0 || (_this$rnd$resizableEl3 = _this$rnd$resizableEl2.focus) === null || _this$rnd$resizableEl3 === void 0 || _this$rnd$resizableEl3.call(_this$rnd$resizableEl2);
313
+ }
309
314
  }
310
315
  });
311
316
  _defineProperty(_this, "onDragStart", function () {
@@ -495,8 +500,11 @@ var ResizeableWindow = /*#__PURE__*/function (_React$Component) {
495
500
  return;
496
501
  }
497
502
  if (this.rnd && this.props.visible && this.props.visible !== prevProps.visible) {
503
+ var _this$rnd$resizableEl4, _this$rnd$resizableEl5, _this$rnd$resizableEl6;
498
504
  this.props.onGeometryChanged(this.state.geometry);
499
505
  this.rnd.updatePosition(this.state.geometry);
506
+ // Set focus to first focusable element
507
+ (_this$rnd$resizableEl4 = this.rnd.resizableElement) === null || _this$rnd$resizableEl4 === void 0 || (_this$rnd$resizableEl4 = _this$rnd$resizableEl4.current) === null || _this$rnd$resizableEl4 === void 0 || (_this$rnd$resizableEl5 = _this$rnd$resizableEl4.querySelector) === null || _this$rnd$resizableEl5 === void 0 || (_this$rnd$resizableEl5 = _this$rnd$resizableEl5.call(_this$rnd$resizableEl4, '[tabindex="0"]')) === null || _this$rnd$resizableEl5 === void 0 || (_this$rnd$resizableEl6 = _this$rnd$resizableEl5.focus) === null || _this$rnd$resizableEl6 === void 0 || _this$rnd$resizableEl6.call(_this$rnd$resizableEl5);
500
508
  }
501
509
  if (this.state.geometry !== prevState.geometry) {
502
510
  this.props.onGeometryChanged(this.state.geometry);
@@ -266,7 +266,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
266
266
  resultsVisible: false
267
267
  });
268
268
  },
269
- setMaxWidth: true
269
+ setMaxWidth: true,
270
+ spaceKeyActivation: false
270
271
  }, children);
271
272
  });
272
273
  _defineProperty(_this, "renderRecentResults", function () {
@@ -789,6 +790,12 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
789
790
  deflt = deflt !== null && deflt !== void 0 ? deflt : _this.props.searchOptions.sectionsDefaultCollapsed || false;
790
791
  return (_this$state$collapsed = _this.state.collapsedSections[section]) !== null && _this$state$collapsed !== void 0 ? _this$state$collapsed : deflt;
791
792
  });
793
+ _defineProperty(_this, "setSearchBoxRef", function (el) {
794
+ _this.searchBox = el;
795
+ if (el && _this.props.searchOptions.focusOnStartup) {
796
+ el.focus();
797
+ }
798
+ });
792
799
  _defineProperty(_this, "toggleFilterOptions", function (visible) {
793
800
  _this.setState({
794
801
  filterOptionsVisible: visible
@@ -845,7 +852,8 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
845
852
  searchResults: {},
846
853
  selectedProvider: '',
847
854
  filterRegionName: "",
848
- filterGeometry: null
855
+ filterGeometry: null,
856
+ resultsVisible: false
849
857
  });
850
858
  _this.props.removeLayer('searchselection');
851
859
  UrlParams.updateParams({
@@ -1201,9 +1209,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
1201
1209
  onFocus: this.onFocus,
1202
1210
  onKeyDown: this.onKeyDown,
1203
1211
  placeholder: placeholder,
1204
- ref: function ref(el) {
1205
- _this3.searchBox = el;
1206
- },
1212
+ ref: this.setSearchBoxRef,
1207
1213
  role: "input",
1208
1214
  type: "text",
1209
1215
  value: this.state.searchText
@@ -1252,6 +1258,7 @@ _defineProperty(SearchBox, "propTypes", {
1252
1258
  replacePlaceholderLayer: PropTypes.func,
1253
1259
  searchOptions: PropTypes.shape({
1254
1260
  allowSearchFilters: PropTypes.bool,
1261
+ focusOnStartup: PropTypes.bool,
1255
1262
  hideResultLabels: PropTypes.bool,
1256
1263
  highlightStyle: PropTypes.object,
1257
1264
  minScaleDenom: PropTypes.number,
@@ -100,6 +100,10 @@ var SideBar = /*#__PURE__*/function (_React$Component) {
100
100
  if (newVisible && (!oldVisible || this.props.currentTask.mode !== prevProps.currentTask.mode)) {
101
101
  this.setState({
102
102
  render: true
103
+ }, function () {
104
+ var _this2$sidebar$queryS, _this2$sidebar$queryS2;
105
+ // Set focus to first focusable element
106
+ (_this2$sidebar$queryS = _this2.sidebar.querySelector('[tabindex="0"]')) === null || _this2$sidebar$queryS === void 0 || (_this2$sidebar$queryS2 = _this2$sidebar$queryS.focus) === null || _this2$sidebar$queryS2 === void 0 || _this2$sidebar$queryS2.call(_this2$sidebar$queryS);
103
107
  });
104
108
  this.props.onShow(this.props.currentTask.mode);
105
109
  } else if (!newVisible && oldVisible) {
@@ -70,7 +70,8 @@ div.identify-body div.identify-result-frame {
70
70
  border: 1px solid var(--border-color);
71
71
  }
72
72
 
73
- div.identify-body div.identify-result-frame:hover {
73
+ div.identify-body div.identify-result-frame:hover,
74
+ div.identify-body div.identify-result-tree-frame:hover {
74
75
  border: 1px solid var(--color-active);
75
76
  }
76
77
 
@@ -112,14 +113,15 @@ div.identify-body .identify-result-tree-frame > div.identify-result-container {
112
113
  }
113
114
 
114
115
  div.identify-compare-results {
115
- display: flex;
116
- flex-wrap: wrap;
116
+ display: grid;
117
+ gap: 0.25em;
118
+ grid-template-columns: repeat(auto-fit, minmax(calc(198px), 1fr));
117
119
  overflow: auto;
118
120
  flex: 1 1 auto;
119
121
  }
120
122
 
121
- div.identify-compare-results > div.identify-result-frame {
122
- flex: 1 1 20em;
123
+ div.identify-compare-results > div {
124
+ overflow: auto;
123
125
  }
124
126
 
125
127
  div.identify-body .identify-result-box {
@@ -65,7 +65,8 @@ var EditableSelect = /*#__PURE__*/function (_React$Component) {
65
65
  return _this.setState({
66
66
  popup: false
67
67
  });
68
- }
68
+ },
69
+ spaceKeyActivation: false
69
70
  }, options) : null;
70
71
  });
71
72
  _defineProperty(_this, "renderSelectedOption", function () {
@@ -47,7 +47,8 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
47
47
  });
48
48
  _defineProperty(_this, "toggleLayerListEntry", function (path) {
49
49
  _this.setState(function (state) {
50
- var newCatalog = _toConsumableArray(state.catalog);
50
+ var catalogKey = _this.state.filteredCatalog ? "filteredCatalog" : "catalog";
51
+ var newCatalog = _toConsumableArray(state[catalogKey]);
51
52
  newCatalog[path[0]] = _objectSpread({}, newCatalog[path[0]]);
52
53
  var cur = newCatalog[path[0]];
53
54
  var _iterator = _createForOfIteratorHelper(path.slice(1)),
@@ -64,9 +65,7 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
64
65
  _iterator.f();
65
66
  }
66
67
  cur.expanded = !cur.expanded;
67
- return {
68
- catalog: newCatalog
69
- };
68
+ return _defineProperty({}, catalogKey, newCatalog);
70
69
  });
71
70
  });
72
71
  _defineProperty(_this, "setFilter", function (text) {
@@ -79,13 +78,22 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
79
78
  }
80
79
  var filter = new RegExp(removeDiacritics(text).replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&"), "i");
81
80
  var _filterCatalogEntry = function filterCatalogEntry(res, entry) {
81
+ var titleMatches = removeDiacritics(entry.title).match(filter);
82
82
  if (entry.sublayers) {
83
- var newEntry = _objectSpread(_objectSpread({}, entry), {}, {
84
- sublayers: entry.sublayers.reduce(_filterCatalogEntry, []),
85
- expanded: true
86
- });
87
- return newEntry.sublayers.length > 0 ? [].concat(_toConsumableArray(res), [newEntry]) : res;
88
- } else if (removeDiacritics(entry.title).match(filter)) {
83
+ var matchedSublayers = entry.sublayers.reduce(_filterCatalogEntry, []);
84
+ if (!isEmpty(matchedSublayers)) {
85
+ return [].concat(_toConsumableArray(res), [_objectSpread(_objectSpread({}, entry), {}, {
86
+ sublayers: matchedSublayers,
87
+ expanded: true
88
+ })]);
89
+ } else if (titleMatches) {
90
+ return [].concat(_toConsumableArray(res), [_objectSpread(_objectSpread({}, entry), {}, {
91
+ expanded: false
92
+ })]);
93
+ } else {
94
+ return res;
95
+ }
96
+ } else if (titleMatches) {
89
97
  return [].concat(_toConsumableArray(res), [entry]);
90
98
  } else {
91
99
  return res;
@@ -102,16 +110,19 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
102
110
  var _entry$name;
103
111
  var asGroup = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
104
112
  var resource = entry.resource ? LayerUtils.splitLayerUrlParam(entry.resource) : null;
113
+ var stripQuery = function stripQuery(url) {
114
+ return (url !== null && url !== void 0 ? url : "").split("?")[0];
115
+ };
105
116
  var existingSublayers = _this.props.layers.reduce(function (res, layer) {
106
117
  var _entry$type, _entry$url;
107
- if (layer.type === ((_entry$type = entry.type) !== null && _entry$type !== void 0 ? _entry$type : resource === null || resource === void 0 ? void 0 : resource.type) && layer.url === ((_entry$url = entry.url) !== null && _entry$url !== void 0 ? _entry$url : resource === null || resource === void 0 ? void 0 : resource.url)) {
118
+ if (layer.type === ((_entry$type = entry.type) !== null && _entry$type !== void 0 ? _entry$type : resource === null || resource === void 0 ? void 0 : resource.type) && stripQuery(layer.url) === stripQuery((_entry$url = entry.url) !== null && _entry$url !== void 0 ? _entry$url : resource === null || resource === void 0 ? void 0 : resource.url)) {
108
119
  return [].concat(_toConsumableArray(res), _toConsumableArray(LayerUtils.getSublayerNames(layer)), [layer.name]);
109
120
  }
110
121
  return res;
111
122
  }, []);
112
123
  if (existingSublayers.includes((_entry$name = entry.name) !== null && _entry$name !== void 0 ? _entry$name : resource === null || resource === void 0 ? void 0 : resource.name)) {
113
- var _ref;
114
- var text = (_ref = LocaleUtils.tr("themelayerslist.existinglayers") + ": " + entry.title) !== null && _ref !== void 0 ? _ref : entry.name;
124
+ var _ref2;
125
+ var text = (_ref2 = LocaleUtils.tr("themelayerslist.existinglayers") + ": " + entry.title) !== null && _ref2 !== void 0 ? _ref2 : entry.name;
115
126
  var actions = [{
116
127
  name: LocaleUtils.tr("themelayerslist.addanyway"),
117
128
  onClick: function onClick() {
@@ -195,7 +206,7 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
195
206
  return /*#__PURE__*/React.createElement("div", {
196
207
  key: key,
197
208
  style: {
198
- paddingLeft: indentSize + 'em'
209
+ paddingLeft: 0.5 * indentSize + 'em'
199
210
  }
200
211
  }, /*#__PURE__*/React.createElement("div", {
201
212
  className: "layer-catalog-widget-entry"
@@ -30,8 +30,10 @@ var MenuButton = /*#__PURE__*/function (_React$Component) {
30
30
  });
31
31
  _defineProperty(_this, "onMenuClicked", function () {
32
32
  if (!_this.props.disabled) {
33
- _this.setState({
34
- popup: true
33
+ _this.setState(function (state) {
34
+ return {
35
+ popup: !state.popup
36
+ };
35
37
  });
36
38
  }
37
39
  });
@@ -39,6 +41,9 @@ var MenuButton = /*#__PURE__*/function (_React$Component) {
39
41
  ev.stopPropagation();
40
42
  if (_this.state.selected) {
41
43
  _this.props.onActivate(_this.state.selected);
44
+ _this.setState({
45
+ popup: false
46
+ });
42
47
  } else {
43
48
  _this.onMenuClicked();
44
49
  }
@@ -88,7 +88,8 @@ var NavBar = /*#__PURE__*/function (_React$Component) {
88
88
  disabled: this.props.currentPage <= 0 || this.props.disabled,
89
89
  onClick: function onClick() {
90
90
  return _this2.props.pageChanged(_this2.props.currentPage - 1);
91
- }
91
+ },
92
+ title: LocaleUtils.tr("navbar.prev")
92
93
  }, /*#__PURE__*/React.createElement(Icon, {
93
94
  icon: "chevron-left"
94
95
  })), pages[0] > 0 || pages[0] === -1 ? this.pageButton(0) : null, pages.map(this.pageButton), pages[pages.length - 1] < this.props.nPages - 1 ? this.pageButton(this.props.nPages - 1) : null, /*#__PURE__*/React.createElement("button", {
@@ -96,7 +97,8 @@ var NavBar = /*#__PURE__*/function (_React$Component) {
96
97
  disabled: this.props.currentPage >= this.props.nPages - 1 || this.props.disabled,
97
98
  onClick: function onClick() {
98
99
  return _this2.props.pageChanged(_this2.props.currentPage + 1);
99
- }
100
+ },
101
+ title: LocaleUtils.tr("navbar.next")
100
102
  }, /*#__PURE__*/React.createElement(Icon, {
101
103
  icon: "chevron-right"
102
104
  })), this.props.pageSizes.length > 1 ? /*#__PURE__*/React.createElement("select", {
@@ -47,6 +47,20 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
47
47
  _this.menuEl.focus();
48
48
  }
49
49
  });
50
+ _defineProperty(_this, "handleMenuClick", function (ev) {
51
+ var disabled = false;
52
+ for (var el = ev.target; ev.currentTarget.contains(el); el = el.parentElement) {
53
+ if (el.attributes.disabled !== undefined) {
54
+ disabled = true;
55
+ }
56
+ }
57
+ if (disabled || _this.props.keepMenuOpen) {
58
+ MiscUtils.killEvent(ev);
59
+ } else {
60
+ var _this$props$onClose, _this$props;
61
+ (_this$props$onClose = (_this$props = _this.props).onClose) === null || _this$props$onClose === void 0 || _this$props$onClose.call(_this$props);
62
+ }
63
+ });
50
64
  _defineProperty(_this, "keyNav", function (ev) {
51
65
  if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp') {
52
66
  var childCount = _this.menuEl.children.length;
@@ -66,11 +80,11 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
66
80
  }
67
81
  MiscUtils.killEvent(ev);
68
82
  } else if (ev.key === 'Escape') {
69
- var _this$props$onClose, _this$props, _this$props$anchor3, _this$props$anchor3$f;
70
- (_this$props$onClose = (_this$props = _this.props).onClose) === null || _this$props$onClose === void 0 || _this$props$onClose.call(_this$props);
83
+ var _this$props$onClose2, _this$props2, _this$props$anchor3, _this$props$anchor3$f;
84
+ (_this$props$onClose2 = (_this$props2 = _this.props).onClose) === null || _this$props$onClose2 === void 0 || _this$props$onClose2.call(_this$props2);
71
85
  (_this$props$anchor3 = _this.props.anchor) === null || _this$props$anchor3 === void 0 || (_this$props$anchor3$f = _this$props$anchor3.focus) === null || _this$props$anchor3$f === void 0 || _this$props$anchor3$f.call(_this$props$anchor3);
72
86
  MiscUtils.killEvent(ev);
73
- } else if (ev.key === 'Enter' || ev.key === ' ') {
87
+ } else if (ev.key === 'Enter' || ev.key === ' ' && _this.props.spaceKeyActivation) {
74
88
  MiscUtils.killEvent(ev);
75
89
  } else if (ev.key !== 'Tab' && ev.key !== 'Shift') {
76
90
  var _this$props$anchor4, _this$props$anchor4$f;
@@ -98,8 +112,8 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
98
112
  _this.shields[i].style.zIndex = 0;
99
113
  setTimeout(function () {
100
114
  return _this.shields[i].addEventListener('click', function () {
101
- var _this$props$onClose2, _this$props2;
102
- (_this$props$onClose2 = (_this$props2 = _this.props).onClose) === null || _this$props$onClose2 === void 0 || _this$props$onClose2.call(_this$props2);
115
+ var _this$props$onClose3, _this$props3;
116
+ (_this$props$onClose3 = (_this$props3 = _this.props).onClose) === null || _this$props$onClose3 === void 0 || _this$props$onClose3.call(_this$props3);
103
117
  });
104
118
  }, 0);
105
119
  _this.container.appendChild(_this.shields[i]);
@@ -108,14 +122,15 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
108
122
  _loop(i);
109
123
  }
110
124
  _this.container.style.pointerEvents = 'none';
125
+ } else {
126
+ setTimeout(function () {
127
+ return _this.container.addEventListener('click', function () {
128
+ var _this$props$onClose4, _this$props4;
129
+ (_this$props$onClose4 = (_this$props4 = _this.props).onClose) === null || _this$props$onClose4 === void 0 || _this$props$onClose4.call(_this$props4);
130
+ });
131
+ }, 0);
111
132
  }
112
133
  _this.menuEl = null;
113
- setTimeout(function () {
114
- return _this.container.addEventListener('click', function () {
115
- var _this$props$onClose3, _this$props3;
116
- (_this$props$onClose3 = (_this$props3 = _this.props).onClose) === null || _this$props$onClose3 === void 0 || _this$props$onClose3.call(_this$props3);
117
- });
118
- }, 0);
119
134
  document.body.appendChild(_this.container);
120
135
  return _this;
121
136
  }
@@ -141,7 +156,15 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
141
156
  }, {
142
157
  key: "render",
143
158
  value: function render() {
144
- var _rect$left, _rect, _rect$bottom, _rect2, _ref, _rect$width, _rect3, _this$props$disabledI;
159
+ var _rect$left,
160
+ _rect,
161
+ _rect$bottom,
162
+ _rect2,
163
+ _ref,
164
+ _rect$width,
165
+ _rect3,
166
+ _this$props$disabledI,
167
+ _this2 = this;
145
168
  if (isEmpty(this.props.children)) {
146
169
  return null;
147
170
  }
@@ -179,6 +202,7 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
179
202
  var children = Array.isArray(this.props.children) ? this.props.children : [this.props.children];
180
203
  return /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
181
204
  className: "popup-menu " + this.props.className,
205
+ onClick: this.handleMenuClick,
182
206
  onKeyDown: this.keyNav,
183
207
  onMouseLeave: this.clearFocus,
184
208
  ref: this.setFocus,
@@ -189,7 +213,9 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
189
213
  return /*#__PURE__*/React.cloneElement(child, {
190
214
  className: className,
191
215
  tabIndex: child.props.disabled ? undefined : 0,
192
- onKeyDown: child.props.disabled ? undefined : MiscUtils.checkKeyActivate,
216
+ onKeyDown: child.props.disabled ? undefined : function (ev) {
217
+ return MiscUtils.checkKeyActivate(ev, null, _this2.props.spaceKeyActivation);
218
+ },
193
219
  onMouseOver: child.props.disabled ? undefined : function (ev) {
194
220
  return ev.target.focus();
195
221
  }
@@ -203,10 +229,15 @@ _defineProperty(PopupMenu, "propTypes", {
203
229
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
204
230
  className: PropTypes.string,
205
231
  disabledItemClass: PropTypes.string,
232
+ keepMenuOpen: PropTypes.bool,
206
233
  onClose: PropTypes.func,
207
234
  setMaxWidth: PropTypes.bool,
235
+ spaceKeyActivation: PropTypes.bool,
208
236
  width: PropTypes.number,
209
237
  x: PropTypes.number,
210
238
  y: PropTypes.number
211
239
  });
240
+ _defineProperty(PopupMenu, "defaultProps", {
241
+ spaceKeyActivation: true
242
+ });
212
243
  export { PopupMenu as default };