@readium/shared 2.2.3 → 2.3.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.
Files changed (163) hide show
  1. package/LICENSE +28 -0
  2. package/README.MD +8 -7
  3. package/dist/_virtual/preload-helper.js +1 -0
  4. package/dist/fetcher/Fetcher.js +1 -0
  5. package/dist/fetcher/HttpFetcher.js +1 -0
  6. package/dist/fetcher/Resource.js +1 -0
  7. package/dist/index.js +1 -4993
  8. package/dist/locales/publication-metadata/ar.json.js +1 -0
  9. package/dist/locales/publication-metadata/da.json.js +1 -0
  10. package/dist/locales/publication-metadata/el.json.js +1 -0
  11. package/dist/locales/publication-metadata/en.json.js +1 -0
  12. package/dist/locales/publication-metadata/es.json.js +1 -0
  13. package/dist/locales/publication-metadata/et.json.js +1 -0
  14. package/dist/locales/publication-metadata/fi.json.js +1 -0
  15. package/dist/locales/publication-metadata/fr.json.js +1 -0
  16. package/dist/locales/publication-metadata/it.json.js +1 -0
  17. package/dist/locales/publication-metadata/pl.json.js +1 -0
  18. package/dist/locales/publication-metadata/pt_PT.json.js +1 -0
  19. package/dist/locales/publication-metadata/sv.json.js +1 -0
  20. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/constants.js +1 -0
  21. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/index.js +1 -0
  22. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/selector-attribute.js +1 -0
  23. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/selector-class.js +1 -0
  24. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/selector-fallback.js +1 -0
  25. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/selector-id.js +1 -0
  26. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/selector-nth-child.js +1 -0
  27. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/selector-nth-of-type.js +1 -0
  28. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/selector-tag.js +1 -0
  29. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/types.js +1 -0
  30. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-cartesian.js +1 -0
  31. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-data.js +1 -0
  32. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-dom.js +1 -0
  33. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-element-data.js +1 -0
  34. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-iselement.js +1 -0
  35. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-messages.js +1 -0
  36. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-options.js +1 -0
  37. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-powerset.js +1 -0
  38. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-selectors.js +1 -0
  39. package/dist/node_modules/.pnpm/css-selector-generator@3.8.0/node_modules/css-selector-generator/esm/utilities-typescript.js +1 -0
  40. package/dist/opds/Acquisition.js +1 -0
  41. package/dist/opds/Availability.js +1 -0
  42. package/dist/opds/Copies.js +1 -0
  43. package/dist/opds/Holds.js +1 -0
  44. package/dist/opds/Price.js +1 -0
  45. package/dist/publication/AltIdentifier.js +1 -0
  46. package/dist/publication/BelongsTo.js +1 -0
  47. package/dist/publication/Contributor.js +1 -0
  48. package/dist/publication/GuidedNavigation.js +1 -0
  49. package/dist/publication/Layout.js +1 -0
  50. package/dist/publication/Link.js +1 -0
  51. package/dist/publication/LocalizedString.js +1 -0
  52. package/dist/publication/Locator.js +1 -0
  53. package/dist/publication/LocatorCollection.js +1 -0
  54. package/dist/publication/Manifest.js +1 -0
  55. package/dist/publication/Metadata.js +1 -0
  56. package/dist/publication/Profiles.js +1 -0
  57. package/dist/publication/Properties.js +1 -0
  58. package/dist/publication/Publication.js +1 -0
  59. package/dist/publication/PublicationCollection.js +1 -0
  60. package/dist/publication/ReadingProgression.js +1 -0
  61. package/dist/publication/Subject.js +1 -0
  62. package/dist/publication/TDM.js +1 -0
  63. package/dist/publication/accessibility/Accessibility.js +1 -0
  64. package/dist/publication/accessibility/AccessibilityMetadataDisplayGuide.js +1 -0
  65. package/dist/publication/accessibility/Localization.js +1 -0
  66. package/dist/publication/accessibility/SupportedLanguages.js +1 -0
  67. package/dist/publication/encryption/Encryption.js +1 -0
  68. package/dist/publication/encryption/Properties.js +1 -0
  69. package/dist/publication/encryption/index.js +1 -0
  70. package/dist/publication/epub/MediaOverlay.js +1 -0
  71. package/dist/publication/epub/Metadata.js +1 -0
  72. package/dist/publication/epub/Properties.js +1 -0
  73. package/dist/publication/epub/Publication.js +1 -0
  74. package/dist/publication/epub/index.js +1 -0
  75. package/dist/publication/html/DomRange.js +1 -0
  76. package/dist/publication/html/DomRangePoint.js +1 -0
  77. package/dist/publication/html/Locations.js +1 -0
  78. package/dist/publication/html/index.js +1 -0
  79. package/dist/publication/opds/Properties.js +1 -0
  80. package/dist/publication/opds/Publication.js +1 -0
  81. package/dist/publication/opds/index.js +1 -0
  82. package/dist/publication/services/content/Content.js +2 -0
  83. package/dist/publication/services/content/ContentTokenizer.js +1 -0
  84. package/dist/publication/services/content/Iterator.js +1 -0
  85. package/dist/publication/services/content/element/attributes.js +1 -0
  86. package/dist/publication/services/content/element/element.js +1 -0
  87. package/dist/publication/services/content/element/text_role.js +1 -0
  88. package/dist/publication/services/content/iterators/HTMLResourceContentIterator.js +1 -0
  89. package/dist/publication/services/content/iterators/PDFTextContentIterator.js +1 -0
  90. package/dist/publication/services/content/iterators/PublicationContentIterator.js +1 -0
  91. package/dist/publication/services/content/iterators/helpers.js +1 -0
  92. package/dist/publication/services/timeline/Timeline.js +1 -0
  93. package/dist/publication/services/timeline/audio.js +1 -0
  94. package/dist/publication/services/timeline/html.js +1 -0
  95. package/dist/publication/services/timeline/index.js +1 -0
  96. package/dist/util/JSONParse.js +1 -0
  97. package/dist/util/URITemplate.js +1 -0
  98. package/dist/util/mediatype/MediaType.js +1 -0
  99. package/dist/util/npt.js +1 -0
  100. package/dist/util/tokenizer/TextTokenizer.js +1 -0
  101. package/dist/util/tokenizer/tokenize-english/abbreviations.js +1 -0
  102. package/dist/util/tokenizer/tokenize-english/index.js +2 -0
  103. package/dist/util/tokenizer/tokenize-english/utils.js +1 -0
  104. package/dist/util/tokenizer/tokenize-text/index.js +1 -0
  105. package/dist/util/tokenizer/tokenize-text/tokens.js +1 -0
  106. package/package.json +34 -27
  107. package/src/locales/publication-metadata/ar.json +402 -0
  108. package/src/locales/publication-metadata/brh.json +1 -0
  109. package/src/locales/publication-metadata/da.json +310 -0
  110. package/src/locales/publication-metadata/el.json +310 -0
  111. package/src/locales/publication-metadata/en.json +310 -0
  112. package/src/locales/publication-metadata/es.json +333 -0
  113. package/src/locales/publication-metadata/et.json +310 -0
  114. package/src/locales/publication-metadata/fi.json +310 -0
  115. package/src/locales/publication-metadata/fr.json +333 -0
  116. package/src/locales/publication-metadata/he.json +9 -0
  117. package/src/locales/publication-metadata/it.json +333 -0
  118. package/src/locales/publication-metadata/lt.json +8 -0
  119. package/src/locales/publication-metadata/pl.json +333 -0
  120. package/src/locales/publication-metadata/pt_PT.json +329 -0
  121. package/src/locales/publication-metadata/sv.json +310 -0
  122. package/src/locales/publication-metadata/tr.json +51 -0
  123. package/src/locales/publication-metadata/uk.json +1 -0
  124. package/src/publication/Link.ts +2 -6
  125. package/src/publication/Locator.ts +21 -3
  126. package/src/publication/Manifest.ts +5 -7
  127. package/src/publication/Publication.ts +2 -1
  128. package/src/publication/accessibility/Localization.ts +12 -14
  129. package/src/publication/accessibility/SupportedLanguages.ts +1 -1
  130. package/src/publication/encryption/Properties.ts +3 -15
  131. package/src/publication/epub/Metadata.ts +6 -12
  132. package/src/publication/epub/Properties.ts +3 -13
  133. package/src/publication/epub/Publication.ts +18 -39
  134. package/src/publication/html/Locations.ts +54 -101
  135. package/src/publication/opds/Properties.ts +21 -66
  136. package/src/publication/opds/Publication.ts +3 -9
  137. package/src/publication/services/content/iterators/HTMLResourceContentIterator.ts +3 -1
  138. package/src/publication/services/timeline/Timeline.ts +305 -59
  139. package/src/publication/services/timeline/TimelineItem.ts +3 -3
  140. package/src/publication/services/timeline/audio.ts +31 -0
  141. package/src/publication/services/timeline/html.ts +5 -0
  142. package/src/publication/services/timeline/index.ts +12 -0
  143. package/src/util/npt.ts +19 -0
  144. package/types/src/publication/encryption/Properties.d.ts +2 -9
  145. package/types/src/publication/epub/Metadata.d.ts +3 -6
  146. package/types/src/publication/epub/Properties.d.ts +2 -10
  147. package/types/src/publication/epub/Publication.d.ts +7 -18
  148. package/types/src/publication/html/Locations.d.ts +15 -44
  149. package/types/src/publication/opds/Properties.d.ts +8 -36
  150. package/types/src/publication/opds/Publication.d.ts +2 -5
  151. package/types/src/publication/services/timeline/Timeline.d.ts +91 -12
  152. package/types/src/publication/services/timeline/TimelineItem.d.ts +3 -3
  153. package/types/src/publication/services/timeline/audio.d.ts +4 -0
  154. package/types/src/publication/services/timeline/html.d.ts +4 -0
  155. package/types/src/publication/services/timeline/index.d.ts +6 -0
  156. package/types/src/util/npt.d.ts +10 -0
  157. package/dist/ar-DyHX_uy2.js +0 -7
  158. package/dist/da-Dct0PS3E.js +0 -7
  159. package/dist/fr-C5HEel98.js +0 -7
  160. package/dist/index.umd.cjs +0 -3
  161. package/dist/it-DFOBoXGy.js +0 -7
  162. package/dist/pt_PT-Di3sVjze.js +0 -7
  163. package/dist/sv-BfzAFsVN.js +0 -7
@@ -0,0 +1,51 @@
1
+ {
2
+ "publication": {
3
+ "format": {
4
+ "audiobook": "Sesli Kitap",
5
+ "audiobookJSON": "Sesli Kitap Manifest Dosyası",
6
+ "cbz": "Çizgi Roman Arşivi",
7
+ "divina": "Divina Yayını",
8
+ "divinaJSON": "Divina Yayını Manifest Dosyası",
9
+ "epub": "EPUB",
10
+ "lcpa": "LCP Korumalı Sesli Kitap",
11
+ "lcpdf": "LCP Korumalı PDF",
12
+ "lcpl": "LCP Lisans Belgesi",
13
+ "pdf": "PDF",
14
+ "rwp": "Readium Web Yayını",
15
+ "rwpm": "Readium Web Yayını Manifest Dosyası",
16
+ "zab": "Sesli Kitap Arşivi",
17
+ "zip": "ZIP Arşivi"
18
+ },
19
+ "kind": {
20
+ "audiobook_one": "Sesli Kitap",
21
+ "audiobook_other": "Sesli Kitaplar",
22
+ "book_one": "kitap",
23
+ "book_other": "kitaplar",
24
+ "comic_one": "çizgi roman",
25
+ "comic_other": "çizgi romanlar",
26
+ "document_one": "belge",
27
+ "document_other": "belgeler"
28
+ },
29
+ "metadata": {
30
+ "accessibility": {
31
+ "display-guide": {
32
+ "accessibility-summary": {
33
+ "no-metadata": "Bilgi mevcut değil",
34
+ "publisher-contact": "Bu ürünün erişilebilirliği hakkında daha fazla bilgi için lütfen yayıncıyla bağlantı kurun: ",
35
+ "title": "Erişilebilirlik özeti"
36
+ },
37
+ "additional-accessibility-information": {
38
+ "aria": {
39
+ "compact": "ARIA rolleri dahildir",
40
+ "descriptive": "İçerik, düzeni en iyi hale getirmek ve gezinmeyi kolaylaştırmak için ARIA rolleriyle iyileştirilmiştir"
41
+ },
42
+ "audio-descriptions": "Sesli betimlemeler",
43
+ "braille": "Braille",
44
+ "color-not-sole-means-of-conveying-information": "Renk, bilgi aktarmanın tek yolu değildir",
45
+ "dyslexia-readability": "Okuma güçlüğü olanlar için uyarlanmış okunabilirlik"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -11,7 +11,7 @@ import {
11
11
  positiveNumberfromJSON,
12
12
  setToArray,
13
13
  } from '../util/JSONParse.ts';
14
- import { LocatorLocations, Locator } from './Locator.ts';
14
+ import { Locator } from './Locator.ts';
15
15
 
16
16
  /**
17
17
  * Link Object for the Readium Web Publication Manifest.
@@ -197,14 +197,10 @@ export class Link {
197
197
  * Creates a [Locator] from a reading order [Link].
198
198
  */
199
199
  public get locator(): Locator {
200
- let parts = this.href.split('#');
201
200
  return new Locator({
202
- href: parts.length > 0 && parts[0] !== undefined ? parts[0] : this.href,
201
+ href: this.href,
203
202
  type: this.type ?? '',
204
203
  title: this.title,
205
- locations: new LocatorLocations({
206
- fragments: parts.length > 1 && parts[1] !== undefined ? [parts[1]] : [],
207
- }),
208
204
  });
209
205
  }
210
206
  }
@@ -59,12 +59,20 @@ export class LocatorLocations {
59
59
  'progression',
60
60
  'totalProgression',
61
61
  'position',
62
+ 'otherLocations',
62
63
  ]);
63
64
  Object.entries(json).forEach(([key, value]) => {
64
65
  if (!reservedKeys.has(key)) {
65
66
  otherLocations.set(key, value);
66
67
  }
67
68
  });
69
+ // json may be a live LocatorLocations instance (e.g. passed through in-memory
70
+ // rather than round-tripped as RWPM JSON) — its otherLocations is a Map, not
71
+ // flattened keys, and must be merged in directly rather than treated as an
72
+ // extension entry itself.
73
+ if (json.otherLocations instanceof Map) {
74
+ json.otherLocations.forEach((value: any, key: string) => otherLocations.set(key, value));
75
+ }
68
76
 
69
77
  return new LocatorLocations({
70
78
  fragments: arrayfromJSONorString(json.fragments || json.fragment),
@@ -176,12 +184,22 @@ export class Locator {
176
184
  locations?: LocatorLocations;
177
185
  text?: LocatorText;
178
186
  }) {
179
- this.href = values.href;
187
+ const hashIndex = values.href.indexOf("#");
188
+ const hrefFragment = hashIndex >= 0 ? values.href.slice(hashIndex + 1) : undefined;
189
+ this.href = hashIndex >= 0 ? values.href.slice(0, hashIndex) : values.href;
180
190
  this.type = values.type;
181
191
  this.title = values.title;
192
+ // If locations.fragments is already set, it takes precedence over any fragment in the href.
193
+ // We don't merge both because explicit fragments are considered authoritative.
194
+ const existingFragments = values.locations?.fragments;
195
+ const needsFragment = hrefFragment && (!existingFragments || existingFragments.length === 0);
182
196
  this.locations = values.locations
183
- ? values.locations
184
- : new LocatorLocations({});
197
+ ? needsFragment
198
+ ? new LocatorLocations({ ...values.locations, fragments: [hrefFragment!] })
199
+ : values.locations
200
+ : hrefFragment
201
+ ? new LocatorLocations({ fragments: [hrefFragment] })
202
+ : new LocatorLocations({});
185
203
  this.text = values.text;
186
204
  }
187
205
 
@@ -145,21 +145,19 @@ export class Manifest {
145
145
  * Returns null if the resource is not found in this manifest.
146
146
  */
147
147
  public locatorFromLink(link: Link): Locator | undefined {
148
- const components = link.href.split("#");
149
- const href = components.length == 2 ? components[0] : link.href;
150
- const resourceLink = this.linkWithHref(href);
148
+ const bare = link.href.split("#")[0];
149
+ const resourceLink = this.linkWithHref(bare);
151
150
  if(!resourceLink) return undefined;
152
151
  const type = resourceLink.type;
153
152
  if(!type) return undefined;
154
- const fragment = components.length == 2 ? components[1] : undefined;
153
+ const hasFragment = link.href.includes("#");
155
154
 
156
155
  return new Locator({
157
- href,
156
+ href: link.href,
158
157
  type,
159
158
  title: resourceLink.title ?? link.title,
160
159
  locations: new LocatorLocations({
161
- fragments: fragment ? [fragment] : undefined,
162
- progression: fragment ? undefined : 0.0,
160
+ progression: hasFragment ? undefined : 0.0,
163
161
  })
164
162
  });
165
163
  }
@@ -13,6 +13,7 @@ import { Resource } from '../fetcher/Resource.ts';
13
13
  import { GuidedNavigationDocument } from "./GuidedNavigation.ts";
14
14
  import { MediaType, URITemplate } from "../util/index.ts";
15
15
  import { Timeline } from './services/timeline/Timeline.ts';
16
+ import { buildTimeline } from './services/timeline/index.ts';
16
17
 
17
18
  /** Shared model for a Readium Publication. */
18
19
  export class Publication {
@@ -51,7 +52,7 @@ export class Publication {
51
52
  * The result is cached after the first call.
52
53
  */
53
54
  public get timeline(): Timeline {
54
- if (!this._timeline) this._timeline = Timeline.build(this);
55
+ if (!this._timeline) this._timeline = buildTimeline(this);
55
56
  return this._timeline;
56
57
  }
57
58
 
@@ -1,8 +1,5 @@
1
- // Localization.ts
2
-
3
1
  import { SUPPORTED_LANGUAGES } from './SupportedLanguages.ts';
4
- // Static import for English (default locale)
5
- import enLocale from '@edrlab/thorium-locales/publication-metadata/en.json';
2
+ import enLocale from '../../locales/publication-metadata/en.json';
6
3
 
7
4
  export interface L10nString {
8
5
  compact: string;
@@ -16,16 +13,17 @@ interface LocaleData {
16
13
 
17
14
  // Dynamic imports for non-English locales
18
15
  const jsonLoaders: Record<string, () => Promise<{ default: any }>> = {
19
- 'fr': () => import('@edrlab/thorium-locales/publication-metadata/fr.json'),
20
- 'ar': () => import('@edrlab/thorium-locales/publication-metadata/ar.json'),
21
- 'da': () => import('@edrlab/thorium-locales/publication-metadata/da.json'),
22
- // 'el': () => import('@edrlab/thorium-locales/publication-metadata/el.json'),
23
- // 'et': () => import('@edrlab/thorium-locales/publication-metadata/et.json'),
24
- 'it': () => import('@edrlab/thorium-locales/publication-metadata/it.json'),
25
- 'pt_PT': () => import('@edrlab/thorium-locales/publication-metadata/pt_PT.json'),
26
- 'sv': () => import('@edrlab/thorium-locales/publication-metadata/sv.json'),
27
- // 'tr': () => import('@edrlab/thorium-locales/publication-metadata/tr.json'),
28
- // 'uk': () => import('@edrlab/thorium-locales/publication-metadata/uk.json')
16
+ 'ar': () => import('../../locales/publication-metadata/ar.json'),
17
+ 'da': () => import('../../locales/publication-metadata/da.json'),
18
+ 'el': () => import('../../locales/publication-metadata/el.json'),
19
+ 'es': () => import('../../locales/publication-metadata/es.json'),
20
+ 'et': () => import('../../locales/publication-metadata/et.json'),
21
+ 'fi': () => import('../../locales/publication-metadata/fi.json'),
22
+ 'fr': () => import('../../locales/publication-metadata/fr.json'),
23
+ 'it': () => import('../../locales/publication-metadata/it.json'),
24
+ 'pl': () => import('../../locales/publication-metadata/pl.json'),
25
+ 'pt_PT': () => import('../../locales/publication-metadata/pt_PT.json'),
26
+ 'sv': () => import('../../locales/publication-metadata/sv.json')
29
27
  };
30
28
 
31
29
  // Extract English accessibility data
@@ -1 +1 @@
1
- export const SUPPORTED_LANGUAGES = ['en', 'ar', 'da', 'fr', 'it', 'pt_PT', 'sv'];
1
+ export const SUPPORTED_LANGUAGES = ['en', 'ar', 'da', 'el', 'es', 'et', 'fi', 'fr', 'it', 'pl', 'pt_PT', 'sv'];
@@ -1,20 +1,8 @@
1
1
  import { Properties } from '../Properties.ts';
2
2
  import { Encryption } from './Encryption.ts';
3
3
 
4
- // Encryption extensions for link [Properties].
4
+ // Encryption extensions for link Properties.
5
5
 
6
- declare module '../Properties' {
7
- export interface Properties {
8
- /**
9
- * Indicates that a resource is encrypted/obfuscated and provides relevant information for
10
- * decryption.
11
- */
12
- encryption: Encryption | undefined;
13
- }
6
+ export function getEncryption(properties: Properties): Encryption | undefined {
7
+ return Encryption.deserialize(properties.otherProperties.encrypted);
14
8
  }
15
-
16
- Object.defineProperty(Properties.prototype, 'encryption', {
17
- get: function(): Encryption | undefined {
18
- return Encryption.deserialize(this.otherProperties.encrypted);
19
- },
20
- });
@@ -1,16 +1,10 @@
1
- import { Metadata } from "../Metadata.ts";
2
- import { MediaOverlay } from "./MediaOverlay.ts";
1
+ import { Metadata } from '../Metadata.ts';
2
+ import { MediaOverlay } from './MediaOverlay.ts';
3
3
 
4
- declare module '../Metadata' {
5
- export interface Metadata {
6
- getMediaOverlay(): MediaOverlay | undefined;
7
- }
8
- }
9
-
10
- Metadata.prototype.getMediaOverlay = function(): MediaOverlay | undefined {
11
- const mediaOverlay = this.otherMetadata?.['mediaOverlay'];
4
+ // EPUB extensions for Metadata.
12
5
 
6
+ export function getMediaOverlay(metadata: Metadata): MediaOverlay | undefined {
7
+ const mediaOverlay = metadata.otherMetadata?.['mediaOverlay'];
13
8
  if (!mediaOverlay) return;
14
-
15
9
  return MediaOverlay.deserialize(mediaOverlay);
16
- };
10
+ }
@@ -1,18 +1,8 @@
1
1
  import { Properties } from '../Properties.ts';
2
2
 
3
- // EPUB extensions for link [Properties].
3
+ // EPUB extensions for link Properties.
4
4
  // https://readium.org/webpub-manifest/schema/extensions/epub/properties.schema.json
5
5
 
6
- declare module '../Properties' {
7
- export interface Properties {
8
- /**
9
- * Identifies content contained in the linked resource, that cannot be strictly identified using a
10
- * media type.
11
- */
12
- getContains(): Set<string> | undefined;
13
- }
6
+ export function getContains(properties: Properties): Set<string> {
7
+ return new Set<string>(properties.otherProperties['contains'] || []);
14
8
  }
15
-
16
- Properties.prototype.getContains = function(): Set<string> | undefined {
17
- return new Set<string>(this.otherProperties['contains'] || []);
18
- };
@@ -1,51 +1,30 @@
1
1
  import { Links } from '../Link.ts';
2
2
  import { Publication } from '../Publication.ts';
3
3
 
4
- // EPUB extensions for [Publication].
4
+ // EPUB extensions for Publication.
5
5
  // https://readium.org/webpub-manifest/schema/extensions/epub/subcollections.schema.json
6
6
  // https://idpf.github.io/epub-vocabs/structure/#navigation
7
7
 
8
- declare module '../Publication' {
9
- export interface Publication {
10
- /**
11
- * Provides navigation to positions in the Publication content that correspond to the locations of
12
- * page boundaries present in a print source being represented by this EPUB Publication.
13
- */
14
- getPageList(): Links | undefined;
15
-
16
- /**
17
- * Identifies fundamental structural components of the publication in order to enable Reading
18
- * Systems to provide the User efficient access to them.
19
- */
20
- getLandmarks(): Links | undefined;
21
-
22
- getListOfAudioClips(): Links | undefined;
23
- getListOfIllustrations(): Links | undefined;
24
- getListOfTables(): Links | undefined;
25
- getListOfVideoClips(): Links | undefined;
26
- }
8
+ export function getPageList(pub: Publication): Links | undefined {
9
+ return pub.linksWithRole('pageList');
27
10
  }
28
11
 
29
- Publication.prototype.getPageList = function(): Links | undefined {
30
- return this.linksWithRole('pageList');
31
- };
32
-
33
- Publication.prototype.getLandmarks = function(): Links | undefined {
34
- return this.linksWithRole('landmarks');
35
- };
12
+ export function getLandmarks(pub: Publication): Links | undefined {
13
+ return pub.linksWithRole('landmarks');
14
+ }
36
15
 
37
- Publication.prototype.getListOfAudioClips = function(): Links | undefined {
38
- return this.linksWithRole('loa');
39
- };
16
+ export function getListOfAudioClips(pub: Publication): Links | undefined {
17
+ return pub.linksWithRole('loa');
18
+ }
40
19
 
41
- Publication.prototype.getListOfIllustrations = function(): Links | undefined {
42
- return this.linksWithRole('loi');
43
- };
20
+ export function getListOfIllustrations(pub: Publication): Links | undefined {
21
+ return pub.linksWithRole('loi');
22
+ }
44
23
 
45
- Publication.prototype.getListOfTables = function(): Links | undefined {
46
- return this.linksWithRole('lot');
47
- };
24
+ export function getListOfTables(pub: Publication): Links | undefined {
25
+ return pub.linksWithRole('lot');
26
+ }
48
27
 
49
- Publication.prototype.getListOfVideoClips = function(): Links | undefined {
50
- return this.linksWithRole('lov');
51
- };
28
+ export function getListOfVideoClips(pub: Publication): Links | undefined {
29
+ return pub.linksWithRole('lov');
30
+ }
@@ -2,128 +2,81 @@ import { LocatorLocations } from '../Locator.ts';
2
2
  import { DomRange } from './DomRange.ts';
3
3
  import { parseNptTime } from '../../util/npt.ts';
4
4
 
5
- // HTML extensions for [Locations].
5
+ // HTML extensions for LocatorLocations.
6
6
  // https://github.com/readium/architecture/blob/master/models/locators/extensions/html.md
7
7
 
8
- declare module '../Locator' {
9
- export interface LocatorLocations {
10
- /**
11
- * A CSS Selector.
12
- */
13
- getCssSelector(): string | undefined;
14
-
15
- /**
16
- * [partialCfi] is an expression conforming to the "right-hand" side of the EPUB CFI syntax, that is
17
- * to say: without the EPUB-specific OPF spine item reference that precedes the first ! exclamation
18
- * mark (which denotes the "step indirection" into a publication document). Note that the wrapping
19
- * epubcfi(***) syntax is not used for the [partialCfi] string, i.e. the "fragment" part of the CFI
20
- * grammar is ignored.
21
- */
22
- getPartialCfi(): string | undefined;
23
-
24
- /**
25
- * An HTML DOM range.
26
- */
27
- getDomRange(): DomRange | undefined;
28
-
29
- /**
30
- * All named parameters found in the fragments, such as `p=5`.
31
- */
32
- fragmentParameters(): Map<string, string>;
33
-
34
- /**
35
- * HTML ID fragment identifier.
36
- */
37
- htmlId(): string | undefined;
38
-
39
- /**
40
- * Page fragment identifier, used for example in PDF.
41
- */
42
- page(): number | undefined;
43
-
44
- /**
45
- * Temporal Dimension media fragment, used for example in audiobooks.
46
- *
47
- * https://www.w3.org/TR/media-frags/
48
- */
49
- time(): number | undefined;
50
-
51
- /**
52
- * Spatial Dimension media fragment, used for example in audiobooks.
53
- *
54
- * https://www.w3.org/TR/media-frags/
55
- */
56
- space(): [number, number, number, number] | undefined;
57
- }
8
+ export function getCssSelector(loc: LocatorLocations): string | undefined {
9
+ return loc.otherLocations?.get('cssSelector');
58
10
  }
59
11
 
60
- LocatorLocations.prototype.getCssSelector = function(): string | undefined {
61
- return this.otherLocations?.get('cssSelector');
62
- };
63
-
64
- LocatorLocations.prototype.getPartialCfi = function(): string | undefined {
65
- return this.otherLocations?.get('partialCfi');
66
- };
67
-
68
- LocatorLocations.prototype.getDomRange = function(): DomRange | undefined {
69
- return DomRange.deserialize(this.otherLocations?.get('domRange'));
70
- };
12
+ export function getPartialCfi(loc: LocatorLocations): string | undefined {
13
+ return loc.otherLocations?.get('partialCfi');
14
+ }
71
15
 
72
- // Below is technically part of the Navigator's Locator extensions, we're putting it here for now
16
+ export function getDomRange(loc: LocatorLocations): DomRange | undefined {
17
+ return DomRange.deserialize(loc.otherLocations?.get('domRange'));
18
+ }
73
19
 
74
- // Reference: https://www.w3.org/TR/fragid-best-practices
75
- LocatorLocations.prototype.fragmentParameters = function(): Map<string, string> {
20
+ export function getFragmentParameters(loc: LocatorLocations): Map<string, string> {
76
21
  return new Map(
77
- this.fragments
78
- // Concatenates fragments together, after dropping any #
79
- .map(f => f.startsWith("#") ? f.slice(1) : f)
80
- .join("&")
81
- // Splits parameters
82
- .split("&")
83
- .filter(f => !f.startsWith("#"))
84
- .map(f => f.split("="))
85
- // Only keep named parameters
22
+ loc.fragments
23
+ .map(f => f.startsWith('#') ? f.slice(1) : f)
24
+ .join('&')
25
+ .split('&')
26
+ .filter(f => !f.startsWith('#'))
27
+ .map(f => f.split('='))
86
28
  .filter(f => f.length === 2)
87
- .map(f => [
88
- f[0].trim().toLowerCase(),
89
- f[1].trim()
90
- ])
29
+ .map(f => [f[0].trim().toLowerCase(), f[1].trim()])
91
30
  );
92
- };
31
+ }
93
32
 
94
- LocatorLocations.prototype.htmlId = function(): string | undefined {
33
+ export function getHtmlId(loc: LocatorLocations): string | undefined {
95
34
  /*
96
35
  The HTML 5 specification (used for WebPub) allows any character in an HTML ID, except spaces.
97
36
  This is an issue to differentiate with named parameters, so we ignore any ID containing `=`.
98
37
  */
99
- if(!this.fragments.length) return;
100
- let f = this.fragments.find(f => f.length && !f.includes("="));
101
- if(!f) {
102
- const fp = this.fragmentParameters();
103
- if(fp.has("id")) f = fp.get("id");
104
- else if(fp.has("name")) f = fp.get("name");
38
+ if (!loc.fragments.length) return;
39
+ let f = loc.fragments.find(f => f.length && !f.includes('='));
40
+ if (!f) {
41
+ const fp = getFragmentParameters(loc);
42
+ if (fp.has('id')) f = fp.get('id');
43
+ else if (fp.has('name')) f = fp.get('name');
105
44
  }
106
- return f?.startsWith("#") ? f.slice(1) : f;
107
- };
45
+ return f?.startsWith('#') ? f.slice(1) : f;
46
+ }
108
47
 
109
- LocatorLocations.prototype.page = function(): number | undefined {
110
- const i = parseInt(this.fragmentParameters().get("page")!);
111
- if(!isNaN(i) && i >= 0) return i;
48
+ export function getPage(loc: LocatorLocations): number | undefined {
49
+ const i = parseInt(getFragmentParameters(loc).get('page')!);
50
+ if (!isNaN(i) && i >= 0) return i;
112
51
  return undefined;
113
52
  }
114
53
 
115
- LocatorLocations.prototype.time = function(): number | undefined {
116
- const raw = this.fragmentParameters().get("t");
54
+ export function getTime(loc: LocatorLocations): number | undefined {
55
+ const raw = getFragmentParameters(loc).get('t');
117
56
  if (!raw) return undefined;
118
57
  return parseNptTime(raw);
119
58
  }
120
59
 
121
- LocatorLocations.prototype.space = function(): [number, number, number, number] | undefined {
122
- const fp = this.fragmentParameters();
123
- if(!fp.has("xywh")) return;
124
- // TODO more sophiticated parsing to handle the format
125
- const xywh = fp.get("xywh")!.split(",").map(s => parseInt(s));
126
- if(xywh.length !== 4) return; // Must have four parts
127
- if(xywh.some(isNaN)) return; // All parts must be numbers
128
- return xywh as [number, number, number, number];
60
+ export function getSpace(loc: LocatorLocations): { unit: "pixel" | "percent"; x: number; y: number; width: number; height: number } | undefined {
61
+ const fp = getFragmentParameters(loc);
62
+ if (!fp.has('xywh')) return;
63
+
64
+ const raw = fp.get('xywh')!;
65
+ let unit: "pixel" | "percent" = "pixel";
66
+ let coords = raw;
67
+
68
+ const normalizedRaw = raw.toLowerCase();
69
+ if (normalizedRaw.startsWith("pixel:")) {
70
+ coords = raw.slice(6);
71
+ } else if (normalizedRaw.startsWith("percent:")) {
72
+ unit = "percent";
73
+ coords = raw.slice(8);
74
+ }
75
+
76
+ const parse = unit === "percent" ? parseFloat : (s: string) => parseInt(s, 10);
77
+ const parts = coords.split(",").map(parse);
78
+ if (parts.length !== 4 || parts.some(isNaN)) return;
79
+
80
+ const [x, y, width, height] = parts;
81
+ return { unit, x, y, width, height };
129
82
  }
@@ -3,82 +3,37 @@ import { positiveNumberfromJSON } from '../../util/JSONParse.ts';
3
3
  import { Link } from '../Link.ts';
4
4
  import { Properties } from '../Properties.ts';
5
5
 
6
- // OPDS extensions for link [Properties].
6
+ // OPDS extensions for link Properties.
7
7
  // https://specs.opds.io/schema/properties.schema.json
8
8
 
9
- declare module '../Properties' {
10
- export interface Properties {
11
- /**
12
- * Provides a hint about the expected number of items returned.
13
- */
14
- getNumberOfItems(): number | undefined;
15
-
16
- /**
17
- * The price of a publication is tied to its acquisition link.
18
- */
19
- getPrice(): Price | undefined;
20
-
21
- /**
22
- * Indirect acquisition provides a hint for the expected media type that will be acquired after
23
- * additional steps.
24
- */
25
- getIndirectAcquisitions(): Array<Acquisition> | undefined;
26
-
27
- /**
28
- * Library-specific features when a specific book is unavailable but provides a hold list.
29
- */
30
- getHolds(): Holds | undefined;
31
-
32
- /**
33
- * Library-specific feature that contains information about the copies that a library has acquired.
34
- */
35
- getCopies(): Copies | undefined;
36
-
37
- /**
38
- * Indicated the availability of a given resource.
39
- */
40
- getAvailability(): Availability | undefined;
41
-
42
- /**
43
- * Indicates that the linked resource supports authentication with the associated Authentication
44
- * Document.
45
- *
46
- * See https://specs.opds.io/authentication-for-opds-1.0.html
47
- */
48
- getAuthenticate(): Link | undefined;
49
- }
9
+ export function getNumberOfItems(properties: Properties): number | undefined {
10
+ return positiveNumberfromJSON(properties.otherProperties['numberOfItems']);
50
11
  }
51
12
 
52
- Properties.prototype.getNumberOfItems = function(): number | undefined {
53
- return positiveNumberfromJSON(this.otherProperties['numberOfItems']);
54
- };
55
-
56
- Properties.prototype.getPrice = function(): Price | undefined {
57
- return Price.deserialize(this.otherProperties['price']);
58
- };
13
+ export function getPrice(properties: Properties): Price | undefined {
14
+ return Price.deserialize(properties.otherProperties['price']);
15
+ }
59
16
 
60
- Properties.prototype.getIndirectAcquisitions = function():
61
- | Array<Acquisition>
62
- | undefined {
63
- const json = this.otherProperties['indirectAcquisition'];
17
+ export function getIndirectAcquisitions(properties: Properties): Array<Acquisition> | undefined {
18
+ const json = properties.otherProperties['indirectAcquisition'];
64
19
  if (!(json && Array.isArray(json))) return;
65
20
  return json
66
21
  .map<Acquisition>(item => Acquisition.deserialize(item) as Acquisition)
67
22
  .filter(x => x !== undefined);
68
- };
23
+ }
69
24
 
70
- Properties.prototype.getHolds = function(): Holds | undefined {
71
- return Holds.deserialize(this.otherProperties['holds']);
72
- };
25
+ export function getHolds(properties: Properties): Holds | undefined {
26
+ return Holds.deserialize(properties.otherProperties['holds']);
27
+ }
73
28
 
74
- Properties.prototype.getCopies = function(): Copies | undefined {
75
- return Copies.deserialize(this.otherProperties['copies']);
76
- };
29
+ export function getCopies(properties: Properties): Copies | undefined {
30
+ return Copies.deserialize(properties.otherProperties['copies']);
31
+ }
77
32
 
78
- Properties.prototype.getAvailability = function(): Availability | undefined {
79
- return Availability.deserialize(this.otherProperties['availability']);
80
- };
33
+ export function getAvailability(properties: Properties): Availability | undefined {
34
+ return Availability.deserialize(properties.otherProperties['availability']);
35
+ }
81
36
 
82
- Properties.prototype.getAuthenticate = function(): Link | undefined {
83
- return Link.deserialize(this.otherProperties['authenticate']);
84
- };
37
+ export function getAuthenticate(properties: Properties): Link | undefined {
38
+ return Link.deserialize(properties.otherProperties['authenticate']);
39
+ }