qwc2 2025.12.15 → 2025.12.18

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 (87) hide show
  1. package/components/AttributeForm.js +8 -8
  2. package/components/AttributeTableWidget.js +3 -3
  3. package/components/EditComboField.js +1 -1
  4. package/components/EditUploadField.js +1 -1
  5. package/components/IdentifyViewer.js +91 -38
  6. package/components/LinkFeatureForm.js +21 -4
  7. package/components/MeasureSwitcher.js +115 -0
  8. package/components/PluginsContainer.js +3 -2
  9. package/components/QtDesignerForm.js +2 -2
  10. package/components/ResizeableWindow.js +9 -1
  11. package/components/SearchBox.js +19 -12
  12. package/components/SideBar.js +4 -0
  13. package/components/map3d/drawtool/EditTool3D.js +1 -1
  14. package/components/style/IdentifyViewer.css +8 -6
  15. package/components/style/LocationRecorder.css +1 -6
  16. package/components/style/PluginsContainer.css +11 -6
  17. package/components/timeline/FixedTimeline.js +2 -2
  18. package/components/timeline/InfiniteTimeline.js +2 -2
  19. package/components/timeline/TimelineFeaturesSlider.js +1 -1
  20. package/components/widgets/EditableSelect.js +2 -1
  21. package/components/widgets/LayerCatalogWidget.js +26 -15
  22. package/components/widgets/MenuButton.js +7 -2
  23. package/components/widgets/NavBar.js +4 -2
  24. package/components/widgets/PopupMenu.js +44 -13
  25. package/components/widgets/SearchWidget.js +39 -50
  26. package/components/widgets/style/SearchWidget.css +3 -19
  27. package/package.json +1 -1
  28. package/plugins/Editing.js +20 -5
  29. package/plugins/FeatureForm.js +1 -1
  30. package/plugins/FeatureSearch.js +3 -3
  31. package/plugins/GeometryDigitizer.js +32 -18
  32. package/plugins/HeightProfile.js +4 -1
  33. package/plugins/Identify.js +5 -4
  34. package/plugins/LayerTree.js +5 -1
  35. package/plugins/MapExport.js +4 -4
  36. package/plugins/MapFilter.js +10 -10
  37. package/plugins/Measure.js +5 -1
  38. package/plugins/NewsPopup.js +1 -1
  39. package/plugins/ObliqueView.js +88 -17
  40. package/plugins/Print.js +8 -8
  41. package/plugins/Redlining.js +25 -73
  42. package/plugins/Reports.js +3 -3
  43. package/plugins/Routing.js +4 -4
  44. package/plugins/TopBar.js +2 -0
  45. package/plugins/ValueTool.js +1 -1
  46. package/plugins/View3D.js +2 -2
  47. package/plugins/ZoomButtons.js +1 -1
  48. package/plugins/map/EditingSupport.js +50 -20
  49. package/plugins/map/MeasurementSupport.js +1 -0
  50. package/plugins/map/RedliningSupport.js +9 -7
  51. package/plugins/map/SnapSupport.js +12 -10
  52. package/plugins/map/style/SnappingSupport.css +1 -8
  53. package/plugins/map3d/Draw3D.js +2 -2
  54. package/plugins/map3d/ExportObjects3D.js +2 -2
  55. package/plugins/map3d/MapExport3D.js +4 -4
  56. package/reducers/editing.js +6 -1
  57. package/reducers/layers.js +18 -36
  58. package/reducers/measurement.js +2 -1
  59. package/scripts/wmts_config_generator.py +1 -1
  60. package/static/translations/bg-BG.json +45 -75
  61. package/static/translations/ca-ES.json +45 -75
  62. package/static/translations/cs-CZ.json +45 -75
  63. package/static/translations/de-CH.json +45 -75
  64. package/static/translations/de-DE.json +45 -75
  65. package/static/translations/en-US.json +45 -75
  66. package/static/translations/es-ES.json +45 -75
  67. package/static/translations/fi-FI.json +45 -75
  68. package/static/translations/fr-FR.json +46 -76
  69. package/static/translations/hu-HU.json +45 -75
  70. package/static/translations/it-IT.json +45 -75
  71. package/static/translations/ja-JP.json +45 -75
  72. package/static/translations/nl-NL.json +45 -75
  73. package/static/translations/no-NO.json +45 -75
  74. package/static/translations/pl-PL.json +45 -75
  75. package/static/translations/pt-BR.json +45 -75
  76. package/static/translations/pt-PT.json +45 -75
  77. package/static/translations/ro-RO.json +45 -75
  78. package/static/translations/ru-RU.json +45 -75
  79. package/static/translations/sv-SE.json +45 -75
  80. package/static/translations/tr-TR.json +45 -75
  81. package/static/translations/tsconfig.json +35 -67
  82. package/static/translations/uk-UA.json +45 -75
  83. package/utils/FeatureStyles.js +18 -20
  84. package/utils/IdentifyUtils.js +14 -11
  85. package/utils/MiscUtils.js +2 -1
  86. package/utils/SearchProviders.js +1 -1
  87. package/utils/VectorLayerUtils.js +4 -2
@@ -128,7 +128,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
128
128
  value: _this.state.selectedProvider
129
129
  }, /*#__PURE__*/React.createElement("div", {
130
130
  value: ""
131
- }, LocaleUtils.tr("search.all")), Object.entries(_this.props.searchProviders).map(function (_ref) {
131
+ }, LocaleUtils.tr("common.all")), Object.entries(_this.props.searchProviders).map(function (_ref) {
132
132
  var _prov$params, _prov$label;
133
133
  var _ref2 = _slicedToArray(_ref, 2),
134
134
  key = _ref2[0],
@@ -162,14 +162,14 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
162
162
  }
163
163
  var filterButtons = [{
164
164
  key: "Polygon",
165
- tooltip: LocaleUtils.tr("redlining.polygon"),
165
+ tooltip: LocaleUtils.tr("common.polygon"),
166
166
  icon: "polygon",
167
- label: LocaleUtils.tr("redlining.polygon")
167
+ label: LocaleUtils.tr("common.polygon")
168
168
  }, {
169
169
  key: "Circle",
170
- tooltip: LocaleUtils.tr("redlining.circle"),
170
+ tooltip: LocaleUtils.tr("common.circle"),
171
171
  icon: "circle",
172
- label: LocaleUtils.tr("redlining.circle")
172
+ label: LocaleUtils.tr("common.circle")
173
173
  }];
174
174
  return /*#__PURE__*/React.createElement("div", {
175
175
  className: "searchbox-filter-options"
@@ -182,7 +182,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
182
182
  }), searchRegionSelection, /*#__PURE__*/React.createElement("button", {
183
183
  className: "button",
184
184
  onClick: _this.clearFilter,
185
- title: LocaleUtils.tr("search.clearfilter")
185
+ title: LocaleUtils.tr("common.clear")
186
186
  }, /*#__PURE__*/React.createElement(Icon, {
187
187
  icon: "clear"
188
188
  }))))), _this.state.filterGeomType === 'Circle' ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("search.circleradius"), ":"), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(NumberInput, {
@@ -253,7 +253,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
253
253
  className: "searchbox-noresults",
254
254
  disabled: true,
255
255
  key: "noresults"
256
- }, LocaleUtils.tr("search.noresults"));
256
+ }, LocaleUtils.tr("common.noresults"));
257
257
  } else {
258
258
  return null;
259
259
  }
@@ -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) {
@@ -498,7 +498,7 @@ var EditTool3D = /*#__PURE__*/function (_React$Component) {
498
498
  }];
499
499
  var extraButtons = [{
500
500
  key: "clone",
501
- tooltip: LocaleUtils.tr("draw3d.clone"),
501
+ tooltip: LocaleUtils.tr("common.clone"),
502
502
  icon: "clone"
503
503
  }, {
504
504
  key: "NumericInput",
@@ -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 {
@@ -192,7 +194,7 @@ span.identify-toolbar-spacer {
192
194
 
193
195
  div.identify-settings-menu {
194
196
  position: absolute;
195
- bottom: 100%;
197
+ bottom: calc(100% - 0.25em);
196
198
  left: 0;
197
199
  border: 1px solid var(--border-color);
198
200
  background-color: var(--container-bg-color);
@@ -1,10 +1,5 @@
1
1
  div.LocationRecorder {
2
- display: inline-flex;
2
+ display: flex;
3
3
  align-items: center;
4
- padding: 0.25em 0.5em;
5
- background-color: var(--container-bg-color);
6
- box-shadow: 0px -2px 4px rgba(136, 136, 136, 0.5);
7
- border-bottom: 1px solid rgba(136, 136, 136, 0.5);
8
4
  column-gap: 0.25em;
9
- order: 1;
10
5
  }
@@ -30,15 +30,20 @@ div.map-bottom-tool-container {
30
30
  position: absolute;
31
31
  pointer-events: none;
32
32
  display: flex;
33
- flex-direction: column-reverse;
34
- align-items: center;
35
- align-content: flex-start;
36
- justify-content: flex-start;
37
- margin-bottom: -1px;
33
+ justify-content: center;
34
+ align-items: flex-end;
38
35
  }
39
36
 
40
- div.map-bottom-tool-container > * {
37
+ div.map-bottom-tool-container > div {
38
+ display: flex;
39
+ flex-wrap: wrap;
40
+ justify-content: center;
41
+ margin-bottom: -1px;
41
42
  pointer-events: initial;
43
+ padding: 0.25em 0.5em;
44
+ gap: 1em;
45
+ background-color: var(--container-bg-color);
46
+ box-shadow: 0px -2px 4px rgba(136, 136, 136, 0.5);
42
47
  }
43
48
 
44
49
  div.app-info {
@@ -158,11 +158,11 @@ var FixedTimeline = /*#__PURE__*/function (_React$Component) {
158
158
  icon: "home"
159
159
  }, {
160
160
  key: "zoomout",
161
- tooltip: LocaleUtils.tr("timemanager.zoomout"),
161
+ tooltip: LocaleUtils.tr("common.zoomout"),
162
162
  icon: "zoomout"
163
163
  }, {
164
164
  key: "zoomin",
165
- tooltip: LocaleUtils.tr("timemanager.zoomin"),
165
+ tooltip: LocaleUtils.tr("common.zoomin"),
166
166
  icon: "zoomin"
167
167
  }];
168
168
  return /*#__PURE__*/React.createElement("div", {
@@ -257,11 +257,11 @@ var InfiniteTimeline = /*#__PURE__*/function (_React$Component) {
257
257
  icon: "home"
258
258
  }, {
259
259
  key: "zoomout",
260
- tooltip: LocaleUtils.tr("timemanager.zoomout"),
260
+ tooltip: LocaleUtils.tr("common.zoomout"),
261
261
  icon: "zoomout"
262
262
  }, {
263
263
  key: "zoomin",
264
- tooltip: LocaleUtils.tr("timemanager.zoomin"),
264
+ tooltip: LocaleUtils.tr("common.zoomin"),
265
265
  icon: "zoomin"
266
266
  }];
267
267
  return /*#__PURE__*/React.createElement("div", {
@@ -414,7 +414,7 @@ var TimelineFeaturesSlider = /*#__PURE__*/function (_React$Component) {
414
414
  onPointerDown: this.pickCurrentTimestamp
415
415
  }, this.props.displayMode === "features" ? this.renderTimeFeatures(sliderGeom) : null, this.props.displayMode === "layers" ? this.renderTimeLayers(sliderGeom) : null, this.renderGradient(sliderGeom)), this.renderCursor(timestamp), this.props.timeFeatures.pendingRequests > 0 ? /*#__PURE__*/React.createElement("div", {
416
416
  className: "timeline-slider-loading"
417
- }, /*#__PURE__*/React.createElement(Spinner, null), /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("timemanager.loading"))) : null);
417
+ }, /*#__PURE__*/React.createElement(Spinner, null), /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("common.loading"))) : null);
418
418
  }
419
419
  }]);
420
420
  }(React.Component);
@@ -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"
@@ -236,7 +247,7 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
236
247
  } else if (isEmpty(this.state.catalog)) {
237
248
  emptyEntry = /*#__PURE__*/React.createElement("div", {
238
249
  className: "layer-catalog-placeholder"
239
- }, LocaleUtils.tr("importlayer.loading"));
250
+ }, LocaleUtils.tr("common.loading"));
240
251
  }
241
252
  var filterplaceholder = LocaleUtils.tr("importlayer.filter");
242
253
  var catalog = (_this$state$filteredC = this.state.filteredCatalog) !== null && _this$state$filteredC !== void 0 ? _this$state$filteredC : this.state.catalog;
@@ -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 };