Related
We recently discovered that Chrome no longer supports window.showModalDialog which is problematic because our enterprise application uses this method.
There is, apparently, a short term workaround that allows you to restore showModalDialog but it involves modifying the registry which is too complicated (and risky) four our average user. Therefore I'm not a big fan of this workaround.
The long term solution is obviously to remove all calls to this obsolete method and replace them with a convenient jQuery plugin (such as VistaPrint's Skinny Modal Dialog plugin, for example. Other suggestions are welcome by the way).
The typical scenario we use the modal dialog is to ask the user for Yes/No confirmation before executing an action that cannot be undone, ask the user to agree to terms and condition before proceeding, etc. Typically the onclick event on the "Yes" or "Ok" button in the modal dialog looks like this:
window.returnValue = true;
window.close();
Similarly, the "Cancel" or "No" button looks like this:
window.returnValue = false;
window.close();
The fact that we can return a value from the dialog is very convenient because it allows the "parent" window to be notified whether the user has clicked the "Ok" or the "Cancel" button like so:
var options = "center:1;status:1;menubar:0;toolbar:0;dialogWidth:875px;dialogHeight:650px";
var termsOfServiceAccepted = window.showModalDialog(myUrl, null, options);
if (termsOfServiceAccepted) {
... proceed ...
}
The last thing I'm going to mention about the showModalDialog is that it works great even when the document displayed in the dialog is from a different domain. It's very common for us to have our javascript running from http://the-client.com but the "Terms of Service" web page is from http://the-enterprise-vendor.com
I need a temporary solution that I can deploy ASAP while we work on the long term solution. Here are my criteria:
minimal code change in existing JavaScript
the pop up window must be able to return a value to the "parent". Typically this value is a Boolean but it could be any simple type (e.g.: string, int, etc.)
solution must work even if the URL of the content is from different domain
Here's what I have so far:
1) Add the following method in my JavaScript:
function OpenDialog(url, width, height, callback)
{
var win = window.open(url, "MyDialog", width, height, "menubar=0,toolbar=0");
var timer = setInterval(function ()
{
if (win.closed)
{
clearInterval(timer);
var returnValue = win.returnValue;
callback(returnValue);
}
}, 500);
}
As you can see in this method, I try to make the pop up window look as similar to a dialog as possible by hiding the menu and the toolbar, I setup a time every 500 milliseconds to check if the window has been closed by the user and if so, get the 'returnValue' and invoke a callback.
2) replace all calls to showModalDialog with the following:
OpenDialog(myUrl, 875, 650, function (termsOfServiceAccepted)
{
if (termsOfServiceAccepted)
{
... proceed ....
}
});
The fourth parameter to the method is the callback where I check if the user has clicked the "Ok" button before allowing her to proceed.
I know it's a long question but basically it boils down to:
What do you think of the solution I propose?
In particular, do you think I'll be able to get a returnValue from a window that was opened with window.open?
Any other alternative you can suggest?
I have two ideas that could help you but the first one is tied to CORS, so you won't be able to use it from different domains at least you can access both services and configure them.
FIRST IDEA:
The first one is related to this native api. You could create on the parent window a global function like this:
window.callback = function (result) {
//Code
}
As you can see it receives a result argument which can hold the boolean value you need. The you could open the popup using the same old window.open(url) function. The popup's onlick event handler could look like this:
function() {
//Do whatever you want.
window.opener.callback(true); //or false
}
SECOND IDEA: Solves the problem
The other idea I got is to use this other native api to trigger an event on the parent window when the popup resolves (better known as cross-document messaging). So you could do this from the parent window:
window.onmessage = function (e) {
if (e.data) {
//Code for true
} else {
//Code for false
}
};
By this way you are listening to any posted message on this window, and checking if the data attached to the message is true (the user clicks ok in the popup) or false (the user clicks cancel in the popup).
In the popup you should post a message to the parent window attaching a true or a false value when corresponds:
window.opener.postMessage(true, '*'); //or false
I think that this solution perfectly fits your needs.
EDIT
I have wrote that the second solution was also tied to CORS but digging deeper
I realized that cross-document messaging isn't tied to CORS
I'm trying to create a script which will run when any browser console is opened or closed. Is there any way to detect if the browser console in all browsers (Firefox/IE/Chrome/Safari/Opera) is open or not via JavaScript, jQuery, or any other client-side script?
If you are willing to accept an interference for the user,
you could use the debugger statement, as it is available in all major browsers.
Side note: If the users of your app are interested in console usage, they're probably familiar with dev tools, and will not be surprised by it showing up.
In short, the statement is acting as a breakpoint, and will affect the UI only if the browser's development tools is on.
Here's an example test:
<body>
<p>Devtools is <span id='test'>off</span></p>
<script>
var minimalUserResponseInMiliseconds = 100;
var before = new Date().getTime();
debugger;
var after = new Date().getTime();
if (after - before > minimalUserResponseInMiliseconds) { // user had to resume the script manually via opened dev tools
document.getElementById('test').innerHTML = 'on';
}
</script>
</body>
devtools-detect should do the job. Try the simple demo page.
devtools-detect → detect whether DevTools is open, and its orientation.
Supported Browsers:
DevTools in Chrome, Safari, Firefox & Opera
Caveats:
Doesn't work if DevTools is undocked (separate window), and may show a false positive if you toggle any kind of sidebar.
I don't think it is directly possible in JS for security reasons.But in here
they are claiming that it is possible and is useful for when you want something special to happen when DevTools is open. Like pausing canvas, adding style debug info, etc.
But As #James Hill tell in this, I also thinks even if a browser chose to make this information accessible to the client, it would not be a standard implementation (supported across multiple browsers).
Also can also try this one also here.
It's not possible in any official cross browser way, but if the occasional false positive is acceptable, you can check for a window.onresize event. Users resizing their windows after loading a page is somewhat uncommon. It's even more effective if you expect users will be frequently opening the console, meaning less false positives as a percentage.
window.onresize = function(){
if ((window.outerHeight - window.innerHeight) > 100) {
// console was opened (or screen was resized)
}
}
Credit to https://stackoverflow.com/a/7809413/3774582. Although that question is chrome specific, the concept applies here.
To expand on this, if you need a very low tolerance on false positives, most window resizes will trigger this event dozens of times because it is usually done as a drag action, while opening the console will only trigger this once. If you can detect this, the approach will become even more accurate.
Note: This will fail to detect if the console is already open when the user visits the page, or if the user opens the console in a new window.
(function() {
'use strict';
const el = new Image();
let consoleIsOpen = false;
let consoleOpened = false;
Object.defineProperty(el, 'id', {
get: () => {
consoleIsOpen = true;
}
});
const verify = () => {
console.dir(el);
if (consoleIsOpen === false && consoleOpened === true) {
// console closed
window.dispatchEvent(new Event('devtools-opened'));
consoleOpened = false;
} else if (consoleIsOpen === true && consoleOpened === false) {
// console opened
window.dispatchEvent(new Event('devtools-closed'));
consoleOpened = true;
}
consoleIsOpen = false;
setTimeout(verify, 1000);
}
verify();
})();
window.addEventListener('devtools-opened', ()=>{console.log('opened')});
window.addEventListener('devtools-closed', ()=>{console.log('closed')});
Here is a code that worked for me.
This solution works like a charm
https://github.com/sindresorhus/devtools-detect
if you are not using modules - disable lines
// if (typeof module !== 'undefined' && module.exports) {
// module.exports = devtools;
// } else {
window.devtools = devtools;
// }
and result is then here
window.devtools.isOpen
I for my project use the blur event.
function yourFunction() {}
window.addEventListener('blur',(e)=>{e.preventDefault(); yourFunction()})
This will execute yourFunction when the window loses focus.
For instance when someone opens the DevTools.
Okay seems like it also fires when you try to access a different window... so maybe not the best solution.
Maybe pair it with looking at the width of the browser.
If it chainged you can be pretty sure about it I think
I seem to be having issues with programmatic opening and closing of a JQM 1.3 Panel.
EDIT: This is for JQM 1.3.x not 1.4+
It is somewhat hard to explain, so I just made a fiddle :)
There is a lot going on in the fiddle, but it is just a sample of a much larger app and conveys the issue.
How to replicate:
Go to Fiddle
On Fiddle open the Panel and go to Page Two
On Page Two open Panel and go to Page One
Try to Open the Panel now on page one, it does nothing.
Browsers Affected:
EDIT: This seems to be fixed in Chrome 30.0.1599.101 m
Chrome 28.0.1500.95 m
IE 10.0.9200.16635
Safari // Latest Ver
Android WebView (4.2.2)
Browsers NOT Affected:
Firefox 23
Opera 12.16
Link to Fiddle:
http://jsfiddle.net/q2YH3/
Link to Other Posts
https://github.com/jquery/jquery-mobile/issues/6308
http://forum.jquery.com/topic/panel-not-responding-after-page-change
EDIT: So Firefox gives me an error that neither Chrome or IE do.
When I click to go back to page one, I get:
Type Error: elem is undefined
The error is thrown by JQ 1.9.1, I trace it back to this:
A method for determining if a DOM node can handle the data expando
acceptData: function( elem ) {
// Do not set data on non-element because it will not be cleared (#8335).
if ( elem.nodeType && elem.nodeType !== 1 && elem.nodeType !== 9 ) {
return false;
}
var noData = elem.nodeName && jQuery.noData[ elem.nodeName.toLowerCase() ];
// nodes accept data unless otherwise specified; rejection can be conditional
return !noData || noData !== true && elem.getAttribute("classid") === noData;
}
`
Note the :
Do not set data on non-element because it will not be cleared (#8335).
Github Issue Link:
https://github.com/jquery/jquery/pull/1232
OG Code:
$('.showMenu').on('click', function(){
$.mobile.loading('hide');
$.mobile.activePage.find('#'+$.mobile.activePage.attr('id')+'P').panel("toggle");
});
$('.btnMenuItem').on('click', function(event){
myPgActions.nav(event, function(target){
$.mobile.changePage(target);
}, false);
});
var myPgActions = {};
myPgActions = {
nav: function(event, callback, manualHash){
var PID = $.mobile.activePage.attr('id'),
target = (!!event) ? event.target.name : manualHash;
$("#"+PID+"P").panel( "close" );
if(PID != 'loading') $("#"+PID+"Iframe").hide();
if(PID == target){
$("#"+PID+"Iframe").hide('fast', function(){
$("#"+PID+"Iframe").attr('src', "");
myPgActions.update(PID, target, 'refresh', function(target){
callback(target)
});
});
}else{
this.update(PID, target, 'change', function(target){
callback(target);
});
}
},// end get
update: function(PID, target, type, updateCallback){
var ifReady = $.Deferred();
if(type == 'refresh'){
this.buildUrl(PID, function(url){
$('#'+PID+'Iframe').attr( 'src', url);
ifReady.resolve();
$.when(ifReady).then(function(){
updateCallback('#'+PID+'Iframe')
});
});
}else if(type == 'change'){
this.buildUrl(target, function(url){
$('#'+target+'Iframe').attr( 'src', url);
ifReady.resolve();
});
$.when(ifReady).then(function(){
updateCallback('#'+target);
});
}
}, // end set
buildUrl: function(page, buildCallback){
switch(page){
case 'dash':
var mobileSiteUrl = 'URL with options for iframe'
setTimeout(function(){buildCallback(mobileSiteUrl);},25);
break;
case 'local':
var mobileSiteUrl = 'URL with options for iframe'
setTimeout(function(){buildCallback(mobileSiteUrl);},25);
break;
}// End Switch
}
}// End Obj
Had the same problem, panel not showing after page changes.
Two small changes can fix that:
what I did was to change the panel from id="myPanel" to class="myPanel", then changed the call to the panel to open: $('.myPanel:visible').panel('open'); - that's it!
The problem is that the panel has to be inside of a jQuery "page", and after the transition, if you have the panel set in the target page, you actually have two (or more) panels with the same id which is wrong or same class which is fine. So you just change the id to a class and call the visible one.
Took me too long, Hope it saves time to someone else.
I played around with your code a bit. I noticed that If I put an alert inside your update function, that it fixes everything. So I researched why an alert would make a program work, and found this page.
http://ubuntuforums.org/archive/index.php/t-930002.html
"You should probably know that JavaScript evaluation is of the 'look ahead' type: the script already runs when it is still being evaluated (and while the page itself is still being evaluated). Now that is why it is recommended to dump all references to scripts in the section of your page, as it will cause the JavaScript to be fully evaluated before you (usually) can call a function (event handlers), and hence avoid silly 'undefined' errors.
Now the alert(); call has 2 effects: (1) it pops up the message box (so far, so good);.but (2) it halts the thread the JavaScript is using! However the browser's other threads will still continue to go on (HTML rendering...). So it may be one of those cases that you would benefit from a more elegant halting method, which is to only execute this (part of the) script when the document has been fully loaded;"
The solution they suggest is putting your script inside of the . Or using "stateChanged() function of the ajax http request".
Well I upvoted #A.sharif 's post, as he got the gears in my head spinning.
The problem lies in the fact that the callback of the "BuildUrl" function was executing before the URL variable was built.
I thought I had allowed ample time with 25ms but it was not. I bumped the time before the callback is executed up to 600 ms and it works fine now.
I am sure there is a more elegant solution, but this is what I got ;)
New Fiddle:
http://jsfiddle.net/t8zyQ/
What was changed was the value of 25 in the setTimeout() to 600.
Changed Code:
buildUrl: function(page, buildCallback){
switch(page){
case 'dash':
var mobileSiteUrl = 'URL with options for iframe'
setTimeout(function(){buildCallback(mobileSiteUrl);},600);
break;
case 'local':
var mobileSiteUrl = 'URL with options for iframe'
setTimeout(function(){buildCallback(mobileSiteUrl);},600);
break;
}// End Switch
I have been trying to figure this one out for a while, but when I try to reference a window that I opened the handle is always undefined.
It is worth noting that this is being used in a userscript and here is the snippet in question:
var donateWindow;
// ######################################################################
// # Show the donation popup and open a window to paypal site
// ######################################################################
function showDonateWindow()
{
if (window.confirm("Question here"))
{
if (! (typeof(donateWindow) == 'undefined' || donateWindow.closed)) window.donateWindow.close();
window.donateWindow = window.open("http://somesite.com/","tabName");
}
}
Any help on this would be very appreciated. It would seem no matter what I do window.open returns the value "undefined".
My goal is to have a popup shown, but if one is already open it should just replaced the old one. This works as expected in FF, but for the life of me I can not get it going in Chrome.
Why are you trying to close existing window before open a new one? you don't need to do that.
if you just use the same name for window when you open it, it will replace the existing one if there is.
this means you don't need to look for if there is an opened window.
function showDonateWindow()
{
if (window.confirm("Question here"))
{
window.open("http://somesite.com/","donateWindowName");
}
}
I need to warn users about unsaved changes before they leave a page (a pretty common problem).
window.onbeforeunload = handler
This works but it raises a default dialog with an irritating standard message that wraps my own text. I need to either completely replace the standard message, so my text is clear, or (even better) replace the entire dialog with a modal dialog using jQuery.
So far I have failed and I haven't found anyone else who seems to have an answer. Is it even possible?
Javascript in my page:
<script type="text/javascript">
window.onbeforeunload = closeIt;
</script>
The closeIt() function:
function closeIt()
{
if (changes == "true" || files == "true")
{
return "Here you can append a custom message to the default dialog.";
}
}
Using jQuery and jqModal I have tried this kind of thing (using a custom confirm dialog):
$(window).beforeunload(function () {
confirm('new message: ' + this.href + ' !', this.href);
return false;
});
which also doesn't work - I cannot seem to bind to the beforeunload event.
You can't modify the default dialogue for onbeforeunload, so your best bet may be to work with it.
window.onbeforeunload = function() {
return 'You have unsaved changes!';
}
Here's a reference to this from Microsoft:
When a string is assigned to the returnValue property of window.event, a dialog box appears that gives users the option to stay on the current page and retain the string that was assigned to it. The default statement that appears in the dialog box, "Are you sure you want to navigate away from this page? ... Press OK to continue, or Cancel to stay on the current page.", cannot be removed or altered.
The problem seems to be:
When onbeforeunload is called, it will take the return value of the handler as window.event.returnValue.
It will then parse the return value as a string (unless it is null).
Since false is parsed as a string, the dialogue box will fire, which will then pass an appropriate true/false.
The result is, there doesn't seem to be a way of assigning false to onbeforeunload to prevent it from the default dialogue.
Additional notes on jQuery:
Setting the event in jQuery may be problematic, as that allows other onbeforeunload events to occur as well. If you wish only for your unload event to occur I'd stick to plain ol' JavaScript for it.
jQuery doesn't have a shortcut for onbeforeunload so you'd have to use the generic bind syntax.
$(window).bind('beforeunload', function() {} );
Edit 09/04/2018: custom messages in onbeforeunload dialogs are deprecated since chrome-51 (cf: release note)
What worked for me, using jQuery and tested in IE8, Chrome and Firefox, is:
$(window).bind("beforeunload",function(event) {
if(hasChanged) return "You have unsaved changes";
});
It is important not to return anything if no prompt is required as there are differences between IE and other browser behaviours here.
While there isn't anything you can do about the box in some circumstances, you can intercept someone clicking on a link. For me, this was worth the effort for most scenarios and as a fallback, I've left the unload event.
I've used Boxy instead of the standard jQuery Dialog, it is available here: http://onehackoranother.com/projects/jquery/boxy/
$(':input').change(function() {
if(!is_dirty){
// When the user changes a field on this page, set our is_dirty flag.
is_dirty = true;
}
});
$('a').mousedown(function(e) {
if(is_dirty) {
// if the user navigates away from this page via an anchor link,
// popup a new boxy confirmation.
answer = Boxy.confirm("You have made some changes which you might want to save.");
}
});
window.onbeforeunload = function() {
if((is_dirty)&&(!answer)){
// call this if the box wasn't shown.
return 'You have made some changes which you might want to save.';
}
};
You could attach to another event, and filter more on what kind of anchor was clicked, but this works for me and what I want to do and serves as an example for others to use or improve. Thought I would share this for those wanting this solution.
I have cut out code, so this may not work as is.
1) Use onbeforeunload, not onunload.
2) The important thing is to avoid executing a return statement. I don't mean, by this, to avoid returning from your handler. You return all right, but you do it by ensuring that you reach the end of the function and DO NOT execute a return statement. Under these conditions the built-in standard dialog does not occur.
3) You can, if you use onbeforeunload, run an ajax call in your unbeforeunload handler to tidy up on the server, but it must be a synchronous one, and you have to wait for and handle the reply in your onbeforeunload handler (still respecting condition (2) above). I do this and it works fine. If you do a synchronous ajax call, everything is held up until the response comes back. If you do an asynchronous one, thinking that you don't care about the reply from the server, the page unload continues and your ajax call is aborted by this process - including a remote script if it's running.
This can't be done in chrome now to avoid spamming, refer to javascript onbeforeunload not showing custom message for more details.
Angular 9 approach:
constructor() {
window.addEventListener('beforeunload', (event: BeforeUnloadEvent) => {
if (this.generatedBarcodeIndex) {
event.preventDefault(); // for Firefox
event.returnValue = ''; // for Chrome
return '';
}
return false;
});
}
Browsers support and the removal of the custom message:
Chrome removed support for the custom message in ver 51 min
Opera removed support for the custom message in ver 38 min
Firefox removed support for the custom message in ver 44.0 min
Safari removed support for the custom message in ver 9.1 min
Try placing a return; instead of a message.. this is working most browsers for me.
(This only really prevents dialog's presents)
window.onbeforeunload = function(evt) {
//Your Extra Code
return;
}
You can detect which button (ok or cancel) pressed by user, because the onunload function called only when the user choise leaveing the page. Althoug in this funcion the possibilities is limited, because the DOM is being collapsed. You can run javascript, but the ajax POST doesn't do anything therefore you can't use this methode for automatic logout. But there is a solution for that. The window.open('logout.php') executed in the onunload funcion, so the user will logged out with a new window opening.
function onunload = (){
window.open('logout.php');
}
This code called when user leave the page or close the active window and user logged out by 'logout.php'.
The new window close immediately when logout php consist of code:
window.close();
I faced the same problem, I was ok to get its own dialog box with my message, but the problem I faced was :
1) It was giving message on all navigations I want it only for close click.
2) with my own confirmation message if user selects cancel it still shows the browser's default dialog box.
Following is the solutions code I found, which I wrote on my Master page.
function closeMe(evt) {
if (typeof evt == 'undefined') {
evt = window.event; }
if (evt && evt.clientX >= (window.event.screenX - 150) &&
evt.clientY >= -150 && evt.clientY <= 0) {
return "Do you want to log out of your current session?";
}
}
window.onbeforeunload = closeMe;
<script type="text/javascript">
window.onbeforeunload = function(evt) {
var message = 'Are you sure you want to leave?';
if (typeof evt == 'undefined') {
evt = window.event;
}
if (evt) {
evt.returnValue = message;
}
return message;
}
</script>
refer from http://www.codeprojectdownload.com
What about to use the specialized version of the "bind" command "one". Once the event handler executes the first time, it’s automatically removed as an event handler.
$(window).one("beforeunload", BeforeUnload);
Try this
$(window).bind('beforeunload', function (event) {
setTimeout(function () {
var retVal = confirm("Do you want to continue ?");
if (retVal == true) {
alert("User wants to continue!");
return true;
}
else {
window.stop();
return false;
}
});
return;
});