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
JavaScript
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 }) => `
epub "http://www.idpf.org/2007/ops";
html {
color-scheme: light dark;
}
/* https://github.com/whatwg/html/issues/5426 */
(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
};