UNPKG

@readium/navigator-html-injectables

Version:

An embeddable solution for connecting frames of HTML publications with a Readium Navigator

1,680 lines 102 kB
const nt = Math.pow(2, 32), ge = () => Math.round(Math.random() * nt).toString(36), ot = () => `${Math.round(performance.now())}-${ge()}-${ge()}`, k = 1; class at { 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((l) => l.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 ?? ot(), // 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); } } } class ie { /** * 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 ie({ 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 w { 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 w(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 w(t); } } Object.defineProperty(w.prototype, "encryption", { get: function() { return ie.deserialize(this.otherProperties.encrypted); } }); function lt(s) { return s && s instanceof Array ? s : void 0; } function We(s) { return s && typeof s == "string" ? [s] : lt(s); } function ye(s) { return typeof s == "string" ? new Date(s) : void 0; } function j(s) { return isNaN(s) ? void 0 : s; } function T(s) { return j(s) !== void 0 && Math.sign(s) >= 0 ? s : void 0; } function ht(s) { const e = new Array(); return s.forEach((t) => e.push(t)), e; } class a { /** 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 f = r[d].split("="); if (f.length === 2) { const g = f[0].toLocaleLowerCase(), m = g === "charset" ? f[1].toUpperCase() : f[1]; o[g] = m; } } const l = {}, c = Object.keys(o); c.sort((d, f) => d.localeCompare(f)), c.forEach((d) => l[d] = o[d]); let h = ""; for (const d in l) { const f = l[d]; h += `;${d}=${f}`; } const u = `${t}/${i}${h}`, p = l.encoding; this.string = u, this.type = t, this.subtype = i, this.parameters = l, this.encoding = p, this.name = e.name, this.fileExtension = e.fileExtension; } static parse(e) { return new a(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" ? a.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" ? a.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( a.ZIP, a.LCP_PROTECTED_AUDIOBOOK, a.LCP_PROTECTED_PDF ) || this.structuredSyntaxSuffix === "+zip"; } /** Returns whether this media type is structured as a JSON file. */ get isJSON() { return this.matchesAny(a.JSON) || this.structuredSyntaxSuffix === "+json"; } /** Returns whether this media type is of an OPDS feed. */ get isOPDS() { return this.matchesAny( a.OPDS1, a.OPDS1_ENTRY, a.OPDS2, a.OPDS2_PUBLICATION, a.OPDS_AUTHENTICATION ) || this.structuredSyntaxSuffix === "+json"; } /** Returns whether this media type is of an HTML document. */ get isHTML() { return this.matchesAny(a.HTML, a.XHTML); } /** Returns whether this media type is of a bitmap image, so excluding vectorial formats. */ get isBitmap() { return this.matchesAny( a.BMP, a.GIF, a.JPEG, a.PNG, a.TIFF, a.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( a.READIUM_AUDIOBOOK_MANIFEST, a.DIVINA_MANIFEST, a.READIUM_WEBPUB_MANIFEST ); } /** Returns whether this media type is of a publication file. */ get isPublication() { return this.matchesAny( a.READIUM_AUDIOBOOK, a.READIUM_AUDIOBOOK_MANIFEST, a.CBZ, a.DIVINA, a.DIVINA_MANIFEST, a.EPUB, a.LCP_PROTECTED_AUDIOBOOK, a.LCP_PROTECTED_PDF, a.LPF, a.PDF, a.W3C_WPUB_MANIFEST, a.READIUM_WEBPUB, a.READIUM_WEBPUB_MANIFEST, a.ZAB ); } // Known Media Types static get AAC() { return a.parse({ mediaType: "audio/aac", fileExtension: "aac" }); } static get ACSM() { return a.parse({ mediaType: "application/vnd.adobe.adept+xml", name: "Adobe Content Server Message", fileExtension: "acsm" }); } static get AIFF() { return a.parse({ mediaType: "audio/aiff", fileExtension: "aiff" }); } static get AVI() { return a.parse({ mediaType: "video/x-msvideo", fileExtension: "avi" }); } static get BINARY() { return a.parse({ mediaType: "application/octet-stream" }); } static get BMP() { return a.parse({ mediaType: "image/bmp", fileExtension: "bmp" }); } static get CBZ() { return a.parse({ mediaType: "application/vnd.comicbook+zip", name: "Comic Book Archive", fileExtension: "cbz" }); } static get CSS() { return a.parse({ mediaType: "text/css", fileExtension: "css" }); } static get DIVINA() { return a.parse({ mediaType: "application/divina+zip", name: "Digital Visual Narratives", fileExtension: "divina" }); } static get DIVINA_MANIFEST() { return a.parse({ mediaType: "application/divina+json", name: "Digital Visual Narratives", fileExtension: "json" }); } static get EPUB() { return a.parse({ mediaType: "application/epub+zip", name: "EPUB", fileExtension: "epub" }); } static get GIF() { return a.parse({ mediaType: "image/gif", fileExtension: "gif" }); } static get GZ() { return a.parse({ mediaType: "application/gzip", fileExtension: "gz" }); } static get HTML() { return a.parse({ mediaType: "text/html", fileExtension: "html" }); } static get JAVASCRIPT() { return a.parse({ mediaType: "text/javascript", fileExtension: "js" }); } static get JPEG() { return a.parse({ mediaType: "image/jpeg", fileExtension: "jpeg" }); } static get JSON() { return a.parse({ mediaType: "application/json" }); } static get LCP_LICENSE_DOCUMENT() { return a.parse({ mediaType: "application/vnd.readium.lcp.license.v1.0+json", name: "LCP License", fileExtension: "lcpl" }); } static get LCP_PROTECTED_AUDIOBOOK() { return a.parse({ mediaType: "application/audiobook+lcp", name: "LCP Protected Audiobook", fileExtension: "lcpa" }); } static get LCP_PROTECTED_PDF() { return a.parse({ mediaType: "application/pdf+lcp", name: "LCP Protected PDF", fileExtension: "lcpdf" }); } static get LCP_STATUS_DOCUMENT() { return a.parse({ mediaType: "application/vnd.readium.license.status.v1.0+json" }); } static get LPF() { return a.parse({ mediaType: "application/lpf+zip", fileExtension: "lpf" }); } static get MP3() { return a.parse({ mediaType: "audio/mpeg", fileExtension: "mp3" }); } static get MPEG() { return a.parse({ mediaType: "video/mpeg", fileExtension: "mpeg" }); } static get NCX() { return a.parse({ mediaType: "application/x-dtbncx+xml", fileExtension: "ncx" }); } static get OGG() { return a.parse({ mediaType: "audio/ogg", fileExtension: "oga" }); } static get OGV() { return a.parse({ mediaType: "video/ogg", fileExtension: "ogv" }); } static get OPDS1() { return a.parse({ mediaType: "application/atom+xml;profile=opds-catalog" }); } static get OPDS1_ENTRY() { return a.parse({ mediaType: "application/atom+xml;type=entry;profile=opds-catalog" }); } static get OPDS2() { return a.parse({ mediaType: "application/opds+json" }); } static get OPDS2_PUBLICATION() { return a.parse({ mediaType: "application/opds-publication+json" }); } static get OPDS_AUTHENTICATION() { return a.parse({ mediaType: "application/opds-authentication+json" }); } static get OPUS() { return a.parse({ mediaType: "audio/opus", fileExtension: "opus" }); } static get OTF() { return a.parse({ mediaType: "font/otf", fileExtension: "otf" }); } static get PDF() { return a.parse({ mediaType: "application/pdf", name: "PDF", fileExtension: "pdf" }); } static get PNG() { return a.parse({ mediaType: "image/png", fileExtension: "png" }); } static get READIUM_AUDIOBOOK() { return a.parse({ mediaType: "application/audiobook+zip", name: "Readium Audiobook", fileExtension: "audiobook" }); } static get READIUM_AUDIOBOOK_MANIFEST() { return a.parse({ mediaType: "application/audiobook+json", name: "Readium Audiobook", fileExtension: "json" }); } static get READIUM_CONTENT_DOCUMENT() { return a.parse({ mediaType: "application/vnd.readium.content+json", name: "Readium Content Document", fileExtension: "json" }); } static get READIUM_GUIDED_NAVIGATION_DOCUMENT() { return a.parse({ mediaType: "application/guided-navigation+json", name: "Readium Guided Navigation Document", fileExtension: "json" }); } static get READIUM_POSITION_LIST() { return a.parse({ mediaType: "application/vnd.readium.position-list+json", name: "Readium Position List", fileExtension: "json" }); } static get READIUM_WEBPUB() { return a.parse({ mediaType: "application/webpub+zip", name: "Readium Web Publication", fileExtension: "webpub" }); } static get READIUM_WEBPUB_MANIFEST() { return a.parse({ mediaType: "application/webpub+json", name: "Readium Web Publication", fileExtension: "json" }); } static get SMIL() { return a.parse({ mediaType: "application/smil+xml", fileExtension: "smil" }); } static get SVG() { return a.parse({ mediaType: "image/svg+xml", fileExtension: "svg" }); } static get TEXT() { return a.parse({ mediaType: "text/plain", fileExtension: "txt" }); } static get TIFF() { return a.parse({ mediaType: "image/tiff", fileExtension: "tiff" }); } static get TTF() { return a.parse({ mediaType: "font/ttf", fileExtension: "ttf" }); } static get W3C_WPUB_MANIFEST() { return a.parse({ mediaType: "application/x.readium.w3c.wpub+json", name: "Web Publication", fileExtension: "json" }); } static get WAV() { return a.parse({ mediaType: "audio/wav", fileExtension: "wav" }); } static get WEBM_AUDIO() { return a.parse({ mediaType: "audio/webm", fileExtension: "webm" }); } static get WEBM_VIDEO() { return a.parse({ mediaType: "video/webm", fileExtension: "webm" }); } static get WEBP() { return a.parse({ mediaType: "image/webp", fileExtension: "webp" }); } static get WOFF() { return a.parse({ mediaType: "font/woff", fileExtension: "woff" }); } static get WOFF2() { return a.parse({ mediaType: "font/woff2", fileExtension: "woff2" }); } static get XHTML() { return a.parse({ mediaType: "application/xhtml+xml", fileExtension: "xhtml" }); } static get XML() { return a.parse({ mediaType: "application/xml", fileExtension: "xml" }); } static get ZAB() { return a.parse({ mediaType: "application/x.readium.zab+zip", name: "Zipped Audio Book", fileExtension: "zab" }); } static get ZIP() { return a.parse({ mediaType: "application/zip", fileExtension: "zip" }); } } class ve { 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], l = e[o]; return l ? `${o}=${encodeURIComponent(l)}` : ""; }).join("&"); return this.uri.replace(/\{(\??)([^}]+)\}/g, (...r) => r[1] ? i(r[2]) : t(r[2])); } } class E { /** * 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 = j(e.progression), i = j(e.totalProgression), r = j(e.position), n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set([ "fragment", "fragments", "progression", "totalProgression", "position" ]); return Object.entries(e).forEach(([l, c]) => { o.has(l) || n.set(l, c); }), new E({ fragments: We(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 U { /** * 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 U({ 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 D { /** * Creates a [Locator]. */ constructor(e) { this.href = e.href, this.type = e.type, this.title = e.title, this.locations = e.locations ? e.locations : new E({}), this.text = e.text; } /** * Parses a [Link] from its RWPM JSON representation. */ static deserialize(e) { if (e && e.href && e.type) return new D({ href: e.href, type: e.type, title: e.title, locations: E.deserialize(e.locations), text: U.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 D({ href: this.href, type: this.type, title: this.title, text: this.text, locations: new E({ ...this.locations, ...e }) }); } } class B { /** * 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 B({ href: e.href, templated: e.templated, type: e.type, title: e.title, rels: e.rel ? e.rel instanceof Array ? new Set(e.rel) : /* @__PURE__ */ new Set([e.rel]) : void 0, properties: w.deserialize(e.properties), height: T(e.height), width: T(e.width), size: T(e.size), duration: T(e.duration), bitrate: T(e.bitrate), languages: We(e.language), alternates: V.deserialize(e.alternate), children: V.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 = ht(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 ? a.parse({ mediaType: this.type }) : a.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 ve(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 B({ href: new ve(this.href).expand(e), templated: !1 }); } /** * Makes a copy of this [Link] after merging in the given additional other [properties]. */ addProperties(e) { var t; const i = B.deserialize(this.serialize()); return i.properties = i.properties ? (t = i.properties) == null ? void 0 : t.add(e) : new w(e), i; } /** * Creates a [Locator] from a reading order [Link]. */ get locator() { let e = this.href.split("#"); return new D({ href: e.length > 0 && e[0] !== void 0 ? e[0] : this.href, type: this.type ?? "", title: this.title, locations: new E({ fragments: e.length > 1 && e[1] !== void 0 ? [e[1]] : [] }) }); } } class V { /** * Creates a [Links]. */ constructor(e) { this.items = e; } /** * Creates a list of [Link] from its RWPM JSON representation. */ static deserialize(e) { if (e && e instanceof Array) return new V( e.map((t) => B.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); } } w.prototype.getContains = function() { return new Set(this.otherProperties.contains || []); }; class q { /** * 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 = T(e.textNodeIndex); if (t === void 0) return; let i = T(e.charOffset); return i === void 0 && (i = T(e.offset)), new q({ 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 se { /** * 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 = q.deserialize(e.start); if (t) return new se({ start: t, end: q.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; } } E.prototype.getCssSelector = function() { var s; return (s = this.otherLocations) == null ? void 0 : s.get("cssSelector"); }; E.prototype.getPartialCfi = function() { var s; return (s = this.otherLocations) == null ? void 0 : s.get("partialCfi"); }; E.prototype.getDomRange = function() { var s; return se.deserialize((s = this.otherLocations) == null ? void 0 : s.get("domRange")); }; E.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() ]) ); }; E.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 != null && s.startsWith("#") ? s.slice(1) : s; }; E.prototype.page = function() { const s = parseInt(this.fragmentParameters().get("page")); if (!isNaN(s) && s >= 0) return s; }; E.prototype.time = function() { const s = parseInt(this.fragmentParameters().get("t")); if (!isNaN(s)) return s; }; E.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 re { /** 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 = T(e.value); if (i !== void 0) return new re({ currency: t, value: i }); } /** * Serializes a [Price] to its RWPM JSON representation. */ serialize() { return { currency: this.currency, value: this.value }; } } class $ { /** 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 $({ type: e.type, children: $.deserializeArray(e.children) }); } static deserializeArray(e) { if (e instanceof Array) return e.map((t) => $.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 ne { /** 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 ne({ total: T(e.total), position: T(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 oe { /** 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 oe({ total: T(e.total), available: T(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: ye(e.since), until: ye(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; } } w.prototype.getNumberOfItems = function() { return T(this.otherProperties.numberOfItems); }; w.prototype.getPrice = function() { return re.deserialize(this.otherProperties.price); }; w.prototype.getIndirectAcquisitions = function() { const s = this.otherProperties.indirectAcquisition; if (s && s instanceof Array) return s.map((e) => $.deserialize(e)).filter((e) => e !== void 0); }; w.prototype.getHolds = function() { return ne.deserialize(this.otherProperties.holds); }; w.prototype.getCopies = function() { return oe.deserialize(this.otherProperties.copies); }; w.prototype.getAvailability = function() { return ae.deserialize(this.otherProperties.availability); }; w.prototype.getAuthenticate = function() { return B.deserialize(this.otherProperties.authenticate); }; var R; (function(s) { s.NONE = "none", s.DESCENDANT = "descendant", s.CHILD = "child"; })(R || (R = {})); var N; (function(s) { s.id = "id", s.class = "class", s.tag = "tag", s.attribute = "attribute", s.nthchild = "nthchild", s.nthoftype = "nthoftype"; })(N || (N = {})); const ct = "CssSelectorGenerator"; function be(s = "unknown problem", ...e) { console.warn(`${ct}: ${s}`, ...e); } N.id, N.class, N.tag, N.attribute, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY; function ut(s) { return s instanceof RegExp; } function dt(s) { return s.replace(/[|\\{}()[\]^$+?.]/g, "\\$&").replace(/\*/g, ".+"); } function pt(s) { const e = s.map((t) => { if (ut(t)) return (i) => t.test(i); if (typeof t == "function") return (i) => { const r = t(i); return typeof r != "boolean" ? (be("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("^" + dt(t) + "$"); return (r) => i.test(r); } return be("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)); } const ft = "", mt = " > ", gt = " "; R.NONE + "", R.NONE, R.DESCENDANT + "", R.DESCENDANT, R.CHILD + "", R.CHILD; N.nthoftype, N.tag, N.id, N.class, N.attribute, N.nthchild; pt([ "class", "id", // Angular attributes "ng-*" ]); class Y { } function Ee(s) { return s.split("").reverse().join(""); } function yt(s, e, t) { const i = Ee(e); return t.map((r) => { const n = Math.max(0, r.end - e.length - r.errors), o = Ee(s.slice(n, r.end)); return { start: Fe(o, i, r.errors).reduce((c, h) => r.end - h.end < c ? r.end - h.end : c, r.end), end: r.end, errors: r.errors }; }); } function Z(s) { return (s | -s) >> 31 & 1; } function xe(s, e, t, i) { let r = s.P[t], n = s.M[t]; const o = i >>> 31, l = e[t] | o, c = l | n, h = (l & r) + r ^ r | l; let u = n | ~(h | r), p = r & h; const d = Z(u & s.lastRowMask[t]) - Z(p & s.lastRowMask[t]); return u <<= 1, p <<= 1, p |= o, u |= Z(i) - o, r = p | ~(c | u), n = u & c, s.P[t] = r, s.M[t] = n, d; } function Fe(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 l = new Uint32Array(n + 1), c = /* @__PURE__ */ new Map(), h = []; for (let d = 0; d < 256; d++) h.push(l); for (let d = 0; d < e.length; d += 1) { const f = e.charCodeAt(d); if (c.has(f)) continue; const g = new Uint32Array(n + 1); c.set(f, g), f < h.length && (h[f] = g); for (let m = 0; m <= n; m += 1) { g[m] = 0; for (let v = 0; v < r; v += 1) { const x = m * r + v; if (x >= e.length) continue; e.charCodeAt(x) === f && (g[m] |= 1 << v); } } } let u = Math.max(0, Math.ceil(t / r) - 1); const p = new Uint32Array(n + 1); for (let d = 0; d <= u; d += 1) p[d] = (d + 1) * r; p[n] = e.length; for (let d = 0; d <= u; d += 1) o.P[d] = -1, o.M[d] = 0; for (let d = 0; d < s.length; d += 1) { const f = s.charCodeAt(d); let g; f < h.length ? g = h[f] : (g = c.get(f), typeof g > "u" && (g = l)); let m = 0; for (let v = 0; v <= u; v += 1) m = xe(o, g, v, m), p[v] += m; if (p[u] - m <= t && u < n && (g[u + 1] & 1 || m < 0)) { u += 1, o.P[u] = -1, o.M[u] = 0; let v; if (u === n) { const x = e.length % r; v = x === 0 ? r : x; } else v = r; p[u] = p[u - 1] + v - m + xe(o, g, u, m); } else for (; u > 0 && p[u] >= t + r; ) u -= 1; u === n && p[u] <= t && (p[u] < t && i.splice(0, i.length), i.push({ start: -1, end: d + 1, errors: p[u] }), t = p[u]); } return i; } function vt(s, e, t) { const i = Fe(s, e, t); return yt(s, e, i); } function Be(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 : vt(s, e, t); } function Se(s, e) { return e.length === 0 || s.length === 0 ? 0 : 1 - Be(s, e, e.length)[0].errors / e.length; } function bt(s, e, t = {}) { if (e.length === 0) return null; const i = Math.min(256, e.length / 2), r = Be(s, e, i); if (r.length === 0) return null; const n = (l) => { const d = 1 - l.errors / e.length, f = t.prefix ? Se( s.slice( Math.max(0, l.start - t.prefix.length), l.start ), t.prefix ) : 1, g = t.suffix ? Se( s.slice(l.end, l.end + t.suffix.length), t.suffix ) : 1; let m = 1; typeof t.hint == "number" && (m = 1 - Math.abs(l.start - t.hint) / s.length); const v = 50 * d + 20 * f + 20 * g + 2 * m, x = 50 + 20 + 20 + 2; return v / x; }, o = r.map((l) => ({ start: l.start, end: l.end, score: n(l) })); return o.sort((l, c) => c.score - l.score), o[0]; } function J(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 Te(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 l = () => { if (n = e === 1 ? t.nextNode() : t.previousNode(), n) { const c = n.textContent, h = e === 1 ? 0 : c.length; o = J(c, h, e); } }; for (; n && o === -1 && n !== r; ) l(); if (n && o >= 0) return { node: n, offset: o }; throw new RangeError("No text nodes with non-whitespace text found in range"); } function Et(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: J( s.startContainer.textContent, s.startOffset, 1 /* Forwards */ ), end: J( 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 } = Te( e, 1 /* Forwards */ ); n && o >= 0 && e.setStart(n, o); } if (!i) { const { node: n, offset: o } = Te( e, 2 /* Backwards */ ); n && o > 0 && e.setEnd(n, o); } return e; } function Ue(s) { var e; switch (s.nodeType) { case Node.ELEMENT_NODE: case Node.TEXT_NODE: return ((e = s.textContent) == null ? void 0 : e.length) ?? 0; default: return 0; } } function we(s) { let e = s.previousSibling, t = 0; for (; e; ) t += Ue(e), e = e.previousSibling; return t; } function ke(s, ...e) { let t = e.shift(); const i = s.ownerDocument.createNodeIterator( s, NodeFilter.SHOW_TEXT ), r = []; let n = i.nextNode(), o, l = 0; for (; t !== void 0 && n; ) o = n, l + o.data.length > t ? (r.push({ node: o, offset: t - l }), t = e.shift()) : (n = i.nextNode(), l += o.data.length); for (; t !== void 0 && o && l === 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 A { 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 += we(t), t = t.parentElement; return new A(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 ke(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 A.fromPoint(e, t); case Node.ELEMENT_NODE: return new A(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 = we(e) + t; return new A(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 += Ue(e.childNodes[r]); return new A(e, i); } default: throw new Error("Point is not in an element or text node"); } } } class z { 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 z( 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] = ke( 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 = A.fromPoint( e.startContainer, e.startOffset ), i = A.fromPoint(e.endContainer, e.endOffset); return new z(t, i); } /** * Create a TextRange representing the `start`th to `end`th characters in * `root` */ static fromOffsets(e, t, i) { return new z( new A(e, t), new A(e, i) ); } /** * Return a new Range representing `range` trimmed of any leading or trailing * whitespace */ static trimmedRange(e) { return Et(z.fromRange(e).toRange()); } } class _ { constructor(e, t, i) { this.root = e, this.start = t, this.end = i; } static fromRange(e, t) { const i = z.fromRange(t).relativeTo(e); return new _( e, i.start.offset, i.end.offset ); } static fromSelector(e, t) { return new _(e, t.start, t.end); } toSelector() { return { type: "TextPositionSelector", start: this.start, end: this.end }; } toRange() { return z.fromOffsets(this.root, this.start, thi