diff --git a/cps/static/js/reading/epub-progress.js b/cps/static/js/reading/epub-progress.js index 4141b485..58fb60ea 100644 --- a/cps/static/js/reading/epub-progress.js +++ b/cps/static/js/reading/epub-progress.js @@ -20,6 +20,7 @@ class EpubParser { } /** + * gets file from files and returns decompressed content as string * @param {string} filename name of the file in filelist * @return {string} string representation of decompressed bytes */ @@ -44,7 +45,7 @@ class EpubParser { resolves an idref in content.opf to its file */ resolveIDref(idref) { - return this.opfXml.getElementById(idref).getAttribute("href"); + return this.absPath(this.opfXml.getElementById(idref).getAttribute("href")); } /** @@ -67,7 +68,7 @@ class EpubParser { let bytesize = 0; for (let file of this.getSpine()) { if (file !== currentFile) { - let filepath = this.absPath(this.resolveIDref(file)); + let filepath = this.resolveIDref(file); //ignore non text files if (filepath.endsWith("html")) { console.log(filepath + " " + bytesize) @@ -79,34 +80,89 @@ class EpubParser { } return bytesize; } - cfiToXmlNode(file,cfi){ + + /** + * 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) + * @return XML Text-Node + */ + cfiToXmlNode(cfi) { + let cfiPath = cfi.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"); + 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(currentFile, CFI) { - let size = 0 - let startnode = this.cfiToXmlNode(currentFile,CFI); - let prev = startnode.previousElementSibling; + getCurrentFileProgress(CFI) { + let size = parseInt(CFI.split(":")[1])//text offset in node + let startnode = this.cfiToXmlNode(CFI); //returns text node + let xmlnsLength = startnode.parentNode.namespaceURI.length; + let prev = startnode.parentNode.previousElementSibling; while (prev !== null) { - size += this.encoder.encode(prev.outerHTML).length; + 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; prev = prev.previousElementSibling; } - let parent = startnode.parentElement; + let parent = startnode.parentElement.parentElement; while (parent !== null) { let parentPrev = parent.previousElementSibling; while (parentPrev !== null) { - size += this.encoder.encode(parentPrev.outerHTML).length; + console.log(parentPrev.outerHTML) + console.log(this.encoder.encode(parentPrev.outerHTML).length - xmlnsLength) + + size += this.encoder.encode(parentPrev.outerHTML).length - xmlnsLength; parentPrev = parentPrev.previousElementSibling; } - parent=parent.parentElement; + parent = parent.parentElement; } return size; } getProgress(currentFile, CFI) { - let percentage = this.getTotalByteLength() / (this.getPreviousFilesSize(currentFile) + this.getCurrentFileProgress(currentFile, CFI)); + let percentage = this.getTotalByteLength() / (this.getPreviousFilesSize(currentFile) + this.getCurrentFileProgress(CFI)); if (percentage === Infinity) { return 0; } else { @@ -114,3 +170,5 @@ class EpubParser { } } } + +e = new EpubParser(reader.book.archive.zip.files)