summaryrefslogtreecommitdiff
path: root/lib/epub.js/src/pagelist.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/epub.js/src/pagelist.js')
-rw-r--r--lib/epub.js/src/pagelist.js274
1 files changed, 274 insertions, 0 deletions
diff --git a/lib/epub.js/src/pagelist.js b/lib/epub.js/src/pagelist.js
new file mode 100644
index 0000000..6de82f6
--- /dev/null
+++ b/lib/epub.js/src/pagelist.js
@@ -0,0 +1,274 @@
+import EpubCFI from "./epubcfi";
+import {
+ qs,
+ qsa,
+ querySelectorByType,
+ indexOfSorted,
+ locationOf
+} from "./utils/core";
+
+/**
+ * Page List Parser
+ * @param {document} [xml]
+ */
+class PageList {
+ constructor(xml) {
+ this.pages = [];
+ this.locations = [];
+ this.epubcfi = new EpubCFI();
+
+ this.firstPage = 0;
+ this.lastPage = 0;
+ this.totalPages = 0;
+
+ this.toc = undefined;
+ this.ncx = undefined;
+
+ if (xml) {
+ this.pageList = this.parse(xml);
+ }
+
+ if(this.pageList && this.pageList.length) {
+ this.process(this.pageList);
+ }
+ }
+
+ /**
+ * Parse PageList Xml
+ * @param {document} xml
+ */
+ parse(xml) {
+ var html = qs(xml, "html");
+ var ncx = qs(xml, "ncx");
+
+ if(html) {
+ return this.parseNav(xml);
+ } else if(ncx){
+ return this.parseNcx(xml);
+ }
+
+ }
+
+ /**
+ * Parse a Nav PageList
+ * @private
+ * @param {node} navHtml
+ * @return {PageList.item[]} list
+ */
+ parseNav(navHtml){
+ var navElement = querySelectorByType(navHtml, "nav", "page-list");
+ var navItems = navElement ? qsa(navElement, "li") : [];
+ var length = navItems.length;
+ var i;
+ var list = [];
+ var item;
+
+ if(!navItems || length === 0) return list;
+
+ for (i = 0; i < length; ++i) {
+ item = this.item(navItems[i]);
+ list.push(item);
+ }
+
+ return list;
+ }
+
+ parseNcx(navXml) {
+ var list = [];
+ var i = 0;
+ var item;
+ var pageList;
+ var pageTargets;
+ var length = 0;
+
+ pageList = qs(navXml, "pageList");
+ if (!pageList) return list;
+
+ pageTargets = qsa(pageList, "pageTarget");
+ length = pageTargets.length;
+
+ if (!pageTargets || pageTargets.length === 0) {
+ return list;
+ }
+
+ for (i = 0; i < length; ++i) {
+ item = this.ncxItem(pageTargets[i]);
+ list.push(item);
+ }
+
+ return list;
+ }
+
+ ncxItem(item) {
+ var navLabel = qs(item, "navLabel");
+ var navLabelText = qs(navLabel, "text");
+ var pageText = navLabelText.textContent;
+ var content = qs(item, "content");
+
+ var href = content.getAttribute("src");
+ var page = parseInt(pageText, 10);
+
+ return {
+ "href": href,
+ "page": page,
+ };
+ }
+
+ /**
+ * Page List Item
+ * @private
+ * @param {node} item
+ * @return {object} pageListItem
+ */
+ item(item){
+ var content = qs(item, "a"),
+ href = content.getAttribute("href") || "",
+ text = content.textContent || "",
+ page = parseInt(text),
+ isCfi = href.indexOf("epubcfi"),
+ split,
+ packageUrl,
+ cfi;
+
+ if(isCfi != -1) {
+ split = href.split("#");
+ packageUrl = split[0];
+ cfi = split.length > 1 ? split[1] : false;
+ return {
+ "cfi" : cfi,
+ "href" : href,
+ "packageUrl" : packageUrl,
+ "page" : page
+ };
+ } else {
+ return {
+ "href" : href,
+ "page" : page
+ };
+ }
+ }
+
+ /**
+ * Process pageList items
+ * @private
+ * @param {array} pageList
+ */
+ process(pageList){
+ pageList.forEach(function(item){
+ this.pages.push(item.page);
+ if (item.cfi) {
+ this.locations.push(item.cfi);
+ }
+ }, this);
+ this.firstPage = parseInt(this.pages[0]);
+ this.lastPage = parseInt(this.pages[this.pages.length-1]);
+ this.totalPages = this.lastPage - this.firstPage;
+ }
+
+ /**
+ * Get a PageList result from a EpubCFI
+ * @param {string} cfi EpubCFI String
+ * @return {number} page
+ */
+ pageFromCfi(cfi){
+ var pg = -1;
+
+ // Check if the pageList has not been set yet
+ if(this.locations.length === 0) {
+ return -1;
+ }
+
+ // TODO: check if CFI is valid?
+
+ // check if the cfi is in the location list
+ // var index = this.locations.indexOf(cfi);
+ var index = indexOfSorted(cfi, this.locations, this.epubcfi.compare);
+ if(index != -1) {
+ pg = this.pages[index];
+ } else {
+ // Otherwise add it to the list of locations
+ // Insert it in the correct position in the locations page
+ //index = EPUBJS.core.insert(cfi, this.locations, this.epubcfi.compare);
+ index = locationOf(cfi, this.locations, this.epubcfi.compare);
+ // Get the page at the location just before the new one, or return the first
+ pg = index-1 >= 0 ? this.pages[index-1] : this.pages[0];
+ if(pg !== undefined) {
+ // Add the new page in so that the locations and page array match up
+ //this.pages.splice(index, 0, pg);
+ } else {
+ pg = -1;
+ }
+
+ }
+ return pg;
+ }
+
+ /**
+ * Get an EpubCFI from a Page List Item
+ * @param {string | number} pg
+ * @return {string} cfi
+ */
+ cfiFromPage(pg){
+ var cfi = -1;
+ // check that pg is an int
+ if(typeof pg != "number"){
+ pg = parseInt(pg);
+ }
+
+ // check if the cfi is in the page list
+ // Pages could be unsorted.
+ var index = this.pages.indexOf(pg);
+ if(index != -1) {
+ cfi = this.locations[index];
+ }
+ // TODO: handle pages not in the list
+ return cfi;
+ }
+
+ /**
+ * Get a Page from Book percentage
+ * @param {number} percent
+ * @return {number} page
+ */
+ pageFromPercentage(percent){
+ var pg = Math.round(this.totalPages * percent);
+ return pg;
+ }
+
+ /**
+ * Returns a value between 0 - 1 corresponding to the location of a page
+ * @param {number} pg the page
+ * @return {number} percentage
+ */
+ percentageFromPage(pg){
+ var percentage = (pg - this.firstPage) / this.totalPages;
+ return Math.round(percentage * 1000) / 1000;
+ }
+
+ /**
+ * Returns a value between 0 - 1 corresponding to the location of a cfi
+ * @param {string} cfi EpubCFI String
+ * @return {number} percentage
+ */
+ percentageFromCfi(cfi){
+ var pg = this.pageFromCfi(cfi);
+ var percentage = this.percentageFromPage(pg);
+ return percentage;
+ }
+
+ /**
+ * Destroy
+ */
+ destroy() {
+ this.pages = undefined;
+ this.locations = undefined;
+ this.epubcfi = undefined;
+
+ this.pageList = undefined;
+
+ this.toc = undefined;
+ this.ncx = undefined;
+ }
+}
+
+export default PageList;