@geogirafe/lib-geoportal 1.0.2154016552 → 1.0.2163361385

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/LICENSE CHANGED
@@ -231,4 +231,34 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
231
231
 
232
232
  -------------------------------------------------------------------------------
233
233
 
234
+ From:
235
+ - https://www.svgrepo.com/svg/309942/select-all
236
+ - https://www.svgrepo.com/svg/310299/arrow-download
237
+ - https://www.svgrepo.com/svg/309942/select-all
238
+ - https://www.svgrepo.com/svg/309943/select-all-off
239
+
240
+
241
+ The MIT License (MIT)
242
+
243
+ Copyright (c) 2025 Microsoft
244
+
245
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
246
+ this software and associated documentation files (the "Software"), to deal in
247
+ the Software without restriction, including without limitation the rights to
248
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
249
+ the Software, and to permit persons to whom the Software is furnished to do so,
250
+ subject to the following conditions:
251
+
252
+ The above copyright notice and this permission notice shall be included in all
253
+ copies or substantial portions of the Software.
254
+
255
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
256
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
257
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
258
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
259
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
260
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
261
+
262
+ -------------------------------------------------------------------------------
263
+
234
264
  ===============================================================================
@@ -41,6 +41,7 @@
41
41
  "Circle": "Kreis",
42
42
  "Classes": "Klassen",
43
43
  "Classification": "Klassifikation",
44
+ "Clear Results and close Panel": "Ergebnisse löschen und Panel schliessen",
44
45
  "Close message": "Nachricht schliessen",
45
46
  "color_option_classification": "Klassifizierung",
46
47
  "color_option_intensity": "Intensität",
@@ -349,6 +350,7 @@
349
350
  "selectFillColor": "Auswahl Füllfarbe",
350
351
  "selectHighlightFillColor": "Auswahl Highlight Füllfarbe",
351
352
  "selectHighlightStrokeColor": "Auswahl Highlight Strichfarbe",
353
+ "Selection": "Auswahl",
352
354
  "selectionComponent": "Komponente für Kartenauswahl",
353
355
  "selectStrokeColor": "Auswahl Strichfarbe",
354
356
  "Send": "Senden",
@@ -41,6 +41,7 @@
41
41
  "Circle": "Circle",
42
42
  "Classes": "Classes",
43
43
  "Classification": "Classification",
44
+ "Clear Results and close Panel": "Clear Results and close Panel",
44
45
  "Close message": "Close message",
45
46
  "color_option_classification": "Classification",
46
47
  "color_option_intensity": "Intensity",
@@ -350,6 +351,7 @@
350
351
  "selectFillColor": "Selection fill color",
351
352
  "selectHighlightFillColor": "Selection highlight fill color",
352
353
  "selectHighlightStrokeColor": "Selection highlight stroke color",
354
+ "Selection": "Selection",
353
355
  "selectionComponent": "Selection component",
354
356
  "selectStrokeColor": "Selection stroke color",
355
357
  "Send": "Send",
@@ -374,6 +376,7 @@
374
376
  "Snap": "Snap",
375
377
  "Snap to layer features": "Enable snapping on this layer",
376
378
  "Some layer could not be added to the layer-tree. This is either because you do not have the rights for it, or because this layer does not exist anymore.": "Some layer could not be added to the layer-tree. This is either because you do not have the rights for it, or because this layer does not exist anymore.",
379
+ "Sort default": "Sort default",
377
380
  "Source": "Source",
378
381
  "Source Type": "Source Type",
379
382
  "Square": "Square",
@@ -41,6 +41,7 @@
41
41
  "Circle": "Cercle",
42
42
  "Classes": "Classes",
43
43
  "Classification": "Classification",
44
+ "Clear Results and close Panel": "Résultats clairs et fermer le panneau",
44
45
  "Close message": "Fermer le message",
45
46
  "color_option_classification": "Classification",
46
47
  "color_option_intensity": "Intensité",
@@ -349,6 +350,7 @@
349
350
  "selectFillColor": "Couleur de remplissage des sélections",
350
351
  "selectHighlightFillColor": "Couleur de remplissage de surbrillance",
351
352
  "selectHighlightStrokeColor": "Couleur du trait de surbrillance",
353
+ "Selection": "Sélection",
352
354
  "selectionComponent": "Composant pour la sélection des cartes",
353
355
  "selectStrokeColor": "Couleur du trait de sélection",
354
356
  "Send": "Envoyer",
@@ -41,6 +41,7 @@
41
41
  "Circle": "Cerchio",
42
42
  "Classes": "Classi",
43
43
  "Classification": "Classificazione",
44
+ "Clear Results and close Panel": "Risultati chiari e chiudi pannello",
44
45
  "Close message": "Chiudi messaggio",
45
46
  "color_option_classification": "Classificazione",
46
47
  "color_option_intensity": "Intensità",
@@ -349,6 +350,7 @@
349
350
  "selectFillColor": "Colore di riempimento per le selezioni",
350
351
  "selectHighlightFillColor": "Colore di riempimento dell'evidenziazione",
351
352
  "selectHighlightStrokeColor": "Colore del tratto di evidenziazione della selezione",
353
+ "Selection": "Selezione",
352
354
  "selectionComponent": "Componente per la selezione della carta",
353
355
  "selectStrokeColor": "Colore del tratto di selezione",
354
356
  "Send": "Invia",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 48 48"><title>ic_fluent_arrow_download_48_regular</title><path fill="#212121" fill-rule="nonzero" d="M12.25 39.5h23.5a1.25 1.25 0 0 1 .128 2.494L35.75 42h-23.5a1.25 1.25 0 0 1-.128-2.494zh23.5zM23.622 6.006 23.75 6c.647 0 1.18.492 1.244 1.122L25 7.25v24.29l5.647-5.646a1.25 1.25 0 0 1 1.767 1.768l-7.778 7.778a1.25 1.25 0 0 1-1.767 0l-7.779-7.778a1.25 1.25 0 1 1 1.768-1.768l5.642 5.642V7.25c0-.647.492-1.18 1.122-1.244L23.75 6z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 24 24"><title>ic_fluent_select_all_off_24_regular</title><path fill="#212121" fill-rule="nonzero" d="M20.496 5.627A2.25 2.25 0 0 1 22 7.75v10A4.25 4.25 0 0 1 17.75 22h-10a2.25 2.25 0 0 1-2.123-1.504l2.097.004H17.75a2.75 2.75 0 0 0 2.75-2.75v-10l-.004-.051zM17.246 2a2.25 2.25 0 0 1 2.25 2.25v12.997a2.25 2.25 0 0 1-2.25 2.25H4.25A2.25 2.25 0 0 1 2 17.247V4.25A2.25 2.25 0 0 1 4.25 2zm0 1.5H4.25a.75.75 0 0 0-.75.75v12.997c0 .414.336.75.75.75h12.997a.75.75 0 0 0 .75-.75V4.25a.75.75 0 0 0-.75-.75"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 24 24"><title>ic_fluent_select_all_24_regular</title><path fill="#212121" fill-rule="nonzero" d="M20.496 5.627A2.25 2.25 0 0 1 22 7.75v10A4.25 4.25 0 0 1 17.75 22h-10a2.25 2.25 0 0 1-2.123-1.504l2.097.004H17.75a2.75 2.75 0 0 0 2.75-2.75v-10l-.004-.051zM17.246 2a2.25 2.25 0 0 1 2.25 2.25v12.997a2.25 2.25 0 0 1-2.25 2.25H4.25A2.25 2.25 0 0 1 2 17.247V4.25A2.25 2.25 0 0 1 4.25 2zm0 1.5H4.25a.75.75 0 0 0-.75.75v12.997c0 .414.336.75.75.75h12.997a.75.75 0 0 0 .75-.75V4.25a.75.75 0 0 0-.75-.75m-7.665 7.858L13.47 7.47a.75.75 0 0 1 1.133.976l-.073.084-4.5 4.5a.75.75 0 0 1-1.056.004L8.9 12.95l-1.5-2a.75.75 0 0 1 1.127-.984l.073.084zL13.47 7.47z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 24 24"><title>ic_fluent_select_all_24_regular</title><path fill="#212121" fill-rule="nonzero" d="M20.496 5.627A2.25 2.25 0 0 1 22 7.75v10A4.25 4.25 0 0 1 17.75 22h-10a2.25 2.25 0 0 1-2.123-1.504l2.097.004H17.75a2.75 2.75 0 0 0 2.75-2.75v-10l-.004-.051ZM17.246 2a2.25 2.25 0 0 1 2.25 2.25v12.997a2.25 2.25 0 0 1-2.25 2.25H4.25A2.25 2.25 0 0 1 2 17.247V4.25A2.25 2.25 0 0 1 4.25 2Zm0 1.5H4.25a.75.75 0 0 0-.75.75v12.997c0 .414.336.75.75.75h12.997a.75.75 0 0 0 .75-.75V4.25a.75.75 0 0 0-.75-.75m-7.665 7.858L13.47 7.47a.75.75 0 0 1 1.133.976l-.073.084-4.5 4.5a.75.75 0 0 1-1.056.004L8.9 12.95l-1.5-2a.75.75 0 0 1 1.127-.984l.073.084zL13.47 7.47Z"/><path d="M12 2.023v1.5h5.277a.75.75 0 0 1 .75.75V17.27a.75.75 0 0 1-.75.75H12v1.5h5.277a2.25 2.25 0 0 0 2.25-2.25V4.273a2.25 2.25 0 0 0-2.25-2.25zm8.527 3.627v2.072l.004.051v10a2.75 2.75 0 0 1-2.75 2.75H12v1.5h5.78a4.25 4.25 0 0 0 4.25-4.25v-10a2.25 2.25 0 0 0-1.503-2.123M14.03 7.273a.75.75 0 0 0-.53.22L12 8.993v2.122l2.56-2.561.073-.084a.75.75 0 0 0-.602-1.197" style="fill:#fff;fill-opacity:1"/><path d="M11.982 2.04v20h10v-3.622a4.25 4.25 0 0 1-4.201 3.605H12v-1.5h5.78a2.75 2.75 0 0 0 2.75-2.75v-10l-.003-.05V5.65a2.25 2.25 0 0 1 1.455 1.656V2.041h-4.424a2.25 2.25 0 0 1 1.97 2.232V17.27a2.25 2.25 0 0 1-2.25 2.25H12v-1.5h5.277a.75.75 0 0 0 .75-.75V4.273a.75.75 0 0 0-.75-.75H12V2.041Zm2.049 5.233a.75.75 0 0 1 .603 1.196l-.073.085L12 11.114v-2.12l1.5-1.501a.75.75 0 0 1 .53-.22" style="fill:#212121;fill-opacity:1;stroke-width:.0298872"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 20 20"><title>ic_fluent_resize_20_regular</title><path fill="#212121" fill-rule="nonzero" d="M2.5 11a.5.5 0 0 1 .5.5V15a2 2 0 0 0 2 2h3.5a.5.5 0 0 1 0 1H5a3 3 0 0 1-3-3v-3.5a.5.5 0 0 1 .5-.5m15 0a.5.5 0 0 1 .492.41l.008.09V15a3 3 0 0 1-2.824 2.995L15 18h-3.5a.5.5 0 0 1-.09-.992L11.5 17H15a2 2 0 0 0 1.995-1.85L17 15v-3.5a.5.5 0 0 1 .5-.5m-9-9a.5.5 0 0 1 .09.992L8.5 3H5a2 2 0 0 0-1.995 1.85L3 5v3.5a.5.5 0 0 1-.992.09L2 8.5V5a3 3 0 0 1 2.824-2.995L5 2zM15 2a3 3 0 0 1 2.995 2.824L18 5v3.5a.5.5 0 0 1-.992.09L17 8.5V5a2 2 0 0 0-1.85-1.995L15 3h-3.5a.5.5 0 0 1-.09-.992L11.5 2z"/></svg>
@@ -263,6 +263,9 @@ class GirafeHTMLElement extends HTMLElement {
263
263
  }
264
264
  parent = parent?.parentNode ?? null;
265
265
  } while (parent && parent !== document);
266
+ if (parent === document) {
267
+ return parent.geogirafe.context;
268
+ }
266
269
  throw new Error('No context was found !');
267
270
  }
268
271
  }
@@ -64,13 +64,13 @@ class GirafeResizableElement extends GirafeHTMLElement {
64
64
  initSizeLimits() {
65
65
  // If there is a configured minWidth or maxWidth, we have to take care of it
66
66
  const css = getComputedStyle(this);
67
- const minWidth = parseFloat(css.minWidth);
67
+ const minWidth = Number.parseFloat(css.minWidth);
68
68
  this.minWidth = isNaN(minWidth) ? undefined : minWidth;
69
- const maxWidth = parseFloat(css.maxWidth);
69
+ const maxWidth = Number.parseFloat(css.maxWidth);
70
70
  this.maxWidth = isNaN(maxWidth) ? undefined : maxWidth;
71
- const minHeight = parseFloat(css.minHeight);
71
+ const minHeight = Number.parseFloat(css.minHeight);
72
72
  this.minHeight = isNaN(minHeight) ? undefined : minHeight;
73
- const maxHeight = parseFloat(css.maxHeight);
73
+ const maxHeight = Number.parseFloat(css.maxHeight);
74
74
  this.maxHeight = isNaN(maxHeight) ? undefined : maxHeight;
75
75
  }
76
76
  mousedown(e) {
@@ -80,8 +80,8 @@ class GirafeResizableElement extends GirafeHTMLElement {
80
80
  document.onmouseup = () => this.mouseup();
81
81
  this.prevX = e.x;
82
82
  this.prevY = e.y;
83
- this.lastWidth = parseFloat(getComputedStyle(this).width);
84
- this.lastHeight = parseFloat(getComputedStyle(this).height);
83
+ this.lastWidth = Number.parseFloat(getComputedStyle(this).width);
84
+ this.lastHeight = Number.parseFloat(getComputedStyle(this).height);
85
85
  }
86
86
  mousemove(e) {
87
87
  e.preventDefault();
@@ -101,6 +101,8 @@ class GirafeResizableElement extends GirafeHTMLElement {
101
101
  // stop moving when mouse button is released
102
102
  document.onmouseup = null;
103
103
  document.onmousemove = null;
104
+ this.lastWidth = Number.parseFloat(getComputedStyle(this).width);
105
+ this.lastHeight = Number.parseFloat(getComputedStyle(this).height);
104
106
  this.dispatchEvent(new CustomEvent('resize-end'));
105
107
  }
106
108
  closePanel() {
@@ -66,50 +66,116 @@ async function getStyleCode(currentFilename, relativeCssPath) {
66
66
  return styleCode;
67
67
  } catch (error) {
68
68
  console.error(`Error reading style file for ${currentFilename}: ${error}`);
69
+ throw error;
69
70
  }
70
71
  }
71
72
 
72
- async function getHtmlCode(htmlFilePath, styleCode) {
73
- let htmlCode = fs.readFileSync(htmlFilePath, 'utf8');
74
- htmlCode = await minify.html(htmlCode, {
75
- html: { minifyCSS: false, collapseBooleanAttributes: false, removeAttributeQuotes: false }
76
- });
77
- htmlCode = `template = () => { return uHtml\`${styleCode}\n${htmlCode}\`; }`;
78
- return htmlCode;
73
+ async function getHtmlCode(currentFilename, relativeHtmlPath, styleCode) {
74
+ const htmlFilePath = path.join(path.dirname(currentFilename), relativeHtmlPath.trim());
75
+ try {
76
+ let htmlCode = fs.readFileSync(htmlFilePath, 'utf8');
77
+ htmlCode = await minify.html(htmlCode, {
78
+ html: {
79
+ minifyCSS: false,
80
+ collapseBooleanAttributes: false,
81
+ removeAttributeQuotes: false
82
+ }
83
+ });
84
+ htmlCode = `template = () => { return uHtml\`${styleCode}\n${htmlCode}\`; }`;
85
+ return htmlCode;
86
+ } catch (error) {
87
+ console.error(`Error reading html file for ${currentFilename}: ${error}`);
88
+ throw error;
89
+ }
90
+ }
91
+
92
+ export function isLineCommented(regExpMatch, code) {
93
+ if (!regExpMatch) {
94
+ return false;
95
+ }
96
+
97
+ const lineStart = code.substring(0, regExpMatch.index);
98
+ const lastNewlineIndex = lineStart.lastIndexOf('\n');
99
+ const lineBeforeMatch = lineStart.substring(lastNewlineIndex + 1);
100
+
101
+ // The line is commented
102
+ if (lineBeforeMatch.trim().startsWith('//')) {
103
+ return true;
104
+ }
105
+
106
+ // Test if we are in a commented block
107
+ let commentedBlock = 0;
108
+ for (let i = 0; i < regExpMatch.index; i++) {
109
+ if (code[i] === '/' && code[i + 1] === '*') {
110
+ commentedBlock++;
111
+ i++;
112
+ } else if (code[i] === '*' && code[i + 1] === '/') {
113
+ commentedBlock--;
114
+ i++;
115
+ }
116
+ }
117
+ if (commentedBlock > 0) {
118
+ return true;
119
+ }
120
+
121
+ return false;
79
122
  }
80
123
 
124
+ function isStringCommented(line) {
125
+ if (!line) {
126
+ return false;
127
+ }
128
+ if (line.trim().startsWith('//')) {
129
+ return true;
130
+ }
131
+ if (line.trim().startsWith('/*')) {
132
+ return true;
133
+ }
134
+ return false;
135
+ }
136
+
137
+ // Regex definitions
138
+ export const styleRegex = /styleUrl *= *['"](.*)['"] *;?/g;
139
+ export const stylesRegex = /styleUrls *= *\[([\s\S]*?)\] *;?/gs;
140
+ export const htmlRegex = /templateUrl *= *['"](.*)['"] *;?/g;
141
+
81
142
  export async function inlineTemplate(filename) {
82
143
  // Read the file
83
144
  const code = fs.readFileSync(filename, 'utf8');
84
145
  const magicString = new MagicString(code);
85
146
 
86
- // Find the HTML template
87
- const htmlRegex = /templateUrl *= *['"](.*)['"] *;?/;
88
- if (htmlRegex.test(code)) {
89
- // Verify if there is a CSS file
90
- let styleCode = '';
91
- const styleRegex = /styleUrl *= *['"](.*)['"] *;?/;
92
- if (styleRegex.test(code)) {
93
- // Read the CSS file
94
- const styleFound = code.match(styleRegex);
95
- styleCode += await getStyleCode(filename, styleFound[1]);
96
- magicString.overwrite(styleFound.index, styleFound.index + styleFound[0].length, '');
97
- }
98
- // Verify if there are many CSS files
99
- const stylesRegex = /styleUrls *= *\[(['"].*['"],? ?)+\] *;?/;
100
- if (stylesRegex.test(code)) {
101
- const stylesFound = code.match(stylesRegex);
102
- for (const styleFound of stylesFound[1].replaceAll("'", '').split(',')) {
103
- styleCode += await getStyleCode(filename, styleFound);
147
+ // We integrate HTML and CSS only if there is an HTML Template
148
+ const htmlFounds = code.matchAll(htmlRegex);
149
+ for (const htmlFound of htmlFounds) {
150
+ if (htmlFound && !isLineCommented(htmlFound, code) && htmlFound[1]) {
151
+ let styleCode = '';
152
+
153
+ // Unique style Url
154
+ const styleFounds = code.matchAll(styleRegex);
155
+ for (const styleFound of styleFounds) {
156
+ if (styleFound && !isLineCommented(styleFound, code) && styleFound[1]) {
157
+ styleCode += await getStyleCode(filename, styleFound[1]);
158
+ magicString.overwrite(styleFound.index, styleFound.index + styleFound[0].length, '');
159
+ }
160
+ }
161
+
162
+ // Multiple style Urls
163
+ const stylesFounds = code.matchAll(stylesRegex);
164
+ for (const stylesFound of stylesFounds) {
165
+ if (stylesFound && !isLineCommented(stylesFound, code) && stylesFound[1]) {
166
+ const stylePaths = stylesFound[1]
167
+ .split(',')
168
+ .map((p) => p.trim().replace(/['"]/g, ''))
169
+ .filter((p) => p.length > 0 && !isStringCommented(p));
170
+ for (const stylePath of stylePaths) {
171
+ styleCode += await getStyleCode(filename, stylePath);
172
+ }
173
+ magicString.overwrite(stylesFound.index, stylesFound.index + stylesFound[0].length, '');
174
+ }
104
175
  }
105
- magicString.overwrite(stylesFound.index, stylesFound.index + stylesFound[0].length, '');
106
- }
107
176
 
108
- // Read HTML template
109
- const htmlFound = code.match(htmlRegex);
110
- const htmlFilePath = path.join(path.dirname(filename), htmlFound[1]);
111
- try {
112
- const htmlCode = await getHtmlCode(htmlFilePath, styleCode);
177
+ // HTML template
178
+ const htmlCode = await getHtmlCode(filename, htmlFound[1], styleCode);
113
179
  magicString.overwrite(htmlFound.index, htmlFound.index + htmlFound[0].length, htmlCode);
114
180
 
115
181
  // Add missing import (uHtml)
@@ -118,8 +184,6 @@ export async function inlineTemplate(filename) {
118
184
  // Include uHtmlFor if it is used in the template
119
185
  magicString.prepend(`import { htmlFor as uHtmlFor } from 'uhtml/keyed';\n`);
120
186
  }
121
- } catch (error) {
122
- console.error(`Error reading HTML file for ${filename}: ${error}`);
123
187
  }
124
188
  }
125
189
 
@@ -15,7 +15,7 @@ declare class SelectionGridComponent extends GirafeResizableElement {
15
15
  private readonly debounceOnFeaturesSelected;
16
16
  visible: boolean;
17
17
  currentTabId: string;
18
- showCsvButton: boolean;
18
+ resultsSelected: boolean;
19
19
  constructor();
20
20
  connectedCallback(): void;
21
21
  /**
@@ -15,9 +15,11 @@ class SelectionGridComponent extends GirafeResizableElement {
15
15
  return uHtml `<style>
16
16
  *{font-family:Arial,sans-serif}.hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height)/1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad2);background-color:var(--text-color-grad2);color:var(--bkg-color)}.gg-button:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3;border:none}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{color:gray;cursor:not-allowed;background-color:#d3d3d3}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height)/1.2);min-height:calc(var(--app-standard-height)/1.2);max-height:calc(var(--app-standard-height)/1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height)/2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height)/2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height)/2);min-height:calc(var(--app-standard-height)/2);max-height:calc(var(--app-standard-height)/2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height)/3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height)/3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover,.gg-select:hover,.gg-input:hover,.gg-textarea:hover,.gg-icon-button:hover{background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height)/2);height:calc(var(--app-standard-height)/2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}
17
17
  </style><style>
18
- :host,#panel{background:var(--bkg-color);height:16rem;min-height:10rem}#panel{inset:0;overflow:hidden}#gutter{background:var(--bkg-color);cursor:row-resize;border:none;width:100%;height:6px;position:absolute;top:0;left:0}#close{color:#777;background-color:var(--bkg-color);cursor:pointer;border:none;width:1rem;height:1rem;margin:.5rem;padding:0;line-height:1rem;position:absolute;top:0;right:0}#close i:before{content:"uf00d"}#close:hover{color:#000;border-color:#000}#content{background:var(--bkg-color);flex-direction:column;margin:.5rem;padding:0;display:flex;position:absolute;inset:0;overflow:hidden}#header{flex:0;justify-content:space-between;display:flex}.selection-panel{margin-right:2rem}.tab{cursor:pointer;background-color:var(--bkg-color-grad2);border:1px solid #ccc;height:2rem;margin-bottom:.2rem;margin-right:.2rem;padding:0 1rem;line-height:2rem;display:inline-block}.tab.active{color:var(--text-color);background-color:var(--bkg-color)}#grid{flex:1;overflow:hidden}.geo-type{margin-right:.5rem}button{margin-left:.5rem}::-webkit-scrollbar{width:8px}::-webkit-scrollbar-thumb{background:#999}.tiny-margin{margin:.1rem}.tabulator-col[aria-sort=none] .tabulator-col-sorter i{color:#999}.tabulator-col[aria-sort=asc] .tabulator-col-sorter i{color:red}.tabulator-col[aria-sort=desc] .tabulator-col-sorter i{color:red;transform:scaleY(-1)}#tabulator{background-color:var(--bkg-color)}#tabulator .tabulator-header .tabulator-col-content{background-color:var(--bkg-color);color:var(--text-color)}#tabulator .tabulator-header .tabulator-col,#tabulator .tabulator-header .tabulator-col-row-handle{white-space:normal}#tabulator .tabulator-tableholder .tabulator-table .tabulator-row{background-color:var(--bkg-color);color:var(--text-color)}#tabulator .tabulator-tableholder .tabulator-table .tabulator-row:nth-child(2n){background-color:var(--bkg-color-grad1)}#tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-selected{background-color:#9abcea}.tabulator-cell img{float:left;height:1.5rem;margin-right:.5rem}.tabulator-cell span{align-items:center;line-height:1.5rem;display:inline-flex;position:relative}.tabulator-cell span sup{position:absolute;top:-.3rem;right:-.5rem}@media (hover:hover) and (pointer:fine){#tabulator .tabulator-tableholder .tabulator-table .tabulator-row:hover{cursor:pointer;background-color:var(--bkg-color-grad2)}}
18
+ .tabulator{text-align:left;background-color:#888;border:1px solid #999;font-size:14px;position:relative;overflow:hidden;-webkit-transform:translateZ(0);-moz-transform:translateZ(0);-ms-transform:translateZ(0);-o-transform:translateZ(0);transform:translateZ(0)}.tabulator[tabulator-layout=fitDataFill] .tabulator-tableholder .tabulator-table{min-width:100%}.tabulator[tabulator-layout=fitDataTable]{display:inline-block}.tabulator.tabulator-block-select,.tabulator.tabulator-ranges .tabulator-cell:not(.tabulator-editing){user-select:none}.tabulator .tabulator-header{box-sizing:border-box;color:#555;-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;white-space:nowrap;background-color:#e6e6e6;border-bottom:1px solid #999;outline:none;width:100%;font-weight:700;position:relative;overflow:hidden}.tabulator .tabulator-header.tabulator-header-hidden{display:none}.tabulator .tabulator-header .tabulator-header-contents{position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-header-contents .tabulator-headers{display:inline-block}.tabulator .tabulator-header .tabulator-col{box-sizing:border-box;text-align:left;vertical-align:bottom;background:#e6e6e6;border-right:1px solid #aaa;flex-direction:column;justify-content:flex-start;display:inline-flex;position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-col.tabulator-moving{pointer-events:none;background:#cdcdcd;border:1px solid #999;position:absolute}.tabulator .tabulator-header .tabulator-col.tabulator-range-highlight{color:#000;background-color:#d6d6d6}.tabulator .tabulator-header .tabulator-col.tabulator-range-selected{color:#fff;background-color:#3876ca}.tabulator .tabulator-header .tabulator-col .tabulator-col-content{box-sizing:border-box;padding:4px;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button{padding:0 8px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-header-popup-button:hover{cursor:pointer;opacity:.6}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title-holder{position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title{box-sizing:border-box;text-overflow:ellipsis;vertical-align:bottom;white-space:nowrap;width:100%;overflow:hidden}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title.tabulator-col-title-wrap{text-overflow:clip;white-space:normal}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-title-editor{box-sizing:border-box;background:#fff;border:1px solid #999;width:100%;padding:1px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-title .tabulator-header-popup-button+.tabulator-title-editor{width:calc(100% - 22px)}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{align-items:center;display:flex;position:absolute;top:0;bottom:0;right:4px}.tabulator .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-bottom:6px solid #bbb;border-left:6px solid #0000;border-right:6px solid #0000;width:0;height:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{border-top:1px solid #aaa;margin-right:-1px;display:flex;position:relative;overflow:hidden}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter{box-sizing:border-box;text-align:center;width:100%;margin-top:2px;position:relative}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter textarea{height:auto!important}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter svg{margin-top:3px}.tabulator .tabulator-header .tabulator-col .tabulator-header-filter input::-ms-clear{width:0;height:0}.tabulator .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-right:25px}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable.tabulator-col-sorter-element:hover{cursor:pointer;background-color:#cdcdcd}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter{color:#bbb}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=none] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #bbb}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-bottom:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=ascending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{border-top:none;border-bottom:6px solid #666}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter{color:#666}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter.tabulator-col-sorter-element .tabulator-arrow:hover{cursor:pointer;border-top:6px solid #555}}.tabulator .tabulator-header .tabulator-col.tabulator-sortable[aria-sort=descending] .tabulator-col-content .tabulator-col-sorter .tabulator-arrow{color:#666;border-top:6px solid #666;border-bottom:none}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical .tabulator-col-content .tabulator-col-title{text-orientation:mixed;writing-mode:vertical-rl;justify-content:center;align-items:center;display:flex}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-col-vertical-flip .tabulator-col-title{transform:rotate(180deg)}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-title{padding-top:20px;padding-right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable.tabulator-col-vertical-flip .tabulator-col-title{padding-bottom:20px;padding-right:0}.tabulator .tabulator-header .tabulator-col.tabulator-col-vertical.tabulator-sortable .tabulator-col-sorter{justify-content:center;inset:4px 0 auto}.tabulator .tabulator-header .tabulator-frozen{z-index:11;position:sticky;left:0}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-left{border-right:2px solid #aaa}.tabulator .tabulator-header .tabulator-frozen.tabulator-frozen-right{border-left:2px solid #aaa}.tabulator .tabulator-header .tabulator-calcs-holder{box-sizing:border-box;border-top:1px solid #aaa;border-bottom:1px solid #aaa;display:inline-block;background:#f3f3f3!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row{background:#f3f3f3!important}.tabulator .tabulator-header .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-header .tabulator-frozen-rows-holder{display:inline-block}.tabulator .tabulator-header .tabulator-frozen-rows-holder:empty{display:none}.tabulator .tabulator-tableholder{-webkit-overflow-scrolling:touch;white-space:nowrap;width:100%;position:relative;overflow:auto}.tabulator .tabulator-tableholder:focus{outline:none}.tabulator .tabulator-tableholder .tabulator-placeholder{box-sizing:border-box;justify-content:center;align-items:center;width:100%;min-width:100%;display:flex}.tabulator .tabulator-tableholder .tabulator-placeholder[tabulator-render-mode=virtual]{min-height:100%}.tabulator .tabulator-tableholder .tabulator-placeholder .tabulator-placeholder-contents{color:#ccc;text-align:center;white-space:normal;padding:10px;font-size:20px;font-weight:700;display:inline-block}.tabulator .tabulator-tableholder .tabulator-table{color:#333;white-space:nowrap;background-color:#fff;display:inline-block;position:relative;overflow:visible}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs{font-weight:700;background:#e2e2e2!important}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-top{border-bottom:2px solid #aaa}.tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-calcs.tabulator-calcs-bottom{border-top:2px solid #aaa}.tabulator .tabulator-tableholder .tabulator-range-overlay{pointer-events:none;z-index:10;position:absolute;inset:0}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range{box-sizing:border-box;border:1px solid #2975dd;position:absolute}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{content:"";background-color:#2975dd;border-radius:999px;width:6px;height:6px;position:absolute;bottom:-3px;right:-3px}.tabulator .tabulator-tableholder .tabulator-range-overlay .tabulator-range-cell-active{box-sizing:border-box;border:2px solid #2975dd;position:absolute}.tabulator .tabulator-footer{color:#555;-webkit-user-select:none;-moz-user-select:none;user-select:none;-khtml-user-select:none;-o-user-select:none;white-space:nowrap;background-color:#e6e6e6;border-top:1px solid #999;font-weight:700}.tabulator .tabulator-footer .tabulator-footer-contents{flex-direction:row;justify-content:space-between;align-items:center;padding:5px 10px;display:flex}.tabulator .tabulator-footer .tabulator-footer-contents:empty{display:none}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs{margin-top:-5px;overflow-x:auto}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab{border:1px solid #999;border-top:none;border-bottom-right-radius:5px;border-bottom-left-radius:5px;padding:5px;font-size:.9em;display:inline-block}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab:hover{cursor:pointer;opacity:.7}.tabulator .tabulator-footer .tabulator-spreadsheet-tabs .tabulator-spreadsheet-tab.tabulator-spreadsheet-tab-active{background:#fff}.tabulator .tabulator-footer .tabulator-calcs-holder{box-sizing:border-box;text-align:left;border-top:1px solid #aaa;border-bottom:1px solid #aaa;width:100%;overflow:hidden;background:#f3f3f3!important}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row{display:inline-block;background:#f3f3f3!important}.tabulator .tabulator-footer .tabulator-calcs-holder .tabulator-row .tabulator-col-resize-handle{display:none}.tabulator .tabulator-footer .tabulator-calcs-holder:only-child{border-bottom:none;margin-bottom:-5px}.tabulator .tabulator-footer>*+.tabulator-page-counter{margin-left:10px}.tabulator .tabulator-footer .tabulator-page-counter{font-weight:400}.tabulator .tabulator-footer .tabulator-paginator{color:#555;font-family:inherit;font-size:inherit;font-weight:inherit;text-align:right;flex:1}.tabulator .tabulator-footer .tabulator-page-size{border:1px solid #aaa;border-radius:3px;margin:0 5px;padding:2px 5px;display:inline-block}.tabulator .tabulator-footer .tabulator-pages{margin:0 7px}.tabulator .tabulator-footer .tabulator-page{background:#fff3;border:1px solid #aaa;border-radius:3px;margin:0 2px;padding:2px 5px;display:inline-block}.tabulator .tabulator-footer .tabulator-page.active{color:#d00}.tabulator .tabulator-footer .tabulator-page:disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-footer .tabulator-page:not(disabled):hover{color:#fff;cursor:pointer;background:#0003}}.tabulator .tabulator-col-resize-handle{vertical-align:middle;z-index:11;width:6px;margin-left:-3px;margin-right:-3px;display:inline-block;position:relative}@media (hover:hover) and (pointer:fine){.tabulator .tabulator-col-resize-handle:hover{cursor:ew-resize}}.tabulator .tabulator-col-resize-handle:last-of-type{width:3px;margin-right:0}.tabulator .tabulator-col-resize-guide{opacity:.5;background-color:#999;width:4px;height:100%;margin-left:-.5px;position:absolute;top:0}.tabulator .tabulator-row-resize-guide{opacity:.5;background-color:#999;width:100%;height:4px;margin-top:-.5px;position:absolute;left:0}.tabulator .tabulator-alert{text-align:center;z-index:100;background:#0006;align-items:center;width:100%;height:100%;display:flex;position:absolute;top:0;left:0}.tabulator .tabulator-alert .tabulator-alert-msg{background:#fff;border-radius:10px;margin:0 auto;padding:10px 20px;font-size:16px;font-weight:700;display:inline-block}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-msg{color:#000;border:4px solid #333}.tabulator .tabulator-alert .tabulator-alert-msg.tabulator-alert-state-error{color:#590000;border:4px solid #d00}.tabulator-row{box-sizing:border-box;background-color:#fff;min-height:22px;position:relative}.tabulator-row.tabulator-row-even{background-color:#efefef}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selectable:hover{cursor:pointer;background-color:#bbb}}.tabulator-row.tabulator-selected{background-color:#9abcea}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-selected:hover{cursor:pointer;background-color:#769bcc}}.tabulator-row.tabulator-row-moving{background:#fff;border:1px solid #000}.tabulator-row.tabulator-moving{pointer-events:none;z-index:15;border-top:1px solid #aaa;border-bottom:1px solid #aaa;position:absolute}.tabulator-row.tabulator-range-highlight .tabulator-cell.tabulator-range-row-header{color:#000;background-color:#d6d6d6}.tabulator-row.tabulator-range-highlight.tabulator-range-selected .tabulator-cell.tabulator-range-row-header,.tabulator-row.tabulator-range-selected .tabulator-cell.tabulator-range-row-header{color:#fff;background-color:#3876ca}.tabulator-row .tabulator-row-resize-handle{height:5px;position:absolute;bottom:0;left:0;right:0}.tabulator-row .tabulator-row-resize-handle.prev{top:0;bottom:auto}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-row-resize-handle:hover{cursor:ns-resize}}.tabulator-row .tabulator-responsive-collapse{box-sizing:border-box;border-top:1px solid #aaa;border-bottom:1px solid #aaa;padding:5px}.tabulator-row .tabulator-responsive-collapse:empty{display:none}.tabulator-row .tabulator-responsive-collapse table{font-size:14px}.tabulator-row .tabulator-responsive-collapse table tr td{position:relative}.tabulator-row .tabulator-responsive-collapse table tr td:first-of-type{padding-right:10px}.tabulator-row .tabulator-cell{box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;white-space:nowrap;border-right:1px solid #aaa;outline:none;padding:4px;display:inline-block;position:relative;overflow:hidden}.tabulator-row .tabulator-cell.tabulator-row-header{background:#e6e6e6;border-bottom:1px solid #aaa;border-right:1px solid #999}.tabulator-row .tabulator-cell.tabulator-frozen{background-color:inherit;z-index:11;display:inline-block;position:sticky;left:0}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-right:2px solid #aaa}.tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-left:2px solid #aaa}.tabulator-row .tabulator-cell.tabulator-editing{border:1px solid #1d68cd;outline:none;padding:0}.tabulator-row .tabulator-cell.tabulator-editing input,.tabulator-row .tabulator-cell.tabulator-editing select{background:0 0;border:1px;outline:none}.tabulator-row .tabulator-cell.tabulator-validation-fail{border:1px solid #d00}.tabulator-row .tabulator-cell.tabulator-validation-fail input,.tabulator-row .tabulator-cell.tabulator-validation-fail select{color:#d00;background:0 0;border:1px}.tabulator-row .tabulator-cell.tabulator-row-handle{-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;justify-content:center;align-items:center;display:inline-flex}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box{width:80%}.tabulator-row .tabulator-cell.tabulator-row-handle .tabulator-row-handle-box .tabulator-row-handle-bar{background:#666;width:100%;height:3px;margin-top:2px}.tabulator-row .tabulator-cell.tabulator-range-selected:not(.tabulator-range-only-cell-selected):not(.tabulator-range-row-header){background-color:#9abcea}.tabulator-row .tabulator-cell .tabulator-data-tree-branch-empty{width:7px;display:inline-block}.tabulator-row .tabulator-cell .tabulator-data-tree-branch{vertical-align:middle;border-bottom:2px solid #aaa;border-left:2px solid #aaa;border-bottom-left-radius:1px;width:7px;height:9px;margin-top:-9px;margin-right:5px;display:inline-block}.tabulator-row .tabulator-cell .tabulator-data-tree-control{vertical-align:middle;background:#0000001a;border:1px solid #333;border-radius:2px;justify-content:center;align-items:center;width:11px;height:11px;margin-right:5px;display:inline-flex;overflow:hidden}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-data-tree-control:hover{cursor:pointer;background:#0003}}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:0 0;width:1px;height:7px;display:inline-block;position:relative}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{content:"";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;width:1px;height:7px;display:inline-block;position:relative}.tabulator-row .tabulator-cell .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{content:"";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle{color:#fff;-webkit-user-select:none;-moz-user-select:none;-khtml-user-select:none;-o-user-select:none;background:#666;border-radius:20px;justify-content:center;align-items:center;width:15px;height:15px;font-size:1.1em;font-weight:700;display:inline-flex}@media (hover:hover) and (pointer:fine){.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle:hover{cursor:pointer;opacity:.7}}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-close{display:initial}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle.open .tabulator-responsive-collapse-toggle-open{display:none}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle svg{stroke:#fff}.tabulator-row .tabulator-cell .tabulator-responsive-collapse-toggle .tabulator-responsive-collapse-toggle-close{display:none}.tabulator-row .tabulator-cell .tabulator-traffic-light{border-radius:14px;width:14px;height:14px;display:inline-block}.tabulator-row.tabulator-group{box-sizing:border-box;background:#ccc;border-top:1px solid #999;border-bottom:1px solid #999;border-right:1px solid #aaa;min-width:100%;padding:5px 5px 5px 10px;font-weight:700}@media (hover:hover) and (pointer:fine){.tabulator-row.tabulator-group:hover{cursor:pointer;background-color:#0000001a}}.tabulator-row.tabulator-group.tabulator-group-visible .tabulator-arrow{border:6px solid #0000;border-top-color:#666;border-bottom:0;margin-right:10px}.tabulator-row.tabulator-group.tabulator-group-level-1{padding-left:30px}.tabulator-row.tabulator-group.tabulator-group-level-2{padding-left:50px}.tabulator-row.tabulator-group.tabulator-group-level-3{padding-left:70px}.tabulator-row.tabulator-group.tabulator-group-level-4{padding-left:90px}.tabulator-row.tabulator-group.tabulator-group-level-5{padding-left:110px}.tabulator-row.tabulator-group .tabulator-group-toggle{display:inline-block}.tabulator-row.tabulator-group .tabulator-arrow{vertical-align:middle;border:6px solid #0000;border-left-color:#666;border-right:0;width:0;height:0;margin-right:16px;display:inline-block}.tabulator-row.tabulator-group span{color:#d00;margin-left:10px}.tabulator-toggle{box-sizing:border-box;background:#dcdcdc;border:1px solid #ccc;flex-direction:row;display:flex}.tabulator-toggle.tabulator-toggle-on{background:#1c6cc2}.tabulator-toggle .tabulator-toggle-switch{box-sizing:border-box;background:#fff;border:1px solid #ccc}.tabulator-popup-container{-webkit-overflow-scrolling:touch;box-sizing:border-box;z-index:10000;background:#fff;border:1px solid #aaa;font-size:14px;display:inline-block;position:absolute;overflow-y:auto;box-shadow:0 0 5px #0003}.tabulator-popup{border-radius:3px;padding:5px}.tabulator-tooltip{box-shadow:none;pointer-events:none;border-radius:2px;max-width:min(500px,100%);padding:3px 5px;font-size:12px}.tabulator-menu .tabulator-menu-item{box-sizing:border-box;user-select:none;padding:5px 10px;position:relative}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-disabled{opacity:.5}@media (hover:hover) and (pointer:fine){.tabulator-menu .tabulator-menu-item:not(.tabulator-menu-item-disabled):hover{cursor:pointer;background:#efefef}}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu{padding-right:25px}.tabulator-menu .tabulator-menu-item.tabulator-menu-item-submenu:after{content:"";vertical-align:top;border:1px solid #aaa;border-width:1px 1px 0 0;width:7px;height:7px;display:inline-block;position:absolute;top:calc(5px + .4em);right:10px;transform:rotate(45deg)}.tabulator-menu .tabulator-menu-separator{border-top:1px solid #aaa}.tabulator-edit-list{-webkit-overflow-scrolling:touch;max-height:200px;font-size:14px;overflow-y:auto}.tabulator-edit-list .tabulator-edit-list-item{color:#333;outline:none;padding:4px}.tabulator-edit-list .tabulator-edit-list-item.active{color:#fff;background:#1d68cd}.tabulator-edit-list .tabulator-edit-list-item.active.focused{outline:1px solid #ffffff80}.tabulator-edit-list .tabulator-edit-list-item.focused{outline:1px solid #1d68cd}@media (hover:hover) and (pointer:fine){.tabulator-edit-list .tabulator-edit-list-item:hover{color:#fff;cursor:pointer;background:#1d68cd}}.tabulator-edit-list .tabulator-edit-list-placeholder{color:#333;text-align:center;padding:4px}.tabulator-edit-list .tabulator-edit-list-group{color:#333;border-bottom:1px solid #aaa;padding:6px 4px 4px;font-weight:700}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-2,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-2{padding-left:12px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-3,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-3{padding-left:20px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-4,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-4{padding-left:28px}.tabulator-edit-list .tabulator-edit-list-group.tabulator-edit-list-group-level-5,.tabulator-edit-list .tabulator-edit-list-item.tabulator-edit-list-group-level-5{padding-left:36px}.tabulator.tabulator-ltr{direction:ltr}.tabulator.tabulator-rtl{text-align:initial;direction:rtl}.tabulator.tabulator-rtl .tabulator-header .tabulator-col{border-left:1px solid #aaa;border-right:initial;text-align:initial}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-col-group .tabulator-col-group-cols{margin-left:-1px;margin-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col.tabulator-sortable .tabulator-col-title{padding-left:25px;padding-right:0}.tabulator.tabulator-rtl .tabulator-header .tabulator-col .tabulator-col-content .tabulator-col-sorter{left:8px;right:auto}.tabulator.tabulator-rtl .tabulator-tableholder .tabulator-range-overlay .tabulator-range.tabulator-range-active:after{content:"";background-color:#2975dd;border-radius:999px;width:6px;height:6px;position:absolute;bottom:-3px;left:-3px;right:auto}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell{border-left:1px solid #aaa;border-right:initial}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-branch{border-left:initial;border-right:2px solid #aaa;border-bottom-right-radius:1px;border-bottom-left-radius:0;margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell .tabulator-data-tree-control{margin-left:5px;margin-right:0}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-left{border-left:2px solid #aaa}.tabulator.tabulator-rtl .tabulator-row .tabulator-cell.tabulator-frozen.tabulator-frozen-right{border-right:2px solid #aaa}.tabulator.tabulator-rtl .tabulator-row .tabulator-col-resize-handle:last-of-type{width:3px;margin-left:0;margin-right:-3px}.tabulator.tabulator-rtl .tabulator-footer .tabulator-calcs-holder{text-align:initial}.tabulator-print-fullscreen{z-index:10000;position:absolute;inset:0}body.tabulator-print-fullscreen-hide>:not(.tabulator-print-fullscreen){display:none!important}.tabulator-print-table{border-collapse:collapse}.tabulator-print-table .tabulator-data-tree-branch{vertical-align:middle;border-bottom:2px solid #aaa;border-left:2px solid #aaa;border-bottom-left-radius:1px;width:7px;height:9px;margin-top:-9px;margin-right:5px;display:inline-block}.tabulator-print-table .tabulator-print-table-group{box-sizing:border-box;background:#ccc;border-top:1px solid #999;border-bottom:1px solid #999;border-right:1px solid #aaa;min-width:100%;padding:5px 5px 5px 10px;font-weight:700}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-print-table-group:hover{cursor:pointer;background-color:#0000001a}}.tabulator-print-table .tabulator-print-table-group.tabulator-group-visible .tabulator-arrow{border:6px solid #0000;border-top-color:#666;border-bottom:0;margin-right:10px}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-1 td{padding-left:30px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-2 td{padding-left:50px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-3 td{padding-left:70px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-4 td{padding-left:90px!important}.tabulator-print-table .tabulator-print-table-group.tabulator-group-level-5 td{padding-left:110px!important}.tabulator-print-table .tabulator-print-table-group .tabulator-group-toggle{display:inline-block}.tabulator-print-table .tabulator-print-table-group .tabulator-arrow{vertical-align:middle;border:6px solid #0000;border-left-color:#666;border-right:0;width:0;height:0;margin-right:16px;display:inline-block}.tabulator-print-table .tabulator-print-table-group span{color:#d00;margin-left:10px}.tabulator-print-table .tabulator-data-tree-control{vertical-align:middle;background:#0000001a;border:1px solid #333;border-radius:2px;justify-content:center;align-items:center;width:11px;height:11px;margin-right:5px;display:inline-flex;overflow:hidden}@media (hover:hover) and (pointer:fine){.tabulator-print-table .tabulator-data-tree-control:hover{cursor:pointer;background:#0003}}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse{background:0 0;width:1px;height:7px;display:inline-block;position:relative}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-collapse:after{content:"";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand{background:#333;width:1px;height:7px;display:inline-block;position:relative}.tabulator-print-table .tabulator-data-tree-control .tabulator-data-tree-control-expand:after{content:"";background:#333;width:7px;height:1px;position:absolute;top:3px;left:-3px}
19
+ </style><style>
20
+ :host,#panel{background:var(--bkg-color);height:16rem;min-height:10rem}#panel{inset:0;overflow:hidden}#gutter{background:var(--bkg-color);cursor:row-resize;width:100%;height:.4rem;position:absolute;top:0;left:0}#gutter:hover{background:var(--bkg-color-grad1)}#gutter:after{content:" ";background:var(--bkg-color-grad1);border-radius:1rem;width:4rem;height:.4rem;display:block;position:relative;left:calc(50% - 2rem)}#close{color:#777;background-color:var(--bkg-color);cursor:pointer;border:none;width:1rem;height:1rem;margin:.5rem;padding:0;line-height:1rem;position:absolute;top:6px;right:0}#close i:before{content:"uf00d"}#close:hover{color:#000;border-color:#000}#content{background:var(--bkg-color);flex-direction:column;margin:0 .5rem .5rem;padding:0;display:flex;position:absolute;inset:.5rem 0 0;overflow:hidden}#header{flex:0;justify-content:space-between;display:flex}.selection-panel{margin-right:.5rem;display:flex;& .gg-icon-button[disabled]{pointer-events:none;opacity:.5}& .gg-icon-button[disabled]:hover{background-color:#0000}& .label{align-self:center;padding-left:1rem}}.gg-tabs{margin:0}#grid{flex:1;overflow:hidden}.geo-type{margin-right:.5rem}::-webkit-scrollbar{width:8px}::-webkit-scrollbar-thumb{background:#999}.tiny-margin{margin:.1rem}.tabulator-col[aria-sort=none] .tabulator-col-sorter i{color:#999}.tabulator-col[aria-sort=asc] .tabulator-col-sorter i{color:red}.tabulator-col[aria-sort=desc] .tabulator-col-sorter i{color:red;transform:scaleY(-1)}#tabulator{background-color:var(--bkg-color)}#tabulator .tabulator-header .tabulator-col-content{background-color:var(--bkg-color);color:var(--text-color)}#tabulator .tabulator-header .tabulator-col,#tabulator .tabulator-header .tabulator-col-row-handle{white-space:normal}#tabulator .tabulator-tableholder .tabulator-table .tabulator-row{background-color:var(--bkg-color);color:var(--text-color)}#tabulator .tabulator-tableholder .tabulator-table .tabulator-row:nth-child(2n){background-color:var(--bkg-color-grad1)}#tabulator .tabulator-tableholder .tabulator-table .tabulator-row.tabulator-selected{background-color:#9abcea}.tabulator-cell img{float:left;height:1.5rem;margin-right:.5rem}.tabulator-cell span{align-items:center;line-height:1.5rem;display:inline-flex;position:relative}.tabulator-cell span sup{position:absolute;top:-.3rem;right:-.5rem}@media (hover:hover) and (pointer:fine){#tabulator .tabulator-tableholder .tabulator-table .tabulator-row:hover{cursor:pointer;background-color:var(--bkg-color-grad2)}}img.sort-icon{width:1rem;height:1rem;&.default{opacity:.5}&:hover{opacity:1}}
19
21
  </style>
20
- <link rel="stylesheet" href="styles/common.css"><link rel="stylesheet" href="lib/tabulator-tables/tabulator.min.css"><link rel="stylesheet" href="../../../node_modules/tabulator-tables/dist/css/tabulator.css"><div id="panel"><div id="content"><div id="header"><div class="tab-panel">${this.getTabHeaders().map((th) => uHtml ` <button id="${th.id}" i18n="${th.text}" class="${th.active ? 'tab active' : 'tab'}" .active="${th.active}" onclick="${() => this.displayGrid(th.id, true)}"></button> `)}</div><div class="selection-panel"><button class="${this.showCsvButton ? 'gg-button' : 'hidden'}" onclick="${() => this.zoomToSelection()}" i18n="Zoom to"></button> <button class="gg-button" onclick="${() => this.selectAll()}" i18n="Select all"></button> <button class="gg-button" onclick="${() => this.selectNone()}" i18n="Select none"></button> <button class="gg-button" onclick="${() => this.invertSelection()}" i18n="Invert selection"></button> <button class="${this.showCsvButton ? 'gg-button' : 'hidden'}" onclick="${() => this.generateCSV()}" i18n="Generate CSV"></button></div></div><div id="tabulator"></div></div><div id="gutter"></div><button id="close" onclick="this.closePanel()"><img id="close" alt="close-icon" src="icons/close.svg"></button></div>`;
22
+ <div id="panel"><div id="content"><div id="header"><div class="gg-tabs">${this.getTabHeaders().map((th) => uHtml ` <button id="${th.id}" i18n="${th.text}" class="${th.active ? 'gg-tab active' : 'gg-tab'}" .active="${th.active}" onclick="${() => this.displayGrid(th.id, true)}"></button> `)}</div><div class="selection-panel"><span class="label" i18n="Selection"></span> <button class="gg-icon-button gg-medium" onclick="${() => this.selectAll()}" tip="Select all"><img alt="select all icon" src="icons/select-all-on.svg"></button> <button class="gg-icon-button gg-medium" onclick="${() => this.selectNone()}" tip="Select none"><img alt="select none icon" src="icons/select-all-off.svg"></button> <button class="gg-icon-button gg-medium" onclick="${() => this.invertSelection()}" tip="Invert selection"><img alt="invert selection icon" src="icons/select-invert.svg"></button> <button class="${this.resultsSelected ? 'gg-icon-button gg-medium' : 'gg-icon-button gg-medium disabled'}" ?disabled="${!this.resultsSelected}" onclick="${() => this.zoomToSelection()}" tip="Zoom to"><img alt="zoom to selection icon" src="icons/zoom-to-selection.svg"></button> <button class="${this.resultsSelected ? 'gg-icon-button gg-medium' : 'gg-icon-button gg-medium disabled'}" ?disabled="${!this.resultsSelected}" onclick="${() => this.generateCSV()}" tip="Generate CSV"><img alt="download csv icon" src="icons/arrow-download.svg"></button> <button class="gg-icon-button gg-medium" onclick="${() => this.closePanel()}" tip="Clear Results and close Panel"><img alt="close-icon" src="icons/trash.svg"></button></div></div><div id="tabulator"></div></div><div id="gutter"></div></div>`;
21
23
  };
22
24
  eventsCallbacks = [];
23
25
  selectionTabulatorManager;
@@ -26,7 +28,7 @@ class SelectionGridComponent extends GirafeResizableElement {
26
28
  debounceOnFeaturesSelected = debounce(this.onFeaturesSelected.bind(this), 200);
27
29
  visible = false;
28
30
  currentTabId = '';
29
- showCsvButton = false;
31
+ resultsSelected = false;
30
32
  constructor() {
31
33
  super('selectiongrid');
32
34
  }
@@ -35,7 +37,7 @@ class SelectionGridComponent extends GirafeResizableElement {
35
37
  this.csvManager = new CsvManager(this.context);
36
38
  this.selectionTabulatorManager = new SelectionTabulatorManager(this.context);
37
39
  this.subscribe('selection.gridSelected', (_oldValue, newValue) => {
38
- this.showCsvButton = newValue;
40
+ this.resultsSelected = newValue;
39
41
  this.render();
40
42
  });
41
43
  this.addEventListener('resize-start', () => {
@@ -62,7 +64,7 @@ class SelectionGridComponent extends GirafeResizableElement {
62
64
  * @returns The current array of TabHeader objects.
63
65
  */
64
66
  getTabHeaders() {
65
- return this.selectionTabulatorManager.tabHeaders;
67
+ return this.selectionTabulatorManager.getTabHeaders();
66
68
  }
67
69
  /**
68
70
  * Activates the specified tab, renders the grid, and displays the grid for the specified id.
@@ -82,7 +84,8 @@ class SelectionGridComponent extends GirafeResizableElement {
82
84
  closePanel() {
83
85
  this.state.interface.selectionComponentVisible = false;
84
86
  this.state.selection.selectedFeatures = [];
85
- this.showCsvButton = false;
87
+ this.state.selection.highlightedFeatures = [];
88
+ this.resultsSelected = false;
86
89
  this.state.selection.gridSelected = false;
87
90
  super.clean();
88
91
  }
@@ -90,46 +93,40 @@ class SelectionGridComponent extends GirafeResizableElement {
90
93
  * Selects all rows in the grid.
91
94
  */
92
95
  selectAll() {
93
- this.selectionTabulatorManager.table?.selectRow();
96
+ this.selectionTabulatorManager.selectAll();
94
97
  }
95
98
  /**
96
99
  * Deselects all rows in the grid.
97
100
  */
98
101
  selectNone() {
99
- this.selectionTabulatorManager.table?.deselectRow();
102
+ this.selectionTabulatorManager.selectNone();
100
103
  }
101
104
  /**
102
105
  * Inverts the selection of all rows in the grid.
103
106
  */
104
107
  invertSelection() {
105
- this.selectionTabulatorManager.table?.getRows().forEach((row) => {
106
- row.toggleSelect();
107
- });
108
+ this.selectionTabulatorManager.invertSelection();
108
109
  }
109
110
  /**
110
111
  * Zooms to the extent of the selected rows in the grid.
111
112
  */
112
113
  zoomToSelection() {
113
114
  const extent = olExtent.createEmpty();
114
- this.selectionTabulatorManager.table?.getRows().forEach((row) => {
115
- if (row.isSelected()) {
116
- const data = row.getData();
117
- const geometry = data.geom ?? data.the_geom ?? data.geometry;
118
- olExtent.extend(extent, geometry.getExtent());
119
- }
120
- });
115
+ for (const row of this.selectionTabulatorManager.getSelectedRows()) {
116
+ const data = row.getData();
117
+ const geometry = data.geom ?? data.the_geom ?? data.geometry;
118
+ olExtent.extend(extent, geometry.getExtent());
119
+ }
121
120
  this.context.mapManager.getMap().getView().fit(extent, { duration: 300 });
122
121
  }
123
122
  /**
124
123
  * Generates a CSV file from the selected rows in the grid.
125
124
  */
126
125
  generateCSV() {
127
- const columns = this.selectionTabulatorManager.data[this.currentTabId].columns.map((column) => {
126
+ const columnDefs = this.selectionTabulatorManager.getNonGeometryColumnFields().map((column) => {
128
127
  return { name: column };
129
128
  });
130
- const excludedColumns = ['geom', 'the_geom', 'geometry'];
131
- const filteredColumns = columns.filter((column) => !excludedColumns.includes(column.name));
132
- this.csvManager.startDownload(this.selectionTabulatorManager.table?.getSelectedData() ?? [], filteredColumns, 'query-results.csv');
129
+ this.csvManager.startDownload(this.selectionTabulatorManager.getSelectedData(), columnDefs, 'query-results.csv');
133
130
  }
134
131
  /**
135
132
  * Renders the component by calling the necessary methods.
@@ -148,7 +145,7 @@ class SelectionGridComponent extends GirafeResizableElement {
148
145
  * @private
149
146
  */
150
147
  setupVisibleComponent() {
151
- this.showCsvButton = false;
148
+ this.resultsSelected = false;
152
149
  this.state.selection.gridSelected = false;
153
150
  this.isVisibleComponentSetup = true;
154
151
  this.registerEvents();
@@ -187,14 +184,14 @@ class SelectionGridComponent extends GirafeResizableElement {
187
184
  * @private
188
185
  */
189
186
  onFeaturesSelected(features) {
190
- this.selectionTabulatorManager.tabHeaders = [];
187
+ this.selectionTabulatorManager.clearTabHeaders();
191
188
  // No feature ? Close.
192
189
  if (this.isNullOrUndefined(features) || features.length <= 0) {
193
190
  this.closePanel();
194
191
  return;
195
192
  }
196
193
  this.selectionTabulatorManager.featuresToGridData(features);
197
- const tabIds = Object.keys(this.selectionTabulatorManager.idTab);
194
+ const tabIds = this.selectionTabulatorManager.getTabIds();
198
195
  //define table element
199
196
  this.selectionTabulatorManager.setElement(this.shadow.querySelector('#tabulator'));
200
197
  // No tab ? Close the panel.
@@ -1,6 +1,6 @@
1
1
  import type OlFeature from 'ol/Feature';
2
2
  import { GridDataById } from '../../../tools/featuretogriddatabyid';
3
- import { ColumnDefinition, TabulatorFull as Tabulator } from 'tabulator-tables';
3
+ import { ColumnDefinition, RowComponent } from 'tabulator-tables';
4
4
  import IGirafeContext from '../../../tools/context/icontext';
5
5
  /**
6
6
  * Represents the header text and state of a tab.
@@ -28,11 +28,11 @@ export interface TabContent {
28
28
  export default class SelectionTabulatorManager {
29
29
  private readonly formatGridGeomValue;
30
30
  private readonly featureToGridData;
31
- idTab: Record<string, TabContent>;
32
- tabHeaders: TabHeader[];
33
- table: Tabulator | null;
34
- element: string | HTMLElement;
35
- data: GridDataById;
31
+ private idTab;
32
+ private tabHeaders;
33
+ private table;
34
+ private element;
35
+ private data;
36
36
  private readonly context;
37
37
  private readonly columnAliasHelper;
38
38
  constructor(context: IGirafeContext);
@@ -77,4 +77,13 @@ export default class SelectionTabulatorManager {
77
77
  private createGridData;
78
78
  blockRedraw(): void;
79
79
  restoreRedraw(): void;
80
+ selectAll(): void;
81
+ selectNone(): void;
82
+ invertSelection(): void;
83
+ getSelectedRows(): RowComponent[];
84
+ getSelectedData(): any[];
85
+ getNonGeometryColumnFields(): string[];
86
+ getTabHeaders(): TabHeader[];
87
+ clearTabHeaders(): void;
88
+ getTabIds(): string[];
80
89
  }
@@ -4,6 +4,7 @@ import FormatGridGeomValue from './formatgridgeomvalue';
4
4
  import { TabulatorFull as Tabulator } from 'tabulator-tables';
5
5
  import { getUid } from 'ol/util';
6
6
  import ColumnAliasHelper from '../../../tools/utils/aliases';
7
+ const geometryColumns = new Set(['geom', 'the_geom', 'geometry']);
7
8
  export default class SelectionTabulatorManager {
8
9
  formatGridGeomValue;
9
10
  featureToGridData;
@@ -38,7 +39,9 @@ export default class SelectionTabulatorManager {
38
39
  * Activates a tab matching the given id.
39
40
  */
40
41
  activateTab(id) {
41
- this.tabHeaders?.forEach((tabHeader) => (tabHeader.active = false));
42
+ for (const tabHeader of this.tabHeaders) {
43
+ tabHeader.active = false;
44
+ }
42
45
  const visibleTabHeader = this.tabHeaders?.find((tabHeader) => tabHeader.id === id);
43
46
  if (!visibleTabHeader) {
44
47
  return;
@@ -62,11 +65,11 @@ export default class SelectionTabulatorManager {
62
65
  headerSortElement: function (_, dir) {
63
66
  switch (dir) {
64
67
  case 'asc':
65
- return '<img alt="sort-up-icon" src="icons/sort-up.svg" />';
68
+ return '<img alt="sort-up-icon" src="icons/sort-up.svg" class="sort-icon" />';
66
69
  case 'desc':
67
- return '<img alt="sort-down-icon" src="icons/sort-down.svg" />';
70
+ return '<img alt="sort-down-icon" src="icons/sort-down.svg" class="sort-icon" />';
68
71
  default:
69
- return '<img alt="sort-icon" src="icons/sort.svg" />';
72
+ return '<img alt="sort-icon" src="icons/sort.svg" class="sort-icon default" />';
70
73
  }
71
74
  }
72
75
  });
@@ -75,15 +78,13 @@ export default class SelectionTabulatorManager {
75
78
  this.context.stateManager.state.selection.gridSelected = selection.length > 0;
76
79
  // Create a Map of features by their UIDs
77
80
  const featureMap = new Map();
78
- this.data[id].features.forEach((feature) => {
79
- const uid = getUid(feature.getGeometry());
80
- featureMap.set(uid, feature);
81
- });
81
+ for (const feature of this.data[id].features) {
82
+ featureMap.set(getUid(feature.getGeometry()), feature);
83
+ }
82
84
  // Highlight selected features on the map.
83
- const highlightedGeometries = selection
85
+ this.context.stateManager.state.selection.highlightedFeatures = selection
84
86
  .map((row) => featureMap.get(getUid(row.geom ?? row.the_geom ?? row.geometry)))
85
87
  .filter((feature) => feature !== undefined);
86
- this.context.stateManager.state.selection.highlightedFeatures = highlightedGeometries;
87
88
  });
88
89
  }
89
90
  /**
@@ -94,7 +95,9 @@ export default class SelectionTabulatorManager {
94
95
  this.idTab = {};
95
96
  const gridDataById = this.featureToGridData.toGridDataById(features);
96
97
  // Create tabs and collect data.
97
- Object.keys(gridDataById).forEach((id) => this.gridDataToGridTab(id, gridDataById[id]));
98
+ for (const id of Object.keys(gridDataById)) {
99
+ this.gridDataToGridTab(id, gridDataById[id]);
100
+ }
98
101
  // Create tabs headers
99
102
  this.tabHeaders = Object.keys(this.idTab).map((key) => {
100
103
  return {
@@ -122,21 +125,22 @@ export default class SelectionTabulatorManager {
122
125
  }
123
126
  columnsToGridColumns(idTable, columns) {
124
127
  const columnDefinition = [];
125
- columns.forEach((column) => {
128
+ for (const column of columns) {
126
129
  const columnAlias = this.columnAliasHelper.getColumnAlias(idTable, column);
127
130
  columnDefinition.push({
128
131
  title: this.context.i18nManager.getTranslation(columnAlias),
129
132
  field: column,
130
- formatter: 'html'
133
+ formatter: 'html',
134
+ sorter: 'string'
131
135
  });
132
- });
133
- columnDefinition.forEach((column) => {
134
- if (column.field === 'the_geom' || column.field === 'geom' || column.field === 'geometry') {
136
+ }
137
+ for (const column of columnDefinition) {
138
+ if (column.field && geometryColumns.has(column.field)) {
135
139
  column.formatter = (cell) => {
136
140
  return this.formatGridGeomValue.getGeometryIcons(cell.getValue()) ?? cell.getValue();
137
141
  };
138
142
  }
139
- });
143
+ }
140
144
  return columnDefinition;
141
145
  }
142
146
  filterEmptyColumnsOnData(data) {
@@ -145,7 +149,7 @@ export default class SelectionTabulatorManager {
145
149
  const notOlProperties = entry.notOlProperties;
146
150
  for (const [_, row] of Object.entries(notOlProperties)) {
147
151
  for (const [key, _] of Object.entries(row)) {
148
- if (!columns.some((column) => column === key)) {
152
+ if (!columns.includes(key)) {
149
153
  delete row[key];
150
154
  }
151
155
  }
@@ -178,4 +182,36 @@ export default class SelectionTabulatorManager {
178
182
  restoreRedraw() {
179
183
  this.table?.restoreRedraw();
180
184
  }
185
+ selectAll() {
186
+ this.table?.selectRow();
187
+ }
188
+ selectNone() {
189
+ this.table?.deselectRow();
190
+ }
191
+ invertSelection() {
192
+ for (const row of this.table.getRows()) {
193
+ row.toggleSelect();
194
+ }
195
+ }
196
+ getSelectedRows() {
197
+ return this.table?.getRows('selected') ?? [];
198
+ }
199
+ getSelectedData() {
200
+ return this.table?.getSelectedData() ?? [];
201
+ }
202
+ getNonGeometryColumnFields() {
203
+ return (this.table
204
+ ?.getColumns(false)
205
+ .map((columnComponent) => columnComponent.getField())
206
+ .filter((column) => !geometryColumns.has(column)) ?? []);
207
+ }
208
+ getTabHeaders() {
209
+ return this.tabHeaders;
210
+ }
211
+ clearTabHeaders() {
212
+ this.tabHeaders = [];
213
+ }
214
+ getTabIds() {
215
+ return Object.keys(this.idTab);
216
+ }
181
217
  }
@@ -28,9 +28,7 @@ class TimeRestrictionComponent extends GirafeHTMLElement {
28
28
  renderComponent() {
29
29
  this.render();
30
30
  super.girafeTranslate();
31
- if (!this.timeWidget) {
32
- this.initTimeWidget();
33
- }
31
+ this.initTimeWidget();
34
32
  // Wait for the time widget to be rendered, then set the time
35
33
  setTimeout(() => {
36
34
  this.onOutsideTimeChange(this.layer.timeRestriction);
@@ -41,7 +39,7 @@ class TimeRestrictionComponent extends GirafeHTMLElement {
41
39
  // The type of time widget component in the template is dependent on the timeOptions > widget value
42
40
  this.timeWidget = this.getById('time-widget');
43
41
  this.timeWidget.initialize(this.timeOptions);
44
- this.render();
42
+ this.timeWidget.render();
45
43
  // Connect change event of widget
46
44
  this.timeWidget.addEventListener(TimeChangeEvent, ((evt) => this.onTimeChange(evt.detail)));
47
45
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geomapfish.dev"
7
7
  },
8
- "version": "1.0.2154016552",
8
+ "version": "1.0.2163361385",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -1 +1 @@
1
- {"version":"1.0.2154016552", "build":"2154016552", "date":"12/11/2025"}
1
+ {"version":"1.0.2163361385", "build":"2163361385", "date":"17/11/2025"}