@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
212 lines (211 loc) • 9.08 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { isListFilterOperator, isTwoSidedFilterOperator, isValuelessFilterOperator, logicalFilterOperators } from '../../models/filter.js';
import { DrawingShape } from '../../tools/drawing/drawingFeature.js';
import DrawingState from '../../tools/drawing/drawingState.js';
import { v4 as uuidv4 } from 'uuid';
import WfsFilterCondition from '../../tools/wfs/wfsfiltercondition.js';
import { isAreaLikeGeometryTypeOrUnknown, isGeometry } from '../../models/xmlTypes.js';
import { UsedInTemplateOnly } from '../../decorators.js';
class FilterConditionElement {
context;
id;
applied;
attribute;
attributeDisplayName;
attributeInputType;
availableOperators;
operator;
value;
value2;
choices;
logicalOperator;
filterConditionInstance;
geometryChangeHandler;
static drawingStateLocation = 'advancedFilterDrawing';
drawingState;
spatialOperatorsByDrawingShape = [
{ shape: DrawingShape.Point, supportedOperators: ['contains', 'intersects'] },
{ shape: DrawingShape.Polyline, supportedOperators: ['contains', 'intersects'] },
{ shape: DrawingShape.Polygon, supportedOperators: ['contains', 'intersects', 'within'] },
{ shape: DrawingShape.Square, supportedOperators: ['contains', 'intersects', 'within'] },
{ shape: DrawingShape.Rectangle, supportedOperators: ['contains', 'intersects', 'within'] },
{ shape: DrawingShape.Disk, supportedOperators: ['contains', 'intersects', 'within'] }
];
constructor(context) {
this.context = context;
this.id = uuidv4();
this.applied = false;
if (!this.context.stateManager.state.extendedState[FilterConditionElement.drawingStateLocation]) {
this.context.stateManager.state.extendedState[FilterConditionElement.drawingStateLocation] = new DrawingState();
}
this.drawingState = this.context.stateManager.state.extendedState[FilterConditionElement.drawingStateLocation];
// Init available tools in the drawing toolbar
this.drawingState.tools = this.spatialOperatorsByDrawingShape.map((c) => {
return { shape: c.shape, enabled: false };
});
}
setLogicalOperator(operator) {
this.logicalOperator = logicalFilterOperators.find((op) => op.operator === operator)?.operator;
}
setAttribute(attribute, attributeDisplayName, attributeInputType, availableOperators, choices) {
this.reset();
this.attribute = attribute;
this.attributeDisplayName = attributeDisplayName;
this.attributeInputType = attributeInputType;
this.availableOperators = availableOperators;
this.choices = choices;
this.updateDrawingToolbar();
}
setOperator(operator) {
this.operator = this.availableOperators?.find((op) => op.operator === operator)?.operator;
if (!this.operator) {
console.warn(`Invalid operator ${operator} for attribute ${this.attribute?.name}`);
}
this.updateDrawingToolbar();
}
updateDrawingToolbar() {
if (this.attribute && isGeometry(this.attribute.type)) {
this.context.stateManager.batchChanges(() => {
for (const drawingTool of this.drawingState.tools) {
drawingTool.enabled = this.getSupportedDrawingToolsByOperator(this.operator).includes(drawingTool.shape);
}
});
this.registerGeometryListener();
}
}
getSupportedDrawingToolsByOperator(operator) {
return this.spatialOperatorsByDrawingShape
.filter((c) => (operator ? c.supportedOperators.includes(operator) : false))
.map((c) => c.shape);
}
registerGeometryListener() {
if (this.geometryChangeHandler) {
return;
}
this.geometryChangeHandler = (_old, newFeatures) => {
if (newFeatures.length > 0) {
this.value = JSON.stringify({
...newFeatures[0].geojson,
properties: { tool: DrawingShape[newFeatures[0].type] }
});
}
else {
this.value = undefined;
}
};
this.context.stateManager.subscribe(`extendedState.${FilterConditionElement.drawingStateLocation}.features`, this.geometryChangeHandler);
}
resetDrawingToolbar() {
if (this.geometryChangeHandler) {
this.context.stateManager.unsubscribe(this.geometryChangeHandler);
this.geometryChangeHandler = undefined;
}
// Remove geometry in map
this.drawingState.activeTool = null;
this.drawingState.features = [];
}
reset() {
this.applied = false;
this.attribute = undefined;
this.attributeDisplayName = undefined;
this.attributeInputType = undefined;
this.operator = undefined;
this.value = undefined;
this.value2 = undefined;
this.choices = undefined;
this.availableOperators = undefined;
this.filterConditionInstance = undefined;
this.resetDrawingToolbar();
}
remove() {
this.resetDrawingToolbar();
}
isValid() {
return (!!this.attribute &&
!!this.operator &&
(!!this.value || isValuelessFilterOperator(this.operator)) &&
(!!this.value2 || !isTwoSidedFilterOperator(this.operator)));
}
apply() {
if (this.isValid()) {
this.filterConditionInstance = new WfsFilterCondition(this.attribute.name, this.operator, this.value, this.value2, this.attribute.type);
this.resetDrawingToolbar();
this.applied = true;
}
return this.applied;
}
i18n(key) {
return this.context.i18nManager.getTranslation(key);
}
// Helper functions for UI elements
isOperatorSelectorEnabled() {
return !!this.attribute;
}
isValueInputVisible() {
return (!!this.attribute &&
(!this.operator || (this.operator && !isValuelessFilterOperator(this.operator))) &&
!this.isGeometryToolbarVisible() &&
!this.isChoicesListVisible());
}
isValue2InputVisible() {
return !!this.attribute && !!this.operator && isTwoSidedFilterOperator(this.operator);
}
isChoicesListVisible() {
return !!this.attribute && !!this.choices && !!this.operator && isListFilterOperator(this.operator);
}
isGeometryToolbarVisible() {
return !!this.attribute && this.attributeInputType === 'geometry';
}
/**
* Check if the operator can be used with the current spatial attribute type
*/
isSpatialOperatorEnabled(operator) {
// If the operator isn't `contains`, there is no restriction necessary
if (!this.attribute || operator !== 'contains') {
return true;
}
// `Contains` only makes sense with area like geometry types
return isAreaLikeGeometryTypeOrUnknown(this.attribute.type);
}
/**
* Converts a filter condition to its text representation, using the filterCondition instances
* toTextRepresentation method and adding the logical operator if it is defined.
*/
toText() {
if (!this.filterConditionInstance || !this.attribute) {
return '';
}
const logicalOperator = this.logicalOperator
? logicalFilterOperators.find((op) => op.operator === this.logicalOperator).displayName
: '';
const filterExpression = this.filterConditionInstance.toTextRepresentation(this.context, this.attributeDisplayName);
return `${this.i18n(logicalOperator)} ${filterExpression}`;
}
}
__decorate([
UsedInTemplateOnly()
], FilterConditionElement.prototype, "isOperatorSelectorEnabled", null);
__decorate([
UsedInTemplateOnly()
], FilterConditionElement.prototype, "isValueInputVisible", null);
__decorate([
UsedInTemplateOnly()
], FilterConditionElement.prototype, "isValue2InputVisible", null);
__decorate([
UsedInTemplateOnly()
], FilterConditionElement.prototype, "isChoicesListVisible", null);
__decorate([
UsedInTemplateOnly()
], FilterConditionElement.prototype, "isGeometryToolbarVisible", null);
__decorate([
UsedInTemplateOnly()
], FilterConditionElement.prototype, "isSpatialOperatorEnabled", null);
__decorate([
UsedInTemplateOnly()
], FilterConditionElement.prototype, "toText", null);
export default FilterConditionElement;