mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-02 14:49:16 +02:00
Added core Url and Path, split up book.open, added Container and Packaging
This commit is contained in:
parent
02725b1771
commit
47787678f7
24 changed files with 1774 additions and 1140 deletions
1008
dist/epub.js
vendored
1008
dist/epub.js
vendored
File diff suppressed because it is too large
Load diff
2
dist/epub.js.map
vendored
2
dist/epub.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/polyfills.js.map
vendored
2
dist/polyfills.js.map
vendored
File diff suppressed because one or more lines are too long
20
gulpfile.js
20
gulpfile.js
|
@ -30,6 +30,8 @@ watchConfig.watch = true;
|
|||
// create a single instance of the compiler to allow caching
|
||||
var watchCompiler = webpack(watchConfig);
|
||||
|
||||
var buildDocs = require('gulp-documentation');
|
||||
|
||||
// Lint JS
|
||||
gulp.task('lint', function() {
|
||||
return gulp.src('src/*.js')
|
||||
|
@ -123,6 +125,24 @@ gulp.task("serve", function(callback) {
|
|||
|
||||
});
|
||||
|
||||
gulp.task('docs:md', function () {
|
||||
return gulp.src('./src/epub.js')
|
||||
.pipe(buildDocs({ format: 'md' }))
|
||||
.pipe(gulp.dest('documentation/md'));
|
||||
});
|
||||
|
||||
gulp.task('docs:html', function () {
|
||||
return gulp.src('./src/epub.js')
|
||||
.pipe(buildDocs({ format: 'html' }))
|
||||
.pipe(gulp.dest('documentation/html'));
|
||||
});
|
||||
|
||||
gulp.task('docs:watch', function () {
|
||||
return gulp.watch('./src/**/*.js', ['docs:html']);
|
||||
});
|
||||
|
||||
gulp.task('docs', ['docs:html', 'docs:md']);
|
||||
|
||||
// Default
|
||||
gulp.task('default', ['lint', 'bundle']);
|
||||
|
||||
|
|
|
@ -48,7 +48,12 @@ module.exports = function(config) {
|
|||
"jszip": "JSZip",
|
||||
"xmldom": "xmldom"
|
||||
},
|
||||
devtool: 'inline-source-map'
|
||||
devtool: 'inline-source-map',
|
||||
resolve: {
|
||||
alias: {
|
||||
path: "path-webpack"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
webpackMiddleware: {
|
||||
|
@ -70,7 +75,7 @@ module.exports = function(config) {
|
|||
|
||||
// level of logging
|
||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
||||
logLevel: config.LOG_DEBUG,
|
||||
logLevel: config.LOG_INFO,
|
||||
|
||||
|
||||
// enable / disable watching file and executing tests whenever any file changes
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
"gulp": "^3.9.0",
|
||||
"gulp-concat": "^2.3.4",
|
||||
"gulp-connect": "~3.1.1",
|
||||
"gulp-documentation": "fchasen/gulp-documentation",
|
||||
"gulp-jshint": "^2.0.0",
|
||||
"gulp-plumber": "^1.1.0",
|
||||
"gulp-rename": "^1.2.0",
|
||||
|
@ -40,6 +41,7 @@
|
|||
"mocha-loader": "^1.0.0",
|
||||
"morgan": "^1.1.1",
|
||||
"optimist": "^0.6.1",
|
||||
"path-webpack": "^0.0.2",
|
||||
"portfinder": "^1.0.2",
|
||||
"raw-loader": "^0.5.1",
|
||||
"serve-static": "^1.3.1",
|
||||
|
|
397
src/book.js
397
src/book.js
|
@ -1,19 +1,37 @@
|
|||
var EventEmitter = require('event-emitter');
|
||||
var path = require('path');
|
||||
var core = require('./core');
|
||||
var Url = require('./core').Url;
|
||||
var Path = require('./core').Path;
|
||||
var Spine = require('./spine');
|
||||
var Locations = require('./locations');
|
||||
var Parser = require('./parser');
|
||||
var Container = require('./container');
|
||||
var Packaging = require('./packaging');
|
||||
var Navigation = require('./navigation');
|
||||
var Rendition = require('./rendition');
|
||||
var Unarchive = require('./unarchive');
|
||||
var request = require('./request');
|
||||
var EpubCFI = require('./epubcfi');
|
||||
|
||||
function Book(_url, options){
|
||||
// Const
|
||||
var CONTAINER_PATH = "META-INF/container.xml";
|
||||
|
||||
/**
|
||||
* Creates a new Book
|
||||
* @class
|
||||
* @param {string} _url
|
||||
* @param {object} options
|
||||
* @param {method} options.requestMethod a request function to use instead of the default
|
||||
* @returns {Book}
|
||||
* @example new Book("/path/to/book.epub", {})
|
||||
*/
|
||||
function Book(url, options){
|
||||
|
||||
this.settings = core.extend(this.settings || {}, {
|
||||
requestMethod: this.requestMethod
|
||||
requestMethod: this.requestMethod,
|
||||
requestCredentials: undefined,
|
||||
encoding: undefined // optional to pass 'binary' or base64' for archived Epubs
|
||||
});
|
||||
|
||||
core.extend(this.settings, options);
|
||||
|
@ -21,11 +39,12 @@ function Book(_url, options){
|
|||
|
||||
// Promises
|
||||
this.opening = new core.defer();
|
||||
/**
|
||||
* @property {promise} opened returns after the book is loaded
|
||||
*/
|
||||
this.opened = this.opening.promise;
|
||||
this.isOpen = false;
|
||||
|
||||
this.url = undefined;
|
||||
|
||||
this.loading = {
|
||||
manifest: new core.defer(),
|
||||
spine: new core.defer(),
|
||||
|
@ -45,6 +64,9 @@ function Book(_url, options){
|
|||
};
|
||||
|
||||
// this.ready = RSVP.hash(this.loaded);
|
||||
/**
|
||||
* @property {promise} ready returns after the book is loaded and parsed
|
||||
*/
|
||||
this.ready = Promise.all([this.loaded.manifest,
|
||||
this.loaded.spine,
|
||||
this.loaded.metadata,
|
||||
|
@ -57,216 +79,214 @@ function Book(_url, options){
|
|||
this.isRendered = false;
|
||||
// this._q = core.queue(this);
|
||||
|
||||
this.request = this.settings.requestMethod.bind(this);
|
||||
/**
|
||||
* @property {method} request
|
||||
*/
|
||||
this.request = this.settings.requestMethod || request;
|
||||
|
||||
this.spine = new Spine(this.request);
|
||||
this.locations = new Locations(this.spine, this.request);
|
||||
/**
|
||||
* @property {Spine} spine
|
||||
*/
|
||||
this.spine = new Spine();
|
||||
|
||||
if(_url) {
|
||||
this.open(_url).catch(function (error) {
|
||||
var err = new Error("Cannot load book at "+ _url );
|
||||
/**
|
||||
* @property {Locations} locations
|
||||
*/
|
||||
this.locations = new Locations(this.spine, this.load);
|
||||
|
||||
/**
|
||||
* @property {Navigation} navigation
|
||||
*/
|
||||
this.navigation = undefined;
|
||||
|
||||
this.url = undefined;
|
||||
this.path = undefined;
|
||||
|
||||
this.archived = false;
|
||||
|
||||
if(url) {
|
||||
this.open(url).catch(function (error) {
|
||||
var err = new Error("Cannot load book at "+ url );
|
||||
console.error(err);
|
||||
console.error(error);
|
||||
|
||||
this.emit("loadFailed", error);
|
||||
this.emit("openFailed", err);
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
Book.prototype.open = function(_url, options){
|
||||
var url;
|
||||
var pathname;
|
||||
var parse = new Parser();
|
||||
var epubPackage;
|
||||
var epubContainer;
|
||||
var book = this;
|
||||
var containerPath = "META-INF/container.xml";
|
||||
var location;
|
||||
var isArrayBuffer = false;
|
||||
var isBase64 = options && options.base64;
|
||||
/**
|
||||
* open a url
|
||||
* @param {string} input URL, Path or ArrayBuffer
|
||||
* @param {string} [what] to force opening
|
||||
* @returns {Promise} of when the book has been loaded
|
||||
* @example book.open("/path/to/book.epub")
|
||||
*/
|
||||
Book.prototype.open = function(input, what){
|
||||
var opening;
|
||||
var type = what || this.determineType(input);
|
||||
|
||||
if(!_url) {
|
||||
this.opening.resolve(this);
|
||||
return this.opened;
|
||||
}
|
||||
|
||||
// Reuse parsed url or create a new uri object
|
||||
// if(typeof(_url) === "object") {
|
||||
// uri = _url;
|
||||
// } else {
|
||||
// uri = core.uri(_url);
|
||||
// }
|
||||
if (_url instanceof ArrayBuffer || isBase64) {
|
||||
isArrayBuffer = true;
|
||||
this.url = '/';
|
||||
}
|
||||
|
||||
if (window && window.location && !isArrayBuffer) {
|
||||
// absoluteUri = uri.absoluteTo(window.location.href);
|
||||
url = new URL(_url, window.location.href);
|
||||
pathname = url.pathname;
|
||||
// this.url = absoluteUri.toString();
|
||||
this.url = url.toString();
|
||||
} else if (window && window.location) {
|
||||
this.url = window.location.href;
|
||||
if (type === "binary") {
|
||||
this.archived = true;
|
||||
opening = this.openEpub(input);
|
||||
} else if (type === "epub") {
|
||||
this.archived = true;
|
||||
opening = this.request(input, 'binary')
|
||||
.then(function(epubData) {
|
||||
return this.openEpub(epubData);
|
||||
}.bind(this));
|
||||
} else if(type == "opf") {
|
||||
this.url = new Url(input);
|
||||
opening = this.openPackaging(input);
|
||||
} else {
|
||||
this.url = _url;
|
||||
}
|
||||
|
||||
// Find path to the Container
|
||||
// if(uri && uri.suffix() === "opf") {
|
||||
if(url && core.extension(pathname) === "opf") {
|
||||
// Direct link to package, no container
|
||||
this.packageUrl = _url;
|
||||
this.containerUrl = '';
|
||||
|
||||
if(url.origin) {
|
||||
// this.baseUrl = uri.origin() + uri.directory() + "/";
|
||||
this.baseUrl = url.origin + path.dirname(pathname) + "/";
|
||||
// } else if(absoluteUri){
|
||||
// this.baseUrl = absoluteUri.origin();
|
||||
// this.baseUrl += absoluteUri.directory() + "/";
|
||||
} else {
|
||||
this.baseUrl = path.dirname(pathname) + "/";
|
||||
}
|
||||
|
||||
epubPackage = this.request(this.packageUrl)
|
||||
.catch(function(error) {
|
||||
book.opening.reject(error);
|
||||
});
|
||||
|
||||
} else if(isArrayBuffer || isBase64 || this.isArchivedUrl(_url)) {
|
||||
// Book is archived
|
||||
this.url = '';
|
||||
// this.containerUrl = URI(containerPath).absoluteTo(this.url).toString();
|
||||
this.containerUrl = path.resolve("", containerPath);
|
||||
|
||||
epubContainer = this.unarchive(_url, isBase64).
|
||||
then(function() {
|
||||
return this.request(this.containerUrl);
|
||||
this.url = new Url(input);
|
||||
opening = this.openContainer(CONTAINER_PATH)
|
||||
.then(function(packagePath) {
|
||||
return this.openPackaging(packagePath);
|
||||
}.bind(this))
|
||||
.catch(function(error) {
|
||||
book.opening.reject(error);
|
||||
});
|
||||
}
|
||||
// Find the path to the Package from the container
|
||||
else if (!core.extension(pathname)) {
|
||||
|
||||
this.containerUrl = this.url + containerPath;
|
||||
|
||||
epubContainer = this.request(this.containerUrl)
|
||||
.catch(function(error) {
|
||||
// handle errors in loading container
|
||||
book.opening.reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
if (epubContainer) {
|
||||
epubPackage = epubContainer.
|
||||
then(function(containerXml){
|
||||
return parse.container(containerXml); // Container has path to content
|
||||
}).
|
||||
then(function(paths){
|
||||
// var packageUri = URI(paths.packagePath);
|
||||
// var absPackageUri = packageUri.absoluteTo(book.url);
|
||||
return opening;
|
||||
};
|
||||
|
||||
Book.prototype.openEpub = function(data, encoding){
|
||||
return this.unarchive(data, encoding || this.settings.encoding)
|
||||
.then(function() {
|
||||
return this.openContainer("/" + CONTAINER_PATH);
|
||||
}.bind(this))
|
||||
.then(function(packagePath) {
|
||||
return this.openPackaging("/" + packagePath);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Book.prototype.openContainer = function(url){
|
||||
return this.load(url)
|
||||
.then(function(xml) {
|
||||
this.container = new Container(xml);
|
||||
return this.container.packagePath;
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Book.prototype.openPackaging = function(url){
|
||||
var packageUrl;
|
||||
this.path = new Path(url);
|
||||
|
||||
if (book.url) {
|
||||
packageUrl = new URL(paths.packagePath, book.url);
|
||||
book.packageUrl = packageUrl.toString();
|
||||
return this.load(url)
|
||||
.then(function(xml) {
|
||||
this.packaging = new Packaging(xml);
|
||||
return this.unpack(this.packaging);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
Book.prototype.load = function (path) {
|
||||
var resolved;
|
||||
if(this.unarchived) {
|
||||
resolved = this.resolve(path);
|
||||
return this.unarchived.request(resolved);
|
||||
} else {
|
||||
book.packageUrl = "/" + paths.packagePath;
|
||||
resolved = this.resolve(path);
|
||||
return this.request(resolved, null, this.requestCredentials, this.requestHeaders);
|
||||
}
|
||||
};
|
||||
|
||||
Book.prototype.resolve = function (path, absolute) {
|
||||
var resolved = path;
|
||||
var isAbsolute = (path.indexOf('://') > -1);
|
||||
|
||||
if (isAbsolute) {
|
||||
return path;
|
||||
}
|
||||
|
||||
book.packagePath = paths.packagePath;
|
||||
book.encoding = paths.encoding;
|
||||
|
||||
// Set Url relative to the content
|
||||
if(packageUrl && packageUrl.origin) {
|
||||
book.baseUrl = book.url + path.dirname(paths.packagePath) + "/";
|
||||
} else {
|
||||
if(path.dirname(paths.packagePath)) {
|
||||
book.baseUrl = ""
|
||||
book.basePath = "/" + path.dirname(paths.packagePath) + "/";
|
||||
} else {
|
||||
book.basePath = "/"
|
||||
}
|
||||
if (this.path) {
|
||||
resolved = this.path.resolve(path);
|
||||
}
|
||||
|
||||
return book.request(book.packageUrl);
|
||||
}).catch(function(error) {
|
||||
// handle errors in either of the two requests
|
||||
book.opening.reject(error);
|
||||
});
|
||||
if(absolute != false && this.url) {
|
||||
resolved = this.url.resolve(resolved);
|
||||
}
|
||||
|
||||
epubPackage.then(function(packageXml) {
|
||||
|
||||
if (!packageXml) {
|
||||
return;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
// Get package information from epub opf
|
||||
book.unpack(packageXml);
|
||||
Book.prototype.determineType = function(input) {
|
||||
var url;
|
||||
var path;
|
||||
var extension;
|
||||
|
||||
if (typeof(input) != "string") {
|
||||
return "binary";
|
||||
}
|
||||
|
||||
url = new Url(input);
|
||||
path = url.path();
|
||||
extension = path.extension;
|
||||
|
||||
if (!extension) {
|
||||
return "directory";
|
||||
}
|
||||
|
||||
if(extension === "epub"){
|
||||
return "epub";
|
||||
}
|
||||
|
||||
if(extension === "opf"){
|
||||
return "opf";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* unpack the contents of the Books packageXml
|
||||
* @param {document} packageXml XML Document
|
||||
*/
|
||||
Book.prototype.unpack = function(opf){
|
||||
this.package = opf;
|
||||
|
||||
this.spine.unpack(this.package, this.resolve.bind(this));
|
||||
|
||||
this.loadNavigation(this.package).then(function(toc){
|
||||
this.toc = toc;
|
||||
this.loading.navigation.resolve(this.toc);
|
||||
}.bind(this));
|
||||
|
||||
this.cover = this.resolve(this.package.coverPath);
|
||||
|
||||
// Resolve promises
|
||||
book.loading.manifest.resolve(book.package.manifest);
|
||||
book.loading.metadata.resolve(book.package.metadata);
|
||||
book.loading.spine.resolve(book.spine);
|
||||
book.loading.cover.resolve(book.cover);
|
||||
this.loading.manifest.resolve(this.package.manifest);
|
||||
this.loading.metadata.resolve(this.package.metadata);
|
||||
this.loading.spine.resolve(this.spine);
|
||||
this.loading.cover.resolve(this.cover);
|
||||
|
||||
book.isOpen = true;
|
||||
|
||||
// Clear queue of any waiting book request
|
||||
this.isOpen = true;
|
||||
|
||||
// Resolve book opened promise
|
||||
book.opening.resolve(book);
|
||||
|
||||
}).catch(function(error) {
|
||||
// handle errors in parsing the book
|
||||
// console.error(error.message, error.stack);
|
||||
book.opening.reject(error);
|
||||
});
|
||||
|
||||
return this.opened;
|
||||
this.opening.resolve(this);
|
||||
};
|
||||
|
||||
Book.prototype.unpack = function(packageXml){
|
||||
var book = this,
|
||||
parse = new Parser();
|
||||
Book.prototype.loadNavigation = function(opf){
|
||||
var navPath = opf.navPath || opf.ncxPath;
|
||||
|
||||
book.package = parse.packageContents(packageXml); // Extract info from contents
|
||||
if(!book.package) {
|
||||
if (!navPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths
|
||||
book.package.basePath = book.basePath; // Provides a url base for resolving paths
|
||||
console.log("book.baseUrl", book.baseUrl );
|
||||
|
||||
this.spine.load(book.package);
|
||||
|
||||
book.navigation = new Navigation(book.package, this.request);
|
||||
book.navigation.load().then(function(toc){
|
||||
book.toc = toc;
|
||||
book.loading.navigation.resolve(book.toc);
|
||||
});
|
||||
|
||||
// //-- Set Global Layout setting based on metadata
|
||||
// MOVE TO RENDER
|
||||
// book.globalLayoutProperties = book.parseLayoutProperties(book.package.metadata);
|
||||
if (book.baseUrl) {
|
||||
book.cover = new URL(book.package.coverPath, book.baseUrl).toString();
|
||||
} else {
|
||||
book.cover = path.resolve(book.baseUrl, book.package.coverPath);
|
||||
}
|
||||
return this.load(navPath, 'xml')
|
||||
.then(function(xml) {
|
||||
this.navigation = new Navigation(xml);
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
// Alias for book.spine.get
|
||||
/**
|
||||
* Alias for book.spine.get
|
||||
* @param {string} target
|
||||
*/
|
||||
Book.prototype.section = function(target) {
|
||||
return this.spine.get(target);
|
||||
};
|
||||
|
||||
// Sugar to render a book
|
||||
/**
|
||||
* Sugar to render a book
|
||||
*/
|
||||
Book.prototype.renderTo = function(element, options) {
|
||||
// var renderMethod = (options && options.method) ?
|
||||
// options.method :
|
||||
|
@ -278,15 +298,6 @@ Book.prototype.renderTo = function(element, options) {
|
|||
return this.rendition;
|
||||
};
|
||||
|
||||
Book.prototype.requestMethod = function(_url) {
|
||||
// Switch request methods
|
||||
if(this.unarchived) {
|
||||
return this.unarchived.request(_url);
|
||||
} else {
|
||||
return request(_url, null, this.requestCredentials, this.requestHeaders);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Book.prototype.setRequestCredentials = function(_credentials) {
|
||||
this.requestCredentials = _credentials;
|
||||
|
@ -296,12 +307,17 @@ Book.prototype.setRequestHeaders = function(_headers) {
|
|||
this.requestHeaders = _headers;
|
||||
};
|
||||
|
||||
Book.prototype.unarchive = function(bookUrl, isBase64){
|
||||
/**
|
||||
* Unarchive a zipped epub
|
||||
*/
|
||||
Book.prototype.unarchive = function(bookUrl, encoding){
|
||||
this.unarchived = new Unarchive();
|
||||
return this.unarchived.open(bookUrl, isBase64);
|
||||
return this.unarchived.open(bookUrl, encoding);
|
||||
};
|
||||
|
||||
//-- Checks if url has a .epub or .zip extension, or is ArrayBuffer (of zip/epub)
|
||||
/**
|
||||
* Checks if url has a .epub or .zip extension, or is ArrayBuffer (of zip/epub)
|
||||
*/
|
||||
Book.prototype.isArchivedUrl = function(bookUrl){
|
||||
var extension;
|
||||
|
||||
|
@ -325,7 +341,9 @@ Book.prototype.isArchivedUrl = function(bookUrl){
|
|||
return false;
|
||||
};
|
||||
|
||||
//-- Returns the cover
|
||||
/**
|
||||
* Get the cover url
|
||||
*/
|
||||
Book.prototype.coverUrl = function(){
|
||||
var retrieved = this.loaded.cover.
|
||||
then(function(url) {
|
||||
|
@ -341,6 +359,9 @@ Book.prototype.coverUrl = function(){
|
|||
return retrieved;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find a DOM Range for a given CFI Range
|
||||
*/
|
||||
Book.prototype.range = function(cfiRange) {
|
||||
var cfi = new EpubCFI(cfiRange);
|
||||
var item = this.spine.get(cfi.spinePos);
|
||||
|
@ -351,7 +372,7 @@ Book.prototype.range = function(cfiRange) {
|
|||
})
|
||||
};
|
||||
|
||||
module.exports = Book;
|
||||
|
||||
//-- Enable binding events to book
|
||||
EventEmitter(Book.prototype);
|
||||
|
||||
module.exports = Book;
|
||||
|
|
33
src/container.js
Normal file
33
src/container.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
var path = require('path');
|
||||
var core = require('./core');
|
||||
var EpubCFI = require('./epubcfi');
|
||||
|
||||
|
||||
function Container(containerDocument) {
|
||||
if (containerDocument) {
|
||||
this.parse(containerDocument);
|
||||
}
|
||||
};
|
||||
|
||||
Container.prototype.parse = function(containerDocument){
|
||||
//-- <rootfile full-path="OPS/package.opf" media-type="application/oebps-package+xml"/>
|
||||
var rootfile, fullpath, folder, encoding;
|
||||
|
||||
if(!containerDocument) {
|
||||
console.error("Container File Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
rootfile = core.qs(containerDocument, "rootfile");
|
||||
|
||||
if(!rootfile) {
|
||||
console.error("No RootFile Found");
|
||||
return;
|
||||
}
|
||||
|
||||
this.packagePath = rootfile.getAttribute('full-path');
|
||||
this.directory = path.dirname(this.packagePath);
|
||||
this.encoding = containerDocument.xmlEncoding;
|
||||
};
|
||||
|
||||
module.exports = Container;
|
|
@ -174,7 +174,7 @@ Contents.prototype.viewport = function(options) {
|
|||
var $viewport = this.document.querySelector("meta[name='viewport']");
|
||||
var newContent = '';
|
||||
|
||||
/**
|
||||
/*
|
||||
* check for the viewport size
|
||||
* <meta name="viewport" content="width=1024,height=697" />
|
||||
*/
|
||||
|
|
223
src/core.js
223
src/core.js
|
@ -2,87 +2,125 @@ var base64 = require('base64-js');
|
|||
var path = require('path');
|
||||
|
||||
var requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;
|
||||
/*
|
||||
//-- Parse the different parts of a url, returning a object
|
||||
function uri(url){
|
||||
var uri = {
|
||||
protocol : '',
|
||||
host : '',
|
||||
path : '',
|
||||
origin : '',
|
||||
directory : '',
|
||||
base : '',
|
||||
filename : '',
|
||||
extension : '',
|
||||
fragment : '',
|
||||
href : url
|
||||
},
|
||||
doubleSlash = url.indexOf('://'),
|
||||
search = url.indexOf('?'),
|
||||
fragment = url.indexOf("#"),
|
||||
withoutProtocol,
|
||||
dot,
|
||||
firstSlash;
|
||||
|
||||
if(fragment != -1) {
|
||||
uri.fragment = url.slice(fragment + 1);
|
||||
url = url.slice(0, fragment);
|
||||
}
|
||||
|
||||
if(search != -1) {
|
||||
uri.search = url.slice(search + 1);
|
||||
url = url.slice(0, search);
|
||||
href = url;
|
||||
}
|
||||
|
||||
if(doubleSlash != -1) {
|
||||
uri.protocol = url.slice(0, doubleSlash);
|
||||
withoutProtocol = url.slice(doubleSlash+3);
|
||||
firstSlash = withoutProtocol.indexOf('/');
|
||||
|
||||
if(firstSlash === -1) {
|
||||
uri.host = uri.path;
|
||||
uri.path = "";
|
||||
} else {
|
||||
uri.host = withoutProtocol.slice(0, firstSlash);
|
||||
uri.path = withoutProtocol.slice(firstSlash);
|
||||
}
|
||||
|
||||
|
||||
uri.origin = uri.protocol + "://" + uri.host;
|
||||
|
||||
uri.directory = folder(uri.path);
|
||||
|
||||
uri.base = uri.origin + uri.directory;
|
||||
// return origin;
|
||||
} else {
|
||||
uri.path = url;
|
||||
uri.directory = folder(url);
|
||||
uri.base = uri.directory;
|
||||
}
|
||||
|
||||
//-- Filename
|
||||
uri.filename = url.replace(uri.base, '');
|
||||
dot = uri.filename.lastIndexOf('.');
|
||||
if(dot != -1) {
|
||||
uri.extension = uri.filename.slice(dot+1);
|
||||
}
|
||||
return uri;
|
||||
};
|
||||
|
||||
//-- Parse out the folder, will return everything before the last slash
|
||||
function folder(url){
|
||||
|
||||
var lastSlash = url.lastIndexOf('/');
|
||||
|
||||
if(lastSlash == -1) var folder = '';
|
||||
|
||||
folder = url.slice(0, lastSlash + 1);
|
||||
|
||||
return folder;
|
||||
|
||||
};
|
||||
/**
|
||||
* creates a uri object
|
||||
* @param {string} urlString a url string (relative or absolute)
|
||||
* @param {[string]} baseString optional base for the url,
|
||||
* default to window.location.href
|
||||
* @return {object} url
|
||||
*/
|
||||
function Url(urlString, baseString) {
|
||||
var absolute = (urlString.indexOf('://') > -1);
|
||||
|
||||
this.href = urlString;
|
||||
this.protocol = "";
|
||||
this.origin = "";
|
||||
this.fragment = "";
|
||||
this.search = "";
|
||||
this.base = baseString || undefined;
|
||||
|
||||
if (!absolute && !baseString) {
|
||||
this.base = window && window.location.href;
|
||||
}
|
||||
|
||||
try {
|
||||
this.Url = new URL(urlString, this.base);
|
||||
this.href = this.Url.href;
|
||||
|
||||
this.protocol = this.Url.protocol;
|
||||
this.origin = this.Url.origin;
|
||||
this.fragment = this.Url.fragment;
|
||||
this.search = this.Url.search;
|
||||
} catch (e) {
|
||||
// console.error(e);
|
||||
this.Url = undefined;
|
||||
}
|
||||
|
||||
this.Path = new Path(this.Url.pathname);
|
||||
this.directory = this.Path.directory;
|
||||
this.filename = this.Path.filename;
|
||||
this.extension = this.Path.extension;
|
||||
|
||||
}
|
||||
|
||||
Url.prototype.path = function () {
|
||||
return this.Path;
|
||||
};
|
||||
|
||||
Url.prototype.resolve = function (what) {
|
||||
var isAbsolute = (what.indexOf('://') > -1);
|
||||
var fullpath;
|
||||
|
||||
if (isAbsolute) {
|
||||
return what;
|
||||
}
|
||||
|
||||
fullpath = path.resolve(this.directory, what);
|
||||
return this.origin + fullpath;
|
||||
};
|
||||
|
||||
Url.prototype.relative = function (what) {
|
||||
return path.relative(what, this.directory);
|
||||
};
|
||||
|
||||
Url.prototype.toString = function () {
|
||||
return this.href;
|
||||
};
|
||||
|
||||
function Path(pathString) {
|
||||
var protocol;
|
||||
var parsed;
|
||||
|
||||
protocol = pathString.indexOf('://');
|
||||
if (protocol > -1) {
|
||||
pathString = new URL(pathString).pathname;
|
||||
}
|
||||
|
||||
parsed = this.parse(pathString);
|
||||
|
||||
this.path = pathString;
|
||||
|
||||
if (this.isDirectory(pathString)) {
|
||||
this.directory = pathString;
|
||||
} else {
|
||||
this.directory = parsed.dir + "/";
|
||||
}
|
||||
|
||||
this.filename = parsed.base;
|
||||
this.extension = parsed.ext.slice(1);
|
||||
|
||||
}
|
||||
|
||||
Path.prototype.parse = function (what) {
|
||||
return path.parse(what);
|
||||
};
|
||||
|
||||
Path.prototype.isDirectory = function (what) {
|
||||
return (what.charAt(what.length-1) === '/');
|
||||
};
|
||||
|
||||
Path.prototype.resolve = function (what) {
|
||||
return path.resolve(this.directory, what);
|
||||
};
|
||||
|
||||
Path.prototype.relative = function (what) {
|
||||
return path.relative(this.directory, what);
|
||||
};
|
||||
|
||||
Path.prototype.splitPath = function(filename) {
|
||||
return this.splitPathRe.exec(filename).slice(1);
|
||||
};
|
||||
|
||||
Path.prototype.toString = function () {
|
||||
return this.path;
|
||||
};
|
||||
|
||||
function assertPath(path) {
|
||||
if (typeof path !== 'string') {
|
||||
throw new TypeError('Path must be a string. Received ', path);
|
||||
}
|
||||
};
|
||||
|
||||
function extension(_url) {
|
||||
var url;
|
||||
|
@ -571,9 +609,27 @@ function defer() {
|
|||
Object.freeze(this);
|
||||
}
|
||||
|
||||
function querySelectorByType(html, element, type){
|
||||
var query;
|
||||
if (typeof html.querySelector != "undefined") {
|
||||
query = html.querySelector(element+'[*|type="'+type+'"]');
|
||||
}
|
||||
// Handle IE not supporting namespaced epub:type in querySelector
|
||||
if(!query || query.length === 0) {
|
||||
query = core.qsa(html, element);
|
||||
for (var i = 0; i < query.length; i++) {
|
||||
if(query[i].getAttributeNS("http://www.idpf.org/2007/ops", "type") === type) {
|
||||
return query[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return query;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
module.exports = {
|
||||
// 'uri': uri,
|
||||
// 'folder': folder,
|
||||
'extension' : extension,
|
||||
'directory' : directory,
|
||||
'isElement': isElement,
|
||||
|
@ -605,5 +661,8 @@ module.exports = {
|
|||
'qsp' : qsp,
|
||||
'blob2base64' : blob2base64,
|
||||
'createBase64Url': createBase64Url,
|
||||
'defer': defer
|
||||
'defer': defer,
|
||||
'Url': Url,
|
||||
'Path': Path,
|
||||
'querySelectorByType': querySelectorByType
|
||||
};
|
||||
|
|
21
src/epub.js
21
src/epub.js
|
@ -3,8 +3,16 @@ var EpubCFI = require('./epubcfi');
|
|||
var Rendition = require('./rendition');
|
||||
var Contents = require('./contents');
|
||||
|
||||
function ePub(_url) {
|
||||
return new Book(_url);
|
||||
/**
|
||||
* Creates a new Book
|
||||
* @param {string|ArrayBuffer} url URL, Path or ArrayBuffer
|
||||
* @param {object} options to pass to the book
|
||||
* @param options.requestMethod the request function to use
|
||||
* @returns {Book} a new Book object
|
||||
* @example ePub("/path/to/book.epub", {})
|
||||
*/
|
||||
function ePub(url, options) {
|
||||
return new Book(url, options);
|
||||
};
|
||||
|
||||
ePub.VERSION = "0.3.0";
|
||||
|
@ -15,10 +23,19 @@ ePub.Contents = Contents;
|
|||
|
||||
ePub.ViewManagers = {};
|
||||
ePub.Views = {};
|
||||
/**
|
||||
* register plugins
|
||||
*/
|
||||
ePub.register = {
|
||||
/**
|
||||
* register a new view manager
|
||||
*/
|
||||
manager : function(name, manager){
|
||||
return ePub.ViewManagers[name] = manager;
|
||||
},
|
||||
/**
|
||||
* register a new view
|
||||
*/
|
||||
view : function(name, view){
|
||||
return ePub.Views[name] = view;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ function Stage(_options) {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Creates an element to render to.
|
||||
* Resizes to passed width and height or to the elements size
|
||||
*/
|
||||
|
|
|
@ -1,85 +1,30 @@
|
|||
var core = require('./core');
|
||||
var Parser = require('./parser');
|
||||
var path = require('path');
|
||||
|
||||
function Navigation(_package, _request){
|
||||
var navigation = this;
|
||||
var parse = new Parser();
|
||||
var request = _request || require('./request');
|
||||
|
||||
this.package = _package;
|
||||
function Navigation(xml){
|
||||
this.toc = [];
|
||||
this.tocByHref = {};
|
||||
this.tocById = {};
|
||||
|
||||
if(_package.navPath) {
|
||||
if (_package.baseUrl) {
|
||||
this.navUrl = new URL(_package.navPath, _package.baseUrl).toString();
|
||||
} else {
|
||||
this.navUrl = path.resolve(_package.basePath, _package.navPath);
|
||||
}
|
||||
this.nav = {};
|
||||
|
||||
this.nav.load = function(_request){
|
||||
var loading = new core.defer();
|
||||
var loaded = loading.promise;
|
||||
|
||||
request(navigation.navUrl, 'xml').then(function(xml){
|
||||
navigation.toc = parse.nav(xml);
|
||||
navigation.loaded(navigation.toc);
|
||||
loading.resolve(navigation.toc);
|
||||
});
|
||||
|
||||
return loaded;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
if(_package.ncxPath) {
|
||||
if (_package.baseUrl) {
|
||||
this.ncxUrl = new URL(_package.ncxPath, _package.baseUrl).toString();
|
||||
} else {
|
||||
this.ncxUrl = path.resolve(_package.basePath, _package.ncxPath);
|
||||
}
|
||||
|
||||
this.ncx = {};
|
||||
|
||||
this.ncx.load = function(_request){
|
||||
var loading = new core.defer();
|
||||
var loaded = loading.promise;
|
||||
|
||||
request(navigation.ncxUrl, 'xml').then(function(xml){
|
||||
navigation.toc = parse.toc(xml);
|
||||
navigation.loaded(navigation.toc);
|
||||
loading.resolve(navigation.toc);
|
||||
});
|
||||
|
||||
return loaded;
|
||||
};
|
||||
|
||||
if (xml) {
|
||||
this.parse(xml);
|
||||
}
|
||||
};
|
||||
|
||||
// Load the navigation
|
||||
Navigation.prototype.load = function(_request) {
|
||||
var request = _request || require('./request');
|
||||
var loading, loaded;
|
||||
Navigation.prototype.parse = function(xml) {
|
||||
var html = core.qs(xml, "html");
|
||||
var ncx = core.qs(xml, "ncx");
|
||||
|
||||
if(this.nav) {
|
||||
loading = this.nav.load();
|
||||
} else if(this.ncx) {
|
||||
loading = this.ncx.load();
|
||||
} else {
|
||||
loaded = new core.defer();
|
||||
loaded.resolve([]);
|
||||
loading = loaded.promise;
|
||||
if(html) {
|
||||
this.toc = this.parseNav(xml);
|
||||
} else if(ncx){
|
||||
this.toc = this.parseNcx(xml);
|
||||
}
|
||||
|
||||
return loading;
|
||||
|
||||
this.unpack(this.toc);
|
||||
};
|
||||
|
||||
Navigation.prototype.loaded = function(toc) {
|
||||
Navigation.prototype.unpack = function(toc) {
|
||||
var item;
|
||||
|
||||
for (var i = 0; i < toc.length; i++) {
|
||||
|
@ -107,4 +52,139 @@ Navigation.prototype.get = function(target) {
|
|||
return this.toc[index];
|
||||
};
|
||||
|
||||
Navigation.prototype.parseNav = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navElement = core.querySelectorByType(navHtml, "nav", "toc");
|
||||
// var navItems = navElement ? navElement.querySelectorAll("ol li") : [];
|
||||
var navItems = navElement ? core.qsa(navElement, "li") : [];
|
||||
var length = navItems.length;
|
||||
var i;
|
||||
var toc = {};
|
||||
var list = [];
|
||||
var item, parent;
|
||||
|
||||
if(!navItems || length === 0) return list;
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
item = this.navItem(navItems[i], spineIndexByURL, bookSpine);
|
||||
toc[item.id] = item;
|
||||
if(!item.parent) {
|
||||
list.push(item);
|
||||
} else {
|
||||
parent = toc[item.parent];
|
||||
parent.subitems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
Navigation.prototype.navItem = function(item, spineIndexByURL, bookSpine){
|
||||
var id = item.getAttribute('id') || false,
|
||||
// content = item.querySelector("a, span"),
|
||||
content = core.qs(item, "a"),
|
||||
src = content.getAttribute('href') || '',
|
||||
text = content.textContent || "",
|
||||
// split = src.split("#"),
|
||||
// baseUrl = split[0],
|
||||
// spinePos = spineIndexByURL[baseUrl],
|
||||
// spineItem = bookSpine[spinePos],
|
||||
subitems = [],
|
||||
parentNode = item.parentNode,
|
||||
parent;
|
||||
// cfi = spineItem ? spineItem.cfi : '';
|
||||
|
||||
if(parentNode && parentNode.nodeName === "navPoint") {
|
||||
parent = parentNode.getAttribute('id');
|
||||
}
|
||||
|
||||
/*
|
||||
if(!id) {
|
||||
if(spinePos) {
|
||||
spineItem = bookSpine[spinePos];
|
||||
id = spineItem.id;
|
||||
cfi = spineItem.cfi;
|
||||
} else {
|
||||
id = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();
|
||||
item.setAttribute('id', id);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return {
|
||||
"id": id,
|
||||
"href": src,
|
||||
"label": text,
|
||||
"subitems" : subitems,
|
||||
"parent" : parent
|
||||
};
|
||||
};
|
||||
|
||||
Navigation.prototype.parseNcx = function(tocXml, spineIndexByURL, bookSpine){
|
||||
// var navPoints = tocXml.querySelectorAll("navMap navPoint");
|
||||
var navPoints = core.qsa(tocXml, "navPoint");
|
||||
var length = navPoints.length;
|
||||
var i;
|
||||
var toc = {};
|
||||
var list = [];
|
||||
var item, parent;
|
||||
|
||||
if(!navPoints || length === 0) return list;
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
item = this.ncxItem(navPoints[i], spineIndexByURL, bookSpine);
|
||||
toc[item.id] = item;
|
||||
if(!item.parent) {
|
||||
list.push(item);
|
||||
} else {
|
||||
parent = toc[item.parent];
|
||||
parent.subitems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
Navigation.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){
|
||||
var id = item.getAttribute('id') || false,
|
||||
// content = item.querySelector("content"),
|
||||
content = core.qs(item, "content"),
|
||||
src = content.getAttribute('src'),
|
||||
// navLabel = item.querySelector("navLabel"),
|
||||
navLabel = core.qs(item, "navLabel"),
|
||||
text = navLabel.textContent ? navLabel.textContent : "",
|
||||
// split = src.split("#"),
|
||||
// baseUrl = split[0],
|
||||
// spinePos = spineIndexByURL[baseUrl],
|
||||
// spineItem = bookSpine[spinePos],
|
||||
subitems = [],
|
||||
parentNode = item.parentNode,
|
||||
parent;
|
||||
// cfi = spineItem ? spineItem.cfi : '';
|
||||
|
||||
if(parentNode && parentNode.nodeName === "navPoint") {
|
||||
parent = parentNode.getAttribute('id');
|
||||
}
|
||||
|
||||
/*
|
||||
if(!id) {
|
||||
if(spinePos) {
|
||||
spineItem = bookSpine[spinePos];
|
||||
id = spineItem.id;
|
||||
cfi = spineItem.cfi;
|
||||
} else {
|
||||
id = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();
|
||||
item.setAttribute('id', id);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return {
|
||||
"id": id,
|
||||
"href": src,
|
||||
"label": text,
|
||||
"subitems" : subitems,
|
||||
"parent" : parent
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = Navigation;
|
||||
|
|
234
src/packaging.js
Normal file
234
src/packaging.js
Normal file
|
@ -0,0 +1,234 @@
|
|||
var path = require('path');
|
||||
var core = require('./core');
|
||||
var EpubCFI = require('./epubcfi');
|
||||
|
||||
|
||||
function Packaging(packageDocument) {
|
||||
if (packageDocument) {
|
||||
this.parse(packageDocument);
|
||||
}
|
||||
};
|
||||
|
||||
Packaging.prototype.parse = function(packageDocument){
|
||||
var metadataNode, manifestNode, spineNode;
|
||||
|
||||
if(!packageDocument) {
|
||||
console.error("Package File Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
metadataNode = core.qs(packageDocument, "metadata");
|
||||
if(!metadataNode) {
|
||||
console.error("No Metadata Found");
|
||||
return;
|
||||
}
|
||||
|
||||
manifestNode = core.qs(packageDocument, "manifest");
|
||||
if(!manifestNode) {
|
||||
console.error("No Manifest Found");
|
||||
return;
|
||||
}
|
||||
|
||||
spineNode = core.qs(packageDocument, "spine");
|
||||
if(!spineNode) {
|
||||
console.error("No Spine Found");
|
||||
return;
|
||||
}
|
||||
|
||||
this.manifest = this.parseManifest(manifestNode);
|
||||
this.navPath = this.findNavPath(manifestNode);
|
||||
this.ncxPath = this.findNcxPath(manifestNode, spineNode);
|
||||
this.coverPath = this.findCoverPath(packageDocument);
|
||||
|
||||
this.spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode);
|
||||
|
||||
this.spine = this.parseSpine(spineNode, this.manifest);
|
||||
|
||||
this.metadata = this.parseMetadata(metadataNode);
|
||||
|
||||
this.metadata.direction = spineNode.getAttribute("page-progression-direction");
|
||||
|
||||
|
||||
return {
|
||||
'metadata' : this.metadata,
|
||||
'spine' : this.spine,
|
||||
'manifest' : this.manifest,
|
||||
'navPath' : this.navPath,
|
||||
'ncxPath' : this.ncxPath,
|
||||
'coverPath': this.coverPath,
|
||||
'spineNodeIndex' : this.spineNodeIndex
|
||||
};
|
||||
};
|
||||
|
||||
Packaging.prototype.parseMetadata = function(xml){
|
||||
var metadata = {};
|
||||
|
||||
metadata.title = this.getElementText(xml, 'title');
|
||||
metadata.creator = this.getElementText(xml, 'creator');
|
||||
metadata.description = this.getElementText(xml, 'description');
|
||||
|
||||
metadata.pubdate = this.getElementText(xml, 'date');
|
||||
|
||||
metadata.publisher = this.getElementText(xml, 'publisher');
|
||||
|
||||
metadata.identifier = this.getElementText(xml, "identifier");
|
||||
metadata.language = this.getElementText(xml, "language");
|
||||
metadata.rights = this.getElementText(xml, "rights");
|
||||
|
||||
metadata.modified_date = this.getPropertyText(xml, 'dcterms:modified');
|
||||
|
||||
metadata.layout = this.getPropertyText(xml, "rendition:layout");
|
||||
metadata.orientation = this.getPropertyText(xml, 'rendition:orientation');
|
||||
metadata.flow = this.getPropertyText(xml, 'rendition:flow');
|
||||
metadata.viewport = this.getPropertyText(xml, 'rendition:viewport');
|
||||
// metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction");
|
||||
|
||||
return metadata;
|
||||
};
|
||||
|
||||
Packaging.prototype.parseManifest = function(manifestXml){
|
||||
var manifest = {};
|
||||
|
||||
//-- Turn items into an array
|
||||
// var selected = manifestXml.querySelectorAll("item");
|
||||
var selected = core.qsa(manifestXml, "item");
|
||||
var items = Array.prototype.slice.call(selected);
|
||||
|
||||
//-- Create an object with the id as key
|
||||
items.forEach(function(item){
|
||||
var id = item.getAttribute('id'),
|
||||
href = item.getAttribute('href') || '',
|
||||
type = item.getAttribute('media-type') || '',
|
||||
properties = item.getAttribute('properties') || '';
|
||||
|
||||
manifest[id] = {
|
||||
'href' : href,
|
||||
// 'url' : href,
|
||||
'type' : type,
|
||||
'properties' : properties.length ? properties.split(' ') : []
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
return manifest;
|
||||
|
||||
};
|
||||
|
||||
Packaging.prototype.parseSpine = function(spineXml, manifest){
|
||||
var spine = [];
|
||||
|
||||
var selected = spineXml.getElementsByTagName("itemref"),
|
||||
items = Array.prototype.slice.call(selected);
|
||||
|
||||
var epubcfi = new EpubCFI();
|
||||
|
||||
//-- Add to array to mantain ordering and cross reference with manifest
|
||||
items.forEach(function(item, index){
|
||||
var idref = item.getAttribute('idref');
|
||||
// var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id);
|
||||
var props = item.getAttribute('properties') || '';
|
||||
var propArray = props.length ? props.split(' ') : [];
|
||||
// var manifestProps = manifest[Id].properties;
|
||||
// var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : [];
|
||||
|
||||
var itemref = {
|
||||
'idref' : idref,
|
||||
'linear' : item.getAttribute('linear') || '',
|
||||
'properties' : propArray,
|
||||
// 'href' : manifest[Id].href,
|
||||
// 'url' : manifest[Id].url,
|
||||
'index' : index
|
||||
// 'cfiBase' : cfiBase
|
||||
};
|
||||
spine.push(itemref);
|
||||
});
|
||||
|
||||
return spine;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find TOC NAV
|
||||
*/
|
||||
Packaging.prototype.findNavPath = function(manifestNode){
|
||||
// Find item with property 'nav'
|
||||
// Should catch nav irregardless of order
|
||||
// var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']");
|
||||
var node = core.qsp(manifestNode, "item", {"properties":"nav"});
|
||||
return node ? node.getAttribute('href') : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find TOC NCX
|
||||
* media-type="application/x-dtbncx+xml" href="toc.ncx"
|
||||
*/
|
||||
Packaging.prototype.findNcxPath = function(manifestNode, spineNode){
|
||||
// var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']");
|
||||
var node = core.qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"});
|
||||
var tocId;
|
||||
|
||||
// If we can't find the toc by media-type then try to look for id of the item in the spine attributes as
|
||||
// according to http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4.1.2,
|
||||
// "The item that describes the NCX must be referenced by the spine toc attribute."
|
||||
if (!node) {
|
||||
tocId = spineNode.getAttribute("toc");
|
||||
if(tocId) {
|
||||
// node = manifestNode.querySelector("item[id='" + tocId + "']");
|
||||
node = manifestNode.getElementById(tocId);
|
||||
}
|
||||
}
|
||||
|
||||
return node ? node.getAttribute('href') : false;
|
||||
};
|
||||
|
||||
//-- Find Cover: <item properties="cover-image" id="ci" href="cover.svg" media-type="image/svg+xml" />
|
||||
//-- Fallback for Epub 2.0
|
||||
Packaging.prototype.findCoverPath = function(packageXml){
|
||||
var pkg = core.qs(packageXml, "package");
|
||||
var epubVersion = pkg.getAttribute('version');
|
||||
|
||||
if (epubVersion === '2.0') {
|
||||
var metaCover = core.qsp(packageXml, 'meta', {'name':'cover'});
|
||||
if (metaCover) {
|
||||
var coverId = metaCover.getAttribute('content');
|
||||
// var cover = packageXml.querySelector("item[id='" + coverId + "']");
|
||||
var cover = packageXml.getElementById(coverId);
|
||||
return cover ? cover.getAttribute('href') : false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// var node = packageXml.querySelector("item[properties='cover-image']");
|
||||
var node = core.qsp(packageXml, 'item', {'properties':'cover-image'});
|
||||
return node ? node.getAttribute('href') : false;
|
||||
}
|
||||
};
|
||||
|
||||
Packaging.prototype.getElementText = function(xml, tag){
|
||||
var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag),
|
||||
el;
|
||||
|
||||
if(!found || found.length === 0) return '';
|
||||
|
||||
el = found[0];
|
||||
|
||||
if(el.childNodes.length){
|
||||
return el.childNodes[0].nodeValue;
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
};
|
||||
|
||||
Packaging.prototype.getPropertyText = function(xml, property){
|
||||
var el = core.qsp(xml, "meta", {"property":property});
|
||||
|
||||
if(el && el.childNodes.length){
|
||||
return el.childNodes[0].nodeValue;
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
module.exports = Packaging;
|
405
src/parser.js
405
src/parser.js
|
@ -5,216 +5,7 @@ var EpubCFI = require('./epubcfi');
|
|||
|
||||
function Parser(){};
|
||||
|
||||
Parser.prototype.container = function(containerXml){
|
||||
//-- <rootfile full-path="OPS/package.opf" media-type="application/oebps-package+xml"/>
|
||||
var rootfile, fullpath, folder, encoding;
|
||||
|
||||
if(!containerXml) {
|
||||
console.error("Container File Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
rootfile = core.qs(containerXml, "rootfile");
|
||||
|
||||
if(!rootfile) {
|
||||
console.error("No RootFile Found");
|
||||
return;
|
||||
}
|
||||
|
||||
fullpath = rootfile.getAttribute('full-path');
|
||||
folder = path.dirname(fullpath);
|
||||
encoding = containerXml.xmlEncoding;
|
||||
|
||||
//-- Now that we have the path we can parse the contents
|
||||
return {
|
||||
'packagePath' : fullpath,
|
||||
'basePath' : folder,
|
||||
'encoding' : encoding
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.identifier = function(packageXml){
|
||||
var metadataNode;
|
||||
|
||||
if(!packageXml) {
|
||||
console.error("Package File Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
metadataNode = core.qs(packageXml, "metadata");
|
||||
|
||||
if(!metadataNode) {
|
||||
console.error("No Metadata Found");
|
||||
return;
|
||||
}
|
||||
|
||||
return this.getElementText(metadataNode, "identifier");
|
||||
};
|
||||
|
||||
Parser.prototype.packageContents = function(packageXml){
|
||||
var parse = this;
|
||||
var metadataNode, manifestNode, spineNode;
|
||||
var manifest, navPath, ncxPath, coverPath;
|
||||
var spineNodeIndex;
|
||||
var spine;
|
||||
var spineIndexByURL;
|
||||
var metadata;
|
||||
|
||||
if(!packageXml) {
|
||||
console.error("Package File Not Found");
|
||||
return;
|
||||
}
|
||||
|
||||
metadataNode = core.qs(packageXml, "metadata");
|
||||
if(!metadataNode) {
|
||||
console.error("No Metadata Found");
|
||||
return;
|
||||
}
|
||||
|
||||
manifestNode = core.qs(packageXml, "manifest");
|
||||
if(!manifestNode) {
|
||||
console.error("No Manifest Found");
|
||||
return;
|
||||
}
|
||||
|
||||
spineNode = core.qs(packageXml, "spine");
|
||||
if(!spineNode) {
|
||||
console.error("No Spine Found");
|
||||
return;
|
||||
}
|
||||
|
||||
manifest = parse.manifest(manifestNode);
|
||||
navPath = parse.findNavPath(manifestNode);
|
||||
ncxPath = parse.findNcxPath(manifestNode, spineNode);
|
||||
coverPath = parse.findCoverPath(packageXml);
|
||||
|
||||
spineNodeIndex = Array.prototype.indexOf.call(spineNode.parentNode.childNodes, spineNode);
|
||||
|
||||
spine = parse.spine(spineNode, manifest);
|
||||
|
||||
metadata = parse.metadata(metadataNode);
|
||||
|
||||
metadata.direction = spineNode.getAttribute("page-progression-direction");
|
||||
|
||||
return {
|
||||
'metadata' : metadata,
|
||||
'spine' : spine,
|
||||
'manifest' : manifest,
|
||||
'navPath' : navPath,
|
||||
'ncxPath' : ncxPath,
|
||||
'coverPath': coverPath,
|
||||
'spineNodeIndex' : spineNodeIndex
|
||||
};
|
||||
};
|
||||
|
||||
//-- Find TOC NAV
|
||||
Parser.prototype.findNavPath = function(manifestNode){
|
||||
// Find item with property 'nav'
|
||||
// Should catch nav irregardless of order
|
||||
// var node = manifestNode.querySelector("item[properties$='nav'], item[properties^='nav '], item[properties*=' nav ']");
|
||||
var node = core.qsp(manifestNode, "item", {"properties":"nav"});
|
||||
return node ? node.getAttribute('href') : false;
|
||||
};
|
||||
|
||||
//-- Find TOC NCX: media-type="application/x-dtbncx+xml" href="toc.ncx"
|
||||
Parser.prototype.findNcxPath = function(manifestNode, spineNode){
|
||||
// var node = manifestNode.querySelector("item[media-type='application/x-dtbncx+xml']");
|
||||
var node = core.qsp(manifestNode, "item", {"media-type":"application/x-dtbncx+xml"});
|
||||
var tocId;
|
||||
|
||||
// If we can't find the toc by media-type then try to look for id of the item in the spine attributes as
|
||||
// according to http://www.idpf.org/epub/20/spec/OPF_2.0.1_draft.htm#Section2.4.1.2,
|
||||
// "The item that describes the NCX must be referenced by the spine toc attribute."
|
||||
if (!node) {
|
||||
tocId = spineNode.getAttribute("toc");
|
||||
if(tocId) {
|
||||
// node = manifestNode.querySelector("item[id='" + tocId + "']");
|
||||
node = manifestNode.getElementById(tocId);
|
||||
}
|
||||
}
|
||||
|
||||
return node ? node.getAttribute('href') : false;
|
||||
};
|
||||
|
||||
//-- Expanded to match Readium web components
|
||||
Parser.prototype.metadata = function(xml){
|
||||
var metadata = {},
|
||||
p = this;
|
||||
|
||||
metadata.title = p.getElementText(xml, 'title');
|
||||
metadata.creator = p.getElementText(xml, 'creator');
|
||||
metadata.description = p.getElementText(xml, 'description');
|
||||
|
||||
metadata.pubdate = p.getElementText(xml, 'date');
|
||||
|
||||
metadata.publisher = p.getElementText(xml, 'publisher');
|
||||
|
||||
metadata.identifier = p.getElementText(xml, "identifier");
|
||||
metadata.language = p.getElementText(xml, "language");
|
||||
metadata.rights = p.getElementText(xml, "rights");
|
||||
|
||||
metadata.modified_date = p.getPropertyText(xml, 'dcterms:modified');
|
||||
|
||||
metadata.layout = p.getPropertyText(xml, "rendition:layout");
|
||||
metadata.orientation = p.getPropertyText(xml, 'rendition:orientation');
|
||||
metadata.flow = p.getPropertyText(xml, 'rendition:flow');
|
||||
metadata.viewport = p.getPropertyText(xml, 'rendition:viewport');
|
||||
// metadata.page_prog_dir = packageXml.querySelector("spine").getAttribute("page-progression-direction");
|
||||
|
||||
return metadata;
|
||||
};
|
||||
|
||||
//-- Find Cover: <item properties="cover-image" id="ci" href="cover.svg" media-type="image/svg+xml" />
|
||||
//-- Fallback for Epub 2.0
|
||||
Parser.prototype.findCoverPath = function(packageXml){
|
||||
var pkg = core.qs(packageXml, "package");
|
||||
var epubVersion = pkg.getAttribute('version');
|
||||
|
||||
if (epubVersion === '2.0') {
|
||||
var metaCover = core.qsp(packageXml, 'meta', {'name':'cover'});
|
||||
if (metaCover) {
|
||||
var coverId = metaCover.getAttribute('content');
|
||||
// var cover = packageXml.querySelector("item[id='" + coverId + "']");
|
||||
var cover = packageXml.getElementById(coverId);
|
||||
return cover ? cover.getAttribute('href') : false;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// var node = packageXml.querySelector("item[properties='cover-image']");
|
||||
var node = core.qsp(packageXml, 'item', {'properties':'cover-image'});
|
||||
return node ? node.getAttribute('href') : false;
|
||||
}
|
||||
};
|
||||
|
||||
Parser.prototype.getElementText = function(xml, tag){
|
||||
var found = xml.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/", tag),
|
||||
el;
|
||||
|
||||
if(!found || found.length === 0) return '';
|
||||
|
||||
el = found[0];
|
||||
|
||||
if(el.childNodes.length){
|
||||
return el.childNodes[0].nodeValue;
|
||||
}
|
||||
|
||||
return '';
|
||||
|
||||
};
|
||||
|
||||
Parser.prototype.getPropertyText = function(xml, property){
|
||||
var el = core.qsp(xml, "meta", {"property":property});
|
||||
|
||||
if(el && el.childNodes.length){
|
||||
return el.childNodes[0].nodeValue;
|
||||
}
|
||||
|
||||
return '';
|
||||
};
|
||||
|
||||
/*
|
||||
Parser.prototype.querySelectorText = function(xml, q){
|
||||
var el = xml.querySelector(q);
|
||||
|
||||
|
@ -224,66 +15,7 @@ Parser.prototype.querySelectorText = function(xml, q){
|
|||
|
||||
return '';
|
||||
};
|
||||
|
||||
Parser.prototype.manifest = function(manifestXml){
|
||||
var manifest = {};
|
||||
|
||||
//-- Turn items into an array
|
||||
// var selected = manifestXml.querySelectorAll("item");
|
||||
var selected = core.qsa(manifestXml, "item");
|
||||
var items = Array.prototype.slice.call(selected);
|
||||
|
||||
//-- Create an object with the id as key
|
||||
items.forEach(function(item){
|
||||
var id = item.getAttribute('id'),
|
||||
href = item.getAttribute('href') || '',
|
||||
type = item.getAttribute('media-type') || '',
|
||||
properties = item.getAttribute('properties') || '';
|
||||
|
||||
manifest[id] = {
|
||||
'href' : href,
|
||||
// 'url' : href,
|
||||
'type' : type,
|
||||
'properties' : properties.length ? properties.split(' ') : []
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
return manifest;
|
||||
|
||||
};
|
||||
|
||||
Parser.prototype.spine = function(spineXml, manifest){
|
||||
var spine = [];
|
||||
|
||||
var selected = spineXml.getElementsByTagName("itemref"),
|
||||
items = Array.prototype.slice.call(selected);
|
||||
|
||||
var epubcfi = new EpubCFI();
|
||||
|
||||
//-- Add to array to mantain ordering and cross reference with manifest
|
||||
items.forEach(function(item, index){
|
||||
var idref = item.getAttribute('idref');
|
||||
// var cfiBase = epubcfi.generateChapterComponent(spineNodeIndex, index, Id);
|
||||
var props = item.getAttribute('properties') || '';
|
||||
var propArray = props.length ? props.split(' ') : [];
|
||||
// var manifestProps = manifest[Id].properties;
|
||||
// var manifestPropArray = manifestProps.length ? manifestProps.split(' ') : [];
|
||||
|
||||
var itemref = {
|
||||
'idref' : idref,
|
||||
'linear' : item.getAttribute('linear') || '',
|
||||
'properties' : propArray,
|
||||
// 'href' : manifest[Id].href,
|
||||
// 'url' : manifest[Id].url,
|
||||
'index' : index
|
||||
// 'cfiBase' : cfiBase
|
||||
};
|
||||
spine.push(itemref);
|
||||
});
|
||||
|
||||
return spine;
|
||||
};
|
||||
*/
|
||||
|
||||
Parser.prototype.querySelectorByType = function(html, element, type){
|
||||
var query;
|
||||
|
@ -303,140 +35,7 @@ Parser.prototype.querySelectorByType = function(html, element, type){
|
|||
}
|
||||
};
|
||||
|
||||
Parser.prototype.nav = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navElement = this.querySelectorByType(navHtml, "nav", "toc");
|
||||
// var navItems = navElement ? navElement.querySelectorAll("ol li") : [];
|
||||
var navItems = navElement ? core.qsa(navElement, "li") : [];
|
||||
var length = navItems.length;
|
||||
var i;
|
||||
var toc = {};
|
||||
var list = [];
|
||||
var item, parent;
|
||||
|
||||
if(!navItems || length === 0) return list;
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
item = this.navItem(navItems[i], spineIndexByURL, bookSpine);
|
||||
toc[item.id] = item;
|
||||
if(!item.parent) {
|
||||
list.push(item);
|
||||
} else {
|
||||
parent = toc[item.parent];
|
||||
parent.subitems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
Parser.prototype.navItem = function(item, spineIndexByURL, bookSpine){
|
||||
var id = item.getAttribute('id') || false,
|
||||
// content = item.querySelector("a, span"),
|
||||
content = core.qs(item, "a"),
|
||||
src = content.getAttribute('href') || '',
|
||||
text = content.textContent || "",
|
||||
// split = src.split("#"),
|
||||
// baseUrl = split[0],
|
||||
// spinePos = spineIndexByURL[baseUrl],
|
||||
// spineItem = bookSpine[spinePos],
|
||||
subitems = [],
|
||||
parentNode = item.parentNode,
|
||||
parent;
|
||||
// cfi = spineItem ? spineItem.cfi : '';
|
||||
|
||||
if(parentNode && parentNode.nodeName === "navPoint") {
|
||||
parent = parentNode.getAttribute('id');
|
||||
}
|
||||
|
||||
/*
|
||||
if(!id) {
|
||||
if(spinePos) {
|
||||
spineItem = bookSpine[spinePos];
|
||||
id = spineItem.id;
|
||||
cfi = spineItem.cfi;
|
||||
} else {
|
||||
id = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();
|
||||
item.setAttribute('id', id);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return {
|
||||
"id": id,
|
||||
"href": src,
|
||||
"label": text,
|
||||
"subitems" : subitems,
|
||||
"parent" : parent
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.ncx = function(tocXml, spineIndexByURL, bookSpine){
|
||||
// var navPoints = tocXml.querySelectorAll("navMap navPoint");
|
||||
var navPoints = core.qsa(tocXml, "navPoint");
|
||||
var length = navPoints.length;
|
||||
var i;
|
||||
var toc = {};
|
||||
var list = [];
|
||||
var item, parent;
|
||||
|
||||
if(!navPoints || length === 0) return list;
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
item = this.ncxItem(navPoints[i], spineIndexByURL, bookSpine);
|
||||
toc[item.id] = item;
|
||||
if(!item.parent) {
|
||||
list.push(item);
|
||||
} else {
|
||||
parent = toc[item.parent];
|
||||
parent.subitems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
Parser.prototype.ncxItem = function(item, spineIndexByURL, bookSpine){
|
||||
var id = item.getAttribute('id') || false,
|
||||
// content = item.querySelector("content"),
|
||||
content = core.qs(item, "content"),
|
||||
src = content.getAttribute('src'),
|
||||
// navLabel = item.querySelector("navLabel"),
|
||||
navLabel = core.qs(item, "navLabel"),
|
||||
text = navLabel.textContent ? navLabel.textContent : "",
|
||||
// split = src.split("#"),
|
||||
// baseUrl = split[0],
|
||||
// spinePos = spineIndexByURL[baseUrl],
|
||||
// spineItem = bookSpine[spinePos],
|
||||
subitems = [],
|
||||
parentNode = item.parentNode,
|
||||
parent;
|
||||
// cfi = spineItem ? spineItem.cfi : '';
|
||||
|
||||
if(parentNode && parentNode.nodeName === "navPoint") {
|
||||
parent = parentNode.getAttribute('id');
|
||||
}
|
||||
|
||||
/*
|
||||
if(!id) {
|
||||
if(spinePos) {
|
||||
spineItem = bookSpine[spinePos];
|
||||
id = spineItem.id;
|
||||
cfi = spineItem.cfi;
|
||||
} else {
|
||||
id = 'epubjs-autogen-toc-id-' + EPUBJS.core.uuid();
|
||||
item.setAttribute('id', id);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return {
|
||||
"id": id,
|
||||
"href": src,
|
||||
"label": text,
|
||||
"subitems" : subitems,
|
||||
"parent" : parent
|
||||
};
|
||||
};
|
||||
|
||||
Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){
|
||||
var navElement = this.querySelectorByType(navHtml, "nav", "page-list");
|
||||
|
|
|
@ -7,6 +7,7 @@ var EpubCFI = require('./epubcfi');
|
|||
var Queue = require('./queue');
|
||||
var Layout = require('./layout');
|
||||
var Mapping = require('./mapping');
|
||||
var Path = require('./core').Path;
|
||||
|
||||
function Rendition(book, options) {
|
||||
|
||||
|
@ -58,7 +59,7 @@ function Rendition(book, options) {
|
|||
// this.started = this.starting.promise;
|
||||
this.q.enqueue(this.start);
|
||||
|
||||
if(this.book.unarchived) {
|
||||
if(this.book.archived) {
|
||||
this.q.enqueue(this.replacements.bind(this));
|
||||
}
|
||||
|
||||
|
@ -106,7 +107,7 @@ Rendition.prototype.start = function(){
|
|||
this.manager = new this.ViewManager({
|
||||
view: this.View,
|
||||
queue: this.q,
|
||||
request: this.book.request,
|
||||
request: this.book.load.bind(this.book),
|
||||
settings: this.settings
|
||||
});
|
||||
}
|
||||
|
@ -441,7 +442,7 @@ Rendition.prototype.replacements = function(){
|
|||
var processing = urls.
|
||||
map(function(url) {
|
||||
// var absolute = new URL(url, this.book.baseUrl).toString();
|
||||
var absolute = path.resolve(this.book.basePath, url);
|
||||
var absolute = this.book.resolve(url);
|
||||
// Full url from archive base
|
||||
return this.book.unarchived.createUrl(absolute, {"base64": this.settings.useBase64});
|
||||
}.bind(this));
|
||||
|
@ -494,32 +495,15 @@ Rendition.prototype.replaceCss = function(href, urls, replacementUrls){
|
|||
}
|
||||
|
||||
var fileUri;
|
||||
var absolute;
|
||||
if (this.book.baseUrl) {
|
||||
fileUri = new URL(href, this.book.baseUrl);
|
||||
absolute = fileUri.toString();
|
||||
} else {
|
||||
absolute = path.resolve(this.book.basePath, href);
|
||||
}
|
||||
|
||||
var absolute = this.book.resolve(href);
|
||||
|
||||
// Get the text of the css file from the archive
|
||||
var textResponse = this.book.unarchived.getText(absolute);
|
||||
// Get asset links relative to css file
|
||||
var relUrls = urls.
|
||||
map(function(assetHref) {
|
||||
// var assetUri = URI(assetHref).absoluteTo(this.book.baseUrl);
|
||||
// var relative = assetUri.relativeTo(absolute).toString();
|
||||
|
||||
var assetUrl;
|
||||
var relativeUrl;
|
||||
if (this.book.baseUrl) {
|
||||
assetUrl = new URL(assetHref, this.book.baseUrl);
|
||||
relative = path.relative(path.dirname(fileUri.pathname), assetUrl.pathname);
|
||||
} else {
|
||||
assetUrl = path.resolve(this.book.basePath, assetHref);
|
||||
relative = path.relative(path.dirname(absolute), assetUrl);
|
||||
}
|
||||
var resolved = this.book.resolve(assetHref);
|
||||
var relative = new Path(absolute).relative(resolved);
|
||||
|
||||
return relative;
|
||||
}.bind(this));
|
||||
|
@ -552,34 +536,17 @@ Rendition.prototype.replaceCss = function(href, urls, replacementUrls){
|
|||
Rendition.prototype.replaceAssets = function(section, urls, replacementUrls){
|
||||
// var fileUri = URI(section.url);
|
||||
var fileUri;
|
||||
var absolute;
|
||||
if (this.book.baseUrl) {
|
||||
fileUri = new URL(section.url, this.book.baseUrl);
|
||||
absolute = fileUri.toString();
|
||||
} else {
|
||||
absolute = path.resolve(this.book.basePath, section.url);
|
||||
}
|
||||
var absolute = section.url;
|
||||
|
||||
// Get Urls relative to current sections
|
||||
var relUrls = urls.
|
||||
map(function(href) {
|
||||
// var assetUri = URI(href).absoluteTo(this.book.baseUrl);
|
||||
// var relative = assetUri.relativeTo(fileUri).toString();
|
||||
|
||||
var assetUrl;
|
||||
var relativeUrl;
|
||||
if (this.book.baseUrl) {
|
||||
assetUrl = new URL(href, this.book.baseUrl);
|
||||
relative = path.relative(path.dirname(fileUri.pathname), assetUrl.pathname);
|
||||
} else {
|
||||
assetUrl = path.resolve(this.book.basePath, href);
|
||||
relative = path.relative(path.dirname(absolute), assetUrl);
|
||||
}
|
||||
var resolved = this.book.resolve(href);
|
||||
var relative = new Path(absolute).relative(resolved);
|
||||
|
||||
return relative;
|
||||
}.bind(this));
|
||||
|
||||
|
||||
section.output = replace.substitute(section.output, relUrls, replacementUrls);
|
||||
};
|
||||
|
||||
|
|
|
@ -57,17 +57,7 @@ function links(view, renderer) {
|
|||
// var linkUri = URI(href);
|
||||
// var absolute = linkUri.absoluteTo(view.section.url);
|
||||
// var relative = absolute.relativeTo(this.book.baseUrl).toString();
|
||||
var linkUrl;
|
||||
var linkPath;
|
||||
var relative;
|
||||
|
||||
if (this.book.baseUrl) {
|
||||
linkUrl = new URL(href, this.book.baseUrl);
|
||||
relative = path.relative(path.dirname(linkUrl.pathname), this.book.packagePath);
|
||||
} else {
|
||||
linkPath = path.resolve(this.book.basePath, href);
|
||||
relative = path.relative(this.book.packagePath, linkPath);
|
||||
}
|
||||
var relative = this.book.resolve(href, false);
|
||||
|
||||
if(linkUrl && linkUrl.protocol){
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ Section.prototype.base = function(_document){
|
|||
var task = new core.defer();
|
||||
var base = _document.createElement("base"); // TODO: check if exists
|
||||
var head;
|
||||
console.log(window.location.origin + "/" +this.url);
|
||||
|
||||
base.setAttribute("href", window.location.origin + "/" +this.url);
|
||||
|
||||
|
@ -113,7 +112,7 @@ Section.prototype.find = function(_query){
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
/*
|
||||
* Reconciles the current chapters layout properies with
|
||||
* the global layout properities.
|
||||
* Takes: global layout settings object, chapter properties string
|
||||
|
|
|
@ -4,8 +4,7 @@ var Hook = require('./hook');
|
|||
var Section = require('./section');
|
||||
var replacements = require('./replacements');
|
||||
|
||||
function Spine(_request){
|
||||
this.request = _request;
|
||||
function Spine(){
|
||||
this.spineItems = [];
|
||||
this.spineByHref = {};
|
||||
this.spineById = {};
|
||||
|
@ -23,7 +22,7 @@ function Spine(_request){
|
|||
this.loaded = false;
|
||||
};
|
||||
|
||||
Spine.prototype.load = function(_package) {
|
||||
Spine.prototype.unpack = function(_package, resolver) {
|
||||
|
||||
this.items = _package.spine;
|
||||
this.manifest = _package.manifest;
|
||||
|
@ -40,7 +39,7 @@ Spine.prototype.load = function(_package) {
|
|||
|
||||
if(manifestItem) {
|
||||
item.href = manifestItem.href;
|
||||
item.url = this.baseUrl + item.href;
|
||||
item.url = resolver(item.href, true);
|
||||
|
||||
if(manifestItem.properties.length){
|
||||
item.properties.push.apply(item.properties, manifestItem.properties);
|
||||
|
|
|
@ -11,26 +11,24 @@ function Unarchive() {
|
|||
|
||||
Unarchive.prototype.checkRequirements = function(callback){
|
||||
try {
|
||||
if (typeof JSZip !== 'undefined') {
|
||||
this.zip = new JSZip();
|
||||
} else {
|
||||
if (typeof JSZip === 'undefined') {
|
||||
JSZip = require('jszip');
|
||||
this.zip = new JSZip();
|
||||
}
|
||||
this.zip = new JSZip();
|
||||
} catch (e) {
|
||||
console.error("JSZip lib not loaded");
|
||||
}
|
||||
};
|
||||
|
||||
Unarchive.prototype.open = function(zipUrl, isBase64){
|
||||
if (zipUrl instanceof ArrayBuffer || isBase64) {
|
||||
return this.zip.loadAsync(zipUrl, {"base64": isBase64});
|
||||
} else {
|
||||
Unarchive.prototype.open = function(input, isBase64){
|
||||
return this.zip.loadAsync(input, {"base64": isBase64});
|
||||
};
|
||||
|
||||
Unarchive.prototype.openUrl = function(zipUrl, isBase64){
|
||||
return request(zipUrl, "binary")
|
||||
.then(function(data){
|
||||
return this.zip.loadAsync(data);
|
||||
return this.zip.loadAsync(data, {"base64": isBase64});
|
||||
}.bind(this));
|
||||
}
|
||||
};
|
||||
|
||||
Unarchive.prototype.request = function(url, type){
|
||||
|
|
11
test/book.js
Normal file
11
test/book.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
var assert = require('assert');
|
||||
describe('Book', function() {
|
||||
|
||||
var Book = require('../src/book');
|
||||
|
||||
before(function(){
|
||||
|
||||
});
|
||||
|
||||
|
||||
})
|
171
test/core.js
Normal file
171
test/core.js
Normal file
|
@ -0,0 +1,171 @@
|
|||
var assert = require('assert');
|
||||
describe('Core', function() {
|
||||
|
||||
|
||||
before(function(){
|
||||
|
||||
});
|
||||
|
||||
|
||||
describe('Url', function () {
|
||||
|
||||
var Url = require('../src/core').Url;
|
||||
|
||||
it("Url()", function() {
|
||||
var url = new Url("http://example.com/fred/chasen/derf.html");
|
||||
|
||||
assert.equal( url.href, "http://example.com/fred/chasen/derf.html" );
|
||||
assert.equal( url.directory, "/fred/chasen/" );
|
||||
assert.equal( url.extension, "html" );
|
||||
assert.equal( url.filename, "derf.html" );
|
||||
assert.equal( url.origin, "http://example.com" );
|
||||
assert.equal( url.protocol, "http:" );
|
||||
assert.equal( url.search, "" );
|
||||
});
|
||||
|
||||
describe('#resolve()', function () {
|
||||
it("should join subfolders", function() {
|
||||
var a = "http://example.com/fred/chasen/";
|
||||
var b = "ops/derf.html";
|
||||
|
||||
var resolved = new Url(a).resolve(b);
|
||||
assert.equal( resolved, "http://example.com/fred/chasen/ops/derf.html" );
|
||||
});
|
||||
|
||||
it("should resolve up a level", function() {
|
||||
var a = "http://example.com/fred/chasen/index.html";
|
||||
var b = "../derf.html";
|
||||
|
||||
var resolved = new Url(a).resolve(b);
|
||||
assert.equal( resolved, "http://example.com/fred/derf.html" );
|
||||
});
|
||||
|
||||
it("should resolve absolute", function() {
|
||||
var a = "http://example.com/fred/chasen/index.html";
|
||||
var b = "/derf.html";
|
||||
|
||||
var resolved = new Url(a).resolve(b);
|
||||
assert.equal( resolved, "http://example.com/derf.html" );
|
||||
});
|
||||
|
||||
it("should resolve with search strings", function() {
|
||||
var a = "http://example.com/fred/chasen/index.html?debug=true";
|
||||
var b = "/derf.html";
|
||||
|
||||
var resolved = new Url(a).resolve(b);
|
||||
assert.equal( resolved, "http://example.com/derf.html" );
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('Path', function () {
|
||||
|
||||
var Path = require('../src/core').Path;
|
||||
|
||||
it("Path()", function() {
|
||||
var path = new Path("/fred/chasen/derf.html");
|
||||
|
||||
assert.equal( path.path, "/fred/chasen/derf.html" );
|
||||
assert.equal( path.directory, "/fred/chasen/" );
|
||||
assert.equal( path.extension, "html" );
|
||||
assert.equal( path.filename, "derf.html" );
|
||||
});
|
||||
|
||||
it("Strip out url", function() {
|
||||
var path = new Path("http://example.com/fred/chasen/derf.html");
|
||||
|
||||
assert.equal( path.path, "/fred/chasen/derf.html" );
|
||||
assert.equal( path.directory, "/fred/chasen/" );
|
||||
assert.equal( path.extension, "html" );
|
||||
assert.equal( path.filename, "derf.html" );
|
||||
});
|
||||
|
||||
describe('#parse()', function () {
|
||||
it("should parse a path", function() {
|
||||
var path = Path.prototype.parse("/fred/chasen/derf.html");
|
||||
|
||||
assert.equal( path.dir, "/fred/chasen" );
|
||||
assert.equal( path.base, "derf.html" );
|
||||
assert.equal( path.ext, ".html" );
|
||||
});
|
||||
|
||||
it("should parse a relative path", function() {
|
||||
var path = Path.prototype.parse("fred/chasen/derf.html");
|
||||
|
||||
assert.equal( path.dir, "fred/chasen" );
|
||||
assert.equal( path.base, "derf.html" );
|
||||
assert.equal( path.ext, ".html" );
|
||||
});
|
||||
});
|
||||
|
||||
describe('#isDirectory()', function () {
|
||||
it("should recognize a directory", function() {
|
||||
var directory = Path.prototype.isDirectory("/fred/chasen/");
|
||||
var notDirectory = Path.prototype.isDirectory("/fred/chasen/derf.html");
|
||||
|
||||
assert(directory, "/fred/chasen/ is a directory" );
|
||||
assert(!notDirectory, "/fred/chasen/derf.html is not directory" );
|
||||
});
|
||||
});
|
||||
|
||||
describe('#resolve()', function () {
|
||||
|
||||
it("should resolve a path", function() {
|
||||
var a = "/fred/chasen/index.html";
|
||||
var b = "derf.html";
|
||||
|
||||
var resolved = new Path(a).resolve(b);
|
||||
assert.equal(resolved, "/fred/chasen/derf.html" );
|
||||
});
|
||||
|
||||
it("should resolve a relative path", function() {
|
||||
var a = "fred/chasen/index.html";
|
||||
var b = "derf.html";
|
||||
|
||||
var resolved = new Path(a).resolve(b);
|
||||
assert.equal(resolved, "/fred/chasen/derf.html" );
|
||||
});
|
||||
|
||||
it("should resolve a level up", function() {
|
||||
var a = "/fred/chasen/index.html";
|
||||
var b = "../derf.html";
|
||||
|
||||
var resolved = new Path(a).resolve(b);
|
||||
assert.equal(resolved, "/fred/derf.html" );
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('#relative()', function () {
|
||||
|
||||
it("should find a relative path at the same level", function() {
|
||||
var a = "/fred/chasen/index.html";
|
||||
var b = "/fred/chasen/derf.html";
|
||||
|
||||
var relative = new Path(a).relative(b);
|
||||
assert.equal(relative, "derf.html" );
|
||||
});
|
||||
|
||||
it("should find a relative path down a level", function() {
|
||||
var a = "/fred/chasen/index.html";
|
||||
var b = "/fred/chasen/ops/derf.html";
|
||||
|
||||
var relative = new Path(a).relative(b);
|
||||
assert.equal(relative, "ops/derf.html" );
|
||||
});
|
||||
|
||||
it("should resolve a level up", function() {
|
||||
var a = "/fred/chasen/index.html";
|
||||
var b = "/fred/derf.html";
|
||||
|
||||
var relative = new Path(a).relative(b);
|
||||
assert.equal(relative, "../derf.html" );
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
14
test/epub.js
14
test/epub.js
|
@ -29,25 +29,23 @@ describe('ePub', function() {
|
|||
// server.restore();
|
||||
});
|
||||
|
||||
it('should open a epub', function(done) {
|
||||
it('should open a epub', function() {
|
||||
var book = ePub("/fixtures/alice/OPS/package.opf");
|
||||
|
||||
book.opened.then(function(){
|
||||
return book.opened.then(function(){
|
||||
assert.equal( book.isOpen, true, "book is opened" );
|
||||
assert.equal( book.url, "http://localhost:9876/fixtures/alice/OPS/package.opf", "book url is passed to new Book" );
|
||||
done();
|
||||
assert.equal( book.url.toString(), "http://localhost:9876/fixtures/alice/OPS/package.opf", "book url is passed to new Book" );
|
||||
});
|
||||
});
|
||||
|
||||
it('should open a archived epub', function(done) {
|
||||
it('should open a archived epub', function() {
|
||||
var book = ePub("/fixtures/alice.epub");
|
||||
|
||||
assert(typeof (JSZip) !== "undefined", "JSZip is present" );
|
||||
|
||||
book.opened.then(function(){
|
||||
return book.opened.then(function(){
|
||||
assert.equal( book.isOpen, true, "book is opened" );
|
||||
assert.equal( book.url, "", "book url is empty as book is archived" );
|
||||
done();
|
||||
assert( book.unarchived, "book is unarchived" );
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -26,6 +26,11 @@ module.exports = {
|
|||
plugins: [
|
||||
// new webpack.IgnorePlugin(/punycode|IPv6/),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
path: "path-webpack"
|
||||
}
|
||||
},
|
||||
devServer: {
|
||||
host: hostname,
|
||||
port: port,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue