Good day all,
Please I need help in resolving a situation where I want to call a function after an epub has fully loaded.
The code below loads the epub successfully, but I would like to display the table of contents (toc), which actually shows in developer console after the epub file has loaded.
I've not been able to make the toc to display, the LoadToc is never called, and when I change where it is being called, it is called immediately, without waiting for the epub to fully load.
book = null;
document.getElementById('bookChooser').addEventListener('change', function(e) {
var firstFile = e.target.files[0];
if (window.FileReader) {
var reader = new FileReader();
reader.onload = function(e) {
book = ePub({
bookPath: e.target.result
});
book.renderTo("area");
/* Replace area with the id for your div to put the book in */
}.bind(this).bind(this.LoadToc);
reader.readAsArrayBuffer(firstFile);
} else {
alert("Your browser does not support the required features. Please use a modern browser such as Google Chrome, or Mozilla Firefox ");
}
});
function LoadToc() {
if (book !== null) {
var results = book.toc;
var $select = document.getElementById("toc"),
docfrag = document.createDocumentFragment();
var $select = document.getElementById("toc"),
docfrag = document.createDocumentFragment();
results.forEach(function(chapter) {
var option = document.createElement("option");
option.textContent = chapter.label;
option.ref = chapter.href;
docfrag.appendChild(option);
});
$select.appendChild(docfrag);
$select.onchange = function() {
var index = $select.selectedIndex,
url = $select.options[index].ref;
display(url);
return false;
};
}
}
document.getElementById("prev").onclick = function() {
book.prevPage();
}
document.getElementById("next").onclick = function() {
book.nextPage();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/epub.js/0.2.13/epub.min.js"></script>
<input type="file" id="bookChooser">
<select id="toc"></select>
<div id="area"></div>
<button id="prev" type="button"><</button>
<button id="next" type="button">></button>
Ok finally I was able to resolve the issue.
The file reader needed to end before calling the function. So using the code below solved the problem.
...
if (window.FileReader) {
var reader = new FileReader();
reader.onload = function(e) {
book = ePub({
bookPath: e.target.result
});
book.renderTo("area");
/* Replace area with the id for your div to put the book in */
}.bind(this).bind(this.LoadToc);
reader.readAsArrayBuffer(firstFile);
reader.onloadend = () => {
LoadToc();
}
} else {
alert("Your browser does not support the required features. Please use a modern
browser such as Google Chrome, or Mozilla Firefox ");
}
...
For anyone that could be facing issues like this
Thanks to everyone that commented
Related
I'm currently trying create a drag and drop file uploader with the standard option to just use the regular input. I'm not sure what to be targeting to write if the user clicked the upload or dropped a file in.
My first thought was to check if the FileList is empty but both ways produce a FileList. Second thought was just write two functions one for the input and one for the drop but that seems like I would be repeating. Last thought was writing an if statement in the read_file function. However, I'm not sure what to target exactly.
Any ideas would be greatly appreciated!! thanks!!
https://jsfiddle.net/nick1572/b4xzt8oh/3/
var uploader = document.querySelector('.uploader');
var output = document.getElementById('output');
var file = document.getElementById('file');
file.addEventListener('change', function(event) {
read_file(event);
});
function read_file(event) {
file = event.target;
var reader = new FileReader();
reader.onload = function() {
var data_url = reader.result;
output.src = data_url;
};
// This will read when the image is dropped.
//reader.readAsDataURL(event.dataTransfer.files[0]);
reader.readAsDataURL(file.files[0]);
/*
Something like this
if () {
reader.readAsDataURL(file.files[0]);
} else if() {
reader.readAsDataURL(event.dataTransfer.files[0]);
}
*/
};
uploader.addEventListener('dragover', function(e) {
console.log('drag over');
e.preventDefault();
});
uploader.addEventListener('dragenter', function(e) {
console.log('drag enter');
e.preventDefault();
});
uploader.addEventListener('dragleave', function() {
console.log('drag leave');
});
uploader.addEventListener('drop', function(event) {
console.log('drop');
event.preventDefault();
read_file(event);
});
Check the type property of the event object to see which event has been used.
function read_file(event) {
file = event.target;
var reader = new FileReader();
reader.onload = function() {
var data_url = reader.result;
output.src = data_url;
};
if (event.type === 'change') {
reader.readAsDataURL(file.files[0]);
} else if(event.type === 'drop') {
reader.readAsDataURL(event.dataTransfer.files[0]);
}
};
I think my javascript in my php file is in conflict with my javascript file.
I have a script that checks of the image is smaller then 2MB and a script that shows the image you selected in a small version. But the second part does not work when the first script is active. how do I fix this?
script in HTML
<script>
window.onload = function() {
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
if(this.files[0].size > 2000000){
alert("File is too big!");
this.value = "";
};
};
var uploadField = document.getElementById("itemImages");
uploadField.onchange = function() {
if(this.files[0].size > 200){
alert("File is too big!");
this.value = "";
};
};
}
</script>
.js file
$("#frontImages").change(function () {
if ($('#frontImages').get(0).files.length > 0) {
$('#frontImages').css('background-color', '#5cb85c');
} else {
$('#frontImages').css('background-color', '#d9534f');
}
});
$("#itemImages").change(function () {
if ($('#itemImages').get(0).files.length > 0) {
$('#itemImages').css('background-color', '#5cb85c');
} else {
$('#itemImages').css('background-color', '#d9534f');
}
});
document.getElementById("frontImages").onchange = function () {
var x = document.getElementById('previewFrontImage');
x.style.display = 'block';
var reader = new FileReader();
reader.onload = function (e) {
document.getElementById("previewFrontImage").src = e.target.result;
};
reader.readAsDataURL(this.files[0]);
};
function previewImages() {
var $preview = $('#previewItemImages').empty();
if (this.files) $.each(this.files, readAndPreview);
function readAndPreview(i, file) {
var reader = new FileReader();
$(reader).on("load", function () {
$preview.append($("<img/>", {src: this.result, height: 100}));
});
reader.readAsDataURL(file);
}
}
$('#itemImages').on("change", previewImages);
I'm guessing that the conflict is between the html script and this
document.getElementById("frontImages").onchange = function ()
I also have a question how I can fix that there will be no small image when the image is too big
Your guess is correct, onchange is simply member variable of various elements, and thus
var uploadField = document.getElementById("frontImages");
uploadField.onchange = function() {
and
document.getElementById("frontImages").onchange = function ()
are setting this single variable (of frontImages), which will store one callback function at a time.
You could use addEventListener() instead, which maintains a list of event listeners, so there can be more than one. Modifying the lines to
var uploadField = document.getElementById("frontImages");
uploadField.addEventListener("change", function() {
and
document.getElementById("frontImages").addEventListener("change", function ()
will register both event listeners on frontImages, regardless of the order they are executed.
Side remark: when you have "nice" ids, document.getElementById() can be omitted, as elements with ids become variables (of window which is the global scope), and thus you could write frontImages.addEventListener(...). You still need the getter in various cases, like when a local variable shadows the id, or when it is not usable as variable identifier (like id="my-favourite-id" or id="Hello World")
I'm working on hybrid mobile app using html5/js. It has a function download zip file then unzip them. The download function is not problem but I don't know how to unzip file (using javascript).
Many people refer to zip.js but it seems only reading zip file (not unzip/extract to new folder)
Very appreciate if someone could help me !!!
Have a look at zip.js documentation and demo page. Also notice the use of JavaScript filesystem API to read/write files and create temporary files.
If the zip file contains multiple entries, you could read the zip file entries and display a table of links to download each individual file as in the demo above.
If you look the source of the demo page, you see the following code (code pasted from Github demo page for zip.js) (I've added comments to explain):
function(obj) {
//Request fileSystemObject from JavaScript library for native support
var requestFileSystem = obj.webkitRequestFileSystem || obj.mozRequestFileSystem || obj.requestFileSystem;
function onerror(message) {
alert(message);
}
//Create a data model to handle unzipping and downloading
var model = (function() {
var URL = obj.webkitURL || obj.mozURL || obj.URL;
return {
getEntries : function(file, onend) {
zip.createReader(new zip.BlobReader(file), function(zipReader) {
zipReader.getEntries(onend);
}, onerror);
},
getEntryFile : function(entry, creationMethod, onend, onprogress) {
var writer, zipFileEntry;
function getData() {
entry.getData(writer, function(blob) {
var blobURL = creationMethod == "Blob" ? URL.createObjectURL(blob) : zipFileEntry.toURL();
onend(blobURL);
}, onprogress);
}
//Write the entire file as a blob
if (creationMethod == "Blob") {
writer = new zip.BlobWriter();
getData();
} else {
//Use the file writer to write the file clicked by user.
createTempFile(function(fileEntry) {
zipFileEntry = fileEntry;
writer = new zip.FileWriter(zipFileEntry);
getData();
});
}
}
};
})();
(function() {
var fileInput = document.getElementById("file-input");
var unzipProgress = document.createElement("progress");
var fileList = document.getElementById("file-list");
var creationMethodInput = document.getElementById("creation-method-input");
//The download function here gets called when the user clicks on the download link for each file.
function download(entry, li, a) {
model.getEntryFile(entry, creationMethodInput.value, function(blobURL) {
var clickEvent = document.createEvent("MouseEvent");
if (unzipProgress.parentNode)
unzipProgress.parentNode.removeChild(unzipProgress);
unzipProgress.value = 0;
unzipProgress.max = 0;
clickEvent.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
a.href = blobURL;
a.download = entry.filename;
a.dispatchEvent(clickEvent);
}, function(current, total) {
unzipProgress.value = current;
unzipProgress.max = total;
li.appendChild(unzipProgress);
});
}
if (typeof requestFileSystem == "undefined")
creationMethodInput.options.length = 1;
fileInput.addEventListener('change', function() {
fileInput.disabled = true;
//Create a list of anchor links to display to download files on the web page
model.getEntries(fileInput.files[0], function(entries) {
fileList.innerHTML = "";
entries.forEach(function(entry) {
var li = document.createElement("li");
var a = document.createElement("a");
a.textContent = entry.filename;
a.href = "#";
//Click event handler
a.addEventListener("click", function(event) {
if (!a.download) {
download(entry, li, a);
event.preventDefault();
return false;
}
}, false);
li.appendChild(a);
fileList.appendChild(li);
});
});
}, false);
})();
})(this);
I'm having an issue with getting the dimensions of a newly updated image element.
I'm using FileReader to display a preview of an image file on screen.
Once the filereader and associated code has finished executing, I retrieve the new dimensions of the image element so I can adjust them accordingly.
On some browsers, the info doesn't get updated straight away and I need to include a delay before I can retrieve the new dimensions. This results in the new image being resized according to the previous image's dimensions, and not its own.
How can I be sure the new image has been fully loaded?
I would have thought FileReader().onloadend would have been sufficient but apparently not. I think this is executed once the fileReader has loaded it, not when the DOM has rendered it. (Am I right?)
Then I found this question, which suggests using a timeout of 1 millisecond. This works sometimes, but not always. It seems to be down to the speed the browser is rendering the image (more-so available resources rather than filesize). Do we have no other way of detecting a change in these parameters?
HTML
<img src="#.png" alt=""/>
<input id="fileInput" type="file" accept='image/*' onChange="loadIt()" />
JS
preview = getElementsByTagName('img')[0];
function loadIt() {
var imgReader = new FileReader();
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
imgReader.onloadstart = function(e) {
//
}
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
//
}
else {
preview.src = 'error.png';
//
}
}
imgReader.onloadend = function(e) {
setImage();
setTimeout(function(){
setImage();
}, 1);
setTimeout(function(){
setImage();
}, 2000);
//
}
};
function setImage() {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
//
};
You should call preview.onload or preview.onloadend on your image to detect that it has finished loading. You're also calling your events after you readAsDataURL The code should look like this
var preview=document.getElementsByTagName("img")[0];
function loadIt() {
var imgReader=new FileReader();
imgReader.onload=function(){
if (isImage()) {
preview.src = imgReader.result;
preview.onload=setImage;
} else {
preview.src = 'error.png';
//
}
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
}
function setImage(){
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
}
You're calling imgReader.readAsDataURL before your .onload and .onloadend is set.
I do not know what some of the variables are with-in the body of your setImage();however, start here:
function loadIt() {
var preview = getElementsByTagName('img')[0],
setImage = function () {
preview_w = preview.width;
preview_h = preview.height;
console.log('dimensions: '+avatar_preview_w+' x '+avatar_preview_h);
},
imgReader = new FileReader();
imgReader.onloadstart = function(e) {};
imgReader.onload = function (imgReaderEvent) {
if (isImage()) {
preview.src = imgReaderEvent.target.result;
}
else {
preview.src = 'error.png';
};
};
imgReader.onloadend = function(e) {setImage();};
imgReader.readAsDataURL(document.getElementById('fileInput').files[0]); //read from file input
};
I need to find a way where I can dynamically change the source of a processing script inside an HTML document.
This is the embedded script which works fine:
<script type='application/processing' src='sketch.txt' id="applet">
</script>
Now I try to change the source:
$('#applet').attr('src', 'sketch2.txt');
alert($('#applet').attr('src'));
The alert shows that the source was changed to 'sketch2.txt' but the applet still remains the same. I think I need to refresh the script in some way.
Thank you in advance for any help!
I believe you have to manually attach each proc to the canvas, instead of just changing the the source file. This worked here:
function first_call(processing) {
processing.size(300,300);
processing.background(100);
var called = false;
processing.draw = function() {
if (!called) { processing.println("called #1"); called = true; }
}
}
function second_call(processing) {
processing.size(400,400);
processing.background(200);
var called = false;
processing.draw = function() {
if (!called) { processing.println("called #2"); called = true; }
}
}
var canvas = document.getElementById('canvas1');
var processingInstance = new Processing(canvas, first_call);
var processingInstance = new Processing(canvas, second_call);