I was developing a GreaseMonkey script which used window.showModalDialog.
But before finishing it, I have discovered that Firefox 29 warns:
Use of window.showModalDialog() is deprecated. Use window.open()
instead. For more help
https://developer.mozilla.org/en-US/docs/Web/API/Window.open
But the problem is that window.open needs UniversalBrowserWrite privilege in order to open a modal window using window.open.
Then, why is window.showModalDialog deprecated? Is there any API which doesn't require privileges?
Note: I don't want a fake modal dialog (like jQuery's one), I need a real modal which pauses JavaScript execution.
Why is window.showModalDialog deprecated?
From http://tjvantoll.com/2012/05/02/showmodaldialog-what-it-is-and-why-you-should-never-use-it/,
In general the idea of putting a native dialog implementation into the
browser was a really good idea, but window.showModalDialog was a bad
implementation that is riddled with issues and poor browser support. (...)
Note that (...) [a modal dialog using showModalDialog] is a full HTML
document, not a snippet that is injected in. This is a characterizing
feature of window.showModalDialog. It’s really just two completely
separate windows communicating with each other. The fact that you have
two separate windows and DOMs means you don’t have to worry about JS &
DOM conflicts, which is appealing if you have a lot of bad JavaScript
with a cluttered global scope. But mostly this just adds unnecessary
complexity, complicates the browser implementation, and contributes to
a number of bugs. (...)
While it’s important that modal dialogs prevent the user from
interacting with the originating window, there’s no reason the user
shouldn’t be allowed to interact with other tabs or native browser
controls (back/forward, favorites, address bar, etc). (...) This is
actually a big annoyance to the end user. (...)
The debugging experience for window.showModalDialog is horrible.
(...) You're basically forced to alert like it’s 1999 to determine
what’s going on. (...)
Currently no major mobile browsers support window.showModalDialog,
so if you’re looking for any sort of tablet / mobile support you need
to stay away.
What to use instead?
HTML5 introduces the new <dialog> element, which can be used to display dialogs, including modal ones.
For example:
<dialog id="myDialog">
Foo bar
<button id="hide">Close</button>
</dialog>
<button id="show">Show Dialog</button>
var dialog = document.getElementById('myDialog');
document.getElementById('show').onclick = function() { dialog.showModal(); };
document.getElementById('hide').onclick = function() { dialog.close(); };
Demo
The problems are:
Browser support is currently negligible, but there is a polyfill.
It doesn't pause JS execution.
You can use my showModalDialog polyfill using <dialog> tag if you want to still use this solution.
Currently, if you don't want to use privileges and want to use modal window, best way is to use jQuery UI Dialog or something similar.
To block script execution, use while (true) { }. The fact that this is equivalently bad behavior to showModalDialog is part of the reason they removed showModalDialog.
Also, "modal" and "blocking script execution" are not the same thing. "Modal" simply means on top of everything else, preventing you from interacting with those things. So jQuery UI dialogs are modal, they just don't block script execution.
Related
I have a link that opens a new window using window.open. The pop up works fine, however the normal web page stops loading objects (images, scripts, ajax scripts) and sometimes the page doesn't load at all.
Here is my code:
MyWindow=window.open('player.php','Player','width=500','height=300'); return false;
Is there anything I am doing wrong?
Thanks,
Peter
First of all, please be more specific: tell us more about your browser and which version, and possible your OS. It could be more related to the browser than to the web content.
Then on to the possible problem; you start with saying "I have a link that ...".
To me that sound like you use <a href="javascript:DoSomething()">. Or perhaps <a href="#" onclick="DoSomething()">.
I tried both in some modern browsers: Chrome v37, IE v11. Both browsers did not produce what you describe:
- Chrome v37 will happily keep on loading, even if I immediately click a "window.open()"-link on top of a (huge) webpage;
- IE v11 will someshow show "false", which is strange, but still not what you got.
In some cases I also got to deal with the popup blocker.
A general tip might be to NOT USE <a href> for things like this. Behaviour seems inconsistent across browsers, also these days there are better alternatives, such as <span onclick="">...</span> and <button onclick="">...<button> or by using JQuery or other frameworks (which I do not know much about).
Although this many not be a conclusive answer, maybe this can help you experiment on your own, and think about possible causes or alternative ways of doing things.
The behaviour you describe should definitely NOT normally happen. This is confirmed by robbmj's JSFiddle, that fails to reproduce the problem. That's evidence that something is going on in the main page that is not plain vanilla page loading, or your "link opening" has something unusual to it. Apart from the syntax error (you use four parameters, not three).
Since you do not supply information on either of these points (how do you load the main page? How do you trigger the popup-opening code?), we do not even know if the problem
might be browser-related; I'd start and try to test things in IE, Chrome and Mozilla to see
whether anything changes; this might provide some useful insights.
One possibility
A very strong possibility is that your inadvertent fourth parameter goes into the window.open() "replace" parameter, which is a boolean, and triggers undefined behaviour or simply an error that stops everything. You should have things somewhat working in IE and not working at all in Firefox.
You should also be able to see whether this is the case by using Firefox and the Firebug extension, or the Web Developer Console in Chrome.
Another possibility
A more esoteric possibility is that the way you define the link might make the browser believe you've actually moved on to another page, so that there's no point in continuing loading the current page. Depending on the browser, this might have to do with how the link is defined and could be remedied by defining it some other way.
For example it could conceivably happen if you had
...
which I suspect is what led user Tomzan to ask, "is the link something like javascript:...?"
So if this is the case, try with this instead (this works for me in IE9/Chrome/FF):
link
function openPopup() {
MyWindow = window.open('player.php', 'Player', 'width=500, height=300');
// Also try the following. You won't probably like the results (it should send the
// popup window behind), but if it works, it proves we're dealing with a browser
// issue there.
// Blur and refocus
// MyWindow.blur();
// window.focus();
// Just focus
// window.focus();
return false;
}
Workaround
A possibly acceptable workaround could be to disable the link altogether (or hide it via CSS), and only reactivate/show it upon main document being ready. This sidesteps the problem, even if user experience could be somewhat worse due to a longer wait.
But if it's so likely that a user clicks on the link before waiting for the whole page to load, I'd also consider not automatically loading the rest of the page at all, and reorganize information to provide a more streamlined navigation. Or maybe distribute it on two sequential pages. Again, unfortunately you did not supply enough information to do more than guess.
As you probably know, JavaScript is single threaded. Every event is queued until there is idle time for it to be executed.
In the case of window.open, both windows must share a single context to keep it thread-safe because the opened window can access to it's parent using window.opener.
I don't know how browsers implements it, but we can guess two possibilities:
Idle time is shared between the two windows. It means if the popup does many blocking statements, it can freeze the main window's events.
Only one of the two windows can be active, which depends on which one has the focus. In that case, all events may be paused in the main window when you're using the popup.
If you want a more precise answer, I need more details about your code.
document.addEventListener("DOMContentLoaded", function () {
//whatever the code
MyWindow=window.open('player.php','Player','width=500','height=300'); return false;
}, false);
Try to wrap the code in SetTimeout
setTimeout(function () {
window.open( .. )
}, 0);
Your document should be loaded first, then popup should be open, So write your javascript code in the scope of $(document).ready().
enter code here
$(document).ready(function(){
$("#clickme").click(function(e){
MyWindow=window.open('player.php','Player','width=500','height=300'); return false;
});
});
So we have an internal web app that was written back in the IE6 days that we are trying to get to a state where it will work cross-browser, including mobile devices. We are using ASP.NET and the codebehind is written in VB.NET.
Unfortunately the app uses the showModalDialog function that only really works in Internet Explorer (and sort of in Firefox) all over the place. It also makes use of the window.returnValue from these popups, so what it expects is that when PopUpWindow() is called, the javascript would block on that statement and stop execution. Most calls are of the form "var a = PopUpWindow(..)". Then when the popup is closed, it would resume and set a to the returnValue and then make use of it.
It looks like these days javascript doesn't really do blocking function calls, which is making the process of finding an easy cross-browser replacement frustrating. We have a javascript file that is included on every page that contains the function that opens the popup windows. We would ideally like to replace this function in this file and have it work across the application without having to make changes on every single page where there is a popup.
Is there anything that would help with this or is there a standard way of replacing these kinds of dialog popups? We are looking at replacing them with jQuery dialogs but since we would need to use a callback function to get the returnValue it wouldn't work as a drop-in replacement. I'm getting the feeling that there is no easy way to do this (since our code relies on blocking javascript) and we will have to bite the bullet and make the changes to each page with a popup.
You can use my showModalDialog polyfill using a modal <dialog> element, which works in the latest Google Chrome. For other browsers, a <dialog> polyfill is available.
I have a requirement to have some modal popups appear on a webpage. At first i implemented them as true modal windows, but then i found out that true modal windows cannot communicate with parent window in IE.
Now i am trying to implement them as regular windows that always steal focus, which is sorta working.
Here is the code that i am using:
modalPopup = window.open(url, 'popup', arr.join(",")); //use a global var here
modalPopup.focus();
$(window).bind("focus.modal", function(){
if(modalPopup){
modalPopup.focus();
} else {
$(window).unbind("focus.modal");
}
});
There are several things wrong with this:
In firefox, once i close the popup, the modalPopup does not become null, it points to parent window. (this is ok, since we dont support firefox anyway)
In IE, it works like a charm when you open 1 window and close it, but opening any more windows results in the exception:
Error: The callee (server [not server application]) is not available and disappeared; all connections are invalid. The call did not execute.
edit: In IE the error happens when modalPopup.focus(); is called. apparently modalPopup is never set to a falsy value when closed :P
Can you help me write a better implementation that uses window.open for creating the popups?
Before anyone says anything, using lightbox is not an option. The popup windows contain A TON of html, javascript etc, and loading them in the DOM is not going to result in a good UX. Also, we sorta have to have this work on IE6.
The windows containing a "ton" of JavaScript, HTML, etc. isn't a reason that you can't use "lightbox" style techniques (which do work on IE6; I don't know if a specific library you've looked at doesn't). The technique is simple:
Have an absolutely-positioned iframe on the page whose z-index is higher than any other content normally shown on the page. Normally the iframe is hidden.
When doing a "modal," show that iframe and set it to cover all other content. Create an absolutely-positioned div with a higher z-index than the iframe and place it wherever you want (typically in the middle of the viewport).
Put your "modal" content in that div. This can be pre-loaded, or you can demand-load JavaScript and other resources to fill it.
Have a UI control of some sort on the div that "closes" it by removing the div and hiding the iframe.
You can build very rich UIs with this that (can) have a dramatically better UX than enforced multiple windows. And you have the advantage of avoiding cross-windows communication and potentially offering much better response time to the user when they "open" one of these windows.
When flash has keyboard focus, CTRL+T (new tab) and CTRL+N (new window) are intercepted by flash.
Is there a way to pass these events through to the browser so that they work (opening new tab, opening new browser) OR is there a javascript command for these actions?
This is a long standing issue with Flash and browsers. (And I mean long - check out this eight-year-old bug on Mozilla browsers.) The problem is that Flash intercepts all input events, rather than the browser. It's sandboxed in its own environment, and doesn't pass events back to the browser.
Conceptually, this isn't necessarily a bad thing. What happens when Flash wants to listen to a ctrl + n event? Should the browser take focus away from Flash because it uses that hotkey already? It'd be a real pain for Flash developers, that is for sure.
There have been proposals on how to fix this issue that I've seen for particular browsers, but there's no catch-all solution. For example, this solution is referenced in the bug, but it obviously won't work the way you want (since the user will have to jump through quite a few hoops to get it working).
So... no, for now. Would be really neat if this problem could be fixed.
Closest you could get is to have ActionScript trigger Javascript to open a blank window to a blank URL
// We abstract it in a function here in case we want to
// change it later
function openBlankWindow()
{
window.open( '' );
}
For most people, this will launch a new window or a new tab (depending on their browser preferences) but since it is being initiated by the web page, may be subject to pop-up blockers.
There is no way to actually ask the browser to specifically do one of the two tasks you are asking about. I would be a security/annoyance nightmare if web pages had the permissions/privileges to do that.
Situation: you've got a .swf embedded in an html page, and when you click on something in the .swf, it needs to popup a chromeless window. Normally this would be fairly easy - but consider Safari, which completely disables all 'window.open' functionality while its popup-blocker is enabled (it makes an exception if the function is triggered onclick, but it doesn't count clicks in flash). How can you create something which gracefully degrades (provides an alternate and roughly equivalent experience) for browsers that won't execute window.open?
(note: this is AS3, and Safari 3 for PC or Mac we're talking about - but more broadly, any browser that doesn't support or refuses to allow the javascript window.open function.)
If your SWF is loaded using wmode='opaque' or wmode='transparent', then you could have the SWF output JavaScript code that would create an empty <div> that's positioned over the SWF area. That <div> could then handle the onclick event and create the popup window rather than the Flash code.
the div overlay was more complicated than the project deserved - check out code.google.com/p/popupfromflash for the code I came up with.
It attempts to use ExternalInterface to setup a window.open function, and if that fails (particularly in Safari) it calls back into flash and prompts it to do a navigateToURL to pop up the window normally (instead of chromlessly)