1
0
Fork 0
mirror of https://github.com/futurepress/epub.js.git synced 2025-10-04 15:09:16 +02:00

added mochify test runner and epubcfi test

This commit is contained in:
fchasen 2015-12-16 21:58:23 -05:00
parent 05f1b92094
commit 7c3af4493c
10 changed files with 441 additions and 64 deletions

2
books

@ -1 +1 @@
Subproject commit 8d6c46ef23ca637d89e66b18b2146ccef93c1ac4 Subproject commit e9790315c2510315e270a7a4c4921825e9918039

323
dist/epub.js vendored
View file

@ -4746,7 +4746,7 @@ module.exports = Continuous;
},{"./core":8,"./rendition":18,"./view":24,"rsvp":4}],8:[function(require,module,exports){ },{"./core":8,"./rendition":18,"./view":24,"rsvp":4}],8:[function(require,module,exports){
var RSVP = require('rsvp'); var RSVP = require('rsvp');
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; var requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;
/* /*
//-- Parse the different parts of a url, returning a object //-- Parse the different parts of a url, returning a object
function uri(url){ function uri(url){
@ -5183,25 +5183,324 @@ module.exports = {
var URI = require('urijs'); var URI = require('urijs');
var core = require('./core'); var core = require('./core');
function EpubCFI(cfiStr){ /**
// var _object = typeof href === 'object' && (href.hostname || href.path || href.pathname); EPUB CFI spec: http://www.idpf.org/epub/linking/cfi/epub-cfi.html
var _string = typeof href === 'string';
Implements:
- Character Offset: epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)
- Simple Ranges : epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)
Does Not Implement:
- Temporal Offset (~)
- Spatial Offset (@)
- Temporal-Spatial Offset (~ + @)
- Text Location Assertion ([)
*/
function EpubCFI(cfiFrom, base, options){
var type;
this.options = {
ignoreClass: 'annotator-hl'
};
this.str = '';
this.base = {};
this.spinePos = 0; // For compatibility
this.range = false; // true || false;
this.path = {};
this.start = null;
this.end = null;
// Allow instantiation without the 'new' keyword // Allow instantiation without the 'new' keyword
if (!(this instanceof EpubCFI)) { if (!(this instanceof EpubCFI)) {
return new URI(url, base); return new EpubCFI(cfiFrom, base, options);
} }
this.ignoreClass = 'annotator-hl'; // Find options
for (var i = 1, length = arguments.length; i < length; i++) {
if(typeof arguments[i] === 'object' && (arguments[i].ignoreClass)) {
if(_string) { core.extend(this.options, arguments[i]);
return this.parse(cfiStr);
} }
else if(_string) { }
return this.parse(cfiStr);
/* TODO: maybe accept object that includes:
{
spineNodeIndex: <int>
index: <int>
idref: <string:optional>
}
}
*/
if(typeof base === 'string') {
this.base = this.parseComponent(base);
} else if(typeof base === 'object' && base.steps) {
this.base = base;
}
type = this.checkType(cfiFrom);
if(type === 'string') {
this.str = cfiFrom;
return core.extend(this, this.parse(cfiFrom));
} else if (type === 'range') {
this.fromRange(cfiFrom);
} else if (type === 'node') {
this.fromNode(cfiFrom);
} else if (type === 'EpubCFI') {
return cfiFrom;
} else {
throw new TypeError('not a valid argument for EpubCFI');
}
return this;
};
EpubCFI.prototype.checkType = function(cfi) {
// is a cfi string, should be wrapped with "epubcfi()"
if (typeof cfi === 'string' &&
cfi.indexOf("epubcfi(") === 0 &&
cfi[cfi.length-1] === ")") {
return 'string';
// Is a range object
} else if (typeof cfi === 'object' && cfi.startContainer && cfi.startOffset){
return 'range';
} else if (typeof cfi === 'object' && cfi.nodeType){ // || typeof cfi === 'function'
return 'node';
} else if (typeof cfi === 'object' && cfi instanceof EpubCFI){
return 'EpubCFI';
} else {
return false;
} }
}; };
EpubCFI.prototype.parse = function(cfiStr) {
var cfi = {
spinePos: -1,
range: false,
base: {},
path: {},
start: null,
end: null
};
var baseComponent, pathComponent, range;
if(typeof cfiStr !== "string") {
return {spinePos: -1};
}
if(cfiStr.indexOf("epubcfi(") === 0 && cfiStr[cfiStr.length-1] === ")") {
// Remove intial epubcfi( and ending )
cfiStr = cfiStr.slice(8, cfiStr.length-1);
}
baseComponent = this.getChapterComponent(cfiStr);
// Make sure this is a valid cfi or return
if(!baseComponent) {
return {spinePos: -1};
}
cfi.base = this.parseComponent(baseComponent);
pathComponent = this.getPathComponent(cfiStr);
cfi.path = this.parseComponent(pathComponent);
range = this.getRange(cfiStr);
if(range) {
cfi.range = true;
cfi.start = this.parseComponent(range[0]);
cfi.end = this.parseComponent(range[1]);
}
// Get spine node position
// cfi.spineSegment = cfi.base.steps[1];
// Chapter segment is always the second step
cfi.spinePos = cfi.base.steps[1].index;
return cfi;
};
EpubCFI.prototype.parseComponent = function(componentStr){
var component = {
steps: [],
terminal: null
};
var parts = componentStr.split(':');
var steps = parts[0].split('/');
var terminal;
if(parts.length > 1) {
terminal = parts[1];
component.terminal = this.parseTerminal(terminal);
}
if (steps[0] === '') {
steps.shift(); // Ignore the first slash
}
component.steps = steps.map(function(step){
return this.parseStep(step);
}.bind(this));
return component;
};
EpubCFI.prototype.parseStep = function(stepStr){
var type, num, index, has_brackets, id;
has_brackets = stepStr.match(/\[(.*)\]/);
if(has_brackets && has_brackets[1]){
id = has_brackets[1];
}
//-- Check if step is a text node or element
num = parseInt(stepStr);
if(isNaN(num)) {
return;
}
if(num % 2 === 0) { // Even = is an element
type = "element";
index = num / 2 - 1;
} else {
type = "text";
index = (num - 1 ) / 2;
}
return {
"type" : type,
'index' : index,
'id' : id || null
};
};
EpubCFI.prototype.parseTerminal = function(termialStr){
var characterOffset, textLocationAssertion;
var assertion = termialStr.match(/\[(.*)\]/);
if(assertion && assertion[1]){
characterOffset = parseInt(termialStr.split('[')[0]);
textLocationAssertion = assertion[1];
} else {
characterOffset = parseInt(termialStr);
}
return {
'offset': characterOffset,
'assertion': textLocationAssertion
};
};
EpubCFI.prototype.getChapterComponent = function(cfiStr) {
var indirection = cfiStr.split("!");
return indirection[0];
};
EpubCFI.prototype.getPathComponent = function(cfiStr) {
var indirection = cfiStr.split("!");
if(indirection[1]) {
ranges = indirection[1].split(',');
return ranges[0];
}
};
EpubCFI.prototype.getRange = function(cfiStr) {
var ranges = cfiStr.split(",");
if(ranges.length === 3){
return [
ranges[1],
ranges[2]
];
}
return false;
};
EpubCFI.prototype.getCharecterOffsetComponent = function(cfiStr) {
var splitStr = cfiStr.split(":");
return splitStr[1] || '';
};
EpubCFI.prototype.joinSteps = function(steps) {
return steps.map(function(part){
var segment = '';
if(part.type === 'element') {
segment += (part.index + 1) * 2;
}
if(part.type === 'text') {
segment += 1 + (2 * part.index); // TODO: double check that this is odd
}
if(part.id) {
segment += "[" + part.id + "]";
}
return segment;
}).join('/');
};
EpubCFI.prototype.segmentString = function(segment) {
var segmentString = '/';
segmentString += this.joinSteps(segment.steps);
if(segment.terminal && segment.terminal.offset){
segmentString += ':' + segment.terminal.offset;
}
if(segment.terminal && segment.terminal.assertion){
segmentString += '[' + segment.terminal.assertion + ']';
}
return segmentString;
};
EpubCFI.prototype.toString = function() {
var cfiString = 'epubcfi(';
cfiString += this.segmentString(this.base);
cfiString += '!';
cfiString += this.segmentString(this.path);
// Add Range, if present
if(this.start) {
cfiString += ',';
cfiString += this.segmentString(this.start);
}
if(this.end) {
cfiString += ',';
cfiString += this.segmentString(this.end);
}
cfiString += ")";
return cfiString;
};
module.exports = EpubCFI;
},{"./core":8,"urijs":5}],10:[function(require,module,exports){ },{"./core":8,"urijs":5}],10:[function(require,module,exports){
var RSVP = require('rsvp'); var RSVP = require('rsvp');

2
dist/epub.js.map vendored

File diff suppressed because one or more lines are too long

View file

@ -60,6 +60,10 @@ gulp.task('serve', function() {
server(); server();
}); });
gulp.task('test', function() {
});
// Default // Default
gulp.task('default', ['lint', 'bundle']); gulp.task('default', ['lint', 'bundle']);

View file

@ -27,6 +27,8 @@
"gulp-sourcemaps": "^1.6.0", "gulp-sourcemaps": "^1.6.0",
"gulp-uglify": "^0.3.1", "gulp-uglify": "^0.3.1",
"gulp-util": "^3.0.0", "gulp-util": "^3.0.0",
"jquery": "^2.1.4",
"mochify": "^2.14.3",
"morgan": "^1.1.1", "morgan": "^1.1.1",
"optimist": "^0.6.1", "optimist": "^0.6.1",
"portfinder": "^0.2.1", "portfinder": "^0.2.1",

View file

@ -1,6 +1,6 @@
var RSVP = require('rsvp'); var RSVP = require('rsvp');
var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame; var requestAnimationFrame = (typeof window != 'undefined') ? (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame) : false;
/* /*
//-- Parse the different parts of a url, returning a object //-- Parse the different parts of a url, returning a object
function uri(url){ function uri(url){

View file

@ -34,18 +34,18 @@ function EpubCFI(cfiFrom, base, options){
// Allow instantiation without the 'new' keyword // Allow instantiation without the 'new' keyword
if (!(this instanceof EpubCFI)) { if (!(this instanceof EpubCFI)) {
return new URI(cfiFrom, base, options); return new EpubCFI(cfiFrom, base, options);
} }
// Find options // Find options
for (var i = 1, length = arguments.length; i < length; i++) { for (var i = 1, length = arguments.length; i < length; i++) {
if(typeof arguments[i] === 'object' && (arguments[i].ignoreClass)) { if(typeof arguments[i] === 'object' && (arguments[i].ignoreClass)) {
core.extend(this.options, arguments[i]); core.extend(this.options, arguments[i]);
}; }
} }
/* Object that includes: /* TODO: maybe accept object that includes:
{ {
spineNodeIndex: <int> spineNodeIndex: <int>
index: <int> index: <int>
@ -55,6 +55,8 @@ function EpubCFI(cfiFrom, base, options){
*/ */
if(typeof base === 'string') { if(typeof base === 'string') {
this.base = this.parseComponent(base); this.base = this.parseComponent(base);
} else if(typeof base === 'object' && base.steps) {
this.base = base;
} }
type = this.checkType(cfiFrom); type = this.checkType(cfiFrom);
@ -63,8 +65,7 @@ function EpubCFI(cfiFrom, base, options){
if(type === 'string') { if(type === 'string') {
this.str = cfiFrom; this.str = cfiFrom;
return core.extend(this, this.parse(cfiFrom)); return core.extend(this, this.parse(cfiFrom));
} } else if (type === 'range') {
else if(type === 'range') {
this.fromRange(cfiFrom); this.fromRange(cfiFrom);
} else if (type === 'node') { } else if (type === 'node') {
this.fromNode(cfiFrom); this.fromNode(cfiFrom);
@ -84,12 +85,12 @@ EpubCFI.prototype.checkType = function(cfi) {
cfi[cfi.length-1] === ")") { cfi[cfi.length-1] === ")") {
return 'string'; return 'string';
// Is a range object // Is a range object
} else (typeof cfi === 'object' && cfi.startContainer && cfi.startOffset){ } else if (typeof cfi === 'object' && cfi.startContainer && cfi.startOffset){
return 'range' return 'range';
} else ((typeof cfi === 'object') && cfi.nodeType){ // || typeof cfi === 'function' } else if (typeof cfi === 'object' && cfi.nodeType){ // || typeof cfi === 'function'
return 'node' return 'node';
} else (typeof cfi === 'object' && cfi instanceof EpubCFI){ } else if (typeof cfi === 'object' && cfi instanceof EpubCFI){
return 'EpubCFI' return 'EpubCFI';
} else { } else {
return false; return false;
} }
@ -101,12 +102,11 @@ EpubCFI.prototype.parse = function(cfiStr) {
range: false, range: false,
base: {}, base: {},
path: {}, path: {},
start: null start: null,
end: null end: null
}; };
var baseComponent, pathComponent, range; var baseComponent, pathComponent, range;
if(typeof cfiStr !== "string") { if(typeof cfiStr !== "string") {
return {spinePos: -1}; return {spinePos: -1};
} }
@ -133,25 +133,24 @@ EpubCFI.prototype.parse = function(cfiStr) {
if(range) { if(range) {
cfi.range = true; cfi.range = true;
cfi.start = this.parseComponent(range[0]); cfi.start = this.parseComponent(range[0]);
cfi.end = this.parseComponent(range[0]); cfi.end = this.parseComponent(range[1]);
} }
// Get spine node position // Get spine node position
// cfi.spineSegment = cfi.base.steps[1]; // cfi.spineSegment = cfi.base.steps[1];
// Chapter segment is always the second one // Chapter segment is always the second step
cfi.spinePos = cfi.base.steps[2]; cfi.spinePos = cfi.base.steps[1].index;
return cfi; return cfi;
}; };
EpubCFI.prototype.parseComponent = function(componentString){ EpubCFI.prototype.parseComponent = function(componentStr){
var component = { var component = {
steps: [], steps: [],
terminal: null terminal: null
}; };
var parts = componentStr.split(':');
var parts = componentString.split(':');
var steps = parts[0].split('/'); var steps = parts[0].split('/');
var terminal; var terminal;
@ -160,28 +159,34 @@ EpubCFI.prototype.parseComponent = function(componentString){
component.terminal = this.parseTerminal(terminal); component.terminal = this.parseTerminal(terminal);
} }
if (steps[0] === '') {
steps.shift(); // Ignore the first slash
}
component.steps = steps.map(function(step){ component.steps = steps.map(function(step){
return this.parseStep(part); return this.parseStep(step);
}.bind(this)); }.bind(this));
return component;
}; };
EpubCFI.prototype.parseStep = function(stepString){ EpubCFI.prototype.parseStep = function(stepStr){
var type, num, index, has_brackets, id; var type, num, index, has_brackets, id;
has_brackets = part.match(/\[(.*)\]/); has_brackets = stepStr.match(/\[(.*)\]/);
if(has_brackets && has_brackets[1]){ if(has_brackets && has_brackets[1]){
id = has_brackets[1]; id = has_brackets[1];
} }
//-- Check if step is a text node or element //-- Check if step is a text node or element
num = parseInt(stepString); num = parseInt(stepStr);
if(isNaN(num)) { if(isNaN(num)) {
return; return;
} }
if(num % 2 === 0) { // Even = is an element if(num % 2 === 0) { // Even = is an element
type = "element" type = "element";
index = num / 2 - 1; index = num / 2 - 1;
} else { } else {
type = "text"; type = "text";
@ -195,15 +200,15 @@ EpubCFI.prototype.parseStep = function(stepString){
}; };
}; };
EpubCFI.prototype.parseTerminal = function(termialString){ EpubCFI.prototype.parseTerminal = function(termialStr){
var characterOffset, textLocationAssertion; var characterOffset, textLocationAssertion;
var assertion = charecterOffsetComponent.match(/\[(.*)\]/); var assertion = termialStr.match(/\[(.*)\]/);
if(assertion && assertion[1]){ if(assertion && assertion[1]){
characterOffset = parseInt(charecterOffsetComponent.split('[')[0]); characterOffset = parseInt(termialStr.split('[')[0]);
textLocationAssertion = assertion[1]; textLocationAssertion = assertion[1];
} else { } else {
characterOffset = parseInt(charecterOffsetComponent); characterOffset = parseInt(termialStr);
} }
return { return {
@ -273,7 +278,7 @@ EpubCFI.prototype.joinSteps = function(steps) {
}; };
EpubCFI.prototype.segmentString = function(segment) { EpubCFI.prototype.segmentString = function(segment) {
var segmentString = ''; var segmentString = '/';
segmentString += this.joinSteps(segment.steps); segmentString += this.joinSteps(segment.steps);
@ -291,7 +296,7 @@ EpubCFI.prototype.segmentString = function(segment) {
EpubCFI.prototype.toString = function() { EpubCFI.prototype.toString = function() {
var cfiString = 'epubcfi('; var cfiString = 'epubcfi(';
cfiString += this.joinSteps(this.base); cfiString += this.segmentString(this.base);
cfiString += '!'; cfiString += '!';
cfiString += this.segmentString(this.path); cfiString += this.segmentString(this.path);
@ -299,15 +304,17 @@ EpubCFI.prototype.toString = function() {
// Add Range, if present // Add Range, if present
if(this.start) { if(this.start) {
cfiString += ','; cfiString += ',';
cfiString + this.segmentString(this.start); cfiString += this.segmentString(this.start);
} }
if(this.end) { if(this.end) {
cfiString += ','; cfiString += ',';
cfiString + this.segmentString(this.end); cfiString += this.segmentString(this.end);
} }
cfiString += ")"; cfiString += ")";
return cfiString; return cfiString;
}; };
module.exports = EpubCFI;

28
test/epub.js Normal file
View file

@ -0,0 +1,28 @@
// var test = require('tape');
var assert = require('assert');
// describe("Create new ePub(/path/to/epub/)", function(t) {
//
// var book = ePub("../books/moby-dick/");
//
// book.opened.then(function(){
// assert.equal( book.url, "../books/moby-dick/OPS/", "book url is passed to new EPUBJS.Book" );
// });
//
// });
describe('ePub', function() {
var ePub = require('../src/epub');
describe('#ePub()', function() {
xit('should save without error', function(done) {
var book = ePub("../books/moby-dick/");
book.opened.then(function(){
assert.equal( book.url, "../books/moby-dick/OPS/", "book url is passed to new EPUBJS.Book" );
done();
});
});
});
});

50
test/epubcfi.js Normal file
View file

@ -0,0 +1,50 @@
var assert = require('assert');
describe('EpubCFI', function() {
var EpubCFI = require('../src/epubcfi.js');
describe('EpubCFI()', function() {
it('parse a cfi on init', function() {
var cfi = EpubCFI("epubcfi(/6/2[cover]!/6)");
assert.equal( cfi.spinePos, 0, "spinePos is parsed as the first item" );
});
it('parse a cfi and ignore the base if present', function() {
var cfi = EpubCFI("epubcfi(/6/2[cover]!/6)", "/6/6[end]");
assert.equal( cfi.spinePos, 0, "base is ignored and spinePos is parsed as the first item" );
});
it('parse a cfi with a charecter offset', function() {
var cfi = EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)");
assert.equal( cfi.path.terminal.offset, 3, "Path has a terminal offset of 3" );
});
it('parse a cfi with a range', function() {
var cfi = EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)");
assert.equal( cfi.range, true, "Range is true" );
assert.equal( cfi.start.steps.length, 2, "Start steps are present" );
assert.equal( cfi.end.steps.length, 1, "End steps are present" );
assert.equal( cfi.start.terminal.offset, 1, "Start has a terminal offset of 1" );
assert.equal( cfi.end.terminal.offset, 4, "End has a terminal offset of 4" );
});
});
describe('#toString()', function() {
it('parse a cfi and write it back', function() {
assert.equal(EpubCFI("epubcfi(/6/2[cover]!/6)").toString(), "epubcfi(/6/2[cover]!/6)", "output cfi string is same as input" );
assert.equal(EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05]/2/1:3)", "output cfi string is same as input" );
assert.equal(EpubCFI("epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)").toString(), "epubcfi(/6/4[chap01ref]!/4[body01]/10[para05],/2/1:1,/3:4)", "output cfi string is same as input" );
});
});
});

View file

@ -7,19 +7,6 @@
<script src="../bower_components/jquery/dist/jquery.js"></script> <script src="../bower_components/jquery/dist/jquery.js"></script>
<script src="../bower_components/qunit/qunit/qunit.js"></script> <script src="../bower_components/qunit/qunit/qunit.js"></script>
<!-- <script src="../bower_components/rsvp/rsvp.js"></script>
<script src="../lib/epub.js"></script>
<script src="../lib/epubjs/core.js"></script>
<script src="../lib/epubjs/hooks.js"></script>
<script src="../lib/epubjs/book.js"></script>
<script src="../lib/epubjs/parser.js"></script>
<script src="../lib/epubjs/spine.js"></script>
<script src="../lib/epubjs/navigation.js"></script>
<script src="../lib/epubjs/epubcfi.js"></script>
<script src="../lib/epubjs/renderer.js"></script>
<script src="../lib/epubjs/view.js"></script> -->
<script src="../dist/epub.js"></script> <script src="../dist/epub.js"></script>
</head> </head>