-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
254 lines (233 loc) · 8.16 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Endless EPub</title>
<style>
html, body {
margin:0px;
padding:0px;
}
body {
color:#333;
height:100%;
background-color:whiteSmoke;
line-height:1.7em;
font-size:19px;
font-family:'palatino linotype', 'georgia', serif;
text-align:left: !important;
}
img {
/* forcefully center images, may cause glitches if
books have any images that are laid out side by side */
display:block;
margin-left:auto;
margin-right:auto;
}
pre {
/* give a tighter line height for code */
line-height:1.2em;
}
h1 {
margin:0px;
}
.large {
font-size:1.3em;
}
.muted {
color:#777;
}
.container {
max-width:800px;
min-height:100%;
margin:0px auto 0px auto;
}
.page {
padding:20px;
margin:0px 10px 20px 10px;
border:1px solid #ccc;
box-shadow:0px 0px 7px #ccc;
min-height:400px;
background-color:white;
}
.upload {
width:500px;
padding:20px;
border:2px solid #ccc;
margin:0px auto 20px auto;
}
</style>
</head>
<body>
<div class="container" id="container">
<br/>
<div class="page" id="form-page">
<h1>Endless Epub</h1>
<p>
This will load your whole book onto one page for easier reading. Once your book has been loaded,
you can use "right click -> save as" to get a complete copy for offline reading.
It may take a while for books with many images so be patient!
</p>
<div class="upload center">
<span class="large">Select an epub:</span>
<input type="file" id="file"/>
</div>
</div>
</div>
</body>
</html>
<script src="jquery-1.7.2.min.js"></script>
<script src="jszip.js"></script>
<script src="jszip-load.js"></script>
<script src="jszip-deflate.js"></script>
<script src="jszip-inflate.js"></script>
<script>
var ZipLoader = new JSZip();
function cleanup() {
$('#form-page').hide();
ZipLoader = null; //gc
}
$(function() {
$('#file').change(function(event) {
$('.upload').css('background-color', 'rgba(100, 100, 100, 0.5)').css('opacity', '0.5');
handleFiles(event.target.files, cleanup);
});
});
function extractPathPrefix(location) {
return location.substr(0, location.lastIndexOf('/') + 1);
}
function buildPath(currentDirectory, relativePath) {
var curSplit = currentDirectory.split('/');
curSplit.pop(); //remove trailing slash
var relSplit = relativePath.split('/');
for (var i = 0; i < relSplit.length; i++) {
if (relSplit[i] == '..') {
curSplit.pop();
} else {
curSplit.push(relSplit[i]);
}
}
return curSplit.join('/');
}
function handleFiles(files, callback) {
var file = files[0];
//calls unzipFile once the load is finished
var reader = makeFileReader();
reader.onload = function(event) {
var blob = event.target.result;
ZipLoader.load(blob);
var containerXML = ZipLoader.file('META-INF/container.xml').data;
var contentLocation = $(containerXML).find('rootfile').attr('full-path');
var pathPrefix = extractPathPrefix(contentLocation);
loadContentXML(pathPrefix, ZipLoader.file(contentLocation).data);
callback();
}
reader.readAsBinaryString(file);
}
function getImageUriFor(imagePath) {
var fileExtension = (/[.]/.exec(imagePath)) && /[^.]+$/.exec(imagePath)[0] || '';
switch (fileExtension.toLowerCase()) {
case 'gif' :
return "data:image/gif;base64,";
case 'png' :
return "data:image/png;base64,";
case 'jpg':
case 'jpeg':
return "data:image/jpeg;base64,";
}
}
function loadContentXML(pathPrefix, contentXML) {
var itemLookup = {};
var parsed = $(contentXML);
parsed.find('manifest item').each(function(){
itemLookup[$(this).attr('id')] = $(this).attr('href');
});
var entirePage = '';
var itemRefs = parsed.find('itemref')
itemRefs.each(function(idx){
var href = itemLookup[$(this).attr('idref')];
var completeHref = pathPrefix + href;
var pagePrefix = extractPathPrefix(completeHref);
var page = ZipLoader.file(completeHref);
var decoded = decodeUTF8(page.data);
var pageHtml = replaceImages(pagePrefix, decoded);
entirePage += createNewPage(pageHtml);
});
$('#container').append(entirePage);
}
function replaceImages(pagePrefix, pageContents){
//prevent loading images when we parse the string
//http://stackoverflow.com/questions/2302129
pageContents = pageContents.replace(/<img(.*?)src=(.*?)>/g, '<img$1blah=$2>');
//console.log(pageContents);
var newContents = $(pageContents);
newContents.find('img').each(function(){
var domImage = $(this);
var imgSrc = domImage.attr('blah');
if (imgSrc.slice(0,7) == 'http://') {
//loading from the web, ignore it
return true;
}
var location = buildPath(pagePrefix, imgSrc);
try {
var imageData = ZipLoader.file(location).data
} catch (err) {
console.log("Error while loading image, skipping");
console.log(err);
return true;
}
var base64image = Base64(imageData);
var imageUri = getImageUriFor(imgSrc);
domImage.attr('src', imageUri + base64image);
});
return newContents;
}
var firstPage = true;
function createNewPage(pageHtml) {
var newPage = $('<div class="page"/>');
newPage.html(pageHtml);
return newPage[0].outerHTML;
}
function makeFileReader() {
var reader = new FileReader();
reader.onerror = function(event) {
if (event.target.error.name !== undefined) {
alert("Error: " + event.target.error.name);
alert(event.target.error.code);
} else {
alert(getErrorDescription(event.target.error.code));
}
}
return reader;
}
// for deprecated FileError object still used by chrome
function getErrorDescription(errorCode) {
switch (errorCode) {
case 1: return 'File not found';
case 2: return 'Security error, you\'re probably trying to run this ' +
'locally in Chrome, which doesn\'t work. Try firefox ' +
'or run it on a server';
case 3: return 'File upload aborted';
case 4: return 'File wasn\'t readable';
case 5: return 'Data URL too long';
default: return 'Unknown error';
}
}
function decodeUTF8(str) {
return decodeURIComponent(escape(str));
}
var Base64 = function(input) {
var StringMaker = undefined;
if(navigator.userAgent.toLowerCase().indexOf(" chrome/")>=0||navigator.userAgent.toLowerCase().indexOf(" firefox/")>=0||
navigator.userAgent.toLowerCase().indexOf(' gecko/')>=0){StringMaker=function(){this.str="";this.length=0;
this.append=function(s){this.str+=s;this.length+=s.length;};this.prepend=function(s){this.str=s+this.str;this.length+=s.length;};
this.toString=function(){return this.str;}}}else{StringMaker=function(){this.parts=[];this.length=0;this.append=function(s){
this.parts.push(s);this.length+=s.length;};this.prepend=function(s){this.parts.unshift(s);this.length+=s.length;};
this.toString=function(){return this.parts.join('');}}}
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o=new StringMaker(),a,b,c,d,f,g,h,i=0;while(i<input.length){a=input.charCodeAt(i++);
b=input.charCodeAt(i++);c=input.charCodeAt(i++);d=a>>2;f=((a&3)<<4)|(b>>4);g=((b&15)<<2)|(c>>6);h=c&63;
if(isNaN(b)){g=h=64;}else if(isNaN(c)){h=64;}o.append(keyStr.charAt(d)+keyStr.charAt(f)+keyStr.charAt(g)
+keyStr.charAt(h));}return o.toString();
}
</script>