@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.
- package/LICENSE +28 -0
- package/README.MD +27 -0
- package/dist/index.js +2536 -0
- package/dist/index.umd.cjs +2 -0
- package/package.json +73 -0
- package/src/fetcher/Fetcher.ts +37 -0
- package/src/fetcher/HttpFetcher.ts +122 -0
- package/src/fetcher/Resource.ts +37 -0
- package/src/fetcher/index.ts +2 -0
- package/src/index.ts +4 -0
- package/src/opds/Acquisition.ts +54 -0
- package/src/opds/Availability.ts +61 -0
- package/src/opds/Copies.ts +43 -0
- package/src/opds/Holds.ts +43 -0
- package/src/opds/Price.ts +51 -0
- package/src/opds/index.ts +5 -0
- package/src/publication/BelongsTo.ts +51 -0
- package/src/publication/Contributor.ts +129 -0
- package/src/publication/GuidedNavigation.ts +176 -0
- package/src/publication/Link.ts +332 -0
- package/src/publication/LocalizedString.ts +74 -0
- package/src/publication/Locator.ts +225 -0
- package/src/publication/LocatorCollection.ts +133 -0
- package/src/publication/Manifest.ts +256 -0
- package/src/publication/Metadata.ts +329 -0
- package/src/publication/Properties.ts +44 -0
- package/src/publication/Publication.ts +148 -0
- package/src/publication/PublicationCollection.ts +144 -0
- package/src/publication/ReadingProgression.ts +28 -0
- package/src/publication/Subject.ts +115 -0
- package/src/publication/encryption/Encryption.ts +68 -0
- package/src/publication/encryption/Properties.ts +20 -0
- package/src/publication/encryption/index.ts +2 -0
- package/src/publication/epub/EPUBLayout.ts +10 -0
- package/src/publication/epub/Presentation.ts +16 -0
- package/src/publication/epub/Properties.ts +28 -0
- package/src/publication/epub/Publication.ts +51 -0
- package/src/publication/epub/index.ts +4 -0
- package/src/publication/html/DomRange.ts +63 -0
- package/src/publication/html/DomRangePoint.ts +64 -0
- package/src/publication/html/Locations.ts +129 -0
- package/src/publication/html/index.ts +3 -0
- package/src/publication/index.ts +19 -0
- package/src/publication/opds/Properties.ts +84 -0
- package/src/publication/opds/Publication.ts +14 -0
- package/src/publication/opds/index.ts +2 -0
- package/src/publication/presentation/Metadata.ts +19 -0
- package/src/publication/presentation/Presentation.ts +155 -0
- package/src/publication/presentation/Properties.ts +70 -0
- package/src/publication/presentation/index.ts +3 -0
- package/src/publication/services/content/Content.ts +36 -0
- package/src/publication/services/content/ContentTokenizer.ts +62 -0
- package/src/publication/services/content/Iterator.ts +46 -0
- package/src/publication/services/content/element/attributes.ts +44 -0
- package/src/publication/services/content/element/element.ts +118 -0
- package/src/publication/services/content/element/index.ts +3 -0
- package/src/publication/services/content/element/text_role.ts +60 -0
- package/src/publication/services/content/index.ts +5 -0
- package/src/publication/services/content/iterators/HTMLResourceContentIterator.ts +571 -0
- package/src/publication/services/content/iterators/PDFTextContentIterator.ts +184 -0
- package/src/publication/services/content/iterators/PublicationContentIterator.ts +144 -0
- package/src/publication/services/content/iterators/helpers.ts +146 -0
- package/src/publication/services/content/iterators/index.ts +3 -0
- package/src/publication/services/index.ts +1 -0
- package/src/util/JSONParse.ts +31 -0
- package/src/util/Language.ts +5 -0
- package/src/util/URITemplate.ts +83 -0
- package/src/util/index.ts +5 -0
- package/src/util/mediatype/MediaType.ts +563 -0
- package/src/util/mediatype/index.ts +1 -0
- package/src/util/tokenizer/TextTokenizer.ts +126 -0
- package/src/util/tokenizer/Tokenizer.ts +8 -0
- package/src/util/tokenizer/index.ts +2 -0
- package/src/util/tokenizer/tokenize-english/README.md +7 -0
- package/src/util/tokenizer/tokenize-english/abbreviations.js +52 -0
- package/src/util/tokenizer/tokenize-english/index.d.ts +3 -0
- package/src/util/tokenizer/tokenize-english/index.js +243 -0
- package/src/util/tokenizer/tokenize-english/utils.js +16 -0
- package/src/util/tokenizer/tokenize-text/README.MD +6 -0
- package/src/util/tokenizer/tokenize-text/index.d.ts +52 -0
- package/src/util/tokenizer/tokenize-text/index.js +256 -0
- package/src/util/tokenizer/tokenize-text/tokens.js +100 -0
- package/types/src/fetcher/Fetcher.d.ts +27 -0
- package/types/src/fetcher/HttpFetcher.d.ts +28 -0
- package/types/src/fetcher/Resource.d.ts +15 -0
- package/types/src/fetcher/index.d.ts +2 -0
- package/types/src/index.d.ts +4 -0
- package/types/src/opds/Acquisition.d.ts +26 -0
- package/types/src/opds/Availability.d.ts +32 -0
- package/types/src/opds/Copies.d.ts +22 -0
- package/types/src/opds/Holds.d.ts +22 -0
- package/types/src/opds/Price.d.ts +29 -0
- package/types/src/opds/index.d.ts +5 -0
- package/types/src/publication/BelongsTo.d.ts +23 -0
- package/types/src/publication/Contributor.d.ts +60 -0
- package/types/src/publication/GuidedNavigation.d.ts +70 -0
- package/types/src/publication/Link.d.ts +128 -0
- package/types/src/publication/LocalizedString.d.ts +48 -0
- package/types/src/publication/Locator.d.ts +101 -0
- package/types/src/publication/LocatorCollection.d.ts +54 -0
- package/types/src/publication/Manifest.d.ts +59 -0
- package/types/src/publication/Metadata.d.ts +101 -0
- package/types/src/publication/Properties.d.ts +28 -0
- package/types/src/publication/Publication.d.ts +53 -0
- package/types/src/publication/PublicationCollection.d.ts +34 -0
- package/types/src/publication/ReadingProgression.d.ts +9 -0
- package/types/src/publication/Subject.d.ts +56 -0
- package/types/src/publication/encryption/Encryption.d.ts +33 -0
- package/types/src/publication/encryption/Properties.d.ts +10 -0
- package/types/src/publication/encryption/index.d.ts +2 -0
- package/types/src/publication/epub/EPUBLayout.d.ts +5 -0
- package/types/src/publication/epub/Presentation.d.ts +7 -0
- package/types/src/publication/epub/Properties.d.ts +14 -0
- package/types/src/publication/epub/Publication.d.ts +19 -0
- package/types/src/publication/epub/index.d.ts +4 -0
- package/types/src/publication/html/DomRange.d.ts +40 -0
- package/types/src/publication/html/DomRangePoint.d.ts +36 -0
- package/types/src/publication/html/Locations.d.ts +45 -0
- package/types/src/publication/html/index.d.ts +3 -0
- package/types/src/publication/index.d.ts +19 -0
- package/types/src/publication/opds/Properties.d.ts +38 -0
- package/types/src/publication/opds/Publication.d.ts +6 -0
- package/types/src/publication/opds/index.d.ts +2 -0
- package/types/src/publication/presentation/Metadata.d.ts +6 -0
- package/types/src/publication/presentation/Presentation.d.ts +95 -0
- package/types/src/publication/presentation/Properties.d.ts +32 -0
- package/types/src/publication/presentation/index.d.ts +3 -0
- package/types/src/publication/services/content/Content.d.ts +20 -0
- package/types/src/publication/services/content/ContentTokenizer.d.ts +19 -0
- package/types/src/publication/services/content/Iterator.d.ts +38 -0
- package/types/src/publication/services/content/element/attributes.d.ts +31 -0
- package/types/src/publication/services/content/element/element.d.ts +107 -0
- package/types/src/publication/services/content/element/index.d.ts +3 -0
- package/types/src/publication/services/content/element/text_role.d.ts +53 -0
- package/types/src/publication/services/content/index.d.ts +5 -0
- package/types/src/publication/services/content/iterators/HTMLResourceContentIterator.d.ts +30 -0
- package/types/src/publication/services/content/iterators/PDFTextContentIterator.d.ts +60 -0
- package/types/src/publication/services/content/iterators/PublicationContentIterator.d.ts +59 -0
- package/types/src/publication/services/content/iterators/helpers.d.ts +10 -0
- package/types/src/publication/services/content/iterators/index.d.ts +3 -0
- package/types/src/publication/services/index.d.ts +1 -0
- package/types/src/util/JSONParse.d.ts +11 -0
- package/types/src/util/Language.d.ts +1 -0
- package/types/src/util/URITemplate.d.ts +24 -0
- package/types/src/util/index.d.ts +5 -0
- package/types/src/util/mediatype/MediaType.d.ts +148 -0
- package/types/src/util/mediatype/index.d.ts +1 -0
- package/types/src/util/tokenizer/TextTokenizer.d.ts +39 -0
- package/types/src/util/tokenizer/Tokenizer.d.ts +6 -0
- package/types/src/util/tokenizer/index.d.ts +2 -0
|
@@ -0,0 +1,329 @@
|
|
|
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 {
|
|
7
|
+
arrayfromJSONorString,
|
|
8
|
+
datefromJSON,
|
|
9
|
+
positiveNumberfromJSON,
|
|
10
|
+
} from '../util/JSONParse';
|
|
11
|
+
import { BelongsTo } from './BelongsTo';
|
|
12
|
+
import { Contributors } from './Contributor';
|
|
13
|
+
import { LocalizedString } from './LocalizedString';
|
|
14
|
+
import { ReadingProgression } from './ReadingProgression';
|
|
15
|
+
import { Subjects } from './Subject';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* https://readium.org/webpub-manifest/schema/metadata.schema.json
|
|
19
|
+
*
|
|
20
|
+
* readingProgression : This contains the reading progression as declared in the
|
|
21
|
+
* publication, so it might be [auto]. To lay out the content, use [effectiveReadingProgression]
|
|
22
|
+
* to get the calculated reading progression from the declared direction and the language.
|
|
23
|
+
* otherMetadata Additional metadata for extensions, as a JSON dictionary.
|
|
24
|
+
*/
|
|
25
|
+
export class Metadata {
|
|
26
|
+
public title: LocalizedString;
|
|
27
|
+
public typeUri?: string;
|
|
28
|
+
public identifier?: string;
|
|
29
|
+
public subtitle?: LocalizedString;
|
|
30
|
+
public sortAs?: LocalizedString;
|
|
31
|
+
public artists?: Contributors;
|
|
32
|
+
public authors?: Contributors;
|
|
33
|
+
public colorists?: Contributors;
|
|
34
|
+
public contributors?: Contributors;
|
|
35
|
+
public editors?: Contributors;
|
|
36
|
+
public illustrators?: Contributors;
|
|
37
|
+
public inkers?: Contributors;
|
|
38
|
+
public letterers?: Contributors;
|
|
39
|
+
public narrators?: Contributors;
|
|
40
|
+
public pencilers?: Contributors;
|
|
41
|
+
public translators?: Contributors;
|
|
42
|
+
public languages?: Array<string>;
|
|
43
|
+
public description?: string;
|
|
44
|
+
public publishers?: Contributors;
|
|
45
|
+
public imprints?: Contributors;
|
|
46
|
+
public published?: Date;
|
|
47
|
+
public modified?: Date;
|
|
48
|
+
public subjects?: Subjects;
|
|
49
|
+
public belongsTo?: BelongsTo;
|
|
50
|
+
public belongsToCollections?: Contributors;
|
|
51
|
+
public belongsToSeries?: Contributors;
|
|
52
|
+
public readingProgression?: ReadingProgression;
|
|
53
|
+
public duration?: number;
|
|
54
|
+
public numberOfPages?: number;
|
|
55
|
+
public otherMetadata?: { [key: string]: any };
|
|
56
|
+
|
|
57
|
+
/**All metadata not in otherMetadata */
|
|
58
|
+
private static readonly mappedProperties = [
|
|
59
|
+
'title',
|
|
60
|
+
'@type',
|
|
61
|
+
'identifier',
|
|
62
|
+
'subtitle',
|
|
63
|
+
'sortAs',
|
|
64
|
+
'artist',
|
|
65
|
+
'author',
|
|
66
|
+
'colorist',
|
|
67
|
+
'contributor',
|
|
68
|
+
'editor',
|
|
69
|
+
'illustrator',
|
|
70
|
+
'inker',
|
|
71
|
+
'letterer',
|
|
72
|
+
'narrator',
|
|
73
|
+
'penciler',
|
|
74
|
+
'translator',
|
|
75
|
+
'language',
|
|
76
|
+
'description',
|
|
77
|
+
'publisher',
|
|
78
|
+
'imprint',
|
|
79
|
+
'published',
|
|
80
|
+
'modified',
|
|
81
|
+
'subject',
|
|
82
|
+
'belongsTo',
|
|
83
|
+
'readingProgression',
|
|
84
|
+
'duration',
|
|
85
|
+
'numberOfPages',
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
/** Creates [Metadata] object */
|
|
89
|
+
constructor(values: {
|
|
90
|
+
title: LocalizedString;
|
|
91
|
+
typeUri?: string;
|
|
92
|
+
identifier?: string;
|
|
93
|
+
subtitle?: LocalizedString;
|
|
94
|
+
sortAs?: LocalizedString;
|
|
95
|
+
artists?: Contributors;
|
|
96
|
+
authors?: Contributors;
|
|
97
|
+
colorists?: Contributors;
|
|
98
|
+
contributors?: Contributors;
|
|
99
|
+
editors?: Contributors;
|
|
100
|
+
illustrators?: Contributors;
|
|
101
|
+
inkers?: Contributors;
|
|
102
|
+
letterers?: Contributors;
|
|
103
|
+
narrators?: Contributors;
|
|
104
|
+
pencilers?: Contributors;
|
|
105
|
+
translators?: Contributors;
|
|
106
|
+
languages?: Array<string>;
|
|
107
|
+
description?: string;
|
|
108
|
+
publishers?: Contributors;
|
|
109
|
+
imprints?: Contributors;
|
|
110
|
+
published?: Date;
|
|
111
|
+
modified?: Date;
|
|
112
|
+
subjects?: Subjects;
|
|
113
|
+
belongsTo?: BelongsTo;
|
|
114
|
+
belongsToCollections?: Contributors;
|
|
115
|
+
belongsToSeries?: Contributors;
|
|
116
|
+
readingProgression?: ReadingProgression;
|
|
117
|
+
duration?: number;
|
|
118
|
+
numberOfPages?: number;
|
|
119
|
+
otherMetadata?: { [key: string]: any };
|
|
120
|
+
}) {
|
|
121
|
+
//title always required
|
|
122
|
+
this.title = values.title as LocalizedString;
|
|
123
|
+
this.typeUri = values.typeUri;
|
|
124
|
+
this.identifier = values.identifier;
|
|
125
|
+
this.subtitle = values.subtitle;
|
|
126
|
+
this.sortAs = values.sortAs;
|
|
127
|
+
this.artists = values.artists;
|
|
128
|
+
this.authors = values.authors;
|
|
129
|
+
this.colorists = values.colorists;
|
|
130
|
+
this.contributors = values.contributors;
|
|
131
|
+
this.editors = values.editors;
|
|
132
|
+
this.illustrators = values.illustrators;
|
|
133
|
+
this.inkers = values.inkers;
|
|
134
|
+
this.letterers = values.letterers;
|
|
135
|
+
this.narrators = values.narrators;
|
|
136
|
+
this.pencilers = values.pencilers;
|
|
137
|
+
this.translators = values.translators;
|
|
138
|
+
this.languages = values.languages;
|
|
139
|
+
this.description = values.description;
|
|
140
|
+
this.publishers = values.publishers;
|
|
141
|
+
this.imprints = values.imprints;
|
|
142
|
+
this.published = values.published;
|
|
143
|
+
this.modified = values.modified;
|
|
144
|
+
this.subjects = values.subjects;
|
|
145
|
+
this.belongsTo = values.belongsTo;
|
|
146
|
+
this.belongsToCollections = values.belongsToCollections;
|
|
147
|
+
this.belongsToSeries = values.belongsToSeries;
|
|
148
|
+
|
|
149
|
+
if (
|
|
150
|
+
this.belongsToCollections &&
|
|
151
|
+
this.belongsToCollections.items.length > 0
|
|
152
|
+
) {
|
|
153
|
+
if (!this.belongsTo) {
|
|
154
|
+
this.belongsTo = new BelongsTo();
|
|
155
|
+
}
|
|
156
|
+
this.belongsTo.items.set('collection', this.belongsToCollections);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (this.belongsToSeries && this.belongsToSeries.items.length > 0) {
|
|
160
|
+
if (!this.belongsTo) {
|
|
161
|
+
this.belongsTo = new BelongsTo();
|
|
162
|
+
}
|
|
163
|
+
this.belongsTo.items.set('series', this.belongsToSeries);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
this.readingProgression = values.readingProgression;
|
|
167
|
+
this.duration = values.duration;
|
|
168
|
+
this.numberOfPages = values.numberOfPages;
|
|
169
|
+
this.otherMetadata = values.otherMetadata;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Parses a [Metadata] from its RWPM JSON representation.
|
|
174
|
+
*
|
|
175
|
+
* If the metadata can't be parsed, a warning will be logged with [warnings].
|
|
176
|
+
*/
|
|
177
|
+
public static deserialize(json: any): Metadata | undefined {
|
|
178
|
+
if (!(json && json.title)) return;
|
|
179
|
+
|
|
180
|
+
const title = LocalizedString.deserialize(json.title) as LocalizedString;
|
|
181
|
+
const typeUri = json['@type'];
|
|
182
|
+
const identifier = json.identifier;
|
|
183
|
+
const subtitle = LocalizedString.deserialize(json.subtitle);
|
|
184
|
+
const sortAs = LocalizedString.deserialize(json.sortAs);
|
|
185
|
+
const artists = Contributors.deserialize(json.artist);
|
|
186
|
+
const authors = Contributors.deserialize(json.author);
|
|
187
|
+
const colorists = Contributors.deserialize(json.colorist);
|
|
188
|
+
const contributors = Contributors.deserialize(json.contributor);
|
|
189
|
+
const editors = Contributors.deserialize(json.editor);
|
|
190
|
+
const illustrators = Contributors.deserialize(json.illustrator);
|
|
191
|
+
const inkers = Contributors.deserialize(json.inker);
|
|
192
|
+
const letterers = Contributors.deserialize(json.letterer);
|
|
193
|
+
const narrators = Contributors.deserialize(json.narrator);
|
|
194
|
+
const pencilers = Contributors.deserialize(json.penciler);
|
|
195
|
+
const translators = Contributors.deserialize(json.translator);
|
|
196
|
+
const languages = arrayfromJSONorString(json.language);
|
|
197
|
+
const description = json.description;
|
|
198
|
+
const publishers = Contributors.deserialize(json.publisher);
|
|
199
|
+
const imprints = Contributors.deserialize(json.imprint);
|
|
200
|
+
const published = datefromJSON(json.published);
|
|
201
|
+
const modified = datefromJSON(json.modified);
|
|
202
|
+
const subjects = Subjects.deserialize(json.subject);
|
|
203
|
+
const belongsTo = BelongsTo.deserialize(json.belongsTo);
|
|
204
|
+
const readingProgression = json.readingProgression;
|
|
205
|
+
const duration = positiveNumberfromJSON(json.duration);
|
|
206
|
+
const numberOfPages = positiveNumberfromJSON(json.numberOfPages);
|
|
207
|
+
|
|
208
|
+
let otherMetadata = Object.assign({}, json);
|
|
209
|
+
Metadata.mappedProperties.forEach(x => delete otherMetadata[x]);
|
|
210
|
+
if (Object.keys(otherMetadata).length === 0) {
|
|
211
|
+
otherMetadata = undefined;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
return new Metadata({
|
|
215
|
+
title,
|
|
216
|
+
typeUri,
|
|
217
|
+
identifier,
|
|
218
|
+
subtitle,
|
|
219
|
+
sortAs,
|
|
220
|
+
artists,
|
|
221
|
+
authors,
|
|
222
|
+
colorists,
|
|
223
|
+
contributors,
|
|
224
|
+
editors,
|
|
225
|
+
illustrators,
|
|
226
|
+
inkers,
|
|
227
|
+
letterers,
|
|
228
|
+
narrators,
|
|
229
|
+
pencilers,
|
|
230
|
+
translators,
|
|
231
|
+
languages,
|
|
232
|
+
description,
|
|
233
|
+
publishers,
|
|
234
|
+
imprints,
|
|
235
|
+
published,
|
|
236
|
+
modified,
|
|
237
|
+
subjects,
|
|
238
|
+
belongsTo,
|
|
239
|
+
readingProgression,
|
|
240
|
+
duration,
|
|
241
|
+
numberOfPages,
|
|
242
|
+
otherMetadata,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Serializes a [Metadata] to its RWPM JSON representation.
|
|
248
|
+
*/
|
|
249
|
+
public serialize(): any {
|
|
250
|
+
const json: any = { title: this.title.serialize() };
|
|
251
|
+
if (this.typeUri !== undefined) json['@type'] = this.typeUri;
|
|
252
|
+
if (this.identifier !== undefined) json.identifier = this.identifier;
|
|
253
|
+
if (this.subtitle) json.subtitle = this.subtitle.serialize();
|
|
254
|
+
if (this.sortAs) json.sortAs = this.sortAs.serialize();
|
|
255
|
+
if (this.editors) json.editor = this.editors.serialize();
|
|
256
|
+
if (this.artists) json.artist = this.artists.serialize();
|
|
257
|
+
if (this.authors) json.author = this.authors.serialize();
|
|
258
|
+
if (this.colorists) json.colorist = this.colorists.serialize();
|
|
259
|
+
if (this.contributors) json.contributor = this.contributors.serialize();
|
|
260
|
+
if (this.illustrators) json.illustrator = this.illustrators.serialize();
|
|
261
|
+
if (this.letterers) json.letterer = this.letterers.serialize();
|
|
262
|
+
if (this.narrators) json.narrator = this.narrators.serialize();
|
|
263
|
+
if (this.pencilers) json.penciler = this.pencilers.serialize();
|
|
264
|
+
if (this.translators) json.translator = this.translators.serialize();
|
|
265
|
+
if (this.inkers) json.inker = this.inkers.serialize();
|
|
266
|
+
if (this.languages) json.language = this.languages;
|
|
267
|
+
if (this.description !== undefined) json.description = this.description;
|
|
268
|
+
if (this.publishers) json.publisher = this.publishers.serialize();
|
|
269
|
+
if (this.imprints) json.imprint = this.imprints.serialize();
|
|
270
|
+
if (this.published !== undefined)
|
|
271
|
+
json.published = this.published.toISOString();
|
|
272
|
+
if (this.modified !== undefined)
|
|
273
|
+
json.modified = this.modified.toISOString();
|
|
274
|
+
if (this.subjects) json.subject = this.subjects.serialize();
|
|
275
|
+
if (this.belongsTo) json.belongsTo = this.belongsTo.serialize();
|
|
276
|
+
if (this.readingProgression)
|
|
277
|
+
json.readingProgression = this.readingProgression;
|
|
278
|
+
if (this.duration !== undefined) json.duration = this.duration;
|
|
279
|
+
if (this.numberOfPages !== undefined)
|
|
280
|
+
json.numberOfPages = this.numberOfPages;
|
|
281
|
+
|
|
282
|
+
if (this.otherMetadata) {
|
|
283
|
+
const metadata = this.otherMetadata;
|
|
284
|
+
Object.keys(metadata).forEach(x => (json[x] = metadata[x]));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return json;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Computes a [ReadingProgression] when the value of [readingProgression] is set to
|
|
292
|
+
* auto, using the publication language.
|
|
293
|
+
*
|
|
294
|
+
* See this issue for more details: https://github.com/readium/architecture/issues/113
|
|
295
|
+
*/
|
|
296
|
+
public get effectiveReadingProgression(): ReadingProgression {
|
|
297
|
+
if (
|
|
298
|
+
this.readingProgression &&
|
|
299
|
+
this.readingProgression !== ReadingProgression.auto
|
|
300
|
+
) {
|
|
301
|
+
return this.readingProgression;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// https://github.com/readium/readium-css/blob/develop/docs/CSS16-internationalization.md#missing-page-progression-direction
|
|
305
|
+
if (this.languages?.length !== 1) {
|
|
306
|
+
return ReadingProgression.ltr;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const primaryLang = this.languages[0].toLowerCase();
|
|
310
|
+
|
|
311
|
+
if (primaryLang === 'zh-hant' || primaryLang === 'zh-tw') {
|
|
312
|
+
return ReadingProgression.rtl;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
// The region is ignored for ar, fa and he.
|
|
316
|
+
const lang = primaryLang.split('-')[0];
|
|
317
|
+
|
|
318
|
+
switch (lang) {
|
|
319
|
+
case 'ar':
|
|
320
|
+
return ReadingProgression.rtl;
|
|
321
|
+
case 'fa':
|
|
322
|
+
return ReadingProgression.rtl;
|
|
323
|
+
case 'he':
|
|
324
|
+
return ReadingProgression.rtl;
|
|
325
|
+
default:
|
|
326
|
+
return ReadingProgression.ltr;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
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
|
+
/**
|
|
7
|
+
* Properties associated to the linked resource.
|
|
8
|
+
*
|
|
9
|
+
* This is opened for extensions.
|
|
10
|
+
* https://readium.org/webpub-manifest/schema/link.schema.json
|
|
11
|
+
*/
|
|
12
|
+
export class Properties {
|
|
13
|
+
public otherProperties: { [key: string]: any };
|
|
14
|
+
|
|
15
|
+
constructor(values: { [key: string]: any }) {
|
|
16
|
+
this.otherProperties = values;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Creates a [Properties] from its RWPM JSON representation.
|
|
21
|
+
*/
|
|
22
|
+
public static deserialize(json: any): Properties | undefined {
|
|
23
|
+
if (!json) return;
|
|
24
|
+
return new Properties(json);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Serializes a [Properties] to its RWPM JSON representation.
|
|
29
|
+
*/
|
|
30
|
+
public serialize(): any {
|
|
31
|
+
return this.otherProperties;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Makes a copy of this [Properties] after merging in the given additional other [properties].
|
|
36
|
+
*/
|
|
37
|
+
public add(properties: { [key: string]: any }): Properties {
|
|
38
|
+
const _properties = Object.assign({}, this.otherProperties);
|
|
39
|
+
for (const property in properties) {
|
|
40
|
+
_properties[property] = properties[property];
|
|
41
|
+
}
|
|
42
|
+
return new Properties(_properties);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
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 { Link, Links } from './Link';
|
|
7
|
+
import { Locator } from './Locator';
|
|
8
|
+
import { Manifest } from './Manifest';
|
|
9
|
+
import { Metadata } from './Metadata';
|
|
10
|
+
import { EmptyFetcher, Fetcher } from '../fetcher/Fetcher';
|
|
11
|
+
import { PublicationCollection } from './PublicationCollection';
|
|
12
|
+
import { Resource } from '../fetcher/Resource';
|
|
13
|
+
import { GuidedNavigationDocument } from "./GuidedNavigation";
|
|
14
|
+
import { URITemplate } from "../util";
|
|
15
|
+
|
|
16
|
+
export type ServiceFactory = () => null;
|
|
17
|
+
|
|
18
|
+
/** Shared model for a Readium Publication. */
|
|
19
|
+
export class Publication {
|
|
20
|
+
/** The manifest holding the publication metadata extracted from the publication file */
|
|
21
|
+
public manifest: Manifest;
|
|
22
|
+
private readonly fetcher: Fetcher = new EmptyFetcher();
|
|
23
|
+
|
|
24
|
+
// Shortcuts to manifest properties
|
|
25
|
+
public readonly context?: Array<string>;
|
|
26
|
+
public readonly metadata: Metadata;
|
|
27
|
+
public readonly links: Links;
|
|
28
|
+
/** Identifies a list of resources in reading order for the publication. */
|
|
29
|
+
public readonly readingOrder: Links;
|
|
30
|
+
/** Identifies resources that are necessary for rendering the publication. */
|
|
31
|
+
public readonly resources?: Links;
|
|
32
|
+
/** Identifies the collection that contains a table of contents. */
|
|
33
|
+
public readonly tableOfContents?: Links;
|
|
34
|
+
/** Identifies the collection that contains sub collections. */
|
|
35
|
+
public readonly subcollections?: Map<string, Array<PublicationCollection>>;
|
|
36
|
+
|
|
37
|
+
constructor(values: { manifest: Manifest; fetcher?: Fetcher }) {
|
|
38
|
+
if (values.fetcher) this.fetcher = values.fetcher;
|
|
39
|
+
this.manifest = values.manifest;
|
|
40
|
+
this.context = values.manifest.context;
|
|
41
|
+
this.metadata = values.manifest.metadata;
|
|
42
|
+
this.links = values.manifest.links;
|
|
43
|
+
this.readingOrder = values.manifest.readingOrder;
|
|
44
|
+
this.resources = values.manifest.resources;
|
|
45
|
+
this.tableOfContents = values.manifest.tableOfContents;
|
|
46
|
+
this.subcollections = values.manifest.subcollections;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** The URL where this publication is served, computed from the `Link` with `self` relation.
|
|
50
|
+
* e.g. https://provider.com/pub1293/manifest.json gives https://provider.com/pub1293/
|
|
51
|
+
*/
|
|
52
|
+
public get baseURL(): string | undefined {
|
|
53
|
+
return this.manifest.baseURL;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Finds the first Link having the given `href` in the publication's links. */
|
|
57
|
+
public linkWithHref(href: string): Link | undefined {
|
|
58
|
+
return this.manifest.linkWithHref(href);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Returns the [links] of the first child [PublicationCollection] with the given role, or an
|
|
63
|
+
* empty list.
|
|
64
|
+
*/
|
|
65
|
+
public linksWithRole(role: string): Links | undefined {
|
|
66
|
+
const list = this.subcollections?.get(role);
|
|
67
|
+
return list && list.length > 0 ? list[0].links : undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Finds all the links with the given relation in the publication's links. */
|
|
71
|
+
public linksWithRel(rel: string): Array<Link> {
|
|
72
|
+
return this.manifest.linksWithRel(rel);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Finds the first [Link] having the given [rel] in the publications's links.
|
|
77
|
+
*/
|
|
78
|
+
public linkWithRel(rel: string): Link | undefined {
|
|
79
|
+
return this.manifest.linkWithRel(rel);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public async positionsFromManifest(): Promise<Locator[]> {
|
|
83
|
+
const positionListLink = this.manifest.links.findWithMediaType(
|
|
84
|
+
'application/vnd.readium.position-list+json'
|
|
85
|
+
);
|
|
86
|
+
if (positionListLink === undefined) return [];
|
|
87
|
+
const positionListJSON = (await this.get(
|
|
88
|
+
positionListLink
|
|
89
|
+
).readAsJSON()) as { positions: unknown[] | null, total: number };
|
|
90
|
+
if(!positionListJSON['total']) return [];
|
|
91
|
+
return (positionListJSON['positions'] as unknown[]) // Get the array for the positions key
|
|
92
|
+
.map(pos => Locator.deserialize(pos)) // Parse locators
|
|
93
|
+
.filter(l => l !== undefined) as Locator[]; // Filter out failures
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public async guideForLink(link: Link): Promise<GuidedNavigationDocument | undefined> {
|
|
97
|
+
const findGNLink = (l: Link): Link | undefined => l.alternates?.findWithMediaType(
|
|
98
|
+
'application/guided-navigation+json'
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
let guidedNavigationLink = findGNLink(link);
|
|
102
|
+
if(!guidedNavigationLink) {
|
|
103
|
+
// If provided link doesn't have a guided navigation link,
|
|
104
|
+
// search through the manfiest for a matching Link based on the `href`
|
|
105
|
+
const foundLink = this.linkWithHref(link.href);
|
|
106
|
+
if (foundLink !== undefined) {
|
|
107
|
+
// A Link was found, attempt to find a guided navigation link
|
|
108
|
+
guidedNavigationLink = findGNLink(foundLink);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if(!guidedNavigationLink) {
|
|
113
|
+
// Still unable to find a guided navigation link, try to use the manifest's global document
|
|
114
|
+
guidedNavigationLink = this.manifest.links.findWithMediaType(
|
|
115
|
+
'application/guided-navigation+json'
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Unable to find any guided navigation Link, give up
|
|
120
|
+
if(!guidedNavigationLink) return;
|
|
121
|
+
|
|
122
|
+
let href = guidedNavigationLink.href;
|
|
123
|
+
if(guidedNavigationLink.templated) {
|
|
124
|
+
// The manifest's guided navigation link is templated, expand it
|
|
125
|
+
const template = new URITemplate(href);
|
|
126
|
+
const params: { [param: string]: string } = {};
|
|
127
|
+
if(template.parameters.has('ref')) {
|
|
128
|
+
// The template has a `ref` parameter that could be used to reduce the returned doc's size
|
|
129
|
+
params['ref'] = link.href;
|
|
130
|
+
}
|
|
131
|
+
href = new URITemplate(href).expand(params);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Fetch the guided navigation document
|
|
135
|
+
const guidedNavigationJSON = (await this.get(new Link({
|
|
136
|
+
href,
|
|
137
|
+
})).readAsJSON());
|
|
138
|
+
return GuidedNavigationDocument.deserialize(guidedNavigationJSON);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Returns the resource targeted by the given non-templated [link].
|
|
143
|
+
*/
|
|
144
|
+
public get(link: Link): Resource {
|
|
145
|
+
// TODO warn about expanding templated links
|
|
146
|
+
return this.fetcher.get(link);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
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
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Core Collection Model
|
|
10
|
+
*
|
|
11
|
+
* https://readium.org/webpub-manifest/schema/subcollection.schema.json
|
|
12
|
+
* Can be used as extension point in the Readium Web Publication Manifest.
|
|
13
|
+
*/
|
|
14
|
+
export class PublicationCollection {
|
|
15
|
+
public metadata?: Map<string, any>;
|
|
16
|
+
public links: Links;
|
|
17
|
+
public subcollections?: Map<string, Array<PublicationCollection>>;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Creates a [PublicationCollection].
|
|
21
|
+
*/
|
|
22
|
+
constructor(values: {
|
|
23
|
+
metadata?: Map<string, any>;
|
|
24
|
+
links: Links;
|
|
25
|
+
subcollections?: Map<string, Array<PublicationCollection>>;
|
|
26
|
+
}) {
|
|
27
|
+
this.metadata = values.metadata;
|
|
28
|
+
this.links = values.links;
|
|
29
|
+
this.subcollections = values.subcollections;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Parses a [PublicationCollection] from its RWPM JSON representation.
|
|
34
|
+
*/
|
|
35
|
+
public static deserialize(json: any): PublicationCollection | undefined {
|
|
36
|
+
if (!json) return;
|
|
37
|
+
|
|
38
|
+
let links: Links | undefined;
|
|
39
|
+
let metadata: Map<string, any> | undefined;
|
|
40
|
+
let subcollections: Map<string, Array<PublicationCollection>> | undefined;
|
|
41
|
+
|
|
42
|
+
if (json instanceof Array) {
|
|
43
|
+
// Parses an array of links.
|
|
44
|
+
links = Links.deserialize(json);
|
|
45
|
+
} else if (json instanceof Object) {
|
|
46
|
+
// Parses a sub-collection object.
|
|
47
|
+
links = Links.deserialize(json.links);
|
|
48
|
+
|
|
49
|
+
metadata = new Map<string, any>();
|
|
50
|
+
|
|
51
|
+
if (json.metadata) {
|
|
52
|
+
Object.entries(json.metadata).forEach(([key, value]) => {
|
|
53
|
+
metadata?.set(key, value);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
subcollections = PublicationCollection.deserializeCollections(json);
|
|
58
|
+
} else {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!links || links.items.length === 0) return;
|
|
63
|
+
|
|
64
|
+
return new PublicationCollection({
|
|
65
|
+
metadata: metadata?.size ? metadata : undefined,
|
|
66
|
+
links,
|
|
67
|
+
subcollections: subcollections?.size ? subcollections : undefined,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Parses a map of [PublicationCollection] indexed by their roles from its RWPM JSON representation.
|
|
73
|
+
*
|
|
74
|
+
*/
|
|
75
|
+
public static deserializeCollections(
|
|
76
|
+
json: any
|
|
77
|
+
): Map<string, Array<PublicationCollection>> | undefined {
|
|
78
|
+
if (!json) return;
|
|
79
|
+
const collections = new Map<string, Array<PublicationCollection>>();
|
|
80
|
+
Object.entries(json).forEach(([role, subJSON]) => {
|
|
81
|
+
if (role !== 'links' && role !== 'metadata') {
|
|
82
|
+
// Parses a list of links or a single collection object.
|
|
83
|
+
const collection = PublicationCollection.deserialize(subJSON);
|
|
84
|
+
|
|
85
|
+
if (collection) {
|
|
86
|
+
const list = new Array<PublicationCollection>();
|
|
87
|
+
list.push(collection);
|
|
88
|
+
collections.set(role, list);
|
|
89
|
+
} else if (subJSON instanceof Array) {
|
|
90
|
+
// Parses a list of collection objects.
|
|
91
|
+
const list = subJSON
|
|
92
|
+
.map<PublicationCollection>(
|
|
93
|
+
item =>
|
|
94
|
+
PublicationCollection.deserialize(item) as PublicationCollection
|
|
95
|
+
)
|
|
96
|
+
.filter(x => x !== undefined);
|
|
97
|
+
|
|
98
|
+
collections.set(role, list);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return collections.size ? collections : undefined;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Serializes a [PublicationCollection] to its RWPM JSON representation.
|
|
108
|
+
*/
|
|
109
|
+
public serialize(): any {
|
|
110
|
+
const json: any = {};
|
|
111
|
+
|
|
112
|
+
if (this.metadata) {
|
|
113
|
+
json.metadata = {};
|
|
114
|
+
this.metadata.forEach(
|
|
115
|
+
(value: any, key: string) => (json.metadata[key] = value)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (this.links.items.length) {
|
|
120
|
+
json.links = this.links.serialize();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
PublicationCollection.serializeCollection(json, this.subcollections);
|
|
124
|
+
|
|
125
|
+
return json;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public static serializeCollection(
|
|
129
|
+
json: any,
|
|
130
|
+
subcollections?: Map<string, Array<PublicationCollection>>
|
|
131
|
+
) {
|
|
132
|
+
if (subcollections && subcollections.size > 0) {
|
|
133
|
+
subcollections.forEach(
|
|
134
|
+
(value: Array<PublicationCollection>, key: string) => {
|
|
135
|
+
if (value.length === 1) {
|
|
136
|
+
json[key] = value[0].serialize();
|
|
137
|
+
} else {
|
|
138
|
+
json[key] = value.map(x => x.serialize());
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
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 { Page } from './presentation/Presentation';
|
|
7
|
+
|
|
8
|
+
export enum ReadingProgression {
|
|
9
|
+
auto = 'auto',
|
|
10
|
+
btt = 'btt',
|
|
11
|
+
ltr = 'ltr',
|
|
12
|
+
rtl = 'rtl',
|
|
13
|
+
ttb = 'ttb',
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function leadingPage(readingProgression: ReadingProgression): Page {
|
|
17
|
+
switch (readingProgression) {
|
|
18
|
+
case ReadingProgression.auto:
|
|
19
|
+
case ReadingProgression.ttb:
|
|
20
|
+
case ReadingProgression.ltr:
|
|
21
|
+
return Page.left;
|
|
22
|
+
case ReadingProgression.rtl:
|
|
23
|
+
case ReadingProgression.btt:
|
|
24
|
+
return Page.right;
|
|
25
|
+
default:
|
|
26
|
+
return Page.left;
|
|
27
|
+
}
|
|
28
|
+
}
|