-
-
Save neilj/4146038 to your computer and use it in GitHub Desktop.
| 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 ) {} | |
| }; |
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
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). ?
Corresponding blog post: https://fastmail.blog/2012/11/26/inter-tab-communication-using-local-storage/
@neilj Hi, what is license of this code?