@panoramax/web-viewer 4.0.3-develop-25adfc80 → 4.0.3-develop-fcd1db46

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/docs/index.md CHANGED
@@ -118,6 +118,19 @@ A photo-only viewer, showing one picture at a time, and offering navigation thro
118
118
  />
119
119
  ```
120
120
 
121
+ If you'd like a photo viewer that looks like an iframe embed (with only a small legend widget), you may use this code:
122
+
123
+ ```html
124
+ <pnx-photo-viewer
125
+ endpoint="https://api.panoramax.xyz/api"
126
+ sequence="id-to-an-existing-sequence"
127
+ picture="id-to-a-picture-in-this-sequence"
128
+ widgets="false"
129
+ >
130
+ <pnx-widget-legend light slot="bottom-right"></pnx-widget-legend>
131
+ </pnx-photo-viewer>
132
+ ```
133
+
121
134
  [Many options are available as well](./reference/components/core/PhotoViewer.md).
122
135
 
123
136
  __Editor__
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@panoramax/web-viewer",
3
- "version": "4.0.3-develop-25adfc80",
3
+ "version": "4.0.3-develop-fcd1db46",
4
4
  "description": "Panoramax web viewer for geolocated pictures",
5
5
  "main": "build/index.js",
6
6
  "author": "Panoramax team",
@@ -35,18 +35,6 @@ pnx-photo-viewer pnx-cornered-grid::part(corner-bottom-right) {
35
35
  }
36
36
  }
37
37
 
38
- @media screen and (min-width: 576px) {
39
- pnx-photo-viewer pnx-widget-legend {
40
- position: absolute;
41
- left: 10px;
42
- top: 60px;
43
- }
44
-
45
- pnx-photo-viewer pnx-widget-legend {
46
- top: 10px;
47
- }
48
- }
49
-
50
38
  /* Hidden widgets on sequence play */
51
39
  pnx-photo-viewer.pnx-playing pnx-bottom-drawer,
52
40
  pnx-photo-viewer.pnx-playing pnx-widget-legend,
@@ -1,5 +1,6 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import { classMap } from "lit/directives/class-map.js";
3
+ import { onceParentAvailable } from "../../utils/widgets";
3
4
 
4
5
  const OPENNESS_Y_PCT = { "opened": 0, "half-opened": 0.7, "closed": 1 };
5
6
 
@@ -104,7 +105,7 @@ export default class BottomDrawer extends LitElement {
104
105
  drawer.style.height = `${this._drawerHeight}px`;
105
106
  drawer.style.maxHeight = `${this._drawerHeight}px`;
106
107
 
107
- this._parent?.onceReady().then(() => {
108
+ onceParentAvailable(this).then(() => this._parent.onceReady()).then(() => {
108
109
  this._parent.map?.addEventListener("click", () => this.openness = "closed");
109
110
  this._parent.psv?.addEventListener("click", () => this.openness = "closed");
110
111
  });
@@ -3,6 +3,7 @@ import { faSvg, iconify } from "../styles";
3
3
  import { fa, moreIcons } from "../../utils/widgets";
4
4
  import { faChevronRight } from "@fortawesome/free-solid-svg-icons/faChevronRight";
5
5
  import { faArrowLeft } from "@fortawesome/free-solid-svg-icons/faArrowLeft";
6
+ import { onceParentAvailable } from "../../utils/widgets";
6
7
  import "iconify-icon";
7
8
 
8
9
  /**
@@ -42,15 +43,18 @@ export default class AnnotationsList extends LitElement {
42
43
  super.connectedCallback();
43
44
 
44
45
  this._onPicChange();
45
- this._parent?.psv?.addEventListener("picture-loaded", this._onPicChange.bind(this));
46
-
47
- this._parent?.psv?.addEventListener("annotation-click", e => {
48
- const aPos = this._meta.properties?.annotations?.findIndex(a => a.id === e.detail.annotationId);
49
- if(aPos >= 0) { this._onListItemClick(Object.assign({nb: aPos+1}, this._meta.properties.annotations[aPos])); }
50
- });
51
-
52
- this._parent?.psv?.addEventListener("annotations-unfocused", () => {
53
- this._onListItemClick(null);
46
+
47
+ onceParentAvailable(this).then(() => {
48
+ this._parent.psv?.addEventListener("picture-loaded", this._onPicChange.bind(this));
49
+
50
+ this._parent.psv?.addEventListener("annotation-click", e => {
51
+ const aPos = this._meta.properties?.annotations?.findIndex(a => a.id === e.detail.annotationId);
52
+ if(aPos >= 0) { this._onListItemClick(Object.assign({nb: aPos+1}, this._meta.properties.annotations[aPos])); }
53
+ });
54
+
55
+ this._parent.psv?.addEventListener("annotations-unfocused", () => {
56
+ this._onListItemClick(null);
57
+ });
54
58
  });
55
59
  }
56
60
 
@@ -1,6 +1,8 @@
1
1
  import { LitElement, html, css } from "lit";
2
2
  import BackgroundAerial from "../../img/bg_aerial.jpg";
3
3
  import BackgroundStreets from "../../img/bg_streets.jpg";
4
+ import { onceParentAvailable } from "../../utils/widgets";
5
+
4
6
 
5
7
  /**
6
8
  * Map Background menu allows user to select background.
@@ -60,10 +62,13 @@ export default class MapBackground extends LitElement {
60
62
  /** @private */
61
63
  connectedCallback() {
62
64
  super.connectedCallback();
63
- this._parent?.map?.on("background-changed", e => {
64
- this.bg = e.background;
65
+
66
+ onceParentAvailable(this).then(() => {
67
+ this._parent.map?.on("background-changed", e => {
68
+ this.bg = e.background;
69
+ });
70
+ this.bg = this._parent.map?.getBackground();
65
71
  });
66
- this.bg = this._parent?.map?.getBackground();
67
72
  }
68
73
 
69
74
  /** @private */
@@ -8,6 +8,7 @@ import { faArrowRight } from "@fortawesome/free-solid-svg-icons/faArrowRight";
8
8
  import { faMedal } from "@fortawesome/free-solid-svg-icons/faMedal";
9
9
  import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
10
10
  import { faUser } from "@fortawesome/free-solid-svg-icons/faUser";
11
+ import { onceParentAvailable } from "../../utils/widgets";
11
12
 
12
13
  /**
13
14
  * Map Filters menu allows user to select map data they want displayed.
@@ -180,7 +181,7 @@ export default class MapFilters extends LitElement {
180
181
  }
181
182
 
182
183
  // Map zoom
183
- this._parent?.onceMapReady?.().then(async () => {
184
+ onceParentAvailable(this).then(() => this._parent.onceMapReady?.().then(async () => {
184
185
  this._parent.map.on("zoomend", this._onMapZoom.bind(this));
185
186
  this._parent.map.on("filters-changed", this._onParentFilterChange.bind(this));
186
187
  this._onMapZoom();
@@ -193,7 +194,7 @@ export default class MapFilters extends LitElement {
193
194
  const username = await this._parent.api.getUserName(vu[0]);
194
195
  if(username) { this.user = username; }
195
196
  }
196
- });
197
+ }));
197
198
  }
198
199
 
199
200
  /**
@@ -5,6 +5,7 @@ import { COLORS } from "../../utils/utils";
5
5
  import { faEarthEurope } from "@fortawesome/free-solid-svg-icons/faEarthEurope";
6
6
  import { faPalette } from "@fortawesome/free-solid-svg-icons/faPalette";
7
7
  import { faInfoCircle } from "@fortawesome/free-solid-svg-icons/faInfoCircle";
8
+ import { onceParentAvailable } from "../../utils/widgets";
8
9
 
9
10
  /**
10
11
  * Map Layers menu allows user to select background and map theme.
@@ -56,10 +57,10 @@ export default class MapLayers extends LitElement {
56
57
  /** @private */
57
58
  connectedCallback() {
58
59
  super.connectedCallback();
59
- this._parent?.onceMapReady?.().then(() => {
60
+ onceParentAvailable(this).then(() => this._parent?.onceMapReady?.().then(() => {
60
61
  this.theme = this._parent.map._mapFilters.theme;
61
62
  this._parent.map.on("filters-changed", e => this.theme = e.theme);
62
- });
63
+ }));
63
64
  }
64
65
 
65
66
  /** @private */
@@ -1,7 +1,7 @@
1
1
  import { LitElement, nothing, css } from "lit";
2
2
  import { html, unsafeStatic } from "lit/static-html.js";
3
3
  import { classMap } from "lit/directives/class-map.js";
4
- import { fa } from "../../utils/widgets";
4
+ import { fa, onceParentAvailable } from "../../utils/widgets";
5
5
  import { faArrowLeft } from "@fortawesome/free-solid-svg-icons/faArrowLeft";
6
6
  import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
7
7
  import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
@@ -165,18 +165,20 @@ export default class PictureLegend extends LitElement {
165
165
  this._expanded = !this.collapsable;
166
166
  this._prevSearches = {};
167
167
 
168
- this._parent.onceReady().then(() => {
169
- this._onPicChange(this._parent.psv.getPictureMetadata());
170
- this._parent.psv.addEventListener("picture-loaded", () => {
168
+ onceParentAvailable(this)
169
+ .then(() => this._parent.onceReady())
170
+ .then(() => {
171
171
  this._onPicChange(this._parent.psv.getPictureMetadata());
172
+ this._parent.psv.addEventListener("picture-loaded", () => {
173
+ this._onPicChange(this._parent.psv.getPictureMetadata());
174
+ });
175
+ this._parent.psv.addEventListener("sequence-stopped", () => {
176
+ this._onPicChange(this._parent.psv.getPictureMetadata());
177
+ });
178
+ this._parent.psv.addEventListener("annotation-click", () => {
179
+ this._expanded = true;
180
+ });
172
181
  });
173
- this._parent.psv.addEventListener("sequence-stopped", () => {
174
- this._onPicChange(this._parent.psv.getPictureMetadata());
175
- });
176
- this._parent.psv.addEventListener("annotation-click", () => {
177
- this._expanded = true;
178
- });
179
- });
180
182
  }
181
183
 
182
184
  /** @private */
@@ -1,6 +1,6 @@
1
1
  import { LitElement, nothing, css } from "lit";
2
2
  import { html, unsafeStatic } from "lit/static-html.js";
3
- import { fa } from "../../utils/widgets";
3
+ import { fa, onceParentAvailable } from "../../utils/widgets";
4
4
  import { faLocationDot } from "@fortawesome/free-solid-svg-icons/faLocationDot";
5
5
  import { faMedal } from "@fortawesome/free-solid-svg-icons/faMedal";
6
6
  import { faCamera } from "@fortawesome/free-solid-svg-icons/faCamera";
@@ -82,14 +82,16 @@ export default class PictureMetadata extends LitElement {
82
82
  connectedCallback() {
83
83
  super.connectedCallback();
84
84
 
85
- this._meta = this._parent?.psv?.getPictureMetadata();
86
- this._parent?.oncePSVReady?.().then(() => {
87
- this._parent.psv.addEventListener("picture-loaded", () => {
88
- this._meta = this._parent.psv.getPictureMetadata();
89
- });
90
- this._parent.psv.addEventListener("annotation-click", () => {
91
- const tabs = this.shadowRoot.querySelector("pnx-tabs");
92
- if(tabs) { tabs.setAttribute("activeTabIndex", 4); }
85
+ onceParentAvailable(this).then(() => {
86
+ this._meta = this._parent?.psv?.getPictureMetadata();
87
+ this._parent?.oncePSVReady?.().then(() => {
88
+ this._parent.psv.addEventListener("picture-loaded", () => {
89
+ this._meta = this._parent.psv.getPictureMetadata();
90
+ });
91
+ this._parent.psv.addEventListener("annotation-click", () => {
92
+ const tabs = this.shadowRoot.querySelector("pnx-tabs");
93
+ if(tabs) { tabs.setAttribute("activeTabIndex", 4); }
94
+ });
93
95
  });
94
96
  });
95
97
  }
@@ -4,7 +4,7 @@ import { faRocket } from "@fortawesome/free-solid-svg-icons/faRocket";
4
4
  import { faLightbulb } from "@fortawesome/free-solid-svg-icons/faLightbulb";
5
5
  import { faPersonBiking } from "@fortawesome/free-solid-svg-icons/faPersonBiking";
6
6
  import { PIC_MAX_STAY_DURATION } from "../ui/Photo";
7
- import { fa } from "../../utils/widgets";
7
+ import { fa, onceParentAvailable } from "../../utils/widgets";
8
8
 
9
9
  /**
10
10
  * Player Options menu displays player speed and contrast settings.
@@ -40,9 +40,9 @@ export default class PlayerOptions extends LitElement {
40
40
  /** @private */
41
41
  connectedCallback() {
42
42
  super.connectedCallback();
43
- this._parent?.psv?.addEventListener("transition-duration-changed", e => {
43
+ onceParentAvailable(this).then(() => this._parent?.psv?.addEventListener("transition-duration-changed", e => {
44
44
  this.renderRoot.querySelector("#pnx-player-speed").value = PIC_MAX_STAY_DURATION - e.detail.value;
45
- });
45
+ }));
46
46
  }
47
47
 
48
48
  /** @private */
@@ -1,5 +1,5 @@
1
1
  import { LitElement, css, html } from "lit";
2
- import { fa } from "../../utils/widgets";
2
+ import { fa, onceParentAvailable } from "../../utils/widgets";
3
3
  import { faSvg, textarea, titles, input } from "../styles";
4
4
  import { faMap } from "@fortawesome/free-solid-svg-icons/faMap";
5
5
  import { faCircleInfo } from "@fortawesome/free-solid-svg-icons/faCircleInfo";
@@ -47,7 +47,7 @@ export default class ShareMenu extends LitElement {
47
47
  /** @private */
48
48
  connectedCallback() {
49
49
  super.connectedCallback();
50
- this._parent?.onceReady().then(() => {
50
+ onceParentAvailable(this).then(() => this._parent.onceReady()).then(() => {
51
51
  this._onUrlChange();
52
52
  this._parent.urlHandler.addEventListener("url-changed", this._onUrlChange.bind(this));
53
53
  });
@@ -3,6 +3,10 @@ import { fa } from "../../utils/widgets";
3
3
  import { faTags } from "@fortawesome/free-solid-svg-icons/faTags";
4
4
  import { faTriangleExclamation } from "@fortawesome/free-solid-svg-icons/faTriangleExclamation";
5
5
  import { hasAnnotations } from "../../utils/picture";
6
+ import { classMap } from "lit/directives/class-map.js";
7
+ import { panel } from "../styles";
8
+
9
+ const DISABLE_ANNOTATIONS_PARAM = "pnx-disable-annotations";
6
10
 
7
11
  /**
8
12
  * AnnotationsSwitch component allows to switch on/off pictures annotations.
@@ -16,7 +20,14 @@ import { hasAnnotations } from "../../utils/picture";
16
20
  */
17
21
  export default class AnnotationsSwitch extends LitElement {
18
22
  /** @private */
19
- static styles = css`
23
+ static styles = [ panel, css`
24
+ .pnx-panel {
25
+ padding: 5px;
26
+ margin-top: 5px;
27
+ width: max-content;
28
+ min-width: unset;
29
+ }
30
+
20
31
  /* Custom button look */
21
32
  pnx-button::part(btn) {
22
33
  border-radius: 8px;
@@ -30,6 +41,13 @@ export default class AnnotationsSwitch extends LitElement {
30
41
  width: 38px;
31
42
  }
32
43
 
44
+ pnx-button[active]::part(btn),
45
+ pnx-button[active]:hover::part(btn) {
46
+ background-color: var(--widget-bg-active) !important;
47
+ border-color: var(--widget-bg-active) !important;
48
+ color: var(--widget-font-active) !important;
49
+ }
50
+
33
51
  /* No-annotations badge */
34
52
  .pnx-annotations-switch-empty {
35
53
  position: absolute;
@@ -48,7 +66,7 @@ export default class AnnotationsSwitch extends LitElement {
48
66
  pnx-button[active] .pnx-annotations-switch-empty {
49
67
  color: var(--yellow);
50
68
  }
51
- `;
69
+ `];
52
70
 
53
71
  /**
54
72
  * Component properties.
@@ -61,12 +79,14 @@ export default class AnnotationsSwitch extends LitElement {
61
79
  size: {type: String},
62
80
  _annotationsToggled: {state: true},
63
81
  _warnNoAnnot: {state: true},
82
+ _warnNoAnnotTooltip: {state: true},
64
83
  };
65
84
 
66
85
  constructor() {
67
86
  super();
68
87
  this._annotationsToggled = false;
69
88
  this._warnNoAnnot = false;
89
+ this._warnNoAnnotTooltip = false;
70
90
  this.size = "xl";
71
91
  }
72
92
 
@@ -74,9 +94,13 @@ export default class AnnotationsSwitch extends LitElement {
74
94
  connectedCallback() {
75
95
  super.connectedCallback();
76
96
 
97
+ // Check if annotations have been explicitly disabled
98
+ const annotsDisabled = localStorage.getItem(DISABLE_ANNOTATIONS_PARAM) === "true";
99
+
77
100
  this._parent.onceReady().then(() => {
78
101
  this._parent.psv.addEventListener("annotations-toggled", e => {
79
102
  this._annotationsToggled = e.detail.visible;
103
+ this._persistAnnotationsLocalStorage(this._annotationsToggled);
80
104
  });
81
105
 
82
106
  this._warnNoAnnot = !hasAnnotations(this._parent.psv.getPictureMetadata());
@@ -88,35 +112,57 @@ export default class AnnotationsSwitch extends LitElement {
88
112
  this._parent.onceFirstPicLoaded().then(() => {
89
113
  this._annotationsToggled = this._parent.psv.areAnnotationsVisible() || false;
90
114
 
91
- if(!this._annotationsToggled) {
115
+ if(!this._annotationsToggled && !annotsDisabled) {
92
116
  this._parent.psv.toggleAllAnnotations(true);
93
117
  this._annotationsToggled = true;
94
118
  }
119
+ this._persistAnnotationsLocalStorage(this._annotationsToggled);
95
120
  });
96
121
  }
97
122
 
123
+ /** @private */
124
+ _persistAnnotationsLocalStorage(isAnnotToggled) {
125
+ console.log("save", isAnnotToggled);
126
+ localStorage.setItem(DISABLE_ANNOTATIONS_PARAM, isAnnotToggled ? "false": "true");
127
+ }
128
+
129
+ /** @private */
98
130
  _onClick() {
131
+ if(!this._annotationsToggled && this._warnNoAnnot) {
132
+ this._warnNoAnnotTooltip = true;
133
+ setTimeout(() => this._warnNoAnnotTooltip = false, 2000);
134
+ }
135
+ this._persistAnnotationsLocalStorage(!this._annotationsToggled);
99
136
  this._parent.psv.toggleAllAnnotations(!this._annotationsToggled);
100
137
  }
101
138
 
102
139
  /** @private */
103
140
  render() {
104
141
  /* eslint-disable indent */
142
+ const panelClasses = {
143
+ "pnx-panel": true,
144
+ "pnx-hidden": !this._warnNoAnnotTooltip,
145
+ };
146
+
105
147
  return html`
106
148
  <pnx-button
107
- kind="outline"
149
+ kind="superflat"
108
150
  size=${this.size}
109
151
  style="vertical-align: middle"
110
- title=${[
111
- this._annotationsToggled ? this._parent._t?.pnx.semantics_hide_annotations : this._parent._t?.pnx.semantics_show_annotations,
112
- this._warnNoAnnot ? this._parent._t?.pnx.semantics_zero_annotations : null
113
- ].filter(v => v).join(" ")}
152
+ class="pnx-print-hidden"
153
+ title=${this._annotationsToggled ? this._parent._t?.pnx.semantics_hide_annotations : this._parent._t?.pnx.semantics_show_annotations}
114
154
  active=${this._annotationsToggled ? "" : nothing}
115
155
  @click=${this._onClick}
116
156
  >
117
- ${fa(faTags, { styles: { "height": "unset" }})}
157
+ ${fa(faTags, { styles: { "height": "20px" }})}
118
158
  ${this._warnNoAnnot ? fa(faTriangleExclamation, { classes: "pnx-annotations-switch-empty" }) : nothing}
119
159
  </pnx-button>
160
+ <div
161
+ class=${classMap(panelClasses)}
162
+ @click=${() => this._warnNoAnnotTooltip = false}
163
+ >
164
+ ${this._parent._t?.pnx.semantics_zero_annotations}
165
+ </div>
120
166
  `;
121
167
  }
122
168
  }
@@ -3,6 +3,7 @@ import maplibregl from "!maplibre-gl";
3
3
 
4
4
  import { LitElement, html } from "lit";
5
5
  import { forwardGeocodingBAN, forwardGeocodingStandard, forwardGeocodingNominatim } from "../../../utils/geocoder";
6
+ import { onceParentAvailable } from "../../../utils/widgets";
6
7
  import "./GeoSearch.css";
7
8
 
8
9
  const GEOCODER_ENGINES = {
@@ -63,10 +64,10 @@ export default class GeoSearch extends LitElement {
63
64
  super.connectedCallback();
64
65
 
65
66
  this._geocoderEngine = GEOCODER_ENGINES[this.geocoder] || (config => GEOCODER_ENGINES.standard(config, this.geocoder));
66
- this._parent?.onceMapReady?.().then(() => {
67
+ onceParentAvailable(this).then(() => this._parent?.onceMapReady?.().then(() => {
67
68
  this._geolocate = this._geolocateCtrl.onAdd(this._parent.map);
68
69
  this._geolocate.setAttribute("slot", "pre");
69
- });
70
+ }));
70
71
  }
71
72
 
72
73
  /** @private */
@@ -1,5 +1,5 @@
1
1
  import { LitElement, html, nothing } from "lit";
2
- import { fa } from "../../../utils/widgets";
2
+ import { fa, onceParentAvailable } from "../../../utils/widgets";
3
3
  import { faSliders } from "@fortawesome/free-solid-svg-icons/faSliders";
4
4
  import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
5
5
  import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark";
@@ -45,7 +45,7 @@ export default class MapFiltersButton extends LitElement {
45
45
  super.connectedCallback();
46
46
 
47
47
  // Listen to user visibility changes to switch the filter active icon
48
- this._parent?.onceMapReady?.().then(() => {
48
+ onceParentAvailable(this).then(() => this._parent?.onceMapReady?.().then(() => {
49
49
  this._active = (
50
50
  Object.keys(this._parent.map._mapFilters).filter(d => d && d !== "theme").length > 0
51
51
  || this._parent.map.getVisibleUsers().filter(u => u !== "geovisio").length > 0
@@ -64,7 +64,7 @@ export default class MapFiltersButton extends LitElement {
64
64
  || e.usersIds.filter(u => u !== "geovisio").length > 0
65
65
  );
66
66
  });
67
- });
67
+ }));
68
68
  }
69
69
 
70
70
  /** @private */
@@ -1,5 +1,5 @@
1
1
  import { LitElement, html, nothing } from "lit";
2
- import { fa } from "../../../utils/widgets";
2
+ import { fa, onceParentAvailable } from "../../../utils/widgets";
3
3
  import { faLayerGroup } from "@fortawesome/free-solid-svg-icons/faLayerGroup";
4
4
  import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
5
5
  import { faXmark } from "@fortawesome/free-solid-svg-icons/faXmark";
@@ -35,12 +35,12 @@ export default class MapLayersButton extends LitElement {
35
35
 
36
36
  const nullThemes = [undefined, null, "", "default"];
37
37
 
38
- this._parent?.onceMapReady?.().then(() => {
38
+ onceParentAvailable(this).then(() => this._parent?.onceMapReady?.().then(() => {
39
39
  this._active = !nullThemes.includes(this._parent.map._mapFilters.theme);
40
40
  this._parent.map.on("filters-changed", e => {
41
41
  this._active = !nullThemes.includes(e.theme);
42
42
  });
43
- });
43
+ }));
44
44
  }
45
45
 
46
46
  /** @private */
@@ -1,5 +1,5 @@
1
1
  import { LitElement, html, nothing, css } from "lit";
2
- import { fa } from "../../../utils/widgets";
2
+ import { fa, onceParentAvailable } from "../../../utils/widgets";
3
3
  import { josmBboxParameters } from "../../../utils/utils";
4
4
  import { IdEditorURL } from "../../../utils/services";
5
5
  import { faLocationDot } from "@fortawesome/free-solid-svg-icons/faLocationDot";
@@ -40,7 +40,7 @@ export default class OSMEditors extends LitElement {
40
40
  /** @private */
41
41
  connectedCallback() {
42
42
  super.connectedCallback();
43
- this._parent?.onceReady().then(() => {
43
+ onceParentAvailable(this).then(() => this._parent.onceReady()).then(() => {
44
44
  this._parent.onceFirstPicLoaded().then(this._onPictureLoad.bind(this));
45
45
  this._parent.psv.addEventListener("picture-loaded", this._onPictureLoad.bind(this));
46
46
  });
@@ -1,5 +1,5 @@
1
1
  import { LitElement, html, nothing, css } from "lit";
2
- import { fa } from "../../../utils/widgets";
2
+ import { fa, onceParentAvailable } from "../../../utils/widgets";
3
3
  import { faEllipsisV } from "@fortawesome/free-solid-svg-icons/faEllipsisV";
4
4
  import { noprint } from "../../styles";
5
5
 
@@ -42,7 +42,7 @@ export default class PictureLegendActions extends LitElement {
42
42
  connectedCallback() {
43
43
  super.connectedCallback();
44
44
 
45
- this._parent?.onceReady().then(() => {
45
+ onceParentAvailable(this).then(() => this._parent.onceReady()).then(() => {
46
46
  this._meta = this._parent.psv.getPictureMetadata();
47
47
  this._parent.psv.addEventListener("picture-loaded", () => {
48
48
  this._meta = this._parent.psv.getPictureMetadata();
@@ -1,5 +1,5 @@
1
1
  import { LitElement, html, nothing } from "lit";
2
- import { fa } from "../../../utils/widgets";
2
+ import { fa, onceParentAvailable } from "../../../utils/widgets";
3
3
  import { faBackward } from "@fortawesome/free-solid-svg-icons/faBackward";
4
4
  import { faPlay } from "@fortawesome/free-solid-svg-icons/faPlay";
5
5
  import { faPause } from "@fortawesome/free-solid-svg-icons/faPause";
@@ -52,13 +52,13 @@ export default class Player extends LitElement {
52
52
  connectedCallback() {
53
53
  super.connectedCallback();
54
54
 
55
- this._parent?.oncePSVReady?.().then(() => {
55
+ onceParentAvailable(this).then(() => this._parent?.oncePSVReady?.().then(() => {
56
56
  this._parent.psv.addEventListener("sequence-playing", () => this.playing = true);
57
57
  this._parent.psv.addEventListener("sequence-stopped", () => this.playing = false);
58
58
  this._parent.psv.addEventListener("picture-loaded", this._changeActiveStates.bind(this));
59
59
  this._parent.addEventListener("pictures-navigation-changed", this._changeActiveStates.bind(this));
60
60
  this._changeActiveStates();
61
- });
61
+ }));
62
62
  }
63
63
 
64
64
  /** @private */
@@ -1,7 +1,7 @@
1
1
  import { LitElement, html } from "lit";
2
2
  import { PSV_DEFAULT_ZOOM, PSV_ANIM_DURATION } from "../Photo";
3
3
  import { PSV_ZOOM_DELTA } from "../../core/Viewer";
4
- import { fa } from "../../../utils/widgets";
4
+ import { fa, onceParentAvailable } from "../../../utils/widgets";
5
5
  import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus";
6
6
  import { faMinus } from "@fortawesome/free-solid-svg-icons/faMinus";
7
7
  import "../ButtonGroup.css";
@@ -30,7 +30,9 @@ export default class Zoom extends LitElement {
30
30
  /** @private */
31
31
  connectedCallback() {
32
32
  super.connectedCallback();
33
- this._parent?.oncePSVReady?.().then(() => this._lastWantedZoom = this._parent?.psv?.getZoomLevel() || PSV_DEFAULT_ZOOM);
33
+ onceParentAvailable(this).then(() => this._parent?.oncePSVReady?.().then(() => {
34
+ this._lastWantedZoom = this._parent?.psv?.getZoomLevel() || PSV_DEFAULT_ZOOM;
35
+ }));
34
36
  }
35
37
 
36
38
  /** @private */
@@ -192,7 +192,7 @@
192
192
  "semantics_qualifiers": "Qualifiers",
193
193
  "semantics_show_annotations": "Display picture annotations",
194
194
  "semantics_hide_annotations": "Hide picture annotations",
195
- "semantics_zero_annotations": "(no annotation set on this picture)",
195
+ "semantics_zero_annotations": "No annotation set on this picture",
196
196
  "semantics_hashtags": "Picture hashtags",
197
197
  "semantics_wikidata_properties": {
198
198
  "P31": "instance of",
@@ -192,7 +192,7 @@
192
192
  "semantics_qualifiers": "Qualificateurs",
193
193
  "semantics_show_annotations": "Afficher les annotations de photo",
194
194
  "semantics_hide_annotations": "Masquer les annotations de photo",
195
- "semantics_zero_annotations": "(aucune annotation sur cette image)",
195
+ "semantics_zero_annotations": "Aucune annotation sur cette image",
196
196
  "semantics_hashtags": "Mots-dièse de la photo",
197
197
  "semantics_wikidata_properties": {
198
198
  "P31": "instance de",
@@ -70,3 +70,23 @@ export function listenForMenuClosure(me, callback) {
70
70
  me._parent.legend?.addEventListener("click", () => callback());
71
71
  });
72
72
  }
73
+
74
+ /**
75
+ * Wait for parent availability
76
+ * @private
77
+ */
78
+ export function onceParentAvailable(comp) {
79
+ if(comp._parent) {
80
+ return Promise.resolve(comp._parent);
81
+ }
82
+ else {
83
+ return new Promise(resolve => {
84
+ const itv = setInterval(() => {
85
+ if(comp._parent) {
86
+ clearInterval(itv);
87
+ resolve(comp._parent);
88
+ }
89
+ }, 100);
90
+ });
91
+ }
92
+ }