Related
In my application, I tried to print out a voucher page for the user like this:
var htm ="<div>Voucher Details</div>";
$('#divprint').html(htm);
window.setTimeout('window.print()',2000);
'divprint' is a div in my page which store information about the voucher.
It works, and the print page pops up. But I want to advance the application once the user clicks 'print' or 'close' in the browser's pop-up print dialog.
For example, I'd like to redirect user to another page after pop up window is closed:
window.application.directtoantherpage();//a function which direct user to other page
How can I determine when the pop up print window is closed or print is finished?
You can listen to the afterprint event.
https://developer.mozilla.org/en-US/docs/Web/API/window.onafterprint
window.onafterprint = function(){
console.log("Printing completed...");
}
It may be possible to use window.matchMedia to get this functionality in another way.
(function() {
var beforePrint = function() {
console.log('Functionality to run before printing.');
};
var afterPrint = function() {
console.log('Functionality to run after printing');
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
}());
Source: http://tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/
On chrome (V.35.0.1916.153 m) Try this:
function loadPrint() {
window.print();
setTimeout(function () { window.close(); }, 100);
}
Works great for me. It will close window after user finished working on printing dialog.
compatible with chrome, firefox, opera, Internet Explorer
Note: jQuery required.
<script>
window.onafterprint = function(e){
$(window).off('mousemove', window.onafterprint);
console.log('Print Dialog Closed..');
};
window.print();
setTimeout(function(){
$(window).one('mousemove', window.onafterprint);
}, 1);
</script>
See https://stackoverflow.com/a/15662720/687315. As a workaround, you can listen for the afterPrint event on the window (Firefox and IE) and listen for mouse movement on the document (indicating that the user has closed the print dialog and returned to the page) after the window.mediaMatch API indicates that the media no longer matches "print" (Firefox and Chrome).
Keep in mind that the user may or may not have actually printed the document. Also, if you call window.print() too often in Chrome, the user may not have even been prompted to print.
window.print behaves synchronously on chrome .. try this in your console
window.print();
console.log("printed");
"printed" doesn't display unless the print dialog is closed(canceled/saved/printed) by the user.
Here is a more detailed explanation about this issue.
I am not sure about IE or Firefox will check and update that later
You can detect when window.print() is finished simply by putting it in another function
//function to call if you want to print
var onPrintFinished=function(printed){console.log("do something...");}
//print command
onPrintFinished(window.print());
tested in Firefox,Google chrome,IE
This Actually worked for me in chrome. I was pretty suprised.
jQuery(document).bind("keyup keydown", function(e){
if(e.ctrlKey && e.keyCode == 80){
Print(); e.preventDefault();
}
});
Where Print is a function I wrote that calls window.print(); It also works as a pure blocker if you disable Print();
As noted here by user3017502
window.print() will pause so you can add an onPrintFinish or onPrintBegin like this
function Print(){
onPrintBegin
window.print();
onPrintFinish();
}
Tested IE, FF, Chrome and works in all.
setTimeout(function () { window.print(); }, 500);
window.onfocus = function () { setTimeout(function () { window.close(); }, 500); }
Given that you wish to wait for the print dialog to go away I would use focus binding on the window.
print();
var handler = function(){
//unbind task();
$(window).unbind("focus",handler);
}
$(window).bind("focus",handler);
By putting in the unbind in the handler function we prevent the focus event staying bond to the window.
Simplest way to detect if print has finished and close print window:
window.onafterprint = function(){
window.onfocus = function(){
window.close();
}
};
Print in new window with w = window.open(url, '_blank') and try w.focus();w.close(); and detect when page is closed. Works in all browsers.
w = window.open(url, '_blank');
w.onunload = function(){
console.log('closed!');
}
w.focus();
w.print();
w.close();
Window close after finish print.
It works for me with $(window).focus().
var w;
var src = 'http://pagetoprint';
if (/chrom(e|ium)/.test(navigator.userAgent.toLowerCase())) {
w = $('<iframe></iframe>');
w.attr('src', src);
w.css('display', 'none');
$('body').append(w);
w.load(function() {
w[0].focus();
w[0].contentWindow.print();
});
$(window).focus(function() {
console.log('After print');
});
}
else {
w = window.open(src);
$(w).unload(function() {
console.log('After print');
});
}
I think the window focus approach is the correct one. Here is an example in which I wanted to open a PDF url blob in a hidden iframe and print it. After printed or canceled, I wanted to remove the iframe.
/**
* printBlob will create if not exists an iframe to load
* the pdf. Once the window is loaded, the PDF is printed.
* It then creates a one-time event to remove the iframe from
* the window.
* #param {string} src Blob or any printable url.
*/
export const printBlob = (src) => {
if (typeof window === 'undefined') {
throw new Error('You cannot print url without defined window.');
}
const iframeId = 'pdf-print-iframe';
let iframe = document.getElementById(iframeId);
if (!iframe) {
iframe = document.createElement('iframe');
iframe.setAttribute('id', iframeId);
iframe.setAttribute('style', 'position:absolute;left:-9999px');
document.body.append(iframe);
}
iframe.setAttribute('src', src);
iframe.addEventListener('load', () => {
iframe.contentWindow.focus();
iframe.contentWindow.print();
const infanticide = () => {
iframe.parentElement.removeChild(iframe);
window.removeEventListener('focus', infanticide);
}
window.addEventListener('focus', infanticide);
});
};
It is difficult, due to different browser behavior after print. Desktop Chrome handles the print dialogue internally, so doesn't shift focus after print, however, afterprint event works fine here (As of now, 81.0). On the other hand, Chrome on mobile device and most of the other browsers shifts focus after print and afterprint event doesn't work consistently here. Mouse movement event doesn't work on mobile devices.
So, Detect if it is Desktop Chrome,
If Yes, use afterprint event. If No, use focus based detection. You can also use mouse movement event(Works in desktop only) in combination of these, to cover more browsers and more scenarios.
well, just to remind everyone that the afterprint will not determine the print action button instead it will execute whenever the print window is closed or closing, both cancel button or esc key which closing the print window will consider afterprint while there is no actual print happening yet.
Implementing window.onbeforeprint and window.onafterprint
The window.close() call after the window.print() is not working in Chrome v 78.0.3904.70
To approach this I'm using Adam's answer with a simple modification:
function print() {
(function () {
let afterPrintCounter = !!window.chrome ? 0 : 1;
let beforePrintCounter = !!window.chrome ? 0 : 1;
var beforePrint = function () {
beforePrintCounter++;
if (beforePrintCounter === 2) {
console.log('Functionality to run before printing.');
}
};
var afterPrint = function () {
afterPrintCounter++;
if (afterPrintCounter === 2) {
console.log('Functionality to run after printing.');
//window.close();
}
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function (mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
}());
//window.print(); //To print the page when it is loaded
}
I'm calling it in here:
<body onload="print();">
This works for me.
Note that I use a counter for both functions, so that I can handle this event in different browsers (fires twice in Chrome, and one time in Mozilla).
For detecting the browser you can refer to this answer
Rewriting the question -
I am trying to make a page on which if user leave the page (either to other link/website or closing window/tab) I want to show the onbeforeunload handeler saying we have a great offer for you? and if user choose to leave the page it should do the normal propogation but if he choose to stay on the page I need him to redirect it to offer page redirection is important, no compromise. For testing lets redirect to google.com
I made a program as follows -
var stayonthis = true;
var a;
function load() {
window.onbeforeunload = function(e) {
if(stayonthis){
a = setTimeout('window.location.href="http://google.com";',100);
stayonthis = false;
return "Do you really want to leave now?";
}
else {
clearTimeout(a);
}
};
window.onunload = function(e) {
clearTimeout(a);
};
}
window.onload = load;
but the problem is that if he click on the link to yahoo.com and choose to leave the page he is not going to yahoo but to google instead :(
Help Me !! Thanks in Advance
here is the fiddle code
here how you can test because onbeforeunload does not work on iframe well
This solution works in all cases, using back browser button, setting new url in address bar or use links.
What i have found is that triggering onbeforeunload handler doesn't show the dialog attached to onbeforeunload handler.
In this case (when triggering is needed), use a confirm box to show the user message. This workaround is tested in chrome/firefox and IE (7 to 10)
http://jsfiddle.net/W3vUB/4/show
http://jsfiddle.net/W3vUB/4/
EDIT: set DEMO on codepen, apparently jsFiddle doesn't like this snippet(?!)
BTW, using bing.com due to google not allowing no more content being displayed inside iframe.
http://codepen.io/anon/pen/dYKKbZ
var a, b = false,
c = "http://bing.com";
function triggerEvent(el, type) {
if ((el[type] || false) && typeof el[type] == 'function') {
el[type](el);
}
}
$(function () {
$('a:not([href^=#])').on('click', function (e) {
e.preventDefault();
if (confirm("Do you really want to leave now?")) c = this.href;
triggerEvent(window, 'onbeforeunload');
});
});
window.onbeforeunload = function (e) {
if (b) return;
a = setTimeout(function () {
b = true;
window.location.href = c;
c = "http://bing.com";
console.log(c);
}, 500);
return "Do you really want to leave now?";
}
window.onunload = function () {
clearTimeout(a);
}
It's better to Check it local.
Check out the comments and try this: LIVE DEMO
var linkClick=false;
document.onclick = function(e)
{
linkClick = true;
var elemntTagName = e.target.tagName;
if(elemntTagName=='A')
{
e.target.getAttribute("href");
if(!confirm('Are your sure you want to leave?'))
{
window.location.href = "http://google.com";
console.log("http://google.com");
}
else
{
window.location.href = e.target.getAttribute("href");
console.log(e.target.getAttribute("href"));
}
return false;
}
}
function OnBeforeUnLoad ()
{
return "Are you sure?";
linkClick=false;
window.location.href = "http://google.com";
console.log("http://google.com");
}
And change your html code to this:
<body onbeforeunload="if(linkClick == false) {return OnBeforeUnLoad()}">
try it
</body>
After playing a while with this problem I did the following. It seems to work but it's not very reliable. The biggest issue is that the timed out function needs to bridge a large enough timespan for the browser to make a connection to the url in the link's href attribute.
jsfiddle to demonstrate. I used bing.com instead of google.com because of X-Frame-Options: SAMEORIGIN
var F = function(){}; // empty function
var offerUrl = 'http://bing.com';
var url;
var handler = function(e) {
timeout = setTimeout(function () {
console.log('location.assign');
location.assign(offerUrl);
/*
* This value makes or breaks it.
* You need enough time so the browser can make the connection to
* the clicked links href else it will still redirect to the offer url.
*/
}, 1400);
// important!
window.onbeforeunload = F;
console.info('handler');
return 'Do you wan\'t to leave now?';
};
window.onbeforeunload = handler;
Try the following, (adds a global function that checks the state all the time though).
var redirected=false;
$(window).bind('beforeunload', function(e){
if(redirected)
return;
var orgLoc=window.location.href;
$(window).bind('focus.unloadev',function(e){
if(redirected==true)
return;
$(window).unbind('focus.unloadev');
window.setTimeout(function(){
if(window.location.href!=orgLoc)
return;
console.log('redirect...');
window.location.replace('http://google.com');
},6000);
redirected=true;
});
console.log('before2');
return "okdoky2";
});
$(window).unload(function(e){console.log('unloading...');redirected=true;});
<script>
function endSession() {
// Browser or Broswer tab is closed
// Write code here
alert('Browser or Broswer tab closed');
}
</script>
<body onpagehide="endSession();">
I think you're confused about the progress of events, on before unload the page is still interacting, the return method is like a shortcut for return "confirm()", the return of the confirm however cannot be handled at all, so you can not really investigate the response of the user and decide upon it which way to go, the response is going to be immediately carried out as "yes" leave page, or "no" don't leave page...
Notice that you have already changed the source of the url to Google before you prompt user, this action, cannot be undone... unless maybe, you can setimeout to something like 5 seconds (but then if the user isn't quick enough it won't pick up his answer)
Edit: I've just made it a 5000 time lapse and it always goes to Yahoo! Never picks up the google change at all.
I've been printing my page using the code below:
window.print();
An image below is what the print preview in Google chrome browser looks like. It has two main buttons: print and cancel.
I want to know if the user has clicked the print or cancel buttons. What I did uses jquery:
HTML Code of the Print Preview:
<button class="print default" i18n-content="printButton">Print</button>
<button class="cancel" i18n-content="cancel">Cancel</button>
Jquery Code:
$('button > .cancel').click(function (e) {
alert('Cancel');
});
$('button > .print').click(function (e) {
alert('Print');
});
I tried the code above with no luck. What am I missing?
You can not access Chrome's internal windows (printing dialog in this case) directly from a regular web page.
(function () {
var beforePrint = function () {
alert('Functionality to run before printing.');
};
var afterPrint = function () {
alert('Functionality to run after printing');
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function (mql) {
//alert($(mediaQueryList).html());
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
}());
Or, If you want to do something when the print preview gets opened, you can try below:
$(document).bind("keyup keydown", function (e) {
if (e.ctrlKey && e.keyCode == 80) {
setTimeout(function () { CallAfterWindowLoad();}, 5000);
return true;
}
});
function CallAfterWindowLoad()
{
alert("Open and call");
}
Reference:
How to capture the click event on the default print menu called by Javascript window.print()
Maybe if you provide your requirements for this two buttons click event, we can provide you an alternate solution.
it is very easily possible:
<body onafterprint="myFunction()">
The myFunction() that you can define within a tag will be fire when either the printing job is done or the cancel button was pressed.
As far as I know, the print preview is not part of any document your JS can access. These might interest you:
Detecting browser print event
ExtJS 4 - detecting if the user pressed "Print" on the print dialog that was called programatically
<script>
window.print();
onafterprint = function () {
window.location.href = "index.html";
}
</script>
This should do the trick. I've used jQuery v2.2.0 which is included in the html file.
$("#print").click(function() { // calls the id of the button that will print
document.body.style.visibility = 'hidden'; //code for hiding the body
document.getElementById('printthis').style.visibility = 'visible'; // div to be printed
document.getElementById('printthis').style.position = 'absolute'; //some code/css for positioning. you can adjust this
document.getElementById('printthis').style.top = '40px';
document.getElementById('printthis').style.left = '0px';
if (print()) { // shows print preview.
} else { // else statement will check if cancel button is clicked.
document.body.style.visibility = 'visible';
document.getElementById('printthis').style.position = '';
document.getElementById('printthis').style.top = '';
document.getElementById('printthis').style.left = '';
alert("Print Canceled");
}
});
I guess this might as well be used as a way to print certain divs in your html. Just hide the body element and only show the div that you want to print with some positioning css. Hope it works in yours. I've tried it and I can say that it worked for me.
In my application, I tried to print out a voucher page for the user like this:
var htm ="<div>Voucher Details</div>";
$('#divprint').html(htm);
window.setTimeout('window.print()',2000);
'divprint' is a div in my page which store information about the voucher.
It works, and the print page pops up. But I want to advance the application once the user clicks 'print' or 'close' in the browser's pop-up print dialog.
For example, I'd like to redirect user to another page after pop up window is closed:
window.application.directtoantherpage();//a function which direct user to other page
How can I determine when the pop up print window is closed or print is finished?
You can listen to the afterprint event.
https://developer.mozilla.org/en-US/docs/Web/API/window.onafterprint
window.onafterprint = function(){
console.log("Printing completed...");
}
It may be possible to use window.matchMedia to get this functionality in another way.
(function() {
var beforePrint = function() {
console.log('Functionality to run before printing.');
};
var afterPrint = function() {
console.log('Functionality to run after printing');
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
}());
Source: http://tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/
On chrome (V.35.0.1916.153 m) Try this:
function loadPrint() {
window.print();
setTimeout(function () { window.close(); }, 100);
}
Works great for me. It will close window after user finished working on printing dialog.
compatible with chrome, firefox, opera, Internet Explorer
Note: jQuery required.
<script>
window.onafterprint = function(e){
$(window).off('mousemove', window.onafterprint);
console.log('Print Dialog Closed..');
};
window.print();
setTimeout(function(){
$(window).one('mousemove', window.onafterprint);
}, 1);
</script>
See https://stackoverflow.com/a/15662720/687315. As a workaround, you can listen for the afterPrint event on the window (Firefox and IE) and listen for mouse movement on the document (indicating that the user has closed the print dialog and returned to the page) after the window.mediaMatch API indicates that the media no longer matches "print" (Firefox and Chrome).
Keep in mind that the user may or may not have actually printed the document. Also, if you call window.print() too often in Chrome, the user may not have even been prompted to print.
window.print behaves synchronously on chrome .. try this in your console
window.print();
console.log("printed");
"printed" doesn't display unless the print dialog is closed(canceled/saved/printed) by the user.
Here is a more detailed explanation about this issue.
I am not sure about IE or Firefox will check and update that later
You can detect when window.print() is finished simply by putting it in another function
//function to call if you want to print
var onPrintFinished=function(printed){console.log("do something...");}
//print command
onPrintFinished(window.print());
tested in Firefox,Google chrome,IE
This Actually worked for me in chrome. I was pretty suprised.
jQuery(document).bind("keyup keydown", function(e){
if(e.ctrlKey && e.keyCode == 80){
Print(); e.preventDefault();
}
});
Where Print is a function I wrote that calls window.print(); It also works as a pure blocker if you disable Print();
As noted here by user3017502
window.print() will pause so you can add an onPrintFinish or onPrintBegin like this
function Print(){
onPrintBegin
window.print();
onPrintFinish();
}
Tested IE, FF, Chrome and works in all.
setTimeout(function () { window.print(); }, 500);
window.onfocus = function () { setTimeout(function () { window.close(); }, 500); }
Given that you wish to wait for the print dialog to go away I would use focus binding on the window.
print();
var handler = function(){
//unbind task();
$(window).unbind("focus",handler);
}
$(window).bind("focus",handler);
By putting in the unbind in the handler function we prevent the focus event staying bond to the window.
Simplest way to detect if print has finished and close print window:
window.onafterprint = function(){
window.onfocus = function(){
window.close();
}
};
Print in new window with w = window.open(url, '_blank') and try w.focus();w.close(); and detect when page is closed. Works in all browsers.
w = window.open(url, '_blank');
w.onunload = function(){
console.log('closed!');
}
w.focus();
w.print();
w.close();
Window close after finish print.
It works for me with $(window).focus().
var w;
var src = 'http://pagetoprint';
if (/chrom(e|ium)/.test(navigator.userAgent.toLowerCase())) {
w = $('<iframe></iframe>');
w.attr('src', src);
w.css('display', 'none');
$('body').append(w);
w.load(function() {
w[0].focus();
w[0].contentWindow.print();
});
$(window).focus(function() {
console.log('After print');
});
}
else {
w = window.open(src);
$(w).unload(function() {
console.log('After print');
});
}
I think the window focus approach is the correct one. Here is an example in which I wanted to open a PDF url blob in a hidden iframe and print it. After printed or canceled, I wanted to remove the iframe.
/**
* printBlob will create if not exists an iframe to load
* the pdf. Once the window is loaded, the PDF is printed.
* It then creates a one-time event to remove the iframe from
* the window.
* #param {string} src Blob or any printable url.
*/
export const printBlob = (src) => {
if (typeof window === 'undefined') {
throw new Error('You cannot print url without defined window.');
}
const iframeId = 'pdf-print-iframe';
let iframe = document.getElementById(iframeId);
if (!iframe) {
iframe = document.createElement('iframe');
iframe.setAttribute('id', iframeId);
iframe.setAttribute('style', 'position:absolute;left:-9999px');
document.body.append(iframe);
}
iframe.setAttribute('src', src);
iframe.addEventListener('load', () => {
iframe.contentWindow.focus();
iframe.contentWindow.print();
const infanticide = () => {
iframe.parentElement.removeChild(iframe);
window.removeEventListener('focus', infanticide);
}
window.addEventListener('focus', infanticide);
});
};
It is difficult, due to different browser behavior after print. Desktop Chrome handles the print dialogue internally, so doesn't shift focus after print, however, afterprint event works fine here (As of now, 81.0). On the other hand, Chrome on mobile device and most of the other browsers shifts focus after print and afterprint event doesn't work consistently here. Mouse movement event doesn't work on mobile devices.
So, Detect if it is Desktop Chrome,
If Yes, use afterprint event. If No, use focus based detection. You can also use mouse movement event(Works in desktop only) in combination of these, to cover more browsers and more scenarios.
well, just to remind everyone that the afterprint will not determine the print action button instead it will execute whenever the print window is closed or closing, both cancel button or esc key which closing the print window will consider afterprint while there is no actual print happening yet.
Implementing window.onbeforeprint and window.onafterprint
The window.close() call after the window.print() is not working in Chrome v 78.0.3904.70
To approach this I'm using Adam's answer with a simple modification:
function print() {
(function () {
let afterPrintCounter = !!window.chrome ? 0 : 1;
let beforePrintCounter = !!window.chrome ? 0 : 1;
var beforePrint = function () {
beforePrintCounter++;
if (beforePrintCounter === 2) {
console.log('Functionality to run before printing.');
}
};
var afterPrint = function () {
afterPrintCounter++;
if (afterPrintCounter === 2) {
console.log('Functionality to run after printing.');
//window.close();
}
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function (mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
}());
//window.print(); //To print the page when it is loaded
}
I'm calling it in here:
<body onload="print();">
This works for me.
Note that I use a counter for both functions, so that I can handle this event in different browsers (fires twice in Chrome, and one time in Mozilla).
For detecting the browser you can refer to this answer
It seems that helloworld.js gets loaded multiple times based on the number of times I click #load. I say this because when I look at Google Chromes Developer Tools Network tab, it shows helloworld.js as many times as I click #load.
$(document).ready(function() {
$("#load").click(function(){
$.getScript('helloworld.js', function() {
hello();
});
});
});
The hello() function looks like this:
function hello(){
alert("hello");
}
Is it possible to detect if helloworld.js has already loaded?
So if it hasn't loaded, load it, and if it has loaded, don't load it.
This is what Developer Tools currently shows me if I click the #load button 4 times:
Set a flag when file loaded successfully. If flag is set then skip the file loading again.
Try this code,
var isLoaded = 0; //Set the flag OFF
$(document).ready(function() {
$("#load").click(function(){
if(isLoaded){ //If flag is ON then return false
alert("File already loaded");
return false;
}
$.getScript('helloworld.js', function() {
isLoaded = 1; //Turn ON the flag
hello();
});
});
});
So why not only fire the event once like this:
$("#load").one("click", function() {
$load = $(this);
$.getScript('helloworld.js', function() {
hello();
// bind hello to the click event of load for subsequent calls
$load.on('click', hello);
});
});
That would prevent subsequent loads and avoids the use of a global
Another option is letting .getScript() run but let it take the script from browser's cache so you won't have it reloaded each and every time.
To achieve this, add such code:
$.ajaxSetup({
cache: true
});
This is taken from the documentation page.
You could create a helper function:
var getScript = (function() {
var loadedFiles = {};
return function(filename, callback) {
if(loadedFiles[filename]) {
callback();
} else {
$.getScript(filename, function() {
loadedFiles[filename] = true;
callback();
});
}
};
})();