qwc2
Version:
QGIS Web Client
365 lines (364 loc) • 18.7 kB
JavaScript
var _FeatureCache, _KeyValCache;
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 _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 _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 _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 _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 _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 _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 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 _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 _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); }
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 nearley from 'nearley';
import toposort from 'toposort';
import { v5 as uuidv5 } from 'uuid';
import StandardApp from '../components/StandardApp';
import ConfigUtils from './ConfigUtils';
import LocaleUtils from './LocaleUtils';
import MiscUtils from './MiscUtils';
import grammar from './expr_grammar/grammar';
var UUID_NS = '5ae5531d-8e21-4456-b45d-77e9840a5bb7';
export var FeatureCache = /*#__PURE__*/_createClass(function FeatureCache() {
_classCallCheck(this, FeatureCache);
});
_FeatureCache = FeatureCache;
_defineProperty(FeatureCache, "store", {});
_defineProperty(FeatureCache, "requestPromises", {});
_defineProperty(FeatureCache, "get", function (editIface, layerName, editConfig, mapCrs, filterExpr) {
var key = layerName + uuidv5(JSON.stringify(filterExpr !== null && filterExpr !== void 0 ? filterExpr : null), UUID_NS);
if (key in _FeatureCache.store) {
return new Promise(function (resolve) {
return resolve(_FeatureCache.store[key]);
});
} else if (key in _FeatureCache.requestPromises) {
return _FeatureCache.requestPromises[key];
} else {
_FeatureCache.requestPromises[key] = new Promise(function (resolve) {
editIface.getFeatures(editConfig, mapCrs, function (result) {
if (key in _FeatureCache.requestPromises) {
if (((result === null || result === void 0 ? void 0 : result.features) || []).length === 1) {
_FeatureCache.store[key] = result.features[0];
} else {
_FeatureCache.store[key] = null;
}
if (key in _FeatureCache.requestPromises) {
resolve(_FeatureCache.store[key]);
delete _FeatureCache.requestPromises[key];
}
} else {
resolve(null);
}
}, null, filterExpr);
});
return _FeatureCache.requestPromises[key];
}
});
_defineProperty(FeatureCache, "getSync", function (editIface, layerName, editConfig, mapCrs, filterExpr) {
var promises = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : [];
var key = layerName + uuidv5(JSON.stringify(filterExpr !== null && filterExpr !== void 0 ? filterExpr : null), UUID_NS);
if (key in _FeatureCache.store) {
return _FeatureCache.store[key];
} else {
promises.push(_FeatureCache.get(editIface, layerName, editConfig, mapCrs, filterExpr));
return null;
}
});
_defineProperty(FeatureCache, "clear", function () {
_FeatureCache.store = {};
_FeatureCache.requests = new Set();
});
export var KeyValCache = /*#__PURE__*/_createClass(function KeyValCache() {
_classCallCheck(this, KeyValCache);
});
_KeyValCache = KeyValCache;
_defineProperty(KeyValCache, "store", {});
_defineProperty(KeyValCache, "requestPromises", {});
_defineProperty(KeyValCache, "get", function (editIface, keyvalrel, filterExpr) {
var key = keyvalrel + uuidv5(JSON.stringify(filterExpr !== null && filterExpr !== void 0 ? filterExpr : null), UUID_NS);
if (key in _KeyValCache.store) {
return new Promise(function (resolve) {
return resolve(_KeyValCache.store[key]);
});
} else if (key in _KeyValCache.requestPromises) {
return _KeyValCache.requestPromises[key];
} else {
_KeyValCache.requestPromises[key] = new Promise(function (resolve) {
editIface.getKeyValues(keyvalrel, function (result) {
if (key in _KeyValCache.requestPromises) {
var dataSet = keyvalrel.split(":")[0];
if (result.keyvalues && result.keyvalues[dataSet]) {
var values = result.keyvalues[dataSet].map(function (entry) {
return {
value: entry.key,
label: entry.value
};
});
_KeyValCache.store[key] = values;
} else {
_KeyValCache.store[key] = [];
}
resolve(_KeyValCache.store[key]);
delete _KeyValCache.requestPromises[key];
} else {
resolve([]);
}
}, filterExpr ? [filterExpr] : null);
});
return _KeyValCache.requestPromises[key];
}
});
_defineProperty(KeyValCache, "getSync", function (editIface, keyvalrel, filterExpr) {
var promises = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
var key = keyvalrel + uuidv5(JSON.stringify(filterExpr !== null && filterExpr !== void 0 ? filterExpr : null), UUID_NS);
if (key in _KeyValCache.store) {
return _KeyValCache.store[key];
} else {
promises.push(_KeyValCache.get(editIface, keyvalrel, filterExpr));
return [];
}
});
_defineProperty(KeyValCache, "clear", function () {
_KeyValCache.store = {};
_KeyValCache.requestPromises = {};
});
function _representValue(attr, editConfig, editIface, promises) {
var _window$qwc2Expressio, _field$constraints;
// Resolve kvrel
var field = (editConfig.fields || []).find(function (f) {
return f.id === attr;
});
var value = (_window$qwc2Expressio = window.qwc2ExpressionParserContext.feature) === null || _window$qwc2Expressio === void 0 || (_window$qwc2Expressio = _window$qwc2Expressio.properties) === null || _window$qwc2Expressio === void 0 ? void 0 : _window$qwc2Expressio[attr];
var keyvalrel = field === null || field === void 0 || (_field$constraints = field.constraints) === null || _field$constraints === void 0 ? void 0 : _field$constraints.keyvalrel;
if (!keyvalrel) {
return value;
}
var keyvals = KeyValCache.getSync(editIface, keyvalrel, null, promises).reduce(function (res, entry) {
return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, entry.value, entry.label));
}, {});
if (field.constraints.allowMulti) {
return '{' + _toConsumableArray(new Set(JSON.parse('[' + value.slice(1, -1) + ']'))).map(function (x) {
var _keyvals$x;
return (_keyvals$x = keyvals[x]) !== null && _keyvals$x !== void 0 ? _keyvals$x : x;
}).join(", ") + '}';
} else {
var _keyvals$value;
return (_keyvals$value = keyvals[value]) !== null && _keyvals$value !== void 0 ? _keyvals$value : value;
}
}
export function parseExpression(expr, feature, editConfig, editIface, mapPrefix, mapCrs, reevaluateCallback) {
var asFilter = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : false;
var reevaluate = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : false;
var parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
var promises = [];
var mapEditConfigs = StandardApp.store.getState().layers.editConfigs[mapPrefix];
window.qwc2ExpressionParserContext = {
feature: feature,
getFeature: function getFeature(layerName, attr, value) {
var _mapEditConfigs$layer;
return FeatureCache.getSync(editIface, layerName, (_mapEditConfigs$layer = mapEditConfigs[layerName]) !== null && _mapEditConfigs$layer !== void 0 ? _mapEditConfigs$layer : {}, mapCrs, [[attr, '=', value]], promises);
},
representValue: function representValue(attr) {
return _representValue(attr, editConfig, editIface, promises);
},
formatDate: MiscUtils.formatDate,
asFilter: asFilter,
username: ConfigUtils.getConfigProp("username"),
layer: editConfig.layerName,
projection: mapCrs,
mapPrefix: mapPrefix,
lang: LocaleUtils.lang()
};
var result = null;
try {
parser.feed(expr.replace(/\n/, ' '));
result = parser.results[0];
} catch (e) {
/* eslint-disable-next-line */
console.warn("Failed to evaluate expression " + expr.replace(/\n/, ' '));
}
delete window.qwc2ExpressionParserContext;
if (promises.length > 0) {
// Expression evaluation is incomplete due to pending feature requests, reevaluate when promises are resolved
Promise.all(promises).then(function () {
return parseExpression(expr, feature, editConfig, editIface, mapPrefix, mapCrs, reevaluateCallback, asFilter, true);
});
return null;
} else {
if (reevaluate) {
reevaluateCallback();
}
if (asFilter) {
result = [result];
}
return result;
}
}
export function parseExpressionsAsync(fieldExpressions, feature, editConfig, editIface, mapPrefix, mapCrs, asFilter) {
var promises = [];
var mapEditConfigs = StandardApp.store.getState().layers.editConfigs[mapPrefix];
return new Promise(function (resolve) {
var newfeature = _objectSpread(_objectSpread({}, feature), {}, {
properties: _objectSpread({}, feature.properties)
});
window.qwc2ExpressionParserContext = {
feature: newfeature,
getFeature: function getFeature(layerName, attr, value) {
var _mapEditConfigs$layer2;
return FeatureCache.getSync(editIface, layerName, (_mapEditConfigs$layer2 = mapEditConfigs[layerName]) !== null && _mapEditConfigs$layer2 !== void 0 ? _mapEditConfigs$layer2 : {}, mapCrs, [[attr, '=', value]], promises);
},
representValue: function representValue(attr) {
return _representValue(attr, editConfig, editIface, promises);
},
asFilter: asFilter,
username: ConfigUtils.getConfigProp("username"),
layer: editConfig.layerName,
projection: mapCrs,
mapPrefix: mapPrefix,
lang: LocaleUtils.lang()
};
var results = fieldExpressions.reduce(function (res, _ref) {
var field = _ref.field,
expression = _ref.expression;
var parser = new nearley.Parser(nearley.Grammar.fromCompiled(grammar));
try {
parser.feed(expression.replace(/\n/, ' '));
// NOTE: include intermediate results in next context feature
newfeature.properties[field] = parser.results[0];
return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, field, parser.results[0]));
} catch (e) {
/* eslint-disable-next-line */
console.warn("Failed to evaluate expression " + expression.replace(/\n/, ' '));
return res;
}
}, {});
delete window.qwc2ExpressionParserContext;
if (promises.length > 0) {
// Expression evaluation is incomplete due to pending feature requests, reevaluate when promises are resolved
Promise.all(promises).then(function () {
parseExpressionsAsync(fieldExpressions, newfeature, editConfig, editIface, mapPrefix, mapCrs, asFilter).then(function (results2) {
return resolve(results2);
});
});
} else {
resolve(results);
}
});
}
var FeatureTemplateFactories = {};
export function setFeatureTemplateFactory(dataset, factory) {
FeatureTemplateFactories[dataset] = factory;
}
export function getFeatureTemplate(editConfig, feature, editIface, mapPrefix, mapCrs, callback) {
if (editConfig.editDataset in FeatureTemplateFactories) {
feature = FeatureTemplateFactories[editConfig.editDataset](feature);
}
// Apply default values
var defaultFieldExpressions = editConfig.fields.reduce(function (res, field) {
if (field.defaultValue && !(field.id in feature.properties)) {
return [].concat(_toConsumableArray(res), [{
field: field.id,
expression: field.defaultValue.replace(/^expr:/, '')
}]);
}
return res;
}, []);
FeatureCache.clear();
parseExpressionsAsync(defaultFieldExpressions, feature, editConfig, editIface, mapPrefix, mapCrs).then(function (result) {
// Adjust values based on field type
editConfig.fields.forEach(function (field) {
if (field.id in result && field.type === "date") {
result[field.id] = result[field.id].split("T")[0];
}
});
callback(_objectSpread(_objectSpread({}, feature), {}, {
properties: _objectSpread(_objectSpread({}, feature.properties), result)
}));
});
}
export function computeExpressionFields(editConfig, feature, editIface, mapCrs, callback) {
// Collect field expressions and dependencies
var dependencies = {};
var fieldExpressions = editConfig.fields.reduce(function (res, field) {
if (field.expression) {
var matches = _toConsumableArray(field.expression.matchAll(/"([^"]+)"/g)).map(function (m) {
return m[1];
});
dependencies[field.id] = _toConsumableArray(new Set(matches));
return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, field.id, field.expression));
}
return res;
}, {});
// Topologically sort expressions so that fields depending on other fields are evaluated later
var edges = [];
var roots = [];
Object.entries(dependencies).forEach(function (_ref2) {
var _ref3 = _slicedToArray(_ref2, 2),
parent = _ref3[0],
children = _ref3[1];
if (children.length > 0) {
children.forEach(function (child) {
return edges.push([child, parent]);
});
} else {
roots.push(parent);
}
});
try {
var sortededges = toposort(edges);
fieldExpressions = roots.concat(sortededges).reduce(function (res, field) {
if (field in fieldExpressions) {
return [].concat(_toConsumableArray(res), [{
field: field,
expression: fieldExpressions[field]
}]);
} else {
return res;
}
}, []);
} catch (e) {
/* eslint-disable-next-line */
console.warn("Failed to sort expressions, they probably contain cyclic dependencies");
fieldExpressions = Object.entries(fieldExpressions).map(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 2),
field = _ref5[0],
expression = _ref5[1];
return {
field: field,
expression: expression
};
}, {});
}
// Evaluate expressions
var mapPrefix = editConfig.editDataset.split(".")[0];
parseExpressionsAsync(fieldExpressions, feature, editConfig, editIface, mapPrefix, mapCrs).then(function (result) {
// Adjust values based on field type
editConfig.fields.forEach(function (field) {
var _field$constraints2;
if ((_field$constraints2 = field.constraints) !== null && _field$constraints2 !== void 0 && _field$constraints2.hidden) {
// Remove hidden fields from result
delete result[field.id];
} else if (field.id in result && field.type === "date") {
result[field.id] = result[field.id].split("T")[0];
}
});
callback(_objectSpread(_objectSpread({}, feature), {}, {
properties: _objectSpread(_objectSpread({}, feature.properties), result)
}));
});
}