mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
@@ -643,6 +643,20 @@ export class MOBI extends PDB {
|
|||||||
const mbpPagebreakRegex = /<\s*(?:mbp:)?pagebreak[^>]*>/gi
|
const mbpPagebreakRegex = /<\s*(?:mbp:)?pagebreak[^>]*>/gi
|
||||||
const fileposRegex = /<[^<>]+filepos=['"]{0,1}(\d+)[^<>]*>/gi
|
const fileposRegex = /<[^<>]+filepos=['"]{0,1}(\d+)[^<>]*>/gi
|
||||||
|
|
||||||
|
const getIndent = el => {
|
||||||
|
let x = 0
|
||||||
|
while (el) {
|
||||||
|
const parent = el.parentElement
|
||||||
|
if (parent) {
|
||||||
|
const tag = parent.tagName.toLowerCase()
|
||||||
|
if (tag === 'p') x += 1.5
|
||||||
|
else if (tag === 'blockquote') x += 2
|
||||||
|
}
|
||||||
|
el = parent
|
||||||
|
}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
class MOBI6 {
|
class MOBI6 {
|
||||||
parser = new DOMParser()
|
parser = new DOMParser()
|
||||||
serializer = new XMLSerializer()
|
serializer = new XMLSerializer()
|
||||||
@@ -690,32 +704,47 @@ class MOBI6 {
|
|||||||
size: section.end - section.start,
|
size: section.end - section.start,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
const fileposInNCX = []
|
|
||||||
try {
|
try {
|
||||||
const ncx = await this.mobi.getNCX()
|
|
||||||
const map = ({ label, offset, children }) => {
|
|
||||||
const filepos = offset.toString().padStart(10, '0')
|
|
||||||
const href = `filepos:${filepos}`
|
|
||||||
fileposInNCX.push(filepos)
|
|
||||||
label = unescapeHTML(label)
|
|
||||||
return { label, href, subitems: children?.map(map) }
|
|
||||||
}
|
|
||||||
this.toc = ncx?.map(map)
|
|
||||||
this.landmarks = await this.getGuide()
|
this.landmarks = await this.getGuide()
|
||||||
|
const tocHref = this.landmarks
|
||||||
// try to build TOC if there's no NCX
|
.find(({ type }) => type?.includes('toc'))?.href
|
||||||
if (!this.toc) {
|
if (tocHref) {
|
||||||
const tocHref = this.landmarks
|
const { index } = this.resolveHref(tocHref)
|
||||||
.find(({ type }) => type?.includes('toc'))?.href
|
const doc = await this.sections[index].createDocument()
|
||||||
if (tocHref) {
|
let lastItem
|
||||||
const { index } = this.resolveHref(tocHref)
|
let lastLevel = 0
|
||||||
const doc = await this.sections[index].createDocument()
|
let lastIndent = 0
|
||||||
this.toc = Array.from(doc.querySelectorAll('a[filepos]'),
|
const lastLevelOfIndent = new Map()
|
||||||
a => ({
|
const lastParentOfLevel = new Map()
|
||||||
|
this.toc = Array.from(doc.querySelectorAll('a[filepos]'))
|
||||||
|
.reduce((arr, a) => {
|
||||||
|
const indent = getIndent(a)
|
||||||
|
const item = {
|
||||||
label: a.innerText?.trim(),
|
label: a.innerText?.trim(),
|
||||||
href: `filepos:${a.getAttribute('filepos')}`,
|
href: `filepos:${a.getAttribute('filepos')}`,
|
||||||
}))
|
}
|
||||||
}
|
const level = indent > lastIndent ? lastLevel + 1
|
||||||
|
: indent === lastIndent ? lastLevel
|
||||||
|
: lastLevelOfIndent.get(indent) ?? Math.max(0, lastLevel - 1)
|
||||||
|
if (level > lastLevel) {
|
||||||
|
if (lastItem) {
|
||||||
|
lastItem.subitems ??= []
|
||||||
|
lastItem.subitems.push(item)
|
||||||
|
lastParentOfLevel.set(level, lastItem)
|
||||||
|
}
|
||||||
|
else arr.push(item)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const parent = lastParentOfLevel.get(level)
|
||||||
|
if (parent) parent.subitems.push(item)
|
||||||
|
else arr.push(item)
|
||||||
|
}
|
||||||
|
lastItem = item
|
||||||
|
lastLevel = level
|
||||||
|
lastIndent = indent
|
||||||
|
lastLevelOfIndent.set(indent, level)
|
||||||
|
return arr
|
||||||
|
}, [])
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.warn(e)
|
console.warn(e)
|
||||||
@@ -724,8 +753,8 @@ class MOBI6 {
|
|||||||
// get list of all `filepos` references in the book,
|
// get list of all `filepos` references in the book,
|
||||||
// which will be used to insert anchor elements
|
// which will be used to insert anchor elements
|
||||||
// because only then can they be referenced in the DOM
|
// because only then can they be referenced in the DOM
|
||||||
this.#fileposList = [...new Set(fileposInNCX
|
this.#fileposList = [...new Set(
|
||||||
.concat(Array.from(str.matchAll(fileposRegex), m => m[1])))]
|
Array.from(str.matchAll(fileposRegex), m => m[1]))]
|
||||||
.map(filepos => ({ filepos, number: Number(filepos) }))
|
.map(filepos => ({ filepos, number: Number(filepos) }))
|
||||||
.sort((a, b) => a.number - b.number)
|
.sort((a, b) => a.number - b.number)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user