I'm currently writing a little program that generates an html file and opens it with the default browser to start multiple downloads.
I don't want to open a tab/window for every download, so creating hidden iframes for the downloads seemed like a good solution.
I'm using onload on the iframes to find out if the download prompts for each download have shown up yet. This approach seems to be very unreliable in the Internet Explorer though.
So I'm wondering if there is there a way to fix this or maybe a better approach?
(Without libraries please.)
Here is my html/js code:
<!DOCTYPE html>
<!-- saved from url=(0016)http://localhost -->
<html><head>
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta content="utf-8" http-equiv="encoding">
<title>Downloads</title>
<script>
"use strict";
var downloadsInfo = {
"http://download-installer.cdn.mozilla.net/pub/firefox/releases/26.0/win32/en-US/Firefox%20Setup%2026.0.exe":"Status: Connecting",
"http://download.piriform.com/ccsetup410.exe":"Status: Connecting"
};
var i = 0;
var iv = setInterval(function() {
i = ++i % 4;
var j = 0;
var finished = true;
for (var key in downloadsInfo) {
var value = downloadsInfo[key];
if (value != "Status: Download Started!") {
value = value+Array(i+1).join(".");
finished = false;
}
document.getElementsByTagName("div")[j].innerHTML = key+"<br/>"+value;
j = j+1;
}
if (finished) {
alert('Done! You can close this window/tab now.');
clearInterval(iv);
}
}, 800);
</script>
</head><body>
<h3>Please wait for your downloads to start and do not reload this site.</h3>
<div></div> <br/><br/>
<div></div> <br/><br/>
<iframe src="http://download-installer.cdn.mozilla.net/pub/firefox/releases/26.0/win32/en-US/Firefox%20Setup%2026.0.exe" onload="downloadsInfo['http://download-installer.cdn.mozilla.net/pub/firefox/releases/26.0/win32/en-US/Firefox%20Setup%2026.0.exe'] = 'Status: Download Started!';" style="display:none"></iframe>
<iframe src="http://download.piriform.com/ccsetup410.exe" onload="downloadsInfo['http://download.piriform.com/ccsetup410.exe'] = 'Status: Download Started!';" style="display:none"></iframe>
</body></html>
Quite simply you can't know whether a native browser download started. Every browser has different ways this is handled, the user may set up his browser to prompt the location or he might just let it auto download to the Downloads folder (the default in most browsers nowadays). If he's prompting for a location he might cancel by mistake, yet your setup would still claim the download started. So, no, there is no way whatsoever to reliably inform the user that they can close a tab once all downloads are started/finished... provided that you use the native browser download mechanism.
The way to achieve this effect would be possibly by first downloading the file using Javascript (requiring you to have access to those files, hotlinking to third party files is of course not an option then). To see this in action try downloading a file from mega.nz. I was planning on writing up how to do this by hand, but there is already a nice (quite outdated) answer outlining this.
If the intention is only to ensure that the download has started you could implement a trigger on the back end to note when the file has been accessed. In it's simplest form this would look like:
Page download.html requests file.php?location=[...]&randomHash=1234
Once file.php is actually loaded it will set a flag in memory or the database that randomHash id 1234 has started.
file.php redirects the page with a 302 header to the actual file location.
download.html checks periodically using Ajax whether flag randomHash=1234 has been raised. If so it knows the download has started.
Indeed IE is reported to not always behave nicely with the onload event handler of iframes. There is an active bug tracker record opened.
The problem is discussed in a number of places around the web, and what seems to be the most reliable solution is to have an indirect download with nested iframes: the iframe loads a HTML file with an iframe that loads the file to download. The reason for that is that IE does not seem to like iframes that point to something else than HTML. So if you have the possibility to do that in your program:
For each file to download, generate a HTML file with a body that looks like this:
<iframe src="http://filetodownload.exe" style="display:none"></iframe>
Store this file in a temporary folder, e.g. C:\tmp\filetodownload.html
In your "master" generated HTML file, replace the iframe source with this intermediate file:
<iframe src="C:\tmp\filetodownload.html"
onload="downloadsInfo['http://filetodownload.exe']='Status: Download Started!';"
style="display:none"></iframe>
That may do the trick. But following IE's tradition, this could or could not work depending on the case...
If it does not work, some solutions that have proved useful include:
Put the onload handler in a function, and write in the definition of the iframe: onload="return theonloadfunction()" (even if the function does not return anything)
Instead of using the onload attribute, attach the event handler in javascript, like so:
iframe = document.getElementById("theiframeid")
iframe.attachEvent("onload", theonloadfunction);`
Note that attachEvent is for IE only. If you want to support other browsers you will have to detect it and use addEventListener for the non-IE cases.
Finally, you may try combinations of two or more of these solutions :)
<html>
<head>
<meta content = 'text/html;charset=utf-8' http-equiv = 'Content-Type'>
<meta content = 'utf-8' http-equiv = 'encoding'>
<script>
/*
First, I removed the setInterval(). Since you rely on the onload property we can aswell just check it on each onload.
Second, I changed your downloadsInfo to an object array.
Also be aware while testing, that some browsers cache your cancel/block choice and do not reask again for the same url.
Additionally firefox does not fire on frame downloads.
Furthermore the alert in your test might not show for overlapping or setting reasons.
*/
var downloadsInfo = [
{url: "http://download-installer.cdn.mozilla.net/pub/firefox/releases/26.0/win32/en-US/Firefox%20Setup%2026.0.exe", Status: "Connecting"},
{url: "http://download.piriform.com/ccsetup410.exe", Status: "Connecting"}
];
//IE has a problem in sometimes merely firing the onload propery once, which we bypass by dynamically creating them
//It is also less limited.
function iframeConnect(){
for(var i=0, j=downloadsInfo.length; i<j; i++){
var tF = document.createElement('iframe');
tF.arrayIndex = i; //For convenience
tF.style.display = 'none';
//Normal load event, working in ie8-11, chrome, safari
tF.onload = function(){
iframeExecuted(this.arrayIndex);
};
//Workaround for firefox, opera and some ie9
tF.addEventListener('DOMSubtreeModified', function(){
iframeExecuted(this.arrayIndex);
}, false);
document.body.appendChild(tF);
tF.src = downloadsInfo[i].url;
}
}
function iframeExecuted(i){
downloadsInfo[i].Status = 'Executed';
var tStatus = iframeFinished();
var tE = document.querySelector('h3');
if (tStatus.Done) tE.innerHTML = 'Finished'
else tE.innerHTML = 'Processed ' + tStatus.Processed + ' of ' + tStatus.Started;
}
function iframeFinished(){
for(var i=0, j=downloadsInfo.length; i<j; i++){
if (downloadsInfo[i].Status != 'Executed') break;
}
//Note that the Processed value is not accurate, yet it solves is testing purpose.
return {Done: (i == j), Processed: i, Started: j}
}
</script>
</head>
<body onload = 'iframeConnect()'>
<h3>Please wait for your downloads to start and do not reload this site.</h3>
</body>
</html>
Related
I want to add data to the current webpage with jQuery before I print the webpage. The reason is that I have a digital CV on my website and don't want to have my personal information on the website available to crawlers etc. I created an XHR request to get my personal information before printing and want to inject the data into HTML.
I found this script to find out with jQuery when a user is printing. This works fine in general but the problem is that the script works "too slow", meaning that the data will not be appended before the print dialogue pops up. This is my HTML code:
<div>
<span id="cvnameplaceholder">My Name</span><br />
<span id="cvstreetplaceholder"></span><br />
<span id="cvcityplaceholder"></span><br /><br />
<span id="cvemailplaceholder"></span>
</div>
And this is the jQuery code which returns an array like {street: 'ABC', city: 'DEF', email: 'mail#example.com}
$(document).ready(function() {
var beforePrint = function() {
$.post("./api/RequestHandler.php", {request : "getCVInformation"}, function (response) {
response = JSON.parse(response);
$('#cvstreetplaceholder').text(response.street);
$('#cvcityplaceholder').text(response.city);
$('#cvemailplaceholder').text(response.email);
})
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
beforePrint();
}
});
}
window.onbeforeprint = beforePrint;
}());
When I hit the print button a second time, the information is there. So is there any possibility to add some text before showing the actual print dialogue?
A good number of crawlers now also either parse the js, or execute it and parse the result, so this may not keep your info private.
That said, it looks as though your problem is that you're not stopping the event, you're just hooking into it. The event listener is calling beforePrint, but it's not stopping anything else from also triggering on that event - in this case, the actual print dialog.
Additionally, you're loading the data via an ajax request, which is asynch. If you were somehow storing the data in a local javascript variable and populating the page, you might get lucky and have the text loaded in before the print dialog actually opened. But you're running into the same kind of problem that's mentioned on the page linked from that other answer, https://www.tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/ , where someone had a mix of low and high-res images actually printing. That is, the ajax request is sent before the print event bubbles up and triggers the print dialog, but the response is coming back after the browser's already rendered the page for printing.
You need to use stop the event from propagating (https://api.jquery.com/event.stoppropagation/ ), then re-trigger the print event within the post's callback, after you actually have the info. That's why you're seeing the info in there that second time; it's actually the info you loaded the first time that you're seeing.
Here's an example of catching and blocking the event, then re-triggering it after your data's arrived and been loaded:
$(document).ready(function() {
var beforePrint = function(e) {
e.stopPropagation();
$.post("./api/RequestHandler.php", {request : "getCVInformation"}, function (response) {
response = JSON.parse(response);
$('#cvstreetplaceholder').text(response.street);
$('#cvcityplaceholder').text(response.city);
$('#cvemailplaceholder').text(response.email);
window.print();
});
};
if (window.matchMedia) {
window.matchMedia('print').addListener(function(mql) {
if (mql.matches) {
beforePrint();
}
});
}
window.onbeforeprint = beforePrint;
}());
It's worth noting, though, that as mentioned on that linked page, the onbeforeprint event is IE5+ and Firefox 6+, window.matchMedia is Chrome 9+ and Safari 5.1, while Opera doesn't support either, and both seem to have various unsolved issues. So you very well might still end up with a printed CV that's lacking your contact info.
I know this does not directly answer the question, but you could iframe in your CV content and use nofollow/noindex to prevent indexing. This solution deals with appending content, but it does not use jQuery.
index.html
<html>
<head>
<style>
iframe {
border: none;
}
.cv {
display: none;
}
#media print {
.cv {
display: block;
}
}
</style>
</head>
<div class="cv">
<iframe src="cv.html"></iframe>
</div>
</html>
cv.html
<html>
<head>
<meta name="robots" content="noindex,nofollow">
</head>
<body>
My CV Details
</body>
</html>
Is there a working example how you can use the zxing Barcode Scanner from a web page?
Referring to this documentation:
https://github.com/zxing/zxing/wiki/Scanning-From-Web-Pages
shouldn't the following test code work?
function Test1()
{
$.ajax(
{
url: "zxing://scan/?ret=http%3A%2F%2Ffoo.com%2Fproducts%2F%7BCODE%7D%2Fdescription&SCAN_FORMATS=UPC_A,EAN_13",
success:function()
{
alert("success");
},
error:function()
{
alert("error");
}
});
}
function Test2()
{
$.ajax(
{
url: "http://zxing.appspot.com/scan?ret=http%3A%2F%2Ffoo.com%2Fproducts%2F%7BCODE%7D%2Fdescription&SCAN_FORMATS=UPC_A,EAN_13",
success:function()
{
alert("success");
},
error:function()
{
alert("error");
}
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button id="button1" onClick="Test1();">Test 1</button>
<br>
<br>
<button id="button2" onClick="Test2();">Test 2</button>
I keep getting "error" on my Android 4.4.2 Samsung Galaxy TabPro and Samsung Galaxy S4.
I've tried the stock browser, Chrome, Firefox and Dolphin Browser.
Even http://zxing.appspot.com/scan doesn't work as it always asks me to install the (already installed) app.
Any help would be much appreciated.
ZXing isn't designed to work with AJAX. Instead, it works by opening a parsed URL in the default browser. The behavior of the browser is mainly what's responsible for the user experience from that point forward.
There are several methods posted regarding this; unfortunately, there is no one method that will work for every browser.
Some browsers, when you open them from the command line, will check to see if the URL is already opened in another tab, and if so, will use that tab instead of a new one. This will cause a "onhashchange" event if the zxing link contains "zxing://scan/?ret=mytab.html#{CODE}".
Other browsers don't perform such a check, so we wind up with multiple tabs, all having the same URL (with the exception of the hash), and none of them raising the "hashchanged" event. For those browsers, we need to re-use the page from cache if possible (to prevent network traffic on every scan), and change the localStorage value to what the hash is. If the browser is capable of listening for the "storage" event, we can use that to trigger the code.
The code below works with Chrome, the intrinsic Android browser, and Firefox. It might work with others, but I haven't tried. One Firefox caveat, though, is that the scanner window will only close if the about:config setting "dom.allow_scripts_to_close_windows" is set to "true".
** This was edited to work better with multiple pages that allow scans, and now you can use have different hashes without interfering with the code. **
NEW VERSION 12/19/16
<!DOCTYPE html>
<HTML>
<HEAD>
<script type="text/javascript">
if(window.location.hash.substr(1,2) == "zx"){
var bc = window.location.hash.substr(3);
localStorage["barcode"] = decodeURI(window.location.hash.substr(3))
window.close();
self.close();
window.location.href = "about:blank";//In case self.close isn't allowed
}
</script>
<SCRIPT type="text/javascript" >
var changingHash = false;
function onbarcode(event){
switch(event.type){
case "hashchange":{
if(changingHash == true){
return;
}
var hash = window.location.hash;
if(hash.substr(0,3) == "#zx"){
hash = window.location.hash.substr(3);
changingHash = true;
window.location.hash = event.oldURL.split("\#")[1] || ""
changingHash = false;
processBarcode(hash);
}
break;
}
case "storage":{
window.focus();
if(event.key == "barcode"){
window.removeEventListener("storage", onbarcode, false);
processBarcode(event.newValue);
}
break;
}
default:{
console.log(event)
break;
}
}
}
window.addEventListener("hashchange", onbarcode, false);
function getScan(){
var href = window.location.href;
var ptr = href.lastIndexOf("#");
if(ptr>0){
href = href.substr(0,ptr);
}
window.addEventListener("storage", onbarcode, false);
setTimeout('window.removeEventListener("storage", onbarcode, false)', 15000);
localStorage.removeItem("barcode");
//window.open (href + "#zx" + new Date().toString());
if(navigator.userAgent.match(/Firefox/i)){
//Used for Firefox. If Chrome uses this, it raises the "hashchanged" event only.
window.location.href = ("zxing://scan/?ret=" + encodeURIComponent(href + "#zx{CODE}"));
}else{
//Used for Chrome. If Firefox uses this, it leaves the scan window open.
window.open ("zxing://scan/?ret=" + encodeURIComponent(href + "#zx{CODE}"));
}
}
function processBarcode(bc){
document.getElementById("scans").innerHTML += "<div>" + bc + "</div>";
//put your code in place of the line above.
}
</SCRIPT>
<META name="viewport" content="width=device-width, initial-scale=1" />
</HEAD>
<BODY>
<INPUT id=barcode type=text >
<INPUT style="width:100px;height:100px" type=button value="Scan" onclick="getScan();">
<div id="scans"></div>
</BODY>
</HTML>
You can make a JS include file for the top block of script, and include it on all the pages where you need scanning capabilities.
Then in the body of your document, you can set an event somewhere to call getZxing(), which will call processBarcode(barcode) that you write into your page. Included is a simple one for example's sake.
Side Note: The first time you run zxing from your page, you'll be asked to choose a default app. Make sure you chose the same browser that you're running the page from. Additionally, if you previously selected a default broswer for zxing and want to change which browser you use for zxing, you'll need to clear defaults from your other browsers.
Many thanks to #sean-owen for his hard work and fantastic product.
UPDATE 12/19/16
Ok, I did a slightly more robust version that works well with Firefox and Chrome. A couple of things I discovered:
Chrome will use the Storage event if the scanner is not set to open Chrome automatically, and will use the Hash event after it becomes default.
Firefox will never use the Hash event, but opens an extra window unless you call the scanner with window.location.href (Thanks, #Roland)
There are a couple of other anomalies, but no deal breakers.
I left the "zx" prefix in the hash, so that the code could delineate between scanner hashes and regular hashes. If you leave it in there, you'll not notice it in the processBarcode function, and non-zx hashes will operate as expected.
I am looking for a way to cancel image loading using javascript. I've looked at other questions and hiding them is not enough. Also, the rest of the page must load (window.stop() is out of the question).
The page that is being loaded is not under my control, only one thing is guaranteed - the first <script> on the page is my javascript (lightweight - no jquery).
I have tried setting all img sources to nothing, that did not help since the dom is created after the page is parsed, and all browsers have the same behavior - the img is loaded once it is parsed.
Not possible with modern browsers. Even if you alter the src attribute of image tag with JavaScript browsers still insist on loading the images. I know this from developing the Lazy Load plugin.
The only way I can see to stop images loading is to not have an src attribute present in the image itself, and using a custom data-* attribute to hold the location of the image:
<img data-src="http://path.to/image.png" />
Obviously this doesn't gracefully degrade for those (admittedly rare) JavaScript disabled browsers, and therefore requires a noscript fall-back:
<img data-src="http://path.to/image.png" />
<noscript><img src="http://path.to/image.png" /></noscript>
And couple this with a simple function to load the images when you, or your users, are ready for them:
/* simple demo */
function imagePopulate(within, attr) {
within = within && within.nodeType == 1 ? within : document;
attr = attr || 'data-src';
var images = within.getElementsByTagName('img');
for (var i = 0, len = images.length; i < len; i++) {
if (images[i].parentNode.tagName.toLowerCase() !== 'noscript') {
images[i].src = images[i].getAttribute(attr);
}
}
}
document.getElementById('addImages').onclick = function(){
imagePopulate();
};
JS Fiddle demo.
I can't be sure for all browsers, but this seems to work in Chrome (in that there's no attempt, from looking at the network tab of the developer tools, to load the noscript-contained img).
It can be done with webworkers. See the following example:
https://github.com/NathanWalker/ng2-image-lazy-load.
Stopping a web worker cancels the image loading in browser
Recalling the onload event:
window.onload=function(){
imgs = document.getElementsByTagName('img');
for(i = 0; i < imgs.length(); i++){
imgs[i].src = '#';
}
};
If you want to only cancel the loading of the image , you can use sємsєм's solution
but i do not think it will work by using an window onload event .
You will probably need to provide a button to cancel the image load. Also i suggest, instead of setting the src attribute to "#" , you can remove the src attribute itself using
removeAttribute()
[Make sure you disable the cache while testing]
You need a proxy.
Your script can redirect to another server using something like
location.replace('http://yourserver.com/rewrite/php?url='+escape(this.href));
perhaps you tell us why you want to cancel image loading and whose site you are loading on so we can come up with a better solution
If there is nothing on the page other than images, you could try
document.write('<base href="http://yourserver.com/" />');
which will mess with all non-absolute src and hrefs on the page.
UPDATE Horrible hack but perhaps this almost pseudo code (I am off to bed) will do someting
document.write('<script src="jquery.js"></script><div id="myDiv"></div><!-'+'-');
$(function() {
$.get(location.href,function(data) {
$("#myDiv").html(data.replace(/src=/g,'xsrc='));
});
})
The closest you can get to what you maybe want is to have a quickly loaded placeholder image (ie. low resolution version of your image) and a hidden image (eg. {display:none}) in which the large image gets loaded but not displayed. Then in the onload event for the large image swap the images over (eg. display:block for the large image display:none for the smaller). I also use an array (with their url), to reuse any images that have already been opened.
BTW if you open an image in a new webpage when it gets closed then the image loading will be cancelled. So maybe you can do something similar in a webpage using an iframe to display the image.
To close the iframe and therefore unload the image, remove the frame from the DOM
(another advantage is that browsers spawn another process to deal with iframes, so the page won't lock up while the image loads)
I'm working on a realtime media browsing/playback application that uses <video> objects in the browser for playback, when available.
I'm using a mix of straight javascript, and jQuery,
My concern is specifically with memory. The application never reloads in the window, and the user can watch many videos, so memory management becomes a large concern over time. In testing today, I see the memory profile jumping by the size of the video to be streamed with each subsequent load, and never dropping back down to the baseline.
I've tried the following things with the same result:
1 - Empty the parent container containing the created element, eg:
$(container_selector).empty();
2 - Pause and remove children matching 'video', and then empty the parent container:
$(container_selector).children().filter("video").each(function(){
this.pause();
$(this).remove();
});
$(container_selector).empty();
Has anyone else run into this issue, and is there a better way to do this?
It is very tricky to dispose video from the DOM structure. It may lead to browser crashing. Here is the solution that helped me in my project.
var videoElement = document.getElementById('id_of_the_video_element_here');
videoElement.pause();
videoElement.removeAttribute('src'); // empty source
videoElement.load();
this will reset everything, silent without errors !
Edit: Here are the full details as recommended in the Standard: https://html.spec.whatwg.org/multipage/media.html#best-practices-for-authors-using-media-elements
Hope it resolve your query.
This "solution" is reported to work, presumably because it would make those video container objects available for garbage collection (see the note below for a discussion of why delete shouldn't be making a difference). In any case, your results are likely to vary by browser:
$(container_selector).children().filter("video").each(function(){
this.pause(); // can't hurt
delete this; // #sparkey reports that this did the trick (even though it makes no sense!)
$(this).remove(); // this is probably what actually does the trick
});
$(container_selector).empty();
Note: There's no doubt that the delete keyword is specified only to remove properties from objects (as others have pointed out in the comments). Logging this to the console both before and after the delete this line, above, shows the same result each time. delete this should do nothing and make no difference. Yet this answer continues to receive a trickle of votes, and people have reported that omitting delete this makes it stop working. Perhaps there's strangeness in how some browser JS engines implement delete, or an unusual interaction between a browser's delete and what jQuery is doing with this.
So, just be aware, if this answer solves your problem, that if it does work, it's not clear why that's the case, and it's just as likely to stop working for any number of reasons.
To reset the video to Blank without removing it
$("#video-intro").first().attr('src','')
It stops the video
delete(this);
is not a solution. If it worked for x or y it is a browser misbehaviour. Read here:
The delete operator removes a property from an object.
The truth is that some browsers (Firefox for example) will cache in memory the video buffer when autoplay property is on. It is a pain to deal with.
Removing the video tag from the DOM or pausing it can only produce unstable results. You have to unload the buffer.
var video = document.getElementById('video-id');
video.src = "";
My experiment shows that it is done as so but unfortunately this is browser implementation not completely specified by the spec. You do not need to call load() after src change. When changing the src of a video tag you implicitly call a load() on it, this is stated in the W3C spec.
This snippet doesn't do any effecient DOM manipulations (no tag removal) and doesn't fire error event for <video> unlike this answer:
var video = document.getElementById('video');
video.removeAttribute('src');
video.load();
Furthermore, it doesn't fire loadstart event. And it's like it should work - no video, no load start.
Checked in Chrome 54 / FF 49.
Just to clarify for anyone trying this later, the solution was this: (confirmed with h264 videos in Safari 5.0, untested in FF/opera yet)
$(container_selector).children().filter("video").each(function(){
this.pause();
delete(this);
$(this).remove();
});
$(container_selector).empty();
I was having an issue while dynamically loading some videos. I had two sources in my <video> element. One mp4 and the other webm as fallback. So I had to iterate through the <source>'s like so.
function removeMedia(){
let videos = document.getElementsByTagName('video');
for(let vid in videos){
if(typeof videos[vid] == 'object'){
let srcs = videos[vid].getElementsByTagName('source');
videos[vid].pause();
for(let xsrc in srcs){
if(srcs[xsrc].src !== undefined){
srcs[xsrc].src = '';
}
}
videos[vid].load();
videos[vid].parentNode.removeChild(videos[vid]);
}
}
}
ok, here's a simple solution which certainly works:
var bodypage = document.getElementsByTagName('body')[0];
var control_to_remove = document.getElementById('id_of_the_element_here');
bodypage.removeChild(control_to_remove);
According to this bug:
https://bugs.chromium.org/p/chromium/issues/detail?id=255456&can=2&q=255456&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Component%20Status%20Owner%20Summary%20OS%20Modified
this seems to be a memory leak issue in Chrome!
var video = document.getElementById('video');
if (video.firstChild) {
video.removeChild(video.firstChild);
video.load();
}
I've encountered this problem on a more complicated level where we are loading ~80 videos on a page, and having problems with memory management in IE and Edge. I posted our solution on a similar question I asked specifically about our issue: https://stackoverflow.com/a/52119742/1253298
My code did not use a <video> element with a src tag, but instead used multiple <source> children to set a video in multiple formats.
To properly destroy and unload this video, I had to use a combination of multiple answers on this page, which resulted in:
var videoElement = $('#my-video')
videoElement[0].pause() // Pause video
videoElement.empty() // Remove all <source> children
videoElement.load() // Load the now sourceless video
delete videoElement // The call mentioned in other answers
videoElement.remove() // Removing the video element altogether
Hope this helps someone.
Here is an answer on how to close the camera - not only pausing. It is the stream that should be stopped - not the video elements reference:
stream.stop()
Not much complicated. Just put your src to null.
Eg: document.querySelector('#yourVideo').src = null;
It will remove your video src attribute. Done.
This is what I did to solve this problem.
I created 2 video elements (video1 & video2).
After finished using video1, get the source(src) attribute value and then remove video1 from DOM.
Then set video2 source (src) to whatever value you got from video1.
Do not use stream from video1 as it is cached in memory.
Hope this will help.
One solution that worked for me in AngularJS is using below code:
In case you don't want to remove your source url, and reset to start of the video
let videoElement = $document[0].getElementById('video-id');
videoElement.pause();
videoElement.seekable.start(0);
videoElement.load();
And in case you want to remove the source from video tag:
let videoElement = $document[0].getElementById('video-id');
videoElement.pause();
videoElement.src="";
videoElement.load();
Hope someone finds it useful.
I know this is an old question, but I came across the same issue, and tried almost every solution mentioning <video>'s src attribute, and all solutions seemed to have their drawbacks.
In my specify case, besides <video> elements, I am also using <audio> elements at the same time.
I was reading an article at MDN when I realized that dealing with the src attribute could be the wrong thing to do. Instead, I rewrote all my code to append and remove <source> elements to both <video> and <audio> elements.
That was the only way I found that does not trigger a new load or generates error or other undesirable notifications.
This is a minimal/simplified version of the code I am using (tested on Firefox 86 and Chrome 88).
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-us">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, minimal-ui, shrink-to-fit=no" />
</head>
<body>
<button type="button" onclick="play()">Play</button>
<button type="button" onclick="stop()">Stop</button>
<video id="myVideo"></video>
<script type="text/javascript">
"use strict";
var myVideo = document.getElementById("myVideo");
myVideo.onloadstart = () => {
console.log("onloadstart");
};
myVideo.onloadeddata = () => {
console.log("onloadeddata");
};
myVideo.onload = () => {
console.log("onload");
};
myVideo.onerror = () => {
console.log("onerror");
};
function play() {
while (myVideo.firstChild)
myVideo.removeChild(myVideo.firstChild);
var source = document.createElement("source");
source.src = "example.mp4";
myVideo.appendChild(source);
myVideo.load();
myVideo.play();
}
function stop() {
while (myVideo.firstChild)
myVideo.removeChild(myVideo.firstChild);
myVideo.load();
}
</script>
</body>
</html>
In my case, i used the solution mentioned above by #toon lite:
Array.from(document.getElementsByTagName('video')).forEach(video => {
video.pause();
video.removeAttribute('src');
video.load();
})
But it occurs the another problem in Chrome browser (version 93):
[Intervention] Blocked attempt to create a WebMediaPlayer as there are too many WebMediaPlayers already in existence. See crbug.com/1144736#c27
I guess it is all about the browser version's limit (mine is too old), anyway i fixed this bug by adding some extra operations:
video.src = '';
video.srcObject = null;
video.remove()
Finally the code looks like:
Array.from(document.getElementsByTagName('video')).forEach(video => {
video.pause();
video.removeAttribute('src'); // video.src = '' works so this line can be deleted
video.load();
video.src = '';
video.srcObject = null;
video.remove()
})
I need to background load some WAV files for an HTML page using AJAX. I use AJAX to get the details of the WAV files, then use the embed tag, and I can confirm that the files have loaded successfully because when I set autostart to true, the files play. However, I need the files to play only when the user clicks on a button (or an event is fired). The following is my code to preload these files:
function preloadMedia() {
for(var i = 0; i < testQuestions.length; i++) {
var soundEmbed = document.createElement("embed");
soundEmbed.setAttribute("src", "/media/sounds/" + testQuestions[i].mediaFile);
soundEmbed.setAttribute("hidden", true);
soundEmbed.setAttribute("id", testQuestions[i].id);
soundEmbed.setAttribute("autostart", false);
soundEmbed.setAttribute("width", 0);
soundEmbed.setAttribute("height", 0);
soundEmbed.setAttribute("enablejavascript", true);
document.body.appendChild((soundEmbed));
}
}
I use the following code to play the file (based on what sound file that user wants to play)
function soundPlay(which) {
var sounder = document.getElementById(which);
sounder.Play();
}
Something is wrong here, as none of the browsers I have tested on play the files using the code above. There are no errors, and the code just returns.
I would have left it at that (that is - I would have convinced the client to convert all WAV's to MP3 and use MooTools). But I realized that I could play the sound files, which were not dynamically embeded.
Thus, the same soundPlay function would work for a file embeded in the following manner:
<embed src="/media/sounds/hug_sw1.wav" id="sound2" width="0" heigh="0" autostart="false" enablejavascript="true"/>
anywhere within the HTML.
And it plays well in all the browsers.
Anyone have a clue on this? Is this some sort of undocumented security restriction in all the browsers? (Please remember that the files do get preloaded dynamically, as I can confirm by setting the autostart property to true - They all play).
Any help appreciated.
Hmm.. perhaps, you need to wait for the embed object to load its "src" after calling preloadMedia() ?
Are you sure that the media file is loaded when you call soundPlay() ?
i know your question got a bit old by now, but in case you still wonder...
soundEmbed.setAttribute("id", testQuestions[i].id);
you used the same id twice, yet getElementById returns only one element, or false if it doesn't find exactly one matching element.
you could try something like this:
soundEmbed.setAttribute("id", "soundEmbed_"+testQuestions[i].id);
always keep in mind that an id must be unique
Just a tip for more compatibility:
I read here that width and height need to be > 0 for Firefox on MacOS.