I want to check with JavaScript if the user has already opened my website in another tab in their browser.
It seems I cannot do that with pagevisibility...
The only way I see is to use WebSocket based on a session cookie, and check if the client has more than one socket. But by this way, from current tab, I have to ask my server if this user has a tab opened right next to their current browser tab. It is a little far-fetched!
Maybe with localstorage
?
Modern websites use multiple "event listeners" and can detect every move the user is executing. So, if a user switches the tab or hovers over to another tab, it can gather the data and see whether the user stayed on the web page or not. A website can detect this anomaly by using cookies and IDs.
You cannot (and should not) do that. User can always just open use another browser or another computer to open another view onto the web site. So, basically you cannot ever prevent this. Your web-site should be able to handle multiple tabs viewing the same state.
How do you check if a tab is already open in Javascript? if (+localStorage. tabCount > 0) alert('Already open! '); else localStorage.
Using local storage I created a simple demo that should accomplish what your looking to do. Basically, it simply maintains a count of currently opened windows. When the window is closed the unload events fire and remove it from the total window count.
When you first look at it, you may think there's more going on than there really is. Most of it was a shotty attempt to add logic into who was the "main" window, and who should take over as the "main" window as you closed children. (Hence the setTimeout calls to recheck if it should be promoted to a main window) After some head scratching, I decided it would take too much time to implement and was outside the scope of this question. However, if you have two windows open (Main, and Child) and you close the Main, the child will be promoted to a main.
For the most part you should be able to get the general idea of whats going on and use it for your own implementation.
See it all in action here: http://jsbin.com/mipanuro/1/edit
Oh yeah, to actually see it in action... Open the link in multiple windows. :)
I've made the necessary changes to have the the local storage maintain the "main" window. As you close tabs child windows can then become promoted to a main window. There are two ways to control the "main" window state through a parameter passed to the constructor of WindowStateManager. This implementation is much nicer than my previous attempt.
JavaScript:
// noprotect var statusWindow = document.getElementById('status'); (function (win) { //Private variables var _LOCALSTORAGE_KEY = 'WINDOW_VALIDATION'; var RECHECK_WINDOW_DELAY_MS = 100; var _initialized = false; var _isMainWindow = false; var _unloaded = false; var _windowArray; var _windowId; var _isNewWindowPromotedToMain = false; var _onWindowUpdated; function WindowStateManager(isNewWindowPromotedToMain, onWindowUpdated) { //this.resetWindows(); _onWindowUpdated = onWindowUpdated; _isNewWindowPromotedToMain = isNewWindowPromotedToMain; _windowId = Date.now().toString(); bindUnload(); determineWindowState.call(this); _initialized = true; _onWindowUpdated.call(this); } //Determine the state of the window //If its a main or child window function determineWindowState() { var self = this; var _previousState = _isMainWindow; _windowArray = localStorage.getItem(_LOCALSTORAGE_KEY); if (_windowArray === null || _windowArray === "NaN") { _windowArray = []; } else { _windowArray = JSON.parse(_windowArray); } if (_initialized) { //Determine if this window should be promoted if (_windowArray.length <= 1 || (_isNewWindowPromotedToMain ? _windowArray[_windowArray.length - 1] : _windowArray[0]) === _windowId) { _isMainWindow = true; } else { _isMainWindow = false; } } else { if (_windowArray.length === 0) { _isMainWindow = true; _windowArray[0] = _windowId; localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(_windowArray)); } else { _isMainWindow = false; _windowArray.push(_windowId); localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(_windowArray)); } } //If the window state has been updated invoke callback if (_previousState !== _isMainWindow) { _onWindowUpdated.call(this); } //Perform a recheck of the window on a delay setTimeout(function() { determineWindowState.call(self); }, RECHECK_WINDOW_DELAY_MS); } //Remove the window from the global count function removeWindow() { var __windowArray = JSON.parse(localStorage.getItem(_LOCALSTORAGE_KEY)); for (var i = 0, length = __windowArray.length; i < length; i++) { if (__windowArray[i] === _windowId) { __windowArray.splice(i, 1); break; } } //Update the local storage with the new array localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(__windowArray)); } //Bind unloading events function bindUnload() { win.addEventListener('beforeunload', function () { if (!_unloaded) { removeWindow(); } }); win.addEventListener('unload', function () { if (!_unloaded) { removeWindow(); } }); } WindowStateManager.prototype.isMainWindow = function () { return _isMainWindow; }; WindowStateManager.prototype.resetWindows = function () { localStorage.removeItem(_LOCALSTORAGE_KEY); }; win.WindowStateManager = WindowStateManager; })(window); var WindowStateManager = new WindowStateManager(false, windowUpdated); function windowUpdated() { //"this" is a reference to the WindowStateManager statusWindow.className = (this.isMainWindow() ? 'main' : 'child'); } //Resets the count in case something goes wrong in code //WindowStateManager.resetWindows()
HTML:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>JS Bin</title> </head> <body> <div id='status'> <span class='mainWindow'>Main Window</span> <span class='childWindow'>Child Window</span> </div> </body> </html>
CSS:
#status { display:table; width:100%; height:500px; border:1px solid black; } span { vertical-align:middle; text-align:center; margin:0 auto; font-size:50px; font-family:arial; color:#ba3fa3; display:none; } #status.main .mainWindow, #status.child .childWindow { display:table-cell; } .mainWindow { background-color:#22d86e; } .childWindow { background-color:#70aeff; }
The shorter version with localStorage
and Storage listener
<script type="text/javascript"> // Broadcast that you're opening a page. localStorage.openpages = Date.now(); var onLocalStorageEvent = function(e){ if(e.key == "openpages"){ // Listen if anybody else is opening the same page! localStorage.page_available = Date.now(); } if(e.key == "page_available"){ alert("One more page already open"); } }; window.addEventListener('storage', onLocalStorageEvent, false); </script>
Update:
chrome://inducebrowsercrashforrealz
Live demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With