qwc2 2026.4.21 → 2026.4.29

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 (44) hide show
  1. package/components/AttributeForm.js +26 -11
  2. package/components/EditComboField.js +58 -15
  3. package/components/LinkFeatureForm.js +9 -10
  4. package/components/QtDesignerForm.js +12 -15
  5. package/components/SearchBox.js +77 -52
  6. package/components/map3d/Map3D.js +19 -4
  7. package/components/map3d/layers/WFSLayer3D.js +4 -0
  8. package/components/map3d/utils/MiscUtils3D.js +3 -1
  9. package/components/style/EditComboField.css +5 -0
  10. package/components/widgets/ComboBox.js +11 -2
  11. package/package.json +3 -3
  12. package/plugins/Redlining.js +14 -5
  13. package/plugins/SensorThingsTool.js +41 -22
  14. package/plugins/TaskButton.js +16 -2
  15. package/plugins/map3d/Identify3D.js +18 -10
  16. package/plugins/map3d/MapCopyright3D.js +36 -17
  17. package/plugins/map3d/MapExport3D.js +1 -1
  18. package/plugins/map3d/Measure3D.js +3 -3
  19. package/plugins/style/SensorThingsTool.css +13 -5
  20. package/static/translations/bg-BG.json +1 -0
  21. package/static/translations/ca-ES.json +1 -0
  22. package/static/translations/cs-CZ.json +1 -0
  23. package/static/translations/de-CH.json +1 -0
  24. package/static/translations/de-DE.json +1 -0
  25. package/static/translations/en-US.json +1 -0
  26. package/static/translations/es-ES.json +1 -0
  27. package/static/translations/fi-FI.json +1 -0
  28. package/static/translations/fr-FR.json +1 -0
  29. package/static/translations/hu-HU.json +1 -0
  30. package/static/translations/it-IT.json +1 -0
  31. package/static/translations/ja-JP.json +1 -0
  32. package/static/translations/nl-NL.json +1 -0
  33. package/static/translations/no-NO.json +1 -0
  34. package/static/translations/pl-PL.json +1 -0
  35. package/static/translations/pt-BR.json +1 -0
  36. package/static/translations/pt-PT.json +1 -0
  37. package/static/translations/ro-RO.json +1 -0
  38. package/static/translations/ru-RU.json +1 -0
  39. package/static/translations/sv-SE.json +1 -0
  40. package/static/translations/tr-TR.json +1 -0
  41. package/static/translations/tsconfig.json +1 -0
  42. package/static/translations/uk-UA.json +1 -0
  43. package/utils/EditingUtils.js +2 -1
  44. package/utils/SearchProviders.js +38 -84
@@ -44,7 +44,7 @@ import { refreshLayer } from '../actions/layers';
44
44
  import { setCurrentTaskBlocked } from '../actions/task';
45
45
  import ConfigUtils from '../utils/ConfigUtils';
46
46
  import CoordinatesUtils from '../utils/CoordinatesUtils';
47
- import { getFeatureTemplate, parseExpressionsAsync } from '../utils/EditingUtils';
47
+ import { FeatureCache, getFeatureTemplate, KeyValCache, parseExpressionsAsync } from '../utils/EditingUtils';
48
48
  import LocaleUtils from '../utils/LocaleUtils';
49
49
  import AutoEditForm from './AutoEditForm';
50
50
  import LinkFeatureForm from './LinkFeatureForm';
@@ -206,6 +206,10 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
206
206
  });
207
207
  });
208
208
  _defineProperty(_this, "updateField", function (key, value) {
209
+ var _this$props$editConte;
210
+ if (value === ((_this$props$editConte = _this.props.editContext.feature) === null || _this$props$editConte === void 0 || (_this$props$editConte = _this$props$editConte.properties) === null || _this$props$editConte === void 0 ? void 0 : _this$props$editConte[key])) {
211
+ return;
212
+ }
209
213
  var newProperties = _objectSpread(_objectSpread({}, _this.props.editContext.feature.properties), {}, _defineProperty({}, key, value));
210
214
  var newFeature = _objectSpread(_objectSpread({}, _this.props.editContext.feature), {}, {
211
215
  properties: newProperties
@@ -344,14 +348,15 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
344
348
  changed: true
345
349
  });
346
350
  });
347
- _defineProperty(_this, "editRelationRecord", function (action, layer, table, idx, displayField) {
348
- var editConfig = _this.props.editConfigs[_this.props.editContext.mapPrefix][table.split('.').slice(-1)];
349
- var feature = _this.props.editContext.feature.relationValues[table].features[idx];
351
+ _defineProperty(_this, "editRelationRecord", function (action, layer, idx, displayField) {
352
+ var dataset = _this.props.editContext.mapPrefix + "." + layer;
353
+ var editConfig = _this.props.editConfigs[_this.props.editContext.mapPrefix][layer];
354
+ var feature = _this.props.editContext.feature.relationValues[dataset].features[idx];
350
355
  var childEdit = {
351
356
  action: action,
352
357
  editConfig: editConfig,
353
358
  editContextId: ':' + layer,
354
- dataset: table,
359
+ dataset: dataset,
355
360
  idx: idx,
356
361
  feature: feature,
357
362
  finishCallback: _this.finishEditRelationRecord,
@@ -491,11 +496,11 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
491
496
  var element = _this.form.elements.namedItem(key);
492
497
  if (element) {
493
498
  if (value === false) {
494
- var _this$props$editConte, _this$props$editConte2;
499
+ var _this$props$editConte2, _this$props$editConte3;
495
500
  valid = false;
496
- var reason = (_this$props$editConte = (_this$props$editConte2 = _this.props.editContext.editConfig.fields.find(function (field) {
501
+ var reason = (_this$props$editConte2 = (_this$props$editConte3 = _this.props.editContext.editConfig.fields.find(function (field) {
497
502
  return field.id === key;
498
- })) === null || _this$props$editConte2 === void 0 || (_this$props$editConte2 = _this$props$editConte2.constraints) === null || _this$props$editConte2 === void 0 ? void 0 : _this$props$editConte2.placeholder) !== null && _this$props$editConte !== void 0 ? _this$props$editConte : LocaleUtils.tr("editing.contraintviolation");
503
+ })) === null || _this$props$editConte3 === void 0 || (_this$props$editConte3 = _this$props$editConte3.constraints) === null || _this$props$editConte3 === void 0 ? void 0 : _this$props$editConte3.placeholder) !== null && _this$props$editConte2 !== void 0 ? _this$props$editConte2 : LocaleUtils.tr("editing.contraintviolation");
499
504
  reasons.push(reason);
500
505
  element.setCustomValidity(reason);
501
506
  } else {
@@ -876,7 +881,8 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
876
881
  displayField: displayField,
877
882
  featureId: featureId,
878
883
  updateField: updateField,
879
- finishCallback: _this.finishChildEdit
884
+ finishCallback: _this.finishChildEdit,
885
+ hideDelete: true
880
886
  };
881
887
  _this.setState({
882
888
  childEdit: childEdit
@@ -885,8 +891,8 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
885
891
  });
886
892
  _defineProperty(_this, "finishChildEdit", function (feature) {
887
893
  _this.props.clearEditContext(_this.state.childEdit.editContextId, _this.props.editContext.id);
888
- if (feature && feature.id !== _this.state.childEdit.featureId) {
889
- _this.state.childEdit.updateField(feature.id);
894
+ if (feature) {
895
+ _this.state.childEdit.updateField(feature);
890
896
  }
891
897
  _this.setState({
892
898
  childEdit: null
@@ -921,6 +927,14 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
921
927
  this.validateFieldConstraints(this.props.editContext.feature);
922
928
  }
923
929
  }
930
+ }, {
931
+ key: "componentWillUnmount",
932
+ value: function componentWillUnmount() {
933
+ if (!this.props.nested) {
934
+ KeyValCache.clear();
935
+ FeatureCache.clear();
936
+ }
937
+ }
924
938
  }]);
925
939
  }(React.Component);
926
940
  _defineProperty(AttributeForm, "propTypes", {
@@ -932,6 +946,7 @@ _defineProperty(AttributeForm, "propTypes", {
932
946
  hideDelete: PropTypes.bool,
933
947
  iface: PropTypes.object,
934
948
  map: PropTypes.object,
949
+ nested: PropTypes.bool,
935
950
  onCommit: PropTypes.func,
936
951
  onDelete: PropTypes.func,
937
952
  onDiscard: PropTypes.func,
@@ -30,6 +30,8 @@ import React from 'react';
30
30
  import PropTypes from 'prop-types';
31
31
  import { KeyValCache } from '../utils/EditingUtils';
32
32
  import LocaleUtils from '../utils/LocaleUtils';
33
+ import Icon from './Icon';
34
+ import ComboBox from './widgets/ComboBox';
33
35
  import './style/EditComboField.css';
34
36
  var EditComboField = /*#__PURE__*/function (_React$Component) {
35
37
  function EditComboField() {
@@ -91,27 +93,39 @@ var EditComboField = /*#__PURE__*/function (_React$Component) {
91
93
  });
92
94
  _defineProperty(_this, "renderComboSelect", function () {
93
95
  var _this$props$placehold;
94
- return /*#__PURE__*/React.createElement("select", {
95
- disabled: _this.props.readOnly,
96
+ return /*#__PURE__*/React.createElement("div", {
97
+ className: "edit-single-select controlgroup"
98
+ }, /*#__PURE__*/React.createElement(ComboBox, {
99
+ className: "controlgroup-expanditem",
96
100
  name: _this.props.name,
97
- onChange: function onChange(ev) {
98
- return _this.props.updateField(_this.props.fieldId, ev.target.selectedIndex === 0 && _this.state.showPlaceholder ? null : ev.target.value);
101
+ onChange: function onChange(value) {
102
+ return _this.props.updateField(_this.props.fieldId, value);
99
103
  },
104
+ placeholder: _this.state.showPlaceholder ? (_this$props$placehold = _this.props.placeholder) !== null && _this$props$placehold !== void 0 ? _this$props$placehold : LocaleUtils.tr("common.select") : undefined,
100
105
  required: _this.props.required,
101
106
  style: _this.props.style,
102
107
  value: String(_this.props.value)
103
- }, _this.state.showPlaceholder ? /*#__PURE__*/React.createElement("option", {
104
- disabled: _this.props.required,
105
- value: ""
106
- }, (_this$props$placehold = _this.props.placeholder) !== null && _this$props$placehold !== void 0 ? _this$props$placehold : LocaleUtils.tr("common.select")) : null, _this.state.values.map(function (item, index) {
108
+ }, _this.state.values.map(function (item, index) {
107
109
  var _this$itemValueLabel2 = _this.itemValueLabel(item),
108
110
  value = _this$itemValueLabel2.value,
109
111
  label = _this$itemValueLabel2.label;
110
- return /*#__PURE__*/React.createElement("option", {
112
+ return /*#__PURE__*/React.createElement("div", {
111
113
  key: _this.props.fieldId + index,
112
114
  value: String(value)
113
115
  }, label);
114
- }));
116
+ })), _this.props.showEdit ? /*#__PURE__*/React.createElement("button", {
117
+ className: "button",
118
+ onClick: _this.onEdit,
119
+ type: "button"
120
+ }, /*#__PURE__*/React.createElement(Icon, {
121
+ icon: "draw"
122
+ })) : null, _this.props.showAdd ? /*#__PURE__*/React.createElement("button", {
123
+ className: "button",
124
+ onClick: _this.onAdd,
125
+ type: "button"
126
+ }, /*#__PURE__*/React.createElement(Icon, {
127
+ icon: "plus"
128
+ })) : null);
115
129
  });
116
130
  _defineProperty(_this, "itemValueLabel", function (item) {
117
131
  var value = "";
@@ -127,6 +141,25 @@ var EditComboField = /*#__PURE__*/function (_React$Component) {
127
141
  label: label
128
142
  };
129
143
  });
144
+ _defineProperty(_this, "onAdd", function () {
145
+ var parts = _this.props.keyvalrel.split(":");
146
+ _this.props.switchEditContext("Create", parts[0], null, _this.childContextDone, parts[2]);
147
+ });
148
+ _defineProperty(_this, "onEdit", function () {
149
+ var parts = _this.props.keyvalrel.split(":");
150
+ _this.props.switchEditContext("Edit", parts[0], _this.props.value, _this.childContextDone, parts[2]);
151
+ });
152
+ _defineProperty(_this, "childContextDone", function (feature) {
153
+ var _this$props$filterExp;
154
+ var parts = _this.props.keyvalrel.split(":");
155
+ KeyValCache.get(_this.props.editIface, _this.props.mapPrefix + "." + _this.props.keyvalrel, (_this$props$filterExp = _this.props.filterExpr) !== null && _this$props$filterExp !== void 0 ? _this$props$filterExp : null, true).then(function (values) {
156
+ _this.setState({
157
+ values: values,
158
+ showPlaceholder: !_this.hasEmptyValue(values)
159
+ });
160
+ _this.props.updateField(_this.props.fieldId, feature.properties[parts[1]]);
161
+ });
162
+ });
130
163
  return _this;
131
164
  }
132
165
  _inherits(EditComboField, _React$Component);
@@ -140,8 +173,8 @@ var EditComboField = /*#__PURE__*/function (_React$Component) {
140
173
  showPlaceholder: !this.hasEmptyValue(this.props.values)
141
174
  });
142
175
  } else if (this.props.keyvalrel) {
143
- var _this$props$filterExp;
144
- KeyValCache.get(this.props.editIface, this.props.keyvalrel, (_this$props$filterExp = this.props.filterExpr) !== null && _this$props$filterExp !== void 0 ? _this$props$filterExp : null).then(function (values) {
176
+ var _this$props$filterExp2;
177
+ KeyValCache.get(this.props.editIface, this.props.mapPrefix + "." + this.props.keyvalrel, (_this$props$filterExp2 = this.props.filterExpr) !== null && _this$props$filterExp2 !== void 0 ? _this$props$filterExp2 : null).then(function (values) {
145
178
  _this2.setState({
146
179
  values: values,
147
180
  showPlaceholder: !_this2.hasEmptyValue(values)
@@ -153,9 +186,15 @@ var EditComboField = /*#__PURE__*/function (_React$Component) {
153
186
  key: "componentDidUpdate",
154
187
  value: function componentDidUpdate(prevProps) {
155
188
  var _this3 = this;
156
- if (this.props.keyvalrel && this.props.filterExpr !== prevProps.filterExpr) {
157
- var _this$props$filterExp2;
158
- KeyValCache.get(this.props.editIface, this.props.keyvalrel, (_this$props$filterExp2 = this.props.filterExpr) !== null && _this$props$filterExp2 !== void 0 ? _this$props$filterExp2 : null).then(function (values) {
189
+ if (this.props.values && this.props.values !== prevProps.values) {
190
+ // This does not handle the case a selected value has disappeared from values, caller should handle that
191
+ this.setState({
192
+ values: this.props.values,
193
+ showPlaceholder: !this.hasEmptyValue(this.props.values)
194
+ });
195
+ } else if (this.props.keyvalrel && this.props.filterExpr !== prevProps.filterExpr) {
196
+ var _this$props$filterExp3;
197
+ KeyValCache.get(this.props.editIface, this.props.mapPrefix + "." + this.props.keyvalrel, (_this$props$filterExp3 = this.props.filterExpr) !== null && _this$props$filterExp3 !== void 0 ? _this$props$filterExp3 : null).then(function (values) {
159
198
  _this3.setState({
160
199
  values: values,
161
200
  showPlaceholder: !_this3.hasEmptyValue(values)
@@ -179,12 +218,16 @@ _defineProperty(EditComboField, "propTypes", {
179
218
  fieldId: PropTypes.string,
180
219
  filterExpr: PropTypes.array,
181
220
  keyvalrel: PropTypes.string,
221
+ mapPrefix: PropTypes.string,
182
222
  multiSelect: PropTypes.bool,
183
223
  name: PropTypes.string,
184
224
  placeholder: PropTypes.string,
185
225
  readOnly: PropTypes.bool,
186
226
  required: PropTypes.bool,
227
+ showAdd: PropTypes.bool,
228
+ showEdit: PropTypes.bool,
187
229
  style: PropTypes.object,
230
+ switchEditContext: PropTypes.func,
188
231
  updateField: PropTypes.func,
189
232
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
190
233
  values: PropTypes.array
@@ -65,9 +65,9 @@ var LinkFeatureForm = /*#__PURE__*/function (_React$Component) {
65
65
  }
66
66
  });
67
67
  });
68
- _defineProperty(_this, "finish", function () {
68
+ _defineProperty(_this, "close", function () {
69
69
  var editContext = _this.props.editing.contexts[_this.props.editContextId];
70
- _this.props.finished(editContext.feature);
70
+ _this.props.finished(editContext.action === 'Draw' ? null : editContext.feature);
71
71
  });
72
72
  _defineProperty(_this, "hoverFeature", function (feature) {
73
73
  var layer = {
@@ -194,13 +194,12 @@ var LinkFeatureForm = /*#__PURE__*/function (_React$Component) {
194
194
  return _this3.hoverFeature(feature);
195
195
  }
196
196
  }, (_feature$properties$_ = feature.properties[_this3.props.displayField]) !== null && _feature$properties$_ !== void 0 ? _feature$properties$_ : feature.id);
197
- })), /*#__PURE__*/React.createElement("div", {
197
+ })), !editContext.changed && /*#__PURE__*/React.createElement("div", {
198
198
  className: "link-feature-form-close"
199
199
  }, /*#__PURE__*/React.createElement("button", {
200
200
  className: "button",
201
- disabled: editContext.changed,
202
- onClick: this.finish
203
- }, LocaleUtils.tr("common.cancel"))));
201
+ onClick: this.close
202
+ }, LocaleUtils.tr("common.close"))));
204
203
  } else if (editContext.feature) {
205
204
  var drawing = editContext.action === 'Draw' && !editContext.feature.geometry && this.props.editConfig.geomType;
206
205
  return /*#__PURE__*/React.createElement("div", {
@@ -211,16 +210,16 @@ var LinkFeatureForm = /*#__PURE__*/function (_React$Component) {
211
210
  editContext: editContext,
212
211
  hideDelete: this.props.hideDelete,
213
212
  iface: this.props.iface,
213
+ nested: true,
214
214
  onDiscard: this.onDiscard,
215
215
  readOnly: this.props.readOnly,
216
216
  translations: this.props.translations
217
- }), /*#__PURE__*/React.createElement("div", {
217
+ }), !editContext.changed && /*#__PURE__*/React.createElement("div", {
218
218
  className: "link-feature-form-close"
219
219
  }, /*#__PURE__*/React.createElement("button", {
220
220
  className: "button",
221
- disabled: editContext.changed,
222
- onClick: this.finish
223
- }, drawing ? LocaleUtils.tr("common.cancel") : LocaleUtils.tr("common.close"))));
221
+ onClick: this.close
222
+ }, editContext.action === 'Draw' ? LocaleUtils.tr("common.cancel") : LocaleUtils.tr("common.close"))));
224
223
  } else {
225
224
  return null;
226
225
  }
@@ -37,7 +37,7 @@ import isEmpty from 'lodash.isempty';
37
37
  import PropTypes from 'prop-types';
38
38
  import { v4 as uuidv4 } from 'uuid';
39
39
  import ConfigUtils from '../utils/ConfigUtils';
40
- import { parseExpression, FeatureCache, KeyValCache } from '../utils/EditingUtils';
40
+ import { parseExpression } from '../utils/EditingUtils';
41
41
  import LocaleUtils from '../utils/LocaleUtils';
42
42
  import MiscUtils from '../utils/MiscUtils';
43
43
  import EditComboField from './EditComboField';
@@ -482,7 +482,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
482
482
  var count = parts.length;
483
483
  var _fieldId = parts.slice(1, count - 3).join("__");
484
484
  value = (_fieldId2 = (feature.properties || [])[_fieldId]) !== null && _fieldId2 !== void 0 ? _fieldId2 : "";
485
- var keyvalrel = _this.props.mapPrefix + "." + parts[count - 3] + ":" + parts[count - 2] + ":" + parts[count - 1];
485
+ var keyvalrel = parts[count - 3] + ":" + parts[count - 2] + ":" + parts[count - 1];
486
486
  var filterExpr = null;
487
487
  if (field !== null && field !== void 0 && field.filterExpression) {
488
488
  filterExpr = parseExpression(field.filterExpression, feature, editConfig, _this.props.iface, _this.props.mapPrefix, _this.props.mapCrs, function () {
@@ -497,12 +497,16 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
497
497
  filterExpr: filterExpr,
498
498
  key: _fieldId,
499
499
  keyvalrel: keyvalrel,
500
+ mapPrefix: _this.props.mapPrefix,
500
501
  multiSelect: widget.property.allowMulti === true || widget.allowMulti === "true",
501
502
  name: nametransform(_fieldId),
502
503
  placeholder: inputConstraints.placeholder,
503
504
  readOnly: inputConstraints.readOnly || fieldConstraints.readOnly,
504
505
  required: inputConstraints.required || fieldConstraints.required,
506
+ showAdd: fieldConstraints.showAdd,
507
+ showEdit: fieldConstraints.showEdit,
505
508
  style: fontStyle,
509
+ switchEditContext: _this.props.switchEditContext,
506
510
  updateField: updateField,
507
511
  value: value
508
512
  });
@@ -650,7 +654,6 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
650
654
  value = (_feature$properties7 = feature.properties) === null || _feature$properties7 === void 0 ? void 0 : _feature$properties7[attrname];
651
655
  if (layer === reltable) {
652
656
  var index = parseInt(nametransform("").split("__")[1], 10); // Ugh..
653
- var reldataset = _this.props.mapPrefix + "." + reltable;
654
657
  var displayField = attrname.split("__")[1];
655
658
  if (feature.__status__ !== "empty") {
656
659
  var featurebuttons = [{
@@ -664,7 +667,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
664
667
  buttons: featurebuttons,
665
668
  forceLabel: true,
666
669
  onClick: function onClick() {
667
- return _this.props.editRelationRecord('Edit', reltable, reldataset, index, displayField);
670
+ return _this.props.editRelationRecord('Edit', reltable, index, displayField);
668
671
  }
669
672
  }));
670
673
  } else {
@@ -685,7 +688,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
685
688
  buttons: _featurebuttons,
686
689
  forceLabel: true,
687
690
  onClick: function onClick(action) {
688
- return _this.props.editRelationRecord(action, reltable, reldataset, index, displayField);
691
+ return _this.props.editRelationRecord(action, reltable, index, displayField);
689
692
  }
690
693
  });
691
694
  }
@@ -701,8 +704,8 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
701
704
  }, /*#__PURE__*/React.createElement(ButtonBar, {
702
705
  buttons: _featurebuttons2,
703
706
  onClick: function onClick() {
704
- return _this.props.switchEditContext('Edit', layer, value, function (v) {
705
- return updateField(attrname, v);
707
+ return _this.props.switchEditContext('Edit', layer, value, function (f) {
708
+ return updateField(attrname, f.id);
706
709
  }, attrname);
707
710
  }
708
711
  }), /*#__PURE__*/React.createElement("button", {
@@ -727,8 +730,8 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
727
730
  return /*#__PURE__*/React.createElement(ButtonBar, {
728
731
  buttons: _featurebuttons3,
729
732
  onClick: function onClick(action) {
730
- return _this.props.switchEditContext(action, layer, null, function (v) {
731
- return updateField(attrname, v);
733
+ return _this.props.switchEditContext(action, layer, null, function (f) {
734
+ return updateField(attrname, f.id);
732
735
  }, attrname);
733
736
  }
734
737
  });
@@ -1112,12 +1115,6 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
1112
1115
  });
1113
1116
  }
1114
1117
  }
1115
- }, {
1116
- key: "componentWillUnmount",
1117
- value: function componentWillUnmount() {
1118
- KeyValCache.clear();
1119
- FeatureCache.clear();
1120
- }
1121
1118
  }, {
1122
1119
  key: "render",
1123
1120
  value: function render() {
@@ -585,7 +585,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
585
585
  });
586
586
  } else if (_this.props.searchProviders[provider].getResultGeometry) {
587
587
  _this.props.searchProviders[provider].getResultGeometry(result, function (response) {
588
- _this.showResultGeometry(result, response);
588
+ return _this.showResultGeometry(result, response);
589
589
  }, axios);
590
590
  } else {
591
591
  // Display marker
@@ -1049,73 +1049,98 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
1049
1049
  _this.props.setCurrentTask('LayerTree');
1050
1050
  });
1051
1051
  _defineProperty(_this, "showResultGeometry", function (item, response) {
1052
- var _response$crs3, _item$bbox, _item$crs4;
1052
+ var _ref0, _item$label, _response$crs3, _item$bbox, _item$crs3;
1053
1053
  var scale = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined;
1054
+ // Collect highlight features
1055
+ var features = [];
1056
+ if (response !== null && response !== void 0 && response.geometry) {
1057
+ var feature = response.geometry.coordinates ? {
1058
+ type: "Feature",
1059
+ geometry: response.geometry
1060
+ } : VectorLayerUtils.wktToGeoJSON(response.geometry, response.crs, response.crs);
1061
+ if (feature) {
1062
+ features.push(feature);
1063
+ }
1064
+ } else if (response !== null && response !== void 0 && response.feature) {
1065
+ var _response$feature$fea;
1066
+ features = (_response$feature$fea = response.feature.features) !== null && _response$feature$fea !== void 0 ? _response$feature$fea : [response.feature];
1067
+ }
1068
+ // Add highlight features and markers
1054
1069
  var mapCrs = _this.props.map.projection;
1055
- var feature = response !== null && response !== void 0 && response.geometry ? {
1056
- type: "Feature",
1057
- geometry: response.geometry
1058
- } : response === null || response === void 0 ? void 0 : response.feature;
1070
+ var showMarkers = !response.hidemarker && _this.props.searchOptions.showHighlightMarker;
1071
+ var label = ((_ref0 = (_item$label = item.label) !== null && _item$label !== void 0 ? _item$label : item.text) !== null && _ref0 !== void 0 ? _ref0 : '').replace(/<\/?\w+\s*\/?>/g, '');
1059
1072
  var layer = {
1060
1073
  id: "searchselection",
1061
1074
  role: LayerRole.SELECTION
1062
1075
  };
1063
- if (feature) {
1064
- var _feature$features;
1065
- var features = (_feature$features = feature.features) !== null && _feature$features !== void 0 ? _feature$features : [feature];
1066
- features.forEach(function (feat) {
1067
- var _response$crs, _feat$geometry, _feat$crs;
1068
- feat.geometry = VectorLayerUtils.reprojectGeometry(feat.geometry, (_response$crs = response.crs) !== null && _response$crs !== void 0 ? _response$crs : mapCrs, mapCrs);
1069
- feat.styleName = ((_feat$geometry = feat.geometry) === null || _feat$geometry === void 0 ? void 0 : _feat$geometry.type) === 'Point' && _this.props.searchOptions.showHighlightMarker ? 'marker' : 'default';
1070
- feat.styleOptions = _this.props.searchOptions.highlightStyle || {};
1071
- if ((_feat$crs = feat.crs) !== null && _feat$crs !== void 0 && (_feat$crs = _feat$crs.properties) !== null && _feat$crs !== void 0 && _feat$crs.name) {
1072
- feat.crs = CoordinatesUtils.fromOgcUrnCrs(feat.crs.properties.name);
1073
- }
1074
- });
1075
- // If first feature is not a point(=marker), add a marker
1076
- if (features[0].styleName !== "marker" && !response.hidemarker && _this.props.searchOptions.showHighlightMarker) {
1077
- var _response$crs2, _item$crs2;
1078
- var center = response.center ? CoordinatesUtils.reproject(response.center, (_response$crs2 = response.crs) !== null && _response$crs2 !== void 0 ? _response$crs2 : mapCrs, mapCrs) : CoordinatesUtils.reproject([item.x, item.y], (_item$crs2 = item.crs) !== null && _item$crs2 !== void 0 ? _item$crs2 : mapCrs, mapCrs);
1079
- features.unshift({
1080
- geometry: {
1081
- type: 'Point',
1082
- coordinates: center
1083
- },
1084
- styleName: 'marker'
1085
- });
1076
+ var highlightFeatures = [];
1077
+ features.forEach(function (feature) {
1078
+ var _response$crs;
1079
+ feature.geometry = VectorLayerUtils.reprojectGeometry(feature.geometry, (_response$crs = response.crs) !== null && _response$crs !== void 0 ? _response$crs : mapCrs, mapCrs);
1080
+ if (!showMarkers || !feature.geometry.type.endsWith("Point")) {
1081
+ highlightFeatures.push(_objectSpread(_objectSpread({}, feature), {}, {
1082
+ properties: _objectSpread({}, !showMarkers && !_this.props.searchOptions.hideResultLabels && {
1083
+ label: label
1084
+ }),
1085
+ styleName: 'default',
1086
+ styleOptions: _this.props.searchOptions.highlightStyle || {}
1087
+ }));
1086
1088
  }
1087
- // Label first feature
1088
- if (!_this.props.searchOptions.hideResultLabels) {
1089
- var _ref0, _item$label;
1090
- var label = ((_ref0 = (_item$label = item.label) !== null && _item$label !== void 0 ? _item$label : item.text) !== null && _ref0 !== void 0 ? _ref0 : '').replace(/<\/?\w+\s*\/?>/g, '');
1091
- features[0].properties = _objectSpread(_objectSpread({}, features[0].properties), {}, {
1092
- label: label
1093
- });
1089
+ if (showMarkers) {
1090
+ if (feature.geometry.type.endsWith("Point")) {
1091
+ var parts = feature.geometry.type.startsWith("Multi") ? feature.geometry.coordinates : [feature.geometry.coordinates];
1092
+ parts.forEach(function (part) {
1093
+ highlightFeatures.push({
1094
+ type: "Feature",
1095
+ geometry: {
1096
+ type: 'Point',
1097
+ coordinates: part
1098
+ },
1099
+ properties: _objectSpread({}, !_this.props.searchOptions.hideResultLabels && {
1100
+ label: label
1101
+ }),
1102
+ styleName: 'marker'
1103
+ });
1104
+ });
1105
+ } else {
1106
+ var _response$crs2;
1107
+ var center = response.center ? CoordinatesUtils.reproject(response.center, (_response$crs2 = response.crs) !== null && _response$crs2 !== void 0 ? _response$crs2 : mapCrs, mapCrs) : VectorLayerUtils.getFeatureCenter(feature);
1108
+ highlightFeatures.push({
1109
+ type: "Feature",
1110
+ geometry: {
1111
+ type: 'Point',
1112
+ coordinates: center
1113
+ },
1114
+ properties: _objectSpread({}, !_this.props.searchOptions.hideResultLabels && {
1115
+ label: label
1116
+ }),
1117
+ styleName: 'marker'
1118
+ });
1119
+ }
1094
1120
  }
1095
- // Mark first feature as searchmarker
1096
- features[0].id = 'searchmarker';
1097
- _this.props.addLayerFeatures(layer, features, true);
1098
- } else {
1099
- var _item$crs3;
1100
- var _center = CoordinatesUtils.reproject([item.x, item.y], (_item$crs3 = item.crs) !== null && _item$crs3 !== void 0 ? _item$crs3 : mapCrs, mapCrs);
1121
+ });
1122
+ if (isEmpty(highlightFeatures)) {
1123
+ var _item$crs2;
1124
+ var center = CoordinatesUtils.reproject([item.x, item.y], (_item$crs2 = item.crs) !== null && _item$crs2 !== void 0 ? _item$crs2 : mapCrs, mapCrs);
1101
1125
  var marker = {
1102
1126
  type: "Feature",
1103
1127
  geometry: {
1104
1128
  type: "Point",
1105
- coordinates: _center
1129
+ coordinates: center
1106
1130
  },
1131
+ properties: _objectSpread({}, !_this.props.searchOptions.hideResultLabels && {
1132
+ label: label
1133
+ }),
1107
1134
  styleName: 'marker'
1108
1135
  };
1109
- if (!_this.props.searchOptions.hideResultLabels) {
1110
- var _ref1, _item$label2;
1111
- var _label = ((_ref1 = (_item$label2 = item.label) !== null && _item$label2 !== void 0 ? _item$label2 : item.text) !== null && _ref1 !== void 0 ? _ref1 : '').replace(/<\/?\w+\s*\/?>/g, '');
1112
- marker.properties = {
1113
- label: _label
1114
- };
1115
- }
1116
- _this.props.addLayerFeatures(layer, [marker], true);
1136
+ highlightFeatures.push(marker);
1117
1137
  }
1118
- var bbox = response !== null && response !== void 0 && response.bbox ? CoordinatesUtils.reprojectBbox(response.bbox, (_response$crs3 = response.crs) !== null && _response$crs3 !== void 0 ? _response$crs3 : mapCrs, mapCrs) : CoordinatesUtils.reprojectBbox((_item$bbox = item.bbox) !== null && _item$bbox !== void 0 ? _item$bbox : [item.x, item.y, item.x, item.y], (_item$crs4 = item.crs) !== null && _item$crs4 !== void 0 ? _item$crs4 : mapCrs, mapCrs);
1138
+ // Mark first feature as searchmarker
1139
+ highlightFeatures[0].id = 'searchmarker';
1140
+ _this.props.addLayerFeatures(layer, highlightFeatures, true);
1141
+
1142
+ // Zoom to result bbox
1143
+ var bbox = response !== null && response !== void 0 && response.bbox ? CoordinatesUtils.reprojectBbox(response.bbox, (_response$crs3 = response.crs) !== null && _response$crs3 !== void 0 ? _response$crs3 : mapCrs, mapCrs) : CoordinatesUtils.reprojectBbox((_item$bbox = item.bbox) !== null && _item$bbox !== void 0 ? _item$bbox : [item.x, item.y, item.x, item.y], (_item$crs3 = item.crs) !== null && _item$crs3 !== void 0 ? _item$crs3 : mapCrs, mapCrs);
1119
1144
  _this.zoomToResultBBox(bbox, scale);
1120
1145
  _this.props.setCurrentSearchResult(item);
1121
1146
  });
@@ -236,7 +236,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
236
236
  sublayers: _preserveSublayerOptions(layer, prevOptions)
237
237
  });
238
238
  Object.assign(colorLayers[layer.id], LayerUtils.buildWMSLayerParams(colorLayers[layer.id]));
239
- if (colorLayers[layer.id].fields === undefined && layerCreator.getFields) {
239
+ if (layerCreator.getFields) {
240
240
  layerCreator.getFields(layer).then(function (fields) {
241
241
  _this2.updateColorLayer(layer.id, {
242
242
  fields: fields
@@ -545,9 +545,14 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
545
545
  _defineProperty(_this2, "updateSceneObject", function (objectId, options) {
546
546
  var flags = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
547
547
  _this2.setState(function (state) {
548
+ var _objectTree$options$p;
548
549
  var objectTree = _objectSpread({}, state.sceneContext.objectTree);
549
550
  var prevOptions = objectTree[objectId] || {};
550
551
  options = _objectSpread(_objectSpread({}, prevOptions), options);
552
+ // Don't allow hiding the visible child of a mutex group
553
+ if ((_objectTree$options$p = objectTree[options.parent]) !== null && _objectTree$options$p !== void 0 && _objectTree$options$p.mutuallyExclusive && !options.visibility && prevOptions.visibility) {
554
+ options.visibility = true;
555
+ }
551
556
  if (options.objectId) {
552
557
  _this2.applySceneObjectState(objectId, options, prevOptions, objectTree);
553
558
  } else if (options.children && options.visibility !== prevOptions.visibility) {
@@ -567,7 +572,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
567
572
  }
568
573
  var changed = false;
569
574
  if (options.visibility !== prevOptions.visibility || options.opacity !== (prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.opacity)) {
570
- var _objectTree$options$p;
575
+ var _objectTree$options$p2;
571
576
  // Visibile if object is visibile and parents also
572
577
  var isVisible = options.opacity > 0 && options.visibility;
573
578
  for (var curId = options.parent; isVisible && curId !== undefined; curId = objectTree[curId].parent) {
@@ -575,12 +580,13 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
575
580
  }
576
581
  changed |= object.visible !== isVisible;
577
582
  object.visible = isVisible;
578
- if ((_objectTree$options$p = objectTree[options.parent]) !== null && _objectTree$options$p !== void 0 && _objectTree$options$p.mutuallyExclusive && objectTree[options.parent].children) {
583
+ if ((_objectTree$options$p2 = objectTree[options.parent]) !== null && _objectTree$options$p2 !== void 0 && _objectTree$options$p2.mutuallyExclusive && objectTree[options.parent].children) {
579
584
  objectTree[options.parent].children.forEach(function (child) {
580
585
  if (child !== objectId) {
581
586
  objectTree[child] = _objectSpread(_objectSpread({}, objectTree[child]), {}, {
582
587
  visibility: false
583
588
  });
589
+ _this2.objectMap[child].visible = false;
584
590
  }
585
591
  });
586
592
  }
@@ -859,6 +865,14 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
859
865
  };
860
866
  // Need this separately to ensure object[groupId] is already assigned
861
867
  objectTree[groupId].children = _buildObjectTree(entry.items, groupId);
868
+ if (entry.mutuallyExclusive) {
869
+ // Ensure only one child is visible
870
+ var haveVisibleChild = false;
871
+ objectTree[groupId].children.forEach(function (childId) {
872
+ objectTree[childId].visibility = objectTree[childId].visibility && !haveVisibleChild;
873
+ haveVisibleChild |= objectTree[childId].visibility;
874
+ });
875
+ }
862
876
  nodeIds.push(groupId);
863
877
  } else if (entry.type === "tiles3d") {
864
878
  var _entry$title, _entry$visibility2, _entry$snap;
@@ -879,7 +893,8 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
879
893
  idAttr: entry.idAttr,
880
894
  colorAttr: entry.colorAttr,
881
895
  alphaAttr: entry.alphaAttr,
882
- labelAttr: entry.labelAttr
896
+ labelAttr: entry.labelAttr,
897
+ infoAttrBlacklist: entry.infoAttrBlacklist
883
898
  });
884
899
  _this2.applySceneObjectState(entry.name, objectTree[entry.name], {}, objectTree);
885
900
  nodeIds.push(entry.name);
@@ -84,6 +84,10 @@ export default {
84
84
  },
85
85
  getFields: function getFields(options) {
86
86
  return new Promise(function (resolve, reject) {
87
+ if (options.fields !== undefined) {
88
+ // Don't requery fields
89
+ resolve(options.fields);
90
+ }
87
91
  var typeName = options.version < "2.0.0" ? "typeName" : "typeNames";
88
92
  var urlParts = url.parse(options.url, true);
89
93
  var urlParams = Object.entries(urlParts.query).reduce(function (res, _ref3) {
@@ -247,7 +247,9 @@ export var TileMeshHelper = /*#__PURE__*/function () {
247
247
  }, {
248
248
  key: "getFeatureProperties",
249
249
  value: function getFeatureProperties(featureId) {
250
- if (featureId in this.propertiesCache) {
250
+ if (featureId === null) {
251
+ return {};
252
+ } else if (featureId in this.propertiesCache) {
251
253
  return this.propertiesCache[featureId];
252
254
  } else if (this.object.userData.structuralMetadata) {
253
255
  this.propertiesCache[featureId] = this.object.userData.structuralMetadata.getPropertyTableData([this.propertyTable], [featureId])[0];
@@ -1,3 +1,8 @@
1
+ div.edit-single-select {
2
+ display: flex;
3
+ align-items: center;
4
+ }
5
+
1
6
  div.edit-multi-select {
2
7
  border: 1px solid var(--border-color);
3
8
  padding: 0.25em;