@geogirafe/lib-geoportal 1.2.0-dev.2675426009 → 1.2.0-dev.2678010155

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/README.md CHANGED
@@ -163,6 +163,42 @@ This will automatically copy the `config.json` file in the right place, and down
163
163
  > Please note that today, the GeoGirafe Viewer is using a backend based on GeoMapFish.
164
164
  > The services you will have to use in your configuration must therefore be compliant with GeoMapFish.
165
165
 
166
+ ## Testing
167
+
168
+ There are 2 kinds of tests in the GeoGirafe project:
169
+
170
+ ### unitests (with vitest)
171
+
172
+ To run the unitests, execute the following command:
173
+
174
+ ```
175
+ npm run test
176
+ ```
177
+
178
+ And that's it.
179
+
180
+ ### End-to-end tests (with playwright)
181
+
182
+ To be able to run the playwright tests, first install the headless chrome and firefox binaries:
183
+
184
+ ```
185
+ npx playwright install
186
+ ```
187
+
188
+ Then you must start the application:
189
+
190
+ ```
191
+ npm start
192
+ ```
193
+
194
+ And then in another console you can run the tests:
195
+
196
+ ```
197
+ npx playwright test
198
+ ```
199
+
200
+ The result page will omen at the end of the tests.
201
+
166
202
  ## Build for Production
167
203
 
168
204
  ```bash
@@ -1,5 +1,5 @@
1
1
  import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
2
- type ModalType = 'alert' | 'confirm' | 'prompt' | 'info';
2
+ type ModalType = 'alert' | 'confirm' | 'prompt' | 'info' | 'choice';
3
3
  declare class ModalsComponent extends GirafeHTMLElement {
4
4
  protected templateUrl: string | null;
5
5
  protected styleUrls: string[] | null;
@@ -9,6 +9,7 @@ declare class ModalsComponent extends GirafeHTMLElement {
9
9
  boxTitle?: string;
10
10
  boxMessage?: string;
11
11
  boxPlaceholder?: string;
12
+ boxChoices: string[];
12
13
  resolveAlertConfirm: (value: boolean) => void;
13
14
  resolvePrompt: (value: string | false) => void;
14
15
  constructor();
@@ -16,11 +17,13 @@ declare class ModalsComponent extends GirafeHTMLElement {
16
17
  private initBoxWithMessageArray;
17
18
  private resetBox;
18
19
  private promptBox;
20
+ private promptChoiceBox;
19
21
  private alertInfoBox;
20
22
  private alertConfirmBox;
21
23
  ok(): void;
22
24
  nok(): void;
23
25
  promptOk(): void;
26
+ choiceOk(choice: string): void;
24
27
  promptNok(): void;
25
28
  render(): void;
26
29
  protected connectedCallback(): void;
@@ -8,10 +8,10 @@ class ModalsComponent extends GirafeHTMLElement {
8
8
  return uHtml `<style>
9
9
  .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}button,input,select,textarea{font:inherit}.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-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.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-icon{justify-content:center;align-items:center;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:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){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}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
10
10
  </style><style>
11
- #content{z-index:10000;background-color:#000000a6;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal{background:var(--bkg-color);border:var(--app-standard-border);border-radius:10px;width:300px;min-height:400px;box-shadow:5px 5px 10px #0003}.wide{width:auto;max-width:480px}header{background:var(--app-color-grey);border-top-left-radius:10px;border-top-right-radius:10px;justify-content:center;height:100px;padding:2rem;display:flex}section{text-align:center;flex-direction:column;padding:30px;display:flex}span{margin-bottom:1rem;font-size:1.2rem;display:inline-block}.confirm-buttons{flex-direction:row;justify-content:center;gap:1rem;margin-top:2rem;display:flex}.confirm-buttons button{width:7rem}h2,span{color:var(--text-color)}
11
+ #content{z-index:10000;background-color:#000000a6;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.modal{background:var(--bkg-color);border:var(--app-standard-border);border-radius:10px;width:300px;min-height:400px;box-shadow:5px 5px 10px #0003}.wide{width:auto;max-width:480px}header{background:var(--app-color-grey);border-top-left-radius:10px;border-top-right-radius:10px;justify-content:center;height:100px;padding:2rem;display:flex}section{text-align:center;flex-direction:column;padding:30px;display:flex}span{margin-bottom:1rem;font-size:1.2rem;display:inline-block}.confirm-buttons{flex-direction:row;justify-content:center;gap:1rem;margin-top:2rem;display:flex}.confirm-buttons button{width:7rem}h2,span{color:var(--text-color)}.choices{grid-template-columns:1fr 1fr;gap:1rem;margin-top:1rem;display:grid}.choice{height:4rem}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div id="content" class="${this.visible ? '' : 'hidden'}"><div class="${this.boxType == 'info' ? 'modal wide' : 'modal'}"><header><img alt="question-icon" src="icons/help.svg" class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'hidden' : ''}"> <img alt="error-icon" src="icons/error.svg" class="${this.boxType === 'alert' ? '' : 'hidden'}"> <img alt="info-icon" src="icons/info.svg" class="${this.boxType === 'info' ? '' : 'hidden'}"></header><section><h2>${this.boxTitle}</h2><span>${this.htmlUnsafe(this.boxMessage)}</span> <input id="input-text" class="${this.boxType === 'prompt' ? 'gg-input' : 'hidden'}" placeholder="${this.boxPlaceholder}"><div class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Ok">Ok</button></div><div class="${this.boxType === 'confirm' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Yes">Yes</button> <button class="gg-button" onclick="${() => this.nok()}" i18n="No">No</button></div><div class="${this.boxType === 'prompt' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.promptOk()}" i18n="Ok">Ok</button> <button class="gg-button" onclick="${() => this.promptNok()}" i18n="Cancel">Cancel</button></div></section></div></div>
14
+ <div id="content" class="${this.visible ? '' : 'hidden'}"><div class="${this.boxType == 'info' ? 'modal wide' : 'modal'}"><header><img alt="question-icon" src="icons/help.svg" class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'hidden' : ''}"> <img alt="error-icon" src="icons/error.svg" class="${this.boxType === 'alert' ? '' : 'hidden'}"> <img alt="info-icon" src="icons/info.svg" class="${this.boxType === 'info' ? '' : 'hidden'}"></header><section><h2>${this.boxTitle}</h2><span>${this.htmlUnsafe(this.boxMessage)}</span> <input id="input-text" class="${this.boxType === 'prompt' ? 'gg-input' : 'hidden'}" placeholder="${this.boxPlaceholder}"><div class="${this.boxType === 'choice' ? 'choices' : 'hidden'}">${this.boxChoices.map(option => uHtml ` <button class="gg-button choice" onclick="${() => this.choiceOk(option)}">${option}</button> `)}</div><div class="${(this.boxType === 'alert' || this.boxType === 'info') ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Ok">Ok</button></div><div class="${this.boxType === 'confirm' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.ok()}" i18n="Yes">Yes</button> <button class="gg-button" onclick="${() => this.nok()}" i18n="No">No</button></div><div class="${this.boxType === 'prompt' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.promptOk()}" i18n="Ok">Ok</button> <button class="gg-button" onclick="${() => this.promptNok()}" i18n="Cancel">Cancel</button></div><div class="${this.boxType === 'choice' ? 'confirm-buttons' : 'hidden'}"><button class="gg-button" onclick="${() => this.promptNok()}" i18n="Cancel">Cancel</button></div></section></div></div>
15
15
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
16
16
  };
17
17
  visible = false;
@@ -19,12 +19,13 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
19
19
  boxTitle;
20
20
  boxMessage;
21
21
  boxPlaceholder;
22
+ boxChoices = [];
22
23
  resolveAlertConfirm;
23
24
  resolvePrompt;
24
25
  constructor() {
25
26
  super('native-modals');
26
27
  }
27
- initBox(type, message, messageHandler, title, placeholder) {
28
+ initBox(type, message, messageHandler, title, placeholder, choices) {
28
29
  this.boxType = type;
29
30
  this.boxMessage = messageHandler(this.context.i18nManager.getTranslation(message));
30
31
  if (title) {
@@ -33,6 +34,9 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
33
34
  if (placeholder) {
34
35
  this.boxPlaceholder = this.context.i18nManager.getTranslation(placeholder);
35
36
  }
37
+ if (choices) {
38
+ this.boxChoices = choices;
39
+ }
36
40
  this.visible = true;
37
41
  this.refreshRender();
38
42
  }
@@ -67,6 +71,12 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
67
71
  this.resolvePrompt = resolve;
68
72
  });
69
73
  }
74
+ async promptChoiceBox(message, title, choices) {
75
+ this.initBox('choice', message, (message) => (Array.isArray(message) ? message[0] : message), title, undefined, choices);
76
+ return new Promise((resolve) => {
77
+ this.resolvePrompt = resolve;
78
+ });
79
+ }
70
80
  async alertInfoBox(message, title, messageHandler) {
71
81
  this.initBoxWithMessageArray('info', message, messageHandler, title);
72
82
  return new Promise((resolve) => {
@@ -94,6 +104,10 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
94
104
  this.resetBox();
95
105
  this.resolvePrompt(text);
96
106
  }
107
+ choiceOk(choice) {
108
+ this.resetBox();
109
+ this.resolvePrompt(choice);
110
+ }
97
111
  promptNok() {
98
112
  this.resetBox();
99
113
  this.resolvePrompt(false);
@@ -108,6 +122,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
108
122
  window.gConfirm = (message, title, messageHandler) => this.alertConfirmBox('confirm', message, title, messageHandler ?? defaultMessageHandler);
109
123
  window.gAlert = (message, title) => this.alertConfirmBox('alert', message, title ?? '', defaultMessageHandler);
110
124
  window.gPrompt = (message, title, placeholder) => this.promptBox(message, title, placeholder);
125
+ window.gPromptChoice = (message, title, choices) => this.promptChoiceBox(message, title, choices);
111
126
  window.gInfo = (message, title, messageHandler) => this.alertInfoBox(message, title, messageHandler ?? defaultMessageArrayHandler);
112
127
  window.gCloseModal = () => {
113
128
  this.ok();
@@ -65,3 +65,14 @@ h2,
65
65
  span {
66
66
  color: var(--text-color);
67
67
  }
68
+
69
+ .choices {
70
+ display: grid;
71
+ grid-template-columns: 1fr 1fr;
72
+ gap: 1rem;
73
+ margin-top: 1rem;
74
+ }
75
+
76
+ .choice {
77
+ height: 4rem;
78
+ }
package/main.tools.d.ts CHANGED
@@ -15,6 +15,7 @@ declare global {
15
15
  gAlert(message: string, title?: string): Promise<boolean>;
16
16
  gInfo(message: string | string[], title: string, messageHandler?: (translatedMessage: string | string[]) => string): Promise<boolean>;
17
17
  gPrompt(message: string, title?: string, placeholder?: string): Promise<string | false>;
18
+ gPromptChoice(message: string, title?: string, choices?: string[]): Promise<string | false>;
18
19
  gOpenWindow(title: string, url: string, width?: string | number, height?: string | number, top?: string | number, left?: string | number): void;
19
20
  gCloseModal(): void;
20
21
  }
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geogirafe.org"
7
7
  },
8
- "version": "1.2.0-dev.2675426009",
8
+ "version": "1.2.0-dev.2678010155",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -66,6 +66,7 @@
66
66
  "@eslint/js": "10.0.1",
67
67
  "@geoblocks/mapfishprint": "0.3.0",
68
68
  "@geoblocks/print": "0.7.9",
69
+ "@playwright/test": "1.61.0",
69
70
  "@types/babel__generator": "7.27.0",
70
71
  "@types/d3": "7.4.3",
71
72
  "@types/file-saver": "2.0.7",
@@ -92,6 +93,7 @@
92
93
  "lint-staged": "16.4.0",
93
94
  "magic-string": "0.30.21",
94
95
  "minify": "14.1.0",
96
+ "odiff-bin": "4.3.8",
95
97
  "ol": "10.8.0",
96
98
  "ol-ext": "4.0.38",
97
99
  "ol-mapbox-style": "13.4.0",
@@ -176,5 +178,12 @@
176
178
  "trust-default-dev-certs-win": "buildtools\\trust-dev-certs.cmd",
177
179
  "size-analysis": "node buildtools/app-clean.js && cross-env NODE_OPTIONS=--max-old-space-size=8192 vite build --mode analyze",
178
180
  "create-component": "tsx buildtools/create-component.ts"
181
+ },
182
+ "allowScripts": {
183
+ "@swc/core@1.15.24": true,
184
+ "esbuild@0.28.1": true,
185
+ "esbuild@0.25.12": true,
186
+ "odiff-bin@4.3.8": true,
187
+ "protobufjs@8.0.1": true
179
188
  }
180
189
  }
@@ -1 +1 @@
1
- {"version":"1.2.0-dev.2675426009", "build":"2675426009", "date":"14/07/2026"}
1
+ {"version":"1.2.0-dev.2678010155", "build":"2678010155", "date":"15/07/2026"}