public
Last active

Cross-tab window controller

  • Download Gist
window-controller.js
JavaScript
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99
function WindowController () {
this.id = Math.random();
this.isMaster = false;
this.others = {};
 
window.addEventListener( 'storage', this, false );
window.addEventListener( 'unload', this, false );
 
this.broadcast( 'hello' );
 
var that = this;
var check = function check () {
that.check();
that._checkTimeout = setTimeout( check, 9000 );
};
var ping = function ping () {
that.sendPing();
that._pingTimeout = setTimeout( ping, 17000 );
};
this._checkTimeout = setTimeout( check, 500 );
this._pingTimeout = setTimeout( ping, 17000 );
}
 
WindowController.prototype.destroy = function () {
clearTimeout( this._pingTimeout );
clearTimeout( this._checkTimeout );
 
window.removeEventListener( 'storage', this, false );
window.removeEventListener( 'unload', this, false );
 
this.broadcast( 'bye' );
};
 
WindowController.prototype.handleEvent = function ( event ) {
if ( event.type === 'unload' ) {
this.destroy();
} else if ( event.key === 'broadcast' ) {
try {
var data = JSON.parse( event.newValue );
if ( data.id !== this.id ) {
this[ data.type ]( data );
}
} catch ( error ) {}
}
};
 
WindowController.prototype.sendPing = function () {
this.broadcast( 'ping' );
};
 
WindowController.prototype.hello = function ( event ) {
this.ping( event );
if ( event.id < this.id ) {
this.check();
} else {
this.sendPing();
}
};
 
WindowController.prototype.ping = function ( event ) {
this.others[ event.id ] = +new Date();
};
 
WindowController.prototype.bye = function ( event ) {
delete this.others[ event.id ];
this.check();
};
 
WindowController.prototype.check = function ( event ) {
var now = +new Date(),
takeMaster = true,
id;
for ( id in this.others ) {
if ( this.others[ id ] + 23000 < now ) {
delete this.others[ id ];
} else if ( id < this.id ) {
takeMaster = false;
}
}
if ( this.isMaster !== takeMaster ) {
this.isMaster = takeMaster;
this.masterDidChange();
}
};
 
WindowController.prototype.masterDidChange = function () {};
 
WindowController.prototype.broadcast = function ( type, data ) {
var event = {
id: this.id,
type: type
};
for ( var x in data ) {
event[x] = data[x];
}
try {
localStorage.setItem( 'broadcast', JSON.stringify( event ) );
} catch ( error ) {}
};

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.