@geogirafe/lib-geoportal
Version:
GeoGirafe is a flexible application to build online geoportals.
209 lines (208 loc) • 8.6 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;
};
// SPDX-License-Identifier: Apache-2.0
import LayerWms from '../../models/layers/layerwms.js';
import { filterOperators, logicalFilterOperators } from '../../models/filter.js';
import { v4 as uuidv4 } from 'uuid';
import WfsFilterCondition from '../../tools/wfs/wfsfiltercondition.js';
import WfsFilter from '../../tools/wfs/wfsfilter.js';
import { typeGroupFromAttributeType as xmlTypeGroupByAttributeType } from '../../models/xmlTypes.js';
import { UsedInTemplateOnly } from '../../decorators.js';
import FilterConditionElement from './filterconditionelement.js';
/**
* Represents the state of a filter element in the AdvancedFilterComponent. This class provides functionality
* to store and manage filter conditions, operators, and attributes.
*/
class LayerFilterElement {
id;
layer;
attributes;
conditions;
inverted = false;
attributeChoices = new Map();
attributeTitles = new Map();
context;
columnAliasHelper;
position;
constructor(context, columnAliasHelper, position) {
this.context = context;
this.columnAliasHelper = columnAliasHelper;
this.id = uuidv4();
this.position = position;
this.attributes = [];
this.conditions = [];
}
/**
* Sets the filter element with all conditions from a given layer with an existing filter.
*/
async setFromLayer(layer) {
await this.setLayer(layer);
if (!layer.filter) {
return;
}
this.conditions = [];
this.setConditionsFromLayerRecursively(layer.filter);
}
setConditionsFromLayerRecursively(filterObject) {
if (filterObject.logicalOperator === 'not') {
this.inverted = true;
}
filterObject.conditions.forEach((nestedFilterCondition) => {
if (nestedFilterCondition instanceof WfsFilter) {
this.setConditionsFromLayerRecursively(nestedFilterCondition);
}
else {
this.addCondition();
const cond = this.conditions.at(-1);
this.setAttributeInCondition(cond, nestedFilterCondition.property);
cond.setOperator(nestedFilterCondition.operator);
cond.value = nestedFilterCondition.value;
cond.value2 = nestedFilterCondition.value2;
cond.logicalOperator = filterObject.logicalOperator;
cond.filterConditionInstance = nestedFilterCondition;
cond.applied = true;
}
});
}
get title() {
const title = `${this.i18n('Filter')} ${this.position + 1}`;
if (this.layer) {
return `${title} (${this.i18n(this.layer.name)})`;
}
else {
return title;
}
}
get availableLogicalOperators() {
// Filter out 'not' logical operator, as it is only available as a dedicated button to negate the whole chained expression
return [...logicalFilterOperators].filter((op) => op.operator !== 'not');
}
async setLayer(layer) {
this.attributes = [];
this.attributeChoices = new Map();
this.attributeTitles = new Map();
this.inverted = false;
this.removeConditions();
if (layer) {
this.layer = layer;
this.attributes = await this.context.wfsManager.commonAttributesByLayer(layer, true);
const queryLayer = layer.queryLayers?.split(',')[0] ?? '';
for (const attribute of this.attributes) {
this.attributeTitles.set(attribute.name, this.columnAliasHelper.getColumnAlias(queryLayer, attribute.name));
}
this.attributeChoices = await this.context.wfsManager.getAttributeChoices(layer);
}
// Add an empty condition
this.addCondition();
}
removeConditions() {
for (const condition of this.conditions) {
this.removeCondition(condition);
}
}
addCondition() {
this.conditions.push(new FilterConditionElement(this.context));
}
removeCondition(condition) {
const idx = this.conditions.indexOf(condition);
if (idx !== -1) {
condition.remove();
this.conditions.splice(idx, 1);
}
if (this.conditions.length > 0) {
// Remove the logical operator from the first condition in the list
this.conditions[0].logicalOperator = undefined;
}
}
hasAppliedConditions() {
return this.conditions.some((condition) => condition.applied);
}
hasNoneAppliedConditions() {
return this.conditions.some((condition) => !condition.applied);
}
removeNonAppliedConditions() {
for (const condition of this.conditions) {
if (!condition.applied) {
this.removeCondition(condition);
}
}
}
setAttributeInCondition(condition, attributeName) {
const attribute = this.attributes.find((attr) => attr.name === attributeName);
if (!attribute) {
return;
}
const attributeDisplayName = this.getAttributeDisplayName(attribute);
const attributeInputType = this.getInputTypeByAttributeType(attribute);
let availableOperators = this.getOperatorsByAttributeType(attribute?.type);
let choices = [];
if (this.isEnumeratedAttribute(attributeName)) {
availableOperators = filterOperators.filter((op) => ['in', 'nin', 'nul', 'nnul'].includes(op.operator));
choices = this.attributeChoices.get(attributeName) ?? [];
}
condition.setAttribute(attribute, attributeDisplayName, attributeInputType, availableOperators, choices);
}
isEnumeratedAttribute(attributeName) {
return this.attributeChoices.has(attributeName) && this.attributeChoices.get(attributeName)?.length;
}
getOperatorsByAttributeType(attributeType) {
if (!attributeType) {
return [];
}
return WfsFilterCondition.supportedOperatorsByAttributeType(attributeType);
}
applyFilter() {
let nestedFilter = undefined;
if (!this.layer) {
return nestedFilter;
}
for (const condition of this.conditions) {
if (!condition.applied) {
continue;
}
if (nestedFilter) {
condition.logicalOperator = condition.logicalOperator ?? this.availableLogicalOperators[0].operator;
nestedFilter = new WfsFilter([nestedFilter, condition.filterConditionInstance], condition.logicalOperator);
}
else {
nestedFilter = new WfsFilter([condition.filterConditionInstance]);
}
}
if (nestedFilter && this.inverted) {
nestedFilter = new WfsFilter([nestedFilter], 'not');
}
return nestedFilter;
}
toggleInverted() {
this.inverted = !this.inverted;
}
i18n(key) {
return this.context.i18nManager.getTranslation(key);
}
isLogicalOperatorSelectorVisible(condition) {
// Show a logical operator for all conditions but the first
return this.conditions.indexOf(condition) > 0; // NOSONAR: This check does exactly what it should do
}
getInputTypeByAttributeType(attr) {
if (!attr?.type) {
return 'string';
}
if (this.layer instanceof LayerWms) {
return xmlTypeGroupByAttributeType(attr.type) || 'string';
}
return 'string';
}
getAttributeDisplayName(attribute) {
const attributeName = this.attributeTitles.get(attribute.name) ?? attribute.name;
const attrType = this.isEnumeratedAttribute(attribute.name) ? 'list' : attribute.type;
return `${this.i18n(attributeName)} [${this.i18n('datatype-' + attrType)}]`;
}
}
__decorate([
UsedInTemplateOnly()
], LayerFilterElement.prototype, "isLogicalOperatorSelectorVisible", null);
export default LayerFilterElement;