@readium/navigator-html-injectables
Version:
An embeddable solution for connecting frames of HTML publications with a Readium Navigator
1,672 lines • 109 kB
JavaScript
const dt = Math.pow(2, 32), Le = () => Math.round(Math.random() * dt).toString(36), pt = () => `${Math.round(performance.now())}-${Le()}-${Le()}`, k = 1;
class ft {
constructor(e) {
this.destination = null, this.registrar = /* @__PURE__ */ new Map(), this.origin = "", this.channelId = "", this.receiver = this.receive.bind(this), this.preLog = [], this.wnd = e, e.addEventListener("message", this.receiver);
}
receive(e) {
if (e.source === null) throw Error("Event source is null");
if (typeof e.data != "object") return;
const t = e.data;
if (!(!("_readium" in t) || !t._readium || t._readium <= 0)) {
if (t.key === "_ping") {
if (!this.destination) {
if (this.destination = e.source, this.origin = e.origin, this.channelId = t._channel, t._readium !== k) {
t._readium > k ? this.send("error", `received comms version ${t._readium} higher than ${k}`) : this.send("error", `received comms version ${t._readium} lower than ${k}`), this.destination = null, this.origin = "", this.channelId = "";
return;
}
this.send("_pong", void 0), this.preLog.forEach((i) => this.send("log", i)), this.preLog = [];
}
return;
} else if (this.channelId) {
if (t._channel !== this.channelId || e.origin !== this.origin) return;
} else
return;
this.handle(t);
}
}
handle(e) {
const t = this.registrar.get(e.key);
if (!t || t.length === 0) {
e.strict && this.send("_unhandled", e);
return;
}
t.forEach((i) => i.cb(e.data, (r) => {
this.send("_ack", r, e.id);
}));
}
register(e, t, i) {
Array.isArray(e) || (e = [e]), e.forEach((r) => {
const n = this.registrar.get(r);
if (n && n.length >= 0) {
if (n.find((a) => a.module === t)) throw new Error(`Trying to register another callback for combination of event ${r} and module ${t}`);
n.push({
cb: i,
module: t
}), this.registrar.set(r, n);
} else
this.registrar.set(r, [{
cb: i,
module: t
}]);
});
}
unregister(e, t) {
Array.isArray(e) || (e = [e]), e.forEach((i) => {
const r = this.registrar.get(i);
!r || r.length === 0 || r.splice(r.findIndex((n) => n.module === t), 1);
});
}
unregisterAll(e) {
this.registrar.forEach((t, i) => this.registrar.set(i, t.filter((r) => r.module !== e)));
}
log(...e) {
this.destination ? this.send("log", e) : this.preLog.push(e);
}
get ready() {
return !!this.destination;
}
destroy() {
this.destination = null, this.channelId = "", this.preLog = [], this.registrar.clear(), this.wnd.removeEventListener("message", this.receiver);
}
send(e, t, i = void 0, r = []) {
if (!this.destination) throw Error("Attempted to send comms message before destination has been initialized");
const n = {
_readium: k,
_channel: this.channelId,
id: i ?? pt(),
// scrict,
key: e,
data: t
};
try {
this.destination.postMessage(n, {
targetOrigin: this.origin,
transfer: r
});
} catch (o) {
if (r.length > 0) throw o;
this.destination.postMessage(n, this.origin, r);
}
}
}
const N = class U {
constructor(e) {
if (typeof e == "string") {
if (!U.VALID_MODES.has(e.toLowerCase()))
return;
this.value = e.toLowerCase();
} else {
const t = e.filter(
(i) => U.VALID_MODES.has(i.toLowerCase())
);
if (t.length === 0)
return;
this.value = Array.from(new Set(t));
}
}
/**
* Parses a [PrimaryAccessMode] from its RWPM JSON representation.
*/
static deserialize(e) {
if (!e) return;
if (typeof e == "string")
return new U(e);
if (!Array.isArray(e)) return;
const t = e.filter((i) => i ? U.VALID_MODES.has(i.toLowerCase()) : !1);
if (t.length !== 0)
return new U(t);
}
/**
* Serializes a [PrimaryAccessMode] to its RWPM JSON representation.
*/
serialize() {
return this.value;
}
};
N.VALID_MODES = /* @__PURE__ */ new Set(["auditory", "tactile", "textual", "visual"]), N.AUDITORY = new N("auditory"), N.TACTILE = new N("tactile"), N.TEXTUAL = new N("textual"), N.VISUAL = new N("visual");
class Te {
/**
* Creates a [Encryption].
*/
constructor(e) {
this.algorithm = e.algorithm, this.compression = e.compression, this.originalLength = e.originalLength, this.profile = e.profile, this.scheme = e.scheme;
}
/**
* Parses a [Encryption] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e && e.algorithm)
return new Te({
algorithm: e.algorithm,
compression: e.compression,
originalLength: e.originalLength,
profile: e.profile,
scheme: e.scheme
});
}
/**
* Serializes a [Encryption] to its RWPM JSON representation.
*/
serialize() {
const e = { algorithm: this.algorithm };
return this.compression !== void 0 && (e.compression = this.compression), this.originalLength !== void 0 && (e.originalLength = this.originalLength), this.profile !== void 0 && (e.profile = this.profile), this.scheme !== void 0 && (e.scheme = this.scheme), e;
}
}
class C {
constructor(e) {
this.otherProperties = e;
}
get page() {
return this.otherProperties.page;
}
/**
* Creates a [Properties] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e)
return new C(e);
}
/**
* Serializes a [Properties] to its RWPM JSON representation.
*/
serialize() {
return this.otherProperties;
}
/**
* Makes a copy of this [Properties] after merging in the given additional other [properties].
*/
add(e) {
const t = Object.assign({}, this.otherProperties);
for (const i in e)
t[i] = e[i];
return new C(t);
}
}
Object.defineProperty(C.prototype, "encryption", {
get: function() {
return Te.deserialize(this.otherProperties.encrypted);
}
});
function mt(s) {
return s && Array.isArray(s) ? s : void 0;
}
function Qe(s) {
return s && typeof s == "string" ? [s] : mt(s);
}
function Re(s) {
return typeof s == "string" ? new Date(s) : void 0;
}
function Q(s) {
return isNaN(s) ? void 0 : s;
}
function S(s) {
return Q(s) !== void 0 && Math.sign(s) >= 0 ? s : void 0;
}
function gt(s) {
const e = new Array();
return s.forEach((t) => e.push(t)), e;
}
class l {
/** Creates a MediaType object. */
constructor(e) {
let t, i, r = e.mediaType.replace(/\s/g, "").split(";");
const n = r[0].split("/");
if (n.length === 2) {
if (t = n[0].toLowerCase().trim(), i = n[1].toLowerCase().trim(), t.length === 0 || i.length === 0)
throw new Error("Invalid media type");
} else
throw new Error("Invalid media type");
const o = {};
for (let d = 1; d < r.length; d++) {
const y = r[d].split("=");
if (y.length === 2) {
const p = y[0].toLocaleLowerCase(), f = p === "charset" ? y[1].toUpperCase() : y[1];
o[p] = f;
}
}
const a = {}, u = Object.keys(o);
u.sort((d, y) => d.localeCompare(y)), u.forEach((d) => a[d] = o[d]);
let h = "";
for (const d in a) {
const y = a[d];
h += `;${d}=${y}`;
}
const c = `${t}/${i}${h}`, m = a.encoding;
this.string = c, this.type = t, this.subtype = i, this.parameters = a, this.encoding = m, this.name = e.name, this.fileExtension = e.fileExtension;
}
static parse(e) {
return new l(e);
}
/** Structured syntax suffix, e.g. `+zip` in `application/epub+zip`.
* Gives a hint on the underlying structure of this media type.
* See. https://tools.ietf.org/html/rfc6838#section-4.2.8
*/
get structuredSyntaxSuffix() {
const e = this.subtype.split("+");
return e.length > 1 ? `+${e[e.length - 1]}` : void 0;
}
/** Parameter values might or might not be case-sensitive, depending on the semantics of
* the parameter name.
* https://tools.ietf.org/html/rfc2616#section-3.7
*
* The character set names may be up to 40 characters taken from the printable characters
* of US-ASCII. However, no distinction is made between use of upper and lower case
* letters.
* https://www.iana.org/assignments/character-sets/character-sets.xhtml
*/
get charset() {
return this.parameters.charset;
}
/** Returns whether the given `other` media type is included in this media type.
* For example, `text/html` contains `text/html;charset=utf-8`.
* - `other` must match the parameters in the `parameters` property, but extra parameters
* are ignored.
* - Order of parameters is ignored.
* - Wildcards are supported, meaning that `image/*` contains `image/png`
*/
contains(e) {
const t = typeof e == "string" ? l.parse({ mediaType: e }) : e;
if (!((this.type === "*" || this.type === t.type) && (this.subtype === "*" || this.subtype === t.subtype)))
return !1;
const i = new Set(
Object.entries(this.parameters).map(([n, o]) => `${n}=${o}`)
), r = new Set(
Object.entries(t.parameters).map(([n, o]) => `${n}=${o}`)
);
for (const n of Array.from(i.values()))
if (!r.has(n))
return !1;
return !0;
}
/** Returns whether this media type and `other` are the same, ignoring parameters that
* are not in both media types.
* For example, `text/html` matches `text/html;charset=utf-8`, but `text/html;charset=ascii`
* doesn't. This is basically like `contains`, but working in both direction.
*/
matches(e) {
const t = typeof e == "string" ? l.parse({ mediaType: e }) : e;
return this.contains(t) || t.contains(this);
}
/**
* Returns whether this media type matches any of the [others] media types.
*/
matchesAny(...e) {
for (const t of e)
if (this.matches(t))
return !0;
return !1;
}
/** Checks the MediaType equals another one (comparing their string) */
equals(e) {
return this.string === e.string;
}
/** Returns whether this media type is structured as a ZIP archive. */
get isZIP() {
return this.matchesAny(
l.ZIP,
l.LCP_PROTECTED_AUDIOBOOK,
l.LCP_PROTECTED_PDF
) || this.structuredSyntaxSuffix === "+zip";
}
/** Returns whether this media type is structured as a JSON file. */
get isJSON() {
return this.matchesAny(l.JSON) || this.structuredSyntaxSuffix === "+json";
}
/** Returns whether this media type is of an OPDS feed. */
get isOPDS() {
return this.matchesAny(
l.OPDS1,
l.OPDS1_ENTRY,
l.OPDS2,
l.OPDS2_PUBLICATION,
l.OPDS_AUTHENTICATION
) || this.structuredSyntaxSuffix === "+json";
}
/** Returns whether this media type is of an HTML document. */
get isHTML() {
return this.matchesAny(l.HTML, l.XHTML);
}
/** Returns whether this media type is of a bitmap image, so excluding vectorial formats. */
get isBitmap() {
return this.matchesAny(
l.BMP,
l.GIF,
l.JPEG,
l.PNG,
l.TIFF,
l.WEBP
);
}
/** Returns whether this media type is of an audio clip. */
get isAudio() {
return this.type === "audio";
}
/** Returns whether this media type is of a video clip. */
get isVideo() {
return this.type === "video";
}
/** Returns whether this media type is of a Readium Web Publication Manifest. */
get isRWPM() {
return this.matchesAny(
l.READIUM_AUDIOBOOK_MANIFEST,
l.DIVINA_MANIFEST,
l.READIUM_WEBPUB_MANIFEST
);
}
/** Returns whether this media type is of a publication file. */
get isPublication() {
return this.matchesAny(
l.READIUM_AUDIOBOOK,
l.READIUM_AUDIOBOOK_MANIFEST,
l.CBZ,
l.DIVINA,
l.DIVINA_MANIFEST,
l.EPUB,
l.LCP_PROTECTED_AUDIOBOOK,
l.LCP_PROTECTED_PDF,
l.LPF,
l.PDF,
l.W3C_WPUB_MANIFEST,
l.READIUM_WEBPUB,
l.READIUM_WEBPUB_MANIFEST,
l.ZAB
);
}
// Known Media Types
static get AAC() {
return l.parse({ mediaType: "audio/aac", fileExtension: "aac" });
}
static get ACSM() {
return l.parse({
mediaType: "application/vnd.adobe.adept+xml",
name: "Adobe Content Server Message",
fileExtension: "acsm"
});
}
static get AIFF() {
return l.parse({ mediaType: "audio/aiff", fileExtension: "aiff" });
}
static get AVI() {
return l.parse({
mediaType: "video/x-msvideo",
fileExtension: "avi"
});
}
static get BINARY() {
return l.parse({ mediaType: "application/octet-stream" });
}
static get BMP() {
return l.parse({ mediaType: "image/bmp", fileExtension: "bmp" });
}
static get CBZ() {
return l.parse({
mediaType: "application/vnd.comicbook+zip",
name: "Comic Book Archive",
fileExtension: "cbz"
});
}
static get CSS() {
return l.parse({ mediaType: "text/css", fileExtension: "css" });
}
static get DIVINA() {
return l.parse({
mediaType: "application/divina+zip",
name: "Digital Visual Narratives",
fileExtension: "divina"
});
}
static get DIVINA_MANIFEST() {
return l.parse({
mediaType: "application/divina+json",
name: "Digital Visual Narratives",
fileExtension: "json"
});
}
static get EPUB() {
return l.parse({
mediaType: "application/epub+zip",
name: "EPUB",
fileExtension: "epub"
});
}
static get GIF() {
return l.parse({ mediaType: "image/gif", fileExtension: "gif" });
}
static get GZ() {
return l.parse({
mediaType: "application/gzip",
fileExtension: "gz"
});
}
static get HTML() {
return l.parse({ mediaType: "text/html", fileExtension: "html" });
}
static get JAVASCRIPT() {
return l.parse({
mediaType: "text/javascript",
fileExtension: "js"
});
}
static get JPEG() {
return l.parse({ mediaType: "image/jpeg", fileExtension: "jpeg" });
}
static get JSON() {
return l.parse({ mediaType: "application/json" });
}
static get LCP_LICENSE_DOCUMENT() {
return l.parse({
mediaType: "application/vnd.readium.lcp.license.v1.0+json",
name: "LCP License",
fileExtension: "lcpl"
});
}
static get LCP_PROTECTED_AUDIOBOOK() {
return l.parse({
mediaType: "application/audiobook+lcp",
name: "LCP Protected Audiobook",
fileExtension: "lcpa"
});
}
static get LCP_PROTECTED_PDF() {
return l.parse({
mediaType: "application/pdf+lcp",
name: "LCP Protected PDF",
fileExtension: "lcpdf"
});
}
static get LCP_STATUS_DOCUMENT() {
return l.parse({
mediaType: "application/vnd.readium.license.status.v1.0+json"
});
}
static get LPF() {
return l.parse({
mediaType: "application/lpf+zip",
fileExtension: "lpf"
});
}
static get MP3() {
return l.parse({ mediaType: "audio/mpeg", fileExtension: "mp3" });
}
static get MPEG() {
return l.parse({ mediaType: "video/mpeg", fileExtension: "mpeg" });
}
static get NCX() {
return l.parse({
mediaType: "application/x-dtbncx+xml",
fileExtension: "ncx"
});
}
static get OGG() {
return l.parse({ mediaType: "audio/ogg", fileExtension: "oga" });
}
static get OGV() {
return l.parse({ mediaType: "video/ogg", fileExtension: "ogv" });
}
static get OPDS1() {
return l.parse({
mediaType: "application/atom+xml;profile=opds-catalog"
});
}
static get OPDS1_ENTRY() {
return l.parse({
mediaType: "application/atom+xml;type=entry;profile=opds-catalog"
});
}
static get OPDS2() {
return l.parse({ mediaType: "application/opds+json" });
}
static get OPDS2_PUBLICATION() {
return l.parse({ mediaType: "application/opds-publication+json" });
}
static get OPDS_AUTHENTICATION() {
return l.parse({
mediaType: "application/opds-authentication+json"
});
}
static get OPUS() {
return l.parse({ mediaType: "audio/opus", fileExtension: "opus" });
}
static get OTF() {
return l.parse({ mediaType: "font/otf", fileExtension: "otf" });
}
static get PDF() {
return l.parse({
mediaType: "application/pdf",
name: "PDF",
fileExtension: "pdf"
});
}
static get PNG() {
return l.parse({ mediaType: "image/png", fileExtension: "png" });
}
static get READIUM_AUDIOBOOK() {
return l.parse({
mediaType: "application/audiobook+zip",
name: "Readium Audiobook",
fileExtension: "audiobook"
});
}
static get READIUM_AUDIOBOOK_MANIFEST() {
return l.parse({
mediaType: "application/audiobook+json",
name: "Readium Audiobook",
fileExtension: "json"
});
}
static get READIUM_CONTENT_DOCUMENT() {
return l.parse({
mediaType: "application/vnd.readium.content+json",
name: "Readium Content Document",
fileExtension: "json"
});
}
static get READIUM_GUIDED_NAVIGATION_DOCUMENT() {
return l.parse({
mediaType: "application/guided-navigation+json",
name: "Readium Guided Navigation Document",
fileExtension: "json"
});
}
static get READIUM_POSITION_LIST() {
return l.parse({
mediaType: "application/vnd.readium.position-list+json",
name: "Readium Position List",
fileExtension: "json"
});
}
static get READIUM_WEBPUB() {
return l.parse({
mediaType: "application/webpub+zip",
name: "Readium Web Publication",
fileExtension: "webpub"
});
}
static get READIUM_WEBPUB_MANIFEST() {
return l.parse({
mediaType: "application/webpub+json",
name: "Readium Web Publication",
fileExtension: "json"
});
}
static get SMIL() {
return l.parse({
mediaType: "application/smil+xml",
fileExtension: "smil"
});
}
static get SVG() {
return l.parse({
mediaType: "image/svg+xml",
fileExtension: "svg"
});
}
static get TEXT() {
return l.parse({ mediaType: "text/plain", fileExtension: "txt" });
}
static get TIFF() {
return l.parse({ mediaType: "image/tiff", fileExtension: "tiff" });
}
static get TTF() {
return l.parse({ mediaType: "font/ttf", fileExtension: "ttf" });
}
static get W3C_WPUB_MANIFEST() {
return l.parse({
mediaType: "application/x.readium.w3c.wpub+json",
name: "Web Publication",
fileExtension: "json"
});
}
static get WAV() {
return l.parse({ mediaType: "audio/wav", fileExtension: "wav" });
}
static get WEBM_AUDIO() {
return l.parse({ mediaType: "audio/webm", fileExtension: "webm" });
}
static get WEBM_VIDEO() {
return l.parse({ mediaType: "video/webm", fileExtension: "webm" });
}
static get WEBP() {
return l.parse({ mediaType: "image/webp", fileExtension: "webp" });
}
static get WOFF() {
return l.parse({ mediaType: "font/woff", fileExtension: "woff" });
}
static get WOFF2() {
return l.parse({ mediaType: "font/woff2", fileExtension: "woff2" });
}
static get XHTML() {
return l.parse({
mediaType: "application/xhtml+xml",
fileExtension: "xhtml"
});
}
static get XML() {
return l.parse({
mediaType: "application/xml",
fileExtension: "xml"
});
}
static get ZAB() {
return l.parse({
mediaType: "application/x.readium.zab+zip",
name: "Zipped Audio Book",
fileExtension: "zab"
});
}
static get ZIP() {
return l.parse({
mediaType: "application/zip",
fileExtension: "zip"
});
}
}
class Ie {
constructor(e) {
this.uri = e, this.parameters = this.getParameters(e);
}
/**
* List of URI template parameter keys, if the [Link] is templated.
*/
getParameters(e) {
const t = /\{\??([^}]+)\}/g, i = e.match(t);
return i ? new Set(
i.join(",").replace(t, "$1").split(",").map((r) => r.trim())
) : /* @__PURE__ */ new Set();
}
/** Expands the URI by replacing the template variables by the given parameters.
* Any extra parameter is appended as query parameters.
* See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570
*/
expand(e) {
const t = (r) => r.split(",").map((n) => {
const o = e[n];
return o ? encodeURIComponent(o) : "";
}).join(","), i = (r) => "?" + r.split(",").map((n) => {
const o = n.split("=")[0], a = e[o];
return a ? `${o}=${encodeURIComponent(a)}` : "";
}).join("&");
return this.uri.replace(/\{(\??)([^}]+)\}/g, (...r) => r[1] ? i(r[2]) : t(r[2]));
}
}
class b {
/**
* Creates a [Locations].
*/
constructor(e) {
this.fragments = e.fragments ? e.fragments : new Array(), this.progression = e.progression, this.totalProgression = e.totalProgression, this.position = e.position, this.otherLocations = e.otherLocations;
}
/**
* Parses a [Locations] from its RWPM JSON representation.
*/
static deserialize(e) {
if (!e) return;
const t = Q(e.progression), i = Q(e.totalProgression), r = Q(e.position), n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set([
"fragment",
"fragments",
"progression",
"totalProgression",
"position"
]);
return Object.entries(e).forEach(([a, u]) => {
o.has(a) || n.set(a, u);
}), new b({
fragments: Qe(e.fragments || e.fragment),
progression: t !== void 0 && t >= 0 && t <= 1 ? t : void 0,
totalProgression: i !== void 0 && i >= 0 && i <= 1 ? i : void 0,
position: r !== void 0 && r > 0 ? r : void 0,
otherLocations: n.size === 0 ? void 0 : n
});
}
/**
* Serializes a [Locations] to its RWPM JSON representation.
*/
serialize() {
const e = {};
return this.fragments && (e.fragments = this.fragments), this.progression !== void 0 && (e.progression = this.progression), this.totalProgression !== void 0 && (e.totalProgression = this.totalProgression), this.position !== void 0 && (e.position = this.position), this.otherLocations && this.otherLocations.forEach((t, i) => e[i] = t), e;
}
}
class D {
/**
* Creates a [Text].
*/
constructor(e) {
this.after = e.after, this.before = e.before, this.highlight = e.highlight;
}
/**
* Parses a [Locations] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e)
return new D({
after: e.after,
before: e.before,
highlight: e.highlight
});
}
/**
* Serializes a [Locations] to its RWPM JSON representation.
*/
serialize() {
const e = {};
return this.after !== void 0 && (e.after = this.after), this.before !== void 0 && (e.before = this.before), this.highlight !== void 0 && (e.highlight = this.highlight), e;
}
}
class R {
/**
* Creates a [Locator].
*/
constructor(e) {
this.href = e.href, this.type = e.type, this.title = e.title, this.locations = e.locations ? e.locations : new b({}), this.text = e.text;
}
/**
* Parses a [Link] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e && e.href && e.type)
return new R({
href: e.href,
type: e.type,
title: e.title,
locations: b.deserialize(e.locations),
text: D.deserialize(e.text)
});
}
/**
* Serializes a [Link] to its RWPM JSON representation.
*/
serialize() {
const e = { href: this.href, type: this.type };
return this.title !== void 0 && (e.title = this.title), this.locations && (e.locations = this.locations.serialize()), this.text && (e.text = this.text.serialize()), e;
}
/**
* Shortcut to get a copy of the [Locator] with different [Locations] sub-properties.
*/
copyWithLocations(e) {
return new R({
href: this.href,
type: this.type,
title: this.title,
text: this.text,
locations: new b({ ...this.locations, ...e })
});
}
}
class H {
/**
* Creates a [Link].
*/
constructor(e) {
this.href = e.href, this.templated = e.templated, this.type = e.type, this.title = e.title, this.rels = e.rels, this.properties = e.properties, this.height = e.height, this.width = e.width, this.size = e.size, this.duration = e.duration, this.bitrate = e.bitrate, this.languages = e.languages, this.alternates = e.alternates, this.children = e.children;
}
/**
* Parses a [Link] from its RWPM JSON representation.
*/
static deserialize(e) {
if (!(!e || typeof e.href != "string"))
return new H({
href: e.href,
templated: e.templated,
type: e.type,
title: e.title,
rels: e.rel ? Array.isArray(e.rel) ? new Set(e.rel) : /* @__PURE__ */ new Set([e.rel]) : void 0,
properties: C.deserialize(e.properties),
height: S(e.height),
width: S(e.width),
size: S(e.size),
duration: S(e.duration),
bitrate: S(e.bitrate),
languages: Qe(e.language),
alternates: ee.deserialize(e.alternate),
children: ee.deserialize(e.children)
});
}
/**
* Serializes a [Link] to its RWPM JSON representation.
*/
serialize() {
const e = { href: this.href };
return this.templated !== void 0 && (e.templated = this.templated), this.type !== void 0 && (e.type = this.type), this.title !== void 0 && (e.title = this.title), this.rels && (e.rel = gt(this.rels)), this.properties && (e.properties = this.properties.serialize()), this.height !== void 0 && (e.height = this.height), this.width !== void 0 && (e.width = this.width), this.size !== void 0 && (e.size = this.size), this.duration !== void 0 && (e.duration = this.duration), this.bitrate !== void 0 && (e.bitrate = this.bitrate), this.languages && (e.language = this.languages), this.alternates && (e.alternate = this.alternates.serialize()), this.children && (e.children = this.children.serialize()), e;
}
/** MediaType of the linked resource. */
get mediaType() {
return this.type !== void 0 ? l.parse({ mediaType: this.type }) : l.BINARY;
}
/** Computes an absolute URL to the link, relative to the given `baseURL`.
* If the link's `href` is already absolute, the `baseURL` is ignored.
*/
toURL(e) {
const t = this.href.replace(/^(\/)/, "");
if (t.length === 0) return;
let i = e || "/";
return i.startsWith("/") && (i = "file://" + i), new URL(t, i).href.replace(/^(file:\/\/)/, "");
}
/** List of URI template parameter keys, if the `Link` is templated. */
get templateParameters() {
return this.templated ? new Ie(this.href).parameters : /* @__PURE__ */ new Set();
}
/** Expands the `Link`'s HREF by replacing URI template variables by the given parameters.
* See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570
*/
expandTemplate(e) {
return new H({
href: new Ie(this.href).expand(e),
templated: !1
});
}
/**
* Makes a copy of this [Link] after merging in the given additional other [properties].
*/
addProperties(e) {
const t = H.deserialize(this.serialize());
return t.properties = t.properties ? t.properties?.add(e) : new C(e), t;
}
/**
* Creates a [Locator] from a reading order [Link].
*/
get locator() {
let e = this.href.split("#");
return new R({
href: e.length > 0 && e[0] !== void 0 ? e[0] : this.href,
type: this.type ?? "",
title: this.title,
locations: new b({
fragments: e.length > 1 && e[1] !== void 0 ? [e[1]] : []
})
});
}
}
class ee {
/**
* Creates a [Links].
*/
constructor(e) {
this.items = e;
}
/**
* Creates a list of [Link] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e && Array.isArray(e))
return new ee(
e.map((t) => H.deserialize(t)).filter((t) => t !== void 0)
);
}
/**
* Serializes an array of [Link] to its RWPM JSON representation.
*/
serialize() {
return this.items.map((e) => e.serialize());
}
/** Finds the first link with the given relation. */
findWithRel(e) {
const t = (i) => i.rels && i.rels.has(e);
return this.items.find(t);
}
/** Finds all the links with the given relation. */
filterByRel(e) {
const t = (i) => i.rels && i.rels.has(e);
return this.items.filter(t);
}
/** Finds the first link matching the given HREF. */
findWithHref(e) {
const t = (i) => i.href === e;
return this.items.find(t);
}
/** Finds the index of the first link matching the given HREF. */
findIndexWithHref(e) {
const t = (i) => i.href === e;
return this.items.findIndex(t);
}
/** Finds the first link matching the given media type. */
findWithMediaType(e) {
const t = (i) => i.mediaType.matches(e);
return this.items.find(t);
}
/** Finds all the links matching the given media type. */
filterByMediaType(e) {
const t = (i) => i.mediaType.matches(e);
return this.items.filter(t);
}
/** Finds all the links matching any of the given media types. */
filterByMediaTypes(e) {
const t = (i) => {
for (const r of e)
if (i.mediaType.matches(r))
return !0;
return !1;
};
return this.items.filter(t);
}
/** Returns whether all the resources in the collection are audio clips. */
everyIsAudio() {
const e = (t) => t.mediaType.isAudio;
return this.items.length > 0 && this.items.every(e);
}
/** Returns whether all the resources in the collection are bitmaps. */
everyIsBitmap() {
const e = (t) => t.mediaType.isBitmap;
return this.items.length > 0 && this.items.every(e);
}
/** Returns whether all the resources in the collection are HTML documents. */
everyIsHTML() {
const e = (t) => t.mediaType.isHTML;
return this.items.length > 0 && this.items.every(e);
}
/** Returns whether all the resources in the collection are video clips. */
everyIsVideo() {
const e = (t) => t.mediaType.isVideo;
return this.items.length > 0 && this.items.every(e);
}
/** Returns whether all the resources in the collection are matching any of the given media types. */
everyMatchesMediaType(e) {
return Array.isArray(e) ? this.items.length > 0 && this.items.every((t) => {
for (const i of e)
return t.mediaType.matches(i);
return !1;
}) : this.items.length > 0 && this.items.every((t) => t.mediaType.matches(e));
}
filterLinksHasType() {
return this.items.filter((e) => e.type);
}
}
C.prototype.getContains = function() {
return new Set(this.otherProperties.contains || []);
};
class te {
/**
* Creates a [DomRange].
*/
constructor(e) {
this.cssSelector = e.cssSelector, this.textNodeIndex = e.textNodeIndex, this.charOffset = e.charOffset;
}
/**
* Parses a [DomRangePoint] from its RWPM JSON representation.
*/
static deserialize(e) {
if (!(e && e.cssSelector)) return;
let t = S(e.textNodeIndex);
if (t === void 0) return;
let i = S(e.charOffset);
return i === void 0 && (i = S(e.offset)), new te({
cssSelector: e.cssSelector,
textNodeIndex: t,
charOffset: i
});
}
/**
* Serializes a [DomRangePoint] to its RWPM JSON representation.
*/
serialize() {
const e = {
cssSelector: this.cssSelector,
textNodeIndex: this.textNodeIndex
};
return this.charOffset !== void 0 && (e.charOffset = this.charOffset), e;
}
}
class we {
/**
* Creates a [DomRange].
*/
constructor(e) {
this.start = e.start, this.end = e.end;
}
/**
* Parses a [DomRange] from its RWPM JSON representation.
*/
static deserialize(e) {
if (!e) return;
let t = te.deserialize(e.start);
if (t)
return new we({
start: t,
end: te.deserialize(e.end)
});
}
/**
* Serializes a [DomRange] to its RWPM JSON representation.
*/
serialize() {
const e = { start: this.start.serialize() };
return this.end && (e.end = this.end.serialize()), e;
}
}
b.prototype.getCssSelector = function() {
return this.otherLocations?.get("cssSelector");
};
b.prototype.getPartialCfi = function() {
return this.otherLocations?.get("partialCfi");
};
b.prototype.getDomRange = function() {
return we.deserialize(this.otherLocations?.get("domRange"));
};
b.prototype.fragmentParameters = function() {
return new Map(
this.fragments.map((s) => s.startsWith("#") ? s.slice(1) : s).join("&").split("&").filter((s) => !s.startsWith("#")).map((s) => s.split("=")).filter((s) => s.length === 2).map((s) => [
s[0].trim().toLowerCase(),
s[1].trim()
])
);
};
b.prototype.htmlId = function() {
if (!this.fragments.length) return;
let s = this.fragments.find((e) => e.length && !e.includes("="));
if (!s) {
const e = this.fragmentParameters();
e.has("id") ? s = e.get("id") : e.has("name") && (s = e.get("name"));
}
return s?.startsWith("#") ? s.slice(1) : s;
};
b.prototype.page = function() {
const s = parseInt(this.fragmentParameters().get("page"));
if (!isNaN(s) && s >= 0) return s;
};
b.prototype.time = function() {
const s = parseInt(this.fragmentParameters().get("t"));
if (!isNaN(s)) return s;
};
b.prototype.space = function() {
const s = this.fragmentParameters();
if (!s.has("xywh")) return;
const e = s.get("xywh").split(",").map((t) => parseInt(t));
if (e.length === 4 && !e.some(isNaN))
return e;
};
class Se {
/** Creates a [Price]. */
constructor(e) {
this.currency = e.currency, this.value = e.value;
}
/**
* Parses a [Price] from its RWPM JSON representation.
*/
static deserialize(e) {
if (!e) return;
let t = e.currency;
if (!(t && typeof t == "string" && t.length > 0))
return;
let i = S(e.value);
if (i !== void 0)
return new Se({ currency: t, value: i });
}
/**
* Serializes a [Price] to its RWPM JSON representation.
*/
serialize() {
return { currency: this.currency, value: this.value };
}
}
class V {
/** Creates a [Acquisition]. */
constructor(e) {
this.type = e.type, this.children = e.children;
}
/**
* Parses a [Acquisition] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e && e.type)
return new V({
type: e.type,
children: V.deserializeArray(e.children)
});
}
static deserializeArray(e) {
if (Array.isArray(e))
return e.map((t) => V.deserialize(t)).filter((t) => t !== void 0);
}
/**
* Serializes a [Acquisition] to its RWPM JSON representation.
*/
serialize() {
const e = { type: this.type };
return this.children && (e.children = this.children.map((t) => t.serialize())), e;
}
}
class Ce {
/** Creates a [Price]. */
constructor(e) {
this.total = e.total, this.position = e.position;
}
/**
* Parses a [Holds] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e)
return new Ce({
total: S(e.total),
position: S(e.position)
});
}
/**
* Serializes a [Holds] to its RWPM JSON representation.
*/
serialize() {
const e = {};
return this.total !== void 0 && (e.total = this.total), this.position !== void 0 && (e.position = this.position), e;
}
}
class Pe {
/** Creates a [Copies]. */
constructor(e) {
this.total = e.total, this.available = e.available;
}
/**
* Parses a [Copies] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e)
return new Pe({
total: S(e.total),
available: S(e.available)
});
}
/**
* Serializes a [Copies] to its RWPM JSON representation.
*/
serialize() {
const e = {};
return this.total !== void 0 && (e.total = this.total), this.available !== void 0 && (e.available = this.available), e;
}
}
class Ae {
/** Creates a [Availability]. */
constructor(e) {
this.state = e.state, this.since = e.since, this.until = e.until;
}
/**
* Parses a [Availability] from its RWPM JSON representation.
*/
static deserialize(e) {
if (e && e.state)
return new Ae({
state: e.state,
since: Re(e.since),
until: Re(e.until)
});
}
/**
* Serializes a [Availability] to its RWPM JSON representation.
*/
serialize() {
const e = { state: this.state };
return this.since !== void 0 && (e.since = this.since.toISOString()), this.until !== void 0 && (e.until = this.until.toISOString()), e;
}
}
C.prototype.getNumberOfItems = function() {
return S(this.otherProperties.numberOfItems);
};
C.prototype.getPrice = function() {
return Se.deserialize(this.otherProperties.price);
};
C.prototype.getIndirectAcquisitions = function() {
const s = this.otherProperties.indirectAcquisition;
if (s && Array.isArray(s))
return s.map((e) => V.deserialize(e)).filter((e) => e !== void 0);
};
C.prototype.getHolds = function() {
return Ce.deserialize(this.otherProperties.holds);
};
C.prototype.getCopies = function() {
return Pe.deserialize(this.otherProperties.copies);
};
C.prototype.getAvailability = function() {
return Ae.deserialize(this.otherProperties.availability);
};
C.prototype.getAuthenticate = function() {
return H.deserialize(this.otherProperties.authenticate);
};
const yt = "CssSelectorGenerator";
function ze(s = "unknown problem", ...e) {
console.warn(`${yt}: ${s}`, ...e);
}
function vt(s) {
return s instanceof RegExp;
}
function bt(s) {
return s.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".+");
}
function Et(s) {
const e = s.map((t) => {
if (vt(t))
return (i) => t.test(i);
if (typeof t == "function")
return (i) => {
const r = t(i);
return typeof r != "boolean" ? (ze("pattern matcher function invalid", "Provided pattern matching function does not return boolean. It's result will be ignored.", t), !1) : r;
};
if (typeof t == "string") {
const i = new RegExp("^" + bt(t) + "$");
return (r) => i.test(r);
}
return ze("pattern matcher invalid", "Pattern matching only accepts strings, regular expressions and/or functions. This item is invalid and will be ignored.", t), () => !1;
});
return (t) => e.some((i) => i(t));
}
Et([
"class",
"id",
// Angular attributes
"ng-*"
]);
class Y {
}
function De(s) {
return s.split("").reverse().join("");
}
function xt(s, e, t) {
const i = De(e);
return t.map((r) => {
const n = Math.max(0, r.end - e.length - r.errors), o = De(s.slice(n, r.end));
return {
start: et(o, i, r.errors).reduce((u, h) => r.end - h.end < u ? r.end - h.end : u, r.end),
end: r.end,
errors: r.errors
};
});
}
function ae(s) {
return (s | -s) >> 31 & 1;
}
function We(s, e, t, i) {
let r = s.P[t], n = s.M[t];
const o = i >>> 31, a = e[t] | o, u = a | n, h = (a & r) + r ^ r | a;
let c = n | ~(h | r), m = r & h;
const d = ae(c & s.lastRowMask[t]) - ae(m & s.lastRowMask[t]);
return c <<= 1, m <<= 1, m |= o, c |= ae(i) - o, r = m | ~(u | c), n = c & u, s.P[t] = r, s.M[t] = n, d;
}
function et(s, e, t) {
if (e.length === 0)
return [];
t = Math.min(t, e.length);
const i = [], r = 32, n = Math.ceil(e.length / r) - 1, o = {
P: new Uint32Array(n + 1),
M: new Uint32Array(n + 1),
lastRowMask: new Uint32Array(n + 1)
};
o.lastRowMask.fill(1 << 31), o.lastRowMask[n] = 1 << (e.length - 1) % r;
const a = new Uint32Array(n + 1), u = /* @__PURE__ */ new Map(), h = [];
for (let d = 0; d < 256; d++)
h.push(a);
for (let d = 0; d < e.length; d += 1) {
const y = e.charCodeAt(d);
if (u.has(y))
continue;
const p = new Uint32Array(n + 1);
u.set(y, p), y < h.length && (h[y] = p);
for (let f = 0; f <= n; f += 1) {
p[f] = 0;
for (let g = 0; g < r; g += 1) {
const E = f * r + g;
if (E >= e.length)
continue;
e.charCodeAt(E) === y && (p[f] |= 1 << g);
}
}
}
let c = Math.max(0, Math.ceil(t / r) - 1);
const m = new Uint32Array(n + 1);
for (let d = 0; d <= c; d += 1)
m[d] = (d + 1) * r;
m[n] = e.length;
for (let d = 0; d <= c; d += 1)
o.P[d] = -1, o.M[d] = 0;
for (let d = 0; d < s.length; d += 1) {
const y = s.charCodeAt(d);
let p;
y < h.length ? p = h[y] : (p = u.get(y), typeof p > "u" && (p = a));
let f = 0;
for (let g = 0; g <= c; g += 1)
f = We(o, p, g, f), m[g] += f;
if (m[c] - f <= t && c < n && (p[c + 1] & 1 || f < 0)) {
c += 1, o.P[c] = -1, o.M[c] = 0;
let g;
if (c === n) {
const E = e.length % r;
g = E === 0 ? r : E;
} else
g = r;
m[c] = m[c - 1] + g - f + We(o, p, c, f);
} else
for (; c > 0 && m[c] >= t + r; )
c -= 1;
c === n && m[c] <= t && (m[c] < t && i.splice(0, i.length), i.push({
start: -1,
end: d + 1,
errors: m[c]
}), t = m[c]);
}
return i;
}
function Tt(s, e, t) {
const i = et(s, e, t);
return xt(s, e, i);
}
function tt(s, e, t) {
let i = 0;
const r = [];
for (; i !== -1; )
i = s.indexOf(e, i), i !== -1 && (r.push({
start: i,
end: i + e.length,
errors: 0
}), i += 1);
return r.length > 0 ? r : Tt(s, e, t);
}
function Fe(s, e) {
return e.length === 0 || s.length === 0 ? 0 : 1 - tt(s, e, e.length)[0].errors / e.length;
}
function wt(s, e, t = {}) {
if (e.length === 0)
return null;
const i = Math.min(256, e.length / 2), r = tt(s, e, i);
if (r.length === 0)
return null;
const n = (a) => {
const d = 1 - a.errors / e.length, y = t.prefix ? Fe(
s.slice(
Math.max(0, a.start - t.prefix.length),
a.start
),
t.prefix
) : 1, p = t.suffix ? Fe(
s.slice(a.end, a.end + t.suffix.length),
t.suffix
) : 1;
let f = 1;
return typeof t.hint == "number" && (f = 1 - Math.abs(a.start - t.hint) / s.length), (50 * d + 20 * y + 20 * p + 2 * f) / 92;
}, o = r.map((a) => ({
start: a.start,
end: a.end,
score: n(a)
}));
return o.sort((a, u) => u.score - a.score), o[0];
}
function ue(s, e, t) {
const i = t === 1 ? e : e - 1;
if (s.charAt(i).trim() !== "")
return e;
let r, n;
if (t === 2 ? (r = s.substring(0, e), n = r.trimEnd()) : (r = s.substring(e), n = r.trimStart()), !n.length)
return -1;
const o = r.length - n.length;
return t === 2 ? e - o : e + o;
}
function Ue(s, e) {
const t = s.commonAncestorContainer.ownerDocument.createNodeIterator(
s.commonAncestorContainer,
NodeFilter.SHOW_TEXT
), i = e === 1 ? s.startContainer : s.endContainer, r = e === 1 ? s.endContainer : s.startContainer;
let n = t.nextNode();
for (; n && n !== i; )
n = t.nextNode();
e === 2 && (n = t.previousNode());
let o = -1;
const a = () => {
if (n = e === 1 ? t.nextNode() : t.previousNode(), n) {
const u = n.textContent, h = e === 1 ? 0 : u.length;
o = ue(u, h, e);
}
};
for (; n && o === -1 && n !== r; )
a();
if (n && o >= 0)
return { node: n, offset: o };
throw new RangeError("No text nodes with non-whitespace text found in range");
}
function St(s) {
if (!s.toString().trim().length)
throw new RangeError("Range contains no non-whitespace text");
if (s.startContainer.nodeType !== Node.TEXT_NODE)
throw new RangeError("Range startContainer is not a text node");
if (s.endContainer.nodeType !== Node.TEXT_NODE)
throw new RangeError("Range endContainer is not a text node");
const e = s.cloneRange();
let t = !1, i = !1;
const r = {
start: ue(
s.startContainer.textContent,
s.startOffset,
1
/* Forwards */
),
end: ue(
s.endContainer.textContent,
s.endOffset,
2
/* Backwards */
)
};
if (r.start >= 0 && (e.setStart(s.startContainer, r.start), t = !0), r.end > 0 && (e.setEnd(s.endContainer, r.end), i = !0), t && i)
return e;
if (!t) {
const { node: n, offset: o } = Ue(
e,
1
/* Forwards */
);
n && o >= 0 && e.setStart(n, o);
}
if (!i) {
const { node: n, offset: o } = Ue(
e,
2
/* Backwards */
);
n && o > 0 && e.setEnd(n, o);
}
return e;
}
function it(s) {
switch (s.nodeType) {
case Node.ELEMENT_NODE:
case Node.TEXT_NODE:
return s.textContent?.length ?? 0;
default:
return 0;
}
}
function Be(s) {
let e = s.previousSibling, t = 0;
for (; e; )
t += it(e), e = e.previousSibling;
return t;
}
function rt(s, ...e) {
let t = e.shift();
const i = s.ownerDocument.createNodeIterator(
s,
NodeFilter.SHOW_TEXT
), r = [];
let n = i.nextNode(), o, a = 0;
for (; t !== void 0 && n; )
o = n, a + o.data.length > t ? (r.push({ node: o, offset: t - a }), t = e.shift()) : (n = i.nextNode(), a += o.data.length);
for (; t !== void 0 && o && a === t; )
r.push({ node: o, offset: o.data.length }), t = e.shift();
if (t !== void 0)
throw new RangeError("Offset exceeds text length");
return r;
}
class M {
constructor(e, t) {
if (t < 0)
throw new Error("Offset is invalid");
this.element = e, this.offset = t;
}
/**
* Return a copy of this position with offset relative to a given ancestor
* element.
*
* @param parent - Ancestor of `this.element`
*/
relativeTo(e) {
if (!e.contains(this.element))
throw new Error("Parent is not an ancestor of current element");
let t = this.element, i = this.offset;
for (; t !== e; )
i += Be(t), t = t.parentElement;
return new M(t, i);
}
/**
* Resolve the position to a specific text node and offset within that node.
*
* Throws if `this.offset` exceeds the length of the element's text. In the
* case where the element has no text and `this.offset` is 0, the `direction`
* option determines what happens.
*
* Offsets at the boundary between two nodes are resolved to the start of the
* node that begins at the boundary.
*
* @param options.direction - Specifies in which direction to search for the
* nearest text node if `this.offset` is `0` and
* `this.element` has no text. If not specified an
* error is thrown.
*
* @throws {RangeError}
*/
resolve(e = {}) {
try {
return rt(this.element, this.offset)[0];
} catch (t) {
if (this.offset === 0 && e.direction !== void 0) {
const i = document.createTreeWalker(
this.element.getRootNode(),
NodeFilter.SHOW_TEXT
);
i.currentNode = this.element;
const r = e.direction === 1, n = r ? i.nextNode() : i.previousNode();
if (!n)
throw t;
return { node: n, offset: r ? 0 : n.data.length };
} else
throw t;
}
}
/**
* Construct a `TextPosition` that refers to the `offset`th character within
* `node`.
*/
static fromCharOffset(e, t) {
switch (e.nodeType) {
case Node.TEXT_NODE:
return M.fromPoint(e, t);
case Node.ELEMENT_NODE:
return new M(e, t);
default:
throw new Error("Node is not an element or text node");
}
}
/**
* Construct a `TextPosition` representing the range start or end point (node, offset).
*
* @param node
* @param offset - Offset within the node
*/
static fromPoint(e, t) {
switch (e.nodeType) {
case Node.TEXT_NODE: {
if (t < 0 || t > e.data.length)
throw new Error("Text node offset is out of range");
if (!e.parentElement)
throw new Error("Text node has no parent");
const i = Be(e) + t;
return new M(e.parentElement, i);
}
case Node.ELEMENT_NODE: {
if (t < 0 || t > e.childNodes.length)
throw new Error("Child node offset is out of range");
let i = 0;
for (let r = 0; r < t; r++)
i += it(e.childNodes[r]);
return new M(e, i);
}
default:
throw new Error("Point is not in an element or text node");
}
}
}
class I {
constructor(e, t) {
this.start = e, this.end = t;
}
/**
* Create a new TextRange whose `start` and `end` are computed relative to
* `element`. `element` must be an ancestor of both `start.element` and
* `end.element`.
*/
relativeTo(e) {
return new I(
this.start.relativeTo(e),
this.end.relativeTo(e)
);
}
/**
* Resolve this TextRange to a (DOM) Range.
*
* The resulting DOM Range will always start and end in a `Text` node.
* Hence `TextRange.fromRange(range).toRange()` can be used to "shrink" a
* range to the text it contains.
*
* May throw if the `start` or `end` positions cannot be resolved to a range.
*/
toRange() {
let e, t;
this.start.element === this.end.element && this.start.offset <= this.end.offset ? [e, t] = rt(
this.start.element,
this.start.offset,
this.end.offset
) : (e = this.start.resolve({
direction: 1
/* FORWARDS */
}), t = this.end.resolve({
direction: 2
/* BACKWARDS */
}));
const i = new Range();
return i.setStart(e.node, e.offset), i.setEnd(t.node, t.offset), i;
}
/**
* Create a TextRange from a (DOM) Range
*/
static fromRange(e) {
const t = M.fromPoint(
e.startContainer,
e.startOffset
), i = M.fromPoint(e.endContainer, e.endOffset);
return new I(t, i);
}
/**
* Create a TextRange representing the `start`th to `end`th characters in
* `root`
*/
static fromOffsets(e, t, i) {
return new I(
new M(e, t),
new M(e, i)
);
}
/**
* Return a new Range representing `range` trimmed of any leading or trailing
* whitespace
*/
static trimmedRange(e) {
return St(I.fromRange(e).toRange());
}
}
class ie {
constructor(e, t, i) {
this.root = e, this.start = t, this.end = i;
}
static fromRange(e, t) {
const i = I.fromRange(t).relativeTo(e);
return new ie(
e,
i.start.offset,
i.end.offset
);
}
static fromSelector(e, t) {
return new ie(e, t.start, t.end);
}
to