qwc2 2025.10.16 → 2025.10.24

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 (62) hide show
  1. package/actions/locate.js +3 -2
  2. package/components/AttributeTableWidget.js +24 -15
  3. package/components/FeatureAttributesWindow.js +177 -0
  4. package/components/IdentifyViewer.js +80 -39
  5. package/components/LocationRecorder.js +138 -0
  6. package/components/PickFeature.js +87 -26
  7. package/components/PluginsContainer.js +16 -3
  8. package/components/map/OlLayer.js +2 -1
  9. package/components/map3d/HeightProfile3D.js +2 -0
  10. package/components/style/App.css +14 -0
  11. package/components/style/AttributeTableWidget.css +1 -1
  12. package/components/style/FeatureAttributesWindow.css +16 -0
  13. package/components/style/IdentifyViewer.css +5 -0
  14. package/components/style/LocationRecorder.css +10 -0
  15. package/components/style/NumericInputWindow.css +7 -0
  16. package/components/style/PluginsContainer.css +16 -0
  17. package/components/widgets/LayerCatalogWidget.js +40 -16
  18. package/components/widgets/NavBar.js +10 -3
  19. package/icons/circle_full.svg +75 -0
  20. package/package.json +1 -1
  21. package/plugins/AttributeTable.js +4 -0
  22. package/plugins/GeometryDigitizer.js +3 -0
  23. package/plugins/HeightProfile.js +2 -0
  24. package/plugins/Identify.js +7 -3
  25. package/plugins/ObjectList.js +116 -0
  26. package/plugins/Redlining.js +14 -55
  27. package/plugins/map/EditingSupport.js +22 -1
  28. package/plugins/map/LocateSupport.js +8 -1
  29. package/plugins/map/RedliningSupport.js +108 -18
  30. package/plugins/map/SnappingSupport.js +11 -6
  31. package/plugins/map/style/SnappingSupport.css +2 -13
  32. package/reducers/locate.js +4 -2
  33. package/reducers/redlining.js +2 -1
  34. package/static/translations/bg-BG.json +13 -0
  35. package/static/translations/ca-ES.json +13 -0
  36. package/static/translations/cs-CZ.json +13 -0
  37. package/static/translations/de-CH.json +13 -0
  38. package/static/translations/de-DE.json +14 -1
  39. package/static/translations/en-US.json +13 -0
  40. package/static/translations/es-ES.json +13 -0
  41. package/static/translations/fi-FI.json +13 -0
  42. package/static/translations/fr-FR.json +13 -0
  43. package/static/translations/hu-HU.json +13 -0
  44. package/static/translations/it-IT.json +13 -0
  45. package/static/translations/ja-JP.json +13 -0
  46. package/static/translations/nl-NL.json +13 -0
  47. package/static/translations/no-NO.json +13 -0
  48. package/static/translations/pl-PL.json +13 -0
  49. package/static/translations/pt-BR.json +13 -0
  50. package/static/translations/pt-PT.json +13 -0
  51. package/static/translations/ro-RO.json +13 -0
  52. package/static/translations/ru-RU.json +13 -0
  53. package/static/translations/sv-SE.json +13 -0
  54. package/static/translations/tr-TR.json +13 -0
  55. package/static/translations/tsconfig.json +10 -0
  56. package/static/translations/uk-UA.json +13 -0
  57. package/utils/EditingInterface.js +4 -1
  58. package/utils/EditingUtils.js +3 -1
  59. package/utils/MiscUtils.js +65 -0
  60. package/utils/expr_grammar/grammar.js +104 -22
  61. package/utils/expr_grammar/grammar.ne +2 -0
  62. package/utils/expr_grammar/test.js +21 -4
package/actions/locate.js CHANGED
@@ -19,10 +19,11 @@ export function changeLocateState(state) {
19
19
  state: state
20
20
  };
21
21
  }
22
- export function changeLocatePosition(position) {
22
+ export function changeLocatePosition(position, mapPos) {
23
23
  return {
24
24
  type: CHANGE_LOCATE_POSITION,
25
- position: position
25
+ position: position,
26
+ mapPos: mapPos
26
27
  };
27
28
  }
28
29
  export function onLocateError(error) {
@@ -123,7 +123,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
123
123
  loadedLayer: ""
124
124
  });
125
125
  }
126
- }, bbox, (_this$props$filter$fi = _this.props.filter.filterParams) === null || _this$props$filter$fi === void 0 ? void 0 : _this$props$filter$fi[selectedLayer], _this.props.filter.filterGeom);
126
+ }, bbox, (_this$props$filter$fi = _this.props.filter.filterParams) === null || _this$props$filter$fi === void 0 ? void 0 : _this$props$filter$fi[selectedLayer], _this.props.filter.filterGeom, _this.props.showDisplayFieldOnly ? [currentEditConfig.displayField, "geometry"] : null);
127
127
  return _objectSpread(_objectSpread({}, AttributeTableWidget.defaultState), {}, {
128
128
  loading: true,
129
129
  selectedLayer: selectedLayer,
@@ -663,7 +663,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
663
663
  if (!currentEditConfig) {
664
664
  return;
665
665
  }
666
- var fields = currentEditConfig.fields.filter(function (field) {
666
+ var fields = _this.props.showDisplayFieldOnly ? currentEditConfig.fields.filter(function (field) {
667
+ return field.name === currentEditConfig.displayField;
668
+ }) : currentEditConfig.fields.filter(function (field) {
667
669
  return field.id !== 'id';
668
670
  });
669
671
  var data = "";
@@ -692,6 +694,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
692
694
  _this.state = AttributeTableWidget.defaultState;
693
695
  _this.table = null;
694
696
  _this.attribTableContents = null;
697
+ _this.state.limitToExtent = props.limitToExtent;
695
698
  return _this;
696
699
  }
697
700
  _inherits(AttributeTableWidget, _React$Component);
@@ -735,7 +738,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
735
738
  var editConfig = this.props.theme.editConfig || {};
736
739
  var currentEditConfig = editConfig[this.state.loadedLayer];
737
740
  var editPermissions = (editConfig[this.state.loadedLayer] || {}).permissions || {};
738
- var readOnly = editPermissions.updatable === false;
741
+ var readOnly = this.props.readOnly || editPermissions.updatable === false;
739
742
  var loadOverlay = null;
740
743
  if (this.state.selectedLayer && this.state.selectedLayer !== this.state.loadedLayer) {
741
744
  if (this.state.loading) {
@@ -755,11 +758,11 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
755
758
  var table = null;
756
759
  var footbar = null;
757
760
  if (currentEditConfig && this.state.features) {
758
- var fields = currentEditConfig.fields.filter(function (field) {
759
- return field.id !== "id";
760
- }).filter(function (field) {
761
+ var fields = this.props.showDisplayFieldOnly ? currentEditConfig.fields.filter(function (field) {
762
+ return field.name === currentEditConfig.displayField;
763
+ }) : currentEditConfig.fields.filter(function (field) {
761
764
  var _field$constraints;
762
- return _this2.props.showHiddenFields || ((_field$constraints = field.constraints) === null || _field$constraints === void 0 ? void 0 : _field$constraints.hidden) !== true;
765
+ return field.id !== "id" && (_this2.props.showHiddenFields || ((_field$constraints = field.constraints) === null || _field$constraints === void 0 ? void 0 : _field$constraints.hidden) !== true);
763
766
  });
764
767
  var indexOffset = this.state.currentPage * this.state.pageSize;
765
768
  var features = this.state.filteredSortedFeatures.slice(indexOffset, indexOffset + this.state.pageSize);
@@ -768,14 +771,14 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
768
771
  ref: function ref(el) {
769
772
  _this2.table = el;
770
773
  }
771
- }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null), /*#__PURE__*/React.createElement("th", {
774
+ }, /*#__PURE__*/React.createElement("thead", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("th", null), !this.props.showDisplayFieldOnly ? /*#__PURE__*/React.createElement("th", {
772
775
  onClick: function onClick() {
773
776
  return _this2.sortBy("id");
774
777
  },
775
778
  title: this.translateFieldName("id", this.state.loadedLayer)
776
779
  }, /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("span", {
777
780
  className: "attribtable-table-headername"
778
- }, this.translateFieldName("id", this.state.loadedLayer)), this.renderSortIndicator("id"), this.renderColumnResizeHandle(1, 'r'))), fields.map(function (field, idx) {
781
+ }, this.translateFieldName("id", this.state.loadedLayer)), this.renderSortIndicator("id"), this.renderColumnResizeHandle(1, 'r'))) : null, fields.map(function (field, idx) {
779
782
  return /*#__PURE__*/React.createElement("th", {
780
783
  key: field.id,
781
784
  onClick: function onClick() {
@@ -790,7 +793,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
790
793
  var disabled = readOnly || _this2.state.changedFeatureIdx !== null && _this2.state.changedFeatureIdx !== featureidx;
791
794
  var key = _this2.state.changedFeatureIdx === featureidx && _this2.state.newFeature ? "newfeature" : feature.id;
792
795
  return /*#__PURE__*/React.createElement("tr", {
793
- className: disabled ? "row-disabled" : "",
796
+ className: disabled && !_this2.props.readOnly ? "row-disabled" : "",
794
797
  key: key,
795
798
  onMouseEnter: function onMouseEnter() {
796
799
  return _this2.setState({
@@ -814,7 +817,7 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
814
817
  });
815
818
  },
816
819
  type: "checkbox"
817
- }), _this2.renderRowResizeHandle(filteredIndex + 1, 'b'))), /*#__PURE__*/React.createElement("td", null, feature.id), fields.map(function (field) {
820
+ }), _this2.renderRowResizeHandle(filteredIndex + 1, 'b'))), !_this2.props.showDisplayFieldOnly ? /*#__PURE__*/React.createElement("td", null, feature.id) : null, fields.map(function (field) {
818
821
  return /*#__PURE__*/React.createElement("td", {
819
822
  key: field.id
820
823
  }, _this2.renderField(currentEditConfig, field, featureidx, indexOffset + filteredIndex, disabled || !!_this2.state.filterVal && field.id === _this2.state.filterField));
@@ -907,9 +910,9 @@ var AttributeTableWidget = /*#__PURE__*/function (_React$Component) {
907
910
  var editing = this.state.changedFeatureIdx !== null;
908
911
  var layerChanged = this.state.selectedLayer !== this.state.loadedLayer;
909
912
  var hasGeometry = (currentEditConfig || {}).geomType !== null;
910
- var showAddButton = editPermissions.creatable !== false && (this.props.allowAddForGeometryLayers || !hasGeometry);
911
- var showDelButton = editPermissions.deletable !== false;
912
- var showEditButton = ConfigUtils.havePlugin("Editing") && this.props.showEditFormButton;
913
+ var showAddButton = !this.props.readOnly && editPermissions.creatable !== false && (this.props.allowAddForGeometryLayers || !hasGeometry);
914
+ var showDelButton = !this.props.readOnly && editPermissions.deletable !== false;
915
+ var showEditButton = !this.props.readOnly && ConfigUtils.havePlugin("Editing") && this.props.showEditFormButton;
913
916
  var deleteButton = showDelButton ? /*#__PURE__*/React.createElement("button", {
914
917
  className: "button",
915
918
  disabled: layerChanged || editing || !Object.values(this.state.selectedFeatures).find(function (entry) {
@@ -1043,12 +1046,17 @@ _defineProperty(AttributeTableWidget, "propTypes", {
1043
1046
  iface: PropTypes.object,
1044
1047
  initialLayer: PropTypes.string,
1045
1048
  layers: PropTypes.array,
1049
+ /** Whether to limit to the extent by default. */
1050
+ limitToExtent: PropTypes.bool,
1046
1051
  mapBbox: PropTypes.object,
1047
1052
  mapCrs: PropTypes.string,
1048
1053
  mapScales: PropTypes.array,
1054
+ readOnly: PropTypes.bool,
1049
1055
  removeLayer: PropTypes.func,
1050
1056
  setCurrentTask: PropTypes.func,
1051
1057
  setCurrentTaskBlocked: PropTypes.func,
1058
+ /** Whether to show the display field only */
1059
+ showDisplayFieldOnly: PropTypes.bool,
1052
1060
  /** Whether to show a button to open the edit form for selected layer. Requires the Editing plugin to be enabled. */
1053
1061
  showEditFormButton: PropTypes.bool,
1054
1062
  /** Whether to show hidden Fields. */
@@ -1067,7 +1075,8 @@ _defineProperty(AttributeTableWidget, "defaultProps", {
1067
1075
  zoomLevel: 1000,
1068
1076
  showEditFormButton: true,
1069
1077
  showHiddenFields: true,
1070
- showLayerSelection: true
1078
+ showLayerSelection: true,
1079
+ limitToExtent: false
1071
1080
  });
1072
1081
  _defineProperty(AttributeTableWidget, "defaultState", {
1073
1082
  loading: false,
@@ -0,0 +1,177 @@
1
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
2
+ function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
3
+ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
4
+ function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
5
+ function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
6
+ 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; }
7
+ 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; }
8
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
9
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
10
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
11
+ 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; }
12
+ 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; } }
13
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
14
+ function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
15
+ 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); } }
16
+ function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
17
+ function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
18
+ function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); }
19
+ function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
20
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
21
+ function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
22
+ function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); }
23
+ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
24
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
25
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
26
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
27
+ /**
28
+ * Copyright 2025 Sourcepole AG
29
+ * All rights reserved.
30
+ *
31
+ * This source code is licensed under the BSD-style license found in the
32
+ * LICENSE file in the root directory of this source tree.
33
+ */
34
+
35
+ import React from 'react';
36
+ import { connect } from 'react-redux';
37
+ import PropTypes from 'prop-types';
38
+ import LocaleUtils from '../utils/LocaleUtils';
39
+ import Icon from './Icon';
40
+ import ResizeableWindow from './ResizeableWindow';
41
+ import TextInput from './widgets/TextInput';
42
+ import './style/FeatureAttributesWindow.css';
43
+ var FeatureAttributesWindow = /*#__PURE__*/function (_React$Component) {
44
+ function FeatureAttributesWindow() {
45
+ var _this;
46
+ _classCallCheck(this, FeatureAttributesWindow);
47
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
48
+ args[_key] = arguments[_key];
49
+ }
50
+ _this = _callSuper(this, FeatureAttributesWindow, [].concat(args));
51
+ _defineProperty(_this, "renderAttributesList", function () {
52
+ var featureAttribs = new Set(Object.keys(_this.props.feature.properties || {}));
53
+ featureAttribs.add("label");
54
+ return /*#__PURE__*/React.createElement("form", {
55
+ action: "",
56
+ onSubmit: _this.addAttrib
57
+ }, /*#__PURE__*/React.createElement("table", null, /*#__PURE__*/React.createElement("tbody", null, Object.entries(_this.props.feature.properties || {}).filter(function (_ref) {
58
+ var _ref2 = _slicedToArray(_ref, 2),
59
+ name = _ref2[0],
60
+ value = _ref2[1];
61
+ return name !== "label" && typeof value === 'string';
62
+ }).map(function (_ref3) {
63
+ var _ref4 = _slicedToArray(_ref3, 2),
64
+ name = _ref4[0],
65
+ value = _ref4[1];
66
+ return /*#__PURE__*/React.createElement("tr", {
67
+ key: name
68
+ }, /*#__PURE__*/React.createElement("td", null, name), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(TextInput, {
69
+ onChange: function onChange(text) {
70
+ return _this.updateAttrib(name, text);
71
+ },
72
+ value: value
73
+ })), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("button", {
74
+ className: "button",
75
+ type: "button"
76
+ }, /*#__PURE__*/React.createElement(Icon, {
77
+ icon: "trash",
78
+ onClick: function onClick() {
79
+ return _this.removeAttrib(name);
80
+ }
81
+ }))));
82
+ }), _this.props.allAttribs.filter(function (attrib) {
83
+ return !featureAttribs.has(attrib);
84
+ }).map(function (name) {
85
+ return /*#__PURE__*/React.createElement("tr", {
86
+ key: name
87
+ }, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("i", null, name)), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(TextInput, {
88
+ onChange: function onChange(text) {
89
+ return _this.updateAttrib(name, text);
90
+ },
91
+ value: ""
92
+ })), /*#__PURE__*/React.createElement("td", null));
93
+ }), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("input", {
94
+ name: "name",
95
+ placeholder: LocaleUtils.tr("featureattributes.name"),
96
+ type: "text"
97
+ })), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("input", {
98
+ name: "value",
99
+ placeholder: LocaleUtils.tr("featureattributes.value"),
100
+ type: "text"
101
+ })), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("button", {
102
+ className: "button",
103
+ type: "submit"
104
+ }, /*#__PURE__*/React.createElement(Icon, {
105
+ icon: "plus"
106
+ })))))));
107
+ });
108
+ _defineProperty(_this, "updateAttrib", function (name, value) {
109
+ var newFeature = _objectSpread({}, _this.props.feature);
110
+ newFeature.properties = _objectSpread({}, newFeature.properties);
111
+ newFeature.properties[name] = value.trim();
112
+ _this.props.onFeatureChanged(newFeature);
113
+ });
114
+ _defineProperty(_this, "removeAttrib", function (name) {
115
+ var newFeature = _objectSpread({}, _this.props.feature);
116
+ newFeature.properties = _objectSpread({}, newFeature.properties);
117
+ delete newFeature.properties[name];
118
+ _this.props.onFeatureChanged(newFeature, [name]);
119
+ });
120
+ _defineProperty(_this, "addAttrib", function (ev) {
121
+ ev.preventDefault();
122
+ var newFeature = _objectSpread({}, _this.props.feature);
123
+ newFeature.properties = _objectSpread({}, newFeature.properties);
124
+ var name = ev.target.elements.name.value.trim();
125
+ var value = ev.target.elements.value.value.trim();
126
+ if (name && !(name in newFeature.properties)) {
127
+ newFeature.properties[name] = value;
128
+ _this.props.onFeatureChanged(newFeature);
129
+ ev.target.elements.name.value = "";
130
+ ev.target.elements.value.value = "";
131
+ }
132
+ });
133
+ return _this;
134
+ }
135
+ _inherits(FeatureAttributesWindow, _React$Component);
136
+ return _createClass(FeatureAttributesWindow, [{
137
+ key: "render",
138
+ value: function render() {
139
+ var body = null;
140
+ if (!this.props.feature) {
141
+ body = /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("featureattributes.nofeature"));
142
+ } else {
143
+ body = this.renderAttributesList();
144
+ }
145
+ return /*#__PURE__*/React.createElement(ResizeableWindow, {
146
+ fitHeight: true,
147
+ icon: "list-alt",
148
+ initialWidth: 320,
149
+ onClose: this.props.onClose,
150
+ scrollable: true,
151
+ title: LocaleUtils.tr("featureattributes.windowtitle")
152
+ }, /*#__PURE__*/React.createElement("div", {
153
+ className: "feature-attributes-body",
154
+ role: "body"
155
+ }, body));
156
+ }
157
+ }]);
158
+ }(React.Component);
159
+ _defineProperty(FeatureAttributesWindow, "propTypes", {
160
+ allAttribs: PropTypes.array,
161
+ feature: PropTypes.object,
162
+ onClose: PropTypes.func,
163
+ onFeatureChanged: PropTypes.func
164
+ });
165
+ export default connect(function (state, ownProps) {
166
+ var _state$layers$flat$fi, _state$layers$flat$fi2;
167
+ return {
168
+ allAttribs: _toConsumableArray(((_state$layers$flat$fi = (_state$layers$flat$fi2 = state.layers.flat.find(function (layer) {
169
+ return layer.id === ownProps.layerid;
170
+ })) === null || _state$layers$flat$fi2 === void 0 ? void 0 : _state$layers$flat$fi2.features) !== null && _state$layers$flat$fi !== void 0 ? _state$layers$flat$fi : []).reduce(function (res, feature) {
171
+ Object.keys(feature.properties || {}).forEach(function (key) {
172
+ return res.add(key);
173
+ });
174
+ return res;
175
+ }, new Set()))
176
+ };
177
+ }, {})(FeatureAttributesWindow);
@@ -324,7 +324,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
324
324
  _defineProperty(_this, "state", {
325
325
  collapsedLayers: new ToggleSet(),
326
326
  expandedResults: new ToggleSet(),
327
- pinnedResults: new ToggleSet(),
327
+ selectedResults: new ToggleSet(),
328
328
  resultTree: {},
329
329
  reports: {},
330
330
  currentResult: null,
@@ -358,13 +358,9 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
358
358
  });
359
359
  });
360
360
  _defineProperty(_this, "setHighlightedFeatures", function (features) {
361
- var paginated = _this.props.resultDisplayMode === 'paginated';
362
- if (!features && (_this.props.highlightAllResults || paginated)) {
361
+ if (!features && _this.props.highlightAllResults) {
363
362
  var resultTree = _this.state.selectedLayer !== '' ? _defineProperty({}, _this.state.selectedLayer, _this.state.resultTree[_this.state.selectedLayer]) : _this.state.resultTree;
364
363
  features = Object.values(resultTree).flat();
365
- if (paginated) {
366
- features = [features[_this.state.currentPage]];
367
- }
368
364
  }
369
365
  features = (features || []).filter(function (feature) {
370
366
  return feature.type.toLowerCase() === "feature";
@@ -412,26 +408,41 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
412
408
  collapsedLayers["delete"](layerid);
413
409
  }
414
410
  var selectedLayer = isEmpty(newResultTree[layerid]) ? '' : state.selectedLayer;
415
- var pinnedResults = state.pinnedResults["delete"](layerid + "$" + feature.id);
411
+ var selectedResults = state.selectedResults["delete"](layerid + "$" + feature.id);
416
412
  return {
417
413
  resultTree: newResultTree,
418
414
  currentResult: ((_state$currentResult2 = state.currentResult) === null || _state$currentResult2 === void 0 ? void 0 : _state$currentResult2.featureid) === feature.id ? null : state.currentResult,
419
415
  selectedLayer: selectedLayer,
420
- pinnedResults: pinnedResults,
416
+ selectedResults: selectedResults,
421
417
  expandedResults: state.expandedResults["delete"](layerid + "$" + feature.id),
422
418
  collapsedLayers: collapsedLayers,
423
- compareEnabled: state.compareEnabled && pinnedResults.size > 1
419
+ compareEnabled: state.compareEnabled && selectedResults.size > 1
424
420
  };
425
421
  });
426
422
  });
427
423
  _defineProperty(_this, "exportResults", function () {
428
424
  var clipboard = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
429
425
  var filteredResults = {};
430
- Object.keys(_this.state.selectedLayer !== '' ? _defineProperty({}, _this.state.selectedLayer, _this.state.resultTree[_this.state.selectedLayer]) : _this.state.resultTree).map(function (key) {
431
- if (!isEmpty(_this.state.resultTree[key])) {
432
- filteredResults[key] = _this.state.resultTree[key];
433
- }
434
- });
426
+ if (_this.state.selectedResults.size() > 0) {
427
+ _this.state.selectedResults.entries().forEach(function (key) {
428
+ var _key$split = key.split("$"),
429
+ _key$split2 = _slicedToArray(_key$split, 2),
430
+ layerid = _key$split2[0],
431
+ featureid = _key$split2[1];
432
+ if (!filteredResults[layerid]) {
433
+ filteredResults[layerid] = [];
434
+ }
435
+ filteredResults[layerid].push(_this.state.resultTree[layerid].find(function (feature) {
436
+ return feature.id === featureid;
437
+ }));
438
+ });
439
+ } else {
440
+ Object.keys(_this.state.selectedLayer !== '' ? _defineProperty({}, _this.state.selectedLayer, _this.state.resultTree[_this.state.selectedLayer]) : _this.state.resultTree).map(function (key) {
441
+ if (!isEmpty(_this.state.resultTree[key])) {
442
+ filteredResults[key] = _this.state.resultTree[key];
443
+ }
444
+ });
445
+ }
435
446
  _this["export"](filteredResults, clipboard);
436
447
  });
437
448
  _defineProperty(_this, "exportResultLayer", function (layer) {
@@ -537,7 +548,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
537
548
  return _this.setCurrentResult(layerid, feature.id);
538
549
  },
539
550
  ref: ref
540
- }, feature.displayname, _this.state.pinnedResults.has(layerid + "$" + feature.id) ? /*#__PURE__*/React.createElement(Icon, {
551
+ }, feature.displayname, _this.state.selectedResults.has(layerid + "$" + feature.id) ? /*#__PURE__*/React.createElement(Icon, {
541
552
  icon: "pin"
542
553
  }) : null), exportEnabled ? /*#__PURE__*/React.createElement(Icon, {
543
554
  className: "identify-export-result",
@@ -704,7 +715,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
704
715
  }
705
716
  var key = layerid + "$" + feature.id;
706
717
  var expanded = _this.state.expandedResults.has(key);
707
- var pinned = _this.state.pinnedResults.has(key);
718
+ var selected = _this.state.selectedResults.has(key);
708
719
  return /*#__PURE__*/React.createElement("div", {
709
720
  className: resultClass,
710
721
  key: key
@@ -720,9 +731,10 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
720
731
  });
721
732
  }
722
733
  }) : null, _this.props.enableCompare ? /*#__PURE__*/React.createElement(Icon, {
723
- icon: pinned ? "unpin" : "pin",
734
+ className: "identify-result-checkbox",
735
+ icon: selected ? "checked" : "unchecked",
724
736
  onClick: function onClick() {
725
- return _this.togglePinnedResult(key);
737
+ return _this.toggleSelectedResult(key);
726
738
  }
727
739
  }) : null, /*#__PURE__*/React.createElement("span", null, (_this.props.showLayerTitles ? feature.layertitle + ": " : "") + feature.displayname), zoomToFeatureButton, /*#__PURE__*/React.createElement(Icon, {
728
740
  icon: "info-sign",
@@ -738,37 +750,47 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
738
750
  className: "identify-result-container"
739
751
  }, resultbox, extraattribs));
740
752
  });
741
- _defineProperty(_this, "togglePinnedResult", function (key) {
753
+ _defineProperty(_this, "toggleSelectedResult", function (key) {
742
754
  _this.setState(function (state) {
743
- var pinnedResults = state.pinnedResults.toggle(key);
755
+ var selectedResults = state.selectedResults.toggle(key);
744
756
  return {
745
- pinnedResults: pinnedResults,
746
- compareEnabled: pinnedResults.size > 1
757
+ selectedResults: selectedResults,
758
+ compareEnabled: selectedResults.size > 1
747
759
  };
748
760
  });
749
761
  });
750
- _defineProperty(_this, "renderToolbar", function (resultCount) {
751
- var toggleButton = function toggleButton(key, icon) {
762
+ _defineProperty(_this, "renderToolbar", function (results) {
763
+ var resultCount = results.length;
764
+ var toggleButton = function toggleButton(key, icon, disabled) {
765
+ var tooltip = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : undefined;
752
766
  return /*#__PURE__*/React.createElement("button", {
753
767
  className: "button" + (_this.state[key] ? " pressed" : ""),
768
+ disabled: disabled,
754
769
  onClick: function onClick() {
755
770
  return _this.setState(function (state) {
756
771
  return _defineProperty({}, key, !state[key]);
757
772
  });
758
- }
773
+ },
774
+ title: tooltip
759
775
  }, /*#__PURE__*/React.createElement(Icon, {
760
776
  icon: icon
761
777
  }));
762
778
  };
763
779
  var infoLabel = null;
764
780
  if (_this.state.compareEnabled) {
765
- infoLabel = /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("identify.comparing", _this.state.pinnedResults.size()));
781
+ infoLabel = /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("identify.comparing", _this.state.selectedResults.size()));
766
782
  } else if (_this.props.resultDisplayMode !== 'paginated') {
767
783
  infoLabel = /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("identify.featurecount", resultCount));
768
784
  }
785
+ var checkedPages = results.reduce(function (res, entry, idx) {
786
+ if (_this.state.selectedResults.has(entry[0] + "$" + entry[1].id)) {
787
+ return [].concat(_toConsumableArray(res), [idx]);
788
+ }
789
+ return res;
790
+ }, []);
769
791
  return /*#__PURE__*/React.createElement("div", {
770
792
  className: "identify-toolbar"
771
- }, toggleButton("settingsMenu", "cog"), _this.state.settingsMenu ? _this.renderSettingsMenu() : null, _this.state.pinnedResults.size() > 1 ? toggleButton("compareEnabled", "compare") : null, /*#__PURE__*/React.createElement("span", {
793
+ }, toggleButton("settingsMenu", "cog", false), _this.state.settingsMenu ? _this.renderSettingsMenu() : null, _this.props.enableCompare ? toggleButton("compareEnabled", "compare", _this.state.selectedResults.size() < 2, LocaleUtils.tr("identify.compare")) : null, /*#__PURE__*/React.createElement("span", {
772
794
  className: "identify-toolbar-spacer"
773
795
  }), infoLabel, /*#__PURE__*/React.createElement("span", {
774
796
  className: "identify-toolbar-spacer"
@@ -780,7 +802,8 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
780
802
  currentPage: page
781
803
  });
782
804
  },
783
- pageSizes: [1]
805
+ pageSizes: [1],
806
+ selectedPages: checkedPages
784
807
  }) : null);
785
808
  });
786
809
  _defineProperty(_this, "renderSettingsMenu", function () {
@@ -798,10 +821,8 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
798
821
  className: "controlgroup"
799
822
  }, /*#__PURE__*/React.createElement("select", {
800
823
  className: "controlgroup-expanditem",
801
- onChange: function onChange(e) {
802
- return _this.setState({
803
- selectedLayer: e.target.value
804
- });
824
+ onChange: function onChange(ev) {
825
+ return _this.setSelectedLayer(ev.target.value);
805
826
  }
806
827
  }, /*#__PURE__*/React.createElement("option", {
807
828
  value: ""
@@ -876,6 +897,20 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
876
897
  icon: "report"
877
898
  }))))) : null)));
878
899
  });
900
+ _defineProperty(_this, "setSelectedLayer", function (layer) {
901
+ _this.setState(function (state) {
902
+ var newSelectedResults = state.selectedResults;
903
+ if (layer !== '') {
904
+ newSelectedResults = state.selectedResults.filtered(function (key) {
905
+ return key.startsWith(layer + "$");
906
+ });
907
+ }
908
+ return {
909
+ selectedResults: newSelectedResults,
910
+ selectedLayer: layer
911
+ };
912
+ });
913
+ });
879
914
  _defineProperty(_this, "computeExtraAttributes", function (layer, result) {
880
915
  var _window$qwc;
881
916
  var rows = [];
@@ -1147,11 +1182,11 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1147
1182
  if (this.state.compareEnabled) {
1148
1183
  body = /*#__PURE__*/React.createElement("div", {
1149
1184
  className: "identify-compare-results"
1150
- }, this.state.pinnedResults.entries().map(function (key) {
1151
- var _key$split = key.split("$"),
1152
- _key$split2 = _slicedToArray(_key$split, 2),
1153
- layerid = _key$split2[0],
1154
- featureid = _key$split2[1];
1185
+ }, this.state.selectedResults.entries().map(function (key) {
1186
+ var _key$split3 = key.split("$"),
1187
+ _key$split4 = _slicedToArray(_key$split3, 2),
1188
+ layerid = _key$split4[0],
1189
+ featureid = _key$split4[1];
1155
1190
  var feature = _this2.state.resultTree[layerid].find(function (f) {
1156
1191
  return f.id === featureid;
1157
1192
  });
@@ -1184,7 +1219,13 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1184
1219
  layerid = _flatResults$this$sta[0],
1185
1220
  feature = _flatResults$this$sta[1];
1186
1221
  body = /*#__PURE__*/React.createElement("div", {
1187
- className: "identify-flat-results-list"
1222
+ className: "identify-flat-results-list",
1223
+ onMouseEnter: function onMouseEnter() {
1224
+ return _this2.setHighlightedFeatures([feature]);
1225
+ },
1226
+ onMouseLeave: function onMouseLeave() {
1227
+ return _this2.setHighlightedFeatures(null);
1228
+ }
1188
1229
  }, this.renderResultAttributes(layerid, feature, 'identify-result-frame'));
1189
1230
  }
1190
1231
  // "el.style.background='inherit'": HACK to trigger an additional repaint, since Safari/Chrome on iOS render the element cut off the first time
@@ -1193,7 +1234,7 @@ var IdentifyViewer = /*#__PURE__*/function (_React$Component) {
1193
1234
  ref: function ref(el) {
1194
1235
  if (el) el.style.background = 'inherit';
1195
1236
  }
1196
- }, body, flatResults.length > 0 ? this.renderToolbar(flatResults.length) : null);
1237
+ }, body, flatResults.length > 0 ? this.renderToolbar(flatResults) : null);
1197
1238
  }
1198
1239
  }]);
1199
1240
  }(React.Component);