Skip to content

Instantly share code, notes, and snippets.

@br3nt
Forked from neilj/window-controller.js
Last active November 29, 2015 10:05
Show Gist options
  • Save br3nt/c6aeec77fcef1a1f3907 to your computer and use it in GitHub Desktop.
Save br3nt/c6aeec77fcef1a1f3907 to your computer and use it in GitHub Desktop.
Cross-tab window communication
function Dispatcher(channel_name, broadcast_to_self) {
this.channel_name = channel_name ? 'dispatcher:' + channel_name : 'dispatcher:default_channel';
this.id = Math.random();
this.isMaster = false;
this.others = {};
this.broadcast_to_self = broadcast_to_self === undefined ? true || !!broadcast_to_self;
this.callbacks = {};
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 );
}
Dispatcher.prototype.destroy = function () {
clearTimeout( this._pingTimeout );
clearTimeout( this._checkTimeout );
window.removeEventListener( 'storage', this, false );
window.removeEventListener( 'unload', this, false );
this.broadcast( 'bye' );
};
Dispatcher.prototype.handleEvent = function ( event ) {
if ( event.type === 'unload' ) {
this.destroy();
} else if ( event.key === this.channel_name ) {
var data = JSON.parse( event.newValue ), type = data.type;
switch ( type ) {
case 'ping':
case 'hello':
case 'bye':
this[ type ]( data );
break;
default:
try {
this.callbacks[ type ].call( this, data );
}
catch ( error ) {}
}
}
};
Dispatcher.prototype.sendPing = function () {
this.broadcast( 'ping' );
};
Dispatcher.prototype.hello = function ( event ) {
this.ping( event );
if ( event.id < this.id ) {
this.check();
} else {
this.sendPing();
}
};
Dispatcher.prototype.ping = function ( event ) {
this.others[ event.id ] = +new Date();
};
Dispatcher.prototype.bye = function ( event ) {
delete this.others[ event.id ];
this.check();
};
Dispatcher.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( takeMaster );
}
};
Dispatcher.prototype.masterDidChange = function () {};
Dispatcher.prototype.broadcast = function ( type, data ) {
var event = {
id: this.id,
type: type
};
for ( var x in data ) {
event[x] = data[x];
}
try {
data = JSON.stringify( event );
localStorage.setItem( this.channel_name, data );
if (this.broadcast_to_self) this.callbacks[ type ].call( this, JSON.parse(data) );
} catch ( error ) {}
};
Dispatcher.prototype.on = function (event_name, callback) {
this.callbacks[event_name] = callback;
return this;
}
Dispatcher.prototype.off = function (event_name) {
delete this.callbacks[event_name];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment