#include utility.js var AmiReconnecter = function(parent) { var handler = new AmiReconnectHandler, indicator = new AmiReconnectIndicator(parent, handler); return { isActive: function() { return handler.isActive(); }, start: function(idleCallback, successCallback, failCallback) { if(typeof idleCallback !== 'function') throw 'idleCallback must be a function'; handler.start( idleCallback, function(fails) { indicator.hide(); if(typeof successCallback === 'function') successCallback(fails); }, function(fails) { if(fails > 0) indicator.showCounter(); if(typeof failCallback === 'function') failCallback(fails); } ); }, session: function(body) { handler.session(body); }, clear: function() { handler.clear(); indicator.hide(); }, }; }; var AmiReconnectHandler = function() { var fails = 0, delays = undefined, timeout = undefined; var idleCallback = undefined, successCallback = undefined, failCallback = undefined; var started = 0, delay = 0; var setDefaultDelays = function() { delays = [0, 10000, 15000, 30000, 45000, 60000, 120000, 300000]; }; var setCustomDelays = function(customDelays) { delays = customDelays.slice(0); delays[0] = 0; }; setDefaultDelays(); var isActive = function() { return idleCallback !== undefined; }; var clearAttemptTimeout = function() { clearTimeout(timeout); timeout = undefined; }; var clear = function() { clearAttemptTimeout(); fails = 0; idleCallback = undefined; successCallback = undefined; failCallback = undefined; started = 0; delay = 0; }; var manager = { success: function() { if(successCallback !== undefined) successCallback(fails); clear(); }, fail: function() { ++fails; if(failCallback !== undefined) failCallback(fails); attempt(); }, }; var attemptBody = function() { clearAttemptTimeout(); idleCallback.call(manager, manager, fails, delay); }; var attempt = function() { started = Date.now(); delay = fails < delays.length ? delays[fails] : delays[delays.length - 1]; if(delay < 1) attemptBody(); else timeout = setTimeout(attemptBody, delay); }; return { isActive: isActive, session: function(callback) { callback.call(manager, manager); }, start: function(idle, success, fail) { if(typeof idle !== 'function' || isActive()) return; clear(); idleCallback = idle; successCallback = success; failCallback = fail; attempt(); }, clear: clear, getTimeRemaining: function() { return Math.max(0, (started + delay) - Date.now()); }, }; }; var AmiReconnectIndicator = function(parent, handler) { var counterTime = $e({ tag: 'span', attrs: { id: 'reconnectCounterTime', }, child: '0.0', }); var counterBody = $e({ attrs: { id: 'reconnectCounter', className: 'hidden', }, child: ['Reconnecting in ', counterTime, ' seconds.'], }); var connectEllipsis = $e({ tag: 'span', attrs: { id: 'reconnectConnectEllipsis', }, child: '...', }); var connectBody = $e({ attrs: { id: 'reconnectConnect', className: 'hidden', }, child: ['Attempting to reconnect', connectEllipsis], }); var body = $e({ attrs: { id: 'reconnectIndicator', className: 'hidden', }, child: [ { child: 'WARNING: Connection Problem' }, counterBody, connectBody, ], }); parent.appendChild(body); var counterInterval = undefined; var clearCounterInterval = function() { clearInterval(counterInterval); counterInterval = undefined; }; var setTime = function(time) { counterTime.textContent = (parseFloat(time || 0) / 1000).toFixed(1); }; var show = function() { body.classList.remove('hidden'); }; var showCounter = function() { clearCounterInterval(); connectBody.classList.add('hidden'); counterBody.classList.remove('hidden'); show(); counterInterval = setInterval(function() { var remaining = handler.getTimeRemaining(); if(remaining < 100) showConnect(); else setTime(remaining); }, 100); }; var showConnect = function() { clearCounterInterval(); counterBody.classList.add('hidden'); connectBody.classList.remove('hidden'); show(); }; return { show: show, hide: function() { body.classList.add('hidden'); clearCounterInterval(); }, setTime: setTime, showCounter: showCounter, showConnect: showConnect, }; };