@geogirafe/lib-geoportal 1.1.0-dev.2597268561 → 1.1.0-dev.2605752849

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/LICENSE +4 -0
  2. package/api/apicontext.d.ts +2 -0
  3. package/api/apicontext.js +4 -0
  4. package/api/apigeogirafeapp.js +5 -6
  5. package/assets/i18n/de.json +5 -0
  6. package/assets/i18n/en.json +7 -2
  7. package/assets/i18n/fr.json +5 -0
  8. package/assets/i18n/it.json +5 -0
  9. package/assets/icons/feedback-comment-add.svg +1 -0
  10. package/assets/icons/feedback-comment.svg +1 -0
  11. package/assets/icons/feedback-thumb-down.svg +1 -0
  12. package/assets/icons/feedback-thumb-up.svg +1 -0
  13. package/base/GirafeHTMLElement.d.ts +2 -0
  14. package/base/GirafeHTMLElement.js +4 -0
  15. package/buildtools/tools.js +2 -1
  16. package/components/about/component.js +2 -1
  17. package/components/addbookmark/component.js +2 -1
  18. package/components/advancedfilter/component.js +2 -1
  19. package/components/alignnorthbutton-mobile/component.js +2 -1
  20. package/components/auth/component.js +2 -1
  21. package/components/auth-mobile/component.js +2 -1
  22. package/components/basemap/component.js +2 -1
  23. package/components/contact/component.js +2 -1
  24. package/components/context-menu/custom-context-menu/component.js +2 -1
  25. package/components/context-menu/custom-context-menu/style.css +19 -18
  26. package/components/context-menu/default-context-menu/component.js +2 -1
  27. package/components/coordinate/component.js +2 -1
  28. package/components/cross-section/cross-section-settings/component.js +2 -1
  29. package/components/cross-section/cross-section-viewer/component.js +2 -1
  30. package/components/displaymenubutton-mobile/component.js +2 -1
  31. package/components/displayselectorbutton-mobile/component.js +2 -1
  32. package/components/drawing/component-mobile.js +2 -1
  33. package/components/drawing/component.js +2 -1
  34. package/components/drawing/fixed-dimension/component.js +2 -1
  35. package/components/drawing/style.css +5 -5
  36. package/components/drawing-container-mobile/component.js +2 -1
  37. package/components/drawing-toolbar/component.js +2 -1
  38. package/components/edit/component.js +2 -1
  39. package/components/edit/editform/component.js +2 -1
  40. package/components/extlayers/component.js +2 -1
  41. package/components/feedbackbutton/component.d.ts +28 -0
  42. package/components/feedbackbutton/component.js +195 -0
  43. package/components/feedbackbutton/style.css +23 -0
  44. package/components/geolocation-mobile/component.js +2 -1
  45. package/components/getdirections/component.d.ts +0 -1
  46. package/components/getdirections/component.js +2 -2
  47. package/components/help/component.js +2 -1
  48. package/components/infobox/component.js +2 -1
  49. package/components/infowindow/component.js +2 -1
  50. package/components/layout/component.js +2 -1
  51. package/components/lr-panel/component.js +2 -1
  52. package/components/main.d.ts +1 -0
  53. package/components/main.js +1 -0
  54. package/components/map/component.js +5 -2
  55. package/components/menu-buttons-mobile/MenuMobile3dButton.js +2 -1
  56. package/components/menu-buttons-mobile/MenuMobileDrawingButton.js +2 -1
  57. package/components/menu-buttons-mobile/MenuMobileOfflineButton.js +2 -1
  58. package/components/menu-mobile/component.js +2 -1
  59. package/components/menubutton/component.js +2 -1
  60. package/components/modals/component.js +2 -1
  61. package/components/navigation/component.js +2 -1
  62. package/components/news/news-button/component.js +2 -1
  63. package/components/news/news-panel/component.js +2 -1
  64. package/components/offline/component.js +2 -1
  65. package/components/print/component.js +2 -1
  66. package/components/prototypebanner/component.js +2 -1
  67. package/components/querybuilder/component.js +2 -1
  68. package/components/scale/component.js +2 -1
  69. package/components/search/component.js +2 -1
  70. package/components/search-mobile/component.js +2 -1
  71. package/components/selectiongrid/component.js +2 -1
  72. package/components/selectiongrid/style.css +1 -1
  73. package/components/selectionpanel-mobile/component.js +2 -1
  74. package/components/selectiontool/component.js +2 -1
  75. package/components/selectionwindow/component.js +2 -1
  76. package/components/share/component.js +2 -1
  77. package/components/swipe-up-panel-mobile/component.js +2 -1
  78. package/components/themes/component.js +2 -1
  79. package/components/themes-mobile/group/component.js +2 -1
  80. package/components/themes-mobile/layer/component.js +2 -1
  81. package/components/themes-mobile/layer-selected/component.js +2 -1
  82. package/components/themes-mobile/theme/component.js +2 -1
  83. package/components/themes-mobile/themes-select/component.js +2 -1
  84. package/components/timerestriction/component.js +2 -1
  85. package/components/timerestriction/timepicker/component.js +2 -1
  86. package/components/timerestriction/timeslider/component.js +2 -1
  87. package/components/treeview/treeviewgroup/component.js +2 -1
  88. package/components/treeview/treeviewitem/component.js +7 -4
  89. package/components/treeview/treeviewroot/component.js +2 -1
  90. package/components/treeview/treeviewroot/style.css +1 -1
  91. package/components/treeview/treeviewtheme/component.js +2 -1
  92. package/components/userpreferences/component.js +2 -1
  93. package/components/videorecord/component.js +2 -1
  94. package/package.json +3 -3
  95. package/styles/index.css +2 -2
  96. package/templates/api.html +4 -1
  97. package/templates/index.html +5 -2
  98. package/templates/public/about.json +1 -1
  99. package/tools/app/geogirafeapp.js +2 -0
  100. package/tools/configuration/girafeconfig.d.ts +11 -0
  101. package/tools/configuration/girafeconfig.js +27 -22
  102. package/tools/context/context.d.ts +2 -0
  103. package/tools/context/context.js +4 -0
  104. package/tools/context/icontext.d.ts +2 -0
  105. package/tools/feedback/feedbackmanager.d.ts +16 -0
  106. package/tools/feedback/feedbackmanager.js +73 -0
  107. package/tools/main.d.ts +2 -0
  108. package/tools/main.js +1 -0
  109. package/tools/state/componentManager.d.ts +5 -3
  110. package/tools/state/componentManager.js +5 -3
  111. package/tools/state/mapposition.js +1 -1
  112. package/tools/tests/mockcontext.d.ts +2 -0
  113. package/tools/tests/mockcontext.js +4 -0
  114. package/tools/utils/utils.js +6 -4
  115. package/components/addbookmark/style.css +0 -0
package/LICENSE CHANGED
@@ -240,6 +240,10 @@ From:
240
240
  - https://www.svgrepo.com/svg/310006/star
241
241
  - https://www.svgrepo.com/svg/310008/star-add
242
242
  - https://www.svgrepo.com/svg/309521/directions
243
+ - https://www.svgrepo.com/svg/309459/comment
244
+ - https://www.svgrepo.com/svg/309461/comment-add
245
+ - https://www.svgrepo.com/svg/310167/thumb-like
246
+ - https://www.svgrepo.com/svg/310166/thumb-dislike
243
247
  - https://www.svgrepo.com/svg/309871/photo-filter
244
248
 
245
249
 
@@ -31,6 +31,7 @@ import IGirafeContext from '../tools/context/icontext.js';
31
31
  import ApiSessionManager from './apisessionmanager.js';
32
32
  import OnBoardingManager from '../tools/onboarding/onboardingmanager.js';
33
33
  import ThemeFavoritesManager from '../tools/themes/themefavoritesmanager.js';
34
+ import FeedbackManager from '../tools/feedback/feedbackmanager.js';
34
35
  export default class GirafeApiContext implements IGirafeContext {
35
36
  readonly userDataManager: UserDataManager;
36
37
  readonly configManager: ConfigManager;
@@ -64,6 +65,7 @@ export default class GirafeApiContext implements IGirafeContext {
64
65
  readonly localFileManager: LocalFileManager;
65
66
  readonly onBoardingManager: OnBoardingManager;
66
67
  readonly themeFavoritesManager: ThemeFavoritesManager;
68
+ readonly feedbackManager: FeedbackManager;
67
69
  constructor();
68
70
  initialize(): Promise<void>;
69
71
  }
package/api/apicontext.js CHANGED
@@ -31,6 +31,7 @@ import WmsManager from '../tools/wms/wmsmanager.js';
31
31
  import ApiSessionManager from './apisessionmanager.js';
32
32
  import OnBoardingManager from '../tools/onboarding/onboardingmanager.js';
33
33
  import ThemeFavoritesManager from '../tools/themes/themefavoritesmanager.js';
34
+ import FeedbackManager from '../tools/feedback/feedbackmanager.js';
34
35
  export default class GirafeApiContext {
35
36
  userDataManager;
36
37
  configManager;
@@ -64,6 +65,7 @@ export default class GirafeApiContext {
64
65
  localFileManager;
65
66
  onBoardingManager;
66
67
  themeFavoritesManager;
68
+ feedbackManager;
67
69
  constructor() {
68
70
  this.componentManager = new ComponentManager(this);
69
71
  this.userDataManager = new UserDataManager(this);
@@ -97,6 +99,7 @@ export default class GirafeApiContext {
97
99
  this.ogcApiFeaturesManager = new OgcApiFeaturesManager(this);
98
100
  this.onBoardingManager = new OnBoardingManager(this);
99
101
  this.themeFavoritesManager = new ThemeFavoritesManager(this);
102
+ this.feedbackManager = new FeedbackManager(this);
100
103
  }
101
104
  async initialize() {
102
105
  // NOTE : This initialization order is important, because some singleton will need other ones !
@@ -134,5 +137,6 @@ export default class GirafeApiContext {
134
137
  this.ogcApiFeaturesManager.initializeSingleton();
135
138
  this.onBoardingManager.initializeSingleton();
136
139
  this.themeFavoritesManager.initializeSingleton();
140
+ this.feedbackManager.initializeSingleton();
137
141
  }
138
142
  }
@@ -37,7 +37,8 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
37
37
  :host{position:relative}girafe-map{width:100%;height:100%;position:relative}girafe-basemap{display:block;position:absolute;bottom:.5rem;left:.5rem}girafe-search{width:50%;height:2.25rem;display:block;position:absolute;top:.5rem;left:.5rem;box-shadow:0 1px 4px #0000004d}girafe-selection-window{z-index:100;width:400px;height:240px;position:absolute;bottom:1rem;right:1rem}
38
38
  </style>
39
39
  <style>${this.customStyle}</style>
40
- <girafe-map></girafe-map>`;
40
+ <girafe-map></girafe-map>
41
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
41
42
  };
42
43
  isInitialized = false;
43
44
  constructor() {
@@ -368,7 +369,7 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
368
369
  }
369
370
  async lineToMarker(line, columnIndexes, legacy) {
370
371
  const columns = line.split('\t');
371
- const getColumOrUndefined = (index) => index ? columns[index]?.trim() : undefined;
372
+ const getColumOrUndefined = (index) => (index ? columns[index]?.trim() : undefined);
372
373
  const coords = splitTrimAndConvertToNumber(columns[columnIndexes.pointIndex]);
373
374
  const imageUrl = columnIndexes.iconIndex ? columns[columnIndexes.iconIndex]?.trim() : undefined;
374
375
  if (!coords || coords.length < 2 || !imageUrl || Number.isNaN(coords[0]) || Number.isNaN(coords[1])) {
@@ -392,15 +393,13 @@ export default class GeoGirafeApi extends GirafeHTMLElement {
392
393
  }
393
394
  const tooltipTitle = getColumOrUndefined(columnIndexes.titleIndex);
394
395
  const tooltipContent = getColumOrUndefined(columnIndexes.descriptionIndex);
395
- const tooltip = tooltipTitle && tooltipContent ?
396
- { title: tooltipTitle, content: DOMPurify.sanitize(tooltipContent) } :
397
- undefined;
396
+ const tooltip = tooltipTitle && tooltipContent ? { title: tooltipTitle, content: DOMPurify.sanitize(tooltipContent) } : undefined;
398
397
  return {
399
398
  position: [coords[0], coords[1]],
400
399
  imageUrl,
401
400
  size,
402
401
  offset,
403
- tooltip,
402
+ tooltip
404
403
  };
405
404
  }
406
405
  async initialize() {
@@ -176,6 +176,11 @@
176
176
  "Failed to update feature": "Objekt konnte nicht aktualisiert werden",
177
177
  "Feature ID": "Objekt-ID",
178
178
  "features": "Elemente",
179
+ "feedback-button-tip": "Feedback geben",
180
+ "feedback-negative": "Nein",
181
+ "feedback-positive": "Ja",
182
+ "feedback-question-default": "Gefällt Ihnen diese Komponente?",
183
+ "feedback-thankyou-default": "Vielen Dank für Ihr Feedback!",
179
184
  "File _fileName_ is not supported": "Datei _fileName_ wird nicht unterstützt",
180
185
  "File from": "Datei vom",
181
186
  "Files _fileNames_ are not supported": "Dateien '_fileNames_' werden nicht unterstützt",
@@ -178,6 +178,11 @@
178
178
  "Failed to update feature": "Failed to update feature",
179
179
  "Feature ID": "Feature ID",
180
180
  "features": "features",
181
+ "feedback-button-tip": "Give feedback",
182
+ "feedback-negative": "No",
183
+ "feedback-positive": "Yes",
184
+ "feedback-question-default": "Do you like this Component?",
185
+ "feedback-thankyou-default": "Thank you for your feedback!",
181
186
  "File _fileName_ is not supported": "File _fileName_ is not supported",
182
187
  "File from": "File from",
183
188
  "Files _fileNames_ are not supported": "Files _fileNames_ are not supported",
@@ -245,6 +250,8 @@
245
250
  "help-themes": "Explore available topics. Once selected, the associated maps load automatically.",
246
251
  "help-user-preferences": "Manage your user preferences, like language, display mode and map options.",
247
252
  "Hide Swiper": "Hide Swiper",
253
+ "highlight-all": "Highlight all",
254
+ "highlight-per-layer": "Highlight per layer",
248
255
  "info": "Info",
249
256
  "Information without public faith": "Information without public faith",
250
257
  "Intensity": "Intensity",
@@ -455,8 +462,6 @@
455
462
  "selectFillColor": "Selection fill color",
456
463
  "selectHighlightFillColor": "Selection highlight fill color",
457
464
  "selectHighlightMode": "Selection highlight mode",
458
- "highlight-all": "Highlight all",
459
- "highlight-per-layer": "Highlight per layer",
460
465
  "selectHighlightStrokeColor": "Selection highlight stroke color",
461
466
  "Selection": "Selection",
462
467
  "selection-mode": "Selection Mode",
@@ -176,6 +176,11 @@
176
176
  "Failed to update feature": "Échec de la mise à jour de l'entité",
177
177
  "Feature ID": "ID d'entité",
178
178
  "features": "caractéristiques",
179
+ "feedback-button-tip": "Donner un avis",
180
+ "feedback-negative": "Non",
181
+ "feedback-positive": "Oui",
182
+ "feedback-question-default": "Aimez-vous ce composant ?",
183
+ "feedback-thankyou-default": "Merci pour votre commentaire !",
179
184
  "File _fileName_ is not supported": "Le fichier _fileName_ n'est pas supporté",
180
185
  "File from": "Fichier de",
181
186
  "Files _fileNames_ are not supported": "Les fichiers _fileNames_ ne sont pas supportés",
@@ -176,6 +176,11 @@
176
176
  "Failed to update feature": "Non è stato possibile aggiornare l'elemento",
177
177
  "Feature ID": "ID elemento",
178
178
  "features": "funzionalità",
179
+ "feedback-button-tip": "Invia feedback",
180
+ "feedback-negative": "No",
181
+ "feedback-positive": "Sì",
182
+ "feedback-question-default": "Ti piace questo componente?",
183
+ "feedback-thankyou-default": "Grazie per il tuo feedback!",
179
184
  "File _fileName_ is not supported": "Il file _fileName_ non è supportato",
180
185
  "File from": "File da",
181
186
  "Files _fileNames_ are not supported": "I file _fileNames_ non sono supportati",
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" viewBox="0 0 24 24"><title>ic_fluent_comment_add_24_regular</title><path fill="#212121" fill-rule="nonzero" d="M12.022 3a6.5 6.5 0 0 0-.709 1.5H5.25A1.75 1.75 0 0 0 3.5 6.25v8.5c0 .966.784 1.75 1.75 1.75h2.249v3.75l5.015-3.75h6.236a1.75 1.75 0 0 0 1.75-1.75l.001-2.483a6.5 6.5 0 0 0 1.5-1.077L22 14.75A3.25 3.25 0 0 1 18.75 18h-5.738L8 21.75a1.25 1.25 0 0 1-1.999-1V18h-.75A3.25 3.25 0 0 1 2 14.75v-8.5A3.25 3.25 0 0 1 5.25 3zM17.5 1a5.5 5.5 0 1 1 0 11 5.5 5.5 0 0 1 0-11m0 1.5-.09.008a.5.5 0 0 0-.402.402L17 3l-.001 3H14l-.09.008a.5.5 0 0 0-.402.402l-.008.09.008.09a.5.5 0 0 0 .402.402L14 7h2.999L17 10l.008.09a.5.5 0 0 0 .402.402l.09.008.09-.008a.5.5 0 0 0 .402-.402L18 10l-.001-3H21l.09-.008a.5.5 0 0 0 .402-.402l.008-.09-.008-.09a.5.5 0 0 0-.402-.402L21 6h-3.001L18 3l-.008-.09a.5.5 0 0 0-.402-.402z"/></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_comment_24_regular</title><path fill="#212121" fill-rule="nonzero" d="M5.25 18A3.25 3.25 0 0 1 2 14.75v-8.5A3.25 3.25 0 0 1 5.25 3h13.5A3.25 3.25 0 0 1 22 6.25v8.5A3.25 3.25 0 0 1 18.75 18h-5.738L8 21.75a1.25 1.25 0 0 1-1.999-1V18zm7.264-1.5h6.236a1.75 1.75 0 0 0 1.75-1.75v-8.5a1.75 1.75 0 0 0-1.75-1.75H5.25A1.75 1.75 0 0 0 3.5 6.25v8.5c0 .966.784 1.75 1.75 1.75h2.249v3.75z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" fill="none" viewBox="0 0 24 24"><path fill="#212121" d="M16.5 17.985c0 2.442-1.14 4.198-3.007 4.198-.975 0-1.341-.542-1.69-1.795l-.207-.772q-.152-.539-.527-1.831a.3.3 0 0 0-.03-.065l-2.866-4.486a5.9 5.9 0 0 0-2.855-2.326l-.473-.182A2.75 2.75 0 0 1 3.13 7.635l.404-2.086A3.25 3.25 0 0 1 5.95 3.01l7.628-1.87a4.75 4.75 0 0 1 5.733 3.44l1.415 5.55a3.25 3.25 0 0 1-3.15 4.052h-1.822c.496 1.633.746 2.893.746 3.802M4.6 7.92a1.25 1.25 0 0 0 .78 1.406l.474.18a7.4 7.4 0 0 1 3.582 2.92l2.867 4.486q.136.212.205.455l.552 1.92.212.791c.14.488.21.605.22.605.868 0 1.507-.983 1.507-2.698 0-.885-.326-2.336-.984-4.315a.75.75 0 0 1 .711-.987h2.85a1.75 1.75 0 0 0 1.696-2.182l-1.415-5.55a3.25 3.25 0 0 0-3.923-2.353l-7.628 1.87a1.75 1.75 0 0 0-1.301 1.366z"/></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" fill="none" viewBox="0 0 24 24"><path fill="#212121" d="M16.5 5.202c0-2.442-1.14-4.198-3.007-4.198-1.026 0-1.378.601-1.746 2-.075.288-.112.429-.151.567q-.152.539-.527 1.831a.3.3 0 0 1-.03.065L8.174 9.953a5.9 5.9 0 0 1-2.855 2.327l-.473.18a2.75 2.75 0 0 0-1.716 3.092l.404 2.087a3.25 3.25 0 0 0 2.417 2.537l7.628 1.87a4.75 4.75 0 0 0 5.733-3.44l1.415-5.55a3.25 3.25 0 0 0-3.15-4.052h-1.822c.496-1.633.746-2.893.746-3.802M4.6 15.267a1.25 1.25 0 0 1 .78-1.405l.474-.182a7.4 7.4 0 0 0 3.582-2.92l2.867-4.485q.136-.212.205-.455.378-1.297.53-1.842c.044-.154.085-.31.159-.593.19-.722.283-.881.295-.881.868 0 1.507.984 1.507 2.698 0 .885-.326 2.336-.984 4.315a.75.75 0 0 0 .711.987h2.85q.22 0 .432.054a1.75 1.75 0 0 1 1.264 2.128l-1.415 5.55a3.25 3.25 0 0 1-3.923 2.353l-7.628-1.87a1.75 1.75 0 0 1-1.301-1.366z"/></svg>
@@ -11,6 +11,7 @@ declare abstract class GirafeHTMLElement extends HTMLElement {
11
11
  protected displayStyle?: string;
12
12
  private timeoutId?;
13
13
  protected rendered: boolean;
14
+ protected feedbackTemplateHtml?: string;
14
15
  private readonly callbacks;
15
16
  private readonly unsafeCache;
16
17
  private _context?;
@@ -46,6 +47,7 @@ declare abstract class GirafeHTMLElement extends HTMLElement {
46
47
  * Render the component's template.
47
48
  */
48
49
  protected render(): void;
50
+ insertFeedbackTemplate(template: string): void;
49
51
  /**
50
52
  * Re-Render the component.
51
53
  * The method should be called when the component
@@ -7,6 +7,7 @@ class GirafeHTMLElement extends HTMLElement {
7
7
  displayStyle;
8
8
  timeoutId;
9
9
  rendered = false;
10
+ feedbackTemplateHtml;
10
11
  callbacks = [];
11
12
  unsafeCache = new Map();
12
13
  _context;
@@ -99,6 +100,9 @@ class GirafeHTMLElement extends HTMLElement {
99
100
  console.warn(`Cannot render: no template has been defined for component ${this.name}.`);
100
101
  }
101
102
  }
103
+ insertFeedbackTemplate(template) {
104
+ this.feedbackTemplateHtml = template;
105
+ }
102
106
  /**
103
107
  * Re-Render the component.
104
108
  * The method should be called when the component
@@ -119,10 +119,11 @@ async function getHtmlCode(currentFilename, relativeHtmlPath, styleCode) {
119
119
  }
120
120
  });
121
121
  const customStyleCode = '<style>${this.customStyle}</style>';
122
+ const feedbackHtmlCode = "${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}";
122
123
  htmlCode = `
123
124
  protected override templateUrl: string | null = null;
124
125
  protected override styleUrls: string[] | null = null;
125
- template = () => { return uHtml\`${styleCode}\n${customStyleCode}\n${htmlCode}\`; }`;
126
+ template = () => { return uHtml\`${styleCode}\n${customStyleCode}\n${htmlCode}\n${feedbackHtmlCode}\`; }`;
126
127
  return htmlCode;
127
128
  } catch (error) {
128
129
  console.error(`Error reading html file for ${currentFilename}: ${error}`);
@@ -11,7 +11,8 @@ class AboutComponent extends GirafeHTMLElement {
11
11
  .panel{color:var(--text-color)}.panel>div{padding:1rem}img.logo{filter:var(--svg-filter);opacity:.8;height:4rem}.list{flex-direction:column;margin-top:1rem;display:flex}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div class="panel"><div><img class="logo" alt="geogirafe-logo" src="images/logo/horizontal_black.svg"><div class="list"><div class="elem"><span i18n="Version">Version</span> : ${this.version}</div><div class="elem"><span i18n="Build">Build</span> : ${this.build}</div><div class="elem"><span i18n="Date">Date</span> : ${this.date}</div></div><div class="list"><div class="elem"><span i18n="Source">Source</span>: <a href="https://gitlab.com/geogirafe/gg-viewer" i18n="GitLab" rel="noopener" target="_blank">GitLab</a></div><div class="elem"><span i18n="Documentation">Documentation</span>: <a href="https://doc.geomapfish.dev" rel="noopener" target="_blank">https://doc.geomapfish.dev</a></div></div></div></div>`;
14
+ <div class="panel"><div><img class="logo" alt="geogirafe-logo" src="images/logo/horizontal_black.svg"><div class="list"><div class="elem"><span i18n="Version">Version</span> : ${this.version}</div><div class="elem"><span i18n="Build">Build</span> : ${this.build}</div><div class="elem"><span i18n="Date">Date</span> : ${this.date}</div></div><div class="list"><div class="elem"><span i18n="Source">Source</span>: <a href="https://gitlab.com/geogirafe/gg-viewer" i18n="GitLab" rel="noopener" target="_blank">GitLab</a></div><div class="elem"><span i18n="Documentation">Documentation</span>: <a href="https://doc.geogirafe.org" rel="noopener" target="_blank">https://doc.geogirafe.org</a></div></div></div></div>
15
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
15
16
  };
16
17
  isPanelVisible = false;
17
18
  panelTitle = 'about-panel';
@@ -10,7 +10,8 @@ class AddBookmarkComponent extends GirafeHTMLElement {
10
10
  *{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-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,.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}.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}
11
11
  </style>
12
12
  <style>${this.customStyle}</style>
13
- <div class="add-bookmark"><button tip="add_bookmark" class="gg-icon-button gg-big" onclick="${() => this.addBookmark()}"><img alt="add-icon" src="icons/bookmark-add.svg" ?hidden="${this.awaitingBookmarkLink}"> <img ?hidden="${!this.awaitingBookmarkLink}" loading="eager" src="icons/progress.svg" class="gg-spin gg-small" alt="${this.context.i18nManager.getTranslation('Loading')}"></button></div>`;
13
+ <div class="add-bookmark"><button tip="add_bookmark" class="gg-icon-button gg-big" onclick="${() => this.addBookmark()}"><img alt="add-icon" src="icons/bookmark-add.svg" ?hidden="${this.awaitingBookmarkLink}"> <img ?hidden="${!this.awaitingBookmarkLink}" loading="eager" src="icons/progress.svg" class="gg-spin gg-small" alt="${this.context.i18nManager.getTranslation('Loading')}"></button></div>
14
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
14
15
  };
15
16
  isMac = navigator.userAgent.includes('Mac');
16
17
  awaitingBookmarkLink = false;
@@ -23,7 +23,8 @@ class AdvancedFilterComponent extends GirafeHTMLElement {
23
23
  #content{background:var(--bkg-color);color:var(--text-color);flex-direction:column;gap:1rem;margin:0;padding:1rem;display:flex}.filter-element-container{flex-direction:column;gap:1.5rem;display:flex}.filter-element{background-color:color-mix(in srgb, var(--bkg-color-grad1) 30%, transparent);box-shadow:var(--bx-shdw);border-radius:3px;flex-direction:column;gap:.5rem;padding:.5rem;display:flex;position:relative}.filter-title{text-overflow:ellipsis;white-space:nowrap;padding-right:2rem;font-size:1.2rem}.filter-expression{padding-right:1.5rem;font-family:monospace,Arial,sans-serif;font-size:.85rem}.gg-label{background-color:#0000}.layer-select-container{flex-direction:column;display:flex}.text-ellipsis{text-overflow:ellipsis;overflow:hidden}.filter-condition-container{flex-direction:column;gap:.5rem;display:flex}.filter-condition{background-color:var(--bkg-color);box-shadow:var(--bx-shdw);border-radius:3px;flex-direction:column;margin-left:.5rem;padding:.5rem;display:flex}.value-inputs{gap:.5rem;display:flex}.value-inputs>input{width:100%}.action-btn{float:left;width:fit-content}.apply-btn{margin-top:1rem}.remove-btn{align-self:flex-end;margin:-.25rem -.25rem 0 0;font-size:1.25rem;position:absolute}ul.value-choices{border:var(--app-standard-border);max-height:10rem;margin:0;padding:0 0 .25em;overflow-y:auto}ul.value-choices li{align-items:flex-start;gap:.25em;display:flex}ul.value-choices li label{flex:1}.footer-container{display:flex}.component-loading{margin-left:auto;margin-right:auto}.layer-loading{margin-left:auto;margin-right:.5rem}.loader{box-sizing:border-box;border:3px solid var(--text-color);opacity:.5;border-bottom-color:#0000;border-radius:50%;align-self:center;width:25px;height:25px;animation:1s linear infinite rotation;display:inline-block}@keyframes rotation{0%{transform:rotate(0)}to{transform:rotate(360deg)}}
24
24
  </style>
25
25
  <style>${this.customStyle}</style>
26
- <div id="content"><div class="filter-element-container">${this.layerFilterElements.map((filterElement) => uHtml `<div class="filter-element" data-id="${filterElement.id}"><div class="filter-title text-ellipsis">${filterElement.title}</div><button class="gg-icon-button gg-small remove-btn" onclick="${() => this.onFilterRemoved(filterElement)}"><img alt="remove-icon" src="icons/close.svg"></button><div class="layer-select-container"><label class="gg-label" i18n="Layer selection" for="${'layer-select-' + filterElement.id}">Layer selection</label> <select id="${'layer-select-' + filterElement.id}" class="gg-select text-ellipsis" onchange="${(e) => this.onLayerChanged(filterElement, e)}"><option value="" i18n="${this.layers.length === 0 ? 'No layer available' : 'Select a layer'}" ?selected="${filterElement.layer === undefined}" disabled="disabled">${this.layers.length === 0 ? 'No layer available' : 'Select a layer'}</option>${this.layers.map(layer => uHtml `<option value="${layer.id}" i18n="${this.getLayerDisplayName(layer)}" ?selected="${filterElement.layer?.id === layer.id}" ?disabled="${!this.isLayerSelectable(filterElement, layer)}">${this.getLayerDisplayName(layer)}</option>`)}</select></div><div class="${filterElement.conditions ? 'filter-condition-container' : 'hidden'}">${filterElement.conditions.map((condition) => uHtml `<div class="filter-condition"><button class="gg-icon-button gg-small remove-btn" onclick="${() => this.onConditionRemoved(filterElement, condition)}"><img alt="remove-icon" src="icons/close.svg"></button> ${condition.applied ? uHtml `<div class="filter-expression">${condition.toText()}</div>` : uHtml ` ${filterElement.isLogicalOperatorSelectorVisible(condition) ? uHtml ` <label class="gg-label" i18n="Logic" for="${'attribute-select-' + condition.id}">Logic</label> <select id="${'logic-select-' + condition.id}" class="gg-select text-ellipsis" onchange="${(e) => this.onLogicalOperatorChanged(condition, e)}">${filterElement.availableLogicalOperators.map((lop) => uHtml `<option value="${lop.operator}" i18n="${lop.displayName}" ?selected="${condition.logicalOperator === lop.operator}">${lop.displayName}</option>`)}</select> ` : ''} <label class="gg-label" i18n="Attribute" for="${'attribute-select-' + condition.id}">Attribute</label> <select id="${'attribute-select-' + condition.id}" class="gg-select text-ellipsis" onchange="${(e) => this.onAttributeChanged(filterElement, condition, e)}"><option value="" i18n="Select an attribute" ?selected="${condition.attribute === undefined}" disabled="disabled">Select an attribute</option>${filterElement.attributes.map((attr) => uHtml `<option value="${attr.name}" ?selected="${condition.attribute?.name === attr.name}">${filterElement.getAttributeDisplayName(attr)}</option>`)}</select> <label class="gg-label" i18n="Operator" for="${'operator-select-' + condition.id}">Operator</label> <select id="${'operator-select-' + condition.id}" class="gg-select text-ellipsis" disabled="${!condition.isOperatorSelectorEnabled()}" onchange="${(e) => this.onOperatorChanged(condition, e)}"><option value="" i18n="Select an operator" ?selected="${condition.operator === undefined}" disabled="disabled">Select an operator</option>${(condition.availableOperators ?? []).map((op) => uHtml `<option value="${op.operator}" i18n="${op.displayName}" ?selected="${condition.operator === op.operator}" ?disabled="${!condition.isSpatialOperatorEnabled(op.operator)}">${op.displayName}</option>`)}</select> ${condition.isValueInputVisible() ? uHtml ` <label class="gg-label" i18n="Value" for="${'value-input-' + condition.id}">Value</label><div class="value-inputs"><input id="${'value-input-' + condition.id}" type="${condition.attributeInputType}" class="gg-input" disabled="${condition.operator ? '' : 'disabled'}" value="${condition.value}" oninput="${(e) => this.onValueChanged(condition, e)}"> ${condition.isValue2InputVisible() ? uHtml ` <input type="${condition.attributeInputType}" class="gg-input" value="${condition.value2}" oninput="${(e) => this.onValue2Changed(condition, e)}"> ` : ''}</div>` : ''}<div class="${condition.isGeometryToolbarVisible() ? '' : 'hidden'}"><label class="gg-label" i18n="Draw geometry" for="${'value-input-' + condition.id}">Draw geometry</label><girafe-drawing-toolbar statelocation="${FilterConditionElement.drawingStateLocation}"></girafe-drawing-toolbar></div>${condition.isChoicesListVisible() ? uHtml ` <label class="gg-label" i18n="Possible values" for="${'choice-' + condition.id}">Possible values</label><ul id="${'choice-' + condition.id}" class="value-choices">${(condition.choices ?? []).map((choice) => uHtml `<li><input id="${'choice-' + condition.id + '-' + choice}" type="checkbox" class="gg-checkbox" value="${choice}" onchange="${(e) => this.onChoiceChanged(condition, e)}"> <label for="${'choice-' + condition.id + '-' + choice}" i18n="${choice}">${choice}</label></li>`)}</ul>` : ''} <button class="gg-button action-btn apply-btn" disabled="${!condition.isValid()}" onclick="${() => this.onConditionApplied(filterElement, condition)}" i18n="Apply">Apply</button> `}</div>`)}</div><div class="footer-container"><button class="${filterElement.layer ? 'gg-button action-btn' : 'hidden'}" disabled="${this.hasNonAppliedFilters()}" onclick="${() => this.onConditionAdded(filterElement)}" i18n="Add condition">Add condition</button><div class="layer-loading"><span class="${filterElement.layer && this.layerIsRefreshing.get(filterElement.layer.id) ? 'loader' : 'hidden'}"></span></div></div></div>`)}</div><div class="component-loading"><span class="${this.loading ? 'loader' : 'hidden'}"></span></div><div class="filter-actions"><button class="gg-button gaction-btn" disabled="${this.hasNonAppliedFilters() || this.loading}" onclick="${() => this.onFilterAdded()}" i18n="New Filter">New Filter</button></div></div>`;
26
+ <div id="content"><div class="filter-element-container">${this.layerFilterElements.map((filterElement) => uHtml `<div class="filter-element" data-id="${filterElement.id}"><div class="filter-title text-ellipsis">${filterElement.title}</div><button class="gg-icon-button gg-small remove-btn" onclick="${() => this.onFilterRemoved(filterElement)}"><img alt="remove-icon" src="icons/close.svg"></button><div class="layer-select-container"><label class="gg-label" i18n="Layer selection" for="${'layer-select-' + filterElement.id}">Layer selection</label> <select id="${'layer-select-' + filterElement.id}" class="gg-select text-ellipsis" onchange="${(e) => this.onLayerChanged(filterElement, e)}"><option value="" i18n="${this.layers.length === 0 ? 'No layer available' : 'Select a layer'}" ?selected="${filterElement.layer === undefined}" disabled="disabled">${this.layers.length === 0 ? 'No layer available' : 'Select a layer'}</option>${this.layers.map(layer => uHtml `<option value="${layer.id}" i18n="${this.getLayerDisplayName(layer)}" ?selected="${filterElement.layer?.id === layer.id}" ?disabled="${!this.isLayerSelectable(filterElement, layer)}">${this.getLayerDisplayName(layer)}</option>`)}</select></div><div class="${filterElement.conditions ? 'filter-condition-container' : 'hidden'}">${filterElement.conditions.map((condition) => uHtml `<div class="filter-condition"><button class="gg-icon-button gg-small remove-btn" onclick="${() => this.onConditionRemoved(filterElement, condition)}"><img alt="remove-icon" src="icons/close.svg"></button> ${condition.applied ? uHtml `<div class="filter-expression">${condition.toText()}</div>` : uHtml ` ${filterElement.isLogicalOperatorSelectorVisible(condition) ? uHtml ` <label class="gg-label" i18n="Logic" for="${'attribute-select-' + condition.id}">Logic</label> <select id="${'logic-select-' + condition.id}" class="gg-select text-ellipsis" onchange="${(e) => this.onLogicalOperatorChanged(condition, e)}">${filterElement.availableLogicalOperators.map((lop) => uHtml `<option value="${lop.operator}" i18n="${lop.displayName}" ?selected="${condition.logicalOperator === lop.operator}">${lop.displayName}</option>`)}</select> ` : ''} <label class="gg-label" i18n="Attribute" for="${'attribute-select-' + condition.id}">Attribute</label> <select id="${'attribute-select-' + condition.id}" class="gg-select text-ellipsis" onchange="${(e) => this.onAttributeChanged(filterElement, condition, e)}"><option value="" i18n="Select an attribute" ?selected="${condition.attribute === undefined}" disabled="disabled">Select an attribute</option>${filterElement.attributes.map((attr) => uHtml `<option value="${attr.name}" ?selected="${condition.attribute?.name === attr.name}">${filterElement.getAttributeDisplayName(attr)}</option>`)}</select> <label class="gg-label" i18n="Operator" for="${'operator-select-' + condition.id}">Operator</label> <select id="${'operator-select-' + condition.id}" class="gg-select text-ellipsis" disabled="${!condition.isOperatorSelectorEnabled()}" onchange="${(e) => this.onOperatorChanged(condition, e)}"><option value="" i18n="Select an operator" ?selected="${condition.operator === undefined}" disabled="disabled">Select an operator</option>${(condition.availableOperators ?? []).map((op) => uHtml `<option value="${op.operator}" i18n="${op.displayName}" ?selected="${condition.operator === op.operator}" ?disabled="${!condition.isSpatialOperatorEnabled(op.operator)}">${op.displayName}</option>`)}</select> ${condition.isValueInputVisible() ? uHtml ` <label class="gg-label" i18n="Value" for="${'value-input-' + condition.id}">Value</label><div class="value-inputs"><input id="${'value-input-' + condition.id}" type="${condition.attributeInputType}" class="gg-input" disabled="${condition.operator ? '' : 'disabled'}" value="${condition.value}" oninput="${(e) => this.onValueChanged(condition, e)}"> ${condition.isValue2InputVisible() ? uHtml ` <input type="${condition.attributeInputType}" class="gg-input" value="${condition.value2}" oninput="${(e) => this.onValue2Changed(condition, e)}"> ` : ''}</div>` : ''}<div class="${condition.isGeometryToolbarVisible() ? '' : 'hidden'}"><label class="gg-label" i18n="Draw geometry" for="${'value-input-' + condition.id}">Draw geometry</label><girafe-drawing-toolbar statelocation="${FilterConditionElement.drawingStateLocation}"></girafe-drawing-toolbar></div>${condition.isChoicesListVisible() ? uHtml ` <label class="gg-label" i18n="Possible values" for="${'choice-' + condition.id}">Possible values</label><ul id="${'choice-' + condition.id}" class="value-choices">${(condition.choices ?? []).map((choice) => uHtml `<li><input id="${'choice-' + condition.id + '-' + choice}" type="checkbox" class="gg-checkbox" value="${choice}" onchange="${(e) => this.onChoiceChanged(condition, e)}"> <label for="${'choice-' + condition.id + '-' + choice}" i18n="${choice}">${choice}</label></li>`)}</ul>` : ''} <button class="gg-button action-btn apply-btn" disabled="${!condition.isValid()}" onclick="${() => this.onConditionApplied(filterElement, condition)}" i18n="Apply">Apply</button> `}</div>`)}</div><div class="footer-container"><button class="${filterElement.layer ? 'gg-button action-btn' : 'hidden'}" disabled="${this.hasNonAppliedFilters()}" onclick="${() => this.onConditionAdded(filterElement)}" i18n="Add condition">Add condition</button><div class="layer-loading"><span class="${filterElement.layer && this.layerIsRefreshing.get(filterElement.layer.id) ? 'loader' : 'hidden'}"></span></div></div></div>`)}</div><div class="component-loading"><span class="${this.loading ? 'loader' : 'hidden'}"></span></div><div class="filter-actions"><button class="gg-button gaction-btn" disabled="${this.hasNonAppliedFilters() || this.loading}" onclick="${() => this.onFilterAdded()}" i18n="New Filter">New Filter</button></div></div>
27
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
27
28
  };
28
29
  isPanelVisible = false;
29
30
  panelTitle = 'advanced-filter-panel';
@@ -11,7 +11,8 @@ export default class AlignNorthButtonMobile extends GirafeHTMLElement {
11
11
  #north-button,#north-button:focus{background-color:#fff;outline:none}.black-to-red{filter:invert(27%)sepia(50%)saturate(3000%)brightness(95%)contrast()}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <link rel="stylesheet" href="styles/common.mobile.css"><button id="north-button" class="girafe-button-big" tip="Theme selection" onpointerup="${(e) => this.alignNorth(e)}"><img id="compass-icon" alt="menu-icon" src="icons/compass.svg"></button>`;
14
+ <link rel="stylesheet" href="styles/common.mobile.css"><button id="north-button" class="girafe-button-big" tip="Theme selection" onpointerup="${(e) => this.alignNorth(e)}"><img id="compass-icon" alt="menu-icon" src="icons/compass.svg"></button>
15
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
15
16
  };
16
17
  constructor() {
17
18
  super('align-north-button-mobile');
@@ -11,7 +11,8 @@ export default class OauthComponent extends GirafeHTMLElement {
11
11
  .container{border-right:var(--app-standard-border);flex-direction:row;align-items:center;display:flex}.name{text-align:left;flex-direction:column;display:flex}.user-avatar{--svg-filter:none}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLogoutClick()}"><img alt="menu-icon" src="${this.userIconUrl ?? 'icons/user.svg'}" class="${this.userIconUrl ? 'user-avatar' : ''}"><div class="name"><span class="${this.state.oauth.userInfo?.given_name ? '' : 'hidden'}">${this.state.oauth.userInfo?.given_name + ' ' + this.state.oauth.userInfo?.family_name}</span> <span>${this.getDisplayName()}</span></div></button></div></div>`;
14
+ <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLogoutClick()}"><img alt="menu-icon" src="${this.userIconUrl ?? 'icons/user.svg'}" class="${this.userIconUrl ? 'user-avatar' : ''}"><div class="name"><span class="${this.state.oauth.userInfo?.given_name ? '' : 'hidden'}">${this.state.oauth.userInfo?.given_name + ' ' + this.state.oauth.userInfo?.family_name}</span> <span>${this.getDisplayName()}</span></div></button></div></div>
15
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
15
16
  };
16
17
  userIconUrl;
17
18
  constructor(name = 'oauth') {
@@ -11,7 +11,8 @@ export default class MobileOauthComponent extends OauthComponent {
11
11
  .container{filter:drop-shadow(0 4px 7px #0004382c);background-color:#fff;border-radius:8px;flex-direction:column;padding:1em;display:flex}.container:active{background-color:#c6ceda}.container>button{background:0 0;border:none;flex-direction:column;flex:1;justify-content:center;align-items:center;display:flex}.container>button>img{opacity:.7;width:25%;padding-bottom:1em}.container>button>span{color:#3f68a7;flex:1;justify-content:center;align-items:center;font-size:1.2em;font-weight:600;display:flex}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLogoutClick()}"><img alt="menu-icon" src="${this.userIconUrl ?? 'icons/user.svg'}" class="${this.userIconUrl ? 'user-avatar' : ''}"><div class="name"><span class="${this.state.oauth.userInfo?.given_name ? '' : 'hidden'}">${this.state.oauth.userInfo?.given_name + ' ' + this.state.oauth.userInfo?.family_name}</span> <span>${this.getDisplayName()}</span></div></button></div></div>`;
14
+ <div class="${this.context.configManager.Config.oauth || this.context.configManager.Config.gmfauth ? '' : 'hidden'}"><div class="${this.state.oauth.status === 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLoginClick()}"><img alt="menu-icon" src="icons/user.svg"> <span i18n="Login">Login</span></button></div><div class="${this.state.oauth.status !== 'loggedIn' ? 'hidden' : 'container'}"><button class="gg-icon-button gg-medium-withtext" onclick="${() => this.onLogoutClick()}"><img alt="menu-icon" src="${this.userIconUrl ?? 'icons/user.svg'}" class="${this.userIconUrl ? 'user-avatar' : ''}"><div class="name"><span class="${this.state.oauth.userInfo?.given_name ? '' : 'hidden'}">${this.state.oauth.userInfo?.given_name + ' ' + this.state.oauth.userInfo?.family_name}</span> <span>${this.getDisplayName()}</span></div></button></div></div>
15
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
15
16
  };
16
17
  constructor() {
17
18
  super('oauth-mobile');
@@ -13,7 +13,8 @@ class BasemapComponent extends GirafeHTMLElement {
13
13
  .basemap-button{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;box-shadow:var(--bx-shdw);border-width:2px;border-radius:4px;outline:0;margin:0;padding:5px;display:inline-flex}#container{flex-direction:column;width:max-content;display:inline-flex}.basemap-icon{background:var(--svg-legend-bkg);filter:var(--svg-map-filter)}.active-basemap{background-color:var(--bkg-color-grad2)!important}.opacity-slider{flex-direction:row;height:20px;padding:0 5px;display:flex}.opacity-slider img{height:16px;position:relative;top:2px}.opacity-slider input[type=range]{flex-grow:1}.basemap-container{flex-direction:column;display:flex}.basemap-container button{color:var(--text-color);background-color:#0000;border:none;flex-direction:row;flex-grow:1;display:flex}.basemap-container button img{height:2rem;margin:.3rem}.basemap-container button span{height:2rem;margin:.3rem;line-height:2rem}.basemap-container:hover{background-color:var(--bkg-color-grad1)}.basemaps-with-opacity-separator{border-top:1px solid var(--bkg-color-grad2);height:1px;margin:6px 8px}
14
14
  </style>
15
15
  <style>${this.customStyle}</style>
16
- <girafe-menu-button direction="up-right" id="basemap-menu-button"><button slot="menu-button" class="basemap-button" tip="Select basemap"><img class="basemap-icon" alt="menu-icon" src="images/button_basemaps.webp"></button><div slot="menu-content" id="container">${Object.values(this.state.basemaps).filter(basemap => basemap.opacity == -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button></div>`)}<div class="basemaps-with-opacity-separator"></div>${Object.values(this.state.basemaps).filter(basemap => basemap.opacity != -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button><div class="opacity-slider"><img alt="Control opacity" src="icons/opacity.svg"> <input type="range" min="0" max="1" step="0.01" class="slider" value="${basemap.opacity}" onkeydown="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onclick="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onchange="${(e) => this.changeBasemapOpacity(basemap, e)}"></div></div>`)}</div></girafe-menu-button>`;
16
+ <girafe-menu-button direction="up-right" id="basemap-menu-button"><button slot="menu-button" class="basemap-button" tip="Select basemap"><img class="basemap-icon" alt="menu-icon" src="images/button_basemaps.webp"></button><div slot="menu-content" id="container">${Object.values(this.state.basemaps).filter(basemap => basemap.opacity == -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button></div>`)}<div class="basemaps-with-opacity-separator"></div>${Object.values(this.state.basemaps).filter(basemap => basemap.opacity != -1).map(basemap => uHtmlFor(basemap, basemap.id) `<div class="${this.determineClassnames(basemap)}"><button onclick="${() => this.changeBasemap(basemap)}"><img class="basemap-icon" alt="basemap-icon" src="${basemap.thumbnail}"> <span i18n="${basemap.name}">${basemap.name}</span></button><div class="opacity-slider"><img alt="Control opacity" src="icons/opacity.svg"> <input type="range" min="0" max="1" step="0.01" class="slider" value="${basemap.opacity}" onkeydown="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onclick="${(e) => { e.preventDefault(); e.stopPropagation(); }}" onchange="${(e) => this.changeBasemapOpacity(basemap, e)}"></div></div>`)}</div></girafe-menu-button>
17
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
17
18
  };
18
19
  constructor() {
19
20
  super('basemap');
@@ -11,7 +11,8 @@ class ContactComponent extends GirafeHTMLElement {
11
11
  #content{background:var(--bkg-color);color:var(--text-color);flex-direction:column;margin:0;padding:1rem;display:flex}label,input,select,textarea{flex-grow:1;font-size:.9rem}.gg-input,.gg-select{margin-bottom:1rem}.mail-contact{margin-top:2rem;margin-bottom:2rem}
12
12
  </style>
13
13
  <style>${this.customStyle}</style>
14
- <div id="panel"><div id="content"><label for="email" i18n="Your email (optional)" class="gg-label">Your email (optional)</label> <input id="email" placeholder="you@example.com" class="gg-input"> <label for="reason" i18n="Why are you contacting us?" class="gg-label">Why are you contacting us?</label> <select id="reason" class="gg-select"><option value="" disabled="disabled" selected="selected">-</option>${this.context.configManager.Config.contact?.reasons.map((reason) => uHtml `<option i18n="${reason}" value="${reason}">${reason}</option>`)}</select> <label for="message" i18n="Your message" class="gg-label">Your message</label> <textarea id="message" class="gg-input gg-textarea"></textarea> <label for="shortlink" i18n="The following link will be sent with your message. It contains your current configuration and will help us to understand your problem." class="gg-label">The following link will be sent with your message. It contains your current configuration and will help us to understand your problem.</label> <input id="shortlink" disabled="disabled" value="${this.shortUrl}" class="gg-input"><div class="mail-contact"><span i18n="You can also contact us directly by E-Mail at">You can also contact us directly by E-Mail at</span> <a href="${'mailto:' + this.context.configManager.Config.contact?.email}">${this.context.configManager.Config.contact?.email}</a></div><button class="gg-button" tip="Send message" i18n="Send" onclick="${() => this.sendMessage()}">Send</button></div></div>`;
14
+ <div id="panel"><div id="content"><label for="email" i18n="Your email (optional)" class="gg-label">Your email (optional)</label> <input id="email" placeholder="you@example.com" class="gg-input"> <label for="reason" i18n="Why are you contacting us?" class="gg-label">Why are you contacting us?</label> <select id="reason" class="gg-select"><option value="" disabled="disabled" selected="selected">-</option>${this.context.configManager.Config.contact?.reasons.map((reason) => uHtml `<option i18n="${reason}" value="${reason}">${reason}</option>`)}</select> <label for="message" i18n="Your message" class="gg-label">Your message</label> <textarea id="message" class="gg-input gg-textarea"></textarea> <label for="shortlink" i18n="The following link will be sent with your message. It contains your current configuration and will help us to understand your problem." class="gg-label">The following link will be sent with your message. It contains your current configuration and will help us to understand your problem.</label> <input id="shortlink" disabled="disabled" value="${this.shortUrl}" class="gg-input"><div class="mail-contact"><span i18n="You can also contact us directly by E-Mail at">You can also contact us directly by E-Mail at</span> <a href="${'mailto:' + this.context.configManager.Config.contact?.email}">${this.context.configManager.Config.contact?.email}</a></div><button class="gg-button" tip="Send message" i18n="Send" onclick="${() => this.sendMessage()}">Send</button></div></div>
15
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
15
16
  };
16
17
  isPanelVisible = false;
17
18
  panelTitle = 'contact-panel';
@@ -17,7 +17,8 @@ class MapCustomContextMenuComponent extends GirafeHTMLElement {
17
17
  .ol-popup{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:.9em}.ol-popup .ol-popup-content{cursor:default;padding:.25em .5em;overflow:hidden}.ol-popup.hasclosebox .ol-popup-content{margin-right:1.7em}.ol-popup .ol-popup-content:after{clear:both;content:"";height:0;font-size:0;display:block}.ol-popup .anchor{pointer-events:none;background:red;width:0;height:0;margin:-11px 22px;display:block;position:absolute}.ol-popup .anchor:after,.ol-popup .anchor:before{position:absolute}.ol-popup-right .anchor:after,.ol-popup-right .anchor:before{right:0}.ol-popup-top .anchor{top:0}.ol-popup-bottom .anchor{bottom:0}.ol-popup-right .anchor{right:0}.ol-popup-left .anchor{left:0}.ol-popup-center .anchor{left:50%;margin-left:0!important}.ol-popup-middle .anchor{top:50%;margin-top:0!important}.ol-popup-center.ol-popup-middle .anchor{display:none}.ol-popup.ol-fixed{margin:0!important;inset:.5em .5em auto auto!important;transform:none!important}.ol-popup.ol-fixed .anchor{display:none}.ol-popup.ol-fixed.anim>div{animation:none}.ol-popup .ol-fix{float:right;cursor:pointer;background:#fff;width:1em;height:.9em;margin:.2em;position:relative}.ol-popup .ol-fix:before{content:"";box-sizing:border-box;border:.1em solid #666;border-right-width:.3em;width:.8em;height:.7em;margin:.1em;display:block}.ol-popup.shadow{box-shadow:2px 2px 2px 2px #00000080}.ol-popup .closeBox{color:#fff;cursor:pointer;float:right;background-color:#003c8880;border:0;border-radius:2px;width:1.4em;height:1.4em;margin:5px 5px 0 0;padding:0;font-size:.9em;font-weight:700;display:none;position:relative}.ol-popup.hasclosebox .closeBox{display:block}.ol-popup .closeBox:hover{background-color:#003c88b3}.ol-popup .closeBox:after{content:"u00d7";text-align:center;width:100%;margin:-.5em 0;font-size:1.5em;line-height:1em;position:absolute;top:50%;left:0;right:0}.ol-popup.modifytouch{background-color:#eee}.ol-popup.modifytouch .ol-popup-content{white-space:nowrap;padding:0 .25em;font-size:.85em}.ol-popup.modifytouch .ol-popup-content a{text-decoration:none}.ol-popup.tooltips{background-color:#ffa}.ol-popup.tooltips .ol-popup-content{white-space:nowrap;padding:0 .25em;font-size:.85em}.ol-popup.default>div{background-color:#fff;border:1px solid #69f;border-radius:5px}.ol-popup.default{margin:-11px 0;transform:translateY(-22px)}.ol-popup-top.ol-popup.default{margin:11px 0;transform:none}.ol-popup-left.default{margin:-11px -22px;transform:translateY(-22px)}.ol-popup-top.ol-popup-left.default{margin:11px -22px;transform:none}.ol-popup-right.default{margin:-11px 22px;transform:translate(44px,-22px)}.ol-popup-top.ol-popup-right.default{margin:11px 22px;transform:translate(44px)}.ol-popup-middle.default{margin:0 10px;transform:none}.ol-popup-middle.ol-popup-right.default{margin:0 -10px;transform:translate(-20px)}.ol-popup.default .anchor{color:#69f}.ol-popup.default .anchor:after,.ol-popup.default .anchor:before{content:"";border:11px solid;border-color:currentColor #0000;margin:0 -11px}.ol-popup.default .anchor:after{border-width:11px;border-color:#fff #0000;margin:2px -11px}.ol-popup-top.default .anchor:before,.ol-popup-top.default .anchor:after{border-top:0;top:0}.ol-popup-bottom.default .anchor:before,.ol-popup-bottom.default .anchor:after{border-bottom:0;bottom:0}.ol-popup-middle.default .anchor:before{border-color:#0000 currentColor;margin:-11px -33px}.ol-popup-middle.default .anchor:after{border-color:#0000 #fff;margin:-11px -31px}.ol-popup-middle.ol-popup-left.default .anchor:before,.ol-popup-middle.ol-popup-left.default .anchor:after{border-left:0}.ol-popup-middle.ol-popup-right.default .anchor:before,.ol-popup-middle.ol-popup-right.default .anchor:after{border-right:0}.ol-popup.placemark{color:#c00;margin:-.65em 0;transform:translateY(-1.3em)}.ol-popup.placemark>div{width:2em;height:2em;min-width:unset;box-sizing:border-box;background-color:#fff;border:0;border-radius:50%;font-size:15px;position:relative;box-shadow:inset 0 0 0 .45em}.ol-popup.placemark .ol-popup-content{cursor:default;text-align:center;width:1em;height:1em;padding:.25em 0;line-height:1em;position:absolute;top:50%;left:50%;overflow:hidden;transform:translate(-50%,-50%)}.ol-popup.placemark .anchor{margin:0}.ol-popup.placemark .anchor:before{content:"";background:0 0;border-radius:50%;width:1em;height:.5em;margin:-.5em;box-shadow:0 1em .5em #00000080}.ol-popup.placemark .anchor:after{content:"";border:.7em solid #0000;border-top:1em solid;border-bottom:0 solid;margin:-.75em -.7em;bottom:0}.ol-popup.placemark.shield>div{border-radius:.2em}.ol-popup.placemark.shield .anchor:after{border-width:.8em 1em 0;margin:-.7em -1em}.ol-popup.placemark.blazon>div{border-radius:.2em}.ol-popup.placemark.pushpin{margin:-2.2em 0;transform:translateY(-4em)}.ol-popup.placemark.pushpin>div{border-radius:0;width:1.1em;box-shadow:inset 2em 0;background:0 0!important}.ol-popup.placemark.pushpin>div:before{content:"";pointer-events:none;border:.5em solid #0000;border-top:.3em solid;border-bottom-color:currentColor;width:1.3em;height:1.5em;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.ol-popup.placemark.needle{margin:-2em 0;transform:translateY(-4em)}.ol-popup.placemark.pushpin .anchor,.ol-popup.placemark.needle .anchor{margin:-1.2em}.ol-popup.placemark.pushpin .anchor:after,.ol-popup.placemark.needle .anchor:after{border-style:solid;border-width:2em .15em 0;width:.1em;margin:-.55em -.2em}.ol-popup.placemark.pushpin .anchor:before,.ol-popup.placemark.needle .anchor:before{margin:-.75em -.5em}.ol-popup.placemark.flagv{margin:-2em 1em;transform:translateY(-4em)}.ol-popup.placemark.flagv>div{box-shadow:none;background-color:#0000;border-radius:0}.ol-popup.placemark.flagv>div:before{content:"";pointer-events:none;border:1em solid #0000;border-left:2em solid;position:absolute}.ol-popup.placemark.flagv .anchor{margin:-1.4em}.ol-popup.placemark.flag{margin:-2em 1em;transform:translateY(-4em)}.ol-popup.placemark.flag>div{border-radius:0;transform-origin:0 150%!important}.ol-popup.placemark.flag .anchor{margin:-1.4em}.ol-popup.placemark.flagv .anchor:after,.ol-popup.placemark.flag .anchor:after{border-style:solid;border-width:2em .15em 0;width:.1em;margin:-.55em -1em}.ol-popup.placemark.flagv .anchor:before,.ol-popup.placemark.flag .anchor:before{margin:-.75em -1.25em}.ol-popup.placemark.flag.finish{margin:-2em 1em}.ol-popup.placemark.flag.finish>div{background-image:linear-gradient(45deg,currentColor 25%,#0000 25% 75%,currentColor 75%,currentColor),linear-gradient(45deg,currentColor 25%,#0000 25% 75%,currentColor 75%,currentColor);background-position:.5em 0,0 .5em;background-size:1em 1em;box-shadow:inset 0 0 0 .25em}.ol-popup.black .closeBox{color:#f80;background-color:#00000080;border-radius:5px}.ol-popup.black .closeBox:hover{color:#da2;background-color:#000000b3}.ol-popup.black{margin:-20px 0;transform:translateY(-40px)}.ol-popup.black>div{color:#fff;background-color:#0009;border-radius:5px}.ol-popup-top.ol-popup.black{margin:20px 0;transform:none}.ol-popup-left.black{margin:-20px -22px;transform:translateY(-40px)}.ol-popup-top.ol-popup-left.black{margin:20px -22px;transform:none}.ol-popup-right.black{margin:-20px 22px;transform:translate(44px,-40px)}.ol-popup-top.ol-popup-right.black{margin:20px 22px;transform:translate(44px)}.ol-popup-middle.black{margin:0 11px;transform:none}.ol-popup-left.ol-popup-middle.black{transform:none}.ol-popup-right.ol-popup-middle.black{margin:0 -11px;transform:translate(-22px)}.ol-popup.black .anchor{color:#0009;margin:-20px 11px}.ol-popup.black .anchor:before{content:"";border:20px solid;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.black .anchor:before{border-top:0;top:0}.ol-popup-bottom.black .anchor:before{border-bottom:0;bottom:0}.ol-popup-middle.black .anchor:before{border-color:#0000 currentColor;margin:-20px -22px}.ol-popup-middle.ol-popup-left.black .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.black .anchor:before{border-right:0}.ol-popup-center.black .anchor:before{margin:0 -10px}.ol-popup.tips .closeBox{color:#fff;background-color:red;border-radius:50%;width:1.2em;height:1.2em}.ol-popup.tips .closeBox:hover{background-color:#f40}.ol-popup.tips{margin:-20px 0;transform:translateY(-40px)}.ol-popup.tips>div{color:#333;background-color:#cea;border:5px solid #ad7;border-radius:5px}.ol-popup-top.ol-popup.tips{margin:20px 0;transform:none}.ol-popup-left.tips{margin:-20px -22px;transform:translateY(-40px)}.ol-popup-top.ol-popup-left.tips{margin:20px -22px;transform:none}.ol-popup-right.tips{margin:-20px 22px;transform:translate(44px,-40px)}.ol-popup-top.ol-popup-right.tips{margin:20px 22px;transform:translate(44px)}.ol-popup-middle.tips{margin:0;transform:none}.ol-popup-left.ol-popup-middle.tips{margin:0 22px;transform:none}.ol-popup-right.ol-popup-middle.tips{margin:0 -22px;transform:translate(-44px)}.ol-popup.tips .anchor{color:#ad7;margin:-18px 22px}.ol-popup.tips .anchor:before{content:"";border:20px solid;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.tips .anchor:before{border-top:0;top:0}.ol-popup-bottom.tips .anchor:before{border-bottom:0;bottom:0}.ol-popup-center.tips .anchor:before{border-width:20px 6px;margin:0 -6px}.ol-popup-left.tips .anchor:before{border-left:0;margin-left:0}.ol-popup-right.tips .anchor:before{border-right:0;margin-right:0}.ol-popup-middle.tips .anchor:before{border-width:6px 20px;border-color:#0000 currentColor;margin:-6px -41px}.ol-popup-middle.ol-popup-left.tips .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.tips .anchor:before{border-right:0}.ol-popup.warning .closeBox{color:#fff;background-color:red;border-radius:50%;font-size:.83em}.ol-popup.warning .closeBox:hover{background-color:#f40}.ol-popup.warning{color:#900;background-color:#fd0;border:4px dashed red;border-radius:3px;margin:-28px 10px;transform:translateY(-56px)}.ol-popup-top.ol-popup.warning{margin:28px 10px;transform:none}.ol-popup-left.warning{margin:-28px -22px;transform:translateY(-56px)}.ol-popup-top.ol-popup-left.warning{margin:28px -22px;transform:none}.ol-popup-right.warning{margin:-28px 22px;transform:translate(44px,-56px)}.ol-popup-top.ol-popup-right.warning{margin:28px 22px;transform:translate(44px)}.ol-popup-middle.warning{margin:0;transform:none}.ol-popup-left.ol-popup-middle.warning{margin:0 22px;transform:none}.ol-popup-right.ol-popup-middle.warning{margin:0 -22px;transform:translate(-44px)}.ol-popup.warning .anchor{margin:-33px 7px}.ol-popup.warning .anchor:before{content:"";border:30px solid red;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.warning .anchor:before{border-top:0;top:0}.ol-popup-bottom.warning .anchor:before{border-bottom:0;bottom:0}.ol-popup-center.warning .anchor:before{margin:0 -21px}.ol-popup-middle.warning .anchor:before{border-width:10px 22px;border-color:#0000 red;margin:-10px -33px}.ol-popup-middle.ol-popup-left.warning .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.warning .anchor:before{border-right:0}.ol-popup .ol-popupfeature table{width:100%}.ol-popup .ol-popupfeature table td{text-overflow:ellipsis;max-width:25em;overflow:hidden}.ol-popup .ol-popupfeature table td img{max-width:100px;max-height:100px}.ol-popup .ol-popupfeature tr:nth-child(odd){background-color:#eee}.ol-popup .ol-popupfeature .ol-zoombt{color:#003c8880;background:0 0;border:0;outline:none;width:2em;height:2em;display:inline-block;position:relative}.ol-popup .ol-popupfeature .ol-zoombt:before{content:"";box-sizing:border-box;background-color:#0000;border:.17em solid;border-radius:100%;width:1em;height:1em;position:absolute;top:.3em;left:.3em}.ol-popup .ol-popupfeature .ol-zoombt:after{content:"";box-sizing:border-box;border-style:solid;border-width:.1em .3em;border-radius:.03em;position:absolute;top:1.35em;left:1.15em;transform:rotate(45deg);box-shadow:-.2em 0 0 -.04em}.ol-popup .ol-popupfeature .ol-count{float:right;margin:.25em 0}.ol-popup .ol-popupfeature .ol-prev,.ol-popup .ol-popupfeature .ol-next{vertical-align:bottom;cursor:pointer;border:.5em solid #0000;border-left-color:#003c8880;border-right:0 solid #003c8880;margin:0 .5em;display:inline-block}.ol-popup .ol-popupfeature .ol-prev{border-width:.5em .5em .5em 0}.ol-popup.tooltips.black{background-color:#0000}.ol-popup.tooltips.black>div{background-color:#00000080;padding:.2em .5em;transform:scaleY(1.3)}.ol-popup-middle.tooltips.black .anchor:before{border-width:5px 10px;margin:-5px -21px}.ol-popup-center.ol-popup-middle,.ol-popup-top.ol-popup-left.ol-fixPopup,.ol-popup-top.ol-popup-right.ol-fixPopup,.ol-popup.ol-fixPopup{margin:0}
18
18
  </style>
19
19
  <style>${this.customStyle}</style>
20
- <div class="map-info-contextmenu"><div class="${this.tooltipTitle ? 'title-container' : 'title-container no-title'}"><span class="title">${this.tooltipTitle}</span> <button class="contextmenu-closer gg-icon-button gg-small" onclick="${() => this.closeMenu()}"></button></div><div>${this.tooltipContent}</div><svg class="tooltip-triangle" viewBox="0 0 20 10" preserveAspectRatio="none"><polygon points="0,0 10,10 20,0" class="triangle-fill"/><path d="M0,0 L10,10 L20,0" class="triangle-border"/></svg></div>`;
20
+ <div class="map-info-contextmenu"><div class="${this.tooltipTitle ? 'title-container' : 'title-container no-title'}"><span class="title">${this.tooltipTitle}</span> <button class="contextmenu-closer gg-icon-button gg-small" onclick="${() => this.closeMenu()}"></button></div><div>${this.tooltipContent}</div><svg class="tooltip-triangle" viewBox="0 0 20 10" preserveAspectRatio="none"><polygon points="0,0 10,10 20,0" class="triangle-fill"/><path d="M0,0 L10,10 L20,0" class="triangle-border"/></svg></div>
21
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
21
22
  };
22
23
  get map() {
23
24
  return this.context.mapManager.getMap();
@@ -1,23 +1,24 @@
1
+ /* SPDX-License-Identifier: Apache-2.0 */
1
2
  .map-info-contextmenu {
2
- --contextmenu-border-width: 1px;
3
- --contextmenu-triangle-width: 20px;
4
- --contextmenu-triangle-height: 10px;
5
- position: absolute;
6
- border-radius: 0;
7
- border: var(--contextmenu-border-width) solid var(--text-color-grad1);
8
- bottom: var(--contextmenu-triangle-height);
9
- left: 0;
10
- transform: translateX(-50%);
3
+ --contextmenu-border-width: 1px;
4
+ --contextmenu-triangle-width: 20px;
5
+ --contextmenu-triangle-height: 10px;
6
+ position: absolute;
7
+ border-radius: 0;
8
+ border: var(--contextmenu-border-width) solid var(--text-color-grad1);
9
+ bottom: var(--contextmenu-triangle-height);
10
+ left: 0;
11
+ transform: translateX(-50%);
11
12
 
12
- .title-container {
13
- padding-bottom: 0.5rem;
13
+ .title-container {
14
+ padding-bottom: 0.5rem;
14
15
 
15
- &.no-title {
16
- padding-bottom: 0;
17
- }
16
+ &.no-title {
17
+ padding-bottom: 0;
18
+ }
18
19
 
19
- span.title {
20
- font-weight: bold;
21
- }
20
+ span.title {
21
+ font-weight: bold;
22
22
  }
23
- }
23
+ }
24
+ }
@@ -19,7 +19,8 @@ table.custom-table{width:100%;max-width:100%;min-width:var(--popup-min);table-la
19
19
  .ol-popup{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:.9em}.ol-popup .ol-popup-content{cursor:default;padding:.25em .5em;overflow:hidden}.ol-popup.hasclosebox .ol-popup-content{margin-right:1.7em}.ol-popup .ol-popup-content:after{clear:both;content:"";height:0;font-size:0;display:block}.ol-popup .anchor{pointer-events:none;background:red;width:0;height:0;margin:-11px 22px;display:block;position:absolute}.ol-popup .anchor:after,.ol-popup .anchor:before{position:absolute}.ol-popup-right .anchor:after,.ol-popup-right .anchor:before{right:0}.ol-popup-top .anchor{top:0}.ol-popup-bottom .anchor{bottom:0}.ol-popup-right .anchor{right:0}.ol-popup-left .anchor{left:0}.ol-popup-center .anchor{left:50%;margin-left:0!important}.ol-popup-middle .anchor{top:50%;margin-top:0!important}.ol-popup-center.ol-popup-middle .anchor{display:none}.ol-popup.ol-fixed{margin:0!important;inset:.5em .5em auto auto!important;transform:none!important}.ol-popup.ol-fixed .anchor{display:none}.ol-popup.ol-fixed.anim>div{animation:none}.ol-popup .ol-fix{float:right;cursor:pointer;background:#fff;width:1em;height:.9em;margin:.2em;position:relative}.ol-popup .ol-fix:before{content:"";box-sizing:border-box;border:.1em solid #666;border-right-width:.3em;width:.8em;height:.7em;margin:.1em;display:block}.ol-popup.shadow{box-shadow:2px 2px 2px 2px #00000080}.ol-popup .closeBox{color:#fff;cursor:pointer;float:right;background-color:#003c8880;border:0;border-radius:2px;width:1.4em;height:1.4em;margin:5px 5px 0 0;padding:0;font-size:.9em;font-weight:700;display:none;position:relative}.ol-popup.hasclosebox .closeBox{display:block}.ol-popup .closeBox:hover{background-color:#003c88b3}.ol-popup .closeBox:after{content:"u00d7";text-align:center;width:100%;margin:-.5em 0;font-size:1.5em;line-height:1em;position:absolute;top:50%;left:0;right:0}.ol-popup.modifytouch{background-color:#eee}.ol-popup.modifytouch .ol-popup-content{white-space:nowrap;padding:0 .25em;font-size:.85em}.ol-popup.modifytouch .ol-popup-content a{text-decoration:none}.ol-popup.tooltips{background-color:#ffa}.ol-popup.tooltips .ol-popup-content{white-space:nowrap;padding:0 .25em;font-size:.85em}.ol-popup.default>div{background-color:#fff;border:1px solid #69f;border-radius:5px}.ol-popup.default{margin:-11px 0;transform:translateY(-22px)}.ol-popup-top.ol-popup.default{margin:11px 0;transform:none}.ol-popup-left.default{margin:-11px -22px;transform:translateY(-22px)}.ol-popup-top.ol-popup-left.default{margin:11px -22px;transform:none}.ol-popup-right.default{margin:-11px 22px;transform:translate(44px,-22px)}.ol-popup-top.ol-popup-right.default{margin:11px 22px;transform:translate(44px)}.ol-popup-middle.default{margin:0 10px;transform:none}.ol-popup-middle.ol-popup-right.default{margin:0 -10px;transform:translate(-20px)}.ol-popup.default .anchor{color:#69f}.ol-popup.default .anchor:after,.ol-popup.default .anchor:before{content:"";border:11px solid;border-color:currentColor #0000;margin:0 -11px}.ol-popup.default .anchor:after{border-width:11px;border-color:#fff #0000;margin:2px -11px}.ol-popup-top.default .anchor:before,.ol-popup-top.default .anchor:after{border-top:0;top:0}.ol-popup-bottom.default .anchor:before,.ol-popup-bottom.default .anchor:after{border-bottom:0;bottom:0}.ol-popup-middle.default .anchor:before{border-color:#0000 currentColor;margin:-11px -33px}.ol-popup-middle.default .anchor:after{border-color:#0000 #fff;margin:-11px -31px}.ol-popup-middle.ol-popup-left.default .anchor:before,.ol-popup-middle.ol-popup-left.default .anchor:after{border-left:0}.ol-popup-middle.ol-popup-right.default .anchor:before,.ol-popup-middle.ol-popup-right.default .anchor:after{border-right:0}.ol-popup.placemark{color:#c00;margin:-.65em 0;transform:translateY(-1.3em)}.ol-popup.placemark>div{width:2em;height:2em;min-width:unset;box-sizing:border-box;background-color:#fff;border:0;border-radius:50%;font-size:15px;position:relative;box-shadow:inset 0 0 0 .45em}.ol-popup.placemark .ol-popup-content{cursor:default;text-align:center;width:1em;height:1em;padding:.25em 0;line-height:1em;position:absolute;top:50%;left:50%;overflow:hidden;transform:translate(-50%,-50%)}.ol-popup.placemark .anchor{margin:0}.ol-popup.placemark .anchor:before{content:"";background:0 0;border-radius:50%;width:1em;height:.5em;margin:-.5em;box-shadow:0 1em .5em #00000080}.ol-popup.placemark .anchor:after{content:"";border:.7em solid #0000;border-top:1em solid;border-bottom:0 solid;margin:-.75em -.7em;bottom:0}.ol-popup.placemark.shield>div{border-radius:.2em}.ol-popup.placemark.shield .anchor:after{border-width:.8em 1em 0;margin:-.7em -1em}.ol-popup.placemark.blazon>div{border-radius:.2em}.ol-popup.placemark.pushpin{margin:-2.2em 0;transform:translateY(-4em)}.ol-popup.placemark.pushpin>div{border-radius:0;width:1.1em;box-shadow:inset 2em 0;background:0 0!important}.ol-popup.placemark.pushpin>div:before{content:"";pointer-events:none;border:.5em solid #0000;border-top:.3em solid;border-bottom-color:currentColor;width:1.3em;height:1.5em;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.ol-popup.placemark.needle{margin:-2em 0;transform:translateY(-4em)}.ol-popup.placemark.pushpin .anchor,.ol-popup.placemark.needle .anchor{margin:-1.2em}.ol-popup.placemark.pushpin .anchor:after,.ol-popup.placemark.needle .anchor:after{border-style:solid;border-width:2em .15em 0;width:.1em;margin:-.55em -.2em}.ol-popup.placemark.pushpin .anchor:before,.ol-popup.placemark.needle .anchor:before{margin:-.75em -.5em}.ol-popup.placemark.flagv{margin:-2em 1em;transform:translateY(-4em)}.ol-popup.placemark.flagv>div{box-shadow:none;background-color:#0000;border-radius:0}.ol-popup.placemark.flagv>div:before{content:"";pointer-events:none;border:1em solid #0000;border-left:2em solid;position:absolute}.ol-popup.placemark.flagv .anchor{margin:-1.4em}.ol-popup.placemark.flag{margin:-2em 1em;transform:translateY(-4em)}.ol-popup.placemark.flag>div{border-radius:0;transform-origin:0 150%!important}.ol-popup.placemark.flag .anchor{margin:-1.4em}.ol-popup.placemark.flagv .anchor:after,.ol-popup.placemark.flag .anchor:after{border-style:solid;border-width:2em .15em 0;width:.1em;margin:-.55em -1em}.ol-popup.placemark.flagv .anchor:before,.ol-popup.placemark.flag .anchor:before{margin:-.75em -1.25em}.ol-popup.placemark.flag.finish{margin:-2em 1em}.ol-popup.placemark.flag.finish>div{background-image:linear-gradient(45deg,currentColor 25%,#0000 25% 75%,currentColor 75%,currentColor),linear-gradient(45deg,currentColor 25%,#0000 25% 75%,currentColor 75%,currentColor);background-position:.5em 0,0 .5em;background-size:1em 1em;box-shadow:inset 0 0 0 .25em}.ol-popup.black .closeBox{color:#f80;background-color:#00000080;border-radius:5px}.ol-popup.black .closeBox:hover{color:#da2;background-color:#000000b3}.ol-popup.black{margin:-20px 0;transform:translateY(-40px)}.ol-popup.black>div{color:#fff;background-color:#0009;border-radius:5px}.ol-popup-top.ol-popup.black{margin:20px 0;transform:none}.ol-popup-left.black{margin:-20px -22px;transform:translateY(-40px)}.ol-popup-top.ol-popup-left.black{margin:20px -22px;transform:none}.ol-popup-right.black{margin:-20px 22px;transform:translate(44px,-40px)}.ol-popup-top.ol-popup-right.black{margin:20px 22px;transform:translate(44px)}.ol-popup-middle.black{margin:0 11px;transform:none}.ol-popup-left.ol-popup-middle.black{transform:none}.ol-popup-right.ol-popup-middle.black{margin:0 -11px;transform:translate(-22px)}.ol-popup.black .anchor{color:#0009;margin:-20px 11px}.ol-popup.black .anchor:before{content:"";border:20px solid;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.black .anchor:before{border-top:0;top:0}.ol-popup-bottom.black .anchor:before{border-bottom:0;bottom:0}.ol-popup-middle.black .anchor:before{border-color:#0000 currentColor;margin:-20px -22px}.ol-popup-middle.ol-popup-left.black .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.black .anchor:before{border-right:0}.ol-popup-center.black .anchor:before{margin:0 -10px}.ol-popup.tips .closeBox{color:#fff;background-color:red;border-radius:50%;width:1.2em;height:1.2em}.ol-popup.tips .closeBox:hover{background-color:#f40}.ol-popup.tips{margin:-20px 0;transform:translateY(-40px)}.ol-popup.tips>div{color:#333;background-color:#cea;border:5px solid #ad7;border-radius:5px}.ol-popup-top.ol-popup.tips{margin:20px 0;transform:none}.ol-popup-left.tips{margin:-20px -22px;transform:translateY(-40px)}.ol-popup-top.ol-popup-left.tips{margin:20px -22px;transform:none}.ol-popup-right.tips{margin:-20px 22px;transform:translate(44px,-40px)}.ol-popup-top.ol-popup-right.tips{margin:20px 22px;transform:translate(44px)}.ol-popup-middle.tips{margin:0;transform:none}.ol-popup-left.ol-popup-middle.tips{margin:0 22px;transform:none}.ol-popup-right.ol-popup-middle.tips{margin:0 -22px;transform:translate(-44px)}.ol-popup.tips .anchor{color:#ad7;margin:-18px 22px}.ol-popup.tips .anchor:before{content:"";border:20px solid;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.tips .anchor:before{border-top:0;top:0}.ol-popup-bottom.tips .anchor:before{border-bottom:0;bottom:0}.ol-popup-center.tips .anchor:before{border-width:20px 6px;margin:0 -6px}.ol-popup-left.tips .anchor:before{border-left:0;margin-left:0}.ol-popup-right.tips .anchor:before{border-right:0;margin-right:0}.ol-popup-middle.tips .anchor:before{border-width:6px 20px;border-color:#0000 currentColor;margin:-6px -41px}.ol-popup-middle.ol-popup-left.tips .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.tips .anchor:before{border-right:0}.ol-popup.warning .closeBox{color:#fff;background-color:red;border-radius:50%;font-size:.83em}.ol-popup.warning .closeBox:hover{background-color:#f40}.ol-popup.warning{color:#900;background-color:#fd0;border:4px dashed red;border-radius:3px;margin:-28px 10px;transform:translateY(-56px)}.ol-popup-top.ol-popup.warning{margin:28px 10px;transform:none}.ol-popup-left.warning{margin:-28px -22px;transform:translateY(-56px)}.ol-popup-top.ol-popup-left.warning{margin:28px -22px;transform:none}.ol-popup-right.warning{margin:-28px 22px;transform:translate(44px,-56px)}.ol-popup-top.ol-popup-right.warning{margin:28px 22px;transform:translate(44px)}.ol-popup-middle.warning{margin:0;transform:none}.ol-popup-left.ol-popup-middle.warning{margin:0 22px;transform:none}.ol-popup-right.ol-popup-middle.warning{margin:0 -22px;transform:translate(-44px)}.ol-popup.warning .anchor{margin:-33px 7px}.ol-popup.warning .anchor:before{content:"";border:30px solid red;border-left:11px solid #0000;border-right:11px solid #0000}.ol-popup-top.warning .anchor:before{border-top:0;top:0}.ol-popup-bottom.warning .anchor:before{border-bottom:0;bottom:0}.ol-popup-center.warning .anchor:before{margin:0 -21px}.ol-popup-middle.warning .anchor:before{border-width:10px 22px;border-color:#0000 red;margin:-10px -33px}.ol-popup-middle.ol-popup-left.warning .anchor:before{border-left:0}.ol-popup-middle.ol-popup-right.warning .anchor:before{border-right:0}.ol-popup .ol-popupfeature table{width:100%}.ol-popup .ol-popupfeature table td{text-overflow:ellipsis;max-width:25em;overflow:hidden}.ol-popup .ol-popupfeature table td img{max-width:100px;max-height:100px}.ol-popup .ol-popupfeature tr:nth-child(odd){background-color:#eee}.ol-popup .ol-popupfeature .ol-zoombt{color:#003c8880;background:0 0;border:0;outline:none;width:2em;height:2em;display:inline-block;position:relative}.ol-popup .ol-popupfeature .ol-zoombt:before{content:"";box-sizing:border-box;background-color:#0000;border:.17em solid;border-radius:100%;width:1em;height:1em;position:absolute;top:.3em;left:.3em}.ol-popup .ol-popupfeature .ol-zoombt:after{content:"";box-sizing:border-box;border-style:solid;border-width:.1em .3em;border-radius:.03em;position:absolute;top:1.35em;left:1.15em;transform:rotate(45deg);box-shadow:-.2em 0 0 -.04em}.ol-popup .ol-popupfeature .ol-count{float:right;margin:.25em 0}.ol-popup .ol-popupfeature .ol-prev,.ol-popup .ol-popupfeature .ol-next{vertical-align:bottom;cursor:pointer;border:.5em solid #0000;border-left-color:#003c8880;border-right:0 solid #003c8880;margin:0 .5em;display:inline-block}.ol-popup .ol-popupfeature .ol-prev{border-width:.5em .5em .5em 0}.ol-popup.tooltips.black{background-color:#0000}.ol-popup.tooltips.black>div{background-color:#00000080;padding:.2em .5em;transform:scaleY(1.3)}.ol-popup-middle.tooltips.black .anchor:before{border-width:5px 10px;margin:-5px -21px}.ol-popup-center.ol-popup-middle,.ol-popup-top.ol-popup-left.ol-fixPopup,.ol-popup-top.ol-popup-right.ol-fixPopup,.ol-popup.ol-fixPopup{margin:0}
20
20
  </style>
21
21
  <style>${this.customStyle}</style>
22
- <div class="map-info-contextmenu"><button class="contextmenu-closer gg-icon-button gg-small" onclick="${() => this.closeMenu()}"></button><div><table class="custom-table"><col class="col-1"><col><col class="col-3"><thead><tr><th scope="col"><th scope="col"><th scope="col"><tbody>${this.mapContextMenuState.crs.map(f => uHtml `<tr><td i18n="${f.translation}"><td>${this.printCoordinate(f.coordinate, f.format, f.precision).join(', ')}<td><div class="justify-right"><button class="gg-icon-button gg-small" onclick="${() => { navigator.clipboard.writeText(this.printCoordinate(f.coordinate, f.format, f.precision).join(', ')); }}"><img src="icons/content_copy.svg" alt="${this.context.i18nManager.getTranslation('Copy value')}"></button></div></tr>`)} ${this.mapContextMenuState.sources.map(f => uHtml `<tr><td i18n="${f.translation}"><td><div class="center-vertically">${f.loading ? uHtml `<img src="icons/progress.svg" class="gg-spin gg-small" alt="${this.context.i18nManager.getTranslation('Loading')}"> ` : ''} ${f.content ? f.content : this.context.i18nManager.getTranslation('No data')}</div><td><div class="justify-right"><button class="gg-icon-button gg-small" onclick="${() => { navigator.clipboard.writeText(f.content ? f.content : ''); }}"><img src="icons/content_copy.svg" alt="${this.context.i18nManager.getTranslation('Copy value')}"></button></div></tr>`)}</table><div>${this.mapContextMenuState.links.map(f => uHtml `<div class="link-div"><a href="${f.content}" target="_blank">${this.context.i18nManager.getTranslation(f.translation)}</a> <img src="icons/open_in_new.svg" alt=""></div>`)}</div></div></div>`;
22
+ <div class="map-info-contextmenu"><button class="contextmenu-closer gg-icon-button gg-small" onclick="${() => this.closeMenu()}"></button><div><table class="custom-table"><col class="col-1"><col><col class="col-3"><thead><tr><th scope="col"><th scope="col"><th scope="col"><tbody>${this.mapContextMenuState.crs.map(f => uHtml `<tr><td i18n="${f.translation}"><td>${this.printCoordinate(f.coordinate, f.format, f.precision).join(', ')}<td><div class="justify-right"><button class="gg-icon-button gg-small" onclick="${() => { navigator.clipboard.writeText(this.printCoordinate(f.coordinate, f.format, f.precision).join(', ')); }}"><img src="icons/content_copy.svg" alt="${this.context.i18nManager.getTranslation('Copy value')}"></button></div></tr>`)} ${this.mapContextMenuState.sources.map(f => uHtml `<tr><td i18n="${f.translation}"><td><div class="center-vertically">${f.loading ? uHtml `<img src="icons/progress.svg" class="gg-spin gg-small" alt="${this.context.i18nManager.getTranslation('Loading')}"> ` : ''} ${f.content ? f.content : this.context.i18nManager.getTranslation('No data')}</div><td><div class="justify-right"><button class="gg-icon-button gg-small" onclick="${() => { navigator.clipboard.writeText(f.content ? f.content : ''); }}"><img src="icons/content_copy.svg" alt="${this.context.i18nManager.getTranslation('Copy value')}"></button></div></tr>`)}</table><div>${this.mapContextMenuState.links.map(f => uHtml `<div class="link-div"><a href="${f.content}" target="_blank">${this.context.i18nManager.getTranslation(f.translation)}</a> <img src="icons/open_in_new.svg" alt=""></div>`)}</div></div></div>
23
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
23
24
  };
24
25
  get map() {
25
26
  return this.context.mapManager.getMap();
@@ -10,7 +10,8 @@ class CoordinateComponent extends GirafeHTMLElement {
10
10
  *{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-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,.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}.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}
11
11
  </style>
12
12
  <style>${this.customStyle}</style>
13
- <label for="coordinates" class="${this.east ? 'gg-label' : 'hidden'}">E ${this.east} / N ${this.north}</label>`;
13
+ <label for="coordinates" class="${this.east ? 'gg-label' : 'hidden'}">E ${this.east} / N ${this.north}</label>
14
+ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
14
15
  };
15
16
  #locale;
16
17
  east = null;