ol-wfst 5.0.0 → 5.1.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.
package/lib/ol-wfst.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /*!
2
- * ol-wfst - v4.4.0
2
+ * ol-wfst - v5.1.0
3
3
  * https://github.com/GastonZalba/ol-wfst#readme
4
- * Built: Thu Sep 10 2026 23:06:22 GMT-0300 (Argentina Standard Time)
4
+ * Built: Thu Oct 08 2026 20:27:34 GMT-0300 (Argentina Standard Time)
5
5
  */
6
6
  import Fill$1 from 'ol/style/Fill.js';
7
7
  import Stroke$1 from 'ol/style/Stroke.js';
@@ -96,7 +96,6 @@ const es = {
96
96
  save: 'Guardar',
97
97
  delete: 'Eliminar',
98
98
  cancel: 'Cancelar',
99
- apply: 'Aplicar cambios',
100
99
  upload: 'Subir',
101
100
  editMode: 'Modo Edición',
102
101
  confirmDelete: '¿Estás seguro de borrar el elemento?',
@@ -117,6 +116,10 @@ const es = {
117
116
  multipleValues: 'Valores múltiples',
118
117
  editElements: 'Editar elementos ({})',
119
118
  multipleEditNotice: 'Edición múltiple activada. Los cambios se aplicarán a los {} elementos seleccionados.',
119
+ tableMode: 'Modo tabla',
120
+ formMode: 'Modo formulario',
121
+ feature: 'Elemento',
122
+ geometry: 'Geometría',
120
123
  geoserverLayers: 'Capas de GeoServer'
121
124
  },
122
125
  errors: {
@@ -147,7 +150,6 @@ const en = {
147
150
  save: 'Save',
148
151
  delete: 'Delete',
149
152
  cancel: 'Cancel',
150
- apply: 'Apply changes',
151
153
  upload: 'Upload',
152
154
  editMode: 'Edit Mode',
153
155
  confirmDelete: 'Are you sure to delete the feature?',
@@ -168,6 +170,10 @@ const en = {
168
170
  multipleValues: 'Multiple values',
169
171
  editElements: 'Edit features ({})',
170
172
  multipleEditNotice: 'Multi-edit active. Changes will be applied to the {} selected features.',
173
+ tableMode: 'Table mode',
174
+ formMode: 'Form mode',
175
+ feature: 'Feature',
176
+ geometry: 'Geometry',
171
177
  geoserverLayers: 'Geoserver Layers'
172
178
  },
173
179
  errors: {
@@ -198,7 +204,6 @@ const zh = {
198
204
  save: '保存',
199
205
  delete: '删除',
200
206
  cancel: '取消',
201
- apply: '确认并应用改变',
202
207
  upload: '上传',
203
208
  editMode: '编辑模式',
204
209
  confirmDelete: '确认删除元素?',
@@ -219,6 +224,10 @@ const zh = {
219
224
  multipleValues: '多个值',
220
225
  editElements: '编辑元素({})',
221
226
  multipleEditNotice: '多选编辑已激活。更改将应用于所有 {} 个选定元素。',
227
+ tableMode: '表格模式',
228
+ formMode: '表单模式',
229
+ feature: '要素',
230
+ geometry: '几何',
222
231
  geoserverLayers: 'GeoServer 图层'
223
232
  },
224
233
  errors: {
@@ -1144,7 +1153,7 @@ class LayersControl extends Observable {
1144
1153
  ${layer.getVisible() ? 'ol-wfst--visible-on' : ''}
1145
1154
  ${layer === getActiveLayerToInsertEls()
1146
1155
  ? 'ol-wfst--selected-on'
1147
- : ''}`, "data-layer": layerName, children: jsxs("label", { htmlFor: `wfst--${layerName}`, children: [jsxs("div", { className: "ol-wfst--tools-control-visible", children: [jsx("span", { className: "ol-wfst--tools-control-visible-btn ol-wfst--visible-btn-on", title: I18N.labels.toggleVisibility, onClick: (evt) => this._visibilityClickHandler(evt), children: visibilityOnSvg() }), jsx("span", { className: "ol-wfst--tools-control-visible-btn ol-wfst--visible-btn-off", title: I18N.labels.toggleVisibility, onClick: (evt) => this._visibilityClickHandler(evt), children: visibilityOffSvg() })] }), input, jsx("span", { title: `${layer instanceof WfsLayer ? 'WFS' : 'WMS'} - ${layer.getDescribeFeatureType()._parsed.geomType}`, children: layer.get(BaseLayerProperty.LABEL) })] }) }));
1156
+ : ''}`, "data-layer": layerName, children: jsxs("label", { htmlFor: `wfst--${layerName}`, children: [jsxs("div", { className: "ol-wfst--layer-control-visible ", children: [jsx("span", { className: "ol-wfst--layer-control-visible -btn ol-wfst--visible-btn-on", title: I18N.labels.toggleVisibility, onClick: (evt) => this._visibilityClickHandler(evt), children: visibilityOnSvg() }), jsx("span", { className: "ol-wfst--layer-control-visible -btn ol-wfst--visible-btn-off", title: I18N.labels.toggleVisibility, onClick: (evt) => this._visibilityClickHandler(evt), children: visibilityOffSvg() })] }), input, jsx("span", { title: `${layer instanceof WfsLayer ? 'WFS' : 'WMS'} - ${layer.getDescribeFeatureType()._parsed.geomType}`, children: layer.get(BaseLayerProperty.LABEL) })] }) }));
1148
1157
  container.appendChild(layerDom);
1149
1158
  if (layer === getActiveLayerToInsertEls()) {
1150
1159
  input.dispatchEvent(new Event('change'));
@@ -1526,13 +1535,13 @@ class EditControlChangesEl extends Control {
1526
1535
  super({
1527
1536
  element: (jsx("div", { className: "ol-wfst--changes-control", children: jsxs("div", { className: "ol-wfst--changes-control-el", children: [jsxs("div", { className: "ol-wfst--changes-control-id", children: [jsx("b", { children: I18N.labels.editMode }), " -", ' ', jsx("i", { children: features.length > 1
1528
1537
  ? I18N_('editElements', features.length)
1529
- : String(features[0].getId()) })] }), jsx("button", { type: "button", className: "btn btn-sm btn-secondary", onClick: () => {
1538
+ : String(features[0].getId()) })] }), jsx("button", { type: "button", className: "btn btn-sm btn-danger", onClick: () => {
1539
+ this._dispatch('delete', features);
1540
+ }, children: I18N.labels.delete }), jsx("button", { type: "button", className: "btn btn-sm btn-secondary", onClick: () => {
1530
1541
  this._dispatch('cancel', features);
1531
1542
  }, children: I18N.labels.cancel }), jsx("button", { type: "button", className: "btn btn-sm btn-primary", onClick: () => {
1532
1543
  this._dispatch('apply', features);
1533
- }, children: I18N.labels.apply }), jsx("button", { type: "button", className: "btn btn-sm btn-danger-outline", onClick: () => {
1534
- this._dispatch('delete', features);
1535
- }, children: I18N.labels.delete })] }) }))
1544
+ }, children: I18N.labels.save })] }) }))
1536
1545
  });
1537
1546
  }
1538
1547
  _dispatch(type, features) {
@@ -1757,11 +1766,22 @@ function queryStyleFunction(_feature) {
1757
1766
  ];
1758
1767
  }
1759
1768
 
1769
+ function tableSvg() {
1770
+ return (new DOMParser().parseFromString("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n <path d=\"M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM8 20H4v-4h4v4zm0-6H4v-4h4v4zm0-6H4V4h4v4zm6 12h-4v-4h4v4zm0-6h-4v-4h4v4zm0-6h-4V4h4v4zm6 12h-4v-4h4v4zm0-6h-4v-4h4v4zm0-6h-4V4h4v4z\"></path>\n</svg>", 'image/svg+xml')).firstChild;
1771
+ }
1772
+
1773
+ function formSvg() {
1774
+ return (new DOMParser().parseFromString("<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\">\n <path d=\"M14 17H4v2h10v-2zm6-8H4v2h16V9zM4 15h16v-2H4v2zM4 5v2h16V5H4z\"></path>\n</svg>", 'image/svg+xml')).firstChild;
1775
+ }
1776
+
1760
1777
  /**
1761
1778
  * Shows a fields form in a modal window to allow changes in the properties of
1762
- * one or several features. When editing multiple features, fields whose value
1763
- * differs across the selection show the "multiple values" placeholder and only
1764
- * the fields actually changed are applied to the whole selection.
1779
+ * one or several features. When editing multiple features, a "table mode"
1780
+ * button renders one feature per row, spreadsheet-style, so each feature can be
1781
+ * edited separately (like an Excel sheet). Otherwise a single form is shown
1782
+ * where fields whose value differs across the selection show the "multiple
1783
+ * values" placeholder and only the fields actually changed are applied to the
1784
+ * whole selection.
1765
1785
  *
1766
1786
  * @param features
1767
1787
  * @private
@@ -1770,10 +1790,12 @@ class EditFieldsModal extends Observable {
1770
1790
  constructor(options) {
1771
1791
  super();
1772
1792
  this._options = options;
1793
+ this._tableMode = false;
1794
+ this._fieldList = [];
1773
1795
  this._modal = new Modal(Object.assign(Object.assign({}, this._options.modal), { header: true, headerClose: true, title: '', content: '<div></div>', footer: `
1774
1796
  <button
1775
1797
  type="button"
1776
- class="btn btn-sm btn-third"
1798
+ class="btn btn-sm btn-danger"
1777
1799
  data-action="delete"
1778
1800
  data-dismiss="modal"
1779
1801
  >
@@ -1798,29 +1820,12 @@ class EditFieldsModal extends Observable {
1798
1820
  this._modal.on('dismiss', (modal, event) => {
1799
1821
  // On saving changes
1800
1822
  if (event.target.dataset.action === 'save') {
1801
- const formElements = modal.el.querySelector('form')
1802
- .elements;
1803
- const multipleFields = new Set(Array.from(formElements)
1804
- .filter((el) => el.dataset.multiple === 'true')
1805
- .map((el) => el.name));
1806
- Array.from(formElements).forEach((el) => {
1807
- const value = el.value;
1808
- const field = el.name;
1809
- // Do not overwrite untouched fields that had
1810
- // multiple values in the selection
1811
- if (multipleFields.has(field) && value === '') {
1812
- return;
1813
- }
1814
- this._features.forEach((feature) => {
1815
- if (feature.get(field) !== value) {
1816
- feature.set(field, value, /* isSilent = */ true);
1817
- }
1818
- });
1819
- });
1820
- this._features.forEach((feature) => {
1821
- feature.changed();
1822
- addFeatureToEditedList(feature);
1823
- });
1823
+ if (this._tableMode) {
1824
+ this._saveTable(modal);
1825
+ }
1826
+ else {
1827
+ this._saveForm(modal);
1828
+ }
1824
1829
  this._dispatch('save', this._features);
1825
1830
  }
1826
1831
  else if (event.target.dataset.action === 'delete') {
@@ -1830,6 +1835,8 @@ class EditFieldsModal extends Observable {
1830
1835
  }
1831
1836
  show(features) {
1832
1837
  this._features = Array.isArray(features) ? features : [features];
1838
+ // Keep the form (current behavior) as default entry view
1839
+ this._tableMode = false;
1833
1840
  const multiple = this._features.length > 1;
1834
1841
  const modalTitle = multiple
1835
1842
  ? I18N_('editElements', this._features.length)
@@ -1838,67 +1845,184 @@ class EditFieldsModal extends Observable {
1838
1845
  // Data schema from the geoserver
1839
1846
  const layer = getStoredLayer(layerName);
1840
1847
  const describeFeatureType = layer.getDescribeFeatureType()._parsed;
1841
- const fieldList = describeFeatureType.properties.filter((field) => field.name !== describeFeatureType.geomField);
1842
- this._modal._html.body.innerHTML = '';
1843
- this._modal._html.body.append(jsxs("div", { children: [multiple && (jsx("div", { className: "ol-wfst--edit-modal-notice", children: I18N_('multipleEditNotice', this._features.length) })), jsx("form", { autocomplete: "false", children: fieldList.flatMap((field) => {
1844
- const key = field.name;
1845
- const values = this._features.map((feature) => feature.get(key));
1846
- const uniqueValues = Array.from(new Set(values.map((value) => String(value !== null && value !== void 0 ? value : ''))));
1847
- const hasMultipleValues = multiple && uniqueValues.length > 1;
1848
- const value = hasMultipleValues
1849
- ? null
1850
- : uniqueValues[0] || null;
1851
- const typeXsd = field.type;
1852
- let type;
1853
- switch (typeXsd) {
1854
- case 'xsd:double':
1855
- case 'xsd:number':
1856
- case 'xsd:int':
1857
- type = 'number';
1858
- break;
1859
- case 'xsd:date':
1860
- type = 'date';
1861
- break;
1862
- case 'xsd:date-time':
1863
- type = 'datetime';
1864
- break;
1865
- case 'xsd:string':
1866
- default:
1867
- type = 'text';
1868
- }
1869
- let input = (jsx("input", { placeholder: hasMultipleValues
1870
- ? I18N.labels.multipleValues
1871
- : 'NULL', className: 'ol-wfst--input-field-input' +
1872
- (hasMultipleValues
1873
- ? ' ol-wfst--input-multiple'
1874
- : ''), type: type, name: key, value: value, "data-multiple": hasMultipleValues ? 'true' : null }));
1875
- if (layer.beforeShowFieldsModal) {
1876
- const hookInput = layer.beforeShowFieldsModal(field, value, input);
1877
- if (!hookInput) {
1878
- return [];
1879
- }
1880
- if (typeof hookInput === 'string') {
1881
- input = new DOMParser().parseFromString(hookInput, 'text/html').body.childNodes[0];
1882
- }
1883
- else {
1884
- input = hookInput;
1885
- }
1886
- }
1887
- if (hasMultipleValues) {
1888
- input.dataset.multiple = 'true';
1889
- input.classList.add('ol-wfst--input-multiple');
1890
- }
1891
- return (jsxs("div", { className: "ol-wfst--input-field-container", children: [jsx("label", { className: "ol-wfst--input-field-label", htmlFor: key, children: key }), input] }));
1892
- }) })] }));
1848
+ this._fieldList = describeFeatureType.properties.filter((field) => field.name !== describeFeatureType.geomField);
1849
+ this._layer = layer;
1850
+ this._modal._html.dialog.classList.remove('ol-wfst--edit-table-modal');
1851
+ this._renderBody();
1893
1852
  this._modal._html.header.innerHTML = modalTitle;
1894
1853
  this._modal.show();
1895
1854
  }
1855
+ _renderBody() {
1856
+ const multiple = this._features.length > 1;
1857
+ this._modal._html.body.innerHTML = '';
1858
+ this._modal._html.body.append(jsxs("div", { children: [multiple && (jsxs("div", { className: "ol-wfst--edit-modal-notice", children: [jsx("span", { className: "ol-wfst--edit-modal-notice-txt", children: I18N_('multipleEditNotice', this._features.length) }), jsx("button", { type: "button", className: "ol-wfst--edit-modal-toolbar-btn", title: this._tableMode
1859
+ ? I18N.labels.formMode
1860
+ : I18N.labels.tableMode, onClick: () => this._toggleTable(), children: this._tableMode ? formSvg() : tableSvg() })] })), this._tableMode ? this._renderTable() : this._renderForm()] }));
1861
+ }
1862
+ _toggleTable() {
1863
+ this._tableMode = !this._tableMode;
1864
+ this._modal._html.dialog.classList.toggle('ol-wfst--edit-table-modal', this._tableMode);
1865
+ this._renderBody();
1866
+ }
1867
+ _renderForm() {
1868
+ const multiple = this._features.length > 1;
1869
+ return (jsx("form", { autocomplete: "false", children: this._fieldList.flatMap((field) => {
1870
+ const key = field.name;
1871
+ const values = this._features.map((feature) => feature.get(key));
1872
+ const uniqueValues = Array.from(new Set(values.map((value) => String(value !== null && value !== void 0 ? value : ''))));
1873
+ const hasMultipleValues = multiple && uniqueValues.length > 1;
1874
+ const value = hasMultipleValues
1875
+ ? null
1876
+ : uniqueValues[0] || null;
1877
+ const type = this._inputType(field.type);
1878
+ let input = (jsx("input", { placeholder: hasMultipleValues
1879
+ ? I18N.labels.multipleValues
1880
+ : 'NULL', className: 'ol-wfst--input-field-input' +
1881
+ (hasMultipleValues
1882
+ ? ' ol-wfst--input-multiple'
1883
+ : ''), type: type, name: key, value: value, "data-multiple": hasMultipleValues ? 'true' : null }));
1884
+ if (this._layer.beforeShowFieldsModal) {
1885
+ const hookInput = this._layer.beforeShowFieldsModal(field, value, input);
1886
+ if (!hookInput) {
1887
+ return [];
1888
+ }
1889
+ if (typeof hookInput === 'string') {
1890
+ input = new DOMParser().parseFromString(hookInput, 'text/html').body.childNodes[0];
1891
+ }
1892
+ else {
1893
+ input = hookInput;
1894
+ }
1895
+ }
1896
+ if (hasMultipleValues) {
1897
+ input.dataset.multiple = 'true';
1898
+ input.classList.add('ol-wfst--input-multiple');
1899
+ }
1900
+ return (jsxs("div", { className: "ol-wfst--input-field-container", children: [jsx("label", { className: "ol-wfst--input-field-label", htmlFor: key, children: key }), input] }));
1901
+ }) }));
1902
+ }
1903
+ _renderTable() {
1904
+ return (jsx("form", { autocomplete: "false", children: jsx("div", { className: "ol-wfst--edit-table-wrap", children: jsxs("table", { className: "ol-wfst--edit-table", children: [jsx("thead", { children: jsxs("tr", { children: [jsx("th", { children: I18N.labels.feature }), jsx("th", { children: I18N.labels.geometry }), this._fieldList.map((field) => (jsx("th", { children: field.name })))] }) }), jsx("tbody", { children: this._features.map((feature, idx) => {
1905
+ var _a;
1906
+ return (jsxs("tr", { children: [jsx("td", { className: "ol-wfst--edit-table-fid", children: String((_a = feature.getId()) !== null && _a !== void 0 ? _a : idx + 1) }), jsx("td", { className: "ol-wfst--edit-table-geom", children: geometryTypeLabel(feature.getGeometry()) }), this._fieldList.map((field) => {
1907
+ var _a;
1908
+ const key = field.name;
1909
+ const type = this._inputType(field.type);
1910
+ const value = (_a = feature.get(key)) !== null && _a !== void 0 ? _a : '';
1911
+ let input = (jsx("input", { type: type, name: key, className: "ol-wfst--input-field-input", "data-feat-idx": String(idx), value: String(value) }));
1912
+ if (this._layer.beforeShowFieldsModal) {
1913
+ const hookInput = this._layer.beforeShowFieldsModal(field, value, input);
1914
+ if (!hookInput) {
1915
+ return jsx("td", {});
1916
+ }
1917
+ if (typeof hookInput === 'string') {
1918
+ input =
1919
+ new DOMParser().parseFromString(hookInput, 'text/html').body
1920
+ .childNodes[0];
1921
+ }
1922
+ else {
1923
+ input = hookInput;
1924
+ }
1925
+ input.setAttribute('name', key);
1926
+ input.setAttribute('data-feat-idx', String(idx));
1927
+ input.classList.add('ol-wfst--input-field-input');
1928
+ }
1929
+ return jsx("td", { children: input });
1930
+ })] }));
1931
+ }) })] }) }) }));
1932
+ }
1933
+ _inputType(typeXsd) {
1934
+ switch (typeXsd) {
1935
+ case 'xsd:double':
1936
+ case 'xsd:number':
1937
+ case 'xsd:int':
1938
+ return 'number';
1939
+ case 'xsd:date':
1940
+ return 'date';
1941
+ case 'xsd:date-time':
1942
+ return 'datetime';
1943
+ case 'xsd:string':
1944
+ default:
1945
+ return 'text';
1946
+ }
1947
+ }
1948
+ _saveForm(modal) {
1949
+ const formElements = modal.el.querySelector('form')
1950
+ .elements;
1951
+ const multipleFields = new Set(Array.from(formElements)
1952
+ .filter((el) => el.dataset.multiple === 'true')
1953
+ .map((el) => el.name));
1954
+ Array.from(formElements).forEach((el) => {
1955
+ const value = el.value;
1956
+ const field = el.name;
1957
+ // Do not overwrite untouched fields that had
1958
+ // multiple values in the selection
1959
+ if (multipleFields.has(field) && value === '') {
1960
+ return;
1961
+ }
1962
+ this._features.forEach((feature) => {
1963
+ if (feature.get(field) !== value) {
1964
+ feature.set(field, value, /* isSilent = */ true);
1965
+ }
1966
+ });
1967
+ });
1968
+ this._features.forEach((feature) => {
1969
+ feature.changed();
1970
+ addFeatureToEditedList(feature);
1971
+ });
1972
+ }
1973
+ _saveTable(modal) {
1974
+ const inputList = Array.from(modal.el.querySelectorAll('form input[data-feat-idx]'));
1975
+ const grouped = new Map();
1976
+ inputList.forEach((input) => {
1977
+ const idx = Number(input.dataset.featIdx);
1978
+ if (!grouped.has(idx)) {
1979
+ grouped.set(idx, []);
1980
+ }
1981
+ grouped.get(idx).push(input);
1982
+ });
1983
+ grouped.forEach((inputs, idx) => {
1984
+ const feature = this._features[idx];
1985
+ if (!feature) {
1986
+ return;
1987
+ }
1988
+ inputs.forEach((input) => {
1989
+ const field = input.name;
1990
+ const value = input.value;
1991
+ if (feature.get(field) !== value) {
1992
+ feature.set(field, value, /* isSilent = */ true);
1993
+ }
1994
+ });
1995
+ });
1996
+ this._features.forEach((feature) => {
1997
+ feature.changed();
1998
+ addFeatureToEditedList(feature);
1999
+ });
2000
+ }
1896
2001
  _dispatch(type, features) {
1897
2002
  const evt = new VectorSourceEvent(type, features[0]);
1898
2003
  evt.features = features;
1899
2004
  this.dispatchEvent(evt);
1900
2005
  }
1901
2006
  }
2007
+ function geometryTypeLabel(geometry) {
2008
+ if (!geometry) {
2009
+ return '-';
2010
+ }
2011
+ if (geometry instanceof GeometryCollection$1) {
2012
+ const types = new Set();
2013
+ const collect = (geom) => {
2014
+ if (geom instanceof GeometryCollection$1) {
2015
+ geom.getGeometriesArray().forEach(collect);
2016
+ }
2017
+ else {
2018
+ types.add(geom.getType());
2019
+ }
2020
+ };
2021
+ collect(geometry);
2022
+ return types.size ? Array.from(types).join(', ') : '-';
2023
+ }
2024
+ return geometry.getType();
2025
+ }
1902
2026
 
1903
2027
  // Ol
1904
2028
  // https://docs.geoserver.org/latest/en/user/services/wfs/axis_order.html
@@ -2709,6 +2833,7 @@ class Wfst extends Control {
2709
2833
  this._map = super.getMap();
2710
2834
  this._view = this._map.getView();
2711
2835
  this._viewport = this._map.getViewport();
2836
+ this._map.getTargetElement().classList.add('ol-wfst--map');
2712
2837
  setMap(this._map);
2713
2838
  //@ts-expect-error
2714
2839
  this._uploads.on('addedFeatures', ({ features }) => {
@@ -3198,6 +3323,23 @@ class Wfst extends Control {
3198
3323
  activateQueryMode(bool = true) {
3199
3324
  var _a, _b;
3200
3325
  if (bool) {
3326
+ // While a geometry/fields edit is in progress the tools toolbar is
3327
+ // hidden)Skip, so the only way out is Apply, Discard or Delete.
3328
+ // Guard here too so programmatic calls cannot leave the edit mode.
3329
+ if (getMode() === Modes.Edit) {
3330
+ return;
3331
+ }
3332
+ // If features are merely selected (not being edited), deselect
3333
+ // them without transacting: each removal restores the feature to
3334
+ // its original layer and turns the edit mode off.
3335
+ if (this._collectionModify.getLength()) {
3336
+ this._collectionModify
3337
+ .getArray()
3338
+ .slice()
3339
+ .forEach((feature) => {
3340
+ this._collectionModify.remove(feature);
3341
+ });
3342
+ }
3201
3343
  // Leave any draw interaction active
3202
3344
  if (this._interactionDraw) {
3203
3345
  this._map.removeInteraction(this._interactionDraw);
@@ -3588,6 +3730,29 @@ class Wfst extends Control {
3588
3730
  }
3589
3731
  });
3590
3732
  }
3733
+ /**
3734
+ * Hide the whole tools toolbar (geometry/draw/select/query buttons and
3735
+ * the layer selector). It is hidden while a geometry/fields edit is in
3736
+ * progress so the only way out is Apply, Discard or Delete.
3737
+ *
3738
+ * @private
3739
+ */
3740
+ _hideControls() {
3741
+ // While an edit is in progress the tools toolbar and the layers widget
3742
+ // disappear together: the only controls left on screen are Apply,
3743
+ // Discard and Delete.
3744
+ this._controlWidgetToolsDiv.classList.add('ol-wfst--controls--hidden');
3745
+ this._layersWidgetDiv.classList.add('ol-wfst--controls--hidden');
3746
+ }
3747
+ /**
3748
+ * Show the tools toolbar again.
3749
+ *
3750
+ * @private
3751
+ */
3752
+ _showControls() {
3753
+ this._controlWidgetToolsDiv.classList.remove('ol-wfst--controls--hidden');
3754
+ this._layersWidgetDiv.classList.remove('ol-wfst--controls--hidden');
3755
+ }
3591
3756
  /**
3592
3757
  *
3593
3758
  * @param features
@@ -3600,6 +3765,10 @@ class Wfst extends Control {
3600
3765
  feature.clone();
3601
3766
  });
3602
3767
  activateMode(Modes.Edit);
3768
+ // While a geometry/fields edit is in progress the whole tools toolbar
3769
+ // and the layers widget are hidden together, so the only way out is
3770
+ // Apply, Discard or Delete
3771
+ this._hideControls();
3603
3772
  // Show the "continue drawing" buttons on the line endpoints
3604
3773
  this._syncExtendLineOverlays();
3605
3774
  // To refresh the style
@@ -3643,6 +3812,8 @@ class Wfst extends Control {
3643
3812
  * @private
3644
3813
  */
3645
3814
  _editModeOff() {
3815
+ // Restore the tools toolbar and the layers widget together
3816
+ this._showControls();
3646
3817
  activateMode(null);
3647
3818
  this._destroyExtendLineOverlays();
3648
3819
  this._map.removeControl(this._controlApplyDiscardChanges);
@@ -3939,10 +4110,10 @@ class Wfst extends Control {
3939
4110
  * Remove features from the edit Layer and from the Geoserver
3940
4111
  *
3941
4112
  * @param feature
3942
- * @param confirm
4113
+ * @param askToConfirm
3943
4114
  * @private
3944
4115
  */
3945
- _deleteFeature(feature, confirm) {
4116
+ _deleteFeature(feature, askToConfirm) {
3946
4117
  const deleteEl = () => {
3947
4118
  var _a;
3948
4119
  const features = Array.isArray(feature) ? feature : [feature];
@@ -3963,14 +4134,21 @@ class Wfst extends Control {
3963
4134
  });
3964
4135
  }
3965
4136
  };
3966
- if (confirm) {
4137
+ if (askToConfirm) {
3967
4138
  const features = Array.isArray(feature) ? feature : [feature];
3968
4139
  const message = features.length > 1
3969
4140
  ? I18N_('confirmDeleteElements', features.length)
3970
4141
  : I18N.labels.confirmDelete;
3971
- const confirmModal = Modal.confirm(message, Object.assign({}, this._options.modal));
3972
- confirmModal.show().once('dismiss', function (modal, ev, button) {
3973
- if (button && button.value) {
4142
+ const confirmModal = Modal.confirm(message, Object.assign(Object.assign({}, this._options.modal), { footer: `
4143
+ <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">
4144
+ ${I18N.labels.cancel}
4145
+ </button>
4146
+ <button type="button" class="btn btn-sm btn-danger" data-action="delete" data-dismiss="modal">
4147
+ ${I18N.labels.delete}
4148
+ </button>
4149
+ ` }));
4150
+ confirmModal.show().once('dismiss', function (modal, event) {
4151
+ if (event.target.dataset.action == 'delete') {
3974
4152
  deleteEl();
3975
4153
  }
3976
4154
  });