qwc2 2026.7.29 → 2026.7.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.
@@ -25,7 +25,6 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
25
25
  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; }
26
26
  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; } }
27
27
  function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
28
- import htmlReactParser, { domToReact } from 'html-react-parser';
29
28
  /**
30
29
  * Copyright 2016-2024 Sourcepole AG
31
30
  * All rights reserved.
@@ -33,6 +32,7 @@ import htmlReactParser, { domToReact } from 'html-react-parser';
33
32
  * This source code is licensed under the BSD-style license found in the
34
33
  * LICENSE file in the root directory of this source tree.
35
34
  */
35
+ import htmlReactParser, { domToReact } from 'html-react-parser';
36
36
  import React from 'react';
37
37
  import { connect } from 'react-redux';
38
38
  import axios from 'axios';
@@ -52,8 +52,11 @@ import LayerUtils from '../utils/LayerUtils';
52
52
  import LocaleUtils from '../utils/LocaleUtils';
53
53
  import MapUtils from '../utils/MapUtils';
54
54
  import MiscUtils, { ToggleSet } from '../utils/MiscUtils';
55
+ import { registerPermalinkDataStoreHook, unregisterPermalinkDataStoreHook } from '../utils/PermaLinkUtils';
55
56
  import VectorLayerUtils from '../utils/VectorLayerUtils';
56
57
  import Icon from './Icon';
58
+ import ButtonBar from './widgets/ButtonBar';
59
+ import FeaturesTable from './widgets/FeaturesTable';
57
60
  import NavBar from './widgets/NavBar';
58
61
  import Spinner from './widgets/Spinner';
59
62
  import ToggleSwitch from './widgets/ToggleSwitch';
@@ -353,7 +356,16 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
353
356
  compareEnabled: false,
354
357
  multiViewEnabled: false,
355
358
  currentPage: 0,
356
- pageSize: 1
359
+ pageSize: 1,
360
+ tableSelection: {}
361
+ });
362
+ _defineProperty(_this, "storeIdentifyResults", function () {
363
+ return new Promise(function (resolve) {
364
+ return resolve({
365
+ identifyResults: _this.state.resultTree,
366
+ currentResultDisplayMode: _this.props.resultDisplayMode
367
+ });
368
+ });
357
369
  });
358
370
  _defineProperty(_this, "getCurrentResultFeature", function () {
359
371
  var _this$state$resultTre, _this$state$resultTre2, _this$state$resultTre3, _this$state$currentRe;
@@ -377,7 +389,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
377
389
  });
378
390
  });
379
391
  _defineProperty(_this, "setHighlightedFeatures", function (features) {
380
- if (!features && _this.props.highlightAllResults) {
392
+ if (isEmpty(features) && _this.props.highlightAllResults) {
381
393
  var resultTree = _this.state.selectedLayer !== '' ? _defineProperty({}, _this.state.selectedLayer, _this.state.resultTree[_this.state.selectedLayer]) : _this.state.resultTree;
382
394
  features = Object.values(resultTree).flat();
383
395
  }
@@ -671,7 +683,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
671
683
  });
672
684
  } else {
673
685
  rows = properties.map(function (attrib) {
674
- if (_this.props.theme.skipEmptyFeatureAttributes && (feature.properties[attrib] === "" || feature.properties[attrib] === null || feature.properties[attrib] === "NULL")) {
686
+ if ((_this.props.theme.skipEmptyFeatureAttributes || _this.props.skipEmptyFeatureAttributes) && (feature.properties[attrib] === "" || feature.properties[attrib] === null || feature.properties[attrib] === "NULL")) {
675
687
  return null;
676
688
  }
677
689
  return /*#__PURE__*/React.createElement("tr", {
@@ -789,6 +801,101 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
789
801
  };
790
802
  });
791
803
  });
804
+ _defineProperty(_this, "renderResultsTable", function () {
805
+ return /*#__PURE__*/React.createElement("div", {
806
+ className: "identify-results-tables"
807
+ }, Object.entries(_this.state.resultTree).map(function (_ref16) {
808
+ var _ref17 = _slicedToArray(_ref16, 2),
809
+ layerid = _ref17[0],
810
+ features = _ref17[1];
811
+ if (features.length === 0 || _this.state.selectedLayer && layerid !== _this.state.selectedLayer) {
812
+ return null;
813
+ }
814
+ var fields = {};
815
+ features.map(function (feature) {
816
+ Object.entries(feature.properties).map(function (_ref18) {
817
+ var _ref19 = _slicedToArray(_ref18, 2),
818
+ attr = _ref19[0],
819
+ value = _ref19[1];
820
+ if (!(attr in fields)) {
821
+ fields[attr] = {
822
+ id: attr,
823
+ name: attr
824
+ };
825
+ }
826
+ });
827
+ });
828
+ var haveSel = !isEmpty(_this.state.tableSelection[layerid]);
829
+ var buttons = [{
830
+ key: "Export",
831
+ icon: "export"
832
+ }, {
833
+ key: "Delete",
834
+ icon: haveSel ? "trash_checked" : "trash"
835
+ }];
836
+ return /*#__PURE__*/React.createElement("div", {
837
+ className: "identify-results-table-container",
838
+ key: layerid
839
+ }, /*#__PURE__*/React.createElement("div", {
840
+ className: "identify-results-table-titlebar"
841
+ }, /*#__PURE__*/React.createElement(Icon, {
842
+ icon: _this.state.collapsedLayers.has(layerid) ? "expand" : "collapse",
843
+ onClick: function onClick() {
844
+ return _this.setState(function (state) {
845
+ return {
846
+ collapsedLayers: state.collapsedLayers.toggle(layerid)
847
+ };
848
+ });
849
+ }
850
+ }), /*#__PURE__*/React.createElement("span", null, features[0].layertitle, " (", features.length, ")"), /*#__PURE__*/React.createElement(ButtonBar, {
851
+ buttons: buttons,
852
+ onClick: function onClick(action) {
853
+ return _this.tableAction(layerid, action);
854
+ }
855
+ })), !_this.state.collapsedLayers.has(layerid) ? /*#__PURE__*/React.createElement(FeaturesTable, {
856
+ allowSelectAll: true,
857
+ features: features,
858
+ fields: Object.values(fields),
859
+ hideIdColumn: true,
860
+ highlightFeatures: _this.setHighlightedFeatures,
861
+ selectionChanged: function selectionChanged(sel) {
862
+ return _this.setState(function (state) {
863
+ return {
864
+ tableSelection: _objectSpread(_objectSpread({}, state.tableSelection), {}, _defineProperty({}, layerid, sel))
865
+ };
866
+ });
867
+ }
868
+ }) : null);
869
+ }));
870
+ });
871
+ _defineProperty(_this, "tableAction", function (layerid, action) {
872
+ if (action === "Export") {
873
+ var features = isEmpty(_this.state.tableSelection[layerid]) ? _this.state.resultTree[layerid] : Object.values(_this.state.tableSelection[layerid]);
874
+ _this["export"]({
875
+ layerid: features
876
+ });
877
+ } else if (action === "Delete") {
878
+ _this.setState(function (state) {
879
+ var tableSelection = state.tableSelection;
880
+ var selection = state.tableSelection[layerid];
881
+ var newLayerResults = !isEmpty(selection) ? state.resultTree[layerid].filter(function (f) {
882
+ return !(f.id in selection);
883
+ }) : [];
884
+ var newResultTree = _objectSpread({}, state.resultTree);
885
+ if (isEmpty(newLayerResults)) {
886
+ delete newResultTree[layerid];
887
+ tableSelection = _objectSpread({}, tableSelection);
888
+ delete tableSelection[layerid];
889
+ } else {
890
+ newResultTree[layerid] = newLayerResults;
891
+ }
892
+ return {
893
+ resultTree: newResultTree,
894
+ tableSelection: tableSelection
895
+ };
896
+ });
897
+ }
898
+ });
792
899
  _defineProperty(_this, "initBody", function (el) {
793
900
  if (el) {
794
901
  // HACK to trigger an additional repaint, since Safari/Chrome on iOS render the element cut off the first time
@@ -856,7 +963,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
856
963
  var haveSettings = Object.values(enabledSettings).find(Boolean) !== undefined;
857
964
  return /*#__PURE__*/React.createElement("div", {
858
965
  className: "identify-toolbar"
859
- }, haveSettings ? toggleButton("settingsMenu", "cog", false) : null, _this.state.settingsMenu ? _this.renderSettingsMenu(enabledSettings) : null, _this.props.enableCompare ? toggleButton("compareEnabled", "compare", _this.state.selectedResults.size() < 2, LocaleUtils.tr("identify.compare")) : null, /*#__PURE__*/React.createElement("span", {
966
+ }, haveSettings ? toggleButton("settingsMenu", "cog", false) : null, _this.state.settingsMenu ? _this.renderSettingsMenu(enabledSettings) : null, _this.props.enableCompare && _this.props.resultDisplayMode !== "table" ? toggleButton("compareEnabled", "compare", _this.state.selectedResults.size() < 2, LocaleUtils.tr("identify.compare")) : null, /*#__PURE__*/React.createElement("span", {
860
967
  className: "identify-toolbar-spacer"
861
968
  }), infoLabel, /*#__PURE__*/React.createElement("span", {
862
969
  className: "identify-toolbar-spacer"
@@ -951,10 +1058,10 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
951
1058
  }, /*#__PURE__*/React.createElement("option", {
952
1059
  disabled: true,
953
1060
  value: ""
954
- }, LocaleUtils.tr("identify.selectreport")), Object.entries(_this.state.reports).map(function (_ref17) {
955
- var _ref18 = _slicedToArray(_ref17, 2),
956
- layername = _ref18[0],
957
- reports = _ref18[1];
1061
+ }, LocaleUtils.tr("identify.selectreport")), Object.entries(_this.state.reports).map(function (_ref21) {
1062
+ var _ref22 = _slicedToArray(_ref21, 2),
1063
+ layername = _ref22[0],
1064
+ reports = _ref22[1];
958
1065
  return reports.map(function (report, idx) {
959
1066
  return /*#__PURE__*/React.createElement("option", {
960
1067
  key: layername + "::" + idx,
@@ -1210,6 +1317,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1210
1317
  _this.bodyEl = null;
1211
1318
  _this.state.exportFormat = !Array.isArray(props.enableExport) ? 'geojson' : props.enableExport[0];
1212
1319
  _this.state.multiViewEnabled = props.resultMultiDisplay;
1320
+ registerPermalinkDataStoreHook("identifyresultstate", _this.storeIdentifyResults);
1213
1321
  return _this;
1214
1322
  }
1215
1323
  _inherits(IdentifyViewer, _React$Component);
@@ -1250,6 +1358,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1250
1358
  key: "componentWillUnmount",
1251
1359
  value: function componentWillUnmount() {
1252
1360
  this.props.removeLayer("__identifyviewerhighlight");
1361
+ unregisterPermalinkDataStoreHook("identifyresultstate");
1253
1362
  }
1254
1363
  }, {
1255
1364
  key: "render",
@@ -1257,10 +1366,10 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1257
1366
  var _this2 = this;
1258
1367
  var body = null;
1259
1368
  var resultTree = this.state.selectedLayer !== '' ? _defineProperty({}, this.state.selectedLayer, this.state.resultTree[this.state.selectedLayer]) : this.state.resultTree;
1260
- var flatResults = Object.entries(resultTree).map(function (_ref21) {
1261
- var _ref22 = _slicedToArray(_ref21, 2),
1262
- layerid = _ref22[0],
1263
- features = _ref22[1];
1369
+ var flatResults = Object.entries(resultTree).map(function (_ref25) {
1370
+ var _ref26 = _slicedToArray(_ref25, 2),
1371
+ layerid = _ref26[0],
1372
+ features = _ref26[1];
1264
1373
  return features.map(function (feature) {
1265
1374
  return [layerid, feature];
1266
1375
  });
@@ -1288,10 +1397,10 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1288
1397
  } else if (this.props.resultDisplayMode === 'flat') {
1289
1398
  body = /*#__PURE__*/React.createElement("div", {
1290
1399
  className: "identify-flat-results-list"
1291
- }, Object.entries(resultTree).map(function (_ref23) {
1292
- var _ref24 = _slicedToArray(_ref23, 2),
1293
- layerid = _ref24[0],
1294
- features = _ref24[1];
1400
+ }, Object.entries(resultTree).map(function (_ref27) {
1401
+ var _ref28 = _slicedToArray(_ref27, 2),
1402
+ layerid = _ref28[0],
1403
+ features = _ref28[1];
1295
1404
  return features.map(function (feature) {
1296
1405
  return _this2.renderResultAttributes(layerid, feature, 'identify-result-frame');
1297
1406
  });
@@ -1305,10 +1414,10 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1305
1414
  body = /*#__PURE__*/React.createElement("div", {
1306
1415
  className: "identify-compare-results",
1307
1416
  style: _style
1308
- }, results.map(function (_ref25) {
1309
- var _ref26 = _slicedToArray(_ref25, 2),
1310
- layerid = _ref26[0],
1311
- feature = _ref26[1];
1417
+ }, results.map(function (_ref29) {
1418
+ var _ref30 = _slicedToArray(_ref29, 2),
1419
+ layerid = _ref30[0],
1420
+ feature = _ref30[1];
1312
1421
  return _this2.renderResultAttributes(layerid, feature, 'identify-result-frame');
1313
1422
  }));
1314
1423
  } else if (this.state.currentPage < flatResults.length) {
@@ -1319,6 +1428,8 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1319
1428
  className: "identify-flat-results-list"
1320
1429
  }, this.renderResultAttributes(layerid, feature, 'identify-result-frame'));
1321
1430
  }
1431
+ } else if (this.props.resultDisplayMode === 'table') {
1432
+ body = this.renderResultsTable();
1322
1433
  }
1323
1434
  return /*#__PURE__*/React.createElement("div", {
1324
1435
  className: "identify-body",
@@ -1353,6 +1464,7 @@ _defineProperty(IdentifyViewer, "propTypes", {
1353
1464
  setActiveLayerInfo: PropTypes.func,
1354
1465
  showLayerSelector: PropTypes.bool,
1355
1466
  showLayerTitles: PropTypes.bool,
1467
+ skipEmptyFeatureAttributes: PropTypes.bool,
1356
1468
  theme: PropTypes.object,
1357
1469
  zoomToPoint: PropTypes.func
1358
1470
  });
@@ -219,3 +219,32 @@ div.identify-body td.identify-attr-spacer {
219
219
  height: 2px;
220
220
  background-color: var(--list-section-bg-color);
221
221
  }
222
+
223
+ div.identify-body div.identify-results-tables {
224
+ flex: 1 1 auto;
225
+ overflow-y: auto;
226
+ }
227
+
228
+ div.identify-results-table-container {
229
+ padding-bottom: 0.5em;
230
+ border-bottom: 1px solid var(--border-color);
231
+ margin-bottom: 0.5em;
232
+ }
233
+
234
+ div.identify-results-table-titlebar {
235
+ display: flex;
236
+ align-items: center;
237
+ padding: 0.25em;
238
+ gap: 1em;
239
+ }
240
+
241
+ div.identify-results-table-titlebar > span:nth-child(2) {
242
+ flex: 1 1 auto;
243
+ font-weight: bold;
244
+ font-size: 110%;
245
+ }
246
+
247
+ div.identify-results-table-container > div.featurestable-frame {
248
+ max-height: 15em;
249
+ margin: 0.25em;
250
+ }
@@ -47,6 +47,10 @@ div.resizeable-window-minimized {
47
47
  min-height: 2.5em!important;
48
48
  }
49
49
 
50
+ div.resizeable-window-minimized div.resizeable-window-body {
51
+ padding: 0;
52
+ }
53
+
50
54
  div.resizeable-window-docked-left {
51
55
  transform: none!important;
52
56
  left: 0!important;