380 lines
12 KiB
JavaScript
380 lines
12 KiB
JavaScript
this.cbrjs = {};
|
|
|
|
cbrjs.open = function(url) {
|
|
var settings = getSettings();
|
|
Ox.load('UI', function() {
|
|
var $body = Ox.$('body')
|
|
.css({
|
|
backgroundColor: 'rgb(255, 255, 255)',
|
|
overflowX: 'hidden'
|
|
});
|
|
window.app = cbrjs.CBRViewer(Ox.extend({
|
|
url: url,
|
|
}, settings)
|
|
).bindEvent({
|
|
page: updateSettings
|
|
}).appendTo($body);
|
|
Ox.$window.on({
|
|
resize: app.resize
|
|
});
|
|
});
|
|
|
|
function getSettings() {
|
|
var settings = {};
|
|
try {
|
|
settings = JSON.parse(localStorage['cbrjs.' + url]);
|
|
} catch(e) {
|
|
settings.page = 1;
|
|
}
|
|
return settings;
|
|
}
|
|
|
|
function updateSettings(data) {
|
|
Ox.forEach(data, function(value, key) {
|
|
settings[key] = value;
|
|
});
|
|
localStorage['cbrjs.' + url] = JSON.stringify(settings);
|
|
}
|
|
};
|
|
|
|
cbrjs.CBRViewer = function(options, self) {
|
|
self = self || {};
|
|
var that = Ox.Element({}, self)
|
|
.defaults({
|
|
url: '',
|
|
page: 1
|
|
})
|
|
.options(options || {})
|
|
.update({
|
|
page: setPage,
|
|
url: loadBook
|
|
}),
|
|
canvas;
|
|
|
|
self.pages = [];
|
|
self.rotateTimes = 0;
|
|
self.hflip = false;
|
|
self.vflip = false;
|
|
self.fitMode = 'B';
|
|
|
|
self.mimeTypes = {
|
|
'png': 'image/png',
|
|
'jpg': 'image/jpeg',
|
|
'jpeg': 'image/jpeg',
|
|
'gif': 'image/gif',
|
|
};
|
|
|
|
self.$frame = Ox.Element()
|
|
.on({
|
|
mousedown: function() {
|
|
self.$frame.gainFocus();
|
|
},
|
|
})
|
|
.bindEvent({
|
|
key_down: function() {
|
|
that.options({
|
|
page: self.pages.length
|
|
})
|
|
},
|
|
key_left: function() {
|
|
that.options({
|
|
page: Math.max(self.options.page - 1, 1)
|
|
})
|
|
},
|
|
key_right: function() {
|
|
that.options({
|
|
page: Math.min(self.options.page + 1, self.pages.length)
|
|
})
|
|
},
|
|
key_up: function() {
|
|
that.options({
|
|
page: 1
|
|
})
|
|
},
|
|
key_n: function() {
|
|
self.fitMode = 'N';
|
|
resize();
|
|
},
|
|
key_h: function() {
|
|
self.fitMode = 'H';
|
|
resize();
|
|
},
|
|
key_b: function() {
|
|
self.fitMode = 'B';
|
|
resize();
|
|
},
|
|
key_w: function() {
|
|
self.fitMode = 'W';
|
|
resize();
|
|
},
|
|
key_l: function() {
|
|
self.rotateTimes--;
|
|
if (self.rotateTimes < 0) {
|
|
self.rotateTimes = 3;
|
|
}
|
|
setPage();
|
|
},
|
|
key_f: function() {
|
|
if (!self.hflip && !self.vflip) {
|
|
self.hflip = true;
|
|
} else if(self.hflip == true) {
|
|
self.vflip = true;
|
|
self.hflip = false;
|
|
} else if(self.vflip == true) {
|
|
self.vflip = false;
|
|
}
|
|
setPage();
|
|
},
|
|
singleclick: function(data) {
|
|
if (data.clientX < (that.width() / 2)) {
|
|
that.options({
|
|
page: Math.max(self.options.page - 1, 1)
|
|
});
|
|
} else {
|
|
that.options({
|
|
page: Math.min(self.options.page + 1, self.pages.length)
|
|
});
|
|
}
|
|
}
|
|
})
|
|
.css({
|
|
margin: 0,
|
|
overflow: 'auto',
|
|
padding: 0,
|
|
textAlign: 'center'
|
|
});
|
|
self.$canvas = Ox.Element('<canvas>')
|
|
.appendTo(self.$frame);
|
|
canvas = self.$canvas[0];
|
|
self.$scrollbar = Ox.Range({
|
|
arrows: true,
|
|
max: self.options.page,
|
|
min: 1,
|
|
orientation: 'horizontal',
|
|
step: 1,
|
|
value: self.options.page,
|
|
thumbValue: true,
|
|
thumbSize: 64
|
|
}).bindEvent({
|
|
change: function(data) {
|
|
Ox.print('change', data);
|
|
that.options({
|
|
page: data.value
|
|
})
|
|
}
|
|
});
|
|
|
|
self.$panel = Ox.SplitPanel({})
|
|
.appendTo(that);
|
|
that.setElement(
|
|
self.$mainPanel = Ox.SplitPanel({
|
|
elements: [
|
|
{
|
|
element: self.$frame,
|
|
},
|
|
{
|
|
element: self.$scrollbar,
|
|
size: 16
|
|
}
|
|
],
|
|
orientation: 'vertical'
|
|
})
|
|
);
|
|
|
|
self.$loading = Ox.LoadingScreen({
|
|
size: 16,
|
|
})
|
|
.css({
|
|
margin: 'auto',
|
|
position: 'absolute'
|
|
})
|
|
.start()
|
|
.appendTo(that);
|
|
|
|
loadBook();
|
|
|
|
function createURLFromArray(array, mimeType) {
|
|
var blob = new Blob([array], {type: mimeType});
|
|
blob = blob.slice(array.byteOffset, array.byteOffset + array.byteLength, mimeType);
|
|
return URL.createObjectURL(blob);
|
|
}
|
|
|
|
function isImage(filename) {
|
|
var extension = filename.split('.').pop().toLowerCase();
|
|
return !Ox.isUndefined(self.mimeTypes[extension]);
|
|
}
|
|
|
|
function loadBook() {
|
|
var xhr = new XMLHttpRequest();
|
|
xhr.open('GET', self.options.url, true);
|
|
xhr.responseType = "arraybuffer";
|
|
xhr.onload = function() {
|
|
loadFromArrayBuffer(this.response, function(pages, progress, total) {
|
|
self.pages = pages;
|
|
self.$scrollbar.options({
|
|
max: Math.max(pages.length, self.options.page),
|
|
size: that.width()
|
|
})
|
|
if (pages.length == self.options.page) {
|
|
setPage();
|
|
if (self.$loading) {
|
|
self.$loading.remove();
|
|
delete self.$loading;
|
|
}
|
|
}
|
|
});
|
|
};
|
|
xhr.send(null);
|
|
}
|
|
|
|
function loadFromArrayBuffer(buffer, progress) {
|
|
var extract,
|
|
start = (new Date).getTime(),
|
|
h = new Uint8Array(buffer, 0, 10),
|
|
pathToBitJS = $('script').map(function(i, script) {
|
|
return script.src;
|
|
}).filter(function(i, url) {
|
|
return url.indexOf('bitjs') > -1;
|
|
})[0].replace('archive.js', '');
|
|
|
|
var pages = [], filenames = [], total;
|
|
|
|
if (h[0] == 0x52 && h[1] == 0x61 && h[2] == 0x72 && h[3] == 0x21) { // RAR
|
|
extract = new bitjs.archive.Unrarrer(buffer, pathToBitJS);
|
|
} else if (h[0] == 80 && h[1] == 75) { // ZIP
|
|
extract = new bitjs.archive.Unzipper(buffer, pathToBitJS);
|
|
} else { // try tar otherwise
|
|
extract = new bitjs.archive.Untarrer(buffer, pathToBitJS);
|
|
}
|
|
if (extract) {
|
|
extract.addEventListener(
|
|
bitjs.archive.UnarchiveEvent.Type.PROGRESS,
|
|
function(e) {
|
|
var percentage = e.currentBytesUnarchived / e.totalUncompressedBytesInArchive;
|
|
total = e.totalFilesInArchive
|
|
progress([], percentage, total);
|
|
}
|
|
);
|
|
extract.addEventListener(
|
|
bitjs.archive.UnarchiveEvent.Type.INFO,
|
|
function(e) {
|
|
Ox.Log('', e.msg);
|
|
}
|
|
);
|
|
extract.addEventListener(
|
|
bitjs.archive.UnarchiveEvent.Type.EXTRACT,
|
|
function(e) {
|
|
// convert DecompressedFile into a bunch of ImageFiles
|
|
if (e.unarchivedFile) {
|
|
var f = e.unarchivedFile;
|
|
// add any new pages based on the filename
|
|
if (!Ox.contains(filenames, f.filename) && isImage(f.filename)) {
|
|
filenames.push(f.filename);
|
|
pages.push(f);
|
|
} else {
|
|
total--;
|
|
}
|
|
progress(pages, pages.length/total, total);
|
|
}
|
|
}
|
|
);
|
|
extract.addEventListener(
|
|
bitjs.archive.UnarchiveEvent.Type.FINISH,
|
|
function(e) {
|
|
total = pages.length;
|
|
progress(pages, 1, pages.length);
|
|
var diff = ((new Date).getTime() - start)/1000;
|
|
Ox.Log('', 'Unarchiving done in ' + diff + 's');
|
|
}
|
|
);
|
|
extract.start();
|
|
} else {
|
|
Ox.Log('', 'bitjs.archive failed to open file');
|
|
}
|
|
}
|
|
|
|
function resize(clear) {
|
|
canvas.style.width = '';
|
|
canvas.style.height = '';
|
|
canvas.style.maxWidth = '';
|
|
canvas.style.maxHeight = '';
|
|
var maxheight = self.$frame.height() - 4;
|
|
if (clear || self.fitMode == 'N') {
|
|
|
|
} else if (self.fitMode == 'B') {
|
|
canvas.style.maxWidth = '100%';
|
|
canvas.style.maxHeight = maxheight + 'px';
|
|
} else if (self.fitMode == 'H') {
|
|
canvas.style.height = maxheight + 'px';
|
|
} else if (self.fitMode == 'W') {
|
|
canvas.style.width = '100%';
|
|
}
|
|
self.$scrollbar.options({
|
|
size: that.width()
|
|
});
|
|
}
|
|
|
|
function setImage(url) {
|
|
var ctx = canvas.getContext('2d'),
|
|
img = new Image();
|
|
img.onerror = function(e) {
|
|
canvas.width = innerWidth - 100;
|
|
canvas.height = 300;
|
|
resize(true);
|
|
ctx.fillStyle = 'orange';
|
|
ctx.font = '50px sans-serif';
|
|
ctx.strokeStyle = 'black';
|
|
ctx.fillText('Page #' + (currentImage+1) + ' (' +
|
|
imageFiles[currentImage].filename + ')', 100, 100)
|
|
ctx.fillStyle = 'red';
|
|
ctx.fillText('Is corrupt or not an image', 100, 200);
|
|
};
|
|
img.onload = function() {
|
|
var h = img.height,
|
|
w = img.width,
|
|
sw = w,
|
|
sh = h;
|
|
self.rotateTimes = (4 + self.rotateTimes) % 4;
|
|
ctx.save();
|
|
if (self.rotateTimes % 2 == 1) { sh = w; sw = h;}
|
|
canvas.height = sh;
|
|
canvas.width = sw;
|
|
ctx.translate(sw/2, sh/2);
|
|
ctx.rotate(Math.PI/2 * self.rotateTimes);
|
|
ctx.translate(-w/2, -h/2);
|
|
if (self.vflip) {
|
|
ctx.scale(1, -1)
|
|
ctx.translate(0, -h);
|
|
}
|
|
if (self.hflip) {
|
|
ctx.scale(-1, 1)
|
|
ctx.translate(-w, 0);
|
|
}
|
|
canvas.style.display = 'none';
|
|
scrollTo(0,0);
|
|
ctx.drawImage(img, 0, 0);
|
|
|
|
resize();
|
|
|
|
canvas.style.display = '';
|
|
document.body.style.overflowY = '';
|
|
ctx.restore();
|
|
};
|
|
img.src = url;
|
|
}
|
|
|
|
function setPage() {
|
|
var file = self.pages[self.options.page - 1],
|
|
filename = file.filename,
|
|
extension = file.filename.split('.').pop().toLowerCase(),
|
|
mimeType = self.mimeTypes[extension];
|
|
setImage(createURLFromArray(file.fileData, mimeType));
|
|
self.$scrollbar.options({value: self.options.page});
|
|
that.triggerEvent('page', {page: self.options.page});
|
|
}
|
|
|
|
that.resize = function() {
|
|
resize();
|
|
};
|
|
return that;
|
|
};
|