1
0
mirror of https://github.com/janeczku/calibre-web synced 2024-12-22 16:10:30 +00:00

-added pako and epub-cfi-resolver as dependencies

-cfi resolving is now done by that module, therefore removed validateChildNodes and adjusted cfiToXmlNode
This commit is contained in:
quarz12 2023-05-24 21:05:50 +02:00
parent 617ee3d781
commit 99c05650a1
4 changed files with 1088 additions and 66 deletions

1062
cps/static/js/libs/epub-cfi-resolver.js vendored Normal file

File diff suppressed because it is too large Load Diff

2
cps/static/js/libs/pako.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -6,8 +6,7 @@ class EpubParser {
this.encoder = new TextEncoder(); this.encoder = new TextEncoder();
} }
getTotalByteLength() {
getTotalByteLength() { //TODO unrealistic values
let size = 0; let size = 0;
for (let key of Object.keys(this.files)) { for (let key of Object.keys(this.files)) {
let file = this.files[key]; let file = this.files[key];
@ -36,7 +35,6 @@ class EpubParser {
return this.parser.parseFromString(this.decompress(path), "text/xml"); return this.parser.parseFromString(this.decompress(path), "text/xml");
} }
getSpine() { getSpine() {
return Array.from(this.opfXml.getElementsByTagName("spine")[0].children).map(node => node.getAttribute("idref")); return Array.from(this.opfXml.getElementsByTagName("spine")[0].children).map(node => node.getAttribute("idref"));
} }
@ -81,71 +79,32 @@ class EpubParser {
} }
return bytesize; return bytesize;
} }
getIdRef(filepath){ getIdRef(filepath){
return this.opfXml.querySelector(`[href="${filepath}"]`).getAttribute("id"); return this.opfXml.querySelector(`[href="${filepath}"]`).getAttribute("id");
} }
/** /**
* resolves the given cfi to the xml node it points to * resolves the given cfi to the xml node it points to
* @param {string} cfi epub-cfi string in the form: epubcfi(/6/16[id13]!/4[id2]/4/2[doc12]/1:0) * @param {string} cfistr epub-cfi string in the form: epubcfi(/6/16[id13]!/4[id2]/4/2[doc12]/1:0)
* @return XML Text-Node * @return object with attributes "node" and "offset"
*/ */
cfiToXmlNode(cfi) { cfiToXmlNode(cfistr) {
let cfiPath = cfi.split("(")[1].split(")")[0]; let cfi = new CFI(cfistr);
let cfiPath = cfistr.split("(")[1].split(")")[0];
let fileId = cfiPath.split("!")[0].split("[")[1].split("]")[0]; let fileId = cfiPath.split("!")[0].split("[")[1].split("]")[0];
let xml = this.parser.parseFromString(this.decompress(this.resolveIDref(fileId)), "text/xml"); return cfi.resolveLast(this.parser.parseFromString(this.decompress(this.resolveIDref(fileId)),"text/xml"));
let components = cfiPath.split("!")[1].split("/").slice(1);
let currentNode = xml.getElementsByTagName("html")[0];
for (const component of components) {
this.validateChildNodes(currentNode);
// console.log(currentNode);
// console.log(component);
let index = 0;
if (component.includes("[")) {
index = parseInt(component.split("[")[0]) - 1;
currentNode = currentNode.childNodes[index];
console.assert(currentNode.getAttribute("id") === component.split("[")[1].split("]")[0], "failed to resolve node");
} else if (component.includes(":")) {
index = component.split(":")[0] - 1;
return currentNode.childNodes[index]; //exit point
} else {
index = parseInt(component);
currentNode = currentNode.childNodes[index - 1];
}
}
}
/**
* inserts missing text/element nodes to keep them alternating
* @param {*} parentNode
*/
validateChildNodes(parentNode) {
for (let index = 0; index < parentNode.childNodes.length;) {
const element = parentNode.childNodes[index];
if (index % 2 === 0 && element.nodeType === 1) {
element.parentNode.insertBefore(parentNode.ownerDocument.createTextNode(""), element);
continue;
}
if (index % 2 === 1 && element.nodeType === 3) {
element.insertBefore(parentNode.ownerDocument.createElement("")); //TODO check
continue;
}
index++;
}
} }
/** /**
takes the node that the cfi points at and counts the bytes of all nodes before that takes the node that the cfi points at and counts the bytes of all nodes before that
*/ */
getCurrentFileProgress(CFI) { getCurrentFileProgress(CFI) {
let size = parseInt(CFI.split(":")[1])//text offset in node let parse=this.cfiToXmlNode(CFI);
let startnode = this.cfiToXmlNode(CFI); //returns text node let size=parse.offset;
let startnode = parse.node//returns text node
let xmlnsLength = startnode.parentNode.namespaceURI.length; let xmlnsLength = startnode.parentNode.namespaceURI.length;
let prev = startnode.parentNode.previousElementSibling; let prev = startnode.parentNode.previousElementSibling;
while (prev !== null) { while (prev !== null) {
// console.log("size: "+size)
// console.log(prev.outerHTML)
// console.log(this.encoder.encode(prev.outerHTML).length - xmlnsLength)
size += this.encoder.encode(prev.outerHTML).length - xmlnsLength; size += this.encoder.encode(prev.outerHTML).length - xmlnsLength;
prev = prev.previousElementSibling; prev = prev.previousElementSibling;
} }
@ -153,9 +112,6 @@ class EpubParser {
while (parent !== null) { while (parent !== null) {
let parentPrev = parent.previousElementSibling; let parentPrev = parent.previousElementSibling;
while (parentPrev !== null) { while (parentPrev !== null) {
// console.log(parentPrev.outerHTML)
// console.log(this.encoder.encode(parentPrev.outerHTML).length - xmlnsLength)
size += this.encoder.encode(parentPrev.outerHTML).length - xmlnsLength; size += this.encoder.encode(parentPrev.outerHTML).length - xmlnsLength;
parentPrev = parentPrev.previousElementSibling; parentPrev = parentPrev.previousElementSibling;
} }
@ -167,7 +123,7 @@ class EpubParser {
/** /**
* @param currentFile filepath * @param currentFile filepath
* @param CFI * @param CFI
* @return {number} percentage * @return {number} percentage as decimal
*/ */
getProgress(currentFile, CFI) { getProgress(currentFile, CFI) {
let percentage = (this.getPreviousFilesSize(currentFile) + this.getCurrentFileProgress(CFI))/this.getTotalByteLength(); let percentage = (this.getPreviousFilesSize(currentFile) + this.getCurrentFileProgress(CFI))/this.getTotalByteLength();
@ -181,6 +137,8 @@ class EpubParser {
} }
} }
} }
//wait until variable is assigned a value
function waitFor(variable, callback) { function waitFor(variable, callback) {
const interval = setInterval(function() { const interval = setInterval(function() {
if (variable!==undefined) { if (variable!==undefined) {
@ -198,14 +156,9 @@ function calculateProgress(){
let data=reader.rendition.currentLocation().end; let data=reader.rendition.currentLocation().end;
return Math.round(epubParser.getProgress(data.href,data.cfi)*100); return Math.round(epubParser.getProgress(data.href,data.cfi)*100);
} }
var epubParser;
waitFor(reader.book,()=>{ // register new event emitter locationchange that fires on urlchange
epubParser = new EpubParser(reader.book.archive.zip.files); // source: https://stackoverflow.com/a/52809105/21941129
});
/*
register new event emitter locationchange that fires on urlchange
source: https://stackoverflow.com/a/52809105/21941129
*/
(() => { (() => {
let oldPushState = history.pushState; let oldPushState = history.pushState;
history.pushState = function pushState() { history.pushState = function pushState() {
@ -225,10 +178,14 @@ source: https://stackoverflow.com/a/52809105/21941129
window.dispatchEvent(new Event('locationchange')); window.dispatchEvent(new Event('locationchange'));
}); });
})(); })();
var epubParser;
waitFor(reader.book,()=>{
epubParser = new EpubParser(reader.book.archive.zip.files);
});
let progressDiv=document.getElementById("progress"); let progressDiv=document.getElementById("progress");
window.addEventListener('locationchange',()=>{ window.addEventListener('locationchange',()=>{
let newPos=calculateProgress(); let newPos=calculateProgress();
console.log(newPos);
progressDiv.textContent=newPos+"%"; progressDiv.textContent=newPos+"%";
//getelement set element value
}); });

View File

@ -154,5 +154,6 @@
<script src="{{ url_for('static', filename='js/reading/epub.js') }}"></script> <script src="{{ url_for('static', filename='js/reading/epub.js') }}"></script>
<script src="{{ url_for('static', filename='js/reading/epub-progress.js') }}"></script> <script src="{{ url_for('static', filename='js/reading/epub-progress.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/pako.min.js') }}"></script> <script src="{{ url_for('static', filename='js/libs/pako.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/libs/epub-cfi-resolver.js') }}"></script>
</body> </body>
</html> </html>