ogm-viewer 0.4.0 → 0.5.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.
- package/dist/cjs/{lerc-CT61sKYw.js → lerc-Df0hDWkS.js} +6 -6
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DKxSOrMP.js → ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DMEfXquS.js} +446 -80
- package/dist/cjs/ogm-alerts_11.cjs.entry.js +18 -0
- package/dist/cjs/ogm-viewer.cjs.js +1 -1
- package/dist/collection/assets/icons/exclamation-triangle-fill.svg +3 -0
- package/dist/collection/collection-manifest.json +2 -0
- package/dist/collection/components/ogm-alerts/ogm-alerts.css +51 -0
- package/dist/collection/components/ogm-alerts/ogm-alerts.js +71 -0
- package/dist/collection/components/ogm-alerts/ogm-alerts.test.js +26 -0
- package/dist/collection/components/ogm-image/ogm-image.js +57 -5
- package/dist/collection/components/ogm-map/ogm-map.css +34 -40
- package/dist/collection/components/ogm-map/ogm-map.js +76 -22
- package/dist/collection/components/ogm-menubar/ogm-menubar.test.js +21 -0
- package/dist/collection/components/ogm-preview/ogm-preview.css +16 -0
- package/dist/collection/components/ogm-preview/ogm-preview.js +144 -0
- package/dist/collection/components/ogm-preview/ogm-preview.test.js +37 -0
- package/dist/collection/components/ogm-previews/ogm-previews.css +3 -2
- package/dist/collection/components/ogm-previews/ogm-previews.js +7 -17
- package/dist/collection/components/ogm-previews/ogm-previews.test.js +83 -0
- package/dist/collection/components/ogm-settings/ogm-settings.js +1 -1
- package/dist/collection/components/ogm-sidebar/ogm-sidebar.js +2 -2
- package/dist/collection/components/ogm-viewer/ogm-viewer.js +36 -15
- package/dist/collection/lib/errors.js +137 -0
- package/dist/collection/lib/errors.test.js +96 -0
- package/dist/collection/lib/sources/geojson.js +2 -1
- package/dist/collection/lib/sources/iiif-manifest.js +2 -3
- package/dist/collection/lib/sources/iiif-manifest.test.js +4 -4
- package/dist/esm/{lerc-Bz409klg.js → lerc-CB_Jcu33.js} +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-C9zV3wMe.js → ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-Dlc6USWB.js} +446 -82
- package/dist/esm/ogm-alerts_11.entry.js +2 -0
- package/dist/esm/ogm-viewer.js +1 -1
- package/dist/ogm-viewer/assets/icons/exclamation-triangle-fill.svg +3 -0
- package/dist/ogm-viewer/ogm-viewer.esm.js +1 -1
- package/dist/ogm-viewer/p-7936ccc9.entry.js +1 -0
- package/dist/ogm-viewer/p-CWtUrqsM.js +2822 -0
- package/dist/ogm-viewer/{p-BrovdLv6.js → p-DqRDI3AC.js} +1 -1
- package/dist/types/components/ogm-alerts/ogm-alerts.d.ts +6 -0
- package/dist/types/components/ogm-alerts/ogm-alerts.test.d.ts +1 -0
- package/dist/types/components/ogm-image/ogm-image.d.ts +5 -0
- package/dist/types/components/ogm-map/ogm-map.d.ts +6 -0
- package/dist/types/components/ogm-preview/ogm-preview.d.ts +13 -0
- package/dist/types/components/ogm-preview/ogm-preview.test.d.ts +1 -0
- package/dist/types/components/ogm-previews/ogm-previews.d.ts +1 -5
- package/dist/types/components/ogm-previews/ogm-previews.test.d.ts +1 -0
- package/dist/types/components/ogm-viewer/ogm-viewer.d.ts +7 -2
- package/dist/types/components.d.ts +52 -0
- package/dist/types/lib/errors.d.ts +13 -0
- package/dist/types/lib/errors.test.d.ts +1 -0
- package/dist/types/lib/sources/source.d.ts +1 -1
- package/package.json +1 -1
- package/dist/cjs/ogm-attributes_9.cjs.entry.js +0 -16
- package/dist/esm/ogm-attributes_9.entry.js +0 -2
- package/dist/ogm-viewer/p-86b8fafc.entry.js +0 -1
- package/dist/ogm-viewer/p-CpCT3zlD.js +0 -2750
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry = require('./ogm-alerts.ogm-attributes.ogm-image.ogm-map.ogm-menubar.ogm-metadata.ogm-preview.ogm-previews.ogm-settings.ogm-sidebar.ogm-viewer-DMEfXquS.js');
|
|
4
|
+
require('./index-mu9UK_Fb.js');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
exports.ogm_alerts = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmAlerts;
|
|
9
|
+
exports.ogm_attributes = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmAttributes;
|
|
10
|
+
exports.ogm_image = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmImage;
|
|
11
|
+
exports.ogm_map = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmMap;
|
|
12
|
+
exports.ogm_menubar = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmMenubar;
|
|
13
|
+
exports.ogm_metadata = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmMetadata;
|
|
14
|
+
exports.ogm_preview = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmPreview;
|
|
15
|
+
exports.ogm_previews = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmPreviews;
|
|
16
|
+
exports.ogm_settings = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmSettings;
|
|
17
|
+
exports.ogm_sidebar = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmSidebar;
|
|
18
|
+
exports.ogm_viewer = ogmAlerts_ogmAttributes_ogmImage_ogmMap_ogmMenubar_ogmMetadata_ogmPreview_ogmPreviews_ogmSettings_ogmSidebar_ogmViewer_entry.OgmViewer;
|
|
@@ -19,7 +19,7 @@ var patchBrowser = () => {
|
|
|
19
19
|
|
|
20
20
|
patchBrowser().then(async (options) => {
|
|
21
21
|
await appGlobals.globalScripts();
|
|
22
|
-
return index.bootstrapLazy([["ogm-
|
|
22
|
+
return index.bootstrapLazy([["ogm-alerts_11.cjs",[[513,"ogm-viewer",{"recordUrl":[1,"record-url"],"theme":[1],"record":[32],"error":[32],"previewOpacity":[32],"sidebarOpen":[32],"loading":[32],"loadRecord":[64]},[[0,"sidebarToggled","toggleSidebar"],[0,"opacityChange","adjustPreviewOpacity"],[0,"mapLoading","setLoadingStarted"],[0,"imageLoading","setLoadingStarted"],[0,"mapIdle","setLoadingFinished"],[0,"imageLoaded","setLoadingFinished"]],{"recordUrl":[{"updateRecord":0}],"record":[{"resetLoading":0}]}],[513,"ogm-previews",{"theme":[1],"record":[16],"previewOpacity":[2,"preview-opacity"],"sidebarPadding":[2,"sidebar-padding"],"sources":[32]},null,{"record":[{"getSources":0}]}],[513,"ogm-sidebar",{"record":[16],"theme":[1],"open":[4]}],[513,"ogm-menubar",{"record":[16],"theme":[1],"loading":[4]}],[513,"ogm-preview",{"theme":[1],"source":[16],"previewOpacity":[2,"preview-opacity"],"sidebarPadding":[2,"sidebar-padding"],"error":[32]},[[0,"previewError","handlePreviewError"]],{"source":[{"resetError":0}]}],[513,"ogm-metadata",{"record":[16],"theme":[1],"fieldNames":[16],"filteredRecord":[32]}],[513,"ogm-settings",{"record":[16]},[[0,"input","handleOpacityChange"]]],[513,"ogm-map",{"source":[16],"theme":[1],"padding":[2],"easeMapTo":[64]},[[16,"featureSelected","handleFeatureSelected"]],{"source":[{"previewSource":0}],"padding":[{"onPaddingChange":0}]}],[513,"ogm-alerts",{"theme":[1],"error":[16]}],[513,"ogm-image",{"source":[16],"theme":[1],"padding":[2]},null,{"source":[{"onSourceChange":0}],"padding":[{"onPaddingChange":0}]}],[513,"ogm-attributes",{"features":[16],"currentIndex":[32]},null,{"features":[{"onFeaturesChange":0}],"currentIndex":[{"onCurrentIndexChange":0}]}]]]], options);
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
exports.setNonce = index.setNonce;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-exclamation-triangle-fill" viewBox="0 0 16 16">
|
|
2
|
+
<path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5m.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2"/>
|
|
3
|
+
</svg>
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"entries": [
|
|
3
|
+
"components/ogm-alerts/ogm-alerts.js",
|
|
3
4
|
"components/ogm-attributes/ogm-attributes.js",
|
|
4
5
|
"components/ogm-image/ogm-image.js",
|
|
5
6
|
"components/ogm-map/ogm-map.js",
|
|
6
7
|
"components/ogm-menubar/ogm-menubar.js",
|
|
7
8
|
"components/ogm-metadata/ogm-metadata.js",
|
|
9
|
+
"components/ogm-preview/ogm-preview.js",
|
|
8
10
|
"components/ogm-previews/ogm-previews.js",
|
|
9
11
|
"components/ogm-settings/ogm-settings.js",
|
|
10
12
|
"components/ogm-sidebar/ogm-sidebar.js",
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* Fill the space left by the preview it replaces and center the error within it */
|
|
2
|
+
:host {
|
|
3
|
+
display: flex;
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 100%;
|
|
6
|
+
place-items: center;
|
|
7
|
+
place-content: center;
|
|
8
|
+
background: var(--wa-color-surface-default);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.alerts {
|
|
12
|
+
padding: var(--wa-space-m);
|
|
13
|
+
max-width: 40rem;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.alert {
|
|
17
|
+
box-shadow: var(--wa-shadow-m);
|
|
18
|
+
align-items: start;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.alert::part(message) {
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: start;
|
|
24
|
+
gap: var(--wa-space-s);
|
|
25
|
+
width: 100%;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.content {
|
|
29
|
+
flex: auto;
|
|
30
|
+
min-width: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.title {
|
|
34
|
+
display: block;
|
|
35
|
+
font-weight: var(--wa-font-weight-bold);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.message {
|
|
39
|
+
margin-top: var(--wa-space-3xs);
|
|
40
|
+
font-size: var(--wa-font-size-s);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.url {
|
|
44
|
+
margin-top: var(--wa-space-2xs);
|
|
45
|
+
font-family: var(--wa-font-family-code);
|
|
46
|
+
font-size: var(--wa-font-size-xs);
|
|
47
|
+
color: var(--wa-color-text-quiet);
|
|
48
|
+
overflow: hidden;
|
|
49
|
+
text-overflow: ellipsis;
|
|
50
|
+
white-space: nowrap;
|
|
51
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Host, h } from "@stencil/core";
|
|
2
|
+
// Renders a single preview error, centered and filling its container. Used in place of a failed
|
|
3
|
+
// preview (inside <ogm-preview>) or in place of the previews entirely (when the record fails to load).
|
|
4
|
+
export class OgmAlerts {
|
|
5
|
+
theme;
|
|
6
|
+
error;
|
|
7
|
+
render() {
|
|
8
|
+
if (!this.error)
|
|
9
|
+
return null;
|
|
10
|
+
return (h(Host, { class: this.theme && `wa-${this.theme}` }, h("div", { class: "alerts", role: "alert", "aria-live": "assertive" }, h("wa-callout", { variant: "danger", appearance: "filled-outlined", class: "alert" }, h("wa-icon", { slot: "icon", name: "exclamation-triangle-fill", canvas: "auto" }), h("div", { class: "content" }, h("strong", { class: "title" }, this.error.title), h("div", { class: "message" }, this.error.message), this.error.url && (h("div", { class: "url", title: this.error.url }, this.error.url)))))));
|
|
11
|
+
}
|
|
12
|
+
static get is() { return "ogm-alerts"; }
|
|
13
|
+
static get encapsulation() { return "shadow"; }
|
|
14
|
+
static get originalStyleUrls() {
|
|
15
|
+
return {
|
|
16
|
+
"$": ["ogm-alerts.css"]
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
static get styleUrls() {
|
|
20
|
+
return {
|
|
21
|
+
"$": ["ogm-alerts.css"]
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
static get properties() {
|
|
25
|
+
return {
|
|
26
|
+
"theme": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"mutable": false,
|
|
29
|
+
"complexType": {
|
|
30
|
+
"original": "'light' | 'dark'",
|
|
31
|
+
"resolved": "\"dark\" | \"light\"",
|
|
32
|
+
"references": {}
|
|
33
|
+
},
|
|
34
|
+
"required": false,
|
|
35
|
+
"optional": false,
|
|
36
|
+
"docs": {
|
|
37
|
+
"tags": [],
|
|
38
|
+
"text": ""
|
|
39
|
+
},
|
|
40
|
+
"getter": false,
|
|
41
|
+
"setter": false,
|
|
42
|
+
"reflect": false,
|
|
43
|
+
"attribute": "theme"
|
|
44
|
+
},
|
|
45
|
+
"error": {
|
|
46
|
+
"type": "unknown",
|
|
47
|
+
"mutable": false,
|
|
48
|
+
"complexType": {
|
|
49
|
+
"original": "PreviewError",
|
|
50
|
+
"resolved": "PreviewError",
|
|
51
|
+
"references": {
|
|
52
|
+
"PreviewError": {
|
|
53
|
+
"location": "import",
|
|
54
|
+
"path": "../../lib/errors",
|
|
55
|
+
"id": "src/lib/errors.ts::PreviewError",
|
|
56
|
+
"referenceLocation": "PreviewError"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"required": false,
|
|
61
|
+
"optional": true,
|
|
62
|
+
"docs": {
|
|
63
|
+
"tags": [],
|
|
64
|
+
"text": ""
|
|
65
|
+
},
|
|
66
|
+
"getter": false,
|
|
67
|
+
"setter": false
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { render, describe, it, expect, h } from "@stencil/vitest";
|
|
2
|
+
import { referenceError } from "../../lib/errors";
|
|
3
|
+
// Mock a network failure on load
|
|
4
|
+
const makeError = (url) => referenceError(new TypeError('Failed to fetch'), 'GeoJSON', url);
|
|
5
|
+
describe('ogm-alerts', () => {
|
|
6
|
+
it('renders nothing when there is no error', async () => {
|
|
7
|
+
const { root } = await render(h("ogm-alerts", null));
|
|
8
|
+
const shadowRoot = root.shadowRoot;
|
|
9
|
+
expect(shadowRoot.querySelector('.alerts')).toBeNull();
|
|
10
|
+
});
|
|
11
|
+
it('renders a danger callout with the error title, message, and url', async () => {
|
|
12
|
+
const { root } = await render(h("ogm-alerts", { error: makeError('http://example.com/data.json') }));
|
|
13
|
+
const shadowRoot = root.shadowRoot;
|
|
14
|
+
const callout = shadowRoot.querySelector('wa-callout');
|
|
15
|
+
expect(callout).not.toBeNull();
|
|
16
|
+
expect(callout.getAttribute('variant')).toBe('danger');
|
|
17
|
+
expect(callout.textContent).toContain('GeoJSON');
|
|
18
|
+
expect(callout.textContent).toContain('CORS');
|
|
19
|
+
expect(callout.textContent).toContain('http://example.com/data.json');
|
|
20
|
+
});
|
|
21
|
+
it('omits the url line when the error has no url', async () => {
|
|
22
|
+
const { root } = await render(h("ogm-alerts", { error: makeError() }));
|
|
23
|
+
const shadowRoot = root.shadowRoot;
|
|
24
|
+
expect(shadowRoot.querySelector('.url')).toBeNull();
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { h, Host } from "@stencil/core";
|
|
2
2
|
import { Viewer } from "openseadragon";
|
|
3
3
|
import { getElement, findElement } from "../../lib/elements";
|
|
4
|
+
import { referenceError } from "../../lib/errors";
|
|
4
5
|
export class OgmImage {
|
|
5
6
|
el;
|
|
6
7
|
source;
|
|
@@ -8,8 +9,11 @@ export class OgmImage {
|
|
|
8
9
|
padding = 0;
|
|
9
10
|
imageLoaded;
|
|
10
11
|
imageLoading;
|
|
12
|
+
previewError;
|
|
11
13
|
// OpenSeadragon viewer instance
|
|
12
14
|
viewer;
|
|
15
|
+
// Guards against reporting more than one error per load attempt
|
|
16
|
+
errorReported = false;
|
|
13
17
|
// Set up OpenSeadragon viewer on load
|
|
14
18
|
async componentDidLoad() {
|
|
15
19
|
this.viewer = new Viewer({
|
|
@@ -26,10 +30,21 @@ export class OgmImage {
|
|
|
26
30
|
nextButton: getElement(this.el, '.next'),
|
|
27
31
|
previousButton: getElement(this.el, '.prev'),
|
|
28
32
|
});
|
|
33
|
+
// Clear loading state whether we succeeded or failed
|
|
29
34
|
this.viewer.addHandler('open', () => this.imageLoaded.emit());
|
|
35
|
+
// Surface OpenSeaDragon decode errors here
|
|
36
|
+
this.viewer.addHandler('open-failed', event => {
|
|
37
|
+
this.imageLoaded.emit();
|
|
38
|
+
this.reportError(new Error(event.message));
|
|
39
|
+
});
|
|
40
|
+
// If we do have a source, load the images
|
|
30
41
|
if (this.source)
|
|
31
42
|
await this.loadImages();
|
|
32
43
|
}
|
|
44
|
+
// Destroy the viewer when we are removed from the DOM
|
|
45
|
+
disconnectedCallback() {
|
|
46
|
+
this.viewer?.destroy();
|
|
47
|
+
}
|
|
33
48
|
// Update preview when source changes
|
|
34
49
|
async onSourceChange() {
|
|
35
50
|
if (this.source)
|
|
@@ -46,14 +61,29 @@ export class OgmImage {
|
|
|
46
61
|
// Get all of the IIIF image URLs and send them to OpenSeadragon
|
|
47
62
|
// This makes a request to fetch and cache the manifest
|
|
48
63
|
async loadImages() {
|
|
64
|
+
this.errorReported = false;
|
|
49
65
|
this.imageLoading.emit();
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
66
|
+
try {
|
|
67
|
+
const images = await this.source.getIIIFImageUrls();
|
|
68
|
+
if (!images)
|
|
69
|
+
throw new Error('No IIIF images found for source');
|
|
70
|
+
this.viewer.open(images);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error(`Error loading IIIF images for ${this.source.url}:`, error);
|
|
74
|
+
this.imageLoaded.emit();
|
|
75
|
+
this.reportError(error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Emit a single preview error per load attempt
|
|
79
|
+
reportError(error) {
|
|
80
|
+
if (this.errorReported || !this.source)
|
|
81
|
+
return;
|
|
82
|
+
this.errorReported = true;
|
|
83
|
+
this.previewError.emit(referenceError(error, this.source.label(), this.source.url));
|
|
54
84
|
}
|
|
55
85
|
render() {
|
|
56
|
-
return (h(Host, { key: '
|
|
86
|
+
return (h(Host, { key: 'ebbebaddac72024a3b311e0e0e501267a83d1e95' }, h("div", { key: '4f171256535cfd11430e2269fda389ffae3cedae', id: "openseadragon" }, h("div", { key: 'c308186a13fd6b8e0b1fadbf1fd1e6924631f9d6', class: "controls" }, h("wa-button", { key: '1f9e0c4c6d881bf09d7ceb160f470992d71ebe07', class: "zoom-in", size: "s", appearance: "filled-outlined", pill: true }, h("wa-icon", { key: 'cbacb0a388de2c7f349e25172027874a0224a678', name: "zoom-in", label: "Zoom In", canvas: "auto" })), h("wa-button", { key: 'dd8d7e9c5584b124ae105b2187100964f5e3a02a', class: "zoom-out", size: "s", appearance: "filled-outlined", pill: true }, h("wa-icon", { key: '2b5acf2e07c99df9556692bf534bb3847506e4d4', name: "zoom-out", label: "Zoom Out", canvas: "auto" })), h("wa-button", { key: '5534a5c77ea20a1f77544e5acd99d4247dd3d287', class: "home", size: "s", appearance: "filled-outlined", pill: true }, h("wa-icon", { key: 'faadb8ea57bf1b831b292eaf66bcea39b7e215d1', name: "house", label: "Reset View", canvas: "auto" })), h("wa-button", { key: '8979cf58a94da89e0e2d132a92fe45323f07de01', class: "full-page", size: "s", appearance: "filled-outlined", pill: true }, h("wa-icon", { key: '12cb3224e7f14258376c1c0bf6ffc5abda5c2252', name: "arrows-fullscreen", label: "Full Screen", canvas: "auto" })), h("wa-button", { key: 'e79c37f27ff14d5c4991ff30ff88aada467214ec', class: "next", size: "s", appearance: "filled-outlined", pill: true }, h("wa-icon", { key: 'ee10870ace583257393c53ba12b73ab3b015371b', name: "arrow-right", label: "Next", canvas: "auto" })), h("wa-button", { key: '9d8999e199b7b6338261eb16a655d2199520cf22', class: "prev", size: "s", appearance: "filled-outlined", pill: true }, h("wa-icon", { key: 'fde1a9022b9e5f90e269c75ce87943808031e021', name: "arrow-left", label: "Previous", canvas: "auto" }))))));
|
|
57
87
|
}
|
|
58
88
|
static get is() { return "ogm-image"; }
|
|
59
89
|
static get encapsulation() { return "shadow"; }
|
|
@@ -163,6 +193,28 @@ export class OgmImage {
|
|
|
163
193
|
"resolved": "void",
|
|
164
194
|
"references": {}
|
|
165
195
|
}
|
|
196
|
+
}, {
|
|
197
|
+
"method": "previewError",
|
|
198
|
+
"name": "previewError",
|
|
199
|
+
"bubbles": true,
|
|
200
|
+
"cancelable": true,
|
|
201
|
+
"composed": true,
|
|
202
|
+
"docs": {
|
|
203
|
+
"tags": [],
|
|
204
|
+
"text": ""
|
|
205
|
+
},
|
|
206
|
+
"complexType": {
|
|
207
|
+
"original": "PreviewError",
|
|
208
|
+
"resolved": "PreviewError",
|
|
209
|
+
"references": {
|
|
210
|
+
"PreviewError": {
|
|
211
|
+
"location": "import",
|
|
212
|
+
"path": "../../lib/errors",
|
|
213
|
+
"id": "src/lib/errors.ts::PreviewError",
|
|
214
|
+
"referenceLocation": "PreviewError"
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
166
218
|
}];
|
|
167
219
|
}
|
|
168
220
|
static get elementRef() { return "el"; }
|
|
@@ -6,6 +6,11 @@
|
|
|
6
6
|
position: relative;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
/* Color of the map background ("space" around the globe) */
|
|
10
|
+
.maplibregl-canvas {
|
|
11
|
+
background-color: var(--wa-color-surface-default);
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
/* Inspection popups. Vertical scrolling (when content is too tall) is handled by the
|
|
10
15
|
<wa-scroller> inside ogm-attributes, not here - that's what gives it the fading shadow cue. */
|
|
11
16
|
.maplibregl-popup-content {
|
|
@@ -14,6 +19,34 @@
|
|
|
14
19
|
padding: 0;
|
|
15
20
|
box-shadow: var(--wa-shadow-l);
|
|
16
21
|
border: var(--wa-panel-border-width) solid var(--wa-color-surface-border);
|
|
22
|
+
color: var(--wa-color-text-normal);
|
|
23
|
+
background-color: var(--wa-color-surface-default);
|
|
24
|
+
|
|
25
|
+
.maplibregl-popup-close-button {
|
|
26
|
+
background-color: var(--wa-color-surface-default);
|
|
27
|
+
border-radius: 10px;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Popup tip (the little triangle) */
|
|
32
|
+
.maplibregl-popup-anchor-right .maplibregl-popup-tip {
|
|
33
|
+
border-left-color: var(--wa-color-surface-border);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.maplibregl-popup-anchor-left .maplibregl-popup-tip {
|
|
37
|
+
border-right-color: var(--wa-color-surface-border);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
|
|
41
|
+
.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip,
|
|
42
|
+
.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip {
|
|
43
|
+
border-top-color: var(--wa-color-surface-border);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.maplibregl-popup-anchor-top .maplibregl-popup-tip,
|
|
47
|
+
.maplibregl-popup-anchor-top-right .maplibregl-popup-tip,
|
|
48
|
+
.maplibregl-popup-anchor-top-left .maplibregl-popup-tip {
|
|
49
|
+
border-bottom-color: var(--wa-color-surface-border);
|
|
17
50
|
}
|
|
18
51
|
|
|
19
52
|
/* Dark mode map adjustments */
|
|
@@ -22,10 +55,6 @@
|
|
|
22
55
|
stroke: white;
|
|
23
56
|
}
|
|
24
57
|
|
|
25
|
-
.maplibregl-canvas {
|
|
26
|
-
background-color: black;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
58
|
.maplibregl-ctrl.maplibregl-ctrl-group {
|
|
30
59
|
filter: invert(1);
|
|
31
60
|
}
|
|
@@ -34,43 +63,8 @@
|
|
|
34
63
|
.maplibregl-ctrl-group button:focus:focus-visible {
|
|
35
64
|
box-shadow: 0 0 2px 2px #ff6900;
|
|
36
65
|
}
|
|
66
|
+
|
|
37
67
|
.maplibregl-ctrl button.maplibregl-ctrl-globe-enabled .maplibregl-ctrl-icon {
|
|
38
68
|
filter: invert(1);
|
|
39
69
|
}
|
|
40
|
-
|
|
41
|
-
details.maplibregl-ctrl.maplibregl-ctrl-attrib {
|
|
42
|
-
background-color: black;
|
|
43
|
-
color: #999;
|
|
44
|
-
}
|
|
45
|
-
details.maplibregl-ctrl.maplibregl-ctrl-attrib a {
|
|
46
|
-
color: #999;
|
|
47
|
-
}
|
|
48
|
-
details.maplibregl-ctrl.maplibregl-ctrl-attrib.maplibregl-compact-show .maplibregl-ctrl-attrib-button {
|
|
49
|
-
background-color: #999;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
div.maplibregl-popup-content {
|
|
53
|
-
background-color: black;
|
|
54
|
-
color: #ccc;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
div.maplibregl-popup-anchor-right div.maplibregl-popup-tip {
|
|
58
|
-
border-left-color: black;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
div.maplibregl-popup-anchor-left div.maplibregl-popup-tip {
|
|
62
|
-
border-right-color: black;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
div.maplibregl-popup-anchor-bottom div.maplibregl-popup-tip,
|
|
66
|
-
div.maplibregl-popup-anchor-bottom-right div.maplibregl-popup-tip,
|
|
67
|
-
div.maplibregl-popup-anchor-bottom-left div.maplibregl-popup-tip {
|
|
68
|
-
border-top-color: black;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
div.maplibregl-popup-anchor-top div.maplibregl-popup-tip,
|
|
72
|
-
div.maplibregl-popup-anchor-top-right div.maplibregl-popup-tip,
|
|
73
|
-
div.maplibregl-popup-anchor-top-left div.maplibregl-popup-tip {
|
|
74
|
-
border-bottom-color: black;
|
|
75
|
-
}
|
|
76
70
|
}
|
|
@@ -8,6 +8,7 @@ import PMTilesSource from "../../lib/sources/pmtiles";
|
|
|
8
8
|
import RasterSource from "../../lib/sources/raster";
|
|
9
9
|
import WmsSource from "../../lib/sources/wms";
|
|
10
10
|
import { getElement } from "../../lib/elements";
|
|
11
|
+
import { referenceError } from "../../lib/errors";
|
|
11
12
|
import CogPreviewer from "../../lib/previewers/cog";
|
|
12
13
|
import GeoJSONPreviewer from "../../lib/previewers/geojson";
|
|
13
14
|
import OpenIndexMapPreviewer from "../../lib/previewers/openindexmap";
|
|
@@ -26,6 +27,9 @@ export class OgmMap {
|
|
|
26
27
|
padding = 0;
|
|
27
28
|
mapIdle;
|
|
28
29
|
mapLoading;
|
|
30
|
+
previewError;
|
|
31
|
+
// Guards against reporting more than one error per load attempt
|
|
32
|
+
errorReported = false;
|
|
29
33
|
// MapLibre map instance and popup instance for feature info display
|
|
30
34
|
map;
|
|
31
35
|
mapTheme;
|
|
@@ -50,10 +54,10 @@ export class OgmMap {
|
|
|
50
54
|
});
|
|
51
55
|
this.getContainer();
|
|
52
56
|
this.addControls();
|
|
53
|
-
this.map.on('idle', () => this.mapIdle.emit());
|
|
54
57
|
this.map.on('load', () => this.previewSource(this.source));
|
|
55
58
|
this.map.on('mousemove', this.handleHover.bind(this));
|
|
56
59
|
this.map.on('click', this.handleClick.bind(this));
|
|
60
|
+
this.map.on('error', this.handleMapError.bind(this));
|
|
57
61
|
// View as a globe with atmosphere effects
|
|
58
62
|
this.map.on('style.load', () => {
|
|
59
63
|
this.map.setProjection({ type: 'globe' });
|
|
@@ -118,30 +122,57 @@ export class OgmMap {
|
|
|
118
122
|
// Do nothing if we didn't get passed a source
|
|
119
123
|
if (!source)
|
|
120
124
|
return;
|
|
125
|
+
// Fresh load attempt: allow one error to be reported again for this source
|
|
126
|
+
this.errorReported = false;
|
|
121
127
|
// Indicate loading state so we can show the spinner
|
|
122
128
|
this.mapLoading.emit();
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
129
|
+
try {
|
|
130
|
+
// Close popup if one is open
|
|
131
|
+
this.clearFeatureSelection();
|
|
132
|
+
this.destroyPopup();
|
|
133
|
+
// Clear existing preview
|
|
134
|
+
if (this.previewer) {
|
|
135
|
+
await this.previewer.clearPreview();
|
|
136
|
+
this.previewer = undefined;
|
|
137
|
+
}
|
|
138
|
+
// Get the appropriate previewer for our source and preview it
|
|
139
|
+
this.previewer = await this.getMapPreviewer(this.map);
|
|
140
|
+
if (!this.previewer)
|
|
141
|
+
throw new Error(`No previewer found for source: ${source.constructor.name}`);
|
|
142
|
+
await this.previewer.preview();
|
|
143
|
+
// Fit to bounds from the record; the spinner stays up until the map finishes moving
|
|
144
|
+
const bounds = await this.source.getBounds();
|
|
145
|
+
if (bounds)
|
|
146
|
+
await this.fitMapBounds(bounds);
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
console.error(`Error previewing source ${source.url}:`, error);
|
|
150
|
+
if (!this.errorReported) {
|
|
151
|
+
this.errorReported = true;
|
|
152
|
+
this.previewError.emit(referenceError(error, source.label(), source.url));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
this.mapIdle.emit();
|
|
130
157
|
}
|
|
131
|
-
// Get the appropriate previewer for our source and preview it
|
|
132
|
-
this.previewer = await this.getMapPreviewer(this.map);
|
|
133
|
-
if (!this.previewer)
|
|
134
|
-
throw new Error(`No previewer found for source: ${source.constructor.name}`);
|
|
135
|
-
await this.previewer.preview();
|
|
136
|
-
// Fit to bounds from the record
|
|
137
|
-
const bounds = await this.source.getBounds();
|
|
138
|
-
if (bounds)
|
|
139
|
-
await this.fitMapBounds(bounds);
|
|
140
|
-
// Emit map idle event to signal that the map is ready
|
|
141
|
-
this.mapIdle.emit();
|
|
142
158
|
}
|
|
143
|
-
//
|
|
159
|
+
// Surface MapLibre errors tied to the current preview source, skipping the
|
|
160
|
+
// noise from basemap/glyph/sprite loads, and deduped to a single alert per load attempt.
|
|
161
|
+
handleMapError(event) {
|
|
162
|
+
if (this.errorReported || !this.source || !this.previewer)
|
|
163
|
+
return;
|
|
164
|
+
if (event.sourceId !== this.previewer.sourceId)
|
|
165
|
+
return;
|
|
166
|
+
this.errorReported = true;
|
|
167
|
+
this.previewError.emit(referenceError(event.error, this.source.label(), this.source.url));
|
|
168
|
+
}
|
|
169
|
+
// Fit the map to the given bounds; resolve once the move finishes. Guard the case where the bounds
|
|
170
|
+
// can't produce a camera - e.g. sidebar padding wider than the viewport, or a hidden, zero-size
|
|
171
|
+
// inactive tab panel - because then fitBounds won't move, 'moveend' never fires, and awaiting this
|
|
172
|
+
// promise (and the loading state that depends on it) would hang forever.
|
|
144
173
|
async fitMapBounds(bounds) {
|
|
174
|
+
if (!this.map.cameraForBounds(bounds))
|
|
175
|
+
return;
|
|
145
176
|
return new Promise(resolve => {
|
|
146
177
|
this.map.once('moveend', () => resolve());
|
|
147
178
|
this.map.fitBounds(bounds);
|
|
@@ -213,7 +244,8 @@ export class OgmMap {
|
|
|
213
244
|
}
|
|
214
245
|
// Create a new popup and set its content and location
|
|
215
246
|
createPopup(location) {
|
|
216
|
-
this.popup = new maplibregl.Popup({ maxWidth: 'none'
|
|
247
|
+
this.popup = new maplibregl.Popup({ maxWidth: 'none' }).setDOMContent(this.attributesEl).setLngLat(location).addTo(this.map);
|
|
248
|
+
this.popup.on('close', this.clearFeatureSelection.bind(this));
|
|
217
249
|
}
|
|
218
250
|
// Remove popup from the map and clear the reference
|
|
219
251
|
destroyPopup() {
|
|
@@ -227,7 +259,7 @@ export class OgmMap {
|
|
|
227
259
|
return this.previewer?.layerIds || [];
|
|
228
260
|
}
|
|
229
261
|
render() {
|
|
230
|
-
return h("div", { key: '
|
|
262
|
+
return h("div", { key: '9519610af20287a4d7e28470c715accc5ffb8430', id: "map", class: `wa-${this.theme}` });
|
|
231
263
|
}
|
|
232
264
|
static get is() { return "ogm-map"; }
|
|
233
265
|
static get encapsulation() { return "shadow"; }
|
|
@@ -337,6 +369,28 @@ export class OgmMap {
|
|
|
337
369
|
"resolved": "void",
|
|
338
370
|
"references": {}
|
|
339
371
|
}
|
|
372
|
+
}, {
|
|
373
|
+
"method": "previewError",
|
|
374
|
+
"name": "previewError",
|
|
375
|
+
"bubbles": true,
|
|
376
|
+
"cancelable": true,
|
|
377
|
+
"composed": true,
|
|
378
|
+
"docs": {
|
|
379
|
+
"tags": [],
|
|
380
|
+
"text": ""
|
|
381
|
+
},
|
|
382
|
+
"complexType": {
|
|
383
|
+
"original": "PreviewError",
|
|
384
|
+
"resolved": "PreviewError",
|
|
385
|
+
"references": {
|
|
386
|
+
"PreviewError": {
|
|
387
|
+
"location": "import",
|
|
388
|
+
"path": "../../lib/errors",
|
|
389
|
+
"id": "src/lib/errors.ts::PreviewError",
|
|
390
|
+
"referenceLocation": "PreviewError"
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
340
394
|
}];
|
|
341
395
|
}
|
|
342
396
|
static get methods() {
|
|
@@ -46,4 +46,25 @@ describe('ogm-menubar', () => {
|
|
|
46
46
|
`);
|
|
47
47
|
});
|
|
48
48
|
});
|
|
49
|
+
describe('loading indicator', () => {
|
|
50
|
+
it('shows the spinner while loading', async () => {
|
|
51
|
+
const { root } = await render(h("ogm-menubar", { loading: true }));
|
|
52
|
+
const shadowRoot = root.shadowRoot;
|
|
53
|
+
expect(shadowRoot.querySelector('.loading-spinner')).not.toBeNull();
|
|
54
|
+
});
|
|
55
|
+
it('hides the spinner when not loading', async () => {
|
|
56
|
+
const { root } = await render(h("ogm-menubar", { loading: false }));
|
|
57
|
+
const shadowRoot = root.shadowRoot;
|
|
58
|
+
expect(shadowRoot.querySelector('.loading-spinner')).toBeNull();
|
|
59
|
+
});
|
|
60
|
+
it('toggles the spinner when the loading prop changes', async () => {
|
|
61
|
+
const { root, setProps } = await render(h("ogm-menubar", { loading: false }));
|
|
62
|
+
const shadowRoot = root.shadowRoot;
|
|
63
|
+
expect(shadowRoot.querySelector('.loading-spinner')).toBeNull();
|
|
64
|
+
await setProps({ loading: true });
|
|
65
|
+
expect(shadowRoot.querySelector('.loading-spinner')).not.toBeNull();
|
|
66
|
+
await setProps({ loading: false });
|
|
67
|
+
expect(shadowRoot.querySelector('.loading-spinner')).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
49
70
|
});
|