qwc2 2025.12.17 → 2025.12.18

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 (70) hide show
  1. package/components/AttributeForm.js +8 -8
  2. package/components/AttributeTableWidget.js +3 -3
  3. package/components/EditComboField.js +1 -1
  4. package/components/EditUploadField.js +1 -1
  5. package/components/IdentifyViewer.js +3 -4
  6. package/components/LinkFeatureForm.js +21 -4
  7. package/components/MeasureSwitcher.js +115 -0
  8. package/components/PluginsContainer.js +3 -2
  9. package/components/QtDesignerForm.js +2 -2
  10. package/components/ResizeableWindow.js +1 -1
  11. package/components/SearchBox.js +7 -7
  12. package/components/map3d/drawtool/EditTool3D.js +1 -1
  13. package/components/style/IdentifyViewer.css +1 -1
  14. package/components/style/LocationRecorder.css +1 -6
  15. package/components/style/PluginsContainer.css +11 -6
  16. package/components/timeline/FixedTimeline.js +2 -2
  17. package/components/timeline/InfiniteTimeline.js +2 -2
  18. package/components/timeline/TimelineFeaturesSlider.js +1 -1
  19. package/components/widgets/LayerCatalogWidget.js +1 -1
  20. package/package.json +1 -1
  21. package/plugins/Editing.js +20 -5
  22. package/plugins/FeatureForm.js +1 -1
  23. package/plugins/FeatureSearch.js +3 -3
  24. package/plugins/GeometryDigitizer.js +32 -18
  25. package/plugins/Identify.js +1 -4
  26. package/plugins/MapExport.js +4 -4
  27. package/plugins/MapFilter.js +10 -10
  28. package/plugins/NewsPopup.js +1 -1
  29. package/plugins/ObliqueView.js +88 -17
  30. package/plugins/Print.js +7 -7
  31. package/plugins/Redlining.js +25 -73
  32. package/plugins/Reports.js +3 -3
  33. package/plugins/Routing.js +4 -4
  34. package/plugins/ValueTool.js +1 -1
  35. package/plugins/View3D.js +2 -2
  36. package/plugins/ZoomButtons.js +1 -1
  37. package/plugins/map/EditingSupport.js +50 -20
  38. package/plugins/map/RedliningSupport.js +2 -2
  39. package/plugins/map/SnapSupport.js +12 -10
  40. package/plugins/map/style/SnappingSupport.css +1 -8
  41. package/plugins/map3d/Draw3D.js +2 -2
  42. package/plugins/map3d/ExportObjects3D.js +2 -2
  43. package/plugins/map3d/MapExport3D.js +4 -4
  44. package/reducers/editing.js +6 -1
  45. package/static/translations/bg-BG.json +39 -74
  46. package/static/translations/ca-ES.json +39 -74
  47. package/static/translations/cs-CZ.json +39 -74
  48. package/static/translations/de-CH.json +39 -74
  49. package/static/translations/de-DE.json +39 -74
  50. package/static/translations/en-US.json +39 -74
  51. package/static/translations/es-ES.json +39 -74
  52. package/static/translations/fi-FI.json +39 -74
  53. package/static/translations/fr-FR.json +39 -74
  54. package/static/translations/hu-HU.json +39 -74
  55. package/static/translations/it-IT.json +39 -74
  56. package/static/translations/ja-JP.json +39 -74
  57. package/static/translations/nl-NL.json +39 -74
  58. package/static/translations/no-NO.json +39 -74
  59. package/static/translations/pl-PL.json +39 -74
  60. package/static/translations/pt-BR.json +39 -74
  61. package/static/translations/pt-PT.json +39 -74
  62. package/static/translations/ro-RO.json +39 -74
  63. package/static/translations/ru-RU.json +39 -74
  64. package/static/translations/sv-SE.json +39 -74
  65. package/static/translations/tr-TR.json +39 -74
  66. package/static/translations/tsconfig.json +30 -67
  67. package/static/translations/uk-UA.json +39 -74
  68. package/utils/FeatureStyles.js +13 -18
  69. package/utils/IdentifyUtils.js +14 -11
  70. package/utils/SearchProviders.js +1 -1
@@ -86,7 +86,7 @@ var FeatureSearch = /*#__PURE__*/function (_React$Component) {
86
86
  }, /*#__PURE__*/React.createElement("option", {
87
87
  disabled: true,
88
88
  value: ""
89
- }, LocaleUtils.tr("featuresearch.select")), Object.entries(_this.state.providerGroups).map(function (_ref) {
89
+ }, LocaleUtils.tr("common.select")), Object.entries(_this.state.providerGroups).map(function (_ref) {
90
90
  var _ref2 = _slicedToArray(_ref, 2),
91
91
  group = _ref2[0],
92
92
  entries = _ref2[1];
@@ -165,7 +165,7 @@ var FeatureSearch = /*#__PURE__*/function (_React$Component) {
165
165
  }, /*#__PURE__*/React.createElement("option", {
166
166
  disabled: true,
167
167
  value: ""
168
- }, LocaleUtils.tr("featuresearch.select")), options.map(function (entry) {
168
+ }, LocaleUtils.tr("common.select")), options.map(function (entry) {
169
169
  var _entry$value, _entry$value2, _entry$label;
170
170
  return /*#__PURE__*/React.createElement("option", {
171
171
  key: (_entry$value = entry.value) !== null && _entry$value !== void 0 ? _entry$value : entry,
@@ -195,7 +195,7 @@ var FeatureSearch = /*#__PURE__*/function (_React$Component) {
195
195
  className: "feature-search-results"
196
196
  }, isEmpty(_this.state.searchResults) ? /*#__PURE__*/React.createElement("div", {
197
197
  className: "feature-search-noresults"
198
- }, LocaleUtils.tr("featuresearch.noresults")) : /*#__PURE__*/React.createElement(IdentifyViewer, {
198
+ }, LocaleUtils.tr("common.noresults")) : /*#__PURE__*/React.createElement(IdentifyViewer, {
199
199
  collapsible: true,
200
200
  displayResultTree: false,
201
201
  enableExport: _this.props.enableExport,
@@ -32,6 +32,7 @@ import React from 'react';
32
32
  import { connect } from 'react-redux';
33
33
  import polySelfIntersections from 'geojson-polygon-self-intersections';
34
34
  import isEmpty from 'lodash.isempty';
35
+ import omit from 'lodash.omit';
35
36
  import PropTypes from 'prop-types';
36
37
  import { LayerRole, removeLayer, addLayerFeatures, removeLayerFeatures, clearLayer } from '../actions/layers';
37
38
  import { changeRedliningState, resetRedliningState } from '../actions/redlining';
@@ -42,6 +43,7 @@ import ButtonBar from '../components/widgets/ButtonBar';
42
43
  import NumberInput from '../components/widgets/NumberInput';
43
44
  import Spinner from '../components/widgets/Spinner';
44
45
  import ConfigUtils from '../utils/ConfigUtils';
46
+ import { EXCLUDE_ATTRS, EXCLUDE_PROPS } from '../utils/IdentifyUtils';
45
47
  import LocaleUtils from '../utils/LocaleUtils';
46
48
  import MiscUtils from '../utils/MiscUtils';
47
49
  import VectorLayerUtils from '../utils/VectorLayerUtils';
@@ -68,7 +70,8 @@ import './style/Redlining.css';
68
70
  * "name": "<geomLinkName>", // Link name referenced in theme item
69
71
  * "title": "<geomLinkTitle>", // Link title, displayed in the selection combo
70
72
  * "geomType": ["<geomType>", "<geomType>"] // Supported geometry types (Point, LineString, Polygon)
71
- * "url": "<targetApplicationUrl>", // Application target URL, receiving the POST submit
73
+ * "format": "wkt|geojson", // Format of data to send to application
74
+ * "url": "<targetApplicationUrl>", // Application target URL, receiving the POST submit. Can contain the $username$ placeholder parameter.
72
75
  * "params": {"<key>": "<value>", ...} // Optional: additional form parameters to post to URL
73
76
  * "target": "<target>" | { // Optional: form POST target which to display the result
74
77
  * "iframedialog": true, // Use an iframe dialog
@@ -80,6 +83,10 @@ import './style/Redlining.css';
80
83
  * }
81
84
  * }
82
85
  * ```
86
+ * If you are using `qwc-services`, you will need to explicitly permit the geometry links in the `qwc-admin-gui` as follows:
87
+ *
88
+ * * Create and permit a `Plugin` resource with name `geometryLinks`
89
+ * * Create and permit `Plugin data` resources with name equal to `<geomLinkName>`
83
90
  */
84
91
  var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
85
92
  function GeometryDigitizer(props) {
@@ -109,7 +116,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
109
116
  _this.props.resetRedliningState();
110
117
  });
111
118
  _defineProperty(_this, "renderBody", function () {
112
- var _this$props$layers$fi, _geomLinkData$target, _geomLinkData$target2, _this$props$theme$plu;
119
+ var _this$props$layers$fi, _geomLinkData$target, _geomLinkData$target2, _this$props$theme$plu, _geomLinkData$url;
113
120
  var geomLinkData = _this.geometryLinkData(_this.state.geomLink);
114
121
  var activeButton = null;
115
122
  if (_this.state.pickGeomType) {
@@ -129,7 +136,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
129
136
  }
130
137
  } : {
131
138
  key: "Point",
132
- tooltip: LocaleUtils.tr("redlining.point"),
139
+ tooltip: LocaleUtils.tr("common.point"),
133
140
  icon: "point",
134
141
  data: {
135
142
  action: "Draw",
@@ -148,7 +155,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
148
155
  }
149
156
  } : {
150
157
  key: "LineString",
151
- tooltip: LocaleUtils.tr("redlining.line"),
158
+ tooltip: LocaleUtils.tr("common.line"),
152
159
  icon: "line",
153
160
  data: {
154
161
  action: "Draw",
@@ -158,7 +165,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
158
165
  disabled: !supportedGeomType.includes("LineString")
159
166
  }, {
160
167
  key: "Polygon",
161
- tooltip: LocaleUtils.tr("redlining.polygon"),
168
+ tooltip: LocaleUtils.tr("common.polygon"),
162
169
  icon: "polygon",
163
170
  data: {
164
171
  action: "Draw",
@@ -169,7 +176,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
169
176
  }];
170
177
  var editButtons = [{
171
178
  key: "Pick",
172
- tooltip: LocaleUtils.tr("redlining.pick"),
179
+ tooltip: LocaleUtils.tr("common.pick"),
173
180
  icon: "pick",
174
181
  data: {
175
182
  action: "Pick",
@@ -178,7 +185,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
178
185
  }
179
186
  }, {
180
187
  key: "Delete",
181
- tooltip: LocaleUtils.tr("redlining.delete"),
188
+ tooltip: LocaleUtils.tr("common.delete"),
182
189
  icon: "trash",
183
190
  data: {
184
191
  action: "Delete",
@@ -237,7 +244,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
237
244
  }
238
245
  })), /*#__PURE__*/React.createElement("div", {
239
246
  className: "redlining-groupcontrol"
240
- }, /*#__PURE__*/React.createElement("div", null, LocaleUtils.tr("redlining.pick")), /*#__PURE__*/React.createElement(ButtonBar, {
247
+ }, /*#__PURE__*/React.createElement("div", null, LocaleUtils.tr("common.pick")), /*#__PURE__*/React.createElement(ButtonBar, {
241
248
  active: activeButton,
242
249
  buttons: pickButtons,
243
250
  onClick: function onClick(key, data) {
@@ -271,7 +278,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
271
278
  value: entry
272
279
  }, _this.geometryLinkData(entry).title);
273
280
  })), /*#__PURE__*/React.createElement("form", {
274
- action: geomLinkData.url,
281
+ action: (_geomLinkData$url = geomLinkData.url) === null || _geomLinkData$url === void 0 ? void 0 : _geomLinkData$url.replace('$username$', ConfigUtils.getConfigProp("username") || ""),
275
282
  method: "post",
276
283
  onSubmit: _this.submitGeometryLink,
277
284
  target: target
@@ -335,7 +342,7 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
335
342
  className: "geomdigitizer-output-window-body"
336
343
  }, !_this.state.outputLoaded ? /*#__PURE__*/React.createElement("span", {
337
344
  className: "geomdigitizer-output-window-wait"
338
- }, /*#__PURE__*/React.createElement(Spinner, null), " ", /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("geomdigitizer.wait"))) : null, /*#__PURE__*/React.createElement("iframe", {
345
+ }, /*#__PURE__*/React.createElement(Spinner, null), " ", /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("common.loading"))) : null, /*#__PURE__*/React.createElement("iframe", {
339
346
  name: "geomdigitizer-output-window",
340
347
  onLoad: function onLoad() {
341
348
  return _this.setState({
@@ -492,19 +499,26 @@ var GeometryDigitizer = /*#__PURE__*/function (_React$Component) {
492
499
  }
493
500
  var data = _this.geometryLinkData(_this.state.geomLink);
494
501
  var supportedGeomType = data.geomType || [];
495
- var geometries = features.filter(function (feature) {
502
+ var supportedFeatures = features.filter(function (feature) {
496
503
  return supportedGeomType.includes(_this.state.bufferDistance > 0 ? "Polygon" : feature.geometry.type.replace(/^Multi/, ''));
497
- }).map(function (feature) {
498
- return VectorLayerUtils.geoJSONGeomToWkt(feature.geometry);
499
504
  });
500
- if (isEmpty(geometries)) {
505
+ if (isEmpty(supportedFeatures)) {
501
506
  ev.preventDefault();
502
507
  return;
503
- } else {
504
- ev.target.GEOMETRIES.value = geometries.join(";");
505
- ev.target.GEOMCOUNT.value = geometries.length;
506
- ev.target.BUFFERDIST.value = _this.state.bufferDistance;
507
508
  }
509
+ var geometries = (data.format || "wkt").toLowerCase() === "wkt" ? supportedFeatures.map(function (feature) {
510
+ return VectorLayerUtils.geoJSONGeomToWkt(feature.geometry);
511
+ }).join(";") : JSON.stringify({
512
+ type: "FeatureCollection",
513
+ features: supportedFeatures.map(function (feature) {
514
+ var newFeature = omit(feature, EXCLUDE_PROPS);
515
+ newFeature.properties = omit(newFeature.properties, EXCLUDE_ATTRS);
516
+ return newFeature;
517
+ })
518
+ });
519
+ ev.target.GEOMETRIES.value = geometries;
520
+ ev.target.GEOMCOUNT.value = supportedFeatures.length;
521
+ ev.target.BUFFERDIST.value = _this.state.bufferDistance;
508
522
  if (ev.target.target === "geomdigitizer-output-window") {
509
523
  _this.setState({
510
524
  outputWindowVisible: true,
@@ -230,7 +230,7 @@ var Identify = /*#__PURE__*/function (_React$Component) {
230
230
  });
231
231
  _defineProperty(_this, "parseResult", function (response, layer, format, clickPoint) {
232
232
  var ctrlPick = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
233
- var newResults = IdentifyUtils.parseResponse(response, layer, format, clickPoint, _this.props.map.projection, _this.props.featureInfoReturnsLayerName);
233
+ var newResults = IdentifyUtils.parseResponse(response, layer, format, clickPoint, _this.props.map.projection);
234
234
  // Merge with previous
235
235
  _this.setState(function (state) {
236
236
  var identifyResults = _objectSpread({}, state.identifyResults);
@@ -481,8 +481,6 @@ _defineProperty(Identify, "propTypes", {
481
481
  exitTaskOnResultsClose: PropTypes.bool,
482
482
  /** Whether to include the geometry in exported features. Default: `true`. */
483
483
  exportGeometry: PropTypes.bool,
484
- /** Whether to assume that XML GetFeatureInfo responses specify the technical layer name in the `name` attribute, rather than the layer title. */
485
- featureInfoReturnsLayerName: PropTypes.bool,
486
484
  /** Default window geometry with size, position and docking status. Positive position values (including '0') are related to top (InitialY) and left (InitialX), negative values (including '-0') to bottom (InitialY) and right (InitialX). */
487
485
  geometry: PropTypes.shape({
488
486
  initialWidth: PropTypes.number,
@@ -527,7 +525,6 @@ _defineProperty(Identify, "defaultProps", {
527
525
  resultDisplayMode: 'flat',
528
526
  resultGridSize: 200,
529
527
  replaceImageUrls: true,
530
- featureInfoReturnsLayerName: true,
531
528
  geometry: {
532
529
  initialWidth: 240,
533
530
  initialHeight: 320,
@@ -169,7 +169,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
169
169
  }
170
170
  }, /*#__PURE__*/React.createElement("table", {
171
171
  className: "options-table"
172
- }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.format")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
172
+ }, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("common.format")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
173
173
  onChange: _this.changeFormat,
174
174
  value: _this.state.selectedFormat
175
175
  }, _this.state.availableFormats.map(function (format) {
@@ -199,7 +199,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
199
199
  key: "size_" + idx,
200
200
  value: idx
201
201
  }, entry.name);
202
- })))) : null, scaleChooser && _this.state.pageSize !== null ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.scale")), /*#__PURE__*/React.createElement("td", null, scaleChooser)) : null, _this.props.dpis && _this.state.selectedFormat !== "application/dxf" ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.resolution")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
202
+ })))) : null, scaleChooser && _this.state.pageSize !== null ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapexport.scale")), /*#__PURE__*/React.createElement("td", null, scaleChooser)) : null, _this.props.dpis && _this.state.selectedFormat !== "application/dxf" ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("common.resolution")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
203
203
  onChange: _this.changeResolution,
204
204
  value: _this.state.dpi
205
205
  }, _this.props.dpis.map(function (dpi) {
@@ -227,7 +227,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
227
227
  type: "submit"
228
228
  }, _this.state.exporting ? /*#__PURE__*/React.createElement("span", {
229
229
  className: "mapexport-wait"
230
- }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("mapexport.wait")) : LocaleUtils.tr("mapexport.submit")))));
230
+ }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("common.wait")) : LocaleUtils.tr("common.export")))));
231
231
  });
232
232
  _defineProperty(_this, "renderPrintSelection", function () {
233
233
  if (_this.state.pageSize !== null) {
@@ -517,7 +517,7 @@ var MapExport = /*#__PURE__*/function (_React$Component) {
517
517
  key: "render",
518
518
  value: function render() {
519
519
  var _this2 = this;
520
- var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("print.maximize") : LocaleUtils.tr("print.minimize");
520
+ var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("window.maximize") : LocaleUtils.tr("window.minimize");
521
521
  var extraTitlebarContent = /*#__PURE__*/React.createElement(Icon, {
522
522
  className: "mapexport-minimize-maximize",
523
523
  icon: this.state.minimized ? 'chevron-down' : 'chevron-up',
@@ -290,12 +290,12 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
290
290
  var commitButtons = [{
291
291
  key: 'Save',
292
292
  icon: 'ok',
293
- label: LocaleUtils.tr("mapfilter.save"),
293
+ label: LocaleUtils.tr("common.save"),
294
294
  extraClasses: "button-accept"
295
295
  }, {
296
296
  key: 'Cancel',
297
297
  icon: 'remove',
298
- label: LocaleUtils.tr("mapfilter.cancel"),
298
+ label: LocaleUtils.tr("common.cancel"),
299
299
  extraClasses: "button-reject"
300
300
  }];
301
301
  var sampleFilters = '["field", "=", "val"]\n' + '[["field", ">", "val1"], "and", ["field", "<", "val2"]]';
@@ -389,7 +389,7 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
389
389
  value: _this.state.filters[config.id].values[field.id]
390
390
  }, !field.defaultValue ? /*#__PURE__*/React.createElement("option", {
391
391
  value: ""
392
- }, LocaleUtils.tr("mapfilter.select")) : null, field.inputConfig.options.map(function (entry) {
392
+ }, LocaleUtils.tr("common.select")) : null, field.inputConfig.options.map(function (entry) {
393
393
  var _entry$value, _entry$value2, _entry$label;
394
394
  return /*#__PURE__*/React.createElement("option", {
395
395
  key: (_entry$value = entry.value) !== null && _entry$value !== void 0 ? _entry$value : entry,
@@ -483,7 +483,7 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
483
483
  onChange: function onChange(value) {
484
484
  return _this.updateCustomFilter(key, 'layer', value);
485
485
  },
486
- placeholder: LocaleUtils.tr("mapfilter.selectlayer"),
486
+ placeholder: LocaleUtils.tr("common.selectlayer"),
487
487
  value: entry.layer
488
488
  }, layerNames.map(function (layerName) {
489
489
  return /*#__PURE__*/React.createElement("div", {
@@ -518,19 +518,19 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
518
518
  var geomFilter = _this.state.geomFilter;
519
519
  var filterButtons = [{
520
520
  key: "Polygon",
521
- tooltip: LocaleUtils.tr("redlining.polygon"),
521
+ tooltip: LocaleUtils.tr("common.polygon"),
522
522
  icon: "polygon",
523
- label: LocaleUtils.tr("redlining.polygon")
523
+ label: LocaleUtils.tr("common.polygon")
524
524
  }, {
525
525
  key: "Circle",
526
- tooltip: LocaleUtils.tr("redlining.circle"),
526
+ tooltip: LocaleUtils.tr("common.circle"),
527
527
  icon: "circle",
528
- label: LocaleUtils.tr("redlining.circle")
528
+ label: LocaleUtils.tr("common.circle")
529
529
  }, {
530
530
  key: "Pick",
531
- tooltip: LocaleUtils.tr("redlining.pick"),
531
+ tooltip: LocaleUtils.tr("common.pick"),
532
532
  icon: "pick",
533
- label: LocaleUtils.tr("redlining.pick")
533
+ label: LocaleUtils.tr("common.pick")
534
534
  }];
535
535
  var active = geomFilter.picking ? "Pick" : geomFilter.geomType || "";
536
536
  return /*#__PURE__*/React.createElement("div", {
@@ -57,7 +57,7 @@ var NewsPopup = /*#__PURE__*/function (_React$Component) {
57
57
  className: "newspopup-dialog-popup-buttonbar"
58
58
  }, /*#__PURE__*/React.createElement("button", {
59
59
  onClick: _this.closeDialog
60
- }, LocaleUtils.tr("newspopup.dialogclose")), /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
60
+ }, LocaleUtils.tr("common.close")), /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
61
61
  onChange: function onChange(ev) {
62
62
  return _this.setState({
63
63
  dontShowAgain: ev.target.checked
@@ -23,14 +23,17 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
23
23
  import React from 'react';
24
24
  import { connect } from 'react-redux';
25
25
  import axios from 'axios';
26
+ import isEqual from 'lodash.isequal';
26
27
  import ol from 'openlayers';
27
28
  import PropTypes from 'prop-types';
29
+ import { zoomToExtent } from '../actions/map';
28
30
  import { setCurrentTask } from '../actions/task';
29
31
  import Icon from '../components/Icon';
30
32
  import ResizeableWindow from '../components/ResizeableWindow';
31
33
  import LayerRegistry from '../components/map/layers/index';
32
34
  import InputContainer from '../components/widgets/InputContainer';
33
35
  import ConfigUtils from '../utils/ConfigUtils';
36
+ import CoordinatesUtils from '../utils/CoordinatesUtils';
34
37
  import LayerUtils from '../utils/LayerUtils';
35
38
  import LocaleUtils from '../utils/LocaleUtils';
36
39
  import MapUtils from '../utils/MapUtils';
@@ -116,17 +119,6 @@ var ObliqueView = /*#__PURE__*/function (_React$Component) {
116
119
  _this.setState({
117
120
  currentZoom: zoom
118
121
  });
119
- _this.map.on('moveend', function () {
120
- _this.setState(function (state) {
121
- var newZoom = _this.map.getView().getZoom();
122
- if (newZoom !== state.currentZoom) {
123
- return {
124
- currentZoom: newZoom
125
- };
126
- }
127
- return null;
128
- });
129
- });
130
122
  var layers = [];
131
123
  var themeConfig = _this.props.theme.obliqueDatasets.find(function (entry) {
132
124
  return entry.name === _this.state.selectedDataset;
@@ -198,6 +190,33 @@ var ObliqueView = /*#__PURE__*/function (_React$Component) {
198
190
  s: 180
199
191
  }[_this.state.currentDirection];
200
192
  });
193
+ _defineProperty(_this, "sync2DExtent", function () {
194
+ if (!_this.state.datasetConfig) {
195
+ return;
196
+ }
197
+ _this.setState(function (state) {
198
+ var center = CoordinatesUtils.reproject(_this.props.map.center, _this.props.map.projection, state.datasetConfig.crs);
199
+ var resolution = MapUtils.computeForZoom(_this.props.map.resolutions, _this.props.map.zoom);
200
+ _this.map.getView().setCenter(center);
201
+ _this.map.getView().setResolution(resolution);
202
+ return {
203
+ currentCenter: center,
204
+ currentZoom: _this.map.getView().getZoom()
205
+ };
206
+ });
207
+ });
208
+ _defineProperty(_this, "trackFocus", function (ev) {
209
+ var _this$map, _this$map$getTargetEl, _mapEl$contains, _mapObliqueEl$contain;
210
+ var mapEl = document.getElementById("map");
211
+ var mapObliqueEl = (_this$map = _this.map) === null || _this$map === void 0 || (_this$map$getTargetEl = _this$map.getTargetElement) === null || _this$map$getTargetEl === void 0 ? void 0 : _this$map$getTargetEl.call(_this$map);
212
+ if (mapEl !== null && mapEl !== void 0 && (_mapEl$contains = mapEl.contains) !== null && _mapEl$contains !== void 0 && _mapEl$contains.call(mapEl, document.activeElement)) {
213
+ _this.focusedMap = "map";
214
+ } else if (mapObliqueEl !== null && mapObliqueEl !== void 0 && (_mapObliqueEl$contain = mapObliqueEl.contains) !== null && _mapObliqueEl$contain !== void 0 && _mapObliqueEl$contain.call(mapObliqueEl, document.activeElement)) {
215
+ _this.focusedMap = "mapOblique";
216
+ } else {
217
+ _this.focusedMap = null;
218
+ }
219
+ });
201
220
  var controls = ol.control.defaults({
202
221
  zoom: false,
203
222
  attribution: false,
@@ -210,15 +229,39 @@ var ObliqueView = /*#__PURE__*/function (_React$Component) {
210
229
  controls: controls,
211
230
  interactions: interactions
212
231
  });
213
- _this.map.on('moveend', _this.searchClosestImage);
214
232
  _this.map.on('rotateend', _this.searchClosestImage);
233
+ _this.map.on('moveend', function () {
234
+ _this.searchClosestImage();
235
+ _this.setState(function (state) {
236
+ var newZoom = _this.map.getView().getZoom();
237
+ var newCenter = _this.map.getView().getCenter();
238
+ if (newZoom !== state.currentZoom || !isEqual(newCenter, state.currentCenter)) {
239
+ return {
240
+ currentZoom: newZoom,
241
+ currentCenter: newCenter
242
+ };
243
+ }
244
+ return null;
245
+ });
246
+ });
215
247
  _this.closestImage = null;
216
248
  _this.obliqueImageryLayer = null;
217
249
  _this.state = ObliqueView.defaultState;
250
+ _this.focusedMap = null;
218
251
  return _this;
219
252
  }
220
253
  _inherits(ObliqueView, _React$Component);
221
254
  return _createClass(ObliqueView, [{
255
+ key: "componentDidMount",
256
+ value: function componentDidMount() {
257
+ window.addEventListener('focus', this.trackFocus, true);
258
+ }
259
+ }, {
260
+ key: "componentWillUnmount",
261
+ value: function componentWillUnmount() {
262
+ window.removeEventListener('focus', this.trackFocus);
263
+ }
264
+ }, {
222
265
  key: "componentDidUpdate",
223
266
  value: function componentDidUpdate(prevProps, prevState) {
224
267
  if (this.props.active && !prevProps.active) {
@@ -256,6 +299,13 @@ var ObliqueView = /*#__PURE__*/function (_React$Component) {
256
299
  var _this$map$getView2, _this$map$getView2$se;
257
300
  (_this$map$getView2 = this.map.getView()) === null || _this$map$getView2 === void 0 || (_this$map$getView2$se = _this$map$getView2.setZoom) === null || _this$map$getView2$se === void 0 || _this$map$getView2$se.call(_this$map$getView2, this.state.currentZoom);
258
301
  }
302
+ if (this.state.viewsLocked && this.state.datasetConfig) {
303
+ if (this.focusedMap === "map" && this.props.map.bbox !== prevProps.map.bbox) {
304
+ this.sync2DExtent();
305
+ } else if (this.focusedMap === "mapOblique" && (this.state.currentCenter !== prevState.currentCenter || this.state.currentZoom !== prevState.currentZoom)) {
306
+ this.props.zoomToExtent(this.map.getView().calculateExtent(), this.state.datasetConfig.crs);
307
+ }
308
+ }
259
309
  }
260
310
  }, {
261
311
  key: "render",
@@ -265,8 +315,25 @@ var ObliqueView = /*#__PURE__*/function (_React$Component) {
265
315
  return null;
266
316
  }
267
317
  var rot = this.getRotation();
318
+ var extraControls = [{
319
+ icon: "sync",
320
+ callback: this.sync2DExtent,
321
+ title: LocaleUtils.tr("common.sync2dview")
322
+ }, {
323
+ icon: "lock",
324
+ callback: function callback() {
325
+ return _this2.setState(function (state) {
326
+ return {
327
+ viewsLocked: !state.viewsLocked
328
+ };
329
+ });
330
+ },
331
+ title: LocaleUtils.tr("common.lock2dview"),
332
+ active: this.state.viewsLocked
333
+ }];
268
334
  return /*#__PURE__*/React.createElement(ResizeableWindow, {
269
335
  dockable: this.props.geometry.side,
336
+ extraControls: extraControls,
270
337
  icon: "oblique",
271
338
  initialHeight: this.props.geometry.initialHeight,
272
339
  initialWidth: this.props.geometry.initialWidth,
@@ -371,13 +438,14 @@ _defineProperty(ObliqueView, "propTypes", {
371
438
  }),
372
439
  /** The initial map scale. */
373
440
  initialScale: PropTypes.number,
374
- mapBbox: PropTypes.object,
441
+ map: PropTypes.object,
375
442
  projection: PropTypes.string,
376
443
  /** A list of allowed map scales, in decreasing order. */
377
444
  scales: PropTypes.arrayOf(PropTypes.number),
378
445
  setCurrentTask: PropTypes.func,
379
446
  theme: PropTypes.object,
380
- themes: PropTypes.object
447
+ themes: PropTypes.object,
448
+ zoomToExtent: PropTypes.func
381
449
  });
382
450
  _defineProperty(ObliqueView, "defaultProps", {
383
451
  geometry: {
@@ -396,15 +464,18 @@ _defineProperty(ObliqueView, "defaultState", {
396
464
  selectedDataset: null,
397
465
  datasetConfig: null,
398
466
  currentDirection: null,
399
- currentZoom: 0
467
+ currentZoom: 0,
468
+ currentCenter: null,
469
+ viewsLocked: false
400
470
  });
401
471
  export default connect(function (state) {
402
472
  return {
403
473
  active: state.task.id === "ObliqueView",
404
- mapBbox: state.map.bbox,
474
+ map: state.map,
405
475
  theme: state.theme.current,
406
476
  themes: state.theme.themes
407
477
  };
408
478
  }, {
409
- setCurrentTask: setCurrentTask
479
+ setCurrentTask: setCurrentTask,
480
+ zoomToExtent: zoomToExtent
410
481
  })(ObliqueView);
package/plugins/Print.js CHANGED
@@ -255,7 +255,7 @@ var Print = /*#__PURE__*/function (_React$Component) {
255
255
  key: item.name,
256
256
  value: item.name
257
257
  }, _this.translateLayoutName(item));
258
- })))), _this.props.formats.length > 1 ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("print.format")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
258
+ })))), _this.props.formats.length > 1 ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("common.format")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
259
259
  disabled: _this.state.printSeriesEnabled,
260
260
  name: "FORMAT",
261
261
  onChange: _this.formatChanged,
@@ -287,7 +287,7 @@ var Print = /*#__PURE__*/function (_React$Component) {
287
287
  disabled: true,
288
288
  placeholder: LocaleUtils.tr("print.pickatlasfeature", _this.state.layout.atlasCoverageLayer),
289
289
  type: "text"
290
- }))) : null, isEmpty(_this.state.atlasFeatures) ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("print.scale")), /*#__PURE__*/React.createElement("td", null, scaleChooser)) : null, resolutionChooser ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("print.resolution")), /*#__PURE__*/React.createElement("td", null, resolutionChooser)) : null, _this.props.displayRotation ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("print.rotation")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(InputContainer, null, /*#__PURE__*/React.createElement(NumberInput, {
290
+ }))) : null, isEmpty(_this.state.atlasFeatures) ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("print.scale")), /*#__PURE__*/React.createElement("td", null, scaleChooser)) : null, resolutionChooser ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("common.resolution")), /*#__PURE__*/React.createElement("td", null, resolutionChooser)) : null, _this.props.displayRotation ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("print.rotation")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(InputContainer, null, /*#__PURE__*/React.createElement(NumberInput, {
291
291
  decimals: 1,
292
292
  mobile: true,
293
293
  name: mapName + ":rotation",
@@ -338,7 +338,7 @@ var Print = /*#__PURE__*/function (_React$Component) {
338
338
  value: _this.state.printSeriesOverlap
339
339
  }), /*#__PURE__*/React.createElement("span", {
340
340
  role: "suffix"
341
- }, _this.state.printSeriesOverlap, "\xA0%")))) : null, !_this.props.inlinePrintOutput && _this.state.printSeriesEnabled ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("print.download")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
341
+ }, _this.state.printSeriesOverlap, "\xA0%")))) : null, !_this.props.inlinePrintOutput && _this.state.printSeriesEnabled ? /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("common.download")), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("select", {
342
342
  onChange: _this.changeDownloadMode,
343
343
  role: "input",
344
344
  value: _this.state.downloadMode || ""
@@ -426,7 +426,7 @@ var Print = /*#__PURE__*/function (_React$Component) {
426
426
  type: "submit"
427
427
  }, _this.state.printing ? /*#__PURE__*/React.createElement("span", {
428
428
  className: "print-wait"
429
- }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("print.wait")) : LocaleUtils.tr("print.submit")))));
429
+ }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("common.wait")) : LocaleUtils.tr("print.submit")))));
430
430
  });
431
431
  _defineProperty(_this, "renderPrintLabelField", function (label, opts) {
432
432
  var defaultValue = opts.defaultValue || "";
@@ -562,7 +562,7 @@ var Print = /*#__PURE__*/function (_React$Component) {
562
562
  _defineProperty(_this, "renderPrintOutputWindow", function () {
563
563
  var extraControls = [{
564
564
  icon: 'save',
565
- title: LocaleUtils.tr('print.save'),
565
+ title: LocaleUtils.tr('common.save'),
566
566
  callback: _this.savePrintOutput
567
567
  }];
568
568
  return /*#__PURE__*/React.createElement(ResizeableWindow, {
@@ -585,7 +585,7 @@ var Print = /*#__PURE__*/function (_React$Component) {
585
585
  className: "print-output-window-body"
586
586
  }, !_this.state.outputLoaded ? /*#__PURE__*/React.createElement("span", {
587
587
  className: "print-output-window-wait"
588
- }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("print.wait")) : null, /*#__PURE__*/React.createElement("iframe", {
588
+ }, /*#__PURE__*/React.createElement(Spinner, null), " ", LocaleUtils.tr("common.wait")) : null, /*#__PURE__*/React.createElement("iframe", {
589
589
  name: "print-output-window",
590
590
  src: _this.state.pdfDataUrl
591
591
  })));
@@ -844,7 +844,7 @@ var Print = /*#__PURE__*/function (_React$Component) {
844
844
  key: "render",
845
845
  value: function render() {
846
846
  var _this3 = this;
847
- var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("print.maximize") : LocaleUtils.tr("print.minimize");
847
+ var minMaxTooltip = this.state.minimized ? LocaleUtils.tr("window.maximize") : LocaleUtils.tr("window.minimize");
848
848
  var extraTitlebarContent = /*#__PURE__*/React.createElement(Icon, {
849
849
  className: "print-minimize-maximize",
850
850
  icon: this.state.minimized ? 'chevron-down' : 'chevron-up',