I know this post is pretty old, but in case it helps anybody, I recently looked into basically doing the same thing using localStorage and sessionStorage.
Similar Anthony's answer, it sets an interval to make sure the originating tab keeps the entry fresh, so that if the browser crashes or somehow closes without calling the unload event (included in the comments but not part of the code for testing purposes), then there would just be a short delay before the application would run properly in a new browser window.
Obviously, you would change the "tab is good", "tab is bad" conditions to do whatever logic you want.
Oh, and also, the createGUID method is just a utility to make the session identifier unique... it is from this answer to a previous question (wanted to make sure I wasn't taking credit for that).
https://jsfiddle.net/yex8k2ts/30/
let localStorageTimeout = 15 * 1000; // 15,000 milliseconds = 15 seconds.
let localStorageResetInterval = 10 * 1000; // 10,000 milliseconds = 10 seconds.
let localStorageTabKey = 'test-application-browser-tab';
let sessionStorageGuidKey = 'browser-tab-guid';
function createGUID() {
let guid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
/*eslint-disable*/
let r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
/*eslint-enable*/
return v.toString(16);
});
return guid;
}
/**
* Compare our tab identifier associated with this session (particular tab)
* with that of one that is in localStorage (the active one for this browser).
* This browser tab is good if any of the following are true:
* 1. There is no localStorage Guid yet (first browser tab).
* 2. The localStorage Guid matches the session Guid. Same tab, refreshed.
* 3. The localStorage timeout period has ended.
*
* If our current session is the correct active one, an interval will continue
* to re-insert the localStorage value with an updated timestamp.
*
* Another thing, that should be done (so you can open a tab within 15 seconds of closing it) would be to do the following (or hook onto an existing onunload method):
* window.onunload = () => {
localStorage.removeItem(localStorageTabKey);
};
*/
function testTab() {
let sessionGuid = sessionStorage.getItem(sessionStorageGuidKey) || createGUID();
let tabObj = JSON.parse(localStorage.getItem(localStorageTabKey)) || null;
sessionStorage.setItem(sessionStorageGuidKey, sessionGuid);
// If no or stale tab object, our session is the winner. If the guid matches, ours is still the winner
if (tabObj === null || (tabObj.timestamp < new Date().getTime() - localStorageTimeout) || tabObj.guid === sessionGuid) {
function setTabObj() {
let newTabObj = {
guid: sessionGuid,
timestamp: new Date().getTime()
};
localStorage.setItem(localStorageTabKey, JSON.stringify(newTabObj));
}
setTabObj();
setInterval(setTabObj, localStorageResetInterval);
return true;
} else {
// An active tab is already open that does not match our session guid.
return false;
}
}
if (testTab()) {
document.getElementById('result').innerHTML = 'tab is good';
} else {
document.getElementById('result').innerHTML = 'tab is bad';
}