wisembly-vendor-realtime
Advanced tools
Comparing version 0.2.1 to 0.3.0
{ | ||
"name": "wisembly-vendor-realtime", | ||
"version": "0.2.1", | ||
"version": "0.3.0", | ||
"moduleType": [ | ||
@@ -15,4 +15,5 @@ "globals" | ||
"dependencies": { | ||
"jquery": "#>=1.6" | ||
"jquery": "#>=1.6", | ||
"socket.io-client": "1.7.2" | ||
} | ||
} |
@@ -1,10 +0,36 @@ | ||
(function ($) { | ||
/*global define,require,module*/ | ||
window.WisemblyRealTime = function (options) { | ||
(function (factory) { | ||
if (typeof define !== 'undefined' && define.amd) { | ||
define(['jquery', 'socket.io-client'], factory); | ||
} else if (typeof module !== 'undefined') { | ||
module.exports = factory(require('jquery'), require('socket.io-client')); | ||
} else if (typeof window !== 'undefined') { | ||
if (typeof window.$ !== 'undefined' && typeof window.io !== 'undefined') { | ||
window.WisemblyRealTime = factory(window.$, window.io); | ||
} else if (typeof require !== 'undefined') { | ||
window.WisemblyRealTime = factory(require('jquery'), require('socket.io-client')); | ||
} | ||
} else { | ||
throw new Error('Unsupported environment'); | ||
} | ||
})(function ($, io) { | ||
var WisemblyRealTime = function (options) { | ||
this.init(options); | ||
}; | ||
window.WisemblyRealTime.version = '0.2.1'; | ||
WisemblyRealTime.version = '0.3.0'; | ||
window.WisemblyRealTime.prototype = { | ||
WisemblyRealTime.prototype = { | ||
init: function (options) { | ||
@@ -21,2 +47,3 @@ this.mode = null; | ||
this.uuid = '------------------------------------'; | ||
this.promises = {}; | ||
@@ -33,3 +60,2 @@ this.rooms = []; | ||
apiToken: null, | ||
client: 'https://cdn.socket.io/socket.io-1.2.1.js', | ||
server: null, | ||
@@ -43,3 +69,4 @@ reconnection: true, | ||
forceNew: true, | ||
inactivityTimeout: 0 | ||
inactivityTimeout: 0, | ||
transports: ['websocket', 'polling'] | ||
//'secure': true | ||
@@ -52,24 +79,8 @@ }; | ||
this.options = $.extend({}, this.options, options); | ||
}, | ||
getIOClient: function () { | ||
var self = this, | ||
dfd = $.Deferred(); | ||
if (window.io || this.io) { | ||
dfd.resolve(window.io || this.io); | ||
} else { | ||
if (typeof require === 'function' && typeof define === 'function' && typeof define.amd === 'object') { | ||
require([this.options.client], dfd.resolve, dfd.reject); | ||
} else { | ||
$.ajax({ url: this.options.client, dataType: 'script', timeout: 5000 }) | ||
.always(function () { | ||
dfd[window.io ? 'resolve' : 'reject'](window.io); | ||
}); | ||
} | ||
if (this.options.apiToken && this.offlineContext) { | ||
var offlineContext = this.offlineContext; | ||
this.offlineContext = null; | ||
this.join(offlineContext); | ||
} | ||
return dfd.promise().done(function (io) { | ||
// console.log('[realtime]', 'getIOClient', !!io); | ||
self.io = io; | ||
}); | ||
}, | ||
@@ -89,21 +100,16 @@ | ||
this.getIOClient() | ||
.done(function (io) { | ||
self.setState('push', 'connecting'); | ||
self.storePromise('push:connecting', dfd); | ||
self.socket = io(self.options.server, self.options); | ||
self.bindSocketEvents(); | ||
}) | ||
.fail(function () { | ||
self.setState('polling', 'connecting'); | ||
self.storePromise('polling:connecting', dfd); | ||
}) | ||
.always(function () { | ||
self.join(self.offlineContext); | ||
self.offlineContext = null; | ||
}); | ||
this.setState('push', 'connecting'); | ||
this.storePromise('push:connecting', dfd); | ||
this.socket = io(this.options.server.toString(), this.options); | ||
this.bindSocketEvents(); | ||
if (this.options.apiToken) { | ||
var offlineContext = this.offlineContext; | ||
this.offlineContext = null; | ||
this.join(offlineContext); | ||
} | ||
return dfd.promise() | ||
.done(function () { | ||
self.trigger('connected', $.extend({ states: this.states }, options)); | ||
self.trigger('connected', $.extend({ states: self.states }, options)); | ||
self.startActivityMonitor(); | ||
@@ -147,3 +153,5 @@ }); | ||
self.promises = {}; | ||
self.trigger('disconnected', $.extend({ states: this.states }, options)); | ||
self.events = {}; | ||
self.entities = {}; | ||
self.trigger('disconnected', $.extend({ states: self.states }, options)); | ||
}); | ||
@@ -229,3 +237,6 @@ }, | ||
switch (this.getState()) { | ||
if (!this.options.apiToken) { | ||
this.offlineContext = $.extend({}, this.offlineContext, params); | ||
dfd.reject(); | ||
} else switch (this.getState()) { | ||
case 'push:connected': | ||
@@ -312,6 +323,2 @@ this.joinFromPush(params) | ||
removeEvents: function () { | ||
this.events = {}; | ||
}, | ||
checkEvent: function (eventData) { | ||
@@ -407,2 +414,3 @@ // accept eventData if event not registered yet | ||
intervall = Math.min(intervall || 0, self.options.reconnectionDelayMax); | ||
clearTimeout(self.pushRejoinTimer); | ||
self.pushRejoinTimer = setTimeout(function () { | ||
@@ -422,2 +430,8 @@ fnRejoinRequest(intervall); | ||
getPushTransport: function () { | ||
if (this.states['push'] !== 'connected') | ||
return null; | ||
return !!this.socket.io.engine.transport.ws ? 'websocket' : 'polling'; | ||
}, | ||
/* | ||
@@ -438,2 +452,3 @@ * Polling | ||
function fnPullIntervall() { | ||
clearTimeout(self.pullTimer); | ||
switch (self.states['polling']) { | ||
@@ -471,15 +486,6 @@ case 'full': | ||
var count = 0; | ||
$.each(data.data || [], function(index, eventData) { | ||
count += self.handleEvent($.extend({}, eventData, { via: 'polling' })) ? 1 : 0; | ||
if (self.handleEvent($.extend({}, eventData, { via: 'polling' })) && self.states['polling'] !== 'full') | ||
self.trigger('missed', eventData); | ||
}); | ||
switch (self.getState()) { | ||
case 'polling:full': | ||
break; | ||
case 'push:connected': | ||
case 'push:connecting': | ||
if (count) | ||
console.warn('[realtime] missed_push_event:' + count + ': on ' + data.data.length + ' events'); | ||
break; | ||
} | ||
@@ -504,2 +510,7 @@ self.lastPullTime = data.since > (self.lastPullTime || 0) ? data.since : self.lastPullTime; | ||
this.socket.on('uuid', function (data) { | ||
console.log('[realtime] Your unique connection ID is: ' + data.uuid); | ||
self.onSocketUuid.apply(self, arguments); | ||
}); | ||
this.socket.on('connect', function () { | ||
@@ -543,2 +554,3 @@ console.log('[realtime] Welcome to the Wisembly websocket server'); | ||
onSocketConnect: function () { | ||
this.trigger('pushUp'); | ||
this.setStates({ push: 'connected', polling: 'medium' }); | ||
@@ -548,9 +560,14 @@ this.resolvePromise('push:connecting'); | ||
onSocketConnectError: function () { | ||
this.onSocketDisconnect(); | ||
onSocketUuid: function (data) { | ||
this.uuid = data.uuid; | ||
}, | ||
onSocketConnectError: function (error) { | ||
this.onSocketDisconnect(error); | ||
this.resolvePromise('push:connecting'); | ||
}, | ||
onSocketDisconnect: function () { | ||
onSocketDisconnect: function (error) { | ||
var self = this; | ||
this.trigger('pushDown'); | ||
this.resolvePromise('push:disconnecting') | ||
@@ -581,3 +598,3 @@ .fail(function () { | ||
return null; | ||
var url = this.options.apiHost + '/' + this.options.apiNamespace + '/' + path; | ||
var url = this.options.apiHost.toString() + '/' + this.options.apiNamespace.toString() + '/' + path; | ||
return url.replace(/([^:]\/)\//g, function ($0, $1) { return $1; }); | ||
@@ -588,4 +605,5 @@ }, | ||
var self = this, | ||
token = this.options.apiToken, | ||
url = this.buildURL(path); | ||
if (!url) | ||
if (!url || !token) | ||
return $.Deferred().reject().promise(); | ||
@@ -597,2 +615,5 @@ options = $.extend(true, { | ||
contentType: 'application/json', | ||
headers: { | ||
'Wisembly-Token': token | ||
}, | ||
cache: false | ||
@@ -602,3 +623,3 @@ }, options); | ||
.fail(function (jqXHR, textStatus, errorThrown) { | ||
var data = { request: $.extend({ path: path }, options) }; | ||
var data = { request: $.extend({ path: path, token: token }, options) }; | ||
try { data = $.extend(data, jqXHR ? $.parseJSON(jqXHR.responseText) : {}); } catch (e) { } | ||
@@ -610,18 +631,11 @@ self.trigger('error', data); | ||
fetchRooms: function (options) { | ||
var self = this, | ||
token = this.options.apiToken; | ||
return this.apiRequest('users/node/credentials?token=' + token, { | ||
type: 'POST', | ||
token: token | ||
}); | ||
return this.apiRequest('users/node/credentials', $.extend({ | ||
type: 'POST' | ||
}, options)); | ||
}, | ||
fetchPullEvents: function (options) { | ||
var self = this, | ||
token = this.options.apiToken; | ||
return this.apiRequest('pull', { | ||
type: 'GET', | ||
token: token, | ||
data: { | ||
token: token, | ||
rooms: this.rooms, | ||
@@ -673,2 +687,4 @@ since: this.lastPullTime, | ||
if (this.state !== state) { | ||
// store previous state | ||
var previousState = this.state; | ||
// store current state | ||
@@ -678,3 +694,3 @@ this.state = state; | ||
// trigger 'state:update' | ||
this.trigger('state', { state: state }); | ||
this.trigger('state', { state: state, previous: previousState }); | ||
} | ||
@@ -721,17 +737,32 @@ | ||
on: function (name, handler) { | ||
if (this.__bindings.hasOwnProperty(name)) | ||
this.__bindings[name].push(handler); | ||
else | ||
this.__bindings[name] = [handler]; | ||
on: function (name, handler, context, once) { | ||
if (context === null) | ||
context = undefined; | ||
if (!this.__bindings.hasOwnProperty(name)) | ||
this.__bindings[name] = []; | ||
this.__bindings[name] = this.__bindings[name].concat([{ | ||
handler: handler, context: context, once: Boolean(once) | ||
}]); | ||
}, | ||
off: function (name, handler) { | ||
off: function (name, handler, context) { | ||
if (context === null) | ||
context = undefined; | ||
if (!this.__bindings.hasOwnProperty(name)) | ||
return; | ||
var index = $.inArray(handler, this.__bindings[name]); | ||
if (index !== -1) | ||
this.__bindings[name].splice(index, 1); | ||
for (var filteredListeners = [], t = 0, T = this.__bindings[name].length; t < T; ++ t) | ||
if (this.__bindings[name][t].handler !== handler || this.__bindings[name][t].context !== context) | ||
filteredListeners.push(this.__bindings[name][t]); | ||
this.__bindings[name] = filteredListeners; | ||
}, | ||
once: function (name, handler, context) { | ||
this.on(name, handler, context, true); | ||
}, | ||
trigger: function (name) { | ||
@@ -741,10 +772,23 @@ if (!this.__bindings.hasOwnProperty(name)) | ||
var bindings = this.__bindings[name], | ||
args = Array.prototype.slice.call(arguments, 1); | ||
// Avoid Array.prototype.slice.call(arguments) to keep the function optimized | ||
// Also: we start at 1 instead of 0 so that we avoid copying the "name" argument | ||
for (var args = [], t = 1, T = arguments.length; t < T; ++ t) | ||
args.push(arguments[t]); | ||
for (var i = 0; i < bindings.length; i++) { | ||
bindings[i].apply(null, args); | ||
var listeners = this.__bindings[name]; | ||
// Remove every "once" listener before actually running them so they will always be called for THIS event only | ||
for (var t = 0, T = listeners.length; t < T; ++ t) | ||
if (listeners[t].once) | ||
this.off(name, listeners[t].handler, listeners[t].context); | ||
// Finally dispatch the events to the listeners | ||
for (var t = 0, T = listeners.length; t < T; ++ t) { | ||
listeners[t].handler.apply(listeners[t].context, args); | ||
} | ||
} | ||
}; | ||
})(jQuery); | ||
return WisemblyRealTime; | ||
}); |
@@ -1,1 +0,1 @@ | ||
!function(t){window.WisemblyRealTime=function(t){this.init(t)},window.WisemblyRealTime.version="0.2.1",window.WisemblyRealTime.prototype={init:function(t){this.mode=null,this.state="offline",this.states={push:"offline",polling:"offline"},this.__bindings={},this.promises={},this.rooms=[],this.analytics=[],this.events={},this.entities={},this.options={apiHost:null,apiNamespace:"api/4/",apiToken:null,client:"https://cdn.socket.io/socket.io-1.2.1.js",server:null,reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:6e4,pullInterval:1e4,pullIntervalEnhance:6e4,forceNew:!0,inactivityTimeout:0},this.setOptions(t)},setOptions:function(e){this.options=t.extend({},this.options,e)},getIOClient:function(){var e=this,n=t.Deferred();return window.io||this.io?n.resolve(window.io||this.io):"function"==typeof require&&"function"==typeof define&&"object"==typeof define.amd?require([this.options.client],n.resolve,n.reject):t.ajax({url:this.options.client,dataType:"script",timeout:5e3}).always(function(){n[window.io?"resolve":"reject"](window.io)}),n.promise().done(function(t){e.io=t})},connect:function(e){switch(this.states.push){case"connected":return t.Deferred().resolve().promise();case"connecting":return this.getPromise("push:connecting").promise()}var n=this,i=t.Deferred();return this.getIOClient().done(function(t){n.setState("push","connecting"),n.storePromise("push:connecting",i),n.socket=t(n.options.server,n.options),n.bindSocketEvents()}).fail(function(){n.setState("polling","connecting"),n.storePromise("polling:connecting",i)}).always(function(){n.join(n.offlineContext),n.offlineContext=null}),i.promise().done(function(){n.trigger("connected",t.extend({states:this.states},e)),n.startActivityMonitor()})},disconnect:function(e){if("offline"===this.getState())return t.Deferred().resolve().promise();if("disconnecting"===this.states.push)return this.getPromise("push:disconnecting").promise();var n=this,i=t.Deferred();return this.socket&&this.socket.connected?(this.setState("push","disconnecting"),this.storePromise("push:disconnecting",i),this.socket.disconnect()):i.resolve(),this.stopPushRejoin(),this.stopPolling(),this.offlineContext=null,i.promise().always(function(){n.setStates({push:"offline",polling:"offline"}),n.socket=null,n.rooms=[],n.analytics=[],n.promises={},n.trigger("disconnected",t.extend({states:this.states},e))})},ping:function(){var e=this,n=t.Deferred();return this.socket.emit("ping",{timestamp:+new Date},function(t,i){"pong"!==t?n.reject():(e.trigger("pong",i),n.resolve(i))}),n.promise()},joinFromPush:function(e){var n=this,i=t.Deferred();return this.socket?this.socket.emit("join",t.extend({token:this.options.apiToken},e),function(t,s,o){o=o||{},"date"in o&&(n.lastPullTime=n.lastPullTime||+new Date(o.date)),t?(console.log("[realtime] Unable to join rooms on the Wisembly websocket server",t,e),n.setState("polling","full"),i.reject(t)):(console.log("[realtime] Successfully joined %d rooms on the Wisembly websocket server",s.length,s),n.setState("polling","medium"),n.rooms=s,n.trigger("rooms",{rooms:n.rooms}),i.resolve(n.rooms))}):i.reject(),i.promise()},joinFromAPI:function(e){var n=this,i=t.Deferred();return this.fetchRooms({data:JSON.stringify(e)}).done(function(e,s,o){e=e.success||e,e=e.data||e,t.each(e.rooms,function(e,i){-1===t.inArray(i,n.rooms)&&n.rooms.push(i)}),o.getResponseHeader("Date")&&(n.lastPullTime=n.lastPullTime||+new Date(o.getResponseHeader("Date"))),n.setState("polling","full"),n.resolvePromise("polling:connecting"),console.log("[realtime] Successfully retrieved %d rooms from Wisembly API",n.rooms.length,n.rooms),n.trigger("rooms",{rooms:n.rooms}),i.resolve(n.rooms)}).fail(i.reject),i.promise()},join:function(e){var n=this,i=t.Deferred();switch(this.getState()){case"push:connected":this.joinFromPush(e).done(i.resolve).fail(function(){n.joinFromAPI(e).done(i.resolve).fail(i.reject).always(function(){n.startPushRejoin(0)})});break;case"push:connecting":this.getPromise("push:connecting").done(function(){n.join(e).done(i.resolve).fail(i.reject)});break;case"polling:connecting":case"polling:full":this.joinFromAPI(e).done(i.resolve).fail(i.reject);break;default:this.offlineContext=t.extend({},this.offlineContext,e),i.reject()}return i.promise()},leave:function(){return t.Deferred().reject().promise()},addAnalytics:function(e){e=!e||t.isArray(e)?e:[e];var n=this,i=t.Deferred();switch(this.getState()){case"push:connected":this.socket.emit("analytics:subscribe",e||[],function(t,e){t?i.reject(t):(console.log("[realtime] Successfully joined %d analytics rooms on the Wisembly websocket server",e.length),n.analytics=e,i.resolve(n.analytics))});break;default:t.each(e||[],function(e,i){-1===t.inArray(i,n.analytics)&&n.analytics.push(i)}),i.resolve(this.analytics)}return i.promise()},removeAnalytics:function(){return t.Deferred().reject().promise()},addEvent:function(t){this.events[t.hash]=!0},removeEvents:function(){this.events={}},checkEvent:function(t){return!this.events.hasOwnProperty(t.hash)},handleEvent:function(t){return this.checkEvent(t)&&this.checkEntity(t)?(this.addEvent(t),this.addEntity(t),this.sendEvent(t),!0):!1},sendEvent:function(t){this.startActivityMonitor(),this.trigger("event",t)},startActivityMonitor:function(){if(this.options.inactivityTimeout){var t=this;clearTimeout(this.inactivityTimer),this.inactivityTimer=setTimeout(function(){t.trigger("inactivity",{timeout:t.options.inactivityTimeout})},this.options.inactivityTimeout)}},stopActivityMonitor:function(){clearTimeout(this.inactivityTimer),this.inactivityTimer=null},addEntity:function(t){var e=t.data||{},n=e.class_name,i=e.id||e.hash,s=n&&i?n+":"+i:null,o=t.time;s&&o&&(this.entities[s]=o)},checkEntity:function(t){var e=t.data||{},n=e.class_name,i=e.id||e.hash,s=n&&i?n+":"+i:null,o=t.time;return!s||!o||!this.entities.hasOwnProperty(s)||o>=this.entities[s]},startPushRejoin:function(e){function n(e){var n=s.rooms.length?s.joinFromPush({rooms:s.rooms}):t.Deferred().resolve().promise();return n.done(function(){s.addAnalytics(s.analytics)}).fail(function(){++nbAttemps<s.options.reconnectionAttempts&&i(e+s.options.reconnectionDelay)}),n}function i(t){"connected"===s.states.push&&(t=Math.min(t||0,s.options.reconnectionDelayMax),s.pushRejoinTimer=setTimeout(function(){n(t)},t))}if("connected"===this.states.push){var s=this;nbAttemps=0,clearTimeout(this.pushRejoinTimer),i(e)}},stopPushRejoin:function(){clearTimeout(this.pushRejoinTimer),this.pushRejoinTimer=null},startPolling:function(){function t(){return n.pull().always(e)}function e(){switch(n.states.polling){case"full":n.pullTimer=setTimeout(t,n.options.pullInterval);break;case"medium":n.pullTimer=setTimeout(t,n.options.pullIntervalEnhance)}}if("offline"!==this.states.polling){var n=this;clearTimeout(this.pullTimer),t()}},stopPolling:function(){clearTimeout(this.pullTimer),this.pullTimer=null,this.setState("polling","offline")},pull:function(){if(this.pullXHR)return this.pullXHR;var e=this;return this.pullXHR=this.fetchPullEvents(),this.pullXHR.done(function(n){n=n.success||n,n=n.data||n;var i=0;switch(t.each(n.data||[],function(n,s){i+=e.handleEvent(t.extend({},s,{via:"polling"}))?1:0}),e.getState()){case"polling:full":break;case"push:connected":case"push:connecting":i&&console.warn("[realtime] missed_push_event:"+i+": on "+n.data.length+" events")}e.lastPullTime=n.since>(e.lastPullTime||0)?n.since:e.lastPullTime}).always(function(){e.pullXHR=null})},bindSocketEvents:function(){var t=this;this.socket.on("broadcast",function(){t.onSocketBroadcast.apply(t,arguments)}),this.socket.on("connect",function(){console.log("[realtime] Welcome to the Wisembly websocket server"),t.onSocketConnect.apply(t,arguments)}),this.socket.on("connect_error",function(){console.log("[realtime] Cannot connect to websocket server"),t.onSocketConnectError.apply(t,arguments)}),this.socket.on("disconnect",function(){console.log("[realtime] Disconnected from the Wisembly websocket server"),t.onSocketDisconnect.apply(t,arguments)}),this.socket.on("reconnecting",function(){console.log("[realtime] Reconnecting to the Wisembly websocket server"),t.onSocketReconnecting.apply(t,arguments)}),this.socket.on("reconnect",function(){console.log("[realtime] Reconnected to the Wisembly websocket server"),t.onSocketReconnect.apply(t,arguments)}),this.socket.on("analytics",function(e){e=e||{},t.onSocketAnalytics.apply(t,arguments)})},onSocketBroadcast:function(e){var e=JSON.parse(e);this.handleEvent(t.extend({},e,{via:"socket"}))},onSocketConnect:function(){this.setStates({push:"connected",polling:"medium"}),this.resolvePromise("push:connecting")},onSocketConnectError:function(){this.onSocketDisconnect(),this.resolvePromise("push:connecting")},onSocketDisconnect:function(){var t=this;this.resolvePromise("push:disconnecting").fail(function(){t.setStates({push:"offline",polling:"full"})})},onSocketReconnecting:function(){this.setState("push","connecting")},onSocketReconnect:function(){this.onSocketConnect()},onSocketAnalytics:function(t){this.trigger("analytics",t)},buildURL:function(t){if(!this.options.apiHost||!this.options.apiNamespace)return null;var e=this.options.apiHost+"/"+this.options.apiNamespace+"/"+t;return e.replace(/([^:]\/)\//g,function(t,e){return e})},apiRequest:function(e,n){var i=this,s=this.buildURL(e);return s?(n=t.extend(!0,{url:s,type:"GET",dataType:"json",contentType:"application/json",cache:!1},n),t.ajax(n).fail(function(s){var o={request:t.extend({path:e},n)};try{o=t.extend(o,s?t.parseJSON(s.responseText):{})}catch(r){}i.trigger("error",o)})):t.Deferred().reject().promise()},fetchRooms:function(){var t=this.options.apiToken;return this.apiRequest("users/node/credentials?token="+t,{type:"POST",token:t})},fetchPullEvents:function(){var t=this.options.apiToken;return this.apiRequest("pull",{type:"GET",token:t,data:{token:t,rooms:this.rooms,since:this.lastPullTime,enhanced:"full"!==this.states.polling}})},storePromise:function(t,e){return this.promises[t]=e},getPromise:function(e){return this.promises[e]||t.Deferred().reject()},resolvePromise:function(t){var e=this,n=this.getPromise(t);return"pending"===n.state()&&n.resolve(),n.promise().always(function(){delete e.promises[t]})},setStates:function(t){if(t.push!==this.states.push||t.polling!==this.states.polling){var e=this.states;this.states=t;var n=this.getState();this.state!==n&&(this.state=n,this.trigger("state",{state:n})),e.polling!==this.states.polling&&this.startPolling(),e.push!==this.states.push&&this.startPushRejoin(0)}},setState:function(t,e){var n={push:this.states.push,polling:this.states.polling};n[t]=e,this.setStates(n)},getState:function(){switch(this.states.polling){case"full":case"connecting":return"polling:"+this.states.polling}switch(this.states.push){case"connected":case"connecting":return"push:"+this.states.push}return"offline"},on:function(t,e){this.__bindings.hasOwnProperty(t)?this.__bindings[t].push(e):this.__bindings[t]=[e]},off:function(e,n){if(this.__bindings.hasOwnProperty(e)){var i=t.inArray(n,this.__bindings[e]);-1!==i&&this.__bindings[e].splice(i,1)}},trigger:function(t){if(this.__bindings.hasOwnProperty(t))for(var e=this.__bindings[t],n=Array.prototype.slice.call(arguments,1),i=0;i<e.length;i++)e[i].apply(null,n)}}}(jQuery); | ||
!function(t){if("undefined"!=typeof define&&define.amd)define(["jquery","socket.io-client"],t);else if("undefined"!=typeof module)module.exports=t(require("jquery"),require("socket.io-client"));else{if("undefined"==typeof window)throw new Error("Unsupported environment");"undefined"!=typeof window.$&&"undefined"!=typeof window.io?window.WisemblyRealTime=t(window.$,window.io):"undefined"!=typeof require&&(window.WisemblyRealTime=t(require("jquery"),require("socket.io-client")))}}(function(t,e){var n=function(t){this.init(t)};return n.version="0.3.0",n.prototype={init:function(t){this.mode=null,this.state="offline",this.states={push:"offline",polling:"offline"},this.__bindings={},this.uuid="------------------------------------",this.promises={},this.rooms=[],this.analytics=[],this.events={},this.entities={},this.options={apiHost:null,apiNamespace:"api/4/",apiToken:null,server:null,reconnection:!0,reconnectionAttempts:1/0,reconnectionDelay:1e3,reconnectionDelayMax:6e4,pullInterval:1e4,pullIntervalEnhance:6e4,forceNew:!0,inactivityTimeout:0,transports:["websocket","polling"]},this.setOptions(t)},setOptions:function(e){if(this.options=t.extend({},this.options,e),this.options.apiToken&&this.offlineContext){var n=this.offlineContext;this.offlineContext=null,this.join(n)}},connect:function(n){switch(this.states.push){case"connected":return t.Deferred().resolve().promise();case"connecting":return this.getPromise("push:connecting").promise()}var i=this,s=t.Deferred();if(this.setState("push","connecting"),this.storePromise("push:connecting",s),this.socket=e(this.options.server.toString(),this.options),this.bindSocketEvents(),this.options.apiToken){var o=this.offlineContext;this.offlineContext=null,this.join(o)}return s.promise().done(function(){i.trigger("connected",t.extend({states:i.states},n)),i.startActivityMonitor()})},disconnect:function(e){if("offline"===this.getState())return t.Deferred().resolve().promise();if("disconnecting"===this.states.push)return this.getPromise("push:disconnecting").promise();var n=this,i=t.Deferred();return this.socket&&this.socket.connected?(this.setState("push","disconnecting"),this.storePromise("push:disconnecting",i),this.socket.disconnect()):i.resolve(),this.stopPushRejoin(),this.stopPolling(),this.offlineContext=null,i.promise().always(function(){n.setStates({push:"offline",polling:"offline"}),n.socket=null,n.rooms=[],n.analytics=[],n.promises={},n.events={},n.entities={},n.trigger("disconnected",t.extend({states:n.states},e))})},ping:function(){var e=this,n=t.Deferred();return this.socket.emit("ping",{timestamp:+new Date},function(t,i){"pong"!==t?n.reject():(e.trigger("pong",i),n.resolve(i))}),n.promise()},joinFromPush:function(e){var n=this,i=t.Deferred();return this.socket?this.socket.emit("join",t.extend({token:this.options.apiToken},e),function(t,s,o){o=o||{},"date"in o&&(n.lastPullTime=n.lastPullTime||+new Date(o.date)),t?(console.log("[realtime] Unable to join rooms on the Wisembly websocket server",t,e),n.setState("polling","full"),i.reject(t)):(console.log("[realtime] Successfully joined %d rooms on the Wisembly websocket server",s.length,s),n.setState("polling","medium"),n.rooms=s,n.trigger("rooms",{rooms:n.rooms}),i.resolve(n.rooms))}):i.reject(),i.promise()},joinFromAPI:function(e){var n=this,i=t.Deferred();return this.fetchRooms({data:JSON.stringify(e)}).done(function(e,s,o){e=e.success||e,e=e.data||e,t.each(e.rooms,function(e,i){t.inArray(i,n.rooms)===-1&&n.rooms.push(i)}),o.getResponseHeader("Date")&&(n.lastPullTime=n.lastPullTime||+new Date(o.getResponseHeader("Date"))),n.setState("polling","full"),n.resolvePromise("polling:connecting"),console.log("[realtime] Successfully retrieved %d rooms from Wisembly API",n.rooms.length,n.rooms),n.trigger("rooms",{rooms:n.rooms}),i.resolve(n.rooms)}).fail(i.reject),i.promise()},join:function(e){var n=this,i=t.Deferred();if(this.options.apiToken)switch(this.getState()){case"push:connected":this.joinFromPush(e).done(i.resolve).fail(function(){n.joinFromAPI(e).done(i.resolve).fail(i.reject).always(function(){n.startPushRejoin(0)})});break;case"push:connecting":this.getPromise("push:connecting").done(function(){n.join(e).done(i.resolve).fail(i.reject)});break;case"polling:connecting":case"polling:full":this.joinFromAPI(e).done(i.resolve).fail(i.reject);break;default:this.offlineContext=t.extend({},this.offlineContext,e),i.reject()}else this.offlineContext=t.extend({},this.offlineContext,e),i.reject();return i.promise()},leave:function(e){return t.Deferred().reject().promise()},addAnalytics:function(e){e=!e||t.isArray(e)?e:[e];var n=this,i=t.Deferred();switch(this.getState()){case"push:connected":this.socket.emit("analytics:subscribe",e||[],function(t,e){t?i.reject(t):(console.log("[realtime] Successfully joined %d analytics rooms on the Wisembly websocket server",e.length),n.analytics=e,i.resolve(n.analytics))});break;default:t.each(e||[],function(e,i){t.inArray(i,n.analytics)===-1&&n.analytics.push(i)}),i.resolve(this.analytics)}return i.promise()},removeAnalytics:function(e){return t.Deferred().reject().promise()},addEvent:function(t){this.events[t.hash]=!0},checkEvent:function(t){return!this.events.hasOwnProperty(t.hash)},handleEvent:function(t){return!(!this.checkEvent(t)||!this.checkEntity(t))&&(this.addEvent(t),this.addEntity(t),this.sendEvent(t),!0)},sendEvent:function(t){this.startActivityMonitor(),this.trigger("event",t)},startActivityMonitor:function(){if(this.options.inactivityTimeout){var t=this;clearTimeout(this.inactivityTimer),this.inactivityTimer=setTimeout(function(){t.trigger("inactivity",{timeout:t.options.inactivityTimeout})},this.options.inactivityTimeout)}},stopActivityMonitor:function(){clearTimeout(this.inactivityTimer),this.inactivityTimer=null},addEntity:function(t){var e=t.data||{},n=e.class_name,i=e.id||e.hash,s=n&&i?n+":"+i:null,o=t.time;s&&o&&(this.entities[s]=o)},checkEntity:function(t){var e=t.data||{},n=e.class_name,i=e.id||e.hash,s=n&&i?n+":"+i:null,o=t.time;return!s||!o||!this.entities.hasOwnProperty(s)||o>=this.entities[s]},startPushRejoin:function(e){function n(e){var n=s.rooms.length?s.joinFromPush({rooms:s.rooms}):t.Deferred().resolve().promise();return n.done(function(){s.addAnalytics(s.analytics)}).fail(function(){++nbAttemps<s.options.reconnectionAttempts&&i(e+s.options.reconnectionDelay)}),n}function i(t){"connected"===s.states.push&&(t=Math.min(t||0,s.options.reconnectionDelayMax),clearTimeout(s.pushRejoinTimer),s.pushRejoinTimer=setTimeout(function(){n(t)},t))}if("connected"===this.states.push){var s=this;nbAttemps=0,clearTimeout(this.pushRejoinTimer),i(e)}},stopPushRejoin:function(){clearTimeout(this.pushRejoinTimer),this.pushRejoinTimer=null},getPushTransport:function(){return"connected"!==this.states.push?null:this.socket.io.engine.transport.ws?"websocket":"polling"},startPolling:function(){function t(){return n.pull().always(e)}function e(){switch(clearTimeout(n.pullTimer),n.states.polling){case"full":n.pullTimer=setTimeout(t,n.options.pullInterval);break;case"medium":n.pullTimer=setTimeout(t,n.options.pullIntervalEnhance)}}if("offline"!==this.states.polling){var n=this;clearTimeout(this.pullTimer),t()}},stopPolling:function(){clearTimeout(this.pullTimer),this.pullTimer=null,this.setState("polling","offline")},pull:function(){if(this.pullXHR)return this.pullXHR;var e=this;return this.pullXHR=this.fetchPullEvents(),this.pullXHR.done(function(n){n=n.success||n,n=n.data||n,t.each(n.data||[],function(n,i){e.handleEvent(t.extend({},i,{via:"polling"}))&&"full"!==e.states.polling&&e.trigger("missed",i)}),e.lastPullTime=n.since>(e.lastPullTime||0)?n.since:e.lastPullTime}).always(function(){e.pullXHR=null})},bindSocketEvents:function(){var t=this;this.socket.on("broadcast",function(){t.onSocketBroadcast.apply(t,arguments)}),this.socket.on("uuid",function(e){console.log("[realtime] Your unique connection ID is: "+e.uuid),t.onSocketUuid.apply(t,arguments)}),this.socket.on("connect",function(){console.log("[realtime] Welcome to the Wisembly websocket server"),t.onSocketConnect.apply(t,arguments)}),this.socket.on("connect_error",function(){console.log("[realtime] Cannot connect to websocket server"),t.onSocketConnectError.apply(t,arguments)}),this.socket.on("disconnect",function(){console.log("[realtime] Disconnected from the Wisembly websocket server"),t.onSocketDisconnect.apply(t,arguments)}),this.socket.on("reconnecting",function(){console.log("[realtime] Reconnecting to the Wisembly websocket server"),t.onSocketReconnecting.apply(t,arguments)}),this.socket.on("reconnect",function(){console.log("[realtime] Reconnected to the Wisembly websocket server"),t.onSocketReconnect.apply(t,arguments)}),this.socket.on("analytics",function(e){e=e||{},t.onSocketAnalytics.apply(t,arguments)})},onSocketBroadcast:function(e){var e=JSON.parse(e);this.handleEvent(t.extend({},e,{via:"socket"}))},onSocketConnect:function(){this.trigger("pushUp"),this.setStates({push:"connected",polling:"medium"}),this.resolvePromise("push:connecting")},onSocketUuid:function(t){this.uuid=t.uuid},onSocketConnectError:function(t){this.onSocketDisconnect(t),this.resolvePromise("push:connecting")},onSocketDisconnect:function(t){var e=this;this.trigger("pushDown"),this.resolvePromise("push:disconnecting").fail(function(){e.setStates({push:"offline",polling:"full"})})},onSocketReconnecting:function(){this.setState("push","connecting")},onSocketReconnect:function(){this.onSocketConnect()},onSocketAnalytics:function(t){this.trigger("analytics",t)},buildURL:function(t){if(!this.options.apiHost||!this.options.apiNamespace)return null;var e=this.options.apiHost.toString()+"/"+this.options.apiNamespace.toString()+"/"+t;return e.replace(/([^:]\/)\//g,function(t,e){return e})},apiRequest:function(e,n){var i=this,s=this.options.apiToken,o=this.buildURL(e);return o&&s?(n=t.extend(!0,{url:o,type:"GET",dataType:"json",contentType:"application/json",headers:{"Wisembly-Token":s},cache:!1},n),t.ajax(n).fail(function(o,r,c){var l={request:t.extend({path:e,token:s},n)};try{l=t.extend(l,o?t.parseJSON(o.responseText):{})}catch(t){}i.trigger("error",l)})):t.Deferred().reject().promise()},fetchRooms:function(e){return this.apiRequest("users/node/credentials",t.extend({type:"POST"},e))},fetchPullEvents:function(t){return this.apiRequest("pull",{type:"GET",data:{rooms:this.rooms,since:this.lastPullTime,enhanced:"full"!==this.states.polling}})},storePromise:function(t,e){return this.promises[t]=e},getPromise:function(e){return this.promises[e]||t.Deferred().reject()},resolvePromise:function(t){var e=this,n=this.getPromise(t);return"pending"===n.state()&&n.resolve(),n.promise().always(function(){delete e.promises[t]})},setStates:function(t){if(t.push!==this.states.push||t.polling!==this.states.polling){var e=this.states;this.states=t;var n=this.getState();if(this.state!==n){var i=this.state;this.state=n,this.trigger("state",{state:n,previous:i})}e.polling!==this.states.polling&&this.startPolling(),e.push!==this.states.push&&this.startPushRejoin(0)}},setState:function(t,e){var n={push:this.states.push,polling:this.states.polling};n[t]=e,this.setStates(n)},getState:function(){switch(this.states.polling){case"full":case"connecting":return"polling:"+this.states.polling}switch(this.states.push){case"connected":case"connecting":return"push:"+this.states.push}return"offline"},on:function(t,e,n,i){null===n&&(n=void 0),this.__bindings.hasOwnProperty(t)||(this.__bindings[t]=[]),this.__bindings[t]=this.__bindings[t].concat([{handler:e,context:n,once:Boolean(i)}])},off:function(t,e,n){if(null===n&&(n=void 0),this.__bindings.hasOwnProperty(t)){for(var i=[],s=0,o=this.__bindings[t].length;s<o;++s)this.__bindings[t][s].handler===e&&this.__bindings[t][s].context===n||i.push(this.__bindings[t][s]);this.__bindings[t]=i}},once:function(t,e,n){this.on(t,e,n,!0)},trigger:function(t){if(this.__bindings.hasOwnProperty(t)){for(var e=[],n=1,i=arguments.length;n<i;++n)e.push(arguments[n]);for(var s=this.__bindings[t],n=0,i=s.length;n<i;++n)s[n].once&&this.off(t,s[n].handler,s[n].context);for(var n=0,i=s.length;n<i;++n)s[n].handler.apply(s[n].context,e)}}},n}); |
{ | ||
"name": "wisembly-vendor-realtime", | ||
"version": "0.2.1", | ||
"main": "src/realtime.js", | ||
"version": "0.3.0", | ||
"scripts": { | ||
"test": "bower install && node node_modules/karma/bin/karma start test/karma.config.js", | ||
"build": "node node_modules/gulp/bin/gulp.js" | ||
"test": "$(npm bin)/bower install && $(npm bin)/karma start test/karma.config.js", | ||
"build": "$(npm bin)/gulp" | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"jquery": ">=1.6", | ||
"socket.io-client": "1.7.2" | ||
}, | ||
"devDependencies": { | ||
"bower": "*", | ||
"karma": "*", | ||
"karma-mocha": "*", | ||
"karma-sinon-expect": "*", | ||
"karma-chrome-launcher": "*", | ||
"karma-firefox-launcher": "*", | ||
"karma-safari-launcher": "*", | ||
"karma-opera-launcher": "*", | ||
"karma-ie-launcher": "*", | ||
"karma-phantomjs-launcher": "*", | ||
"gulp": "*", | ||
"gulp-uglify": "*", | ||
"gulp-rename": "*" | ||
}, | ||
"spm": { | ||
"main": "src/realtime.js" | ||
"gulp-rename": "*", | ||
"mocha": "*", | ||
"phantomjs-prebuilt": "*" | ||
} | ||
} |
@@ -1,10 +0,36 @@ | ||
(function ($) { | ||
/*global define,require,module*/ | ||
window.WisemblyRealTime = function (options) { | ||
(function (factory) { | ||
if (typeof define !== 'undefined' && define.amd) { | ||
define(['jquery', 'socket.io-client'], factory); | ||
} else if (typeof module !== 'undefined') { | ||
module.exports = factory(require('jquery'), require('socket.io-client')); | ||
} else if (typeof window !== 'undefined') { | ||
if (typeof window.$ !== 'undefined' && typeof window.io !== 'undefined') { | ||
window.WisemblyRealTime = factory(window.$, window.io); | ||
} else if (typeof require !== 'undefined') { | ||
window.WisemblyRealTime = factory(require('jquery'), require('socket.io-client')); | ||
} | ||
} else { | ||
throw new Error('Unsupported environment'); | ||
} | ||
})(function ($, io) { | ||
var WisemblyRealTime = function (options) { | ||
this.init(options); | ||
}; | ||
window.WisemblyRealTime.version = '0.2.1'; | ||
WisemblyRealTime.version = '0.3.0'; | ||
window.WisemblyRealTime.prototype = { | ||
WisemblyRealTime.prototype = { | ||
init: function (options) { | ||
@@ -21,2 +47,3 @@ this.mode = null; | ||
this.uuid = '------------------------------------'; | ||
this.promises = {}; | ||
@@ -33,3 +60,2 @@ this.rooms = []; | ||
apiToken: null, | ||
client: 'https://cdn.socket.io/socket.io-1.2.1.js', | ||
server: null, | ||
@@ -43,3 +69,4 @@ reconnection: true, | ||
forceNew: true, | ||
inactivityTimeout: 0 | ||
inactivityTimeout: 0, | ||
transports: ['websocket', 'polling'] | ||
//'secure': true | ||
@@ -52,24 +79,8 @@ }; | ||
this.options = $.extend({}, this.options, options); | ||
}, | ||
getIOClient: function () { | ||
var self = this, | ||
dfd = $.Deferred(); | ||
if (window.io || this.io) { | ||
dfd.resolve(window.io || this.io); | ||
} else { | ||
if (typeof require === 'function' && typeof define === 'function' && typeof define.amd === 'object') { | ||
require([this.options.client], dfd.resolve, dfd.reject); | ||
} else { | ||
$.ajax({ url: this.options.client, dataType: 'script', timeout: 5000 }) | ||
.always(function () { | ||
dfd[window.io ? 'resolve' : 'reject'](window.io); | ||
}); | ||
} | ||
if (this.options.apiToken && this.offlineContext) { | ||
var offlineContext = this.offlineContext; | ||
this.offlineContext = null; | ||
this.join(offlineContext); | ||
} | ||
return dfd.promise().done(function (io) { | ||
// console.log('[realtime]', 'getIOClient', !!io); | ||
self.io = io; | ||
}); | ||
}, | ||
@@ -89,21 +100,16 @@ | ||
this.getIOClient() | ||
.done(function (io) { | ||
self.setState('push', 'connecting'); | ||
self.storePromise('push:connecting', dfd); | ||
self.socket = io(self.options.server, self.options); | ||
self.bindSocketEvents(); | ||
}) | ||
.fail(function () { | ||
self.setState('polling', 'connecting'); | ||
self.storePromise('polling:connecting', dfd); | ||
}) | ||
.always(function () { | ||
self.join(self.offlineContext); | ||
self.offlineContext = null; | ||
}); | ||
this.setState('push', 'connecting'); | ||
this.storePromise('push:connecting', dfd); | ||
this.socket = io(this.options.server.toString(), this.options); | ||
this.bindSocketEvents(); | ||
if (this.options.apiToken) { | ||
var offlineContext = this.offlineContext; | ||
this.offlineContext = null; | ||
this.join(offlineContext); | ||
} | ||
return dfd.promise() | ||
.done(function () { | ||
self.trigger('connected', $.extend({ states: this.states }, options)); | ||
self.trigger('connected', $.extend({ states: self.states }, options)); | ||
self.startActivityMonitor(); | ||
@@ -147,3 +153,5 @@ }); | ||
self.promises = {}; | ||
self.trigger('disconnected', $.extend({ states: this.states }, options)); | ||
self.events = {}; | ||
self.entities = {}; | ||
self.trigger('disconnected', $.extend({ states: self.states }, options)); | ||
}); | ||
@@ -229,3 +237,6 @@ }, | ||
switch (this.getState()) { | ||
if (!this.options.apiToken) { | ||
this.offlineContext = $.extend({}, this.offlineContext, params); | ||
dfd.reject(); | ||
} else switch (this.getState()) { | ||
case 'push:connected': | ||
@@ -312,6 +323,2 @@ this.joinFromPush(params) | ||
removeEvents: function () { | ||
this.events = {}; | ||
}, | ||
checkEvent: function (eventData) { | ||
@@ -407,2 +414,3 @@ // accept eventData if event not registered yet | ||
intervall = Math.min(intervall || 0, self.options.reconnectionDelayMax); | ||
clearTimeout(self.pushRejoinTimer); | ||
self.pushRejoinTimer = setTimeout(function () { | ||
@@ -422,2 +430,8 @@ fnRejoinRequest(intervall); | ||
getPushTransport: function () { | ||
if (this.states['push'] !== 'connected') | ||
return null; | ||
return !!this.socket.io.engine.transport.ws ? 'websocket' : 'polling'; | ||
}, | ||
/* | ||
@@ -438,2 +452,3 @@ * Polling | ||
function fnPullIntervall() { | ||
clearTimeout(self.pullTimer); | ||
switch (self.states['polling']) { | ||
@@ -471,15 +486,6 @@ case 'full': | ||
var count = 0; | ||
$.each(data.data || [], function(index, eventData) { | ||
count += self.handleEvent($.extend({}, eventData, { via: 'polling' })) ? 1 : 0; | ||
if (self.handleEvent($.extend({}, eventData, { via: 'polling' })) && self.states['polling'] !== 'full') | ||
self.trigger('missed', eventData); | ||
}); | ||
switch (self.getState()) { | ||
case 'polling:full': | ||
break; | ||
case 'push:connected': | ||
case 'push:connecting': | ||
if (count) | ||
console.warn('[realtime] missed_push_event:' + count + ': on ' + data.data.length + ' events'); | ||
break; | ||
} | ||
@@ -504,2 +510,7 @@ self.lastPullTime = data.since > (self.lastPullTime || 0) ? data.since : self.lastPullTime; | ||
this.socket.on('uuid', function (data) { | ||
console.log('[realtime] Your unique connection ID is: ' + data.uuid); | ||
self.onSocketUuid.apply(self, arguments); | ||
}); | ||
this.socket.on('connect', function () { | ||
@@ -543,2 +554,3 @@ console.log('[realtime] Welcome to the Wisembly websocket server'); | ||
onSocketConnect: function () { | ||
this.trigger('pushUp'); | ||
this.setStates({ push: 'connected', polling: 'medium' }); | ||
@@ -548,9 +560,14 @@ this.resolvePromise('push:connecting'); | ||
onSocketConnectError: function () { | ||
this.onSocketDisconnect(); | ||
onSocketUuid: function (data) { | ||
this.uuid = data.uuid; | ||
}, | ||
onSocketConnectError: function (error) { | ||
this.onSocketDisconnect(error); | ||
this.resolvePromise('push:connecting'); | ||
}, | ||
onSocketDisconnect: function () { | ||
onSocketDisconnect: function (error) { | ||
var self = this; | ||
this.trigger('pushDown'); | ||
this.resolvePromise('push:disconnecting') | ||
@@ -581,3 +598,3 @@ .fail(function () { | ||
return null; | ||
var url = this.options.apiHost + '/' + this.options.apiNamespace + '/' + path; | ||
var url = this.options.apiHost.toString() + '/' + this.options.apiNamespace.toString() + '/' + path; | ||
return url.replace(/([^:]\/)\//g, function ($0, $1) { return $1; }); | ||
@@ -588,4 +605,5 @@ }, | ||
var self = this, | ||
token = this.options.apiToken, | ||
url = this.buildURL(path); | ||
if (!url) | ||
if (!url || !token) | ||
return $.Deferred().reject().promise(); | ||
@@ -597,2 +615,5 @@ options = $.extend(true, { | ||
contentType: 'application/json', | ||
headers: { | ||
'Wisembly-Token': token | ||
}, | ||
cache: false | ||
@@ -602,3 +623,3 @@ }, options); | ||
.fail(function (jqXHR, textStatus, errorThrown) { | ||
var data = { request: $.extend({ path: path }, options) }; | ||
var data = { request: $.extend({ path: path, token: token }, options) }; | ||
try { data = $.extend(data, jqXHR ? $.parseJSON(jqXHR.responseText) : {}); } catch (e) { } | ||
@@ -610,18 +631,11 @@ self.trigger('error', data); | ||
fetchRooms: function (options) { | ||
var self = this, | ||
token = this.options.apiToken; | ||
return this.apiRequest('users/node/credentials?token=' + token, { | ||
type: 'POST', | ||
token: token | ||
}); | ||
return this.apiRequest('users/node/credentials', $.extend({ | ||
type: 'POST' | ||
}, options)); | ||
}, | ||
fetchPullEvents: function (options) { | ||
var self = this, | ||
token = this.options.apiToken; | ||
return this.apiRequest('pull', { | ||
type: 'GET', | ||
token: token, | ||
data: { | ||
token: token, | ||
rooms: this.rooms, | ||
@@ -673,2 +687,4 @@ since: this.lastPullTime, | ||
if (this.state !== state) { | ||
// store previous state | ||
var previousState = this.state; | ||
// store current state | ||
@@ -678,3 +694,3 @@ this.state = state; | ||
// trigger 'state:update' | ||
this.trigger('state', { state: state }); | ||
this.trigger('state', { state: state, previous: previousState }); | ||
} | ||
@@ -721,17 +737,32 @@ | ||
on: function (name, handler) { | ||
if (this.__bindings.hasOwnProperty(name)) | ||
this.__bindings[name].push(handler); | ||
else | ||
this.__bindings[name] = [handler]; | ||
on: function (name, handler, context, once) { | ||
if (context === null) | ||
context = undefined; | ||
if (!this.__bindings.hasOwnProperty(name)) | ||
this.__bindings[name] = []; | ||
this.__bindings[name] = this.__bindings[name].concat([{ | ||
handler: handler, context: context, once: Boolean(once) | ||
}]); | ||
}, | ||
off: function (name, handler) { | ||
off: function (name, handler, context) { | ||
if (context === null) | ||
context = undefined; | ||
if (!this.__bindings.hasOwnProperty(name)) | ||
return; | ||
var index = $.inArray(handler, this.__bindings[name]); | ||
if (index !== -1) | ||
this.__bindings[name].splice(index, 1); | ||
for (var filteredListeners = [], t = 0, T = this.__bindings[name].length; t < T; ++ t) | ||
if (this.__bindings[name][t].handler !== handler || this.__bindings[name][t].context !== context) | ||
filteredListeners.push(this.__bindings[name][t]); | ||
this.__bindings[name] = filteredListeners; | ||
}, | ||
once: function (name, handler, context) { | ||
this.on(name, handler, context, true); | ||
}, | ||
trigger: function (name) { | ||
@@ -741,10 +772,23 @@ if (!this.__bindings.hasOwnProperty(name)) | ||
var bindings = this.__bindings[name], | ||
args = Array.prototype.slice.call(arguments, 1); | ||
// Avoid Array.prototype.slice.call(arguments) to keep the function optimized | ||
// Also: we start at 1 instead of 0 so that we avoid copying the "name" argument | ||
for (var args = [], t = 1, T = arguments.length; t < T; ++ t) | ||
args.push(arguments[t]); | ||
for (var i = 0; i < bindings.length; i++) { | ||
bindings[i].apply(null, args); | ||
var listeners = this.__bindings[name]; | ||
// Remove every "once" listener before actually running them so they will always be called for THIS event only | ||
for (var t = 0, T = listeners.length; t < T; ++ t) | ||
if (listeners[t].once) | ||
this.off(name, listeners[t].handler, listeners[t].context); | ||
// Finally dispatch the events to the listeners | ||
for (var t = 0, T = listeners.length; t < T; ++ t) { | ||
listeners[t].handler.apply(listeners[t].context, args); | ||
} | ||
} | ||
}; | ||
})(jQuery); | ||
return WisemblyRealTime; | ||
}); |
@@ -9,2 +9,3 @@ module.exports = function(config) { | ||
'bower_components/jquery/dist/jquery.min.js', | ||
'bower_components/socket.io-client/socket.io.js', | ||
'src/realtime.js', | ||
@@ -11,0 +12,0 @@ 'test/test.js', |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
61408
10
1340
1
2
1
+ Addedjquery@>=1.6
+ Addedsocket.io-client@1.7.2
+ Addedafter@0.8.2(transitive)
+ Addedarraybuffer.slice@0.0.6(transitive)
+ Addedbacko2@1.0.2(transitive)
+ Addedbase64-arraybuffer@0.1.5(transitive)
+ Addedbetter-assert@1.0.2(transitive)
+ Addedblob@0.0.4(transitive)
+ Addedcallsite@1.0.0(transitive)
+ Addedcomponent-bind@1.0.0(transitive)
+ Addedcomponent-emitter@1.1.21.2.1(transitive)
+ Addedcomponent-inherit@0.0.3(transitive)
+ Addeddebug@2.2.02.3.3(transitive)
+ Addedengine.io-client@1.8.2(transitive)
+ Addedengine.io-parser@1.3.2(transitive)
+ Addedhas-binary@0.1.7(transitive)
+ Addedhas-cors@1.1.0(transitive)
+ Addedindexof@0.0.1(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedjquery@3.7.1(transitive)
+ Addedjson3@3.3.2(transitive)
+ Addedms@0.7.10.7.2(transitive)
+ Addedobject-component@0.0.3(transitive)
+ Addedoptions@0.0.6(transitive)
+ Addedparsejson@0.0.3(transitive)
+ Addedparseqs@0.0.5(transitive)
+ Addedparseuri@0.0.5(transitive)
+ Addedsocket.io-client@1.7.2(transitive)
+ Addedsocket.io-parser@2.3.1(transitive)
+ Addedto-array@0.1.4(transitive)
+ Addedultron@1.0.2(transitive)
+ Addedws@1.1.1(transitive)
+ Addedwtf-8@1.0.0(transitive)
+ Addedxmlhttprequest-ssl@1.5.3(transitive)
+ Addedyeast@0.1.2(transitive)