qwc2 2025.10.15 → 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 (67) 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 +450 -319
  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/map3d/Map3D.js +1 -1
  11. package/components/style/App.css +18 -0
  12. package/components/style/AttributeTableWidget.css +2 -1
  13. package/components/style/FeatureAttributesWindow.css +16 -0
  14. package/components/style/IdentifyViewer.css +56 -80
  15. package/components/style/LocationRecorder.css +10 -0
  16. package/components/style/NumericInputWindow.css +7 -0
  17. package/components/style/PluginsContainer.css +16 -0
  18. package/components/widgets/LayerCatalogWidget.js +40 -16
  19. package/components/widgets/NavBar.js +12 -5
  20. package/components/widgets/style/NavBar.css +0 -1
  21. package/icons/circle_full.svg +75 -0
  22. package/icons/eye-slash.svg +138 -0
  23. package/icons/pin.svg +41 -0
  24. package/icons/unpin.svg +41 -0
  25. package/package.json +1 -1
  26. package/plugins/AttributeTable.js +4 -0
  27. package/plugins/GeometryDigitizer.js +3 -0
  28. package/plugins/HeightProfile.js +2 -0
  29. package/plugins/Identify.js +12 -7
  30. package/plugins/ObjectList.js +116 -0
  31. package/plugins/Redlining.js +14 -55
  32. package/plugins/map/EditingSupport.js +22 -1
  33. package/plugins/map/LocateSupport.js +8 -1
  34. package/plugins/map/RedliningSupport.js +108 -18
  35. package/plugins/map/SnappingSupport.js +11 -6
  36. package/plugins/map/style/SnappingSupport.css +2 -13
  37. package/reducers/locate.js +4 -2
  38. package/reducers/redlining.js +2 -1
  39. package/static/translations/bg-BG.json +16 -1
  40. package/static/translations/ca-ES.json +16 -1
  41. package/static/translations/cs-CZ.json +15 -0
  42. package/static/translations/de-CH.json +17 -2
  43. package/static/translations/de-DE.json +18 -3
  44. package/static/translations/en-US.json +16 -1
  45. package/static/translations/es-ES.json +15 -0
  46. package/static/translations/fi-FI.json +15 -0
  47. package/static/translations/fr-FR.json +16 -1
  48. package/static/translations/hu-HU.json +15 -0
  49. package/static/translations/it-IT.json +16 -1
  50. package/static/translations/ja-JP.json +16 -1
  51. package/static/translations/nl-NL.json +15 -0
  52. package/static/translations/no-NO.json +15 -0
  53. package/static/translations/pl-PL.json +15 -0
  54. package/static/translations/pt-BR.json +15 -0
  55. package/static/translations/pt-PT.json +15 -0
  56. package/static/translations/ro-RO.json +15 -0
  57. package/static/translations/ru-RU.json +15 -0
  58. package/static/translations/sv-SE.json +15 -0
  59. package/static/translations/tr-TR.json +15 -0
  60. package/static/translations/tsconfig.json +12 -0
  61. package/static/translations/uk-UA.json +15 -0
  62. package/utils/EditingInterface.js +4 -1
  63. package/utils/EditingUtils.js +3 -1
  64. package/utils/MiscUtils.js +118 -0
  65. package/utils/expr_grammar/grammar.js +104 -22
  66. package/utils/expr_grammar/grammar.ne +2 -0
  67. package/utils/expr_grammar/test.js +21 -4
@@ -0,0 +1,138 @@
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 _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
3
+ 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); } }
4
+ function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
5
+ function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
6
+ 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); }
7
+ function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
8
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
9
+ function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
10
+ 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); }
11
+ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
12
+ 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; }
13
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
14
+ 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); }
15
+ /**
16
+ * Copyright 2015 Sourcepole AG
17
+ * All rights reserved.
18
+ *
19
+ * This source code is licensed under the BSD-style license found in the
20
+ * LICENSE file in the root directory of this source tree.
21
+ */
22
+
23
+ import React from 'react';
24
+ import ReactDOM from 'react-dom';
25
+ import { connect } from 'react-redux';
26
+ import classNames from 'classnames';
27
+ import PropTypes from 'prop-types';
28
+ import LocaleUtils from '../utils/LocaleUtils';
29
+ import Icon from './Icon';
30
+ import { BottomToolPortalContext } from './PluginsContainer';
31
+ import NumberInput from './widgets/NumberInput';
32
+ import './style/LocationRecorder.css';
33
+ var LocationRecorder = /*#__PURE__*/function (_React$Component) {
34
+ function LocationRecorder(props) {
35
+ var _this;
36
+ _classCallCheck(this, LocationRecorder);
37
+ _this = _callSuper(this, LocationRecorder, [props]);
38
+ _defineProperty(_this, "state", {
39
+ recording: false,
40
+ interval: 1
41
+ });
42
+ _defineProperty(_this, "toggleRecording", function () {
43
+ if (_this.state.recording) {
44
+ _this.stopRecording();
45
+ } else {
46
+ _this.props.drawInteraction.abortDrawing();
47
+ _this.props.drawInteraction.setActive(false);
48
+ // Re-add overlay to map, removed by setActive(false), to ensure traced feature is visibile
49
+ _this.props.drawInteraction.getOverlay().setMap(_this.props.map);
50
+ _this.setState({
51
+ recording: true
52
+ });
53
+ if (!navigator.geolocation) {
54
+ _this.stopRecording();
55
+ /* eslint-disable-next-line */
56
+ console.error("Geolocation not supported");
57
+ } else {
58
+ _this.props.drawInteraction.appendCoordinates([_this.props.locatePosition]);
59
+ if (_this.props.geomType === "Point") {
60
+ _this.stopRecording();
61
+ } else {
62
+ _this.pollInterval = setInterval(function () {
63
+ _this.props.drawInteraction.appendCoordinates([_this.props.locatePosition]);
64
+ }, _this.state.interval * 1000);
65
+ }
66
+ }
67
+ }
68
+ });
69
+ _defineProperty(_this, "stopRecording", function () {
70
+ _this.setState({
71
+ recording: false
72
+ }, _this.finishDrawing);
73
+ clearInterval(_this.pollInterval);
74
+ });
75
+ _defineProperty(_this, "finishDrawing", function () {
76
+ _this.props.drawInteraction.finishDrawing();
77
+ _this.props.drawInteraction.setActive(true);
78
+ });
79
+ _this.pollInterval = null;
80
+ return _this;
81
+ }
82
+ _inherits(LocationRecorder, _React$Component);
83
+ return _createClass(LocationRecorder, [{
84
+ key: "componentWillUnmount",
85
+ value: function componentWillUnmount() {
86
+ this.stopRecording();
87
+ }
88
+ }, {
89
+ key: "render",
90
+ value: function render() {
91
+ var _this2 = this;
92
+ if (!this.props.locateEnabled || !this.props.locatePosition) {
93
+ return null;
94
+ }
95
+ var buttonClasses = classNames({
96
+ button: true,
97
+ pressed: this.state.recording
98
+ });
99
+ return /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
100
+ className: "LocationRecorder"
101
+ }, /*#__PURE__*/React.createElement(Icon, {
102
+ icon: "screenshot"
103
+ }), /*#__PURE__*/React.createElement("button", {
104
+ className: buttonClasses,
105
+ onClick: this.toggleRecording
106
+ }, /*#__PURE__*/React.createElement(Icon, {
107
+ icon: this.state.recording ? "square" : "circle_full"
108
+ }), /*#__PURE__*/React.createElement("span", null, this.state.recording ? LocaleUtils.tr("locationrecorder.stop") : LocaleUtils.tr("locationrecorder.record"))), /*#__PURE__*/React.createElement(NumberInput, {
109
+ decimals: 1,
110
+ max: 30,
111
+ min: 0.5,
112
+ mobile: true,
113
+ onChange: function onChange(value) {
114
+ return _this2.setState({
115
+ interval: value
116
+ });
117
+ },
118
+ step: 0.5,
119
+ suffix: "s",
120
+ value: this.state.interval
121
+ })), this.context);
122
+ }
123
+ }]);
124
+ }(React.Component);
125
+ _defineProperty(LocationRecorder, "contextType", BottomToolPortalContext);
126
+ _defineProperty(LocationRecorder, "propTypes", {
127
+ drawInteraction: PropTypes.object,
128
+ geomType: PropTypes.string,
129
+ locateEnabled: PropTypes.bool,
130
+ locatePosition: PropTypes.array,
131
+ map: PropTypes.object
132
+ });
133
+ export default connect(function (state) {
134
+ return {
135
+ locateEnabled: ["ENABLED", "FOLLOWING"].includes(state.locate.state),
136
+ locatePosition: state.locate.mapPos
137
+ };
138
+ })(LocationRecorder);
@@ -31,6 +31,9 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
31
31
  import React from 'react';
32
32
  import { connect } from 'react-redux';
33
33
  import isEmpty from 'lodash.isempty';
34
+ import ol from 'openlayers';
35
+ import pointInPolygon from 'point-in-polygon';
36
+ import polygonIntersectTest from 'polygon-intersect-test';
34
37
  import PropTypes from 'prop-types';
35
38
  import { v4 as uuidv4 } from 'uuid';
36
39
  import { LayerRole, addLayerFeatures, clearLayer } from '../actions/layers';
@@ -121,29 +124,40 @@ var PickFeature = /*#__PURE__*/function (_React$Component) {
121
124
  value: function componentDidUpdate(prevProps, prevState) {
122
125
  var _this2 = this;
123
126
  if (this.state.pickGeom && this.state.pickGeom !== prevState.pickGeom) {
124
- var queryLayers = [];
127
+ var queryWmsLayers = [];
128
+ var queryVectorLayers = [];
125
129
  if (this.props.layerFilter) {
126
- queryLayers = [this.props.layers.find(function (l) {
130
+ queryWmsLayers = [this.props.layers.find(function (l) {
127
131
  return l.url === _this2.props.layerFilter.url;
128
132
  })].filter(Boolean);
129
133
  } else {
130
- queryLayers = IdentifyUtils.getQueryLayers(this.props.layers, this.props.map);
134
+ queryWmsLayers = IdentifyUtils.getQueryLayers(this.props.layers, this.props.map);
135
+ queryVectorLayers = this.props.layers.filter(function (layer) {
136
+ return layer.visibility && LayerRole.USERLAYER && (layer.type === 'vector' || layer.type === 'wfs');
137
+ });
131
138
  }
132
- if (!isEmpty(queryLayers)) {
133
- this.setState(function (state) {
134
- var getPixelFromCoordinate = MapUtils.getHook(MapUtils.GET_PIXEL_FROM_COORDINATES_HOOK);
135
- var coordinates = _this2.props.pickGeomType === "Point" ? [[state.pickGeom.coordinates]] : state.pickGeom.coordinates;
136
- var maxX = coordinates[0][0][0];
137
- var maxY = coordinates[0][0][1];
138
- for (var i = 1; i < coordinates[0].length; ++i) {
139
- if (coordinates[0][i][0] > maxX) {
140
- maxX = coordinates[0][i][0];
141
- maxY = coordinates[0][i][1];
142
- }
139
+ if (this.props.layerFilterFunc) {
140
+ queryWmsLayers = queryWmsLayers.filter(this.props.layerFilterFunc);
141
+ queryVectorLayers = queryVectorLayers.filter(this.props.layerFilterFunc);
142
+ }
143
+ if (isEmpty(queryWmsLayers) && isEmpty(queryVectorLayers)) {
144
+ return;
145
+ }
146
+ this.setState(function (state) {
147
+ var coordinates = _this2.props.pickGeomType === "Point" ? [[state.pickGeom.coordinates]] : state.pickGeom.coordinates;
148
+ var maxX = coordinates[0][0][0];
149
+ var maxY = coordinates[0][0][1];
150
+ for (var i = 1; i < coordinates[0].length; ++i) {
151
+ if (coordinates[0][i][0] > maxX) {
152
+ maxX = coordinates[0][i][0];
153
+ maxY = coordinates[0][i][1];
143
154
  }
144
- var clickPos = getPixelFromCoordinate([maxX, maxY], false);
145
- var reqId = uuidv4();
146
- queryLayers.forEach(function (layer) {
155
+ }
156
+ var reqId = uuidv4();
157
+ var getPixelFromCoordinate = MapUtils.getHook(MapUtils.GET_PIXEL_FROM_COORDINATES_HOOK);
158
+ var clickPos = getPixelFromCoordinate([maxX, maxY], false);
159
+ if (!isEmpty(queryWmsLayers)) {
160
+ queryWmsLayers.forEach(function (layer) {
147
161
  var request = null;
148
162
  if (_this2.props.pickGeomType === 'Point') {
149
163
  var _this2$props$layerFil;
@@ -159,14 +173,58 @@ var PickFeature = /*#__PURE__*/function (_React$Component) {
159
173
  return _this2.handleIdentifyResponse(response, reqId, layer, request.params.info_format);
160
174
  });
161
175
  });
162
- return {
163
- pickResults: {},
164
- clickPos: clickPos,
165
- pendingQueries: queryLayers.length,
166
- reqId: reqId
167
- };
168
- });
169
- }
176
+ }
177
+ var pickResults = {};
178
+ if (!isEmpty(queryVectorLayers)) {
179
+ var olMap = MapUtils.getHook(MapUtils.GET_MAP);
180
+ var layerMap = queryVectorLayers.reduce(function (res, layer) {
181
+ return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, layer.id, layer));
182
+ }, {});
183
+ var format = new ol.format.GeoJSON();
184
+ if (_this2.props.pickGeomType === 'Point') {
185
+ olMap.forEachFeatureAtPixel(clickPos, function (feature, layer) {
186
+ var _layer$get;
187
+ var layerid = layer === null || layer === void 0 || (_layer$get = layer.get) === null || _layer$get === void 0 ? void 0 : _layer$get.call(layer, 'id');
188
+ if (layerid in layerMap) {
189
+ var featureObj = format.writeFeatureObject(feature);
190
+ var layername = layerMap[layerid].name;
191
+ pickResults[layername] = pickResults[layername] || [];
192
+ pickResults[layername].push(featureObj);
193
+ }
194
+ });
195
+ } else if (_this2.props.pickGeomType === 'Polygon') {
196
+ var extent = ol.extent.boundingExtent(coordinates[0]);
197
+ olMap.getLayers().forEach(function (layer) {
198
+ if (!(layer.get('id') in layerMap)) {
199
+ return;
200
+ }
201
+ layer.getSource().forEachFeatureIntersectingExtent(extent, function (feature) {
202
+ var intersects = false;
203
+ if (feature.getGeometry().getType() === "Point") {
204
+ intersects = pointInPolygon(feature.getGeometry().getCoordinates(), coordinates[0]);
205
+ } else if (feature.getGeometry().getType() === "LineString") {
206
+ intersects = true; // TODO
207
+ } else if (feature.getGeometry().getType() === "Polygon") {
208
+ intersects = polygonIntersectTest(feature.getGeometry().getCoordinates()[0], coordinates[0]);
209
+ }
210
+ if (!intersects) {
211
+ return;
212
+ }
213
+ var featureObj = format.writeFeatureObject(feature);
214
+ var layername = layerMap[layer.get('id')].name;
215
+ pickResults[layername] = pickResults[layername] || [];
216
+ pickResults[layername].push(featureObj);
217
+ });
218
+ });
219
+ }
220
+ }
221
+ return {
222
+ pickResults: pickResults,
223
+ clickPos: clickPos,
224
+ pendingQueries: queryWmsLayers.length,
225
+ reqId: reqId
226
+ };
227
+ });
170
228
  }
171
229
  }
172
230
  }, {
@@ -186,6 +244,7 @@ var PickFeature = /*#__PURE__*/function (_React$Component) {
186
244
  layername = _ref6[0],
187
245
  features = _ref6[1];
188
246
  return features.map(function (feature) {
247
+ var _feature$displayname;
189
248
  return /*#__PURE__*/React.createElement("div", {
190
249
  key: layername + ":" + feature.id,
191
250
  onClickCapture: function onClickCapture() {
@@ -197,7 +256,7 @@ var PickFeature = /*#__PURE__*/function (_React$Component) {
197
256
  onMouseOver: function onMouseOver() {
198
257
  return _this3.highlightFeature(layername, feature);
199
258
  }
200
- }, layername + ": " + feature.displayname);
259
+ }, layername + ": " + ((_feature$displayname = feature.displayname) !== null && _feature$displayname !== void 0 ? _feature$displayname : feature.id));
201
260
  });
202
261
  }) : /*#__PURE__*/React.createElement("div", {
203
262
  className: "pick-feature-menu-querying"
@@ -240,6 +299,8 @@ _defineProperty(PickFeature, "propTypes", {
240
299
  url: PropTypes.string,
241
300
  name: PropTypes.string
242
301
  }),
302
+ /** Optional: Filter function to restrict pick layers */
303
+ layerFilterFunc: PropTypes.func,
243
304
  layers: PropTypes.array,
244
305
  map: PropTypes.object,
245
306
  /** Pick geometry type: Point, Polygon, ... (default: Point) */
@@ -40,6 +40,7 @@ import './style/PluginsContainer.css';
40
40
  export var MapButtonPortalContext = /*#__PURE__*/React.createContext(null);
41
41
  export var MapContainerPortalContext = /*#__PURE__*/React.createContext(null);
42
42
  export var AppInfosPortalContext = /*#__PURE__*/React.createContext(null);
43
+ export var BottomToolPortalContext = /*#__PURE__*/React.createContext(null);
43
44
  var PluginsContainer = /*#__PURE__*/function (_React$Component) {
44
45
  function PluginsContainer() {
45
46
  var _this;
@@ -51,7 +52,8 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
51
52
  _defineProperty(_this, "state", {
52
53
  mapButtonsContainerRef: null,
53
54
  mapContainerRef: null,
54
- appInfosContainerRef: null
55
+ appInfosContainerRef: null,
56
+ bottomToolContainerRef: null
55
57
  });
56
58
  _defineProperty(_this, "renderPlugins", function () {
57
59
  var device = ConfigUtils.isMobile() ? 'mobile' : 'desktop';
@@ -134,6 +136,11 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
134
136
  appInfosContainerRef: el
135
137
  });
136
138
  });
139
+ _defineProperty(_this, "setBottomToolContanerRef", function (el) {
140
+ _this.setState({
141
+ bottomToolContainerRef: el
142
+ });
143
+ });
137
144
  _defineProperty(_this, "setButtonContainerRef", function (el) {
138
145
  _this.setState({
139
146
  mapButtonsContainerRef: el
@@ -190,7 +197,7 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
190
197
  right: 'calc(' + right + 'px)',
191
198
  bottom: 'calc(var(--bottombar-height) + ' + bottom + 'px)'
192
199
  };
193
- var haveRefs = this.state.mapButtonsContainerRef && this.state.mapContainerRef && this.state.appInfosContainerRef;
200
+ var haveRefs = this.state.mapButtonsContainerRef && this.state.mapContainerRef && this.state.appInfosContainerRef && this.state.bottomToolContainerRef;
194
201
  return /*#__PURE__*/React.createElement("div", {
195
202
  className: "plugins-container " + ((_this$props$className = this.props.className) !== null && _this$props$className !== void 0 ? _this$props$className : ""),
196
203
  ref: this.setupTouchEvents
@@ -200,7 +207,9 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
200
207
  value: this.state.mapButtonsContainerRef
201
208
  }, /*#__PURE__*/React.createElement(MapContainerPortalContext.Provider, {
202
209
  value: this.state.mapContainerRef
203
- }, haveRefs ? this.renderPlugins() : null, haveRefs ? this.props.children : null))), /*#__PURE__*/React.createElement(WindowManager, null), /*#__PURE__*/React.createElement("div", {
210
+ }, /*#__PURE__*/React.createElement(BottomToolPortalContext.Provider, {
211
+ value: this.state.bottomToolContainerRef
212
+ }, haveRefs ? this.renderPlugins() : null, haveRefs ? this.props.children : null)))), /*#__PURE__*/React.createElement(WindowManager, null), /*#__PURE__*/React.createElement("div", {
204
213
  className: "map-container",
205
214
  ref: this.setMapContainerRef,
206
215
  style: mapContainerStyle
@@ -212,6 +221,10 @@ var PluginsContainer = /*#__PURE__*/function (_React$Component) {
212
221
  className: "app-infos-container",
213
222
  ref: this.setAppInfosContainerRef,
214
223
  style: mapContainerStyle
224
+ }), /*#__PURE__*/React.createElement("div", {
225
+ className: "map-bottom-tool-container",
226
+ ref: this.setBottomToolContanerRef,
227
+ style: mapContainerStyle
215
228
  }));
216
229
  }
217
230
  }]);
@@ -252,7 +252,8 @@ _defineProperty(OlLayer, "propTypes", {
252
252
  refreshLayer: PropTypes.func,
253
253
  setLayerLoading: PropTypes.func,
254
254
  swipe: PropTypes.number,
255
- zIndex: PropTypes.number
255
+ zIndex: PropTypes.number,
256
+ zoomToExtent: PropTypes.func
256
257
  });
257
258
  export default connect(function () {
258
259
  return {};
@@ -102,6 +102,8 @@ var HeightProfilePrintDialog = /*#__PURE__*/function (_React$PureComponent) {
102
102
  value: function componentDidMount() {
103
103
  var templatePath = MiscUtils.resolveAssetsPath(this.props.templatePath);
104
104
  this.externalWindow = window.open(templatePath, LocaleUtils.tr("heightprofile.title"), "toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=yes, resizable=yes");
105
+ // Inherit API
106
+ this.externalWindow.qwc2 = window.qwc2;
105
107
  this.externalWindow.addEventListener('load', this.setWindowContent, false);
106
108
  this.externalWindow.addEventListener('resize', this.windowResized, false);
107
109
  window.addEventListener('beforeunload', this.closePrintWindow);
@@ -618,7 +618,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
618
618
  // Setup map
619
619
  var initialBbox = (_this2$props$theme$ma = (_this2$props$theme$ma2 = _this2.props.theme.map3d) === null || _this2$props$theme$ma2 === void 0 ? void 0 : _this2$props$theme$ma2.extent) !== null && _this2$props$theme$ma !== void 0 ? _this2$props$theme$ma : _this2.props.theme.initialBbox;
620
620
  var bounds = CoordinatesUtils.reprojectBbox(initialBbox.bounds, initialBbox.crs, projection);
621
- var extent = new Extent(crs, bounds[0], bounds[2], bounds[1], bounds[3]);
621
+ var extent = new Extent(projection, bounds[0], bounds[2], bounds[1], bounds[3]);
622
622
  _this2.map = new Map({
623
623
  extent: extent,
624
624
  backgroundColor: "white"
@@ -169,6 +169,20 @@ button.button > div.spinner {
169
169
  height: 1.5em;
170
170
  }
171
171
 
172
+ button.selected {
173
+ position: relative;
174
+ }
175
+ button.selected:after {
176
+ position: absolute;
177
+ left: 0;
178
+ right: 0;
179
+ bottom: 0;
180
+ height: 3px;
181
+ background-color: var(--color-active);
182
+ border-top: 1px solid var(--border-color);
183
+ content: "";
184
+ }
185
+
172
186
  div.controlgroup {
173
187
  display: flex;
174
188
  align-items: center;
@@ -179,6 +193,10 @@ div.controlgroup > .controlgroup-fillitem {
179
193
  width: 0;
180
194
  }
181
195
 
196
+ div.controlgroup > .controlgroup-expanditem {
197
+ flex: 1 0 auto;
198
+ }
199
+
182
200
  div.controlgroup > *:not(:last-child):not(span) {
183
201
  margin-right: -1px;
184
202
  }
@@ -182,7 +182,7 @@ table.attribtable-table td > div.TextInput > pre {
182
182
  min-height: 2em;
183
183
  }
184
184
 
185
- table.attribtable-table td > *:disabled,
185
+ table.attribtable-table tr.row-disabled td > *:disabled,
186
186
  table.attribtable-table tr.row-disabled,
187
187
  table.attribtable-table tr.row-disabled * {
188
188
  color: var(--text-color-disabled);
@@ -192,6 +192,7 @@ table.attribtable-table tr.row-disabled * {
192
192
  div.attribtable-footbar {
193
193
  display: flex;
194
194
  align-items: center;
195
+ margin: 0 -0.25em;
195
196
  }
196
197
 
197
198
  div.attribtable-footbar > div {
@@ -0,0 +1,16 @@
1
+ div.feature-attributes-body table {
2
+ width: 100%;
3
+ }
4
+
5
+ div.feature-attributes-body table td:first-child {
6
+ width: 25%
7
+ }
8
+
9
+ div.feature-attributes-body table td:last-child {
10
+ width: 1%;
11
+ }
12
+
13
+ div.feature-attributes-body table td > input {
14
+ min-width: 0;
15
+ width: 100%;
16
+ }
@@ -9,7 +9,7 @@ span.identify-body-message {
9
9
  padding: 0.25em;
10
10
  }
11
11
 
12
- div.identify-body div.identify-results-container {
12
+ div.identify-body div.identify-results-tree {
13
13
  overflow-y: auto;
14
14
  flex: 1 1 50%;
15
15
  min-height: 0;
@@ -20,79 +20,44 @@ div.identify-body div.identify-results-container {
20
20
  font-size: small;
21
21
  }
22
22
 
23
- div.identify-layer-expandable {
24
- position: relative;
25
- margin-left: 1em;
26
- }
27
-
28
- div.identify-layer-expandable > div.identify-layer-entries {
29
- display: none;
30
- }
31
-
32
- div.identify-layer-expanded > div.identify-layer-entries {
33
- display: block;
34
- }
35
-
36
- div.identify-layer-expandable:before {
37
- content: "";
38
- border-color: transparent var(--text-color);
39
- border-width: 0.35em 0 0.35em 0.45em;
40
- border-style: solid;
41
- display: block;
42
- height: 0;
43
- width: 0;
44
- left: -1em;
45
- top: 0.3em;
46
- position: absolute;
47
- }
48
-
49
- div.identify-layer-expanded:before {
50
- border-color: var(--text-color) transparent;
51
- border-width: 0.45em 0.35em 0 0.35em;
52
- top: 0.4em;
53
- }
54
-
55
- div.identify-layer-entries {
56
- padding: 0.25em 0.25em 0.25em 1em;
57
- }
58
-
59
- div.identify-result-entry {
23
+ div.identify-results-tree-entry {
60
24
  display: flex;
61
25
  }
62
26
 
63
- div.identify-result-entry span.clickable {
27
+ div.identify-results-tree-entry > span:first-child {
28
+ display: flex;
29
+ align-items: center;
64
30
  cursor: pointer;
31
+ flex: 1 1 auto;
65
32
  }
66
33
 
67
- div.identify-result-entry span.active {
34
+ span.identify-results-tree-entry-active {
68
35
  font-weight: bold;
69
36
  }
70
37
 
71
- div.identify-result-entry > span:first-child {
72
- flex: 1 1 auto;
73
- }
74
-
75
- div.identify-result-entry span.identify-remove-result,
76
- div.identify-result-entry span.identify-export-result {
38
+ div.identify-results-tree-entry span.identify-remove-result,
39
+ div.identify-results-tree-entry span.identify-export-result {
77
40
  margin: 0 0.25em;
78
- color: var(--border-color);
79
41
  cursor: pointer;
80
42
  visibility: hidden;
81
- font-size: large;
82
43
  flex: 0 0 auto;
83
44
  }
84
45
 
85
- div.identify-result-entry:hover > span.identify-remove-result,
86
- div.identify-result-entry:hover > span.identify-export-result {
46
+ div.identify-results-tree-entry:hover > span.identify-remove-result,
47
+ div.identify-results-tree-entry:hover > span.identify-export-result {
87
48
  visibility: visible;
88
49
  }
89
50
 
51
+ div.identify-results-tree-entries {
52
+ padding: 0.25em 0.25em 0.25em 1em;
53
+ }
54
+
90
55
  div.identify-body div.identify-flat-results-list {
91
56
  overflow: auto;
92
57
  flex: 1 1 auto;
93
58
  }
94
59
 
95
- div.identify-body .identify-result-tree-frame {
60
+ div.identify-body div.identify-result-tree-frame {
96
61
  flex: 1 1 50%;
97
62
  min-height: 0;
98
63
  display: flex;
@@ -100,18 +65,18 @@ div.identify-body .identify-result-tree-frame {
100
65
  border: 1px solid var(--border-color);
101
66
  }
102
67
 
103
- div.identify-body .identify-result-frame-normal {
104
- margin-top: 0.25em;
68
+ div.identify-body div.identify-result-frame {
69
+ margin-bottom: 0.25em;
105
70
  border: 1px solid var(--border-color);
106
71
  }
107
72
 
108
- div.identify-body .identify-result-frame-highlighted {
109
- margin-top: 0.25em;
73
+ div.identify-body div.identify-result-frame:hover {
110
74
  border: 1px solid var(--color-active);
111
75
  }
112
76
 
113
77
  div.identify-body .identify-result-title {
114
78
  background-color: var(--list-section-bg-color);
79
+ color: var(--list-section-text-color);
115
80
  padding: 0.25em;
116
81
  font-weight: bold;
117
82
  flex: 0 0 auto;
@@ -130,6 +95,10 @@ div.identify-body .identify-result-title > span.icon {
130
95
  flex: 0 0 auto;
131
96
  }
132
97
 
98
+ span.identify-result-checkbox {
99
+ background-color: white;
100
+ }
101
+
133
102
  div.identify-body .identify-result-title > span:not(:first-child) {
134
103
  margin-left: 0.5em;
135
104
  }
@@ -142,6 +111,17 @@ div.identify-body .identify-result-tree-frame > div.identify-result-container {
142
111
  overflow-y: auto;
143
112
  }
144
113
 
114
+ div.identify-compare-results {
115
+ display: flex;
116
+ flex-wrap: wrap;
117
+ overflow: auto;
118
+ flex: 1 1 auto;
119
+ }
120
+
121
+ div.identify-compare-results > div.identify-result-frame {
122
+ flex: 1 1 20em;
123
+ }
124
+
145
125
  div.identify-body .identify-result-box {
146
126
  border: 0;
147
127
  background-color: var(--list-bg-color);
@@ -195,21 +175,34 @@ div.identify-body td.identify-attr-value > a > img {
195
175
  max-width: 100%;
196
176
  }
197
177
 
198
- div.identify-body div.identify-buttonbox {
199
- margin-top: 0.5em;
178
+ div.identify-body div.identify-toolbar {
179
+ background-color: var(--container-bg-color);
180
+ margin-top: -0.25em;
200
181
  flex: 0 0 auto;
201
182
  display: flex;
202
183
  align-items: center;
184
+ position: relative;
185
+ border-top: 1px solid var(--border-color);
186
+ padding-top: 0.25em;
203
187
  }
204
188
 
205
- div.identify-body div.identify-selectbox {
206
- flex: 0 0 auto;
207
- display: flex;
208
- align-items: center;
189
+ span.identify-toolbar-spacer {
190
+ flex: 1 1 auto;
209
191
  }
210
192
 
211
- select:focus {
212
- outline: none;
193
+ div.identify-settings-menu {
194
+ position: absolute;
195
+ bottom: 100%;
196
+ left: 0;
197
+ border: 1px solid var(--border-color);
198
+ background-color: var(--container-bg-color);
199
+ box-shadow: 0px 0px 5px rgba(136, 136, 136, 1);
200
+ z-index: 1;
201
+ padding: 0.25em;
202
+ }
203
+
204
+ div.identify-settings-menu table td > div.controlgroup {
205
+ width: 100%;
213
206
  }
214
207
 
215
208
  div.identify-body table.identify-attr-subtable {
@@ -224,20 +217,3 @@ div.identify-body td.identify-attr-spacer {
224
217
  height: 2px;
225
218
  background-color: var(--list-section-bg-color);
226
219
  }
227
-
228
- span.identify-buttonbox-spacer {
229
- flex: 1 1 auto;
230
- }
231
-
232
- div.identify-body div.identify-result-feature-report-frame {
233
- padding: 0.25em 0.5em;
234
- font-size: small;
235
- display: flex;
236
- align-items: center;
237
- }
238
-
239
- div.identify-body div.identify-result-feature-report-frame > div.spinner {
240
- width: 1em;
241
- height: 1em;
242
- margin-left: 0.5em;
243
- }