UNPKG

vue-book-reader

Version:

vue-book-reader is a vue wrapper for [foliate-js](https://github.com/johnfactotum/foliate-js) - library for rendering e-books in the browser. Supports EPUB, MOBI, KF8 (AZW3), FB2, CBZ, PDF (experimental; requires PDF.js), or add support for other formats

1,186 lines (1,184 loc) 44 kB
var Wt = Object.defineProperty; var jt = (n, o, t) => o in n ? Wt(n, o, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[o] = t; var q = (n, o, t) => (jt(n, typeof o != "symbol" ? o + "" : o, t), t), ht = (n, o, t) => { if (!o.has(n)) throw TypeError("Cannot " + t); }; var f = (n, o, t) => (ht(n, o, "read from private field"), t ? t.call(n) : o.get(n)), y = (n, o, t) => { if (o.has(n)) throw TypeError("Cannot add the same private member more than once"); o instanceof WeakSet ? o.add(n) : o.set(n, t); }, E = (n, o, t, e) => (ht(n, o, "write to private field"), e ? e.call(n, t) : o.set(n, t), t); var wt = (n, o, t, e) => ({ set _(s) { E(n, o, s, t); }, get _() { return f(n, o, e); } }), b = (n, o, t) => (ht(n, o, "access private method"), t); import { toRefs as ut, ref as U, watch as Vt, onMounted as Ht, openBlock as O, createElementBlock as D, createElementVNode as P, withDirectives as Ut, vShow as Xt, renderSlot as ft, createCommentVNode as Y, defineComponent as qt, getCurrentInstance as Yt, h as Zt, Transition as Gt, reactive as Jt, normalizeClass as vt, unref as V, normalizeStyle as Kt, toDisplayString as Qt, createVNode as yt, mergeProps as te, withCtx as ee } from "vue"; const se = (n, o) => n.map((t, e, s) => o(t, e, s) ? e : null).filter((t) => t != null), St = (n, o) => [-1, ...o, n.length].reduce(({ xs: t, a: e }, s) => ({ xs: (t == null ? void 0 : t.concat([n.slice(e + 1, s)])) ?? [], a: s }), {}).xs, ne = (n, o) => n.slice(0, -1).concat([n[n.length - 1].concat(o[0])]).concat(o.slice(1)), dt = /\d/, at = /^epubcfi\((.*)\)$/, bt = (n) => n.replace(/[\^[\](),;=]/g, "^$&"), Ft = (n) => at.test(n) ? n : `epubcfi(${n})`, oe = (n) => { var o; return ((o = n.match(at)) == null ? void 0 : o[1]) ?? n; }, ie = (n) => (...o) => `epubcfi(${n(...o.map((t) => { var e; return ((e = t.match(at)) == null ? void 0 : e[1]) ?? t; }))})`, re = ie((...n) => n.join("!")), ae = (n) => { const o = []; let t, e, s = ""; const r = (a) => (o.push(a), t = null, s = ""), i = (a) => (s += a, e = !1); for (const a of Array.from(n.trim()).concat("")) { if (a === "^" && !e) { e = !0; continue; } if (t === "!") r(["!"]); else if (t === ",") r([","]); else if (t === "/" || t === ":") if (dt.test(a)) { i(a); continue; } else r([t, parseInt(s)]); else if (t === "~") if (dt.test(a) || a === ".") { i(a); continue; } else r(["~", parseFloat(s)]); else if (t === "@") { if (a === ":") { r(["@", parseFloat(s)]), t = "@"; continue; } if (dt.test(a) || a === ".") { i(a); continue; } else r(["@", parseFloat(s)]); } else if (t === "[") { a === ";" && !e ? (r(["[", s]), t = ";") : a === "," && !e ? (r(["[", s]), t = "[") : a === "]" && !e ? r(["[", s]) : i(a); continue; } else if (t != null && t.startsWith(";")) { a === "=" && !e ? (t = `;${s}`, s = "") : a === ";" && !e ? (r([t, s]), t = ";") : a === "]" && !e ? r([t, s]) : i(a); continue; } (a === "/" || a === ":" || a === "~" || a === "@" || a === "[" || a === "!" || a === ",") && (t = a); } return o; }, Lt = (n, o) => se(n, ([t]) => t === o), ce = (n) => { const o = []; let t; for (const [e, s] of n) { if (e === "/") o.push({ index: s }); else { const r = o[o.length - 1]; if (e === ":") r.offset = s; else if (e === "~") r.temporal = s; else if (e === "@") r.spatial = (r.spatial ?? []).concat(s); else if (e === ";s") r.side = s; else if (e === "[") if (t === "/" && s) r.id = s; else { r.text = (r.text ?? []).concat(s); continue; } } t = e; } return o; }, At = (n) => St(n, Lt(n, "!")).map(ce), J = (n) => { const o = ae(oe(n)), t = Lt(o, ","); if (!t.length) return At(o); const [e, s, r] = St(o, t).map(At); return { parent: e, start: s, end: r }; }, le = ({ index: n, id: o, offset: t, temporal: e, spatial: s, text: r, side: i }) => { var l; const a = i ? `;s=${i}` : ""; return `/${n}` + (o ? `[${bt(o)}${a}]` : "") + (t != null && n % 2 ? `:${t}` : "") + (e ? `~${e}` : "") + (s ? `@${s.join(":")}` : "") + (r || !o && i ? "[" + (((l = r == null ? void 0 : r.map(bt)) == null ? void 0 : l.join(",")) ?? "") + a + "]" : ""); }, It = (n) => n.parent ? [n.parent, n.start, n.end].map(It).join(",") : n.map((o) => o.map(le).join("")).join("!"), ct = (n) => Ft(It(n)), j = (n, o) => typeof n == "string" ? ct(j(J(n), o)) : n.parent ? ne(n.parent, n[o ? "end" : "start"]) : n, he = (n, o) => { typeof n == "string" && (n = J(n)), typeof o == "string" && (o = J(o)), n = j(n), o = j(o, !0); const t = n[n.length - 1], e = o[o.length - 1], s = [], r = [], i = []; let a = !0; const l = Math.max(t.length, e.length); for (let h = 0; h < l; h++) { const d = t[h], u = e[h]; a && (a = (d == null ? void 0 : d.index) === (u == null ? void 0 : u.index) && !(d != null && d.offset) && !(u != null && u.offset)), a ? s.push(d) : (d && r.push(d), u && i.push(u)); } const c = n.slice(0, -1).concat([s]); return ct({ parent: c, start: [r], end: [i] }); }, gt = ({ nodeType: n }) => n === 3 || n === 4, Z = ({ nodeType: n }) => n === 1, Pt = (n, o) => { const t = Array.from(n.childNodes).filter((e) => gt(e) || Z(e)); return o ? t.map((e) => { const s = o(e); return s === NodeFilter.FILTER_REJECT ? null : s === NodeFilter.FILTER_SKIP ? Pt(e, o) : e; }).flat().filter((e) => e) : t; }, mt = (n, o) => { const t = Pt(n, o).reduce((e, s) => { let r = e[e.length - 1]; return r ? gt(s) ? Array.isArray(r) ? r.push(s) : gt(r) ? e[e.length - 1] = [r, s] : e.push(s) : Z(r) ? e.push(null, s) : e.push(s) : e.push(s), e; }, []); return Z(t[0]) && t.unshift("first"), Z(t[t.length - 1]) && t.push("last"), t.unshift("before"), t.push("after"), t; }, pt = (n, o, t) => { const { id: e } = o[o.length - 1]; if (e) { const i = n.ownerDocument.getElementById(e); if (i) return { node: i, offset: 0 }; } for (const { index: i } of o) { const a = n ? mt(n, t)[i] : null; if (a === "first") return { node: n.firstChild ?? n }; if (a === "last") return { node: n.lastChild ?? n }; if (a === "before") return { node: n, before: !0 }; if (a === "after") return { node: n, after: !0 }; n = a; } const { offset: s } = o[o.length - 1]; if (!Array.isArray(n)) return { node: n, offset: s }; let r = 0; for (const i of n) { const { length: a } = i.nodeValue; if (r + a >= s) return { node: i, offset: s - r }; r += a; } }, K = (n, o, t) => { const { parentNode: e, id: s } = n, r = mt(e, t), i = r.findIndex((c) => Array.isArray(c) ? c.some((h) => h === n) : c === n), a = r[i]; if (Array.isArray(a)) { let c = 0; for (const h of a) if (h === n) { c += o; break; } else c += h.nodeValue.length; o = c; } const l = { id: s, index: i, offset: o }; return (e !== n.ownerDocument.documentElement ? K(e, null, t).concat(l) : [l]).filter((c) => c.index !== -1); }, de = (n, o) => { const { startContainer: t, startOffset: e, endContainer: s, endOffset: r } = n, i = K(t, e, o); if (n.collapsed) return ct([i]); const a = K(s, r, o); return he([i], [a]); }, ue = (n, o, t) => { const e = j(o), s = j(o, !0), r = n.documentElement, i = pt(r, e[0], t), a = pt(r, s[0], t), l = n.createRange(); return i.before ? l.setStartBefore(i.node) : i.after ? l.setStartAfter(i.node) : l.setStart(i.node, i.offset), a.before ? l.setEndBefore(a.node) : a.after ? l.setEndAfter(a.node) : l.setEnd(a.node, a.offset), l; }, Ye = (n) => { const o = [], { parentNode: t } = n[0], e = K(t); for (const [s, r] of mt(t).entries()) { const i = n[o.length]; r === i && o.push(ct([e.concat({ id: i.id, index: s })])); } return o; }, Ze = (n, o) => pt(n.documentElement, j(o)).node, Tt = { fromIndex: (n) => Ft(`/6/${(n + 1) * 2}`), toIndex: (n) => (n == null ? void 0 : n.at(-1).index) / 2 - 1 }, fe = (n) => { let o = 0; const t = (e) => { if (e.id = o++, e.subitems) for (const s of e.subitems) t(s); }; for (const e of n) t(e); return n; }, Nt = (n) => n.map((o) => { var t; return (t = o.subitems) != null && t.length ? [o, Nt(o.subitems)].flat() : o; }).flat(); class xt { async init({ toc: o, ids: t, splitHref: e, getFragment: s }) { fe(o); const r = Nt(o), i = /* @__PURE__ */ new Map(); for (const [l, c] of r.entries()) { const [h, d] = await e(c == null ? void 0 : c.href) ?? [], u = { fragment: d, item: c }; i.has(h) ? i.get(h).items.push(u) : i.set(h, { prev: r[l - 1], items: [u] }); } const a = /* @__PURE__ */ new Map(); for (const [l, c] of t.entries()) i.has(c) ? a.set(c, i.get(c)) : a.set(c, a.get(t[l - 1])); this.ids = t, this.map = a, this.getFragment = s; } getProgress(o, t) { var l; if (!this.ids) return; const e = this.ids[o], s = this.map.get(e); if (!s) return null; const { prev: r, items: i } = s; if (!i) return r; if (!t || i.length === 1 && !i[0].fragment) return i[0].item; const a = t.startContainer.getRootNode(); for (const [c, { fragment: h }] of i.entries()) { const d = this.getFragment(a, h); if (d && t.comparePoint(d, 0) > 0) return ((l = i[c - 1]) == null ? void 0 : l.item) ?? r; } return i[i.length - 1].item; } } var Q, Rt; class ge { constructor(o, t, e) { y(this, Q); this.sizes = o.map((s) => s.linear != "no" && s.size > 0 ? s.size : 0), this.sizePerLoc = t, this.sizePerTimeUnit = e, this.sizeTotal = this.sizes.reduce((s, r) => s + r, 0), this.sectionFractions = b(this, Q, Rt).call(this); } // get progress given index of and fractions within a section getProgress(o, t, e = 0) { const { sizes: s, sizePerLoc: r, sizePerTimeUnit: i, sizeTotal: a } = this, l = s[o] ?? 0, h = s.slice(0, o).reduce((v, A) => v + A, 0) + t * l, d = h + e * l, u = a - h, g = (1 - t) * l; return { fraction: d / a, section: { current: o, total: s.length }, location: { current: Math.floor(h / r), next: Math.floor(d / r), total: Math.ceil(a / r) }, time: { section: g / i, total: u / i } }; } // the inverse of `getProgress` // get index of and fraction in section based on total fraction getSection(o) { if (o <= 0) return [0, 0]; if (o >= 1) return [this.sizes.length - 1, 1]; o = o + Number.EPSILON; const { sizeTotal: t } = this; let e = this.sectionFractions.findIndex((r) => r > o) - 1; if (e < 0) return [0, 0]; for (; !this.sizes[e]; ) e++; const s = (o - this.sectionFractions[e]) / (this.sizes[e] / t); return [e, s]; } } Q = new WeakSet(), Rt = function() { const { sizeTotal: o } = this, t = [0]; let e = 0; for (const s of this.sizes) t.push((e += s) / o); return t; }; const T = (n) => document.createElementNS("http://www.w3.org/2000/svg", n); var L, I; class Et { constructor() { y(this, L, T("svg")); y(this, I, /* @__PURE__ */ new Map()); Object.assign(f(this, L).style, { position: "absolute", top: "0", left: "0", width: "100%", height: "100%", pointerEvents: "none" }); } get element() { return f(this, L); } add(o, t, e, s) { f(this, I).has(o) && this.remove(o), typeof t == "function" && (t = t(f(this, L).getRootNode())); const r = t.getClientRects(), i = e(r, s); f(this, L).append(i), f(this, I).set(o, { range: t, draw: e, options: s, element: i, rects: r }); } remove(o) { f(this, I).has(o) && (f(this, L).removeChild(f(this, I).get(o).element), f(this, I).delete(o)); } redraw() { for (const o of f(this, I).values()) { const { range: t, draw: e, options: s, element: r } = o; f(this, L).removeChild(r); const i = t.getClientRects(), a = e(i, s); f(this, L).append(a), o.element = a, o.rects = i; } } hitTest({ x: o, y: t }) { const e = Array.from(f(this, I).entries()); for (let s = e.length - 1; s >= 0; s--) { const [r, i] = e[s]; for (const { left: a, top: l, right: c, bottom: h } of i.rects) if (l <= t && a <= o && h > t && c > o) return [r, i.range]; } return []; } static underline(o, t = {}) { const { color: e = "red", width: s = 2, writingMode: r } = t, i = T("g"); if (i.setAttribute("fill", e), r === "vertical-rl" || r === "vertical-lr") for (const { right: a, top: l, height: c } of o) { const h = T("rect"); h.setAttribute("x", a - s), h.setAttribute("y", l), h.setAttribute("height", c), h.setAttribute("width", s), i.append(h); } else for (const { left: a, bottom: l, width: c } of o) { const h = T("rect"); h.setAttribute("x", a), h.setAttribute("y", l - s), h.setAttribute("height", s), h.setAttribute("width", c), i.append(h); } return i; } static strikethrough(o, t = {}) { const { color: e = "red", width: s = 2, writingMode: r } = t, i = T("g"); if (i.setAttribute("fill", e), r === "vertical-rl" || r === "vertical-lr") for (const { right: a, left: l, top: c, height: h } of o) { const d = T("rect"); d.setAttribute("x", (a + l) / 2), d.setAttribute("y", c), d.setAttribute("height", h), d.setAttribute("width", s), i.append(d); } else for (const { left: a, top: l, bottom: c, width: h } of o) { const d = T("rect"); d.setAttribute("x", a), d.setAttribute("y", (l + c) / 2), d.setAttribute("height", s), d.setAttribute("width", h), i.append(d); } return i; } static squiggly(o, t = {}) { const { color: e = "red", width: s = 2, writingMode: r } = t, i = T("g"); i.setAttribute("fill", "none"), i.setAttribute("stroke", e), i.setAttribute("stroke-width", s); const a = s * 1.5; if (r === "vertical-rl" || r === "vertical-lr") for (const { right: l, top: c, height: h } of o) { const d = T("path"), u = Math.round(h / a / 1.5), g = h / u, v = Array.from( { length: u }, (A, p) => `l${p % 2 ? -a : a} ${g}` ).join(""); d.setAttribute("d", `M${l} ${c}${v}`), i.append(d); } else for (const { left: l, bottom: c, width: h } of o) { const d = T("path"), u = Math.round(h / a / 1.5), g = h / u, v = Array.from( { length: u }, (A, p) => `l${g} ${p % 2 ? a : -a}` ).join(""); d.setAttribute("d", `M${l} ${c}${v}`), i.append(d); } return i; } static highlight(o, t = {}) { const { color: e = "red" } = t, s = T("g"); s.setAttribute("fill", e), s.style.opacity = "var(--overlayer-highlight-opacity, .3)", s.style.mixBlendMode = "var(--overlayer-highlight-blend-mode, normal)"; for (const { left: r, top: i, height: a, width: l } of o) { const c = T("rect"); c.setAttribute("x", r), c.setAttribute("y", i), c.setAttribute("height", a), c.setAttribute("width", l), s.append(c); } return s; } static outline(o, t = {}) { const { color: e = "red", width: s = 3, radius: r = 3 } = t, i = T("g"); i.setAttribute("fill", "none"), i.setAttribute("stroke", e), i.setAttribute("stroke-width", s); for (const { left: a, top: l, height: c, width: h } of o) { const d = T("rect"); d.setAttribute("x", a), d.setAttribute("y", l), d.setAttribute("height", c), d.setAttribute("width", h), d.setAttribute("rx", r), i.append(d); } return i; } // make an exact copy of an image in the overlay // one can then apply filters to the entire element, without affecting them; // it's a bit silly and probably better to just invert images twice // (though the color will be off in that case if you do heu-rotate) static copyImage([o], t = {}) { const { src: e } = t, s = T("image"), { left: r, top: i, height: a, width: l } = o; return s.setAttribute("href", e), s.setAttribute("x", r), s.setAttribute("y", i), s.setAttribute("height", a), s.setAttribute("width", l), s; } } L = new WeakMap(), I = new WeakMap(); const pe = (n, o) => { const t = []; for (let e = o.currentNode; e; e = o.nextNode()) { const s = n.comparePoint(e, 0); if (s === 0) t.push(e); else if (s > 0) break; } return t; }, me = (n, o) => { const t = []; for (let e = o.nextNode(); e; e = o.nextNode()) t.push(e); return t; }, we = NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_CDATA_SECTION, ve = (n) => { if (n.nodeType === 1) { const o = n.tagName.toLowerCase(); return o === "script" || o === "style" ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_SKIP; } return NodeFilter.FILTER_ACCEPT; }, kt = function* (n, o) { const t = n.commonAncestorContainer ?? n.body ?? n, e = document.createTreeWalker(t, we, { acceptNode: ve }), r = (n.commonAncestorContainer ? pe : me)(n, e), i = r.map((l) => l.nodeValue), a = (l, c, h, d) => { const u = document.createRange(); return u.setStart(r[l], c), u.setEnd(r[h], d), u; }; for (const l of o(i, a)) yield l; }, H = "foliate-search:"; var k, x; class ye extends EventTarget { constructor() { super(...arguments); y(this, k, []); y(this, x, -1); } pushState(t) { const e = f(this, k)[f(this, x)]; e === t || e != null && e.fraction && e.fraction === t.fraction || (f(this, k)[++wt(this, x)._] = t, f(this, k).length = f(this, x) + 1, this.dispatchEvent(new Event("index-change"))); } replaceState(t) { const e = f(this, x); f(this, k)[e] = t; } back() { const t = f(this, x); if (t <= 0) return; const e = { state: f(this, k)[t - 1] }; E(this, x, t - 1), this.dispatchEvent(new CustomEvent("popstate", { detail: e })), this.dispatchEvent(new Event("index-change")); } forward() { const t = f(this, x); if (t >= f(this, k).length - 1) return; const e = { state: f(this, k)[t + 1] }; E(this, x, t + 1), this.dispatchEvent(new CustomEvent("popstate", { detail: e })), this.dispatchEvent(new Event("index-change")); } get canGoBack() { return f(this, x) > 0; } get canGoForward() { return f(this, x) < f(this, k).length - 1; } clear() { E(this, k, []), E(this, x, -1); } } k = new WeakMap(), x = new WeakMap(); const be = (n) => { var o, t; if (!n) return {}; try { const e = Intl.getCanonicalLocales(n)[0], s = new Intl.Locale(e), r = ["zh", "ja", "kr"].includes(s.language), i = (t = ((o = s.getTextInfo) == null ? void 0 : o.call(s)) ?? s.textInfo) == null ? void 0 : t.direction; return { canonical: e, locale: s, isCJK: r, direction: i }; } catch (e) { return console.warn(e), {}; } }; var tt, _, C, $, B, S, R, et, _t, st, Bt, nt, zt, W, G, ot, $t, it, Mt, rt, Ot; class Ae extends HTMLElement { constructor() { super(); y(this, S); y(this, et); y(this, st); y(this, nt); y(this, W); y(this, ot); y(this, it); y(this, rt); y(this, tt, this.attachShadow({ mode: "closed" })); y(this, _, void 0); y(this, C, void 0); y(this, $, void 0); y(this, B, /* @__PURE__ */ new Map()); q(this, "isFixedLayout", !1); q(this, "lastLocation"); q(this, "history", new ye()); this.history.addEventListener("popstate", ({ detail: t }) => { const e = this.resolveNavigation(t.state); this.renderer.goTo(e); }); } async open(t) { var e, s, r; if (this.book = t, this.language = be((e = t.metadata) == null ? void 0 : e.language), t.splitTOCHref && t.getTOCFragment) { const i = t.sections.map((c) => c.id); E(this, _, new ge(t.sections, 1500, 1600)); const a = t.splitTOCHref.bind(t), l = t.getTOCFragment.bind(t); E(this, C, new xt()), await f(this, C).init({ toc: t.toc ?? [], ids: i, splitHref: a, getFragment: l }), E(this, $, new xt()), await f(this, $).init({ toc: t.pageList ?? [], ids: i, splitHref: a, getFragment: l }); } if (this.isFixedLayout = ((s = this.book.rendition) == null ? void 0 : s.layout) === "pre-paginated", this.isFixedLayout ? (await import("./fixed-layout-DpOZsuor.js"), this.renderer = document.createElement("foliate-fxl")) : (await import("./paginator-Czje3OX9.js"), this.renderer = document.createElement("foliate-paginator")), this.renderer.setAttribute("exportparts", "head,foot,filter"), this.renderer.addEventListener("load", (i) => b(this, st, Bt).call(this, i.detail)), this.renderer.addEventListener("relocate", (i) => b(this, et, _t).call(this, i.detail)), this.renderer.addEventListener("create-overlayer", (i) => i.detail.attach(b(this, ot, $t).call(this, i.detail))), this.renderer.open(t), f(this, tt).append(this.renderer), t.sections.some((i) => i.mediaOverlay)) { (r = t.media).activeClass || (r.activeClass = "-epub-media-overlay-active"); const i = t.media.activeClass; this.mediaOverlay = t.getMediaOverlay(); let a; this.mediaOverlay.addEventListener("highlight", (l) => { const c = this.resolveNavigation(l.detail.text); this.renderer.goTo(c).then(() => { const { doc: h } = this.renderer.getContents().find((u) => u.index = c.index), d = c.anchor(h); d.classList.add(i), a = new WeakRef(d); }); }), this.mediaOverlay.addEventListener("unhighlight", () => { var l, c; (c = (l = a == null ? void 0 : a.deref()) == null ? void 0 : l.classList) == null || c.remove(i); }); } } close() { var t, e; (t = this.renderer) == null || t.destroy(), (e = this.renderer) == null || e.remove(), E(this, _, null), E(this, C, null), E(this, $, null), E(this, B, /* @__PURE__ */ new Map()), this.lastLocation = null, this.history.clear(), this.tts = null, this.mediaOverlay = null; } goToTextStart() { var t, e; return this.goTo(((e = (t = this.book.landmarks) == null ? void 0 : t.find((s) => s.type.includes("bodymatter") || s.type.includes("text"))) == null ? void 0 : e.href) ?? this.book.sections.findIndex((s) => s.linear !== "no")); } async init({ lastLocation: t, showTextStart: e }) { const s = t ? this.resolveNavigation(t) : null; s ? (await this.renderer.goTo(s), this.history.pushState(t)) : e ? await this.goToTextStart() : (this.history.pushState(0), await this.next()); } async addAnnotation(t, e) { var c; const { value: s } = t; if (s.startsWith(H)) { const h = s.replace(H, ""), { index: d, anchor: u } = await this.resolveNavigation(h), g = b(this, W, G).call(this, d); if (g) { const { overlayer: v, doc: A } = g; if (e) { v.remove(s); return; } const p = A ? u(A) : u; v.add(s, p, Et.outline); } return; } const { index: r, anchor: i } = await this.resolveNavigation(s), a = b(this, W, G).call(this, r); if (a) { const { overlayer: h, doc: d } = a; if (h.remove(s), !e) { const u = d ? i(d) : i, g = (v, A) => h.add(s, u, v, A); b(this, S, R).call(this, "draw-annotation", { draw: g, annotation: t, doc: d, range: u }); } } const l = ((c = f(this, C).getProgress(r)) == null ? void 0 : c.label) ?? ""; return { index: r, label: l }; } deleteAnnotation(t) { return this.addAnnotation(t, !0); } async showAnnotation(t) { const { value: e } = t, s = await this.goTo(e); if (s) { const { index: r, anchor: i } = s, { doc: a } = b(this, W, G).call(this, r), l = i(a); b(this, S, R).call(this, "show-annotation", { value: e, index: r, range: l }); } } getCFI(t, e) { const s = this.book.sections[t].cfi ?? Tt.fromIndex(t); return e ? re(s, de(e)) : s; } resolveCFI(t) { if (this.book.resolveCFI) return this.book.resolveCFI(t); { const e = J(t); return { index: Tt.toIndex((e.parent ?? e).shift()), anchor: (i) => ue(i, e) }; } } resolveNavigation(t) { try { if (typeof t == "number") return { index: t }; if (typeof t.fraction == "number") { const [e, s] = f(this, _).getSection(t.fraction); return { index: e, anchor: s }; } return at.test(t) ? this.resolveCFI(t) : this.book.resolveHref(t); } catch (e) { console.error(e), console.error(`Could not resolve target ${t}`); } } async goTo(t) { const e = this.resolveNavigation(t); try { return await this.renderer.goTo(e), this.history.pushState(t), e; } catch (s) { console.error(s), console.error(`Could not go to ${t}`); } } async goToFraction(t) { const [e, s] = f(this, _).getSection(t); await this.renderer.goTo({ index: e, anchor: s }), this.history.pushState({ fraction: t }); } async select(t) { try { const e = await this.resolveNavigation(t); await this.renderer.goTo({ ...e, select: !0 }), this.history.pushState(t); } catch (e) { console.error(e), console.error(`Could not go to ${t}`); } } deselect() { for (const { doc: t } of this.renderer.getContents()) t.defaultView.getSelection().removeAllRanges(); } getSectionFractions() { var t; return (((t = f(this, _)) == null ? void 0 : t.sectionFractions) ?? []).map((e) => e + Number.EPSILON); } getProgressOf(t, e) { var i, a; const s = (i = f(this, C)) == null ? void 0 : i.getProgress(t, e), r = (a = f(this, $)) == null ? void 0 : a.getProgress(t, e); return { tocItem: s, pageItem: r }; } async getTOCItemOf(t) { try { const { index: e, anchor: s } = await this.resolveNavigation(t), r = await this.book.sections[e].createDocument(), i = s(r), a = i instanceof Range, l = a ? i : r.createRange(); return a || l.selectNodeContents(i), f(this, C).getProgress(e, l); } catch (e) { console.error(e), console.error(`Could not get ${t}`); } } async prev(t) { await this.renderer.prev(t); } async next(t) { await this.renderer.next(t); } goLeft() { return this.book.dir === "rtl" ? this.next() : this.prev(); } goRight() { return this.book.dir === "rtl" ? this.prev() : this.next(); } async *search(t) { var c; this.clearSearch(); const { searchMatcher: e } = await import("./search-Dw1WQJVD.js"), { query: s, index: r } = t, i = e( kt, { defaultLocale: this.language, ...t } ), a = r != null ? b(this, it, Mt).call(this, i, s, r) : b(this, rt, Ot).call(this, i, s), l = []; f(this, B).set(r, l); for await (const h of a) if (h.subitems) { const d = h.subitems.map(({ cfi: u }) => ({ value: H + u })); f(this, B).set(h.index, d); for (const u of d) this.addAnnotation(u); yield { label: ((c = f(this, C).getProgress(h.index)) == null ? void 0 : c.label) ?? "", subitems: h.subitems }; } else { if (h.cfi) { const d = { value: H + h.cfi }; l.push(d), this.addAnnotation(d); } yield h; } yield "done"; } clearSearch() { for (const t of f(this, B).values()) for (const e of t) this.deleteAnnotation(e); f(this, B).clear(); } async initTTS() { const t = this.renderer.getContents()[0].doc; if (this.tts && this.tts.doc === t) return; const { TTS: e } = await import("./tts-CuDZu6rz.js"); this.tts = new e(t, kt, (s) => this.renderer.scrollToAnchor(s, !0)); } startMediaOverlay() { const { index: t } = this.renderer.getContents()[0]; return this.mediaOverlay.start(t); } } tt = new WeakMap(), _ = new WeakMap(), C = new WeakMap(), $ = new WeakMap(), B = new WeakMap(), S = new WeakSet(), R = function(t, e, s) { return this.dispatchEvent(new CustomEvent(t, { detail: e, cancelable: s })); }, et = new WeakSet(), _t = function({ reason: t, range: e, index: s, fraction: r, size: i }) { var d, u, g; const a = ((d = f(this, _)) == null ? void 0 : d.getProgress(s, r, i)) ?? {}, l = (u = f(this, C)) == null ? void 0 : u.getProgress(s, e), c = (g = f(this, $)) == null ? void 0 : g.getProgress(s, e), h = this.getCFI(s, e); this.lastLocation = { ...a, tocItem: l, pageItem: c, cfi: h, range: e }, (t === "snap" || t === "page" || t === "scroll") && this.history.replaceState(h), b(this, S, R).call(this, "relocate", this.lastLocation); }, st = new WeakSet(), Bt = function({ doc: t, index: e }) { var s, r; (s = t.documentElement).lang || (s.lang = this.language.canonical ?? ""), this.language.isCJK || (r = t.documentElement).dir || (r.dir = this.language.direction ?? ""), b(this, nt, zt).call(this, t, e), b(this, S, R).call(this, "load", { doc: t, index: e }); }, nt = new WeakSet(), zt = function(t, e) { const { book: s } = this, r = s.sections[e]; for (const i of t.querySelectorAll("a[href]")) i.addEventListener("click", (a) => { var h, d; a.preventDefault(); const l = i.getAttribute("href"), c = ((h = r == null ? void 0 : r.resolveHref) == null ? void 0 : h.call(r, l)) ?? l; (d = s == null ? void 0 : s.isExternal) != null && d.call(s, c) ? Promise.resolve(b(this, S, R).call(this, "external-link", { a: i, href: c }, !0)).then((u) => u ? globalThis.open(c, "_blank") : null).catch((u) => console.error(u)) : Promise.resolve(b(this, S, R).call(this, "link", { a: i, href: c }, !0)).then((u) => u ? this.goTo(c) : null).catch((u) => console.error(u)); }); }, W = new WeakSet(), G = function(t) { return this.renderer.getContents().find((e) => e.index === t && e.overlayer); }, ot = new WeakSet(), $t = function({ doc: t, index: e }) { const s = new Et(); t.addEventListener("click", (i) => { const [a, l] = s.hitTest(i); a && !a.startsWith(H) && b(this, S, R).call(this, "show-annotation", { value: a, index: e, range: l }); }, !1); const r = f(this, B).get(e); if (r) for (const i of r) this.addAnnotation(i); return b(this, S, R).call(this, "create-overlay", { index: e }), s; }, it = new WeakSet(), Mt = async function* (t, e, s) { const r = await this.book.sections[s].createDocument(); for (const { range: i, excerpt: a } of t(r, e)) yield { cfi: this.getCFI(s, i), excerpt: a }; }, rt = new WeakSet(), Ot = async function* (t, e) { const { sections: s } = this.book; for (const [r, { createDocument: i }] of s.entries()) { if (!i) continue; const a = await i(), l = Array.from(t(a, e), ({ range: h, excerpt: d }) => ({ cfi: this.getCFI(r, h), excerpt: d })); yield { progress: (r + 1) / s.length }, l.length && (yield { index: r, subitems: l }); } }; customElements.define("foliate-view", Ae); const Te = async (n) => { const o = new Uint8Array(await n.slice(0, 4).arrayBuffer()); return o[0] === 80 && o[1] === 75 && o[2] === 3 && o[3] === 4; }, xe = async (n) => { const o = new Uint8Array(await n.slice(0, 5).arrayBuffer()); return o[0] === 37 && o[1] === 80 && o[2] === 68 && o[3] === 70 && o[4] === 45; }, Ee = async (n) => { const { configure: o, ZipReader: t, BlobReader: e, TextWriter: s, BlobWriter: r } = await import("./zip-FQL_v1pL.js"); o({ useWebWorkers: !1 }); const a = await new t(new e(n)).getEntries(), l = new Map(a.map((g) => [g.filename, g])), c = (g) => (v, ...A) => l.has(v) ? g(l.get(v), ...A) : null, h = c((g) => g.getData(new s())), d = c((g, v) => g.getData(new r(v))); return { entries: a, loadText: h, loadBlob: d, getSize: (g) => { var v; return ((v = l.get(g)) == null ? void 0 : v.uncompressedSize) ?? 0; } }; }, Dt = async (n) => n.isFile ? n : (await Promise.all(Array.from( await new Promise((o, t) => n.createReader().readEntries((e) => o(e), (e) => t(e))), Dt ))).flat(), ke = async (n) => { const o = await Dt(n), t = await Promise.all( o.map((h) => new Promise((d, u) => h.file( (g) => d([g, h.fullPath]), (g) => u(g) ))) ), e = new Map(t.map(([h, d]) => [d.replace(n.fullPath + "/", ""), h])), s = new TextDecoder(), r = (h) => h ? s.decode(h) : null, i = (h) => { var d; return ((d = e.get(h)) == null ? void 0 : d.arrayBuffer()) ?? null; }; return { loadText: async (h) => r(await i(h)), loadBlob: (h) => e.get(h), getSize: (h) => { var d; return ((d = e.get(h)) == null ? void 0 : d.size) ?? 0; } }; }, Ce = ({ name: n, type: o }) => o === "application/vnd.comicbook+zip" || n.endsWith(".cbz"), Se = ({ name: n, type: o }) => o === "application/x-fictionbook+xml" || n.endsWith(".fb2"), Fe = ({ name: n, type: o }) => o === "application/x-zip-compressed-fb2" || n.endsWith(".fb2.zip") || n.endsWith(".fbz"), Ct = async (n, o) => { let t; if (n.isDirectory) { const s = await ke(n), { EPUB: r } = await import("./epub-TvZmxYCF.js"); t = await new r(s).init(); } else if (n.size) if (await Te(n)) { const s = await Ee(n); if (Ce(n)) { const { makeComicBook: r } = await import("./comic-book-D2H5riQt.js"); t = r(s, n); } else if (Fe(n)) { const { makeFB2: r } = await import("./fb2-DHUjllK8.js"), { entries: i } = s, a = i.find((c) => c.filename.endsWith(".fb2")), l = await s.loadBlob((a ?? i[0]).filename); t = await r(l); } else { const { EPUB: r } = await import("./epub-TvZmxYCF.js"); t = await new r(s).init(); } } else if (await xe(n)) { const { makePDF: s } = await import("./pdf-CsfA1oys.js"); t = await s(n); } else { const { isMOBI: s, MOBI: r } = await import("./mobi-BpkZoq9g.js"); if (await s(n)) { const i = await import("./fflate-9VGFqnqw.js"); t = await new r({ unzlib: i.unzlibSync }).open(n); } else if (Se(n)) { const { makeFB2: i } = await import("./fb2-DHUjllK8.js"); t = await i(n); } } else throw new Error("File not found"); if (!t) throw new Error("File type not supported"); const e = document.createElement("foliate-view"); return o.append(e), await e.open(t), e; }; function Le(n, o) { n.addEventListener( "keyup", (t) => { t.key === "ArrowUp" || t.key === "ArrowRight" ? o("next") : (t.key === "ArrowDown" || t.key === "ArrowLeft") && o("prev"); }, !1 ); } function Ie(n, o) { let s = 0, r; n.addEventListener("wheel", (i) => { i.ignore || (i.ignore = !0, clearTimeout(r), s += i.deltaY, r = setTimeout(() => { if (Math.abs(s) >= 750) { let a = Math.sign(s) > 0 ? "next" : "prev"; o(a), s = 0; } s = 0; }, 50)); }); } function Pe(n, o) { let r, i, a; n.addEventListener( "touchstart", (l) => { l.ignore || (l.ignore = !0, r = l.changedTouches[0].pageX, i = l.changedTouches[0].pageY, a = Date.now()); }, !1 ), n.addEventListener( "touchend", (l) => { var u, g; if (l.ignore) return; l.ignore = !0; const c = l.changedTouches[0].pageX - r, h = l.changedTouches[0].pageY - i; Date.now() - a <= 500 && (Math.abs(c) >= 50 && Math.abs(h) <= 200 ? o(c < 0 ? "next" : "prev") : Math.abs(h) >= 50 && Math.abs(c) <= 200 ? o(h < 0 ? "up" : "down") : ((g = (u = n == null ? void 0 : n.defaultView) == null ? void 0 : u.getSelection()) == null || g.removeAllRanges(), n.dispatchEvent( new MouseEvent("click", { clientX: r, clientY: i }) ), l.preventDefault())); }, !1 ); } const Ne = (n, o) => { const t = n.__vccOpts || n; for (const [e, s] of o) t[e] = s; return t; }, Re = { class: "reader" }, _e = { class: "viewHolder" }, Be = { key: 0 }, ze = { __name: "BookView", props: { url: { type: [String, File] }, location: { type: [String, Number] }, tocChanged: Function, getRendition: Function }, emits: ["update:location"], setup(n, { expose: o, emit: t }) { const e = n, { tocChanged: s, getRendition: r } = e, { url: i, location: a } = ut(e), l = t; let c = null; const h = U(null), d = U(!1), u = ({ spacing: m, justify: w, hyphenate: M }) => ` @namespace epub "http://www.idpf.org/2007/ops"; html { color-scheme: light dark; } /* https://github.com/whatwg/html/issues/5426 */ @media (prefers-color-scheme: dark) { a:link { color: lightblue; } } p, li, blockquote, dd { line-height: ${m}; text-align: ${w ? "justify" : "start"}; -webkit-hyphens: ${M ? "auto" : "manual"}; hyphens: ${M ? "auto" : "manual"}; -webkit-hyphenate-limit-before: 3; -webkit-hyphenate-limit-after: 2; -webkit-hyphenate-limit-lines: 2; hanging-punctuation: allow-end last; widows: 2; } /* prevent the above from overriding the align attribute */ [align="left"] { text-align: left; } [align="right"] { text-align: right; } [align="center"] { text-align: center; } [align="justify"] { text-align: justify; } pre { white-space: pre-wrap !important; } aside[epub|type~="endnote"], aside[epub|type~="footnote"], aside[epub|type~="note"], aside[epub|type~="rearnote"] { display: none; } `, g = async () => { i.value && (c && c.close(), typeof i.value == "string" ? fetch(i.value).then((m) => m.blob()).then(async (m) => { const w = i.value.split("/"); c = await Ct( new File([m], w[w.length - 1]), h.value ), v(); }).catch((m) => console.error(m)) : (c = await Ct(i.value, h.value), v())); }, v = () => { var w, M; d.value = !0; const { book: m } = c; (M = (w = c.renderer).setStyles) == null || M.call( w, u({ spacing: 1.4, justify: !0, hyphenate: !0 }) ), p(), r(c), s && s(m.toc), a.value ? c == null || c.goTo(a.value) : c.renderer.next(); }, A = (m) => { m === "next" ? N() : m === "prev" && X(); }, p = () => { c.addEventListener("load", z), c.addEventListener("relocate", F); }, z = ({ detail: { doc: m } }) => { Ie(m, A), Pe(m, A), Le(m, A); }, F = ({ detail: m }) => { l("update:location", m); }, N = () => c == null ? void 0 : c.next(), X = () => c == null ? void 0 : c.prev(), lt = (m) => c == null ? void 0 : c.goTo(m); return Vt(i, () => { g(); }), Ht(() => { g(); }), o({ nextPage: N, prevPage: X, setLocation: lt }), (m, w) => (O(), D("div", Re, [ P("div", _e, [ Ut(P("div", { ref_key: "viewer", ref: h, id: "viewer" }, null, 512), [ [Xt, d.value] ]), d.value ? Y("", !0) : (O(), D("div", Be, [ ft(m.$slots, "loadingView", {}, void 0, !0) ])) ]) ])); } }, $e = /* @__PURE__ */ Ne(ze, [["__scopeId", "data-v-7b9f0714"]]), Me = { class: "container" }, Oe = /* @__PURE__ */ P("span", { class: "tocButtonBar", style: { top: "35%" } }, null, -1), De = /* @__PURE__ */ P("span", { class: "tocButtonBar", style: { top: "66%" } }, null, -1), We = [ Oe, De ], je = ["title"], Ve = /* @__PURE__ */ P("div", { class: "loadingView" }, "Loading…", -1), He = { key: 0 }, Ue = { class: "tocArea" }, Ge = { __name: "VueReader", props: { title: { type: String }, showToc: { type: Boolean, default: !0 }, title: { type: String, default: "" }, getRendition: { type: Function }, backgroundColor: { type: String, default: "#fff" } }, setup(n) { const o = qt({ name: "TocComponent", props: { toc: { type: Array, default: () => [] }, current: { type: [String, Number], default: "" }, setLocation: { type: Function, required: !0 }, isSubmenu: { type: Boolean, default: !1, required: !1 } }, setup(p) { const z = Yt(), F = Zt.bind(z), { setLocation: N, isSubmenu: X } = p, { toc: lt, current: m } = ut(p); return () => lt.value.map((w, M) => F("div", { key: M }, [ F( "button", { class: [ "tocAreaButton", w.href === m.value ? "active" : "" ], onClick: () => { w.subitems && w.subitems.length > 0 ? (w.expansion = !w.expansion, N(w.href, !1)) : N(w.href); } }, [ X ? " ".repeat(4) + w.label : w.label, // 展开 w.subitems && w.subitems.length > 0 && F("div", { class: `${w.expansion ? "open" : ""} expansion` }) ] ), //多级目录 w.subitems && w.subitems.length > 0 && F( Gt, { name: "collapse-transition" }, { default: () => F( "div", { style: { display: w.expansion ? void 0 : "none" } }, [ F(o, { toc: w.subitems, current: m.value, setLocation: N, isSubmenu: !0 }) ] ) } ) ])); } }), t = n, e = Jt({ toc: [], //目录 expandedToc: !1 //目录展开 }), { getRendition: s } = t, { toc: r, expandedToc: i } = ut(e), a = U(null), l = U(null), c = U(""), h = (p) => { var N; s && s(p); const { book: z } = p, F = (N = z.metadata) == null ? void 0 : N.title; c.value = F || ""; }, d = (p) => { r.value = p; }, u = () => { i.value = !i.value; }, g = () => { var p; (p = a.value) == null || p.nextPage(); }, v = () => { var p; (p = a.value) == null || p.prevPage(); }, A = (p, z = !0) => { a.value.setLocation(p), i.value = !1, i.value = !z; }; return (p, z) => (O(), D("div", Me, [ P("div", { class: vt(["readerArea", { containerExpanded: V(i) }]), style: Kt({ backgroundColor: n.backgroundColor }) }, [ n.showToc ? (O(), D("button", { key: 0, class: vt(["tocButton", { tocButtonExpanded: V(i) }]), type: "button", onClick: u }, We, 2)) : Y("", !0), ft(p.$slots, "title", {}, () => [ P("div", { class: "titleArea", title: n.title || c.value }, Qt(n.title || c.value), 9, je) ]), yt($e, te({ ref_key: "bookRef", ref: a }, p.$attrs, { tocChanged: d, getRendition: h }), { loadingView: ee(() => [ ft(p.$slots, "loadingView", {}, () => [ Ve ]) ]), _: 3 }, 16), P("button", { class: "arrow pre", onClick: v }, "‹"), P("button", { class: "arrow next", onClick: g }, "›") ], 6), n.showToc ? (O(), D("div", He, [ P("div", Ue, [ yt(V(o), { toc: V(r), current: l.value, setLocation: A }, null, 8, ["toc", "current"]) ]), V(i) ? (O(), D("div", { key: 0, class: "tocBackground", onClick: u })) : Y("", !0) ])) : Y("", !0) ])); } }; export { $e as B, Ge as _, ue as a, Ye as f, J as p, Ze as t };