1
0
Fork 0
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:
Fred Chasen 2016-11-08 02:06:10 +01:00
parent 02725b1771
commit 47787678f7
24 changed files with 1774 additions and 1140 deletions

1034
dist/epub.js vendored

File diff suppressed because it is too large Load diff

2
dist/epub.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -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']);

View file

@ -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

View file

@ -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",

View file

@ -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);
var packageUrl;
if (book.url) {
packageUrl = new URL(paths.packagePath, book.url);
book.packageUrl = packageUrl.toString();
} else {
book.packageUrl = "/" + paths.packagePath;
}
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 = "/"
}
}
return book.request(book.packageUrl);
}).catch(function(error) {
// handle errors in either of the two requests
book.opening.reject(error);
});
}
epubPackage.then(function(packageXml) {
if (!packageXml) {
return;
}
// Get package information from epub opf
book.unpack(packageXml);
// 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);
book.isOpen = true;
// Clear queue of any waiting book request
// 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;
return opening;
};
Book.prototype.unpack = function(packageXml){
var book = this,
parse = new Parser();
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.package = parse.packageContents(packageXml); // Extract info from contents
if(!book.package) {
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);
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 {
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;
}
if (this.path) {
resolved = this.path.resolve(path);
}
if(absolute != false && this.url) {
resolved = this.url.resolve(resolved);
}
return resolved;
}
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
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);
this.isOpen = true;
// Resolve book opened promise
this.opening.resolve(this);
};
Book.prototype.loadNavigation = function(opf){
var navPath = opf.navPath || opf.ncxPath;
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
View 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;

View file

@ -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" />
*/

View file

@ -2,88 +2,126 @@ 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);
/**
* 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;
}
if(search != -1) {
uri.search = url.slice(search + 1);
url = url.slice(0, search);
href = url;
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;
}
if(doubleSlash != -1) {
uri.protocol = url.slice(0, doubleSlash);
withoutProtocol = url.slice(doubleSlash+3);
firstSlash = withoutProtocol.indexOf('/');
this.Path = new Path(this.Url.pathname);
this.directory = this.Path.directory;
this.filename = this.Path.filename;
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 () {
return this.Path;
};
uri.origin = uri.protocol + "://" + uri.host;
Url.prototype.resolve = function (what) {
var isAbsolute = (what.indexOf('://') > -1);
var fullpath;
uri.directory = folder(uri.path);
if (isAbsolute) {
return what;
}
uri.base = uri.origin + uri.directory;
// return origin;
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 {
uri.path = url;
uri.directory = folder(url);
uri.base = uri.directory;
this.directory = parsed.dir + "/";
}
//-- Filename
uri.filename = url.replace(uri.base, '');
dot = uri.filename.lastIndexOf('.');
if(dot != -1) {
uri.extension = uri.filename.slice(dot+1);
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);
}
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;
};
*/
function extension(_url) {
var url;
var pathname;
@ -159,7 +197,7 @@ function resolveUrl(base, path) {
paths;
// if(uri.host) {
// return path;
// return path;
// }
if(baseDirectory[0] === "/") {
@ -399,10 +437,10 @@ function windowBounds() {
};
//https://stackoverflow.com/questions/13482352/xquery-looking-for-text-with-single-quote/13483496#13483496
function cleanStringForXpath(str) {
function cleanStringForXpath(str) {
var parts = str.match(/[^'"]+|['"]/g);
parts = parts.map(function(part){
if (part === "'") {
if (part === "'") {
return '\"\'\"'; // output "'"
}
@ -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
};

View file

@ -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;
}

View file

@ -12,7 +12,7 @@ function Stage(_options) {
}
/**
/*
* Creates an element to render to.
* Resizes to passed width and height or to the elements size
*/

View file

@ -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
View 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;

View file

@ -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");

View file

@ -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);
};

View file

@ -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){

View file

@ -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

View file

@ -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);

View file

@ -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 {
return request(zipUrl, "binary")
.then(function(data){
return this.zip.loadAsync(data);
}.bind(this));
}
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, {"base64": isBase64});
}.bind(this));
};
Unarchive.prototype.request = function(url, type){

11
test/book.js Normal file
View 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
View 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" );
});
});
});
});

View file

@ -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" );
});
});

View file

@ -26,6 +26,11 @@ module.exports = {
plugins: [
// new webpack.IgnorePlugin(/punycode|IPv6/),
],
resolve: {
alias: {
path: "path-webpack"
}
},
devServer: {
host: hostname,
port: port,