cozy-iiif 0.2.0 → 0.2.1

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 h, a as $, 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 u(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], M = { 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 k(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);
@@ -282,12 +282,12 @@ function ot(t) {
282
282
  function ct(t, e = "Rights/License", r = "none") {
283
283
  let i = null, s = [], n = Array.isArray(t) ? t : [t];
284
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;
285
+ let c = a ? ot(a) : void 0;
286
+ if (c && (c.indexOf("creativecommons.org") !== -1 || c.indexOf("rightsstatements.org") !== -1)) {
287
+ c.startsWith("https://") ? i = `http://${c.slice(8)}` : i = c;
288
288
  continue;
289
289
  }
290
- o && s.push({ label: { [r]: [e] }, value: { [r]: [o] } });
290
+ c && s.push({ label: { [r]: [e] }, value: { [r]: [c] } });
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: k(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(M.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: k(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: M.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(M.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 u({ ...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), u({ ...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 u({ ...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 u({ ...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: j(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 u({ ...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 u({ ...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), u({ ...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 u({ ...d(t), ...y(t), ...C(t), items: t.members });
402
402
  }
403
403
  function wt(t) {
404
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 });
405
+ return e && (a["@id"] = e), a["@type"] = k(t), a["@type"] === "unknown" && (i && i.length && (a["@context"] = i), a["@type"] = "Service"), s && (a.profile = Y(s)), u({ ...a, ...n });
406
406
  }
407
407
  function It(t) {
408
- return h({ ...m(t), ...g(t), ...A(t) });
408
+ return u({ ...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 j(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 [j(t.default), ...(Array.isArray(t.item) ? t.item : [t.item]).map(j)];
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 x(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 P = 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 && (x(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))), x(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) : x(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);
@@ -552,18 +552,18 @@ 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) => h(t, "type").startsWith("ImageService") || t.profile && t.profile.toString().includes("iiif.io/api/image/"), se = (t) => {
556
+ const e = h(t, "type"), r = h(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((c) => s.findIndex((l) => c.toString().includes(l))).filter((c) => c > -1).sort((c, l) => l - c)[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 = h(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];
566
+ const a = t.sizes.sort((c, l) => l.width * l.height - c.width * c.height).filter((c) => c.width * c.height >= e * r)[0];
567
567
  if (a)
568
568
  return `${i}/full/${a.width},${a.height}/0/default.jpg`;
569
569
  }
@@ -571,10 +571,10 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
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 = h(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: a, y: c, w: l, h: p } = e, v = l / p, f = v < 1, L = Math.ceil(f ? r / v : r), o = Math.ceil(f ? r : r / v), m = `${Math.round(a)},${Math.round(c)},${Math.round(l)},${Math.round(p)}`;
577
+ return `${i}/${m}/!${o},${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, a = n < 1, c = Math.ceil(a ? r / n : r), l = Math.ceil(a ? r : r / n);
586
586
  if (t.thumbnail && t.thumbnail.length > 0) {
587
587
  const p = t.thumbnail[0];
588
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);
589
+ const v = p.service.find((f) => ie(f));
590
+ if (v)
591
+ return _(v, l, c);
592
592
  }
593
593
  if ("id" in p) return p.id;
594
594
  }
595
595
  for (const p of e) {
596
596
  if (p.type === "dynamic" || p.type === "level0")
597
- return _(p.service, c, o);
597
+ return _(p.service, l, c);
598
598
  if (p.type === "static")
599
599
  return p.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;
602
+ const { format: e, height: r, width: i } = t, s = h(t, "id"), n = (t.service || []).find(ie), a = n ? se(n) : void 0;
603
603
  if (a) {
604
- const o = {
604
+ const c = {
605
605
  source: t,
606
606
  type: a.profileLevel === 0 ? "level0" : "dynamic",
607
607
  service: n,
608
608
  width: i,
609
609
  height: r,
610
610
  majorVersion: a.majorVersion,
611
- serviceUrl: ne(v(n, "id"))
611
+ serviceUrl: ne(h(n, "id"))
612
612
  };
613
- return a.profileLevel === 0 ? o : {
614
- ...o,
615
- getRegionURL: $t(o)
613
+ return a.profileLevel === 0 ? c : {
614
+ ...c,
615
+ getRegionURL: $t(c)
616
616
  };
617
617
  } else
618
618
  return {
@@ -625,7 +625,7 @@ 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 P({
629
629
  annotation: [(i) => {
630
630
  if (i.motivation === "painting" || !i.motivation) {
631
631
  const n = (i.body ? Array.isArray(i.body) ? i.body : [i.body] : []).filter((a) => a.type === "Image");
@@ -634,34 +634,42 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
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, l = 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: l,
647
+ getLabel: a.getLabel
645
648
  };
646
- return i.items && i.items.length > 0 && i.items.forEach((o) => {
649
+ a.items && a.items.length > 0 && a.items.forEach((o) => {
647
650
  if (o.source.type === "Range") {
648
- const c = e(o, a, n + 1);
649
- a.children.push(c);
651
+ const I = r(o, p, l + 1);
652
+ p.children.push(I);
650
653
  } else
651
- a.children.push({
654
+ p.children.push({
652
655
  id: o.id,
653
656
  type: "canvas",
654
- getLabel: o.getLabel,
657
+ source: o,
655
658
  children: [],
656
- parent: a,
657
- level: n + 1
659
+ navItems: [],
660
+ navSections: [],
661
+ parent: p,
662
+ level: l + 1,
663
+ getLabel: o.getLabel
658
664
  });
659
- }), a;
665
+ });
666
+ const v = p.children.map((o) => o.type === "canvas" ? o.source : o.children.length === 1 && o.children[0].type === "canvas" ? o.children[0].source : o.source), f = v.filter((o) => o.source.type === "Canvas"), L = v.filter((o) => o.source.type === "Range");
667
+ return p.navItems.push(...f), 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)), getNode: (a) => e.get(a) };
665
673
  }, Ot = async (t) => {
666
674
  try {
667
675
  new URL(t);
@@ -716,7 +724,7 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
716
724
  code: "INVALID_MANIFEST",
717
725
  message: "Missing @context"
718
726
  };
719
- const i = v(t, "id");
727
+ const i = h(t, "id");
720
728
  if (!i)
721
729
  return {
722
730
  type: "error",
@@ -725,7 +733,7 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
725
733
  };
726
734
  if (r.includes("presentation/2") || r.includes("presentation/3")) {
727
735
  const s = r.includes("presentation/2") ? 2 : 3;
728
- return v(t, "type").includes("Collection") ? {
736
+ return h(t, "type").includes("Collection") ? {
729
737
  type: "collection",
730
738
  url: e || i,
731
739
  resource: Ut(t, s)
@@ -755,13 +763,13 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
755
763
  }, Ut = (t, e) => {
756
764
  const r = (n) => {
757
765
  const a = [];
758
- return new k({
759
- manifest: [(c) => a.push(c)]
760
- }).traverseCollection(n), a.map((c) => ({
761
- id: c.id,
762
- type: c.type,
763
- getLabel: L(c),
764
- source: c
766
+ return new P({
767
+ manifest: [(l) => a.push(l)]
768
+ }).traverseCollection(n), a.map((l) => ({
769
+ id: l.id,
770
+ type: l.type,
771
+ getLabel: w(l),
772
+ source: l
765
773
  }));
766
774
  }, i = e === 2 ? te(t) : t, s = r(i);
767
775
  return {
@@ -769,46 +777,46 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
769
777
  id: i.id,
770
778
  majorVersion: e,
771
779
  items: s,
772
- getLabel: L(i),
773
- getMetadata: x(i)
780
+ getLabel: w(i),
781
+ getMetadata: $(i)
774
782
  };
775
783
  }, Dt = (t, e) => {
776
784
  const r = (a) => {
777
- const o = [], c = [];
778
- new k({
779
- canvas: [(l) => {
780
- l.items && o.push(l);
785
+ const c = [], l = [];
786
+ new P({
787
+ canvas: [(o) => {
788
+ o.items && c.push(o);
781
789
  }],
782
- range: [(l) => {
783
- l.type === "Range" && c.push(l);
790
+ range: [(o) => {
791
+ o.type === "Range" && l.push(o);
784
792
  }]
785
793
  }).traverseManifest(a);
786
- const u = o.map((l) => {
787
- const d = kt(l);
794
+ const v = c.map((o) => {
795
+ const m = kt(o);
788
796
  return {
789
- source: l,
790
- id: l.id,
791
- width: l.width,
792
- height: l.height,
793
- images: d,
794
- annotations: l.annotations || [],
795
- getLabel: L(l),
796
- getMetadata: x(l),
797
- getThumbnailURL: Mt(l, d)
797
+ source: o,
798
+ id: o.id,
799
+ width: o.width,
800
+ height: o.height,
801
+ images: m,
802
+ annotations: o.annotations || [],
803
+ getLabel: w(o),
804
+ getMetadata: $(o),
805
+ getThumbnailURL: Mt(o, m)
798
806
  };
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];
807
+ }), f = (o) => {
808
+ const m = o.items || [], I = m.filter((g) => g.type === "Canvas").map((g) => v.find((T) => T.id === g.id)).filter(Boolean), O = m.filter((g) => g.type === "Range").map((g) => f(g)), oe = [...I, ...O];
801
809
  return {
802
- source: l,
803
- id: l.id,
810
+ source: o,
811
+ id: o.id,
804
812
  // Maintain original order
805
- items: d.map((f) => oe.find((S) => S.id === f.id)),
806
- canvases: P,
813
+ items: m.map((g) => oe.find((T) => T.id === g.id)),
814
+ canvases: I,
807
815
  ranges: O,
808
- getLabel: L(l)
816
+ getLabel: w(o)
809
817
  };
810
- }, I = c.map((l) => C(l));
811
- return { canvases: u, ranges: I };
818
+ }, L = l.map((o) => f(o));
819
+ return { canvases: v, ranges: L };
812
820
  }, i = e === 2 ? te(t) : t, { canvases: s, ranges: n } = r(i);
813
821
  return {
814
822
  source: i,
@@ -816,8 +824,8 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
816
824
  majorVersion: e,
817
825
  canvases: s,
818
826
  structure: n,
819
- getLabel: L(i),
820
- getMetadata: x(i),
827
+ getLabel: w(i),
828
+ getMetadata: $(i),
821
829
  getTableOfContents: Pt(n)
822
830
  };
823
831
  }, Et = (t) => {
@@ -829,16 +837,16 @@ const ie = (t) => v(t, "type").startsWith("ImageService") || t.profile && t.prof
829
837
  width: e,
830
838
  height: r,
831
839
  majorVersion: i.majorVersion,
832
- serviceUrl: ne(v(t, "id"))
840
+ serviceUrl: ne(h(t, "id"))
833
841
  };
834
842
  }, qt = { parse: ae, parseURL: Ot };
835
843
  export {
836
844
  qt as Cozy,
837
845
  _ as getImageURLFromService,
838
846
  kt as getImages,
839
- L as getLabel,
840
- x as getMetadata,
841
- v as getPropertyValue,
847
+ w as getLabel,
848
+ $ as getMetadata,
849
+ h as getPropertyValue,
842
850
  $t as getRegionURL,
843
851
  xt as getRegionURLFromService,
844
852
  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,20 @@ export interface CozyMetadata {
69
69
  readonly label: string;
70
70
  readonly value: string;
71
71
  }
72
+ export interface CozyTOC {
73
+ root: CozyTOCNode[];
74
+ getNode(id: string): CozyTOCNode | undefined;
75
+ }
72
76
  export interface CozyTOCNode {
73
77
  readonly id: string;
74
78
  readonly type: 'range' | 'canvas';
79
+ readonly source: CozyRange | CozyCanvas;
80
+ readonly children: CozyTOCNode[];
81
+ readonly navItems: CozyCanvas[];
82
+ readonly navSections: CozyRange[];
83
+ readonly parent?: CozyTOCNode;
84
+ readonly level: number;
75
85
  getLabel(locale?: string): string | undefined;
76
- children: CozyTOCNode[];
77
- parent?: CozyTOCNode;
78
- level: number;
79
86
  }
80
87
  export type CozyImageResource = StaticImageResource | ImageServiceResource;
81
88
  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.1",
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,75 @@
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
+ return { root, getNode };
38
75
  }
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,33 @@ export interface CozyMetadata {
106
115
 
107
116
  }
108
117
 
118
+ export interface CozyTOC {
119
+
120
+ root: CozyTOCNode[];
121
+
122
+ getNode(id: string): CozyTOCNode | undefined;
123
+
124
+ }
125
+
109
126
  export interface CozyTOCNode {
110
127
 
111
128
  readonly id: string;
112
129
 
113
130
  readonly type: 'range' | 'canvas';
114
131
 
115
- getLabel(locale?: string): string | undefined;
132
+ readonly source: CozyRange | CozyCanvas;
133
+
134
+ readonly children: CozyTOCNode[];
135
+
136
+ readonly navItems: CozyCanvas[];
116
137
 
117
- children: CozyTOCNode[];
138
+ readonly navSections: CozyRange[];
118
139
 
119
- parent?: CozyTOCNode;
140
+ readonly parent?: CozyTOCNode;
120
141
 
121
- level: number;
142
+ readonly level: number;
143
+
144
+ getLabel(locale?: string): string | undefined;
122
145
 
123
146
  }
124
147