qwc2 2026.2.9 → 2026.2.13

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 (35) hide show
  1. package/components/AttributeTableWidget.js +14 -8
  2. package/components/SearchBox.js +2 -1
  3. package/components/map3d/utils/Tiles3DStyle.js +4 -1
  4. package/components/widgets/LayerCatalogWidget.js +2 -1
  5. package/package.json +1 -1
  6. package/plugins/AttributeTable.js +3 -0
  7. package/plugins/Bookmark.js +1 -1
  8. package/plugins/GeometryDigitizer.js +1 -1
  9. package/plugins/MapFilter.js +71 -75
  10. package/plugins/TopBar.js +3 -0
  11. package/plugins/map3d/Identify3D.js +7 -2
  12. package/plugins/style/Bookmark.css +3 -2
  13. package/static/translations/bg-BG.json +1 -0
  14. package/static/translations/ca-ES.json +1 -0
  15. package/static/translations/cs-CZ.json +1 -0
  16. package/static/translations/de-CH.json +1 -0
  17. package/static/translations/de-DE.json +1 -0
  18. package/static/translations/en-US.json +1 -0
  19. package/static/translations/es-ES.json +1 -0
  20. package/static/translations/fi-FI.json +1 -0
  21. package/static/translations/fr-FR.json +1 -0
  22. package/static/translations/hu-HU.json +1 -0
  23. package/static/translations/it-IT.json +1 -0
  24. package/static/translations/ja-JP.json +1 -0
  25. package/static/translations/nl-NL.json +1 -0
  26. package/static/translations/no-NO.json +1 -0
  27. package/static/translations/pl-PL.json +1 -0
  28. package/static/translations/pt-BR.json +1 -0
  29. package/static/translations/pt-PT.json +1 -0
  30. package/static/translations/ro-RO.json +1 -0
  31. package/static/translations/ru-RU.json +1 -0
  32. package/static/translations/sv-SE.json +1 -0
  33. package/static/translations/tr-TR.json +1 -0
  34. package/static/translations/tsconfig.json +1 -0
  35. package/static/translations/uk-UA.json +1 -0
@@ -815,7 +815,8 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
815
815
  }, {
816
816
  key: "render",
817
817
  value: function render() {
818
- var _this2 = this;
818
+ var _this2 = this,
819
+ _ConfigUtils$getPlugi;
819
820
  var captchaRequired = ConfigUtils.getConfigProp("editServiceCaptchaSiteKey") && !ConfigUtils.getConfigProp("username");
820
821
  var captchaPending = captchaRequired && !this.state.captchaResponse;
821
822
  var curEditConfig = this.state.curEditConfig;
@@ -824,6 +825,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
824
825
  var loading = this.state.loading;
825
826
  var editing = this.state.changedFeatureIdx !== null || this.state.newFeature !== null;
826
827
  var selectionEmpty = this.state.selectedFeatures.isEmpty();
828
+ var showIdColumn = !this.props.showDisplayFieldOnly && !this.props.hideIdColumn;
827
829
  var loadOverlay = null;
828
830
  if (loading) {
829
831
  loadOverlay = /*#__PURE__*/React.createElement("div", {
@@ -881,7 +883,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
881
883
  style: {
882
884
  display: this.state.tableReady ? '' : 'none'
883
885
  }
884
- }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null), !this.props.showDisplayFieldOnly ? /*#__PURE__*/React.createElement("th", {
886
+ }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null), showIdColumn ? /*#__PURE__*/React.createElement("th", {
885
887
  onClick: function onClick() {
886
888
  return _this2.sortBy(primaryKey);
887
889
  },
@@ -904,7 +906,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
904
906
  }, _this2.translateFieldName(field.name), field.expression ? /*#__PURE__*/React.createElement(Icon, {
905
907
  icon: "epsilon",
906
908
  title: LocaleUtils.tr("attribtable.calculatedfield")
907
- }) : null), _this2.renderSortIndicator(field.id), idx < fields.length - 1 ? _this2.renderColumnResizeHandle(idx + 2, 'r') : null));
909
+ }) : null), _this2.renderSortIndicator(field.id), idx < fields.length - 1 ? _this2.renderColumnResizeHandle(idx + (showIdColumn ? 2 : 1), 'r') : null));
908
910
  }))), /*#__PURE__*/React.createElement("tbody", null, features.map(function (feature, sliceidx) {
909
911
  var featureidx = indexOffset + sliceidx;
910
912
  var disabled = readOnly || editing && _this2.state.changedFeatureIdx !== featureidx;
@@ -937,7 +939,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
937
939
  });
938
940
  },
939
941
  type: "checkbox"
940
- }), _this2.renderRowResizeHandle(sliceidx + 1, 'b'))), !_this2.props.showDisplayFieldOnly ? /*#__PURE__*/React.createElement("td", null, feature.id) : null, fields.map(function (field) {
942
+ }), _this2.renderRowResizeHandle(sliceidx + 1, 'b'))), showIdColumn ? /*#__PURE__*/React.createElement("td", null, feature.id) : null, fields.map(function (field) {
941
943
  return /*#__PURE__*/React.createElement("td", {
942
944
  key: field.id
943
945
  }, _this2.renderField(feature, curEditConfig, mapPrefix, field, updateField, disabled || !!_this2.state.filterVal && field.id === _this2.state.filterField));
@@ -945,7 +947,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
945
947
  }), this.state.newFeature ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("span", null, features.length > 0 ? this.renderRowResizeHandle(features.length, 't') : null, /*#__PURE__*/React.createElement("input", {
946
948
  disabled: true,
947
949
  type: "checkbox"
948
- }), this.renderRowResizeHandle(features.length + 1, 'b'))), !this.props.showDisplayFieldOnly ? /*#__PURE__*/React.createElement("td", null, this.state.newFeature.id) : null, fields.map(function (field) {
950
+ }), this.renderRowResizeHandle(features.length + 1, 'b'))), showIdColumn ? /*#__PURE__*/React.createElement("td", null, this.state.newFeature.id) : null, fields.map(function (field) {
949
951
  return /*#__PURE__*/React.createElement("td", {
950
952
  key: field.id
951
953
  }, _this2.renderField(_this2.state.newFeature, curEditConfig, mapPrefix, field, _this2.updateNewFeatureField, false));
@@ -1027,9 +1029,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
1027
1029
  return _this2.updateFilter("filterField", ev.target.value);
1028
1030
  },
1029
1031
  value: this.state.filterField
1030
- }, /*#__PURE__*/React.createElement("option", {
1032
+ }, showIdColumn ? /*#__PURE__*/React.createElement("option", {
1031
1033
  value: "<id>"
1032
- }, this.translateFieldName("id")), fields.map(function (field) {
1034
+ }, this.translateFieldName(primaryKey)) : null, fields.map(function (field) {
1033
1035
  return /*#__PURE__*/React.createElement("option", {
1034
1036
  key: field.id,
1035
1037
  value: field.id
@@ -1070,7 +1072,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
1070
1072
  var hasGeometry = (curEditConfig || {}).geomType !== null;
1071
1073
  var showAddButton = !this.props.readOnly && editPermissions.creatable !== false && (this.props.allowAddForGeometryLayers || !hasGeometry);
1072
1074
  var showDelButton = !this.props.readOnly && editPermissions.deletable !== false;
1073
- var showEditButton = !this.props.readOnly && ConfigUtils.havePlugin("Editing") && this.props.showEditFormButton;
1075
+ var showEditButton = !this.props.readOnly && ConfigUtils.havePlugin("Editing") && this.props.showEditFormButton && !((_ConfigUtils$getPlugi = ConfigUtils.getPluginConfig("Editing")) !== null && _ConfigUtils$getPlugi !== void 0 && (_ConfigUtils$getPlugi = _ConfigUtils$getPlugi.cfg) !== null && _ConfigUtils$getPlugi !== void 0 && _ConfigUtils$getPlugi.omitReadOnlyDatasets && Object.values((curEditConfig === null || curEditConfig === void 0 ? void 0 : curEditConfig.permissions) || {}).every(function (permission) {
1076
+ return permission === false;
1077
+ }));
1074
1078
  var deleteButton = showDelButton ? /*#__PURE__*/React.createElement("button", {
1075
1079
  className: "button",
1076
1080
  disabled: layerChanged || editing || selectionEmpty,
@@ -1217,6 +1221,8 @@ _defineProperty(AttributeTableWidget, "propTypes", {
1217
1221
  allowAddForGeometryLayers: PropTypes.bool,
1218
1222
  editConfigs: PropTypes.object,
1219
1223
  filter: PropTypes.object,
1224
+ /** Whether to hide the id (primary key) column. */
1225
+ hideIdColumn: PropTypes.bool,
1220
1226
  iface: PropTypes.object,
1221
1227
  initialLayer: PropTypes.string,
1222
1228
  layers: PropTypes.array,
@@ -477,7 +477,7 @@ var SearchBox = /*#__PURE__*/function (_React$Component) {
477
477
  return _this.selectLayerResult(provider, group, result);
478
478
  },
479
479
  title: LocaleUtils.tr("themeswitcher.addtotheme")
480
- }) : null, result.sublayers ? /*#__PURE__*/React.createElement(Icon, {
480
+ }) : null, _this.props.searchOptions.allowAddLayerAsGroup && result.sublayers ? /*#__PURE__*/React.createElement(Icon, {
481
481
  icon: "group",
482
482
  onClick: function onClick() {
483
483
  return _this.selectLayerResult(provider, group, result, true);
@@ -1258,6 +1258,7 @@ _defineProperty(SearchBox, "propTypes", {
1258
1258
  removeLayer: PropTypes.func,
1259
1259
  replacePlaceholderLayer: PropTypes.func,
1260
1260
  searchOptions: PropTypes.shape({
1261
+ allowAddLayerAsGroup: PropTypes.bool,
1261
1262
  allowSearchFilters: PropTypes.bool,
1262
1263
  focusOnStartup: PropTypes.bool,
1263
1264
  hideResultLabels: PropTypes.bool,
@@ -83,7 +83,10 @@ function featureLabel(objectId, featureProperties, context) {
83
83
  offset: (_context$featureStyle5 = context.featureStyles[objectId].labelOffset) !== null && _context$featureStyle5 !== void 0 ? _context$featureStyle5 : 80
84
84
  };
85
85
  } else if (context.labelAttr) {
86
- return featureProperties[context.labelAttr];
86
+ return {
87
+ text: featureProperties[context.labelAttr],
88
+ offset: 0
89
+ };
87
90
  } else {
88
91
  return null;
89
92
  }
@@ -267,7 +267,8 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
267
267
  icon: "clear",
268
268
  onClick: function onClick() {
269
269
  return _this3.setState({
270
- filter: ""
270
+ filter: "",
271
+ filteredCatalog: null
271
272
  });
272
273
  },
273
274
  role: "suffix"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2026.02.09",
3
+ "version": "2026.02.13",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -75,6 +75,7 @@ var AttributeTable = /*#__PURE__*/function (_React$Component) {
75
75
  title: LocaleUtils.tr("attribtable.title")
76
76
  }, /*#__PURE__*/React.createElement(AttributeTableWidget, {
77
77
  allowAddForGeometryLayers: this.props.allowAddForGeometryLayers,
78
+ hideIdColumn: this.props.hideIdColumn,
78
79
  iface: this.props.iface,
79
80
  initialLayer: (_this$props$taskData = this.props.taskData) === null || _this$props$taskData === void 0 ? void 0 : _this$props$taskData.layer,
80
81
  limitToExtent: this.props.limitToExtent,
@@ -100,6 +101,8 @@ _defineProperty(AttributeTable, "propTypes", {
100
101
  initiallyDocked: PropTypes.bool,
101
102
  side: PropTypes.string
102
103
  }),
104
+ /** Whether to hide the id (primary key) column. */
105
+ hideIdColumn: PropTypes.bool,
103
106
  iface: PropTypes.object,
104
107
  /** Whether to limit to the extent by default. */
105
108
  limitToExtent: PropTypes.bool,
@@ -124,7 +124,7 @@ var Bookmark = /*#__PURE__*/function (_React$Component) {
124
124
  _this.setState({
125
125
  busy: true
126
126
  });
127
- createBookmark(_this.props.theme.title, function (success, key) {
127
+ createBookmark(LocaleUtils.tr("bookmark.newbookmark"), function (success, key) {
128
128
  if (!success) {
129
129
  /* eslint-disable-next-line */
130
130
  alert(LocaleUtils.tr("bookmark.addfailed"));
@@ -488,7 +488,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
488
488
  features.push(_this.props.redlining.selectedFeature);
489
489
  }
490
490
  var invalidPoly = features.find(function (feature) {
491
- return feature.geometry.type === "Polygon" && !isEmpty(polySelfIntersections(feature).geometry.coordinates);
491
+ return feature.geometry.type === "Polygon" && !isEmpty(polySelfIntersections(feature));
492
492
  });
493
493
  if (invalidPoly) {
494
494
  /* eslint-disable-next-line */
@@ -77,7 +77,7 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
77
77
  filterInvalid: false
78
78
  });
79
79
  _defineProperty(_this, "collectPredefinedFilters", function (layers) {
80
- return layers.reduce(function (res, layer) {
80
+ var filters = layers.reduce(function (res, layer) {
81
81
  return _objectSpread(_objectSpread({}, res), (layer.predefinedFilters || []).reduce(function (res2, config) {
82
82
  return _objectSpread(_objectSpread({}, res2), {}, _defineProperty({}, config.id, _objectSpread(_objectSpread({}, config), {}, {
83
83
  filter: Object.fromEntries(Object.entries(config.filter).map(function (_ref) {
@@ -89,40 +89,55 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
89
89
  })));
90
90
  }, {}));
91
91
  }, {});
92
+ if (_this.props.allowFilterByTime) {
93
+ var timeFilter = {};
94
+ layers.forEach(function (layer) {
95
+ return _this.buildTimeFilter(layer, timeFilter, layer.wms_name);
96
+ });
97
+ if (!isEmpty(timeFilter)) {
98
+ filters.__timefilter = {
99
+ id: "__timefilter",
100
+ active: false,
101
+ filter: timeFilter,
102
+ title: LocaleUtils.tr("mapfilter.timefilter"),
103
+ fields: [{
104
+ id: "tstart",
105
+ defaultValue: "",
106
+ inputConfig: {
107
+ type: "datetime"
108
+ },
109
+ title: LocaleUtils.tr("mapfilter.timefrom")
110
+ }, {
111
+ id: "tend",
112
+ defaultValue: "",
113
+ inputConfig: {
114
+ type: "datetime"
115
+ },
116
+ title: LocaleUtils.tr("mapfilter.timeto")
117
+ }],
118
+ defaultValues: {
119
+ tstart: '1800-01-01',
120
+ tend: '9999-12-31'
121
+ }
122
+ };
123
+ }
124
+ }
125
+ return filters;
92
126
  });
93
127
  _defineProperty(_this, "initializeFilters", function (predefinedFilters, prevFilters) {
94
128
  clearTimeout(_this.applyFilterTimeout);
95
129
  _this.applyFilterTimeout = null;
96
- var filters = Object.values(predefinedFilters).reduce(function (res, filterConfig) {
130
+ return Object.values(predefinedFilters).reduce(function (res, filterConfig) {
97
131
  var _prevFilters$filterCo;
98
132
  return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, filterConfig.id, (_prevFilters$filterCo = prevFilters === null || prevFilters === void 0 ? void 0 : prevFilters[filterConfig.id]) !== null && _prevFilters$filterCo !== void 0 ? _prevFilters$filterCo : {
99
133
  active: false,
100
134
  filter: filterConfig.filter,
101
135
  values: filterConfig.fields.reduce(function (values, valueConfig) {
102
136
  return _objectSpread(_objectSpread({}, values), {}, _defineProperty({}, valueConfig.id, valueConfig.defaultValue));
103
- }, {})
137
+ }, {}),
138
+ defaultValues: filterConfig.defaultValues
104
139
  }));
105
140
  }, {});
106
- var timeFilter = {};
107
- _this.props.layers.forEach(function (layer) {
108
- return _this.buildTimeFilter(layer, timeFilter, layer.wms_name);
109
- });
110
- if (!isEmpty(timeFilter) && _this.props.allowFilterByTime) {
111
- var _prevFilters$__timefi, _prevFilters$__timefi2, _prevFilters$__timefi3, _prevFilters$__timefi4;
112
- filters.__timefilter = {
113
- active: (_prevFilters$__timefi = (_prevFilters$__timefi2 = prevFilters.__timefilter) === null || _prevFilters$__timefi2 === void 0 ? void 0 : _prevFilters$__timefi2.active) !== null && _prevFilters$__timefi !== void 0 ? _prevFilters$__timefi : false,
114
- filter: timeFilter,
115
- values: (_prevFilters$__timefi3 = (_prevFilters$__timefi4 = prevFilters.__timefilter) === null || _prevFilters$__timefi4 === void 0 ? void 0 : _prevFilters$__timefi4.values) !== null && _prevFilters$__timefi3 !== void 0 ? _prevFilters$__timefi3 : {
116
- tstart: "",
117
- tend: ""
118
- },
119
- defaultValues: {
120
- tstart: '1800-01-01',
121
- tend: '9999-12-31'
122
- }
123
- };
124
- }
125
- return filters;
126
141
  });
127
142
  _defineProperty(_this, "applyFilter", function () {
128
143
  var _this$state$filters$_;
@@ -279,7 +294,7 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
279
294
  if (_this.state.filterEditor) {
280
295
  return _this.renderFilterEditor();
281
296
  } else {
282
- return [_this.renderInvalidWarning()].concat(_toConsumableArray(_this.renderPredefinedFilters()), [_this.props.allowFilterByTime ? _this.renderTimeFilter() : null, _this.props.allowFilterByGeom ? _this.renderGeomFilter() : null], _toConsumableArray(_this.renderCustomFilters()));
297
+ return [_this.renderInvalidWarning()].concat(_toConsumableArray(_this.renderPredefinedFilters()), [_this.props.allowFilterByGeom ? _this.renderGeomFilter() : null], _toConsumableArray(_this.renderCustomFilters()));
283
298
  }
284
299
  });
285
300
  _defineProperty(_this, "renderInvalidWarning", function () {
@@ -389,61 +404,42 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
389
404
  var _field$title;
390
405
  return /*#__PURE__*/React.createElement("tr", {
391
406
  key: field.id
392
- }, /*#__PURE__*/React.createElement("td", null, (_field$title = field.title) !== null && _field$title !== void 0 ? _field$title : LocaleUtils.tr(field.titlemsgid), ": "), /*#__PURE__*/React.createElement("td", null, field.inputConfig.type === 'select' ? /*#__PURE__*/React.createElement("select", {
393
- onChange: function onChange(ev) {
394
- return _this.updateFieldValue(config.id, field.id, ev.target.value);
395
- },
396
- value: _this.state.filters[config.id].values[field.id]
397
- }, !field.defaultValue ? /*#__PURE__*/React.createElement("option", {
398
- value: ""
399
- }, LocaleUtils.tr("common.select")) : null, field.inputConfig.options.map(function (entry) {
400
- var _entry$value, _entry$value2, _entry$label;
401
- return /*#__PURE__*/React.createElement("option", {
402
- key: (_entry$value = entry.value) !== null && _entry$value !== void 0 ? _entry$value : entry,
403
- value: (_entry$value2 = entry.value) !== null && _entry$value2 !== void 0 ? _entry$value2 : entry
404
- }, (_entry$label = entry.label) !== null && _entry$label !== void 0 ? _entry$label : entry.labelmsgid ? LocaleUtils.tr(entry.labelmsgid) : entry);
405
- })) : /*#__PURE__*/React.createElement("input", _extends({
406
- onChange: function onChange(ev) {
407
- return _this.updateFieldValue(config.id, field.id, ev.target.value);
408
- },
409
- type: "text",
410
- value: _this.state.filters[config.id].values[field.id] || ""
411
- }, field.inputConfig))));
407
+ }, /*#__PURE__*/React.createElement("td", null, (_field$title = field.title) !== null && _field$title !== void 0 ? _field$title : LocaleUtils.tr(field.titlemsgid), ": "), /*#__PURE__*/React.createElement("td", null, _this.renderFilterField(config.id, field)));
412
408
  })))));
413
409
  });
414
410
  });
415
- _defineProperty(_this, "renderTimeFilter", function () {
416
- var timeFilter = _this.state.filters.__timefilter;
417
- if (!timeFilter) {
418
- return null;
411
+ _defineProperty(_this, "renderFilterField", function (configid, field) {
412
+ if (field.inputConfig.type === 'select') {
413
+ return /*#__PURE__*/React.createElement("select", {
414
+ onChange: function onChange(ev) {
415
+ return _this.updateFieldValue(configid, field.id, ev.target.value);
416
+ },
417
+ value: _this.state.filters[configid].values[field.id]
418
+ }, !field.defaultValue ? /*#__PURE__*/React.createElement("option", {
419
+ value: ""
420
+ }, LocaleUtils.tr("common.select")) : null, field.inputConfig.options.map(function (entry) {
421
+ var _entry$value, _entry$value2, _entry$label;
422
+ return /*#__PURE__*/React.createElement("option", {
423
+ key: (_entry$value = entry.value) !== null && _entry$value !== void 0 ? _entry$value : entry,
424
+ value: (_entry$value2 = entry.value) !== null && _entry$value2 !== void 0 ? _entry$value2 : entry
425
+ }, (_entry$label = entry.label) !== null && _entry$label !== void 0 ? _entry$label : entry.labelmsgid ? LocaleUtils.tr(entry.labelmsgid) : entry);
426
+ }));
427
+ } else if (field.inputConfig.type === "datetime") {
428
+ return /*#__PURE__*/React.createElement(DateTimeInput, {
429
+ onChange: function onChange(value) {
430
+ return _this.updateFieldValue(configid, field.id, value);
431
+ },
432
+ value: _this.state.filters[configid].values[field.id] || ""
433
+ });
434
+ } else {
435
+ return /*#__PURE__*/React.createElement("input", _extends({
436
+ onChange: function onChange(ev) {
437
+ return _this.updateFieldValue(configid, field.id, ev.target.value);
438
+ },
439
+ type: "text",
440
+ value: _this.state.filters[configid].values[field.id] || ""
441
+ }, field.inputConfig));
419
442
  }
420
- return /*#__PURE__*/React.createElement("div", {
421
- className: "map-filter-entry",
422
- key: "__timefilter"
423
- }, /*#__PURE__*/React.createElement("div", {
424
- className: "map-filter-entry-titlebar"
425
- }, /*#__PURE__*/React.createElement("span", {
426
- className: "map-filter-entry-title"
427
- }, LocaleUtils.tr("mapfilter.timefilter")), /*#__PURE__*/React.createElement(ToggleSwitch, {
428
- active: timeFilter.active,
429
- onChange: function onChange(active) {
430
- return _this.toggleFilter("__timefilter", active);
431
- }
432
- })), /*#__PURE__*/React.createElement("div", {
433
- className: "map-filter-entry-body"
434
- }, /*#__PURE__*/React.createElement("table", {
435
- className: "map-filter-entry-fields"
436
- }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapfilter.timefrom"), ": "), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(DateTimeInput, {
437
- onChange: function onChange(value) {
438
- return _this.updateFieldValue("__timefilter", "tstart", value);
439
- },
440
- value: timeFilter.values.tstart
441
- }))), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapfilter.timeto"), ": "), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(DateTimeInput, {
442
- onChange: function onChange(value) {
443
- return _this.updateFieldValue("__timefilter", "tend", value);
444
- },
445
- value: timeFilter.values.tend
446
- })))))));
447
443
  });
448
444
  _defineProperty(_this, "renderCustomFilters", function () {
449
445
  if (!_this.props.allowCustomFilters) {
package/plugins/TopBar.js CHANGED
@@ -241,6 +241,8 @@ _defineProperty(TopBar, "propTypes", {
241
241
  registerTaskSearchProvider: PropTypes.bool,
242
242
  /** Options passed down to the search component. */
243
243
  searchOptions: PropTypes.shape({
244
+ /** Whether to show an icon to add a layer result as a group (i.e. with visibile sublayers). */
245
+ allowAddLayerAsGroup: PropTypes.bool,
244
246
  /** Whether to show the search filter widget. */
245
247
  allowSearchFilters: PropTypes.bool,
246
248
  /** Whether to focus the search field on startup. */
@@ -284,6 +286,7 @@ _defineProperty(TopBar, "propTypes", {
284
286
  });
285
287
  _defineProperty(TopBar, "defaultProps", {
286
288
  searchOptions: {
289
+ allowAddLayerAsGroup: true,
287
290
  showHighlightMarker: true,
288
291
  showResultInSearchText: true,
289
292
  minScaleDenom: 1000
@@ -33,12 +33,14 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
33
33
  import React from 'react';
34
34
  import { connect } from 'react-redux';
35
35
  import axios from 'axios';
36
+ import DOMPurify from 'dompurify';
36
37
  import isEmpty from 'lodash.isempty';
37
38
  import PropTypes from 'prop-types';
38
39
  import { BufferGeometry, Float32BufferAttribute, Mesh, MeshStandardMaterial, Raycaster, Vector2 } from 'three';
39
40
  import { TileMeshHelper } from '../../components/map3d/utils/MiscUtils3D';
40
41
  import ResizeableWindow from '../../components/ResizeableWindow';
41
42
  import LocaleUtils from '../../utils/LocaleUtils';
43
+ import MiscUtils from '../../utils/MiscUtils';
42
44
  import '../../components/style/IdentifyViewer.css';
43
45
 
44
46
  /**
@@ -248,8 +250,11 @@ var Identify3D = /*#__PURE__*/function (_React$Component) {
248
250
  }, /*#__PURE__*/React.createElement("td", {
249
251
  className: "identify-attr-title"
250
252
  }, /*#__PURE__*/React.createElement("i", null, key)), /*#__PURE__*/React.createElement("td", {
251
- className: "identify-attr-value"
252
- }, value.toString()));
253
+ className: "identify-attr-value",
254
+ dangerouslySetInnerHTML: {
255
+ __html: MiscUtils.addLinkAnchors(DOMPurify.sanitize(value))
256
+ }
257
+ }));
253
258
  }))))));
254
259
  }
255
260
  }]);
@@ -57,7 +57,7 @@ div.bookmark-list-item > span.icon {
57
57
  flex: 0 0 1.5em;
58
58
  }
59
59
 
60
- div.bookmark-list-item > span.icon-trash {
60
+ div.bookmark-list-item > span.icon-trash:hover {
61
61
  color: red;
62
62
  }
63
63
 
@@ -65,7 +65,8 @@ div.bookmark-list-item:not(.bookmark-list-item-active):nth-child(even) {
65
65
  background-color: var(--list-item-bg-color-even);
66
66
  }
67
67
 
68
- div.bookmark-list-item:hover {
68
+ div.bookmark-list-item:hover,
69
+ div.bookmark-list-item:not(.bookmark-list-item-active):nth-child(even):hover {
69
70
  background-color: var(--list-item-bg-color-hover);
70
71
  color: var(--list-item-text-color-hover);
71
72
  }
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Неуспешно създаване на отметки",
94
94
  "lastUpdate": "Последно запазен",
95
95
  "manage": "Управление на отметките",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Няма отметки",
97
98
  "notloggedin": "Трябва да сте влезли в системата, за да съхранявате отметки",
98
99
  "open": "Отваряне на отметки в текущия раздел",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Error al crear",
94
94
  "lastUpdate": "Darrer canvi",
95
95
  "manage": "Gestionar",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Cap marcador",
97
98
  "notloggedin": "No logat",
98
99
  "open": "Obrir",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Vytváření záložky selhalo",
94
94
  "lastUpdate": "Naposledy upraveno",
95
95
  "manage": "Správa záložek",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Zatím žádné záložky",
97
98
  "notloggedin": "Pro vytvoření záložky se musíte přihlásit",
98
99
  "open": "Otevřít záložku",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Lesezeichen konnte nicht angelegt werden",
94
94
  "lastUpdate": "Zuletzt gespeichert",
95
95
  "manage": "Lesezeichen verwalten",
96
+ "newbookmark": "Neues Lesezeichen",
96
97
  "nobookmarks": "Keine Lesezeichen",
97
98
  "notloggedin": "Sie müssen angemeldet sein, um Lesezeichen zu verwenden",
98
99
  "open": "In aktuellem Fenster öffnen",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Lesezeichen konnte nicht angelegt werden",
94
94
  "lastUpdate": "Zuletzt gespeichert",
95
95
  "manage": "Lesezeichen verwalten",
96
+ "newbookmark": "Neues Lesezeichen",
96
97
  "nobookmarks": "Keine Lesezeichen",
97
98
  "notloggedin": "Sie müssen angemeldet sein, um Lesezeichen zu verwenden",
98
99
  "open": "In aktuellem Fenster öffnen",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Failed to create bookmark",
94
94
  "lastUpdate": "Last saved",
95
95
  "manage": "Manage bookmarks",
96
+ "newbookmark": "New bookmark",
96
97
  "nobookmarks": "No bookmarks",
97
98
  "notloggedin": "You need to be logged in to store bookmarks",
98
99
  "open": "Open bookmark in current tab",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Error al crear",
94
94
  "lastUpdate": "Último guardado",
95
95
  "manage": "Administrar",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Ningún marcador",
97
98
  "notloggedin": "Se necesita tener sesión iniciada para guardar marcadores",
98
99
  "open": "Abrir en la pestaña actual",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "",
94
94
  "lastUpdate": "",
95
95
  "manage": "Kirjanmerkkien hallinta",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "",
97
98
  "notloggedin": "",
98
99
  "open": "",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Echec de création du marque-page",
94
94
  "lastUpdate": "Dernier enregistrement",
95
95
  "manage": "Gérer les marque-pages",
96
+ "newbookmark": "Nouveau marque-page",
96
97
  "nobookmarks": "Pas de marque-pages",
97
98
  "notloggedin": "Vous avez besoin d'être authentifié pour pouvoir enregistrer des marques-pages",
98
99
  "open": "Ouvrir le marque-page dans l'onglet courant",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "",
94
94
  "lastUpdate": "",
95
95
  "manage": "",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "",
97
98
  "notloggedin": "",
98
99
  "open": "",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Impossibile creare il segnalibro",
94
94
  "lastUpdate": "Ultimo salvataggio",
95
95
  "manage": "Gestisci segnalibri",
96
+ "newbookmark": "Nuovo segnalibro",
96
97
  "nobookmarks": "Nessun segnalibro",
97
98
  "notloggedin": "È necessario aver effettuato l'accesso per utilizzare i segnalibri",
98
99
  "open": "Apri nella finestra corrente",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "ブックマークを作成出来ませんでした",
94
94
  "lastUpdate": "最後の保存",
95
95
  "manage": "ブックマークを管理",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "ブックマーク無し",
97
98
  "notloggedin": "ブックマークを保存するためにはログインする必要があります",
98
99
  "open": "ブックマークを現在のタブで開く",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Bladwijzer maken mislukt",
94
94
  "lastUpdate": "Laatst opgeslagen",
95
95
  "manage": "Beheer bladwijzers",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Geen bladwijzers",
97
98
  "notloggedin": "Je moet ingelogd zijn om bladwijzers op te slaan",
98
99
  "open": "Bladwijzer openen",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "",
94
94
  "lastUpdate": "",
95
95
  "manage": "",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "",
97
98
  "notloggedin": "",
98
99
  "open": "",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "",
94
94
  "lastUpdate": "",
95
95
  "manage": "",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "",
97
98
  "notloggedin": "",
98
99
  "open": "",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Falha ao adicionar",
94
94
  "lastUpdate": "Última atualização",
95
95
  "manage": "Gerenciar",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Sem favoritos",
97
98
  "notloggedin": "Não logado",
98
99
  "open": "Abrir",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Falha ao Adicionar",
94
94
  "lastUpdate": "Última Atualização",
95
95
  "manage": "Gerir",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Sem Marcadores",
97
98
  "notloggedin": "Não Iniciou Sessão",
98
99
  "open": "Abrir",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Semnul de carte nu a putut fi creat",
94
94
  "lastUpdate": "Ultima actualizare",
95
95
  "manage": "Gestionează ssemnele de carte",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Nu există semne de carte salvate",
97
98
  "notloggedin": "Pentru a salva semnele de carte trebuie să fiți autentificat",
98
99
  "open": "Deschide deschide semnul de carte în această pagină",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "",
94
94
  "lastUpdate": "",
95
95
  "manage": "",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "",
97
98
  "notloggedin": "",
98
99
  "open": "",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "",
94
94
  "lastUpdate": "",
95
95
  "manage": "",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "",
97
98
  "notloggedin": "",
98
99
  "open": "",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "Yer işareti oluşturulamadı",
94
94
  "lastUpdate": "Son kaydedilen",
95
95
  "manage": "Yer işaretlerini yönet",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "Yer işareti yok",
97
98
  "notloggedin": "Yer işaretlerini kaydedebilmek için giriş yapmalısınız",
98
99
  "open": "Yer işaretini geçerli sekmede aç",
@@ -119,6 +119,7 @@
119
119
  "bookmark.addfailed",
120
120
  "bookmark.lastUpdate",
121
121
  "bookmark.manage",
122
+ "bookmark.newbookmark",
122
123
  "bookmark.nobookmarks",
123
124
  "bookmark.notloggedin",
124
125
  "bookmark.open",
@@ -93,6 +93,7 @@
93
93
  "addfailed": "",
94
94
  "lastUpdate": "",
95
95
  "manage": "",
96
+ "newbookmark": "",
96
97
  "nobookmarks": "",
97
98
  "notloggedin": "",
98
99
  "open": "",