mirror of
https://github.com/john-okeefe/foliate-js.git
synced 2026-09-09 11:29:14 -04:00
Add destroy method
Which revokes all blob URLs and removes the element from document.
This commit is contained in:
@@ -36,5 +36,9 @@ export const makeComicBook = ({ entries, loadBlob, getSize }, file) => {
|
|||||||
book.resolveHref = href => ({ index: book.sections.findIndex(s => s.id === href) })
|
book.resolveHref = href => ({ index: book.sections.findIndex(s => s.id === href) })
|
||||||
book.splitTOCHref = href => [href, null]
|
book.splitTOCHref = href => [href, null]
|
||||||
book.getTOCFragment = doc => doc.documentElement
|
book.getTOCFragment = doc => doc.documentElement
|
||||||
|
book.destroy = () => {
|
||||||
|
for (const arr of urls.values())
|
||||||
|
for (const url of arr) URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
return book
|
return book
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -611,6 +611,9 @@ class Loader {
|
|||||||
unloadItem(item) {
|
unloadItem(item) {
|
||||||
this.unref(item?.href)
|
this.unref(item?.href)
|
||||||
}
|
}
|
||||||
|
destroy() {
|
||||||
|
for (const url of this.#cache.values()) URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getHTMLFragment = (doc, id) => doc.getElementById(id)
|
const getHTMLFragment = (doc, id) => doc.getElementById(id)
|
||||||
@@ -628,6 +631,7 @@ const getPageSpread = properties => {
|
|||||||
|
|
||||||
export class EPUB {
|
export class EPUB {
|
||||||
parser = new DOMParser()
|
parser = new DOMParser()
|
||||||
|
#loader
|
||||||
#encryption
|
#encryption
|
||||||
constructor({ loadText, loadBlob, getSize, sha1 }) {
|
constructor({ loadText, loadBlob, getSize, sha1 }) {
|
||||||
this.loadText = loadText
|
this.loadText = loadText
|
||||||
@@ -662,7 +666,7 @@ export class EPUB {
|
|||||||
opf,
|
opf,
|
||||||
resolveHref: url => resolveURL(url, opfPath),
|
resolveHref: url => resolveURL(url, opfPath),
|
||||||
})
|
})
|
||||||
const loader = new Loader({
|
this.#loader = new Loader({
|
||||||
loadText: this.loadText,
|
loadText: this.loadText,
|
||||||
loadBlob: uri => Promise.resolve(this.loadBlob(uri))
|
loadBlob: uri => Promise.resolve(this.loadBlob(uri))
|
||||||
.then(this.#encryption.getDecoder(uri)),
|
.then(this.#encryption.getDecoder(uri)),
|
||||||
@@ -677,8 +681,8 @@ export class EPUB {
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
id: this.resources.getItemByID(idref)?.href,
|
id: this.resources.getItemByID(idref)?.href,
|
||||||
load: () => loader.loadItem(item),
|
load: () => this.#loader.loadItem(item),
|
||||||
unload: () => loader.unloadItem(item),
|
unload: () => this.#loader.unloadItem(item),
|
||||||
createDocument: () => this.loadDocument(item),
|
createDocument: () => this.loadDocument(item),
|
||||||
size: this.getSize(item.href),
|
size: this.getSize(item.href),
|
||||||
cfi: this.resources.cfis[index],
|
cfi: this.resources.cfis[index],
|
||||||
@@ -805,4 +809,7 @@ export class EPUB {
|
|||||||
return JSON.parse(json)
|
return JSON.parse(json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
destroy() {
|
||||||
|
this.#loader?.destroy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,6 +272,7 @@ export const makeFB2 = async blob => {
|
|||||||
}), converted]
|
}), converted]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const urls = []
|
||||||
const sectionData = bodyData[0][0]
|
const sectionData = bodyData[0][0]
|
||||||
// make a separate section for each section in the first body
|
// make a separate section for each section in the first body
|
||||||
.map(({ el, ids }) => {
|
.map(({ el, ids }) => {
|
||||||
@@ -294,6 +295,7 @@ export const makeFB2 = async blob => {
|
|||||||
const str = template(el.outerHTML)
|
const str = template(el.outerHTML)
|
||||||
const blob = new Blob([str], { type: MIME.XHTML })
|
const blob = new Blob([str], { type: MIME.XHTML })
|
||||||
const url = URL.createObjectURL(blob)
|
const url = URL.createObjectURL(blob)
|
||||||
|
urls.push(url)
|
||||||
const title = normalizeWhitespace(
|
const title = normalizeWhitespace(
|
||||||
el.querySelector('.title, .subtitle, p')?.textContent
|
el.querySelector('.title, .subtitle, p')?.textContent
|
||||||
?? (el.classList.contains('title') ? el.textContent : ''))
|
?? (el.classList.contains('title') ? el.textContent : ''))
|
||||||
@@ -338,5 +340,8 @@ export const makeFB2 = async blob => {
|
|||||||
book.splitTOCHref = href => href?.split('#')?.map(x => Number(x)) ?? []
|
book.splitTOCHref = href => href?.split('#')?.map(x => Number(x)) ?? []
|
||||||
book.getTOCFragment = (doc, id) => doc.querySelector(`[${dataID}="${id}"]`)
|
book.getTOCFragment = (doc, id) => doc.querySelector(`[${dataID}="${id}"]`)
|
||||||
|
|
||||||
|
book.destroy = () => {
|
||||||
|
for (const url of urls) URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
return book
|
return book
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -30,6 +30,7 @@ const getViewport = (doc, viewport) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Container {
|
class Container {
|
||||||
|
#observer = new ResizeObserver(() => this.render())
|
||||||
#element = document.createElement('div')
|
#element = document.createElement('div')
|
||||||
defaultViewport
|
defaultViewport
|
||||||
spread
|
spread
|
||||||
@@ -46,7 +47,7 @@ class Container {
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
})
|
})
|
||||||
new ResizeObserver(() => this.render()).observe(this.#element)
|
this.#observer.observe(this.#element)
|
||||||
}
|
}
|
||||||
get element() {
|
get element() {
|
||||||
return this.#element
|
return this.#element
|
||||||
@@ -170,6 +171,10 @@ class Container {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
destroy() {
|
||||||
|
this.#observer.unobserve(this.#element)
|
||||||
|
this.#element.remove()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class FixedLayout {
|
export class FixedLayout {
|
||||||
@@ -289,4 +294,7 @@ export class FixedLayout {
|
|||||||
for (const frame of this.#container.element.querySelectorAll('iframe'))
|
for (const frame of this.#container.element.querySelectorAll('iframe'))
|
||||||
frame.contentWindow.getSelection().removeAllRanges()
|
frame.contentWindow.getSelection().removeAllRanges()
|
||||||
}
|
}
|
||||||
|
destroy() {
|
||||||
|
this.#container.destroy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -842,6 +842,10 @@ class MOBI6 {
|
|||||||
isExternal(uri) {
|
isExternal(uri) {
|
||||||
return /^(?!blob|filepos)\w+:/i.test(uri)
|
return /^(?!blob|filepos)\w+:/i.test(uri)
|
||||||
}
|
}
|
||||||
|
destroy() {
|
||||||
|
for (const url of this.#resourceCache.values()) URL.revokeObjectURL(url)
|
||||||
|
for (const url of this.#cache.values()) URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handlers for `kindle:` uris
|
// handlers for `kindle:` uris
|
||||||
@@ -1154,4 +1158,7 @@ class KF8 {
|
|||||||
isExternal(uri) {
|
isExternal(uri) {
|
||||||
return /^(?!blob|kindle)\w+:/i.test(uri)
|
return /^(?!blob|kindle)\w+:/i.test(uri)
|
||||||
}
|
}
|
||||||
|
destroy() {
|
||||||
|
for (const url of this.#cache.values()) URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-1
@@ -329,6 +329,7 @@ class View {
|
|||||||
export class Paginator {
|
export class Paginator {
|
||||||
#gap = 0
|
#gap = 0
|
||||||
#shouldUpdateGap = true
|
#shouldUpdateGap = true
|
||||||
|
#observer = new ResizeObserver(() => this.render())
|
||||||
#element = document.createElement('div')
|
#element = document.createElement('div')
|
||||||
#background = document.createElement('div')
|
#background = document.createElement('div')
|
||||||
#maxSizeContainer = document.createElement('div')
|
#maxSizeContainer = document.createElement('div')
|
||||||
@@ -394,7 +395,7 @@ export class Paginator {
|
|||||||
this.#maxSizeContainer.append(this.#header)
|
this.#maxSizeContainer.append(this.#header)
|
||||||
this.#maxSizeContainer.append(this.#footer)
|
this.#maxSizeContainer.append(this.#footer)
|
||||||
|
|
||||||
new ResizeObserver(() => this.render()).observe(this.#element)
|
this.#observer.observe(this.#element)
|
||||||
this.#container.addEventListener('scroll', debounce(() => {
|
this.#container.addEventListener('scroll', debounce(() => {
|
||||||
if (this.scrolled) this.#afterScroll('scroll')
|
if (this.scrolled) this.#afterScroll('scroll')
|
||||||
}, 250))
|
}, 250))
|
||||||
@@ -774,4 +775,8 @@ export class Paginator {
|
|||||||
this.#anchor = anchor
|
this.#anchor = anchor
|
||||||
await this.#scrollToAnchor(select)
|
await this.#scrollToAnchor(select)
|
||||||
}
|
}
|
||||||
|
destroy() {
|
||||||
|
this.#observer.unobserve(this.#element)
|
||||||
|
this.#element.remove()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user