Do browsers propagate javascript variables across tabs? - javascript

I have some JavaScript that will look to see if a var is set, if it is set then do something if not don't.
if (reset === 'reset') {
gallery.unformat(container);
}
reset is only set once the page has loaded. So this script will only execute after the user reloads the page.
If i open a new tab in firefox reset isn't set. If i open a new tab in chrome reset is set.
So for my case chrome handles it correctly and only on the first going to the site does this var get set and thus everything works correctly.
I want to know is do variables propagate across tabs and if so which browsers do what?

Variables should not persist across new tabs. I can't reproduce the behaviour you see in Chrome.
You should looking at using cookies, or if you want to be HTML5, look at localStorage.
Both of these are domain specific, rather than per-tab.
E.g. in localStorage, you could go for;
// Check that localStorage is supported in the current browser, and then try
// to retrieve the item.
if ('localStorage' in window && localStorage.getItem('reset') === 'reset') {
gallery.unformat(container);
}
You'd then be able to set reset later via;
localStorage.setItem('reset', 'reset');

No, variable values should not propagate between tabs - each tab should have its own global namespace, there would be all kinds of security issues if one tab could affect the JavaScript in another.

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,

SessionStorage browser wide (scope) or LocalStorage deleted on exit

Is there any mechanism that would allow me handle the values on a browser level? What I mean is either:
sessionStorage that I can access values in ANY tab in browser (something like server side sessions)
localStorage that would be removed on session end (when closing the browser, not tab)
For example, the video starts in player in one tab. Some flag is stored in that kind of storage. When user opens another tab with the same URL, app should read that flag and dissalow playing the video. Of course it should be removed on exit, otherwise flag would dissalow all the future requests in that browser. Any suggestions?
every tab or window data can save/read to local/session storage but it's limited to that domain only.
The question that you asked about video handling over two tabs, it can be pulled of, but that is very tricky to handle, and I would not suggest to go that road! You can periodicaly save timestamps of video to browser storage but it also depends on server that is sending the video to browser, and you could end up not serving the video to the user at all!
For clearing the data when browser window close I think there is no event for that but there is event for window loosing focus so you can use that I guess.
hth,
$(window).on('beforeunload', function DecideAction() {
if (('localStorage' in window) && window['localStorage'] !== null) {
//get value from localstorage using getItem and allow/deny the further access
}
});
If the requirement is to have this last "as long as the browser window is open", you're going to hit repeated issues as browsers don't work on that level any more - there is tab-level and domain-level (persists like cookies). The "Browser Window" is just a collection of tabs, unless you specifically set up your browser in a certain way (to remove cookies and session data on closing and not share data between window instances). This however is browser setup (and isn't even standard across different browsers), and not something you can control client-side.
If you're willing to consider some alternatives that will provide the end result you seem to require, if not in the specific manner you have specified, read on:
To Expand on AkshayJ's original comment, use localStorage as sessionStorage is only ever tab-specific (it can't be shared).
In order to clear the flag, as part of the same functionality that sets the flag, add an onunload event to the tab playing the video that will clear it when the tab is closed or the window location moves away from the video. This will allow greater functionality than you originally requested, because in your original case the user would have to close down the browser entirely before they could play the video again, even if the tab that was playing the video was long gone or had moved on to another page.
UPDATE:
If the security/authorization around this is of paramount importance (rather than just wanting to stop it happening "by accident"), then using localStorage is completely the wrong approach - this data and its existence is ultimately controlled by the user. They can remove it, or set up their browser so that window instances don't share the data, so all they need to do is open a new window to view your video twice at the same time. A determined user would find their way around this in minutes.
If you want to control it absolutely, you have to take this domain side rather than relying on browser storage, and use some other tag like a list of currently-accessing IPs, or some other method of identifying a unique user, to determine whether the video can be played or not. Bear in mind that you would have the same issues as before regarding when to clear the flag whether it's browser side of domain side.
UPDATE:
re: what event to use, it appears that onunload and onbeforeunload are both fully supported across all common browsers (ref: Here and Here). This Answer recommends using both in order to be on the safe side.
UPDATE:
The OP has expressed worry that unload events are unreliable and that the user might remain locked out forever if something goes wrong. Personally I haven't experienced any unreliability here, but if you're worried, then introduce a timeout aspect. Have the tab playing the video update the flag (wherever it is stored) with a timestamp every 30 seconds/1 minute/whatever. Then when a new instance of the page loads, have it check the timestamp. if something has happened to the existing page such that it froze and unload events didn't run, the timestamp will be out of date because it will have also stopped updating, so you just have to check whether the timestamp is out of date as well as checking for presence.
Finally I gave up of the server side sessions because it raised other issues, and solved it with this workflow:
After page load, localStorage value is set if it hasn't been before, as well as flag that the player is opened in this tab. If the localStorage is already set, flag is set to false.
If flag is set, play video, otherwise prohibit.
On page unload, only if the flag is set (that is, if user opened video in this tab), remove localStorage value.
$(function () {
if (localStorage.playerTabOpened) {
var dateNow = Date.now();
var diffSinceLastTabOpened = (dateNow - localStorage.playerTabOpened) / 1000;
// if playerTabOpened value was stored more than 1 day ago, delete it anyway because it could be left by chance
if (diffSinceLastTabOpened > 86400) {
localStorage.removeItem("playerTabOpened");
};
}
if (!localStorage.playerTabOpened) {
shared.playerTabOpenedHere = true;
localStorage.setItem("playerTabOpened", Date.now());
} else {
shared.playerTabOpenedHere = false;
}
});
$(window).on("beforeunload", function () {
if (shared.playerTabOpenedHere) {
localStorage.removeItem("playerTabOpened");
}
});
if (shared.playerTabOpenedHere) {
// play
} else {
// throw error
}

Way to set focus manually (e.g. right click -> set focus) to an element on a website?

I'm working a lot with NVDA to test website accessibility.
One way to move through a website is to use the tab key. So to reach an area that I want to test, I often have to press the tab key until I reach the needed area. This sometimes is very cumbersome and means repeating the tab key again and again after page refreshes.
It would be very nice to somehow set the focus manually, e.g. by right clicking on a link and choose "Set focus" or something like that. It would be even greater to have an extension which automatically sets focus to a specified element after each page refresh, so when developing, the focus is always on the right element after a page refresh.
Is there any browser extension (Chrome/Firefox) for this? I found some extensions that allow to inject custom JS/CSS (Control Freak, JScript tricks, Script Runner for Chrome) which can be used for something like this, but it's still a bit of a hassle.
You can do this using browser cache to save the last field accesed and then you can focus the concrecte input with something like
$(selector).focus(); //for example with jQuery.
Store/Retrive data from browser cache:
// Store
localStorage.setItem("lastname", "Smith");
// Retrieve
document.getElementById("result").innerHTML = localStorage.getItem("lastname");
http://www.w3schools.com/html/html5_webstorage.asp

Communicating between different windows on the same domain [duplicate]

This question already has answers here:
Communication between tabs or windows
(9 answers)
Closed 6 years ago.
I am building an app that performs a lot of client side data downloading and processing. The data processing is isolated from the main app by being processed in an iframe that resides on a sub domain. It is this iframe that downloads the data. Communication is via postMessage.
Everything works fine, except it could be better.
If the user opens extra tabs/windows, the app currently reloads all the data and may even do duplicate processing work, which isn't a problem other than that it slows everything down and pages take longer to load.
What I would like to do is have each top level tab/window communicate with just the one processing iframe, which could be reinstated if the original window is closed. The trouble is, these are not opened via javascript, but via the normal browser methods to open links in tabs so I can't get a reference to the iframe that is needed to send a message.
Is there anyway I can communicate the window reference for the iframe to the other tabs so that they can communicate with it via a postMessage? Could this in someway be achieved using shared workers?
I realize I could use shared workers for the whole processing task, but this would have it's own problems as the the data comes from third party domains, which can't be accessed from within a worker.
Only compatibility with the latest versions of all major browsers is needed.
Edit: I've just discovered that SharedWorker is not yet implemented in firefox, so I guess that is not going to work. Any other way I could achieve this?
Edit 2: I've discovered that you can use :
var win = window.open('', 'my_window_name');
to capture a reference to an iframe from any other window. However, if the iframe does not already exist then it will open it as a window. Even if it is closed immediately, it causes a flicker and causes the 'popup blocked' messages, making it unusable.
In case any one else finds this, I've come up with a solution. It is somewhat hacky and requires further testing. But so far it is working. It works cross domain if that is needed.
It uses a combination of two tricks.
The first is to use
remote_window = window.open("", "remote_window_name");
to fetch a reference to the window. This works because if a window is already open with the given name then a reference is returned to it rather than opening a new window.
It does however have the problem that if the iframe does not exist then a new window will pop up. Local storage is used in order to prevent this. When a window/tab loads, it checks localStorage to see if there is another page already with a shared iframe. If not it inserts the the iframe and sets a flag in local storage to say that it is available.
As a last ditched resort, if the window still opens, a try block is used to close the newly opened window. The try block prevents cross domain errors. This means that the worst that will happen is the user sees a window pop up and disappear or they will see the 'enable pop-ups' message. I've yet to manage to trigger this in testing - it is only an edge case fall back.
try {
if(store_window.location.href === "about:blank" ){
remote_window.close();
remote_window = insertIfame();
}
} catch(err) {
}
An onunload event is added which removes the flag should the page be closed.
Also a setInterval is created that constantly refreshes a timeout flag. I have it running 4 times a second; when a second window/tab is loaded it checks that the iframe flag has not timed out before trying to communicate with it. This is a small overhead, but far less than the cost to me of having that second iframe loading. This serves the purpose of preventing stale data if the browser crashes or the the onunload does not fire for any reason. I include a small leeway when checking the timeout - currently 1 second - in case the main window is stuck in a loop. The leeway is only on the timeout, not the unload event which removes the flag entirely.
The flag needs to be checked every time a message is sent in case the original window with the iframe has closed. When this happens the iframe is reinserted in the first open window that requires it and the flag is reset.
Sending messages back is easy. Just use the event.source property of the receiveMessage -this points to the sending window.
One final edge case to account for is if the primary window closes whilst it's iframe is mid process for a secondary window. Theoretically this could be dealt with by using an onunload event in the iframe to send a message back to any windows with data in process. But I've yet to implement it and it may not finish before the page unloads. Another way of dealing with it would be by having a timeout in the secondary window which checks the flag and retries, I'll probably go this route as the messages already have timeouts attached.

Ways to detect CTRL-N or when a user opens a new window

How can we detect when a user opens a new window. The user is already authenticated and we make heavy use of sessions.
We were trying to avoid Ctrl+N javascript hooks but maybe that is an option.
I am assuming the request is the exact same URL...with Ctrl+N?
We were trying to avoid ctrl-n javascript hooks
Forget it. Whilst you could in theory try to catch keypress events for ‘n’ with the Control key modifier, there are any number of other ways to open a new window or tab which may be more likely to be used, and you won't be able to catch. File->New Window/Tab, middle click or shift-click link, middle click back/forward buttons, right-click-open-in-new-window, open bookmark in new tab, double-click browser icon...
The user is already authenticated and we make heavy use of sessions.
That shouldn't be a problem in itself. I guess what you mean is that your application is dumping all sorts of page-specific data in the session that it shouldn't have, and now you find the application breaks when you have more than one window open on it? Well, commiserations and happy rewriting.
In the meantime about all you can do is tell the user “please don't try to open two browser windows on the same application”. There are potential ways you can make JavaScript on one page notice that JavaScript is running on another page in the same domain at the same time, generally involving using document.cookie as a inter-page communications conduit. But that's also a bit fragile.
If opening a new window causes a problem in your application, then you should fix the application code to handle it instead of trying to apply an inconsistent and unreliable client-side "bandage". That's my opinion.
Why?
And anyway you can't detect it. User can open new window not only with Ctrl+N but also with File->New Window.
You could possibly put a window count into the session and increment it on window.onload and decrement it on window.onunload.
Imagine me tutting, sucking air through my teeth and going "better you than me, guvna" if you use that, though.
What I have done to solve this issue is when the user authenticates set the window name on valid login.
<script>
window.name = 'oneWindow';
</script>
And then on the master page do a javascript check:
<script>
if (window.history.length == 0 || window.name != 'oneWindow')
//history length to see if it's a new tab or opened in a new window 0 for IE, 1 for FF
//window name to see if it's a CTRL + N new window
</script>
If the check is true then hide/remove the main content of the page and show a message stating they are doing something unsupported.
This works when your login page is not tied into the master page.
If you do not have a master page then I would suggest putting the check on all your pages.
Yes and no,
You'll always see it if a control has focus, else the event is sent directly to the browser and the code on the page never hear about it.
In my experience you can't hijack the browser's shortcut, your mileage may vary. You are likely to know it happened but the browser will do its thing (for obvious reason)
In most browsers, the effect of Ctrl-N is to open a new window at the same URL as the old one and associate it with the same sessionID.
Your best bet would be to modify the back end code if possible and allow for such things. Breaking the browser's feature is never a good thing.

Categories

Resources