cozy-iiif 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -7,7 +7,7 @@ A developer-friendly API for working with IIIF resources. Built on top of the II
7
7
  - Resource identification for any URL: IIIF collection and presentation manifests, image services, static image, and more.
8
8
  - Developer-friendly TypeScript API for parsing and working with IIIF resources.
9
9
  - Seamless upgrade from IIIF Presentation API v2 to v3 (using `@iiif/parser` under the hood).
10
- - Preserves access to underlying `@iiif-presentation/3` types.
10
+ - Preserves access to underlying `@iiif/presentation-3` types.
11
11
  - Helpers for stitching thumbnails and cropping regions from IIIF Level 0 tilesets.
12
12
  - Helpers for adding annotations to Canvases and Presentation manifests.
13
13
 
@@ -69,12 +69,15 @@ console.log(manifest.getLabel('de'));
69
69
 
70
70
  // Metadata as normalized CozyMetada[]
71
71
  console.log(manifest.getMetadata());
72
+
73
+ // The raw source data, @iiif/presentation-3 typed
74
+ console.log(manifest.source);
72
75
  ```
73
76
 
74
77
  ### Thumbnail Helper
75
78
 
76
79
  CozyCanvas has a simple helper for getting a Thumbnail URL. The URL
77
- will use the `thumbnail` property if available, or the image service
80
+ will use the `thumbnail` property of the original resource if available, or the image service
78
81
  otherwise.
79
82
 
80
83
  ```ts
@@ -94,19 +97,19 @@ based on the manifest's `structures` property.
94
97
 
95
98
  ```ts
96
99
  // Returns a list of CozyTOCNode objects.
97
- const root = manifest.getTableOfContents();
100
+ const toc = manifest.getTableOfContents();
98
101
 
99
102
  const logTOCNode = (node: CozyTOCNode) => {
100
103
  console.log(node.getLabel());
101
104
  node.children.forEach(logTOCNode);
102
105
  }
103
106
 
104
- root.forEach(logTOCNode);
107
+ root.forEach(logTOCNode.root);
105
108
  ```
106
109
 
107
- ### Working with different Image Types and Levels
110
+ ### Image Types and Levels
108
111
 
109
- The **CozyImageResource** type provides a helper property for identify the type and level of
112
+ The **CozyImageResource** provides a helper properties that identify the type and level of
110
113
  an image.
111
114
 
112
115
  ```ts
@@ -204,8 +207,11 @@ const annotations: Annotation[] = [{
204
207
 
205
208
  // Generates a new CozyManifest with annotations from an original CozyManifest.
206
209
  const updated = importAnnotations(original, annotations);
210
+
211
+ // The source field has the raw manifest JSON (annotations included!)
212
+ console.log(updated.source);
207
213
  ```
208
214
 
209
215
  ## License
210
216
 
211
- MIT License - see the [LICENSE](LICENSE) file for details.
217
+ MIT License - see the [LICENSE](LICENSE) file for details.
@@ -1,2 +1,2 @@
1
- import { CozyRange, CozyTOCNode } from '../types';
2
- export declare const getTableOfContents: (ranges: CozyRange[]) => () => CozyTOCNode[];
1
+ import { CozyRange, CozyTOC } from '../types';
2
+ export declare const getTableOfContents: (ranges: CozyRange[]) => () => CozyTOC;
package/dist/index.js CHANGED
@@ -1,14 +1,14 @@
1
- import { g as v, a as x, b as L } from "./resource-DS2brz47.js";
1
+ import { g as f, a as M, b as w } from "./resource-DS2brz47.js";
2
2
  import { c as Ft } from "./resource-DS2brz47.js";
3
3
  var ce = "http://library.stanford.edu/iiif/image-api/compliance.html#level0", le = "http://library.stanford.edu/iiif/image-api/compliance.html#level1", V = "http://library.stanford.edu/iiif/image-api/compliance.html#level2", pe = "http://library.stanford.edu/iiif/image-api/conformance.html#level0", ve = "http://library.stanford.edu/iiif/image-api/conformance.html#level1", F = "http://library.stanford.edu/iiif/image-api/conformance.html#level2", he = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level0", ue = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1", W = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2", fe = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level0", me = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level1", B = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level2", ge = "http://iiif.io/api/image/1/level0.json", de = "http://iiif.io/api/image/1/profiles/level0.json", ye = "http://iiif.io/api/image/1/level1.json", Ae = "http://iiif.io/api/image/1/profiles/level1.json", H = "http://iiif.io/api/image/1/level2.json", J = "http://iiif.io/api/image/1/profiles/level2.json", Ce = "http://iiif.io/api/image/2/level0.json", be = "http://iiif.io/api/image/2/profiles/level0.json", Re = "http://iiif.io/api/image/2/level1.json", Le = "http://iiif.io/api/image/2/profiles/level1.json", G = "http://iiif.io/api/image/2/level2.json", z = "http://iiif.io/api/image/2/profiles/level2.json", we = "level0", Ie = "level1", K = "level2", Se = "http://iiif.io/api/image/2/level0", Te = "http://iiif.io/api/image/2/level1", Q = "http://iiif.io/api/image/2/level2", xe = [Q, V, F, W, B, H, J, G, z, K], $e = [Se, Te, Q, ce, le, V, pe, ve, F, he, ue, W, fe, me, B, ge, de, ye, Ae, H, J, Ce, be, Re, Le, G, z, we, Ie, K], Me = $e;
4
- function h(t) {
4
+ function m(t) {
5
5
  for (let e in t) (typeof t[e] > "u" || t[e] === null) && delete t[e];
6
6
  return t;
7
7
  }
8
8
  function b(t) {
9
9
  return Array.isArray(t) ? t : t ? [t] : [];
10
10
  }
11
- var je = Object.defineProperty, ke = (t, e, r) => e in t ? je(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r, y = (t, e, r) => (ke(t, typeof e != "symbol" ? e + "" : e, r), r), U = ["sc:Collection", "sc:Manifest", "sc:Canvas", "sc:AnnotationList", "oa:Annotation", "sc:Range", "sc:Layer", "sc:Sequence", "oa:Choice", "Service", "ContentResource"];
11
+ var je = Object.defineProperty, ke = (t, e, r) => e in t ? je(t, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : t[e] = r, A = (t, e, r) => (ke(t, typeof e != "symbol" ? e + "" : e, r), r), U = ["sc:Collection", "sc:Manifest", "sc:Canvas", "sc:AnnotationList", "oa:Annotation", "sc:Range", "sc:Layer", "sc:Sequence", "oa:Choice", "Service", "ContentResource"];
12
12
  function Pe(t) {
13
13
  if (typeof t > "u" || t === null) throw new Error("Null or undefined is not a valid entity.");
14
14
  if (Array.isArray(t)) throw new Error("Array is not a valid entity");
@@ -23,7 +23,7 @@ function Pe(t) {
23
23
  }
24
24
  var Oe = class X {
25
25
  constructor(e, r = {}) {
26
- y(this, "traversals"), y(this, "options"), this.traversals = { collection: [], manifest: [], canvas: [], annotationList: [], sequence: [], annotation: [], contentResource: [], choice: [], range: [], service: [], layer: [], ...e }, this.options = { convertPropsToArray: !0, mergeMemberProperties: !0, allowUndefinedReturn: !1, ...r };
26
+ A(this, "traversals"), A(this, "options"), this.traversals = { collection: [], manifest: [], canvas: [], annotationList: [], sequence: [], annotation: [], contentResource: [], choice: [], range: [], service: [], layer: [], ...e }, this.options = { convertPropsToArray: !0, mergeMemberProperties: !0, allowUndefinedReturn: !1, ...r };
27
27
  }
28
28
  static all(e) {
29
29
  return new X({ collection: [e], manifest: [e], canvas: [e], annotationList: [e], sequence: [e], annotation: [e], contentResource: [e], choice: [e], range: [e], service: [e], layer: [e] });
@@ -152,7 +152,7 @@ var Oe = class X {
152
152
  return typeof n > "u" && !this.options.allowUndefinedReturn ? i : n;
153
153
  }, e);
154
154
  }
155
- }, Ue = "http://library.stanford.edu/iiif/image-api/compliance.html#level1", De = "http://library.stanford.edu/iiif/image-api/compliance.html#level2", Ee = "http://library.stanford.edu/iiif/image-api/conformance.html#level1", Ne = "http://library.stanford.edu/iiif/image-api/conformance.html#level2", qe = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1", _e = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2", Ve = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level1", Fe = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level2", We = "http://iiif.io/api/image/1/level1.json", Be = "http://iiif.io/api/image/1/profiles/level1.json", He = "http://iiif.io/api/image/1/level2.json", Je = "http://iiif.io/api/image/1/profiles/level2.json", Ge = "http://iiif.io/api/image/2/level1.json", ze = "http://iiif.io/api/image/2/profiles/level1.json", Ke = "http://iiif.io/api/image/2/level2.json", Qe = "http://iiif.io/api/image/2/profiles/level2.json", Xe = "level1", Ye = "level2", Ze = "http://iiif.io/api/image/2/level1", et = "http://iiif.io/api/image/2/level2", tt = [Ze, et, Ue, De, Ee, Ne, qe, _e, Ve, Fe, We, Be, He, Je, Ge, ze, Ke, Qe, Xe, Ye], $ = { attributionLabel: "Attribution", providerId: "http://example.org/provider", providerName: "Unknown" };
155
+ }, Ue = "http://library.stanford.edu/iiif/image-api/compliance.html#level1", De = "http://library.stanford.edu/iiif/image-api/compliance.html#level2", Ee = "http://library.stanford.edu/iiif/image-api/conformance.html#level1", Ne = "http://library.stanford.edu/iiif/image-api/conformance.html#level2", qe = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level1", _e = "http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2", Ve = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level1", Fe = "http://library.stanford.edu/iiif/image-api/1.1/conformance.html#level2", We = "http://iiif.io/api/image/1/level1.json", Be = "http://iiif.io/api/image/1/profiles/level1.json", He = "http://iiif.io/api/image/1/level2.json", Je = "http://iiif.io/api/image/1/profiles/level2.json", Ge = "http://iiif.io/api/image/2/level1.json", ze = "http://iiif.io/api/image/2/profiles/level1.json", Ke = "http://iiif.io/api/image/2/level2.json", Qe = "http://iiif.io/api/image/2/profiles/level2.json", Xe = "level1", Ye = "level2", Ze = "http://iiif.io/api/image/2/level1", et = "http://iiif.io/api/image/2/level2", tt = [Ze, et, Ue, De, Ee, Ne, qe, _e, Ve, Fe, We, Be, He, Je, Ge, ze, Ke, Qe, Xe, Ye], j = { attributionLabel: "Attribution", providerId: "http://example.org/provider", providerName: "Unknown" };
156
156
  function rt(t) {
157
157
  if (typeof t == "string") return [t];
158
158
  if (!t) return [];
@@ -237,7 +237,7 @@ function D(t) {
237
237
  return t;
238
238
  }
239
239
  var nt = ["Collection", "Manifest", "Annotation", "AnnotationPage", "Range", "Service"];
240
- function j(t) {
240
+ function P(t) {
241
241
  let e = t["@id"] || t.id, r = t["@type"] || t.type, i = t.profile || void 0, s = t["@context"] || void 0;
242
242
  if (i) {
243
243
  let n = st(i);
@@ -281,13 +281,13 @@ function ot(t) {
281
281
  }
282
282
  function ct(t, e = "Rights/License", r = "none") {
283
283
  let i = null, s = [], n = Array.isArray(t) ? t : [t];
284
- for (let a of n) {
285
- let o = a ? ot(a) : void 0;
286
- if (o && (o.indexOf("creativecommons.org") !== -1 || o.indexOf("rightsstatements.org") !== -1)) {
287
- o.startsWith("https://") ? i = `http://${o.slice(8)}` : i = o;
284
+ for (let o of n) {
285
+ let a = o ? ot(o) : void 0;
286
+ if (a && (a.indexOf("creativecommons.org") !== -1 || a.indexOf("rightsstatements.org") !== -1)) {
287
+ a.startsWith("https://") ? i = `http://${a.slice(8)}` : i = a;
288
288
  continue;
289
289
  }
290
- o && s.push({ label: { [r]: [e] }, value: { [r]: [o] } });
290
+ a && s.push({ label: { [r]: [e] }, value: { [r]: [a] } });
291
291
  }
292
292
  return [i, s];
293
293
  }
@@ -307,15 +307,15 @@ function Z(t, e) {
307
307
  let r = encodeURI(t.id || t["@id"] || "").trim();
308
308
  return r && e ? `${r}/${e}` : r || (E++, `http://example.org/${t["@type"]}${e ? `/${e}` : ""}/${E}`);
309
309
  }
310
- function m(t) {
310
+ function d(t) {
311
311
  let e = [...t.behavior || []];
312
312
  t.viewingHint && e.push(t.viewingHint);
313
313
  let r;
314
- return Array.isArray(t.motivation) ? r = t.motivation.map(D) : t.motivation && (r = D(t.motivation)), { "@context": t["@context"] ? pt(t["@context"]) : void 0, id: (t["@id"] || Z(t)).trim(), type: j(t), behavior: e.length ? e : void 0, height: t.height ? t.height : void 0, width: t.width ? t.width : void 0, motivation: r, viewingDirection: t.viewingDirection, profile: t.profile, format: t.format ? t.format : void 0, duration: void 0, timeMode: void 0 };
314
+ return Array.isArray(t.motivation) ? r = t.motivation.map(D) : t.motivation && (r = D(t.motivation)), { "@context": t["@context"] ? pt(t["@context"]) : void 0, id: (t["@id"] || Z(t)).trim(), type: P(t), behavior: e.length ? e : void 0, height: t.height ? t.height : void 0, width: t.width ? t.width : void 0, motivation: r, viewingDirection: t.viewingDirection, profile: t.profile, format: t.format ? t.format : void 0, duration: void 0, timeMode: void 0 };
315
315
  }
316
- function g(t) {
316
+ function y(t) {
317
317
  let [e, r] = ct(t.license), i = [...t.metadata ? vt(t.metadata) : [], ...r];
318
- return { rights: e, metadata: i.length ? i : void 0, label: t.label ? R(t.label) : void 0, requiredStatement: t.attribution ? { label: R($.attributionLabel), value: R(t.attribution) } : void 0, navDate: t.navDate, summary: t.description ? R(t.description) : void 0, thumbnail: ht(t.thumbnail) };
318
+ return { rights: e, metadata: i.length ? i : void 0, label: t.label ? R(t.label) : void 0, requiredStatement: t.attribution ? { label: R(j.attributionLabel), value: R(t.attribution) } : void 0, navDate: t.navDate, summary: t.description ? R(t.description) : void 0, thumbnail: ht(t.thumbnail) };
319
319
  }
320
320
  function ht(t) {
321
321
  return t && (Array.isArray(t) ? t : [t]).map((e) => typeof e == "string" ? { id: e, type: "Image" } : (e.type === "unknown" && (e.type = "Image"), e));
@@ -329,24 +329,24 @@ function ut(t) {
329
329
  r.push({ id: i, type: "Collection" });
330
330
  break;
331
331
  }
332
- } else i["@id"] && r.push({ id: i["@id"], type: j(i) });
332
+ } else i["@id"] && r.push({ id: i["@id"], type: P(i) });
333
333
  return r.length ? r : void 0;
334
334
  }
335
- function A(t) {
335
+ function C(t) {
336
336
  let e = t.related ? Array.isArray(t.related) ? t.related : [t.related] : [], r = t.contentLayer;
337
- return { provider: t.logo || e.length ? [{ id: $.providerId, type: "Agent", homepage: e.length ? [e[0]] : void 0, logo: t.logo ? Array.isArray(t.logo) ? t.logo : [t.logo] : void 0, label: R($.providerName) }] : void 0, partOf: ut(t), rendering: t.rendering, seeAlso: t.seeAlso, start: t.startCanvas, service: t.service ? b(t.service) : void 0, supplementary: r ? [r] : void 0 };
337
+ return { provider: t.logo || e.length ? [{ id: j.providerId, type: "Agent", homepage: e.length ? [e[0]] : void 0, logo: t.logo ? Array.isArray(t.logo) ? t.logo : [t.logo] : void 0, label: R(j.providerName) }] : void 0, partOf: ut(t), rendering: t.rendering, seeAlso: t.seeAlso, start: t.startCanvas, service: t.service ? b(t.service) : void 0, supplementary: r ? [r] : void 0 };
338
338
  }
339
339
  function ft(t) {
340
340
  return { chars: t.chars, format: t.format ? t.format : void 0, language: t.language };
341
341
  }
342
342
  function mt(t) {
343
- return h({ ...m(t), ...g(t), ...A(t), items: t.members });
343
+ return m({ ...d(t), ...y(t), ...C(t), items: t.members });
344
344
  }
345
345
  function gt(t) {
346
346
  let e = [], r = [], i;
347
347
  for (let n of t.sequences || []) n.canvases.length && e.push(...n.canvases), n.behavior && r.push(...n.behavior), n.startCanvas && (i = n.startCanvas);
348
- let s = m(t);
349
- return r.length && (s.behavior ? s.behavior.push(...r) : s.behavior = r), h({ ...s, ...g(t), ...A(t), start: i, items: e, structures: dt(t.structures) });
348
+ let s = d(t);
349
+ return r.length && (s.behavior ? s.behavior.push(...r) : s.behavior = r), m({ ...s, ...y(t), ...C(t), start: i, items: e, structures: dt(t.structures) });
350
350
  }
351
351
  function dt(t) {
352
352
  if (!t) return t;
@@ -360,10 +360,10 @@ function dt(t) {
360
360
  return t.filter((i) => r.indexOf(i.id) === -1);
361
361
  }
362
362
  function yt(t) {
363
- return h({ ...m(t), ...g(t), ...A(t), annotations: t.otherContent && t.otherContent.length ? t.otherContent : void 0, items: t.images && t.images.length ? [{ id: Z(t, "annotation-page"), type: "AnnotationPage", items: t.images }] : void 0 });
363
+ return m({ ...d(t), ...y(t), ...C(t), annotations: t.otherContent && t.otherContent.length ? t.otherContent : void 0, items: t.images && t.images.length ? [{ id: Z(t, "annotation-page"), type: "AnnotationPage", items: t.images }] : void 0 });
364
364
  }
365
365
  function At(t) {
366
- return h({ ...m(t), ...g(t), ...A(t), items: t.resources && t.resources.length ? t.resources : void 0 });
366
+ return m({ ...d(t), ...y(t), ...C(t), items: t.resources && t.resources.length ? t.resources : void 0 });
367
367
  }
368
368
  function Ct(t) {
369
369
  return !t.canvases || t.canvases.length === 0 ? { canvases: [], behavior: [] } : { canvases: t.canvases, behavior: t.viewingHint ? [t.viewingHint] : [], startCanvas: t.startCanvas };
@@ -381,47 +381,47 @@ function bt(t) {
381
381
  else if (r.full["@type"] === "dctypes:Image") i = { id: r.full["@id"], type: "Image" };
382
382
  else if (r.full["@type"] === "sc:Canvas") i = { id: r.full["@id"], type: "Canvas" };
383
383
  else throw new Error(`Unsupported source type on annotation: ${r.full["@type"]}`);
384
- return { type: "SpecificResource", source: i, selector: M(r.selector) };
384
+ return { type: "SpecificResource", source: i, selector: k(r.selector) };
385
385
  } else return encodeURI(r["@id"]).trim();
386
386
  }
387
- return h({ ...m(t), ...g(t), ...A(t), target: e(t.on), body: Array.isArray(t.resource) ? t.resource.map(N) : N(t.resource) });
387
+ return m({ ...d(t), ...y(t), ...C(t), target: e(t.on), body: Array.isArray(t.resource) ? t.resource.map(N) : N(t.resource) });
388
388
  }
389
389
  function N(t) {
390
390
  return t.type === "Choice" ? t : ee(t);
391
391
  }
392
392
  function ee(t) {
393
393
  let e = t;
394
- return h({ ...m(e), ...g(e), ...A(e), ...ft(e) });
394
+ return m({ ...d(e), ...y(e), ...C(e), ...ft(e) });
395
395
  }
396
396
  function Rt(t) {
397
397
  let e = [];
398
- return t.default && t.default !== "rdf:nil" && e.push(t.default), t.item && t.item !== "rdf:nil" && e.push(...t.item), h({ ...m(t), ...g(t), items: e });
398
+ return t.default && t.default !== "rdf:nil" && e.push(t.default), t.item && t.item !== "rdf:nil" && e.push(...t.item), m({ ...d(t), ...y(t), items: e });
399
399
  }
400
400
  function Lt(t) {
401
- return h({ ...m(t), ...g(t), ...A(t), items: t.members });
401
+ return m({ ...d(t), ...y(t), ...C(t), items: t.members });
402
402
  }
403
403
  function wt(t) {
404
- let { "@id": e, "@type": r, "@context": i, profile: s, ...n } = t, a = {};
405
- return e && (a["@id"] = e), a["@type"] = j(t), a["@type"] === "unknown" && (i && i.length && (a["@context"] = i), a["@type"] = "Service"), s && (a.profile = Y(s)), h({ ...a, ...n });
404
+ let { "@id": e, "@type": r, "@context": i, profile: s, ...n } = t, o = {};
405
+ return e && (o["@id"] = e), o["@type"] = P(t), o["@type"] === "unknown" && (i && i.length && (o["@context"] = i), o["@type"] = "Service"), s && (o.profile = Y(s)), m({ ...o, ...n });
406
406
  }
407
407
  function It(t) {
408
- return h({ ...m(t), ...g(t), ...A(t) });
408
+ return m({ ...d(t), ...y(t), ...C(t) });
409
409
  }
410
410
  var St = new Oe({ collection: [mt], manifest: [gt], canvas: [yt], annotationList: [At], sequence: [Ct], annotation: [bt], contentResource: [ee], choice: [Rt], range: [Lt], service: [wt], layer: [It] });
411
411
  function te(t) {
412
412
  return t && t["@context"] && (t["@context"] === "http://iiif.io/api/presentation/2/context.json" || t["@context"].indexOf("http://iiif.io/api/presentation/2/context.json") !== -1 || t["@context"] === "http://www.shared-canvas.org/ns/context.json") || t["@context"] === "http://iiif.io/api/image/2/context.json" ? St.traverseUnknown(t) : t;
413
413
  }
414
- function M(t) {
414
+ function k(t) {
415
415
  if ((Array.isArray(t["@type"]) && t["@type"].includes("oa:SvgSelector") || t["@type"] == "oa:SvgSelector") && ("chars" in t || "value" in t)) return { type: "SvgSelector", value: "chars" in t ? t.chars : t.value };
416
416
  if (t["@type"] === "oa:FragmentSelector") return { type: "FragmentSelector", value: t.value };
417
- if (t["@type"] === "oa:Choice") return [M(t.default), ...(Array.isArray(t.item) ? t.item : [t.item]).map(M)];
417
+ if (t["@type"] === "oa:Choice") return [k(t.default), ...(Array.isArray(t.item) ? t.item : [t.item]).map(k)];
418
418
  if (t["@type"] == "iiif:ImageApiSelector") return { type: "ImageApiSelector", region: "region" in t ? t.region : void 0, rotation: "rotation" in t ? t.rotation : void 0 };
419
419
  throw new Error(`Unsupported selector type: ${t["@type"]}`);
420
420
  }
421
- function T(t) {
421
+ function $(t) {
422
422
  return typeof t == "string" ? !1 : t && !t.type && "source" in t ? (t.type = "SpecificResource", !0) : !!t && t.type === "SpecificResource";
423
423
  }
424
- function w(...t) {
424
+ function S(...t) {
425
425
  return (e) => t.reduce((r, i) => i(r), e);
426
426
  }
427
427
  var q = ["Collection", "Manifest", "Canvas", "AnnotationPage", "AnnotationCollection", "Annotation", "ContentResource", "Range", "Service", "Selector", "Agent"];
@@ -439,9 +439,9 @@ function Tt(t, e) {
439
439
  if (t.profile) return "Service";
440
440
  throw new Error("Resource type is not known");
441
441
  }
442
- var k = class re {
442
+ var O = class re {
443
443
  constructor(e, r = {}) {
444
- y(this, "traversals"), y(this, "options"), y(this, "_traverseManifest", w(this.traverseManifestItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this), this.traverseManifestStructures.bind(this), this.traverseInlineAnnotationPages.bind(this))), y(this, "_traverseCanvas", w(this.traverseCanvasItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this), this.traverseInlineAnnotationPages.bind(this))), y(this, "_traverseAnnotationPage", w(this.traverseAnnotationPageItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this))), y(this, "_traverseRange", w(this.traverseRangeRanges.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this))), this.traversals = { collection: [], manifest: [], canvas: [], annotationCollection: [], annotationPage: [], annotation: [], contentResource: [], choice: [], range: [], service: [], agent: [], specificResource: [], geoJson: [], ...e }, this.options = { allowUndefinedReturn: !1, ...r };
444
+ A(this, "traversals"), A(this, "options"), A(this, "_traverseManifest", S(this.traverseManifestItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this), this.traverseManifestStructures.bind(this), this.traverseInlineAnnotationPages.bind(this))), A(this, "_traverseCanvas", S(this.traverseCanvasItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this), this.traverseInlineAnnotationPages.bind(this))), A(this, "_traverseAnnotationPage", S(this.traverseAnnotationPageItems.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this))), A(this, "_traverseRange", S(this.traverseRangeRanges.bind(this), this.traverseLinking.bind(this), this.traverseDescriptive.bind(this), this.traverseLinkedCanvases.bind(this))), this.traversals = { collection: [], manifest: [], canvas: [], annotationCollection: [], annotationPage: [], annotation: [], contentResource: [], choice: [], range: [], service: [], agent: [], specificResource: [], geoJson: [], ...e }, this.options = { allowUndefinedReturn: !1, ...r };
445
445
  }
446
446
  static all(e) {
447
447
  return new re({ collection: [e], manifest: [e], canvas: [e], annotationCollection: [e], annotationPage: [e], annotation: [e], contentResource: [e], choice: [e], range: [e], service: [e], geoJson: [e], specificResource: [e], agent: [e] });
@@ -450,7 +450,7 @@ var k = class re {
450
450
  return e.thumbnail && (e.thumbnail = b(e.thumbnail).map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.provider && (e.provider = e.provider.map((r) => this.traverseAgent(r, e))), e;
451
451
  }
452
452
  traverseLinking(e) {
453
- return e.seeAlso && (e.seeAlso = e.seeAlso.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.service && (e.service = b(e.service).map((r) => this.traverseService(r))), e.services && (e.services = b(e.services).map((r) => this.traverseService(r, e))), e.logo && (e.logo = e.logo.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.homepage && (e.homepage = b(e.homepage).map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.partOf && (e.partOf = e.partOf.map((r) => typeof r == "string" || !r.type ? this.traverseType(r, { parent: e }, this.traversals.contentResource) : r.type === "Canvas" ? this.traverseType(r, { parent: e }, this.traversals.canvas) : r.type === "AnnotationCollection" ? this.traverseType(r, { parent: e }, this.traversals.annotationCollection) : r.type === "Collection" ? this.traverseType(r, { parent: e }, this.traversals.collection) : this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.start && (T(e.start) ? e.start = this.traverseSpecificResource(e.start, "Canvas", e) : e.start = this.traverseType(e.start, { parent: e }, this.traversals.canvas)), e.rendering && (e.rendering = e.rendering.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.supplementary && (e.supplementary = e.supplementary.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e;
453
+ return e.seeAlso && (e.seeAlso = e.seeAlso.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.service && (e.service = b(e.service).map((r) => this.traverseService(r))), e.services && (e.services = b(e.services).map((r) => this.traverseService(r, e))), e.logo && (e.logo = e.logo.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.homepage && (e.homepage = b(e.homepage).map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.partOf && (e.partOf = e.partOf.map((r) => typeof r == "string" || !r.type ? this.traverseType(r, { parent: e }, this.traversals.contentResource) : r.type === "Canvas" ? this.traverseType(r, { parent: e }, this.traversals.canvas) : r.type === "AnnotationCollection" ? this.traverseType(r, { parent: e }, this.traversals.annotationCollection) : r.type === "Collection" ? this.traverseType(r, { parent: e }, this.traversals.collection) : this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.start && ($(e.start) ? e.start = this.traverseSpecificResource(e.start, "Canvas", e) : e.start = this.traverseType(e.start, { parent: e }, this.traversals.canvas)), e.rendering && (e.rendering = e.rendering.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e.supplementary && (e.supplementary = e.supplementary.map((r) => this.traverseType(r, { parent: e }, this.traversals.contentResource))), e;
454
454
  }
455
455
  traverseCollectionItems(e) {
456
456
  return e.items && e.items.map((r) => r.type === "Collection" ? this.traverseCollection(r) : this.traverseManifest(r)), e;
@@ -501,14 +501,14 @@ var k = class re {
501
501
  return typeof e == "string" || !e || e && e.service && (e.service = b(e.service || []).map((r) => this.traverseService(r, e))), e;
502
502
  }
503
503
  traverseContentResource(e, r) {
504
- return e.type === "Choice" && (e.items = e.items.map((i) => this.traverseContentResource(i, e))), T(e) ? this.traverseSpecificResource(e, "ContentResource") : this.traverseType(this.traverseInlineAnnotationPages(this.traverseContentResourceLinking(e)), { parent: r }, this.traversals.contentResource);
504
+ return e.type === "Choice" && (e.items = e.items.map((i) => this.traverseContentResource(i, e))), $(e) ? this.traverseSpecificResource(e, "ContentResource") : this.traverseType(this.traverseInlineAnnotationPages(this.traverseContentResourceLinking(e)), { parent: r }, this.traversals.contentResource);
505
505
  }
506
506
  traverseSpecificResource(e, r, i) {
507
507
  let s = e.source;
508
508
  return typeof e.source == "string" && (s = { id: e.source, type: r || "unknown" }), this.traverseType({ ...e, source: r === "Canvas" || s.type === "Canvas" ? this.traverseType(s, { parent: i }, this.traversals.canvas) : r === "ContentResource" ? this.traverseContentResource(s, { parent: i }) : this.traverseUnknown(s, { parent: i, typeHint: r }) }, { parent: i }, this.traversals.specificResource);
509
509
  }
510
510
  traverseRangeRanges(e) {
511
- return e.items && (e.items = e.items.map((r) => typeof r == "string" ? this.traverseCanvas({ id: r, type: "Canvas" }, e) : T(r) ? this.traverseSpecificResource(r, "Canvas", e) : r.type === "Manifest" ? this.traverseManifest(r, e) : this.traverseRange(r, e))), e;
511
+ return e.items && (e.items = e.items.map((r) => typeof r == "string" ? this.traverseCanvas({ id: r, type: "Canvas" }, e) : $(r) ? this.traverseSpecificResource(r, "Canvas", e) : r.type === "Manifest" ? this.traverseManifest(r, e) : this.traverseRange(r, e))), e;
512
512
  }
513
513
  traverseRange(e, r) {
514
514
  return this.traverseType(this._traverseRange(e), { parent: r }, this.traversals.range);
@@ -518,8 +518,8 @@ var k = class re {
518
518
  }
519
519
  traverseType(e, r, i) {
520
520
  return i.reduce((s, n) => {
521
- let a = n(s, r);
522
- return typeof a > "u" && !this.options.allowUndefinedReturn ? s : a;
521
+ let o = n(s, r);
522
+ return typeof o > "u" && !this.options.allowUndefinedReturn ? s : o;
523
523
  }, e);
524
524
  }
525
525
  traverseService(e, r) {
@@ -552,29 +552,29 @@ var k = class re {
552
552
  }
553
553
  }
554
554
  };
555
- const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.profile.toString().includes("iiif.io/api/image/"), se = (t) => {
556
- const e = v(t, "type"), r = v(t, "context");
555
+ const ie = (t) => f(t, "type").startsWith("ImageService") || t.profile && t.profile.toString().includes("iiif.io/api/image/"), se = (t) => {
556
+ const e = f(t, "type"), r = f(t, "context");
557
557
  if (e === "ImageService2" || r != null && r.includes("image/2")) {
558
558
  const i = t, s = ["level0", "level1", "level2"];
559
- return { majorVersion: 2, profileLevel: (Array.isArray(i.profile) ? i.profile : [i.profile]).map((o) => s.findIndex((c) => o.toString().includes(c))).filter((o) => o > -1).sort((o, c) => c - o)[0] };
559
+ return { majorVersion: 2, profileLevel: (Array.isArray(i.profile) ? i.profile : [i.profile]).map((a) => s.findIndex((c) => a.toString().includes(c))).filter((a) => a > -1).sort((a, c) => c - a)[0] };
560
560
  } else if (e || r)
561
561
  return { majorVersion: 3, profileLevel: parseInt(t.profile) };
562
562
  }, _ = (t, e, r) => {
563
- const i = v(t, "id"), s = t.profile || "";
563
+ const i = f(t, "id"), s = t.profile || "";
564
564
  if (typeof s == "string" && (s.includes("level0") || s.includes("level:0"))) {
565
565
  if ("sizes" in t && Array.isArray(t.sizes)) {
566
- const a = t.sizes.sort((o, c) => c.width * c.height - o.width * o.height).filter((o) => o.width * o.height >= e * r)[0];
567
- if (a)
568
- return `${i}/full/${a.width},${a.height}/0/default.jpg`;
566
+ const o = t.sizes.sort((a, c) => c.width * c.height - a.width * a.height).filter((a) => a.width * a.height >= e * r)[0];
567
+ if (o)
568
+ return `${i}/full/${o.width},${o.height}/0/default.jpg`;
569
569
  }
570
570
  return `${i}/full/full/0/default.jpg`;
571
571
  }
572
572
  return `${i}/full/!${e},${r}/0/default.jpg`;
573
573
  }, xt = (t, e, r) => {
574
- const i = v(t, "id"), s = t.profile || "";
574
+ const i = f(t, "id"), s = t.profile || "";
575
575
  if (typeof s == "string" && (s.includes("level0") || s.includes("level:0"))) return;
576
- const { x: a, y: o, w: c, h: p } = e, u = c / p, C = u < 1, I = Math.ceil(C ? r / u : r), l = Math.ceil(C ? r : r / u), d = `${Math.round(a)},${Math.round(o)},${Math.round(c)},${Math.round(p)}`;
577
- return `${i}/${d}/!${l},${I}/0/default.jpg`;
576
+ const { x: o, y: a, w: c, h } = e, p = c / h, u = p < 1, L = Math.ceil(u ? r / p : r), l = Math.ceil(u ? r : r / p), v = `${Math.round(o)},${Math.round(a)},${Math.round(c)},${Math.round(h)}`;
577
+ return `${i}/${v}/!${l},${L}/0/default.jpg`;
578
578
  }, $t = (t) => (e, r = 400) => {
579
579
  if (t.type === "dynamic")
580
580
  return xt(t.service, e, r);
@@ -582,37 +582,37 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
582
582
  }, Mt = (t, e = []) => (r = 400) => {
583
583
  const { width: i, height: s } = t;
584
584
  if (!i || !s) return;
585
- const n = i / s, a = n < 1, o = Math.ceil(a ? r / n : r), c = Math.ceil(a ? r : r / n);
585
+ const n = i / s, o = n < 1, a = Math.ceil(o ? r / n : r), c = Math.ceil(o ? r : r / n);
586
586
  if (t.thumbnail && t.thumbnail.length > 0) {
587
- const p = t.thumbnail[0];
588
- if ("service" in p && Array.isArray(p.service)) {
589
- const u = p.service.find((C) => ie(C));
590
- if (u)
591
- return _(u, c, o);
587
+ const h = t.thumbnail[0];
588
+ if ("service" in h && Array.isArray(h.service)) {
589
+ const p = h.service.find((u) => ie(u));
590
+ if (p)
591
+ return _(p, c, a);
592
592
  }
593
- if ("id" in p) return p.id;
593
+ if ("id" in h) return h.id;
594
594
  }
595
- for (const p of e) {
596
- if (p.type === "dynamic" || p.type === "level0")
597
- return _(p.service, c, o);
598
- if (p.type === "static")
599
- return p.url;
595
+ for (const h of e) {
596
+ if (h.type === "dynamic" || h.type === "level0")
597
+ return _(h.service, c, a);
598
+ if (h.type === "static")
599
+ return h.url;
600
600
  }
601
601
  }, ne = (t) => t.endsWith("/info.json") ? t : `${t.endsWith("/") ? t : `${t}/`}info.json`, jt = (t) => {
602
- const { format: e, height: r, width: i } = t, s = v(t, "id"), n = (t.service || []).find(ie), a = n ? se(n) : void 0;
603
- if (a) {
604
- const o = {
602
+ const { format: e, height: r, width: i } = t, s = f(t, "id"), n = (t.service || []).find(ie), o = n ? se(n) : void 0;
603
+ if (o) {
604
+ const a = {
605
605
  source: t,
606
- type: a.profileLevel === 0 ? "level0" : "dynamic",
606
+ type: o.profileLevel === 0 ? "level0" : "dynamic",
607
607
  service: n,
608
608
  width: i,
609
609
  height: r,
610
- majorVersion: a.majorVersion,
611
- serviceUrl: ne(v(n, "id"))
610
+ majorVersion: o.majorVersion,
611
+ serviceUrl: ne(f(n, "id"))
612
612
  };
613
- return a.profileLevel === 0 ? o : {
614
- ...o,
615
- getRegionURL: $t(o)
613
+ return o.profileLevel === 0 ? a : {
614
+ ...a,
615
+ getRegionURL: $t(a)
616
616
  };
617
617
  } else
618
618
  return {
@@ -625,43 +625,56 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
625
625
  };
626
626
  }, kt = (t) => {
627
627
  const e = [];
628
- return new k({
628
+ return new O({
629
629
  annotation: [(i) => {
630
630
  if (i.motivation === "painting" || !i.motivation) {
631
- const n = (i.body ? Array.isArray(i.body) ? i.body : [i.body] : []).filter((a) => a.type === "Image");
632
- e.push(...n.map((a) => jt(a)));
631
+ const n = (i.body ? Array.isArray(i.body) ? i.body : [i.body] : []).filter((o) => o.type === "Image");
632
+ e.push(...n.map((o) => jt(o)));
633
633
  }
634
634
  }]
635
635
  }).traverseCanvas(t), e;
636
636
  }, Pt = (t) => () => {
637
- const e = (i, s, n = 0) => {
638
- const a = {
639
- id: i.id,
637
+ const e = /* @__PURE__ */ new Map(), r = (a, c, h = 0) => {
638
+ const p = {
639
+ id: a.id,
640
640
  type: "range",
641
- getLabel: i.getLabel,
641
+ source: a,
642
642
  children: [],
643
- parent: s,
644
- level: n
643
+ navItems: [],
644
+ navSections: [],
645
+ parent: c,
646
+ level: h,
647
+ getLabel: a.getLabel
645
648
  };
646
- return i.items && i.items.length > 0 && i.items.forEach((o) => {
647
- if (o.source.type === "Range") {
648
- const c = e(o, a, n + 1);
649
- a.children.push(c);
649
+ a.items && a.items.length > 0 && a.items.forEach((v) => {
650
+ if (v.source.type === "Range") {
651
+ const I = r(v, p, h + 1);
652
+ p.children.push(I);
650
653
  } else
651
- a.children.push({
652
- id: o.id,
654
+ p.children.push({
655
+ id: v.id,
653
656
  type: "canvas",
654
- getLabel: o.getLabel,
657
+ source: v,
655
658
  children: [],
656
- parent: a,
657
- level: n + 1
659
+ navItems: [],
660
+ navSections: [],
661
+ parent: p,
662
+ level: h + 1,
663
+ getLabel: v.getLabel
658
664
  });
659
- }), a;
665
+ });
666
+ const u = p.children.map((v) => v.type === "canvas" ? v.source : v.children.length === 1 && v.children[0].type === "canvas" ? v.children[0].source : v.source), L = u.filter((v) => v.source.type === "Canvas"), l = u.filter((v) => v.source.type === "Range");
667
+ return p.navItems.push(...L), p.navSections.push(...l), e.set(p.id, p), p;
660
668
  };
661
- return t.filter((i) => {
662
- var s;
663
- return (s = i.source.behavior) == null ? void 0 : s.includes("top");
664
- }).map((i) => e(i, void 0));
669
+ return { root: t.filter((a) => {
670
+ var c;
671
+ return (c = a.source.behavior) == null ? void 0 : c.includes("top");
672
+ }).map((a) => r(a, void 0)), getBreadcrumbs: (a) => {
673
+ const c = e.get(a);
674
+ if (!c) return [];
675
+ const h = (p, u = []) => p.parent ? h(p.parent, [p, ...u]) : [p, ...u];
676
+ return h(c);
677
+ }, getNode: (a) => e.get(a) };
665
678
  }, Ot = async (t) => {
666
679
  try {
667
680
  new URL(t);
@@ -716,7 +729,7 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
716
729
  code: "INVALID_MANIFEST",
717
730
  message: "Missing @context"
718
731
  };
719
- const i = v(t, "id");
732
+ const i = f(t, "id");
720
733
  if (!i)
721
734
  return {
722
735
  type: "error",
@@ -725,7 +738,7 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
725
738
  };
726
739
  if (r.includes("presentation/2") || r.includes("presentation/3")) {
727
740
  const s = r.includes("presentation/2") ? 2 : 3;
728
- return v(t, "type").includes("Collection") ? {
741
+ return f(t, "type").includes("Collection") ? {
729
742
  type: "collection",
730
743
  url: e || i,
731
744
  resource: Ut(t, s)
@@ -754,13 +767,13 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
754
767
  };
755
768
  }, Ut = (t, e) => {
756
769
  const r = (n) => {
757
- const a = [];
758
- return new k({
759
- manifest: [(c) => a.push(c)]
760
- }).traverseCollection(n), a.map((c) => ({
770
+ const o = [];
771
+ return new O({
772
+ manifest: [(c) => o.push(c)]
773
+ }).traverseCollection(n), o.map((c) => ({
761
774
  id: c.id,
762
775
  type: c.type,
763
- getLabel: L(c),
776
+ getLabel: w(c),
764
777
  source: c
765
778
  }));
766
779
  }, i = e === 2 ? te(t) : t, s = r(i);
@@ -769,46 +782,46 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
769
782
  id: i.id,
770
783
  majorVersion: e,
771
784
  items: s,
772
- getLabel: L(i),
773
- getMetadata: x(i)
785
+ getLabel: w(i),
786
+ getMetadata: M(i)
774
787
  };
775
788
  }, Dt = (t, e) => {
776
- const r = (a) => {
777
- const o = [], c = [];
778
- new k({
789
+ const r = (o) => {
790
+ const a = [], c = [];
791
+ new O({
779
792
  canvas: [(l) => {
780
- l.items && o.push(l);
793
+ l.items && a.push(l);
781
794
  }],
782
795
  range: [(l) => {
783
796
  l.type === "Range" && c.push(l);
784
797
  }]
785
- }).traverseManifest(a);
786
- const u = o.map((l) => {
787
- const d = kt(l);
798
+ }).traverseManifest(o);
799
+ const p = a.map((l) => {
800
+ const v = kt(l);
788
801
  return {
789
802
  source: l,
790
803
  id: l.id,
791
804
  width: l.width,
792
805
  height: l.height,
793
- images: d,
806
+ images: v,
794
807
  annotations: l.annotations || [],
795
- getLabel: L(l),
796
- getMetadata: x(l),
797
- getThumbnailURL: Mt(l, d)
808
+ getLabel: w(l),
809
+ getMetadata: M(l),
810
+ getThumbnailURL: Mt(l, v)
798
811
  };
799
- }), C = (l) => {
800
- const d = l.items || [], P = d.filter((f) => f.type === "Canvas").map((f) => u.find((S) => S.id === f.id)).filter(Boolean), O = d.filter((f) => f.type === "Range").map((f) => C(f)), oe = [...P, ...O];
812
+ }), u = (l) => {
813
+ const v = l.items || [], T = v.filter((g) => g.type === "Canvas").map((g) => p.find((x) => x.id === g.id)).filter(Boolean), I = v.filter((g) => g.type === "Range").map((g) => u(g)), oe = [...T, ...I];
801
814
  return {
802
815
  source: l,
803
816
  id: l.id,
804
817
  // Maintain original order
805
- items: d.map((f) => oe.find((S) => S.id === f.id)),
806
- canvases: P,
807
- ranges: O,
808
- getLabel: L(l)
818
+ items: v.map((g) => oe.find((x) => x.id === g.id)),
819
+ canvases: T,
820
+ ranges: I,
821
+ getLabel: w(l)
809
822
  };
810
- }, I = c.map((l) => C(l));
811
- return { canvases: u, ranges: I };
823
+ }, L = c.map((l) => u(l));
824
+ return { canvases: p, ranges: L };
812
825
  }, i = e === 2 ? te(t) : t, { canvases: s, ranges: n } = r(i);
813
826
  return {
814
827
  source: i,
@@ -816,8 +829,8 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
816
829
  majorVersion: e,
817
830
  canvases: s,
818
831
  structure: n,
819
- getLabel: L(i),
820
- getMetadata: x(i),
832
+ getLabel: w(i),
833
+ getMetadata: M(i),
821
834
  getTableOfContents: Pt(n)
822
835
  };
823
836
  }, Et = (t) => {
@@ -829,16 +842,16 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
829
842
  width: e,
830
843
  height: r,
831
844
  majorVersion: i.majorVersion,
832
- serviceUrl: ne(v(t, "id"))
845
+ serviceUrl: ne(f(t, "id"))
833
846
  };
834
847
  }, qt = { parse: ae, parseURL: Ot };
835
848
  export {
836
849
  qt as Cozy,
837
850
  _ as getImageURLFromService,
838
851
  kt as getImages,
839
- L as getLabel,
840
- x as getMetadata,
841
- v as getPropertyValue,
852
+ w as getLabel,
853
+ M as getMetadata,
854
+ f as getPropertyValue,
842
855
  $t as getRegionURL,
843
856
  xt as getRegionURLFromService,
844
857
  Ft as getStringValue,
package/dist/types.d.ts CHANGED
@@ -43,7 +43,7 @@ export interface CozyManifest {
43
43
  readonly canvases: CozyCanvas[];
44
44
  readonly structure: CozyRange[];
45
45
  getLabel(locale?: string): string | undefined;
46
- getTableOfContents(): CozyTOCNode[];
46
+ getTableOfContents(): CozyTOC;
47
47
  getMetadata(locale?: string): CozyMetadata[];
48
48
  }
49
49
  export interface CozyRange {
@@ -69,13 +69,21 @@ export interface CozyMetadata {
69
69
  readonly label: string;
70
70
  readonly value: string;
71
71
  }
72
+ export interface CozyTOC {
73
+ root: CozyTOCNode[];
74
+ getBreadcrumbs(id: string): CozyTOCNode[];
75
+ getNode(id: string): CozyTOCNode | undefined;
76
+ }
72
77
  export interface CozyTOCNode {
73
78
  readonly id: string;
74
79
  readonly type: 'range' | 'canvas';
80
+ readonly source: CozyRange | CozyCanvas;
81
+ readonly children: CozyTOCNode[];
82
+ readonly navItems: CozyCanvas[];
83
+ readonly navSections: CozyRange[];
84
+ readonly parent?: CozyTOCNode;
85
+ readonly level: number;
75
86
  getLabel(locale?: string): string | undefined;
76
- children: CozyTOCNode[];
77
- parent?: CozyTOCNode;
78
- level: number;
79
87
  }
80
88
  export type CozyImageResource = StaticImageResource | ImageServiceResource;
81
89
  export type ImageServiceResource = DynamicImageServiceResource | Level0ImageServiceResource;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-iiif",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "A developer-friendly collection of abstractions and utilities built on top of @iiif/presentation-3 and @iiif/parser",
5
5
  "license": "MIT",
6
6
  "author": "Rainer Simon",
@@ -1,38 +1,90 @@
1
- import type { CozyRange, CozyTOCNode } from '../types';
1
+ import type { CozyCanvas, CozyRange, CozyTOC, CozyTOCNode } from '../types';
2
2
 
3
- export const getTableOfContents = (ranges: CozyRange[]) => () => {
3
+ export const getTableOfContents = (ranges: CozyRange[]) => (): CozyTOC => {
4
+
5
+ const index = new Map<string, CozyTOCNode>();
4
6
 
5
7
  const buildTree = (range: CozyRange, parent: CozyTOCNode | undefined, level: number = 0): CozyTOCNode => {
6
8
  const node: CozyTOCNode = {
7
9
  id: range.id,
8
10
  type: 'range',
9
- getLabel: range.getLabel,
11
+ source: range,
10
12
  children: [],
13
+ navItems: [],
14
+ navSections: [],
11
15
  parent,
12
- level
16
+ level,
17
+ getLabel: range.getLabel,
13
18
  };
14
19
 
15
20
  if (range.items && range.items.length > 0) {
16
21
  range.items.forEach(item => {
17
22
  if (item.source.type === 'Range') {
18
- const childNode = buildTree(item as CozyRange, node, level + 1);
23
+ const r = item as CozyRange;
24
+ const childNode = buildTree(r, node, level + 1);
19
25
  node.children.push(childNode);
20
26
  } else {
27
+ // This child is Canvas, i.e. a TOCNode with
28
+ // no further children.
21
29
  node.children.push({
22
30
  id: item.id,
23
31
  type: 'canvas',
24
- getLabel: item.getLabel,
32
+ source: item as CozyCanvas,
25
33
  children: [],
34
+ navItems: [],
35
+ navSections: [],
26
36
  parent: node,
27
- level: level + 1
37
+ level: level + 1,
38
+ getLabel: item.getLabel
28
39
  });
29
40
  }
30
41
  });
31
42
  }
43
+
44
+ // From the actual child ToC Nodes, infer the "logical" child navItems
45
+ // (canvases) and navSections (ranges).
46
+ const navChildren = node.children.map(n => {
47
+ if (n.type === 'canvas') {
48
+ // An actual leaf node
49
+ return n.source as CozyCanvas;
50
+ } else if (n.children.length === 1 && n.children[0].type === 'canvas') {
51
+ // A range with a single canvas child - logical leaf node!
52
+ return n.children[0].source as CozyCanvas;
53
+ } else {
54
+ return n.source as CozyRange;
55
+ }
56
+ });
57
+
58
+ const navItems = navChildren.filter(c => c.source.type === 'Canvas') as CozyCanvas[];
59
+ const navSections = navChildren.filter(c => c.source.type === 'Range') as CozyRange[];
32
60
 
61
+ node.navItems.push(...navItems);
62
+ node.navSections.push(...navSections);
63
+
64
+ index.set(node.id, node);
65
+
33
66
  return node;
34
67
  };
35
68
 
36
69
  const topRanges = ranges.filter(range => range.source.behavior?.includes('top'));
37
- return topRanges.map(range => buildTree(range, undefined));
70
+ const root = topRanges.map(range => buildTree(range, undefined));
71
+
72
+ const getNode = (id: string) => index.get(id);
73
+
74
+ const getBreadcrumbs = (id: string) => {
75
+ const thisNode = index.get(id);
76
+ if (!thisNode) return [];
77
+
78
+ const addParent = (node: CozyTOCNode, breadcrumbs: CozyTOCNode[] = []) => {
79
+ if (node.parent) {
80
+ return addParent(node.parent, [node, ...breadcrumbs]);
81
+ } else {
82
+ return [node, ...breadcrumbs];
83
+ }
84
+ }
85
+
86
+ return addParent(thisNode);
87
+ }
88
+
89
+ return { root, getBreadcrumbs, getNode };
38
90
  }
package/src/types.ts CHANGED
@@ -1,4 +1,13 @@
1
- import type { Manifest, Canvas, ImageService2, ImageService3, IIIFExternalWebResource, Collection, Range, Annotation, AnnotationPage } from '@iiif/presentation-3';
1
+ import type {
2
+ Manifest,
3
+ Canvas,
4
+ ImageService2,
5
+ ImageService3,
6
+ IIIFExternalWebResource,
7
+ Collection,
8
+ Range,
9
+ AnnotationPage
10
+ } from '@iiif/presentation-3';
2
11
 
3
12
  export type CozyParseResult =
4
13
  | { type: 'collection', url: string, resource: CozyCollection }
@@ -54,7 +63,7 @@ export interface CozyManifest {
54
63
 
55
64
  getLabel(locale?: string): string | undefined;
56
65
 
57
- getTableOfContents(): CozyTOCNode[];
66
+ getTableOfContents(): CozyTOC;
58
67
 
59
68
  getMetadata(locale?: string): CozyMetadata[];
60
69
 
@@ -106,19 +115,35 @@ export interface CozyMetadata {
106
115
 
107
116
  }
108
117
 
118
+ export interface CozyTOC {
119
+
120
+ root: CozyTOCNode[];
121
+
122
+ getBreadcrumbs(id: string): CozyTOCNode[];
123
+
124
+ getNode(id: string): CozyTOCNode | undefined;
125
+
126
+ }
127
+
109
128
  export interface CozyTOCNode {
110
129
 
111
130
  readonly id: string;
112
131
 
113
132
  readonly type: 'range' | 'canvas';
114
133
 
115
- getLabel(locale?: string): string | undefined;
134
+ readonly source: CozyRange | CozyCanvas;
135
+
136
+ readonly children: CozyTOCNode[];
137
+
138
+ readonly navItems: CozyCanvas[];
116
139
 
117
- children: CozyTOCNode[];
140
+ readonly navSections: CozyRange[];
118
141
 
119
- parent?: CozyTOCNode;
142
+ readonly parent?: CozyTOCNode;
120
143
 
121
- level: number;
144
+ readonly level: number;
145
+
146
+ getLabel(locale?: string): string | undefined;
122
147
 
123
148
  }
124
149
 
package/test/Cozy.test.ts CHANGED
@@ -10,7 +10,7 @@ describe('Cozy', () => {
10
10
  expect(result.type).toBe('collection');
11
11
  });
12
12
 
13
- it('should parse strctures in presentation manifests', async () => {
13
+ it('should parse structures in presentation manifests', async () => {
14
14
  const result = await Cozy.parseURL(WITH_STRUCTURES);
15
15
  expect(result.type).toBe('manifest');
16
16
  expect('resource' in result).toBeTruthy();
@@ -19,8 +19,8 @@ describe('Cozy', () => {
19
19
  expect(manifest.structure.length > 0).toBeTruthy();
20
20
 
21
21
  const tableOfContents = manifest.getTableOfContents();
22
- expect(tableOfContents.length).toBe(1);
23
- expect(tableOfContents[0].children.length).toBe(14);
22
+ expect(tableOfContents.root.length).toBe(1);
23
+ expect(tableOfContents.root[0].children.length).toBe(14);
24
24
  });
25
25
 
26
26
  });
@@ -0,0 +1,2 @@
1
+ export const WITH_STRUCTURES =
2
+ 'https://lib.is/IE19255085/manifest';
@@ -0,0 +1,26 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { Cozy, CozyManifest } from '../../src';
3
+
4
+ import { WITH_STRUCTURES } from './fixtures';
5
+
6
+ describe('manifest', () => {
7
+
8
+ it('should generate proper ToC breadcrumbs', async () => {
9
+ const result = await Cozy.parseURL(WITH_STRUCTURES);
10
+ expect(result.type).toBe('manifest');
11
+ expect('resource' in result).toBeTruthy();
12
+
13
+ const manifest = (result as any).resource as CozyManifest;
14
+ expect(manifest.structure.length > 0).toBeTruthy();
15
+
16
+ const toc = manifest.getTableOfContents();
17
+
18
+ const breadcrumbs = toc.getBreadcrumbs('https://lib.is/IE19255085/range/range-0-12-0.json');
19
+
20
+ expect(breadcrumbs.length).toBe(3);
21
+ expect(breadcrumbs[0].getLabel()).toBe('Table of Contents');
22
+ expect(breadcrumbs[1].getLabel()).toBe('Woodcuts full');
23
+ expect(breadcrumbs[2].getLabel()).toBe('f. X2v-f. X3r: woodcut full ')
24
+ });
25
+
26
+ });
@@ -1,6 +1,7 @@
1
1
  import { describe, it, expect } from 'vitest';
2
2
  import { Annotation } from '@iiif/presentation-3';
3
3
  import { Cozy, CozyManifest } from '../../src';
4
+ import { importAnnotations } from '../../src/helpers';
4
5
 
5
6
  import {
6
7
  ANNOTATIONS,
@@ -21,7 +22,7 @@ describe('import-annotations', () => {
21
22
 
22
23
  const annotations = ANNOTATIONS as Annotation[];
23
24
 
24
- const modified = Cozy.Helpers.importAnnotations(firstCanvas, annotations)
25
+ const modified = importAnnotations(firstCanvas, annotations)
25
26
  expect(modified.annotations.length).toBe(1);
26
27
  });
27
28
 
@@ -37,7 +38,7 @@ describe('import-annotations', () => {
37
38
 
38
39
  const annotations = ANNOTATIONS as Annotation[];
39
40
 
40
- const modified = Cozy.Helpers.importAnnotations(manifest, annotations, 'cozy');
41
+ const modified = importAnnotations(manifest, annotations, 'cozy');
41
42
  expect(modified.canvases[0].annotations.length).toBe(1);
42
43
  expect(modified.canvases[1].annotations.length).toBe(1);
43
44
  });
File without changes