Sharing xmlhttpObject 'progress' and 'load' Event handlers between two functions (no JQUERY) - javascript

I am uploading a video file using an API to a third party server.
I have an upload function vim.uploadVidFile which has 'progress' and 'load' event listeners. If there is internet connectivity loss, I have a second function which uploads the file from where the upload got disrupted, vim.resumeUpload. This functions shares the same 'progress' and 'load' event listeners.
The issue I have is that the 'progress', and 'load' event listeners are still registering the original size of the file to be uploaded rather than the new (originalFileSize - fileSizeAlreadyUploadedToServer). This affects my progress bar and the fact that instead of uploading from where I left off, it re-uploads the entire file again.
With reference to vim.uploadProgres I found that In the console:
console.log('ORIGINAL_e.total: '+ e.total) == console.log('adjusted_e.total: '+ e.total);
vim.uploadVidFile function:
vim.uploadVidFile = function(){
console.log('uploadVidFile()...');
// GET VIDEO FILE
var input = document.getElementById('vidInput');
var vidFile = input.files[0];
var xmh = new XMLHttpRequest;
// SET EVENT LISTENERS
xmh.upload.addEventListener('progress', vim.uploadProgres, false);
xmh.addEventListener('load', vim.uploadComplete, false);
xmh.addEventListener('error', vim.uploadError, false);
xmh.onreadystatechange = function(){
if(this.readyState == this.HEADERS_RECEIVED){
console.log('RESPONSE HEADERS: ' + xmh.getAllResponseHeaders());
}
}
xmh.open('PUT', vim.upload_link_secure);
xmh.send(vidFile);
}
vim.resumeUpload function:
vim.resumeUpload = function(stringArgument){
console.log('vim.resumeUpload() ...');
console.log('stringArgument: ' + stringArgument);
// GET VIDEO FILE
var input = document.getElementById('vidInput');
var vidFile = input.files[0];
var xmh = new XMLHttpRequest;
// SET EVENT LISTENERS
// SET EVENT LISTENERS
xmh.upload.addEventListener('progress', vim.uploadProgres, false);
xmh.addEventListener('load', vim.uploadComplete, false);
xmh.addEventListener('error', vim.uploadError, false);
xmh.onreadystatechange = function(){
if(xmh.readyState == xmh.HEADERS_RECEIVED){
console.log('VERIFY RESPONSE HEADERS222: ' + xmh.getAllResponseHeaders());
console.log('getResponseHeader(\'Content-Range\')222' + xmh.getResponseHeader("Range"));
}
}
xmh.open('PUT', vim.upload_link_secure);
xmh.setRequestHeader('Content-Range', stringArgument);
xmh.send(vidFile);
}
'progress' eventListener:
// vim.bytesUploaded - bytes already uploaded to the server
vim.uploadProgres = function(e){
console.log('bytesUploaded_CONSTANT: '+ vim.bytesUploaded);
if(vim.bytesUploaded == 0){
var percent = (e.loaded/e.total) * 100;
document.getElementById('span_fill').setAttribute('style', 'width: '+ percent + '%');
document.getElementById('p_status').innerHTML= Math.round(percent) + '%';
console.log('e.loaded: '+e.loaded);
console.log('e.total: '+e.total);
}else{
console.log('ORIGINAL_e.total: '+ e.total);
e.total = e.total - vim.bytesUploaded;
var percent = (e.loaded/e.total) * 100;
document.getElementById('span_fill').setAttribute('style', 'width: '+ percent + '%');
document.getElementById('p_status').innerHTML= Math.round(percent) + '%';
console.log('adjusted_e.total: '+ e.total);
console.log('uploadedFoFar: ' + uploadedFoFar);
}
}

Related

How to detect, that drawing a canvas object is finished?

I have following JS code (found here, on stackoverflow, and a little-bit modded), which resize image on client side using canvas.
function FileListItem(a) {
// Necesary to proper-work of CatchFile function (especially image-resizing).
// Code by Jimmy Wärting (https://github.com/jimmywarting)
a = [].slice.call(Array.isArray(a) ? a : arguments)
for (var c, b = c = a.length, d = !0; b-- && d;) d = a[b] instanceof File
if (!d) throw new TypeError('expected argument to FileList is File or array of File objects')
for (b = (new ClipboardEvent('')).clipboardData || new DataTransfer; c--;) b.items.add(a[c])
return b.files
}
function CatchFile(obj) {
// Based on ResizeImage function.
// Original code by Jimmy Wärting (https://github.com/jimmywarting)
var file = obj.files[0];
// Check that file is image (regex)
var imageReg = /[\/.](gif|jpg|jpeg|tiff|png|bmp)$/i;
if (!file) return
var uploadButtonsDiv = document.getElementById('upload_buttons_area');
// Check, that it is first uploaded file, or not
// If first, draw a div for showing status
var uploadStatusDiv = document.getElementById('upload_status_area');
if (!uploadStatusDiv) {
var uploadStatusDiv = document.createElement('div');
uploadStatusDiv.setAttribute('class', 'upload-status-area');
uploadStatusDiv.setAttribute('id', 'upload_status_area');
uploadButtonsDiv.parentNode.insertBefore(uploadStatusDiv, uploadButtonsDiv.nextSibling);
// Draw sub-div for each input field
var i;
for (i = 0; i < 3; i++) {
var uploadStatus = document.createElement('div');
uploadStatus.setAttribute('class', 'upload-status');
uploadStatus.setAttribute('id', ('upload_status_id_commentfile_set-' + i + '-file'));
uploadStatusDiv.append(uploadStatus);
}
}
var canvasDiv = document.getElementById('canvas-area');
var currField = document.getElementById(obj.id);
var currFieldLabel = document.getElementById(('label_' + obj.id));
// Main image-converting procedure
if (imageReg.test(file.name)) {
file.image().then(img => {
const canvas = document.createElement('canvas')
canvas.setAttribute('id', ('canvas_' + obj.id));
const ctx = canvas.getContext('2d')
const maxWidth = 1600
const maxHeight = 1200
// Calculate new size
const ratio = Math.min(maxWidth / img.width, maxHeight / img.height)
const width = img.width * ratio + .5|0
const height = img.height * ratio + .5|0
// Resize the canvas to the new dimensions
canvas.width = width
canvas.height = height
// Drawing canvas-object is necessary to proper-work
// on mobile browsers.
// In this case, canvas is inserted to hidden div (display: none)
ctx.drawImage(img, 0, 0, width, height)
canvasDiv.appendChild(canvas)
// Get the binary (aka blob)
canvas.toBlob(blob => {
const resizedFile = new File([blob], file.name, file)
const fileList = new FileListItem(resizedFile)
// Temporary remove event listener since
// assigning a new filelist to the input
// will trigger a new change event...
obj.onchange = null
obj.files = fileList
obj.onchange = CatchFile
}, 'image/jpeg', 0.70)
}
)
// If file is image, during conversion show status
function ShowConvertConfirmation() {
if (document.getElementById('canvas_' + obj.id)) {
document.getElementById(('upload_status_' + obj.id)).innerHTML =
'<font color="#4CAF50">Konwertowanie pliku ' + file.name + ' zakończone!</font>';
return true;
}
else {
document.getElementById(('upload_status_' + obj.id)).innerHTML =
'<font color="#4CAF50">Konwertowanie pliku ' + file.name + ' zakończone!</font>';
return false;
}
}
// Loop ShowConvertConfirmation function untill return true (file is converted)
var convertConfirmationLoop = setInterval(function() {
var isConfirmed = ShowConvertConfirmation();
if (!isConfirmed) {
ShowConvertConfirmation();
}
else {
// Break loop
clearInterval(convertConfirmationLoop);
}
}, 2000); // Check every 2000ms
}
// If file is not an image, show status with filename
else {
document.getElementById(('upload_status_' + obj.id)).innerHTML =
'<font color="#4CAF50">Dodano plik ' + file.name + '</font>';
//uploadStatusDiv.append(uploadStatus);
}
}
Canvas is drawn in hidden div:
<div id="canvas-area" style="overflow: hidden; height: 0;"></div>
I am only detect, that div canvas-area is presented and basing on this, JS append another div with status.
Unfortunatelly on some mobile devices (mid-range smartphones), message will be showed before finish of drawing (it is wrong). Due to this, some uploaded images are corrupted or stay in original size.
How to prevent this?
Everything that should happen after the image has loaded, should be executed within the then callback, or called from within it.
It is important to realise that the code that is not within that callback will execute immediately, well before the drawing has completed.

using the result of a file selected by the user inside a script

I am trying to use the name of a file selected by a user inside a script. If I have a input form element as:
<input id="browse" type="file" name="image_field"/>
and my script as:
function getVideoDimensionsOf(url){
return new Promise(function(resolve){
// create the video element
video = document.createElement('video');
// place a listener on it
video.addEventListener( "loadedmetadata", function () {
// retrieve dimensions
height = this.videoHeight;
width = this.videoWidth;
// send back result
resolve({
height : height,
width : width
});
}, false );
// start download meta-datas
video.src = url;
});
}
getVideoDimensionsOf("http://clips.vorwaerts-gmbh.de/VfE_html5.mp4")
.then(function(dimensions){
console.log("Video width: " + dimensions.width) ;
console.log("Video height: " + dimensions.height) ;
alert("Video width: " + dimensions.width + " Video height: " + dimensions.height);
});
What do I have to do to use the content of id="browse" to replace "http://clips.vorwaerts-gmbh.de/VfE_html5.mp4"
Many thanks in advance for your time.
You can use an object URL for this via createObjectURL:
video.src = URL.createObjectURL(document.getElementById("browse").files[0]);
It's best to revoke it when you're done with it (perhaps in your loadedmetadata callback):
URL.revokeObjectURL(video.src);
Check this:
function getVideoDimensionsOf(url){
return new Promise(function(resolve){
// create the video element
video = document.createElement('video');
// place a listener on it
video.addEventListener( "loadedmetadata", function () {
// retrieve dimensions
height = this.videoHeight;
width = this.videoWidth;
// send back result
resolve({
height : height,
width : width
});
}, false );
// start download meta-datas
video.src = url;
});
}
const inputElement = document.getElementById("browse");
inputElement.addEventListener("change", handleFiles, false);
function handleFiles() {
const fileList = this.files;
console.log(this.files[0].name);
getVideoDimensionsOf(URL.createObjectURL(this.files[0]))
.then(function(dimensions){
console.log("Video width: " + dimensions.width) ;
console.log("Video height: " + dimensions.height) ;
alert("Video width: " + dimensions.width + " Video height: " + dimensions.height);
});
}
https://jsfiddle.net/ch14trm0/1/

Can ajax give me the data size on the URL?

I'v been using the progress event, and b.c. it can track this, I was wondering if the xjr object has access to the total data size in KB or MB or similar?
FYI here is my code
var container = Pub.el('#super-1');
if (container) {
xhr.addEventListener("progress", function(evt){
if (evt.lengthComputable) {
// Pub.log(config_ajax.url);
var percent = ( evt.loaded / evt.total ) * 100;
var exists = document.getElementById(config_ajax.url)
if(exists){
Pub.log('div exists');
exists.style.width = percent + '%';
} else {
Pub.log('div created');
var div = document.createElement('div');
div.id=config_ajax.url;
div.style.width = percent + '%';
div.style.height = '5px';
div.style.background = 'rgba(255,255,255,0.2)';
div.style.borderBottom = '1px solid white';
container.appendChild(div);
}
}
}, false);
}
return xhr;
};
Servers may provide the length of content in the optional content-length header. You can read it, if available with getResponseHeader.

Prevent drag and drop on captions

the hosting company loads a script on all their sites that is allowing for the tabs to be dragged/dropped , however it is also causing the caption images within the same body_home page to be drag/drop , i have requested this be fixed but i don't think they are concerned.
I am permitted to load my own jquery, javascript , html ,css onto the site to do changes , but i can not stop the host from loading this js file , so how can i reverse this ? Here is a snippet of the portion of the js file i think that is causing this problem .
I am permitted to load my own footer and header messages , so is there anyway i can remove what they are doing here , or reverse the effect on the captions ?
i cant find a way for the listener to be removed from outside.
They have used an anonymous function on the event 'domready' .
Does javascript have a feature to remove the listener from outside the anonymous method
window.onload=function() {
if (document.getElementById("body_home")) {
set_up_double_click_events();
if (document.getElementById("homepagetabs") && document.getElementById("tab2")) {
new Sortables($('homepagetabs'), {
onComplete: function() {
var parent = this.element.parentNode;
var saveIt = false;
if (typeof currentTabOrder == "undefined") {
currentTabOrder = new Array();
for (var i = 0; i < parent.getChildren().length; i++) {
currentTabOrder[i] = i;
}
}
for (var i = 0; i < parent.getChildren().length; i++) {
var seqno = parent.getChildren()[i].id.substr("tab".length);
if (currentTabOrder[i] != seqno) {
saveIt = true;
currentTabOrder[i] = seqno;
}
}
if (saveIt) {
var url = window.location.protocol + "//" + window.location.host + "/" + year + "/save_setting?L=" + league_id + "&TITLE=TABORDER&VALUE=" + currentTabOrder.join();
makeHttpRequest(url);
}
}
});
}
window.addEvent('domready', function() {
new Sortables('.homepagemodule CAPTION', {
clone: true,
revert: true,
opacity: 0.7,
onStart: function() {
dndMovingModule = this.element.parentNode.parentNode.id.toUpperCase();
},
onComplete: function() {
dndDroppedOntoModule = this.element.parentNode.parentNode.id.toUpperCase();
if (typeof dndMovingModule != "undefined" && typeof dndDroppedOntoModule != "undefined" && dndMovingModule != dndDroppedOntoModule) {
var url = window.location.protocol + "//" + window.location.host + "/" + year + "/save_setting?L=" + league_id + "&TITLE=MODULE&VALUE=" + dndMovingModule + "," + dndDroppedOntoModule;
// alert("calling: " + url);
makeHttpRequest(url);
setTimeout("window.location.reload();", 250);
}
}
});
});
}
}
$(document).ready(function() {
$('#DIVID').on('mousedown', function(e) {
return false;
});
});
I would put an HTML class attribute on all of your images that are producing the problem. Obviously, jQuery uses CSS style selectors. See the following example.
$(function(){
$('.ElementClass').mousedown(function(){
return false;
});
});
When you return false; onmousedown it prevents the default behavior in most Browsers, which is to grab the image so the Client can drop and drag the image into into a new tab or window to view it with their Browser.

Filereader and Socket.io uploader: subsequent uploads include previous uploads

I'm trying to implement a file uploader in html5/js and node that uploads large files in chunks. It works great for a single upload. But when I try and upload again on the same page, it goes into an infinite loop where it looks like it's trying to reupload the previous upload and the new file at once.
Client.js
$('input').change(function() {
var file = this.files[0]
var fileSize = file.size
var fileName = file.name
// file size gate:
var fileSizeLimit = 15000000 // ~15mb
if (fileSize <= fileSizeLimit) {
// get preview blob
var windowURL = window.URL || window.webkitURL
var blobURL = windowURL.createObjectURL(this.files[0])
// render preview image
// render status progress
// set progress to 0
// read the file to server:
var reader = new FileReader()
console.log('new filereader init')
socket.emit('startSend', fileName, fileSize, entryID)
console.log('startSend emitted now for ' + fileName)
reader.onload = function(event) {
var data = event.target.result
console.log('reader onload for ' + fileName)
socket.emit('sendPiece', data, fileName, fileSize, entryID)
}
socket.on('morePlease', function (place, entryID, percent){
progressUpdate(percent)
var chunkSize = 262144
var startPlace = place * chunkSize // The newBlock's Starting Position
var newBlock = file.slice(startPlace, startPlace + Math.min(chunkSize, (fileSize-startPlace)))
reader.readAsBinaryString(newBlock) // triggers reader onload
})
function progressUpdate(percent){
console.log('current percent is: ' + percent + '%')
$('.sendfile .progress').val(percent).text(percent + '%')
}
socket.on('sendSuccessful', function(entryID){
console.log('sendSuccessful triggered for ' + entryID + '. File should be in temp folder.')
$('.status .sendfile').addClass('hidden')
$('.status .savetext').removeClass('hidden')
$('.status .saved').removeClass('hidden')
$('.sendfile .progress').val(0).text('0%')
})
} else {
// file size is too big
}
}) // close input onchange event
Server.js
// start file upload
var chunkSize = 262144
socket.on('startSend', function(fileName, fileSize, entryID) {
var files = {}
console.log('startSend hit for ' + fileName)
files[fileName] = { // create new entry in files {}
fileSize : fileSize,
data : '',
downloaded : 0
}
var fileWriting = files[fileName]
var tempPath = 'temp/' + entryID + '-' + fileName
var place = 0 // stores where in the file we are up to
console.log('place: in startSend, the place for ' + fileName + ' is ' + place) //
try{
var stat = fs.statSync(tempPath)
if(stat.isFile())
{
fileWriting['downloaded'] = stat.size
place = stat.size / chunkSize; // we're passing data in 1/4 mb increments
console.log('downloaded: ' + stat.size)
}
}
catch(er){} // it's a new file
fs.open(tempPath, "a", 0755, function(err, fd){
if(err)
{
console.log(err)
}
else // requesting
{
fileWriting['handler'] = fd //We store the file handler so we can write to it later
var percent = 0
socket.emit('morePlease', place, entryID, percent) // requesting more file pieces
}
})
// processing the file pieces from client
socket.on('sendPiece', function(data, fileName, fileSize, entryID) {
console.log('sendPiece hit for ' + entryID + ' ' + fileName)
fileWriting['downloaded'] += data.length
fileWriting['data'] += data
if(fileWriting['downloaded'] == fileWriting['fileSize']) { // If File is Fully Uploaded
fs.write(fileWriting['handler'], fileWriting['data'], null, 'Binary', function(err, Writen){
console.log('file ' + entryID + 'has been written to temp folder: ' + fileName)
socket.emit('sendSuccessful', entryID)
})
}
else if(fileWriting['data'].length > 10485760){ //If the Data Buffer reaches 10MB
fs.write(fileWriting['handler'], fileWriting['data'], null, 'Binary', function(err, Writen){
fileWriting['data'] = ""; //Reset The Buffer
var place = fileWriting['downloaded'] / chunkSize
var percent = (fileWriting['downloaded'] / fileWriting['fileSize']) * 100
socket.emit('MorePlease', place, entryID, percent) // requesting more file pieces
})
}
else { // need more file pieces
var place = fileWriting['downloaded'] / chunkSize
console.log('MorePlease: ' + fileName + ' pieces needed at place ' + place + ' and percent ' + percent)
var percent = (fileWriting['downloaded'] / fileWriting['fileSize']) * 100
socket.emit('morePlease', place, entryID, percent) // requesting more file pieces
}
})
}) // close startSend
server log: Here's the node log based on the console.logs scattered throughout:
uploading the first file goes fine:
startSend hit for file1.jpeg
place: in startSend, the place for file1.jpeg is 0
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
file 52a530f8649b5db8b2000001has been written to temp folder: file1.jpeg
and for the subsequent file:
startSend hit for file2.JPG
place: in startSend, the place for file2.JPG is 0
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
MorePlease: file1.jpeg pieces needed at place 1.9332275390625 and percent undefined
sendPiece hit for 52a530f8649b5db8b2000001 file1.jpeg
MorePlease: file1.jpeg pieces needed at place 0.96661376953125 and percent undefined
sendPiece hit for 52a530f8649b5db8b2000001 file2.JPG
MorePlease: file2.JPG pieces needed at place 2.6120567321777344 and percent undefined
... infinite loop.
webinspector messages:
reader onload for file1.jpeg (client.js, line 260)
reader onload for file2.JPG (client.js, line 260)
current percent is: 270.227552566774% (client.js, line 273, x2)
current percent is: 242.3942545981759% (client.js, line 273)
InvalidStateError: DOM Exception 11: An attempt was made to use an object that is not, or is no longer, usable.
... infinite loop
I've been racking my brain on this for hours , trying to step through the code on my own. I'm not a developer by trade so any help would be super appreciated!
I never use Socket for file uploading with Node.js. Basically, http does an excellent job. This is example code:
var http = require('http'),
fs = require('fs');
var server = http.createServer();
server.listen(8080);
console.log('Start is started on port 8080');
server.on('request', function(req, res) {
var file = fs.createWriteStream('sample.jpg');
var fileSize = req.headers['content-length'];
var uploadedSize = 0;
req.on('data', function (chunk) {
uploadedSize += chunk.length;
var buffer = file.write(chunk);
if(buffer == false)
req.pause();
});
file.on('drain', function() {
req.resume();
});
req.on('end', function() {
res.write('File uploading is completed!!');
res.end();
});
});
If you want to notify the client about progress uploading, you can add some logic in the data event.
By the way, I've found that someone already asked the same question and get the answer. The answer posted a link to a tutorial. I've checked and think that it is a solution that you are looking for. Check this Node.js file upload capabilities: Large Video Files Uploading with support for interruption!

Categories

Resources