qwc2 2026.9.17 → 2026.9.27

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 (44) hide show
  1. package/components/QtDesignerForm.js +1 -1
  2. package/components/SegmentInput.js +116 -0
  3. package/components/StandardApp.js +10 -0
  4. package/components/style/PluginsContainer.css +1 -0
  5. package/components/style/SegmentInput.css +11 -0
  6. package/package.json +1 -1
  7. package/plugins/Authentication.js +3 -13
  8. package/plugins/Print.js +102 -32
  9. package/plugins/VisibilityPreset.js +10 -10
  10. package/plugins/map/ConstraintInteraction.js +95 -0
  11. package/plugins/map/RedliningSupport.js +31 -5
  12. package/plugins/map/SnappingSupport.js +4 -2
  13. package/plugins/map/style/SnappingSupport.css +6 -0
  14. package/reducers/editing.js +4 -4
  15. package/scripts/themesConfig.py +3 -3
  16. package/static/translations/bg-BG.json +1 -0
  17. package/static/translations/ca-ES.json +1 -0
  18. package/static/translations/cs-CZ.json +1 -0
  19. package/static/translations/de-CH.json +1 -0
  20. package/static/translations/de-DE.json +1 -0
  21. package/static/translations/en-US.json +1 -0
  22. package/static/translations/es-ES.json +1 -0
  23. package/static/translations/fi-FI.json +1 -0
  24. package/static/translations/fr-FR.json +1 -0
  25. package/static/translations/hu-HU.json +1 -0
  26. package/static/translations/it-IT.json +1 -0
  27. package/static/translations/ja-JP.json +1 -0
  28. package/static/translations/nl-NL.json +1 -0
  29. package/static/translations/no-NO.json +1 -0
  30. package/static/translations/pl-PL.json +1 -0
  31. package/static/translations/pt-BR.json +1 -0
  32. package/static/translations/pt-PT.json +1 -0
  33. package/static/translations/ro-RO.json +1 -0
  34. package/static/translations/ru-RU.json +1 -0
  35. package/static/translations/sv-SE.json +1 -0
  36. package/static/translations/tr-TR.json +1 -0
  37. package/static/translations/tsconfig.json +1 -0
  38. package/static/translations/uk-UA.json +1 -0
  39. package/utils/ConfigUtils.js +25 -12
  40. package/utils/CoordinatesUtils.js +30 -0
  41. package/utils/MeasureUtils.js +19 -0
  42. package/utils/MiscUtils.js +8 -0
  43. package/utils/PermaLinkUtils.js +9 -0
  44. package/utils/PluginStore.js +8 -0
@@ -907,7 +907,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
907
907
  return _this.props.removeRelationRecord(relDataset, idx);
908
908
  }
909
909
  })) : null);
910
- })))), !_this.props.readOnly && editPermissions.creatable !== false ? /*#__PURE__*/React.createElement(ButtonBar, {
910
+ })))), !_this.props.readOnly && editPermissions.creatable !== false && editPermissions.geomreadonly !== true ? /*#__PURE__*/React.createElement(ButtonBar, {
911
911
  buttons: addButtons,
912
912
  onClick: _this.addRelationRecordAction
913
913
  }) : null, /*#__PURE__*/React.createElement("div", {
@@ -0,0 +1,116 @@
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
+ import React from 'react';
16
+ import ReactDOM from 'react-dom';
17
+ import PropTypes from 'prop-types';
18
+ import ConfigUtils from '../utils/ConfigUtils';
19
+ import LocaleUtils from '../utils/LocaleUtils';
20
+ import MeasureUtils from '../utils/MeasureUtils';
21
+ import Icon from './Icon';
22
+ import { BottomToolPortalContext } from './PluginsContainer';
23
+ import NumberInput from './widgets/NumberInput';
24
+ import './style/SegmentInput.css';
25
+ var DefaultUnit = {
26
+ metric: 'm',
27
+ imperial: 'ft'
28
+ };
29
+ var SegmentInput = /*#__PURE__*/function (_React$Component) {
30
+ function SegmentInput() {
31
+ var _ref, _DefaultUnit$_this$pr;
32
+ var _this;
33
+ _classCallCheck(this, SegmentInput);
34
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
35
+ args[_key] = arguments[_key];
36
+ }
37
+ _this = _callSuper(this, SegmentInput, [].concat(args));
38
+ _defineProperty(_this, "state", {
39
+ enabled: false,
40
+ distance: null,
41
+ unit: (_ref = (_DefaultUnit$_this$pr = DefaultUnit[_this.props.lenUnit]) !== null && _DefaultUnit$_this$pr !== void 0 ? _DefaultUnit$_this$pr : _this.props.lenUnit) !== null && _ref !== void 0 ? _ref : 'm'
42
+ });
43
+ _defineProperty(_this, "toggle", function () {
44
+ _this.setState(function (state) {
45
+ return {
46
+ enabled: !state.enabled
47
+ };
48
+ });
49
+ });
50
+ return _this;
51
+ }
52
+ _inherits(SegmentInput, _React$Component);
53
+ return _createClass(SegmentInput, [{
54
+ key: "componentDidUpdate",
55
+ value: function componentDidUpdate(prevProps, prevState) {
56
+ if (this.props.constraintInteraction !== prevProps.constraintInteraction || this.state !== prevState) {
57
+ var _this$state = this.state,
58
+ enabled = _this$state.enabled,
59
+ distance = _this$state.distance,
60
+ unit = _this$state.unit;
61
+ this.props.constraintInteraction.setDistance(enabled && distance !== null ? MeasureUtils.convertLength(distance, unit, 'm') : null);
62
+ }
63
+ }
64
+ }, {
65
+ key: "render",
66
+ value: function render() {
67
+ var _this2 = this;
68
+ var decimals = ConfigUtils.getConfigProp("measurementPrecision", null, 2);
69
+ var label = LocaleUtils.tr("redlining.segmentdistance");
70
+ return /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
71
+ className: "segment-input"
72
+ }, /*#__PURE__*/React.createElement("span", {
73
+ className: "segment-input-label"
74
+ }, label), /*#__PURE__*/React.createElement("div", {
75
+ className: "controlgroup"
76
+ }, /*#__PURE__*/React.createElement("button", {
77
+ className: "button" + (this.state.enabled ? " pressed" : ""),
78
+ onClick: this.toggle,
79
+ title: label
80
+ }, /*#__PURE__*/React.createElement(Icon, {
81
+ icon: "measure_line"
82
+ })), this.state.enabled ? /*#__PURE__*/React.createElement(NumberInput, {
83
+ decimals: decimals,
84
+ max: 99999,
85
+ min: Math.pow(10, -decimals),
86
+ onChange: function onChange(distance) {
87
+ return _this2.setState({
88
+ distance: distance
89
+ });
90
+ },
91
+ value: this.state.distance
92
+ }) : null, this.state.enabled ? /*#__PURE__*/React.createElement("select", {
93
+ onChange: function onChange(ev) {
94
+ return _this2.setState({
95
+ unit: ev.target.value
96
+ });
97
+ },
98
+ value: this.state.unit
99
+ }, /*#__PURE__*/React.createElement("option", {
100
+ value: "m"
101
+ }, "m"), /*#__PURE__*/React.createElement("option", {
102
+ value: "ft"
103
+ }, "ft"), /*#__PURE__*/React.createElement("option", {
104
+ value: "km"
105
+ }, "km"), /*#__PURE__*/React.createElement("option", {
106
+ value: "mi"
107
+ }, "mi")) : null)), this.context);
108
+ }
109
+ }]);
110
+ }(React.Component);
111
+ _defineProperty(SegmentInput, "contextType", BottomToolPortalContext);
112
+ _defineProperty(SegmentInput, "propTypes", {
113
+ constraintInteraction: PropTypes.object,
114
+ lenUnit: PropTypes.string
115
+ });
116
+ export { SegmentInput as default };
@@ -303,6 +303,13 @@ var StandardApp = /*#__PURE__*/function (_React$Component2) {
303
303
  config.plugins.mobile = completePluginConfig(deepmerge(commonConfig, mobileConfig));
304
304
  delete config.plugins.common;
305
305
 
306
+ // Redirect to login before rendering, so the viewer never flashes
307
+ var authConfig = ConfigUtils.getPluginConfig("Authentication").cfg;
308
+ if (authConfig !== null && authConfig !== void 0 && authConfig.requireLogin && !ConfigUtils.getConfigProp("username")) {
309
+ window.location.href = MiscUtils.loginUrl(authConfig.clearLayerParam);
310
+ return;
311
+ }
312
+
306
313
  // Add projections from config
307
314
  var _iterator = _createForOfIteratorHelper(config.projections || []),
308
315
  _step;
@@ -369,6 +376,9 @@ var StandardApp = /*#__PURE__*/function (_React$Component2) {
369
376
  key: "componentWillUnmount",
370
377
  value: function componentWillUnmount() {
371
378
  window.removeEventListener('resize', this.computeVh);
379
+ UrlParams.cancelPendingUpdates();
380
+ PluginStore.reset();
381
+ ConfigUtils.reset();
372
382
  }
373
383
  }, {
374
384
  key: "render",
@@ -39,6 +39,7 @@ div.map-bottom-tool-container > div {
39
39
  display: flex;
40
40
  flex-wrap: wrap;
41
41
  justify-content: center;
42
+ align-items: flex-end;
42
43
  margin-bottom: -1px;
43
44
  pointer-events: initial;
44
45
  padding: 0.25em 0.5em;
@@ -0,0 +1,11 @@
1
+ div.segment-input {
2
+ order: 1;
3
+ display: flex;
4
+ flex-direction: column;
5
+ align-items: center;
6
+ }
7
+
8
+ span.segment-input-label {
9
+ font-size: 85%;
10
+ white-space: nowrap;
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2026.09.17",
3
+ "version": "2026.09.27",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -24,10 +24,10 @@ import React from 'react';
24
24
  import ReactDOM from 'react-dom';
25
25
  import { connect } from 'react-redux';
26
26
  import PropTypes from 'prop-types';
27
- import url from 'url';
28
27
  import Icon from '../components/Icon';
29
28
  import { AppInfosPortalContext } from '../components/PluginsContainer';
30
29
  import ConfigUtils from '../utils/ConfigUtils';
30
+ import MiscUtils from '../utils/MiscUtils';
31
31
  import './style/Authentication.css';
32
32
 
33
33
  /**
@@ -41,12 +41,7 @@ var Authentication = /*#__PURE__*/function (_React$Component) {
41
41
  _classCallCheck(this, Authentication);
42
42
  _this = _callSuper(this, Authentication, [props]);
43
43
  _defineProperty(_this, "showLogin", function () {
44
- var urlObj = url.parse(window.location.href, true);
45
- if (_this.props.clearLayerParam) {
46
- delete urlObj.query.l;
47
- }
48
- urlObj.search = undefined;
49
- window.location.href = ConfigUtils.getConfigProp("authServiceUrl") + "login?url=" + encodeURIComponent(url.format(urlObj));
44
+ window.location.href = MiscUtils.loginUrl(_this.props.clearLayerParam);
50
45
  });
51
46
  _defineProperty(_this, "resetIdleTimer", function () {
52
47
  if (_this.idleTimer) {
@@ -55,9 +50,7 @@ var Authentication = /*#__PURE__*/function (_React$Component) {
55
50
  }
56
51
  });
57
52
  _defineProperty(_this, "idleAutologout", function () {
58
- var urlObj = url.parse(window.location.href, true);
59
- urlObj.search = undefined;
60
- var loginUrl = ConfigUtils.getConfigProp("authServiceUrl") + "login?url=" + encodeURIComponent(url.format(urlObj));
53
+ var loginUrl = MiscUtils.loginUrl();
61
54
  window.location.href = ConfigUtils.getConfigProp("authServiceUrl") + "logout?url=" + encodeURIComponent(loginUrl);
62
55
  });
63
56
  _this.idleTimer = null;
@@ -68,9 +61,6 @@ var Authentication = /*#__PURE__*/function (_React$Component) {
68
61
  key: "componentDidMount",
69
62
  value: function componentDidMount() {
70
63
  var username = ConfigUtils.getConfigProp("username");
71
- if (this.props.requireLogin && !username) {
72
- this.showLogin();
73
- }
74
64
  if (this.props.idleTimeout && username) {
75
65
  this.idleTimer = setTimeout(this.idleAutologout, this.props.idleTimeout * 1000);
76
66
  window.addEventListener('keydown', this.resetIdleTimer, {
package/plugins/Print.js CHANGED
@@ -672,8 +672,42 @@ var Print = /*#__PURE__*/function (_React$Component) {
672
672
  selectedFormat: ev.target.value
673
673
  });
674
674
  });
675
- _defineProperty(_this, "print", function (ev) {
675
+ _defineProperty(_this, "presetLayersAndStyles", function (presetName) {
676
676
  var _this$props$theme$vis;
677
+ var preset = ((_this$props$theme$vis = _this.props.theme.visibilityPresets) !== null && _this$props$theme$vis !== void 0 ? _this$props$theme$vis : {})[presetName];
678
+ if (!preset) {
679
+ return null;
680
+ }
681
+ // Desktop resolves a theme through mapThemeVisibleLayers, which orders the
682
+ // theme's layers by the project layer order rather than by the order they
683
+ // were captured in. Entries without a style are checked group nodes, which
684
+ // are not requestable layers.
685
+ var themeLayer = _this.props.layers.find(function (layer) {
686
+ return layer.role === LayerRole.THEME;
687
+ });
688
+ var layerOrder = LayerUtils.getSublayerNames(themeLayer !== null && themeLayer !== void 0 ? themeLayer : {});
689
+ var entries = Object.entries(preset).filter(function (_ref3) {
690
+ var _ref4 = _slicedToArray(_ref3, 2),
691
+ options = _ref4[1];
692
+ return options.checked && options.style !== undefined;
693
+ }).map(function (_ref5) {
694
+ var _ref6 = _slicedToArray(_ref5, 2),
695
+ layerPath = _ref6[0],
696
+ options = _ref6[1];
697
+ return [layerPath.split("/").slice(-1)[0], options.style];
698
+ }).sort(function (a, b) {
699
+ return layerOrder.indexOf(a[0]) - layerOrder.indexOf(b[0]);
700
+ }).reverse();
701
+ return {
702
+ layers: entries.map(function (entry) {
703
+ return entry[0];
704
+ }).join(","),
705
+ styles: entries.map(function (entry) {
706
+ return entry[1];
707
+ }).join(",")
708
+ };
709
+ });
710
+ _defineProperty(_this, "print", function (ev) {
677
711
  ev.preventDefault();
678
712
  _this.setState({
679
713
  printing: true
@@ -692,35 +726,71 @@ var Print = /*#__PURE__*/function (_React$Component) {
692
726
 
693
727
  // Add base print params
694
728
  var printParams = LayerUtils.collectPrintParams(_this.props.layers, _this.props.theme, _this.state.scale, mapCrs, _this.props.printExternalLayers);
695
- Object.entries(printParams).forEach(function (_ref3) {
696
- var _ref4 = _slicedToArray(_ref3, 2),
697
- key = _ref4[0],
698
- value = _ref4[1];
729
+ Object.entries(printParams).forEach(function (_ref7) {
730
+ var _ref8 = _slicedToArray(_ref7, 2),
731
+ key = _ref8[0],
732
+ value = _ref8[1];
699
733
  formData[key] = value;
700
734
  });
701
735
  formData[mapName + ":LAYERS"] = printParams.LAYERS;
702
736
  formData[mapName + ":STYLES"] = printParams.STYLES;
703
737
  formData[mapName + ":FILTER"] = printParams.FILTER;
704
738
  formData[mapName + ":FILTER_GEOM"] = printParams.FILTER_GEOM;
705
- if (_this.state.layout.map.followPresetName in ((_this$props$theme$vis = _this.props.theme.visibilityPresets) !== null && _this$props$theme$vis !== void 0 ? _this$props$theme$vis : {})) {
706
- var preset = _this.props.theme.visibilityPresets[_this.state.layout.map.followPresetName];
707
- var layers = [];
708
- var styles = [];
709
- Object.entries(preset).forEach(function (_ref5) {
710
- var _ref6 = _slicedToArray(_ref5, 2),
711
- layerPath = _ref6[0],
712
- options = _ref6[1];
713
- if (options.visible) {
714
- layers.push(layerPath.split("/").slice(-1)[0]);
715
- styles.push(options.style);
716
- }
717
- });
718
- formData.LAYERS = layers.join(",");
719
- formData.STYLES = styles.join(",");
720
- formData[mapName + ":LAYERS"] = layers.join(",");
721
- formData[mapName + ":STYLES"] = styles.join(",");
739
+ var mainPreset = _this.presetLayersAndStyles(_this.state.layout.map.followPresetName);
740
+ if (mainPreset) {
741
+ formData.LAYERS = mainPreset.layers;
742
+ formData.STYLES = mainPreset.styles;
743
+ formData[mapName + ":LAYERS"] = mainPreset.layers;
744
+ formData[mapName + ":STYLES"] = mainPreset.styles;
745
+ // The theme's own styles carry the opacity, as they do on the desktop.
746
+ // The opacities collected from the client layer tree describe a different
747
+ // layer list and are applied positionally by the server, so drop them.
748
+ delete formData.OPACITIES;
749
+ delete formData.COLORS;
722
750
  }
723
751
 
752
+ // Frozen layout maps: the server drops any layout map the request carries no
753
+ // extent for, so send each one the extent stored in the layout
754
+ (_this.state.layout.fixedMaps || []).forEach(function (fixedMap) {
755
+ var extent = fixedMap.extent;
756
+ // A map item with its own CRS keeps that CRS on the server, which assigns
757
+ // the extent to it verbatim, so the saved extent is sent unchanged
758
+ if (!fixedMap.ownCrs && fixedMap.crs && fixedMap.crs !== mapCrs) {
759
+ extent = CoordinatesUtils.reprojectBboxDensified(extent, fixedMap.crs, mapCrs);
760
+ if (!extent) {
761
+ /* eslint-disable-next-line */
762
+ console.warn("Print: cannot reproject the extent of " + fixedMap.name + " from " + fixedMap.crs + " to " + mapCrs + ", the map will be omitted from the printed layout");
763
+ return;
764
+ }
765
+ // The server resizes the layout item to the aspect of the extent it
766
+ // receives, so restore the aspect of the authored on-page rectangle
767
+ // by growing the deficient axis about the centre
768
+ var targetAspect = fixedMap.height / fixedMap.width;
769
+ var width = extent[2] - extent[0];
770
+ var height = extent[3] - extent[1];
771
+ if (height / width > targetAspect) {
772
+ var delta = (height / targetAspect - width) / 2;
773
+ extent = [extent[0] - delta, extent[1], extent[2] + delta, extent[3]];
774
+ } else {
775
+ var _delta = (width * targetAspect - height) / 2;
776
+ extent = [extent[0], extent[1] - _delta, extent[2], extent[3] + _delta];
777
+ }
778
+ }
779
+ formData[fixedMap.name + ":EXTENT"] = _this.formatExtent(extent);
780
+ var preset = _this.presetLayersAndStyles(fixedMap.followPresetName);
781
+ if (preset) {
782
+ // Frozen on a map theme rather than on a locked layer set: without explicit
783
+ // layers the server would render this map with the interactive map's layers
784
+ formData[fixedMap.name + ":LAYERS"] = preset.layers;
785
+ formData[fixedMap.name + ":STYLES"] = preset.styles;
786
+ }
787
+ // The server resets a layout map's grid interval unless the request resends it
788
+ if (fixedMap.gridIntervalX && fixedMap.gridIntervalY) {
789
+ formData[fixedMap.name + ":GRID_INTERVAL_X"] = fixedMap.gridIntervalX;
790
+ formData[fixedMap.name + ":GRID_INTERVAL_Y"] = fixedMap.gridIntervalY;
791
+ }
792
+ });
793
+
724
794
  // Add highlight params
725
795
  var printDpi = parseInt(_this.state.dpi, 10) || 0;
726
796
  if (_this.props.printMapHighlights) {
@@ -759,10 +829,10 @@ var Print = /*#__PURE__*/function (_React$Component) {
759
829
  // Add dimension values
760
830
  _this.props.layers.forEach(function (layer) {
761
831
  if (layer.role === LayerRole.THEME) {
762
- Object.entries(layer.dimensionValues || {}).forEach(function (_ref7) {
763
- var _ref8 = _slicedToArray(_ref7, 2),
764
- key = _ref8[0],
765
- value = _ref8[1];
832
+ Object.entries(layer.dimensionValues || {}).forEach(function (_ref9) {
833
+ var _ref0 = _slicedToArray(_ref9, 2),
834
+ key = _ref0[0],
835
+ value = _ref0[1];
766
836
  if (value !== undefined) {
767
837
  formData[key] = value;
768
838
  }
@@ -774,10 +844,10 @@ var Print = /*#__PURE__*/function (_React$Component) {
774
844
  var extraOptions = Object.fromEntries((_this.props.theme.extraPrintParameters || "").split("&").filter(Boolean).map(function (entry) {
775
845
  return entry.split("=");
776
846
  }));
777
- Object.entries(extraOptions).forEach(function (_ref9) {
778
- var _ref0 = _slicedToArray(_ref9, 2),
779
- key = _ref0[0],
780
- value = _ref0[1];
847
+ Object.entries(extraOptions).forEach(function (_ref1) {
848
+ var _ref10 = _slicedToArray(_ref1, 2),
849
+ key = _ref10[0],
850
+ value = _ref10[1];
781
851
  formData[key] = value;
782
852
  });
783
853
  var pages = [formData];
@@ -811,8 +881,8 @@ var Print = /*#__PURE__*/function (_React$Component) {
811
881
  });
812
882
  });
813
883
  _defineProperty(_this, "translateLayoutName", function (themeLayer, item) {
814
- var _ref1, _ref10, _themeLayer$translati, _themeLayer$translati2, _themeLayer$translati3;
815
- return (_ref1 = (_ref10 = (_themeLayer$translati = (_themeLayer$translati2 = themeLayer.translations) === null || _themeLayer$translati2 === void 0 || (_themeLayer$translati2 = _themeLayer$translati2.layouts) === null || _themeLayer$translati2 === void 0 ? void 0 : _themeLayer$translati2[item.title]) !== null && _themeLayer$translati !== void 0 ? _themeLayer$translati : (_themeLayer$translati3 = themeLayer.translations) === null || _themeLayer$translati3 === void 0 || (_themeLayer$translati3 = _themeLayer$translati3.layouts) === null || _themeLayer$translati3 === void 0 ? void 0 : _themeLayer$translati3[item.name]) !== null && _ref10 !== void 0 ? _ref10 : item.title) !== null && _ref1 !== void 0 ? _ref1 : item.name;
884
+ var _ref11, _ref12, _themeLayer$translati, _themeLayer$translati2, _themeLayer$translati3;
885
+ return (_ref11 = (_ref12 = (_themeLayer$translati = (_themeLayer$translati2 = themeLayer.translations) === null || _themeLayer$translati2 === void 0 || (_themeLayer$translati2 = _themeLayer$translati2.layouts) === null || _themeLayer$translati2 === void 0 ? void 0 : _themeLayer$translati2[item.title]) !== null && _themeLayer$translati !== void 0 ? _themeLayer$translati : (_themeLayer$translati3 = themeLayer.translations) === null || _themeLayer$translati3 === void 0 || (_themeLayer$translati3 = _themeLayer$translati3.layouts) === null || _themeLayer$translati3 === void 0 ? void 0 : _themeLayer$translati3[item.name]) !== null && _ref12 !== void 0 ? _ref12 : item.title) !== null && _ref11 !== void 0 ? _ref11 : item.name;
816
886
  });
817
887
  _this.printForm = null;
818
888
  _this.state.grid = props.gridInitiallyEnabled;
@@ -39,14 +39,14 @@ import { VisibilityPresetsInterface } from '../utils/PermaLinkUtils';
39
39
  * Requires `permalinkServiceUrl` to point to a `qwc-permalink-service` with tables setup for visibility presets
40
40
  * (see `qwc-permalink-service` documentation for details).
41
41
  **/
42
- var VisibilityPreset = /*#__PURE__*/function (_React$Component) {
43
- function VisibilityPreset() {
42
+ var VisibilityPresets = /*#__PURE__*/function (_React$Component) {
43
+ function VisibilityPresets() {
44
44
  var _this;
45
- _classCallCheck(this, VisibilityPreset);
45
+ _classCallCheck(this, VisibilityPresets);
46
46
  for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
47
47
  args[_key] = arguments[_key];
48
48
  }
49
- _this = _callSuper(this, VisibilityPreset, [].concat(args));
49
+ _this = _callSuper(this, VisibilityPresets, [].concat(args));
50
50
  _defineProperty(_this, "translations", {
51
51
  addfailed: LocaleUtils.tr("visibilitypreset.addfailed"),
52
52
  title: LocaleUtils.tr("appmenu.items.VisibilityPresets"),
@@ -94,8 +94,8 @@ var VisibilityPreset = /*#__PURE__*/function (_React$Component) {
94
94
  });
95
95
  return _this;
96
96
  }
97
- _inherits(VisibilityPreset, _React$Component);
98
- return _createClass(VisibilityPreset, [{
97
+ _inherits(VisibilityPresets, _React$Component);
98
+ return _createClass(VisibilityPresets, [{
99
99
  key: "componentDidMount",
100
100
  value: function componentDidMount() {
101
101
  var _this2 = this;
@@ -121,8 +121,8 @@ var VisibilityPreset = /*#__PURE__*/function (_React$Component) {
121
121
  }
122
122
  }]);
123
123
  }(React.Component);
124
- _defineProperty(VisibilityPreset, "availableIn3D", true);
125
- _defineProperty(VisibilityPreset, "propTypes", {
124
+ _defineProperty(VisibilityPresets, "availableIn3D", true);
125
+ _defineProperty(VisibilityPresets, "propTypes", {
126
126
  /** Whether to directly open the bookmark on click / middle click, instead of showing dedicated open buttons. */
127
127
  openOnClick: PropTypes.bool,
128
128
  setThemeLayersVisibilityPreset: PropTypes.func,
@@ -132,7 +132,7 @@ _defineProperty(VisibilityPreset, "propTypes", {
132
132
  theme: PropTypes.object,
133
133
  visibilityPresets: PropTypes.array
134
134
  });
135
- _defineProperty(VisibilityPreset, "defaultProps", {
135
+ _defineProperty(VisibilityPresets, "defaultProps", {
136
136
  side: 'right'
137
137
  });
138
138
  var selector = function selector(state) {
@@ -145,4 +145,4 @@ var selector = function selector(state) {
145
145
  export default connect(selector, {
146
146
  setVisibilityPresets: setVisibilityPresets,
147
147
  setThemeLayersVisibilityPreset: setThemeLayersVisibilityPreset
148
- })(VisibilityPreset);
148
+ })(VisibilityPresets);
@@ -0,0 +1,95 @@
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 _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
6
+ 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); }
7
+ function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
8
+ 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); }
9
+ function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
10
+ function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
11
+ function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
12
+ 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); }
13
+ function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
14
+ import ol from 'openlayers';
15
+ import ConfigUtils from '../../utils/ConfigUtils';
16
+ import MeasureUtils from '../../utils/MeasureUtils';
17
+ var DOUBLE_CLICK_DELAY = 250;
18
+ var DOUBLE_CLICK_TOLERANCE = 12;
19
+
20
+ /**
21
+ * Constrains the segments drawn by a line or polygon DrawInteraction to a fixed length.
22
+ */
23
+ var ConstraintInteraction = /*#__PURE__*/function (_ol$interaction$Inter) {
24
+ function ConstraintInteraction(options) {
25
+ var _this;
26
+ _classCallCheck(this, ConstraintInteraction);
27
+ _this = _callSuper(this, ConstraintInteraction);
28
+ _this.drawInteraction = options.drawInteraction;
29
+ _this.distanceMeters = null;
30
+ _this.vertices = [];
31
+ _this.minVertices = 2;
32
+ _this.lastDown = null;
33
+ _this.finishVertex = null;
34
+ _this.drawInteraction.on('vertexadded', function (ev) {
35
+ _this.vertices.push(ev.coordinate.slice(0, 2));
36
+ _this.minVertices = ev.feature.getGeometry().getType() === "Polygon" ? 3 : 2;
37
+ });
38
+ _this.drawInteraction.on(['drawstart', 'drawend', 'drawabort'], function () {
39
+ _this.vertices = [];
40
+ });
41
+ return _this;
42
+ }
43
+ _inherits(ConstraintInteraction, _ol$interaction$Inter);
44
+ return _createClass(ConstraintInteraction, [{
45
+ key: "setDistance",
46
+ value: function setDistance(distanceMeters) {
47
+ this.distanceMeters = distanceMeters;
48
+ }
49
+ }, {
50
+ key: "handleEvent",
51
+ value: function handleEvent(evt) {
52
+ var base = this.vertices[this.vertices.length - 1];
53
+ // Shift is Draw's freehand modifier, freehand stays unconstrained
54
+ if (!base || this.distanceMeters === null || !this.drawInteraction.getActive() || ol.events.condition.shiftKeyOnly(evt)) {
55
+ return true;
56
+ }
57
+ // Aim from the raw pointer, snapping may already have moved evt.pixel
58
+ var pixel = evt.map.getEventPixel(evt.originalEvent);
59
+ if (evt.type === "pointerdown") {
60
+ var time = evt.originalEvent.timeStamp;
61
+ this.finishVertex = this.isDoubleClick(pixel, time) && this.vertices.length >= this.minVertices ? base : null;
62
+ this.lastDown = {
63
+ pixel: pixel,
64
+ time: time
65
+ };
66
+ }
67
+ if (this.finishVertex) {
68
+ // Double click finish: map the second click onto the last vertex, which is not under the pointer
69
+ evt.coordinate = this.finishVertex;
70
+ evt.pixel = evt.map.getPixelFromCoordinate(this.finishVertex);
71
+ } else if (["pointermove", "pointerdrag", "pointerup"].includes(evt.type)) {
72
+ var _this$constrain;
73
+ // Only the coordinate is rewritten: Draw detects clicks, long presses and finishes by pixel
74
+ evt.coordinate = (_this$constrain = this.constrain(base, pixel, evt.map)) !== null && _this$constrain !== void 0 ? _this$constrain : evt.coordinate;
75
+ }
76
+ if (evt.type === "pointerup") {
77
+ this.finishVertex = null;
78
+ }
79
+ return true;
80
+ }
81
+ }, {
82
+ key: "isDoubleClick",
83
+ value: function isDoubleClick(pixel, time) {
84
+ return this.lastDown !== null && time - this.lastDown.time <= DOUBLE_CLICK_DELAY && Math.hypot(pixel[0] - this.lastDown.pixel[0], pixel[1] - this.lastDown.pixel[1]) <= DOUBLE_CLICK_TOLERANCE;
85
+ }
86
+ }, {
87
+ key: "constrain",
88
+ value: function constrain(base, pixel, map) {
89
+ var crs = map.getView().getProjection().getCode();
90
+ var geodesic = ConfigUtils.getConfigProp("geodesicMeasurements");
91
+ return MeasureUtils.computeOffsetCoordinate(base, map.getCoordinateFromPixel(pixel), this.distanceMeters, crs, geodesic);
92
+ }
93
+ }]);
94
+ }(ol.interaction.Interaction);
95
+ export { ConstraintInteraction as default };
@@ -42,10 +42,12 @@ import FeatureAttributesWindow from '../../components/FeatureAttributesWindow';
42
42
  import LocationRecorder from '../../components/LocationRecorder';
43
43
  import { OlLayerAdded, OlLayerUpdated } from '../../components/map/OlLayer';
44
44
  import NumericInputWindow from '../../components/NumericInputWindow';
45
+ import SegmentInput from '../../components/SegmentInput';
45
46
  import FeatureStyles, { computeFeatureStyle } from '../../utils/FeatureStyles';
46
47
  import MapUtils from '../../utils/MapUtils';
47
48
  import MeasureUtils from '../../utils/MeasureUtils';
48
49
  import VectorLayerUtils from '../../utils/VectorLayerUtils';
50
+ import ConstraintInteraction from './ConstraintInteraction';
49
51
  import DrawInteraction from './DrawInteraction';
50
52
  var GeomTypeConfig = {
51
53
  Text: {
@@ -75,7 +77,8 @@ var GeomTypeConfig = {
75
77
  },
76
78
  editTool: 'Pick',
77
79
  drawNodes: true,
78
- showRecordLocation: true
80
+ showRecordLocation: true,
81
+ constrainSegments: true
79
82
  },
80
83
  Polygon: {
81
84
  drawInteraction: function drawInteraction(opts) {
@@ -84,7 +87,8 @@ var GeomTypeConfig = {
84
87
  }));
85
88
  },
86
89
  editTool: 'Pick',
87
- drawNodes: true
90
+ drawNodes: true,
91
+ constrainSegments: true
88
92
  },
89
93
  Circle: {
90
94
  drawInteraction: function drawInteraction(opts) {
@@ -138,7 +142,8 @@ var RedliningSupport = /*#__PURE__*/function (_React$Component) {
138
142
  _classCallCheck(this, RedliningSupport);
139
143
  _this = _callSuper(this, RedliningSupport, [props]);
140
144
  _defineProperty(_this, "state", {
141
- showRecordLocation: false
145
+ showRecordLocation: false,
146
+ showSegmentInput: false
142
147
  });
143
148
  _defineProperty(_this, "createInteraction", function () {
144
149
  if (_this.props.redlining.action === 'Draw') {
@@ -331,8 +336,17 @@ var RedliningSupport = /*#__PURE__*/function (_React$Component) {
331
336
  }, _this);
332
337
  _this.props.map.addInteraction(drawInteraction);
333
338
  _this.interactions.push(drawInteraction);
339
+ var constrainSegments = geomTypeConfig.constrainSegments && !isFreeHand;
340
+ if (constrainSegments) {
341
+ var constraintInteraction = new ConstraintInteraction({
342
+ drawInteraction: drawInteraction
343
+ });
344
+ _this.props.map.addInteraction(constraintInteraction);
345
+ _this.interactions.push(constraintInteraction);
346
+ }
334
347
  _this.setState({
335
- showRecordLocation: geomTypeConfig.showRecordLocation
348
+ showRecordLocation: geomTypeConfig.showRecordLocation,
349
+ showSegmentInput: constrainSegments
336
350
  });
337
351
  });
338
352
  _defineProperty(_this, "enterTemporaryEditMode", function (featureId, layerId, editTool) {
@@ -703,7 +717,8 @@ var RedliningSupport = /*#__PURE__*/function (_React$Component) {
703
717
  });
704
718
  _defineProperty(_this, "reset", function (redliningProps) {
705
719
  _this.setState({
706
- showRecordLocation: false
720
+ showRecordLocation: false,
721
+ showSegmentInput: false
707
722
  });
708
723
  while (_this.interactions.length > 0) {
709
724
  _this.props.map.removeInteraction(_this.interactions.shift());
@@ -931,6 +946,17 @@ var RedliningSupport = /*#__PURE__*/function (_React$Component) {
931
946
  map: this.props.map
932
947
  }));
933
948
  }
949
+ // Clone clears the interactions without reset(), so check the constraint still exists
950
+ var constraintInteraction = this.state.showSegmentInput && this.interactions.find(function (interaction) {
951
+ return interaction instanceof ConstraintInteraction;
952
+ });
953
+ if (constraintInteraction) {
954
+ widgets.push(/*#__PURE__*/React.createElement(SegmentInput, {
955
+ constraintInteraction: constraintInteraction,
956
+ key: "SegmentInput",
957
+ lenUnit: this.props.redlining.lenUnit
958
+ }));
959
+ }
934
960
  return widgets;
935
961
  }
936
962
  }]);
@@ -335,7 +335,9 @@ var SnappingSupport = /*#__PURE__*/function (_React$Component) {
335
335
  var snapPerpendicular = this.snapModeActive(this.props.mapObj.snapping, 'perpendicular');
336
336
  return /*#__PURE__*/ReactDOM.createPortal(/*#__PURE__*/React.createElement("div", {
337
337
  className: className
338
- }, this.state.reqId !== null ? /*#__PURE__*/React.createElement(Spinner, null) : /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("button", {
338
+ }, /*#__PURE__*/React.createElement("span", {
339
+ className: "snapping-toolbar-label"
340
+ }, this.state.reqId ? LocaleUtils.tr("snapping.loading") : LocaleUtils.tr("snapping.snappingenabled")), this.state.reqId !== null ? /*#__PURE__*/React.createElement(Spinner, null) : /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement("button", {
339
341
  className: "button" + (snapVertex ? " pressed" : ""),
340
342
  onClick: function onClick() {
341
343
  return _this3.toggleSnap('vertex');
@@ -367,7 +369,7 @@ var SnappingSupport = /*#__PURE__*/function (_React$Component) {
367
369
  title: LocaleUtils.tr("snapping.perpendicular")
368
370
  }, /*#__PURE__*/React.createElement(Icon, {
369
371
  icon: "snap_perpendicular"
370
- }))), "\xA0", this.state.reqId ? LocaleUtils.tr("snapping.loading") : LocaleUtils.tr("snapping.snappingenabled")), this.context);
372
+ })))), this.context);
371
373
  }
372
374
  }]);
373
375
  }(React.Component);
@@ -1,8 +1,14 @@
1
1
  div.snapping-toolbar {
2
2
  display: flex;
3
+ flex-direction: column;
3
4
  align-items: center;
4
5
  }
5
6
 
7
+ span.snapping-toolbar-label {
8
+ font-size: 85%;
9
+ white-space: nowrap;
10
+ }
11
+
6
12
  div.snapping-toolbar-container div.spinner {
7
13
  width: 1.5em;
8
14
  height: 1.5em;
@@ -34,9 +34,9 @@ var checkNonZeroZ = function checkNonZeroZ(oldState, newState, fallback) {
34
34
  return (oldState === null || oldState === void 0 ? void 0 : oldState.geomNonZeroZ) || false;
35
35
  };
36
36
  var checkGeomReadOnly = function checkGeomReadOnly(editConfig) {
37
- var _editConfig$geomType;
37
+ var _editConfig$geomType, _editConfig$permissio;
38
38
  var simpleGeomType = ((_editConfig$geomType = editConfig === null || editConfig === void 0 ? void 0 : editConfig.geomType) !== null && _editConfig$geomType !== void 0 ? _editConfig$geomType : "").replace(/^Multi/, '').replace(/Z$/, '');
39
- return (editConfig === null || editConfig === void 0 ? void 0 : editConfig.geomType) && !['Point', 'LineString', 'Polygon'].includes(simpleGeomType);
39
+ return (editConfig === null || editConfig === void 0 || (_editConfig$permissio = editConfig.permissions) === null || _editConfig$permissio === void 0 ? void 0 : _editConfig$permissio.geomreadonly) || (editConfig === null || editConfig === void 0 ? void 0 : editConfig.geomType) && !['Point', 'LineString', 'Polygon'].includes(simpleGeomType);
40
40
  };
41
41
  export default function editing() {
42
42
  var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : defaultState;
@@ -44,7 +44,7 @@ export default function editing() {
44
44
  switch (action.type) {
45
45
  case SET_EDIT_CONTEXT:
46
46
  {
47
- var _action$editContext$e, _action$editContext, _state$contexts$actio, _editConfig$permissio;
47
+ var _action$editContext$e, _action$editContext, _state$contexts$actio, _editConfig$permissio2;
48
48
  var editConfig = (_action$editContext$e = (_action$editContext = action.editContext) === null || _action$editContext === void 0 ? void 0 : _action$editContext.editConfig) !== null && _action$editContext$e !== void 0 ? _action$editContext$e : (_state$contexts$actio = state.contexts[action.contextId]) === null || _state$contexts$actio === void 0 ? void 0 : _state$contexts$actio.editConfig;
49
49
  return {
50
50
  contexts: _objectSpread(_objectSpread({}, state.contexts), {}, _defineProperty({}, action.contextId, _objectSpread(_objectSpread(_objectSpread({
@@ -58,7 +58,7 @@ export default function editing() {
58
58
  geomReadOnly: checkGeomReadOnly(editConfig),
59
59
  id: action.contextId,
60
60
  geomType: editConfig === null || editConfig === void 0 ? void 0 : editConfig.geomType,
61
- permissions: (_editConfig$permissio = editConfig === null || editConfig === void 0 ? void 0 : editConfig.permissions) !== null && _editConfig$permissio !== void 0 ? _editConfig$permissio : {}
61
+ permissions: (_editConfig$permissio2 = editConfig === null || editConfig === void 0 ? void 0 : editConfig.permissions) !== null && _editConfig$permissio2 !== void 0 ? _editConfig$permissio2 : {}
62
62
  }))),
63
63
  currentContext: action.contextId
64
64
  };
@@ -228,9 +228,9 @@ def getLayerTree(layer, resultLayers, visibleLayers, printLayers, level, collaps
228
228
 
229
229
  styles = {}
230
230
  for style in layer.getElementsByTagName("Style"):
231
- name = getChildElementValue(style, "Name")
232
- title = getChildElementValue(style, "Title")
233
- styles[name] = title
231
+ style_name = getChildElementValue(style, "Name")
232
+ style_title = getChildElementValue(style, "Title")
233
+ styles[style_name] = style_title
234
234
  layerEntry["styles"] = styles
235
235
  layerEntry['style'] = 'default' if 'default' in styles else (list(styles)[0] if len(styles) > 0 else '')
236
236
 
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Redlining",
607
607
  "markers": "Маркери",
608
608
  "numericinput": "Цифрово въвеждане",
609
+ "segmentdistance": "",
609
610
  "size": "Размер",
610
611
  "transform": "Преобразуване"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Redlining",
607
607
  "markers": "Marcadors",
608
608
  "numericinput": "Entrada numèrica",
609
+ "segmentdistance": "",
609
610
  "size": "Mida",
610
611
  "transform": "Transforma"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Velikost",
610
611
  "transform": ""
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Zeichnung",
607
607
  "markers": "Spitzen",
608
608
  "numericinput": "Numerische Eingabe",
609
+ "segmentdistance": "Distanz",
609
610
  "size": "Grösse",
610
611
  "transform": "Transformieren"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Zeichnung",
607
607
  "markers": "Spitzen",
608
608
  "numericinput": "Numerische Eingabe",
609
+ "segmentdistance": "Distanz",
609
610
  "size": "Größe",
610
611
  "transform": "Transformieren"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Redlining",
607
607
  "markers": "Markers",
608
608
  "numericinput": "Numeric input",
609
+ "segmentdistance": "Distance",
609
610
  "size": "Size",
610
611
  "transform": "Transform"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Línea de demarcación",
607
607
  "markers": "Marcadores",
608
608
  "numericinput": "Entrada numérica",
609
+ "segmentdistance": "",
609
610
  "size": "Tamaño",
610
611
  "transform": "Transformar"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Koko",
610
611
  "transform": ""
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Dessin",
607
607
  "markers": "Pointes",
608
608
  "numericinput": "Entrée numérique",
609
+ "segmentdistance": "Distance",
609
610
  "size": "Taille",
610
611
  "transform": "Transformer"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Méret",
610
611
  "transform": ""
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Disegno",
607
607
  "markers": "Punte",
608
608
  "numericinput": "Formulario numerico",
609
+ "segmentdistance": "",
609
610
  "size": "Dimensione",
610
611
  "transform": "Transforma"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "スケッチ",
607
607
  "markers": "マーカー",
608
608
  "numericinput": "数値入力",
609
+ "segmentdistance": "",
609
610
  "size": "サイズ",
610
611
  "transform": "変形"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Laag",
607
607
  "markers": "Markeringen",
608
608
  "numericinput": "Numeriek invoerpaneel tonen",
609
+ "segmentdistance": "",
609
610
  "size": "Afmeting",
610
611
  "transform": "Transformeer"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Størrelse",
610
611
  "transform": ""
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Rozmiar",
610
611
  "transform": ""
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "Entrada numérica",
609
+ "segmentdistance": "",
609
610
  "size": "Tamanho",
610
611
  "transform": "Transformar"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "Marcadores",
608
608
  "numericinput": "Entrada Numérica",
609
+ "segmentdistance": "",
609
610
  "size": "Tamanho",
610
611
  "transform": "Transformar"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Evidențiere",
607
607
  "markers": "Marcaje",
608
608
  "numericinput": "Afișare formular pentru valori numerice",
609
+ "segmentdistance": "",
609
610
  "size": "Dimeniuni",
610
611
  "transform": "Transformare"
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Размер",
610
611
  "transform": ""
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Storlek",
610
611
  "transform": ""
611
612
  },
@@ -606,6 +606,7 @@
606
606
  "layertitle": "Eskiz",
607
607
  "markers": "İşaretçiler",
608
608
  "numericinput": "Sayısal giriş panelini göster",
609
+ "segmentdistance": "",
609
610
  "size": "Boyut",
610
611
  "transform": "Dönüşüm"
611
612
  },
@@ -530,6 +530,7 @@
530
530
  "redlining.layertitle",
531
531
  "redlining.markers",
532
532
  "redlining.numericinput",
533
+ "redlining.segmentdistance",
533
534
  "redlining.size",
534
535
  "redlining.transform",
535
536
  "reports.region",
@@ -606,6 +606,7 @@
606
606
  "layertitle": "",
607
607
  "markers": "",
608
608
  "numericinput": "",
609
+ "segmentdistance": "",
609
610
  "size": "Розмір",
610
611
  "transform": ""
611
612
  },
@@ -16,24 +16,37 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
16
16
  import axios from 'axios';
17
17
  import isMobile from 'ismobilejs';
18
18
  import url from 'url';
19
- var config = {
20
- assetsPath: "assets",
21
- translationsPath: "translations",
22
- defaultFeatureStyle: {
23
- strokeColor: [0, 0, 255, 1],
24
- strokeWidth: 2,
25
- strokeDash: [4],
26
- fillColor: [0, 0, 255, 0.33],
27
- circleRadius: 10,
28
- textFill: 'black',
29
- textStroke: 'white'
30
- }
19
+ var defaultConfig = function defaultConfig() {
20
+ return {
21
+ assetsPath: "assets",
22
+ translationsPath: "translations",
23
+ defaultFeatureStyle: {
24
+ strokeColor: [0, 0, 255, 1],
25
+ strokeWidth: 2,
26
+ strokeDash: [4],
27
+ fillColor: [0, 0, 255, 0.33],
28
+ circleRadius: 10,
29
+ textFill: 'black',
30
+ textStroke: 'white'
31
+ }
32
+ };
31
33
  };
34
+ var config = defaultConfig();
32
35
  var sessionConfig = {};
33
36
  export default {
34
37
  getDefaults: function getDefaults() {
35
38
  return config;
36
39
  },
40
+ /**
41
+ * Resets the configuration to its defaults, so that a subsequent loadConfiguration
42
+ * does not merge onto the configuration of a previous application instance.
43
+ */
44
+ reset: function reset() {
45
+ config = defaultConfig();
46
+ Object.keys(sessionConfig).forEach(function (key) {
47
+ return delete sessionConfig[key];
48
+ });
49
+ },
37
50
  loadConfiguration: function loadConfiguration() {
38
51
  var configParams = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
39
52
  var configPath = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
@@ -110,6 +110,36 @@ var CoordinatesUtils = {
110
110
  var ne = CoordinatesUtils.reproject([bbox[2], bbox[3]], source, dest);
111
111
  return [].concat(_toConsumableArray(sw), _toConsumableArray(ne));
112
112
  },
113
+ /**
114
+ * Reprojects a bounding box, sampling along its edges rather than just the corners.
115
+ *
116
+ * @param bbox {array} [minx, miny, maxx, maxy]
117
+ * @param source {string} SRS of the given bbox
118
+ * @param dest {string} SRS of the returned bbox
119
+ * @param stops {number} number of sampling points per edge
120
+ *
121
+ * @return {array} [minx, miny, maxx, maxy], or null if the transform failed
122
+ */
123
+ reprojectBboxDensified: function reprojectBboxDensified(bbox, source, dest) {
124
+ var stops = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 8;
125
+ if (source === dest) {
126
+ return _toConsumableArray(bbox);
127
+ }
128
+ try {
129
+ var result = ol.proj.transformExtent(bbox, source, dest, stops);
130
+ if (!result || !result.every(function (value) {
131
+ return Number.isFinite(value);
132
+ })) {
133
+ return null;
134
+ }
135
+ if (result[2] - result[0] <= 0 || result[3] - result[1] <= 0) {
136
+ return null;
137
+ }
138
+ return result;
139
+ } catch (_unused2) {
140
+ return null;
141
+ }
142
+ },
113
143
  calculateAzimuth: function calculateAzimuth(p1, p2, pj) {
114
144
  var p1proj = CoordinatesUtils.reproject(p1, pj, 'EPSG:4326');
115
145
  var p2proj = CoordinatesUtils.reproject(p2, pj, 'EPSG:4326');
@@ -336,6 +336,25 @@ var MeasureUtils = {
336
336
  var conv = units === 'feet' ? 0.3048 : 1;
337
337
  return geometry.getArea() * conv * conv;
338
338
  }
339
+ },
340
+ computeOffsetCoordinate: function computeOffsetCoordinate(base, target, distance, featureCrs, geodesic) {
341
+ var dx = target[0] - base[0];
342
+ var dy = target[1] - base[1];
343
+ var length = Math.sqrt(dx * dx + dy * dy);
344
+ if (length === 0) {
345
+ return null;
346
+ }
347
+ if (geodesic || CoordinatesUtils.getUnits(featureCrs) === 'degrees') {
348
+ var azimuth = CoordinatesUtils.calculateAzimuth(base, target, featureCrs) * Math.PI / 180;
349
+ var wgsCoo = ol.sphere.offset(CoordinatesUtils.reproject(base, featureCrs, "EPSG:4326"), distance, azimuth);
350
+ return CoordinatesUtils.reproject(wgsCoo, "EPSG:4326", featureCrs);
351
+ }
352
+ var metersPerUnit = ol.proj.get(featureCrs).getMetersPerUnit();
353
+ if (!metersPerUnit) {
354
+ return null;
355
+ }
356
+ var scale = distance / metersPerUnit / length;
357
+ return [base[0] + dx * scale, base[1] + dy * scale];
339
358
  }
340
359
  };
341
360
  export default MeasureUtils;
@@ -34,6 +34,14 @@ var MiscUtils = {
34
34
  var _ref, _el$closest, _el$closest2, _el$ownerDocument;
35
35
  return (_ref = (_el$closest = el === null || el === void 0 || (_el$closest2 = el.closest) === null || _el$closest2 === void 0 ? void 0 : _el$closest2.call(el, '.plugins-container')) !== null && _el$closest !== void 0 ? _el$closest : el === null || el === void 0 || (_el$ownerDocument = el.ownerDocument) === null || _el$ownerDocument === void 0 ? void 0 : _el$ownerDocument.body) !== null && _ref !== void 0 ? _ref : document.body;
36
36
  },
37
+ loginUrl: function loginUrl() {
38
+ var clearLayerParam = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
39
+ var target = new URL(window.location.href);
40
+ if (clearLayerParam) {
41
+ target.searchParams["delete"]('l');
42
+ }
43
+ return ConfigUtils.getConfigProp("authServiceUrl") + "login?url=" + encodeURIComponent(target.href);
44
+ },
37
45
  addLinkAnchors: function addLinkAnchors(text) {
38
46
  // If text already contains tags, do nothing
39
47
  var tagRegEx = /(<.[^(><.)]+>)/;
@@ -128,6 +128,15 @@ export var UrlParams = {
128
128
  return query;
129
129
  }
130
130
  },
131
+ /**
132
+ * Cancels a pending location update, so that it does not fire after the application
133
+ * has been torn down.
134
+ */
135
+ cancelPendingUpdates: function cancelPendingUpdates() {
136
+ clearTimeout(historyUpdateTimeout);
137
+ historyUpdateTimeout = null;
138
+ pendingParams = {};
139
+ },
131
140
  clear: function clear() {
132
141
  var clearKeys = ['k', 't', 'l', 'bl', 'bk', 'c', 'hc', 'ic', 'if', 's', 'e', 'crs', 'st', 'sp', 'f', 'v', 'vp', 'v3d', 'bl3d', 'task'];
133
142
  this.updateParams(clearKeys.reduce(function (res, key) {
@@ -21,6 +21,14 @@ export default {
21
21
  removeCustomPlugin: function removeCustomPlugin(name) {
22
22
  delete CustomPlugins[name];
23
23
  },
24
+ reset: function reset() {
25
+ Object.keys(BuiltInPlugins).forEach(function (name) {
26
+ return delete BuiltInPlugins[name];
27
+ });
28
+ Object.keys(CustomPlugins).forEach(function (name) {
29
+ return delete CustomPlugins[name];
30
+ });
31
+ },
24
32
  getPlugins: function getPlugins() {
25
33
  return _objectSpread(_objectSpread({}, BuiltInPlugins), CustomPlugins);
26
34
  }