@readium/shared 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/LICENSE +28 -0
  2. package/README.MD +27 -0
  3. package/dist/index.js +2536 -0
  4. package/dist/index.umd.cjs +2 -0
  5. package/package.json +73 -0
  6. package/src/fetcher/Fetcher.ts +37 -0
  7. package/src/fetcher/HttpFetcher.ts +122 -0
  8. package/src/fetcher/Resource.ts +37 -0
  9. package/src/fetcher/index.ts +2 -0
  10. package/src/index.ts +4 -0
  11. package/src/opds/Acquisition.ts +54 -0
  12. package/src/opds/Availability.ts +61 -0
  13. package/src/opds/Copies.ts +43 -0
  14. package/src/opds/Holds.ts +43 -0
  15. package/src/opds/Price.ts +51 -0
  16. package/src/opds/index.ts +5 -0
  17. package/src/publication/BelongsTo.ts +51 -0
  18. package/src/publication/Contributor.ts +129 -0
  19. package/src/publication/GuidedNavigation.ts +176 -0
  20. package/src/publication/Link.ts +332 -0
  21. package/src/publication/LocalizedString.ts +74 -0
  22. package/src/publication/Locator.ts +225 -0
  23. package/src/publication/LocatorCollection.ts +133 -0
  24. package/src/publication/Manifest.ts +256 -0
  25. package/src/publication/Metadata.ts +329 -0
  26. package/src/publication/Properties.ts +44 -0
  27. package/src/publication/Publication.ts +148 -0
  28. package/src/publication/PublicationCollection.ts +144 -0
  29. package/src/publication/ReadingProgression.ts +28 -0
  30. package/src/publication/Subject.ts +115 -0
  31. package/src/publication/encryption/Encryption.ts +68 -0
  32. package/src/publication/encryption/Properties.ts +20 -0
  33. package/src/publication/encryption/index.ts +2 -0
  34. package/src/publication/epub/EPUBLayout.ts +10 -0
  35. package/src/publication/epub/Presentation.ts +16 -0
  36. package/src/publication/epub/Properties.ts +28 -0
  37. package/src/publication/epub/Publication.ts +51 -0
  38. package/src/publication/epub/index.ts +4 -0
  39. package/src/publication/html/DomRange.ts +63 -0
  40. package/src/publication/html/DomRangePoint.ts +64 -0
  41. package/src/publication/html/Locations.ts +129 -0
  42. package/src/publication/html/index.ts +3 -0
  43. package/src/publication/index.ts +19 -0
  44. package/src/publication/opds/Properties.ts +84 -0
  45. package/src/publication/opds/Publication.ts +14 -0
  46. package/src/publication/opds/index.ts +2 -0
  47. package/src/publication/presentation/Metadata.ts +19 -0
  48. package/src/publication/presentation/Presentation.ts +155 -0
  49. package/src/publication/presentation/Properties.ts +70 -0
  50. package/src/publication/presentation/index.ts +3 -0
  51. package/src/publication/services/content/Content.ts +36 -0
  52. package/src/publication/services/content/ContentTokenizer.ts +62 -0
  53. package/src/publication/services/content/Iterator.ts +46 -0
  54. package/src/publication/services/content/element/attributes.ts +44 -0
  55. package/src/publication/services/content/element/element.ts +118 -0
  56. package/src/publication/services/content/element/index.ts +3 -0
  57. package/src/publication/services/content/element/text_role.ts +60 -0
  58. package/src/publication/services/content/index.ts +5 -0
  59. package/src/publication/services/content/iterators/HTMLResourceContentIterator.ts +571 -0
  60. package/src/publication/services/content/iterators/PDFTextContentIterator.ts +184 -0
  61. package/src/publication/services/content/iterators/PublicationContentIterator.ts +144 -0
  62. package/src/publication/services/content/iterators/helpers.ts +146 -0
  63. package/src/publication/services/content/iterators/index.ts +3 -0
  64. package/src/publication/services/index.ts +1 -0
  65. package/src/util/JSONParse.ts +31 -0
  66. package/src/util/Language.ts +5 -0
  67. package/src/util/URITemplate.ts +83 -0
  68. package/src/util/index.ts +5 -0
  69. package/src/util/mediatype/MediaType.ts +563 -0
  70. package/src/util/mediatype/index.ts +1 -0
  71. package/src/util/tokenizer/TextTokenizer.ts +126 -0
  72. package/src/util/tokenizer/Tokenizer.ts +8 -0
  73. package/src/util/tokenizer/index.ts +2 -0
  74. package/src/util/tokenizer/tokenize-english/README.md +7 -0
  75. package/src/util/tokenizer/tokenize-english/abbreviations.js +52 -0
  76. package/src/util/tokenizer/tokenize-english/index.d.ts +3 -0
  77. package/src/util/tokenizer/tokenize-english/index.js +243 -0
  78. package/src/util/tokenizer/tokenize-english/utils.js +16 -0
  79. package/src/util/tokenizer/tokenize-text/README.MD +6 -0
  80. package/src/util/tokenizer/tokenize-text/index.d.ts +52 -0
  81. package/src/util/tokenizer/tokenize-text/index.js +256 -0
  82. package/src/util/tokenizer/tokenize-text/tokens.js +100 -0
  83. package/types/src/fetcher/Fetcher.d.ts +27 -0
  84. package/types/src/fetcher/HttpFetcher.d.ts +28 -0
  85. package/types/src/fetcher/Resource.d.ts +15 -0
  86. package/types/src/fetcher/index.d.ts +2 -0
  87. package/types/src/index.d.ts +4 -0
  88. package/types/src/opds/Acquisition.d.ts +26 -0
  89. package/types/src/opds/Availability.d.ts +32 -0
  90. package/types/src/opds/Copies.d.ts +22 -0
  91. package/types/src/opds/Holds.d.ts +22 -0
  92. package/types/src/opds/Price.d.ts +29 -0
  93. package/types/src/opds/index.d.ts +5 -0
  94. package/types/src/publication/BelongsTo.d.ts +23 -0
  95. package/types/src/publication/Contributor.d.ts +60 -0
  96. package/types/src/publication/GuidedNavigation.d.ts +70 -0
  97. package/types/src/publication/Link.d.ts +128 -0
  98. package/types/src/publication/LocalizedString.d.ts +48 -0
  99. package/types/src/publication/Locator.d.ts +101 -0
  100. package/types/src/publication/LocatorCollection.d.ts +54 -0
  101. package/types/src/publication/Manifest.d.ts +59 -0
  102. package/types/src/publication/Metadata.d.ts +101 -0
  103. package/types/src/publication/Properties.d.ts +28 -0
  104. package/types/src/publication/Publication.d.ts +53 -0
  105. package/types/src/publication/PublicationCollection.d.ts +34 -0
  106. package/types/src/publication/ReadingProgression.d.ts +9 -0
  107. package/types/src/publication/Subject.d.ts +56 -0
  108. package/types/src/publication/encryption/Encryption.d.ts +33 -0
  109. package/types/src/publication/encryption/Properties.d.ts +10 -0
  110. package/types/src/publication/encryption/index.d.ts +2 -0
  111. package/types/src/publication/epub/EPUBLayout.d.ts +5 -0
  112. package/types/src/publication/epub/Presentation.d.ts +7 -0
  113. package/types/src/publication/epub/Properties.d.ts +14 -0
  114. package/types/src/publication/epub/Publication.d.ts +19 -0
  115. package/types/src/publication/epub/index.d.ts +4 -0
  116. package/types/src/publication/html/DomRange.d.ts +40 -0
  117. package/types/src/publication/html/DomRangePoint.d.ts +36 -0
  118. package/types/src/publication/html/Locations.d.ts +45 -0
  119. package/types/src/publication/html/index.d.ts +3 -0
  120. package/types/src/publication/index.d.ts +19 -0
  121. package/types/src/publication/opds/Properties.d.ts +38 -0
  122. package/types/src/publication/opds/Publication.d.ts +6 -0
  123. package/types/src/publication/opds/index.d.ts +2 -0
  124. package/types/src/publication/presentation/Metadata.d.ts +6 -0
  125. package/types/src/publication/presentation/Presentation.d.ts +95 -0
  126. package/types/src/publication/presentation/Properties.d.ts +32 -0
  127. package/types/src/publication/presentation/index.d.ts +3 -0
  128. package/types/src/publication/services/content/Content.d.ts +20 -0
  129. package/types/src/publication/services/content/ContentTokenizer.d.ts +19 -0
  130. package/types/src/publication/services/content/Iterator.d.ts +38 -0
  131. package/types/src/publication/services/content/element/attributes.d.ts +31 -0
  132. package/types/src/publication/services/content/element/element.d.ts +107 -0
  133. package/types/src/publication/services/content/element/index.d.ts +3 -0
  134. package/types/src/publication/services/content/element/text_role.d.ts +53 -0
  135. package/types/src/publication/services/content/index.d.ts +5 -0
  136. package/types/src/publication/services/content/iterators/HTMLResourceContentIterator.d.ts +30 -0
  137. package/types/src/publication/services/content/iterators/PDFTextContentIterator.d.ts +60 -0
  138. package/types/src/publication/services/content/iterators/PublicationContentIterator.d.ts +59 -0
  139. package/types/src/publication/services/content/iterators/helpers.d.ts +10 -0
  140. package/types/src/publication/services/content/iterators/index.d.ts +3 -0
  141. package/types/src/publication/services/index.d.ts +1 -0
  142. package/types/src/util/JSONParse.d.ts +11 -0
  143. package/types/src/util/Language.d.ts +1 -0
  144. package/types/src/util/URITemplate.d.ts +24 -0
  145. package/types/src/util/index.d.ts +5 -0
  146. package/types/src/util/mediatype/MediaType.d.ts +148 -0
  147. package/types/src/util/mediatype/index.d.ts +1 -0
  148. package/types/src/util/tokenizer/TextTokenizer.d.ts +39 -0
  149. package/types/src/util/tokenizer/Tokenizer.d.ts +6 -0
  150. package/types/src/util/tokenizer/index.d.ts +2 -0
@@ -0,0 +1,115 @@
1
+ /* Copyright 2021 Readium Foundation. All rights reserved.
2
+ * Use of this source code is governed by a BSD-style license,
3
+ * available in the LICENSE file present in the Github repository of the project.
4
+ */
5
+
6
+ import { Links } from './Link';
7
+ import { LocalizedString } from './LocalizedString';
8
+
9
+ /**
10
+ * https://github.com/readium/webpub-manifest/tree/master/contexts/default#subjects
11
+ */
12
+ export class Subject {
13
+ /** Subject name. */
14
+ public readonly name: LocalizedString;
15
+
16
+ /** Provides a string that a machine can sort. */
17
+ public readonly sortAs?: string;
18
+
19
+ /** EPUB 3.1 opf:term. */
20
+ public readonly code?: string;
21
+
22
+ /** EPUB 3.1 opf:authority. */
23
+ public readonly scheme?: string;
24
+
25
+ /** PUsed to retrieve similar publications for the given subjects. */
26
+ public readonly links?: Links;
27
+
28
+ /** Creates a [Subject]. */
29
+ constructor(values: {
30
+ name: LocalizedString;
31
+ sortAs?: string;
32
+ code?: string;
33
+ scheme?: string;
34
+ links?: Links;
35
+ }) {
36
+ this.name = values.name;
37
+ this.sortAs = values.sortAs;
38
+ this.code = values.code;
39
+ this.scheme = values.scheme;
40
+ this.links = values.links;
41
+ }
42
+
43
+ /**
44
+ * Parses a [Subject] from its RWPM JSON representation.
45
+ *
46
+ * A [Subject] can be parsed from a single string, or a full-fledged object.
47
+ */
48
+ public static deserialize(json: any): Subject | undefined {
49
+ if (!json) return;
50
+
51
+ if (typeof json === 'string') {
52
+ return new Subject({
53
+ name: LocalizedString.deserialize(json) as LocalizedString,
54
+ });
55
+ } else {
56
+ if (!json.name) return;
57
+ return new Subject({
58
+ name: LocalizedString.deserialize(json.name) as LocalizedString,
59
+ sortAs: json.sortAs,
60
+ code: json.code,
61
+ scheme: json.scheme,
62
+ links: Links.deserialize(json.links),
63
+ });
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Serializes a [Subject] to its RWPM JSON representation.
69
+ */
70
+ public serialize(): any {
71
+ const json: any = { name: this.name.serialize() };
72
+ if (this.sortAs !== undefined) json.sortAs = this.sortAs;
73
+ if (this.code !== undefined) json.code = this.code;
74
+ if (this.scheme !== undefined) json.scheme = this.scheme;
75
+ if (this.links) json.links = this.links.serialize();
76
+ return json;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * https://github.com/readium/webpub-manifest/blob/master/schema/subject.schema.json
82
+ *
83
+ * Collection of [Subject]
84
+ */
85
+ export class Subjects {
86
+ /**
87
+ * Array of [Subject] items.
88
+ */
89
+ public readonly items: Array<Subject>;
90
+
91
+ /** Creates an Array of [Subject]. */
92
+ constructor(items: Array<Subject>) {
93
+ this.items = items;
94
+ }
95
+
96
+ /**
97
+ * Parses a [Subjects] from its RWPM JSON representation.
98
+ */
99
+ public static deserialize(json: any): Subjects | undefined {
100
+ if (!json) return;
101
+ const items = json instanceof Array ? json : [json];
102
+ return new Subjects(
103
+ items
104
+ .map<Subject>(item => Subject.deserialize(item) as Subject)
105
+ .filter(x => x !== undefined)
106
+ );
107
+ }
108
+
109
+ /**
110
+ * Serializes a [Subjects] to its RWPM JSON representation.
111
+ */
112
+ public serialize(): any {
113
+ return this.items.map(x => x.serialize());
114
+ }
115
+ }
@@ -0,0 +1,68 @@
1
+ /* Copyright 2021 Readium Foundation. All rights reserved.
2
+ * Use of this source code is governed by a BSD-style license,
3
+ * available in the LICENSE file present in the Github repository of the project.
4
+ */
5
+
6
+ /** Indicates that a resource is encrypted/obfuscated and provides relevant information
7
+ * for decryption.
8
+ */
9
+ export class Encryption {
10
+ /** Identifies the algorithm used to encrypt the resource. */
11
+ public readonly algorithm: string;
12
+
13
+ /** Compression method used on the resource. */
14
+ public readonly compression?: string;
15
+
16
+ /** Original length of the resource in bytes before compression and/or encryption. */
17
+ public readonly originalLength?: number;
18
+
19
+ /** Identifies the encryption profile used to encrypt the resource. */
20
+ public readonly profile?: string;
21
+
22
+ /** Identifies the encryption scheme used to encrypt the resource. */
23
+ public readonly scheme?: string;
24
+
25
+ /**
26
+ * Creates a [Encryption].
27
+ */
28
+ constructor(values: {
29
+ algorithm: string;
30
+ compression?: string;
31
+ originalLength?: number;
32
+ profile?: string;
33
+ scheme?: string;
34
+ }) {
35
+ this.algorithm = values.algorithm;
36
+ this.compression = values.compression;
37
+ this.originalLength = values.originalLength;
38
+ this.profile = values.profile;
39
+ this.scheme = values.scheme;
40
+ }
41
+
42
+ /**
43
+ * Parses a [Encryption] from its RWPM JSON representation.
44
+ */
45
+ public static deserialize(json: any): Encryption | undefined {
46
+ if (!(json && json.algorithm)) return;
47
+ return new Encryption({
48
+ algorithm: json.algorithm,
49
+ compression: json.compression,
50
+ originalLength: json.originalLength,
51
+ profile: json.profile,
52
+ scheme: json.scheme,
53
+ });
54
+ }
55
+
56
+ /**
57
+ * Serializes a [Encryption] to its RWPM JSON representation.
58
+ */
59
+ public serialize(): any {
60
+ const json: any = { algorithm: this.algorithm };
61
+ if (this.compression !== undefined) json.compression = this.compression;
62
+ if (this.originalLength !== undefined)
63
+ json.originalLength = this.originalLength;
64
+ if (this.profile !== undefined) json.profile = this.profile;
65
+ if (this.scheme !== undefined) json.scheme = this.scheme;
66
+ return json;
67
+ }
68
+ }
@@ -0,0 +1,20 @@
1
+ import { Properties } from '../Properties';
2
+ import { Encryption } from './Encryption';
3
+
4
+ // Encryption extensions for link [Properties].
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
+ }
14
+ }
15
+
16
+ Object.defineProperty(Properties.prototype, 'encryption', {
17
+ get: function(): Encryption | undefined {
18
+ return Encryption.deserialize(this.otherProperties.encrypted);
19
+ },
20
+ });
@@ -0,0 +1,2 @@
1
+ export * from './Encryption';
2
+ export * from './Properties';
@@ -0,0 +1,10 @@
1
+ /* Copyright 2021 Readium Foundation. All rights reserved.
2
+ * Use of this source code is governed by a BSD-style license,
3
+ * available in the LICENSE file present in the Github repository of the project.
4
+ */
5
+
6
+ /** Hint about the nature of the layout for the linked resources. */
7
+ export enum EPUBLayout {
8
+ fixed = 'fixed',
9
+ reflowable = 'reflowable',
10
+ }
@@ -0,0 +1,16 @@
1
+ import { Link } from '../Link';
2
+ import { Presentation } from '../presentation/Presentation';
3
+ import { EPUBLayout } from './EPUBLayout';
4
+
5
+ declare module '../presentation/Presentation' {
6
+ export interface Presentation {
7
+ layoutOf(link: Link): EPUBLayout;
8
+ }
9
+ }
10
+
11
+ /** Determines the layout of the given resource in this publication.
12
+ * Default layout is reflowable.
13
+ */
14
+ Presentation.prototype.layoutOf = function(link: Link): EPUBLayout {
15
+ return link.properties?.getLayout() || this.layout || EPUBLayout.reflowable;
16
+ };
@@ -0,0 +1,28 @@
1
+ import { Properties } from '../Properties';
2
+ import { EPUBLayout } from './EPUBLayout';
3
+
4
+ // EPUB extensions for link [Properties].
5
+ // https://readium.org/webpub-manifest/schema/extensions/epub/properties.schema.json
6
+
7
+ declare module '../Properties' {
8
+ export interface Properties {
9
+ /**
10
+ * Identifies content contained in the linked resource, that cannot be strictly identified using a
11
+ * media type.
12
+ */
13
+ getContains(): Set<string> | undefined;
14
+
15
+ /**
16
+ * Hints how the layout of the resource should be presented.
17
+ */
18
+ getLayout(): EPUBLayout | undefined;
19
+ }
20
+ }
21
+
22
+ Properties.prototype.getContains = function(): Set<string> | undefined {
23
+ return new Set<string>(this.otherProperties['contains'] || []);
24
+ };
25
+
26
+ Properties.prototype.getLayout = function(): EPUBLayout | undefined {
27
+ return this.otherProperties['layout'];
28
+ };
@@ -0,0 +1,51 @@
1
+ import { Links } from '../Link';
2
+ import { Publication } from '../Publication';
3
+
4
+ // EPUB extensions for [Publication].
5
+ // https://readium.org/webpub-manifest/schema/extensions/epub/subcollections.schema.json
6
+ // https://idpf.github.io/epub-vocabs/structure/#navigation
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
+ }
27
+ }
28
+
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
+ };
36
+
37
+ Publication.prototype.getListOfAudioClips = function(): Links | undefined {
38
+ return this.linksWithRole('loa');
39
+ };
40
+
41
+ Publication.prototype.getListOfIllustrations = function(): Links | undefined {
42
+ return this.linksWithRole('loi');
43
+ };
44
+
45
+ Publication.prototype.getListOfTables = function(): Links | undefined {
46
+ return this.linksWithRole('lot');
47
+ };
48
+
49
+ Publication.prototype.getListOfVideoClips = function(): Links | undefined {
50
+ return this.linksWithRole('lov');
51
+ };
@@ -0,0 +1,4 @@
1
+ export * from './EPUBLayout';
2
+ export * from './Presentation';
3
+ export * from './Properties';
4
+ export * from './Publication';
@@ -0,0 +1,63 @@
1
+ /* Copyright 2021 Readium Foundation. All rights reserved.
2
+ * Use of this source code is governed by a BSD-style license,
3
+ * available in the LICENSE file present in the Github repository of the project.
4
+ */
5
+
6
+ import { DomRangePoint } from './DomRangePoint';
7
+
8
+ /**
9
+ * This construct enables a serializable representation of a DOM Range.
10
+ *
11
+ * In a DOM Range object, the startContainer + startOffset tuple represents the [start] boundary
12
+ * point. Similarly, the the endContainer + endOffset tuple represents the [end] boundary point.
13
+ * In both cases, the start/endContainer property is a pointer to either a DOM text node, or a DOM
14
+ * element (this typically depends on the mechanism from which the DOM Range instance originates,
15
+ * for example when obtaining the currently-selected document fragment using the `window.selection`
16
+ * API). In the case of a DOM text node, the start/endOffset corresponds to a position within the
17
+ * character data. In the case of a DOM element node, the start/endOffset corresponds to a position
18
+ * that designates a child text node.
19
+ *
20
+ * Note that [end] field is optional. When only the start field is specified, the domRange object
21
+ * represents a "collapsed" range that has identical [start] and [end] boundary points.
22
+ *
23
+ * https://github.com/readium/architecture/blob/master/models/locators/extensions/html.md#the-domrange-object
24
+ *
25
+ */
26
+ export class DomRange {
27
+ /** A serializable representation of the "start" boundary point of the DOM Range. */
28
+ public start: DomRangePoint;
29
+
30
+ /** A serializable representation of the "end" boundary point of the DOM Range. */
31
+ public end?: DomRangePoint;
32
+
33
+ /**
34
+ * Creates a [DomRange].
35
+ */
36
+ constructor(values: { start: DomRangePoint; end?: DomRangePoint }) {
37
+ this.start = values.start;
38
+ this.end = values.end;
39
+ }
40
+
41
+ /**
42
+ * Parses a [DomRange] from its RWPM JSON representation.
43
+ */
44
+ public static deserialize(json: any): DomRange | undefined {
45
+ if (!json) return;
46
+ let start = DomRangePoint.deserialize(json.start);
47
+ if (!start) return;
48
+
49
+ return new DomRange({
50
+ start,
51
+ end: DomRangePoint.deserialize(json.end),
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Serializes a [DomRange] to its RWPM JSON representation.
57
+ */
58
+ public serialize(): any {
59
+ const json: any = { start: this.start.serialize() };
60
+ if (this.end) json.end = this.end.serialize();
61
+ return json;
62
+ }
63
+ }
@@ -0,0 +1,64 @@
1
+ import { positiveNumberfromJSON } from '../../util/JSONParse';
2
+
3
+ /**
4
+ * A serializable representation of a boundary point in a DOM Range.
5
+ *
6
+ * The [cssSelector] field always references a DOM element. If the original DOM Range
7
+ * start/endContainer property references a DOM text node, the [textNodeIndex] field is used to
8
+ * complement the CSS Selector; thereby providing a pointer to a child DOM text node; and
9
+ * [charOffset] is used to tell a position within the character data of that DOM text node
10
+ * (just as the DOM Range start/endOffset does). If the original DOM Range start/endContainer
11
+ * property references a DOM Element, then the [textNodeIndex] field is used to designate the
12
+ * child Text node (just as the DOM Range start/endOffset does), and the optional [charOffset]
13
+ * field is not used (as there is no explicit position within the character data of the text
14
+ * node).
15
+ *
16
+ * https://github.com/readium/architecture/blob/master/models/locators/extensions/html.md#the-start-and-end-object
17
+ */
18
+ export class DomRangePoint {
19
+ public cssSelector: string;
20
+ public textNodeIndex: number;
21
+ public charOffset?: number;
22
+
23
+ /**
24
+ * Creates a [DomRange].
25
+ */
26
+ constructor(values: {
27
+ cssSelector: string;
28
+ textNodeIndex: number;
29
+ charOffset?: number;
30
+ }) {
31
+ this.cssSelector = values.cssSelector;
32
+ this.textNodeIndex = values.textNodeIndex;
33
+ this.charOffset = values.charOffset;
34
+ }
35
+
36
+ /**
37
+ * Parses a [DomRangePoint] from its RWPM JSON representation.
38
+ */
39
+ public static deserialize(json: any): DomRangePoint | undefined {
40
+ if (!(json && json.cssSelector)) return;
41
+ let textNodeIndex = positiveNumberfromJSON(json.textNodeIndex);
42
+ if (textNodeIndex === undefined) return;
43
+ let charOffset = positiveNumberfromJSON(json.charOffset);
44
+ if (charOffset === undefined)
45
+ charOffset = positiveNumberfromJSON(json.offset);
46
+ return new DomRangePoint({
47
+ cssSelector: json.cssSelector,
48
+ textNodeIndex,
49
+ charOffset,
50
+ });
51
+ }
52
+
53
+ /**
54
+ * Serializes a [DomRangePoint] to its RWPM JSON representation.
55
+ */
56
+ public serialize(): any {
57
+ const json: any = {
58
+ cssSelector: this.cssSelector,
59
+ textNodeIndex: this.textNodeIndex,
60
+ };
61
+ if (this.charOffset !== undefined) json.charOffset = this.charOffset;
62
+ return json;
63
+ }
64
+ }
@@ -0,0 +1,129 @@
1
+ import { LocatorLocations } from '../Locator';
2
+ import { DomRange } from './DomRange';
3
+
4
+ // HTML extensions for [Locations].
5
+ // https://github.com/readium/architecture/blob/master/models/locators/extensions/html.md
6
+
7
+ declare module '../Locator' {
8
+ export interface LocatorLocations {
9
+ /**
10
+ * A CSS Selector.
11
+ */
12
+ getCssSelector(): string | undefined;
13
+
14
+ /**
15
+ * [partialCfi] is an expression conforming to the "right-hand" side of the EPUB CFI syntax, that is
16
+ * to say: without the EPUB-specific OPF spine item reference that precedes the first ! exclamation
17
+ * mark (which denotes the "step indirection" into a publication document). Note that the wrapping
18
+ * epubcfi(***) syntax is not used for the [partialCfi] string, i.e. the "fragment" part of the CFI
19
+ * grammar is ignored.
20
+ */
21
+ getPartialCfi(): string | undefined;
22
+
23
+ /**
24
+ * An HTML DOM range.
25
+ */
26
+ getDomRange(): DomRange | undefined;
27
+
28
+ /**
29
+ * All named parameters found in the fragments, such as `p=5`.
30
+ */
31
+ fragmentParameters(): Map<string, string>;
32
+
33
+ /**
34
+ * HTML ID fragment identifier.
35
+ */
36
+ htmlId(): string | undefined;
37
+
38
+ /**
39
+ * Page fragment identifier, used for example in PDF.
40
+ */
41
+ page(): number | undefined;
42
+
43
+ /**
44
+ * Temporal Dimension media fragment, used for example in audiobooks.
45
+ *
46
+ * https://www.w3.org/TR/media-frags/
47
+ */
48
+ time(): number | undefined;
49
+
50
+ /**
51
+ * Spatial Dimension media fragment, used for example in audiobooks.
52
+ *
53
+ * https://www.w3.org/TR/media-frags/
54
+ */
55
+ space(): [number, number, number, number] | undefined;
56
+ }
57
+ }
58
+
59
+ LocatorLocations.prototype.getCssSelector = function(): string | undefined {
60
+ return this.otherLocations?.get('cssSelector');
61
+ };
62
+
63
+ LocatorLocations.prototype.getPartialCfi = function(): string | undefined {
64
+ return this.otherLocations?.get('partialCfi');
65
+ };
66
+
67
+ LocatorLocations.prototype.getDomRange = function(): DomRange | undefined {
68
+ return DomRange.deserialize(this.otherLocations?.get('domRange'));
69
+ };
70
+
71
+ // Below is technically part of the Navigator's Locator extensions, we're putting it here for now
72
+
73
+ // Reference: https://www.w3.org/TR/fragid-best-practices
74
+ LocatorLocations.prototype.fragmentParameters = function(): Map<string, string> {
75
+ return new Map(
76
+ this.fragments
77
+ // Concatenates fragments together, after dropping any #
78
+ .map(f => f.startsWith("#") ? f.slice(1) : f)
79
+ .join("&")
80
+ // Splits parameters
81
+ .split("&")
82
+ .filter(f => !f.startsWith("#"))
83
+ .map(f => f.split("="))
84
+ // Only keep named parameters
85
+ .filter(f => f.length === 2)
86
+ .map(f => [
87
+ f[0].trim().toLowerCase(),
88
+ f[1].trim()
89
+ ])
90
+ );
91
+ };
92
+
93
+ LocatorLocations.prototype.htmlId = function(): string | undefined {
94
+ /*
95
+ The HTML 5 specification (used for WebPub) allows any character in an HTML ID, except spaces.
96
+ This is an issue to differentiate with named parameters, so we ignore any ID containing `=`.
97
+ */
98
+ if(!this.fragments.length) return;
99
+ let f = this.fragments.find(f => f.length && !f.includes("="));
100
+ if(!f) {
101
+ const fp = this.fragmentParameters();
102
+ if(fp.has("id")) f = fp.get("id");
103
+ else if(fp.has("name")) f = fp.get("name");
104
+ }
105
+ return f?.startsWith("#") ? f.slice(1) : f;
106
+ };
107
+
108
+ LocatorLocations.prototype.page = function(): number | undefined {
109
+ const i = parseInt(this.fragmentParameters().get("page")!);
110
+ if(!isNaN(i) && i >= 0) return i;
111
+ return undefined;
112
+ }
113
+
114
+ LocatorLocations.prototype.time = function(): number | undefined {
115
+ // TODO more sophiticated parsing
116
+ const i = parseInt(this.fragmentParameters().get("t")!);
117
+ if(!isNaN(i)) return i;
118
+ return undefined;
119
+ }
120
+
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];
129
+ }
@@ -0,0 +1,3 @@
1
+ export * from './DomRange';
2
+ export * from './DomRangePoint';
3
+ export * from './Locations';
@@ -0,0 +1,19 @@
1
+ export * from './encryption';
2
+ export * from './epub';
3
+ export * from './html';
4
+ export * from './opds';
5
+ export * from './presentation';
6
+ export * from './BelongsTo';
7
+ export * from './Contributor';
8
+ export * from './Link';
9
+ export * from './LocalizedString';
10
+ export * from './Locator';
11
+ export * from './LocatorCollection';
12
+ export * from './Manifest';
13
+ export * from './Metadata';
14
+ export * from './Properties';
15
+ export * from './Publication';
16
+ export * from './PublicationCollection';
17
+ export * from './ReadingProgression';
18
+ export * from './Subject';
19
+ export * from './GuidedNavigation';