qwc2 2026.8.13 → 2026.8.21

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 (46) hide show
  1. package/README.md +1 -1
  2. package/components/AttributeTableWidget.js +121 -285
  3. package/components/BookmarkPanel.js +3 -2
  4. package/components/IdentifyViewer.js +39 -20
  5. package/components/ImportLayer.js +6 -392
  6. package/components/QtDesignerForm.js +1 -1
  7. package/components/ResizeableWindow.js +10 -0
  8. package/components/map3d/style/Map3D.css +1 -0
  9. package/components/style/AttributeTableWidget.css +1 -140
  10. package/components/widgets/FeaturesTable.js +30 -31
  11. package/components/widgets/MenuButton.js +10 -10
  12. package/components/widgets/TextInput.js +0 -10
  13. package/components/widgets/style/FeaturesTable.css +46 -19
  14. package/icons/public.svg +63 -0
  15. package/package.json +1 -1
  16. package/plugins/BottomBar.js +123 -111
  17. package/plugins/MapDropImport.js +135 -0
  18. package/plugins/map3d/Viewshed3D.js +171 -52
  19. package/plugins/map3d/style/Viewshed3D.css +4 -0
  20. package/plugins/style/BottomBar.css +10 -3
  21. package/plugins/style/MapDropImport.css +19 -0
  22. package/static/translations/bg-BG.json +8 -0
  23. package/static/translations/ca-ES.json +8 -0
  24. package/static/translations/cs-CZ.json +8 -0
  25. package/static/translations/de-CH.json +8 -0
  26. package/static/translations/de-DE.json +8 -0
  27. package/static/translations/en-US.json +8 -0
  28. package/static/translations/es-ES.json +8 -0
  29. package/static/translations/fi-FI.json +8 -0
  30. package/static/translations/fr-FR.json +8 -0
  31. package/static/translations/hu-HU.json +8 -0
  32. package/static/translations/it-IT.json +8 -0
  33. package/static/translations/ja-JP.json +8 -0
  34. package/static/translations/nl-NL.json +8 -0
  35. package/static/translations/no-NO.json +8 -0
  36. package/static/translations/pl-PL.json +8 -0
  37. package/static/translations/pt-BR.json +8 -0
  38. package/static/translations/pt-PT.json +8 -0
  39. package/static/translations/ro-RO.json +8 -0
  40. package/static/translations/ru-RU.json +8 -0
  41. package/static/translations/sv-SE.json +8 -0
  42. package/static/translations/tr-TR.json +8 -0
  43. package/static/translations/tsconfig.json +4 -0
  44. package/static/translations/uk-UA.json +8 -0
  45. package/utils/FileImportUtils.js +390 -0
  46. package/utils/LayerUtils.js +2 -2
@@ -48,53 +48,47 @@ import NavBar from '../components/widgets/NavBar';
48
48
  import NumberInput from '../components/widgets/NumberInput';
49
49
  import ReCaptchaWidget from '../components/widgets/ReCaptchaWidget';
50
50
  import Spinner from '../components/widgets/Spinner';
51
- import TextInput, { TextInputInitContext } from '../components/widgets/TextInput';
51
+ import TextInput from '../components/widgets/TextInput';
52
52
  import ConfigUtils from '../utils/ConfigUtils';
53
53
  import CoordinatesUtils from '../utils/CoordinatesUtils';
54
54
  import { FeatureCache, KeyValCache, parseExpression, getFeatureTemplate } from '../utils/EditingUtils';
55
55
  import LayerUtils from '../utils/LayerUtils';
56
56
  import LocaleUtils from '../utils/LocaleUtils';
57
57
  import MapUtils from '../utils/MapUtils';
58
- import MiscUtils, { ToggleSet } from '../utils/MiscUtils';
59
58
  import VectorLayerUtils from '../utils/VectorLayerUtils';
59
+ import FeaturesTable from './widgets/FeaturesTable';
60
60
  import './style/AttributeTableWidget.css';
61
61
  var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
62
62
  function AttributeTableWidget(props) {
63
63
  var _this;
64
64
  _classCallCheck(this, AttributeTableWidget);
65
65
  _this = _callSuper(this, AttributeTableWidget, [props]);
66
- _defineProperty(_this, "renderSortIndicator", function (field) {
67
- if (_this.state.sortField && _this.state.sortField.field === field) {
68
- return /*#__PURE__*/React.createElement(Icon, {
69
- icon: _this.state.sortField.dir > 0 ? "chevron-down" : "chevron-up"
70
- });
71
- } else {
72
- return null;
73
- }
66
+ _defineProperty(_this, "rowIsDisabled", function (idx) {
67
+ return _this.state.changedFeatureIdx !== null && _this.state.changedFeatureIdx !== idx;
74
68
  });
75
- _defineProperty(_this, "renderColumnResizeHandle", function (col, pos) {
76
- return /*#__PURE__*/React.createElement("span", {
77
- className: "attribtable-table-" + pos + "draghandle",
78
- onPointerDown: function onPointerDown(ev) {
79
- return _this.resizeTable(ev, col, true);
80
- }
69
+ _defineProperty(_this, "setSelectedFeatures", function (features) {
70
+ _this.setState({
71
+ selectedFeatures: features
81
72
  });
82
73
  });
83
- _defineProperty(_this, "renderRowResizeHandle", function (row, pos) {
84
- return /*#__PURE__*/React.createElement("span", {
85
- className: "attribtable-table-" + pos + "draghandle",
86
- onPointerDown: function onPointerDown(ev) {
87
- return _this.resizeTable(ev, row, false);
88
- }
74
+ _defineProperty(_this, "setHoveredFeature", function (feature) {
75
+ _this.setState({
76
+ hoveredFeature: feature
89
77
  });
90
78
  });
91
- _defineProperty(_this, "renderField", function (feature, editConfig, mapPrefix, field, updateField, fielddisabled) {
79
+ _defineProperty(_this, "renderField", function (feature, field, featureidx, rowdisabled) {
80
+ var editConfig = _this.state.curEditConfig;
81
+ var mapPrefix = editConfig.editDataset.split(".")[0];
82
+ var updateField = function updateField(fieldid, val) {
83
+ var emptynull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
84
+ return _this.updateField(featureidx, fieldid, val, emptynull);
85
+ };
92
86
  var value = feature.properties[field.id];
93
87
  if (value === undefined || value === null) {
94
88
  value = "";
95
89
  }
96
90
  var constraints = field.constraints || {};
97
- var disabled = constraints.readOnly || fielddisabled;
91
+ var disabled = constraints.readOnly || rowdisabled;
98
92
  var input = null;
99
93
  if (field.type === "boolean" || field.type === "bool") {
100
94
  input = /*#__PURE__*/React.createElement("input", _extends({
@@ -229,6 +223,16 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
229
223
  layerName = _selectedLayer$split2[1];
230
224
  var newState = _objectSpread(_objectSpread({}, state), stateChange);
231
225
  var editConfig = _this.props.editConfigs[wmsName][layerName];
226
+ var fields = (_this.props.showDisplayFieldOnly ? editConfig.fields.filter(function (field) {
227
+ return field.name === editConfig.displayField;
228
+ }) : editConfig.fields.filter(function (field) {
229
+ var _field$constraints;
230
+ return _this.props.showHiddenFields || ((_field$constraints = field.constraints) === null || _field$constraints === void 0 ? void 0 : _field$constraints.hidden) !== true;
231
+ })).map(function (field) {
232
+ return _objectSpread(_objectSpread({}, field), {}, {
233
+ name: _this.translateFieldName(field.name)
234
+ });
235
+ });
232
236
  if (selectedLayer !== state.loadedLayer) {
233
237
  var _this$props$layers$fi, _this$props$layers$fi2;
234
238
  KeyValCache.clear();
@@ -236,12 +240,13 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
236
240
  Object.assign(newState, AttributeTableWidget.defaultState);
237
241
  newState.limitToExtent = state.limitToExtent;
238
242
  newState.curEditConfig = editConfig;
243
+ newState.curFields = fields;
239
244
  newState.fieldTranslations = (_this$props$layers$fi = (_this$props$layers$fi2 = _this.props.layers.find(function (layer) {
240
245
  return layer.wms_name === wmsName;
241
246
  })) === null || _this$props$layers$fi2 === void 0 || (_this$props$layers$fi2 = _this$props$layers$fi2.translations) === null || _this$props$layers$fi2 === void 0 || (_this$props$layers$fi2 = _this$props$layers$fi2.layers) === null || _this$props$layers$fi2 === void 0 || (_this$props$layers$fi2 = _this$props$layers$fi2[layerName]) === null || _this$props$layers$fi2 === void 0 ? void 0 : _this$props$layers$fi2.fields) !== null && _this$props$layers$fi !== void 0 ? _this$props$layers$fi : {};
242
247
  }
243
248
  newState.selectedLayer = selectedLayer;
244
- newState.selectedFeatures = new ToggleSet();
249
+ newState.selectedFeatures = {};
245
250
  newState.tableReady = false;
246
251
  _this.pendingTextEdits = new Set();
247
252
  var options = {
@@ -254,14 +259,14 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
254
259
  var fieldMap = (((_newState$curEditConf = newState.curEditConfig) === null || _newState$curEditConf === void 0 ? void 0 : _newState$curEditConf.fields) || []).reduce(function (res, field) {
255
260
  return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, field.id, field));
256
261
  }, {});
257
- var clientSideFilterSort = newState.clientSideData || newState.filterVal && ((_fieldMap$newState$fi = fieldMap[newState.filterField]) === null || _fieldMap$newState$fi === void 0 ? void 0 : _fieldMap$newState$fi.expression) || ((_fieldMap$newState$so = fieldMap[(_newState$sortField = newState.sortField) === null || _newState$sortField === void 0 ? void 0 : _newState$sortField.field]) === null || _fieldMap$newState$so === void 0 ? void 0 : _fieldMap$newState$so.expression);
262
+ var clientSideFilterSort = newState.filterVal && ((_fieldMap$newState$fi = fieldMap[newState.filterField]) === null || _fieldMap$newState$fi === void 0 ? void 0 : _fieldMap$newState$fi.expression) || ((_fieldMap$newState$so = fieldMap[(_newState$sortField = newState.sortField) === null || _newState$sortField === void 0 ? void 0 : _newState$sortField.field]) === null || _fieldMap$newState$so === void 0 ? void 0 : _fieldMap$newState$so.expression);
258
263
  if (!forceReload && clientSideFilterSort && newState.allFeatures) {
259
264
  return _objectSpread(_objectSpread({}, newState), {}, {
260
265
  features: _this.filteredSortedFeatures(newState.allFeatures, newState)
261
266
  });
262
267
  } else {
263
268
  Object.assign(newState, {
264
- allFeatures: [],
269
+ allFeatures: null,
265
270
  features: []
266
271
  });
267
272
  if (clientSideFilterSort) {
@@ -278,7 +283,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
278
283
  } else if (newState.filterVal) {
279
284
  options.filter = [[newState.filterField, newState.filterOp, newState.filterVal]];
280
285
  } else {
281
- // NOTE: Query full feature set when filtering so that filtered geometries can be highlighted
286
+ // NOTE: set offset/limit only when not filtering. Query all filtered features so that they can be highlighted.
282
287
  options.offset = newState.currentPage * newState.pageSize;
283
288
  options.limit = newState.pageSize;
284
289
  }
@@ -287,18 +292,13 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
287
292
  newState.loading = true;
288
293
  _this.props.iface.getFeatures(editConfig, _this.props.mapCrs, function (result) {
289
294
  if (result) {
290
- var _result$numberMatched, _options$offset;
291
- var featuresSlice = result.features || [];
292
- var features = new Array((_result$numberMatched = result.numberMatched) !== null && _result$numberMatched !== void 0 ? _result$numberMatched : featuresSlice.length);
293
- features.splice.apply(features, [(_options$offset = options.offset) !== null && _options$offset !== void 0 ? _options$offset : 0, featuresSlice.length].concat(_toConsumableArray(featuresSlice)));
294
- var sortedFilteredFeatures = clientSideFilterSort ? _this.filteredSortedFeatures(features, newState) : features;
295
+ var _result$numberMatched;
295
296
  _this.setState({
296
297
  loading: false,
297
- allFeatures: options.limit === undefined || result.numberMatched === undefined ? features : null,
298
- features: sortedFilteredFeatures,
299
- featureCount: Math.ceil(sortedFilteredFeatures.length / newState.pageSize),
300
- loadedLayer: newState.selectedLayer,
301
- clientSideData: result.numberMatched === undefined
298
+ allFeatures: clientSideFilterSort ? result.features : null,
299
+ features: clientSideFilterSort ? _this.filteredSortedFeatures(result.features, newState) : result.features,
300
+ totFeatureCount: (_result$numberMatched = result.numberMatched) !== null && _result$numberMatched !== void 0 ? _result$numberMatched : result.features.length,
301
+ loadedLayer: newState.selectedLayer
302
302
  });
303
303
  } else {
304
304
  // eslint-disable-next-line
@@ -361,7 +361,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
361
361
  }, []);
362
362
  }
363
363
  if (state.sortField) {
364
- var sortFieldValue = state.sortField.field === "id" ? function (feature) {
364
+ var _this$state$curEditCo;
365
+ var pk = (_this$state$curEditCo = _this.state.curEditConfig.primaryKey) !== null && _this$state$curEditCo !== void 0 ? _this$state$curEditCo : "id";
366
+ var sortFieldValue = state.sortField.field === pk ? function (feature) {
365
367
  return feature.id;
366
368
  } : function (feature) {
367
369
  return feature.properties[state.sortField.field];
@@ -378,10 +380,6 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
378
380
  return filteredFeatures;
379
381
  }
380
382
  });
381
- _defineProperty(_this, "currentPageFeatures", function (state) {
382
- var indexOffset = state.currentPage * state.pageSize;
383
- return state.features.slice(indexOffset, indexOffset + state.pageSize);
384
- });
385
383
  _defineProperty(_this, "updateFilter", function (stateField, val) {
386
384
  var newState = {
387
385
  filterField: _this.state.filterField,
@@ -433,28 +431,31 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
433
431
  };
434
432
  var mapPrefix = _this.state.curEditConfig.editDataset.split(".")[0];
435
433
  getFeatureTemplate(_this.state.curEditConfig, featureSkel, _this.props.iface, mapPrefix, _this.props.mapCrs, function (feature) {
436
- _this.setState({
437
- newFeature: feature,
438
- filterVal: ""
434
+ _this.setState(function (state) {
435
+ return {
436
+ features: [].concat(_toConsumableArray(state.features), [feature]),
437
+ changedFeatureIdx: state.features.length,
438
+ filterVal: ""
439
+ };
440
+ }, function () {
441
+ if (_this.attribTableContents) {
442
+ _this.attribTableContents.firstElementChild.scrollTop = _this.attribTableContents.firstElementChild.scrollHeight;
443
+ }
439
444
  });
440
445
  _this.props.setCurrentTaskBlocked(true, LocaleUtils.tr("editing.unsavedchanged"));
441
446
  });
442
447
  });
443
448
  _defineProperty(_this, "deleteSelectedFeatured", function () {
444
449
  _this.setState(function (state) {
445
- var features = _this.currentPageFeatures(state).filter(function (feature) {
446
- return state.selectedFeatures.has(feature.id);
447
- });
448
- features.forEach(function (feature) {
449
- _this.props.iface.deleteFeature(state.curEditConfig, feature.id, function (success) {
450
- _this.onFeatureDeleted(feature.id, success);
450
+ var featureIds = Object.keys(state.selectedFeatures);
451
+ featureIds.forEach(function (featureId) {
452
+ _this.props.iface.deleteFeature(state.curEditConfig, featureId, function (success) {
453
+ _this.onFeatureDeleted(featureId, success);
451
454
  }, state.captchaResponse);
452
455
  });
453
456
  return {
454
457
  deleteTask: {
455
- pending: features.map(function (feature) {
456
- return feature.id;
457
- }),
458
+ pending: featureIds,
458
459
  failed: [],
459
460
  deleted: []
460
461
  }
@@ -479,7 +480,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
479
480
  alert(LocaleUtils.tr("attribtable.deletefailed"));
480
481
  }
481
482
  // Compute new page taking into account number of deleted features
482
- newState.currentPage = Math.max(0, state.currentPage - Math.floor(newState.deleteTask.deleted.length / state.pageSize));
483
+ if (newState.deleteTask.deleted.length >= state.features.length) {
484
+ newState.currentPage = Math.max(0, state.currentPage - 1);
485
+ }
483
486
  newState.deleteTask = null;
484
487
  newState.confirmDelete = false;
485
488
  reload = true;
@@ -510,19 +513,8 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
510
513
  };
511
514
  });
512
515
  });
513
- _defineProperty(_this, "updateNewFeatureField", function (fieldid, value, emptynull) {
514
- _this.setState(function (state) {
515
- value = value === "" && emptynull ? null : value;
516
- return {
517
- newFeature: _objectSpread(_objectSpread({}, state.newFeature), {}, {
518
- properties: _objectSpread(_objectSpread({}, state.newFeature.properties), {}, _defineProperty({}, fieldid, value))
519
- })
520
- };
521
- });
522
- });
523
516
  _defineProperty(_this, "commit", function () {
524
- var _this$state$newFeatur;
525
- var feature = (_this$state$newFeatur = _this.state.newFeature) !== null && _this$state$newFeatur !== void 0 ? _this$state$newFeatur : _objectSpread(_objectSpread({}, _this.state.features[_this.state.changedFeatureIdx]), {}, {
517
+ var feature = _objectSpread(_objectSpread({}, _this.state.features[_this.state.changedFeatureIdx]), {}, {
526
518
  crs: {
527
519
  type: "name",
528
520
  properties: {
@@ -531,10 +523,10 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
531
523
  }
532
524
  });
533
525
  Object.keys(feature.properties || {}).forEach(function (name) {
534
- var _this$state$curEditCo, _this$state$curEditCo2, _this$state$curEditCo3;
535
- var fieldConfig = (_this$state$curEditCo = (_this$state$curEditCo2 = _this.state.curEditConfig.fields) === null || _this$state$curEditCo2 === void 0 || (_this$state$curEditCo3 = _this$state$curEditCo2.find) === null || _this$state$curEditCo3 === void 0 ? void 0 : _this$state$curEditCo3.call(_this$state$curEditCo2, function (f) {
526
+ var _this$state$curEditCo2, _this$state$curEditCo3, _this$state$curEditCo4;
527
+ var fieldConfig = (_this$state$curEditCo2 = (_this$state$curEditCo3 = _this.state.curEditConfig.fields) === null || _this$state$curEditCo3 === void 0 || (_this$state$curEditCo4 = _this$state$curEditCo3.find) === null || _this$state$curEditCo4 === void 0 ? void 0 : _this$state$curEditCo4.call(_this$state$curEditCo3, function (f) {
536
528
  return f.id === name;
537
- })) !== null && _this$state$curEditCo !== void 0 ? _this$state$curEditCo : {};
529
+ })) !== null && _this$state$curEditCo2 !== void 0 ? _this$state$curEditCo2 : {};
538
530
  if (fieldConfig.expression) {
539
531
  // Skip virtual fields
540
532
  delete feature.properties[name];
@@ -556,7 +548,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
556
548
  if (_this.state.captchaResponse) {
557
549
  featureData.set('g-recaptcha-response', _this.state.captchaResponse);
558
550
  }
559
- if (_this.state.newFeature) {
551
+ if (!feature.id) {
560
552
  _this.props.iface.addFeatureMultipart(_this.state.curEditConfig, _this.props.mapCrs, featureData, function (success, result) {
561
553
  return _this.featureCommited(success, result);
562
554
  });
@@ -587,9 +579,11 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
587
579
  _defineProperty(_this, "discard", function () {
588
580
  _this.changedFiles = {};
589
581
  _this.setState(function (state) {
582
+ var featureidx = state.changedFeatureIdx;
590
583
  var newFeatures = _toConsumableArray(state.features);
591
- if (!state.newFeature) {
592
- var featureidx = state.changedFeatureIdx;
584
+ if (!newFeatures[featureidx].id) {
585
+ newFeatures.pop();
586
+ } else {
593
587
  newFeatures[featureidx] = _objectSpread({}, newFeatures[featureidx]);
594
588
  newFeatures[featureidx].properties = state.originalFeatureProps;
595
589
  }
@@ -604,12 +598,10 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
604
598
  });
605
599
  _defineProperty(_this, "highlightFeatures", function () {
606
600
  var features = [];
607
- if (_this.state.highlightedFeature) {
608
- features.push(_this.state.highlightedFeature);
609
- } else if (!_this.state.selectedFeatures.isEmpty()) {
610
- features = _this.currentPageFeatures(_this.state).filter(function (feature) {
611
- return _this.state.selectedFeatures.has(feature.id);
612
- });
601
+ if (_this.state.hoveredFeature) {
602
+ features = [_this.state.hoveredFeature];
603
+ } else if (!isEmpty(_this.state.selectedFeatures)) {
604
+ features = Object.values(_this.state.selectedFeatures);
613
605
  } else if (_this.state.filterVal) {
614
606
  features = _this.state.features;
615
607
  }
@@ -627,9 +619,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
627
619
  _defineProperty(_this, "zoomToSelection", function () {
628
620
  var collection = {
629
621
  type: "FeatureCollection",
630
- features: _this.currentPageFeatures(_this.state).filter(function (feature) {
631
- return _this.state.selectedFeatures.has(feature.id);
632
- })
622
+ features: Object.values(_this.state.selectedFeatures)
633
623
  };
634
624
  if (!isEmpty(collection.features)) {
635
625
  if (collection.features.length === 1 && collection.features[0].geometry.type === "Point") {
@@ -647,67 +637,16 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
647
637
  alert(LocaleUtils.tr("attribtable.nogeomnoform"));
648
638
  return;
649
639
  }
650
- var feature = _this.currentPageFeatures(_this.state).find(function (f) {
651
- return _this.state.selectedFeatures.has(f.id);
652
- });
640
+ var feature = Object.values(_this.state.selectedFeatures)[0];
653
641
  _this.props.setCurrentTask("Editing", null, null, {
654
642
  layer: _this.state.loadedLayer,
655
643
  feature: feature
656
644
  });
657
645
  });
658
- _defineProperty(_this, "resizeTable", function (ev, index, resizeCol) {
659
- if (_this.table) {
660
- var element = _this.table.getElementsByTagName(resizeCol ? "th" : "tr")[index];
661
- var initial = 0;
662
- if (resizeCol) {
663
- initial = parseFloat(element.style.minWidth.replace(/px$/, '')) || element.clientWidth;
664
- } else {
665
- initial = parseFloat(element.style.height.replace(/px$/, '')) || element.clientHeight;
666
- }
667
- var resize = {
668
- anchor: resizeCol ? ev.clientX : ev.clientY,
669
- element: element,
670
- initial: initial,
671
- newsize: initial
672
- };
673
- var contentsEl = element.parentElement.parentElement.parentElement.parentElement;
674
- var origin = contentsEl.getBoundingClientRect()[resizeCol ? "left" : "top"];
675
- var resizeLine = document.createElement('div');
676
- resizeLine.className = resizeCol ? 'attribtable-resize-line-vert' : 'attribtable-resize-line-horiz';
677
- resizeLine.style[resizeCol ? "left" : "top"] = resize.anchor - origin + "px";
678
- contentsEl.appendChild(resizeLine);
679
- var resizeDo = resizeCol ? function (event) {
680
- resizeLine.style.left = event.clientX - origin + "px";
681
- resize.newsize = resize.initial + event.clientX - resize.anchor;
682
- } : function (event) {
683
- resizeLine.style.top = event.clientY - origin + "px";
684
- resize.newsize = resize.initial + event.clientY - resize.anchor;
685
- };
686
- var eventShield = ev.view.document.createElement("div");
687
- eventShield.className = '__event_shield';
688
- ev.view.document.body.appendChild(eventShield);
689
- ev.view.document.body.classList.add(resizeCol ? 'ewresizing' : 'nsresizing');
690
- ev.view.addEventListener("pointermove", resizeDo);
691
- ev.view.addEventListener("pointerup", function (event) {
692
- event.view.document.body.removeChild(eventShield);
693
- contentsEl.removeChild(resizeLine);
694
- event.view.removeEventListener("pointermove", resizeDo);
695
- event.view.document.body.classList.remove(resizeCol ? 'ewresizing' : 'nsresizing');
696
- if (resizeCol) {
697
- resize.element.style.minWidth = Math.max(resize.newsize, 16) + "px";
698
- resize.element.style.width = Math.max(resize.newsize, 16) + "px";
699
- } else {
700
- resize.element.style.height = Math.max(resize.newsize, 16) + "px";
701
- }
702
- }, {
703
- once: true
704
- });
705
- }
706
- });
707
646
  _defineProperty(_this, "csvExport", function () {
708
647
  var formatCsv = function formatCsv(features) {
709
- var _this$state$curEditCo4;
710
- var primaryKey = (_this$state$curEditCo4 = _this.state.curEditConfig.primaryKey) !== null && _this$state$curEditCo4 !== void 0 ? _this$state$curEditCo4 : "id";
648
+ var _this$state$curEditCo5;
649
+ var primaryKey = (_this$state$curEditCo5 = _this.state.curEditConfig.primaryKey) !== null && _this$state$curEditCo5 !== void 0 ? _this$state$curEditCo5 : "id";
711
650
  var fields = _this.props.showDisplayFieldOnly ? _this.state.curEditConfig.fields.filter(function (field) {
712
651
  return field.name === _this.state.curEditConfig.displayField;
713
652
  }) : _this.state.curEditConfig.fields.filter(function (field) {
@@ -731,38 +670,32 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
731
670
  type: "text/plain;charset=utf-8"
732
671
  }), _this.state.loadedLayer.split("#").slice(-1)[0] + ".csv");
733
672
  };
734
- if (_this.state.clientSideData) {
673
+
674
+ // Use full-table-load if available
675
+ if (_this.state.allFeatures) {
735
676
  formatCsv(_this.state.allFeatures);
736
677
  } else {
737
- var _this$props$filter$fi4, _state$curEditConfig, _fieldMap$state$filte, _fieldMap$state$sortF, _state$sortField;
678
+ var _this$props$filter$fi4, _this$props$filter$fi5;
738
679
  var state = _this.state;
739
680
  var options = {
740
681
  bbox: state.limitToExtent ? _this.props.mapBbox.bounds : null,
741
682
  filter: (_this$props$filter$fi4 = _this.props.filter.filterParams) === null || _this$props$filter$fi4 === void 0 ? void 0 : _this$props$filter$fi4[state.loadedLayer],
742
683
  filterGeom: _this.props.filter.filterGeom,
743
- fields: _this.props.showDisplayFieldOnly ? [state.curEditConfig.displayField, "geometry"] : null
684
+ fields: _this.props.showDisplayFieldOnly ? [state.curEditConfig.displayField, "geometry"] : null,
685
+ sortby: state.sortField ? (state.sortField.dir < 0 ? "-" : "") + state.sortField.field : null
744
686
  };
745
- // If sort or filter field is virtual, query full feature set and sort/filter client side
746
- var fieldMap = (((_state$curEditConfig = state.curEditConfig) === null || _state$curEditConfig === void 0 ? void 0 : _state$curEditConfig.fields) || []).reduce(function (res, field) {
747
- return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, field.id, field));
748
- }, {});
749
- var clientSideFilterSort = state.clientSideData || state.filterVal && ((_fieldMap$state$filte = fieldMap[state.filterField]) === null || _fieldMap$state$filte === void 0 ? void 0 : _fieldMap$state$filte.expression) || ((_fieldMap$state$sortF = fieldMap[(_state$sortField = state.sortField) === null || _state$sortField === void 0 ? void 0 : _state$sortField.field]) === null || _fieldMap$state$sortF === void 0 ? void 0 : _fieldMap$state$sortF.expression);
750
- if (!clientSideFilterSort) {
751
- var _this$props$filter$fi5;
752
- if ((_this$props$filter$fi5 = _this.props.filter.filterParams) !== null && _this$props$filter$fi5 !== void 0 && _this$props$filter$fi5[state.loadedLayer] && state.filterVal) {
753
- var _this$props$filter$fi6;
754
- options.filter = [(_this$props$filter$fi6 = _this.props.filter.filterParams) === null || _this$props$filter$fi6 === void 0 ? void 0 : _this$props$filter$fi6[_this.state.loadedLayer], 'and', [state.filterField, state.filterOp, state.filterVal]];
755
- } else if (state.filterVal) {
756
- options.filter = [[state.filterField, state.filterOp, state.filterVal]];
757
- }
758
- options.sortby = state.sortField ? (state.sortField.dir < 0 ? "-" : "") + state.sortField.field : null;
687
+ if ((_this$props$filter$fi5 = _this.props.filter.filterParams) !== null && _this$props$filter$fi5 !== void 0 && _this$props$filter$fi5[state.loadedLayer] && state.filterVal) {
688
+ var _this$props$filter$fi6;
689
+ options.filter = [(_this$props$filter$fi6 = _this.props.filter.filterParams) === null || _this$props$filter$fi6 === void 0 ? void 0 : _this$props$filter$fi6[_this.state.loadedLayer], 'and', [state.filterField, state.filterOp, state.filterVal]];
690
+ } else if (state.filterVal) {
691
+ options.filter = [[state.filterField, state.filterOp, state.filterVal]];
759
692
  }
760
693
  _this.setState({
761
694
  loading: true
762
695
  });
763
696
  _this.props.iface.getFeatures(_this.state.curEditConfig, _this.props.mapCrs, function (result) {
764
697
  if (result) {
765
- formatCsv(clientSideFilterSort ? _this.filteredSortedFeatures(result.features, _this.state) : result.features);
698
+ formatCsv(result.features);
766
699
  } else {
767
700
  // eslint-disable-next-line
768
701
  alert(LocaleUtils.tr("attribtable.loadfailed"));
@@ -797,11 +730,6 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
797
730
  }, {
798
731
  key: "componentDidUpdate",
799
732
  value: function componentDidUpdate(prevProps, prevState) {
800
- if (this.state.newFeature && !prevState.newFeature) {
801
- if (this.attribTableContents) {
802
- this.attribTableContents.scrollTop = this.attribTableContents.scrollHeight;
803
- }
804
- }
805
733
  // Reload conditions when limited to extent
806
734
  if (this.state.limitToExtent && this.state.loadedLayer && (!prevState.limitToExtent || this.props.mapBbox !== prevProps.mapBbox)) {
807
735
  this.reload(this.state.loadedLayer, true, {
@@ -813,7 +741,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
813
741
  });
814
742
  }
815
743
  // Highlight feature
816
- if (this.state.highlightedFeature !== prevState.highlightedFeature || this.state.features !== prevState.features || this.state.selectedFeatures !== prevState.selectedFeatures) {
744
+ if (this.state.features !== prevState.features || this.state.hoveredFeature !== prevState.hoveredFeature || this.state.selectedFeatures !== prevState.selectedFeatures) {
817
745
  this.highlightFeatures();
818
746
  }
819
747
  if (this.state.loadedLayer !== prevState.loadedLayer && this.props.showDisplayFieldOnly) {
@@ -838,10 +766,10 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
838
766
  var captchaPending = captchaRequired && !this.state.captchaResponse;
839
767
  var curEditConfig = this.state.curEditConfig;
840
768
  var editPermissions = (curEditConfig === null || curEditConfig === void 0 ? void 0 : curEditConfig.permissions) || {};
841
- var readOnly = this.props.readOnly || editPermissions.updatable === false;
769
+ var readOnly = this.props.readOnly || editPermissions.updatable === false || this.state.confirmDelete;
842
770
  var loading = this.state.loading;
843
- var editing = this.state.changedFeatureIdx !== null || this.state.newFeature !== null;
844
- var selectionEmpty = this.state.selectedFeatures.isEmpty();
771
+ var editing = this.state.changedFeatureIdx !== null;
772
+ var selectionEmpty = isEmpty(this.state.selectedFeatures);
845
773
  var showIdColumn = !this.props.showDisplayFieldOnly && !this.props.hideIdColumn;
846
774
  var loadOverlay = null;
847
775
  if (loading) {
@@ -860,116 +788,22 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
860
788
  var table = null;
861
789
  var footbar = null;
862
790
  if (curEditConfig && this.state.features && this.state.selectedLayer === this.state.loadedLayer) {
863
- var _curEditConfig$primar, _fieldConfig$constrai, _fieldConfig$constrai2;
864
- var primaryKey = (_curEditConfig$primar = curEditConfig.primaryKey) !== null && _curEditConfig$primar !== void 0 ? _curEditConfig$primar : "id";
865
- var mapPrefix = this.state.curEditConfig.editDataset.split(".")[0];
866
- var fields = this.props.showDisplayFieldOnly ? curEditConfig.fields.filter(function (field) {
867
- return field.name === curEditConfig.displayField;
868
- }) : curEditConfig.fields.filter(function (field) {
869
- var _field$constraints;
870
- return field.id !== primaryKey && (_this2.props.showHiddenFields || ((_field$constraints = field.constraints) === null || _field$constraints === void 0 ? void 0 : _field$constraints.hidden) !== true);
871
- });
872
- var indexOffset = this.state.currentPage * this.state.pageSize;
873
- var features = this.state.features.slice(indexOffset, indexOffset + this.state.pageSize);
874
- table = /*#__PURE__*/React.createElement(TextInputInitContext.Provider, {
875
- value: {
876
- register: function register(uuid) {
877
- return _this2.pendingTextEdits.add(uuid);
878
- },
879
- notifyReady: function notifyReady(uuid) {
880
- _this2.pendingTextEdits["delete"](uuid);
881
- if (_this2.pendingTextEdits.size === 0) {
882
- _this2.setState({
883
- tableReady: true
884
- });
885
- }
886
- }
887
- }
888
- }, /*#__PURE__*/React.createElement("div", {
889
- style: {
890
- display: "none"
891
- }
892
- }, /*#__PURE__*/React.createElement(TextInput, {
893
- onChange: function onChange() {},
894
- value: "x"
895
- })), /*#__PURE__*/React.createElement("table", {
791
+ var _fieldConfig$constrai, _fieldConfig$constrai2;
792
+ var primaryKey = curEditConfig.primaryKey;
793
+ table = /*#__PURE__*/React.createElement(FeaturesTable, {
896
794
  className: "attribtable-table",
897
- ref: function ref(el) {
898
- _this2.table = el;
899
- },
900
- style: {
901
- display: this.state.tableReady ? '' : 'none'
902
- }
903
- }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null), showIdColumn ? /*#__PURE__*/React.createElement("th", {
904
- onClick: function onClick() {
905
- return _this2.sortBy(primaryKey);
906
- },
907
- onKeyDown: MiscUtils.checkKeyActivate,
908
- tabIndex: 0,
909
- title: this.translateFieldName(primaryKey)
910
- }, /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("span", {
911
- className: "attribtable-table-headername"
912
- }, this.translateFieldName(primaryKey)), this.renderSortIndicator(primaryKey), this.renderColumnResizeHandle(1, 'r'))) : null, fields.map(function (field, idx) {
913
- return /*#__PURE__*/React.createElement("th", {
914
- key: field.id,
915
- onClick: function onClick() {
916
- return _this2.sortBy(field.id);
917
- },
918
- onKeyDown: MiscUtils.checkKeyActivate,
919
- tabIndex: 0,
920
- title: _this2.translateFieldName(field.name)
921
- }, /*#__PURE__*/React.createElement("span", null, _this2.renderColumnResizeHandle(idx + 1, 'l'), /*#__PURE__*/React.createElement("span", {
922
- className: "attribtable-table-headername"
923
- }, _this2.translateFieldName(field.name), field.expression ? /*#__PURE__*/React.createElement(Icon, {
924
- icon: "epsilon",
925
- title: LocaleUtils.tr("attribtable.calculatedfield")
926
- }) : null), _this2.renderSortIndicator(field.id), idx < fields.length - 1 ? _this2.renderColumnResizeHandle(idx + (showIdColumn ? 2 : 1), 'r') : null));
927
- }))), /*#__PURE__*/React.createElement("tbody", null, features.map(function (feature, sliceidx) {
928
- var featureidx = indexOffset + sliceidx;
929
- var disabled = readOnly || editing && _this2.state.changedFeatureIdx !== featureidx;
930
- var updateField = function updateField(fieldid, val) {
931
- var emptynull = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
932
- return _this2.updateField(featureidx, fieldid, val, emptynull);
933
- };
934
- return /*#__PURE__*/React.createElement("tr", {
935
- className: disabled && !_this2.props.readOnly ? "row-disabled" : "",
936
- key: feature.id,
937
- onMouseEnter: function onMouseEnter() {
938
- return _this2.setState({
939
- highlightedFeature: feature
940
- });
941
- },
942
- onMouseLeave: function onMouseLeave() {
943
- return _this2.setState(function (state) {
944
- return {
945
- highlightedFeature: state.highlightedFeature === feature ? null : state.highlightedFeature
946
- };
947
- });
948
- }
949
- }, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("span", null, sliceidx > 0 ? _this2.renderRowResizeHandle(sliceidx, 't') : null, /*#__PURE__*/React.createElement("input", {
950
- checked: _this2.state.selectedFeatures.has(feature.id),
951
- onChange: function onChange() {
952
- return _this2.setState(function (state) {
953
- return {
954
- selectedFeatures: state.selectedFeatures.toggle(feature.id)
955
- };
956
- });
957
- },
958
- type: "checkbox"
959
- }), _this2.renderRowResizeHandle(sliceidx + 1, 'b'))), showIdColumn ? /*#__PURE__*/React.createElement("td", null, feature.id) : null, fields.map(function (field) {
960
- return /*#__PURE__*/React.createElement("td", {
961
- key: field.id
962
- }, _this2.renderField(feature, curEditConfig, mapPrefix, field, updateField, disabled || !!_this2.state.filterVal && field.id === _this2.state.filterField));
963
- }));
964
- }), 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", {
965
- disabled: true,
966
- type: "checkbox"
967
- }), this.renderRowResizeHandle(features.length + 1, 'b'))), showIdColumn ? /*#__PURE__*/React.createElement("td", null, this.state.newFeature.id) : null, fields.map(function (field) {
968
- return /*#__PURE__*/React.createElement("td", {
969
- key: field.id
970
- }, _this2.renderField(_this2.state.newFeature, curEditConfig, mapPrefix, field, _this2.updateNewFeatureField, false));
971
- })) : null)));
972
- var npages = this.state.featureCount;
795
+ features: this.state.features,
796
+ fields: this.state.curFields,
797
+ hideIdColumn: !showIdColumn,
798
+ hoverChanged: this.setHoveredFeature,
799
+ onSort: this.sortBy,
800
+ primaryKey: primaryKey,
801
+ readOnly: readOnly,
802
+ renderField: this.renderField,
803
+ rowIsDisabled: this.rowIsDisabled,
804
+ selectionChanged: this.setSelectedFeatures
805
+ });
806
+ var npages = Math.ceil(this.state.totFeatureCount / this.state.pageSize);
973
807
  var pages = [this.state.currentPage];
974
808
  var extraright = Math.max(0, 2 - this.state.currentPage);
975
809
  var extraleft = Math.max(0, this.state.currentPage - (npages - 3));
@@ -1031,7 +865,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
1031
865
  },
1032
866
  pageSize: this.state.pageSize,
1033
867
  pageSizeChanged: function pageSizeChanged(pageSize) {
1034
- return _this2.setState({
868
+ return _this2.reload(_this2.state.selectedLayer, false, {
1035
869
  pageSize: pageSize,
1036
870
  currentPage: 0
1037
871
  });
@@ -1051,11 +885,14 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
1051
885
  value: ""
1052
886
  }, LocaleUtils.tr("common.select")), showIdColumn ? /*#__PURE__*/React.createElement("option", {
1053
887
  value: "<id>"
1054
- }, this.translateFieldName(primaryKey)) : null, fields.map(function (field) {
1055
- return /*#__PURE__*/React.createElement("option", {
1056
- key: field.id,
1057
- value: field.id
1058
- }, _this2.translateFieldName(field.name));
888
+ }, this.translateFieldName(primaryKey)) : null, this.state.curFields.map(function (field) {
889
+ if (field.id !== primaryKey) {
890
+ return /*#__PURE__*/React.createElement("option", {
891
+ key: field.id,
892
+ value: field.id
893
+ }, _this2.translateFieldName(field.name));
894
+ }
895
+ return null;
1059
896
  })), /*#__PURE__*/React.createElement("select", {
1060
897
  disabled: footbarDisabled,
1061
898
  onChange: function onChange(ev) {
@@ -1192,7 +1029,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
1192
1029
  icon: "search"
1193
1030
  })), showEditButton ? /*#__PURE__*/React.createElement("button", {
1194
1031
  className: "button",
1195
- disabled: layerChanged || editing || this.state.selectedFeatures.size() !== 1,
1032
+ disabled: layerChanged || editing || Object.keys(this.state.selectedFeatures).length !== 1,
1196
1033
  onClick: this.switchToFormEditMode,
1197
1034
  title: LocaleUtils.tr("attribtable.formeditmode")
1198
1035
  }, /*#__PURE__*/React.createElement(Icon, {
@@ -1290,12 +1127,13 @@ _defineProperty(AttributeTableWidget, "defaultState", {
1290
1127
  selectedLayer: "",
1291
1128
  loadedLayer: "",
1292
1129
  curEditConfig: null,
1130
+ curFields: null,
1293
1131
  fieldTranslations: null,
1294
1132
  features: [],
1295
- featureCount: 0,
1296
1133
  allFeatures: null,
1297
- selectedFeatures: new ToggleSet(),
1298
- highlightedFeature: null,
1134
+ totFeatureCount: 0,
1135
+ selectedFeatures: {},
1136
+ hoveredFeature: null,
1299
1137
  changedFeatureIdx: null,
1300
1138
  originalFeatureProps: null,
1301
1139
  pageSize: 50,
@@ -1305,11 +1143,9 @@ _defineProperty(AttributeTableWidget, "defaultState", {
1305
1143
  filterVal: "",
1306
1144
  sortField: null,
1307
1145
  deleteTask: null,
1308
- newFeature: null,
1309
1146
  confirmDelete: false,
1310
1147
  limitToExtent: false,
1311
1148
  captchaResponse: '',
1312
- clientSideData: false,
1313
1149
  tableReady: false
1314
1150
  });
1315
1151
  export default connect(function (state) {