ol-wfst 3.0.4 → 4.0.0

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 (140) hide show
  1. package/CHANGELOG.md +88 -67
  2. package/LICENSE.md +21 -0
  3. package/README.md +548 -173
  4. package/dist/@enums.d.ts +5 -0
  5. package/dist/@enums.d.ts.map +1 -1
  6. package/dist/@types.d.ts +163 -0
  7. package/dist/@types.d.ts.map +1 -0
  8. package/dist/Geoserver.d.ts +260 -0
  9. package/dist/Geoserver.d.ts.map +1 -0
  10. package/dist/WfsLayer.d.ts +40 -0
  11. package/dist/WfsLayer.d.ts.map +1 -0
  12. package/dist/WmsLayer.d.ts +48 -0
  13. package/dist/WmsLayer.d.ts.map +1 -0
  14. package/dist/css/ol-wfst.bootstrap5.css +364 -481
  15. package/dist/css/ol-wfst.bootstrap5.min.css +1 -1
  16. package/dist/css/ol-wfst.css +22 -18
  17. package/dist/css/ol-wfst.min.css +1 -1
  18. package/dist/defaults.d.ts +4 -0
  19. package/dist/defaults.d.ts.map +1 -0
  20. package/dist/modules/EditControlChanges.d.ts +18 -0
  21. package/dist/modules/EditControlChanges.d.ts.map +1 -0
  22. package/dist/modules/EditFieldsModal.d.ts +18 -0
  23. package/dist/modules/EditFieldsModal.d.ts.map +1 -0
  24. package/dist/modules/EditOverlay.d.ts +7 -0
  25. package/dist/modules/EditOverlay.d.ts.map +1 -0
  26. package/dist/modules/LayersControl.d.ts +35 -0
  27. package/dist/modules/LayersControl.d.ts.map +1 -0
  28. package/dist/modules/Modes/WfsSource.d.ts +60 -0
  29. package/dist/modules/Modes/WfsSource.d.ts.map +1 -0
  30. package/dist/modules/Modes/WmsSource.d.ts +82 -0
  31. package/dist/modules/Modes/WmsSource.d.ts.map +1 -0
  32. package/dist/modules/Modes/baseLayer.d.ts +62 -0
  33. package/dist/modules/Modes/baseLayer.d.ts.map +1 -0
  34. package/dist/modules/Modes/baseSource.d.ts +103 -0
  35. package/dist/modules/Modes/baseSource.d.ts.map +1 -0
  36. package/dist/modules/Uploads.d.ts +47 -0
  37. package/dist/modules/Uploads.d.ts.map +1 -0
  38. package/dist/modules/editLayer.d.ts +4 -0
  39. package/dist/modules/editLayer.d.ts.map +1 -0
  40. package/dist/modules/errors.d.ts +11 -0
  41. package/dist/modules/errors.d.ts.map +1 -0
  42. package/dist/modules/helpers.d.ts +7 -0
  43. package/dist/modules/helpers.d.ts.map +1 -0
  44. package/dist/{assets → modules}/i18n/en.d.ts +0 -0
  45. package/dist/modules/i18n/en.d.ts.map +1 -0
  46. package/dist/{assets → modules}/i18n/es.d.ts +0 -0
  47. package/dist/modules/i18n/es.d.ts.map +1 -0
  48. package/dist/modules/i18n/index.d.ts +15 -0
  49. package/dist/modules/i18n/index.d.ts.map +1 -0
  50. package/dist/{assets → modules}/i18n/zh.d.ts +0 -0
  51. package/dist/modules/i18n/zh.d.ts.map +1 -0
  52. package/dist/modules/loading.d.ts +3 -0
  53. package/dist/modules/loading.d.ts.map +1 -0
  54. package/dist/modules/state.d.ts +22 -0
  55. package/dist/modules/state.d.ts.map +1 -0
  56. package/dist/modules/styleFunction.d.ts +13 -0
  57. package/dist/modules/styleFunction.d.ts.map +1 -0
  58. package/dist/myPragma.d.ts +2 -0
  59. package/dist/myPragma.d.ts.map +1 -0
  60. package/dist/ol-wfst.d.ts +89 -315
  61. package/dist/ol-wfst.d.ts.map +1 -1
  62. package/dist/ol-wfst.js +6368 -5113
  63. package/dist/ol-wfst.js.map +1 -1
  64. package/dist/ol-wfst.min.js +1 -15
  65. package/dist/ol-wfst.min.js.map +1 -1
  66. package/dist/tsconfig.tsbuildinfo +1 -1
  67. package/lib/@enums.d.ts +5 -0
  68. package/lib/@enums.d.ts.map +1 -1
  69. package/lib/@types.d.ts +163 -0
  70. package/lib/@types.d.ts.map +1 -0
  71. package/lib/Geoserver.d.ts +260 -0
  72. package/lib/Geoserver.d.ts.map +1 -0
  73. package/lib/WfsLayer.d.ts +40 -0
  74. package/lib/WfsLayer.d.ts.map +1 -0
  75. package/lib/WmsLayer.d.ts +48 -0
  76. package/lib/WmsLayer.d.ts.map +1 -0
  77. package/lib/defaults.d.ts +4 -0
  78. package/lib/defaults.d.ts.map +1 -0
  79. package/lib/index-es.js +3008 -0
  80. package/lib/index-es.js.map +1 -0
  81. package/lib/modules/EditControlChanges.d.ts +18 -0
  82. package/lib/modules/EditControlChanges.d.ts.map +1 -0
  83. package/lib/modules/EditFieldsModal.d.ts +18 -0
  84. package/lib/modules/EditFieldsModal.d.ts.map +1 -0
  85. package/lib/modules/EditOverlay.d.ts +7 -0
  86. package/lib/modules/EditOverlay.d.ts.map +1 -0
  87. package/lib/modules/LayersControl.d.ts +35 -0
  88. package/lib/modules/LayersControl.d.ts.map +1 -0
  89. package/lib/modules/Modes/WfsSource.d.ts +60 -0
  90. package/lib/modules/Modes/WfsSource.d.ts.map +1 -0
  91. package/lib/modules/Modes/WmsSource.d.ts +82 -0
  92. package/lib/modules/Modes/WmsSource.d.ts.map +1 -0
  93. package/lib/modules/Modes/baseLayer.d.ts +62 -0
  94. package/lib/modules/Modes/baseLayer.d.ts.map +1 -0
  95. package/lib/modules/Modes/baseSource.d.ts +103 -0
  96. package/lib/modules/Modes/baseSource.d.ts.map +1 -0
  97. package/lib/modules/Uploads.d.ts +47 -0
  98. package/lib/modules/Uploads.d.ts.map +1 -0
  99. package/lib/modules/editLayer.d.ts +4 -0
  100. package/lib/modules/editLayer.d.ts.map +1 -0
  101. package/lib/modules/errors.d.ts +11 -0
  102. package/lib/modules/errors.d.ts.map +1 -0
  103. package/lib/modules/helpers.d.ts +7 -0
  104. package/lib/modules/helpers.d.ts.map +1 -0
  105. package/lib/{assets → modules}/i18n/en.d.ts +0 -0
  106. package/lib/modules/i18n/en.d.ts.map +1 -0
  107. package/lib/{assets → modules}/i18n/es.d.ts +0 -0
  108. package/lib/modules/i18n/es.d.ts.map +1 -0
  109. package/lib/modules/i18n/index.d.ts +15 -0
  110. package/lib/modules/i18n/index.d.ts.map +1 -0
  111. package/lib/{assets → modules}/i18n/zh.d.ts +0 -0
  112. package/lib/modules/i18n/zh.d.ts.map +1 -0
  113. package/lib/modules/loading.d.ts +3 -0
  114. package/lib/modules/loading.d.ts.map +1 -0
  115. package/lib/modules/state.d.ts +22 -0
  116. package/lib/modules/state.d.ts.map +1 -0
  117. package/lib/modules/styleFunction.d.ts +13 -0
  118. package/lib/modules/styleFunction.d.ts.map +1 -0
  119. package/lib/myPragma.d.ts +2 -0
  120. package/lib/myPragma.d.ts.map +1 -0
  121. package/lib/ol-wfst.d.ts +89 -315
  122. package/lib/ol-wfst.d.ts.map +1 -1
  123. package/lib/style/css/ol-gisify.css +22 -18
  124. package/lib/style/css/ol-wfst.bootstrap5.css +364 -481
  125. package/lib/style/scss/_variables.scss +17 -0
  126. package/lib/style/scss/ol-wfst.scss +31 -28
  127. package/lib/tsconfig.tsbuildinfo +1 -1
  128. package/package.json +71 -70
  129. package/dist/assets/i18n/en.d.ts.map +0 -1
  130. package/dist/assets/i18n/es.d.ts.map +0 -1
  131. package/dist/assets/i18n/index.d.ts +0 -4
  132. package/dist/assets/i18n/index.d.ts.map +0 -1
  133. package/dist/assets/i18n/zh.d.ts.map +0 -1
  134. package/lib/assets/i18n/en.d.ts.map +0 -1
  135. package/lib/assets/i18n/es.d.ts.map +0 -1
  136. package/lib/assets/i18n/index.d.ts +0 -4
  137. package/lib/assets/i18n/index.d.ts.map +0 -1
  138. package/lib/assets/i18n/zh.d.ts.map +0 -1
  139. package/lib/ol-wfst.js +0 -2259
  140. package/lib/ol-wfst.js.map +0 -1
@@ -0,0 +1,3008 @@
1
+ import { Style, Stroke, Fill, Circle } from 'ol/style';
2
+ import { Control } from 'ol/control';
3
+ import { Modify, Snap, Select, Draw } from 'ol/interaction';
4
+ import { Observable, Feature, Overlay, Collection } from 'ol';
5
+ import BaseEvent from 'ol/events/Event';
6
+ import { primaryAction, never } from 'ol/events/condition';
7
+ import { unByKey } from 'ol/Observable';
8
+ import Modal from 'modal-vanilla';
9
+ import VectorLayer from 'ol/layer/Vector';
10
+ import { Mixin } from 'ts-mixer';
11
+ import Layer from 'ol/layer/Base';
12
+ import GeoJSON from 'ol/format/GeoJSON';
13
+ import VectorSource, { VectorSourceEvent } from 'ol/source/Vector';
14
+ import { transformExtent } from 'ol/proj';
15
+ import { bbox } from 'ol/loadingstrategy';
16
+ import BaseObject from 'ol/Object';
17
+ import TileLayer from 'ol/layer/Tile';
18
+ import { GeoJSON as GeoJSON$1, WFS, KML } from 'ol/format';
19
+ import TileWMS from 'ol/source/TileWMS';
20
+ import TileState from 'ol/TileState';
21
+ import { MultiPolygon, MultiLineString, MultiPoint, GeometryCollection, Polygon, Circle as Circle$1 } from 'ol/geom';
22
+ import { fromCircle } from 'ol/geom/Polygon';
23
+ import { getCenter } from 'ol/extent';
24
+
25
+ // External
26
+ let options = {};
27
+ // Store layerNames that has errors
28
+ const isError = new Set();
29
+ const initModal = (opts) => {
30
+ options = opts;
31
+ };
32
+ const parseError = (geoserverError) => {
33
+ if ('exceptions' in geoserverError) {
34
+ return geoserverError.exceptions.map((e) => e.text).join(',');
35
+ }
36
+ else {
37
+ return '';
38
+ }
39
+ };
40
+ /**
41
+ * Show modal with errors
42
+ *
43
+ * @param msg
44
+ * @private
45
+ */
46
+ const showError = (msg, originalError = null, layerName = '') => {
47
+ // Prevent multiples modals error in the same layer
48
+ if (isError.has(layerName)) {
49
+ return;
50
+ }
51
+ isError.add(layerName);
52
+ let err_msg = `<b>Error: ${msg}</b>`;
53
+ if (originalError) {
54
+ console.log(originalError);
55
+ //err_msg += `. ${originalError.message}`;
56
+ }
57
+ const al = Modal.alert(err_msg, options);
58
+ al.show();
59
+ al.on('hidden', () => {
60
+ isError.delete(layerName);
61
+ });
62
+ };
63
+
64
+ const es = {
65
+ labels: {
66
+ select: 'Seleccionar',
67
+ addElement: 'Modo dibujo',
68
+ editElement: 'Editar elemento',
69
+ save: 'Guardar',
70
+ delete: 'Eliminar',
71
+ cancel: 'Cancelar',
72
+ apply: 'Aplicar cambios',
73
+ upload: 'Subir',
74
+ editMode: 'Modo Edición',
75
+ confirmDelete: '¿Estás seguro de borrar el elemento?',
76
+ geomTypeNotSupported: 'Geometría no compatible con la capa',
77
+ editFields: 'Editar campos',
78
+ editGeom: 'Editar geometría',
79
+ selectDrawType: 'Tipo de geometría para dibujar',
80
+ uploadToLayer: 'Subir archivo a la capa seleccionada',
81
+ uploadFeatures: 'Subida de elementos a la capa',
82
+ validFeatures: 'Válidas',
83
+ invalidFeatures: 'Invalidas',
84
+ loading: 'Cargando...',
85
+ toggleVisibility: 'Cambiar visibilidad de la capa',
86
+ close: 'Cerrar'
87
+ },
88
+ errors: {
89
+ capabilities: 'No se pudieron obtener las Capabilidades del GeoServer',
90
+ wfst: 'El GeoServer no tiene soporte a Transacciones',
91
+ layer: 'No se pudieron obtener datos de la capa',
92
+ layerNotFound: 'Capa no encontrada',
93
+ layerNotVisible: 'La capa no está visible',
94
+ noValidGeometry: 'No se encontraron geometrías válidas para agregar a esta capa',
95
+ geoserver: 'No se pudieron obtener datos desde el GeoServer',
96
+ badFormat: 'Formato no soportado',
97
+ badFile: 'Error al leer elementos del archivo',
98
+ lockFeature: 'No se pudieron bloquear elementos en el GeoServer.',
99
+ transaction: 'Error al hacer transacción con el GeoServer.',
100
+ getFeatures: 'Error al obtener elemento desde el GeoServer.'
101
+ }
102
+ };
103
+
104
+ const en = {
105
+ labels: {
106
+ select: 'Select',
107
+ addElement: 'Toggle Draw mode',
108
+ editElement: 'Edit feature',
109
+ save: 'Save',
110
+ delete: 'Delete',
111
+ cancel: 'Cancel',
112
+ apply: 'Apply changes',
113
+ upload: 'Upload',
114
+ editMode: 'Edit Mode',
115
+ confirmDelete: 'Are you sure to delete the feature?',
116
+ geomTypeNotSupported: 'Geometry not supported by layer',
117
+ editFields: 'Edit fields',
118
+ editGeom: 'Edit geometry',
119
+ selectDrawType: 'Geometry type to draw',
120
+ uploadToLayer: 'Upload file to selected layer',
121
+ uploadFeatures: 'Uploaded features to layer',
122
+ validFeatures: 'Valid geometries',
123
+ invalidFeatures: 'Invalid',
124
+ loading: 'Loading...',
125
+ toggleVisibility: 'Toggle layer visibility',
126
+ close: 'Close'
127
+ },
128
+ errors: {
129
+ capabilities: 'GeoServer Capabilities could not be downloaded.',
130
+ wfst: 'The GeoServer does not support Transactions',
131
+ layer: 'Could not get data from layer',
132
+ layerNotFound: 'Layer not found',
133
+ layerNotVisible: 'Layer is not visible',
134
+ noValidGeometry: 'No valid geometries found to add to this layer',
135
+ geoserver: 'Failed to get data from GeoServer',
136
+ badFormat: 'Unsupported format',
137
+ badFile: 'Error reading items from file',
138
+ lockFeature: 'Could not lock items on the GeoServer.',
139
+ transaction: 'Error when doing Transaction with GeoServer.',
140
+ getFeatures: 'Error getting elements from GeoServer.'
141
+ }
142
+ };
143
+
144
+ const zh = {
145
+ labels: {
146
+ select: '选择',
147
+ addElement: '切换绘图类型',
148
+ editElement: '编辑元素',
149
+ save: '保存',
150
+ delete: '删除',
151
+ cancel: '取消',
152
+ apply: '确认并应用改变',
153
+ upload: '上传',
154
+ editMode: '编辑模式',
155
+ confirmDelete: '确认删除元素?',
156
+ geomTypeNotSupported: '图层不支持该几何',
157
+ editFields: '编辑区域',
158
+ editGeom: '编辑几何',
159
+ selectDrawType: '几何类型',
160
+ uploadToLayer: '通过文件上传图层',
161
+ uploadFeatures: '上传元素到图层',
162
+ validFeatures: '合法的几何类型',
163
+ invalidFeatures: '不合法',
164
+ loading: '加载中...',
165
+ toggleVisibility: '切换图层透明度',
166
+ close: '关闭'
167
+ },
168
+ errors: {
169
+ capabilities: '无法加载GeoServer服务所支持的能力.',
170
+ wfst: 'GeoServer不支持事务',
171
+ layer: '无法从图层获得数据',
172
+ layerNotFound: 'Layer not found',
173
+ layerNotVisible: 'Layer is not visible',
174
+ noValidGeometry: '不支持的几何类型无法加载到图层',
175
+ geoserver: '无法从GeoServer获取数据',
176
+ badFormat: '不支持的格式',
177
+ badFile: '读取文件数据出错',
178
+ lockFeature: '无法锁定GeoServer上的元素.',
179
+ transaction: 'GeoServer处理事务出错.',
180
+ getFeatures: '从GeoServer获取元素出错.'
181
+ }
182
+ };
183
+
184
+ const langs = {
185
+ es,
186
+ en,
187
+ zh
188
+ };
189
+ // Set default Language
190
+ let I18N = en;
191
+ const setLang = (lang = 'en', customI18n = null) => {
192
+ // Check if language exists
193
+ if (lang in langs) {
194
+ I18N = langs[lang];
195
+ }
196
+ // Check if customs translations are provided
197
+ if (customI18n) {
198
+ I18N = { ...I18N, ...customI18n };
199
+ }
200
+ };
201
+
202
+ let loadingDiv;
203
+ const initLoading = () => {
204
+ loadingDiv = document.createElement('div');
205
+ loadingDiv.className = 'ol-wfst--tools-control--loading';
206
+ loadingDiv.innerHTML = I18N.labels.loading;
207
+ return loadingDiv;
208
+ };
209
+ const showLoading = (bool = true) => {
210
+ if (bool) {
211
+ loadingDiv.classList.add('ol-wfst--tools-control--loading-show');
212
+ }
213
+ else {
214
+ loadingDiv.classList.remove('ol-wfst--tools-control--loading-show');
215
+ }
216
+ };
217
+
218
+ var GeometryType;
219
+ (function (GeometryType) {
220
+ GeometryType["Point"] = "Point";
221
+ GeometryType["LineString"] = "LineString";
222
+ GeometryType["LinearRing"] = "LinearRing";
223
+ GeometryType["Polygon"] = "Polygon";
224
+ GeometryType["MultiPoint"] = "MultiPoint";
225
+ GeometryType["MultiLineString"] = "MultiLineString";
226
+ GeometryType["MultiPolygon"] = "MultiPolygon";
227
+ GeometryType["GeometryCollection"] = "GeometryCollection";
228
+ GeometryType["Circle"] = "Circle";
229
+ })(GeometryType || (GeometryType = {}));
230
+ var TransactionType;
231
+ (function (TransactionType) {
232
+ TransactionType["Insert"] = "insert";
233
+ TransactionType["Delete"] = "delete";
234
+ TransactionType["Update"] = "update";
235
+ })(TransactionType || (TransactionType = {}));
236
+
237
+ let map;
238
+ let layerToInsertElements = null;
239
+ let mode = null;
240
+ var Modes;
241
+ (function (Modes) {
242
+ Modes["Edit"] = "EDIT";
243
+ Modes["Draw"] = "DRAW";
244
+ })(Modes || (Modes = {}));
245
+ function activateMode(m = null) {
246
+ mode = m;
247
+ }
248
+ function getMode() {
249
+ return mode;
250
+ }
251
+ const editedFeatures = new Set();
252
+ const mapLayers = {};
253
+ function setMap(m) {
254
+ map = m;
255
+ }
256
+ function getMap() {
257
+ return map;
258
+ }
259
+ function setActiveLayerToInsertEls(layer) {
260
+ layerToInsertElements = layer;
261
+ }
262
+ function getActiveLayerToInsertEls() {
263
+ return layerToInsertElements;
264
+ }
265
+ function setMapLayers(data) {
266
+ Object.assign(mapLayers, data);
267
+ }
268
+ function getStoredMapLayers() {
269
+ return mapLayers;
270
+ }
271
+ function getStoredLayer(layerName) {
272
+ return getStoredMapLayers()[layerName];
273
+ }
274
+ function addFeatureToEditedList(feature) {
275
+ editedFeatures.add(String(feature.getId()));
276
+ }
277
+ function removeFeatureFromEditList(feature) {
278
+ editedFeatures.delete(String(feature.getId()));
279
+ }
280
+ function isFeatureEdited(feature) {
281
+ return editedFeatures.has(String(feature.getId()));
282
+ }
283
+
284
+ /**
285
+ * Base class from which all layer types are derived.
286
+ */
287
+ class BaseLayer extends Layer {
288
+ /**
289
+ * @private
290
+ */
291
+ _init() {
292
+ const geoserver = this.getGeoserver();
293
+ if (geoserver.isLoaded()) {
294
+ this.getAndUpdateDescribeFeatureType();
295
+ }
296
+ else {
297
+ geoserver.on('change:capabilities', () => {
298
+ this.getAndUpdateDescribeFeatureType();
299
+ });
300
+ }
301
+ }
302
+ /**
303
+ * Request and store data layers obtained by DescribeFeatureType
304
+ *
305
+ * @public
306
+ */
307
+ async getAndUpdateDescribeFeatureType() {
308
+ const layerName = this.get(BaseLayerProperty.NAME);
309
+ const layerLabel = this.get(BaseLayerProperty.LABEL);
310
+ try {
311
+ const geoserver = this.getGeoserver();
312
+ const params = new URLSearchParams({
313
+ service: 'wfs',
314
+ version: geoserver.getAdvanced().describeFeatureTypeVersion,
315
+ request: 'DescribeFeatureType',
316
+ typeName: layerName,
317
+ outputFormat: 'application/json',
318
+ exceptions: 'application/json'
319
+ });
320
+ const url_fetch = geoserver.getUrl() + '?' + params.toString();
321
+ const response = await fetch(url_fetch, {
322
+ headers: geoserver.getHeaders(),
323
+ credentials: geoserver.getCredentials()
324
+ });
325
+ if (!response.ok) {
326
+ throw new Error('');
327
+ }
328
+ const data = await response.json();
329
+ if (!data) {
330
+ throw new Error('');
331
+ }
332
+ const targetNamespace = data.targetNamespace;
333
+ const properties = data.featureTypes[0].properties;
334
+ // Find the geometry field
335
+ const geom = properties.find((el) => el.type.indexOf('gml:') >= 0);
336
+ data._parsed = {
337
+ namespace: targetNamespace,
338
+ properties: properties,
339
+ geomType: geom.localType,
340
+ geomField: geom.name
341
+ };
342
+ this.set(BaseLayerProperty.DESCRIBEFEATURETYPE, data);
343
+ }
344
+ catch (err) {
345
+ console.error(err);
346
+ throw new Error(`${I18N.errors.layer} "${layerLabel}"`);
347
+ }
348
+ }
349
+ /**
350
+ * @public
351
+ * @returns
352
+ */
353
+ isVisibleByZoom() {
354
+ return getMap().getView().getZoom() > this.getMinZoom();
355
+ }
356
+ /**
357
+ *
358
+ * @param mode
359
+ * @param features
360
+ * @public
361
+ */
362
+ async transactFeatures(mode, features) {
363
+ const geoserver = this.getGeoserver();
364
+ return geoserver.transact(mode, features, this.get(BaseLayerProperty.NAME));
365
+ }
366
+ async insertFeatures(features) {
367
+ return this.transactFeatures(TransactionType.Insert, features);
368
+ }
369
+ /**
370
+ * @public
371
+ * @param featureId
372
+ * @returns
373
+ */
374
+ async maybeLockFeature(featureId) {
375
+ const geoserver = this.getGeoserver();
376
+ if (geoserver.getUseLockFeature() && geoserver.hasLockFeature()) {
377
+ return await geoserver.lockFeature(featureId, this.get(BaseLayerProperty.NAME));
378
+ }
379
+ return null;
380
+ }
381
+ /**
382
+ *
383
+ * @returns
384
+ * @public
385
+ */
386
+ getGeoserver() {
387
+ return this.get(BaseLayerProperty.GEOSERVER);
388
+ }
389
+ /**
390
+ *
391
+ * @returns
392
+ * @public
393
+ */
394
+ getDescribeFeatureType() {
395
+ return this.get(BaseLayerProperty.DESCRIBEFEATURETYPE);
396
+ }
397
+ }
398
+ var BaseLayerProperty;
399
+ (function (BaseLayerProperty) {
400
+ BaseLayerProperty["NAME"] = "name";
401
+ BaseLayerProperty["LABEL"] = "label";
402
+ BaseLayerProperty["DESCRIBEFEATURETYPE"] = "describeFeatureType";
403
+ BaseLayerProperty["ISVISIBLE"] = "isVisible";
404
+ BaseLayerProperty["GEOSERVER"] = "geoserver";
405
+ })(BaseLayerProperty || (BaseLayerProperty = {}));
406
+
407
+ class BaseSource extends BaseObject {
408
+ /**
409
+ * @public
410
+ * @param value
411
+ * @param opt_silent
412
+ */
413
+ setCqlFilter(value, opt_silent) {
414
+ this.set(BaseSourceProperty.CQLFILTER, value, opt_silent);
415
+ }
416
+ /**
417
+ * @public
418
+ * @returns
419
+ */
420
+ getCqlFilter() {
421
+ return this.get(BaseSourceProperty.CQLFILTER);
422
+ }
423
+ /**
424
+ * @public
425
+ * @param value
426
+ * @param opt_silent
427
+ */
428
+ setSortBy(value, opt_silent) {
429
+ this.set(BaseSourceProperty.SORTBY, value, opt_silent);
430
+ }
431
+ /**
432
+ * @public
433
+ * @returns
434
+ */
435
+ getSortBy() {
436
+ return this.get(BaseSourceProperty.SORTBY);
437
+ }
438
+ /**
439
+ * @public
440
+ * @param value
441
+ * @param opt_silent
442
+ */
443
+ setFeatureId(value, opt_silent) {
444
+ this.set(BaseSourceProperty.FEATUREID, value, opt_silent);
445
+ }
446
+ /**
447
+ * @public
448
+ * @returns
449
+ */
450
+ getFeatureId() {
451
+ return this.get(BaseSourceProperty.FEATUREID);
452
+ }
453
+ /**
454
+ * @public
455
+ * @param value
456
+ * @param opt_silent
457
+ */
458
+ setFilter(value, opt_silent) {
459
+ this.set(BaseSourceProperty.FILTER, value, opt_silent);
460
+ }
461
+ /**
462
+ * @public
463
+ * @returns
464
+ */
465
+ getFilter() {
466
+ return this.get(BaseSourceProperty.FILTER);
467
+ }
468
+ /**
469
+ * @public
470
+ * @param value
471
+ * @param opt_silent
472
+ */
473
+ setFormatOptions(value, opt_silent) {
474
+ this.set(BaseSourceProperty.FORMATOPTIONS, value, opt_silent);
475
+ }
476
+ /**
477
+ * @public
478
+ * @returns
479
+ */
480
+ getFormatOptions() {
481
+ return this.get(BaseSourceProperty.FORMATOPTIONS);
482
+ }
483
+ /**
484
+ * @public
485
+ * @param value
486
+ * @param opt_silent
487
+ */
488
+ setMaxFeatures(value, opt_silent) {
489
+ this.set(BaseSourceProperty.MAXFEATURES, value, opt_silent);
490
+ }
491
+ /**
492
+ * @public
493
+ * @returns
494
+ */
495
+ getMaxFeatures() {
496
+ return this.get(BaseSourceProperty.MAXFEATURES);
497
+ }
498
+ /**
499
+ * @public
500
+ * @param value
501
+ * @param opt_silent
502
+ */
503
+ setStartIndex(value, opt_silent) {
504
+ this.set(BaseSourceProperty.STARTINDEX, value, opt_silent);
505
+ }
506
+ /**
507
+ * @public
508
+ * @returns
509
+ */
510
+ getStartIndex() {
511
+ return this.get(BaseSourceProperty.STARTINDEX);
512
+ }
513
+ /**
514
+ * @public
515
+ * @param value
516
+ * @param opt_silent
517
+ */
518
+ setPropertyName(value, opt_silent) {
519
+ this.set(BaseSourceProperty.PROPERTYNAME, value, opt_silent);
520
+ }
521
+ /**
522
+ * @public
523
+ * @returns
524
+ */
525
+ getPropertyName() {
526
+ return this.get(BaseSourceProperty.PROPERTYNAME);
527
+ }
528
+ }
529
+ var BaseSourceProperty;
530
+ (function (BaseSourceProperty) {
531
+ BaseSourceProperty["CQLFILTER"] = "cql_filter";
532
+ BaseSourceProperty["SORTBY"] = "sortBy";
533
+ BaseSourceProperty["FEATUREID"] = "featureid";
534
+ BaseSourceProperty["FILTER"] = "filter";
535
+ BaseSourceProperty["FORMATOPTIONS"] = "format_options";
536
+ BaseSourceProperty["MAXFEATURES"] = "maxFeatures";
537
+ BaseSourceProperty["STARTINDEX"] = "startIndex";
538
+ BaseSourceProperty["PROPERTYNAME"] = "propertyname";
539
+ })(BaseSourceProperty || (BaseSourceProperty = {}));
540
+
541
+ class WfsSource extends Mixin(VectorSource, BaseSource) {
542
+ geoserverProps_ = [
543
+ 'cql_filter',
544
+ 'filter',
545
+ 'orderBy',
546
+ 'maxFeatures',
547
+ 'startIndex',
548
+ 'featureid',
549
+ 'format_options',
550
+ 'propertyname',
551
+ 'strict'
552
+ ];
553
+ urlParams_ = new URLSearchParams({
554
+ SERVICE: 'wfs',
555
+ REQUEST: 'GetFeature',
556
+ OUTPUTFORMAT: 'application/json',
557
+ EXCEPTIONS: 'application/json'
558
+ });
559
+ constructor(options) {
560
+ super({
561
+ ...options,
562
+ format: new GeoJSON(),
563
+ loader: async (extent, resolution, projection, success, failure) => {
564
+ try {
565
+ // If bbox, add extent to the request
566
+ if (options.strategy == bbox) {
567
+ const extentGeoServer = transformExtent(extent, projection.getCode(), options.geoServerAdvanced.projection);
568
+ // https://docs.geoserver.org/stable/en/user/services/wfs/reference.html
569
+ // request features using a bounding box with CRS maybe different from featureTypes native CRS
570
+ this.urlParams_.set('bbox', extentGeoServer.toString() +
571
+ `,${options.geoServerAdvanced.projection}`);
572
+ }
573
+ const cqlFilter = this.getCqlFilter();
574
+ if (cqlFilter) {
575
+ this.urlParams_.set('cql_filter', cqlFilter);
576
+ }
577
+ const sortBy = this.getSortBy();
578
+ if (sortBy) {
579
+ this.urlParams_.set('sortBy', sortBy);
580
+ }
581
+ const filter = this.getFilter();
582
+ if (filter) {
583
+ this.urlParams_.set('filter', filter);
584
+ }
585
+ const featureId = this.getFeatureId();
586
+ if (featureId) {
587
+ this.urlParams_.set('featureid', featureId);
588
+ }
589
+ const formatOptions = this.getFormatOptions();
590
+ if (formatOptions) {
591
+ this.urlParams_.set('formatOptions', formatOptions);
592
+ }
593
+ const maxFeatures = this.getMaxFeatures();
594
+ if (maxFeatures) {
595
+ this.urlParams_.set('maxFeatures', String(maxFeatures));
596
+ }
597
+ const startIndex = this.getStartIndex();
598
+ if (startIndex) {
599
+ this.urlParams_.set('startIndex', String(startIndex));
600
+ }
601
+ const propertyName = this.getPropertyName();
602
+ if (propertyName) {
603
+ this.urlParams_.set('propertyname', propertyName);
604
+ }
605
+ const strict = this.getStrict();
606
+ if (strict !== undefined) {
607
+ this.urlParams_.set('strict', String(strict));
608
+ }
609
+ const url_fetch = options.geoserverUrl + '?' + this.urlParams_.toString();
610
+ const response = await fetch(url_fetch, {
611
+ headers: options.headers,
612
+ credentials: options.credentials
613
+ });
614
+ if (!response.ok) {
615
+ throw new Error('');
616
+ }
617
+ const data = await response.json();
618
+ if (data.exceptions) {
619
+ throw new Error(parseError(data));
620
+ }
621
+ const features = this.getFormat().readFeatures(data, {
622
+ featureProjection: projection.getCode(),
623
+ dataProjection: options.geoServerAdvanced.projection
624
+ });
625
+ features.forEach((feature) => {
626
+ feature.set('_layerName_', options.name,
627
+ /* silent = */ true);
628
+ });
629
+ this.addFeatures(features);
630
+ success(features);
631
+ }
632
+ catch (err) {
633
+ this.removeLoadedExtent(extent);
634
+ showError(I18N.errors.geoserver, err, options.name);
635
+ failure();
636
+ }
637
+ }
638
+ });
639
+ this.urlParams_.set('version', options.geoServerAdvanced.getFeatureVersion);
640
+ this.urlParams_.set('typename', options.name);
641
+ this.urlParams_.set('srsName', options.geoServerAdvanced.projection.toString());
642
+ const geoserverOptions = options.geoserverVendor;
643
+ this.setCqlFilter(geoserverOptions.cql_filter, true);
644
+ this.setSortBy(geoserverOptions.sortBy, true);
645
+ this.setFeatureId(geoserverOptions.featureid, true);
646
+ this.setFilter(geoserverOptions.filter, true);
647
+ this.setFormatOptions(geoserverOptions.format_options, true);
648
+ this.setMaxFeatures(geoserverOptions.maxFeatures, true);
649
+ this.setStartIndex(geoserverOptions.startIndex, true);
650
+ this.setPropertyName(geoserverOptions.propertyname, true);
651
+ this.setStrict(geoserverOptions.strict, true);
652
+ this.addEvents_();
653
+ }
654
+ /**
655
+ * @public
656
+ * @param value
657
+ * @param opt_silent
658
+ */
659
+ setStrict(value, opt_silent) {
660
+ this.set(WfsSourceProperty.STRICT, value, opt_silent);
661
+ }
662
+ /**
663
+ * @public
664
+ * @returns
665
+ */
666
+ getStrict() {
667
+ return this.get(WfsSourceProperty.STRICT);
668
+ }
669
+ /**
670
+ * @private
671
+ */
672
+ addEvents_() {
673
+ this.on(['propertychange'], (evt) => {
674
+ // If a geoserver property was modified, refresh the source
675
+ if (this.geoserverProps_.includes(evt.key)) {
676
+ this.refresh();
677
+ }
678
+ });
679
+ }
680
+ }
681
+ var WfsSourceProperty;
682
+ (function (WfsSourceProperty) {
683
+ WfsSourceProperty["STRICT"] = "strict";
684
+ })(WfsSourceProperty || (WfsSourceProperty = {}));
685
+
686
+ /**
687
+ * Layer to retrieve WFS features from geoservers
688
+ * https://docs.geoserver.org/stable/en/user/services/wfs/reference.html
689
+ *
690
+ * @fires layerRendered
691
+ * @extends {ol/layer/Vector~VectorLayer}
692
+ * @param options
693
+ */
694
+ class WfsLayer extends Mixin(BaseLayer, (VectorLayer)) {
695
+ _loadingCount = 0;
696
+ _loadedCount = 0;
697
+ beforeTransactFeature;
698
+ constructor(options) {
699
+ super({
700
+ name: options.name,
701
+ label: options.label || options.name,
702
+ minZoom: options.minZoom,
703
+ ...options
704
+ });
705
+ if (options.beforeTransactFeature) {
706
+ this.beforeTransactFeature = options.beforeTransactFeature;
707
+ }
708
+ const geoserver = options.geoserver;
709
+ const source = new WfsSource({
710
+ name: options.name,
711
+ geoserverUrl: geoserver.getUrl(),
712
+ geoServerAdvanced: geoserver.getAdvanced(),
713
+ ...(options.strategy && { strategy: options.strategy }),
714
+ geoserverVendor: options.geoserverVendor
715
+ });
716
+ this._loadingCount = 0;
717
+ this._loadedCount = 0;
718
+ source.on('featuresloadstart', () => {
719
+ this._loadingCount++;
720
+ if (this._loadingCount === 1 && this.isVisibleByZoom()) {
721
+ showLoading();
722
+ }
723
+ });
724
+ source.on(['featuresloadend', 'featuresloaderror'], () => {
725
+ this._loadedCount++;
726
+ if (this._loadingCount === this._loadedCount) {
727
+ this._loadingCount = 0;
728
+ this._loadedCount = 0;
729
+ setTimeout(() => {
730
+ this.dispatchEvent('layerRendered');
731
+ }, 300);
732
+ }
733
+ });
734
+ this.setSource(source);
735
+ }
736
+ /**
737
+ * @public
738
+ */
739
+ refresh() {
740
+ const source = this.getSource();
741
+ // Refrescamos el wms
742
+ source.refresh();
743
+ }
744
+ }
745
+
746
+ class WmsSource extends Mixin(TileWMS, BaseSource) {
747
+ geoserverProps_ = [
748
+ 'cql_filter',
749
+ 'filter',
750
+ 'orderBy',
751
+ 'maxFeatures',
752
+ 'startIndex',
753
+ 'featureid',
754
+ 'format_options',
755
+ 'propertyname',
756
+ 'buffer',
757
+ 'clip',
758
+ 'env'
759
+ ];
760
+ constructor(options) {
761
+ super({
762
+ url: options.geoserverUrl,
763
+ serverType: 'geoserver',
764
+ params: {
765
+ SERVICE: 'wms',
766
+ TILED: true,
767
+ LAYERS: options.name,
768
+ EXCEPTIONS: 'application/json',
769
+ ...(options.geoserverVendor && options.geoserverVendor)
770
+ },
771
+ tileLoadFunction: async (tile, src) => {
772
+ const blobToJson = (blob) => {
773
+ return new Promise((resolve) => {
774
+ const reader = new FileReader();
775
+ reader.onloadend = () => resolve(JSON.parse(reader.result));
776
+ reader.readAsText(blob);
777
+ });
778
+ };
779
+ try {
780
+ const response = await fetch(src, {
781
+ headers: options.headers,
782
+ credentials: options.credentials
783
+ });
784
+ if (!response.ok) {
785
+ throw new Error('');
786
+ }
787
+ let data = await response.blob();
788
+ // Check if the response has an error
789
+ if (data.type == 'application/json') {
790
+ const parsedError = await blobToJson(data);
791
+ throw new Error(parseError(parsedError));
792
+ }
793
+ tile.getImage().src =
794
+ URL.createObjectURL(data);
795
+ tile.setState(TileState.LOADED);
796
+ }
797
+ catch (err) {
798
+ showError(I18N.errors.geoserver, err, options.name);
799
+ tile.setState(TileState.ERROR);
800
+ }
801
+ },
802
+ ...options
803
+ });
804
+ this.addEvents_();
805
+ }
806
+ /**
807
+ * @public
808
+ * @param value
809
+ * @param opt_silent
810
+ */
811
+ setBuffer(value, opt_silent) {
812
+ this.set(WmsSourceProperty.BUFFER, value, opt_silent);
813
+ }
814
+ /**
815
+ * @public
816
+ * @returns
817
+ */
818
+ getBuffer() {
819
+ return this.get(WmsSourceProperty.BUFFER);
820
+ }
821
+ /**
822
+ * @public
823
+ * @param value
824
+ * @param opt_silent
825
+ */
826
+ setEnv(value, opt_silent) {
827
+ this.set(WmsSourceProperty.ENV, value, opt_silent);
828
+ }
829
+ /**
830
+ * @public
831
+ * @returns
832
+ */
833
+ getEnv() {
834
+ return this.get(WmsSourceProperty.ENV);
835
+ }
836
+ /**
837
+ * @public
838
+ * @param value
839
+ * @param opt_silent
840
+ */
841
+ setClip(value, opt_silent) {
842
+ this.set(WmsSourceProperty.CLIP, value, opt_silent);
843
+ }
844
+ /**
845
+ * @public
846
+ * @returns
847
+ */
848
+ getClip() {
849
+ return this.get(WmsSourceProperty.CLIP);
850
+ }
851
+ /**
852
+ * @private
853
+ */
854
+ addEvents_() {
855
+ this.on(['propertychange'], (evt) => {
856
+ console.log(evt.key);
857
+ // If a geoserver property was modified, refresh the source
858
+ if (this.geoserverProps_.includes(evt.key)) {
859
+ this.updateParams({
860
+ [evt.key]: evt.target.get(evt.key)
861
+ });
862
+ this.refresh();
863
+ }
864
+ });
865
+ }
866
+ }
867
+ var WmsSourceProperty;
868
+ (function (WmsSourceProperty) {
869
+ WmsSourceProperty["BUFFER"] = "buffer";
870
+ WmsSourceProperty["ENV"] = "env";
871
+ WmsSourceProperty["CLIP"] = "clip";
872
+ })(WmsSourceProperty || (WmsSourceProperty = {}));
873
+
874
+ /**
875
+ * Layer to retrieve WMS information from geoservers
876
+ * https://docs.geoserver.org/stable/en/user/services/wms/reference.html
877
+ *
878
+ * @fires layerRendered
879
+ * @extends {ol/layer/Tile~TileLayer}
880
+ * @param options
881
+ */
882
+ class WmsLayer extends Mixin(BaseLayer, (TileLayer)) {
883
+ _loadingCount = 0;
884
+ _loadedCount = 0;
885
+ beforeTransactFeature;
886
+ // Formats
887
+ _formatGeoJSON;
888
+ constructor(options) {
889
+ super({
890
+ name: options.name,
891
+ label: options.label || options.name,
892
+ minZoom: options.minZoom,
893
+ ...options
894
+ });
895
+ if (options.beforeTransactFeature) {
896
+ this.beforeTransactFeature = options.beforeTransactFeature;
897
+ }
898
+ this._formatGeoJSON = new GeoJSON$1();
899
+ const geoserver = options.geoserver;
900
+ const source = new WmsSource({
901
+ name: options.name,
902
+ geoserverUrl: geoserver.getUrl(),
903
+ geoServerAdvanced: geoserver.getAdvanced(),
904
+ geoserverVendor: options.geoserverVendor
905
+ });
906
+ this._loadingCount = 0;
907
+ this._loadedCount = 0;
908
+ source.on('tileloadstart', () => {
909
+ this._loadingCount++;
910
+ if (this._loadingCount === 1 && this.isVisibleByZoom()) {
911
+ showLoading();
912
+ }
913
+ });
914
+ source.on(['tileloadend', 'tileloaderror'], () => {
915
+ this._loadedCount++;
916
+ if (this._loadingCount === this._loadedCount) {
917
+ this._loadingCount = 0;
918
+ this._loadedCount = 0;
919
+ setTimeout(() => {
920
+ this.dispatchEvent('layerRendered');
921
+ }, 300);
922
+ }
923
+ });
924
+ this.setSource(source);
925
+ }
926
+ /**
927
+ * Get the features on the click area
928
+ * @param evt
929
+ * @returns
930
+ * @private
931
+ */
932
+ async getFeaturesByClickEvent(evt) {
933
+ const coordinate = evt.coordinate;
934
+ const view = getMap().getView();
935
+ // Si la vista es lejana, disminumos el buffer
936
+ // Si es cercana, lo aumentamos, por ejemplo, para podeer clickear los vectores
937
+ // y mejorar la sensibilidad en IOS
938
+ const buffer = view.getZoom() > 10 ? 10 : 5;
939
+ const source = this.getSource();
940
+ // Fallback to support a bad name
941
+ // https://openlayers.org/en/v5.3.0/apidoc/module-ol_source_ImageWMS-ImageWMS.html#getGetFeatureInfoUrl
942
+ const fallbackOl5 = 'getFeatureInfoUrl' in source
943
+ ? 'getFeatureInfoUrl'
944
+ : 'getGetFeatureInfoUrl';
945
+ const url = source[fallbackOl5](coordinate, view.getResolution(), view.getProjection().getCode(), {
946
+ INFO_FORMAT: 'application/json',
947
+ BUFFER: buffer,
948
+ FEATURE_COUNT: 1,
949
+ EXCEPTIONS: 'application/json'
950
+ });
951
+ const geoserver = this.getGeoserver();
952
+ try {
953
+ const response = await fetch(url, {
954
+ headers: geoserver.getHeaders(),
955
+ credentials: geoserver.getCredentials()
956
+ });
957
+ if (!response.ok) {
958
+ throw new Error(`${I18N.errors.getFeatures} ${response.status}`);
959
+ }
960
+ const data = await response.json();
961
+ const features = this._formatGeoJSON.readFeatures(data);
962
+ return features;
963
+ }
964
+ catch (err) {
965
+ showError(err.message, err);
966
+ }
967
+ }
968
+ /**
969
+ * @public
970
+ */
971
+ refresh() {
972
+ const source = this.getSource();
973
+ // Refrescamos el wms
974
+ source.refresh();
975
+ // Force refresh the tiles
976
+ const params = source.getParams();
977
+ params.t = new Date().getMilliseconds();
978
+ source.updateParams(params);
979
+ }
980
+ }
981
+
982
+ function createElement(tagName, attrs = {}, ...children) {
983
+ if (typeof tagName === 'function')
984
+ return tagName(attrs, children);
985
+ const elem = tagName === null
986
+ ? new DocumentFragment()
987
+ : document.createElement(tagName);
988
+ Object.entries(attrs || {}).forEach(([name, value]) => {
989
+ if (typeof value !== undefined &&
990
+ value !== null &&
991
+ value !== undefined) {
992
+ if (name.startsWith('on') && name.toLowerCase() in window)
993
+ elem.addEventListener(name.toLowerCase().substr(2), value);
994
+ else {
995
+ if (name === 'className')
996
+ elem.setAttribute('class', value.toString());
997
+ else if (name === 'htmlFor')
998
+ elem.setAttribute('for', value.toString());
999
+ else
1000
+ elem.setAttribute(name, value.toString());
1001
+ }
1002
+ }
1003
+ });
1004
+ for (const child of children) {
1005
+ if (!child)
1006
+ continue;
1007
+ if (Array.isArray(child))
1008
+ elem.append(...child);
1009
+ else {
1010
+ if (child.nodeType === undefined)
1011
+ elem.innerHTML += child;
1012
+ else
1013
+ elem.appendChild(child);
1014
+ }
1015
+ }
1016
+ return elem;
1017
+ }
1018
+
1019
+ var img$5 = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' width='512' height='512' viewBox='0 0 512 512'%3e%3cpath d='M240 352h-240v128h480v-128h-240zM448 416h-64v-32h64v32zM112 160l128-128 128 128h-80v160h-96v-160z'%3e%3c/path%3e%3c/svg%3e";
1020
+
1021
+ var img$4 = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' width='768' height='768' viewBox='0 0 768 768'%3e %3cpath d='M663 225l-58.5 58.5-120-120 58.5-58.5q9-9 22.5-9t22.5 9l75 75q9 9 9 22.5t-9 22.5zM96 552l354-354 120 120-354 354h-120v-120z'%3e%3c/path%3e%3c/svg%3e";
1022
+
1023
+ var img$3 = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' width='768' height='768' viewBox='0 0 768 768'%3e%3cpath d='M384 288q39 0 67.5 28.5t28.5 67.5-28.5 67.5-67.5 28.5-67.5-28.5-28.5-67.5 28.5-67.5 67.5-28.5zM384 544.5q66 0 113.25-47.25t47.25-113.25-47.25-113.25-113.25-47.25-113.25 47.25-47.25 113.25 47.25 113.25 113.25 47.25zM384 144q118.5 0 214.5 66t138 174q-42 108-138 174t-214.5 66-214.5-66-138-174q42-108 138-174t214.5-66z'%3e%3c/path%3e%3c/svg%3e";
1024
+
1025
+ var img$2 = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' width='768' height='768' viewBox='0 0 768 768'%3e%3cpath d='M379.5 288h4.5q39 0 67.5 28.5t28.5 67.5v6zM241.5 313.5q-18 36-18 70.5 0 66 47.25 113.25t113.25 47.25q34.5 0 70.5-18l-49.5-49.5q-12 3-21 3-39 0-67.5-28.5t-28.5-67.5q0-9 3-21zM64.5 136.5l40.5-40.5 567 567-40.5 40.5q-7.5-7.5-47.25-46.5t-60.75-60q-64.5 27-139.5 27-118.5 0-214.5-66t-138-174q16.5-39 51.75-86.25t68.25-72.75q-18-18-50.25-51t-36.75-37.5zM384 223.5q-30 0-58.5 12l-69-69q58.5-22.5 127.5-22.5 118.5 0 213.75 66t137.25 174q-36 88.5-109.5 151.5l-93-93q12-28.5 12-58.5 0-66-47.25-113.25t-113.25-47.25z'%3e%3c/path%3e%3c/svg%3e";
1026
+
1027
+ /**
1028
+ * Removes in the DOM the class of the tools
1029
+ * @private
1030
+ */
1031
+ const resetStateButtons = () => {
1032
+ const activeBtn = document.querySelector('.ol-wfst--tools-control-btn.wfst--active');
1033
+ if (activeBtn) {
1034
+ activeBtn.classList.remove('wfst--active');
1035
+ }
1036
+ };
1037
+ const activateModeButtons = () => {
1038
+ const btn = document.querySelector('.ol-wfst--tools-control-btn-edit');
1039
+ if (btn) {
1040
+ btn.classList.add('wfst--active');
1041
+ }
1042
+ };
1043
+ const activateDrawButton = () => {
1044
+ const btn = document.querySelector('.ol-wfst--tools-control-btn-draw');
1045
+ if (btn) {
1046
+ btn.classList.add('wfst--active');
1047
+ }
1048
+ };
1049
+ class LayersControl extends Observable {
1050
+ _uploads;
1051
+ _uploadFormats;
1052
+ constructor(uploads, uploadFormats) {
1053
+ super();
1054
+ this._uploads = uploads;
1055
+ this._uploadFormats = uploadFormats;
1056
+ }
1057
+ /**
1058
+ *
1059
+ * @param layer
1060
+ * @public
1061
+ */
1062
+ addLayerEl(layer) {
1063
+ const container = document.querySelector('.wfst--tools-control--select-layers');
1064
+ const layerName = layer.get(BaseLayerProperty.NAME);
1065
+ const checked = layer === getActiveLayerToInsertEls() ? { checked: 'checked' } : {};
1066
+ const input = (createElement("input", { value: layerName, id: `wfst--${layerName}`, type: "radio", className: "ol-wfst--tools-control-input", name: "wfst--select-layer", ...checked, onchange: (evt) => this._layerChangeHandler(evt, layer) }));
1067
+ const layerDom = (createElement("div", { className: `wfst--layer-control
1068
+ ${layer.getVisible() ? 'ol-wfst--visible-on' : ''}
1069
+ ${layer === getActiveLayerToInsertEls()
1070
+ ? 'ol-wfst--selected-on'
1071
+ : ''}`, "data-layer": layerName },
1072
+ createElement("div", { className: "ol-wfst--tools-control-visible" },
1073
+ createElement("span", { className: "ol-wfst--tools-control-visible-btn ol-wfst--visible-btn-on", title: I18N.labels.toggleVisibility, onclick: (evt) => this._visibilityClickHandler(evt) },
1074
+ createElement("img", { src: img$3 })),
1075
+ createElement("span", { className: "ol-wfst--tools-control-visible-btn ol-wfst--visible-btn-off", title: I18N.labels.toggleVisibility, onclick: (evt) => this._visibilityClickHandler(evt) },
1076
+ createElement("img", { src: img$2 }))),
1077
+ createElement("label", { htmlFor: `wfst--${layerName}` },
1078
+ input,
1079
+ createElement("span", { title: layer.getDescribeFeatureType()._parsed.geomType }, layer.get(BaseLayerProperty.LABEL)))));
1080
+ container.appendChild(layerDom);
1081
+ if (layer === getActiveLayerToInsertEls()) {
1082
+ input.dispatchEvent(new Event('change'));
1083
+ }
1084
+ return layerDom;
1085
+ }
1086
+ /**
1087
+ * Update geom Types availibles to select for this layer
1088
+ *
1089
+ * @param layerName
1090
+ * @param geomDrawTypeSelected
1091
+ * @private
1092
+ */
1093
+ _changeStateSelect(layer, geomDrawTypeSelected = null) {
1094
+ /**
1095
+ * Set the geometry type in the select according to the geometry of
1096
+ * the layer in the geoserver and disable what does not correspond.
1097
+ *
1098
+ * @param value
1099
+ * @param options
1100
+ * @private
1101
+ */
1102
+ const setSelectState = (value, options) => {
1103
+ Array.from(selectDraw.options).forEach((option) => {
1104
+ option.selected = option.value === value ? true : false;
1105
+ option.disabled =
1106
+ options === 'all'
1107
+ ? false
1108
+ : options.includes(option.value)
1109
+ ? false
1110
+ : true;
1111
+ option.title = option.disabled
1112
+ ? I18N.labels.geomTypeNotSupported
1113
+ : '';
1114
+ });
1115
+ };
1116
+ const selectDraw = document.querySelector('.wfst--tools-control--select-draw');
1117
+ let drawType;
1118
+ if (selectDraw) {
1119
+ const geomLayer = layer.getDescribeFeatureType()._parsed.geomType;
1120
+ if (geomDrawTypeSelected) {
1121
+ drawType = selectDraw.value;
1122
+ }
1123
+ else {
1124
+ if (geomLayer === GeometryType.GeometryCollection) {
1125
+ drawType = GeometryType.LineString; // Default drawing type for GeometryCollection
1126
+ setSelectState(drawType, 'all');
1127
+ }
1128
+ else if (geomLayer === GeometryType.LinearRing) {
1129
+ drawType = GeometryType.LineString; // Default drawing type for GeometryCollection
1130
+ setSelectState(drawType, [
1131
+ GeometryType.Circle,
1132
+ GeometryType.LinearRing,
1133
+ GeometryType.Polygon
1134
+ ]);
1135
+ selectDraw.value = drawType;
1136
+ }
1137
+ else {
1138
+ drawType = geomLayer;
1139
+ setSelectState(drawType, [geomLayer]);
1140
+ }
1141
+ }
1142
+ }
1143
+ return drawType;
1144
+ }
1145
+ _visibilityClickHandler(evt) {
1146
+ const btn = evt.currentTarget;
1147
+ const parentDiv = btn.closest('.wfst--layer-control');
1148
+ const layerName = parentDiv.dataset['layer'];
1149
+ parentDiv.classList.toggle('ol-wfst--visible-on');
1150
+ const layer = getStoredMapLayers()[layerName];
1151
+ if (parentDiv.classList.contains('ol-wfst--visible-on')) {
1152
+ layer.setVisible(true);
1153
+ }
1154
+ else {
1155
+ layer.setVisible(false);
1156
+ }
1157
+ }
1158
+ _layerChangeHandler(evt, layer) {
1159
+ const radioInput = evt.currentTarget;
1160
+ const parentDiv = radioInput.closest('.wfst--layer-control');
1161
+ // Deselect DOM previous layer
1162
+ const selected = document.querySelector('.ol-wfst--selected-on');
1163
+ if (selected)
1164
+ selected.classList.remove('ol-wfst--selected-on');
1165
+ // Select this layer
1166
+ parentDiv.classList.add('ol-wfst--selected-on');
1167
+ setActiveLayerToInsertEls(layer);
1168
+ this._changeStateSelect(layer);
1169
+ }
1170
+ render() {
1171
+ return (createElement(null, null,
1172
+ createElement("div", { className: "wfst--tools-control--head" },
1173
+ this._uploads && (createElement("div", null,
1174
+ createElement("input", { id: "ol-wfst--upload", type: "file", accept: this._uploadFormats, onchange: (evt) => this._uploads.process(evt) }),
1175
+ createElement("label", { className: "ol-wfst--tools-control-btn ol-wfst--tools-control-btn-upload", htmlFor: "ol-wfst--upload", title: I18N.labels.uploadToLayer },
1176
+ createElement("img", { src: img$5 })))),
1177
+ createElement("div", { className: "ol-wfst--tools-control-draw-cnt" },
1178
+ createElement("button", { className: "ol-wfst--tools-control-btn ol-wfst--tools-control-btn-draw", type: "button", title: I18N.labels.addElement, onclick: () => {
1179
+ this.dispatchEvent('drawMode');
1180
+ } },
1181
+ createElement("img", { src: img$4 })),
1182
+ createElement("select", { title: I18N.labels.selectDrawType, className: "wfst--tools-control--select-draw", onchange: (evt) => {
1183
+ const selectedValue = evt.target
1184
+ .value;
1185
+ this._changeStateSelect(getActiveLayerToInsertEls(), selectedValue);
1186
+ this.dispatchEvent('changeGeom');
1187
+ } }, [
1188
+ GeometryType.Point,
1189
+ GeometryType.MultiPoint,
1190
+ GeometryType.LineString,
1191
+ GeometryType.MultiLineString,
1192
+ GeometryType.Polygon,
1193
+ GeometryType.MultiPolygon,
1194
+ GeometryType.Circle
1195
+ ].map((type) => {
1196
+ // Show all options, but enable only the accepted ones
1197
+ return createElement("option", { value: type }, type);
1198
+ })))),
1199
+ createElement("div", { className: "wfst--tools-control--select-layers" })));
1200
+ }
1201
+ }
1202
+
1203
+ let editLayer = new VectorLayer({
1204
+ source: new VectorSource(),
1205
+ zIndex: 100
1206
+ });
1207
+ const getEditLayer = () => {
1208
+ return editLayer;
1209
+ };
1210
+
1211
+ // Ol
1212
+ class Uploads extends Observable {
1213
+ _options;
1214
+ // Formats
1215
+ _formatWFS;
1216
+ _formatGeoJSON;
1217
+ _formatKml;
1218
+ _xs;
1219
+ _processUpload;
1220
+ constructor(options) {
1221
+ super();
1222
+ this._options = options;
1223
+ this._processUpload = options.processUpload;
1224
+ // Formats
1225
+ this._formatWFS = new WFS();
1226
+ this._formatGeoJSON = new GeoJSON$1();
1227
+ this._formatKml = new KML({
1228
+ extractStyles: false,
1229
+ showPointNames: false
1230
+ });
1231
+ this._xs = new XMLSerializer();
1232
+ }
1233
+ /**
1234
+ * Parse and check geometry of uploaded files
1235
+ *
1236
+ * @param evt
1237
+ * @public
1238
+ */
1239
+ async process(evt) {
1240
+ const map = getMap();
1241
+ const view = map.getView();
1242
+ const file = evt.target.files[0];
1243
+ let features;
1244
+ if (!file) {
1245
+ return;
1246
+ }
1247
+ const extension = file.name.split('.').pop().toLowerCase();
1248
+ try {
1249
+ // If the user uses a custom fucntion...
1250
+ if (this._processUpload) {
1251
+ features = this._processUpload(file);
1252
+ }
1253
+ // If the user functions return features, we dont process anything more
1254
+ if (!features) {
1255
+ const string = await this._fileReader(file);
1256
+ if (extension === 'geojson' || extension === 'json') {
1257
+ features = this._formatGeoJSON.readFeatures(string, {
1258
+ featureProjection: view.getProjection().getCode()
1259
+ });
1260
+ }
1261
+ else if (extension === 'kml') {
1262
+ features = this._formatKml.readFeatures(string, {
1263
+ featureProjection: view.getProjection().getCode()
1264
+ });
1265
+ }
1266
+ else {
1267
+ showError(I18N.errors.badFormat);
1268
+ }
1269
+ }
1270
+ let invalidFeaturesCount = 0;
1271
+ let validFeaturesCount = 0;
1272
+ const featuresToInsert = [];
1273
+ for (let feature of features) {
1274
+ // If the geometry doesn't correspond to the layer, try to fixit.
1275
+ // If we can't, don't use it
1276
+ if (!this._checkGeometry(feature)) {
1277
+ feature = this._fixGeometry(feature);
1278
+ }
1279
+ if (feature) {
1280
+ featuresToInsert.push(feature);
1281
+ validFeaturesCount++;
1282
+ }
1283
+ else {
1284
+ invalidFeaturesCount++;
1285
+ continue;
1286
+ }
1287
+ }
1288
+ if (!validFeaturesCount) {
1289
+ showError(I18N.errors.noValidGeometry);
1290
+ }
1291
+ else {
1292
+ resetStateButtons();
1293
+ this.dispatchEvent(new VectorSourceEvent('loadedFeatures', null, featuresToInsert));
1294
+ const content = `
1295
+ ${I18N.labels.validFeatures}: ${validFeaturesCount}<br>
1296
+ ${invalidFeaturesCount
1297
+ ? `${I18N.labels.invalidFeatures}: ${invalidFeaturesCount}`
1298
+ : ''}`;
1299
+ this._initModal(content, featuresToInsert);
1300
+ }
1301
+ // Reset the input to allow another onChange trigger
1302
+ evt.target.value = null;
1303
+ }
1304
+ catch (err) {
1305
+ showError(I18N.errors.badFile, err);
1306
+ }
1307
+ }
1308
+ /**
1309
+ * Read data file
1310
+ * @param file
1311
+ * @public
1312
+ */
1313
+ async _fileReader(file) {
1314
+ return new Promise((resolve, reject) => {
1315
+ const reader = new FileReader();
1316
+ reader.addEventListener('load', async (e) => {
1317
+ const fileData = e.target.result;
1318
+ resolve(fileData);
1319
+ });
1320
+ reader.addEventListener('error', (err) => {
1321
+ console.error('Error' + err);
1322
+ reject();
1323
+ });
1324
+ reader.readAsText(file);
1325
+ });
1326
+ }
1327
+ /**
1328
+ * Attemp to change the geometry feature to the layer
1329
+ * @param feature
1330
+ * @private
1331
+ */
1332
+ _fixGeometry(feature) {
1333
+ // Geometry of the layer
1334
+ const geomTypeLayer = getActiveLayerToInsertEls().getDescribeFeatureType()._parsed
1335
+ .geomType;
1336
+ const geomTypeFeature = feature.getGeometry().getType();
1337
+ let geom;
1338
+ switch (geomTypeFeature) {
1339
+ case GeometryType.Point: {
1340
+ if (geomTypeLayer === GeometryType.MultiPoint) {
1341
+ const coords = feature.getGeometry().getCoordinates();
1342
+ geom = new MultiPoint([coords]);
1343
+ }
1344
+ break;
1345
+ }
1346
+ case GeometryType.LineString:
1347
+ if (geomTypeLayer === GeometryType.MultiLineString) {
1348
+ const coords = feature.getGeometry().getCoordinates();
1349
+ geom = new MultiLineString([coords]);
1350
+ }
1351
+ break;
1352
+ case GeometryType.Polygon:
1353
+ if (geomTypeLayer === GeometryType.MultiPolygon) {
1354
+ const coords = feature.getGeometry().getCoordinates();
1355
+ geom = new MultiPolygon([coords]);
1356
+ }
1357
+ break;
1358
+ default:
1359
+ geom = null;
1360
+ }
1361
+ if (!geom) {
1362
+ return null;
1363
+ }
1364
+ feature.setGeometry(geom);
1365
+ return feature;
1366
+ }
1367
+ /**
1368
+ * Check if the feature has the same geometry as the target layer
1369
+ * @param feature
1370
+ * @private
1371
+ */
1372
+ _checkGeometry(feature) {
1373
+ // Geometry of the layer
1374
+ const geomTypeLayer = getActiveLayerToInsertEls().getDescribeFeatureType()._parsed
1375
+ .geomType;
1376
+ const geomTypeFeature = feature.getGeometry().getType();
1377
+ // This geom accepts every type of geometry
1378
+ if (geomTypeLayer === GeometryType.GeometryCollection) {
1379
+ return true;
1380
+ }
1381
+ return geomTypeFeature === geomTypeLayer;
1382
+ }
1383
+ /**
1384
+ * Confirm modal before transact to the GeoServer the features in the file
1385
+ *
1386
+ * @param content
1387
+ * @param featuresToInsert
1388
+ * @private
1389
+ */
1390
+ _initModal(content, featuresToInsert) {
1391
+ const footer = `
1392
+ <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">
1393
+ ${I18N.labels.cancel}
1394
+ </button>
1395
+ <button type="button" class="btn btn-sm btn-primary" data-action="save" data-dismiss="modal">
1396
+ ${I18N.labels.upload}
1397
+ </button>
1398
+ `;
1399
+ const modal = new Modal({
1400
+ ...this._options.modal,
1401
+ header: true,
1402
+ headerClose: false,
1403
+ title: I18N.labels.uploadFeatures +
1404
+ ' ' +
1405
+ getActiveLayerToInsertEls().get(BaseLayerProperty.NAME),
1406
+ content: content,
1407
+ backdrop: 'static',
1408
+ footer: footer
1409
+ }).show();
1410
+ modal.on('dismiss', (modal, event) => {
1411
+ // On saving changes
1412
+ if (event.target.dataset.action === 'save') {
1413
+ this.dispatchEvent(new VectorSourceEvent('addedFeatures', null, featuresToInsert));
1414
+ }
1415
+ else {
1416
+ // On cancel button
1417
+ getEditLayer().getSource().clear();
1418
+ }
1419
+ });
1420
+ }
1421
+ }
1422
+
1423
+ /**
1424
+ * @param target
1425
+ * @param sources
1426
+ * @returns
1427
+ */
1428
+ const deepObjectAssign = (target, ...sources) => {
1429
+ sources.forEach((source) => {
1430
+ Object.keys(source).forEach((key) => {
1431
+ const s_val = source[key];
1432
+ const t_val = target[key];
1433
+ target[key] =
1434
+ t_val &&
1435
+ s_val &&
1436
+ typeof t_val === 'object' &&
1437
+ typeof s_val === 'object' &&
1438
+ !Array.isArray(t_val) // Don't merge arrays
1439
+ ? deepObjectAssign(t_val, s_val)
1440
+ : s_val;
1441
+ });
1442
+ });
1443
+ return target;
1444
+ };
1445
+
1446
+ const DEFAULT_LANGUAGE = 'en';
1447
+ const getDefaultOptions = () => {
1448
+ return {
1449
+ layers: null,
1450
+ evtType: 'singleclick',
1451
+ active: true,
1452
+ showControl: true,
1453
+ language: DEFAULT_LANGUAGE,
1454
+ uploadFormats: '.geojson,.json,.kml',
1455
+ processUpload: null,
1456
+ modal: {
1457
+ animateClass: 'fade',
1458
+ animateInClass: 'show',
1459
+ transition: 300,
1460
+ backdropTransition: 150,
1461
+ templates: {
1462
+ dialog: '<div class="modal-dialog modal-dialog-centered"></div>',
1463
+ headerClose: `<button type="button" class="btn-close" data-dismiss="modal" aria-label="${I18N.labels.close}"><span aria-hidden="true">×</span></button>`
1464
+ }
1465
+ }
1466
+ };
1467
+ };
1468
+
1469
+ class EditControlChangesEl extends Control {
1470
+ constructor(feature) {
1471
+ super({
1472
+ element: (createElement("div", { className: "ol-wfst--changes-control" },
1473
+ createElement("div", { className: "ol-wfst--changes-control-el" },
1474
+ createElement("div", { className: "ol-wfst--changes-control-id" },
1475
+ createElement("b", null, I18N.labels.editMode),
1476
+ " -",
1477
+ ' ',
1478
+ createElement("i", null, String(feature.getId()))),
1479
+ createElement("button", { type: "button", className: "btn btn-sm btn-secondary", onclick: () => {
1480
+ this.dispatchEvent(new VectorSourceEvent('cancel', feature));
1481
+ } }, I18N.labels.cancel),
1482
+ createElement("button", { type: "button", className: "btn btn-sm btn-primary", onclick: () => {
1483
+ this.dispatchEvent(new VectorSourceEvent('apply', feature));
1484
+ } }, I18N.labels.apply),
1485
+ createElement("button", { type: "button", className: "btn btn-sm btn-danger-outline", onclick: () => {
1486
+ this.dispatchEvent(new VectorSourceEvent('delete', feature));
1487
+ } }, I18N.labels.delete))))
1488
+ });
1489
+ }
1490
+ }
1491
+
1492
+ // Ol
1493
+ /**
1494
+ * Master style that handles two modes on the Edit Layer:
1495
+ * - one is the basic, showing only the vertices
1496
+ * - and the other when modify is active, showing bigger vertices
1497
+ *
1498
+ * @param feature
1499
+ * @private
1500
+ */
1501
+ function styleFunction(feature) {
1502
+ const getVertexs = (feature) => {
1503
+ let geometry = feature.getGeometry();
1504
+ if (geometry instanceof GeometryCollection) {
1505
+ geometry = geometry.getGeometries()[0];
1506
+ }
1507
+ const coordinates = geometry.getCoordinates();
1508
+ let flatCoordinates = null;
1509
+ if (geometry instanceof Polygon ||
1510
+ geometry instanceof MultiLineString) {
1511
+ flatCoordinates = coordinates.flat(1);
1512
+ }
1513
+ else if (geometry instanceof MultiPolygon) {
1514
+ flatCoordinates = coordinates.flat(2);
1515
+ }
1516
+ else {
1517
+ flatCoordinates = coordinates;
1518
+ }
1519
+ if (!flatCoordinates || !flatCoordinates.length) {
1520
+ return;
1521
+ }
1522
+ return new MultiPoint(flatCoordinates);
1523
+ };
1524
+ let geometry = feature.getGeometry();
1525
+ let type = geometry.getType();
1526
+ if (geometry instanceof GeometryCollection) {
1527
+ geometry = geometry.getGeometries()[0];
1528
+ type = geometry.getType();
1529
+ }
1530
+ switch (type) {
1531
+ case GeometryType.Point:
1532
+ case GeometryType.MultiPoint:
1533
+ if (getMode() === Modes.Edit) {
1534
+ return [
1535
+ new Style({
1536
+ image: new Circle({
1537
+ radius: 6,
1538
+ fill: new Fill({
1539
+ color: '#000000'
1540
+ })
1541
+ })
1542
+ }),
1543
+ new Style({
1544
+ image: new Circle({
1545
+ radius: 4,
1546
+ fill: new Fill({
1547
+ color: '#ff0000'
1548
+ })
1549
+ })
1550
+ })
1551
+ ];
1552
+ }
1553
+ else {
1554
+ return [
1555
+ new Style({
1556
+ image: new Circle({
1557
+ radius: 5,
1558
+ fill: new Fill({
1559
+ color: '#ff0000'
1560
+ })
1561
+ })
1562
+ }),
1563
+ new Style({
1564
+ image: new Circle({
1565
+ radius: 2,
1566
+ fill: new Fill({
1567
+ color: '#000000'
1568
+ })
1569
+ })
1570
+ })
1571
+ ];
1572
+ }
1573
+ default:
1574
+ // If editing mode is active, show bigger vertex
1575
+ if (getMode() == Modes.Draw || getMode() == Modes.Edit) {
1576
+ return [
1577
+ new Style({
1578
+ stroke: new Stroke({
1579
+ color: 'rgba( 255, 0, 0, 1)',
1580
+ width: 4
1581
+ }),
1582
+ fill: new Fill({
1583
+ color: 'rgba(255, 0, 0, 0.7)'
1584
+ })
1585
+ }),
1586
+ new Style({
1587
+ image: new Circle({
1588
+ radius: 4,
1589
+ fill: new Fill({
1590
+ color: '#ff0000'
1591
+ }),
1592
+ stroke: new Stroke({
1593
+ width: 2,
1594
+ color: 'rgba(5, 5, 5, 0.9)'
1595
+ })
1596
+ }),
1597
+ geometry: (feature) => getVertexs(feature)
1598
+ }),
1599
+ new Style({
1600
+ stroke: new Stroke({
1601
+ color: 'rgba(255, 255, 255, 0.7)',
1602
+ width: 2
1603
+ })
1604
+ })
1605
+ ];
1606
+ }
1607
+ else {
1608
+ return [
1609
+ new Style({
1610
+ image: new Circle({
1611
+ radius: 2,
1612
+ fill: new Fill({
1613
+ color: '#000000'
1614
+ })
1615
+ }),
1616
+ geometry: (feature) => getVertexs(feature)
1617
+ }),
1618
+ new Style({
1619
+ stroke: new Stroke({
1620
+ color: '#ff0000',
1621
+ width: 4
1622
+ }),
1623
+ fill: new Fill({
1624
+ color: 'rgba(255, 0, 0, 0.7)'
1625
+ })
1626
+ })
1627
+ ];
1628
+ }
1629
+ }
1630
+ }
1631
+
1632
+ // Ol
1633
+ /**
1634
+ * Shows a fields form in a modal window to allow changes in the properties of the feature.
1635
+ *
1636
+ * @param feature
1637
+ * @private
1638
+ */
1639
+ class EditFieldsModal extends Observable {
1640
+ _options;
1641
+ _modal;
1642
+ _feature;
1643
+ constructor(options) {
1644
+ super();
1645
+ this._options = options;
1646
+ const footer = `
1647
+ <button type="button" class="btn btn-sm btn-link btn-third" data-action="delete" data-dismiss="modal">
1648
+ ${I18N.labels.delete}
1649
+ </button>
1650
+ <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">
1651
+ ${I18N.labels.cancel}
1652
+ </button>
1653
+ <button type="button" class="btn btn-sm btn-primary" data-action="save" data-dismiss="modal">
1654
+ ${I18N.labels.save}
1655
+ </button>
1656
+ `;
1657
+ this._modal = new Modal({
1658
+ ...this._options,
1659
+ header: true,
1660
+ headerClose: true,
1661
+ title: '',
1662
+ content: '<div></div>',
1663
+ footer: footer
1664
+ });
1665
+ this._modal.on('dismiss', (modal, event) => {
1666
+ // On saving changes
1667
+ if (event.target.dataset.action === 'save') {
1668
+ const inputs = modal.el.querySelectorAll('input');
1669
+ inputs.forEach((el) => {
1670
+ const value = el.value;
1671
+ const field = el.name;
1672
+ this._feature.set(field, value, /*isSilent = */ true);
1673
+ });
1674
+ this._feature.changed();
1675
+ addFeatureToEditedList(this._feature);
1676
+ this.dispatchEvent(new VectorSourceEvent('save', this._feature));
1677
+ }
1678
+ else if (event.target.dataset.action === 'delete') {
1679
+ this.dispatchEvent(new VectorSourceEvent('delete', this._feature));
1680
+ }
1681
+ });
1682
+ }
1683
+ show(feature) {
1684
+ this._feature = feature;
1685
+ const title = `${I18N.labels.editElement} ${feature.getId()} `;
1686
+ const properties = feature.getProperties();
1687
+ const layerName = feature.get('_layerName_');
1688
+ // Data schema from the geoserver
1689
+ const layer = getStoredLayer(layerName);
1690
+ const dataSchema = layer.getDescribeFeatureType()._parsed.properties;
1691
+ let content = '<form autocomplete="false">';
1692
+ Object.keys(properties).forEach((key) => {
1693
+ // If the feature field exists in the geoserver and is not added by openlayers
1694
+ const field = dataSchema.find((data) => data.name === key);
1695
+ if (field) {
1696
+ const typeXsd = field.type;
1697
+ let type;
1698
+ switch (typeXsd) {
1699
+ case 'xsd:string':
1700
+ type = 'text';
1701
+ break;
1702
+ case 'xsd:number':
1703
+ case 'xsd:int':
1704
+ type = 'number';
1705
+ break;
1706
+ case 'xsd:date-time':
1707
+ type = 'datetime';
1708
+ break;
1709
+ default:
1710
+ type = 'text';
1711
+ }
1712
+ if (type) {
1713
+ content += `
1714
+ <div class="ol-wfst--input-field-container">
1715
+ <label class="ol-wfst--input-field-label" for="${key}">${key}</label>
1716
+ <input placeholder="NULL" class="ol-wfst--input-field-input" type="${type}" name="${key}" value="${properties[key] || ''}">
1717
+ </div>`;
1718
+ }
1719
+ }
1720
+ });
1721
+ content += '</form>';
1722
+ this._modal._html.body.innerHTML = content;
1723
+ this._modal._html.header.innerHTML = title;
1724
+ this._modal.show();
1725
+ }
1726
+ }
1727
+
1728
+ // Ol
1729
+ // https://docs.geoserver.org/latest/en/user/services/wfs/axis_order.html
1730
+ // Axis ordering: latitude/longitude
1731
+ const DEFAULT_GEOSERVER_SRS = 'EPSG:3857';
1732
+ /**
1733
+ * @fires change:capabilities
1734
+ * @extends {ol/Object~BaseObject}
1735
+ * @param options
1736
+ */
1737
+ class Geoserver extends BaseObject {
1738
+ _options;
1739
+ _countRequests;
1740
+ _insertFeatures;
1741
+ _updateFeatures;
1742
+ _deleteFeatures;
1743
+ // Formats
1744
+ _formatWFS;
1745
+ _formatGeoJSON;
1746
+ _formatKml;
1747
+ _xs;
1748
+ state_;
1749
+ constructor(options) {
1750
+ super();
1751
+ const defaults = {
1752
+ url: null,
1753
+ advanced: {
1754
+ getCapabilitiesVersion: '1.3.0',
1755
+ getFeatureVersion: '1.0.0',
1756
+ describeFeatureTypeVersion: '1.1.0',
1757
+ lockFeatureVersion: '1.1.0',
1758
+ wfsTransactionVersion: '1.1.0',
1759
+ projection: DEFAULT_GEOSERVER_SRS,
1760
+ lockFeatureParams: {
1761
+ expiry: 5,
1762
+ lockId: 'GeoServer',
1763
+ releaseAction: 'SOME'
1764
+ }
1765
+ },
1766
+ headers: {},
1767
+ credentials: 'same-origin',
1768
+ useLockFeature: true
1769
+ };
1770
+ this._options = deepObjectAssign(defaults, options);
1771
+ this.setAdvanced(this._options.advanced);
1772
+ this.setHeaders(this._options.headers);
1773
+ this.setCredentials(this._options.credentials);
1774
+ this.setUrl(this._options.url);
1775
+ this.setUseLockFeature(this._options.useLockFeature);
1776
+ this._countRequests = 0;
1777
+ this._insertFeatures = [];
1778
+ this._updateFeatures = [];
1779
+ this._deleteFeatures = [];
1780
+ // Formats
1781
+ this._formatWFS = new WFS();
1782
+ this._formatGeoJSON = new GeoJSON$1();
1783
+ this._formatKml = new KML({
1784
+ extractStyles: false,
1785
+ showPointNames: false
1786
+ });
1787
+ this._xs = new XMLSerializer();
1788
+ this.getAndUpdateCapabilities();
1789
+ this.on('change:capabilities', () => {
1790
+ this._checkGeoserverCapabilities();
1791
+ });
1792
+ }
1793
+ /**
1794
+ *
1795
+ * @returns
1796
+ * @public
1797
+ */
1798
+ getCapabilities() {
1799
+ return this.get(GeoserverProperty.CAPABILITIES);
1800
+ }
1801
+ /**
1802
+ *
1803
+ * @param url
1804
+ * @param opt_silent
1805
+ * @public
1806
+ */
1807
+ setUrl(url, opt_silent = false) {
1808
+ this.set(GeoserverProperty.URL, url, opt_silent);
1809
+ }
1810
+ /**
1811
+ *
1812
+ * @returns
1813
+ */
1814
+ getUrl() {
1815
+ return this.get(GeoserverProperty.URL);
1816
+ }
1817
+ /**
1818
+ *
1819
+ * @param headers
1820
+ * @param opt_silent
1821
+ * @returns
1822
+ * @public
1823
+ */
1824
+ setHeaders(headers = {}, opt_silent = false) {
1825
+ return this.set(GeoserverProperty.HEADERS, headers, opt_silent);
1826
+ }
1827
+ /**
1828
+ *
1829
+ * @returns
1830
+ * @public
1831
+ */
1832
+ getHeaders() {
1833
+ return this.get(GeoserverProperty.HEADERS);
1834
+ }
1835
+ /**
1836
+ *
1837
+ * @param credentials
1838
+ * @param opt_silent
1839
+ * @public
1840
+ */
1841
+ setCredentials(credentials = null, opt_silent = false) {
1842
+ this.set(GeoserverProperty.CREDENTIALS, credentials, opt_silent);
1843
+ }
1844
+ /**
1845
+ *
1846
+ * @returns
1847
+ * @public
1848
+ */
1849
+ getCredentials() {
1850
+ return this.get(GeoserverProperty.CREDENTIALS);
1851
+ }
1852
+ /**
1853
+ *
1854
+ * @returns
1855
+ * @public
1856
+ */
1857
+ setAdvanced(advanced = {}, opt_silent = false) {
1858
+ this.set(GeoserverProperty.ADVANCED, advanced, opt_silent);
1859
+ }
1860
+ /**
1861
+ *
1862
+ * @returns
1863
+ * @public
1864
+ */
1865
+ getAdvanced() {
1866
+ return this.get(GeoserverProperty.ADVANCED);
1867
+ }
1868
+ /**
1869
+ *
1870
+ * @returns
1871
+ * @public
1872
+ */
1873
+ hasTransaction() {
1874
+ return this.get(GeoserverProperty.HASTRASNACTION);
1875
+ }
1876
+ /**
1877
+ *
1878
+ * @returns
1879
+ * @public
1880
+ */
1881
+ hasLockFeature() {
1882
+ return this.get(GeoserverProperty.HASLOCKFEATURE);
1883
+ }
1884
+ /**
1885
+ *
1886
+ * @returns
1887
+ * @public
1888
+ */
1889
+ getUseLockFeature() {
1890
+ return this.get(GeoserverProperty.USELOCKFEATURE);
1891
+ }
1892
+ /**
1893
+ *
1894
+ * @returns
1895
+ * @public
1896
+ */
1897
+ setUseLockFeature(useLockFeature, opt_silent = false) {
1898
+ this.set(GeoserverProperty.USELOCKFEATURE, useLockFeature, opt_silent);
1899
+ }
1900
+ /**
1901
+ *
1902
+ * @returns
1903
+ * @public
1904
+ */
1905
+ isLoaded() {
1906
+ return this.get(GeoserverProperty.ISLOADED);
1907
+ }
1908
+ /**
1909
+ *
1910
+ * @returns
1911
+ */
1912
+ getState() {
1913
+ return this.state_;
1914
+ }
1915
+ /**
1916
+ * Get the capabilities from the GeoServer and check
1917
+ * all the available operations.
1918
+ *
1919
+ * @fires getcapabilities
1920
+ * @public
1921
+ */
1922
+ async getAndUpdateCapabilities() {
1923
+ try {
1924
+ const params = new URLSearchParams({
1925
+ service: 'wfs',
1926
+ version: this.getAdvanced().getCapabilitiesVersion,
1927
+ request: 'GetCapabilities',
1928
+ exceptions: 'application/json'
1929
+ });
1930
+ const url_fetch = this.getUrl() + '?' + params.toString();
1931
+ const response = await fetch(url_fetch, {
1932
+ headers: this.getHeaders(),
1933
+ credentials: this.getCredentials()
1934
+ });
1935
+ if (!response.ok) {
1936
+ throw new Error('');
1937
+ }
1938
+ const data = await response.text();
1939
+ const capabilities = new window.DOMParser().parseFromString(data, 'text/xml');
1940
+ this.set(GeoserverProperty.CAPABILITIES, capabilities);
1941
+ this.state_ = capabilities ? 'ready' : 'error';
1942
+ return capabilities;
1943
+ }
1944
+ catch (err) {
1945
+ console.error(err);
1946
+ const msg = typeof err === 'string' ? err : I18N.errors.capabilities;
1947
+ showError(msg, err);
1948
+ }
1949
+ }
1950
+ /**
1951
+ *
1952
+ * @private
1953
+ */
1954
+ _checkGeoserverCapabilities() {
1955
+ // Available operations in the geoserver
1956
+ const operations = this.getCapabilities().getElementsByTagName('ows:Operation');
1957
+ Array.from(operations).forEach((operation) => {
1958
+ if (operation.getAttribute('name') === 'Transaction') {
1959
+ this.set(GeoserverProperty.HASTRASNACTION, true);
1960
+ }
1961
+ else if (operation.getAttribute('name') === 'LockFeature') {
1962
+ this.set(GeoserverProperty.HASLOCKFEATURE, true);
1963
+ }
1964
+ else if (operation.getAttribute('name') === 'DescribeFeatureType') {
1965
+ this.set(GeoserverProperty.HASDESCRIBEFEATURETYPE, true);
1966
+ }
1967
+ });
1968
+ if (!this.hasTransaction()) {
1969
+ throw I18N.errors.wfst;
1970
+ }
1971
+ }
1972
+ /**
1973
+ * Make the WFS Transactions
1974
+ *
1975
+ * @param transactionType
1976
+ * @param features
1977
+ * @param layerName
1978
+ * @private
1979
+ */
1980
+ async transact(transactionType, features, layerName) {
1981
+ features = Array.isArray(features) ? features : [features];
1982
+ const clonedFeatures = [];
1983
+ const geoLayer = getStoredLayer(layerName);
1984
+ for (const feature of features) {
1985
+ let clone = this._cloneFeature(feature);
1986
+ const cloneGeom = clone.getGeometry();
1987
+ // Ugly fix to support GeometryCollection on GML
1988
+ // See https://github.com/openlayers/openlayers/issues/4220
1989
+ if (cloneGeom instanceof GeometryCollection) {
1990
+ this._transformGeoemtryCollectionToGeometries(clone, cloneGeom);
1991
+ }
1992
+ else if (cloneGeom instanceof Circle$1) {
1993
+ // Geoserver has no Support to Circles
1994
+ this._transformCircleToPolygon(clone, cloneGeom);
1995
+ }
1996
+ // Filters
1997
+ if ('beforeTransactFeature' in geoLayer &&
1998
+ typeof geoLayer.beforeTransactFeature === 'function') {
1999
+ clone = geoLayer.beforeTransactFeature(clone, transactionType);
2000
+ }
2001
+ if (clone) {
2002
+ clonedFeatures.push(clone);
2003
+ }
2004
+ }
2005
+ if (!clonedFeatures.length) {
2006
+ showError(I18N.errors.noValidGeometry);
2007
+ return false;
2008
+ }
2009
+ switch (transactionType) {
2010
+ case TransactionType.Insert:
2011
+ this._insertFeatures = [
2012
+ ...this._insertFeatures,
2013
+ ...clonedFeatures
2014
+ ];
2015
+ break;
2016
+ case TransactionType.Update:
2017
+ this._updateFeatures = [
2018
+ ...this._updateFeatures,
2019
+ ...clonedFeatures
2020
+ ];
2021
+ break;
2022
+ case TransactionType.Delete:
2023
+ this._deleteFeatures = [
2024
+ ...this._deleteFeatures,
2025
+ ...clonedFeatures
2026
+ ];
2027
+ break;
2028
+ }
2029
+ this._countRequests++;
2030
+ const numberRequest = this._countRequests;
2031
+ return new Promise((resolve, reject) => {
2032
+ setTimeout(async () => {
2033
+ try {
2034
+ // Prevent fire multiples times
2035
+ if (numberRequest !== this._countRequests) {
2036
+ return;
2037
+ }
2038
+ let srs = getMap().getView().getProjection().getCode();
2039
+ // Force latitude/longitude order on transactions
2040
+ // EPSG:4326 is longitude/latitude (assumption) and is not managed correctly by GML3
2041
+ srs =
2042
+ srs === 'EPSG:4326'
2043
+ ? 'urn:x-ogc:def:crs:EPSG:4326'
2044
+ : srs;
2045
+ const describeFeatureType = geoLayer.getDescribeFeatureType()._parsed;
2046
+ if (!geoLayer) {
2047
+ throw new Error(I18N.errors.layerNotFound);
2048
+ }
2049
+ const options = {
2050
+ featureNS: describeFeatureType.namespace,
2051
+ featureType: layerName,
2052
+ srsName: srs,
2053
+ featurePrefix: null,
2054
+ nativeElements: null,
2055
+ version: this.getAdvanced().wfsTransactionVersion
2056
+ };
2057
+ const transaction = this._formatWFS.writeTransaction(this._insertFeatures, this._updateFeatures, this._deleteFeatures, options);
2058
+ let payload = this._xs.serializeToString(transaction);
2059
+ const geomType = describeFeatureType.geomType;
2060
+ const geomField = describeFeatureType.geomField;
2061
+ // Ugly fix to support GeometryCollection on GML
2062
+ // See https://github.com/openlayers/openlayers/issues/4220
2063
+ if (geomType === GeometryType.GeometryCollection) {
2064
+ if (transactionType === TransactionType.Insert) {
2065
+ payload = payload.replace(/<geometry>/g, `<geometry><MultiGeometry xmlns="http://www.opengis.net/gml" srsName="${srs}"><geometryMember>`);
2066
+ payload = payload.replace(/<\/geometry>/g, `</geometryMember></MultiGeometry></geometry>`);
2067
+ }
2068
+ else if (transactionType === TransactionType.Update) {
2069
+ const gmemberIn = `<MultiGeometry xmlns="http://www.opengis.net/gml" srsName="${srs}"><geometryMember>`;
2070
+ const gmemberOut = `</geometryMember></MultiGeometry>`;
2071
+ payload = payload.replace(/(.*)(<Name>geometry<\/Name><Value>)(.*?)(<\/Value>)(.*)/g, `$1$2${gmemberIn}$3${gmemberOut}$4$5`);
2072
+ }
2073
+ }
2074
+ // Fixes geometry name, weird bug with GML:
2075
+ // The property for the geometry column is always named "geometry"
2076
+ if (transactionType === TransactionType.Insert) {
2077
+ payload = payload.replace(/<(\/?)\bgeometry\b>/g, `<$1${geomField}>`);
2078
+ }
2079
+ else {
2080
+ payload = payload.replace(/<Name>geometry<\/Name>/g, `<Name>${geomField}</Name>`);
2081
+ }
2082
+ // This has to be te same used before
2083
+ if (this.hasLockFeature &&
2084
+ this.getUseLockFeature() &&
2085
+ transactionType !== TransactionType.Insert) {
2086
+ payload = payload.replace(`</Transaction>`, `<LockId>${this._options.advanced.lockFeatureParams.lockId}</LockId></Transaction>`);
2087
+ }
2088
+ const headers = {
2089
+ 'Content-Type': 'text/xml',
2090
+ ...this.getHeaders()
2091
+ };
2092
+ const response = await fetch(this.getUrl(), {
2093
+ method: 'POST',
2094
+ body: payload,
2095
+ headers: headers,
2096
+ credentials: this._options.credentials
2097
+ });
2098
+ if (!response.ok) {
2099
+ throw new Error(I18N.errors.transaction + ' ' + response.status);
2100
+ }
2101
+ const parseResponse = this._formatWFS.readTransactionResponse(await response.text());
2102
+ if (!Object.keys(parseResponse).length) {
2103
+ const responseStr = await response.text();
2104
+ const findError = String(responseStr).match(/<ows:ExceptionText>([\s\S]*?)<\/ows:ExceptionText>/);
2105
+ if (findError) {
2106
+ throw new Error(findError[1]);
2107
+ }
2108
+ }
2109
+ if (transactionType !== TransactionType.Delete) {
2110
+ for (const feature of features) {
2111
+ getEditLayer().getSource().removeFeature(feature);
2112
+ }
2113
+ }
2114
+ const wlayer = getStoredLayer(layerName);
2115
+ wlayer.refresh();
2116
+ showLoading(false);
2117
+ this._insertFeatures = [];
2118
+ this._updateFeatures = [];
2119
+ this._deleteFeatures = [];
2120
+ this._countRequests = 0;
2121
+ resolve(parseResponse);
2122
+ }
2123
+ catch (err) {
2124
+ showError(err.message, err);
2125
+ showLoading(false);
2126
+ this._countRequests = 0;
2127
+ reject();
2128
+ }
2129
+ }, 0);
2130
+ });
2131
+ }
2132
+ /**
2133
+ *
2134
+ * @param feature
2135
+ * @param geom
2136
+ * @private
2137
+ */
2138
+ _transformCircleToPolygon(feature, geom) {
2139
+ const geomConverted = fromCircle(geom);
2140
+ feature.setGeometry(geomConverted);
2141
+ }
2142
+ /**
2143
+ *
2144
+ * @param feature
2145
+ * @private
2146
+ * @param geom
2147
+ */
2148
+ _transformGeoemtryCollectionToGeometries(feature, geom) {
2149
+ let geomConverted = geom.getGeometries()[0];
2150
+ if (geomConverted instanceof Circle$1) {
2151
+ geomConverted = fromCircle(geomConverted);
2152
+ }
2153
+ feature.setGeometry(geomConverted);
2154
+ }
2155
+ /**
2156
+ *
2157
+ * @param feature
2158
+ * @returns
2159
+ * @private
2160
+ */
2161
+ _cloneFeature(feature) {
2162
+ removeFeatureFromEditList(feature);
2163
+ const featureProperties = feature.getProperties();
2164
+ delete featureProperties.boundedBy;
2165
+ delete featureProperties._layerName_;
2166
+ const clone = new Feature(featureProperties);
2167
+ clone.setId(feature.getId());
2168
+ return clone;
2169
+ }
2170
+ /**
2171
+ * Lock a feature in the geoserver. Useful before editing a geometry,
2172
+ * to avoid changes from multiples suers
2173
+ *
2174
+ * @param featureId
2175
+ * @param layerName
2176
+ * @param retry
2177
+ * @public
2178
+ */
2179
+ async lockFeature(featureId, layerName, retry = 0) {
2180
+ const params = new URLSearchParams({
2181
+ service: 'wfs',
2182
+ version: this.getAdvanced().lockFeatureVersion,
2183
+ request: 'LockFeature',
2184
+ typeName: layerName,
2185
+ expiry: String(this._options.advanced.lockFeatureParams.expiry),
2186
+ LockId: this._options.advanced.lockFeatureParams.lockId,
2187
+ releaseAction: this._options.advanced.lockFeatureParams.releaseAction,
2188
+ exceptions: 'application/json',
2189
+ featureid: `${featureId}`
2190
+ });
2191
+ const url_fetch = this.getUrl() + '?' + params.toString();
2192
+ try {
2193
+ const response = await fetch(url_fetch, {
2194
+ headers: this._options.headers,
2195
+ credentials: this._options.credentials
2196
+ });
2197
+ if (!response.ok) {
2198
+ throw new Error(I18N.errors.lockFeature);
2199
+ }
2200
+ const data = await response.text();
2201
+ try {
2202
+ // First, check if is a JSON (with errors)
2203
+ const dataParsed = JSON.parse(data);
2204
+ if ('exceptions' in dataParsed) {
2205
+ const exceptions = dataParsed.exceptions;
2206
+ if (exceptions[0].code === 'CannotLockAllFeatures') {
2207
+ // Maybe the Feature is already blocked, ant thats trigger error, so, we try one locking more time again
2208
+ if (!retry) {
2209
+ this.lockFeature(featureId, layerName, 1);
2210
+ }
2211
+ else {
2212
+ showError(I18N.errors.lockFeature, exceptions);
2213
+ }
2214
+ }
2215
+ else {
2216
+ showError(exceptions[0].text, exceptions);
2217
+ }
2218
+ }
2219
+ }
2220
+ catch (err) {
2221
+ /*
2222
+
2223
+ let dataDoc = (new window.DOMParser()).parseFromString(data, 'text/xml');
2224
+
2225
+ let lockId = dataDoc.getElementsByTagName('wfs:LockId');
2226
+
2227
+ let featuresLocked: HTMLCollectionOf<Element> = dataDoc.getElementsByTagName('ogc:FeatureId');
2228
+
2229
+ for (let featureLocked of featuresLocked as any) {
2230
+
2231
+ console.log(featureLocked.getAttribute('fid'));
2232
+
2233
+ }
2234
+
2235
+ */
2236
+ }
2237
+ return data;
2238
+ }
2239
+ catch (err) {
2240
+ showError(err.message, err);
2241
+ }
2242
+ }
2243
+ }
2244
+ var GeoserverProperty;
2245
+ (function (GeoserverProperty) {
2246
+ GeoserverProperty["CAPABILITIES"] = "capabilities";
2247
+ GeoserverProperty["URL"] = "url";
2248
+ GeoserverProperty["HEADERS"] = "headers";
2249
+ GeoserverProperty["CREDENTIALS"] = "credentials";
2250
+ GeoserverProperty["ADVANCED"] = "advanced";
2251
+ GeoserverProperty["HASTRASNACTION"] = "hasTransaction";
2252
+ GeoserverProperty["HASLOCKFEATURE"] = "hasLockFeature";
2253
+ GeoserverProperty["HASDESCRIBEFEATURETYPE"] = "hasDescribeFeatureType";
2254
+ GeoserverProperty["USELOCKFEATURE"] = "useLockFeature";
2255
+ GeoserverProperty["ISLOADED"] = "isLoaded";
2256
+ })(GeoserverProperty || (GeoserverProperty = {}));
2257
+
2258
+ var img$1 = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' width='448' height='448' viewBox='0 0 448 448'%3e %3cpath d='M222 296l29-29-38-38-29 29v14h24v24h14zM332 116c-2.25-2.25-6-2-8.25 0.25l-87.5 87.5c-2.25 2.25-2.5 6-0.25 8.25s6 2 8.25-0.25l87.5-87.5c2.25-2.25 2.5-6 0.25-8.25zM352 264.5v47.5c0 39.75-32.25 72-72 72h-208c-39.75 0-72-32.25-72-72v-208c0-39.75 32.25-72 72-72h208c10 0 20 2 29.25 6.25 2.25 1 4 3.25 4.5 5.75 0.5 2.75-0.25 5.25-2.25 7.25l-12.25 12.25c-2.25 2.25-5.25 3-8 2-3.75-1-7.5-1.5-11.25-1.5h-208c-22 0-40 18-40 40v208c0 22 18 40 40 40h208c22 0 40-18 40-40v-31.5c0-2 0.75-4 2.25-5.5l16-16c2.5-2.5 5.75-3 8.75-1.75s5 4 5 7.25zM328 80l72 72-168 168h-72v-72zM439 113l-23 23-72-72 23-23c9.25-9.25 24.75-9.25 34 0l38 38c9.25 9.25 9.25 24.75 0 34z'%3e%3c/path%3e%3c/svg%3e";
2259
+
2260
+ var img = "data:image/svg+xml,%3csvg version='1.1' xmlns='http://www.w3.org/2000/svg' width='541' height='512' viewBox='0 0 541 512'%3e %3cpath fill='black' d='M103.306 228.483l129.493-125.249c-17.662-4.272-31.226-18.148-34.98-35.663l-0.055-0.307-129.852 125.248c17.812 4.15 31.53 18.061 35.339 35.662l0.056 0.308z'%3e%3c/path%3e %3cpath fill='black' d='M459.052 393.010c-13.486-8.329-22.346-23.018-22.373-39.779v-0.004c-0.053-0.817-0.082-1.772-0.082-2.733s0.030-1.916 0.089-2.863l-0.007 0.13-149.852 71.94c9.598 8.565 15.611 20.969 15.611 34.779 0 0.014 0 0.029 0 0.043v-0.002c-0.048 5.164-0.94 10.104-2.544 14.711l0.098-0.322z'%3e%3c/path%3e %3cpath fill='black' d='M290.207 57.553c-0.009 15.55-7.606 29.324-19.289 37.819l-0.135 0.093 118.054 46.69c-0.216-1.608-0.346-3.48-0.36-5.379v-0.017c0.033-16.948 9.077-31.778 22.596-39.953l0.209-0.118-122.298-48.056c0.659 2.633 1.098 5.693 1.221 8.834l0.002 0.087z'%3e%3c/path%3e %3cpath fill='black' d='M241.36 410.132l-138.629-160.067c-4.734 17.421-18.861 30.61-36.472 33.911l-0.29 0.045 143.881 166.255c1.668-18.735 14.197-34.162 31.183-40.044l0.327-0.099z'%3e%3c/path%3e %3cpath fill='black' d='M243.446 115.105c-31.785 0-57.553-25.767-57.553-57.553s25.767-57.553 57.553-57.553c31.785 0 57.552 25.767 57.552 57.553v0c0 31.786-25.767 57.553-57.553 57.553v0zM243.446 21.582c-19.866 0-35.97 16.105-35.97 35.97s16.105 35.97 35.97 35.97c19.866 0 35.97-16.105 35.97-35.97v0c0-19.866-16.104-35.97-35.97-35.97v0z'%3e%3c/path%3e %3cpath fill='black' d='M483.224 410.78c-31.786 0-57.553-25.767-57.553-57.553s25.767-57.553 57.553-57.553c31.786 0 57.552 25.767 57.552 57.553v0c0 31.786-25.767 57.553-57.553 57.553v0zM483.224 317.257c-19.866 0-35.97 16.104-35.97 35.97s16.105 35.97 35.97 35.97c19.866 0 35.97-16.105 35.97-35.97v0c0-19.866-16.105-35.97-35.97-35.97v0z'%3e%3c/path%3e %3cpath fill='black' d='M57.553 295.531c-31.785 0-57.553-25.767-57.553-57.553s25.767-57.553 57.553-57.553c31.785 0 57.553 25.767 57.553 57.553v0c0 31.786-25.767 57.553-57.553 57.553v0zM57.553 202.008c-19.866 0-35.97 16.105-35.97 35.97s16.105 35.97 35.97 35.97c19.866 0 35.97-16.105 35.97-35.97v0c-0.041-19.835-16.13-35.898-35.97-35.898 0 0 0 0 0 0v0z'%3e%3c/path%3e %3cpath fill='black' d='M256.036 512.072c-31.786 0-57.553-25.767-57.553-57.553s25.767-57.553 57.553-57.553c31.786 0 57.553 25.767 57.553 57.553v0c0 31.786-25.767 57.553-57.553 57.553v0zM256.036 418.55c-19.866 0-35.97 16.104-35.97 35.97s16.105 35.97 35.97 35.97c19.866 0 35.97-16.105 35.97-35.97v0c0-19.866-16.105-35.97-35.97-35.97v0z'%3e%3c/path%3e %3cpath fill='black' d='M435.24 194.239c-31.786 0-57.553-25.767-57.553-57.553s25.767-57.553 57.553-57.553c31.786 0 57.553 25.767 57.553 57.553v0c0 31.785-25.767 57.553-57.553 57.553v0zM435.24 100.716c-19.866 0-35.97 16.105-35.97 35.97s16.105 35.97 35.97 35.97c19.866 0 35.97-16.105 35.97-35.97v0c0-19.866-16.105-35.97-35.97-35.97v0z'%3e%3c/path%3e%3c/svg%3e";
2261
+
2262
+ class EditOverlay extends Overlay {
2263
+ constructor(feature, coordinate = null) {
2264
+ super({
2265
+ id: feature.getId(),
2266
+ position: coordinate || getCenter(feature.getGeometry().getExtent()),
2267
+ positioning: 'center-center',
2268
+ offset: [0, -40],
2269
+ stopEvent: true,
2270
+ element: (createElement("div", null,
2271
+ createElement("div", { className: "ol-wfst--edit-button-cnt", onclick: () => {
2272
+ this.dispatchEvent('editFields');
2273
+ } },
2274
+ createElement("button", { className: "ol-wfst--edit-button", type: "button", title: I18N.labels.editFields },
2275
+ createElement("img", { src: img$1, alt: I18N.labels.editFields }))),
2276
+ createElement("div", { className: "ol-wfst--edit-button-cnt", onclick: () => {
2277
+ this.dispatchEvent('editGeom');
2278
+ } },
2279
+ createElement("button", { class: "ol-wfst--edit-button", type: "button", title: I18N.labels.editGeom },
2280
+ createElement("img", { src: img, alt: I18N.labels.editGeom })))))
2281
+ });
2282
+ }
2283
+ }
2284
+
2285
+ const controlElement = document.createElement('div');
2286
+ /**
2287
+ * Tiny WFST-T client to insert (drawing/uploading), modify and delete
2288
+ * features on GeoServers using OpenLayers. Layers with these types
2289
+ * of geometries are supported: "GeometryCollection" (in this case, you can
2290
+ * choose the geometry type of each element to draw), "Point", "MultiPoint",
2291
+ * "LineString", "MultiLineString", "Polygon" and "MultiPolygon".
2292
+ *
2293
+ * @constructor
2294
+ * @fires modifystart
2295
+ * @fires modifyend
2296
+ * @fires drawstart
2297
+ * @fires drawend
2298
+ * @fires load
2299
+ * @fires describeFeatureType
2300
+ * @extends {ol/control/Control~Control}
2301
+ * @param options Wfst options, see [Wfst Options](#options) for more details.
2302
+ */
2303
+ class Wfst extends Control {
2304
+ _options;
2305
+ _i18n;
2306
+ // Ol
2307
+ _map;
2308
+ _view;
2309
+ _viewport;
2310
+ _initialized = false;
2311
+ _layersControl;
2312
+ _overlay;
2313
+ // Interactions
2314
+ _interactionWfsSelect;
2315
+ _interactionSelectModify;
2316
+ _collectionModify;
2317
+ _interactionModify;
2318
+ _interactionSnap;
2319
+ _interactionDraw;
2320
+ // Obserbable keys
2321
+ _keyClickWms;
2322
+ _keyRemove;
2323
+ _keySelect;
2324
+ // Controls
2325
+ _controlApplyDiscardChanges;
2326
+ _controlWidgetToolsDiv;
2327
+ _selectDraw;
2328
+ // State
2329
+ _currentZoom;
2330
+ _lastZoom;
2331
+ // Editing
2332
+ _editFeature;
2333
+ _editFeatureOriginal;
2334
+ _uploads;
2335
+ _editFields;
2336
+ constructor(options) {
2337
+ super({
2338
+ target: null,
2339
+ element: controlElement,
2340
+ render: () => {
2341
+ if (!this._map)
2342
+ this._init();
2343
+ }
2344
+ });
2345
+ setLang(options.language, options.i18n);
2346
+ const defaultOptions = getDefaultOptions();
2347
+ this._options = deepObjectAssign(defaultOptions, options);
2348
+ // By default, the first layer is ready to accept new draws
2349
+ setActiveLayerToInsertEls(this._options.layers[0]);
2350
+ this._controlWidgetToolsDiv = controlElement;
2351
+ this._controlWidgetToolsDiv.className = 'ol-wfst--tools-control';
2352
+ this._uploads = new Uploads(this._options);
2353
+ this._editFields = new EditFieldsModal(this._options.modal);
2354
+ }
2355
+ /**
2356
+ * Get all the layers in the ol-wfst instance
2357
+ * @public
2358
+ */
2359
+ getLayers() {
2360
+ return Object.values(getStoredMapLayers());
2361
+ }
2362
+ /**
2363
+ * Get a layer
2364
+ * @public
2365
+ */
2366
+ getLayerByName(layerName = '') {
2367
+ const layers = getStoredMapLayers();
2368
+ if (layerName && layerName in layers) {
2369
+ return layers[layerName];
2370
+ }
2371
+ return null;
2372
+ }
2373
+ /**
2374
+ * Connect to the GeoServer and retrieve metadata about the service (GetCapabilities).
2375
+ * Get each layer specs (DescribeFeatureType) and create the layers and map controls.
2376
+ * @fires describeFeatureType
2377
+ * @private
2378
+ */
2379
+ async _initMapAndLayers() {
2380
+ try {
2381
+ const layers = this._options.layers;
2382
+ if (layers.length) {
2383
+ let layerRendered = 0;
2384
+ let layersNumber = 0; // Only count visibles
2385
+ layers.forEach((layer) => {
2386
+ if (layer.getVisible())
2387
+ layersNumber++;
2388
+ layer.on('layerRendered', () => {
2389
+ layerRendered++;
2390
+ if (layerRendered >= layersNumber) {
2391
+ // run only once
2392
+ if (!this._initialized) {
2393
+ this.dispatchEvent('load');
2394
+ this._initialized = true;
2395
+ }
2396
+ showLoading(false);
2397
+ }
2398
+ });
2399
+ layer.on('change:describeFeatureType', () => {
2400
+ const domEl = this._layersControl.addLayerEl(layer);
2401
+ layer.on('change:isVisible', () => {
2402
+ const layerNotVisible = 'ol-wfst--layer-not-visible';
2403
+ const visible = layer.isVisibleByZoom();
2404
+ if (visible)
2405
+ domEl.classList.remove(layerNotVisible);
2406
+ else
2407
+ domEl.classList.add(layerNotVisible);
2408
+ });
2409
+ layer.set(BaseLayerProperty.ISVISIBLE, this._currentZoom > layer.getMinZoom());
2410
+ this.dispatchEvent(new WfstEvent({
2411
+ type: 'describeFeatureType',
2412
+ layer: layer,
2413
+ data: layer.getDescribeFeatureType()
2414
+ }));
2415
+ });
2416
+ layer._init();
2417
+ this._map.addLayer(layer);
2418
+ setMapLayers({
2419
+ [layer.get(BaseLayerProperty.NAME)]: layer
2420
+ });
2421
+ });
2422
+ this._createMapElements(this._options.showControl, this._options.active);
2423
+ }
2424
+ }
2425
+ catch (err) {
2426
+ showLoading(false);
2427
+ showError(err.message, err);
2428
+ }
2429
+ }
2430
+ /**
2431
+ * @private
2432
+ */
2433
+ _init() {
2434
+ this._map = super.getMap();
2435
+ this._view = this._map.getView();
2436
+ this._viewport = this._map.getViewport();
2437
+ setMap(this._map);
2438
+ //@ts-expect-error
2439
+ this._uploads.on('addedFeatures', ({ features }) => {
2440
+ const layer = getActiveLayerToInsertEls();
2441
+ layer.insertFeatures(features);
2442
+ });
2443
+ //@ts-expect-error
2444
+ this._uploads.on('loadedFeatures', ({ features }) => {
2445
+ this.activateEditMode();
2446
+ const editLayerSource = getEditLayer().getSource();
2447
+ editLayerSource.addFeatures(features);
2448
+ this._view.fit(editLayerSource.getExtent(), {
2449
+ size: this._map.getSize(),
2450
+ maxZoom: 21,
2451
+ padding: [100, 100, 100, 100]
2452
+ });
2453
+ });
2454
+ // @ts-expect-error
2455
+ this._editFields.on('save', ({ feature }) => {
2456
+ // Force deselect to trigger handler
2457
+ this._collectionModify.remove(feature);
2458
+ });
2459
+ // @ts-expect-error
2460
+ this._editFields.dispose('delete', ({ feature }) => {
2461
+ this._deleteFeature(feature, true);
2462
+ });
2463
+ this._addMapEvents();
2464
+ initModal(this._options['modal']);
2465
+ this._controlWidgetToolsDiv.append(initLoading());
2466
+ this._initMapAndLayers();
2467
+ }
2468
+ /**
2469
+ * Create the edit layer to allow modify elements, add interactions,
2470
+ * map controls and keyboard handlers.
2471
+ *
2472
+ * @param showControl
2473
+ * @param active
2474
+ * @private
2475
+ */
2476
+ async _createMapElements(showControl, active) {
2477
+ // VectorLayer to store features on editing and inserting
2478
+ this._prepareEditLayer();
2479
+ this._addInteractions();
2480
+ this._addInteractionHandlers();
2481
+ if (showControl) {
2482
+ this._addMapControl();
2483
+ }
2484
+ // By default, init in edit mode
2485
+ this.activateEditMode(active);
2486
+ }
2487
+ /**
2488
+ * @private
2489
+ */
2490
+ _addInteractions() {
2491
+ /**
2492
+ * Select the wfs feature already downloaded
2493
+ * @private
2494
+ */
2495
+ const prepareWfsInteraction = () => {
2496
+ this._collectionModify = new Collection();
2497
+ // Interaction to select wfs layer elements
2498
+ this._interactionWfsSelect = new Select({
2499
+ hitTolerance: 10,
2500
+ style: (feature) => styleFunction(feature),
2501
+ toggleCondition: never,
2502
+ filter: (feature, layer) => {
2503
+ return (getMode() !== Modes.Edit &&
2504
+ layer &&
2505
+ layer instanceof WfsLayer &&
2506
+ layer === getActiveLayerToInsertEls());
2507
+ }
2508
+ });
2509
+ this._map.addInteraction(this._interactionWfsSelect);
2510
+ this._interactionWfsSelect.on('select', ({ selected, deselected, mapBrowserEvent }) => {
2511
+ const coordinate = mapBrowserEvent.coordinate;
2512
+ if (selected.length) {
2513
+ selected.forEach((feature) => {
2514
+ if (!isFeatureEdited(feature)) {
2515
+ // Remove the feature from the original layer
2516
+ const layer = this._interactionWfsSelect.getLayer(feature);
2517
+ layer.getSource().removeFeature(feature);
2518
+ this._addFeatureToEditMode(feature, coordinate, layer.get(BaseLayerProperty.NAME));
2519
+ }
2520
+ });
2521
+ }
2522
+ if (deselected.length) {
2523
+ if (getMode() !== Modes.Edit) {
2524
+ deselected.forEach((feature) => {
2525
+ // Trigger deselect
2526
+ // This is necessary for those times where two features overlap.
2527
+ this._collectionModify.remove(feature);
2528
+ });
2529
+ }
2530
+ }
2531
+ });
2532
+ };
2533
+ /**
2534
+ * Call the geoserver to get the clicked feature
2535
+ * @private
2536
+ */
2537
+ const prepareWmsInteraction = () => {
2538
+ // Interaction to allow select features in the edit layer
2539
+ this._interactionSelectModify = new Select({
2540
+ style: (feature) => styleFunction(feature),
2541
+ layers: [getEditLayer()],
2542
+ toggleCondition: never,
2543
+ removeCondition: () => (getMode() === Modes.Edit ? true : false) // Prevent deselect on clicking outside the feature
2544
+ });
2545
+ this._map.addInteraction(this._interactionSelectModify);
2546
+ this._collectionModify =
2547
+ this._interactionSelectModify.getFeatures();
2548
+ this._keyClickWms = this._map.on(this._options.evtType, async (evt) => {
2549
+ if (this._map.hasFeatureAtPixel(evt.pixel)) {
2550
+ return;
2551
+ }
2552
+ // Only get other features if editmode is disabled
2553
+ if (getMode() !== Modes.Edit) {
2554
+ const layer = getActiveLayerToInsertEls();
2555
+ // If layer is hidden or is a wfs, skip
2556
+ if (!layer.getVisible() ||
2557
+ !layer.isVisibleByZoom() ||
2558
+ layer instanceof WfsLayer) {
2559
+ return;
2560
+ }
2561
+ const features = await layer.getFeaturesByClickEvent(evt);
2562
+ if (!features.length) {
2563
+ return;
2564
+ }
2565
+ // For now, support is only for one feature at time
2566
+ this._addFeatureToEditMode(features[0], evt.coordinate, layer.get(BaseLayerProperty.NAME));
2567
+ }
2568
+ });
2569
+ };
2570
+ if (this._options.layers.find((layer) => layer instanceof WfsLayer)) {
2571
+ prepareWfsInteraction();
2572
+ }
2573
+ if (this._options.layers.find((layer) => layer instanceof WmsLayer)) {
2574
+ prepareWmsInteraction();
2575
+ }
2576
+ this._interactionModify = new Modify({
2577
+ style: () => {
2578
+ if (getMode() === Modes.Edit) {
2579
+ return new Style({
2580
+ image: new Circle({
2581
+ radius: 6,
2582
+ fill: new Fill({
2583
+ color: '#ff0000'
2584
+ }),
2585
+ stroke: new Stroke({
2586
+ width: 2,
2587
+ color: 'rgba(5, 5, 5, 0.9)'
2588
+ })
2589
+ })
2590
+ });
2591
+ }
2592
+ else {
2593
+ return;
2594
+ }
2595
+ },
2596
+ features: this._collectionModify,
2597
+ condition: (evt) => {
2598
+ return primaryAction(evt) && getMode() === Modes.Edit;
2599
+ }
2600
+ });
2601
+ this._map.addInteraction(this._interactionModify);
2602
+ this._interactionSnap = new Snap({
2603
+ source: getEditLayer().getSource()
2604
+ });
2605
+ this._map.addInteraction(this._interactionSnap);
2606
+ }
2607
+ /**
2608
+ * Layer to store temporary the elements to be edited
2609
+ * @private
2610
+ */
2611
+ _prepareEditLayer() {
2612
+ this._map.addLayer(getEditLayer());
2613
+ }
2614
+ /**
2615
+ * @private
2616
+ */
2617
+ _addMapEvents() {
2618
+ /**
2619
+ * @private
2620
+ */
2621
+ const keyboardEvents = () => {
2622
+ document.addEventListener('keydown', ({ key }) => {
2623
+ const inputFocus = document.querySelector('input:focus');
2624
+ if (inputFocus) {
2625
+ return;
2626
+ }
2627
+ if (key === 'Delete') {
2628
+ const selectedFeatures = this._collectionModify;
2629
+ if (selectedFeatures) {
2630
+ selectedFeatures.forEach((feature) => {
2631
+ this._deleteFeature(feature, true);
2632
+ });
2633
+ }
2634
+ }
2635
+ });
2636
+ };
2637
+ keyboardEvents();
2638
+ this._map.on('moveend', () => {
2639
+ this._currentZoom = this._view.getZoom();
2640
+ if (this._currentZoom !== this._lastZoom) {
2641
+ const layers = getStoredMapLayers();
2642
+ Object.keys(layers).forEach((key) => {
2643
+ const layer = layers[key];
2644
+ if (this._currentZoom > layer.getMinZoom()) {
2645
+ // Show the layers
2646
+ if (!layer.get(BaseLayerProperty.ISVISIBLE)) {
2647
+ layer.set(BaseLayerProperty.ISVISIBLE, true);
2648
+ }
2649
+ }
2650
+ else {
2651
+ // Hide the layer
2652
+ if (layer.get(BaseLayerProperty.ISVISIBLE)) {
2653
+ layer.set(BaseLayerProperty.ISVISIBLE, false);
2654
+ }
2655
+ }
2656
+ });
2657
+ this._lastZoom = this._currentZoom;
2658
+ }
2659
+ });
2660
+ }
2661
+ /**
2662
+ * Add map handlers
2663
+ * @private
2664
+ */
2665
+ _addInteractionHandlers() {
2666
+ // When a feature is modified, add this to a list.
2667
+ // This prevent events fired on select and deselect features that has no changes and should
2668
+ // not be updated in the geoserver
2669
+ this._interactionModify.on('modifyend', (evt) => {
2670
+ const feature = evt.features.item(0);
2671
+ addFeatureToEditedList(feature);
2672
+ super.dispatchEvent(evt);
2673
+ });
2674
+ this._interactionModify.on('modifystart', (evt) => {
2675
+ super.dispatchEvent(evt);
2676
+ });
2677
+ this._onDeselectFeatureEvent();
2678
+ this._onRemoveFeatureEvent();
2679
+ }
2680
+ /**
2681
+ * Add the widget on the map to allow change the tools and select active layers
2682
+ * @private
2683
+ */
2684
+ _addMapControl() {
2685
+ this._layersControl = new LayersControl(this._options.showUpload ? this._uploads : null, this._options.uploadFormats);
2686
+ // @ts-expect-error
2687
+ this._layersControl.on('drawMode', () => {
2688
+ if (getMode() === Modes.Draw) {
2689
+ resetStateButtons();
2690
+ this.activateEditMode();
2691
+ }
2692
+ else {
2693
+ const activeLayer = getActiveLayerToInsertEls();
2694
+ if (!activeLayer.isVisibleByZoom()) {
2695
+ showError(I18N.errors.layerNotVisible);
2696
+ }
2697
+ else {
2698
+ this.activateDrawMode(getActiveLayerToInsertEls());
2699
+ }
2700
+ }
2701
+ });
2702
+ // @ts-expect-error
2703
+ this._layersControl.on('changeGeom', () => {
2704
+ if (getMode() === Modes.Draw) {
2705
+ this.activateDrawMode(getActiveLayerToInsertEls());
2706
+ }
2707
+ });
2708
+ const controlEl = this._layersControl.render();
2709
+ this._selectDraw = controlEl.querySelector('.wfst--tools-control--select-draw');
2710
+ this._controlWidgetToolsDiv.append(controlEl);
2711
+ }
2712
+ /**
2713
+ *
2714
+ * @param feature
2715
+ * @private
2716
+ */
2717
+ _deselectEditFeature(feature) {
2718
+ this._removeOverlayHelper(feature);
2719
+ }
2720
+ /**
2721
+ *
2722
+ * @param feature
2723
+ * @param layerName
2724
+ * @private
2725
+ */
2726
+ _restoreFeatureToLayer(feature, layerName) {
2727
+ layerName = layerName || feature.get('_layerName_');
2728
+ const layer = getStoredMapLayers()[layerName];
2729
+ layer.getSource().addFeature(feature);
2730
+ }
2731
+ /**
2732
+ * @param feature
2733
+ * @private
2734
+ */
2735
+ _removeFeatureFromTmpLayer(feature) {
2736
+ // Remove element from the Layer
2737
+ getEditLayer().getSource().removeFeature(feature);
2738
+ }
2739
+ /**
2740
+ * Trigger on deselecting a feature from in the Edit layer
2741
+ *
2742
+ * @private
2743
+ */
2744
+ _onDeselectFeatureEvent() {
2745
+ const checkIfFeatureIsChanged = (feature) => {
2746
+ const layerName = feature.get('_layerName_');
2747
+ const layer = this._options.layers.find((layer) => layer.get(BaseLayerProperty.NAME) === layerName);
2748
+ if (layer instanceof WfsLayer) {
2749
+ this._interactionWfsSelect.getFeatures().remove(feature);
2750
+ }
2751
+ if (isFeatureEdited(feature)) {
2752
+ layer.transactFeatures(TransactionType.Update, feature);
2753
+ }
2754
+ else {
2755
+ // Si es wfs y el elemento no tuvo cambios, lo devolvemos a la layer original
2756
+ if (layer instanceof WfsLayer) {
2757
+ this._restoreFeatureToLayer(feature, layerName);
2758
+ }
2759
+ this._removeFeatureFromTmpLayer(feature);
2760
+ }
2761
+ };
2762
+ // This is fired when a feature is deselected and fires the transaction process
2763
+ this._keySelect = this._collectionModify.on('remove', (evt) => {
2764
+ const feature = evt.element;
2765
+ this._deselectEditFeature(feature);
2766
+ checkIfFeatureIsChanged(feature);
2767
+ this._editModeOff();
2768
+ });
2769
+ }
2770
+ /**
2771
+ * Trigger on removing a feature from the Edit layer
2772
+ *
2773
+ * @private
2774
+ */
2775
+ _onRemoveFeatureEvent() {
2776
+ // If a feature is removed from the edit layer
2777
+ this._keyRemove = getEditLayer()
2778
+ .getSource()
2779
+ .on('removefeature', (evt) => {
2780
+ const feature = evt.feature;
2781
+ if (!feature.get('_delete_')) {
2782
+ return;
2783
+ }
2784
+ if (this._keySelect) {
2785
+ unByKey(this._keySelect);
2786
+ }
2787
+ const layerName = feature.get('_layerName_');
2788
+ const ll = this.getLayerByName(layerName);
2789
+ ll.transactFeatures(TransactionType.Delete, feature);
2790
+ this._deselectEditFeature(feature);
2791
+ this._editModeOff();
2792
+ if (this._keySelect) {
2793
+ setTimeout(() => {
2794
+ this._onDeselectFeatureEvent();
2795
+ }, 150);
2796
+ }
2797
+ });
2798
+ }
2799
+ /**
2800
+ *
2801
+ * @param feature
2802
+ * @private
2803
+ */
2804
+ _editModeOn(feature) {
2805
+ this._editFeatureOriginal = feature.clone();
2806
+ activateMode(Modes.Edit);
2807
+ // To refresh the style
2808
+ getEditLayer().getSource().changed();
2809
+ this._removeOverlayHelper(feature);
2810
+ this._controlApplyDiscardChanges = new EditControlChangesEl(feature);
2811
+ this._controlApplyDiscardChanges.on('cancel', ({ feature }) => {
2812
+ feature.setGeometry(this._editFeatureOriginal.getGeometry());
2813
+ removeFeatureFromEditList(feature);
2814
+ this._collectionModify.remove(feature);
2815
+ });
2816
+ this._controlApplyDiscardChanges.on('apply', ({ feature }) => {
2817
+ showLoading();
2818
+ this._collectionModify.remove(feature);
2819
+ });
2820
+ this._controlApplyDiscardChanges.on('delete', ({ feature }) => {
2821
+ this._deleteFeature(feature, true);
2822
+ });
2823
+ this._map.addControl(this._controlApplyDiscardChanges);
2824
+ }
2825
+ /**
2826
+ * @private
2827
+ */
2828
+ _editModeOff() {
2829
+ activateMode(null);
2830
+ this._map.removeControl(this._controlApplyDiscardChanges);
2831
+ }
2832
+ /**
2833
+ * Remove a feature from the edit Layer and from the Geoserver
2834
+ *
2835
+ * @param feature
2836
+ * @private
2837
+ */
2838
+ _deleteFeature(feature, confirm) {
2839
+ const deleteEl = () => {
2840
+ const features = Array.isArray(feature) ? feature : [feature];
2841
+ features.forEach((feature) => {
2842
+ feature.set('_delete_', true, true);
2843
+ getEditLayer().getSource().removeFeature(feature);
2844
+ });
2845
+ this._collectionModify.clear();
2846
+ const layerName = feature.get('_layerName_');
2847
+ const layer = this._options.layers.find((layer) => layer.get(BaseLayerProperty.NAME) === layerName);
2848
+ if (layer instanceof WfsLayer) {
2849
+ this._interactionWfsSelect.getFeatures().remove(feature);
2850
+ }
2851
+ };
2852
+ if (confirm) {
2853
+ const confirmModal = Modal.confirm(I18N.labels.confirmDelete, {
2854
+ ...this._options.modal
2855
+ });
2856
+ confirmModal.show().once('dismiss', function (modal, ev, button) {
2857
+ if (button && button.value) {
2858
+ deleteEl();
2859
+ }
2860
+ });
2861
+ }
2862
+ else {
2863
+ deleteEl();
2864
+ }
2865
+ }
2866
+ /**
2867
+ * Add a feature to the Edit Layer to allow editing, and creates an Overlay Helper to show options
2868
+ *
2869
+ * @param feature
2870
+ * @param coordinate
2871
+ * @param layerName
2872
+ * @private
2873
+ */
2874
+ _addFeatureToEditMode(feature, coordinate = null, layerName = null) {
2875
+ // For now, only allow one element at time
2876
+ // @TODO: allow edit multiples elements
2877
+ if (this._collectionModify.getLength())
2878
+ return;
2879
+ if (layerName) {
2880
+ // Store the layer information inside the feature
2881
+ feature.set('_layerName_', layerName);
2882
+ }
2883
+ const props = feature ? feature.getProperties() : '';
2884
+ if (props) {
2885
+ if (feature.getGeometry()) {
2886
+ getEditLayer().getSource().addFeature(feature);
2887
+ this._collectionModify.push(feature);
2888
+ const overlay = new EditOverlay(feature, coordinate);
2889
+ // @ts-expect-error
2890
+ overlay.on('editFields', () => {
2891
+ this._editFields.show(feature);
2892
+ });
2893
+ // @ts-expect-error
2894
+ overlay.on('editGeom', () => {
2895
+ this._editModeOn(feature);
2896
+ });
2897
+ this._map.addOverlay(overlay);
2898
+ const layer = getStoredLayer(layerName);
2899
+ if (layer) {
2900
+ layer.maybeLockFeature(feature.getId());
2901
+ }
2902
+ }
2903
+ }
2904
+ }
2905
+ /**
2906
+ * Activate/deactivate the draw mode
2907
+ *
2908
+ * @param layer
2909
+ * @public
2910
+ */
2911
+ activateDrawMode(layer) {
2912
+ /**
2913
+ *
2914
+ * @param layer
2915
+ * @private
2916
+ */
2917
+ const addDrawInteraction = (layer) => {
2918
+ this.activateEditMode(false);
2919
+ // If already exists, remove
2920
+ if (this._interactionDraw) {
2921
+ this._map.removeInteraction(this._interactionDraw);
2922
+ }
2923
+ const geomDrawType = this._selectDraw.value;
2924
+ this._interactionDraw = new Draw({
2925
+ source: getEditLayer().getSource(),
2926
+ type: geomDrawType,
2927
+ style: (feature) => styleFunction(feature),
2928
+ stopClick: true // To prevent firing a map/wms click
2929
+ });
2930
+ this._map.addInteraction(this._interactionDraw);
2931
+ this._interactionDraw.on('drawstart', (evt) => {
2932
+ super.dispatchEvent(evt);
2933
+ });
2934
+ this._interactionDraw.on('drawend', (evt) => {
2935
+ const feature = evt.feature;
2936
+ layer.transactFeatures(TransactionType.Insert, feature);
2937
+ super.dispatchEvent(evt);
2938
+ });
2939
+ };
2940
+ if (!this._interactionDraw && !layer) {
2941
+ return;
2942
+ }
2943
+ if (layer) {
2944
+ // If layer is set to invisible, show warning
2945
+ if (!layer.getVisible()) {
2946
+ return;
2947
+ }
2948
+ activateDrawButton();
2949
+ this._viewport.classList.add('draw-mode');
2950
+ addDrawInteraction(layer);
2951
+ }
2952
+ else {
2953
+ this._map.removeInteraction(this._interactionDraw);
2954
+ this._viewport.classList.remove('draw-mode');
2955
+ }
2956
+ activateMode(layer ? Modes.Draw : null);
2957
+ }
2958
+ /**
2959
+ * Activate/desactivate the edit mode
2960
+ *
2961
+ * @param bool
2962
+ * @public
2963
+ */
2964
+ activateEditMode(bool = true) {
2965
+ if (bool) {
2966
+ activateModeButtons();
2967
+ this.activateDrawMode(false);
2968
+ }
2969
+ else {
2970
+ // Deselct features
2971
+ this._collectionModify.clear();
2972
+ }
2973
+ if (this._interactionSelectModify) {
2974
+ this._interactionSelectModify.setActive(bool);
2975
+ }
2976
+ this._interactionModify.setActive(bool);
2977
+ if (this._interactionWfsSelect)
2978
+ this._interactionWfsSelect.setActive(bool);
2979
+ }
2980
+ /**
2981
+ * Remove the overlay helper atttached to a specify feature
2982
+ * @param feature
2983
+ * @private
2984
+ */
2985
+ _removeOverlayHelper(feature) {
2986
+ const featureId = feature.getId();
2987
+ if (!featureId) {
2988
+ return;
2989
+ }
2990
+ const overlay = this._map.getOverlayById(featureId);
2991
+ if (!overlay) {
2992
+ return;
2993
+ }
2994
+ this._map.removeOverlay(overlay);
2995
+ }
2996
+ }
2997
+ class WfstEvent extends BaseEvent {
2998
+ data;
2999
+ layer;
3000
+ constructor(options) {
3001
+ super(options.type);
3002
+ this.layer = options.layer;
3003
+ this.data = options.data;
3004
+ }
3005
+ }
3006
+
3007
+ export { Geoserver, WfsLayer, WmsLayer, Wfst as default };
3008
+ //# sourceMappingURL=index-es.js.map