Detect and notify when download is complete - javascript

Let's say I am having a drive link to download a zip file. When I click on the link, the download starts in the browser. Once the download is completed, I want to send an email to notify the user. Is it Possible. I have a .net application(C#) and a page that shows all the drive links. Once a drive link is clicked and gets downloaded completely, I want to send the mail. Also if the download fails in between, I want to send the failed email. Can I do that?

I have updated the below reference code. Add a proper download url link and try this out.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
body {
padding: 0;
margin: 0;
}
svg:not(:root) {
display: block;
}
.playable-code {
background-color: #f4f7f8;
border: none;
border-left: 6px solid #558abb;
border-width: medium medium medium 6px;
color: #4d4e53;
height: 100px;
width: 90%;
padding: 10px 10px 0;
}
.playable-canvas {
border: 1px solid #4d4e53;
border-radius: 2px;
}
.playable-buttons {
text-align: right;
width: 90%;
padding: 5px 10px 5px 26px;
}
</style>
<style type="text/css">
.event-log {
width: 25rem;
height: 4rem;
border: 1px solid black;
margin: .5rem;
padding: .2rem;
}
input {
width: 11rem;
margin: .5rem;
}
</style>
<title>XMLHttpRequest: progress event - Live_example - code sample</title>
</head>
<body>
<div class="controls">
<input class="xhr success" type="button" name="xhr" value="Click to start XHR (success)" />
<input class="xhr error" type="button" name="xhr" value="Click to start XHR (error)" />
<input class="xhr abort" type="button" name="xhr" value="Click to start XHR (abort)" />
</div>
<textarea readonly class="event-log"></textarea>
<script>
const xhrButtonSuccess = document.querySelector('.xhr.success');
const xhrButtonError = document.querySelector('.xhr.error');
const xhrButtonAbort = document.querySelector('.xhr.abort');
const log = document.querySelector('.event-log');
function handleEvent(e) {
if (e.type=='progress')
{log.textContent = log.textContent + `${e.type}: ${e.loaded} bytes transferred Received ${event.loaded} of ${event.total}\n`;
}
else if (e.type=='loadstart')
{
log.textContent = log.textContent + `${e.type}: started\n`;
}
else if (e.type=='error')
{
log.textContent = log.textContent + `${e.type}: error\n`;
}
else if (e.type=='loadend')
{
log.textContent = log.textContent + `${e.type}: completed\n`;
}
}
function addListeners(xhr) {
xhr.addEventListener('loadstart', handleEvent);
xhr.addEventListener('load', handleEvent);
xhr.addEventListener('loadend', handleEvent);
xhr.addEventListener('progress', handleEvent);
xhr.addEventListener('error', handleEvent);
xhr.addEventListener('abort', handleEvent);
}
function runXHR(url) {
log.textContent = '';
const xhr = new XMLHttpRequest();
var request = new XMLHttpRequest();
addListeners(request);
request.open('GET', url, true);
request.responseType = 'blob';
request.onload = function (e) {
var data = request.response;
var blobUrl = window.URL.createObjectURL(data);
var downloadLink = document.createElement('a');
downloadLink.href = blobUrl;
downloadLink.download ='download.zip';
downloadLink.click();
};
request.send();
return request
}
xhrButtonSuccess.addEventListener('click', () => {
runXHR('https://abbbbbc.com/download.zip');
});
xhrButtonError.addEventListener('click', () => {
runXHR('http://i-dont-exist');
});
xhrButtonAbort.addEventListener('click', () => {
runXHR('https://raw.githubusercontent.com/mdn/content/main/files/en-us/_wikihistory.json').abort();
});
</script>
</body>
</html>
The download link works for zip files as well.
Reference:https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/progress_event#live_example

Related

Record audio & video in browser

Hi i need to record audio and video content on frontend that is streamed to the browser from server
I've found some info about MediaStreams so i did it and it seems that i don't record my html video and audio output but a camera output
<audio id="audio" autoplay="true"></audio>
<video id="video" autoplay="true" playsinline="true" controls></video>
var constraints = {
audio: true,
video: true,
};
navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStreamObj) {
let start = document.getElementById('btnStart');
let stop = document.getElementById('btnStop');
let vidSave = document.getElementById('vid2');
let mediaRecorder = new MediaRecorder(mediaStreamObj);
let chunks = [];
start.addEventListener('click', (ev)=>{
mediaRecorder.start();
console.log(mediaRecorder.state);
})
stop.addEventListener('click', (ev)=>{
mediaRecorder.stop();
console.log(mediaRecorder.state);
});
mediaRecorder.ondataavailable = function(ev) {
chunks.push(ev.data);
}
mediaRecorder.onstop = (ev)=>{
let blob = new Blob(chunks, { 'type' : 'video/mp4;' });
chunks = [];
let videoURL = window.URL.createObjectURL(blob);
vidSave.src = videoURL;
}
})
.catch(function(err) {
console.log(err.name, err.message);
});
}
any help is appreciated because i want to do this in clean way but for now only option i see is to record whole browser window
Well, I'm guessing you're aiming for a webcam-like setup, so this works, on a server, keep in mind, you can't download video/audio unless you're hosting HTML through a server. It won't work while testing on a file though:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style type="text/css">
body {
padding: 0;
margin: 0;
}
svg:not(:root) {
display: block;
}
.playable-code {
background-color: #f4f7f8;
border: none;
border-left: 6px solid #558abb;
border-width: medium medium medium 6px;
color: #4d4e53;
height: 100px;
width: 90%;
padding: 10px 10px 0;
}
.playable-canvas {
border: 1px solid #4d4e53;
border-radius: 2px;
}
.playable-buttons {
text-align: right;
width: 90%;
padding: 5px 10px 5px 26px;
}
</style>
<style type="text/css">
body {
font: 14px "Open Sans", "Arial", sans-serif;
}
video {
margin-top: 2px;
border: 1px solid black;
}
.button {
cursor: pointer;
display: block;
width: 160px;
border: 1px solid black;
font-size: 16px;
text-align: center;
padding-top: 2px;
padding-bottom: 4px;
color: white;
background-color: darkgreen;
text-decoration: none;
}
h2 {
margin-bottom: 4px;
}
.left {
margin-right: 10px;
float: left;
width: 160px;
padding: 0px;
}
.right {
margin-left: 10px;
float: left;
width: 160px;
padding: 0px;
}
.bottom {
clear: both;
padding-top: 10px;
}
</style>
<title>Recording a media element - Example - code sample</title>
</head>
<body>
<p>Click the "Start" button to begin video recording for a few seconds. You can stop
the video by clicking the creatively-named "Stop" button. The "Download"
button will download the received data (although it's in a raw, unwrapped form
that isn't very useful).
</p>
<br>
<div class="left">
<div id="startButton" class="button">
Start
</div>
<h2>Preview</h2>
<video id="preview" width="160" height="120" autoplay muted></video>
</div>
<div class="right">
<div id="stopButton" class="button">
Stop
</div>
<h2>Recording</h2>
<video id="recording" width="160" height="120" controls></video>
<a id="downloadButton" class="button">
Download
</a>
</div>
<div class="bottom">
<pre id="log"></pre>
</div>
<script>
let preview = document.getElementById("preview");
let recording = document.getElementById("recording");
let startButton = document.getElementById("startButton");
let stopButton = document.getElementById("stopButton");
let downloadButton = document.getElementById("downloadButton");
let logElement = document.getElementById("log");
let recordingTimeMS = 5000;
function log(msg) {
logElement.innerHTML += msg + "\n";
}
function wait(delayInMS) {
return new Promise(resolve => setTimeout(resolve, delayInMS));
}
function startRecording(stream, lengthInMS) {
let recorder = new MediaRecorder(stream);
let data = [];
recorder.ondataavailable = event => data.push(event.data);
recorder.start();
log(recorder.state + " for " + (lengthInMS/1000) + " seconds...");
let stopped = new Promise((resolve, reject) => {
recorder.onstop = resolve;
recorder.onerror = event => reject(event.name);
});
let recorded = wait(lengthInMS).then(
() => recorder.state == "recording" && recorder.stop()
);
return Promise.all([
stopped,
recorded
])
.then(() => data);
}
function stop(stream) {
stream.getTracks().forEach(track => track.stop());
}
startButton.addEventListener("click", function() {
navigator.mediaDevices.getUserMedia({
video: true,
audio: true
}).then(stream => {
preview.srcObject = stream;
downloadButton.href = stream;
preview.captureStream = preview.captureStream || preview.mozCaptureStream;
return new Promise(resolve => preview.onplaying = resolve);
}).then(() => startRecording(preview.captureStream(), recordingTimeMS))
.then (recordedChunks => {
let recordedBlob = new Blob(recordedChunks, { type: "video/webm" });
recording.src = URL.createObjectURL(recordedBlob);
downloadButton.href = recording.src;
downloadButton.download = "RecordedVideo.webm";
log("Successfully recorded " + recordedBlob.size + " bytes of " +
recordedBlob.type + " media.");
})
.catch(log);
}, false);
stopButton.addEventListener("click", function() {
stop(preview.srcObject);
}, false);
</script>
</body>
</html>
This will work if you're hosting on a server, like I said, so assuming you are, this is your code. If you haven't setup a server yet, consider using Python and Flask, my personal favourites.
The above code is from MDN Web Docs by the way. This is where you can find the full tutorial and code: https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API/Recording_a_media_element.
Thanks and I hope this helps you, if not, please let me know!

Qr & Barcode Reader javascript documentation for html5

I want to make an input where it can be automatically filled in after scanning a QR or barcode scanner using a webcam or phone cam.
for the script I imagined something like this
<video autoplay = "true" id = "video-webcam">
</video>
<input type = "text" id = "scanresult">
<script>
external or internal script for scan qr or barcode. save result in variable = result
html DOM getElementById ('scanresult'). value (result);
</script>
I hope anyone can give me suggestions or feedback for my problem.
Thank you
Before it thank you for JaromandaX,
i have found script for barcode scanner on Html5 using webcam.
this is my index.html
<!DOCTYPE html>
<html>
<head>
<title>QR Code Scanner</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;" />
<link rel="stylesheet" href="style.css" />
<script src="https://rawgit.com/sitepoint-editors/jsqrcode/master/src/qr_packed.js"></script>
</head>
<body>
<div id="container">
<h1>QR Code Scanner</h1>
<a id="btn-scan-qr">
<img src="https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2017/07/1499401426qr_icon.svg">
<a/>
<canvas hidden="" id="qr-canvas"></canvas>
<div id="qr-result" hidden="">
<b>Data:</b> <span id="outputData"></span>
</div>
</div>
<script src="qrCodeScanner.js"></script>
</body>
</html>
qsCodeScanner.js
//const qrcode = window.qrcode;
const video = document.createElement("video");
const canvasElement = document.getElementById("qr-canvas");
const canvas = canvasElement.getContext("2d");
const qrResult = document.getElementById("qr-result");
const outputData = document.getElementById("outputData");
const btnScanQR = document.getElementById("btn-scan-qr");
let scanning = false;
qrcode.callback = res => {
if (res) {
outputData.innerText = res;
scanning = false;
video.srcObject.getTracks().forEach(track => {
track.stop();
});
qrResult.hidden = false;
canvasElement.hidden = true;
btnScanQR.hidden = false;
}
};
btnScanQR.onclick = () => {
navigator.mediaDevices
.getUserMedia({ video: { facingMode: "environment" } })
.then(function(stream) {
scanning = true;
qrResult.hidden = true;
btnScanQR.hidden = true;
canvasElement.hidden = false;
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreen
video.srcObject = stream;
video.play();
tick();
scan();
});
};
function tick() {
canvasElement.height = video.videoHeight;
canvasElement.width = video.videoWidth;
canvas.drawImage(video, 0, 0, canvasElement.width, canvasElement.height);
scanning && requestAnimationFrame(tick);
}
function scan() {
try {
qrcode.decode();
} catch (e) {
setTimeout(scan, 300);
}
}
style.css
html {
height: 100%;
}
body {
font-family: sans-serif;
padding: 0 10px;
height: 100%;
background: black;
margin: 0;
}
h1 {
color: white;
margin: 0;
padding: 15px;
}
#container {
text-align: center;
margin: 0;
}
#qr-canvas {
margin: auto;
width: calc(100% - 20px);
max-width: 400px;
}
#btn-scan-qr {
cursor: pointer;
}
#btn-scan-qr img {
height: 10em;
padding: 15px;
margin: 15px;
background: white;
}
#qr-result {
font-size: 1.2em;
margin: 20px auto;
padding: 20px;
max-width: 700px;
background-color: white;
}
There are lots of better libraries out there for doing this, but I'd personally recommend QrScanner because of its simplicity and intuitiveness.
Your live QrCode Scanner would be like this...
scanner.html
<div id="holder">
<h3>Scan QR Code from Camera</h3>
<div class="make">
<video id="scan"></video>
</div>
<div>
<input type = "text" id = "scanresult"><br>
<button id="start">Start</button>
<button id="stop">Stop</button>
</div>
</div>
Then add a little CSS as:
style.css
#holder{
width: 30%;
margin:auto;
}
#holder .make {
width: 99%;
height: 30vh;
margin-bottom: 15px;
text-align: center;
}
video {
width: 99%;
margin:auto;
}
Then add your QrScanner code as:
<script type="module">
import QrScanner from "/path/to/qr-scanner.min.js";
QrScanner.WORKER_PATH = "/path/to/qr-scanner-worker.min.js";
// Scanner Object
const scanner = new QrScanner(
document.getElementById("scan"),
function(result){
document.getElementById("scanresult").value = result;
}
);
document.getElementById("start").onclick = e => scanner.start();
document.getElementById("stop").onclick = e => scanner.stop();
</script>
Then connect your camera and click start button...

How can I make the speechRecognition and speechSynthesis API's work together?

I am currently working on an experiment using the Web Speech API. The idea is to use speech recognition and synthesis to improve the user's experience with HTML forms. Keep in mind that the code below is just a concept and has many issues. However, it seems that the speechRecognition API and the speechSynthesis API do not work well together. My desired result is that when an input or button receives focus, the label will be read using speechSynthesis and then it will listen to the user's answer using speechRecognition. That seems to be working as expected.
The issue is, that after the speechRecognition has started for the first time the speechSynthesis get's much lower in volume and somethings just fail (does not read). I have added some logic to abort the recognition on focus loss but this does not seem to work. Has anyone ever ran into this issue? Am I doing something wrong? Any help is welcome.
EDIT: StackOverflow does not ask for the user's mic permissions, please use this fiddle: https://jsfiddle.net/wzt0nfp3/ for a working demo.
const speechRecognition = !!window.SpeechRecognition || !!window.webkitSpeechRecognition ?
new(window.SpeechRecognition || window.webkitSpeechRecognition)() :
false;
const speechSynthesis =
"speechSynthesis" in window ? window.speechSynthesis : false;
if (!!speechRecognition && !!speechSynthesis) {
let voice = null;
speechRecognition.lang = "en-US";
speechRecognition.continuous = false;
speechRecognition.interimResults = false;
const state = {
speaking: false,
listening: false
};
function loadVoice() {
const voices = speechSynthesis.getVoices();
let defaultVoice = null;
let preferredVoice = null;
voices.forEach(voice => {
if (defaultVoice && preferredVoice) return;
if (voice.default) defaultVoice = voice;
if (voice.name.startsWith("Microsoft Jessa Online")) {
preferredVoice = voice;
}
});
voice = preferredVoice ? preferredVoice : defaultVoice;
}
loadVoice();
speechSynthesis.onvoiceschanged = loadVoice;
const abortRecognition = () => speechRecognition.abort();
const startRecognition = () => speechRecognition.start();
function speak(text) {
if (speechSynthesis.speaking) speechSynthesis.cancel();
if (text !== "") {
const utterThis = new SpeechSynthesisUtterance(text);
utterThis.lang = "en-US";
utterThis.voice = voice;
utterThis.volume = 1;
utterThis.pitch = 1;
utterThis.rate = 1;
utterThis.addEventListener("start", event => {
state.speaking = true;
console.log("Start Speaking.", state);
});
utterThis.addEventListener("error", event => {
state.speaking = false;
console.log("Error: " + event.error, state);
});
utterThis.addEventListener("end", event => {
startRecognition();
state.speaking = false;
console.log("Stop Speaking.", state);
});
speechSynthesis.speak(utterThis);
}
}
speechRecognition.addEventListener("start", event => {
state.listening = true;
console.log("Start Listening.", state);
});
speechRecognition.addEventListener("error", event => {
state.listening = false;
console.log("Error: " + event.error, state);
});
speechRecognition.addEventListener("end", event => {
state.listening = false;
console.log("Stop Listening.", state);
});
speechRecognition.addEventListener("result", event => {
if (typeof event.results === "undefined") return;
state.listening = false;
const capitalize = s => s.charAt(0).toUpperCase() + s.slice(1);
const transcript = capitalize(event.results[0][0].transcript.trim());
console.log("Transcript: " + transcript, state);
if (transcript !== "") {
const inputField = document.activeElement;
inputField.value = transcript;
}
});
document.querySelectorAll("input").forEach(input => {
input.addEventListener("blur", () => abortRecognition());
input.addEventListener("focus", e => {
speak(e.target.parentElement.textContent.trim());
});
});
document.querySelectorAll("textarea").forEach(textarea => {
textarea.addEventListener("blur", () => abortRecognition());
textarea.addEventListener("focus", e => {
speak(e.target.parentElement.textContent.trim());
});
});
document.querySelectorAll("button").forEach(button => {
button.addEventListener("blur", () => abortRecognition());
button.addEventListener("focus", e => {
speak(e.target.textContent.trim());
});
});
}
body {
font-family: sans-serif;
margin: 5% 0;
}
form {
display: flex;
flex-direction: column;
margin: 0 auto;
max-width: 600px;
width: 90%;
}
label {
align-items: center;
color: blue;
display: flex;
justify-content: space-between;
margin-bottom: 1em;
}
input,
textarea {
border: none;
border-bottom: 1px solid blue;
flex-grow: 1;
font-size: inherit;
margin-left: 1rem;
max-width: 350px;
padding: 0.5rem 0;
}
input:focus,
textarea:focus {
outline: none;
box-shadow: 0 1px 0 0 blue;
}
textarea {
resize: vertical;
}
button {
background-color: blue;
border-radius: 0;
border-radius: 3px;
border: none;
color: white;
font-size: inherit;
margin-top: 2rem;
padding: 0.75rem 5rem;
width: fit-content;
}
button:focus,
button:hover {
background-color: transparent;
border: 2px solid blue;
color: blue;
outline: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Web Speech API</title>
</head>
<body>
<form>
<label>My name is
<input type="text" placeholder="Your name" />
</label>
<label>My business is
<input type="text" placeholder="Company name" />
</label>
<label>You can email me at
<input type="email" placeholder="Email address" />
</label>
<label>You can call me at
<input type="tel" placeholder="Phone number" />
</label>
<label>My project is
<textarea rows="5" placeholder="Description of my project, budget, time constraints..."></textarea>
</label>
<button type="submit">Get in touch</button>
</form>
<script src="./index.js"></script>
</body>
</html>

How to save an Arduino code ".ino extension" from my webpage?

I have created a webpage to write an Arduino code and after that i would like to save the code on the pc, so i use new Blob to save the file and the extension is .ino,, but when i go to the created file i got these messages
Could not create the sketch
Failed to open sketch: 'direction for the file'
I would like to know How to save .ino file
var textToSaveAsBlob = new Blob([encodeURIComponent(arduinoSource)], {type:'data:text/ino;charset=utf-8,'});
var datenow = Date.now();
var fileNameToSaveAs = "arduino_code" +datenow+ ".ino";
saveAs(textToSaveAsBlob, fileNameToSaveAs);
You can use data URIs inside anchor element to generate your download. Browser support varies though, check out Wikipedia description.
For example, the following function takes in your filename and code and generates a download. The way it works is that it creates an anchor element in your DOM, defines charset and content type of your file, appends your code, launches a click event on the anchor element to generate download and then destroys the element.
function download(filename, code) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(code));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
I have written the following snippet to generate your required functionality, added a bit of Arduino style CSS as well. Hope it helps!
function download(filename, code) {
var element = document.createElement('a');
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(code));
element.setAttribute('download', filename);
element.style.display = 'none';
document.body.appendChild(element);
element.click();
document.body.removeChild(element);
}
var dateNow = Date.now();
var fileName = 'ArduinoCode';
document.getElementById("arduino-file-name").innerHTML = fileName;
document.getElementById("download-code").addEventListener("click", function() {
var arduinoCode = document.getElementById("arduino-code").value;
var fileNameFull = fileName + "-" + dateNow + ".ino";
download(fileNameFull, arduinoCode);
}, false);
.arduino-menu-bar {
background-color: #006468;
padding: 10px;
}
.arduino-menu-bar--footer {
display: block;
height: 10px;
background-color: #4db7bb;
}
#download-code {
border: none;
color: #4db7bb;
font-size: 30px;
cursor: pointer;
}
#download-code:hover {
color: #7ac4c7;
}
.arduino-files-bar {
background-color: #4db7bb;
padding: 5px 5px 0 5px;
}
.open-file-title {
background-color: #fff;
padding: 5px 15px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
display: inline-block;
color: #006468;
font-family: Arial, Helvetica, sans-serif;
}
#arduino-code {
font-family: 'Fira Code', monospace;
outline: none;
display: block;
width: 100%;
height: 250px;
border: 0px;
font-size: 14px;
resize: none;
}
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css">
<link href="https://fonts.googleapis.com/css?family=Fira+Code&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css">
<div class="arduino-code-container">
<div class="arduino-menu-bar">
<i id="download-code" class="fas fa-cloud-download-alt"></i>
</div>
<div class="arduino-files-bar">
<div id="arduino-file-name" class="open-file-title"></div>
</div>
<textarea id="arduino-code">
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
</textarea>
<div class="arduino-menu-bar arduino-menu-bar--footer"></div>
</div>

Ajax file downloads with same name

This is my Fiddle: https://jsfiddle.net/e6b5hdow/2/
const links = document.querySelectorAll('[href$=".jpg"], [href$=".png"], [href$=".mp4"], [href$=".avi"], [href$=".jpeg"], [href$=".mkv"], [href$=".csv"]');
links.forEach(link => link.classList.add('download-button'));
$('.name').prepend($("<div class='download-ui-container'><div class='start-download'>Starting Download..</div><div class='download-progress-container'><div class='download-progress'></div></div><a class='save-file'>Save File</a></div>"));
var _OBJECT_URL;
$(document).on('click', '.download-button', function(event) {
var request = new XMLHttpRequest();
fileDownload = $(this).attr('href');
var _t = $(this);
request.addEventListener('readystatechange', function(e) {
if (request.readyState == 2 && request.status == 200) {
_t.parents('td').find('.start-download').css('display', 'block');
_t.parents('td').find('.download-button').hide();
} else if (request.readyState == 3) {
_t.parents('td').find('.download-progress-container').css('display', 'block');
_t.parents('td').find('.start-download').hide()
} else if (request.readyState == 4) {
_OBJECT_URL = URL.createObjectURL(request.response);
var fileName = fileDownload.split("/")
fileName = fileName[fileName.length - 1]
var downloadLink = document.createElement('a');
console.log(downloadLink);
downloadLink.href = _OBJECT_URL;
downloadLink.download = fileName;
// document.body.appendChild(downloadLink);
downloadLink.click();
_t.parents('td').find('.download-button').css('display', 'block');
_t.parents('td').find('.download-progress-container').hide();
_t.parents('td').find('.save-file').click();
setTimeout(function() {
window.URL.revokeObjectURL(_OBJECT_URL);
_t.parents('td').find('.download-button').css('display', 'block');
_t.parents('td').find('.save-file').css('display', 'hide');
}, 60 * 1000);
}
});
request.addEventListener('progress', function(e) {
var percent_complete = (e.loaded / e.total) * 100;
_t.parents('td').find('.download-progress').css('width', percent_complete + '%');
});
request.responseType = 'blob';
request.open('get', fileDownload);
request.send();
return false;
});
.demo-container {
width: 400px;
margin: 60px auto;
}
.download-button {
background-color: white;
color: #2980b9;
border: 2px solid #2980b9;
font-family: inherit;
outline: none;
min-width: 100px;
padding: 10px;
font-size: inherit;
border-radius: 2px;
cursor: pointer;
display: block;
margin: 0 auto;
}
.start-download {
text-align: center;
display: none;
}
.download-progress-container {
border: 1px solid #cccccc;
padding: 4px;
display: none;
height: 20px;
}
.download-progress {
background-color: #2980b9;
display: inline-block;
height: 100%;
}
.save-file {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<table>
<tr>
<td class="name">
First link, large file
</td>
</tr>
<tr>
<br><br><br>
<td class="name">
Second link small file
</td>
</tr>
</table>
Here, I am trying to download the file using Ajax and show progress bar. It works perfectly but one problem.
If the first link file is big, and second link file is small.
Then if someone clicks on the first link and file starts downloading and
then immediately clicks on second link and file downloads because of small size, and first link file is still downloading.
After the first link click file is downloaded, it saves with the file with name of second file.
Reproducing steps:
Click on first link
Click on second link
If second link file downloads first, then the name of first link file is same as of second file link
I think, when I call the function again, the filename variable, it gets overwritten something.
Is it possible to use request header instead of filename?
Basically, what I need is.
A way to prevent the overwrite of variable name, when a function is called two times with different parameters, and the function called first time, takes longer to execute, and function called second time, executes within 1 sec.
just replace
fileDownload = $(this).attr('href');
with
var fileDownload = $(this).attr('href');
so that your variable is not considered global by javascript

Categories