@panoramax/web-viewer 3.2.3-develop-6e69906d → 3.2.3-develop-8b82a4e5

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 (61) hide show
  1. package/build/index.css +2 -2
  2. package/build/index.css.map +1 -1
  3. package/build/index.js +535 -216
  4. package/build/index.js.map +1 -1
  5. package/build/widgets.html +1 -1
  6. package/docs/reference/components/core/PhotoViewer.md +2 -0
  7. package/docs/reference/components/core/Viewer.md +2 -0
  8. package/docs/reference/components/layout/BottomDrawer.md +35 -0
  9. package/docs/reference/components/layout/Tabs.md +45 -0
  10. package/docs/reference/components/menus/PictureLegend.md +1 -0
  11. package/docs/reference/components/ui/Button.md +3 -2
  12. package/docs/reference/components/ui/CopyButton.md +7 -4
  13. package/docs/reference/components/ui/LinkButton.md +1 -0
  14. package/docs/reference/components/ui/ListGroup.md +22 -0
  15. package/docs/reference/components/ui/widgets/Legend.md +11 -0
  16. package/docs/reference/components/ui/widgets/OSMEditors.md +15 -0
  17. package/docs/reference/components/ui/widgets/PictureLegendActions.md +32 -0
  18. package/docs/reference.md +6 -2
  19. package/mkdocs.yml +5 -1
  20. package/package.json +1 -1
  21. package/public/widgets.html +45 -9
  22. package/src/components/core/Basic.css +1 -0
  23. package/src/components/core/PhotoViewer.css +0 -23
  24. package/src/components/core/PhotoViewer.js +41 -22
  25. package/src/components/core/Viewer.css +6 -31
  26. package/src/components/core/Viewer.js +40 -11
  27. package/src/components/layout/BottomDrawer.js +204 -0
  28. package/src/components/layout/CorneredGrid.js +3 -0
  29. package/src/components/layout/Tabs.js +133 -0
  30. package/src/components/layout/index.js +2 -0
  31. package/src/components/menus/PictureLegend.js +162 -23
  32. package/src/components/menus/PictureMetadata.js +220 -110
  33. package/src/components/menus/Share.js +2 -142
  34. package/src/components/styles.js +47 -47
  35. package/src/components/ui/Button.js +4 -2
  36. package/src/components/ui/CopyButton.js +34 -5
  37. package/src/components/ui/LinkButton.js +6 -7
  38. package/src/components/ui/ListGroup.js +66 -0
  39. package/src/components/ui/Map.js +4 -1
  40. package/src/components/ui/QualityScore.js +19 -24
  41. package/src/components/ui/TogglableGroup.js +47 -53
  42. package/src/components/ui/index.js +1 -0
  43. package/src/components/ui/widgets/Legend.js +29 -6
  44. package/src/components/ui/widgets/OSMEditors.js +153 -0
  45. package/src/components/ui/widgets/PictureLegendActions.js +131 -0
  46. package/src/components/ui/widgets/index.js +5 -4
  47. package/src/translations/en.json +14 -8
  48. package/src/translations/fr.json +14 -8
  49. package/src/utils/InitParameters.js +2 -1
  50. package/src/utils/geocoder.js +3 -1
  51. package/src/utils/picture.js +1 -2
  52. package/src/utils/widgets.js +5 -43
  53. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +12 -32
  54. package/tests/components/core/__snapshots__/Viewer.test.js.snap +5 -25
  55. package/tests/components/ui/__snapshots__/Photo.test.js.snap +6 -2
  56. package/tests/utils/InitParameters.test.js +7 -9
  57. package/tests/utils/__snapshots__/picture.test.js.snap +13 -4
  58. package/tests/utils/picture.test.js +2 -2
  59. package/tests/utils/widgets.test.js +0 -59
  60. package/docs/reference/components/ui/widgets/Share.md +0 -15
  61. package/src/components/ui/widgets/Share.js +0 -30
@@ -1,6 +1,7 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { panel } from "../styles";
3
3
  import { listenForMenuClosure } from "../../utils/widgets";
4
+ import { classMap } from "lit/directives/class-map.js";
4
5
 
5
6
  /**
6
7
  * Togglable Group element allows to make a menu appear/disappear based on button click.
@@ -27,9 +28,8 @@ export default class TogglableGroup extends LitElement {
27
28
  height: 100%;
28
29
  }
29
30
 
30
- .pnx-panel {
31
- z-index: 130;
32
- }
31
+ .pnx-panel { z-index: 130; }
32
+ .pnx-panel-fixed { position: fixed; }
33
33
  ` ];
34
34
 
35
35
  /**
@@ -88,71 +88,65 @@ export default class TogglableGroup extends LitElement {
88
88
 
89
89
  /** @private */
90
90
  adjustMenuPosition(btn) {
91
- const smallWidth = window.innerWidth < 576;
92
- const menu = this.shadowRoot.querySelector(".pnx-panel");
91
+ const btnMenuMargin = 5;
92
+ const borderMargin = 10;
93
+
94
+ // Reset menu position
95
+ const menu = this.shadowRoot.querySelector("div[part='menu']");
96
+ menu.style.top = null;
97
+ menu.style.bottom = null;
98
+ menu.style.right = null;
99
+ menu.style.left = null;
100
+ menu.style.overflowY = null;
101
+
102
+ // Get positions on screen
93
103
  const btnRect = btn.getBoundingClientRect();
94
104
  let menuRect = menu.getBoundingClientRect();
105
+ const fitsWidth = menuRect.right <= window.innerWidth - borderMargin;
106
+ const fitsHeight = menuRect.bottom <= window.innerHeight - borderMargin;
95
107
 
96
- const overflowHeight = menuRect.height > window.innerHeight * 0.8;
97
- if(overflowHeight) {
98
- menu.style.height = `${window.innerHeight * 0.8}px`;
99
- menu.style.overflowY = "scroll";
100
- menuRect = menu.getBoundingClientRect();
108
+ // No overflow = space a bit under button
109
+ if(fitsWidth && fitsHeight) {
110
+ menu.style.top = `${btnRect.bottom+btnMenuMargin}px`;
101
111
  }
102
- else {
103
- // Try to remove height limiter
104
- menu.style.height = "unset";
105
- menu.style.overflowY = "unset";
112
+ // Overflows width+height = put at button's top+left
113
+ else if(!fitsWidth && !fitsHeight) {
114
+ menu.style.right = `${window.innerWidth - btnRect.left + btnMenuMargin}px`;
115
+ menu.style.bottom = `${window.innerHeight - btnRect.bottom}px`;
116
+
117
+ // Check if it doesn't overflow on top
106
118
  menuRect = menu.getBoundingClientRect();
107
-
108
- // If height is too high, put back limitation
109
- if(menuRect.height > window.innerHeight * 0.8) {
110
- menu.style.height = `${window.innerHeight * 0.8}px`;
111
- menu.style.overflowY = "scroll";
112
- menuRect = menu.getBoundingClientRect();
119
+ if(menuRect.top - borderMargin < 0) {
120
+ menu.style.bottom = `${borderMargin}px`;
121
+ menu.style.top = `${btnRect.top}px`;
122
+ menu.style.overflowY = "auto";
113
123
  }
114
124
  }
115
-
116
- const overflowRight = btnRect.left + menuRect.width > window.innerWidth;
117
- const overflowBottom = btnRect.bottom + menuRect.height > window.innerHeight;
118
- const overflowTop = btnRect.top - menuRect.height < 0;
119
-
120
- if(overflowRight && overflowBottom && overflowTop) {
121
- menu.style.top = smallWidth ? "0px" : `${btnRect.height + 5}px`;
122
- menu.style.bottom = null;
123
- menu.style.right = `${btnRect.width + 5}px`;
124
- menu.style.left = null;
125
+ // Overflows height = limit height
126
+ else if(!fitsHeight) {
127
+ menu.style.bottom = `${borderMargin}px`;
128
+ menu.style.top = `${btnRect.bottom+btnMenuMargin}px`;
129
+ menu.style.overflowY = "auto";
125
130
  }
126
- else if(overflowRight && overflowBottom) {
127
- menu.style.top = null;
128
- menu.style.bottom = "0px";
129
- menu.style.right = `${btnRect.width + 5}px`;
130
- menu.style.left = null;
131
- }
132
- else if(overflowRight) {
133
- menu.style.top = smallWidth ? "0px" : `${btnRect.height + 5}px`;
134
- menu.style.bottom = null;
135
- menu.style.right = smallWidth ? `${btnRect.width + 5}px` : "0px";
136
- menu.style.left = null;
137
- }
138
- else if(overflowBottom && !overflowTop) {
139
- menu.style.top = null;
140
- menu.style.bottom = "0px";
141
- menu.style.left = `${btnRect.width + 5}px`;
142
- }
143
- else {
144
- menu.style.top = `${btnRect.height + 5}px`;
145
- menu.style.right = null;
146
- menu.style.left = "0px";
147
- menu.style.bottom = null;
131
+ // Overflows width = move to left
132
+ else if(!fitsWidth) {
133
+ menu.style.top = `${btnRect.bottom+btnMenuMargin}px`;
134
+ menu.style.right = `${window.innerWidth - btnRect.right}px`;
148
135
  }
149
136
  }
150
137
 
151
138
  /** @private */
152
139
  render() {
140
+ const panelClasses = {
141
+ "pnx-panel": true,
142
+ "pnx-panel-fixed": true,
143
+ "pnx-hidden": !this._opened,
144
+ "pnx-padded": this.padded !== "false",
145
+ };
146
+
153
147
  return html`<div class="container">
154
148
  <slot name="button" @slotchange=${this.handleButtonSlotChange}></slot>
155
- <div class="pnx-panel ${this._opened ? "" : "pnx-hidden"} ${this.padded == "false" ? "" : "pnx-padded"}">
149
+ <div class=${classMap(panelClasses)} part="menu">
156
150
  <slot></slot>
157
151
  </div>
158
152
  </div>`;
@@ -8,6 +8,7 @@ export {default as Button} from "./Button";
8
8
  export {default as CopyButton} from "./CopyButton";
9
9
  export {default as Grade} from "./Grade";
10
10
  export {default as LinkButton} from "./LinkButton";
11
+ export {default as ListGroup} from "./ListGroup";
11
12
  export {default as Loader} from "./Loader";
12
13
  export {default as Map} from "./Map";
13
14
  export {default as MapMore} from "./MapMore";
@@ -3,6 +3,7 @@ import { panel } from "../../styles";
3
3
  import { fa } from "../../../utils/widgets";
4
4
  import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
5
5
  import PanoramaxImg from "../../../img/panoramax.svg";
6
+ import { classMap } from "lit/directives/class-map.js";
6
7
 
7
8
  /**
8
9
  * Legend widget, handling switch between map and photo components.
@@ -10,25 +11,39 @@ import PanoramaxImg from "../../../img/panoramax.svg";
10
11
  * @class Panoramax.components.ui.widgets.Legend
11
12
  * @element pnx-widget-legend
12
13
  * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
14
+ * @slot `editors` External links to map editors, or any tool that may be helpful. Defaults to OSM tools (iD & JOSM).
13
15
  * @example
14
16
  * ```html
17
+ * <!-- Default legend -->
15
18
  * <pnx-widget-legend
16
19
  * _parent=${viewer}
17
20
  * focus="map"
18
21
  * picture="PICTURE-ID-IF-ANY"
19
22
  * />
23
+ *
24
+ * <!-- With custom editor links -->
25
+ * <pnx-widget-legend
26
+ * _parent=${viewer}
27
+ * focus="map"
28
+ * picture="PICTURE-ID-IF-ANY"
29
+ * >
30
+ * <div slot="editors"><a href="http://my.own.tool">Edit in my own tool</a></div>
31
+ * </pnx-widget-legend>
20
32
  * ```
21
33
  */
22
34
  export default class Legend extends LitElement {
23
35
  /** @private */
24
36
  static styles = [panel, css`
25
- .pnx-panel.pnx-padded {
37
+ .pnx-panel[part="panel"] {
26
38
  border-radius: 10px;
27
- padding: 10px;
28
39
  position: relative;
40
+ max-width: 80vw;
41
+ z-index: 121; /* To appear above mini component */
42
+ min-width: unset;
43
+ }
44
+ .pnx-panel[part="panel"].pnx-padded {
45
+ padding: 10px;
29
46
  width: 250px;
30
- max-width: 80vh;
31
- z-index: 120;
32
47
  }
33
48
  .presentation {
34
49
  font-size: 0.9em;
@@ -54,7 +69,12 @@ export default class Legend extends LitElement {
54
69
  };
55
70
 
56
71
  render() {
57
- return html`<div class="pnx-panel pnx-padded" part="panel">
72
+ const classes = {
73
+ "pnx-panel": true,
74
+ "pnx-padded": this.focus == "map",
75
+ };
76
+
77
+ return html`<div class=${classMap(classes)} part="panel">
58
78
  <div
59
79
  class="presentation"
60
80
  style=${this.focus != "map" && this.picture ? "display: none": ""}
@@ -70,7 +90,10 @@ export default class Legend extends LitElement {
70
90
  <pnx-picture-legend
71
91
  ._parent=${this._parent}
72
92
  style=${this.focus == "map" ? "display: none": ""}
73
- ></pnx-picture-legend>
93
+ collapsable
94
+ >
95
+ <slot slot="editors" name="editors"></slot>
96
+ </pnx-picture-legend>
74
97
  <pnx-map-legend
75
98
  ._parent=${this._parent}
76
99
  style=${this.focus != "map" ? "display: none": ""}
@@ -0,0 +1,153 @@
1
+ import { LitElement, html, nothing, css } from "lit";
2
+ import { fa } from "../../../utils/widgets";
3
+ import { josmBboxParameters } from "../../../utils/utils";
4
+ import { faLocationDot } from "@fortawesome/free-solid-svg-icons/faLocationDot";
5
+ import { faSatelliteDish } from "@fortawesome/free-solid-svg-icons/faSatelliteDish";
6
+ import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons/faExternalLinkAlt";
7
+
8
+ const JOSM_REMOTE_URL = "http://127.0.0.1:8111";
9
+ const ID_URL = "https://www.openstreetmap.org/edit?editor=id";
10
+
11
+ /**
12
+ * OSM Editors component offers direct links to OpenStreetMap's iD and JOSM editors.
13
+ * @class Panoramax.components.ui.widgets.OSMEditors
14
+ * @element pnx-widget-osmeditors
15
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
16
+ * @example
17
+ * ```html
18
+ * <pnx-widget-osmeditors _parent=${viewer} />
19
+ * ```
20
+ */
21
+ export default class OSMEditors extends LitElement {
22
+ /** @private */
23
+ static properties = {
24
+ _pic: {state: true},
25
+ _josm: {state: true},
26
+ };
27
+
28
+ /** @private */
29
+ static styles = css`
30
+ :host { display: inline-flex; gap: 5px; }
31
+ :host > * { flex: 1; }
32
+ pnx-link-button::part(btn) { height: auto; }
33
+ `;
34
+
35
+ constructor() {
36
+ super();
37
+ this._josm = false;
38
+ }
39
+
40
+ /** @private */
41
+ connectedCallback() {
42
+ super.connectedCallback();
43
+ this._parent?.onceReady().then(() => {
44
+ this._parent.onceFirstPicLoaded().then(this._onPictureLoad.bind(this));
45
+ this._parent.psv.addEventListener("picture-loaded", this._onPictureLoad.bind(this));
46
+ });
47
+ }
48
+
49
+ /** @private */
50
+ _onPictureLoad() {
51
+ this._pic = this._parent?.psv?.getPictureMetadata();
52
+ }
53
+
54
+ /**
55
+ * Enable or disable JOSM live editing using [Remote](https://josm.openstreetmap.de/wiki/Help/RemoteControlCommands)
56
+ * @private
57
+ */
58
+ _toggleJOSMLive() {
59
+ this._josm = !this._josm;
60
+
61
+ if(this._josm) {
62
+ // Check if JOSM remote is enabled
63
+ fetch(JOSM_REMOTE_URL+"/version")
64
+ .then(() => {
65
+ // First loading : download + zoom
66
+ const p1 = josmBboxParameters(this._parent?.psv?.getPictureMetadata?.());
67
+ if(p1) {
68
+ const url = `${JOSM_REMOTE_URL}/load_and_zoom?${p1}`;
69
+ fetch(url).catch(e => {
70
+ console.warn(e);
71
+ this._toggleJOSMLive();
72
+ });
73
+ }
74
+
75
+ // Enable event listening
76
+ this._josmListener = () => {
77
+ const p2 = josmBboxParameters(this._parent?.psv?.getPictureMetadata?.());
78
+ if(p2) {
79
+ // Next loadings : just zoom
80
+ // This avoids desktop focus to go on JOSM instead of
81
+ // staying on web browser
82
+ const url = `${JOSM_REMOTE_URL}/zoom?${p2}`;
83
+ fetch(url).catch(e => {
84
+ console.warn(e);
85
+ this._toggleJOSMLive();
86
+ });
87
+ }
88
+ };
89
+ this._parent?.psv?.addEventListener?.("picture-loaded", this._josmListener);
90
+ this._parent?.psv?.addEventListener?.("picture-loading", this._josmListener);
91
+ })
92
+ .catch(e => {
93
+ console.warn(e);
94
+ alert(this._parent?._t.pnx.error_josm);
95
+ this._toggleJOSMLive();
96
+ });
97
+ }
98
+ else {
99
+ if(this._josmListener) {
100
+ this._parent?.psv?.removeEventListener?.("picture-loading", this._josmListener);
101
+ this._parent?.psv?.removeEventListener?.("picture-loaded", this._josmListener);
102
+ delete this._josmListener;
103
+ }
104
+ }
105
+ }
106
+
107
+ /** @private */
108
+ render() {
109
+ // Mobile -> Geo URI
110
+ if(this._parent?.isWidthSmall()) {
111
+ return html`
112
+ <pnx-link-button
113
+ size="sm"
114
+ href="geo:${this._pic.gps[1]},${this._pic.gps[0]};u=3"
115
+ >
116
+ ${fa(faExternalLinkAlt)} ${this._parent?._t.pnx.geo_uri}
117
+ </pnx-link-button>
118
+ `;
119
+ }
120
+ else {
121
+ const idOpts = this._pic && {
122
+ "map": `19/${this._pic.gps[1]}/${this._pic.gps[0]}`,
123
+ "source": "Panoramax",
124
+ "photo_overlay": "panoramax",
125
+ "photo": `panoramax/${this._pic.id}`,
126
+ };
127
+ const idUrl = idOpts && `${ID_URL}#${new URLSearchParams(idOpts).toString()}`;
128
+
129
+ return html`
130
+ <pnx-link-button
131
+ size="sm"
132
+ href=${idUrl}
133
+ target="_blank"
134
+ title="${this._parent?._t.pnx.contribute_id}"
135
+ >
136
+ ${fa(faLocationDot)} ${this._parent?._t.pnx.id}
137
+ </pnx-link-button>
138
+
139
+ <pnx-button
140
+ id="pnx-edit-josm"
141
+ size="sm"
142
+ active=${this._josm ? "" : nothing}
143
+ @click=${this._toggleJOSMLive}
144
+ title="${this._parent?._t.pnx.josm_live}"
145
+ >
146
+ ${fa(faSatelliteDish)} ${this._parent?._t.pnx.josm}
147
+ </pnx-button>
148
+ `;
149
+ }
150
+ }
151
+ }
152
+
153
+ customElements.define("pnx-widget-osmeditors", OSMEditors);
@@ -0,0 +1,131 @@
1
+ import { LitElement, html, nothing, css } from "lit";
2
+ import { fa } from "../../../utils/widgets";
3
+ import { faEllipsisV } from "@fortawesome/free-solid-svg-icons/faEllipsisV";
4
+ import { noprint } from "../../styles";
5
+
6
+ /**
7
+ * Picture Legend Actions is a menu showing up complementary actions for picture legend.
8
+ * @class Panoramax.components.ui.widgets.PictureLegendActions
9
+ * @element pnx-picture-legend-actions
10
+ * @extends [lit.LitElement](https://lit.dev/docs/api/LitElement/)
11
+ * @example
12
+ * ```html
13
+ * <pnx-picture-legend-actions _parent=${viewer} />
14
+ * ```
15
+ */
16
+ export default class PictureLegendActions extends LitElement {
17
+ /** @private */
18
+ static styles = [ noprint, css`
19
+ pnx-togglable-group::part(menu) {
20
+ border-radius: 5px;
21
+ min-width: unset;
22
+ }
23
+ `];
24
+
25
+ /**
26
+ * Component properties.
27
+ * @memberof Panoramax.components.ui.widgets.PictureLegendActions#
28
+ * @type {Object}
29
+ * @property {boolean} [full=false] Show advanced actions
30
+ */
31
+ static properties = {
32
+ full: { type: Boolean },
33
+ _baseUrl: {state: true},
34
+ _meta: { state: true },
35
+ };
36
+
37
+ constructor() {
38
+ super();
39
+ this.full = false;
40
+ this._onUrlChange();
41
+ }
42
+
43
+ /** @private */
44
+ connectedCallback() {
45
+ super.connectedCallback();
46
+
47
+ this._parent?.onceReady().then(() => {
48
+ this._onUrlChange();
49
+ this._meta = this._parent.psv.getPictureMetadata();
50
+ this._parent.urlHandler.addEventListener("url-changed", this._onUrlChange.bind(this));
51
+ this._parent.psv.addEventListener("picture-loaded", () => {
52
+ this._meta = this._parent.psv.getPictureMetadata();
53
+ });
54
+ });
55
+ }
56
+
57
+ /** @private */
58
+ _onUrlChange() {
59
+ this._baseUrl = window.location.href.replace(/\/$/, "");
60
+ }
61
+
62
+ /** @private */
63
+ _onPrint() {
64
+ this._closeGroup();
65
+ window.print();
66
+ }
67
+
68
+ /** @private */
69
+ _closeGroup() {
70
+ this.renderRoot.querySelector("pnx-togglable-group").close();
71
+ }
72
+
73
+ /** @private */
74
+ _onShareClick() {
75
+ this._closeGroup();
76
+ this._parent._showShareOptions();
77
+ }
78
+
79
+ /** @private */
80
+ _onReportClick() {
81
+ this._closeGroup();
82
+ this._parent._showReportForm();
83
+ }
84
+
85
+ /** @private */
86
+ render() {
87
+ const shareUrl = this._parent?.urlHandler?.nextShortLink(this._baseUrl) || this._baseUrl;
88
+
89
+ return html`<pnx-togglable-group padded="false" id="pic-legend-headline-menu" ._parent=${this._parent}>
90
+ <pnx-button slot="button" kind="inline">${fa(faEllipsisV)}</pnx-button>
91
+ <pnx-list-group class="pnx-print-hidden" @click=${this._closeMenu}>
92
+ ${this.full ? html`
93
+ <a
94
+ download
95
+ target="_blank"
96
+ href=${this._meta?.panorama?.hdUrl}
97
+ @click=${this._closeGroup}
98
+ >${this._parent?._t.pnx.share_image}</a>
99
+ <pnx-copy-button ._t=${this._parent?._t} text=${shareUrl} unstyled>
100
+ ${this._parent?._t.pnx.share_page}
101
+ </pnx-copy-button>
102
+ ${this._parent.isWidthSmall() ? nothing : html`<button @click=${this._onPrint}>
103
+ ${this._parent?._t.pnx.share_print}
104
+ </button>`}
105
+ ${this._parent?.api?.getRSSURL() && html`
106
+ <a
107
+ target="_blank"
108
+ href=${this._parent?.api.getRSSURL(this._parent?.map?.getBounds?.())}
109
+ title=${this._parent?._t.pnx.share_rss_title}
110
+ @click=${this._closeGroup}
111
+ >
112
+ ${this._parent?._t.pnx.share_rss}
113
+ </a>
114
+ `}
115
+ ` : html`
116
+ <button @click=${this._onReportClick}>
117
+ ${this._parent?._t.pnx.report}
118
+ </button>
119
+ <button @click=${this._onShareClick}>
120
+ ${this._parent?._t.pnx.share}
121
+ </button>
122
+ ${this._meta ? html`<pnx-copy-button ._t=${this._parent?._t} text=${this._meta.id} unstyled>
123
+ ${this._parent?._t.pnx.metadata_general_copy_picid}
124
+ </pnx-copy-button>` : nothing}
125
+ ` }
126
+ </pnx-list-group>
127
+ </pnx-togglable-group>`;
128
+ }
129
+ }
130
+
131
+ customElements.define("pnx-picture-legend-actions", PictureLegendActions);
@@ -3,10 +3,11 @@
3
3
  * @module Panoramax:components:ui:widgets
4
4
  */
5
5
 
6
- export {default as Zoom} from "./Zoom";
7
- export {default as Player} from "./Player";
8
- export {default as Share} from "./Share";
9
6
  export {default as GeoSearch} from "./GeoSearch";
7
+ export {default as Legend} from "./Legend";
10
8
  export {default as MapFiltersButton} from "./MapFiltersButton";
11
9
  export {default as MapLayersButton} from "./MapLayersButton";
12
- export {default as Legend} from "./Legend";
10
+ export {default as OSMEditors} from "./OSMEditors";
11
+ export {default as PictureLegendActions} from "./PictureLegendActions";
12
+ export {default as Player} from "./Player";
13
+ export {default as Zoom} from "./Zoom";
@@ -52,8 +52,9 @@
52
52
  "sequence_speed": "Player speed",
53
53
  "legend_license": "License: {l}",
54
54
  "legend_title": "Show details of picture",
55
- "edit_osm": "Edit OSM",
56
55
  "id": "iD",
56
+ "contribute_id": "Contribute to OpenStreetMap with iD editor",
57
+ "geo_uri": "External app",
57
58
  "josm": "JOSM",
58
59
  "josm_live": "Enable JOSM automatic sync on picture loading",
59
60
  "loading_labels_serious": [
@@ -102,6 +103,8 @@
102
103
  "filter_zoom_in": "Zoom-in to see this filter",
103
104
  "picture_flat": "Classic",
104
105
  "picture_360": "360°",
106
+ "picture_flat_long": "Classic picture",
107
+ "picture_360_long": "Panoramic picture",
105
108
  "filter_qualityscore": "Quality score",
106
109
  "filter_qualityscore_help": "Click to enable or disable",
107
110
  "qualityscore_title": "About the quality score",
@@ -123,8 +126,11 @@
123
126
  "map_theme_score": "Quality score",
124
127
  "contrast": "Enable higher image contrast",
125
128
  "metadata": "Picture metadata",
126
- "metadata_general_picid": "Picture identifier",
127
- "metadata_general_seqid": "Sequence identifier",
129
+ "metadata_summary": "Summary",
130
+ "metadata_general_copy_id": "Copy ID",
131
+ "metadata_general_copy_picid": "Copy picture ID",
132
+ "metadata_general_picid": "Picture",
133
+ "metadata_general_seqid": "Sequence",
128
134
  "metadata_general_picid_link": "Go to JSON description of the picture",
129
135
  "metadata_general_seqid_link": "Go to JSON description of the sequence",
130
136
  "metadata_general_author": "Author",
@@ -137,21 +143,21 @@
137
143
  "metadata_camera_type": "Type",
138
144
  "metadata_camera_resolution": "Resolution",
139
145
  "metadata_camera_focal_length": "Focal length",
140
- "metadata_location": "Location",
146
+ "metadata_location": "Position",
141
147
  "metadata_location_longitude": "Longitude",
142
148
  "metadata_location_latitude": "Latitude",
143
- "metadata_location_orientation": "Capture direction",
149
+ "metadata_location_orientation": "Direction",
144
150
  "metadata_location_precision": "Positioning precision",
145
- "metadata_quality": "Quality score",
151
+ "metadata_quality": "Quality",
146
152
  "metadata_quality_help": "Know more about Quality Score",
147
153
  "metadata_quality_score": "Global score",
148
154
  "metadata_quality_gps_score": "Positioning score",
149
155
  "metadata_quality_resolution_score": "Resolution score",
150
156
  "metadata_quality_missing": "no value set in picture",
151
- "metadata_exif": "EXIF / XMP",
157
+ "metadata_exif": "EXIF",
152
158
  "metadata_exif_name": "Tag",
153
159
  "metadata_exif_value": "Value",
154
- "report": "Report picture",
160
+ "report": "Report",
155
161
  "report_auth": "This report will be sent using your account \"{a}\"",
156
162
  "report_nature_label": "Nature of the issue",
157
163
  "report_nature": {
@@ -52,8 +52,9 @@
52
52
  "sequence_speed": "Vitesse de lecture",
53
53
  "legend_license": "Licence : {l}",
54
54
  "legend_title": "Afficher les détails de l'image",
55
- "edit_osm": "Contribuer sur OSM",
56
55
  "id": "iD",
56
+ "contribute_id": "Contribuez à OpenStreetMap avec l'éditeur iD",
57
+ "geo_uri": "App externe",
57
58
  "josm": "JOSM",
58
59
  "josm_live": "Active la synchronisation automatique de JOSM lors du chargement d'une photo",
59
60
  "loading_labels_serious": [
@@ -101,6 +102,8 @@
101
102
  "filter_picture": "Type d'image",
102
103
  "picture_flat": "Classique",
103
104
  "picture_360": "360°",
105
+ "picture_flat_long": "Photo classique",
106
+ "picture_360_long": "Photo panoramique",
104
107
  "filter_qualityscore": "Score de qualité",
105
108
  "filter_qualityscore_help": "Cliquez pour activer ou désactiver",
106
109
  "qualityscore_title": "À propos du score qualité",
@@ -123,8 +126,11 @@
123
126
  "map_theme_score": "Score de qualité",
124
127
  "contrast": "Augmenter le contraste de l'image",
125
128
  "metadata": "Métadonnées de la photo",
126
- "metadata_general_picid": "Identifiant de photo",
127
- "metadata_general_seqid": "Identifiant de séquence",
129
+ "metadata_summary": "Résumé",
130
+ "metadata_general_copy_id": "Copier l'ID",
131
+ "metadata_general_copy_picid": "Copier l'ID de photo",
132
+ "metadata_general_picid": "Photo",
133
+ "metadata_general_seqid": "Séquence",
128
134
  "metadata_general_picid_link": "Aller au descriptif JSON de la photo",
129
135
  "metadata_general_seqid_link": "Aller au descriptif JSON de la séquence",
130
136
  "metadata_general_author": "Auteur",
@@ -137,21 +143,21 @@
137
143
  "metadata_camera_type": "Type",
138
144
  "metadata_camera_resolution": "Résolution",
139
145
  "metadata_camera_focal_length": "Longueur focale",
140
- "metadata_location": "Localisation",
146
+ "metadata_location": "Position",
141
147
  "metadata_location_longitude": "Longitude",
142
148
  "metadata_location_latitude": "Latitude",
143
- "metadata_location_orientation": "Direction de prise de vue",
149
+ "metadata_location_orientation": "Direction",
144
150
  "metadata_location_precision": "Précision du positionnement",
145
- "metadata_quality": "Score de qualité",
151
+ "metadata_quality": "Qualité",
146
152
  "metadata_quality_help": "En savoir plus sur le score de qualité",
147
153
  "metadata_quality_score": "Note globale",
148
154
  "metadata_quality_gps_score": "Note du positionnement",
149
155
  "metadata_quality_resolution_score": "Note de la résolution",
150
156
  "metadata_quality_missing": "pas d'info dans l'image",
151
- "metadata_exif": "EXIF / XMP",
157
+ "metadata_exif": "EXIF",
152
158
  "metadata_exif_name": "Balise",
153
159
  "metadata_exif_value": "Valeur",
154
- "report": "Signaler la photo",
160
+ "report": "Signaler",
155
161
  "report_auth": "Ce signalement sera envoyé en utilisant votre compte \"{a}\"",
156
162
  "report_nature_label": "Nature du problème",
157
163
  "report_nature": {
@@ -376,7 +376,8 @@ export function alterViewerState(viewer, params) {
376
376
  // Restore selected picture
377
377
  let pic = params.picture || params.pic;
378
378
  if(pic && params.focus && params.focus == "meta") {
379
- viewer.psv.addEventListener("picture-loaded", () => viewer._showPictureMetadata(), { once: true });
379
+ // TODO open expanded legend
380
+ //viewer.psv.addEventListener("picture-loaded", () => viewer._showPictureMetadata(), { once: true });
380
381
  }
381
382
 
382
383
  // Change focus
@@ -57,7 +57,9 @@ function nominatimAddressToPlaceName(addr) {
57
57
  // Zone Indus-like
58
58
  "farm", "farmyard", "industrial", "commercial", "retail", "city_block", "residential",
59
59
  // Quarter-like
60
- "neighbourhood", "allotments", "quarter"
60
+ "neighbourhood", "allotments", "quarter",
61
+ // Fallback to road if nothing else found
62
+ "road"
61
63
  ];
62
64
  for(let pn of potentialNames) {
63
65
  if(addr[pn]) {