@panoramax/web-viewer 4.0.3 → 4.1.0

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 (103) hide show
  1. package/CHANGELOG.md +40 -1
  2. package/build/index.css +9 -9
  3. package/build/index.css.map +1 -1
  4. package/build/index.js +640 -456
  5. package/build/index.js.map +1 -1
  6. package/build/photo.html +1 -1
  7. package/build/viewer.html +3 -3
  8. package/build/widgets.html +1 -1
  9. package/config/jest/mocks.js +9 -1
  10. package/docs/03_URL_settings.md +21 -0
  11. package/docs/09_Develop.md +6 -0
  12. package/docs/images/comparative_3drender.jpg +0 -0
  13. package/docs/index.md +13 -0
  14. package/docs/reference/components/core/Editor.md +18 -0
  15. package/docs/reference/components/core/PhotoViewer.md +1 -0
  16. package/docs/reference/components/core/Viewer.md +1 -0
  17. package/docs/reference/components/menus/MapLegend.md +17 -0
  18. package/docs/reference/components/menus/MiniPictureLegend.md +15 -0
  19. package/docs/reference/components/menus/PictureLegend.md +17 -0
  20. package/docs/reference/components/ui/AnnotationsSwitch.md +15 -0
  21. package/docs/reference/components/ui/Button.md +1 -1
  22. package/docs/reference/components/ui/CopyButton.md +1 -1
  23. package/docs/reference/components/ui/LinkButton.md +1 -1
  24. package/docs/reference/components/ui/Map.md +18 -2
  25. package/docs/reference/components/ui/MapMore.md +6 -2
  26. package/docs/reference/components/ui/SemanticsEditor.md +87 -0
  27. package/docs/reference/components/ui/widgets/Legend.md +5 -4
  28. package/docs/reference/utils/URLHandler.md +7 -0
  29. package/docs/reference.md +3 -1
  30. package/docs/tutorials/aerial_imagery.md +13 -11
  31. package/mkdocs.yml +3 -1
  32. package/package.json +7 -7
  33. package/public/photo.html +1 -1
  34. package/public/viewer.html +3 -3
  35. package/public/widgets.html +32 -0
  36. package/src/components/core/Basic.css +2 -0
  37. package/src/components/core/Basic.js +3 -1
  38. package/src/components/core/CoverageMap.js +6 -0
  39. package/src/components/core/Editor.css +1 -0
  40. package/src/components/core/Editor.js +58 -7
  41. package/src/components/core/PhotoViewer.css +5 -10
  42. package/src/components/core/PhotoViewer.js +55 -20
  43. package/src/components/core/Viewer.css +9 -2
  44. package/src/components/core/Viewer.js +62 -33
  45. package/src/components/layout/BottomDrawer.js +2 -1
  46. package/src/components/layout/Tabs.js +4 -0
  47. package/src/components/menus/AnnotationsList.js +13 -9
  48. package/src/components/menus/MapBackground.js +8 -3
  49. package/src/components/menus/MapFilters.js +11 -2
  50. package/src/components/menus/MapLayers.js +3 -2
  51. package/src/components/menus/MapLegend.js +28 -4
  52. package/src/components/menus/MiniPictureLegend.js +74 -0
  53. package/src/components/menus/PictureLegend.js +88 -33
  54. package/src/components/menus/PictureMetadata.js +49 -17
  55. package/src/components/menus/PlayerOptions.js +3 -3
  56. package/src/components/menus/Share.js +3 -3
  57. package/src/components/menus/index.js +5 -4
  58. package/src/components/styles.js +11 -0
  59. package/src/components/ui/AnnotationsSwitch.js +169 -0
  60. package/src/components/ui/Button.js +1 -1
  61. package/src/components/ui/CopyButton.js +1 -1
  62. package/src/components/ui/LinkButton.js +1 -1
  63. package/src/components/ui/Map.css +4 -0
  64. package/src/components/ui/Map.js +17 -5
  65. package/src/components/ui/MapMore.js +61 -25
  66. package/src/components/ui/Photo.css +11 -2
  67. package/src/components/ui/Photo.js +6 -3
  68. package/src/components/ui/SemanticsEditor.js +157 -0
  69. package/src/components/ui/index.js +2 -1
  70. package/src/components/ui/widgets/GeoSearch.js +3 -2
  71. package/src/components/ui/widgets/Legend.js +69 -14
  72. package/src/components/ui/widgets/MapFiltersButton.js +3 -3
  73. package/src/components/ui/widgets/MapLayersButton.js +3 -3
  74. package/src/components/ui/widgets/OSMEditors.js +2 -2
  75. package/src/components/ui/widgets/PictureLegendActions.js +24 -42
  76. package/src/components/ui/widgets/Player.js +3 -3
  77. package/src/components/ui/widgets/Zoom.js +4 -2
  78. package/src/translations/ar.json +1 -0
  79. package/src/translations/da.json +3 -2
  80. package/src/translations/de.json +64 -13
  81. package/src/translations/en.json +5 -1
  82. package/src/translations/eo.json +32 -2
  83. package/src/translations/fr.json +7 -1
  84. package/src/translations/it.json +33 -2
  85. package/src/translations/nl.json +53 -11
  86. package/src/translations/zh_Hant.json +29 -2
  87. package/src/utils/API.js +17 -1
  88. package/src/utils/InitParameters.js +46 -4
  89. package/src/utils/URLHandler.js +9 -1
  90. package/src/utils/map.js +24 -1
  91. package/src/utils/semantics.js +53 -1
  92. package/src/utils/services.js +16 -0
  93. package/src/utils/widgets.js +20 -0
  94. package/tests/components/core/Editor.test.js +1 -1
  95. package/tests/components/core/__snapshots__/PhotoViewer.test.js.snap +18 -6
  96. package/tests/components/core/__snapshots__/Viewer.test.js.snap +15 -3
  97. package/tests/components/ui/Photo.test.js +1 -0
  98. package/tests/components/ui/__snapshots__/Map.test.js.snap +164 -0
  99. package/tests/utils/InitParameters.test.js +27 -0
  100. package/tests/utils/map.test.js +12 -0
  101. package/tests/utils/semantics.test.js +34 -5
  102. package/docs/reference/components/ui/HashTags.md +0 -15
  103. package/src/components/ui/HashTags.js +0 -98
@@ -94,7 +94,7 @@ export default class Photo extends PSViewer {
94
94
  resolution: parent.isWidthSmall() ? 32 : 64,
95
95
  shouldGoFast: options.shouldGoFast,
96
96
  }],
97
- withCredentials: parent?.fetchOptions?.credentials == "include",
97
+ withCredentials: parent.api._getPSVWithCredentials(),
98
98
  requestHeaders: parent?.fetchOptions?.headers,
99
99
  panorama: BASE_PANORAMA,
100
100
  lang: parent._t.psv,
@@ -803,6 +803,7 @@ export default class Photo extends PSViewer {
803
803
  */
804
804
  playSequence() {
805
805
  this._sequencePlaying = true;
806
+ this.container.classList.add("pnx-psv-playing");
806
807
 
807
808
  /**
808
809
  * Event for sequence starting to play
@@ -841,6 +842,7 @@ export default class Photo extends PSViewer {
841
842
  */
842
843
  stopSequence() {
843
844
  this._sequencePlaying = false;
845
+ this.container.classList.remove("pnx-psv-playing");
844
846
 
845
847
  // Next picture timer is pending
846
848
  if(this._playTimer) {
@@ -952,8 +954,8 @@ export default class Photo extends PSViewer {
952
954
 
953
955
  if(!visible) { this._myMarkers.clearMarkers(); }
954
956
  else {
955
- let annotations = meta.properties.annotations;
956
- if(annotations.length === 0) { console.warn("No annotation available on picture", meta.id); }
957
+ let annotations = meta.properties.annotations || [];
958
+ if(annotations?.length === 0) { console.warn("No annotation available on picture", meta.id); }
957
959
 
958
960
  const picBData = this.state.textureData.panoData?.baseData;
959
961
 
@@ -990,6 +992,7 @@ export default class Photo extends PSViewer {
990
992
  id: `annotation-${a.id}`,
991
993
  polygon: shape,
992
994
  data: { id: a.id },
995
+ className: "pnx-psv-annotation",
993
996
  svgStyle: {
994
997
  stroke: "var(--orange)",
995
998
  strokeWidth: "3px",
@@ -0,0 +1,157 @@
1
+ import { LitElement, html, css } from "lit";
2
+ import Basic from "../core/Basic";
3
+ import { parseSemanticsString, computeDiffTags } from "../../utils/semantics";
4
+ import { textarea } from "../styles";
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
+ /** @private */
96
+ _onInput(e) {
97
+ const tarea = e.target;
98
+ try {
99
+ this.semantics = parseSemanticsString(tarea.value) || [];
100
+ this._valid = true;
101
+ } catch (err) {
102
+ if(err.message !== "Invalid tags") { console.error(err); }
103
+ this._valid = false;
104
+ }
105
+ }
106
+
107
+ /** @private */
108
+ _onBlur(e) {
109
+ const prevValidity = e.target.checkValidity();
110
+
111
+ if(this._valid) {
112
+ e.target.setCustomValidity("");
113
+
114
+ /**
115
+ * Event for value change.
116
+ *
117
+ * Note that this event is launched only on valid input.
118
+ *
119
+ * @event Panoramax.components.ui.SemanticsEditor#change
120
+ * @type {CustomEvent}
121
+ * @property {object[]} detail.semantics The new tags list (in API semantics property format)
122
+ * @property {object[]} detail.delta The delta between old and current tags (expected by API)
123
+ */
124
+ this.dispatchEvent(new CustomEvent("change", {
125
+ detail: {
126
+ semantics: this.semantics || [],
127
+ delta: computeDiffTags(this._firstSemantics || [], this.semantics),
128
+ }
129
+ }));
130
+ }
131
+ else if(prevValidity) { // Do not call again if already shows up, to fix Chrome issue
132
+ e.target.setCustomValidity(this._t?.pnx.semantics_editor_error || "Invalid syntax");
133
+ e.target.reportValidity();
134
+ }
135
+ }
136
+
137
+ /** @private */
138
+ render() {
139
+ /* eslint-disable indent */
140
+ return html`
141
+ <textarea
142
+ part="text"
143
+ autocomplete="off"
144
+ autocorrect="off"
145
+ autocapitalize="off"
146
+ spellcheck="false"
147
+ placeholder="key1=value1\nprefix|key2=value2"
148
+ @input=${this._onInput}
149
+ @blur=${this._onBlur}
150
+ rows=${this.rows}
151
+ .value=${(this.semantics || []).map(s => `${s.key}=${s.value}`).join("\n")}
152
+ ></textarea>
153
+ `;
154
+ }
155
+ }
156
+
157
+ customElements.define("pnx-semantics-editor", SemanticsEditor);
@@ -7,7 +7,7 @@ export {default as ButtonGroup} from "./ButtonGroup";
7
7
  export {default as Button} from "./Button";
8
8
  export {default as CopyButton} from "./CopyButton";
9
9
  export {default as Grade} from "./Grade";
10
- export {default as HashTags} from "./HashTags";
10
+ export {default as AnnotationsSwitch} from "./AnnotationsSwitch";
11
11
  export {default as LinkButton} from "./LinkButton";
12
12
  export {default as ListGroup} from "./ListGroup";
13
13
  export {default as ListItem} from "./ListItem";
@@ -19,6 +19,7 @@ export {default as Popup} from "./Popup";
19
19
  export {default as ProgressBar} from "./ProgressBar";
20
20
  export {default as QualityScore} from "./QualityScore";
21
21
  export {default as SearchBar} from "./SearchBar";
22
+ export {default as SemanticsEditor} from "./SemanticsEditor";
22
23
  export {default as SemanticsTable} from "./SemanticsTable";
23
24
  export {default as TogglableGroup} from "./TogglableGroup";
24
25
  import * as widgets from "./widgets";
@@ -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,9 +1,10 @@
1
- import {LitElement, html, css} from "lit";
1
+ import { LitElement, html, css, nothing } from "lit";
2
2
  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
6
  import { classMap } from "lit/directives/class-map.js";
7
+ import { PanoramaxWebsiteURL } from "../../../utils/services";
7
8
 
8
9
  /**
9
10
  * Legend widget, handling switch between map and photo components.
@@ -37,7 +38,7 @@ export default class Legend extends LitElement {
37
38
  .pnx-panel[part="panel"] {
38
39
  border-radius: 10px;
39
40
  position: relative;
40
- max-width: 80vw;
41
+ max-width: 450px;
41
42
  z-index: 121; /* To appear above mini component */
42
43
  min-width: unset;
43
44
  }
@@ -46,7 +47,8 @@ export default class Legend extends LitElement {
46
47
  width: 250px;
47
48
  }
48
49
  .presentation {
49
- font-size: 0.9em;
50
+ font-size: 0.85em;
51
+ line-height: 1em;
50
52
  display: flex;
51
53
  gap: 5px;
52
54
  align-items: center;
@@ -54,6 +56,40 @@ export default class Legend extends LitElement {
54
56
  .logo {
55
57
  width: 45px;
56
58
  }
59
+ pnx-map-legend {
60
+ display: block;
61
+ margin-top: 5px;
62
+ }
63
+
64
+ /* Lighter/smaller version */
65
+ .pnx-panel[part="panel"].pnx-legend-light {
66
+ display: flex;
67
+ gap: 3px;
68
+ padding: 3px 8px 3px 3px;
69
+ width: unset;
70
+ min-width: unset;
71
+ align-items: center;
72
+ font-size: 10px;
73
+ margin-right: -10px;
74
+ margin-bottom: -10px;
75
+ border-radius: 0;
76
+ border-top-left-radius: 5px;
77
+ border-right: none;
78
+ border-bottom: none;
79
+ }
80
+ .pnx-legend-light a,
81
+ .pnx-legend-light .presentation {
82
+ font-size: 10px;
83
+ }
84
+ .pnx-legend-light .logo {
85
+ width: 15px;
86
+ }
87
+
88
+ .pnx-legend-light pnx-map-legend {
89
+ width: max-content;
90
+ margin-top: unset;
91
+ font-size: 10px;
92
+ }
57
93
  `];
58
94
 
59
95
  /**
@@ -62,41 +98,59 @@ export default class Legend extends LitElement {
62
98
  * @type {Object}
63
99
  * @property {string} [focus] The focused main component (map, pic)
64
100
  * @property {string} [picture] The picture ID
101
+ * @property {boolean} [light=false] Lighter version (for iframes)
65
102
  */
66
103
  static properties = {
67
104
  focus: {type: String},
68
105
  picture: {type: String},
106
+ light: {type: Boolean},
69
107
  };
70
108
 
109
+ constructor() {
110
+ super();
111
+ this.light = false;
112
+ }
113
+
71
114
  render() {
72
115
  const classes = {
73
116
  "pnx-panel": true,
74
117
  "pnx-padded": this.focus == "map",
118
+ "pnx-legend-light": this.light,
75
119
  };
76
120
 
77
121
  return html`<div class=${classMap(classes)} part="panel">
78
122
  <div
79
123
  class="presentation"
80
- style=${this.focus != "map" && this.picture ? "display: none": ""}
124
+ style=${!this.light && this.focus != "map" && this.picture ? "display: none": ""}
81
125
  >
82
126
  <img class="logo" src=${PanoramaxImg} alt="" />
83
- <div>
84
- ${this._parent?._t.pnx.whats_panoramax}
85
- <pnx-link-button
127
+
128
+ ${this.light ? html`
129
+ &copy; <a
130
+ href=${PanoramaxWebsiteURL()}
86
131
  title=${this._parent?._t.map.more_panoramax}
87
- kind="superinline"
88
- href="https://panoramax.fr"
89
132
  target="_blank"
90
- size="sm"
91
- >
92
- ${fa(faInfoCircle)}
93
- </pnx-link-button>
94
- </div>
133
+ >${this._parent?._t.pnx.panoramax}</a> |
134
+ ` : html`
135
+ <div>
136
+ ${this._parent?._t.pnx.whats_panoramax}
137
+ <pnx-link-button
138
+ title=${this._parent?._t.map.more_panoramax}
139
+ kind="superinline"
140
+ href=${PanoramaxWebsiteURL()}
141
+ target="_blank"
142
+ size="sm"
143
+ >
144
+ ${fa(faInfoCircle)}
145
+ </pnx-link-button>
146
+ </div>
147
+ `}
95
148
  </div>
96
149
  <pnx-picture-legend
97
150
  ._parent=${this._parent}
98
151
  style=${this.focus == "map" ? "display: none": ""}
99
152
  collapsable
153
+ light=${this.light || nothing}
100
154
  >
101
155
  <slot slot="editors" name="editors">
102
156
  <pnx-widget-osmeditors ._parent=${this._parent} />
@@ -105,6 +159,7 @@ export default class Legend extends LitElement {
105
159
  <pnx-map-legend
106
160
  ._parent=${this._parent}
107
161
  style=${this.focus != "map" ? "display: none": ""}
162
+ light=${this.light || nothing}
108
163
  ></pnx-map-legend>
109
164
  </div>`;
110
165
  }
@@ -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();
@@ -61,54 +61,36 @@ export default class PictureLegendActions extends LitElement {
61
61
  this.renderRoot.querySelector("#pic-legend-headline-menu").close();
62
62
  }
63
63
 
64
- /** @private */
65
- _onShareClick() {
66
- this._closeGroup();
67
- this._parent._showShareOptions();
68
- }
69
-
70
- /** @private */
71
- _onReportClick() {
72
- this._closeGroup();
73
- this._parent._showReportForm();
74
- }
75
-
76
64
  /** @private */
77
65
  render() {
78
66
  return html`<pnx-togglable-group padded="false" id="pic-legend-headline-menu" ._parent=${this._parent}>
79
67
  <pnx-button slot="button" kind="inline">${fa(faEllipsisV)}</pnx-button>
80
68
  <pnx-list-group class="pnx-print-hidden" @click=${this._closeMenu}>
81
- ${this.full ? html`
69
+ ${this._meta ? html`<pnx-copy-button ._t=${this._parent?._t} text=${this._meta.id} unstyled>
70
+ ${this._parent?._t.pnx.metadata_general_copy_picid}
71
+ </pnx-copy-button>` : nothing}
72
+
73
+ <a
74
+ download
75
+ target="_blank"
76
+ href=${this._meta?.panorama?.hdUrl}
77
+ @click=${this._closeGroup}
78
+ >${this._parent?._t.pnx.share_image}</a>
79
+
80
+ ${this._parent.isWidthSmall() ? nothing : html`<button @click=${this._onPrint}>
81
+ ${this._parent?._t.pnx.share_print}
82
+ </button>`}
83
+
84
+ ${this._parent?.api?.getRSSURL() && html`
82
85
  <a
83
- download
84
86
  target="_blank"
85
- href=${this._meta?.panorama?.hdUrl}
87
+ href=${this._parent?.api.getRSSURL(this._parent?.map?.getBounds?.())}
88
+ title=${this._parent?._t.pnx.share_rss_title}
86
89
  @click=${this._closeGroup}
87
- >${this._parent?._t.pnx.share_image}</a>
88
- ${this._parent.isWidthSmall() ? nothing : html`<button @click=${this._onPrint}>
89
- ${this._parent?._t.pnx.share_print}
90
- </button>`}
91
- ${this._parent?.api?.getRSSURL() && html`
92
- <a
93
- target="_blank"
94
- href=${this._parent?.api.getRSSURL(this._parent?.map?.getBounds?.())}
95
- title=${this._parent?._t.pnx.share_rss_title}
96
- @click=${this._closeGroup}
97
- >
98
- ${this._parent?._t.pnx.share_rss}
99
- </a>
100
- `}
101
- ` : html`
102
- <button @click=${this._onReportClick}>
103
- ${this._parent?._t.pnx.report}
104
- </button>
105
- <button @click=${this._onShareClick}>
106
- ${this._parent?._t.pnx.share}
107
- </button>
108
- ${this._meta ? html`<pnx-copy-button ._t=${this._parent?._t} text=${this._meta.id} unstyled>
109
- ${this._parent?._t.pnx.metadata_general_copy_picid}
110
- </pnx-copy-button>` : nothing}
111
- ` }
90
+ >
91
+ ${this._parent?._t.pnx.share_rss}
92
+ </a>
93
+ `}
112
94
  </pnx-list-group>
113
95
  </pnx-togglable-group>`;
114
96
  }
@@ -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 */
@@ -0,0 +1 @@
1
+ {}
@@ -187,7 +187,8 @@
187
187
  "metadata_general_copy_id": "Kopi-ID",
188
188
  "metadata_general_copy_picid": "Kopi billed-ID",
189
189
  "filter_date_6months": "6 måneder",
190
- "picture_all": "Alle"
190
+ "picture_all": "Alle",
191
+ "panoramax": "Panoramax"
191
192
  },
192
193
  "psv": {
193
194
  "loadError": "Panoramaet kan ikke indlæses",
@@ -199,7 +200,7 @@
199
200
  "thumbnail": "Miniature af billedet, der holdes",
200
201
  "not_public": "Ikke offentligt synlig",
201
202
  "slow_loading": "Kortet indlæses langsomt og kan virke defekt",
202
- "map_data": "Kortdata:",
203
+ "map_data": "Kortdata: {m}",
203
204
  "more_panoramax": "Få mere at vide om Panoramax"
204
205
  }
205
206
  }