mirror of
https://github.com/JonathanHerrewijnen/calibre-web.git
synced 2024-11-11 05:33:57 +00:00
-Added a more subtle progress bar which only shows the page number on hover
-Added Current page indicator to the thumbnail list, as well as a hover state -Thumbnail list now scrolls to the current page on open or page change -Added @andy29485's request for controlling page with space/shift+space -Added the book title to the top of the page -Fixed IE11 failing on imagecallback
This commit is contained in:
parent
4e11272023
commit
2fe03961bb
@ -1,17 +1,21 @@
|
||||
body {
|
||||
background: #444;
|
||||
background: #444;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
margin: 0px;
|
||||
color: white;
|
||||
font-family: sans-serif;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#main {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.view {
|
||||
padding-top:0px;
|
||||
}
|
||||
|
||||
#sidebar a,
|
||||
#sidebar ul,
|
||||
#sidebar li,
|
||||
@ -20,10 +24,28 @@ body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#sidebar ul {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#sidebar a {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
|
||||
transition: all .2s ease;
|
||||
}
|
||||
|
||||
#sidebar a:hover,
|
||||
#sidebar a:focus {
|
||||
outline: none;
|
||||
box-shadow: 0px 2px 8px 1px black;
|
||||
}
|
||||
|
||||
#sidebar a.active,
|
||||
#sidebar a.active img + span {
|
||||
background-color: #45B29D;
|
||||
}
|
||||
|
||||
#sidebar li img {
|
||||
@ -47,21 +69,65 @@ body {
|
||||
}
|
||||
|
||||
#progress {
|
||||
position: absolute;
|
||||
display: inline;
|
||||
left: 20%;
|
||||
right: 20%;
|
||||
height: 20px;
|
||||
margin-top: 4px;
|
||||
text-align: right;
|
||||
position: absolute;
|
||||
display: inline;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
min-height: 4px;
|
||||
font-family: sans-serif;
|
||||
font-size: 10px;
|
||||
line-height: 10px;
|
||||
text-align: right;
|
||||
|
||||
transition: min-height 150ms ease-in-out;
|
||||
}
|
||||
|
||||
#progress .bar-load,
|
||||
#progress .bar-read {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
||||
transition: width 150ms ease-in-out;
|
||||
}
|
||||
|
||||
#progress .bar-load {
|
||||
color: #000;
|
||||
background-color: #CCC;
|
||||
}
|
||||
|
||||
#progress .bar-read {
|
||||
color: #FFF;
|
||||
background-color: #45B29D;
|
||||
}
|
||||
|
||||
#progress .text {
|
||||
display: none;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
#progress.loading,
|
||||
#titlebar:hover #progress {
|
||||
min-height: 10px;
|
||||
}
|
||||
|
||||
#progress.loading .text,
|
||||
#titlebar:hover #progress .text {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none !important;
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#mainContent {
|
||||
overflow: auto;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
#mainText {
|
||||
@ -82,6 +148,10 @@ body {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
#metainfo {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
#prev {
|
||||
left: 40px;
|
||||
}
|
||||
@ -176,43 +246,11 @@ th {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.dark-theme #progress .bar-read {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
|
||||
.dark-theme .overlay {
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
}
|
||||
|
||||
.view {
|
||||
padding-top:0px;
|
||||
}
|
||||
|
||||
#Progress {
|
||||
margin: auto;
|
||||
width: 80%;
|
||||
background-color: #ddd;
|
||||
display: inline-block;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#meter {
|
||||
width: 0%;
|
||||
height: 5px;
|
||||
background-color: #1C5484;
|
||||
}
|
||||
|
||||
#meter2 {
|
||||
width: 0%;
|
||||
height: 15px;
|
||||
background-color: #028138;
|
||||
}
|
||||
|
||||
#page {
|
||||
text-align:left;
|
||||
margin-top:-20px;
|
||||
font-size:80%;
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
#progress_title {
|
||||
text-align:right;
|
||||
margin-top:-15px;
|
||||
font-size:80%;
|
||||
}
|
||||
|
@ -17,8 +17,6 @@
|
||||
*/
|
||||
/* global screenfull */
|
||||
|
||||
// var start = 0;
|
||||
|
||||
if (window.opera) {
|
||||
window.console.log = function(str) {
|
||||
opera.postError(str);
|
||||
@ -44,11 +42,12 @@ if (typeof window.kthoom === "undefined" ) {
|
||||
// key codes
|
||||
kthoom.Key = {
|
||||
ESCAPE: 27,
|
||||
SPACE: 32,
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40,
|
||||
A: 65, B: 66, C: 67, D: 68, E: 69, F: 70, G: 71, H: 72, I: 73, J: 74, K: 75, L: 76, M: 77,
|
||||
DOWN: 40,
|
||||
A: 65, B: 66, C: 67, D: 68, E: 69, F: 70, G: 71, H: 72, I: 73, J: 74, K: 75, L: 76, M: 77,
|
||||
N: 78, O: 79, P: 80, Q: 81, R: 82, S: 83, T: 84, U: 85, V: 86, W: 87, X: 88, Y: 89, Z: 90,
|
||||
QUESTION_MARK: 191,
|
||||
LEFT_SQUARE_BRACKET: 219,
|
||||
@ -62,8 +61,8 @@ var imageFilenames = [];
|
||||
var totalImages = 0;
|
||||
|
||||
var settings = {
|
||||
hflip: false,
|
||||
vflip: false,
|
||||
hflip: false,
|
||||
vflip: false,
|
||||
rotateTimes: 0,
|
||||
fitMode: kthoom.Key.B,
|
||||
theme: "light"
|
||||
@ -106,48 +105,16 @@ kthoom.ImageFile = function(file) {
|
||||
this.data = file;
|
||||
};
|
||||
|
||||
|
||||
kthoom.initProgressMeter = function() {
|
||||
$("#Progress").removeClass("hide");
|
||||
$("#Progress").click(function(e) {
|
||||
var page = Math.max(1, Math.ceil((e.offsetX / $(this).width()) * totalImages)) - 1;
|
||||
currentImage = page;
|
||||
updatePage();
|
||||
});
|
||||
};
|
||||
|
||||
kthoom.setProgressMeter = function(optLabel) {
|
||||
var pct = imageFiles.length / totalImages * 100;
|
||||
if (pct === 100) {
|
||||
//smartpct = 100;
|
||||
getElem("progress_title").innerHTML = "Complete";
|
||||
} else {
|
||||
var labelText = pct.toFixed(2) + "% " + imageFiles.length + "/" + totalImages + "";
|
||||
if (optLabel) {
|
||||
labelText = optLabel + " " + labelText;
|
||||
}
|
||||
getElem("progress_title").innerHTML=labelText;
|
||||
}
|
||||
if (!isNaN(pct)) {
|
||||
getElem("meter").style.width = pct + "%";
|
||||
}
|
||||
|
||||
getElem("meter2").style.width= 100 * (totalImages === 0 ? 0 : ((currentImage + 1) / totalImages)) + "%";
|
||||
getElem("page").innerHTML=(currentImage + 1) + "/" + totalImages ;
|
||||
};
|
||||
|
||||
function loadFromArrayBuffer(ab) {
|
||||
var f = [];
|
||||
if (typeof ab !== "object") {
|
||||
ab = JSON.parse(ab);
|
||||
}
|
||||
|
||||
f.fileData = ab.content;
|
||||
f.filename = ab.name;
|
||||
// add any new pages based on the filename
|
||||
if (imageFilenames.indexOf(f.filename) === -1) {
|
||||
imageFilenames.push(f.filename);
|
||||
imageFiles.push(new kthoom.ImageFile(f));
|
||||
|
||||
|
||||
// add thumbnails to the TOC list
|
||||
$("#thumbnails").append(
|
||||
"<li>" +
|
||||
@ -158,10 +125,10 @@ function loadFromArrayBuffer(ab) {
|
||||
"</li>"
|
||||
);
|
||||
}
|
||||
// var percentage = (ab.page + 1) / (ab.last + 1);
|
||||
var percentage = ((ab.page + 1) / (ab.last + 1)) * 100;
|
||||
updateProgress(percentage);
|
||||
|
||||
totalImages = ab.last + 1;
|
||||
kthoom.setProgressMeter("Unzipping");
|
||||
// lastCompletion = percentage * 100;
|
||||
|
||||
// display first page if we haven't yet
|
||||
if (imageFiles.length === currentImage + 1) {
|
||||
@ -169,10 +136,28 @@ function loadFromArrayBuffer(ab) {
|
||||
}
|
||||
}
|
||||
|
||||
function scrollTocToActive() {
|
||||
// Scroll to the thumbnail in the TOC on page change
|
||||
$('#tocView').stop().animate({
|
||||
scrollTop: $('#tocView a.active').position().top
|
||||
}, 200);
|
||||
}
|
||||
|
||||
function updatePage() {
|
||||
getElem("page").innerHTML=(currentImage + 1) + "/" + totalImages ;
|
||||
getElem("meter2").style.width= 100 * (totalImages === 0 ? 0 : ((currentImage + 1) / totalImages)) + "%";
|
||||
$('.page').text((currentImage + 1 ) + "/" + totalImages);
|
||||
|
||||
// Mark the current page in the TOC
|
||||
$('#tocView a[data-page]')
|
||||
// Remove the currently active thumbnail
|
||||
.removeClass('active')
|
||||
// Find the new one
|
||||
.filter('[data-page='+ (currentImage + 1) +']')
|
||||
// Set it to active
|
||||
.addClass('active');
|
||||
|
||||
scrollTocToActive();
|
||||
updateProgress();
|
||||
|
||||
if (imageFiles[currentImage]) {
|
||||
setImage(imageFiles[currentImage].dataURI);
|
||||
} else {
|
||||
@ -185,6 +170,22 @@ function updatePage() {
|
||||
kthoom.saveSettings();
|
||||
}
|
||||
|
||||
function updateProgress(loadPercentage) {
|
||||
// Set the load/unzip progress if it's passed in
|
||||
if (loadPercentage) {
|
||||
$("#progress .bar-load").css({ width: loadPercentage + "%" });
|
||||
|
||||
if (loadPercentage === 100) {
|
||||
$("#progress")
|
||||
.removeClass('loading')
|
||||
.find(".load").text('');
|
||||
}
|
||||
}
|
||||
|
||||
// Set page progress bar
|
||||
$("#progress .bar-read").css({ width: totalImages === 0 ? 0 : Math.round((currentImage + 1) / totalImages * 100) + "%"});
|
||||
}
|
||||
|
||||
function setImage(url) {
|
||||
var canvas = $("#mainImage")[0];
|
||||
var x = $("#mainImage")[0].getContext("2d");
|
||||
@ -332,23 +333,18 @@ function updateScale(clear) {
|
||||
}
|
||||
|
||||
function keyHandler(evt) {
|
||||
var code = evt.keyCode;
|
||||
|
||||
if ($("#progress").css("display") === "none") {
|
||||
return;
|
||||
}
|
||||
// canKeyNext = (($("body").css("offsetWidth") + $("body").css("scrollLeft")) / $("body").css("scrollWidth")) >= 1;
|
||||
// canKeyPrev = (scrollX <= 0);
|
||||
|
||||
if (evt.ctrlKey || evt.shiftKey || evt.metaKey) return;
|
||||
switch (code) {
|
||||
var hasModifier = evt.ctrlKey || evt.shiftKey || evt.metaKey;
|
||||
switch (evt.keyCode) {
|
||||
case kthoom.Key.LEFT:
|
||||
if (hasModifier) break;
|
||||
showPrevPage();
|
||||
break;
|
||||
case kthoom.Key.RIGHT:
|
||||
if (hasModifier) break;
|
||||
showNextPage();
|
||||
break;
|
||||
case kthoom.Key.L:
|
||||
if (hasModifier) break;
|
||||
settings.rotateTimes--;
|
||||
if (settings.rotateTimes < 0) {
|
||||
settings.rotateTimes = 3;
|
||||
@ -356,6 +352,7 @@ function keyHandler(evt) {
|
||||
updatePage();
|
||||
break;
|
||||
case kthoom.Key.R:
|
||||
if (hasModifier) break;
|
||||
settings.rotateTimes++;
|
||||
if (settings.rotateTimes > 3) {
|
||||
settings.rotateTimes = 0;
|
||||
@ -363,6 +360,7 @@ function keyHandler(evt) {
|
||||
updatePage();
|
||||
break;
|
||||
case kthoom.Key.F:
|
||||
if (hasModifier) break;
|
||||
if (!settings.hflip && !settings.vflip) {
|
||||
settings.hflip = true;
|
||||
} else if (settings.hflip === true && settings.vflip === true) {
|
||||
@ -377,23 +375,43 @@ function keyHandler(evt) {
|
||||
updatePage();
|
||||
break;
|
||||
case kthoom.Key.W:
|
||||
if (hasModifier) break;
|
||||
settings.fitMode = kthoom.Key.W;
|
||||
updateScale(false);
|
||||
break;
|
||||
case kthoom.Key.H:
|
||||
if (hasModifier) break;
|
||||
settings.fitMode = kthoom.Key.H;
|
||||
updateScale(false);
|
||||
break;
|
||||
case kthoom.Key.B:
|
||||
if (hasModifier) break;
|
||||
settings.fitMode = kthoom.Key.B;
|
||||
updateScale(false);
|
||||
break;
|
||||
case kthoom.Key.N:
|
||||
if (hasModifier) break;
|
||||
settings.fitMode = kthoom.Key.N;
|
||||
updateScale(false);
|
||||
break;
|
||||
case kthoom.Key.SPACE:
|
||||
var container = $('#mainContent');
|
||||
var atTop = container.scrollTop() === 0;
|
||||
var atBottom = container.scrollTop() >= container[0].scrollHeight - container.height();
|
||||
|
||||
if (evt.shiftKey && atTop) {
|
||||
evt.preventDefault();
|
||||
// If it's Shift + Space and the container is at the top of the page
|
||||
showPrevPage();
|
||||
} else if (!evt.shiftKey && atBottom) {
|
||||
evt.preventDefault();
|
||||
// If you're at the bottom of the page and you only pressed space
|
||||
showNextPage();
|
||||
container.scrollTop(0);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
//console.log('KeyCode = ' + code);
|
||||
//console.log('KeyCode', evt.keyCode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -404,31 +422,31 @@ function ImageLoadCallback() {
|
||||
if (jso === null) {
|
||||
setImage("error");
|
||||
} else {
|
||||
// IE 11 sometimes sees the response as a string
|
||||
if (typeof jso !== "object") {
|
||||
jso = JSON.parse(jso);
|
||||
}
|
||||
|
||||
if (jso.page !== jso.last) {
|
||||
this.open("GET", this.fileid + "/" + (jso.page + 1));
|
||||
this.addEventListener("load", ImageLoadCallback);
|
||||
this.send();
|
||||
}
|
||||
/*else
|
||||
{
|
||||
var diff = ((new Date).getTime() - start) / 1000;
|
||||
console.log("Transfer done in " + diff + "s");
|
||||
}*/
|
||||
|
||||
loadFromArrayBuffer(jso);
|
||||
}
|
||||
}
|
||||
function init(fileid) {
|
||||
// start = (new Date).getTime();
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", fileid);
|
||||
request.responseType = "json";
|
||||
request.fileid = fileid.substring(0, fileid.length - 2);
|
||||
request.addEventListener("load", ImageLoadCallback);
|
||||
request.send();
|
||||
kthoom.initProgressMeter();
|
||||
document.body.className += /AppleWebKit/.test(navigator.userAgent) ? " webkit" : "";
|
||||
kthoom.loadSettings();
|
||||
updateScale(true);
|
||||
|
||||
$(document).keydown(keyHandler);
|
||||
|
||||
$(window).resize(function() {
|
||||
@ -440,6 +458,13 @@ function init(fileid) {
|
||||
$("#sidebar").toggleClass("open");
|
||||
$("#main").toggleClass("closed");
|
||||
$(this).toggleClass("icon-menu icon-right");
|
||||
|
||||
// We need this in a timeout because if we call it during the CSS transition, IE11 shakes the page ¯\_(ツ)_/¯
|
||||
setTimeout(function(){
|
||||
// Focus on the TOC or the main content area, depending on which is open
|
||||
$('#main:not(.closed) #mainContent, #sidebar.open #tocView').focus();
|
||||
scrollTocToActive();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Open Settings modal
|
||||
@ -487,6 +512,9 @@ function init(fileid) {
|
||||
}
|
||||
}
|
||||
|
||||
// Focus the scrollable area so that keyboard scrolling work as expected
|
||||
$('#mainContent').focus();
|
||||
|
||||
$("#mainImage").click(function(evt) {
|
||||
// Firefox does not support offsetX/Y so we have to manually calculate
|
||||
// where the user clicked in the image.
|
||||
|
@ -1,148 +1,156 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>Comic Reader</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/libs/normalize.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}" type="text/css"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/kthoom.css') }}" type="text/css"/>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<title>Comic Reader</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<script src="{{ url_for('static', filename='js/libs/jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/libs/screenfull.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/kthoom.js') }}"></script>
|
||||
<script>
|
||||
document.onreadystatechange = function () {
|
||||
if (document.readyState == "complete") {
|
||||
init("{{ url_for('get_comic_book', book_id=comicfile, book_format=extension, page=0) }}");
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="sidebar">
|
||||
<!--div id="panels"-->
|
||||
<!-- <a id="show-Toc" class="show_view icon-list-1 active" data-view="Toc">TOC</a> -->
|
||||
<!-- <a id="show-Bookmarks" class="show_view icon-bookmark" data-view="Bookmarks">Bookmarks</a> -->
|
||||
<!--/div-->
|
||||
<div id="tocView" class="view">
|
||||
<ul id="thumbnails"></ul>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/libs/normalize.css') }}">
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}" type="text/css"/>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/kthoom.css') }}" type="text/css"/>
|
||||
|
||||
<script src="{{ url_for('static', filename='js/libs/jquery.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/libs/screenfull.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/kthoom.js') }}"></script>
|
||||
<script>
|
||||
document.onreadystatechange = function () {
|
||||
if (document.readyState == "complete") {
|
||||
init("{{ url_for('get_comic_book', book_id=comicfile, book_format=extension, page=0) }}");
|
||||
}
|
||||
};
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="sidebar">
|
||||
<!--
|
||||
<div id="panels">
|
||||
<a id="show-Toc" class="show_view icon-list-1 active" data-view="Toc">TOC</a>
|
||||
<a id="show-Bookmarks" class="show_view icon-bookmark" data-view="Bookmarks">Bookmarks</a>
|
||||
</div>
|
||||
-->
|
||||
<div id="tocView" class="view" tabindex="-1">
|
||||
<ul id="thumbnails"></ul>
|
||||
</div>
|
||||
<div id="bookmarksView" class="view">
|
||||
<ul id="bookmarks"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main" class="main">
|
||||
<div id="titlebar" class="main">
|
||||
<div id="opener">
|
||||
<a id="slider" class="icon-menu">Menu</a>
|
||||
</div>
|
||||
<div id="metainfo">
|
||||
<span id="book-title">{{ book.title | shortentitle }}</span>
|
||||
<span id="title-seperator"> – </span>
|
||||
<span id="chapter-title"></span>
|
||||
</div>
|
||||
<div id="title-controls">
|
||||
<a id="setting" class="icon-cog">Settings</a>
|
||||
<a id="fullscreen" class="icon-resize-full">Fullscreen</a>
|
||||
</div>
|
||||
<div id="progress" role="progressbar" class="loading">
|
||||
<div class="bar-load">
|
||||
<div class="text load">
|
||||
Loading...
|
||||
</div>
|
||||
</div>
|
||||
<div id="bookmarksView" class="view">
|
||||
<ul id="bookmarks"></ul>
|
||||
<div class="bar-read">
|
||||
<div class="text page"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main" class="main">
|
||||
<div id="titlebar" class="main">
|
||||
<div id="opener">
|
||||
<a id="slider" class="icon-menu">Menu</a>
|
||||
</div>
|
||||
<div id="metainfo">
|
||||
<span id="book-title"></span>
|
||||
<span id="title-seperator"> – </span>
|
||||
<span id="chapter-title"></span>
|
||||
</div>
|
||||
<div id="Progress" class="hide">
|
||||
<div id="meter2"></div><div class="progress_title" id="progress_title" ></div>
|
||||
<div id="meter"></div><div class="page" id="page" ></div>
|
||||
</div>
|
||||
<div id="title-controls">
|
||||
<a id="setting" class="icon-cog">Settings</a>
|
||||
<a id="fullscreen" class="icon-resize-full">Fullscreen</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="mainContent">
|
||||
<div id="mainText" style="display:none"></div>
|
||||
<canvas id="mainImage"></canvas>
|
||||
</div>
|
||||
<div id="prev" class="arrow" onclick="showPrevPage()">‹</div>
|
||||
<div id="next" class="arrow" onclick="showNextPage()">›</div>
|
||||
</div>
|
||||
<div id="mainContent" tabindex="-1">
|
||||
<div id="mainText" style="display:none"></div>
|
||||
<canvas id="mainImage"></canvas>
|
||||
</div>
|
||||
<div id="prev" class="arrow" onclick="showPrevPage()">‹</div>
|
||||
<div id="next" class="arrow" onclick="showNextPage()">›</div>
|
||||
</div>
|
||||
|
||||
<div class="modal md-effect-1" id="settings-modal">
|
||||
<div class="md-content">
|
||||
<h3>{{_('Settings')}}</h3>
|
||||
<div>
|
||||
<div class="settings-column">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th colspan="2">{{_('Keyboard Shortcuts')}}</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>←</td> <td>{{_('Previous Page')}}</td></tr>
|
||||
<tr><td>→</td> <td>{{_('Next Page')}}</td></tr>
|
||||
<tr><td>B</td> <td>{{_('Scale to Best')}}</td></tr>
|
||||
<tr><td>W</td> <td>{{_('Scale to Width')}}</td></tr>
|
||||
<tr><td>H</td> <td>{{_('Scale to Height')}}</td></tr>
|
||||
<tr><td>N</td> <td>{{_('Scale to Native')}}</td></tr>
|
||||
<tr><td>R</td> <td>{{_('Rotate Right')}}</td></tr>
|
||||
<tr><td>L</td> <td>{{_('Rotate Left')}}</td></tr>
|
||||
<tr><td>F</td> <td>{{_('Flip Image')}}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="modal md-effect-1" id="settings-modal">
|
||||
<div class="md-content">
|
||||
<h3>{{_('Settings')}}</h3>
|
||||
<div>
|
||||
<div class="settings-column">
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th colspan="2">{{_('Keyboard Shortcuts')}}</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>←</td> <td>{{_('Previous Page')}}</td></tr>
|
||||
<tr><td>→</td> <td>{{_('Next Page')}}</td></tr>
|
||||
<tr><td>B</td> <td>{{_('Scale to Best')}}</td></tr>
|
||||
<tr><td>W</td> <td>{{_('Scale to Width')}}</td></tr>
|
||||
<tr><td>H</td> <td>{{_('Scale to Height')}}</td></tr>
|
||||
<tr><td>N</td> <td>{{_('Scale to Native')}}</td></tr>
|
||||
<tr><td>R</td> <td>{{_('Rotate Right')}}</td></tr>
|
||||
<tr><td>L</td> <td>{{_('Rotate Left')}}</td></tr>
|
||||
<tr><td>F</td> <td>{{_('Flip Image')}}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="settings-column">
|
||||
<table id="settings">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{_('Settings')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{_('Theme')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="lightTheme"><input type="radio" id="lightTheme" name="theme" value="light" /> {{_('Light')}}</label>
|
||||
<label for="darkTheme"><input type="radio" id="darkTheme" name="theme" value="dark" /> {{_('Dark')}}</label>
|
||||
</div>
|
||||
<div class="settings-column">
|
||||
<table id="settings">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{_('Settings')}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>{{_('Theme')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="lightTheme"><input type="radio" id="lightTheme" name="theme" value="light" /> {{_('Light')}}</label>
|
||||
<label for="darkTheme"><input type="radio" id="darkTheme" name="theme" value="dark" /> {{_('Dark')}}</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{_('Scale')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="fitBest"><input type="radio" id="fitBest" name="fitMode" value="66" /> {{_('Best')}}</label>
|
||||
<label for="fitWidth"><input type="radio" id="fitWidth" name="fitMode" value="87" /> {{_('Width')}}</label>
|
||||
<label for="fitHeight"><input type="radio" id="fitHeight" name="fitMode" value="72" /> {{_('Height')}}</label>
|
||||
<label for="fitNative"><input type="radio" id="fitNative" name="fitMode" value="78" /> {{_('Native')}}</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{_('Rotate')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="r0"><input type="radio" id="r0" name="rotateTimes" value="0" /> 0°</label>
|
||||
<label for="r90"><input type="radio" id="r90" name="rotateTimes" value="1" /> 90°</label>
|
||||
<label for="r180"><input type="radio" id="r180" name="rotateTimes" value="2" /> 180°</label>
|
||||
<label for="r270"><input type="radio" id="r270" name="rotateTimes" value="3" /> 270°</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{_('Flip')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="vflip"><input type="checkbox" id="vflip" name="vflip" /> {{_('Horizontal')}}</label>
|
||||
<label for="hflip"><input type="checkbox" id="hflip" name="hflip" /> {{_('Vertical')}}</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{_('Scale')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="fitBest"><input type="radio" id="fitBest" name="fitMode" value="66" /> {{_('Best')}}</label>
|
||||
<label for="fitWidth"><input type="radio" id="fitWidth" name="fitMode" value="87" /> {{_('Width')}}</label>
|
||||
<label for="fitHeight"><input type="radio" id="fitHeight" name="fitMode" value="72" /> {{_('Height')}}</label>
|
||||
<label for="fitNative"><input type="radio" id="fitNative" name="fitMode" value="78" /> {{_('Native')}}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="closer icon-cancel-circled"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{_('Rotate')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="r0"><input type="radio" id="r0" name="rotateTimes" value="0" /> 0°</label>
|
||||
<label for="r90"><input type="radio" id="r90" name="rotateTimes" value="1" /> 90°</label>
|
||||
<label for="r180"><input type="radio" id="r180" name="rotateTimes" value="2" /> 180°</label>
|
||||
<label for="r270"><input type="radio" id="r270" name="rotateTimes" value="3" /> 270°</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{_('Flip')}}:</th>
|
||||
<td>
|
||||
<div class="inputs">
|
||||
<label for="vflip"><input type="checkbox" id="vflip" name="vflip" /> {{_('Horizontal')}}</label>
|
||||
<label for="hflip"><input type="checkbox" id="hflip" name="hflip" /> {{_('Vertical')}}</label>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay"></div>
|
||||
<div class="closer icon-cancel-circled"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overlay"></div>
|
||||
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1972,7 +1972,7 @@ def read_book(book_id, book_format):
|
||||
extensionList = ["cbt","cbz"]
|
||||
for fileext in extensionList:
|
||||
if book_format.lower() == fileext:
|
||||
return render_title_template('readcbr.html', comicfile=book_id, extension=fileext, title=_(u"Read a Book"))
|
||||
return render_title_template('readcbr.html', comicfile=book_id, extension=fileext, title=_(u"Read a Book"), book=book)
|
||||
flash(_(u"Error opening eBook. File does not exist or file is not accessible."), category="error")
|
||||
return redirect(url_for("index"))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user