mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +02:00
Documentation clean up
This commit is contained in:
parent
7ff4c8e37c
commit
77846842cd
20 changed files with 1090 additions and 8239 deletions
|
@ -1,28 +1,9 @@
|
|||
// Manage annotations for a book?
|
||||
|
||||
/*
|
||||
let a = rendition.annotations.highlight(cfiRange, data)
|
||||
|
||||
a.on("added", () => console.log("added"))
|
||||
a.on("removed", () => console.log("removed"))
|
||||
a.on("clicked", () => console.log("clicked"))
|
||||
|
||||
a.update(data)
|
||||
a.remove();
|
||||
a.text();
|
||||
|
||||
rendition.annotations.show()
|
||||
rendition.annotations.hide()
|
||||
|
||||
rendition.annotations.highlights.show()
|
||||
rendition.annotations.highlights.hide()
|
||||
*/
|
||||
|
||||
import EventEmitter from "event-emitter";
|
||||
import EpubCFI from "./epubcfi";
|
||||
|
||||
/**
|
||||
* Handles managing adding & removing Annotations
|
||||
* @param {Rendition} rendition
|
||||
* @class
|
||||
*/
|
||||
class Annotations {
|
||||
|
@ -39,6 +20,14 @@ class Annotations {
|
|||
this.rendition.hooks.unloaded.register(this.clear.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an annotation to store
|
||||
* @param {string} type Type of annotation to add: "highlight", "underline", "mark"
|
||||
* @param {EpubCFI} cfiRange EpubCFI range to attach annotation to
|
||||
* @param {object} data Data to assign to annotation
|
||||
* @param {function} [cb] Callback after annotation is added
|
||||
* @returns {Annotation} annotation
|
||||
*/
|
||||
add (type, cfiRange, data, cb) {
|
||||
let hash = encodeURI(cfiRange);
|
||||
let cfi = new EpubCFI(cfiRange);
|
||||
|
@ -70,6 +59,11 @@ class Annotations {
|
|||
return annotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an annotation from store
|
||||
* @param {EpubCFI} cfiRange EpubCFI range the annotation is attached to
|
||||
* @param {string} type Type of annotation to add: "highlight", "underline", "mark"
|
||||
*/
|
||||
remove (cfiRange, type) {
|
||||
let hash = encodeURI(cfiRange);
|
||||
|
||||
|
@ -92,30 +86,65 @@ class Annotations {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an annotations by Section Index
|
||||
* @private
|
||||
*/
|
||||
_removeFromAnnotationBySectionIndex (sectionIndex, hash) {
|
||||
this._annotationsBySectionIndex[sectionIndex] = this._annotationsAt(sectionIndex).filter(h => h !== hash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get annotations by Section Index
|
||||
* @private
|
||||
*/
|
||||
_annotationsAt (index) {
|
||||
return this._annotationsBySectionIndex[index];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a highlight to the store
|
||||
* @param {EpubCFI} cfiRange EpubCFI range to attach annotation to
|
||||
* @param {object} data Data to assign to annotation
|
||||
* @param {function} cb Callback after annotation is added
|
||||
*/
|
||||
highlight (cfiRange, data, cb) {
|
||||
this.add("highlight", cfiRange, data, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a underline to the store
|
||||
* @param {EpubCFI} cfiRange EpubCFI range to attach annotation to
|
||||
* @param {object} data Data to assign to annotation
|
||||
* @param {function} cb Callback after annotation is added
|
||||
*/
|
||||
underline (cfiRange, data, cb) {
|
||||
this.add("underline", cfiRange, data, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a mark to the store
|
||||
* @param {EpubCFI} cfiRange EpubCFI range to attach annotation to
|
||||
* @param {object} data Data to assign to annotation
|
||||
* @param {function} cb Callback after annotation is added
|
||||
*/
|
||||
mark (cfiRange, data, cb) {
|
||||
this.add("mark", cfiRange, data, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* iterate over annotations in the store
|
||||
*/
|
||||
each () {
|
||||
return this._annotations.forEach.apply(this._annotations, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for injecting annotation into a view
|
||||
* @param {View} view
|
||||
* @private
|
||||
*/
|
||||
inject (view) {
|
||||
let sectionIndex = view.index;
|
||||
if (sectionIndex in this._annotationsBySectionIndex) {
|
||||
|
@ -127,6 +156,11 @@ class Annotations {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for removing annotation from a view
|
||||
* @param {View} view
|
||||
* @private
|
||||
*/
|
||||
clear (view) {
|
||||
let sectionIndex = view.index;
|
||||
if (sectionIndex in this._annotationsBySectionIndex) {
|
||||
|
@ -138,16 +172,35 @@ class Annotations {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* [Not Implemented] Show annotations
|
||||
* @TODO: needs implementation in View
|
||||
*/
|
||||
show () {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* [Not Implemented] Hide annotations
|
||||
* @TODO: needs implementation in View
|
||||
*/
|
||||
hide () {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Annotation object
|
||||
* @class
|
||||
* @param {object} options
|
||||
* @param {string} options.type Type of annotation to add: "highlight", "underline", "mark"
|
||||
* @param {EpubCFI} options.cfiRange EpubCFI range to attach annotation to
|
||||
* @param {object} options.data Data to assign to annotation
|
||||
* @param {int} options.sectionIndex Index in the Spine of the Section annotation belongs to
|
||||
* @param {function} [options.cb] Callback after annotation is added
|
||||
* @returns {Annotation} annotation
|
||||
*/
|
||||
class Annotation {
|
||||
|
||||
constructor ({
|
||||
|
@ -165,18 +218,21 @@ class Annotation {
|
|||
this.cb = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update stored data
|
||||
* @param {object} data
|
||||
*/
|
||||
update (data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add to a view
|
||||
* @param {View} view
|
||||
*/
|
||||
attach (view) {
|
||||
let {cfiRange, data, type, mark, cb} = this;
|
||||
let result;
|
||||
/*
|
||||
if (mark) {
|
||||
return; // already added
|
||||
}
|
||||
*/
|
||||
|
||||
if (type === "highlight") {
|
||||
result = view.highlight(cfiRange, data, cb);
|
||||
|
@ -191,6 +247,10 @@ class Annotation {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove from a view
|
||||
* @param {View} view
|
||||
*/
|
||||
detach (view) {
|
||||
let {cfiRange, type} = this;
|
||||
let result;
|
||||
|
@ -210,8 +270,12 @@ class Annotation {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* [Not Implemented] Get text of an annotation
|
||||
* @TODO: needs implementation in contents
|
||||
*/
|
||||
text () {
|
||||
// TODO: needs implementation in contents
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ class Archive {
|
|||
}
|
||||
|
||||
/**
|
||||
* Request
|
||||
* Request a url from the archive
|
||||
* @param {string} url a url to request from the archive
|
||||
* @param {[string]} type specify the type of the returned result
|
||||
* @param {string} [type] specify the type of the returned result
|
||||
* @return {Promise}
|
||||
*/
|
||||
request(url, type){
|
||||
|
@ -98,7 +98,7 @@ class Archive {
|
|||
* Handle the response from request
|
||||
* @private
|
||||
* @param {any} response
|
||||
* @param {[string]} type
|
||||
* @param {string} [type]
|
||||
* @return {any} the parsed result
|
||||
*/
|
||||
handleResponse(response, type){
|
||||
|
@ -128,7 +128,7 @@ class Archive {
|
|||
/**
|
||||
* Get a Blob from Archive by Url
|
||||
* @param {string} url
|
||||
* @param {[string]} mimeType
|
||||
* @param {string} [mimeType]
|
||||
* @return {Blob}
|
||||
*/
|
||||
getBlob(url, mimeType){
|
||||
|
@ -146,7 +146,7 @@ class Archive {
|
|||
/**
|
||||
* Get Text from Archive by Url
|
||||
* @param {string} url
|
||||
* @param {[string]} encoding
|
||||
* @param {string} [encoding]
|
||||
* @return {string}
|
||||
*/
|
||||
getText(url, encoding){
|
||||
|
@ -163,7 +163,7 @@ class Archive {
|
|||
/**
|
||||
* Get a base64 encoded result from Archive by Url
|
||||
* @param {string} url
|
||||
* @param {[string]} mimeType
|
||||
* @param {string} [mimeType]
|
||||
* @return {string} base64 encoded
|
||||
*/
|
||||
getBase64(url, mimeType){
|
||||
|
@ -181,7 +181,7 @@ class Archive {
|
|||
/**
|
||||
* Create a Url from an unarchived item
|
||||
* @param {string} url
|
||||
* @param {[object]} options.base64 use base64 encoding or blob url
|
||||
* @param {object} [options.base64] use base64 encoding or blob url
|
||||
* @return {Promise} url promise with Url string
|
||||
*/
|
||||
createUrl(url, options){
|
||||
|
|
132
src/book.js
132
src/book.js
|
@ -1,5 +1,4 @@
|
|||
import EventEmitter from "event-emitter";
|
||||
// import path from "path";
|
||||
import {extend, defer} from "./utils/core";
|
||||
import Url from "./utils/url";
|
||||
import Path from "./utils/path";
|
||||
|
@ -19,16 +18,27 @@ import { EVENTS } from "./utils/constants";
|
|||
const CONTAINER_PATH = "META-INF/container.xml";
|
||||
const EPUBJS_VERSION = "0.3";
|
||||
|
||||
const INPUT_TYPE = {
|
||||
BINARY: "binary",
|
||||
BASE64: "base64",
|
||||
EPUB: "epub",
|
||||
OPF: "opf",
|
||||
MANIFEST: "json",
|
||||
DIRECTORY: "directory"
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new Book
|
||||
* An Epub representation with methods for the loading, parsing and manipulation
|
||||
* of its contents.
|
||||
* @class
|
||||
* @param {string} url
|
||||
* @param {object} options
|
||||
* @param {method} options.requestMethod a request function to use instead of the default
|
||||
* @param {string} [url]
|
||||
* @param {object} [options]
|
||||
* @param {method} [options.requestMethod] a request function to use instead of the default
|
||||
* @param {boolean} [options.requestCredentials=undefined] send the xhr request withCredentials
|
||||
* @param {object} [options.requestHeaders=undefined] send the xhr request headers
|
||||
* @param {string} [options.encoding=binary] optional to pass 'binary' or base64' for archived Epubs
|
||||
* @param {string} [options.replacements=none] use base64, blobUrl, or none for replacing assets in archived Epubs
|
||||
* @param {method} [options.canonical] optional function to determine canonical urls for a path
|
||||
* @returns {Book}
|
||||
* @example new Book("/path/to/book.epub", {})
|
||||
* @example new Book({ replacements: "blobUrl" })
|
||||
|
@ -57,7 +67,8 @@ class Book {
|
|||
// Promises
|
||||
this.opening = new defer();
|
||||
/**
|
||||
* @property {promise} opened returns after the book is loaded
|
||||
* @member {promise} opened returns after the book is loaded
|
||||
* @memberof Book
|
||||
*/
|
||||
this.opened = this.opening.promise;
|
||||
this.isOpen = false;
|
||||
|
@ -82,9 +93,9 @@ class Book {
|
|||
resources: this.loading.resources.promise
|
||||
};
|
||||
|
||||
// this.ready = RSVP.hash(this.loaded);
|
||||
/**
|
||||
* @property {promise} ready returns after the book is loaded and parsed
|
||||
* @member {promise} ready returns after the book is loaded and parsed
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.ready = Promise.all([
|
||||
|
@ -102,70 +113,93 @@ class Book {
|
|||
// this._q = queue(this);
|
||||
|
||||
/**
|
||||
* @property {method} request
|
||||
* @member {method} request
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.request = this.settings.requestMethod || request;
|
||||
|
||||
/**
|
||||
* @property {Spine} spine
|
||||
* @member {Spine} spine
|
||||
* @memberof Book
|
||||
*/
|
||||
this.spine = new Spine();
|
||||
|
||||
/**
|
||||
* @property {Locations} locations
|
||||
* @member {Locations} locations
|
||||
* @memberof Book
|
||||
*/
|
||||
this.locations = new Locations(this.spine, this.load.bind(this));
|
||||
|
||||
/**
|
||||
* @property {Navigation} navigation
|
||||
* @member {Navigation} navigation
|
||||
* @memberof Book
|
||||
*/
|
||||
this.navigation = undefined;
|
||||
|
||||
/**
|
||||
* @property {PageList} pagelist
|
||||
* @member {PageList} pagelist
|
||||
* @memberof Book
|
||||
*/
|
||||
this.pageList = undefined;
|
||||
|
||||
/**
|
||||
* @property {Url} url
|
||||
* @member {Url} url
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.url = undefined;
|
||||
|
||||
/**
|
||||
* @property {Path} path
|
||||
* @member {Path} path
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.path = undefined;
|
||||
|
||||
/**
|
||||
* @property {boolean} archived
|
||||
* @member {boolean} archived
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.archived = false;
|
||||
|
||||
/**
|
||||
* @property {Archive} archive
|
||||
* @member {Archive} archive
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.archive = undefined;
|
||||
|
||||
/**
|
||||
* @property {Resources} resources
|
||||
* @member {Resources} resources
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.resources = undefined;
|
||||
|
||||
/**
|
||||
* @property {Rendition} rendition
|
||||
* @member {Rendition} rendition
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.rendition = undefined;
|
||||
|
||||
/**
|
||||
* @member {Container} container
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.container = undefined;
|
||||
|
||||
/**
|
||||
* @member {Packaging} packaging
|
||||
* @memberof Book
|
||||
* @private
|
||||
*/
|
||||
this.packaging = undefined;
|
||||
this.toc = undefined;
|
||||
|
||||
// this.toc = undefined;
|
||||
|
||||
if(url) {
|
||||
this.open(url).catch((error) => {
|
||||
|
@ -177,8 +211,8 @@ class Book {
|
|||
|
||||
/**
|
||||
* Open a epub or url
|
||||
* @param {string} input URL, Path or ArrayBuffer
|
||||
* @param {string} [what] to force opening
|
||||
* @param {string | ArrayBuffer} input Url, Path or ArrayBuffer
|
||||
* @param {string} [what="binary", "base64", "epub", "opf", "json", "directory"] force opening as a certain type
|
||||
* @returns {Promise} of when the book has been loaded
|
||||
* @example book.open("/path/to/book.epub")
|
||||
*/
|
||||
|
@ -186,23 +220,23 @@ class Book {
|
|||
var opening;
|
||||
var type = what || this.determineType(input);
|
||||
|
||||
if (type === "binary") {
|
||||
if (type === INPUT_TYPE.BINARY) {
|
||||
this.archived = true;
|
||||
this.url = new Url("/", "");
|
||||
opening = this.openEpub(input);
|
||||
} else if (type === "base64") {
|
||||
} else if (type === INPUT_TYPE.BASE64) {
|
||||
this.archived = true;
|
||||
this.url = new Url("/", "");
|
||||
opening = this.openEpub(input, type);
|
||||
} else if (type === "epub") {
|
||||
} else if (type === INPUT_TYPE.EPUB) {
|
||||
this.archived = true;
|
||||
this.url = new Url("/", "");
|
||||
opening = this.request(input, "binary")
|
||||
.then(this.openEpub.bind(this));
|
||||
} else if(type == "opf") {
|
||||
} else if(type == INPUT_TYPE.OPF) {
|
||||
this.url = new Url(input);
|
||||
opening = this.openPackaging(this.url.Path.toString());
|
||||
} else if(type == "json") {
|
||||
} else if(type == INPUT_TYPE.MANIFEST) {
|
||||
this.url = new Url(input);
|
||||
opening = this.openManifest(this.url.Path.toString());
|
||||
} else {
|
||||
|
@ -218,7 +252,7 @@ class Book {
|
|||
* Open an archived epub
|
||||
* @private
|
||||
* @param {binary} data
|
||||
* @param {[string]} encoding
|
||||
* @param {string} [encoding]
|
||||
* @return {Promise}
|
||||
*/
|
||||
openEpub(data, encoding) {
|
||||
|
@ -296,7 +330,7 @@ class Book {
|
|||
/**
|
||||
* Resolve a path to it's absolute position in the Book
|
||||
* @param {string} path
|
||||
* @param {[boolean]} absolute force resolving the full URL
|
||||
* @param {boolean} [absolute] force resolving the full URL
|
||||
* @return {string} the resolved path string
|
||||
*/
|
||||
resolve(path, absolute) {
|
||||
|
@ -354,11 +388,11 @@ class Book {
|
|||
var extension;
|
||||
|
||||
if (this.settings.encoding === "base64") {
|
||||
return "base64";
|
||||
return INPUT_TYPE.BASE64;
|
||||
}
|
||||
|
||||
if(typeof(input) != "string") {
|
||||
return "binary";
|
||||
return INPUT_TYPE.BINARY;
|
||||
}
|
||||
|
||||
url = new Url(input);
|
||||
|
@ -366,19 +400,19 @@ class Book {
|
|||
extension = path.extension;
|
||||
|
||||
if (!extension) {
|
||||
return "directory";
|
||||
return INPUT_TYPE.DIRECTORY;
|
||||
}
|
||||
|
||||
if(extension === "epub"){
|
||||
return "epub";
|
||||
return INPUT_TYPE.EPUB;
|
||||
}
|
||||
|
||||
if(extension === "opf"){
|
||||
return "opf";
|
||||
return INPUT_TYPE.OPF;
|
||||
}
|
||||
|
||||
if(extension === "json"){
|
||||
return "json";
|
||||
return INPUT_TYPE.MANIFEST;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,7 +435,7 @@ class Book {
|
|||
});
|
||||
|
||||
this.loadNavigation(this.package).then(() => {
|
||||
this.toc = this.navigation.toc;
|
||||
// this.toc = this.navigation.toc;
|
||||
this.loading.navigation.resolve(this.navigation);
|
||||
});
|
||||
|
||||
|
@ -472,24 +506,22 @@ class Book {
|
|||
}
|
||||
|
||||
/**
|
||||
* Alias for book.spine.get
|
||||
* Gets a Section of the Book from the Spine
|
||||
* Alias for `book.spine.get`
|
||||
* @param {string} target
|
||||
* @return {Section}
|
||||
*/
|
||||
section(target) {
|
||||
return this.spine.get(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sugar to render a book
|
||||
* @param {element} element element to add the views to
|
||||
* @param {[object]} options
|
||||
* Sugar to render a book to an element
|
||||
* @param {element | string} element element or string to add a rendition to
|
||||
* @param {object} [options]
|
||||
* @return {Rendition}
|
||||
*/
|
||||
renderTo(element, options) {
|
||||
// var renderMethod = (options && options.method) ?
|
||||
// options.method :
|
||||
// "single";
|
||||
|
||||
this.rendition = new Rendition(this, options);
|
||||
this.rendition.attachTo(element);
|
||||
|
||||
|
@ -516,7 +548,7 @@ class Book {
|
|||
* Unarchive a zipped epub
|
||||
* @private
|
||||
* @param {binary} input epub data
|
||||
* @param {[string]} encoding
|
||||
* @param {string} [encoding]
|
||||
* @return {Archive}
|
||||
*/
|
||||
unarchive(input, encoding) {
|
||||
|
@ -539,13 +571,11 @@ class Book {
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
return retrieved;
|
||||
}
|
||||
|
||||
/**
|
||||
* load replacement urls
|
||||
* Load replacement urls
|
||||
* @private
|
||||
* @return {Promise} completed loading urls
|
||||
*/
|
||||
|
@ -582,7 +612,7 @@ class Book {
|
|||
|
||||
/**
|
||||
* Generates the Book Key using the identifer in the manifest or other string provided
|
||||
* @param {[string]} identifier to use instead of metadata identifier
|
||||
* @param {string} [identifier] to use instead of metadata identifier
|
||||
* @return {string} key
|
||||
*/
|
||||
key(identifier) {
|
||||
|
@ -590,6 +620,9 @@ class Book {
|
|||
return `epubjs:${EPUBJS_VERSION}:${ident}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the Book and all associated objects
|
||||
*/
|
||||
destroy() {
|
||||
this.opened = undefined;
|
||||
this.loading = undefined;
|
||||
|
@ -621,7 +654,6 @@ class Book {
|
|||
this.url = undefined;
|
||||
this.path = undefined;
|
||||
this.archived = false;
|
||||
this.toc = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import {qs} from "./utils/core";
|
|||
/**
|
||||
* Handles Parsing and Accessing an Epub Container
|
||||
* @class
|
||||
* @param {[document]} containerDocument xml document
|
||||
* @param {document} [containerDocument] xml document
|
||||
*/
|
||||
class Container {
|
||||
constructor(containerDocument) {
|
||||
|
|
268
src/contents.js
268
src/contents.js
|
@ -11,6 +11,14 @@ const isWebkit = !isChrome && /AppleWebKit/.test(navigator.userAgent);
|
|||
const ELEMENT_NODE = 1;
|
||||
const TEXT_NODE = 3;
|
||||
|
||||
/**
|
||||
* Handles DOM manipulation, queries and events for View contents
|
||||
* @class
|
||||
* @param {document} doc Document
|
||||
* @param {element} content Parent Element (typically Body)
|
||||
* @param {string} cfiBase Section component of CFIs
|
||||
* @param {number} sectionIndex Index in Spine of Conntent's Section
|
||||
*/
|
||||
class Contents {
|
||||
constructor(doc, content, cfiBase, sectionIndex) {
|
||||
// Blank Cfi for Parsing
|
||||
|
@ -34,10 +42,18 @@ class Contents {
|
|||
this.listeners();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get DOM events that are listened for and passed along
|
||||
*/
|
||||
static get listenedEvents() {
|
||||
return DOM_EVENTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or Set width
|
||||
* @param {number} [w]
|
||||
* @returns {number} width
|
||||
*/
|
||||
width(w) {
|
||||
// var frame = this.documentElement;
|
||||
var frame = this.content;
|
||||
|
@ -56,6 +72,11 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or Set height
|
||||
* @param {number} [h]
|
||||
* @returns {number} height
|
||||
*/
|
||||
height(h) {
|
||||
// var frame = this.documentElement;
|
||||
var frame = this.content;
|
||||
|
@ -73,6 +94,11 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or Set width of the contents
|
||||
* @param {number} [w]
|
||||
* @returns {number} width
|
||||
*/
|
||||
contentWidth(w) {
|
||||
|
||||
var content = this.content || this.document.body;
|
||||
|
@ -90,6 +116,11 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or Set height of the contents
|
||||
* @param {number} [h]
|
||||
* @returns {number} height
|
||||
*/
|
||||
contentHeight(h) {
|
||||
|
||||
var content = this.content || this.document.body;
|
||||
|
@ -106,6 +137,10 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the text using Range
|
||||
* @returns {number} width
|
||||
*/
|
||||
textWidth() {
|
||||
let width;
|
||||
let range = this.document.createRange();
|
||||
|
@ -125,6 +160,10 @@ class Contents {
|
|||
return Math.round(width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the height of the text using Range
|
||||
* @returns {number} height
|
||||
*/
|
||||
textHeight() {
|
||||
let height;
|
||||
let range = this.document.createRange();
|
||||
|
@ -142,18 +181,30 @@ class Contents {
|
|||
return Math.round(height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get documentElement scrollWidth
|
||||
* @returns {number} width
|
||||
*/
|
||||
scrollWidth() {
|
||||
var width = this.documentElement.scrollWidth;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get documentElement scrollHeight
|
||||
* @returns {number} height
|
||||
*/
|
||||
scrollHeight() {
|
||||
var height = this.documentElement.scrollHeight;
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set overflow css style of the contents
|
||||
* @param {string} [overflow]
|
||||
*/
|
||||
overflow(overflow) {
|
||||
|
||||
if (overflow) {
|
||||
|
@ -163,6 +214,10 @@ class Contents {
|
|||
return this.window.getComputedStyle(this.documentElement)["overflow"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set overflowX css style of the documentElement
|
||||
* @param {string} [overflow]
|
||||
*/
|
||||
overflowX(overflow) {
|
||||
|
||||
if (overflow) {
|
||||
|
@ -172,6 +227,10 @@ class Contents {
|
|||
return this.window.getComputedStyle(this.documentElement)["overflowX"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set overflowY css style of the documentElement
|
||||
* @param {string} [overflow]
|
||||
*/
|
||||
overflowY(overflow) {
|
||||
|
||||
if (overflow) {
|
||||
|
@ -181,6 +240,12 @@ class Contents {
|
|||
return this.window.getComputedStyle(this.documentElement)["overflowY"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Css styles on the contents element (typically Body)
|
||||
* @param {string} property
|
||||
* @param {string} value
|
||||
* @param {boolean} [priority] set as "important"
|
||||
*/
|
||||
css(property, value, priority) {
|
||||
var content = this.content || this.document.body;
|
||||
|
||||
|
@ -191,6 +256,16 @@ class Contents {
|
|||
return this.window.getComputedStyle(content)[property];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or Set the viewport element
|
||||
* @param {object} [options]
|
||||
* @param {string} [options.width]
|
||||
* @param {string} [options.height]
|
||||
* @param {string} [options.scale]
|
||||
* @param {string} [options.minimum]
|
||||
* @param {string} [options.maximum]
|
||||
* @param {string} [options.scalable]
|
||||
*/
|
||||
viewport(options) {
|
||||
var _width, _height, _scale, _minimum, _maximum, _scalable;
|
||||
// var width, height, scale, minimum, maximum, scalable;
|
||||
|
@ -288,32 +363,18 @@ class Contents {
|
|||
return settings;
|
||||
}
|
||||
|
||||
|
||||
// layout(layoutFunc) {
|
||||
//
|
||||
// this.iframe.style.display = "inline-block";
|
||||
//
|
||||
// // Reset Body Styles
|
||||
// this.content.style.margin = "0";
|
||||
// //this.document.body.style.display = "inline-block";
|
||||
// //this.document.documentElement.style.width = "auto";
|
||||
//
|
||||
// if(layoutFunc){
|
||||
// layoutFunc(this);
|
||||
// }
|
||||
//
|
||||
// this.onLayout(this);
|
||||
//
|
||||
// };
|
||||
//
|
||||
// onLayout(view) {
|
||||
// // stub
|
||||
// };
|
||||
|
||||
/**
|
||||
* Event emitter for when the contents has expanded
|
||||
* @private
|
||||
*/
|
||||
expand() {
|
||||
this.emit(EVENTS.CONTENTS.EXPAND);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add DOM listeners
|
||||
* @private
|
||||
*/
|
||||
listeners() {
|
||||
|
||||
this.imageLoadListeners();
|
||||
|
@ -335,6 +396,10 @@ class Contents {
|
|||
this.linksHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove DOM listeners
|
||||
* @private
|
||||
*/
|
||||
removeListeners() {
|
||||
|
||||
this.removeEventListeners();
|
||||
|
@ -344,6 +409,11 @@ class Contents {
|
|||
clearTimeout(this.expanding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if size of contents has changed and
|
||||
* emit 'resize' event if it has.
|
||||
* @private
|
||||
*/
|
||||
resizeCheck() {
|
||||
let width = this.textWidth();
|
||||
let height = this.textHeight();
|
||||
|
@ -360,6 +430,10 @@ class Contents {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Poll for resize detection
|
||||
* @private
|
||||
*/
|
||||
resizeListeners() {
|
||||
var width, height;
|
||||
// Test size again
|
||||
|
@ -370,6 +444,10 @@ class Contents {
|
|||
this.expanding = setTimeout(this.resizeListeners.bind(this), 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use css transitions to detect resize
|
||||
* @private
|
||||
*/
|
||||
transitionListeners() {
|
||||
let body = this.content;
|
||||
|
||||
|
@ -381,13 +459,16 @@ class Contents {
|
|||
this.document.addEventListener('transitionend', this.resizeCheck.bind(this));
|
||||
}
|
||||
|
||||
//https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js
|
||||
/**
|
||||
* Listen for media query changes and emit 'expand' event
|
||||
* Adapted from: https://github.com/tylergaw/media-query-events/blob/master/js/mq-events.js
|
||||
* @private
|
||||
*/
|
||||
mediaQueryListeners() {
|
||||
var sheets = this.document.styleSheets;
|
||||
var mediaChangeHandler = function(m){
|
||||
if(m.matches && !this._expanding) {
|
||||
setTimeout(this.expand.bind(this), 1);
|
||||
// this.expand();
|
||||
}
|
||||
}.bind(this);
|
||||
|
||||
|
@ -411,6 +492,10 @@ class Contents {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Use MutationObserver to listen for changes in the DOM and check for resize
|
||||
* @private
|
||||
*/
|
||||
resizeObservers() {
|
||||
// create an observer instance
|
||||
this.observer = new MutationObserver((mutations) => {
|
||||
|
@ -437,22 +522,36 @@ class Contents {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for font load and check for resize when loaded
|
||||
* @private
|
||||
*/
|
||||
fontLoadListeners(target) {
|
||||
if (!this.document || !this.document.fonts) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.document.fonts.ready.then(function () {
|
||||
this.expand();
|
||||
this.resizeCheck();
|
||||
}.bind(this));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the documentElement
|
||||
* @returns {element} documentElement
|
||||
*/
|
||||
root() {
|
||||
if(!this.document) return null;
|
||||
return this.document.documentElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the location offset of a EpubCFI or an #id
|
||||
* @param {string | EpubCFI} target
|
||||
* @param {string} [ignoreClass] for the cfi
|
||||
* @returns { {left: Number, top: Number }
|
||||
*/
|
||||
locationOf(target, ignoreClass) {
|
||||
var position;
|
||||
var targetPos = {"left": 0, "top": 0};
|
||||
|
@ -517,6 +616,10 @@ class Contents {
|
|||
return targetPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a stylesheet link to the document head
|
||||
* @param {string} src url
|
||||
*/
|
||||
addStylesheet(src) {
|
||||
return new Promise(function(resolve, reject){
|
||||
var $stylesheet;
|
||||
|
@ -553,8 +656,12 @@ class Contents {
|
|||
}.bind(this));
|
||||
}
|
||||
|
||||
// Array: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
|
||||
// Object: https://github.com/desirable-objects/json-to-css
|
||||
/**
|
||||
* Append stylesheet rules to a generate stylesheet
|
||||
* Array: https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/insertRule
|
||||
* Object: https://github.com/desirable-objects/json-to-css
|
||||
* @param {array | object} rules
|
||||
*/
|
||||
addStylesheetRules(rules) {
|
||||
var styleEl;
|
||||
var styleSheet;
|
||||
|
@ -615,6 +722,11 @@ class Contents {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a script tag to the document head
|
||||
* @param {string} src url
|
||||
* @returns {Promise} loaded
|
||||
*/
|
||||
addScript(src) {
|
||||
|
||||
return new Promise(function(resolve, reject){
|
||||
|
@ -644,6 +756,10 @@ class Contents {
|
|||
}.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a class to the contents container
|
||||
* @param {string} className
|
||||
*/
|
||||
addClass(className) {
|
||||
var content;
|
||||
|
||||
|
@ -657,6 +773,10 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a class from the contents container
|
||||
* @param {string} removeClass
|
||||
*/
|
||||
removeClass(className) {
|
||||
var content;
|
||||
|
||||
|
@ -670,6 +790,10 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add DOM event listeners
|
||||
* @private
|
||||
*/
|
||||
addEventListeners(){
|
||||
if(!this.document) {
|
||||
return;
|
||||
|
@ -681,6 +805,10 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove DOM event listeners
|
||||
* @private
|
||||
*/
|
||||
removeEventListeners(){
|
||||
if(!this.document) {
|
||||
return;
|
||||
|
@ -691,11 +819,18 @@ class Contents {
|
|||
|
||||
}
|
||||
|
||||
// Pass browser events
|
||||
/**
|
||||
* Emit passed browser events
|
||||
* @private
|
||||
*/
|
||||
triggerEvent(e){
|
||||
this.emit(e.type, e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add listener for text selection
|
||||
* @private
|
||||
*/
|
||||
addSelectionListeners(){
|
||||
if(!this.document) {
|
||||
return;
|
||||
|
@ -703,6 +838,10 @@ class Contents {
|
|||
this.document.addEventListener("selectionchange", this.onSelectionChange.bind(this), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove listener for text selection
|
||||
* @private
|
||||
*/
|
||||
removeSelectionListeners(){
|
||||
if(!this.document) {
|
||||
return;
|
||||
|
@ -710,6 +849,10 @@ class Contents {
|
|||
this.document.removeEventListener("selectionchange", this.onSelectionChange, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle getting text on selection
|
||||
* @private
|
||||
*/
|
||||
onSelectionChange(e){
|
||||
if (this.selectionEndTimeout) {
|
||||
clearTimeout(this.selectionEndTimeout);
|
||||
|
@ -720,6 +863,10 @@ class Contents {
|
|||
}.bind(this), 250);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit event on text selection
|
||||
* @private
|
||||
*/
|
||||
triggerSelectedEvent(selection){
|
||||
var range, cfirange;
|
||||
|
||||
|
@ -734,24 +881,48 @@ class Contents {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a Dom Range from EpubCFI
|
||||
* @param {EpubCFI} _cfi
|
||||
* @param {string} [ignoreClass]
|
||||
* @returns {Range} range
|
||||
*/
|
||||
range(_cfi, ignoreClass){
|
||||
var cfi = new EpubCFI(_cfi);
|
||||
return cfi.toRange(this.document, ignoreClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an EpubCFI from a Dom Range
|
||||
* @param {Range} range
|
||||
* @param {string} [ignoreClass]
|
||||
* @returns {EpubCFI} cfi
|
||||
*/
|
||||
cfiFromRange(range, ignoreClass){
|
||||
return new EpubCFI(range, this.cfiBase, ignoreClass).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an EpubCFI from a Dom node
|
||||
* @param {node} node
|
||||
* @param {string} [ignoreClass]
|
||||
* @returns {EpubCFI} cfi
|
||||
*/
|
||||
cfiFromNode(node, ignoreClass){
|
||||
return new EpubCFI(node, this.cfiBase, ignoreClass).toString();
|
||||
}
|
||||
|
||||
// TODO: find where this is used - remove?
|
||||
map(layout){
|
||||
var map = new Mapping(layout);
|
||||
return map.section();
|
||||
}
|
||||
|
||||
/**
|
||||
* Size the contents to a given width and height
|
||||
* @param {number} [width]
|
||||
* @param {number} [height]
|
||||
*/
|
||||
size(width, height){
|
||||
var viewport = { scale: 1.0, scalable: "no" };
|
||||
|
||||
|
@ -775,6 +946,13 @@ class Contents {
|
|||
this.viewport(viewport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply columns to the contents for pagination
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
* @param {number} columnWidth
|
||||
* @param {number} gap
|
||||
*/
|
||||
columns(width, height, columnWidth, gap){
|
||||
var COLUMN_AXIS = prefixed("column-axis");
|
||||
var COLUMN_GAP = prefixed("column-gap");
|
||||
|
@ -810,6 +988,12 @@ class Contents {
|
|||
this.css(COLUMN_WIDTH, columnWidth+"px");
|
||||
}
|
||||
|
||||
/**
|
||||
* Scale contents from center
|
||||
* @param {number} scale
|
||||
* @param {number} offsetX
|
||||
* @param {number} offsetY
|
||||
*/
|
||||
scaler(scale, offsetX, offsetY){
|
||||
var scaleStr = "scale(" + scale + ")";
|
||||
var translateStr = "";
|
||||
|
@ -823,6 +1007,11 @@ class Contents {
|
|||
this.css("transform", scaleStr + translateStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fit contents into a fixed width and height
|
||||
* @param {number} width
|
||||
* @param {number} height
|
||||
*/
|
||||
fit(width, height){
|
||||
var viewport = this.viewport();
|
||||
var widthScale = width / parseInt(viewport.width);
|
||||
|
@ -843,6 +1032,10 @@ class Contents {
|
|||
this.css("background-color", "transparent");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the direction of the text
|
||||
* @param {string} [dir="ltr"] "rtl" | "ltr"
|
||||
*/
|
||||
direction(dir) {
|
||||
if (this.documentElement) {
|
||||
this.documentElement.style["direction"] = dir;
|
||||
|
@ -855,12 +1048,20 @@ class Contents {
|
|||
return mapping.page(this, cfiBase, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit event when link in content is clicked
|
||||
* @private
|
||||
*/
|
||||
linksHandler() {
|
||||
replaceLinks(this.content, (href) => {
|
||||
this.emit(EVENTS.CONTENTS.LINK_CLICKED, href);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the writingMode of the text
|
||||
* @param {string} [mode="horizontal-tb"] "horizontal-tb" | "vertical-rl" | "vertical-lr"
|
||||
*/
|
||||
writingMode(mode) {
|
||||
let WRITING_MODE = prefixed("writing-mode");
|
||||
|
||||
|
@ -871,6 +1072,11 @@ class Contents {
|
|||
return this.window.getComputedStyle(this.documentElement)[WRITING_MODE] || '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the layoutStyle of the content
|
||||
* @param {string} [style="paginated"] "scrolling" | "paginated"
|
||||
* @private
|
||||
*/
|
||||
layoutStyle(style) {
|
||||
|
||||
if (style) {
|
||||
|
@ -881,6 +1087,12 @@ class Contents {
|
|||
return this._layoutStyle || "paginated";
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the epubReadingSystem object to the navigator
|
||||
* @param {string} name
|
||||
* @param {string} version
|
||||
* @private
|
||||
*/
|
||||
epubReadingSystem(name, version) {
|
||||
navigator.epubReadingSystem = {
|
||||
name: name,
|
||||
|
|
14
src/epub.js
14
src/epub.js
|
@ -1,10 +1,14 @@
|
|||
import Book from "./book";
|
||||
import EpubCFI from "./epubcfi";
|
||||
import Rendition from "./rendition";
|
||||
import EpubCFI from "./epubcfi";
|
||||
import Contents from "./contents";
|
||||
import * as core from "./utils/core";
|
||||
import '../libs/url/url-polyfill'
|
||||
|
||||
import IframeView from "./managers/views/iframe";
|
||||
import DefaultViewManager from "./managers/default";
|
||||
import ContinuousViewManager from "./managers/continuous";
|
||||
|
||||
/**
|
||||
* Creates a new Book
|
||||
* @param {string|ArrayBuffer} url URL, Path or ArrayBuffer
|
||||
|
@ -30,7 +34,7 @@ ePub.utils = core;
|
|||
ePub.ViewManagers = {};
|
||||
ePub.Views = {};
|
||||
/**
|
||||
* register plugins
|
||||
* Register Managers and Views
|
||||
*/
|
||||
ePub.register = {
|
||||
/**
|
||||
|
@ -48,10 +52,10 @@ ePub.register = {
|
|||
};
|
||||
|
||||
// Default Views
|
||||
ePub.register.view("iframe", require("./managers/views/iframe"));
|
||||
ePub.register.view("iframe", IframeView);
|
||||
|
||||
// Default View Managers
|
||||
ePub.register.manager("default", require("./managers/default"));
|
||||
ePub.register.manager("continuous", require("./managers/continuous"));
|
||||
ePub.register.manager("default", DefaultViewManager);
|
||||
ePub.register.manager("continuous", ContinuousViewManager);
|
||||
|
||||
export default ePub;
|
||||
|
|
|
@ -1,24 +1,27 @@
|
|||
import {extend, type, findChildren, RangeObject, isNumber} from "./utils/core";
|
||||
|
||||
/**
|
||||
EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html
|
||||
|
||||
Implements:
|
||||
- Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)
|
||||
- Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)
|
||||
|
||||
Does Not Implement:
|
||||
- Temporal Offset (~)
|
||||
- Spatial Offset (@)
|
||||
- Temporal-Spatial Offset (~ + @)
|
||||
- Text Location Assertion ([)
|
||||
*/
|
||||
|
||||
const ELEMENT_NODE = 1;
|
||||
const TEXT_NODE = 3;
|
||||
// const COMMENT_NODE = 8;
|
||||
const COMMENT_NODE = 8;
|
||||
const DOCUMENT_NODE = 9;
|
||||
|
||||
/**
|
||||
* Parsing and creation of EpubCFIs: http://www.idpf.org/epub/linking/cfi/epub-cfi.html
|
||||
|
||||
* Implements:
|
||||
* - Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)
|
||||
* - Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)
|
||||
|
||||
* Does Not Implement:
|
||||
* - Temporal Offset (~)
|
||||
* - Spatial Offset (@)
|
||||
* - Temporal-Spatial Offset (~ + @)
|
||||
* - Text Location Assertion ([)
|
||||
* @class
|
||||
@param {string | Range | Node } [cfiFrom]
|
||||
@param {string | object} [base]
|
||||
@param {string} [ignoreClass] class to ignore when parsing DOM
|
||||
*/
|
||||
class EpubCFI {
|
||||
constructor(cfiFrom, base, ignoreClass){
|
||||
var type;
|
||||
|
@ -65,6 +68,10 @@ class EpubCFI {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the type of constructor input
|
||||
* @private
|
||||
*/
|
||||
checkType(cfi) {
|
||||
|
||||
if (this.isCfiString(cfi)) {
|
||||
|
@ -81,6 +88,11 @@ class EpubCFI {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a cfi string to a CFI object representation
|
||||
* @param {string} cfiStr
|
||||
* @returns {object} cfi
|
||||
*/
|
||||
parse(cfiStr) {
|
||||
var cfi = {
|
||||
spinePos: -1,
|
||||
|
@ -289,6 +301,10 @@ class EpubCFI {
|
|||
return segmentString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert CFI to a epubcfi(...) string
|
||||
* @returns {string} epubcfi
|
||||
*/
|
||||
toString() {
|
||||
var cfiString = "epubcfi(";
|
||||
|
||||
|
@ -313,6 +329,11 @@ class EpubCFI {
|
|||
return cfiString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare which of two CFIs is earlier in the text
|
||||
* @returns {number} First is earlier = 1, Second is earlier = -1, They are equal = 0
|
||||
*/
|
||||
compare(cfiOne, cfiTwo) {
|
||||
var stepsA, stepsB;
|
||||
var terminalA, terminalB;
|
||||
|
@ -477,6 +498,13 @@ class EpubCFI {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CFI object from a Range
|
||||
* @param {Range} range
|
||||
* @param {string | object} base
|
||||
* @param {string} [ignoreClass]
|
||||
* @returns {object} cfi
|
||||
*/
|
||||
fromRange(range, base, ignoreClass) {
|
||||
var cfi = {
|
||||
range: false,
|
||||
|
@ -564,6 +592,13 @@ class EpubCFI {
|
|||
return cfi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a CFI object from a Node
|
||||
* @param {Node} anchor
|
||||
* @param {string | object} base
|
||||
* @param {string} [ignoreClass]
|
||||
* @returns {object} cfi
|
||||
*/
|
||||
fromNode(anchor, base, ignoreClass) {
|
||||
var cfi = {
|
||||
range: false,
|
||||
|
@ -886,6 +921,12 @@ class EpubCFI {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DOM range representing a CFI
|
||||
* @param {document} _doc document referenced in the base
|
||||
* @param {string} [ignoreClass]
|
||||
* @return {Range}
|
||||
*/
|
||||
toRange(_doc, ignoreClass) {
|
||||
var doc = _doc || document;
|
||||
var range;
|
||||
|
@ -953,7 +994,11 @@ class EpubCFI {
|
|||
return range;
|
||||
}
|
||||
|
||||
// is a cfi string, should be wrapped with "epubcfi()"
|
||||
/**
|
||||
* Check if a string is wrapped with "epubcfi()"
|
||||
* @param {string} str
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isCfiString(str) {
|
||||
if(typeof str === "string" &&
|
||||
str.indexOf("epubcfi(") === 0 &&
|
||||
|
@ -978,6 +1023,10 @@ class EpubCFI {
|
|||
return cfi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse a CFI Range to a single CFI Position
|
||||
* @param {boolean} [toStart=false]
|
||||
*/
|
||||
collapse(toStart) {
|
||||
if (!this.range) {
|
||||
return;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
* Figures out the CSS to apply for a layout
|
||||
* Figures out the CSS values to apply for a layout
|
||||
* @class
|
||||
* @param {object} settings
|
||||
* @param {[string=reflowable]} settings.layout
|
||||
* @param {[string]} settings.spread
|
||||
* @param {[int=800]} settings.minSpreadWidth
|
||||
* @param {[boolean=false]} settings.evenSpreads
|
||||
* @param {string} [settings.layout='reflowable']
|
||||
* @param {string} [settings.spread]
|
||||
* @param {int} [settings.minSpreadWidth=800]
|
||||
* @param {boolean} [settings.evenSpreads=false]
|
||||
*/
|
||||
class Layout {
|
||||
constructor(settings) {
|
||||
|
@ -166,7 +166,7 @@ class Layout {
|
|||
/**
|
||||
* Apply Css to a Document
|
||||
* @param {Contents} contents
|
||||
* @return {[Promise]}
|
||||
* @return {Promise}
|
||||
*/
|
||||
format(contents){
|
||||
var formating;
|
||||
|
@ -184,12 +184,12 @@ class Layout {
|
|||
|
||||
/**
|
||||
* Count number of pages
|
||||
* @param {number} totalWidth
|
||||
* @return {number} spreads
|
||||
* @return {number} pages
|
||||
* @param {number} totalLength
|
||||
* @param {number} pageLength
|
||||
* @return {{spreads: Number, pages: Number}}
|
||||
*/
|
||||
count(totalLength, pageLength) {
|
||||
// var totalWidth = contents.scrollWidth();
|
||||
|
||||
let spreads, pages;
|
||||
|
||||
if (this.name === "pre-paginated") {
|
||||
|
|
|
@ -171,6 +171,11 @@ class Locations {
|
|||
return locations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a location from an EpubCFI
|
||||
* @param {EpubCFI} cfi
|
||||
* @return {number}
|
||||
*/
|
||||
locationFromCfi(cfi){
|
||||
let loc;
|
||||
if (EpubCFI.prototype.isCfiString(cfi)) {
|
||||
|
@ -190,6 +195,11 @@ class Locations {
|
|||
return loc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a percentage position in locations from an EpubCFI
|
||||
* @param {EpubCFI} cfi
|
||||
* @return {number}
|
||||
*/
|
||||
percentageFromCfi(cfi) {
|
||||
if(this._locations.length === 0) {
|
||||
return null;
|
||||
|
@ -200,6 +210,11 @@ class Locations {
|
|||
return this.percentageFromLocation(loc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a percentage position from a location index
|
||||
* @param {number} location
|
||||
* @return {number}
|
||||
*/
|
||||
percentageFromLocation(loc) {
|
||||
if (!loc || !this.total) {
|
||||
return 0;
|
||||
|
@ -208,6 +223,11 @@ class Locations {
|
|||
return (loc / this.total);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an EpubCFI from location index
|
||||
* @param {number} loc
|
||||
* @return {EpubCFI} cfi
|
||||
*/
|
||||
cfiFromLocation(loc){
|
||||
var cfi = -1;
|
||||
// check that pg is an int
|
||||
|
@ -222,6 +242,11 @@ class Locations {
|
|||
return cfi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an EpubCFI from location percentage
|
||||
* @param {number} percentage
|
||||
* @return {EpubCFI} cfi
|
||||
*/
|
||||
cfiFromPercentage(percentage){
|
||||
let loc;
|
||||
if (percentage > 1) {
|
||||
|
@ -239,6 +264,10 @@ class Locations {
|
|||
return this.cfiFromLocation(loc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load locations from JSON
|
||||
* @param {json} locations
|
||||
*/
|
||||
load(locations){
|
||||
if (typeof locations === "string") {
|
||||
this._locations = JSON.parse(locations);
|
||||
|
@ -249,11 +278,15 @@ class Locations {
|
|||
return this._locations;
|
||||
}
|
||||
|
||||
save(json){
|
||||
/**
|
||||
* Save locations to JSON
|
||||
* @return {json}
|
||||
*/
|
||||
save(){
|
||||
return JSON.stringify(this._locations);
|
||||
}
|
||||
|
||||
getCurrent(json){
|
||||
getCurrent(){
|
||||
return this._current;
|
||||
}
|
||||
|
||||
|
@ -284,14 +317,23 @@ class Locations {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current location
|
||||
*/
|
||||
get currentLocation() {
|
||||
return this._current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current location
|
||||
*/
|
||||
set currentLocation(curr) {
|
||||
this.setCurrent(curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locations length
|
||||
*/
|
||||
length () {
|
||||
return this._locations.length;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import EpubCFI from "./epubcfi";
|
||||
|
||||
/**
|
||||
* Map text locations to CFI ranges
|
||||
* @class
|
||||
*/
|
||||
class Mapping {
|
||||
constructor(layout, direction, axis, dev) {
|
||||
this.layout = layout;
|
||||
|
@ -8,6 +12,9 @@ class Mapping {
|
|||
this._dev = dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find CFI pairs for entire section at once
|
||||
*/
|
||||
section(view) {
|
||||
var ranges = this.findRanges(view);
|
||||
var map = this.rangeListToCfiList(view.section.cfiBase, ranges);
|
||||
|
@ -15,6 +22,9 @@ class Mapping {
|
|||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find CFI pairs for a page
|
||||
*/
|
||||
page(contents, cfiBase, start, end) {
|
||||
var root = contents && contents.document ? contents.document.body : false;
|
||||
var result;
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
|
||||
/**
|
||||
* Page List Parser
|
||||
* @param {[document]} xml
|
||||
* @param {document} [xml]
|
||||
*/
|
||||
class PageList {
|
||||
constructor(xml) {
|
||||
|
|
254
src/rendition.js
254
src/rendition.js
|
@ -11,19 +11,22 @@ import Annotations from "./annotations";
|
|||
import { EVENTS } from "./utils/constants";
|
||||
|
||||
/**
|
||||
* [Rendition description]
|
||||
* Displays an Epub as a series of Views for each Section.
|
||||
* Requires Manager and View class to handle specifics of rendering
|
||||
* the section contetn.
|
||||
* @class
|
||||
* @param {Book} book
|
||||
* @param {object} options
|
||||
* @param {int} options.width
|
||||
* @param {int} options.height
|
||||
* @param {string} options.ignoreClass
|
||||
* @param {string} options.manager
|
||||
* @param {string} options.view
|
||||
* @param {string} options.layout
|
||||
* @param {string} options.spread
|
||||
* @param {int} options.minSpreadWidth overridden by spread: none (never) / both (always)
|
||||
* @param {string} options.stylesheet url of stylesheet to be injected
|
||||
* @param {object} [options]
|
||||
* @param {number} [options.width]
|
||||
* @param {number} [options.height]
|
||||
* @param {string} [options.ignoreClass] class for the cfi parser to ignore
|
||||
* @param {string | function | object} [options.manager='default']
|
||||
* @param {string | function} [options.view='iframe']
|
||||
* @param {string} [options.layout] layout to force
|
||||
* @param {string} [options.spread] force spread value
|
||||
* @param {number} [options.minSpreadWidth] overridden by spread: none (never) / both (always)
|
||||
* @param {string} [options.stylesheet] url of stylesheet to be injected
|
||||
* @param {string} [options.script] url of script to be injected
|
||||
*/
|
||||
class Rendition {
|
||||
constructor(book, options) {
|
||||
|
@ -50,19 +53,15 @@ class Rendition {
|
|||
|
||||
this.book = book;
|
||||
|
||||
// this.views = null;
|
||||
|
||||
/**
|
||||
* Adds Hook methods to the Rendition prototype
|
||||
* @property {Hook} hooks
|
||||
* @member {object} hooks
|
||||
* @property {Hook} hooks.content
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.hooks = {};
|
||||
this.hooks.display = new Hook(this);
|
||||
this.hooks.serialize = new Hook(this);
|
||||
/**
|
||||
* @property {method} hooks.content
|
||||
* @type {Hook}
|
||||
*/
|
||||
this.hooks.content = new Hook(this);
|
||||
this.hooks.unloaded = new Hook(this);
|
||||
this.hooks.layout = new Hook(this);
|
||||
|
@ -83,20 +82,60 @@ class Rendition {
|
|||
this.book.spine.hooks.content.register(this.injectScript.bind(this));
|
||||
}
|
||||
|
||||
// this.hooks.display.register(this.afterDisplay.bind(this));
|
||||
/**
|
||||
* @member {Themes} themes
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.themes = new Themes(this);
|
||||
|
||||
/**
|
||||
* @member {Annotations} annotations
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.annotations = new Annotations(this);
|
||||
|
||||
this.epubcfi = new EpubCFI();
|
||||
|
||||
this.q = new Queue(this);
|
||||
|
||||
/**
|
||||
* A Rendered Location Range
|
||||
* @typedef location
|
||||
* @type {Object}
|
||||
* @property {object} start
|
||||
* @property {string} start.index
|
||||
* @property {string} start.href
|
||||
* @property {object} start.displayed
|
||||
* @property {EpubCFI} start.cfi
|
||||
* @property {number} start.location
|
||||
* @property {number} start.percentage
|
||||
* @property {number} start.displayed.page
|
||||
* @property {number} start.displayed.total
|
||||
* @property {object} end
|
||||
* @property {string} end.index
|
||||
* @property {string} end.href
|
||||
* @property {object} end.displayed
|
||||
* @property {EpubCFI} end.cfi
|
||||
* @property {number} end.location
|
||||
* @property {number} end.percentage
|
||||
* @property {number} end.displayed.page
|
||||
* @property {number} end.displayed.total
|
||||
* @property {boolean} atStart
|
||||
* @property {boolean} atEnd
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.location = undefined;
|
||||
|
||||
// Hold queue until book is opened
|
||||
this.q.enqueue(this.book.opened);
|
||||
|
||||
// Block the queue until rendering is started
|
||||
this.starting = new defer();
|
||||
/**
|
||||
* @member {promise} started returns after the rendition has started
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.started = this.starting.promise;
|
||||
// Block the queue until rendering is started
|
||||
this.q.enqueue(this.start);
|
||||
}
|
||||
|
||||
|
@ -109,20 +148,19 @@ class Rendition {
|
|||
}
|
||||
|
||||
/**
|
||||
* Require the manager from passed string, or as a function
|
||||
* @param {string|function} manager [description]
|
||||
* Require the manager from passed string, or as a class function
|
||||
* @param {string|object} manager [description]
|
||||
* @return {method}
|
||||
*/
|
||||
requireManager(manager) {
|
||||
var viewManager;
|
||||
|
||||
// If manager is a string, try to load from register managers,
|
||||
// or require included managers directly
|
||||
if (typeof manager === "string") {
|
||||
// Use global or require
|
||||
viewManager = typeof ePub != "undefined" ? ePub.ViewManagers[manager] : undefined; //require("./managers/"+manager);
|
||||
// If manager is a string, try to load from global registered managers
|
||||
if (typeof manager === "string" && typeof ePub != "undefined") {
|
||||
// Use global
|
||||
viewManager = ePub.ViewManagers[manager];
|
||||
} else {
|
||||
// otherwise, assume we were passed a function
|
||||
// otherwise, assume we were passed a class function
|
||||
viewManager = manager;
|
||||
}
|
||||
|
||||
|
@ -130,17 +168,19 @@ class Rendition {
|
|||
}
|
||||
|
||||
/**
|
||||
* Require the view from passed string, or as a function
|
||||
* @param {string|function} view
|
||||
* Require the view from passed string, or as a class function
|
||||
* @param {string|object} view
|
||||
* @return {view}
|
||||
*/
|
||||
requireView(view) {
|
||||
var View;
|
||||
|
||||
if (typeof view == "string") {
|
||||
View = typeof ePub != "undefined" ? ePub.Views[view] : undefined; //require("./views/"+view);
|
||||
// If view is a string, try to load from global registered views,
|
||||
if (typeof view == "string" && typeof ePub != "undefined") {
|
||||
// Use global
|
||||
View = ePub.Views[view];
|
||||
} else {
|
||||
// otherwise, assume we were passed a function
|
||||
// otherwise, assume we were passed a class function
|
||||
View = view;
|
||||
}
|
||||
|
||||
|
@ -187,7 +227,11 @@ class Rendition {
|
|||
// Listen for scroll changes
|
||||
this.manager.on(EVENTS.MANAGERS.SCROLLED, this.reportLocation.bind(this));
|
||||
|
||||
// Trigger that rendering has started
|
||||
/**
|
||||
* Emit that rendering has started
|
||||
* @event started
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.STARTED);
|
||||
|
||||
// Start processing queue
|
||||
|
@ -210,7 +254,11 @@ class Rendition {
|
|||
"height" : this.settings.height
|
||||
});
|
||||
|
||||
// Trigger Attached
|
||||
/**
|
||||
* Emit that rendering has attached to an element
|
||||
* @event attached
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.ATTACHED);
|
||||
|
||||
}.bind(this));
|
||||
|
@ -270,9 +318,21 @@ class Rendition {
|
|||
displaying.resolve(section);
|
||||
this.displaying = undefined;
|
||||
|
||||
/**
|
||||
* Emit that a section has been displayed
|
||||
* @event displayed
|
||||
* @param {Section} section
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.DISPLAYED, section);
|
||||
this.reportLocation();
|
||||
}, (err) => {
|
||||
/**
|
||||
* Emit that has been an error displaying
|
||||
* @event displayError
|
||||
* @param {Section} section
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.DISPLAY_ERROR, err);
|
||||
});
|
||||
|
||||
|
@ -325,7 +385,7 @@ class Rendition {
|
|||
*/
|
||||
|
||||
/**
|
||||
* Report what has been displayed
|
||||
* Report what section has been displayed
|
||||
* @private
|
||||
* @param {*} view
|
||||
*/
|
||||
|
@ -337,6 +397,13 @@ class Rendition {
|
|||
.then(() => {
|
||||
if (view.contents) {
|
||||
this.hooks.content.trigger(view.contents, this).then(() => {
|
||||
/**
|
||||
* Emit that a section has been rendered
|
||||
* @event rendered
|
||||
* @param {Section} section
|
||||
* @param {View} view
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.RENDERED, view.section, view);
|
||||
});
|
||||
} else {
|
||||
|
@ -344,7 +411,6 @@ class Rendition {
|
|||
}
|
||||
});
|
||||
|
||||
// this.reportLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -354,6 +420,13 @@ class Rendition {
|
|||
*/
|
||||
afterRemoved(view){
|
||||
this.hooks.unloaded.trigger(view, this).then(() => {
|
||||
/**
|
||||
* Emit that a section has been removed
|
||||
* @event removed
|
||||
* @param {Section} section
|
||||
* @param {View} view
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.REMOVED, view.section, view);
|
||||
});
|
||||
}
|
||||
|
@ -364,6 +437,13 @@ class Rendition {
|
|||
*/
|
||||
onResized(size){
|
||||
|
||||
/**
|
||||
* Emit that the rendition has been resized
|
||||
* @event resized
|
||||
* @param {number} width
|
||||
* @param {height} height
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.RESIZED, {
|
||||
width: size.width,
|
||||
height: size.height
|
||||
|
@ -380,11 +460,12 @@ class Rendition {
|
|||
* @private
|
||||
*/
|
||||
onOrientationChange(orientation){
|
||||
// Handled in resize event
|
||||
// if (this.location) {
|
||||
// this.display(this.location.start.cfi);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Emit that the rendition has been rotated
|
||||
* @event orientationchange
|
||||
* @param {string} orientation
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.ORIENTATION_CHANGE, orientation);
|
||||
}
|
||||
|
||||
|
@ -450,14 +531,6 @@ class Rendition {
|
|||
return properties;
|
||||
}
|
||||
|
||||
// applyLayoutProperties(){
|
||||
// var settings = this.determineLayoutProperties(this.book.package.metadata);
|
||||
//
|
||||
// this.flow(settings.flow);
|
||||
//
|
||||
// this.layout(settings);
|
||||
// };
|
||||
|
||||
/**
|
||||
* Adjust the flow of the rendition to paginated or scrolled
|
||||
* (scrolled-continuous vs scrolled-doc are handled by different view managers)
|
||||
|
@ -548,7 +621,8 @@ class Rendition {
|
|||
|
||||
/**
|
||||
* Report the current location
|
||||
* @private
|
||||
* @fires relocated
|
||||
* @fires locationChanged
|
||||
*/
|
||||
reportLocation(){
|
||||
return this.q.enqueue(function reportedLocation(){
|
||||
|
@ -583,6 +657,17 @@ class Rendition {
|
|||
|
||||
this.location = located;
|
||||
|
||||
/**
|
||||
* @event locationChanged
|
||||
* @deprecated
|
||||
* @type {object}
|
||||
* @property {number} index
|
||||
* @property {string} href
|
||||
* @property {EpubCFI} start
|
||||
* @property {EpubCFI} end
|
||||
* @property {number} percentage
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.LOCATION_CHANGED, {
|
||||
index: this.location.start.index,
|
||||
href: this.location.start.href,
|
||||
|
@ -591,6 +676,11 @@ class Rendition {
|
|||
percentage: this.location.start.percentage
|
||||
});
|
||||
|
||||
/**
|
||||
* @event relocated
|
||||
* @type {displayedLocation}
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.RELOCATED, this.location);
|
||||
}
|
||||
}.bind(this));
|
||||
|
@ -598,8 +688,8 @@ class Rendition {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the Current Location CFI
|
||||
* @return {EpubCFI} location (may be a promise)
|
||||
* Get the Current Location object
|
||||
* @return {displayedLocation | promise} location (may be a promise)
|
||||
*/
|
||||
currentLocation(){
|
||||
var location = this.manager.currentLocation();
|
||||
|
@ -614,6 +704,12 @@ class Rendition {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Rendition#locationRange from location
|
||||
* passed by the Manager
|
||||
* @returns {displayedLocation}
|
||||
* @private
|
||||
*/
|
||||
located(location){
|
||||
if (!location.length) {
|
||||
return {};
|
||||
|
@ -740,6 +836,13 @@ class Rendition {
|
|||
* @param {EpubCFI} cfirange
|
||||
*/
|
||||
triggerSelectedEvent(cfirange, contents){
|
||||
/**
|
||||
* Emit that a text selection has occured
|
||||
* @event selected
|
||||
* @param {EpubCFI} cfirange
|
||||
* @param {Contents} contents
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.SELECTED, cfirange, contents);
|
||||
}
|
||||
|
||||
|
@ -749,6 +852,14 @@ class Rendition {
|
|||
* @param {EpubCFI} cfirange
|
||||
*/
|
||||
triggerMarkEvent(cfiRange, data, contents){
|
||||
/**
|
||||
* Emit that a mark was clicked
|
||||
* @event markClicked
|
||||
* @param {EpubCFI} cfirange
|
||||
* @param {object} data
|
||||
* @param {Contents} contents
|
||||
* @memberof Rendition
|
||||
*/
|
||||
this.emit(EVENTS.RENDITION.MARK_CLICKED, cfiRange, data, contents);
|
||||
}
|
||||
|
||||
|
@ -772,7 +883,8 @@ class Rendition {
|
|||
|
||||
/**
|
||||
* Hook to adjust images to fit in columns
|
||||
* @param {View} view
|
||||
* @param {Contents} contents
|
||||
* @private
|
||||
*/
|
||||
adjustImages(contents) {
|
||||
|
||||
|
@ -799,15 +911,28 @@ class Rendition {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Contents object of each rendered view
|
||||
* @returns {Contents[]}
|
||||
*/
|
||||
getContents () {
|
||||
return this.manager ? this.manager.getContents() : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the views member from the manager
|
||||
* @returns {Views}
|
||||
*/
|
||||
views () {
|
||||
let views = this.manager ? this.manager.views : undefined;
|
||||
return views || [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to handle link clicks in rendered content
|
||||
* @param {Contents} contents
|
||||
* @private
|
||||
*/
|
||||
handleLinks(contents) {
|
||||
if (contents) {
|
||||
contents.on(EVENTS.CONTENTS.LINK_CLICKED, (href) => {
|
||||
|
@ -817,6 +942,13 @@ class Rendition {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to handle injecting stylesheet before
|
||||
* a Section is serialized
|
||||
* @param {document} doc
|
||||
* @param {Section} section
|
||||
* @private
|
||||
*/
|
||||
injectStylesheet(doc, section) {
|
||||
let style = doc.createElement("link");
|
||||
style.setAttribute("type", "text/css");
|
||||
|
@ -825,6 +957,13 @@ class Rendition {
|
|||
doc.getElementsByTagName("head")[0].appendChild(style);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to handle injecting scripts before
|
||||
* a Section is serialized
|
||||
* @param {document} doc
|
||||
* @param {Section} section
|
||||
* @private
|
||||
*/
|
||||
injectScript(doc, section) {
|
||||
let script = doc.createElement("script");
|
||||
script.setAttribute("type", "text/javascript");
|
||||
|
@ -833,6 +972,13 @@ class Rendition {
|
|||
doc.getElementsByTagName("head")[0].appendChild(script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to handle the document identifier before
|
||||
* a Section is serialized
|
||||
* @param {document} doc
|
||||
* @param {Section} section
|
||||
* @private
|
||||
*/
|
||||
injectIdentifier(doc, section) {
|
||||
let ident = this.book.package.metadata.identifier;
|
||||
let meta = doc.createElement("meta");
|
||||
|
|
|
@ -150,8 +150,8 @@ class Resources {
|
|||
/**
|
||||
* Replace URLs in CSS resources
|
||||
* @private
|
||||
* @param {[Archive]} archive
|
||||
* @param {[method]} resolver
|
||||
* @param {Archive} [archive]
|
||||
* @param {method} [resolver]
|
||||
* @return {Promise}
|
||||
*/
|
||||
replaceCss(archive, resolver){
|
||||
|
@ -277,7 +277,7 @@ class Resources {
|
|||
* Substitute urls in content, with replacements,
|
||||
* relative to a url if provided
|
||||
* @param {string} content
|
||||
* @param {[string]} url url to resolve to
|
||||
* @param {string} [url] url to resolve to
|
||||
* @return {string} content with urls substituted
|
||||
*/
|
||||
substitute(content, url) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import { replaceBase } from "./utils/replacements";
|
|||
|
||||
/**
|
||||
* Represents a Section of the Book
|
||||
*
|
||||
* In most books this is equivelent to a Chapter
|
||||
* @param {object} item The spine item representing the section
|
||||
* @param {object} hooks hooks for serialize and content
|
||||
|
|
|
@ -112,7 +112,7 @@ class Spine {
|
|||
|
||||
/**
|
||||
* Get an item from the spine
|
||||
* @param {[string|int]} target
|
||||
* @param {string|int} [target]
|
||||
* @return {Section} section
|
||||
* @example spine.get();
|
||||
* @example spine.get(1);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
import Url from "./utils/url";
|
||||
|
||||
/**
|
||||
* Themes to apply to displayed content
|
||||
* @class
|
||||
* @param {Rendition} rendition
|
||||
*/
|
||||
class Themes {
|
||||
constructor(rendition) {
|
||||
this.rendition = rendition;
|
||||
|
@ -18,6 +23,13 @@ class Themes {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add themes to be used by a rendition
|
||||
* @param {object | string}
|
||||
* @example themes.register("light", "http://example.com/light.css")
|
||||
* @example themes.register("light", { "body": { "color": "purple"}})
|
||||
* @example themes.register({ "light" : {...}, "dark" : {...}})
|
||||
*/
|
||||
register () {
|
||||
if (arguments.length === 0) {
|
||||
return;
|
||||
|
@ -36,6 +48,12 @@ class Themes {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a default theme to be used by a rendition
|
||||
* @param {object | string} theme
|
||||
* @example themes.register("http://example.com/default.css")
|
||||
* @example themes.register({ "body": { "color": "purple"}})
|
||||
*/
|
||||
default (theme) {
|
||||
if (!theme) {
|
||||
return;
|
||||
|
@ -154,10 +172,18 @@ class Themes {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the font size of a rendition
|
||||
* @param {number} size
|
||||
*/
|
||||
fontSize (size) {
|
||||
this.override("font-size", size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust the font-family of a rendition
|
||||
* @param {string} f
|
||||
*/
|
||||
font (f) {
|
||||
this.override("font-family", f);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,13 @@
|
|||
/**
|
||||
* Core Utilities and Helpers
|
||||
* @module Core
|
||||
*/
|
||||
|
||||
/**
|
||||
* Vendor prefixed requestAnimationFrame
|
||||
* @returns {function} requestAnimationFrame
|
||||
* @memberof Core
|
||||
*/
|
||||
export const requestAnimationFrame = (typeof window != "undefined") ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;
|
||||
const ELEMENT_NODE = 1;
|
||||
const TEXT_NODE = 3;
|
||||
|
@ -5,11 +15,12 @@ const COMMENT_NODE = 8;
|
|||
const DOCUMENT_NODE = 9;
|
||||
const _URL = typeof URL != "undefined" ? URL : (typeof window != "undefined" ? (window.URL || window.webkitURL || window.mozURL) : undefined);
|
||||
|
||||
export function isElement(obj) {
|
||||
return !!(obj && obj.nodeType == 1);
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
||||
/**
|
||||
* Generates a UUID
|
||||
* based on: http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
||||
* @returns {string} uuid
|
||||
* @memberof Core
|
||||
*/
|
||||
export function uuid() {
|
||||
var d = new Date().getTime();
|
||||
var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
||||
|
@ -20,6 +31,11 @@ export function uuid() {
|
|||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of a document
|
||||
* @returns {number} height
|
||||
* @memberof Core
|
||||
*/
|
||||
export function documentHeight() {
|
||||
return Math.max(
|
||||
document.documentElement.clientHeight,
|
||||
|
@ -30,15 +46,37 @@ export function documentHeight() {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a node is an element
|
||||
* @returns {boolean}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function isElement(obj) {
|
||||
return !!(obj && obj.nodeType == 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function isNumber(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function isFloat(n) {
|
||||
let f = parseFloat(n);
|
||||
return f === n && isNumber(n) && (Math.floor(f) !== n);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a prefixed css property
|
||||
* @returns {string}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function prefixed(unprefixed) {
|
||||
var vendors = ["Webkit", "webkit", "Moz", "O", "ms" ];
|
||||
var prefixes = ["-webkit-", "-webkit-", "-moz-", "-o-", "-ms-"];
|
||||
|
@ -58,6 +96,12 @@ export function prefixed(unprefixed) {
|
|||
return unprefixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply defaults to an object
|
||||
* @param {object} obj
|
||||
* @returns {object}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function defaults(obj) {
|
||||
for (var i = 1, length = arguments.length; i < length; i++) {
|
||||
var source = arguments[i];
|
||||
|
@ -68,6 +112,12 @@ export function defaults(obj) {
|
|||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend undefined properties of an object
|
||||
* @param {object} target
|
||||
* @returns {object}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function extend(target) {
|
||||
var sources = [].slice.call(arguments, 1);
|
||||
sources.forEach(function (source) {
|
||||
|
@ -79,8 +129,15 @@ export function extend(target) {
|
|||
return target;
|
||||
}
|
||||
|
||||
// Fast quicksort insert for sorted array -- based on:
|
||||
// http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers
|
||||
/**
|
||||
* Fast quicksort insert for sorted array -- based on:
|
||||
* http://stackoverflow.com/questions/1344500/efficient-way-to-insert-a-number-into-a-sorted-array-of-numbers
|
||||
* @param {any} item
|
||||
* @param {array} array
|
||||
* @param {function} [compareFunction]
|
||||
* @returns {number} location (in array)
|
||||
* @memberof Core
|
||||
*/
|
||||
export function insert(item, array, compareFunction) {
|
||||
var location = locationOf(item, array, compareFunction);
|
||||
array.splice(location, 0, item);
|
||||
|
@ -88,7 +145,16 @@ export function insert(item, array, compareFunction) {
|
|||
return location;
|
||||
}
|
||||
|
||||
// Returns where something would fit in
|
||||
/**
|
||||
* Finds where something would fit into a sorted array
|
||||
* @param {any} item
|
||||
* @param {array} array
|
||||
* @param {function} [compareFunction]
|
||||
* @param {function} [_start]
|
||||
* @param {function} [_end]
|
||||
* @returns {number} location (in array)
|
||||
* @memberof Core
|
||||
*/
|
||||
export function locationOf(item, array, compareFunction, _start, _end) {
|
||||
var start = _start || 0;
|
||||
var end = _end || array.length;
|
||||
|
@ -119,7 +185,17 @@ export function locationOf(item, array, compareFunction, _start, _end) {
|
|||
}
|
||||
}
|
||||
|
||||
// Returns -1 of mpt found
|
||||
/**
|
||||
* Finds index of something in a sorted array
|
||||
* Returns -1 if not found
|
||||
* @param {any} item
|
||||
* @param {array} array
|
||||
* @param {function} [compareFunction]
|
||||
* @param {function} [_start]
|
||||
* @param {function} [_end]
|
||||
* @returns {number} index (in array) or -1
|
||||
* @memberof Core
|
||||
*/
|
||||
export function indexOfSorted(item, array, compareFunction, _start, _end) {
|
||||
var start = _start || 0;
|
||||
var end = _end || array.length;
|
||||
|
@ -149,7 +225,13 @@ export function indexOfSorted(item, array, compareFunction, _start, _end) {
|
|||
return indexOfSorted(item, array, compareFunction, start, pivot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the bounds of an element
|
||||
* taking padding and margin into account
|
||||
* @param {element} el
|
||||
* @returns {{ width: Number, height: Number}}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function bounds(el) {
|
||||
|
||||
var style = window.getComputedStyle(el);
|
||||
|
@ -174,6 +256,13 @@ export function bounds(el) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the bounds of an element
|
||||
* taking padding, margin and borders into account
|
||||
* @param {element} el
|
||||
* @returns {{ width: Number, height: Number}}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function borders(el) {
|
||||
|
||||
var style = window.getComputedStyle(el);
|
||||
|
@ -198,6 +287,11 @@ export function borders(el) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the equivelent of getBoundingClientRect of a browser window
|
||||
* @returns {{ width: Number, height: Number, top: Number, left: Number, right: Number, bottom: Number }}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function windowBounds() {
|
||||
|
||||
var width = window.innerWidth;
|
||||
|
@ -214,22 +308,11 @@ export function windowBounds() {
|
|||
|
||||
}
|
||||
|
||||
//-- https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496
|
||||
export function cleanStringForXpath(str) {
|
||||
var parts = str.match(/[^'"]+|['"]/g);
|
||||
parts = parts.map(function(part){
|
||||
if (part === "'") {
|
||||
return "\"\'\""; // output "'"
|
||||
}
|
||||
|
||||
if (part === "\"") {
|
||||
return "\'\"\'"; // output '"'
|
||||
}
|
||||
return `\'${part}\'`;
|
||||
});
|
||||
return `concat(\'\',${ parts.join(",") })`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a node in its parent
|
||||
* @private
|
||||
* @memberof Core
|
||||
*/
|
||||
export function indexOfNode(node, typeId) {
|
||||
var parent = node.parentNode;
|
||||
var children = parent.childNodes;
|
||||
|
@ -246,22 +329,54 @@ export function indexOfNode(node, typeId) {
|
|||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of a text node in its parent
|
||||
* @param {node} textNode
|
||||
* @returns {number} index
|
||||
* @memberof Core
|
||||
*/
|
||||
export function indexOfTextNode(textNode) {
|
||||
return indexOfNode(textNode, TEXT_NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of an element node in its parent
|
||||
* @param {element} elementNode
|
||||
* @returns {number} index
|
||||
* @memberof Core
|
||||
*/
|
||||
export function indexOfElementNode(elementNode) {
|
||||
return indexOfNode(elementNode, ELEMENT_NODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if extension is xml
|
||||
* @param {string} ext
|
||||
* @returns {boolean}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function isXml(ext) {
|
||||
return ["xml", "opf", "ncx"].indexOf(ext) > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new blob
|
||||
* @param {any} content
|
||||
* @param {string} mime
|
||||
* @returns {Blob}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function createBlob(content, mime){
|
||||
return new Blob([content], {type : mime });
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new blob url
|
||||
* @param {any} content
|
||||
* @param {string} mime
|
||||
* @returns {string} url
|
||||
* @memberof Core
|
||||
*/
|
||||
export function createBlobUrl(content, mime){
|
||||
var tempUrl;
|
||||
var blob = createBlob(content, mime);
|
||||
|
@ -271,11 +386,22 @@ export function createBlobUrl(content, mime){
|
|||
return tempUrl;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a blob url
|
||||
* @param {string} url
|
||||
* @memberof Core
|
||||
*/
|
||||
export function revokeBlobUrl(url){
|
||||
return _URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new base64 encoded url
|
||||
* @param {any} content
|
||||
* @param {string} mime
|
||||
* @returns {string} url
|
||||
* @memberof Core
|
||||
*/
|
||||
export function createBase64Url(content, mime){
|
||||
var data;
|
||||
var datauri;
|
||||
|
@ -292,10 +418,24 @@ export function createBase64Url(content, mime){
|
|||
return datauri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get type of an object
|
||||
* @param {object} obj
|
||||
* @returns {string} type
|
||||
* @memberof Core
|
||||
*/
|
||||
export function type(obj){
|
||||
return Object.prototype.toString.call(obj).slice(8, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse xml (or html) markup
|
||||
* @param {string} markup
|
||||
* @param {string} mime
|
||||
* @param {boolean} forceXMLDom force using xmlDom to parse instead of native parser
|
||||
* @returns {document} document
|
||||
* @memberof Core
|
||||
*/
|
||||
export function parse(markup, mime, forceXMLDom) {
|
||||
var doc;
|
||||
var Parser;
|
||||
|
@ -317,6 +457,13 @@ export function parse(markup, mime, forceXMLDom) {
|
|||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* querySelector polyfill
|
||||
* @param {element} el
|
||||
* @param {string} sel selector string
|
||||
* @returns {element} element
|
||||
* @memberof Core
|
||||
*/
|
||||
export function qs(el, sel) {
|
||||
var elements;
|
||||
if (!el) {
|
||||
|
@ -333,6 +480,13 @@ export function qs(el, sel) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* querySelectorAll polyfill
|
||||
* @param {element} el
|
||||
* @param {string} sel selector string
|
||||
* @returns {element[]} elements
|
||||
* @memberof Core
|
||||
*/
|
||||
export function qsa(el, sel) {
|
||||
|
||||
if (typeof el.querySelector != "undefined") {
|
||||
|
@ -342,6 +496,14 @@ export function qsa(el, sel) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* querySelector by property
|
||||
* @param {element} el
|
||||
* @param {string} sel selector string
|
||||
* @param {props[]} props
|
||||
* @returns {element[]} elements
|
||||
* @memberof Core
|
||||
*/
|
||||
export function qsp(el, sel, props) {
|
||||
var q, filtered;
|
||||
if (typeof el.querySelector != "undefined") {
|
||||
|
@ -370,6 +532,7 @@ export function qsp(el, sel, props) {
|
|||
|
||||
/**
|
||||
* Sprint through all text nodes in a document
|
||||
* @memberof Core
|
||||
* @param {element} root element to start with
|
||||
* @param {function} func function to run on each element
|
||||
*/
|
||||
|
@ -394,24 +557,10 @@ export function treeWalker(root, func, filter) {
|
|||
}
|
||||
}
|
||||
|
||||
// export function walk(root, func, onlyText) {
|
||||
// var node = root;
|
||||
//
|
||||
// if (node && !onlyText || node.nodeType === 3) { // Node.TEXT_NODE
|
||||
// func(node);
|
||||
// }
|
||||
// console.log(root);
|
||||
//
|
||||
// node = node.firstChild;
|
||||
// while(node) {
|
||||
// walk(node, func, onlyText);
|
||||
// node = node.nextSibling;
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param callback return false for continue,true for break
|
||||
* @return boolean true: break visit;
|
||||
* @memberof Core
|
||||
* @param {node} node
|
||||
* @param {callback} return false for continue,true for break inside callback
|
||||
*/
|
||||
export function walk(node,callback){
|
||||
if(callback(node)){
|
||||
|
@ -429,6 +578,12 @@ export function walk(node,callback){
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a blob to a base64 encoded string
|
||||
* @param {Blog} blob
|
||||
* @returns {string}
|
||||
* @memberof Core
|
||||
*/
|
||||
export function blob2base64(blob) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var reader = new FileReader();
|
||||
|
@ -439,7 +594,12 @@ export function blob2base64(blob) {
|
|||
});
|
||||
}
|
||||
|
||||
// From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible
|
||||
|
||||
/**
|
||||
* Creates a new pending promise and provides methods to resolve or reject it.
|
||||
* From: https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/Promise.jsm/Deferred#backwards_forwards_compatible
|
||||
* @memberof Core
|
||||
*/
|
||||
export function defer() {
|
||||
/* A method to resolve the associated Promise with the value passed.
|
||||
* If the promise is already settled it does nothing.
|
||||
|
@ -471,6 +631,14 @@ export function defer() {
|
|||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* querySelector with filter by epub type
|
||||
* @param {element} html
|
||||
* @param {string} element element type to find
|
||||
* @param {string} type epub type to find
|
||||
* @returns {element[]} elements
|
||||
* @memberof Core
|
||||
*/
|
||||
export function querySelectorByType(html, element, type){
|
||||
var query;
|
||||
if (typeof html.querySelector != "undefined") {
|
||||
|
@ -490,6 +658,12 @@ export function querySelectorByType(html, element, type){
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find direct decendents of an element
|
||||
* @param {element} el
|
||||
* @returns {element[]} children
|
||||
* @memberof Core
|
||||
*/
|
||||
export function findChildren(el) {
|
||||
var result = [];
|
||||
var childNodes = el.childNodes;
|
||||
|
@ -502,6 +676,12 @@ export function findChildren(el) {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all parents (ancestors) of an element
|
||||
* @param {element} node
|
||||
* @returns {element[]} parents
|
||||
* @memberof Core
|
||||
*/
|
||||
export function parents(node) {
|
||||
var nodes = [node];
|
||||
for (; node; node = node.parentNode) {
|
||||
|
@ -510,6 +690,14 @@ export function parents(node) {
|
|||
return nodes
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all direct decendents of a specific type
|
||||
* @param {element} el
|
||||
* @param {string} nodeName
|
||||
* @param {boolean} [single]
|
||||
* @returns {element[]} children
|
||||
* @memberof Core
|
||||
*/
|
||||
export function filterChildren(el, nodeName, single) {
|
||||
var result = [];
|
||||
var childNodes = el.childNodes;
|
||||
|
@ -528,6 +716,13 @@ export function filterChildren(el, nodeName, single) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter all parents (ancestors) with tag name
|
||||
* @param {element} node
|
||||
* @param {string} tagname
|
||||
* @returns {element[]} parents
|
||||
* @memberof Core
|
||||
*/
|
||||
export function getParentByTagName(node, tagname) {
|
||||
let parent;
|
||||
if (node === null || tagname === '') return;
|
||||
|
@ -540,6 +735,11 @@ export function getParentByTagName(node, tagname) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lightweight Polyfill for DOM Range
|
||||
* @class
|
||||
* @memberof Core
|
||||
*/
|
||||
export class RangeObject {
|
||||
constructor() {
|
||||
this.collapsed = false;
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
import path from "path-webpack";
|
||||
|
||||
/**
|
||||
* Creates a Path object for parsing and manipulation of a path strings
|
||||
*
|
||||
* Uses a polyfill for Nodejs path: https://nodejs.org/api/path.html
|
||||
* @param {string} pathString a url string (relative or absolute)
|
||||
* @class
|
||||
*/
|
||||
class Path {
|
||||
constructor(pathString) {
|
||||
var protocol;
|
||||
|
@ -25,22 +32,50 @@ class Path {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the path: https://nodejs.org/api/path.html#path_path_parse_path
|
||||
* @param {string} what
|
||||
* @returns {object}
|
||||
*/
|
||||
parse (what) {
|
||||
return path.parse(what);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} what
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isAbsolute (what) {
|
||||
return path.isAbsolute(what || this.path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if path ends with a directory
|
||||
* @param {string} what
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isDirectory (what) {
|
||||
return (what.charAt(what.length-1) === "/");
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path against the directory of the Path
|
||||
*
|
||||
* https://nodejs.org/api/path.html#path_path_resolve_paths
|
||||
* @param {string} what
|
||||
* @returns {string} resolved
|
||||
*/
|
||||
resolve (what) {
|
||||
return path.resolve(this.directory, what);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path relative to the directory of the Path
|
||||
*
|
||||
* https://nodejs.org/api/path.html#path_path_relative_from_to
|
||||
* @param {string} what
|
||||
* @returns {string} relative
|
||||
*/
|
||||
relative (what) {
|
||||
return path.relative(this.directory, what);
|
||||
}
|
||||
|
@ -49,6 +84,10 @@ class Path {
|
|||
return this.splitPathRe.exec(filename).slice(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path string
|
||||
* @returns {string} path
|
||||
*/
|
||||
toString () {
|
||||
return this.path;
|
||||
}
|
||||
|
|
|
@ -2,13 +2,11 @@ import Path from "./path";
|
|||
import path from "path-webpack";
|
||||
|
||||
/**
|
||||
* creates a uri object
|
||||
* creates a Url object for parsing and manipulation of a url string
|
||||
* @param {string} urlString a url string (relative or absolute)
|
||||
* @param {[string]} baseString optional base for the url,
|
||||
* @param {string} [baseString] optional base for the url,
|
||||
* default to window.location.href
|
||||
* @return {object} url
|
||||
*/
|
||||
|
||||
class Url {
|
||||
constructor(urlString, baseString) {
|
||||
var absolute = (urlString.indexOf("://") > -1);
|
||||
|
@ -66,10 +64,17 @@ class Url {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {Path}
|
||||
*/
|
||||
path () {
|
||||
return this.Path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a relative path to a absolute url
|
||||
* @returns {string} url
|
||||
*/
|
||||
resolve (what) {
|
||||
var isAbsolute = (what.indexOf("://") > -1);
|
||||
var fullpath;
|
||||
|
@ -82,10 +87,17 @@ class Url {
|
|||
return this.origin + fullpath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a path relative to the url
|
||||
* @returns {string} path
|
||||
*/
|
||||
relative (what) {
|
||||
return path.relative(what, this.directory);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
toString () {
|
||||
return this.href;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue