qwc2
Version:
QGIS Web Client
876 lines (874 loc) • 42.9 kB
JavaScript
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
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); }
function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
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); } }
function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; }
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
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); }
function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); }
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); }
function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); }
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; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; }
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); }
/**
* Copyright 2024 Sourcepole AG
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
import React from 'react';
import { connect } from 'react-redux';
import axios from 'axios';
import isEmpty from 'lodash.isempty';
import isEqual from 'lodash.isequal';
import PropTypes from 'prop-types';
import { v4 as uuidv4 } from 'uuid';
import { LayerRole, setFilter } from '../actions/layers';
import { setPermalinkParameters } from '../actions/localConfig';
import { setCurrentTask } from '../actions/task';
import Icon from '../components/Icon';
import MapButton from '../components/MapButton';
import MapSelection from '../components/MapSelection';
import PickFeature from '../components/PickFeature';
import SideBar from '../components/SideBar';
import ButtonBar from '../components/widgets/ButtonBar';
import ComboBox from '../components/widgets/ComboBox';
import DateTimeInput from '../components/widgets/DateTimeInput';
import TextInput from '../components/widgets/TextInput';
import ToggleSwitch from '../components/widgets/ToggleSwitch';
import ConfigUtils from '../utils/ConfigUtils';
import LayerUtils from '../utils/LayerUtils';
import LocaleUtils from '../utils/LocaleUtils';
import MiscUtils from '../utils/MiscUtils';
import './style/MapFilter.css';
/**
* Allows filtering the map content via QGIS Server WMS FILTER.
*
* See [Map filtering](../../topics/MapFilter).
*/
var MapFilter = /*#__PURE__*/function (_React$Component) {
function MapFilter(props) {
var _this;
_classCallCheck(this, MapFilter);
_this = _callSuper(this, MapFilter, [props]);
_defineProperty(_this, "state", {
filters: {},
geomFilter: {},
customFilters: {},
filterEditor: null,
filterInvalid: false
});
_defineProperty(_this, "collectPredefinedFilters", function (layers) {
return layers.reduce(function (res, layer) {
return _objectSpread(_objectSpread({}, res), (layer.predefinedFilters || []).reduce(function (res2, config) {
return _objectSpread(_objectSpread({}, res2), {}, _defineProperty({}, config.id, config));
}, {}));
}, {});
});
_defineProperty(_this, "initializeFilters", function (predefinedFilters, prevFilters) {
clearTimeout(_this.applyFilterTimeout);
_this.applyFilterTimeout = null;
var filters = Object.values(predefinedFilters).reduce(function (res, filterConfig) {
var _prevFilters$filterCo;
return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, filterConfig.id, (_prevFilters$filterCo = prevFilters === null || prevFilters === void 0 ? void 0 : prevFilters[filterConfig.id]) !== null && _prevFilters$filterCo !== void 0 ? _prevFilters$filterCo : {
active: false,
filter: filterConfig.filter,
values: filterConfig.fields.reduce(function (values, valueConfig) {
return _objectSpread(_objectSpread({}, values), {}, _defineProperty({}, valueConfig.id, valueConfig.defaultValue));
}, {})
}));
}, {});
var timeFilter = {};
_this.props.layers.forEach(function (layer) {
return _this.buildTimeFilter(layer, timeFilter);
});
if (!isEmpty(timeFilter) && _this.props.allowFilterByTime) {
var _prevFilters$__timefi, _prevFilters$__timefi2, _prevFilters$__timefi3, _prevFilters$__timefi4;
filters.__timefilter = {
active: (_prevFilters$__timefi = (_prevFilters$__timefi2 = prevFilters.__timefilter) === null || _prevFilters$__timefi2 === void 0 ? void 0 : _prevFilters$__timefi2.active) !== null && _prevFilters$__timefi !== void 0 ? _prevFilters$__timefi : false,
filter: timeFilter,
values: (_prevFilters$__timefi3 = (_prevFilters$__timefi4 = prevFilters.__timefilter) === null || _prevFilters$__timefi4 === void 0 ? void 0 : _prevFilters$__timefi4.values) !== null && _prevFilters$__timefi3 !== void 0 ? _prevFilters$__timefi3 : {
tstart: "",
tend: ""
},
defaultValues: {
tstart: '1800-01-01',
tend: '9999-12-31'
}
};
}
return filters;
});
_defineProperty(_this, "applyFilter", function () {
var _this$state$filters$_;
_this.applyFilterTimeout = null;
var layerExpressions = {};
// Recompute filter expressions
Object.values(_this.state.filters).forEach(function (entry) {
if (entry.active) {
Object.entries(entry.filter).forEach(function (_ref) {
var _ref2 = _slicedToArray(_ref, 2),
layer = _ref2[0],
expression = _ref2[1];
var replacedExpr = _this.replaceExpressionVariables(expression, entry.values, entry.defaultValues || {});
if (replacedExpr === null) {
/* eslint-disable-next-line */
console.warn("Invalid filter expression: " + JSON.stringify(expression));
} else if (layerExpressions[layer]) {
layerExpressions[layer].push('and', replacedExpr);
} else {
layerExpressions[layer] = [replacedExpr];
}
});
}
}, {});
Object.values(_this.state.customFilters).forEach(function (entry) {
if (entry.active && entry.layer) {
var expr = '';
try {
expr = JSON.parse(entry.expr);
} catch (e) {
return;
}
if (layerExpressions[entry.layer]) {
layerExpressions[entry.layer].push('and', expr);
} else {
layerExpressions[entry.layer] = [expr];
}
}
});
var timeRange = (_this$state$filters$_ = _this.state.filters.__timefilter) !== null && _this$state$filters$_ !== void 0 && _this$state$filters$_.active ? {
tstart: _this.state.filters.__timefilter.values.tstart,
tend: _this.state.filters.__timefilter.values.tend
} : null;
_this.props.setFilter(layerExpressions, _this.state.geomFilter.geom, timeRange);
// Validate parameters with test request
var themeLayer = _this.props.layers.find(function (layer) {
return layer.role === LayerRole.THEME;
});
if (themeLayer) {
var wmsParams = LayerUtils.buildWMSLayerParams(themeLayer, {
filterParams: layerExpressions,
filterGeom: _this.state.geomFilter.geom
}).params;
var wmsLayers = wmsParams.LAYERS.split(",");
var reqParams = {
SERVICE: 'WMS',
REQUEST: 'GetMap',
VERSION: '1.3.0',
CRS: 'EPSG:4326',
WIDTH: 10,
HEIGHT: 10,
BBOX: "-0.5,-0.5,0.5,0.5",
LAYERS: Object.keys(layerExpressions).filter(function (layer) {
return wmsLayers.includes(layer);
}).join(","),
csrf_token: MiscUtils.getCsrfToken()
};
if (wmsParams.FILTER) {
reqParams.FILTER = wmsParams.FILTER;
}
if (wmsParams.FILTER_GEOM) {
reqParams.FILTER_GEOM = wmsParams.FILTER_GEOM;
}
var options = {
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
responseType: "blob"
};
axios.post(themeLayer.url, new URLSearchParams(reqParams).toString(), options).then(function () {
_this.setState({
filterInvalid: false
});
})["catch"](function () {
_this.setState({
filterInvalid: true
});
});
}
var permalinkState = Object.entries(_this.state.filters).reduce(function (res, _ref3) {
var _ref4 = _slicedToArray(_ref3, 2),
key = _ref4[0],
value = _ref4[1];
if (value.active) {
return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, key, value.values));
} else {
return res;
}
}, {});
if (_this.state.geomFilter.geom) {
permalinkState.__geomfilter = _this.state.geomFilter.geom.coordinates;
}
permalinkState.__custom = Object.values(_this.state.customFilters).map(function (entry) {
if (!entry.active) {
return null;
}
var expr = null;
try {
expr = JSON.parse(entry.expr);
} catch (e) {
return null;
}
return {
title: entry.title,
layer: entry.layer,
expr: expr
};
}).filter(Boolean);
_this.props.setPermalinkParameters({
f: JSON.stringify(permalinkState)
});
});
_defineProperty(_this, "buildTimeFilter", function (layer, filters) {
if (layer.sublayers) {
layer.sublayers.forEach(function (sublayer) {
return _this.buildTimeFilter(sublayer, filters);
});
} else {
var timeDimension = (layer.dimensions || []).find(function (dimension) {
return dimension.units === "ISO8601";
});
if (timeDimension) {
filters[layer.name] = [[[timeDimension.fieldName, '>=', "$tstart$"], 'or', [timeDimension.fieldName, 'IS', null]], 'and', [[timeDimension.endFieldName, '<=', "$tend$"], 'or', [timeDimension.endFieldName, 'IS', null]]];
}
}
});
_defineProperty(_this, "filterMapButtonClicked", function () {
var mapClickAction = ConfigUtils.getPluginConfig("MapFilter").mapClickAction;
_this.props.setCurrentTask(_this.props.currentTask === "MapFilter" ? null : "MapFilter", null, mapClickAction);
});
_defineProperty(_this, "onSidebarHide", function () {
_this.setState(function (state) {
var newState = _objectSpread({}, state);
if (!state.geomFilter.geom && state.geomFilter.geomType) {
newState.geomFilter.geomType = null;
}
if (state.geomFilter.picking) {
newState.geomFilter.picking = false;
}
return newState;
});
});
_defineProperty(_this, "renderBody", function () {
if (_this.state.filterEditor) {
return _this.renderFilterEditor();
} else {
return [_this.renderInvalidWarning()].concat(_toConsumableArray(_this.renderPredefinedFilters()), [_this.props.allowFilterByTime ? _this.renderTimeFilter() : null, _this.props.allowFilterByGeom ? _this.renderGeomFilter() : null], _toConsumableArray(_this.renderCustomFilters()));
}
});
_defineProperty(_this, "renderInvalidWarning", function () {
if (_this.state.filterInvalid) {
return /*#__PURE__*/React.createElement("div", {
className: "map-filter-invalid-warning",
key: "InvalidFilterWarning"
}, /*#__PURE__*/React.createElement(Icon, {
icon: "warning"
}), " ", /*#__PURE__*/React.createElement("div", null, LocaleUtils.tr("mapfilter.brokenrendering")));
}
return null;
});
_defineProperty(_this, "renderFilterEditor", function () {
var commitButtons = [{
key: 'Save',
icon: 'ok',
label: LocaleUtils.tr("common.save"),
extraClasses: "button-accept"
}, {
key: 'Cancel',
icon: 'remove',
label: LocaleUtils.tr("common.cancel"),
extraClasses: "button-reject"
}];
var sampleFilters = '["field", "=", "val"]\n' + '[["field", ">", "val1"], "and", ["field", "<", "val2"]]';
return /*#__PURE__*/React.createElement("div", {
className: "map-filter-editor-container"
}, /*#__PURE__*/React.createElement(TextInput, {
className: "map-filter-editor " + (_this.state.filterEditor.invalid ? "map-filter-editor-invalid" : ""),
multiline: true,
onChange: function onChange(value) {
return _this.setState(function (state) {
return {
filterEditor: _objectSpread(_objectSpread({}, state.filterEditor), {}, {
value: value,
invalid: false
})
};
});
},
placeholder: sampleFilters,
value: _this.state.filterEditor.value
}), _this.state.filterEditor.invalid ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Icon, {
icon: "warning"
}), " ", /*#__PURE__*/React.createElement("span", null, LocaleUtils.tr("mapfilter.invalidfilter"))) : null, /*#__PURE__*/React.createElement(ButtonBar, {
buttons: commitButtons,
onClick: _this.commitFilterEditor
}));
});
_defineProperty(_this, "commitFilterEditor", function (action) {
if (action === 'Save') {
// Validate expression
var _validateExpression = function validateExpression(values) {
if (Array.isArray(values[0])) {
// Even entries must be arrays, odd entries must be 'and' or 'or'
return values.every(function (value, idx) {
return idx % 2 === 0 ? Array.isArray(value) && _validateExpression(value) : ["and", "or"].includes(value.toLowerCase());
}, true);
} else {
return values.length === 3 && typeof values[0] === 'string' && typeof values[1] === 'string' && ['string', 'number'].includes(_typeof(values[2]));
}
};
var filterexpr = null;
try {
filterexpr = JSON.parse(_this.state.filterEditor.value);
} catch (e) {
// Pass
}
if (!Array.isArray(filterexpr) || !_validateExpression(filterexpr)) {
_this.setState(function (state) {
return {
filterEditor: _objectSpread(_objectSpread({}, state.filterEditor), {}, {
invalid: true
})
};
});
return;
}
_this.updateCustomFilter(_this.state.filterEditor.filterId, 'expr', _this.state.filterEditor.value);
}
_this.setState({
filterEditor: null
});
});
_defineProperty(_this, "renderPredefinedFilters", function () {
var predefinedFilters = _this.collectPredefinedFilters(_this.props.layers);
return Object.values(predefinedFilters).map(function (config) {
var _config$title, _this$state$filters$c;
return /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry",
key: config.id
}, /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-titlebar"
}, /*#__PURE__*/React.createElement("span", {
className: "map-filter-entry-title"
}, (_config$title = config.title) !== null && _config$title !== void 0 ? _config$title : LocaleUtils.tr(config.titlemsgid)), /*#__PURE__*/React.createElement(ToggleSwitch, {
active: (_this$state$filters$c = _this.state.filters[config.id]) === null || _this$state$filters$c === void 0 ? void 0 : _this$state$filters$c.active,
onChange: function onChange(active) {
return _this.toggleFilter(config.id, active);
}
})), /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-body"
}, /*#__PURE__*/React.createElement("table", {
className: "map-filter-entry-fields"
}, /*#__PURE__*/React.createElement("tbody", null, config.fields.map(function (field) {
var _field$title;
return /*#__PURE__*/React.createElement("tr", {
key: field.id
}, /*#__PURE__*/React.createElement("td", null, (_field$title = field.title) !== null && _field$title !== void 0 ? _field$title : LocaleUtils.tr(field.titlemsgid), ": "), /*#__PURE__*/React.createElement("td", null, field.inputConfig.type === 'select' ? /*#__PURE__*/React.createElement("select", {
onChange: function onChange(ev) {
return _this.updateFieldValue(config.id, field.id, ev.target.value);
},
value: _this.state.filters[config.id].values[field.id]
}, !field.defaultValue ? /*#__PURE__*/React.createElement("option", {
value: ""
}, LocaleUtils.tr("common.select")) : null, field.inputConfig.options.map(function (entry) {
var _entry$value, _entry$value2, _entry$label;
return /*#__PURE__*/React.createElement("option", {
key: (_entry$value = entry.value) !== null && _entry$value !== void 0 ? _entry$value : entry,
value: (_entry$value2 = entry.value) !== null && _entry$value2 !== void 0 ? _entry$value2 : entry
}, (_entry$label = entry.label) !== null && _entry$label !== void 0 ? _entry$label : entry.labelmsgid ? LocaleUtils.tr(entry.labelmsgid) : entry);
})) : /*#__PURE__*/React.createElement("input", _extends({
onChange: function onChange(ev) {
return _this.updateFieldValue(config.id, field.id, ev.target.value);
},
type: "text",
value: _this.state.filters[config.id].values[field.id] || ""
}, field.inputConfig))));
})))));
});
});
_defineProperty(_this, "renderTimeFilter", function () {
var timeFilter = _this.state.filters.__timefilter;
if (!timeFilter) {
return null;
}
return /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry",
key: "__timefilter"
}, /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-titlebar"
}, /*#__PURE__*/React.createElement("span", {
className: "map-filter-entry-title"
}, LocaleUtils.tr("mapfilter.timefilter")), /*#__PURE__*/React.createElement(ToggleSwitch, {
active: timeFilter.active,
onChange: function onChange(active) {
return _this.toggleFilter("__timefilter", active);
}
})), /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-body"
}, /*#__PURE__*/React.createElement("table", {
className: "map-filter-entry-fields"
}, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapfilter.timefrom"), ": "), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(DateTimeInput, {
onChange: function onChange(value) {
return _this.updateFieldValue("__timefilter", "tstart", value);
},
value: timeFilter.values.tstart
}))), /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, LocaleUtils.tr("mapfilter.timeto"), ": "), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(DateTimeInput, {
onChange: function onChange(value) {
return _this.updateFieldValue("__timefilter", "tend", value);
},
value: timeFilter.values.tend
})))))));
});
_defineProperty(_this, "renderCustomFilters", function () {
if (!_this.props.allowCustomFilters) {
return [];
}
var layerNames = _this.props.layers.reduce(function (res, layer) {
if (layer.role === LayerRole.THEME) {
return [].concat(_toConsumableArray(res), _toConsumableArray(LayerUtils.getSublayerNames(layer, true, function (lyr) {
return !!lyr.geometryType;
})));
}
return res;
}, []);
var customFilters = Object.entries(_this.state.customFilters).map(function (_ref5) {
var _ref6 = _slicedToArray(_ref5, 2),
key = _ref6[0],
entry = _ref6[1];
return /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry",
key: key
}, /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-titlebar map-filter-custom-entry-titlebar"
}, /*#__PURE__*/React.createElement(TextInput, {
className: "map-filter-entry-title",
onChange: function onChange(value) {
return _this.updateCustomFilter(key, 'title', value);
},
value: entry.title
}), /*#__PURE__*/React.createElement(ToggleSwitch, {
active: entry.active,
onChange: function onChange(active) {
return _this.updateCustomFilter(key, 'active', active);
}
}), /*#__PURE__*/React.createElement(Icon, {
icon: "trash",
onClick: function onClick() {
return _this.deleteCustomFilter(key);
}
})), /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-body"
}, /*#__PURE__*/React.createElement("table", {
className: "map-filter-entry-fields"
}, /*#__PURE__*/React.createElement("tbody", null, /*#__PURE__*/React.createElement("tr", null, /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement(ComboBox, {
onChange: function onChange(value) {
return _this.updateCustomFilter(key, 'layer', value);
},
placeholder: LocaleUtils.tr("common.selectlayer"),
value: entry.layer
}, layerNames.map(function (layerName) {
return /*#__PURE__*/React.createElement("div", {
key: layerName,
value: layerName
}, layerName);
}))), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("input", {
className: "map-filter-custom-entry-expr",
onChange: function onChange() {},
onClick: function onClick() {
return _this.setState({
filterEditor: {
filterId: key,
value: entry.expr
}
});
},
readOnly: true,
value: entry.expr
})))))));
});
return [].concat(_toConsumableArray(customFilters), [/*#__PURE__*/React.createElement("div", {
className: "map-filter-add-custom",
key: "addcustomfilter"
}, /*#__PURE__*/React.createElement("button", {
className: "button",
onClick: _this.addCustomFilter,
type: "button"
}, LocaleUtils.tr("mapfilter.addcustomfilter")))]);
});
_defineProperty(_this, "renderGeomFilter", function () {
var geomFilter = _this.state.geomFilter;
var filterButtons = [{
key: "Polygon",
tooltip: LocaleUtils.tr("common.polygon"),
icon: "polygon",
label: LocaleUtils.tr("common.polygon")
}, {
key: "Circle",
tooltip: LocaleUtils.tr("common.circle"),
icon: "circle",
label: LocaleUtils.tr("common.circle")
}, {
key: "Pick",
tooltip: LocaleUtils.tr("common.pick"),
icon: "pick",
label: LocaleUtils.tr("common.pick")
}];
var active = geomFilter.picking ? "Pick" : geomFilter.geomType || "";
return /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry",
key: "__geomfilter"
}, /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-titlebar"
}, /*#__PURE__*/React.createElement("span", {
className: "map-filter-entry-title"
}, LocaleUtils.tr("mapfilter.geomfilter"))), /*#__PURE__*/React.createElement("div", {
className: "map-filter-entry-body"
}, /*#__PURE__*/React.createElement(ButtonBar, {
active: active,
buttons: filterButtons,
onClick: _this.triggerGeometryFilter
}), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("label", null, /*#__PURE__*/React.createElement("input", {
checked: !!geomFilter.hideFilterGeom,
onChange: _this.toggleHideFilterGeom,
type: "checkbox"
}), " ", LocaleUtils.tr("mapfilter.hidefiltergeom")))));
});
_defineProperty(_this, "triggerGeometryFilter", function (action) {
if (action === 'Pick') {
_this.setState(function (state) {
return {
geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, {
geom: null,
picking: !state.geomFilter.picking,
geomType: null
})
};
});
} else {
_this.setState(function (state) {
return {
geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, {
geom: null,
picking: false,
geomType: state.geomFilter.geomType === action ? null : action
})
};
});
}
});
_defineProperty(_this, "setFilterGeometry", function (geom) {
_this.setState(function (state) {
return {
geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, {
geom: geom
})
};
});
});
_defineProperty(_this, "filterGeomPicked", function (layer, feature) {
_this.setState(function (state) {
return {
geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, {
geom: feature.geometry,
geomType: feature.geometry.type
})
};
});
});
_defineProperty(_this, "toggleHideFilterGeom", function (ev) {
_this.setState(function (state) {
return {
geomFilter: _objectSpread(_objectSpread({}, state.geomFilter), {}, {
hideFilterGeom: ev.target.checked
})
};
});
});
_defineProperty(_this, "toggleFilter", function (filterId, active) {
_this.setState(function (state) {
return {
filters: _objectSpread(_objectSpread({}, state.filters), {}, _defineProperty({}, filterId, _objectSpread(_objectSpread({}, state.filters[filterId]), {}, {
active: active
})))
};
});
});
_defineProperty(_this, "updateFieldValue", function (filterId, fieldId, value) {
_this.setState(function (state) {
return {
filters: _objectSpread(_objectSpread({}, state.filters), {}, _defineProperty({}, filterId, _objectSpread(_objectSpread({}, state.filters[filterId]), {}, {
values: _objectSpread(_objectSpread({}, state.filters[filterId].values), {}, _defineProperty({}, fieldId, value))
})))
};
});
});
_defineProperty(_this, "updateCustomFilter", function (filterId, key, value) {
_this.setState(function (state) {
return {
customFilters: _objectSpread(_objectSpread({}, state.customFilters), {}, _defineProperty({}, filterId, _objectSpread(_objectSpread({}, state.customFilters[filterId]), {}, _defineProperty({}, key, value))))
};
});
});
_defineProperty(_this, "addCustomFilter", function () {
var key = uuidv4();
_this.setState(function (state) {
return {
customFilters: _objectSpread(_objectSpread({}, state.customFilters), {}, _defineProperty({}, key, {
active: false,
title: '',
layer: '',
expr: ''
}))
};
});
});
_defineProperty(_this, "deleteCustomFilter", function (key) {
_this.setState(function (state) {
var newCustomFilters = _objectSpread({}, state.customFilters);
delete newCustomFilters[key];
return {
customFilters: newCustomFilters
};
});
});
_defineProperty(_this, "replaceExpressionVariables", function (expr, values, defaultValues) {
if (expr.length < 3 || expr.length % 2 === 0 || typeof expr[1] !== 'string') {
// Invalid expression: array must have at least three and odd number of entries,
// mid entry must be a string (operator)
return null;
}
var op = expr[1].toLowerCase();
if (typeof expr[0] === 'string') {
if (typeof expr[2] === 'string') {
var right = Object.entries(values).reduce(function (res, _ref7) {
var _ref9;
var _ref8 = _slicedToArray(_ref7, 2),
key = _ref8[0],
value = _ref8[1];
return res.replace("$".concat(key, "$"), (_ref9 = value || defaultValues[key]) !== null && _ref9 !== void 0 ? _ref9 : value);
}, expr[2]);
return [expr[0], op, right];
} else {
return [expr[0], op, expr[2]];
}
} else {
// Even indices must be arrays, odd and|or strings
var isAndOr = function isAndOr(entry) {
return ["and", "or"].includes(String(entry).toLowerCase());
};
var invalid = expr.find(function (entry, idx) {
return idx % 2 === 0 ? !Array.isArray(entry) : !isAndOr(entry);
});
if (invalid) {
return null;
}
return expr.map(function (entry, idx) {
return idx % 2 === 0 ? _this.replaceExpressionVariables(entry, values, defaultValues) : entry;
});
}
});
_this.applyFilterTimeout = null;
return _this;
}
_inherits(MapFilter, _React$Component);
return _createClass(MapFilter, [{
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps, prevState) {
var _this2 = this;
if (this.props.theme !== prevProps.theme) {
var _this$props$startupPa;
// Initialize filter state
var predefinedFilters = this.collectPredefinedFilters(this.props.layers);
var filters = this.initializeFilters(predefinedFilters, {});
var geomFilter = {};
var customFilters = {};
if (!prevProps.theme && (_this$props$startupPa = this.props.startupParams) !== null && _this$props$startupPa !== void 0 && _this$props$startupPa.f) {
try {
var startupConfig = JSON.parse(this.props.startupParams.f);
Object.entries(startupConfig).forEach(function (_ref10) {
var _ref11 = _slicedToArray(_ref10, 2),
filterId = _ref11[0],
values = _ref11[1];
if (filterId in filters) {
filters[filterId].active = true;
Object.entries(values).forEach(function (_ref12) {
var _ref13 = _slicedToArray(_ref12, 2),
fieldId = _ref13[0],
value = _ref13[1];
filters[filterId].values[fieldId] = value;
});
}
});
if ("__geomfilter" in startupConfig) {
geomFilter = {
geomType: "Polygon",
geom: {
type: "Polygon",
coordinates: startupConfig.__geomfilter
}
};
}
if ("__custom" in startupConfig) {
customFilters = startupConfig.__custom.reduce(function (res, entry) {
return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, uuidv4(), {
title: entry.title || "",
layer: entry.layer,
expr: JSON.stringify(entry.expr),
active: true
}));
}, {});
}
} catch (e) {
/* eslint-disable-next-line */
console.log("Error while parsing startup filter");
}
}
this.setState({
filters: filters,
geomFilter: geomFilter,
customFilters: customFilters
});
} else if (this.props.layers !== prevProps.layers) {
var _predefinedFilters = this.collectPredefinedFilters(this.props.layers);
var prevPredefinedFilters = this.collectPredefinedFilters(prevProps.layers);
if (!isEqual(Object.keys(_predefinedFilters).sort(), Object.keys(prevPredefinedFilters).sort())) {
this.setState(function (state) {
return {
filters: _this2.initializeFilters(_predefinedFilters, state.filters)
};
});
}
}
if (this.state.filters !== prevState.filters || this.state.customFilters !== prevState.customFilters || this.state.geomFilter.geom !== prevState.geomFilter.geom) {
clearTimeout(this.applyFilterTimeout);
this.applyFilterTimeout = setTimeout(this.applyFilter, 500);
}
}
}, {
key: "render",
value: function render() {
var _this$state$geomFilte,
_this$state$geomFilte2,
_this3 = this,
_this$state$geomFilte3,
_this$state$geomFilte4;
var button = null;
var taskActive = this.props.currentTask === "MapFilter";
if (this.props.position >= 0) {
var filterActive = !isEmpty(this.props.filter.filterParams) || !!this.props.filter.filterGeom;
var title = LocaleUtils.tr("appmenu.items.MapFilter");
var className = filterActive && this.state.filterInvalid ? "filter-map-button-error" : "";
button = /*#__PURE__*/React.createElement(MapButton, {
active: taskActive,
className: className,
engaged: filterActive && !this.state.filterInvalid,
icon: "filter",
key: "MapFilterButton",
onClick: this.filterMapButtonClicked,
position: this.props.position,
tooltip: title
});
}
var selGeomType = (_this$state$geomFilte = this.state.geomFilter) !== null && _this$state$geomFilte !== void 0 && _this$state$geomFilte.picking ? null : (_this$state$geomFilte2 = this.state.geomFilter) === null || _this$state$geomFilte2 === void 0 ? void 0 : _this$state$geomFilte2.geomType;
return [button, /*#__PURE__*/React.createElement(SideBar, {
icon: "filter",
id: "MapFilter",
key: "MapFilterSidebar",
onHide: this.onSidebarHide,
side: this.props.side,
title: LocaleUtils.tr("appmenu.items.MapFilter"),
width: "20em"
}, function () {
return {
body: _this3.renderBody()
};
}), this.state.geomFilter.picking ? /*#__PURE__*/React.createElement(PickFeature, {
featureFilter: function featureFilter(feature) {
var _feature$geometry;
return ((feature === null || feature === void 0 || (_feature$geometry = feature.geometry) === null || _feature$geometry === void 0 ? void 0 : _feature$geometry.type) || "").endsWith("Polygon");
},
featurePicked: this.filterGeomPicked,
highlightStyle: this.props.highlightStyle,
key: "FeaturePicker"
}) : null, /*#__PURE__*/React.createElement(MapSelection, {
active: taskActive && !!selGeomType,
geomType: selGeomType,
geometry: (_this$state$geomFilte3 = this.state.geomFilter) === null || _this$state$geomFilte3 === void 0 ? void 0 : _this$state$geomFilte3.geom,
geometryChanged: this.setFilterGeometry,
hideGeometry: (_this$state$geomFilte4 = this.state.geomFilter) === null || _this$state$geomFilte4 === void 0 ? void 0 : _this$state$geomFilte4.hideFilterGeom,
key: "MapSelection",
styleOptions: this.props.highlightStyle
})];
}
}]);
}(React.Component);
_defineProperty(MapFilter, "propTypes", {
/** Whether to allow custom filters. */
allowCustomFilters: PropTypes.bool,
/** Whether to allow filter by geometry. Requires the filter_geom plugin from qwc-qgis-server-plugins, and the filter will only be applied to postgis layers. */
allowFilterByGeom: PropTypes.bool,
/** Whether to display the temporal filter if temporal dimensions are found. */
allowFilterByTime: PropTypes.bool,
currentTask: PropTypes.string,
filter: PropTypes.object,
/** The style used for highlighting filter geometries. */
highlightStyle: PropTypes.shape({
/* Stroke color rgba array, i.e. [255, 0, 0, 0.5] */
strokeColor: PropTypes.array,
/* Stroke width */
strokeWidth: PropTypes.number,
/* Stroke dash/gap pattern array. Empty for solid line. */
strokeDash: PropTypes.array,
/* Fill color rgba array, i.e. [255, 0, 0, 0.33] */
fillColor: PropTypes.array
}),
layers: PropTypes.array,
/** The position slot index of the map button, from the bottom (0: bottom slot). Set to -1 to hide the button. */
position: PropTypes.number,
setCurrentTask: PropTypes.func,
setFilter: PropTypes.func,
setPermalinkParameters: PropTypes.func,
/** The side of the application on which to display the sidebar. */
side: PropTypes.string,
startupParams: PropTypes.object,
theme: PropTypes.object
});
_defineProperty(MapFilter, "defaultProps", {
allowFilterByTime: true,
position: 5,
predefinedFilters: [],
highlightStyle: {
strokeColor: [0, 0, 0],
fillColor: [255, 255, 0, 0.25]
}
});
export default connect(function (state) {
return {
currentTask: state.task.id,
theme: state.theme.current,
layers: state.layers.flat,
filter: state.layers.filter,
startupParams: state.localConfig.startupParams
};
}, {
setFilter: setFilter,
setCurrentTask: setCurrentTask,
setPermalinkParameters: setPermalinkParameters
})(MapFilter);