Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Cross-tab window controller
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 ) {}
};
@shamrin

This comment has been minimized.

Copy link

shamrin commented Mar 23, 2015

@neilj Hi, what is license of this code?

@shamrin

This comment has been minimized.

Copy link

shamrin commented Mar 24, 2015

I've asked @neilj about it via email. His reply:

Consider it MIT licensed

Thank you, Neil!

In addition, this functionality is fully included in Overture library: https://github.com/fastmail/overture/blob/master/source/Overture/application/WindowController.js

@cwellsx

This comment has been minimized.

Copy link

cwellsx commented Aug 6, 2016

Thank you for publishing this code. Why do this.id = Math.random(); instead of e.g. this.id = new Date().getTime();? I would have guessed that using monotonically-increasing id values would be better: because it would be more deterministic ; and because the master would change less often (it would only change when the existing master closes, and not change when a new tab with a randomly-lower id is opened). ?

@dwaltrip

This comment has been minimized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.