@panoramax/web-viewer 5.0.0-develop-d26305dd → 5.0.0-develop-be5ba1a7

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 (153) hide show
  1. package/build/cjs/index.js +1 -1
  2. package/build/cjs/index_photoviewer.js +1 -1
  3. package/build/esm/components/core/Basic.js +1 -1
  4. package/build/esm/translations/el.json +92 -1
  5. package/package.json +1 -1
  6. package/build/bundle.cjs +0 -3399
  7. package/build/bundle.cjs.map +0 -1
  8. package/build/bundle_photoviewer.cjs +0 -2510
  9. package/build/bundle_photoviewer.cjs.map +0 -1
  10. package/build/components/core/Basic.css +0 -56
  11. package/build/components/core/Basic.js +0 -378
  12. package/build/components/core/CoverageMap.css +0 -10
  13. package/build/components/core/CoverageMap.js +0 -169
  14. package/build/components/core/Editor.css +0 -33
  15. package/build/components/core/Editor.js +0 -398
  16. package/build/components/core/PhotoViewer.css +0 -70
  17. package/build/components/core/PhotoViewer.js +0 -650
  18. package/build/components/core/Viewer.css +0 -130
  19. package/build/components/core/Viewer.js +0 -711
  20. package/build/components/core/index.js +0 -10
  21. package/build/components/index.js +0 -11
  22. package/build/components/index_photoviewer.js +0 -6
  23. package/build/components/layout/BottomDrawer.js +0 -258
  24. package/build/components/layout/CorneredGrid.js +0 -143
  25. package/build/components/layout/Mini.js +0 -121
  26. package/build/components/layout/Tabs.js +0 -140
  27. package/build/components/layout/index.js +0 -9
  28. package/build/components/menus/LocationPrecisionDoc.js +0 -42
  29. package/build/components/menus/MapBackground.js +0 -110
  30. package/build/components/menus/MapFilters.js +0 -567
  31. package/build/components/menus/MapLayers.js +0 -238
  32. package/build/components/menus/MapLegend.js +0 -68
  33. package/build/components/menus/MiniPictureLegend.js +0 -73
  34. package/build/components/menus/PictureLegend.js +0 -379
  35. package/build/components/menus/PictureMetadata.js +0 -380
  36. package/build/components/menus/PlayerOptions.js +0 -93
  37. package/build/components/menus/QualityScoreDoc.js +0 -42
  38. package/build/components/menus/ReportForm.js +0 -132
  39. package/build/components/menus/SemanticsDoc.js +0 -38
  40. package/build/components/menus/SemanticsDownload.js +0 -33
  41. package/build/components/menus/SemanticsFilters.js +0 -153
  42. package/build/components/menus/SemanticsList.js +0 -413
  43. package/build/components/menus/SemanticsMetadata.js +0 -368
  44. package/build/components/menus/Share.js +0 -105
  45. package/build/components/menus/index.js +0 -22
  46. package/build/components/menus/index_photoviewer.js +0 -11
  47. package/build/components/styles.js +0 -557
  48. package/build/components/ui/AnnotationsSwitch.js +0 -159
  49. package/build/components/ui/Button.js +0 -77
  50. package/build/components/ui/ButtonGroup.css +0 -59
  51. package/build/components/ui/ButtonGroup.js +0 -69
  52. package/build/components/ui/CopyButton.js +0 -110
  53. package/build/components/ui/Grade.js +0 -54
  54. package/build/components/ui/GradeFilter.js +0 -122
  55. package/build/components/ui/IconSwitch.js +0 -193
  56. package/build/components/ui/LinkButton.js +0 -67
  57. package/build/components/ui/ListGroup.js +0 -66
  58. package/build/components/ui/ListItem.js +0 -90
  59. package/build/components/ui/Loader.js +0 -203
  60. package/build/components/ui/Map.css +0 -63
  61. package/build/components/ui/Map.js +0 -853
  62. package/build/components/ui/MapMore.js +0 -175
  63. package/build/components/ui/Photo.css +0 -50
  64. package/build/components/ui/Photo.js +0 -1502
  65. package/build/components/ui/Popup.js +0 -145
  66. package/build/components/ui/ProgressBar.js +0 -104
  67. package/build/components/ui/QualityScore.js +0 -147
  68. package/build/components/ui/SearchBar.js +0 -374
  69. package/build/components/ui/SemanticsEditor.js +0 -191
  70. package/build/components/ui/SemanticsTable.js +0 -88
  71. package/build/components/ui/Switch.js +0 -139
  72. package/build/components/ui/TogglableGroup.js +0 -157
  73. package/build/components/ui/index.js +0 -29
  74. package/build/components/ui/index_photoviewer.js +0 -21
  75. package/build/components/ui/widgets/CopyCoordinates.js +0 -75
  76. package/build/components/ui/widgets/GeoSearch.css +0 -21
  77. package/build/components/ui/widgets/GeoSearch.js +0 -150
  78. package/build/components/ui/widgets/Legend.js +0 -190
  79. package/build/components/ui/widgets/LevelSelect.css +0 -51
  80. package/build/components/ui/widgets/LevelSelect.js +0 -143
  81. package/build/components/ui/widgets/MapFiltersButton.js +0 -114
  82. package/build/components/ui/widgets/MapLayersButton.js +0 -79
  83. package/build/components/ui/widgets/OSMEditors.js +0 -155
  84. package/build/components/ui/widgets/PictureLegendActions.js +0 -99
  85. package/build/components/ui/widgets/Player.css +0 -7
  86. package/build/components/ui/widgets/Player.js +0 -154
  87. package/build/components/ui/widgets/SemanticsFiltersButton.js +0 -65
  88. package/build/components/ui/widgets/Zoom.js +0 -84
  89. package/build/components/ui/widgets/index.js +0 -16
  90. package/build/components/ui/widgets/index_photoviewer.js +0 -7
  91. package/build/img/arrow_360.svg +0 -14
  92. package/build/img/arrow_flat.svg +0 -11
  93. package/build/img/arrow_triangle.svg +0 -9
  94. package/build/img/arrow_turn.svg +0 -8
  95. package/build/img/bg_aerial.jpg +0 -0
  96. package/build/img/bg_streets.jpg +0 -0
  97. package/build/img/loader_base.jpg +0 -0
  98. package/build/img/logo_dead.svg +0 -91
  99. package/build/img/marker.svg +0 -17
  100. package/build/img/marker_blue.svg +0 -20
  101. package/build/img/osm.svg +0 -49
  102. package/build/img/panoramax.svg +0 -13
  103. package/build/img/switch_big.svg +0 -54
  104. package/build/img/switch_mini.svg +0 -48
  105. package/build/img/wd.svg +0 -1
  106. package/build/index_photoviewer.js +0 -4
  107. package/build/package.json +0 -148
  108. package/build/servers.js +0 -14
  109. package/build/translations/ar.json +0 -1
  110. package/build/translations/be.json +0 -257
  111. package/build/translations/br.json +0 -81
  112. package/build/translations/cy.json +0 -117
  113. package/build/translations/da.json +0 -300
  114. package/build/translations/de.json +0 -309
  115. package/build/translations/en.json +0 -294
  116. package/build/translations/eo.json +0 -235
  117. package/build/translations/es.json +0 -292
  118. package/build/translations/fi.json +0 -1
  119. package/build/translations/fr.json +0 -294
  120. package/build/translations/hr.json +0 -294
  121. package/build/translations/hu.json +0 -294
  122. package/build/translations/it.json +0 -306
  123. package/build/translations/ja.json +0 -182
  124. package/build/translations/ko.json +0 -1
  125. package/build/translations/nl.json +0 -305
  126. package/build/translations/nn.json +0 -1
  127. package/build/translations/pl.json +0 -169
  128. package/build/translations/pt.json +0 -296
  129. package/build/translations/pt_BR.json +0 -304
  130. package/build/translations/sv.json +0 -182
  131. package/build/translations/ti.json +0 -9
  132. package/build/translations/tr.json +0 -297
  133. package/build/translations/uk.json +0 -268
  134. package/build/translations/zh_Hant.json +0 -309
  135. package/build/utils/API.js +0 -928
  136. package/build/utils/InitParameters.js +0 -521
  137. package/build/utils/MapStyleComposer.js +0 -889
  138. package/build/utils/PanoraMapProtocol.js +0 -49
  139. package/build/utils/PhotoAdapter.js +0 -49
  140. package/build/utils/PresetsManager.js +0 -148
  141. package/build/utils/SemanticsMapProtocol.js +0 -144
  142. package/build/utils/URLHandler.js +0 -426
  143. package/build/utils/geocoder.js +0 -203
  144. package/build/utils/i18n.js +0 -128
  145. package/build/utils/index.js +0 -17
  146. package/build/utils/index_photoviewer.js +0 -14
  147. package/build/utils/indoor.js +0 -200
  148. package/build/utils/map.js +0 -788
  149. package/build/utils/picture.js +0 -507
  150. package/build/utils/semantics.js +0 -321
  151. package/build/utils/services.js +0 -148
  152. package/build/utils/utils.js +0 -433
  153. package/build/utils/widgets.js +0 -110
@@ -1,374 +0,0 @@
1
- import { LitElement, css, html, nothing } from "lit";
2
- import { classMap } from "lit/directives/class-map.js";
3
- import { map } from "lit/directives/map.js";
4
- import { fa, listenForMenuClosure } from "../../utils/widgets.js";
5
- import { faSvg } from "../styles.js";
6
- import {
7
- faCircleExclamation, faCircleNotch, faMagnifyingGlass, faXmark
8
- } from "@fortawesome/free-solid-svg-icons";
9
-
10
-
11
- /**
12
- * Search Bar Element displays an interactive search widget.
13
- * @class Panoramax.components.ui.SearchBar
14
- * @element pnx-search-bar
15
- * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
16
- * @fires Panoramax.components.ui.SearchBar#result
17
- * @example
18
- * ```html
19
- * <pnx-search-bar
20
- * id="my-search-bar"
21
- * placeholder="Search something..."
22
- * .searcher=${mysearchfct}
23
- * ._parent=${viewer}
24
- * reduceable="false"
25
- * reduced="false"
26
- * size="xxl" @result=${e => console.log(e.detail)}
27
- * >
28
- * <!-- Optional icon for display on left-side of search bar -->
29
- * </pnx-search-bar>
30
- * ```
31
- */
32
- export default class SearchBar extends LitElement {
33
- /** @private */
34
- static styles = [ faSvg, css`
35
- /* Container */
36
- .sb {
37
- display: flex;
38
- align-items: center;
39
- justify-content: space-between;
40
- gap: 5px;
41
- border: 1px solid var(--widget-border-div);
42
- border-radius: 5px;
43
- background-color: var(--widget-bg);
44
- color: var(--widget-font);
45
- height: 30px;
46
- border-radius: 20px;
47
- position: relative;
48
- padding: 0 0 0 10px;
49
- width: fit-content;
50
- max-width: 100%;
51
- box-sizing: border-box;
52
- font-family: var(--font-family);
53
- }
54
- .sb.sb-xxl {
55
- height: 40px;
56
- line-height: 40px;
57
- }
58
- .sb.sb-reduceable {
59
- width: 360px;
60
- }
61
- .sb.sb-reduceable.sb-reduced {
62
- width: fit-content;
63
- padding: 0;
64
- gap: 0;
65
- }
66
-
67
- /* Text field */
68
- .sb input {
69
- background: none;
70
- border: none !important;
71
- outline: none;
72
- height: 20px;
73
- width: 100%;
74
- font-family: var(--font-family);
75
- }
76
- .sb.sb-xxl input {
77
- font-size: 1.1em;
78
- }
79
- .sb.sb-reduceable.sb-reduced input {
80
- display: none;
81
- }
82
-
83
- /* Status icon */
84
- .sb-icon {
85
- cursor: pointer;
86
- height: 30px;
87
- line-height: 30px;
88
- width: 30px;
89
- min-width: 30px;
90
- text-align: center;
91
- }
92
- .sb.sb-xxl .sb-icon {
93
- height: 40px;
94
- line-height: 40px;
95
- width: 40px;
96
- min-width: 40px;
97
- }
98
- .sb-icon svg {
99
- pointer-events: none;
100
- width: 14px;
101
- height: 14px;
102
- }
103
-
104
- /* Search results */
105
- .sb-results {
106
- position: absolute;
107
- top: 35px;
108
- list-style: none;
109
- margin: 0;
110
- padding: 0;
111
- max-width: calc(100% - 20px);
112
- border: 1px solid var(--widget-border-div);
113
- border-radius: 10px;
114
- background-color: var(--widget-bg);
115
- color: var(--widget-font);
116
- z-index: 130;
117
- font-size: 1.05em;
118
- line-height: normal;
119
- font-family: var(--font-family);
120
- max-height: 50vh;
121
- overflow-y: auto;
122
- }
123
- .sb.sb-xxl .sb-results {
124
- top: 45px;
125
- }
126
- .sb-result,
127
- .sb-empty {
128
- display: block;
129
- padding: 5px 15px;
130
- white-space: nowrap;
131
- overflow: hidden;
132
- text-overflow: ellipsis;
133
- cursor: pointer;
134
- border-radius: 0;
135
- }
136
- .sb-result:hover {
137
- background-color: var(--widget-bg-hover);
138
- }
139
- .sb-result:first-child {
140
- border-top-right-radius: 10px;
141
- border-top-left-radius: 10px;
142
- padding-top: 15px;
143
- }
144
- .sb-result:last-child {
145
- border-bottom-right-radius: 10px;
146
- border-bottom-left-radius: 10px;
147
- padding-bottom: 15px;
148
- }
149
- ` ];
150
-
151
- /**
152
- * Component properties.
153
- * @memberof Panoramax.components.ui.SearchBar#
154
- * @type {Object}
155
- * @property {string} [id] The ID attribute set on component and prefix for input as well
156
- * @property {string} [placeholder] Default text to display on empty field
157
- * @property {boolean} [reduceable=false] Can the search bar be collapsed (for mobile view)
158
- * @property {boolean} [reduced=false] Is the search bar currently collapsed ?
159
- * @property {string} [value] The default input value
160
- * @property {string} [size=md] The component sizing (md, xxl)
161
- * @property {function} [searcher] Search callback, function that takes as parameter the input text value, and resolves on list of results ({title, subtitle} and any other data you'd like to get on validation)
162
- * @property {boolean} [no-menu-closure=false] Set to true to ignore menu closure events
163
- */
164
- static properties = {
165
- id: {type: String},
166
- placeholder: {type: String},
167
- reduceable: {type: Boolean, reflect: true},
168
- reduced: {type: Boolean, reflect: true},
169
- value: {type: String},
170
- size: {type: String},
171
- _icon: {state: true},
172
- _results: {state: true},
173
- searcher: {type: Function},
174
- "no-menu-closure": {type: Boolean},
175
- };
176
-
177
- constructor() {
178
- super();
179
-
180
- // State properties
181
- this.reduceable = false;
182
- this.reduced = false;
183
- this.placeholder = nothing;
184
- this.size = "md";
185
- this._icon = "search";
186
- this._results = null;
187
- this["no-menu-closure"] = false;
188
-
189
- // Other properties
190
- this._throttler = null;
191
- delete this._lastSearch;
192
- }
193
-
194
- /** @private */
195
- connectedCallback() {
196
- super.connectedCallback();
197
- if(!this["no-menu-closure"]) { listenForMenuClosure(this, this.reset.bind(this)); }
198
- }
199
-
200
- /** @private */
201
- attributeChangedCallback(name, _old, value) {
202
- super.attributeChangedCallback(name, _old, value);
203
-
204
- if(name === "value") {
205
- if([null, undefined, "", "null"].includes(value)) {
206
- this._icon = "search";
207
- }
208
- else {
209
- this._icon = "empty";
210
- }
211
- }
212
- }
213
-
214
- /** @private */
215
- _onIconClick() {
216
- if(["empty", "warn"].includes(this._icon)) {
217
- this.reset();
218
- }
219
- if(this.reduceable && this._icon == "search") {
220
- this.reduced = !this.reduced;
221
- }
222
- }
223
-
224
- /** @private */
225
- _onInputChange(e) {
226
- this.value = e.target.value;
227
- this._throttledSearch();
228
- }
229
-
230
- /** @private */
231
- _onResultClick(item) {
232
- /**
233
- * Event for search result clicked
234
- * @event Panoramax.components.ui.SearchBar#result
235
- * @type {CustomEvent}
236
- * @property {object|null} detail The data associated to clicked item (format based on searcher function results), or null on reset
237
- */
238
- this.dispatchEvent(new CustomEvent("result", {bubbles: true, composed: true, detail: item}));
239
-
240
- this._results = null;
241
- if(this._throttler) {
242
- clearTimeout(this._throttler);
243
- this._throttler = null;
244
- }
245
-
246
- if(!this.reduceable && item) {
247
- this.value = item?.title;
248
- this._icon = "empty";
249
- }
250
- else {
251
- this.value = "";
252
- this._icon = "search";
253
- if(this.reduceable) { this.reduced = true; }
254
- }
255
- }
256
-
257
- /**
258
- * Limit search calls to every 500ms
259
- * @private
260
- */
261
- _throttledSearch() {
262
- if(this._throttler) {
263
- clearTimeout(this._throttler);
264
- delete this._throttler;
265
- }
266
-
267
- this._throttler = setTimeout(this._search.bind(this), 500);
268
- }
269
-
270
- /**
271
- * Perform real search
272
- * @private
273
- */
274
- _search() {
275
- if(!this.value || this.value.length == 0) {
276
- this.reset();
277
- return;
278
- }
279
-
280
- if(!this.searcher) {
281
- console.warn("No search handler defined");
282
- return;
283
- }
284
-
285
- this._icon = "loading";
286
- this._results = null;
287
-
288
- this.searcher(this.value).then(data => {
289
- if(this._icon !== "loading") { return; }
290
-
291
- this._icon = "empty";
292
- if(!data || data.length == 0) {
293
- this._results = [];
294
- }
295
- else if(data === true) {
296
- this._results = null;
297
- }
298
- else {
299
- this._results = data;
300
- if(!this["no-menu-closure"]) {
301
- this._parent?.dispatchEvent(new CustomEvent("menu-opened", { detail: { menu: this }}));
302
- }
303
- }
304
- }).catch(e => {
305
- console.error(e);
306
- this._icon = "warn";
307
- });
308
- }
309
-
310
- /**
311
- * Empty results list and reset search bar content.
312
- */
313
- reset() {
314
- this._onResultClick(null);
315
- }
316
-
317
- /** @private */
318
- render() {
319
- const classes = {
320
- sb: true,
321
- "sb-xxl": this.size === "xxl",
322
- "sb-reduceable": this.reduceable,
323
- "sb-reduced": this.reduced,
324
- };
325
-
326
- return html`<div
327
- id=${this.id}
328
- class=${classMap(classes)}
329
- part="container"
330
- >
331
- <slot name="pre" class=${classMap({"sb-reduced": this.reduced})}></slot>
332
-
333
- <input
334
- id="${this.id}-input"
335
- type="text"
336
- placeholder=${this.placeholder}
337
- autocomplete="off"
338
- @change=${this._onInputChange.bind(this)}
339
- @keypress=${this._onInputChange.bind(this)}
340
- @paste=${this._onInputChange.bind(this)}
341
- @input=${this._onInputChange.bind(this)}
342
- .value=${this.value || ""}
343
- part="input"
344
- />
345
-
346
- <span
347
- class="sb-icon"
348
- @click=${this._onIconClick.bind(this)}
349
- >
350
- ${this._icon == "search" ? fa(faMagnifyingGlass) : nothing}
351
- ${this._icon == "loading" ? fa(faCircleNotch, { classes: ["fa-spin"] }) : nothing}
352
- ${this._icon == "empty" ? fa(faXmark) : nothing}
353
- ${this._icon == "warn" ? fa(faCircleExclamation) : nothing}
354
- </span>
355
-
356
- ${!this.reduced && this._results ? html`
357
- <div class="sb-results">
358
- ${this._results.length === 0 ? html`
359
- <div class="sb-empty">${this._parent?._t?.pnx.search_empty}</div>
360
- ` : nothing}
361
-
362
- ${map(this._results, i => html`
363
- <div class="sb-result" @click=${() => this._onResultClick(i)}>
364
- ${i.title}
365
- ${i.subtitle && i.subtitle != "" ? html`<br /><small>${i.subtitle}</small>` : nothing}
366
- </div>
367
- `)}
368
- </div>
369
- ` : nothing}
370
- </div>`;
371
- }
372
- }
373
-
374
- customElements.define("pnx-search-bar", SearchBar);
@@ -1,191 +0,0 @@
1
- import { LitElement, css, html } from "lit";
2
- import Basic from "../core/Basic.js";
3
- import { computeDiffTags, parseSemanticsString, semanticsToString } from "../../utils/semantics.js";
4
- import { textarea } from "../styles.js";
5
- import JSON5 from "json5";
6
-
7
- /**
8
- * Semantics Editor offer an easy-to-use input for adding or editing semantics tags.
9
- *
10
- * It manipulates list of `{key: "mypanokey", value: "myvalue"}` entries through `semantics` attribute.
11
- *
12
- * @class Panoramax.components.ui.SemanticsEditor
13
- * @element pnx-semantics-editor
14
- * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
15
- * @fires Panoramax.components.ui.SemanticsEditor#change
16
- * @example
17
- * ```html
18
- * <!-- Basic example -->
19
- * <pnx-semantics-editor
20
- * id="editor"
21
- * semantics=${mypic.semantics}
22
- * ._t=${viewer._t}
23
- * onchange=${e => console.log(e.detail.semantics)}
24
- * />
25
- *
26
- * <!-- You can access editor and check its validity through native web browser functions -->
27
- * <script>
28
- * const editor = document.getElementById("editor");
29
- * console.log(editor.checkValidity()); // True if input is valid
30
- * </script>
31
- *
32
- * <!-- You can change specifically style of textarea -->
33
- * <style>
34
- * pnx-semantics-editor::part(text) {
35
- * color: blue;
36
- * }
37
- * </style>
38
- * ```
39
- */
40
- export default class SemanticsEditor extends LitElement {
41
- static styles = [textarea, css`
42
- textarea:invalid {
43
- border: 2px solid var(--red);
44
- background-color:var(--beige);
45
- }
46
- `];
47
-
48
- /**
49
- * Component properties.
50
- * @memberof Panoramax.components.ui.SemanticsEditor#
51
- * @type {Object}
52
- * @property {object} [semantics] The `semantics` field of a picture or annotation feature. It is updated when field changes, but reflect the whole list of new tags (not delta needed by API). If you want delta, please use getDiff function.
53
- * @property {number} [rows=3] The amount of rows shown for textarea
54
- */
55
- static properties = {
56
- semantics: {converter: Basic.GetJSONConverter(), reflect: true},
57
- rows: {type: Number},
58
- _valid: {state: true},
59
- _t: {converter: Basic.GetJSONConverter()},
60
- _firstSemantics: {state: true},
61
- };
62
-
63
- constructor() {
64
- super();
65
- this.semantics = null;
66
- this._valid = true;
67
- this._firstSemantics = null;
68
- this.rows = 3;
69
- }
70
-
71
- /** @private */
72
- connectedCallback() {
73
- super.connectedCallback();
74
- this._firstSemantics = this.semantics === null ? [] : JSON5.parse(JSON5.stringify(this.semantics));
75
- }
76
-
77
- /**
78
- * Get current delta between initial tags and user changes.
79
- * @memberof Panoramax.components.ui.SemanticsEditor#
80
- * @returns {object[]} The list of tag changes (in API format)
81
- */
82
- getDiff() {
83
- return computeDiffTags(this._firstSemantics || [], this.semantics);
84
- }
85
-
86
- /**
87
- * Check if input is having a valid value.
88
- * @memberof Panoramax.components.ui.SemanticsEditor#
89
- * @returns {boolean} True if it's valid
90
- */
91
- checkValidity() {
92
- return this._valid;
93
- }
94
-
95
- /**
96
- * Force display of invalid input
97
- * @memberof Panoramax.components.ui.SemanticsEditor#
98
- */
99
- reportValidity() {
100
- this.renderRoot.querySelector("textarea")?.reportValidity();
101
- }
102
-
103
- /**
104
- * Forces Editor to goes back to its empty, initial state.
105
- * @param {object} [baseSemantics=null] Initial existing semantics you want to show in editor. This is useful for getting a diff of only new semantic entries. Leave empty if no tags pre-exist.
106
- * @memberof Panoramax.components.ui.SemanticsEditor#
107
- */
108
- reset(baseSemantics = null) {
109
- this.semantics = null;
110
- this._valid = true;
111
-
112
- const txt = this.renderRoot.querySelector("textarea");
113
- txt?.setCustomValidity("");
114
- txt?.reportValidity();
115
-
116
- this._firstSemantics = baseSemantics;
117
- this.semantics = baseSemantics;
118
- }
119
-
120
- /**
121
- * Forces Editor to save current text and parse semantics.
122
- * @memberof Panoramax.components.ui.SemanticsEditor#
123
- */
124
- forceInput() {
125
- const target = this.renderRoot.querySelector("textarea");
126
- this._onInput({ target });
127
- this._onBlur({ target });
128
- }
129
-
130
- /** @private */
131
- _onInput(e) {
132
- const tarea = e.target;
133
- try {
134
- this.semantics = parseSemanticsString(tarea.value) || [];
135
- this._valid = true;
136
- } catch (err) {
137
- if(err.message !== "Invalid tags") { console.error(err); }
138
- this._valid = false;
139
- }
140
- }
141
-
142
- /** @private */
143
- _onBlur(e) {
144
- const prevValidity = e.target.checkValidity();
145
-
146
- if(this._valid) {
147
- e.target.setCustomValidity("");
148
-
149
- /**
150
- * Event for value change.
151
- *
152
- * Note that this event is launched only on valid input.
153
- *
154
- * @event Panoramax.components.ui.SemanticsEditor#change
155
- * @type {CustomEvent}
156
- * @property {object[]} detail.semantics The new tags list (in API semantics property format)
157
- * @property {object[]} detail.delta The delta between old and current tags (expected by API)
158
- */
159
- this.dispatchEvent(new CustomEvent("change", {
160
- detail: {
161
- semantics: this.semantics || [],
162
- delta: computeDiffTags(this._firstSemantics || [], this.semantics),
163
- }
164
- }));
165
- }
166
- else if(prevValidity) { // Do not call again if already shows up, to fix Chrome issue
167
- e.target.setCustomValidity(this._t?.pnx.semantics_editor_error || "Invalid syntax");
168
- e.target.reportValidity();
169
- }
170
- }
171
-
172
- /** @private */
173
- render() {
174
- return html`
175
- <textarea
176
- part="text"
177
- autocomplete="off"
178
- autocorrect="off"
179
- autocapitalize="off"
180
- spellcheck="false"
181
- placeholder=${this._t?.pnx.semantics_editor_example || "key1=value1\nprefix|key2=value2"}
182
- @input=${this._onInput}
183
- @blur=${this._onBlur}
184
- rows=${this.rows}
185
- .value=${semanticsToString(this.semantics)}
186
- ></textarea>
187
- `;
188
- }
189
- }
190
-
191
- customElements.define("pnx-semantics-editor", SemanticsEditor);
@@ -1,88 +0,0 @@
1
- import { LitElement, css, html, nothing } from "lit";
2
- import { table } from "../styles.js";
3
- import { groupByPrefix } from "../../utils/semantics.js";
4
-
5
- /**
6
- * Semantics Tables display all semantics tags from either a picture or an annotation.
7
- *
8
- * @class Panoramax.components.ui.SemanticsTable
9
- * @element pnx-semantics-table
10
- * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
11
- * @example
12
- * ```html
13
- * <pnx-semantics-table source=${picture.properties} ._t=${viewer._t} />
14
- * ```
15
- */
16
- export default class SemanticsTable extends LitElement {
17
- /** @private */
18
- static styles = [ table, css`
19
- :host { display: block; }
20
- th:first-child, td:first-child { width: 40%; }
21
- td { vertical-align: top; }
22
-
23
- td small { color: var(--grey-semi-dark); }
24
- td a small { color: unset; }
25
- .qualifiers { margin-top: 5px; }
26
- .qualifiers > b { margin: 8px 0; }
27
- .qualifiers ul {
28
- list-style: none;
29
- margin: 0px 0px 0px 15px;
30
- padding: 0;
31
- }
32
-
33
- img.prefix-logo {
34
- max-width: 15px;
35
- max-height: 15px;
36
- aspect-ratio: 1;
37
- vertical-align: middle;
38
- }
39
- ` ];
40
-
41
- /**
42
- * Component properties.
43
- * @memberof Panoramax.components.ui.SemanticsTable#
44
- * @type {Object}
45
- * @property {object} [source] The picture or annotation feature (having a `semantics` property)
46
- */
47
- static properties = {
48
- source: {type: Object},
49
- };
50
-
51
- render() {
52
- if(!this.source) { return nothing; }
53
-
54
- const groups = groupByPrefix(this.source.semantics);
55
-
56
- return html`<table>
57
- <thead>
58
- <tr><th>${this._t.pnx.semantics_key}</th><th>${this._t.pnx.semantics_value}</th></tr>
59
- </thead>
60
- <tbody>
61
- ${groups.map(g => g.tags.map(tag => html`
62
- <tr>
63
- <td>
64
- ${g.prefix != ""
65
- ? (g.logo
66
- ? html`<img src=${g.logo} class="prefix-logo" alt=${g.prefix} title=${g.title} />`
67
- : html`<small>(${g.prefix})</small>`)
68
- : nothing
69
- }
70
- ${g.key_transform ? g.key_transform(tag, this._t) : tag.key}
71
- </td>
72
- <td>
73
- ${g.value_transform ? g.value_transform(tag, this._t) : tag.value}
74
- ${tag.qualifiers ? html`<div class="qualifiers">
75
- <b>${this._t.pnx.semantics_qualifiers}</b>
76
- <ul>
77
- ${tag.qualifiers.map(q => html`<li>${q.subkey} = ${q.value}</li>`)}
78
- </ul>
79
- </div>` : nothing}
80
- </td>
81
- </tr>
82
- `))}
83
- </tbody>
84
- </table>`;
85
- }
86
- }
87
-
88
- customElements.define("pnx-semantics-table", SemanticsTable);