AngularJS: How to open a file in a new tab? - javascript

LIVE DEMO
Given a URI of a file, I'd like to open it in a new tab (not a new window).
It looks like it is not possible to use $window.open(uri, '_blank').
So, I tried the following trick:
var link = angular.element('');
angular.element(document.body).append(link);
link[0].click();
link.remove();
and it works.
But, if I put exactly the same code in a promise callback, it doesn't work anymore (it opens the file in a new window instead).
Any idea what's going on here?
PLAYGROUND HERE

From your code/content, you can't force the browser to open a new tab (rather than a new window, or vice-versa). It's up to the browser settings to force it one way or another.
Anything else would be a security risk.

Let us understand fundamental how pop up blocker work.
If user trigger the function to open a new url, then pop up blocker will allow it(it should applied to any modern browser - at least firefox, chrome)
If not from user (like javascript function in background, promise or any other function trigger not from user), browser will block unless user whitelist the site manually.
This is not working.
function openInNewTab() {
window.open('http://stackoverflow.com','_blank');
}
openInNewTab();//fail
This is working
<h1><button onclick="openInNewTab()">Open In New Tab - working</button></h1>
I created simple plunkr version - http://plnkr.co/edit/QqsEzMtG5oawZsQq0XBV?p=preview
So, to answer your question. It is impossible unless user authorize it (user trigger it or white listed the site).
Quote from firefox -
Pop-up windows, or pop-ups, are windows that appear automatically
without your permission.
https://support.mozilla.org/en-US/kb/pop-blocker-settings-exceptions-troubleshooting
*Open in new tab / new windows not make any difference. Pop up blocker will still always block. It doesn't means that browser will allow if open in new tab. It is just coincidentally for certain browser default the settings in that manner.
Workaround
You can ask user explicitly to trigger the function to open in new tab after the background execution.
You can display message in UI to ask user to open the url.
Example - http://plnkr.co/edit/iyNzpg64DtsrijAGbHlT?p=preview

You can only open new windows inside click event handlers fired by the user.
The reason for this is usability.
I'm not sure if all browsers have this behavior but some browsers do not allow scripts to open windows without the user being noticed. Imagine when you visit a web page and suddenly, the web page opens several windows => it's annoying.
See this DEMO (tested with my Chrome and Firefox), even we trigger click event by script, the browser still blocks the popup.
$("#test").click(function(){
openInNewTab();
});
$("#test").click();
You cannot open a new window inside your ajax success callback because your ajax success is run in another cycle after the click event handler has finished its execution.
See this link for a workaround
if I put exactly the same code in a promise callback, it doesn't work
anymore (it opens the file in a new window instead).
I'm surprised that you're still able to open a new window. But this problem really has a lot of things to do with click events fired by the user.

Your problem is two-fold, and both folds tread on uncertain territory.
In the old days of browsers, window.open did exactly that – open a new window. That's because the concept of tabs hadn't been invented yet. When tabs were introduced, they were treated exactly like windows to improve compatibility, and that tradition continues to this day. That, and the fact that window.open was only standardized very recently, means that JavaScript cannot distinguish between windows and tabs.
There is no "normal" way to specify whether a link should open in a new tab or not. You can use the following hack, though: specify a custom window size to the open call (via the third argument), like so:
window.open('http://example.com', '', 'width=' + screen.width);
This will cause almost all browsers to open a separate window because tabs cannot have custom sizes.
In JavaScript, there are trusted events and untrusted events. Trusted events are, for example, legitimate clicks on a link by the user, whereas an untrusted event would be a manual click() call on a link.
Only trusted event handlers may open new windows/tabs. This is to prevent client-side attacks that crash the browser or confuse a user by rapidly opening a hundred tabs on mouseover or something similar.
Your second example doesn't work because the popup blocker blocks the untrusted event that you triggered via the click(). Although it was caused by a real click, the asynchronous call in-between severs the link to trustedness.

working version
$http.get('https://api.github.com/users/angular').then(openInNewTab());
EDIT----------------
Do not know why but a click() method called from a callback function acts differently than calling it straight.
You can see it here with a set interval example.
That is why I had call the function directly rather than going through a callback.
see it with timer callback

or you can use $window service please see here : http://plnkr.co/edit/8egebfFj4T3LwM0Kd64s?p=preview
angular.module("Demo", []).controller("DemoCtrl", function($scope, $http, $window) {
$scope.uri = 'http://martinfowler.com/ieeeSoftware/whenType.pdf';
function openInNewTab() {
var link = angular.element('');
angular.element(document.body).append(link);
link[0].click();
link.remove();
}
$scope.works = openInNewTab;
$scope.doesntWork = function() {
$http.get('https://api.github.com/users/angular').then($window.open($scope.uri));
};
});

For us the following worked well: http://blog-it.hypoport.de/2014/08/19/how-to-open-async-calls-in-a-new-tab-instead-of-new-window-within-an-angularjs-app/
In short: We remember the reference to the new window and changing the location afterwards.

Related

Get tab URL from page action (WebExtensions, Android)

I would like to get the URL of the current tab within a page action popup.
At first it seems obvious: Just use the tabs API. But that doesn't seem to be available on Android if I deciphering the docs correctly. So I kept looking for something else and found the onClicked event of the pageAction API.
The pageAction API seems to be listed as compatible with Android and the onClicked event is marked as supported. So that implies that it would actually return a tabs.Tab object. But does it really? Has anyone tried it?
What is the best way to retrieve the URL? I know I could just use a content script and let that run in every single tab and create a long lived messaging connection to send the URL to the page action popup whenever it is requested. But that would be very inefficient and make the code insanely complicated compared to how easy it would be using the tabs API.
Is there anything else I could do?
Current (Firefox 54 and later)
As of Firefox 54, the tabs API is available in Firefox for Android. This means you can use the normal methods available to desktop Firefox. Specifically, chrome.tabs.query() or browser.tabs.query(). However, you will need the activeTab and/or tabs permissions in your manifest.json.
chrome.tabs.query:
chrome.tabs.query({active:true,currentWindow:true},function(tabs){
//'tabs' will be an array with only one element: an Object describing the active tab
// in the current window.
var currentTabUrl = tabs[0].url;
});
browser.tabs.query:
browser.tabs.query({active:true,currentWindow:true}).then(function(tabs){
//'tabs' will be an array with only one element: an Object describing the active tab
// in the current window.
var currentTabUrl = tabs[0].url;
});
Prior to Firefox 54
If you have defined a page/browser action popup
If you have defined a popup for your page/browser action, then the onClicked event does not fire. Your popup is not passed any information when it is created/shown. Thus, you will not receive a tabs.Tab object. The normal way to obtain tab information is from tabs.query, which, as you have already determined, is not (yet) available in Firefox for Android.
The APIs available to Firefox on Android are quite limited. For what you are wanting to do, using webNavigation events to keep a record of each tab's frame 0 URL would be more efficient than a content script in every page. You could use the webNavigation.onCommitted or webNavigation.onCompleted events depending on your needs. You will need to assume that the active tab of the current window is the one which most recently had a webNavigation event, or perhaps you could also monitor webRequest events. However, any way that you do it, which tab you assume to be the current tab will just be an assumption, and will be inaccurate under some circumstances.
A more accurate URL (and active tab determination) requires using a content script
If the page that is being visited changes the tab's URL through some method that does not trigger navigation, using webNavigation events will not give you the updated URL. As you have identified, without the tabs API, the only way to be certain you have the actual current URL for the tab, when you define an actual page/browser action popup (and thus don't get a tabs.Tab object), is to inject a content script into every page. You will either need the content scripts to continuously update the URLs, or be listening with storage.onChanged for a request for that information from your background/popup script. Communication from the background/popup scripts to content scripts must be accomplished through the storage API due to not having the tabs API (i.e. no tabs.sendMessage).
Using page/browser action onClicked
An alternative, which I have not tried on Firefox on Android, would be to not define an actual page/browser action popup. If you don't define an actual popup, you receive the onClicked event (getting the tabs.Tab Object with both the active tab's ID and the URL) and then can open a pseudo-popup1.
1. The implementation of opening a a pseudo-popup in my linked answer uses the tabs and windows APIs which are both currently unavailable for Firefox for Android. It could be re-written to use the above mentioned webNavigation listener to track tab URLs and window.open() to open the window used for the pseudo-popup. Again, I have not tested this with Firefox on Android to determine that it actually works.
You can get it this way with webextensions. Take into account that if you want to debug a popup, you have to "prevent popups to be closed" (4-squares icon at the top-right of the browser's toolbox)
var activeTabPromise = browser.tabs.query({active: true, currentWindow: true});
activeTabPromise.then((tabs) => {
console.log(tabs[0].url);
});
I hope this will help you,

How to open a new tab in separate thread with JavaScript? (chrome)

Is it possible to open a new popup tab that would run in a separate thread? To be more specific, if I create a new popup tab and start debugging in that new tab, tab which contains link will also pause javascript until I click resume in a new tab. What I want to achieve is to create a new tab that is separated so I can debug it while parent tab continues running.
I have this problem using Chrome browser. Note that this works fine in Firefox (haven't tested in other browsers).
Usually chrome forces new window to run on the same Process ID.
But, there are techniques which allows sites to open a new window without forcing it into the same process:
Use a link to a different web site that targets a new window without passing on referrer information.
Open in new tab and new process
If you want the new tab to open in a new process while still passing on referrer information, you can use the following steps in JavaScript:
Open the new tab with about:blank as its target.
Set the newly opened tab's opener variable to null, so that it can't access the original page.
Redirect from about:blank to a different web site than the original page.
For example:
var w = window.open();
w.opener = null;
w.document.location = "http://differentsite.com/index.html";
Technically the original website still has access to the new one through w, but they treat .opener=null as a clue to neuter the window.
Source: https://bugzilla.mozilla.org/show_bug.cgi?id=666746
The current version of Chrome does not appear to use a separate thread when using the null opener trick that domagojk referenced. However, if you're in a javascript handler you can still take advantage of the noreferrer link trick he mentions:
var e = document.createElement("a");
e.href="/index.html";
e.target="_blank";
e.rel = "noreferrer";
e.click();
Have you tried using Web Workers? Not sure about support, but they're supposed to offer parallel JS execution functionality. See here and here.
While not exactly an answer, to me it is the best answer. The print dialog should not be blocking.
I have reported this as a bug and given a test case. Show your support at here - https://bugs.chromium.org/p/chromium/issues/detail?id=1023161&q=ryein%20goddard&colspec=ID%20Pri%20M%20Stars%20ReleaseBlock%20Component%20Status%20Owner%20Summary%20OS%20Modified
I think once Chromium fixes this bug we won't have to worry about it any more. It is really the only choice at this point.
So to me the answer is we need Google/Chromium to fix this issue.

Why does browser block popup windows in callback but not otherwise

Strange behavior - Im trying to open a new window in a callback - using Angular but probably a general JS issue.
If I do this:
$window.open('http://google.com', '_blank');
It works fine. However this doesn't as it gets blocked by my browser - I am using Safari 7 and have "block popup windows" checked:
Items.list(function(items) {
$window.open('http://google.com', '_blank')
});
Why does the browser block that and not the other and how can I circumvent this? I played with setTimeout as well as some SO post suggestion to assign $window.open to a variable before calling async but did not work here.
Popup blocker logic often blocks popup windows when the popup window is not opened as a direct consequence of a user action (like a click).
A callback that happens asynchronously is NOT a direct consequence of a user action - it's sometime later and is not directly connected to that action (as the browser sees it), thus the browser may not allow it.
The usual work-around is to open the popup window immediately (as a direct consequence of the user action) and then populate its content later after the asynchronous callback occurs and the content is available.
Does angular 6 support popup window like javascript? I am not looking for a modal window solution. I want to be able move the window to another screen like you can do with JavaScript popup windows. Is there any documentation on that? How can you go about doing it on Angular 5/6 ie to open a pop up window

hotkey plugin opens new window even if pop-ups are blocked?

I want to open new window if "F2" pressed. Below code gives me newWindow is null error message in firefox. If I don't use pop-up blocker it works. The same in IE. It work in chrome even with pop-up blocker on.
using jstree pre 1.0 stable
hotkeys: {
"f3" : function () {
url = "http://www.vse.cz";
var newWindow = window.open(url, '_blank');
newWindow.focus();
return false;
},
Q1: Can I make it work for all browsers so users don't have to change their settings when using hotkeys plugin?
Q2: How come Using JavaScript instead of target to open new windows works without any troubles in firefox? Is that because it's a link and not using hotkeys plugin?
My understanding is that the script from above page somehow
manipulates what happens
when user clicks a link. It changes the properties of the click so
browsers "don't know" that it's new window so pop-up blocker is
bypassed.
In my case I use pure js function triggered by something else, not by
a user click. And that 'my function' doesn't changes properties of any html objects. I think this is the difference. I am not sure if I am
right here.
Unfortunately, there's nothing you can do to open a new window on a keypress (other than disabling the popup blocker).
The way that the popup blockers in IE, Firefox and Chrome work (from a high level) is by the browser (upon encountering a call to window.open) walking up the JavaScript call stack to determine if the current function is—or was called by a function that is—an event handler. In other words, it finds out if the current function is executing because the user did something that triggered a DOM event.
If so, then the popup is allowed; otherwise it is blocked. However, the question of which events qualify as "popup-allowing" vary by browser. By default in Mozilla, only change, click, dblclick, mouseup, reset, and submit qualify. (I assume IE is similar.)
Functions that are event handlers for any other type of event – such as keydown/keyup/keypress in your case – do not qualify for special popup-allowing treatment, which means your popup is blocked and is why your call to window.open returns null.
Chrome, however, does consider the keydown event eligible for allowing popups to be opened, which is why your script works in that browser.
Here's a reduced example to demonstrate how this works. This demo:
Defines a function called spawn() which calls window.open to open a popup.
Calls spawn() immediately as the page is loaded. This is blocked by all browsers since the call is made from the global scope; it is not called from an event handler.
Attaches a function to window.onkeydown which calls spawn(). If you press any key in Chrome, the popup will open because it allows popups from keydown handlers. In IE and Firefox, the popup will be blocked becuase those browsers do not allow popups from keyboard events.
Attaches an event handler to the link which calls spawn(). When you click the link, the popup will be allowed in all browsers because the call to window.open can be traced back to an event handler for a click event.
As you can now see, nothing goes on to manipulate event properties or "trick" the browser in to not knowing that there's a new window. The behavior of popups being allowed to open from link clicks is by design, the theory being that if you've clicked on something, it's likely that you want to see whatever is in the popup. However, when a call is made to window.open from a place where you've not done anything (such as the global scope), it's likely you do not have any interest in whatever [ad] is in the automatically-launching popup.
In this way, popup blockers prevent annoyances (automatically launching ads) while still allowing pages to open popups at the user's request.

window .open is not opening on page load in ie8

Hi unable to open window.open on page load in ie8 If I use window.location its not opening in new page please help me out of this.
This is because you're running into the popup blocker. This is a Good Thing(tm) :-) You can only open popups in response to the user taking an explicit action, like clicking something (and then typically only from within the event handler itself), not on things like page load where the unwitting user could be (and historically has been) inundated with dozens of windows opening all over the place. (And even doing it in response to an explicit user action may not be allowed by some blockers.)
Are no-one seeing a big problem with running window.open(window.location.href,'_blank') in the onload handler?
This is systematically a recursive function which would continue until the user manages to close the new window prior to the onload handler running.
I'm not saying that this has anything to do with the problem it might just be that IE8 is clever enough to see this..

Categories

Resources