qwc2 2026.9.17 → 2026.9.30

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 (60) hide show
  1. package/components/AttributeTableWidget.js +270 -104
  2. package/components/IdentifyTool.js +38 -9
  3. package/components/IdentifyViewer.js +21 -14
  4. package/components/QtDesignerForm.js +18 -11
  5. package/components/SegmentInput.js +116 -0
  6. package/components/StandardApp.js +10 -0
  7. package/components/map/layers/VectorLayer.js +52 -86
  8. package/components/map3d/Map3D.js +24 -10
  9. package/components/style/IdentifyViewer.css +1 -1
  10. package/components/style/PluginsContainer.css +1 -0
  11. package/components/style/QtDesignerForm.css +6 -6
  12. package/components/style/SegmentInput.css +11 -0
  13. package/components/widgets/FeaturesTable.js +26 -55
  14. package/components/widgets/style/ButtonBar.css +1 -1
  15. package/icons/sync2d.svg +76 -0
  16. package/package.json +1 -1
  17. package/plugins/Authentication.js +3 -13
  18. package/plugins/FeatureSelection.js +3 -0
  19. package/plugins/Identify.js +3 -0
  20. package/plugins/Print.js +102 -32
  21. package/plugins/View3D.js +3 -0
  22. package/plugins/VisibilityPreset.js +10 -10
  23. package/plugins/map/ConstraintInteraction.js +95 -0
  24. package/plugins/map/RedliningSupport.js +31 -5
  25. package/plugins/map/SnappingSupport.js +4 -2
  26. package/plugins/map/style/SnappingSupport.css +6 -0
  27. package/plugins/map3d/LayerTree3D.js +13 -0
  28. package/plugins/map3d/style/LayerTree3D.css +10 -0
  29. package/reducers/editing.js +4 -4
  30. package/reducers/layers.js +14 -18
  31. package/scripts/themesConfig.py +3 -3
  32. package/static/translations/bg-BG.json +7 -0
  33. package/static/translations/ca-ES.json +7 -0
  34. package/static/translations/cs-CZ.json +7 -0
  35. package/static/translations/de-CH.json +7 -0
  36. package/static/translations/de-DE.json +7 -0
  37. package/static/translations/en-US.json +7 -0
  38. package/static/translations/es-ES.json +7 -0
  39. package/static/translations/fi-FI.json +7 -0
  40. package/static/translations/fr-FR.json +7 -0
  41. package/static/translations/hu-HU.json +7 -0
  42. package/static/translations/it-IT.json +7 -0
  43. package/static/translations/ja-JP.json +7 -0
  44. package/static/translations/nl-NL.json +7 -0
  45. package/static/translations/no-NO.json +7 -0
  46. package/static/translations/pl-PL.json +7 -0
  47. package/static/translations/pt-BR.json +7 -0
  48. package/static/translations/pt-PT.json +7 -0
  49. package/static/translations/ro-RO.json +7 -0
  50. package/static/translations/ru-RU.json +7 -0
  51. package/static/translations/sv-SE.json +7 -0
  52. package/static/translations/tr-TR.json +7 -0
  53. package/static/translations/tsconfig.json +7 -0
  54. package/static/translations/uk-UA.json +7 -0
  55. package/utils/ConfigUtils.js +25 -12
  56. package/utils/CoordinatesUtils.js +30 -0
  57. package/utils/MeasureUtils.js +19 -0
  58. package/utils/MiscUtils.js +8 -0
  59. package/utils/PermaLinkUtils.js +9 -0
  60. package/utils/PluginStore.js +8 -0
@@ -9,9 +9,11 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
9
9
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
10
10
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
11
11
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
12
+ function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
12
13
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
13
14
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
14
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
15
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
16
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
15
17
  function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
16
18
  function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } }
17
19
  function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
@@ -35,9 +37,12 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
35
37
 
36
38
  import React from 'react';
37
39
  import { connect } from 'react-redux';
40
+ import { featureCollection } from '@turf/helpers';
41
+ import intersect from '@turf/intersect';
38
42
  import FileSaver from 'file-saver';
39
43
  import isEmpty from 'lodash.isempty';
40
44
  import PropTypes from 'prop-types';
45
+ import { v4 as uuidv4 } from 'uuid';
41
46
  import { LayerRole, addLayerFeatures, removeLayer, refreshLayer } from '../actions/layers';
42
47
  import { zoomToExtent, zoomToPoint } from '../actions/map';
43
48
  import { setCurrentTask, setCurrentTaskBlocked } from '../actions/task';
@@ -52,11 +57,14 @@ import TextInput from '../components/widgets/TextInput';
52
57
  import ConfigUtils from '../utils/ConfigUtils';
53
58
  import CoordinatesUtils from '../utils/CoordinatesUtils';
54
59
  import { FeatureCache, KeyValCache, parseExpression, getFeatureTemplate } from '../utils/EditingUtils';
60
+ import { defaultHighlightStyle } from '../utils/FeatureStyles';
55
61
  import LayerUtils from '../utils/LayerUtils';
56
62
  import LocaleUtils from '../utils/LocaleUtils';
57
63
  import MapUtils from '../utils/MapUtils';
58
64
  import MiscUtils from '../utils/MiscUtils';
59
65
  import VectorLayerUtils from '../utils/VectorLayerUtils';
66
+ import MapSelection from './MapSelection';
67
+ import ButtonBar from './widgets/ButtonBar';
60
68
  import ComboBox from './widgets/ComboBox';
61
69
  import FeaturesTable from './widgets/FeaturesTable';
62
70
  import MenuButton from './widgets/MenuButton';
@@ -66,12 +74,79 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
66
74
  var _this;
67
75
  _classCallCheck(this, AttributeTableWidget);
68
76
  _this = _callSuper(this, AttributeTableWidget, [props]);
77
+ _defineProperty(_this, "filterFunctions", {
78
+ '~': function _(attr, filterVal) {
79
+ return String(attr).toLowerCase().includes(filterVal);
80
+ },
81
+ '=': function _(attr, filterVal) {
82
+ return String(attr).toLowerCase() === filterVal;
83
+ },
84
+ '!=': function _(attr, filterVal) {
85
+ return String(attr).toLowerCase() !== filterVal;
86
+ },
87
+ '>': function _(attr, filterVal) {
88
+ return Number(attr) > Number(filterVal);
89
+ },
90
+ '>=': function _(attr, filterVal) {
91
+ return Number(attr) >= Number(filterVal);
92
+ },
93
+ '<': function _(attr, filterVal) {
94
+ return Number(attr) < Number(filterVal);
95
+ },
96
+ '<=': function _(attr, filterVal) {
97
+ return Number(attr) <= Number(filterVal);
98
+ }
99
+ });
69
100
  _defineProperty(_this, "rowIsDisabled", function (idx) {
70
101
  return _this.state.changedFeatureIdx !== null && _this.state.changedFeatureIdx !== idx;
71
102
  });
72
- _defineProperty(_this, "setSelectedFeatures", function (features) {
103
+ _defineProperty(_this, "setSelectMode", function (mode) {
104
+ _this.setState(function (state) {
105
+ return {
106
+ selectMode: state.selectMode === mode ? null : mode,
107
+ selectionGeom: null
108
+ };
109
+ });
110
+ });
111
+ _defineProperty(_this, "selectFeatures", function (geom) {
112
+ _this.getFeatures(_this.state, _this.state.loadedLayer, false, geom, function (result) {
113
+ if (result) {
114
+ _this.setState(function (state) {
115
+ if (state.selectMode === 'Point' && result.features.length === 1 && state.selectedFeatures[result.features[0].id]) {
116
+ /* eslint-disable-next-line no-unused-vars */
117
+ var _state$selectedFeatur = state.selectedFeatures,
118
+ _result$features$0$id = result.features[0].id,
119
+ _ = _state$selectedFeatur[_result$features$0$id],
120
+ selectedFeatures = _objectWithoutProperties(_state$selectedFeatur, [_result$features$0$id].map(_toPropertyKey));
121
+ return {
122
+ selectionGeom: null,
123
+ selectedFeatures: selectedFeatures
124
+ };
125
+ } else {
126
+ return {
127
+ selectionGeom: null,
128
+ selectedFeatures: _objectSpread(_objectSpread({}, state.selectedFeatures), result.features.reduce(function (res, f) {
129
+ return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, f.id, f));
130
+ }, {}))
131
+ };
132
+ }
133
+ });
134
+ } else {
135
+ _this.setState({
136
+ selectionGeom: null
137
+ });
138
+ }
139
+ });
73
140
  _this.setState({
74
- selectedFeatures: features
141
+ selectionGeom: geom
142
+ });
143
+ });
144
+ _defineProperty(_this, "setSelectedFeatures", function (selection) {
145
+ _this.setState(function (state) {
146
+ return {
147
+ selectedFeatures: selection,
148
+ selectedOnly: state.selectedOnly && !isEmpty(selection)
149
+ };
75
150
  });
76
151
  });
77
152
  _defineProperty(_this, "setHoveredFeature", function (feature) {
@@ -247,15 +322,34 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
247
322
  newState.limitToExtent = state.limitToExtent;
248
323
  newState.curEditConfig = editConfig;
249
324
  newState.curFields = fields;
325
+ newState.selectedFeatures = {};
326
+ newState.selectedOnly = false;
327
+ }
328
+ if (newState.selectedOnly) {
329
+ // Note: if selectedOnly is set, all selected features have already been fetched from the service, no reload is necessary
330
+ var features = newState.sortField ? Object.values(newState.selectedFeatures).sort(function (f1, f2) {
331
+ var v1 = String(f1.properties[newState.sortField.field]);
332
+ var v2 = String(f2.properties[newState.sortField.field]);
333
+ return v1.localeCompare(v2, undefined, {
334
+ numeric: true,
335
+ sensitivity: 'base'
336
+ }) * newState.sortField.dir;
337
+ }) : Object.values(newState.selectedFeatures);
338
+ return {
339
+ features: features,
340
+ totFeatureCount: features
341
+ };
250
342
  }
251
- newState.selectedFeatures = {};
252
343
  newState.loading = true;
253
- _this.getFeatures(newState, loadLayer, true, function (result) {
344
+ _this.getFeatures(newState, loadLayer, true, null, function (result) {
254
345
  if (result) {
255
- _this.setState(_objectSpread({
256
- loading: false,
257
- loadedLayer: loadLayer
258
- }, result));
346
+ _this.setState(function (state2) {
347
+ return _objectSpread({
348
+ loading: false,
349
+ loadedLayer: loadLayer,
350
+ selectedFeatures: _this.filterSelectedFeatures(state2)
351
+ }, result);
352
+ });
259
353
  } else {
260
354
  // eslint-disable-next-line
261
355
  alert(LocaleUtils.tr("attribtable.loadfailed"));
@@ -267,7 +361,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
267
361
  return newState;
268
362
  });
269
363
  });
270
- _defineProperty(_this, "getFeatures", function (state, loadedLayer, paginate, callback) {
364
+ _defineProperty(_this, "getFeatures", function (state, loadedLayer, paginate, filterGeom, callback) {
271
365
  var _state$curEditConfig, _fieldMap$state$filte, _fieldMap$state$sortF, _state$sortField, _this$props$filter$fi, _this$props$filter$fi2, _fieldMap$state$filte2, _fieldMap$state$sortF2, _state$sortField2;
272
366
  // If sort or filter field is virtual, query non-paginated features and apply additional sorting/filtering client side
273
367
  var fieldMap = (((_state$curEditConfig = state.curEditConfig) === null || _state$curEditConfig === void 0 ? void 0 : _state$curEditConfig.fields) || []).reduce(function (res, field) {
@@ -306,6 +400,22 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
306
400
  options.offset = state.currentPage * state.pageSize;
307
401
  options.limit = state.pageSize;
308
402
  }
403
+ if (filterGeom) {
404
+ if (options.filterGeom) {
405
+ var intersection = intersect(featureCollection([{
406
+ type: "Feature",
407
+ properties: {},
408
+ geometry: options.filterGeom
409
+ }, {
410
+ type: "Feature",
411
+ properties: {},
412
+ geometry: filterGeom
413
+ }]));
414
+ options.filterGeom = intersection !== null && intersection !== void 0 && intersection.geometry ? VectorLayerUtils.geoJSONGeomToWkt(intersection.geometry) : null;
415
+ } else {
416
+ options.filterGeom = filterGeom;
417
+ }
418
+ }
309
419
  _this.props.iface.getFeatures(state.curEditConfig, _this.props.mapCrs, function (result) {
310
420
  if (result) {
311
421
  var _result$numberMatched;
@@ -322,32 +432,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
322
432
  });
323
433
  _defineProperty(_this, "filteredSortedFeatures", function (features, state, fieldMap) {
324
434
  var _fieldMap$state$filte3, _fieldMap$state$sortF3, _state$sortField3;
325
- var filterFunctions = {
326
- '~': function _(attr, filterVal) {
327
- return String(attr).toLowerCase().includes(filterVal);
328
- },
329
- '=': function _(attr, filterVal) {
330
- return String(attr).toLowerCase() === filterVal;
331
- },
332
- '!=': function _(attr, filterVal) {
333
- return String(attr).toLowerCase() !== filterVal;
334
- },
335
- '>': function _(attr, filterVal) {
336
- return Number(attr) > Number(filterVal);
337
- },
338
- '>=': function _(attr, filterVal) {
339
- return Number(attr) >= Number(filterVal);
340
- },
341
- '<': function _(attr, filterVal) {
342
- return Number(attr) < Number(filterVal);
343
- },
344
- '<=': function _(attr, filterVal) {
345
- return Number(attr) <= Number(filterVal);
346
- }
347
- };
348
435
  if (state.filterVal && (_fieldMap$state$filte3 = fieldMap[state.filterField]) !== null && _fieldMap$state$filte3 !== void 0 && _fieldMap$state$filte3.expression) {
349
436
  var filterVal = state.filterVal.toLowerCase();
350
- var test = filterFunctions[state.filterOp];
437
+ var test = _this.filterFunctions[state.filterOp];
351
438
  features = features.filter(function (feature) {
352
439
  return test(feature.properties[state.filterField], filterVal);
353
440
  });
@@ -359,7 +446,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
359
446
  value = _ref4[1];
360
447
  if ((_fieldMap$field2 = fieldMap[field]) !== null && _fieldMap$field2 !== void 0 && _fieldMap$field2.expression) {
361
448
  features = features.filter(function (feature) {
362
- return filterFunctions['~'](feature.properties[field], value);
449
+ return _this.filterFunctions['~'](feature.properties[field], value);
363
450
  });
364
451
  }
365
452
  });
@@ -375,6 +462,31 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
375
462
  }
376
463
  return features;
377
464
  });
465
+ _defineProperty(_this, "filterSelectedFeatures", function (state) {
466
+ // Apply client side filtering to selected features...
467
+ return Object.entries(state.selectedFeatures).reduce(function (res, _ref5) {
468
+ var _ref6 = _slicedToArray(_ref5, 2),
469
+ fid = _ref6[0],
470
+ f = _ref6[1];
471
+ if (state.filterVal) {
472
+ var filterVal = state.filterVal.toLowerCase();
473
+ var test = _this.filterFunctions[state.filterOp];
474
+ if (!test(f.properties[state.filterField], filterVal)) {
475
+ return res;
476
+ }
477
+ }
478
+ for (var _i = 0, _Object$entries = Object.entries(state.columnFilters); _i < _Object$entries.length; _i++) {
479
+ var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
480
+ field = _Object$entries$_i[0],
481
+ value = _Object$entries$_i[1];
482
+ var _test = _this.filterFunctions['~'];
483
+ if (!_test(f.properties[field], value)) {
484
+ return res;
485
+ }
486
+ }
487
+ return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, fid, f));
488
+ }, {});
489
+ });
378
490
  _defineProperty(_this, "updateFilter", function (stateField, val) {
379
491
  var newState = {
380
492
  filterField: _this.state.filterField,
@@ -463,6 +575,13 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
463
575
  deleted: !success ? state.deleteTask.deleted : [].concat(_toConsumableArray(state.deleteTask.deleted), [featureid])
464
576
  })
465
577
  };
578
+ if (featureid in state.selectedFeatures) {
579
+ /* eslint-disable-next-line no-unused-vars */
580
+ var _state$selectedFeatur2 = state.selectedFeatures,
581
+ _ = _state$selectedFeatur2[featureid],
582
+ newSelectedFeatures = _state$selectedFeatur2.newSelectedFeatures;
583
+ newState.selectedFeatures = newSelectedFeatures;
584
+ }
466
585
  if (isEmpty(newState.deleteTask.pending)) {
467
586
  if (!isEmpty(newState.deleteTask.failed)) {
468
587
  // eslint-disable-next-line
@@ -528,10 +647,10 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
528
647
  }
529
648
  var featureData = new FormData();
530
649
  featureData.set('feature', JSON.stringify(feature));
531
- Object.entries(_this.changedFiles).forEach(function (_ref5) {
532
- var _ref6 = _slicedToArray(_ref5, 2),
533
- key = _ref6[0],
534
- value = _ref6[1];
650
+ Object.entries(_this.changedFiles).forEach(function (_ref7) {
651
+ var _ref8 = _slicedToArray(_ref7, 2),
652
+ key = _ref8[0],
653
+ value = _ref8[1];
535
654
  return featureData.set('file:' + key, value);
536
655
  });
537
656
  if (_this.state.captchaResponse) {
@@ -552,6 +671,13 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
552
671
  // eslint-disable-next-line
553
672
  alert(result);
554
673
  } else {
674
+ if (_this.state.selectedFeatures[result.id]) {
675
+ _this.setState(function (state) {
676
+ return {
677
+ selectedFeatures: _objectSpread(_objectSpread({}, state.selectFeatures), {}, _defineProperty({}, result.id, result))
678
+ };
679
+ });
680
+ }
555
681
  _this.changedFiles = {};
556
682
  var mapPrefix = _this.state.curEditConfig.editDataset.split(".")[0];
557
683
  _this.props.refreshLayer(function (layer) {
@@ -585,26 +711,6 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
585
711
  });
586
712
  _this.props.setCurrentTaskBlocked(false);
587
713
  });
588
- _defineProperty(_this, "highlightFeatures", function () {
589
- var features = [];
590
- if (_this.state.hoveredFeature) {
591
- features = [_this.state.hoveredFeature];
592
- } else if (!isEmpty(_this.state.selectedFeatures)) {
593
- features = Object.values(_this.state.selectedFeatures);
594
- } else if (_this.state.filterVal) {
595
- features = _this.state.features;
596
- }
597
- var layer = {
598
- id: "__attributetablehighlight",
599
- role: LayerRole.SELECTION
600
- };
601
- _this.props.addLayerFeatures(layer, features.map(function (f) {
602
- return {
603
- id: f.id,
604
- geometry: f.geometry
605
- };
606
- }), true);
607
- });
608
714
  _defineProperty(_this, "zoomToSelection", function () {
609
715
  var collection = {
610
716
  type: "FeatureCollection",
@@ -687,20 +793,24 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
687
793
  csv: formatCsv,
688
794
  xlsx: formatXlsx
689
795
  };
690
- _this.setState({
691
- loading: true
692
- });
693
- _this.getFeatures(_this.state, _this.state.loadedLayer, false, function (result) {
694
- if (result) {
695
- formatters[format](result.features);
696
- } else {
697
- // eslint-disable-next-line
698
- alert(LocaleUtils.tr("attribtable.loadfailed"));
699
- }
796
+ if (_this.state.selectedOnly) {
797
+ formatters[format](_this.state.features);
798
+ } else {
700
799
  _this.setState({
701
- loading: false
800
+ loading: true
702
801
  });
703
- });
802
+ _this.getFeatures(_this.state, _this.state.loadedLayer, false, null, function (result) {
803
+ if (result) {
804
+ formatters[format](result.features);
805
+ } else {
806
+ // eslint-disable-next-line
807
+ alert(LocaleUtils.tr("attribtable.loadfailed"));
808
+ }
809
+ _this.setState({
810
+ loading: false
811
+ });
812
+ });
813
+ }
704
814
  });
705
815
  _this.changedFiles = {};
706
816
  _this.state = AttributeTableWidget.defaultState;
@@ -708,6 +818,8 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
708
818
  _this.attribTableContents = null;
709
819
  _this.state.limitToExtent = props.limitToExtent;
710
820
  _this.filterWarningShown = false;
821
+ _this.selectionLayerId = uuidv4();
822
+ _this.highlightLayerId = uuidv4();
711
823
  return _this;
712
824
  }
713
825
  _inherits(AttributeTableWidget, _React$Component);
@@ -722,18 +834,34 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
722
834
  key: "componentDidUpdate",
723
835
  value: function componentDidUpdate(prevProps, prevState) {
724
836
  // Reload conditions when limited to extent
725
- if (this.state.limitToExtent && this.state.loadedLayer && (!prevState.limitToExtent || this.props.mapBbox !== prevProps.mapBbox)) {
726
- this.reload({
727
- currentPage: 0
728
- });
729
- } else if (!this.state.limitToExtent && prevState.limitToExtent) {
837
+ if (this.state.loadedLayer && (this.state.limitToExtent && (!prevState.limitToExtent || this.props.mapBbox !== prevProps.mapBbox) || !this.state.limitToExtent && prevState.limitToExtent || this.state.selectedOnly !== prevState.selectedOnly || this.state.selectedOnly && this.state.selectedFeatures !== prevState.selectedFeatures)) {
730
838
  this.reload({
731
839
  currentPage: 0
732
840
  });
733
841
  }
734
842
  // Highlight feature
735
- if (this.state.features !== prevState.features || this.state.hoveredFeature !== prevState.hoveredFeature || this.state.selectedFeatures !== prevState.selectedFeatures) {
736
- this.highlightFeatures();
843
+ if (this.state.selectedFeatures !== prevState.selectedFeatures || this.state.filterVal && this.state.features !== prevState.features) {
844
+ var features = [];
845
+ if (!isEmpty(this.state.selectedFeatures)) {
846
+ features = Object.values(this.state.selectedFeatures);
847
+ } else if (this.state.filterVal) {
848
+ features = this.state.features;
849
+ }
850
+ var layer = {
851
+ id: this.highlightLayerId,
852
+ role: LayerRole.SELECTION,
853
+ zIndex: 100000
854
+ };
855
+ this.props.addLayerFeatures(layer, features, true);
856
+ }
857
+ if (this.state.hoveredFeature !== prevState.hoveredFeature) {
858
+ var _layer = {
859
+ id: this.selectionLayerId,
860
+ role: LayerRole.SELECTION,
861
+ styleOptions: defaultHighlightStyle(),
862
+ zIndex: 100001
863
+ };
864
+ this.props.addLayerFeatures(_layer, this.state.hoveredFeature ? [this.state.hoveredFeature] : [], true);
737
865
  }
738
866
  if (this.state.loadedLayer !== prevState.loadedLayer && this.props.showDisplayFieldOnly) {
739
867
  this.setState(function (state) {
@@ -746,7 +874,8 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
746
874
  }, {
747
875
  key: "componentWillUnmount",
748
876
  value: function componentWillUnmount() {
749
- this.props.removeLayer("__attributetablehighlight");
877
+ this.props.removeLayer(this.highlightLayerId);
878
+ this.props.removeLayer(this.selectionLayerId);
750
879
  }
751
880
  }, {
752
881
  key: "render",
@@ -782,6 +911,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
782
911
  var _fieldConfig$constrai, _fieldConfig$constrai2;
783
912
  var primaryKey = curEditConfig.primaryKey;
784
913
  table = /*#__PURE__*/React.createElement(FeaturesTable, {
914
+ allowSelectAll: !isEmpty(this.state.selectedFeatures),
785
915
  className: "attribtable-table",
786
916
  features: this.state.features,
787
917
  fields: this.state.curFields,
@@ -793,8 +923,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
793
923
  readOnly: readOnly,
794
924
  renderField: this.renderField,
795
925
  rowIsDisabled: this.rowIsDisabled,
926
+ selection: this.state.selectedFeatures,
796
927
  selectionChanged: this.setSelectedFeatures,
797
- showColumnFilters: this.props.showColumnFilters
928
+ showColumnFilters: !this.state.selectedOnly && this.props.showColumnFilters
798
929
  });
799
930
  var npages = Math.ceil(this.state.totFeatureCount / this.state.pageSize);
800
931
  var pages = [this.state.currentPage];
@@ -805,9 +936,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
805
936
  pages.unshift(this.state.currentPage - i);
806
937
  }
807
938
  }
808
- for (var _i = 0; _i < 3 + extraright; ++_i) {
809
- if (this.state.currentPage + _i < npages - 1) {
810
- pages.push(this.state.currentPage - _i + 1);
939
+ for (var _i2 = 0; _i2 < 3 + extraright; ++_i2) {
940
+ if (this.state.currentPage + _i2 < npages - 1) {
941
+ pages.push(this.state.currentPage - _i2 + 1);
811
942
  }
812
943
  }
813
944
  var footbarDisabled = loading || editing;
@@ -822,7 +953,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
822
953
  }
823
954
  valueInput = /*#__PURE__*/React.createElement(ComboBox, {
824
955
  className: "attribtable-filter-value",
825
- disabled: footbarDisabled,
956
+ disabled: footbarDisabled || this.state.selectedOnly,
826
957
  onChange: function onChange(value) {
827
958
  return _this2.updateFilter("filterVal", value);
828
959
  },
@@ -838,7 +969,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
838
969
  } else {
839
970
  valueInput = /*#__PURE__*/React.createElement(TextInput, {
840
971
  className: "attribtable-filter-value",
841
- disabled: footbarDisabled,
972
+ disabled: footbarDisabled || this.state.selectedOnly,
842
973
  onChange: function onChange(value) {
843
974
  return _this2.updateFilter("filterVal", value);
844
975
  },
@@ -868,7 +999,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
868
999
  }, /*#__PURE__*/React.createElement(Icon, {
869
1000
  icon: "filter"
870
1001
  }), /*#__PURE__*/React.createElement(ComboBox, {
871
- disabled: footbarDisabled,
1002
+ disabled: footbarDisabled || this.state.selectedOnly,
872
1003
  onChange: function onChange(value) {
873
1004
  return _this2.updateFilter("filterField", value);
874
1005
  },
@@ -889,7 +1020,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
889
1020
  }
890
1021
  return null;
891
1022
  })), /*#__PURE__*/React.createElement(ComboBox, {
892
- disabled: footbarDisabled,
1023
+ disabled: footbarDisabled || this.state.selectedOnly,
893
1024
  onChange: function onChange(value) {
894
1025
  return _this2.updateFilter("filterOp", value);
895
1026
  },
@@ -908,7 +1039,21 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
908
1039
  value: "<="
909
1040
  }, "<="), /*#__PURE__*/React.createElement("div", {
910
1041
  value: "<"
911
- }, "<")), valueInput), this.props.showLimitToExtent ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
1042
+ }, "<")), valueInput, /*#__PURE__*/React.createElement("button", {
1043
+ className: "button " + (this.state.selectedOnly ? "pressed" : ""),
1044
+ disabled: isEmpty(this.state.selectedFeatures),
1045
+ onClick: function onClick() {
1046
+ return _this2.setState(function (state) {
1047
+ return {
1048
+ selectedOnly: !state.selectedOnly
1049
+ };
1050
+ });
1051
+ },
1052
+ title: LocaleUtils.tr("attribtable.selectedonly"),
1053
+ type: "button"
1054
+ }, /*#__PURE__*/React.createElement(Icon, {
1055
+ icon: "checked"
1056
+ }))), this.props.showLimitToExtent ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
912
1057
  checked: this.state.limitToExtent,
913
1058
  disabled: loading,
914
1059
  onChange: function onChange(ev) {
@@ -950,26 +1095,26 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
950
1095
  sitekey: ConfigUtils.getConfigProp("editServiceCaptchaSiteKey")
951
1096
  }));
952
1097
  }
953
- var editLayers = Object.entries(this.props.editConfigs).map(function (_ref7) {
954
- var _ref8 = _slicedToArray(_ref7, 2),
955
- wmsName = _ref8[0],
956
- serviceConfigs = _ref8[1];
957
- return Object.entries(serviceConfigs).map(function (_ref9) {
958
- var _ref0 = _slicedToArray(_ref9, 2),
959
- layerName = _ref0[0],
960
- editConfig = _ref0[1];
1098
+ var editLayers = Object.entries(this.props.editConfigs).map(function (_ref9) {
1099
+ var _ref0 = _slicedToArray(_ref9, 2),
1100
+ wmsName = _ref0[0],
1101
+ serviceConfigs = _ref0[1];
1102
+ return Object.entries(serviceConfigs).map(function (_ref1) {
1103
+ var _ref10 = _slicedToArray(_ref1, 2),
1104
+ layerName = _ref10[0],
1105
+ editConfig = _ref10[1];
961
1106
  var match = LayerUtils.searchLayer(_this2.props.layers, 'wms_name', wmsName, 'name', layerName);
962
1107
  var layerTitle = layerName;
963
1108
  if (match) {
964
- var _ref1, _ref10, _match$layer$translat, _match$layer$translat2, _match$sublayer;
965
- layerTitle = (_ref1 = (_ref10 = (_match$layer$translat = (_match$layer$translat2 = match.layer.translations) === null || _match$layer$translat2 === void 0 || (_match$layer$translat2 = _match$layer$translat2.layertree) === null || _match$layer$translat2 === void 0 ? void 0 : _match$layer$translat2[layerName]) !== null && _match$layer$translat !== void 0 ? _match$layer$translat : editConfig.layerTitle) !== null && _ref10 !== void 0 ? _ref10 : match === null || match === void 0 || (_match$sublayer = match.sublayer) === null || _match$sublayer === void 0 ? void 0 : _match$sublayer.title) !== null && _ref1 !== void 0 ? _ref1 : layerName;
1109
+ var _ref11, _ref12, _match$layer$translat, _match$layer$translat2, _match$sublayer;
1110
+ layerTitle = (_ref11 = (_ref12 = (_match$layer$translat = (_match$layer$translat2 = match.layer.translations) === null || _match$layer$translat2 === void 0 || (_match$layer$translat2 = _match$layer$translat2.layertree) === null || _match$layer$translat2 === void 0 ? void 0 : _match$layer$translat2[layerName]) !== null && _match$layer$translat !== void 0 ? _match$layer$translat : editConfig.layerTitle) !== null && _ref12 !== void 0 ? _ref12 : match === null || match === void 0 || (_match$sublayer = match.sublayer) === null || _match$sublayer === void 0 ? void 0 : _match$sublayer.title) !== null && _ref11 !== void 0 ? _ref11 : layerName;
966
1111
  } else {
967
- var _this2$props$layers$f, _ref11, _translations$layertr, _translations$layertr2;
1112
+ var _this2$props$layers$f, _ref13, _translations$layertr, _translations$layertr2;
968
1113
  // Note: geometry-less tables are filtered from the theme sublayers
969
1114
  var translations = (_this2$props$layers$f = _this2.props.layers.find(function (layer) {
970
1115
  return layer.wms_name === wmsName;
971
1116
  })) === null || _this2$props$layers$f === void 0 ? void 0 : _this2$props$layers$f.translations;
972
- layerTitle = (_ref11 = (_translations$layertr = translations === null || translations === void 0 || (_translations$layertr2 = translations.layertree) === null || _translations$layertr2 === void 0 ? void 0 : _translations$layertr2[layerName]) !== null && _translations$layertr !== void 0 ? _translations$layertr : editConfig.layerTitle) !== null && _ref11 !== void 0 ? _ref11 : layerName;
1117
+ layerTitle = (_ref13 = (_translations$layertr = translations === null || translations === void 0 || (_translations$layertr2 = translations.layertree) === null || _translations$layertr2 === void 0 ? void 0 : _translations$layertr2[layerName]) !== null && _translations$layertr !== void 0 ? _translations$layertr : editConfig.layerTitle) !== null && _ref13 !== void 0 ? _ref13 : layerName;
973
1118
  }
974
1119
  return {
975
1120
  value: wmsName + "#" + layerName,
@@ -979,9 +1124,23 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
979
1124
  }).flat().filter(Boolean).sort(function (a, b) {
980
1125
  return a.title.localeCompare(b.title);
981
1126
  });
1127
+ var pickButtons = [{
1128
+ key: 'Point',
1129
+ icon: 'pick_point',
1130
+ title: LocaleUtils.tr("attribtable.selectatpoint")
1131
+ }, {
1132
+ key: 'Polygon',
1133
+ icon: 'pick_region',
1134
+ title: LocaleUtils.tr("attribtable.selectinregion")
1135
+ }];
982
1136
  return /*#__PURE__*/React.createElement("div", {
983
1137
  className: "AttributeTable"
984
- }, /*#__PURE__*/React.createElement("div", {
1138
+ }, /*#__PURE__*/React.createElement(MapSelection, {
1139
+ active: this.state.selectMode !== null,
1140
+ geomType: this.state.selectMode,
1141
+ geometry: this.state.selectionGeom,
1142
+ geometryChanged: this.selectFeatures
1143
+ }), /*#__PURE__*/React.createElement("div", {
985
1144
  className: "attribtable-toolbar"
986
1145
  }, this.props.showLayerSelection ? /*#__PURE__*/React.createElement(ComboBox, {
987
1146
  disabled: loading || editing,
@@ -1022,7 +1181,12 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
1022
1181
  title: LocaleUtils.tr("attribtable.zoomtoselection")
1023
1182
  }, /*#__PURE__*/React.createElement(Icon, {
1024
1183
  icon: "search"
1025
- })), showEditButton ? /*#__PURE__*/React.createElement("button", {
1184
+ })), /*#__PURE__*/React.createElement(ButtonBar, {
1185
+ active: this.state.selectMode,
1186
+ buttons: pickButtons,
1187
+ disabled: nolayer,
1188
+ onClick: this.setSelectMode
1189
+ }), showEditButton ? /*#__PURE__*/React.createElement("button", {
1026
1190
  className: "button",
1027
1191
  disabled: layerChanged || editing || Object.keys(this.state.selectedFeatures).length !== 1,
1028
1192
  onClick: this.switchToFormEditMode,
@@ -1125,7 +1289,6 @@ _defineProperty(AttributeTableWidget, "defaultState", {
1125
1289
  curEditConfig: null,
1126
1290
  curFields: null,
1127
1291
  features: [],
1128
- allFeatures: null,
1129
1292
  totFeatureCount: 0,
1130
1293
  selectedFeatures: {},
1131
1294
  hoveredFeature: null,
@@ -1141,7 +1304,10 @@ _defineProperty(AttributeTableWidget, "defaultState", {
1141
1304
  deleteTask: null,
1142
1305
  confirmDelete: false,
1143
1306
  limitToExtent: false,
1144
- captchaResponse: ''
1307
+ captchaResponse: '',
1308
+ selectMode: null,
1309
+ selectionGeom: null,
1310
+ selectedOnly: false
1145
1311
  });
1146
1312
  export default connect(function (state) {
1147
1313
  return {