8

I would like to detect if user has open more than one window or tab on the same session and if he did it - I would like to print an special information on screen.

This limte should oblige only in one special URL, so if user has open two tabs/windows with urls: http://page.com/limite.htm - I would like to print special information. When user has open two windows/tabs with urls: http://page.com/limite.htm and http://page.com/index.htm - everything is OK and I wouldn't show any informations.

Is it possible? Thanks.

Newester
  • 1,457
  • 2
  • 14
  • 26

3 Answers3

3

I think the best way to do it is with localStorage. http://www.gwtproject.org/doc/latest/DevGuideHtml5Storage.html

From the link, about localStorage:

Availability to other Windows/tabs: Shared across every window and tab of one browser running same web app

So, you could set an entry when the tab/window is open, and change it when it's closed. When another tab/window is open, you first check this entry value.

Obviously you need to be careful: browser crashes, for example, might not trigger the "on close" part, so the user wouldn't be able to open a new tab, even with none open (localStorage persists!). If you have server sessions, you can ask the user to login again (or run your auth process again), and reset this value. You can also try to use a sessionStorage entry to keep track of this kind of problem. From the link, about sessionStorage:

Persistence: Survives only as long as its originating window or tab.

Also, there is something called "Cross window messaging", that allow you communicate between tabs, but check if it's supported on the browsers you want to support.

http://ajaxian.com/archives/cross-window-messaging-with-html-5-postmessage

gbuzogany
  • 1,911
  • 16
  • 17
  • The link is dead, Please see the Internet Archive cached version instead. https://web.archive.org/web/20200615143322/http://ajaxian.com/archives/cross-window-messaging-with-html-5-postmessage – Rikijs Mar 23 '23 at 19:33
2

I have done something very similar today. I hope this helps.

// helper function to set cookies
function setCookie(cname, cvalue, seconds) {
    var d = new Date();
    d.setTime(d.getTime() + (seconds * 1000));
    var expires = "expires="+ d.toUTCString();
    document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
}

// helper function to get a cookie
function getCookie(cname) {
    var name = cname + "=";
    var decodedCookie = decodeURIComponent(document.cookie);
    var ca = decodedCookie.split(';');
    for(var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') {
            c = c.substring(1);
        }
        if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
        }
    }
    return "";
}

// Do not allow multiple call center tabs
if (~window.location.hash.indexOf('#admin/callcenter')) {
    $(window).on('beforeunload onbeforeunload', function(){
        document.cookie = 'ic_window_id=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;';
    });

    function validateCallCenterTab() {
        var win_id_cookie_duration = 10; // in seconds

        if (!window.name) {
            window.name = Math.random().toString();
        }

        if (!getCookie('ic_window_id') || window.name === getCookie('ic_window_id')) {
            // This means they are using just one tab. Set/clobber the cookie to prolong the tab's validity.
            setCookie('ic_window_id', window.name, win_id_cookie_duration);
        } else if (getCookie('ic_window_id') !== window.name) {
            // this means another browser tab is open, alert them to close the tabs until there is only one remaining
            var message = 'You cannot have this website open in multiple tabs. ' +
                'Please close them until there is only one remaining. Thanks!';
            $('html').html(message);
            clearInterval(callCenterInterval);
            throw 'Multiple call center tabs error. Program terminating.';
        }
    }

    callCenterInterval = setInterval(validateCallCenterTab, 3000);
}
Anthony Vipond
  • 1,879
  • 2
  • 19
  • 21
1

LocalStorage won't work across protocols - so if the user has your site open in one tab using http, and another tab using https, both those tabs will see separate localStorage objects. Cookies don't have the same issue (they have other issues, e.g. inflating the size of every http request back to your website)

The sample code below maintains a map where the key is a unique browser tab identifier and the value is a timestamp indicating when that tab last confirmed it was still open. The map is stored in a cookie. Its not a perfect approach - each tab updates itself every 3 seconds rather than instantly, and there are race conditions (multiple tabs updating the same cookie) but depending what you're after this may do the trick.

If you ran this code on just a specific page you'd (more or less) know when that page was open more than once in the same browser. Or run it on every page of your website and know when your website was open in multiple tabs.

Cookie reading/writing code is omitted for brevity (but taken from https://stackoverflow.com/a/24103596/4486628), and the encoding of the data in the cookie is done with json for simplicity, but you get the idea.

If you run this code and watch the cookies using FireBug's cookie tab you can see the cookie updating as tabs are opened and closed. Actually doing something like alerting the user when multiple tabs are open is left as an exercise for the reader.

var timePeriod = 3000; // 3 seconds
function tabHandler() {

    // ensure the current window has an identifier set
    if (!window.name.match(/^MySite[0-9]{3}/)) {
        window.name = 'MySite' + Math.round(Math.random() * 1000);
    }

    // read in the state of all the tabs
    var tabCookie = readCookie('tabs') || null;
    var tabs = JSON.parse(tabCookie) || {};

    // update the timestamp for the current tab
    var now = (new Date()).getTime();
    tabs[window.name] = now;

    // remove tab details that haven't had their timestamp updated
    var tooOld = timePeriod * 2;
    for (var tabKey in tabs) {
        if ((now - tabs[tabKey]) > tooOld) {
            delete tabs[tabKey];
        }
    }

    // write back the current state of tabs
    createCookie('tabs', JSON.stringify(tabs), 1);
    setTimeout(tabHandler, timePeriod);
}

setTimeout(tabHandler, timePeriod);
Community
  • 1
  • 1
Jamie
  • 36
  • 3