Moved reconnect handling out of protocol handler.
UI is extremely shoddy right now, redo will follow. Enjoy LoadingOverlay while you still can.
This commit is contained in:
parent
b37352534b
commit
e32eabea1f
6 changed files with 278 additions and 122 deletions
110
src/mami.js/conman.js
Normal file
110
src/mami.js/conman.js
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
#include eventtarget.js
|
||||||
|
#include utility.js
|
||||||
|
|
||||||
|
const MamiConnectionManager = function(urls) {
|
||||||
|
if(!Array.isArray(urls))
|
||||||
|
throw 'urls must be an array';
|
||||||
|
|
||||||
|
const eventTarget = new MamiEventTarget('mami:conn');
|
||||||
|
const delays = [0, 2000, 2000, 2000, 5000, 5000, 5000, 5000, 5000, 10000, 10000, 10000, 10000, 10000, 15000, 30000, 45000, 60000, 120000, 300000];
|
||||||
|
|
||||||
|
let timeout;
|
||||||
|
let attempts, started, delay, url;
|
||||||
|
let attemptConnect;
|
||||||
|
let startResolve;
|
||||||
|
|
||||||
|
const resetTimeout = () => {
|
||||||
|
if(timeout !== undefined) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
timeout = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const clear = () => {
|
||||||
|
resetTimeout();
|
||||||
|
attempts = started = delay = 0;
|
||||||
|
url = undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
$as(urls);
|
||||||
|
|
||||||
|
const onFailure = ex => {
|
||||||
|
++attempts;
|
||||||
|
delay = attempts < delays.length ? delays[attempts] : delays[delays.length - 1];
|
||||||
|
|
||||||
|
eventTarget.dispatch('fail', {
|
||||||
|
url: url,
|
||||||
|
started: started,
|
||||||
|
attempt: attempts,
|
||||||
|
delay: delay,
|
||||||
|
error: ex,
|
||||||
|
});
|
||||||
|
|
||||||
|
attempt();
|
||||||
|
};
|
||||||
|
|
||||||
|
const attempt = () => {
|
||||||
|
started = Date.now();
|
||||||
|
url = urls[attempts % urls.length];
|
||||||
|
|
||||||
|
const attempt = attempts + 1;
|
||||||
|
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
resetTimeout();
|
||||||
|
|
||||||
|
eventTarget.dispatch('attempt', {
|
||||||
|
url: url,
|
||||||
|
started: started,
|
||||||
|
attempt: attempt,
|
||||||
|
});
|
||||||
|
|
||||||
|
attemptConnect(url).then(result => {
|
||||||
|
if(typeof result === 'boolean' && !result) {
|
||||||
|
onFailure();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
eventTarget.dispatch('success', {
|
||||||
|
url: url,
|
||||||
|
started: started,
|
||||||
|
attempt: attempt,
|
||||||
|
});
|
||||||
|
|
||||||
|
startResolve();
|
||||||
|
startResolve = undefined;
|
||||||
|
attemptConnect = undefined;
|
||||||
|
}).catch(ex => onFailure(ex));
|
||||||
|
}, delay);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isActive = () => timeout !== undefined || startResolve !== undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
isActive: isActive,
|
||||||
|
start: body => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if(typeof body !== 'function')
|
||||||
|
throw 'body must be a function';
|
||||||
|
if(isActive())
|
||||||
|
throw 'already attempting to connect';
|
||||||
|
|
||||||
|
attemptConnect = body;
|
||||||
|
startResolve = resolve;
|
||||||
|
|
||||||
|
clear();
|
||||||
|
attempt();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
force: () => {
|
||||||
|
if(!isActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
resetTimeout();
|
||||||
|
delay = 0;
|
||||||
|
attempt();
|
||||||
|
},
|
||||||
|
clear: clear,
|
||||||
|
watch: eventTarget.watch,
|
||||||
|
unwatch: eventTarget.unwatch,
|
||||||
|
};
|
||||||
|
};
|
|
@ -5,6 +5,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
#include channels.js
|
#include channels.js
|
||||||
#include common.js
|
#include common.js
|
||||||
#include compat.js
|
#include compat.js
|
||||||
|
#include conman.js
|
||||||
#include context.js
|
#include context.js
|
||||||
#include emotes.js
|
#include emotes.js
|
||||||
#include message.js
|
#include message.js
|
||||||
|
@ -151,7 +152,6 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.watch('soundEnable', ev => {
|
settings.watch('soundEnable', ev => {
|
||||||
console.log(ev);
|
|
||||||
if(ev.detail.value) {
|
if(ev.detail.value) {
|
||||||
if(!soundCtx.ready)
|
if(!soundCtx.ready)
|
||||||
soundCtx.reset();
|
soundCtx.reset();
|
||||||
|
@ -221,14 +221,16 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
loadingOverlay.setMessage('Preparing UI...');
|
loadingOverlay.setMessage('Preparing UI...');
|
||||||
|
|
||||||
const textTriggers = new MamiTextTriggers;
|
const textTriggers = new MamiTextTriggers;
|
||||||
|
const conMan = new MamiConnectionManager(futami.get('servers'));
|
||||||
|
|
||||||
// define this as late as possible'
|
// define this as late as possible
|
||||||
const ctx = new MamiContext({
|
const ctx = new MamiContext({
|
||||||
settings: settings,
|
settings: settings,
|
||||||
views: views,
|
views: views,
|
||||||
sound: soundCtx,
|
sound: soundCtx,
|
||||||
textTriggers: textTriggers,
|
textTriggers: textTriggers,
|
||||||
eeprom: eeprom,
|
eeprom: eeprom,
|
||||||
|
conMan: conMan,
|
||||||
});
|
});
|
||||||
Object.defineProperty(window, 'mami', { enumerable: true, value: ctx });
|
Object.defineProperty(window, 'mami', { enumerable: true, value: ctx });
|
||||||
|
|
||||||
|
@ -535,11 +537,15 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
Umi.UI.InputMenus.Add('markup', 'BB Code');
|
Umi.UI.InputMenus.Add('markup', 'BB Code');
|
||||||
Umi.UI.InputMenus.Add('emotes', 'Emoticons');
|
Umi.UI.InputMenus.Add('emotes', 'Emoticons');
|
||||||
|
|
||||||
|
let isUnloading = false;
|
||||||
|
|
||||||
window.addEventListener('beforeunload', function(ev) {
|
window.addEventListener('beforeunload', function(ev) {
|
||||||
if(settings.get('closeTabConfirm')) {
|
if(settings.get('closeTabConfirm')) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
return ev.returnValue = 'Are you sure you want to close the tab?';
|
return ev.returnValue = 'Are you sure you want to close the tab?';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isUnloading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
@ -573,7 +579,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
'_1008': 'Your client did something the server did not agree with.',
|
'_1008': 'Your client did something the server did not agree with.',
|
||||||
'_1009': 'Your client sent too much data to the server at once.',
|
'_1009': 'Your client sent too much data to the server at once.',
|
||||||
'_1011': 'Something went wrong on the server side.',
|
'_1011': 'Something went wrong on the server side.',
|
||||||
'_1012': 'The server is restarting, reconnecting soon...',
|
'_1012': 'The chat server is restarting.',
|
||||||
'_1013': 'You cannot connect to the server right now, try again later.',
|
'_1013': 'You cannot connect to the server right now, try again later.',
|
||||||
'_1015': 'Your client and the server could not establish a secure connection.',
|
'_1015': 'Your client and the server could not establish a secure connection.',
|
||||||
};
|
};
|
||||||
|
@ -597,30 +603,54 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
MamiCompat('Umi.Protocol.SockChat.Protocol.Instance.SendMessage', { value: text => sockChat.sendMessage(text), configurable: true });
|
MamiCompat('Umi.Protocol.SockChat.Protocol.Instance.SendMessage', { value: text => sockChat.sendMessage(text), configurable: true });
|
||||||
MamiCompat('Umi.Protocol.SockLegacy.Protocol.Instance.SendMessage', { value: text => sockChat.sendMessage(text), configurable: true });
|
MamiCompat('Umi.Protocol.SockLegacy.Protocol.Instance.SendMessage', { value: text => sockChat.sendMessage(text), configurable: true });
|
||||||
|
|
||||||
sockChat.watch('conn:init', ev => {
|
sockChat.watch('conn:lost', ev => {
|
||||||
if(dumpEvents) console.log('conn:init', ev);
|
if(dumpEvents) console.log('conn:lost', ev);
|
||||||
|
|
||||||
let message = 'Connecting to server...';
|
if(conMan.isActive() || isUnloading)
|
||||||
if(ev.detail.attempt > 2)
|
return;
|
||||||
message += ` (Attempt ${connectAttempts})`;
|
|
||||||
|
|
||||||
getLoadingOverlay('spinner', 'Loading...', message);
|
const errorCode = ev.detail.code;
|
||||||
});
|
const isRestarting = ev.detail.isRestarting;
|
||||||
sockChat.watch('conn:ready', ev => {
|
|
||||||
if(dumpEvents) console.log('conn:ready', ev);
|
|
||||||
|
|
||||||
getLoadingOverlay('spinner', 'Loading...', 'Authenticating...');
|
pingToggle.title = '∞ms';
|
||||||
|
pingIndicator.setStrength(-1);
|
||||||
|
|
||||||
|
const conManAttempt = ev => {
|
||||||
|
if(isRestarting || ev.detail.attempt > 1) {
|
||||||
|
let message = ev.detail.attempt > 2 ? `Attempt ${ev.detail.attempt}...` : 'Connecting to server...';
|
||||||
|
getLoadingOverlay('spinner', 'Connecting...', message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const conManFail = ev => {
|
||||||
|
if(isRestarting || ev.detail.attempt > 1) {
|
||||||
|
let header = isRestarting ? 'Restarting...' : 'Disconnected';
|
||||||
|
let message = wsCloseReasons[`_${errorCode}`] ?? `Something caused an unexpected connection loss. (${errorCode})`;
|
||||||
|
|
||||||
|
if(ev.detail.delay > 0)
|
||||||
|
message += ` Retrying in ${ev.detail.delay / 1000} seconds...`;
|
||||||
|
|
||||||
|
// this is absolutely disgusting but i really don't care right now sorry
|
||||||
|
message += ' <a href="javascript:void(0)" onclick="mami.conMan.force()">Retry now</a>';
|
||||||
|
|
||||||
|
getLoadingOverlay('unlink', header, message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
conMan.watch('attempt', conManAttempt);
|
||||||
|
conMan.watch('fail', conManFail);
|
||||||
|
|
||||||
|
conMan.start(async url => {
|
||||||
|
await sockChat.open(url);
|
||||||
|
}).then(() => {
|
||||||
|
conMan.unwatch('attempt', conManAttempt);
|
||||||
|
conMan.unwatch('fail', conManFail);
|
||||||
|
|
||||||
|
pingToggle.title = 'Ready~';
|
||||||
|
pingIndicator.setStrength(3);
|
||||||
|
|
||||||
const authInfo = MamiMisuzuAuth.getInfo();
|
const authInfo = MamiMisuzuAuth.getInfo();
|
||||||
sockChat.sendAuth(authInfo.method, authInfo.token);
|
sockChat.sendAuth(authInfo.method, authInfo.token);
|
||||||
});
|
});
|
||||||
sockChat.watch('conn:lost', ev => {
|
|
||||||
if(dumpEvents) console.log('conn:lost', ev);
|
|
||||||
|
|
||||||
getLoadingOverlay(
|
|
||||||
'unlink', 'Disconnected!',
|
|
||||||
wsCloseReasons[`_${ev.detail.code}`] ?? `Something caused an unexpected connection loss. (${ev.detail.code})`
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sockChat.watch('ping:send', ev => {
|
sockChat.watch('ping:send', ev => {
|
||||||
|
@ -643,7 +673,6 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
pingIndicator.setStrength(strength);
|
pingIndicator.setStrength(strength);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
sockChat.watch('session:start', ev => {
|
sockChat.watch('session:start', ev => {
|
||||||
if(dumpEvents) console.log('session:start', ev);
|
if(dumpEvents) console.log('session:start', ev);
|
||||||
|
|
||||||
|
@ -655,6 +684,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
Umi.UI.Emoticons.Init();
|
Umi.UI.Emoticons.Init();
|
||||||
Umi.Parsing.Init();
|
Umi.Parsing.Init();
|
||||||
|
|
||||||
|
if(views.count() > 1)
|
||||||
views.pop(ctx => MamiAnimate({
|
views.pop(ctx => MamiAnimate({
|
||||||
async: true,
|
async: true,
|
||||||
duration: 120,
|
duration: 120,
|
||||||
|
@ -880,7 +910,28 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
||||||
Umi.UI.Messages.RemoveAll();
|
Umi.UI.Messages.RemoveAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
sockChat.open();
|
const conManAttempt = ev => {
|
||||||
|
let message = ev.detail.attempt > 2 ? `Attempt ${ev.detail.attempt}...` : 'Connecting to server...';
|
||||||
|
getLoadingOverlay('spinner', 'Connecting...', message);
|
||||||
|
};
|
||||||
|
const conManFail = ev => {
|
||||||
|
getLoadingOverlay('cross', 'Failed to connect', `Retrying in ${ev.detail.delay / 1000} seconds...`);
|
||||||
|
};
|
||||||
|
|
||||||
|
conMan.watch('attempt', conManAttempt);
|
||||||
|
conMan.watch('fail', conManFail);
|
||||||
|
|
||||||
|
await conMan.start(async url => {
|
||||||
|
await sockChat.open(url);
|
||||||
|
});
|
||||||
|
|
||||||
|
conMan.unwatch('attempt', conManAttempt);
|
||||||
|
conMan.unwatch('fail', conManFail);
|
||||||
|
|
||||||
|
getLoadingOverlay('spinner', 'Connecting...', 'Authenticating...');
|
||||||
|
|
||||||
|
const authInfo = MamiMisuzuAuth.getInfo();
|
||||||
|
sockChat.sendAuth(authInfo.method, authInfo.token);
|
||||||
|
|
||||||
if(window.dispatchEvent)
|
if(window.dispatchEvent)
|
||||||
window.dispatchEvent(new Event('umi:connect'));
|
window.dispatchEvent(new Event('umi:connect'));
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
#include common.js
|
|
||||||
#include utility.js
|
|
||||||
|
|
||||||
const UmiServers = (function() {
|
|
||||||
let servers = undefined,
|
|
||||||
index = Number.MAX_SAFE_INTEGER - 1;
|
|
||||||
|
|
||||||
return {
|
|
||||||
getServer: function(callback) {
|
|
||||||
// FutamiCommon is delayed load
|
|
||||||
if(servers === undefined) {
|
|
||||||
const futamiServers = futami.get('servers');
|
|
||||||
$as(futamiServers);
|
|
||||||
servers = futamiServers;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(++index >= servers.length)
|
|
||||||
index = 0;
|
|
||||||
|
|
||||||
let server = servers[index];
|
|
||||||
if(server.includes('//'))
|
|
||||||
server = location.protocol.replace('http', 'ws') + server;
|
|
||||||
|
|
||||||
callback(server);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
})();
|
|
|
@ -1,5 +1,4 @@
|
||||||
#include eventtarget.js
|
#include eventtarget.js
|
||||||
#include servers.js
|
|
||||||
#include websock.js
|
#include websock.js
|
||||||
|
|
||||||
Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
|
@ -31,8 +30,6 @@ Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
};
|
};
|
||||||
|
|
||||||
let wasConnected = false;
|
let wasConnected = false;
|
||||||
let noReconnect = false;
|
|
||||||
let connectAttempts = 0;
|
|
||||||
let wasKicked = false;
|
let wasKicked = false;
|
||||||
let isRestarting = false;
|
let isRestarting = false;
|
||||||
let dumpPackets = false;
|
let dumpPackets = false;
|
||||||
|
@ -40,6 +37,7 @@ Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
let sock;
|
let sock;
|
||||||
let selfUserId, selfChannelName, selfPseudoChannelName;
|
let selfUserId, selfChannelName, selfPseudoChannelName;
|
||||||
let lastPing, lastPong, pingTimer, pingWatcher;
|
let lastPing, lastPong, pingTimer, pingWatcher;
|
||||||
|
let openResolve, openReject;
|
||||||
|
|
||||||
const handlers = {};
|
const handlers = {};
|
||||||
|
|
||||||
|
@ -104,7 +102,10 @@ Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
|
|
||||||
isRestarting = false;
|
isRestarting = false;
|
||||||
|
|
||||||
eventTarget.dispatch('conn:ready', { wasConnected: wasConnected });
|
if(typeof openResolve === 'function') {
|
||||||
|
openResolve();
|
||||||
|
openResolve = undefined;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClose = ev => {
|
const onClose = ev => {
|
||||||
|
@ -126,15 +127,20 @@ Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
} else if(code === 1012)
|
} else if(code === 1012)
|
||||||
isRestarting = true;
|
isRestarting = true;
|
||||||
|
|
||||||
|
if(typeof openReject === 'function') {
|
||||||
|
openReject({
|
||||||
|
code: code,
|
||||||
|
wasConnected: wasConnected,
|
||||||
|
isRestarting: isRestarting,
|
||||||
|
});
|
||||||
|
openReject = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
eventTarget.dispatch('conn:lost', {
|
eventTarget.dispatch('conn:lost', {
|
||||||
wasConnected: wasConnected,
|
wasConnected: wasConnected,
|
||||||
isRestarting: isRestarting,
|
isRestarting: isRestarting,
|
||||||
code: code,
|
code: code,
|
||||||
});
|
});
|
||||||
|
|
||||||
connectAttempts = 0;
|
|
||||||
|
|
||||||
setTimeout(() => beginConnecting(), 5000);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const unfuckText = text => text.replace(/ <br\/> /g, "\n");
|
const unfuckText = text => text.replace(/ <br\/> /g, "\n");
|
||||||
|
@ -501,7 +507,6 @@ Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
|
|
||||||
// baka (ban/kick)
|
// baka (ban/kick)
|
||||||
handlers['9'] = (type, expiry) => {
|
handlers['9'] = (type, expiry) => {
|
||||||
noReconnect = true;
|
|
||||||
wasKicked = true;
|
wasKicked = true;
|
||||||
|
|
||||||
const bakaInfo = {
|
const bakaInfo = {
|
||||||
|
@ -534,20 +539,22 @@ Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const beginConnecting = () => {
|
return {
|
||||||
|
sendAuth: sendAuth,
|
||||||
|
sendMessage: sendMessage,
|
||||||
|
open: url => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if(typeof url !== 'string')
|
||||||
|
throw 'url must be a string';
|
||||||
|
if(url.startsWith('//'))
|
||||||
|
url = location.protocol.replace('http', 'ws') + url;
|
||||||
|
|
||||||
|
openResolve = resolve;
|
||||||
|
openReject = reject;
|
||||||
|
|
||||||
sock?.close();
|
sock?.close();
|
||||||
|
|
||||||
if(noReconnect)
|
sock = new UmiWebSocket(url);
|
||||||
return;
|
|
||||||
|
|
||||||
UmiServers.getServer(server => {
|
|
||||||
eventTarget.dispatch('conn:init', {
|
|
||||||
server: server,
|
|
||||||
wasConnected: wasConnected,
|
|
||||||
attempt: ++connectAttempts,
|
|
||||||
});
|
|
||||||
|
|
||||||
sock = new UmiWebSocket(server);
|
|
||||||
sock.watch('open', onOpen);
|
sock.watch('open', onOpen);
|
||||||
sock.watch('close', onClose);
|
sock.watch('close', onClose);
|
||||||
sock.watch('message', onMessage);
|
sock.watch('message', onMessage);
|
||||||
|
@ -562,21 +569,13 @@ Umi.Protocol.SockChat.Protocol = function(pingDuration) {
|
||||||
pingTimer = undefined;
|
pingTimer = undefined;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
sendAuth: sendAuth,
|
|
||||||
sendMessage: sendMessage,
|
|
||||||
open: () => {
|
|
||||||
noReconnect = false;
|
|
||||||
beginConnecting();
|
|
||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
noReconnect = true;
|
|
||||||
sock?.close();
|
sock?.close();
|
||||||
|
sock = undefined;
|
||||||
},
|
},
|
||||||
watch: (name, handler) => eventTarget.watch(name, handler),
|
watch: eventTarget.watch,
|
||||||
unwatch: (name, handler) => eventTarget.unwatch(name, handler),
|
unwatch: eventTarget.unwatch,
|
||||||
setDumpPackets: state => dumpPackets = !!state,
|
setDumpPackets: state => dumpPackets = !!state,
|
||||||
switchChannel: channelInfo => {
|
switchChannel: channelInfo => {
|
||||||
if(selfUserId === undefined)
|
if(selfUserId === undefined)
|
||||||
|
|
|
@ -31,7 +31,7 @@ Umi.UI.LoadingOverlay = function(icon, header, message) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const setHeader = text => headerElem.textContent = (text || '').toString();
|
const setHeader = text => headerElem.textContent = (text || '').toString();
|
||||||
const setMessage = text => messageElem.textContent = (text || '').toString();
|
const setMessage = text => messageElem.innerHTML = (text || '').toString();
|
||||||
|
|
||||||
setIcon(icon);
|
setIcon(icon);
|
||||||
setHeader(header);
|
setHeader(header);
|
||||||
|
@ -44,8 +44,5 @@ Umi.UI.LoadingOverlay = function(icon, header, message) {
|
||||||
getElement: function() {
|
getElement: function() {
|
||||||
return html;
|
return html;
|
||||||
},
|
},
|
||||||
implode: function() {
|
|
||||||
html.parentNode.removeChild(html);
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -13,15 +13,41 @@ const MamiPingIndicator = function(initialStrength) {
|
||||||
for(let i = 1; i <= 3; ++i)
|
for(let i = 1; i <= 3; ++i)
|
||||||
bars.push(html.appendChild(<div class={`ping-bar ping-bar-${i}`}/>));
|
bars.push(html.appendChild(<div class={`ping-bar ping-bar-${i}`}/>));
|
||||||
|
|
||||||
|
let interval;
|
||||||
|
|
||||||
const setStrength = strength => {
|
const setStrength = strength => {
|
||||||
if(typeof strength !== 'number')
|
if(typeof strength !== 'number')
|
||||||
throw 'strength must be a number';
|
throw 'strength must be a number';
|
||||||
|
|
||||||
|
if(strength < 0) {
|
||||||
|
if(interval === undefined) {
|
||||||
|
const cyclesMax = bars.length * 2;
|
||||||
|
let cycles = -1;
|
||||||
|
|
||||||
|
const updateCycle = () => {
|
||||||
|
let curCycle = ++cycles % cyclesMax;
|
||||||
|
if(curCycle > bars.length)
|
||||||
|
curCycle = cyclesMax - curCycle;
|
||||||
|
|
||||||
|
for(const i in bars)
|
||||||
|
bars[i].classList.toggle('ping-bar-on', curCycle === (parseInt(i) + 1));
|
||||||
|
};
|
||||||
|
|
||||||
|
interval = setInterval(updateCycle, 200);
|
||||||
|
updateCycle();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(interval !== undefined) {
|
||||||
|
clearInterval(interval);
|
||||||
|
interval = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
for(const i in bars)
|
for(const i in bars)
|
||||||
bars[i].classList.toggle('ping-bar-on', i < strength);
|
bars[i].classList.toggle('ping-bar-on', i < strength);
|
||||||
|
}
|
||||||
|
|
||||||
html.classList.toggle('ping-state-good', strength > 1);
|
html.classList.toggle('ping-state-good', strength > 1);
|
||||||
html.classList.toggle('ping-state-warn', strength === 1);
|
html.classList.toggle('ping-state-warn', strength == 1);
|
||||||
html.classList.toggle('ping-state-poor', strength < 1);
|
html.classList.toggle('ping-state-poor', strength < 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue