mirror of
https://github.com/futurepress/epub.js.git
synced 2025-10-03 14:59:18 +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
1002
dist/epub.js
vendored
1002
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
|
// create a single instance of the compiler to allow caching
|
||||||
var watchCompiler = webpack(watchConfig);
|
var watchCompiler = webpack(watchConfig);
|
||||||
|
|
||||||
|
var buildDocs = require('gulp-documentation');
|
||||||
|
|
||||||
// Lint JS
|
// Lint JS
|
||||||
gulp.task('lint', function() {
|
gulp.task('lint', function() {
|
||||||
return gulp.src('src/*.js')
|
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
|
// Default
|
||||||
gulp.task('default', ['lint', 'bundle']);
|
gulp.task('default', ['lint', 'bundle']);
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,12 @@ module.exports = function(config) {
|
||||||
"jszip": "JSZip",
|
"jszip": "JSZip",
|
||||||
"xmldom": "xmldom"
|
"xmldom": "xmldom"
|
||||||
},
|
},
|
||||||
devtool: 'inline-source-map'
|
devtool: 'inline-source-map',
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
path: "path-webpack"
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
webpackMiddleware: {
|
webpackMiddleware: {
|
||||||
|
@ -70,7 +75,7 @@ module.exports = function(config) {
|
||||||
|
|
||||||
// level of logging
|
// level of logging
|
||||||
// possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
|
// 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
|
// enable / disable watching file and executing tests whenever any file changes
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"gulp": "^3.9.0",
|
"gulp": "^3.9.0",
|
||||||
"gulp-concat": "^2.3.4",
|
"gulp-concat": "^2.3.4",
|
||||||
"gulp-connect": "~3.1.1",
|
"gulp-connect": "~3.1.1",
|
||||||
|
"gulp-documentation": "fchasen/gulp-documentation",
|
||||||
"gulp-jshint": "^2.0.0",
|
"gulp-jshint": "^2.0.0",
|
||||||
"gulp-plumber": "^1.1.0",
|
"gulp-plumber": "^1.1.0",
|
||||||
"gulp-rename": "^1.2.0",
|
"gulp-rename": "^1.2.0",
|
||||||
|
@ -40,6 +41,7 @@
|
||||||
"mocha-loader": "^1.0.0",
|
"mocha-loader": "^1.0.0",
|
||||||
"morgan": "^1.1.1",
|
"morgan": "^1.1.1",
|
||||||
"optimist": "^0.6.1",
|
"optimist": "^0.6.1",
|
||||||
|
"path-webpack": "^0.0.2",
|
||||||
"portfinder": "^1.0.2",
|
"portfinder": "^1.0.2",
|
||||||
"raw-loader": "^0.5.1",
|
"raw-loader": "^0.5.1",
|
||||||
"serve-static": "^1.3.1",
|
"serve-static": "^1.3.1",
|
||||||
|
|
395
src/book.js
395
src/book.js
|
@ -1,19 +1,37 @@
|
||||||
var EventEmitter = require('event-emitter');
|
var EventEmitter = require('event-emitter');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var core = require('./core');
|
var core = require('./core');
|
||||||
|
var Url = require('./core').Url;
|
||||||
|
var Path = require('./core').Path;
|
||||||
var Spine = require('./spine');
|
var Spine = require('./spine');
|
||||||
var Locations = require('./locations');
|
var Locations = require('./locations');
|
||||||
var Parser = require('./parser');
|
var Parser = require('./parser');
|
||||||
|
var Container = require('./container');
|
||||||
|
var Packaging = require('./packaging');
|
||||||
var Navigation = require('./navigation');
|
var Navigation = require('./navigation');
|
||||||
var Rendition = require('./rendition');
|
var Rendition = require('./rendition');
|
||||||
var Unarchive = require('./unarchive');
|
var Unarchive = require('./unarchive');
|
||||||
var request = require('./request');
|
var request = require('./request');
|
||||||
var EpubCFI = require('./epubcfi');
|
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 || {}, {
|
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);
|
core.extend(this.settings, options);
|
||||||
|
@ -21,11 +39,12 @@ function Book(_url, options){
|
||||||
|
|
||||||
// Promises
|
// Promises
|
||||||
this.opening = new core.defer();
|
this.opening = new core.defer();
|
||||||
|
/**
|
||||||
|
* @property {promise} opened returns after the book is loaded
|
||||||
|
*/
|
||||||
this.opened = this.opening.promise;
|
this.opened = this.opening.promise;
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
|
|
||||||
this.url = undefined;
|
|
||||||
|
|
||||||
this.loading = {
|
this.loading = {
|
||||||
manifest: new core.defer(),
|
manifest: new core.defer(),
|
||||||
spine: new core.defer(),
|
spine: new core.defer(),
|
||||||
|
@ -45,6 +64,9 @@ function Book(_url, options){
|
||||||
};
|
};
|
||||||
|
|
||||||
// this.ready = RSVP.hash(this.loaded);
|
// 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.ready = Promise.all([this.loaded.manifest,
|
||||||
this.loaded.spine,
|
this.loaded.spine,
|
||||||
this.loaded.metadata,
|
this.loaded.metadata,
|
||||||
|
@ -57,216 +79,214 @@ function Book(_url, options){
|
||||||
this.isRendered = false;
|
this.isRendered = false;
|
||||||
// this._q = core.queue(this);
|
// 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) {
|
* @property {Locations} locations
|
||||||
var err = new Error("Cannot load book at "+ _url );
|
*/
|
||||||
|
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(err);
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
this.emit("loadFailed", error);
|
this.emit("openFailed", err);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Book.prototype.open = function(_url, options){
|
/**
|
||||||
var url;
|
* open a url
|
||||||
var pathname;
|
* @param {string} input URL, Path or ArrayBuffer
|
||||||
var parse = new Parser();
|
* @param {string} [what] to force opening
|
||||||
var epubPackage;
|
* @returns {Promise} of when the book has been loaded
|
||||||
var epubContainer;
|
* @example book.open("/path/to/book.epub")
|
||||||
var book = this;
|
*/
|
||||||
var containerPath = "META-INF/container.xml";
|
Book.prototype.open = function(input, what){
|
||||||
var location;
|
var opening;
|
||||||
var isArrayBuffer = false;
|
var type = what || this.determineType(input);
|
||||||
var isBase64 = options && options.base64;
|
|
||||||
|
|
||||||
if(!_url) {
|
if (type === "binary") {
|
||||||
this.opening.resolve(this);
|
this.archived = true;
|
||||||
return this.opened;
|
opening = this.openEpub(input);
|
||||||
}
|
} else if (type === "epub") {
|
||||||
|
this.archived = true;
|
||||||
// Reuse parsed url or create a new uri object
|
opening = this.request(input, 'binary')
|
||||||
// if(typeof(_url) === "object") {
|
.then(function(epubData) {
|
||||||
// uri = _url;
|
return this.openEpub(epubData);
|
||||||
// } else {
|
}.bind(this));
|
||||||
// uri = core.uri(_url);
|
} else if(type == "opf") {
|
||||||
// }
|
this.url = new Url(input);
|
||||||
if (_url instanceof ArrayBuffer || isBase64) {
|
opening = this.openPackaging(input);
|
||||||
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;
|
|
||||||
} else {
|
} else {
|
||||||
this.url = _url;
|
this.url = new Url(input);
|
||||||
}
|
opening = this.openContainer(CONTAINER_PATH)
|
||||||
|
.then(function(packagePath) {
|
||||||
// Find path to the Container
|
return this.openPackaging(packagePath);
|
||||||
// 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);
|
|
||||||
}.bind(this))
|
}.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) {
|
return opening;
|
||||||
epubPackage = epubContainer.
|
};
|
||||||
then(function(containerXml){
|
|
||||||
return parse.container(containerXml); // Container has path to content
|
Book.prototype.openEpub = function(data, encoding){
|
||||||
}).
|
return this.unarchive(data, encoding || this.settings.encoding)
|
||||||
then(function(paths){
|
.then(function() {
|
||||||
// var packageUri = URI(paths.packagePath);
|
return this.openContainer("/" + CONTAINER_PATH);
|
||||||
// var absPackageUri = packageUri.absoluteTo(book.url);
|
}.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;
|
var packageUrl;
|
||||||
|
this.path = new Path(url);
|
||||||
|
|
||||||
if (book.url) {
|
return this.load(url)
|
||||||
packageUrl = new URL(paths.packagePath, book.url);
|
.then(function(xml) {
|
||||||
book.packageUrl = packageUrl.toString();
|
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 {
|
} 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;
|
if (this.path) {
|
||||||
book.encoding = paths.encoding;
|
resolved = this.path.resolve(path);
|
||||||
|
|
||||||
// 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 = "/"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return book.request(book.packageUrl);
|
if(absolute != false && this.url) {
|
||||||
}).catch(function(error) {
|
resolved = this.url.resolve(resolved);
|
||||||
// handle errors in either of the two requests
|
|
||||||
book.opening.reject(error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
epubPackage.then(function(packageXml) {
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
if (!packageXml) {
|
Book.prototype.determineType = function(input) {
|
||||||
return;
|
var url;
|
||||||
|
var path;
|
||||||
|
var extension;
|
||||||
|
|
||||||
|
if (typeof(input) != "string") {
|
||||||
|
return "binary";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get package information from epub opf
|
url = new Url(input);
|
||||||
book.unpack(packageXml);
|
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
|
// Resolve promises
|
||||||
book.loading.manifest.resolve(book.package.manifest);
|
this.loading.manifest.resolve(this.package.manifest);
|
||||||
book.loading.metadata.resolve(book.package.metadata);
|
this.loading.metadata.resolve(this.package.metadata);
|
||||||
book.loading.spine.resolve(book.spine);
|
this.loading.spine.resolve(this.spine);
|
||||||
book.loading.cover.resolve(book.cover);
|
this.loading.cover.resolve(this.cover);
|
||||||
|
|
||||||
book.isOpen = true;
|
this.isOpen = true;
|
||||||
|
|
||||||
// Clear queue of any waiting book request
|
|
||||||
|
|
||||||
// Resolve book opened promise
|
// Resolve book opened promise
|
||||||
book.opening.resolve(book);
|
this.opening.resolve(this);
|
||||||
|
|
||||||
}).catch(function(error) {
|
|
||||||
// handle errors in parsing the book
|
|
||||||
// console.error(error.message, error.stack);
|
|
||||||
book.opening.reject(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
return this.opened;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Book.prototype.unpack = function(packageXml){
|
Book.prototype.loadNavigation = function(opf){
|
||||||
var book = this,
|
var navPath = opf.navPath || opf.ncxPath;
|
||||||
parse = new Parser();
|
|
||||||
|
|
||||||
book.package = parse.packageContents(packageXml); // Extract info from contents
|
if (!navPath) {
|
||||||
if(!book.package) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
book.package.baseUrl = book.baseUrl; // Provides a url base for resolving paths
|
return this.load(navPath, 'xml')
|
||||||
book.package.basePath = book.basePath; // Provides a url base for resolving paths
|
.then(function(xml) {
|
||||||
console.log("book.baseUrl", book.baseUrl );
|
this.navigation = new Navigation(xml);
|
||||||
|
}.bind(this));
|
||||||
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);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Alias for book.spine.get
|
/**
|
||||||
|
* Alias for book.spine.get
|
||||||
|
* @param {string} target
|
||||||
|
*/
|
||||||
Book.prototype.section = function(target) {
|
Book.prototype.section = function(target) {
|
||||||
return this.spine.get(target);
|
return this.spine.get(target);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sugar to render a book
|
/**
|
||||||
|
* Sugar to render a book
|
||||||
|
*/
|
||||||
Book.prototype.renderTo = function(element, options) {
|
Book.prototype.renderTo = function(element, options) {
|
||||||
// var renderMethod = (options && options.method) ?
|
// var renderMethod = (options && options.method) ?
|
||||||
// options.method :
|
// options.method :
|
||||||
|
@ -278,15 +298,6 @@ Book.prototype.renderTo = function(element, options) {
|
||||||
return this.rendition;
|
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) {
|
Book.prototype.setRequestCredentials = function(_credentials) {
|
||||||
this.requestCredentials = _credentials;
|
this.requestCredentials = _credentials;
|
||||||
|
@ -296,12 +307,17 @@ Book.prototype.setRequestHeaders = function(_headers) {
|
||||||
this.requestHeaders = _headers;
|
this.requestHeaders = _headers;
|
||||||
};
|
};
|
||||||
|
|
||||||
Book.prototype.unarchive = function(bookUrl, isBase64){
|
/**
|
||||||
|
* Unarchive a zipped epub
|
||||||
|
*/
|
||||||
|
Book.prototype.unarchive = function(bookUrl, encoding){
|
||||||
this.unarchived = new Unarchive();
|
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){
|
Book.prototype.isArchivedUrl = function(bookUrl){
|
||||||
var extension;
|
var extension;
|
||||||
|
|
||||||
|
@ -325,7 +341,9 @@ Book.prototype.isArchivedUrl = function(bookUrl){
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
//-- Returns the cover
|
/**
|
||||||
|
* Get the cover url
|
||||||
|
*/
|
||||||
Book.prototype.coverUrl = function(){
|
Book.prototype.coverUrl = function(){
|
||||||
var retrieved = this.loaded.cover.
|
var retrieved = this.loaded.cover.
|
||||||
then(function(url) {
|
then(function(url) {
|
||||||
|
@ -341,6 +359,9 @@ Book.prototype.coverUrl = function(){
|
||||||
return retrieved;
|
return retrieved;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a DOM Range for a given CFI Range
|
||||||
|
*/
|
||||||
Book.prototype.range = function(cfiRange) {
|
Book.prototype.range = function(cfiRange) {
|
||||||
var cfi = new EpubCFI(cfiRange);
|
var cfi = new EpubCFI(cfiRange);
|
||||||
var item = this.spine.get(cfi.spinePos);
|
var item = this.spine.get(cfi.spinePos);
|
||||||
|
@ -351,7 +372,7 @@ Book.prototype.range = function(cfiRange) {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Book;
|
|
||||||
|
|
||||||
//-- Enable binding events to book
|
//-- Enable binding events to book
|
||||||
EventEmitter(Book.prototype);
|
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 $viewport = this.document.querySelector("meta[name='viewport']");
|
||||||
var newContent = '';
|
var newContent = '';
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* check for the viewport size
|
* check for the viewport size
|
||||||
* <meta name="viewport" content="width=1024,height=697" />
|
* <meta name="viewport" content="width=1024,height=697" />
|
||||||
*/
|
*/
|
||||||
|
|
203
src/core.js
203
src/core.js
|
@ -2,87 +2,125 @@ var base64 = require('base64-js');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
var requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;
|
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);
|
* creates a uri object
|
||||||
url = url.slice(0, fragment);
|
* @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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(search != -1) {
|
try {
|
||||||
uri.search = url.slice(search + 1);
|
this.Url = new URL(urlString, this.base);
|
||||||
url = url.slice(0, search);
|
this.href = this.Url.href;
|
||||||
href = url;
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(doubleSlash != -1) {
|
this.Path = new Path(this.Url.pathname);
|
||||||
uri.protocol = url.slice(0, doubleSlash);
|
this.directory = this.Path.directory;
|
||||||
withoutProtocol = url.slice(doubleSlash+3);
|
this.filename = this.Path.filename;
|
||||||
firstSlash = withoutProtocol.indexOf('/');
|
this.extension = this.Path.extension;
|
||||||
|
|
||||||
if(firstSlash === -1) {
|
}
|
||||||
uri.host = uri.path;
|
|
||||||
uri.path = "";
|
|
||||||
} else {
|
|
||||||
uri.host = withoutProtocol.slice(0, firstSlash);
|
|
||||||
uri.path = withoutProtocol.slice(firstSlash);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Url.prototype.path = function () {
|
||||||
uri.origin = uri.protocol + "://" + uri.host;
|
return this.Path;
|
||||||
|
|
||||||
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
|
Url.prototype.resolve = function (what) {
|
||||||
function folder(url){
|
var isAbsolute = (what.indexOf('://') > -1);
|
||||||
|
var fullpath;
|
||||||
|
|
||||||
var lastSlash = url.lastIndexOf('/');
|
if (isAbsolute) {
|
||||||
|
return what;
|
||||||
if(lastSlash == -1) var folder = '';
|
}
|
||||||
|
|
||||||
folder = url.slice(0, lastSlash + 1);
|
|
||||||
|
|
||||||
return folder;
|
|
||||||
|
|
||||||
|
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) {
|
function extension(_url) {
|
||||||
var url;
|
var url;
|
||||||
|
@ -571,9 +609,27 @@ function defer() {
|
||||||
Object.freeze(this);
|
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 = {
|
module.exports = {
|
||||||
// 'uri': uri,
|
|
||||||
// 'folder': folder,
|
|
||||||
'extension' : extension,
|
'extension' : extension,
|
||||||
'directory' : directory,
|
'directory' : directory,
|
||||||
'isElement': isElement,
|
'isElement': isElement,
|
||||||
|
@ -605,5 +661,8 @@ module.exports = {
|
||||||
'qsp' : qsp,
|
'qsp' : qsp,
|
||||||
'blob2base64' : blob2base64,
|
'blob2base64' : blob2base64,
|
||||||
'createBase64Url': createBase64Url,
|
'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 Rendition = require('./rendition');
|
||||||
var Contents = require('./contents');
|
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";
|
ePub.VERSION = "0.3.0";
|
||||||
|
@ -15,10 +23,19 @@ ePub.Contents = Contents;
|
||||||
|
|
||||||
ePub.ViewManagers = {};
|
ePub.ViewManagers = {};
|
||||||
ePub.Views = {};
|
ePub.Views = {};
|
||||||
|
/**
|
||||||
|
* register plugins
|
||||||
|
*/
|
||||||
ePub.register = {
|
ePub.register = {
|
||||||
|
/**
|
||||||
|
* register a new view manager
|
||||||
|
*/
|
||||||
manager : function(name, manager){
|
manager : function(name, manager){
|
||||||
return ePub.ViewManagers[name] = manager;
|
return ePub.ViewManagers[name] = manager;
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* register a new view
|
||||||
|
*/
|
||||||
view : function(name, view){
|
view : function(name, view){
|
||||||
return ePub.Views[name] = view;
|
return ePub.Views[name] = view;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ function Stage(_options) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Creates an element to render to.
|
* Creates an element to render to.
|
||||||
* Resizes to passed width and height or to the elements size
|
* Resizes to passed width and height or to the elements size
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,85 +1,30 @@
|
||||||
var core = require('./core');
|
var core = require('./core');
|
||||||
var Parser = require('./parser');
|
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
function Navigation(_package, _request){
|
function Navigation(xml){
|
||||||
var navigation = this;
|
|
||||||
var parse = new Parser();
|
|
||||||
var request = _request || require('./request');
|
|
||||||
|
|
||||||
this.package = _package;
|
|
||||||
this.toc = [];
|
this.toc = [];
|
||||||
this.tocByHref = {};
|
this.tocByHref = {};
|
||||||
this.tocById = {};
|
this.tocById = {};
|
||||||
|
|
||||||
if(_package.navPath) {
|
if (xml) {
|
||||||
if (_package.baseUrl) {
|
this.parse(xml);
|
||||||
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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Load the navigation
|
Navigation.prototype.parse = function(xml) {
|
||||||
Navigation.prototype.load = function(_request) {
|
var html = core.qs(xml, "html");
|
||||||
var request = _request || require('./request');
|
var ncx = core.qs(xml, "ncx");
|
||||||
var loading, loaded;
|
|
||||||
|
|
||||||
if(this.nav) {
|
if(html) {
|
||||||
loading = this.nav.load();
|
this.toc = this.parseNav(xml);
|
||||||
} else if(this.ncx) {
|
} else if(ncx){
|
||||||
loading = this.ncx.load();
|
this.toc = this.parseNcx(xml);
|
||||||
} else {
|
|
||||||
loaded = new core.defer();
|
|
||||||
loaded.resolve([]);
|
|
||||||
loading = loaded.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return loading;
|
this.unpack(this.toc);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Navigation.prototype.loaded = function(toc) {
|
Navigation.prototype.unpack = function(toc) {
|
||||||
var item;
|
var item;
|
||||||
|
|
||||||
for (var i = 0; i < toc.length; i++) {
|
for (var i = 0; i < toc.length; i++) {
|
||||||
|
@ -107,4 +52,139 @@ Navigation.prototype.get = function(target) {
|
||||||
return this.toc[index];
|
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;
|
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(){};
|
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){
|
Parser.prototype.querySelectorText = function(xml, q){
|
||||||
var el = xml.querySelector(q);
|
var el = xml.querySelector(q);
|
||||||
|
|
||||||
|
@ -224,66 +15,7 @@ Parser.prototype.querySelectorText = function(xml, q){
|
||||||
|
|
||||||
return '';
|
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){
|
Parser.prototype.querySelectorByType = function(html, element, type){
|
||||||
var query;
|
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){
|
Parser.prototype.pageList = function(navHtml, spineIndexByURL, bookSpine){
|
||||||
var navElement = this.querySelectorByType(navHtml, "nav", "page-list");
|
var navElement = this.querySelectorByType(navHtml, "nav", "page-list");
|
||||||
|
|
|
@ -7,6 +7,7 @@ var EpubCFI = require('./epubcfi');
|
||||||
var Queue = require('./queue');
|
var Queue = require('./queue');
|
||||||
var Layout = require('./layout');
|
var Layout = require('./layout');
|
||||||
var Mapping = require('./mapping');
|
var Mapping = require('./mapping');
|
||||||
|
var Path = require('./core').Path;
|
||||||
|
|
||||||
function Rendition(book, options) {
|
function Rendition(book, options) {
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ function Rendition(book, options) {
|
||||||
// this.started = this.starting.promise;
|
// this.started = this.starting.promise;
|
||||||
this.q.enqueue(this.start);
|
this.q.enqueue(this.start);
|
||||||
|
|
||||||
if(this.book.unarchived) {
|
if(this.book.archived) {
|
||||||
this.q.enqueue(this.replacements.bind(this));
|
this.q.enqueue(this.replacements.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ Rendition.prototype.start = function(){
|
||||||
this.manager = new this.ViewManager({
|
this.manager = new this.ViewManager({
|
||||||
view: this.View,
|
view: this.View,
|
||||||
queue: this.q,
|
queue: this.q,
|
||||||
request: this.book.request,
|
request: this.book.load.bind(this.book),
|
||||||
settings: this.settings
|
settings: this.settings
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -441,7 +442,7 @@ Rendition.prototype.replacements = function(){
|
||||||
var processing = urls.
|
var processing = urls.
|
||||||
map(function(url) {
|
map(function(url) {
|
||||||
// var absolute = new URL(url, this.book.baseUrl).toString();
|
// 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
|
// Full url from archive base
|
||||||
return this.book.unarchived.createUrl(absolute, {"base64": this.settings.useBase64});
|
return this.book.unarchived.createUrl(absolute, {"base64": this.settings.useBase64});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -494,32 +495,15 @@ Rendition.prototype.replaceCss = function(href, urls, replacementUrls){
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileUri;
|
var fileUri;
|
||||||
var absolute;
|
var absolute = this.book.resolve(href);
|
||||||
if (this.book.baseUrl) {
|
|
||||||
fileUri = new URL(href, this.book.baseUrl);
|
|
||||||
absolute = fileUri.toString();
|
|
||||||
} else {
|
|
||||||
absolute = path.resolve(this.book.basePath, href);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Get the text of the css file from the archive
|
// Get the text of the css file from the archive
|
||||||
var textResponse = this.book.unarchived.getText(absolute);
|
var textResponse = this.book.unarchived.getText(absolute);
|
||||||
// Get asset links relative to css file
|
// Get asset links relative to css file
|
||||||
var relUrls = urls.
|
var relUrls = urls.
|
||||||
map(function(assetHref) {
|
map(function(assetHref) {
|
||||||
// var assetUri = URI(assetHref).absoluteTo(this.book.baseUrl);
|
var resolved = this.book.resolve(assetHref);
|
||||||
// var relative = assetUri.relativeTo(absolute).toString();
|
var relative = new Path(absolute).relative(resolved);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return relative;
|
return relative;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -552,34 +536,17 @@ Rendition.prototype.replaceCss = function(href, urls, replacementUrls){
|
||||||
Rendition.prototype.replaceAssets = function(section, urls, replacementUrls){
|
Rendition.prototype.replaceAssets = function(section, urls, replacementUrls){
|
||||||
// var fileUri = URI(section.url);
|
// var fileUri = URI(section.url);
|
||||||
var fileUri;
|
var fileUri;
|
||||||
var absolute;
|
var absolute = section.url;
|
||||||
if (this.book.baseUrl) {
|
|
||||||
fileUri = new URL(section.url, this.book.baseUrl);
|
|
||||||
absolute = fileUri.toString();
|
|
||||||
} else {
|
|
||||||
absolute = path.resolve(this.book.basePath, section.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Urls relative to current sections
|
// Get Urls relative to current sections
|
||||||
var relUrls = urls.
|
var relUrls = urls.
|
||||||
map(function(href) {
|
map(function(href) {
|
||||||
// var assetUri = URI(href).absoluteTo(this.book.baseUrl);
|
var resolved = this.book.resolve(href);
|
||||||
// var relative = assetUri.relativeTo(fileUri).toString();
|
var relative = new Path(absolute).relative(resolved);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
return relative;
|
return relative;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
|
||||||
section.output = replace.substitute(section.output, relUrls, replacementUrls);
|
section.output = replace.substitute(section.output, relUrls, replacementUrls);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -57,17 +57,7 @@ function links(view, renderer) {
|
||||||
// var linkUri = URI(href);
|
// var linkUri = URI(href);
|
||||||
// var absolute = linkUri.absoluteTo(view.section.url);
|
// var absolute = linkUri.absoluteTo(view.section.url);
|
||||||
// var relative = absolute.relativeTo(this.book.baseUrl).toString();
|
// var relative = absolute.relativeTo(this.book.baseUrl).toString();
|
||||||
var linkUrl;
|
var relative = this.book.resolve(href, false);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(linkUrl && linkUrl.protocol){
|
if(linkUrl && linkUrl.protocol){
|
||||||
|
|
||||||
|
|
|
@ -58,7 +58,6 @@ Section.prototype.base = function(_document){
|
||||||
var task = new core.defer();
|
var task = new core.defer();
|
||||||
var base = _document.createElement("base"); // TODO: check if exists
|
var base = _document.createElement("base"); // TODO: check if exists
|
||||||
var head;
|
var head;
|
||||||
console.log(window.location.origin + "/" +this.url);
|
|
||||||
|
|
||||||
base.setAttribute("href", 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
|
* Reconciles the current chapters layout properies with
|
||||||
* the global layout properities.
|
* the global layout properities.
|
||||||
* Takes: global layout settings object, chapter properties string
|
* Takes: global layout settings object, chapter properties string
|
||||||
|
|
|
@ -4,8 +4,7 @@ var Hook = require('./hook');
|
||||||
var Section = require('./section');
|
var Section = require('./section');
|
||||||
var replacements = require('./replacements');
|
var replacements = require('./replacements');
|
||||||
|
|
||||||
function Spine(_request){
|
function Spine(){
|
||||||
this.request = _request;
|
|
||||||
this.spineItems = [];
|
this.spineItems = [];
|
||||||
this.spineByHref = {};
|
this.spineByHref = {};
|
||||||
this.spineById = {};
|
this.spineById = {};
|
||||||
|
@ -23,7 +22,7 @@ function Spine(_request){
|
||||||
this.loaded = false;
|
this.loaded = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Spine.prototype.load = function(_package) {
|
Spine.prototype.unpack = function(_package, resolver) {
|
||||||
|
|
||||||
this.items = _package.spine;
|
this.items = _package.spine;
|
||||||
this.manifest = _package.manifest;
|
this.manifest = _package.manifest;
|
||||||
|
@ -40,7 +39,7 @@ Spine.prototype.load = function(_package) {
|
||||||
|
|
||||||
if(manifestItem) {
|
if(manifestItem) {
|
||||||
item.href = manifestItem.href;
|
item.href = manifestItem.href;
|
||||||
item.url = this.baseUrl + item.href;
|
item.url = resolver(item.href, true);
|
||||||
|
|
||||||
if(manifestItem.properties.length){
|
if(manifestItem.properties.length){
|
||||||
item.properties.push.apply(item.properties, manifestItem.properties);
|
item.properties.push.apply(item.properties, manifestItem.properties);
|
||||||
|
|
|
@ -11,26 +11,24 @@ function Unarchive() {
|
||||||
|
|
||||||
Unarchive.prototype.checkRequirements = function(callback){
|
Unarchive.prototype.checkRequirements = function(callback){
|
||||||
try {
|
try {
|
||||||
if (typeof JSZip !== 'undefined') {
|
if (typeof JSZip === 'undefined') {
|
||||||
this.zip = new JSZip();
|
|
||||||
} else {
|
|
||||||
JSZip = require('jszip');
|
JSZip = require('jszip');
|
||||||
this.zip = new JSZip();
|
|
||||||
}
|
}
|
||||||
|
this.zip = new JSZip();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("JSZip lib not loaded");
|
console.error("JSZip lib not loaded");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Unarchive.prototype.open = function(zipUrl, isBase64){
|
Unarchive.prototype.open = function(input, isBase64){
|
||||||
if (zipUrl instanceof ArrayBuffer || isBase64) {
|
return this.zip.loadAsync(input, {"base64": isBase64});
|
||||||
return this.zip.loadAsync(zipUrl, {"base64": isBase64});
|
};
|
||||||
} else {
|
|
||||||
|
Unarchive.prototype.openUrl = function(zipUrl, isBase64){
|
||||||
return request(zipUrl, "binary")
|
return request(zipUrl, "binary")
|
||||||
.then(function(data){
|
.then(function(data){
|
||||||
return this.zip.loadAsync(data);
|
return this.zip.loadAsync(data, {"base64": isBase64});
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Unarchive.prototype.request = function(url, type){
|
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();
|
// server.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open a epub', function(done) {
|
it('should open a epub', function() {
|
||||||
var book = ePub("/fixtures/alice/OPS/package.opf");
|
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.isOpen, true, "book is opened" );
|
||||||
assert.equal( book.url, "http://localhost:9876/fixtures/alice/OPS/package.opf", "book url is passed to new Book" );
|
assert.equal( book.url.toString(), "http://localhost:9876/fixtures/alice/OPS/package.opf", "book url is passed to new Book" );
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should open a archived epub', function(done) {
|
it('should open a archived epub', function() {
|
||||||
var book = ePub("/fixtures/alice.epub");
|
var book = ePub("/fixtures/alice.epub");
|
||||||
|
|
||||||
assert(typeof (JSZip) !== "undefined", "JSZip is present" );
|
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.isOpen, true, "book is opened" );
|
||||||
assert.equal( book.url, "", "book url is empty as book is archived" );
|
assert( book.unarchived, "book is unarchived" );
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,11 @@ module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
// new webpack.IgnorePlugin(/punycode|IPv6/),
|
// new webpack.IgnorePlugin(/punycode|IPv6/),
|
||||||
],
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
path: "path-webpack"
|
||||||
|
}
|
||||||
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
host: hostname,
|
host: hostname,
|
||||||
port: port,
|
port: port,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue