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
@@ -34,11 +34,11 @@ import isEmpty from 'lodash.isempty';
34
34
  import PropTypes from 'prop-types';
35
35
  import { v4 as uuidv4 } from 'uuid';
36
36
  import LocaleUtils from '../../utils/LocaleUtils';
37
- import MiscUtils from '../../utils/MiscUtils';
38
37
  import { SearchResultType } from '../../utils/SearchProviders';
39
38
  import VectorLayerUtils from '../../utils/VectorLayerUtils';
40
39
  import Icon from '../Icon';
41
40
  import InputContainer from './InputContainer';
41
+ import PopupMenu from './PopupMenu';
42
42
  import Spinner from './Spinner';
43
43
  import './style/SearchWidget.css';
44
44
  var SearchWidget = /*#__PURE__*/function (_React$Component) {
@@ -51,42 +51,40 @@ var SearchWidget = /*#__PURE__*/function (_React$Component) {
51
51
  reqId: null,
52
52
  results: [],
53
53
  pending: 0,
54
- active: false
54
+ resultsVisible: false
55
55
  });
56
56
  _defineProperty(_this, "renderResults", function () {
57
- return /*#__PURE__*/React.createElement("div", {
57
+ return /*#__PURE__*/React.createElement(PopupMenu, {
58
+ anchor: _this.input,
58
59
  className: "search-widget-results",
59
- onMouseDown: _this.setPreventBlur
60
+ onClose: function onClose() {
61
+ return _this.setState({
62
+ resultsVisible: false
63
+ });
64
+ },
65
+ setMaxWidth: true,
66
+ spaceKeyActivation: false
60
67
  }, _this.state.results.filter(function (group) {
61
68
  var _group$type;
62
69
  return _this.props.resultTypeFilter.includes((_group$type = group.type) !== null && _group$type !== void 0 ? _group$type : SearchResultType.PLACE);
63
70
  }).map(function (group) {
64
71
  var _group$title;
65
- return /*#__PURE__*/React.createElement("div", {
66
- className: "search-widget-results-group",
67
- key: group.id,
68
- onMouseDown: MiscUtils.killEvent
69
- }, /*#__PURE__*/React.createElement("div", {
70
- className: "search-widget-results-group-title"
72
+ return [/*#__PURE__*/React.createElement("div", {
73
+ className: "search-widget-results-group-title",
74
+ disabled: true,
75
+ key: group.id
71
76
  }, /*#__PURE__*/React.createElement("span", null, (_group$title = group.title) !== null && _group$title !== void 0 ? _group$title : LocaleUtils.tr(group.titlemsgid))), group.items.map(function (item) {
72
77
  item.text = (item.label !== undefined ? item.label : item.text || '').replace(/<\/?\w+\s*\/?>/g, '');
73
78
  return /*#__PURE__*/React.createElement("div", {
74
- className: "search-widget-results-group-item",
75
- key: item.id,
79
+ className: "search-widget-results-item",
80
+ key: group.id + ":" + item.id,
76
81
  onClick: function onClick() {
77
82
  return _this.resultSelected(group, item);
78
83
  },
79
84
  title: item.text
80
85
  }, item.text);
81
- }));
82
- }));
83
- });
84
- _defineProperty(_this, "setPreventBlur", function () {
85
- _this.preventBlur = true;
86
- setTimeout(function () {
87
- _this.preventBlur = false;
88
- return false;
89
- }, 100);
86
+ })];
87
+ }).flat());
90
88
  });
91
89
  _defineProperty(_this, "textChanged", function (ev) {
92
90
  _this.setState({
@@ -102,27 +100,19 @@ var SearchWidget = /*#__PURE__*/function (_React$Component) {
102
100
  _this.searchTimeout = setTimeout(_this.startSearch, 250);
103
101
  }
104
102
  });
105
- _defineProperty(_this, "onBlur", function () {
106
- if (!_this.preventBlur) {
107
- clearTimeout(_this.searchTimeout);
108
- _this.props.onBlur();
109
- _this.setState({
110
- active: false
111
- });
112
- }
113
- });
114
103
  _defineProperty(_this, "onFocus", function (ev) {
115
- ev.target.select();
116
- _this.props.onFocus();
117
- _this.setState({
118
- active: true
119
- });
104
+ if (_this.input && !_this.state.resultsVisible) {
105
+ ev.target.select();
106
+ }
120
107
  });
121
108
  _defineProperty(_this, "onKeyDown", function (ev) {
122
109
  if (ev.key === 'Enter') {
123
110
  _this.startSearch();
124
- } else if (ev.key === 'Escape') {
125
- ev.target.blur();
111
+ } else if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp') {
112
+ ev.preventDefault();
113
+ _this.setState({
114
+ resultsVisible: true
115
+ });
126
116
  }
127
117
  });
128
118
  _defineProperty(_this, "startSearch", function () {
@@ -149,7 +139,8 @@ var SearchWidget = /*#__PURE__*/function (_React$Component) {
149
139
  provider: provider
150
140
  });
151
141
  }))),
152
- pending: state.pending - 1
142
+ pending: state.pending - 1,
143
+ resultsVisible: true
153
144
  };
154
145
  });
155
146
  }, axios);
@@ -174,14 +165,12 @@ var SearchWidget = /*#__PURE__*/function (_React$Component) {
174
165
  } : null
175
166
  }));
176
167
  }
177
- if (_this.input) {
178
- _this.input.blur();
179
- }
180
168
  });
181
169
  _defineProperty(_this, "clear", function () {
182
170
  _this.setState({
183
171
  results: [],
184
- text: ""
172
+ text: "",
173
+ resultsVisible: false
185
174
  });
186
175
  _this.props.resultSelected(null);
187
176
  });
@@ -209,13 +198,17 @@ var SearchWidget = /*#__PURE__*/function (_React$Component) {
209
198
  }, {
210
199
  key: "render",
211
200
  value: function render() {
212
- var _this$props$placehold,
213
- _this2 = this;
201
+ var _this2 = this,
202
+ _this$props$placehold;
214
203
  return /*#__PURE__*/React.createElement("div", {
215
204
  className: "search-widget-container"
216
205
  }, /*#__PURE__*/React.createElement(InputContainer, null, /*#__PURE__*/React.createElement("input", {
217
- onBlur: this.onBlur,
218
206
  onChange: this.textChanged,
207
+ onClick: function onClick() {
208
+ return _this2.setState({
209
+ resultsVisible: true
210
+ });
211
+ },
219
212
  onFocus: this.onFocus,
220
213
  onKeyDown: this.onKeyDown,
221
214
  placeholder: (_this$props$placehold = this.props.placeholder) !== null && _this$props$placehold !== void 0 ? _this$props$placehold : LocaleUtils.tr("search.search"),
@@ -231,14 +224,12 @@ var SearchWidget = /*#__PURE__*/function (_React$Component) {
231
224
  icon: "clear",
232
225
  onClick: this.clear,
233
226
  role: "suffix"
234
- })), (!isEmpty(this.state.results) || this.state.pending > 0) && this.state.active ? this.renderResults() : null);
227
+ })), (!isEmpty(this.state.results) || this.state.pending > 0) && this.state.resultsVisible ? this.renderResults() : null);
235
228
  }
236
229
  }]);
237
230
  }(React.Component);
238
231
  _defineProperty(SearchWidget, "propTypes", {
239
232
  className: PropTypes.string,
240
- onBlur: PropTypes.func,
241
- onFocus: PropTypes.func,
242
233
  placeholder: PropTypes.string,
243
234
  queryGeometries: PropTypes.bool,
244
235
  resultSelected: PropTypes.func.isRequired,
@@ -251,8 +242,6 @@ _defineProperty(SearchWidget, "propTypes", {
251
242
  value: PropTypes.string
252
243
  });
253
244
  _defineProperty(SearchWidget, "defaultProps", {
254
- onBlur: function onBlur() {},
255
- onFocus: function onFocus() {},
256
245
  resultTypeFilter: [SearchResultType.PLACE],
257
246
  searchParams: {},
258
247
  searchProviders: []
@@ -11,31 +11,15 @@ div.search-widget-container > div.input-container > div.spinner {
11
11
  height: 2em;
12
12
  }
13
13
 
14
- div.search-widget-results {
15
- position: absolute;
16
- left: 0;
17
- right: 0;
18
- top: 100%;
19
- border: 1px solid var(--border-color);
20
- background-color: var(--list-bg-color);
21
- max-height: 10em;
22
- overflow-y: auto;
23
- z-index: 1;
24
- box-shadow: 0px 2px 4px rgba(136, 136, 136, 0.5);
25
- }
26
14
 
27
15
  div.search-widget-results-group-title {
28
16
  background-color: var(--list-section-bg-color);
29
17
  color: var(--list-section-text-color);
30
- font-weight: bold;;
31
- }
32
-
33
- div.search-widget-results-group-item:hover {
34
- background-color: var(--list-item-bg-color-hover);
35
- color: var(--list-item-text-color-hover);
18
+ font-weight: bold;
19
+ padding: 0.25em;
36
20
  }
37
21
 
38
- div.search-widget-results-group div {
22
+ div.search-widget-results-item {
39
23
  padding: 0.25em;
40
24
  white-space: nowrap;
41
25
  overflow: hidden;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2025.12.15",
3
+ "version": "2025.12.18",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -33,6 +33,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
33
33
  */
34
34
 
35
35
  import React from 'react';
36
+ import ReactDOM from 'react-dom';
36
37
  import { connect } from 'react-redux';
37
38
  import { parseNumber } from '@norbulcz/num-parse';
38
39
  import dateParser from 'any-date-parser';
@@ -46,7 +47,9 @@ import { setSnappingConfig } from '../actions/map';
46
47
  import { setCurrentTask, setCurrentTaskBlocked } from '../actions/task';
47
48
  import AttributeForm from '../components/AttributeForm';
48
49
  import Icon from '../components/Icon';
50
+ import MeasureSwitcher from '../components/MeasureSwitcher';
49
51
  import PickFeature from '../components/PickFeature';
52
+ import { BottomToolPortalContext } from '../components/PluginsContainer';
50
53
  import SideBar from '../components/SideBar';
51
54
  import ButtonBar from '../components/widgets/ButtonBar';
52
55
  import ConfigUtils from '../utils/ConfigUtils';
@@ -173,7 +176,7 @@ var Editing = /*#__PURE__*/function (_React$Component) {
173
176
  actionButtons.push({
174
177
  key: 'Pick',
175
178
  icon: 'pick',
176
- label: LocaleUtils.tr("editing.pick"),
179
+ label: LocaleUtils.tr("common.pick"),
177
180
  data: {
178
181
  action: 'Pick',
179
182
  feature: null
@@ -258,7 +261,7 @@ var Editing = /*#__PURE__*/function (_React$Component) {
258
261
  }, /*#__PURE__*/React.createElement("option", {
259
262
  disabled: true,
260
263
  value: ""
261
- }, LocaleUtils.tr("editing.selectlayer")), Object.entries(_this.props.editConfigs).map(function (_ref) {
264
+ }, LocaleUtils.tr("common.selectlayer")), Object.entries(_this.props.editConfigs).map(function (_ref) {
262
265
  var _ref2 = _slicedToArray(_ref, 2),
263
266
  mapName = _ref2[0],
264
267
  serviceConfigs = _ref2[1];
@@ -285,6 +288,11 @@ var Editing = /*#__PURE__*/function (_React$Component) {
285
288
  onClick: _this.actionClicked
286
289
  }), featureSelection, pickBar, attributeForm);
287
290
  });
291
+ _defineProperty(_this, "changeMeasurementState", function (diff) {
292
+ _this.props.setEditContext('Editing', {
293
+ measurements: _objectSpread(_objectSpread({}, _this.props.editContext.measurements), diff)
294
+ });
295
+ });
288
296
  _defineProperty(_this, "actionClicked", function (action, data) {
289
297
  _this.setState({
290
298
  drawPick: false,
@@ -635,8 +643,9 @@ var Editing = /*#__PURE__*/function (_React$Component) {
635
643
  }, {
636
644
  key: "render",
637
645
  value: function render() {
638
- var _this3 = this;
639
- var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("editing.maximize") : LocaleUtils.tr("editing.minimize");
646
+ var _this3 = this,
647
+ _this$props$editConte3;
648
+ var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("window.maximize") : LocaleUtils.tr("window.minimize");
640
649
  var extraTitlebarContent = /*#__PURE__*/React.createElement(Icon, {
641
650
  className: "editing-minimize-maximize",
642
651
  icon: this.state.minimized ? 'chevron-down' : 'chevron-up',
@@ -669,10 +678,16 @@ var Editing = /*#__PURE__*/function (_React$Component) {
669
678
  featureFilter: this.pickFilter,
670
679
  featurePicked: this.geomPicked,
671
680
  key: "FeaturePicker"
672
- }) : null];
681
+ }) : null, this.props.editContext.action === "Draw" || (_this$props$editConte3 = this.props.editContext.feature) !== null && _this$props$editConte3 !== void 0 && _this$props$editConte3.geometry ? /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement(MeasureSwitcher, {
682
+ changeMeasureState: this.changeMeasurementState,
683
+ geomType: this.props.editContext.geomType,
684
+ iconSize: "large",
685
+ measureState: this.props.editContext.measurements
686
+ }), this.context) : null];
673
687
  }
674
688
  }]);
675
689
  }(React.Component);
690
+ _defineProperty(Editing, "contextType", BottomToolPortalContext);
676
691
  _defineProperty(Editing, "propTypes", {
677
692
  addLayerFeatures: PropTypes.func,
678
693
  /** Whether to enable the "Clone existing geometry" functionality. */
@@ -233,7 +233,7 @@ var FeatureForm = /*#__PURE__*/function (_React$Component) {
233
233
  className: "feature-query-body"
234
234
  }, /*#__PURE__*/React.createElement("span", {
235
235
  className: "identify-body-message"
236
- }, LocaleUtils.tr("featureform.noresults")));
236
+ }, LocaleUtils.tr("common.noresults")));
237
237
  } else {
238
238
  var featureText = LocaleUtils.tr("featureform.feature");
239
239
  var attributeForm = null;
@@ -86,7 +86,7 @@ var FeatureSearch = /*#__PURE__*/function (_React$Component) {
86
86
  }, /*#__PURE__*/React.createElement("option", {
87
87
  disabled: true,
88
88
  value: ""
89
- }, LocaleUtils.tr("featuresearch.select")), Object.entries(_this.state.providerGroups).map(function (_ref) {
89
+ }, LocaleUtils.tr("common.select")), Object.entries(_this.state.providerGroups).map(function (_ref) {
90
90
  var _ref2 = _slicedToArray(_ref, 2),
91
91
  group = _ref2[0],
92
92
  entries = _ref2[1];
@@ -165,7 +165,7 @@ var FeatureSearch = /*#__PURE__*/function (_React$Component) {
165
165
  }, /*#__PURE__*/React.createElement("option", {
166
166
  disabled: true,
167
167
  value: ""
168
- }, LocaleUtils.tr("featuresearch.select")), options.map(function (entry) {
168
+ }, LocaleUtils.tr("common.select")), options.map(function (entry) {
169
169
  var _entry$value, _entry$value2, _entry$label;
170
170
  return /*#__PURE__*/React.createElement("option", {
171
171
  key: (_entry$value = entry.value) !== null && _entry$value !== void 0 ? _entry$value : entry,
@@ -195,7 +195,7 @@ var FeatureSearch = /*#__PURE__*/function (_React$Component) {
195
195
  className: "feature-search-results"
196
196
  }, isEmpty(_this.state.searchResults) ? /*#__PURE__*/React.createElement("div", {
197
197
  className: "feature-search-noresults"
198
- }, LocaleUtils.tr("featuresearch.noresults")) : /*#__PURE__*/React.createElement(IdentifyViewer, {
198
+ }, LocaleUtils.tr("common.noresults")) : /*#__PURE__*/React.createElement(IdentifyViewer, {
199
199
  collapsible: true,
200
200
  displayResultTree: false,
201
201
  enableExport: _this.props.enableExport,
@@ -32,6 +32,7 @@ import React from 'react';
32
32
  import { connect } from 'react-redux';
33
33
  import polySelfIntersections from 'geojson-polygon-self-intersections';
34
34
  import isEmpty from 'lodash.isempty';
35
+ import omit from 'lodash.omit';
35
36
  import PropTypes from 'prop-types';
36
37
  import { LayerRole, removeLayer, addLayerFeatures, removeLayerFeatures, clearLayer } from '../actions/layers';
37
38
  import { changeRedliningState, resetRedliningState } from '../actions/redlining';
@@ -42,6 +43,7 @@ import ButtonBar from '../components/widgets/ButtonBar';
42
43
  import NumberInput from '../components/widgets/NumberInput';
43
44
  import Spinner from '../components/widgets/Spinner';
44
45
  import ConfigUtils from '../utils/ConfigUtils';
46
+ import { EXCLUDE_ATTRS, EXCLUDE_PROPS } from '../utils/IdentifyUtils';
45
47
  import LocaleUtils from '../utils/LocaleUtils';
46
48
  import MiscUtils from '../utils/MiscUtils';
47
49
  import VectorLayerUtils from '../utils/VectorLayerUtils';
@@ -68,7 +70,8 @@ import './style/Redlining.css';
68
70
  * "name": "<geomLinkName>", // Link name referenced in theme item
69
71
  * "title": "<geomLinkTitle>", // Link title, displayed in the selection combo
70
72
  * "geomType": ["<geomType>", "<geomType>"] // Supported geometry types (Point, LineString, Polygon)
71
- * "url": "<targetApplicationUrl>", // Application target URL, receiving the POST submit
73
+ * "format": "wkt|geojson", // Format of data to send to application
74
+ * "url": "<targetApplicationUrl>", // Application target URL, receiving the POST submit. Can contain the $username$ placeholder parameter.
72
75
  * "params": {"<key>": "<value>", ...} // Optional: additional form parameters to post to URL
73
76
  * "target": "<target>" | { // Optional: form POST target which to display the result
74
77
  * "iframedialog": true, // Use an iframe dialog
@@ -80,6 +83,10 @@ import './style/Redlining.css';
80
83
  * }
81
84
  * }
82
85
  * ```
86
+ * If you are using `qwc-services`, you will need to explicitly permit the geometry links in the `qwc-admin-gui` as follows:
87
+ *
88
+ * * Create and permit a `Plugin` resource with name `geometryLinks`
89
+ * * Create and permit `Plugin data` resources with name equal to `<geomLinkName>`
83
90
  */
84
91
  var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
85
92
  function GeometryDigitizer(props) {
@@ -109,7 +116,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
109
116
  _this.props.resetRedliningState();
110
117
  });
111
118
  _defineProperty(_this, "renderBody", function () {
112
- var _this$props$layers$fi, _geomLinkData$target, _geomLinkData$target2, _this$props$theme$plu;
119
+ var _this$props$layers$fi, _geomLinkData$target, _geomLinkData$target2, _this$props$theme$plu, _geomLinkData$url;
113
120
  var geomLinkData = _this.geometryLinkData(_this.state.geomLink);
114
121
  var activeButton = null;
115
122
  if (_this.state.pickGeomType) {
@@ -129,7 +136,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
129
136
  }
130
137
  } : {
131
138
  key: "Point",
132
- tooltip: LocaleUtils.tr("redlining.point"),
139
+ tooltip: LocaleUtils.tr("common.point"),
133
140
  icon: "point",
134
141
  data: {
135
142
  action: "Draw",
@@ -148,7 +155,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
148
155
  }
149
156
  } : {
150
157
  key: "LineString",
151
- tooltip: LocaleUtils.tr("redlining.line"),
158
+ tooltip: LocaleUtils.tr("common.line"),
152
159
  icon: "line",
153
160
  data: {
154
161
  action: "Draw",
@@ -158,7 +165,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
158
165
  disabled: !supportedGeomType.includes("LineString")
159
166
  }, {
160
167
  key: "Polygon",
161
- tooltip: LocaleUtils.tr("redlining.polygon"),
168
+ tooltip: LocaleUtils.tr("common.polygon"),
162
169
  icon: "polygon",
163
170
  data: {
164
171
  action: "Draw",
@@ -169,7 +176,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
169
176
  }];
170
177
  var editButtons = [{
171
178
  key: "Pick",
172
- tooltip: LocaleUtils.tr("redlining.pick"),
179
+ tooltip: LocaleUtils.tr("common.pick"),
173
180
  icon: "pick",
174
181
  data: {
175
182
  action: "Pick",
@@ -178,7 +185,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
178
185
  }
179
186
  }, {
180
187
  key: "Delete",
181
- tooltip: LocaleUtils.tr("redlining.delete"),
188
+ tooltip: LocaleUtils.tr("common.delete"),
182
189
  icon: "trash",
183
190
  data: {
184
191
  action: "Delete",
@@ -237,7 +244,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
237
244
  }
238
245
  })), /*#__PURE__*/React.createElement("div", {
239
246
  className: "redlining-groupcontrol"
240
- }, /*#__PURE__*/React.createElement("div", null, LocaleUtils.tr("redlining.pick")), /*#__PURE__*/React.createElement(ButtonBar, {
247
+ }, /*#__PURE__*/React.createElement("div", null, LocaleUtils.tr("common.pick")), /*#__PURE__*/React.createElement(ButtonBar, {
241
248
  active: activeButton,
242
249
  buttons: pickButtons,
243
250
  onClick: function onClick(key, data) {
@@ -271,7 +278,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
271
278
  value: entry
272
279
  }, _this.geometryLinkData(entry).title);
273
280
  })), /*#__PURE__*/React.createElement("form", {
274
- action: geomLinkData.url,
281
+ action: (_geomLinkData$url = geomLinkData.url) === null || _geomLinkData$url === void 0 ? void 0 : _geomLinkData$url.replace('$username$', ConfigUtils.getConfigProp("username") || ""),
275
282
  method: "post",
276
283
  onSubmit: _this.submitGeometryLink,
277
284
  target: target
@@ -335,7 +342,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
335
342
  className: "geomdigitizer-output-window-body"
336
343
  }, !_this.state.outputLoaded ? /*#__PURE__*/React.createElement("span", {
337
344
  className: "geomdigitizer-output-window-wait"
338
- }, /*#__PURE__*/React.createElement(Spinner, null), " ", /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("geomdigitizer.wait"))) : null, /*#__PURE__*/React.createElement("iframe", {
345
+ }, /*#__PURE__*/React.createElement(Spinner, null), " ", /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("common.loading"))) : null, /*#__PURE__*/React.createElement("iframe", {
339
346
  name: "geomdigitizer-output-window",
340
347
  onLoad: function onLoad() {
341
348
  return _this.setState({
@@ -492,19 +499,26 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
492
499
  }
493
500
  var data = _this.geometryLinkData(_this.state.geomLink);
494
501
  var supportedGeomType = data.geomType || [];
495
- var geometries = features.filter(function (feature) {
502
+ var supportedFeatures = features.filter(function (feature) {
496
503
  return supportedGeomType.includes(_this.state.bufferDistance > 0 ? "Polygon" : feature.geometry.type.replace(/^Multi/, ''));
497
- }).map(function (feature) {
498
- return VectorLayerUtils.geoJSONGeomToWkt(feature.geometry);
499
504
  });
500
- if (isEmpty(geometries)) {
505
+ if (isEmpty(supportedFeatures)) {
501
506
  ev.preventDefault();
502
507
  return;
503
- } else {
504
- ev.target.GEOMETRIES.value = geometries.join(";");
505
- ev.target.GEOMCOUNT.value = geometries.length;
506
- ev.target.BUFFERDIST.value = _this.state.bufferDistance;
507
508
  }
509
+ var geometries = (data.format || "wkt").toLowerCase() === "wkt" ? supportedFeatures.map(function (feature) {
510
+ return VectorLayerUtils.geoJSONGeomToWkt(feature.geometry);
511
+ }).join(";") : JSON.stringify({
512
+ type: "FeatureCollection",
513
+ features: supportedFeatures.map(function (feature) {
514
+ var newFeature = omit(feature, EXCLUDE_PROPS);
515
+ newFeature.properties = omit(newFeature.properties, EXCLUDE_ATTRS);
516
+ return newFeature;
517
+ })
518
+ });
519
+ ev.target.GEOMETRIES.value = geometries;
520
+ ev.target.GEOMCOUNT.value = supportedFeatures.length;
521
+ ev.target.BUFFERDIST.value = _this.state.bufferDistance;
508
522
  if (ev.target.target === "geomdigitizer-output-window") {
509
523
  _this.setState({
510
524
  outputWindowVisible: true,
@@ -124,7 +124,8 @@ var HeightProfilePrintDialog_ = /*#__PURE__*/function (_React$PureComponent) {
124
124
  strokeWidth: 4,
125
125
  strokeDash: [],
126
126
  headmarker: _this.props.measurement.lineHeadMarker,
127
- tailmarker: _this.props.measurement.lineTailMarker
127
+ tailmarker: _this.props.measurement.lineTailMarker,
128
+ markerscale: _this.props.measurement.markerScale
128
129
  },
129
130
  properties: {
130
131
  segment_labels: measurement.segment_lengths.map(function (length) {
@@ -147,6 +148,8 @@ var HeightProfilePrintDialog_ = /*#__PURE__*/function (_React$PureComponent) {
147
148
  REQUEST: 'GetMap',
148
149
  TRANSPARENT: 'true',
149
150
  TILED: 'false',
151
+ filename: 'heightprofile.png',
152
+ // To make the ogc-service treat this as a raster export
150
153
  CRS: _this.props.map.projection,
151
154
  BBOX: bounds,
152
155
  WIDTH: _this.props.map.size.width,
@@ -230,7 +230,7 @@ var Identify = /*#__PURE__*/function (_React$Component) {
230
230
  });
231
231
  _defineProperty(_this, "parseResult", function (response, layer, format, clickPoint) {
232
232
  var ctrlPick = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
233
- var newResults = IdentifyUtils.parseResponse(response, layer, format, clickPoint, _this.props.map.projection, _this.props.featureInfoReturnsLayerName);
233
+ var newResults = IdentifyUtils.parseResponse(response, layer, format, clickPoint, _this.props.map.projection);
234
234
  // Merge with previous
235
235
  _this.setState(function (state) {
236
236
  var identifyResults = _objectSpread({}, state.identifyResults);
@@ -415,6 +415,7 @@ var Identify = /*#__PURE__*/function (_React$Component) {
415
415
  longAttributesDisplay: this.props.longAttributesDisplay,
416
416
  replaceImageUrls: this.props.replaceImageUrls,
417
417
  resultDisplayMode: this.props.resultDisplayMode,
418
+ resultGridSize: this.props.resultGridSize,
418
419
  showLayerSelector: this.props.showLayerSelector
419
420
  });
420
421
  }
@@ -480,8 +481,6 @@ _defineProperty(Identify, "propTypes", {
480
481
  exitTaskOnResultsClose: PropTypes.bool,
481
482
  /** Whether to include the geometry in exported features. Default: `true`. */
482
483
  exportGeometry: PropTypes.bool,
483
- /** Whether to assume that XML GetFeatureInfo responses specify the technical layer name in the `name` attribute, rather than the layer title. */
484
- featureInfoReturnsLayerName: PropTypes.bool,
485
484
  /** Default window geometry with size, position and docking status. Positive position values (including '0') are related to top (InitialY) and left (InitialX), negative values (including '-0') to bottom (InitialY) and right (InitialX). */
486
485
  geometry: PropTypes.shape({
487
486
  initialWidth: PropTypes.number,
@@ -507,6 +506,8 @@ _defineProperty(Identify, "propTypes", {
507
506
  replaceImageUrls: PropTypes.bool,
508
507
  /** Result display mode, one of `tree`, `flat`, `paginated`. */
509
508
  resultDisplayMode: PropTypes.string,
509
+ /** Target cell size of the result grid in comparison mode. */
510
+ resultGridSize: PropTypes.number,
510
511
  selection: PropTypes.object,
511
512
  setCurrentTask: PropTypes.func,
512
513
  /** Whether to show a layer selector to filter the identify results by layer. */
@@ -522,8 +523,8 @@ _defineProperty(Identify, "defaultProps", {
522
523
  customExporters: [],
523
524
  longAttributesDisplay: 'ellipsis',
524
525
  resultDisplayMode: 'flat',
526
+ resultGridSize: 200,
525
527
  replaceImageUrls: true,
526
- featureInfoReturnsLayerName: true,
527
528
  geometry: {
528
529
  initialWidth: 240,
529
530
  initialHeight: 320,
@@ -441,7 +441,8 @@ var LayerTree = /*#__PURE__*/function (_React$Component) {
441
441
  icon: "tree",
442
442
  onClick: function onClick() {
443
443
  return _this.props.changeLayerProperty(layer.id, "visibility", subtreevisibility !== 1, path, "children");
444
- }
444
+ },
445
+ title: LocaleUtils.tr("layertree.togglegroup")
445
446
  });
446
447
  }
447
448
  var infoButton = null;
@@ -689,18 +690,21 @@ var LayerTree = /*#__PURE__*/function (_React$Component) {
689
690
  }), _this.state.visibilityMenu ? /*#__PURE__*/React.createElement(PopupMenu, {
690
691
  anchor: _this.visibilityButton,
691
692
  className: "layertree-visibility-menu",
693
+ keepMenuOpen: true,
692
694
  onClose: function onClose() {
693
695
  return _this.setState({
694
696
  visibilityMenu: false
695
697
  });
696
698
  }
697
699
  }, _this.props.showToggleAllLayersCheckbox ? /*#__PURE__*/React.createElement("div", {
700
+ key: "hidealllayers",
698
701
  onClick: function onClick() {
699
702
  return _this.toggleLayerTreeVisibility(vis === 0);
700
703
  }
701
704
  }, /*#__PURE__*/React.createElement(Icon, {
702
705
  icon: vis === 0 ? "checked" : "unchecked"
703
706
  }), " ", LocaleUtils.tr("layertree.hidealllayers")) : null, _this.props.enableVisibleFilter ? /*#__PURE__*/React.createElement("div", {
707
+ key: "filtervisible",
704
708
  onClick: function onClick() {
705
709
  return _this.setState(function (state) {
706
710
  return {
@@ -169,7 +169,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
169
169
  }
170
170
  }, /*#__PURE__*/React.createElement("table", {
171
171
  className: "options-table"
172
- }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.format")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
172
+ }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("common.format")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
173
173
  onChange: _this.changeFormat,
174
174
  value: _this.state.selectedFormat
175
175
  }, _this.state.availableFormats.map(function (format) {
@@ -199,7 +199,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
199
199
  key: "size_" + idx,
200
200
  value: idx
201
201
  }, entry.name);
202
- })))) : null, scaleChooser && _this.state.pageSize !== null ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.scale")), /*#__PURE__*/React.createElement("td", null, scaleChooser)) : null, _this.props.dpis && _this.state.selectedFormat !== "application/dxf" ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.resolution")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
202
+ })))) : null, scaleChooser && _this.state.pageSize !== null ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.scale")), /*#__PURE__*/React.createElement("td", null, scaleChooser)) : null, _this.props.dpis && _this.state.selectedFormat !== "application/dxf" ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("common.resolution")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
203
203
  onChange: _this.changeResolution,
204
204
  value: _this.state.dpi
205
205
  }, _this.props.dpis.map(function (dpi) {
@@ -227,7 +227,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
227
227
  type: "submit"
228
228
  }, _this.state.exporting ? /*#__PURE__*/React.createElement("span", {
229
229
  className: "mapexport-wait"
230
- }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("mapexport.wait")) : LocaleUtils.tr("mapexport.submit")))));
230
+ }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("common.wait")) : LocaleUtils.tr("common.export")))));
231
231
  });
232
232
  _defineProperty(_this, "renderPrintSelection", function () {
233
233
  if (_this.state.pageSize !== null) {
@@ -517,7 +517,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
517
517
  key: "render",
518
518
  value: function render() {
519
519
  var _this2 = this;
520
- var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("print.maximize") : LocaleUtils.tr("print.minimize");
520
+ var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("window.maximize") : LocaleUtils.tr("window.minimize");
521
521
  var extraTitlebarContent = /*#__PURE__*/React.createElement(Icon, {
522
522
  className: "mapexport-minimize-maximize",
523
523
  icon: this.state.minimized ? 'chevron-down' : 'chevron-up',