@geogirafe/lib-geoportal 1.3.0-dev.2937711922 → 1.3.0-dev.2938437315

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.
@@ -23,7 +23,7 @@ class CrossSectionSettingsComponent extends GirafeHTMLElement {
23
23
  .hidden{display:none!important}.gg-rotate90{transform:rotate(90deg)}.gg-rotate180{transform:rotate(180deg)}.gg-rotate270{transform:rotate(270deg)}img{filter:var(--svg-filter)}img.legend-image{filter:var(--svg-map-filter);background:var(--svg-legend-bkg)}div{scrollbar-width:thin}a,a:visited{color:var(--link-color)}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes spin-wait{0%{transform:rotate(0)}7%{transform:rotate(360deg)}to{transform:rotate(360deg)}}.gg-spin{animation-name:spin;animation-duration:2s;animation-timing-function:linear;animation-iteration-count:infinite}.gg-spin-wait{animation-name:spin-wait;animation-duration:10s;animation-timing-function:linear;animation-iteration-count:infinite}::-webkit-scrollbar{width:5px}::-webkit-scrollbar-thumb{background:#999}button,input,select,textarea{font:inherit}.gg-button,.gg-select,.gg-input,.gg-textarea{background-color:var(--bkg-color);color:var(--text-color);border:var(--app-standard-border);box-sizing:border-box;cursor:pointer;border-radius:3px;outline:0;margin:0;padding:0 0 0 .5rem;display:inline-block}.gg-label{background-color:var(--bkg-color);color:var(--text-color);border:none;align-items:center;margin:0;padding:0;display:flex}.gg-button,.gg-select,.gg-input,.gg-label{min-height:calc(var(--app-standard-height) / 1.5)}.gg-textarea{max-height:initial;resize:vertical;height:6rem;padding:.5rem;line-height:1.3rem}.gg-input{cursor:text}.gg-checkbox{accent-color:var(--text-color);cursor:pointer;width:1.2rem}.gg-range{accent-color:var(--text-color)}.gg-button{padding:0 .5rem}.gg-button.active{border:solid 1px var(--text-color-grad1);background-color:var(--bkg-color-grad2)}.gg-button:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed;border:none}.gg-button:disabled img{filter:opacity(.6)}.gg-input:disabled,.gg-select:disabled,.gg-textarea:disabled{background-color:var(--bkg-color-grad1);color:var(--text-color-grad2);cursor:not-allowed}.gg-button>img{vertical-align:middle}.gg-icon-button{color:var(--text-color);cursor:pointer;background-color:#0000;border:none;flex-direction:column;justify-content:center;align-items:center;padding:0;display:flex}.gg-icon{justify-content:center;align-items:center;display:flex}.gg-big,.gg-big-withtext{min-width:var(--app-standard-height);min-height:var(--app-standard-height);max-height:var(--app-standard-height)}.gg-big img,.gg-big-withtext img{width:calc(var(--app-standard-height) - 1.5rem);margin:0}.gg-big-withtext span{font-variant:small-caps;padding:0 1rem;font-size:.9rem}.gg-medium,.gg-medium-withtext{min-width:calc(var(--app-standard-height) / 1.2);min-height:calc(var(--app-standard-height) / 1.2);max-height:calc(var(--app-standard-height) / 1.2);flex-direction:row}.gg-medium img{width:calc(var(--app-standard-height) / 2.4);margin:0}.gg-medium-withtext img{width:calc(var(--app-standard-height) / 2.4);margin-left:.5rem}.gg-medium-withtext span{padding:0 1rem 0 .5rem;font-size:.9rem}.gg-small,.gg-small-withtext{min-width:calc(var(--app-standard-height) / 2);min-height:calc(var(--app-standard-height) / 2);max-height:calc(var(--app-standard-height) / 2);flex-direction:row}.gg-small img{width:calc(var(--app-standard-height) / 3);margin:0}.gg-small-withtext img{width:calc(var(--app-standard-height) / 3);margin-left:.5rem}.gg-small-withtext span{padding:0 .5rem 0 .3rem;font-size:.9rem}.gg-button:hover:not(:disabled),.gg-select:hover:not(:disabled),.gg-input:hover:not(:disabled),.gg-textarea:hover:not(:disabled),.gg-icon-button:hover:not(:disabled){background-color:var(--bkg-color-grad1)}.gg-opacity{opacity:.5}.gg-opacity:hover{opacity:1;background-color:#0000}.gg-tabs{cursor:pointer;grid-auto-flow:column;padding-bottom:1rem;font-size:1rem;display:grid}.gg-tab{border:none;border-bottom:var(--app-standard-border);cursor:pointer;color:var(--text-color);background:0 0;padding:.5rem}.gg-tab.active{border-bottom:solid 1px var(--text-color)}.girafe-button-big,.girafe-button-large,.girafe-button-small,.girafe-button-tiny{color:var(--text-color);background-color:#0000;border:none;flex-direction:column;display:flex}.girafe-button-big:hover,.girafe-button-large:hover,.girafe-button-small:hover,.girafe-button-tiny:hover{background-color:var(--bkg-color-grad1);cursor:pointer}.girafe-button-big.dark,.girafe-button-large.dark,.girafe-button-small.dark,.girafe-button-tiny.dark{background-color:var(--bkg-color);filter:invert()}.girafe-button-big{width:var(--app-standard-height);height:var(--app-standard-height);align-items:center;padding:1rem}.girafe-button-big img{overflow:hidden}.girafe-button-large{flex-direction:row}.girafe-button-large img{height:2rem;margin:.3rem}.girafe-button-large span{height:2rem;margin:.3rem;line-height:2rem}.girafe-button-small{min-width:calc(var(--app-standard-height) / 2);height:calc(var(--app-standard-height) / 2);align-items:center;padding:.5rem}.girafe-button-small img{overflow:hidden}.girafe-button-small span{text-align:left;text-overflow:ellipsis;width:100%;overflow:hidden}.girafe-button-tiny{align-items:center;width:1rem;height:1rem;padding:0}.girafe-button-tiny img{overflow:hidden}.girafe-onboarding-theme{background-color:var(--bkg-color)!important;color:var(--text-color)!important}.girafe-onboarding-theme button{background-color:var(--bkg-color)!important;color:var(--text-color)!important;text-shadow:none!important}.girafe-onboarding-theme button.driver-popover-close-btn{z-index:10000}.tippy-box{background-color:var(--bkg-color)!important;border:var(--app-standard-border)!important}.tippy-content{color:var(--text-color)!important}.tippy-arrow{color:var(--bkg-color)!important}.tippy-box[data-theme~=error]{background-color:var(--error-color);white-space:pre-line}div.tippy-box[data-theme=image-popup]{border:var(--app-standard-border)!important;& div.tippy-content{background-color:var(--bkg-color)!important;& img{max-width:20rem;max-height:20rem}}& div.tippy-arrow{color:var(--bkg-color)!important}}
24
24
  </style>
25
25
  <style>${this.customStyle}</style>
26
- <div id="panel"><div id="content"><div class="btn-group-flex"><button id="draw-profile-btn" class="${this.crossSectionState.drawProfile ? 'gg-button active' : 'gg-button'}" tip="draw_profile_help" onclick="${() => this.toggleLineDraw()}" i18n="draw_profile">Draw</button> <button id="delete-profile-btn" class="gg-button" tip="delete_help" onclick="${() => this.deleteProfile()}" i18n="delete">Delete</button></div><div class="btn-group-flex"><label for="section-width-btn" i18n="profile_width" class="gg-label">Width [m]</label> <input id="section-width-btn" class="gg-input" type="number" value="${this.crossSectionState.sectionWidthSettings.value}" min="${this.crossSectionState.sectionWidthSettings.min}" max="${this.crossSectionState.sectionWidthSettings.max}" step="${this.crossSectionState.sectionWidthSettings.step}" onchange="${(e) => this.setSectionWidth(e.target.value)}"></div><div class="btn-group-flex"><button id="reset-zoom-btn" class="gg-button" tip="profile_reset_view_help" onclick="${() => this.resetZoom()}" i18n="profile_reset_view">Reset view</button> <button id="sync-views-btn" class="${this.crossSectionState.syncViews ? 'gg-button active' : 'gg-button'}" tip="profile_sync_view_help" onclick="${() => this.setViewSync(!this.crossSectionState.syncViews)}" i18n="profile_sync_view">Sync. views</button></div><div class="btn-group-flex"><button class="gg-icon-button gg-big" tip="profile_shift_up_help" onclick="${() => this.shiftLinestring([0.0, this.crossSectionState.linestringShift])}"><img src="icons/arrow_up.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_up_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_down_help" onclick="${() => this.shiftLinestring([0.0, -this.crossSectionState.linestringShift])}"><img src="icons/arrow_down.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_down_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_left_help" onclick="${() => this.shiftLinestring([-this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_left.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_left_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_right_help" onclick="${() => this.shiftLinestring([this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_right.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_right_help')}"></button></div><div class="btn-group-flex"><div class="cell"><label for="z-ratio-btn" class="gg-label">${this.context.i18nManager.getTranslation('profile_exaggeration')} (${this.crossSectionState.verticalExaggerationSettings.value})</label><div style="display: flex; align-items: center"><input id="z-ratio-btn" type="range" class="gg-range" min="${this.crossSectionState.verticalExaggerationSettings.min}" max="${this.crossSectionState.verticalExaggerationSettings.max}" step="${this.crossSectionState.verticalExaggerationSettings.step}" value="${this.crossSectionState.verticalExaggerationSettings.value}" oninput="${(e) => this.setVerticalExaggeration(Number.parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="z-ratio-reset-btn" class="reset-btn" tip="profile_exaggeration_reset_help" onclick="${() => this.setVerticalExaggeration(this.crossSectionState.verticalExaggerationSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_exaggeration_reset_help')}"></button></div></div></div><div class="btn-group-flex"><div class="cell"><label for="point-size-btn" class="gg-label">${this.context.i18nManager.getTranslation('profile_point_size')} (${this.crossSectionState.pointSizeSettings.value})</label><div style="display: flex; align-items: center"><input id="point-size-btn" type="range" class="gg-range" min="${this.crossSectionState.pointSizeSettings.min}" max="${this.crossSectionState.pointSizeSettings.max}" step="${this.crossSectionState.pointSizeSettings.step}" value="${this.crossSectionState.pointSizeSettings.value}" oninput="${(e) => this.setPointSize(Number.parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="point-size-reset-btn" class="reset-btn" tip="profile_point_size_reset_help" onclick="${() => this.setPointSize(this.crossSectionState.pointSizeSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_point_size_reset_help')}"></button></div></div></div><div class="btn-group-flex"><label for="background-color-btn" i18n="profile_background_color" class="gg-label">Background color</label> <input id="background-color-btn" class="gg-input" type="color" value="${this.crossSectionState.backgroundColor}" oninput="${(e) => this.setBackgroundColor(e.target.value)}"></div><div class="btn-group-flex"><label for="sequential-color-btn" i18n="profile_colormap" class="gg-label">Colorscale</label> <select id="sequential-color-btn" class="gg-select" oninput="${(e) => this.setColorPalette(e.target.value)}"><option value="spectral" ?selected="${this.crossSectionState.colorPalette === 'spectral'}" i18n="palette_option_spectral">Spectral<option value="greys" ?selected="${this.crossSectionState.colorPalette === 'greys'}" i18n="palette_option_greys">Greys<option value="blues" ?selected="${this.crossSectionState.colorPalette === 'blues'}" i18n="palette_option_blues">Blues<option value="viridis" ?selected="${this.crossSectionState.colorPalette === 'viridis'}" i18n="palette_option_viridis">Viridis<option value="magma" ?selected="${this.crossSectionState.colorPalette === 'magma'}" i18n="palette_option_magma">Magma</select></div><div class="option"><label for="grid-btn" i18n="profile_toggle_grid" class="gg-label">Show grid</label> <input id="grid-btn" class="gg-checkbox" ?checked="${this.crossSectionState.gridVisible}" type="checkbox" onchange="${(e) => this.setGridVisibility(e.target.checked)}"></div><h3 i18n="profile_pointcloud">Pointclouds</h3><div class="btn-group-flex loader-progress"><div class="progress-wrapper" tip="profile_load_indicator_help"><progress id="load-progress" class="gg-progress" value="${this.crossSectionState.numberOfPoints}" max="${this.crossSectionState.maxNumberOfPoints}"></progress> <span class="progress-label">${(this.crossSectionState.loading) ? uHtml `<img src="icons/progress.svg" alt="Loading" class="gg-spin gg-small progress-icon">` : uHtml ``} ${this.crossSectionState.numberOfPoints} / ${this.crossSectionState.maxNumberOfPoints}</span></div></div><div>${this.crossSectionState.datasets.map(f => uHtml `<div class="dataset-row"><input type="checkbox" id="${f.id}" class="gg-checkbox" aria-label="Dataset ${f.id}" ?checked="${f.active}" onchange="${() => this.toggleVisibility(f.id)}"> <span class="dataset-name" i18n="${f.id}">${f.id}</span> <select class="gg-select" aria-label="Color variable" oninput="${(e) => this.setColorVariable(f.id, e.target.value)}"><option value="uniform" ?selected="${f.colorby === 'uniform'}" i18n="color_option_uniform">Uniform<option value="natural" ?selected="${f.colorby === 'natural'}" i18n="color_option_natural">Natural<option value="intensity" ?selected="${f.colorby === 'intensity'}" i18n="color_option_intensity">Intensity<option value="classification" ?selected="${f.colorby === 'classification'}" i18n="color_option_classification">Classification</select> <input id="uniform-color-btn" type="color" aria-label="Uniform color" value="${f.color}" oninput="${(e) => this.setColor(f.id, e.target.value)}"></div>`)}</div><h3 i18n="profile_measure_and_annotate">Measurements and annotations</h3><div class="btn-group-flex"><button id="draw-measurements-btn" class="${this.crossSectionState.drawMeasurement ? 'gg-button active' : 'gg-button'}" tip="profile_measurement_help" onclick="${() => this.toggleMeasureDraw()}" i18n="profile_measurement" ?disabled="${!this.crossSectionState.enableMeasurement}">Measure</button> <button id="delete-measurements-btn" class="gg-button" tip="profile_delete_measurements_help" onclick="${() => this.deleteAllMeasurements()}" i18n="profile_delete_measurements">Delete all</button></div><div class="scrollable-table-container"><table id="measurements-table" class="scrollable-table"><thead><tr><th class="table-cell sticky-header" style="text-align: center"><th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_dist">DIST.<th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_slope">SLOPE.<th class="table-cell sticky-header" style="text-align: center"><tbody></table></div><div class="btn-group-flex"><button id="draw-markers-btn" class="${this.crossSectionState.drawMarker ? 'gg-button active' : 'gg-button'}" tip="profile_draw_markers_help" onclick="${() => this.toggleMarkerDraw()}" i18n="profile_draw_markers" ?disabled="${!this.crossSectionState.enableAnnotation}">Annotate</button> <button id="delete-markers-btn" class="gg-button" tip="profile_delete_markers_help" onclick="${() => this.deleteAllMarkers()}" i18n="profile_delete_markers">Delete all</button></div><div class="scrollable-table-container"><table id="markers-table" class="scrollable-table"><thead><tr><th class="sticky-header" style="text-align: center" i18n="profile_table_id">ID<th class="sticky-header" style="text-align: right" i18n="profile_table_coord">COORD.<th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><tbody></table></div><h3 i18n="profile_print_title">Print</h3><div class="btn-group-flex"><select id="print-profile-format-btn" class="gg-select" aria-label="Print format" oninput="${(e) => this.setPrintFileFormat(e.target.value)}"><option value="svg" i18n="SVG">SVG</select> <button id="print-profile-btn" class="gg-button" tip="profile_print_help" onclick="${() => this.printPlot(this.crossSectionState.printFileFormat)}" i18n="profile_print">Print</button></div><h3 i18n="profile_download_title">Downloads</h3><div class="text-label" i18n="profile_markers_download">Markers</div><div class="btn-group-flex"><select id="download-markers-format-btn" class="gg-select" aria-label="Markers format" oninput="${(e) => this.setAnnotationsFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-markers-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature(this.points, 'markers', this.crossSectionState.downloadAnnotationsFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableAnnotationsDownload}">Download</button></div><div class="text-label" i18n="profile_linestring_download">Profile line</div><div class="btn-group-flex"><select id="download-linestring-format-btn" class="gg-select" aria-label="Profile line format" oninput="${(e) => this.setLineFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-linestring-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature([this.linestring], 'linestring', this.crossSectionState.downloadLinestringFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableLinestringDownload}">Download</button></div></div></div>
26
+ <div id="panel"><div id="content"><div class="btn-group-flex"><button id="draw-profile-btn" class="${this.crossSectionState.drawProfile ? 'gg-button active' : 'gg-button'}" tip="draw_profile_help" onclick="${() => this.toggleLineDraw()}" i18n="draw_profile">Draw</button> <button id="delete-profile-btn" class="gg-button" tip="delete_help" onclick="${() => this.deleteProfile()}" i18n="delete">Delete</button></div><div class="btn-group-flex"><label for="section-width-btn" i18n="profile_width" class="gg-label">Width [m]</label> <input id="section-width-btn" class="gg-input" type="number" value="${this.crossSectionState.sectionWidthSettings.value}" min="${this.crossSectionState.sectionWidthSettings.min}" max="${this.crossSectionState.sectionWidthSettings.max}" step="${this.crossSectionState.sectionWidthSettings.step}" onchange="${(e) => this.setSectionWidth(e.target.value)}"></div><div class="btn-group-flex"><button id="reset-zoom-btn" class="gg-button" tip="profile_reset_view_help" onclick="${() => this.resetZoom()}" i18n="profile_reset_view">Reset view</button> <button id="sync-views-btn" class="${this.crossSectionState.syncViews ? 'gg-button active' : 'gg-button'}" tip="profile_sync_view_help" onclick="${() => this.setViewSync(!this.crossSectionState.syncViews)}" i18n="profile_sync_view">Sync. views</button></div><div class="btn-group-flex"><button class="gg-icon-button gg-big" tip="profile_shift_up_help" onclick="${() => this.shiftLinestring([0.0, this.crossSectionState.linestringShift])}"><img src="icons/arrow_up.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_up_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_down_help" onclick="${() => this.shiftLinestring([0.0, -this.crossSectionState.linestringShift])}"><img src="icons/arrow_down.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_down_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_left_help" onclick="${() => this.shiftLinestring([-this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_left.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_left_help')}"></button> <button class="gg-icon-button gg-big" tip="profile_shift_right_help" onclick="${() => this.shiftLinestring([this.crossSectionState.linestringShift, 0.0])}"><img src="icons/arrow_right.svg" alt="${this.context.i18nManager.getTranslation('profile_shift_right_help')}"></button></div><div class="btn-group-flex"><div class="cell"><label for="z-ratio-btn" class="gg-label">${this.context.i18nManager.getTranslation('profile_exaggeration')} (${this.crossSectionState.verticalExaggerationSettings.value})</label><div style="display: flex; align-items: center"><input id="z-ratio-btn" type="range" class="gg-range" min="${this.crossSectionState.verticalExaggerationSettings.min}" max="${this.crossSectionState.verticalExaggerationSettings.max}" step="${this.crossSectionState.verticalExaggerationSettings.step}" value="${this.crossSectionState.verticalExaggerationSettings.value}" oninput="${(e) => this.setVerticalExaggeration(Number.parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="z-ratio-reset-btn" class="reset-btn" tip="profile_exaggeration_reset_help" onclick="${() => this.setVerticalExaggeration(this.crossSectionState.verticalExaggerationSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_exaggeration_reset_help')}"></button></div></div></div><div class="btn-group-flex"><div class="cell"><label for="point-size-btn" class="gg-label">${this.context.i18nManager.getTranslation('profile_point_size')} (${this.crossSectionState.pointSizeSettings.value})</label><div style="display: flex; align-items: center"><input id="point-size-btn" type="range" class="gg-range" min="${this.crossSectionState.pointSizeSettings.min}" max="${this.crossSectionState.pointSizeSettings.max}" step="${this.crossSectionState.pointSizeSettings.step}" value="${this.crossSectionState.pointSizeSettings.value}" oninput="${(e) => this.setPointSize(Number.parseFloat(e.target.value))}" style="flex: 1; min-width: 0; box-sizing: border-box"> <button id="point-size-reset-btn" class="reset-btn" tip="profile_point_size_reset_help" onclick="${() => this.setPointSize(this.crossSectionState.pointSizeSettings.default)}"><img src="icons/restart_alt.svg" alt="${this.context.i18nManager.getTranslation('profile_point_size_reset_help')}"></button></div></div></div><div class="btn-group-flex"><label for="background-color-btn" i18n="profile_background_color" class="gg-label">Background color</label> <input id="background-color-btn" class="gg-input" type="color" value="${this.crossSectionState.backgroundColor}" oninput="${(e) => this.setBackgroundColor(e.target.value)}"></div><div class="btn-group-flex"><label for="sequential-color-btn" i18n="profile_colormap" class="gg-label">Colorscale</label> <select id="sequential-color-btn" class="gg-select" oninput="${(e) => this.setColorPalette(e.target.value)}"><option value="spectral" ?selected="${this.crossSectionState.colorPalette === 'spectral'}" i18n="palette_option_spectral">Spectral<option value="greys" ?selected="${this.crossSectionState.colorPalette === 'greys'}" i18n="palette_option_greys">Greys<option value="blues" ?selected="${this.crossSectionState.colorPalette === 'blues'}" i18n="palette_option_blues">Blues<option value="viridis" ?selected="${this.crossSectionState.colorPalette === 'viridis'}" i18n="palette_option_viridis">Viridis<option value="magma" ?selected="${this.crossSectionState.colorPalette === 'magma'}" i18n="palette_option_magma">Magma</select></div><div class="option"><label for="grid-btn" i18n="profile_toggle_grid" class="gg-label">Show grid</label> <input id="grid-btn" class="gg-checkbox" ?checked="${this.crossSectionState.gridVisible}" type="checkbox" onchange="${(e) => this.setGridVisibility(e.target.checked)}"></div><h3 i18n="profile_pointcloud">Pointclouds</h3><div class="btn-group-flex loader-progress"><div class="progress-wrapper" tip="profile_load_indicator_help"><progress id="load-progress" class="gg-progress" value="${this.crossSectionState.numberOfPoints}" max="${this.crossSectionState.maxNumberOfPoints}"></progress> <span class="progress-label">${(this.crossSectionState.loading) ? uHtml `<img src="icons/progress.svg" alt="Loading" class="gg-spin gg-small progress-icon">` : uHtml ``} ${this.crossSectionState.numberOfPoints} / ${this.crossSectionState.maxNumberOfPoints}</span></div></div><div>${this.crossSectionState.datasets.map(f => uHtml `<div class="dataset-row"><input type="checkbox" id="${f.id}" class="gg-checkbox" aria-label="${f.id}" ?checked="${f.active}" onchange="${() => this.toggleVisibility(f.id)}"> <span class="dataset-name" i18n="${f.id}">${f.id}</span> <select class="gg-select" aria-label="Color variable" oninput="${(e) => this.setColorVariable(f.id, e.target.value)}"><option value="uniform" ?selected="${f.colorby === 'uniform'}" i18n="color_option_uniform">Uniform<option value="natural" ?selected="${f.colorby === 'natural'}" i18n="color_option_natural">Natural<option value="intensity" ?selected="${f.colorby === 'intensity'}" i18n="color_option_intensity">Intensity<option value="classification" ?selected="${f.colorby === 'classification'}" i18n="color_option_classification">Classification</select> <input id="uniform-color-btn" type="color" aria-label="Uniform color" value="${f.color}" oninput="${(e) => this.setColor(f.id, e.target.value)}"></div>`)}</div><h3 i18n="profile_measure_and_annotate">Measurements and annotations</h3><div class="btn-group-flex"><button id="draw-measurements-btn" class="${this.crossSectionState.drawMeasurement ? 'gg-button active' : 'gg-button'}" tip="profile_measurement_help" onclick="${() => this.toggleMeasureDraw()}" i18n="profile_measurement" ?disabled="${!this.crossSectionState.enableMeasurement}">Measure</button> <button id="delete-measurements-btn" class="gg-button" tip="profile_delete_measurements_help" onclick="${() => this.deleteAllMeasurements()}" i18n="profile_delete_measurements">Delete all</button></div><div class="scrollable-table-container"><table id="measurements-table" class="scrollable-table"><thead><tr><th class="table-cell sticky-header" style="text-align: center"><th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_dist">DIST.<th class="table-cell sticky-header" style="text-align: right" i18n="profile_table_slope">SLOPE.<th class="table-cell sticky-header" style="text-align: center"><tbody></table></div><div class="btn-group-flex"><button id="draw-markers-btn" class="${this.crossSectionState.drawMarker ? 'gg-button active' : 'gg-button'}" tip="profile_draw_markers_help" onclick="${() => this.toggleMarkerDraw()}" i18n="profile_draw_markers" ?disabled="${!this.crossSectionState.enableAnnotation}">Annotate</button> <button id="delete-markers-btn" class="gg-button" tip="profile_delete_markers_help" onclick="${() => this.deleteAllMarkers()}" i18n="profile_delete_markers">Delete all</button></div><div class="scrollable-table-container"><table id="markers-table" class="scrollable-table"><thead><tr><th class="sticky-header" style="text-align: center" i18n="profile_table_id">ID<th class="sticky-header" style="text-align: right" i18n="profile_table_coord">COORD.<th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><th class="sticky-header" style="text-align: center"><tbody></table></div><h3 i18n="profile_print_title">Print</h3><div class="btn-group-flex"><select id="print-profile-format-btn" class="gg-select" aria-label="Print format" oninput="${(e) => this.setPrintFileFormat(e.target.value)}"><option value="svg" i18n="SVG">SVG</select> <button id="print-profile-btn" class="gg-button" tip="profile_print_help" onclick="${() => this.printPlot(this.crossSectionState.printFileFormat)}" i18n="profile_print">Print</button></div><h3 i18n="profile_download_title">Downloads</h3><div class="text-label" i18n="profile_markers_download">Markers</div><div class="btn-group-flex"><select id="download-markers-format-btn" class="gg-select" aria-label="Markers format" oninput="${(e) => this.setAnnotationsFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-markers-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature(this.points, 'markers', this.crossSectionState.downloadAnnotationsFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableAnnotationsDownload}">Download</button></div><div class="text-label" i18n="profile_linestring_download">Profile line</div><div class="btn-group-flex"><select id="download-linestring-format-btn" class="gg-select" aria-label="Profile line format" oninput="${(e) => this.setLineFileFormat(e.target.value)}"><option value="kml" i18n="KML">KML<option value="geojson" i18n="GeoJSON">GeoJSON<option value="gpx" i18n="GPX">GPX</select> <button id="download-linestring-btn" class="gg-button" tip="download_help" onclick="${() => this.exportFeature([this.linestring], 'linestring', this.crossSectionState.downloadLinestringFormat)}" i18n="download" ?disabled="${!this.crossSectionState.enableLinestringDownload}">Download</button></div></div></div>
27
27
  ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
28
28
  };
29
29
  crossSectionState;
@@ -3,7 +3,7 @@ import GirafeHTMLElement from '../../base/GirafeHTMLElement.js';
3
3
  /**
4
4
  * Create a link to a page or an email if the pattern matches
5
5
  */
6
- export declare function getLinkFriendlyString(inputStr: string): string;
6
+ export declare function getLinkFriendlyString(value: unknown): string;
7
7
  export default class SelectionPanelMobile extends GirafeHTMLElement {
8
8
  protected templateUrl: string | null;
9
9
  protected styleUrls: string[] | null;
@@ -6,12 +6,13 @@ import { isValidEmail } from '../../tools/utils/utils.js';
6
6
  /**
7
7
  * Create a link to a page or an email if the pattern matches
8
8
  */
9
- export function getLinkFriendlyString(inputStr) {
9
+ export function getLinkFriendlyString(value) {
10
+ const inputStr = String(value);
10
11
  // Create a link if starting with http
11
12
  if (inputStr.startsWith('http')) {
12
13
  return `<a href="${inputStr}" target="_blank" rel="noreferrer">${inputStr}</a>`;
13
14
  }
14
- // Create an emial link if has email form
15
+ // Create an email link if has email form
15
16
  if (isValidEmail(inputStr)) {
16
17
  return `<a href="mailto:${inputStr}">${inputStr}</a>`;
17
18
  }
@@ -1,6 +1,7 @@
1
1
  import type OlFeature from 'ol/Feature.js';
2
2
  import GirafeDraggableElement from '../../base/GirafeDraggableElement.js';
3
3
  import type { GridDataById } from '../../tools/featuretogriddatabyid.js';
4
+ import type GirafeConfig from '../../tools/configuration/girafeconfig.js';
4
5
  /**
5
6
  * Represents a Feature displayed in the SelectionWindowComponent.
6
7
  */
@@ -135,5 +136,11 @@ declare class SelectionWindowComponent extends GirafeDraggableElement {
135
136
  * @static
136
137
  */
137
138
  static createWindowFeatures(gridDataById: GridDataById): WindowFeature[];
139
+ /**
140
+ * Converts a feature property value (string, number, boolean...) to a linkified and sanitized html string.
141
+ * @returns The html string to display.
142
+ * @static
143
+ */
144
+ static formatDisplayedValue(value: unknown, config: GirafeConfig): string;
138
145
  }
139
146
  export default SelectionWindowComponent;
@@ -182,8 +182,7 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
182
182
  });
183
183
  this.displayedProperties.forEach((keyValue) => {
184
184
  keyValue[0] = this.context.i18nManager.getTranslation(this.columnAliasHelper.getColumnAlias(windowFeature.id, keyValue[0]));
185
- keyValue[1] = linkify(keyValue[1]);
186
- keyValue[1] = sanitize(keyValue[1], this.context.configManager.Config);
185
+ keyValue[1] = SelectionWindowComponent.formatDisplayedValue(keyValue[1], this.context.configManager.Config);
187
186
  });
188
187
  // Render and translate data.
189
188
  this.render();
@@ -312,5 +311,13 @@ ${this.htmlUnsafe(this.feedbackTemplateHtml ?? '')}`;
312
311
  });
313
312
  return windowFeatures;
314
313
  }
314
+ /**
315
+ * Converts a feature property value (string, number, boolean...) to a linkified and sanitized html string.
316
+ * @returns The html string to display.
317
+ * @static
318
+ */
319
+ static formatDisplayedValue(value, config) {
320
+ return sanitize(linkify(String(value)), config);
321
+ }
315
322
  }
316
323
  export default SelectionWindowComponent;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "GeoGirafe PSC",
6
6
  "url": "https://doc.geogirafe.org"
7
7
  },
8
- "version": "1.3.0-dev.2937711922",
8
+ "version": "1.3.0-dev.2938437315",
9
9
  "type": "module",
10
10
  "engines": {
11
11
  "node": ">=20.19.0"
@@ -1 +1 @@
1
- {"version":"1.3.0-dev.2937711922", "build":"2937711922", "date":"12/10/2026"}
1
+ {"version":"1.3.0-dev.2938437315", "build":"2938437315", "date":"12/10/2026"}