@panoramax/web-viewer 4.1.0-develop-381f3f1a → 4.1.0-develop-22cdb9e7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/build/index.js +138 -75
- package/build/index.js.map +1 -1
- package/docs/reference/components/menus/SemanticsMetadata.md +15 -0
- package/docs/reference/utils/API.md +14 -0
- package/docs/reference.md +2 -0
- package/mkdocs.yml +2 -0
- package/package.json +1 -1
- package/src/components/core/Basic.js +5 -1
- package/src/components/menus/PictureMetadata.js +8 -86
- package/src/components/menus/SemanticsMetadata.js +186 -0
- package/src/components/menus/index.js +1 -0
- package/src/components/styles.js +22 -0
- package/src/components/ui/SemanticsEditor.js +1 -1
- package/src/components/ui/SemanticsTable.js +1 -0
- package/src/translations/en.json +6 -0
- package/src/translations/fr.json +6 -0
- package/src/utils/API.js +40 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<a name="Panoramax.components.menus.SemanticsMetadata"></a>
|
|
2
|
+
|
|
3
|
+
## Panoramax.components.menus.SemanticsMetadata ⇐ <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
4
|
+
**Kind**: static class of <code>Panoramax.components.menus</code>
|
|
5
|
+
**Extends**: <code>[lit.LitElement](https://lit.dev/docs/api/LitElement/)</code>
|
|
6
|
+
**Element**: pnx-semantics-metadata
|
|
7
|
+
<a name="new_Panoramax.components.menus.SemanticsMetadata_new"></a>
|
|
8
|
+
|
|
9
|
+
### new SemanticsMetadata()
|
|
10
|
+
Semantics metadata displays detailed info about semantic attributes of a single picture.
|
|
11
|
+
|
|
12
|
+
**Example**
|
|
13
|
+
```html
|
|
14
|
+
<pnx-semantics-metadata ._parent=${viewer}></pnx-semantics-metadata>
|
|
15
|
+
```
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
* [.searchUsers(query)](#Panoramax.utils.API+searchUsers) ⇒ <code>Promise</code>
|
|
26
26
|
* [.getUserName(userId)](#Panoramax.utils.API+getUserName) ⇒ <code>Promise</code>
|
|
27
27
|
* [.sendReport(data)](#Panoramax.utils.API+sendReport) ⇒ <code>Promise</code>
|
|
28
|
+
* [.sendPictureSemantics(picMeta, semanticsDiff)](#Panoramax.utils.API+sendPictureSemantics) ⇒ <code>Promise</code>
|
|
28
29
|
* ["broken"](#Panoramax.utils.API+event_broken)
|
|
29
30
|
* ["ready"](#Panoramax.utils.API+event_ready)
|
|
30
31
|
* _static_
|
|
@@ -284,6 +285,19 @@ Send a report to API
|
|
|
284
285
|
| --- | --- | --- |
|
|
285
286
|
| data | <code>object</code> | The input form data |
|
|
286
287
|
|
|
288
|
+
<a name="Panoramax.utils.API+sendPictureSemantics"></a>
|
|
289
|
+
|
|
290
|
+
### api.sendPictureSemantics(picMeta, semanticsDiff) ⇒ <code>Promise</code>
|
|
291
|
+
Send picture semantics change to origin API.
|
|
292
|
+
|
|
293
|
+
**Kind**: instance method of [<code>API</code>](#Panoramax.utils.API)
|
|
294
|
+
**Fulfil**: <code>object</code> The JSON API response
|
|
295
|
+
|
|
296
|
+
| Param | Type | Description |
|
|
297
|
+
| --- | --- | --- |
|
|
298
|
+
| picMeta | <code>object</code> | The picture metadata |
|
|
299
|
+
| semanticsDiff | <code>object</code> | The difference in semantics compared to original data |
|
|
300
|
+
|
|
287
301
|
<a name="Panoramax.utils.API+event_broken"></a>
|
|
288
302
|
|
|
289
303
|
### "broken"
|
package/docs/reference.md
CHANGED
|
@@ -36,6 +36,7 @@ All-in-one, ready-to-use menus for complex operations. Note that they don't embe
|
|
|
36
36
|
- [PlayerOptions](./reference/components/menus/PlayerOptions.md) : speed and constrast settings for play sequence feature.
|
|
37
37
|
- [QualityScoreDoc](./reference/components/menus/QualityScoreDoc.md) : details about quality score computation.
|
|
38
38
|
- [ReportForm](./reference/components/menus/ReportForm.md) : picture issue reporting form.
|
|
39
|
+
- [SemanticsMetadata](./reference/components/menus/SemanticsMetadata.md) : display full details about a picture semantics.
|
|
39
40
|
- [ShareMenu](./reference/components/menus/ShareMenu.md) : links and iframe sharing.
|
|
40
41
|
|
|
41
42
|
## `components.ui`
|
|
@@ -83,4 +84,5 @@ General helpers outside of single component scope:
|
|
|
83
84
|
|
|
84
85
|
- [API](./reference/utils/API.md) : the Panoramax API helper (many get & post HTTP helpers).
|
|
85
86
|
- [InitParameters](./reference/utils/InitParameters.md) : helper for merging URL and component parameters.
|
|
87
|
+
- [PresetsManager](./reference/utils/PresetsManager.md) : the semantics attributes presets manager.
|
|
86
88
|
- [URLHandler](./reference/utils/URLHandler.md) : the window URL manager (changes query part).
|
package/mkdocs.yml
CHANGED
|
@@ -76,6 +76,7 @@ nav:
|
|
|
76
76
|
- PlayerOptions: 'reference/components/menus/PlayerOptions.md'
|
|
77
77
|
- QualityScoreDoc: 'reference/components/menus/QualityScoreDoc.md'
|
|
78
78
|
- ReportForm: 'reference/components/menus/ReportForm.md'
|
|
79
|
+
- SemanticsMetadata: 'reference/components/menus/SemanticsMetadata.md'
|
|
79
80
|
- ShareMenu: 'reference/components/menus/ShareMenu.md'
|
|
80
81
|
- ui:
|
|
81
82
|
- widgets:
|
|
@@ -110,4 +111,5 @@ nav:
|
|
|
110
111
|
- utils:
|
|
111
112
|
- API: 'reference/utils/API.md'
|
|
112
113
|
- InitParameters: 'reference/utils/InitParameters.md'
|
|
114
|
+
- PresetsManager: 'reference/utils/PresetsManager.md'
|
|
113
115
|
- URLHandler: 'reference/utils/URLHandler.md'
|
package/package.json
CHANGED
|
@@ -345,7 +345,11 @@ export default class Basic extends LitElement {
|
|
|
345
345
|
else if(typeof value === "object" || Array.isArray(value)) { return value; }
|
|
346
346
|
else { return JSON5.parse(value); }
|
|
347
347
|
},
|
|
348
|
-
toAttribute: (value) =>
|
|
348
|
+
toAttribute: (value) => {
|
|
349
|
+
if(value === null || value === "") { return ""; }
|
|
350
|
+
else if(typeof value === "string") { return value; }
|
|
351
|
+
else { return JSON5.stringify(value); }
|
|
352
|
+
}
|
|
349
353
|
};
|
|
350
354
|
}
|
|
351
355
|
}
|
|
@@ -9,12 +9,10 @@ import { faImages } from "@fortawesome/free-solid-svg-icons/faImages";
|
|
|
9
9
|
import { faScroll } from "@fortawesome/free-solid-svg-icons/faScroll";
|
|
10
10
|
import { faQuestion } from "@fortawesome/free-solid-svg-icons/faQuestion";
|
|
11
11
|
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
|
|
12
|
-
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
|
13
|
-
import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
|
|
14
12
|
import { faTags } from "@fortawesome/free-solid-svg-icons/faTags";
|
|
15
|
-
import { faSvg, titles, textarea, hidden } from "../styles";
|
|
13
|
+
import { faSvg, titles, textarea, hidden, dataBlocks } from "../styles";
|
|
16
14
|
import { createWebComp } from "../../utils/widgets";
|
|
17
|
-
import { getGPSPrecision
|
|
15
|
+
import { getGPSPrecision } from "../../utils/picture";
|
|
18
16
|
import { PanoramaxMetaCatalogURL } from "../../utils/services";
|
|
19
17
|
import {
|
|
20
18
|
getGrade, QUALITYSCORE_GPS_VALUES, QUALITYSCORE_RES_360_VALUES,
|
|
@@ -35,30 +33,14 @@ const missing = () => fa(faQuestion, {styles: {height: "16px"}});
|
|
|
35
33
|
*/
|
|
36
34
|
export default class PictureMetadata extends LitElement {
|
|
37
35
|
/** @private */
|
|
38
|
-
static styles = [ faSvg, titles, textarea, hidden, css`
|
|
36
|
+
static styles = [ faSvg, titles, textarea, hidden, dataBlocks, css`
|
|
39
37
|
div[slot="content"] {
|
|
40
38
|
padding: 5px 10px;
|
|
41
39
|
background-color: #ededed;
|
|
42
40
|
}
|
|
43
41
|
|
|
44
|
-
/* Small data blocks */
|
|
45
42
|
.data-block {
|
|
46
|
-
display: inline-block;
|
|
47
43
|
min-width: 50%;
|
|
48
|
-
margin: 8px 0;
|
|
49
|
-
box-sizing: border-box;
|
|
50
|
-
vertical-align: top;
|
|
51
|
-
}
|
|
52
|
-
.data-block h5 {
|
|
53
|
-
font-size: 0.8em;
|
|
54
|
-
font-weight: 400;
|
|
55
|
-
color: var(--blue-dark);
|
|
56
|
-
margin: 0 0 5px 0;
|
|
57
|
-
}
|
|
58
|
-
.data-block h5 pnx-button { vertical-align: middle; }
|
|
59
|
-
.data-block h5 svg.svg-inline--fa { height: 14px; }
|
|
60
|
-
.data-block div {
|
|
61
|
-
font-size: 0.8em;
|
|
62
44
|
}
|
|
63
45
|
|
|
64
46
|
pnx-semantics-table {
|
|
@@ -70,14 +52,8 @@ export default class PictureMetadata extends LitElement {
|
|
|
70
52
|
/** @private */
|
|
71
53
|
static properties = {
|
|
72
54
|
_meta: {state: true},
|
|
73
|
-
_semanticsPicShowAll: {state: true},
|
|
74
55
|
};
|
|
75
56
|
|
|
76
|
-
constructor() {
|
|
77
|
-
super();
|
|
78
|
-
this._semanticsPicShowAll = false;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
57
|
/** @private */
|
|
82
58
|
connectedCallback() {
|
|
83
59
|
super.connectedCallback();
|
|
@@ -238,61 +214,6 @@ export default class PictureMetadata extends LitElement {
|
|
|
238
214
|
];
|
|
239
215
|
}
|
|
240
216
|
|
|
241
|
-
// Semantics data
|
|
242
|
-
const hasSemantics = (
|
|
243
|
-
(this._meta.properties.semantics || []).length > 0
|
|
244
|
-
|| (this._meta.properties.annotations || []).length > 0
|
|
245
|
-
);
|
|
246
|
-
let semanticsData = [];
|
|
247
|
-
if(hasSemantics) {
|
|
248
|
-
// Hashtags
|
|
249
|
-
const hashtags = getHashTags(this._meta);
|
|
250
|
-
if(hashtags.length > 0) {
|
|
251
|
-
semanticsData.push({
|
|
252
|
-
title: this._parent?._t.pnx.semantics_hashtags,
|
|
253
|
-
style: "width: 100%",
|
|
254
|
-
content: hashtags.join(" ")
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Full list of picture tags
|
|
259
|
-
semanticsData.push({
|
|
260
|
-
title: this._parent?._t.pnx.semantics_tags_picture,
|
|
261
|
-
style: "width: 100%",
|
|
262
|
-
content: html`${this._meta.properties.semantics?.length > 0
|
|
263
|
-
? html`
|
|
264
|
-
<pnx-button
|
|
265
|
-
kind="outline"
|
|
266
|
-
size="sm"
|
|
267
|
-
style="width: 100%"
|
|
268
|
-
@click=${() => this._semanticsPicShowAll = !this._semanticsPicShowAll}
|
|
269
|
-
>
|
|
270
|
-
${this._semanticsPicShowAll ? fa(faChevronUp) : fa(faChevronDown)}
|
|
271
|
-
${this._semanticsPicShowAll ? this._parent?._t.pnx.semantics_hide_all_tags : this._parent?._t.pnx.semantics_show_all_tags}
|
|
272
|
-
</pnx-button>
|
|
273
|
-
<pnx-semantics-table
|
|
274
|
-
._t=${this._parent?._t}
|
|
275
|
-
.source=${this._meta.properties}
|
|
276
|
-
style="margin-top: 5px"
|
|
277
|
-
class=${this._semanticsPicShowAll ? "":"pnx-hidden"}
|
|
278
|
-
/>
|
|
279
|
-
`
|
|
280
|
-
: this._parent?._t.pnx.semantics_tags_picture_none
|
|
281
|
-
}`
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
// Annotations (features in picture)
|
|
285
|
-
semanticsData.push({
|
|
286
|
-
title: this._parent?._t.pnx.semantics_features,
|
|
287
|
-
style: "width: 100%",
|
|
288
|
-
content: html`
|
|
289
|
-
${this._meta.properties.annotations?.length > 0
|
|
290
|
-
? html`<pnx-annotations-list ._parent=${this._parent} />`
|
|
291
|
-
: this._parent?._t.pnx.semantics_features_none}
|
|
292
|
-
`
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
217
|
// EXIF data
|
|
297
218
|
const exifData = Object.entries(this._meta.properties.exif)
|
|
298
219
|
.sort()
|
|
@@ -426,10 +347,11 @@ export default class PictureMetadata extends LitElement {
|
|
|
426
347
|
qualityData
|
|
427
348
|
) : nothing}
|
|
428
349
|
|
|
429
|
-
${
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
350
|
+
<h4 slot="title">${fa(faTags)} ${this._parent?._t.pnx.semantics_title}</h4>
|
|
351
|
+
<div slot="content" class="data-blocks">
|
|
352
|
+
<pnx-semantics-metadata ._parent=${this._parent}></pnx-semantics-metadata>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
433
355
|
|
|
434
356
|
${this._meta.properties?.exif ? this._toTab( // EXIF
|
|
435
357
|
html`${fa(faScroll)} ${this._parent?._t.pnx.metadata_exif}`,
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { LitElement, html, nothing, css } from "lit";
|
|
2
|
+
import { fa, onceParentAvailable } from "../../utils/widgets";
|
|
3
|
+
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
|
4
|
+
import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
|
|
5
|
+
import { faPen } from "@fortawesome/free-solid-svg-icons/faPen";
|
|
6
|
+
import { faFloppyDisk } from "@fortawesome/free-solid-svg-icons/faFloppyDisk";
|
|
7
|
+
import { faRotateLeft } from "@fortawesome/free-solid-svg-icons/faRotateLeft";
|
|
8
|
+
import { getHashTags } from "../../utils/picture";
|
|
9
|
+
import { hidden, dataBlocks } from "../styles";
|
|
10
|
+
import { getUserAccount } from "../../utils/utils";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Semantics metadata displays detailed info about semantic attributes of a single picture.
|
|
14
|
+
* @class Panoramax.components.menus.SemanticsMetadata
|
|
15
|
+
* @element pnx-semantics-metadata
|
|
16
|
+
* @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
|
|
17
|
+
* @example
|
|
18
|
+
* ```html
|
|
19
|
+
* <pnx-semantics-metadata ._parent=${viewer}></pnx-semantics-metadata>
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export default class SemanticsMetadata extends LitElement {
|
|
23
|
+
/** @private */
|
|
24
|
+
static styles = [ hidden, dataBlocks, css`
|
|
25
|
+
.data-block {
|
|
26
|
+
width: 100%;
|
|
27
|
+
}
|
|
28
|
+
` ];
|
|
29
|
+
|
|
30
|
+
/** @private */
|
|
31
|
+
static properties = {
|
|
32
|
+
_meta: {state: true},
|
|
33
|
+
_picShowAll: {state: true},
|
|
34
|
+
_editPicSem: {state: true},
|
|
35
|
+
_editedPicSemTags: {state: true},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
constructor() {
|
|
39
|
+
super();
|
|
40
|
+
this._meta = {};
|
|
41
|
+
this._picShowAll = false;
|
|
42
|
+
this._editPicSem = false;
|
|
43
|
+
this._editedPicSemTags = null;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** @private */
|
|
47
|
+
connectedCallback() {
|
|
48
|
+
super.connectedCallback();
|
|
49
|
+
|
|
50
|
+
onceParentAvailable(this).then(() => {
|
|
51
|
+
this._meta = this._parent?.psv?.getPictureMetadata();
|
|
52
|
+
this._parent?.oncePSVReady?.().then(() => {
|
|
53
|
+
this._parent.psv.addEventListener("picture-loaded", () => {
|
|
54
|
+
this._meta = this._parent.psv.getPictureMetadata();
|
|
55
|
+
});
|
|
56
|
+
this._parent.psv.addEventListener("annotation-click", () => {
|
|
57
|
+
const tabs = this.shadowRoot.querySelector("pnx-tabs");
|
|
58
|
+
if(tabs) { tabs.setAttribute("activeTabIndex", 4); }
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** @private */
|
|
65
|
+
_onStartEditPicSem() {
|
|
66
|
+
this._editedPicSemTags = null;
|
|
67
|
+
this._editPicSem = true;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** @private */
|
|
71
|
+
_onPicSemEditorChange(e) {
|
|
72
|
+
this._editedPicSemTags = e.detail;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** @private */
|
|
76
|
+
_onSavePicSem() {
|
|
77
|
+
const field = this.renderRoot.querySelector("#pnx-sem-pic-editor");
|
|
78
|
+
|
|
79
|
+
// Check field validity
|
|
80
|
+
if(!field || !field.checkValidity()) {
|
|
81
|
+
alert(this._parent?._t.pnx.semantics_cantsave_invalid);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Send changes to API
|
|
86
|
+
this._parent?.api.sendPictureSemantics(this._meta, this._editedPicSemTags.delta).then(newPic => {
|
|
87
|
+
const newMeta = Object.assign({}, this._meta);
|
|
88
|
+
newMeta.properties.semantics = newPic.properties.semantics;
|
|
89
|
+
this._meta = newMeta;
|
|
90
|
+
this._editPicSem = false;
|
|
91
|
+
alert(this._parent?._t.pnx.semantics_send_ok);
|
|
92
|
+
}).catch(e => {
|
|
93
|
+
this._editPicSem = false;
|
|
94
|
+
alert(this._parent?._t.pnx.semantics_send_fail);
|
|
95
|
+
console.error("Can't send semantics", e);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** @private */
|
|
100
|
+
render() {
|
|
101
|
+
/* eslint-disable indent */
|
|
102
|
+
if(!this._meta?.properties) { return; }
|
|
103
|
+
|
|
104
|
+
const hashtags = getHashTags(this._meta);
|
|
105
|
+
const canEdit = !this._meta.origInstance && getUserAccount() !== null;
|
|
106
|
+
|
|
107
|
+
return html`
|
|
108
|
+
${hashtags.length > 0 ? html`
|
|
109
|
+
<div class="data-block">
|
|
110
|
+
<h5>${this._parent?._t.pnx.semantics_hashtags}</h5>
|
|
111
|
+
<div>${hashtags.join(" ")}</div>
|
|
112
|
+
</div>
|
|
113
|
+
` : nothing}
|
|
114
|
+
|
|
115
|
+
<div class="data-block">
|
|
116
|
+
<h5>
|
|
117
|
+
${this._parent?._t.pnx.semantics_tags_picture}
|
|
118
|
+
|
|
119
|
+
${canEdit && this._editPicSem ?
|
|
120
|
+
html`<pnx-button-group style="display: inline-block; vertical-align: middle;">
|
|
121
|
+
<pnx-button
|
|
122
|
+
kind="superinline"
|
|
123
|
+
title=${this._parent?._t.pnx.semantics_undo}
|
|
124
|
+
@click=${() => this._editPicSem = false}
|
|
125
|
+
>
|
|
126
|
+
${fa(faRotateLeft)}
|
|
127
|
+
</pnx-button>
|
|
128
|
+
<pnx-button
|
|
129
|
+
kind="superinline"
|
|
130
|
+
title=${this._parent?._t.pnx.semantics_save}
|
|
131
|
+
@click=${this._onSavePicSem}
|
|
132
|
+
>
|
|
133
|
+
${fa(faFloppyDisk)}
|
|
134
|
+
</pnx-button>
|
|
135
|
+
</pnx-button-group>`
|
|
136
|
+
: (canEdit ? html`<pnx-button
|
|
137
|
+
kind="superinline"
|
|
138
|
+
title=${this._parent?._t.pnx.semantics_edit}
|
|
139
|
+
@click=${this._onStartEditPicSem}
|
|
140
|
+
>
|
|
141
|
+
${fa(faPen)}
|
|
142
|
+
</pnx-button>` : "")
|
|
143
|
+
}
|
|
144
|
+
</h5>
|
|
145
|
+
<div>
|
|
146
|
+
${this._editPicSem ? html`
|
|
147
|
+
<pnx-semantics-editor
|
|
148
|
+
id="pnx-sem-pic-editor"
|
|
149
|
+
.semantics=${this._editedPicSemTags ? this._editedPicSemTags.semantics : this._meta.properties.semantics}
|
|
150
|
+
._t=${this._parent._t}
|
|
151
|
+
@change=${this._onPicSemEditorChange}
|
|
152
|
+
></pnx-semantics-editor>
|
|
153
|
+
` : html`
|
|
154
|
+
${this._meta.properties.semantics?.length > 0 ? html`
|
|
155
|
+
<pnx-button
|
|
156
|
+
kind="outline"
|
|
157
|
+
size="sm"
|
|
158
|
+
style="width: 100%"
|
|
159
|
+
@click=${() => this._picShowAll = !this._picShowAll}
|
|
160
|
+
>
|
|
161
|
+
${this._picShowAll ? fa(faChevronUp) : fa(faChevronDown)}
|
|
162
|
+
${this._picShowAll ? this._parent?._t.pnx.semantics_hide_all_tags : this._parent?._t.pnx.semantics_show_all_tags}
|
|
163
|
+
</pnx-button>
|
|
164
|
+
<pnx-semantics-table
|
|
165
|
+
._t=${this._parent?._t}
|
|
166
|
+
.source=${this._meta.properties}
|
|
167
|
+
style="margin-top: 5px"
|
|
168
|
+
class=${this._picShowAll ? "":"pnx-hidden"}
|
|
169
|
+
/>`
|
|
170
|
+
: this._parent?._t.pnx.semantics_tags_picture_none}
|
|
171
|
+
`}
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
|
|
175
|
+
<div class="data-block">
|
|
176
|
+
<h5>${this._parent?._t.pnx.semantics_features}</h5>
|
|
177
|
+
<div>${this._meta.properties.annotations?.length > 0
|
|
178
|
+
? html`<pnx-annotations-list ._parent=${this._parent} />`
|
|
179
|
+
: this._parent?._t.pnx.semantics_features_none}
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
customElements.define("pnx-semantics-metadata", SemanticsMetadata);
|
|
@@ -14,4 +14,5 @@ export {default as PictureMetadata} from "./PictureMetadata";
|
|
|
14
14
|
export {default as PlayerOptions} from "./PlayerOptions";
|
|
15
15
|
export {default as QualityScoreDoc} from "./QualityScoreDoc";
|
|
16
16
|
export {default as ReportForm} from "./ReportForm";
|
|
17
|
+
export {default as SemanticsMetadata} from "./SemanticsMetadata";
|
|
17
18
|
export {default as Share} from "./Share";
|
package/src/components/styles.js
CHANGED
|
@@ -149,6 +149,7 @@ export const btn = css`
|
|
|
149
149
|
.pnx-btn ::slotted(.svg-inline--fa),
|
|
150
150
|
.pnx-btn slot .svg-inline--fa {
|
|
151
151
|
height: 16px;
|
|
152
|
+
pointer-events: none;
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
/* Sizing */
|
|
@@ -487,3 +488,24 @@ export const iconify = css`
|
|
|
487
488
|
height: 1em;
|
|
488
489
|
}
|
|
489
490
|
`;
|
|
491
|
+
|
|
492
|
+
// Tabbed-legend data blocks
|
|
493
|
+
export const dataBlocks = css`
|
|
494
|
+
.data-block {
|
|
495
|
+
display: inline-block;
|
|
496
|
+
margin: 8px 0;
|
|
497
|
+
box-sizing: border-box;
|
|
498
|
+
vertical-align: top;
|
|
499
|
+
}
|
|
500
|
+
.data-block h5 {
|
|
501
|
+
font-size: 0.8em;
|
|
502
|
+
font-weight: 400;
|
|
503
|
+
color: var(--blue-dark);
|
|
504
|
+
margin: 0 0 5px 0;
|
|
505
|
+
}
|
|
506
|
+
.data-block h5 pnx-button { vertical-align: middle; }
|
|
507
|
+
.data-block h5 svg.svg-inline--fa { height: 14px; }
|
|
508
|
+
.data-block div {
|
|
509
|
+
font-size: 0.8em;
|
|
510
|
+
}
|
|
511
|
+
`;
|
|
@@ -82,7 +82,7 @@ export default class SemanticsEditor extends LitElement {
|
|
|
82
82
|
getDiff() {
|
|
83
83
|
return computeDiffTags(this._firstSemantics || [], this.semantics);
|
|
84
84
|
}
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
/**
|
|
87
87
|
* Check if input is having a valid value.
|
|
88
88
|
* @memberof Panoramax.components.ui.SemanticsEditor#
|
|
@@ -16,6 +16,7 @@ import { groupByPrefix } from "../../utils/semantics";
|
|
|
16
16
|
export default class SemanticsTable extends LitElement {
|
|
17
17
|
/** @private */
|
|
18
18
|
static styles = [ table, css`
|
|
19
|
+
:host { display: block; }
|
|
19
20
|
th:first-child, td:first-child { width: 30%; }
|
|
20
21
|
td { vertical-align: top; }
|
|
21
22
|
|
package/src/translations/en.json
CHANGED
|
@@ -201,6 +201,12 @@
|
|
|
201
201
|
},
|
|
202
202
|
"semantics_editor_error": "The syntax is invalid. Your tags may look like:\nkey=value\nprefix|key=value\nprefix|key[qualif_key=qualif_val]=value\n\nMax key length is 256 characters, max value length 2048 characters.",
|
|
203
203
|
"semantics_editor_example": "key=value\nprefix|key=value",
|
|
204
|
+
"semantics_edit": "Edit attributes",
|
|
205
|
+
"semantics_save": "Save your edits",
|
|
206
|
+
"semantics_undo": "Cancel your edits",
|
|
207
|
+
"semantics_cantsave_invalid": "Can't save your attributes, input is not valid",
|
|
208
|
+
"semantics_send_fail": "We can't send your edits for now, please retry later.",
|
|
209
|
+
"semantics_send_ok": "Your edits were successfully sent",
|
|
204
210
|
"report": "Report",
|
|
205
211
|
"report_auth": "This report will be sent using your account \"{a}\"",
|
|
206
212
|
"report_nature_label": "Nature of the issue",
|
package/src/translations/fr.json
CHANGED
|
@@ -201,6 +201,12 @@
|
|
|
201
201
|
},
|
|
202
202
|
"semantics_editor_error": "La syntaxe est invalide. Vos attributs doivent avoir cette forme:\nclé=valeur\npréfixe|clé=valeur\npréfixe|clé[qualif_clé=qualif_val]=valeur\n\nLongueur max des clés : 256 caractères, max des valeurs 2048 caractères.",
|
|
203
203
|
"semantics_editor_example": "clé=valeur\npréfixe|clé=valeur",
|
|
204
|
+
"semantics_edit": "Modifier les attributs",
|
|
205
|
+
"semantics_save": "Enregistrer vos modifications",
|
|
206
|
+
"semantics_undo": "Annuler vos modifications",
|
|
207
|
+
"semantics_cantsave_invalid": "Impossible de sauvegarder les modifications, les attributs ne sont pas valides",
|
|
208
|
+
"semantics_send_fail": "Nous n'avons pas pu enregistrer vos modifications, merci de réessayer plus tard",
|
|
209
|
+
"semantics_send_ok": "Vos modifications ont bien été enregistrées",
|
|
204
210
|
"report": "Signaler",
|
|
205
211
|
"report_auth": "Ce signalement sera envoyé en utilisant votre compte \"{a}\"",
|
|
206
212
|
"report_nature_label": "Nature du problème",
|
package/src/utils/API.js
CHANGED
|
@@ -789,6 +789,46 @@ export default class API extends EventTarget {
|
|
|
789
789
|
});
|
|
790
790
|
}
|
|
791
791
|
|
|
792
|
+
/**
|
|
793
|
+
* Send picture semantics change to origin API.
|
|
794
|
+
* @memberOf Panoramax.utils.API#
|
|
795
|
+
* @param {object} picMeta The picture metadata
|
|
796
|
+
* @param {object} semanticsDiff The difference in semantics compared to original data
|
|
797
|
+
* @returns {Promise}
|
|
798
|
+
* @fulfil {object} The JSON API response
|
|
799
|
+
*/
|
|
800
|
+
sendPictureSemantics(picMeta, semanticsDiff) {
|
|
801
|
+
/* eslint-disable */
|
|
802
|
+
if(!this.isReady()) { throw new Error("API is not ready to use"); }
|
|
803
|
+
if(!picMeta?.sequence?.id || !picMeta?.id) { throw new Error("Missing IDs from picture"); }
|
|
804
|
+
|
|
805
|
+
// Check if it's from metacatalog
|
|
806
|
+
let picLink = this.getPictureMetadataUrl(picMeta.id, picMeta.sequence.id);
|
|
807
|
+
if(picMeta?.origInstance) {
|
|
808
|
+
picLink = `${picMeta.origInstance.href}/api/collections/${picMeta.sequence.id}/items/${picMeta.id}`;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
const opts = {
|
|
812
|
+
...this._getFetchOptions(),
|
|
813
|
+
method: "PATCH",
|
|
814
|
+
body: JSON.stringify({ semantics: semanticsDiff }),
|
|
815
|
+
headers: { "Content-Type": "application/json" },
|
|
816
|
+
};
|
|
817
|
+
|
|
818
|
+
return fetch(picLink, opts)
|
|
819
|
+
.then(async res => {
|
|
820
|
+
if(res.status >= 400) {
|
|
821
|
+
let txt = await res.text();
|
|
822
|
+
try {
|
|
823
|
+
txt = JSON.parse(txt)["message"];
|
|
824
|
+
}
|
|
825
|
+
catch(e) {} // eslint-disable-line no-empty
|
|
826
|
+
return Promise.reject(txt);
|
|
827
|
+
}
|
|
828
|
+
return res.json();
|
|
829
|
+
});
|
|
830
|
+
}
|
|
831
|
+
|
|
792
832
|
/**
|
|
793
833
|
* Checks URL string validity
|
|
794
834
|
* @memberOf Panoramax.utils.API
|