Search code examples
javascriptjqueryember.jscross-domaindeezer

How can I make an Ember action considered a trusted event so that window.open succeeds?


My ember app must open a window (via an external JS API) and the corresponding API instruction should be called by a controller action, since it should then transition to another route.

My problem is that when the action is triggered, the window won't open. It will only open from a code dealing directly with a trusted event, i.e. a click from the user.

So, getting away from Ember and debugging with jQuery and supposing that the window.open() instruction is in the MyLib.login(), this code A works:

$('#mybutton').click(() ->
  MyLib.login()
)

but this code B doesn't:

$.myNamespace = {
  myLoginFunction: () ->
    MyLib.login()
}

$('#mybutton').click(() ->
  $.myNamespace.myLoginFunction()
)

and an ember action won't work either, generating the same code as B, which after debugging, is that window.open() will return an undefined object.

My questions are:

  • Is there a way I can make code B work? (which would make a lot of sense for factorizing reasons)
  • Is there a way an Ember action can also work?

PS: for more transparency, the lib I'm talking about is Deezer's JavaScript SDK.

PPS: pardon my CoffeeScript


Solution

  • First of all, what you are fighting here is the pop-up blocker that most browsers have enabled by default these days.

    I am only familiar with the way the pop-up blocker works in Firefox (originally implemented in bug 252326 and not changed much since then), other browsers are similar however. The idea is simple: pop-ups can only open in response to an explicit user action. This goes beyond trusted events, only mouse clicks and key presses count as such actions. All other pop-ups are considered undesirable and will be blocked.

    So, to answer your question:

    How can I make an Ember action considered a trusted event so that window.open succeeds?

    Any code running in response to a user action (meaning synchronous code execution) is allowed to open pop-ups. As to other code, e.g. delayed actions (including asynchronous callbacks to synchronous code executed in response to a user action) or code responding to application-generated events - the pop-up blocker won't let is pass and there is nothing you can do about it. A web application cannot fake trusted events, just as it cannot circumvent the pop-up blocker at will (either one would be a security issue).

    Is there a way an Ember action can also work?

    You have essentially two options:

    1. window.open() will return null in Firefox if blocked (behavior in other browsers might be different). You could detect this and ask the user to add your site to pop-up blocker exceptions. However, most of them will ignore such requests.
    2. You change the way your web application works. E.g. you could open an empty pop-up window when the user clicks the "log in" button but only fill it with real content later. Or you could move the login action into the pop-up window. Or you could stop using pop-up windows altogether and display a layer in your main window instead. Your choice.

    Obviously, the second option makes more sense and that's what all websites do. Fighting browser's security mechanisms is no fun.