Use EventTarget instead of the custom watchers bag.

This commit is contained in:
flash 2024-03-01 19:07:17 +00:00
parent 53258703e1
commit bc859a042d
6 changed files with 213 additions and 269 deletions

View file

@ -0,0 +1,22 @@
const MamiEventTarget = function(prefix) {
prefix = typeof prefix === 'string' ? `${prefix}:` : '';
const eventTarget = new EventTarget;
const createEvent = (name, detail) => new CustomEvent(prefix + name, (typeof detail === 'object' && detail !== null && 'detail' in detail ? detail : { detail: detail }));
return {
create: createEvent,
addEventListener: eventTarget.addEventListener.bind(eventTarget),
removeEventListener: eventTarget.removeEventListener.bind(eventTarget),
dispatchEvent: eventTarget.dispatchEvent.bind(eventTarget),
watch: (name, ...args) => {
eventTarget.addEventListener(prefix + name, ...args);
},
unwatch: (name, ...args) => {
eventTarget.removeEventListener(prefix + name, ...args);
},
dispatch: (...args) => eventTarget.dispatchEvent(createEvent(...args)),
};
};

View file

@ -150,8 +150,9 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
settings.virtualise('soundEnable');
}
settings.watch('soundEnable', (v, n, i) => {
if(v) {
settings.watch('soundEnable', ev => {
console.log(ev);
if(ev.detail.value) {
if(!soundCtx.ready)
soundCtx.reset();
@ -161,22 +162,22 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
soundCtx.library.play(soundCtx.pack.getEventSound('server'));
}
soundCtx.muted = !v;
soundCtx.muted = !ev.detail.value;
});
settings.watch('soundPack', (v, n, i) => {
settings.watch('soundPack', ev => {
const packs = soundCtx.packs;
if(!packs.has(v)) {
settings.delete(n);
if(!packs.has(ev.detail.value)) {
settings.delete(ev.detail.name);
return;
}
soundCtx.pack = packs.get(v);
if(!i) soundCtx.library.play(soundCtx.pack.getEventSound('server'));
soundCtx.pack = packs.get(ev.detail.value);
if(!ev.detail.initial) soundCtx.library.play(soundCtx.pack.getEventSound('server'));
});
settings.watch('soundVolume', v => {
soundCtx.volume = v / 100;
settings.watch('soundVolume', ev => {
soundCtx.volume = ev.detail.value / 100;
})
@ -238,28 +239,28 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
Umi.UI.View.AccentReload();
Umi.UI.Hooks.AddHooks();
settings.watch('style', (v, n, i) => { if(!i) Umi.UI.View.AccentReload(); });
settings.watch('compactView', (v, n, i) => { if(!i) Umi.UI.View.AccentReload(); });
settings.watch('preventOverflow', v => document.body.classList.toggle('prevent-overflow', v));
settings.watch('tmpDisableOldThemeSys', (v, n, i) => { if(!i) Umi.UI.View.AccentReload(); });
settings.watch('style', ev => { if(!ev.detail.initial) Umi.UI.View.AccentReload(); });
settings.watch('compactView', ev => { if(!ev.detail.initial) Umi.UI.View.AccentReload(); });
settings.watch('preventOverflow', ev => document.body.classList.toggle('prevent-overflow', ev.detail.value));
settings.watch('tmpDisableOldThemeSys', ev => { if(!ev.detail.initial) Umi.UI.View.AccentReload(); });
settings.watch('minecraft', (v, n, i) => {
if(i && v === 'no')
settings.watch('minecraft', ev => {
if(ev.detail.initial && ev.detail.value === 'no')
return;
soundCtx.library.play((() => {
if(i)
return 'minecraft:nether:enter';
if(v === 'yes')
if(ev.detail.value === 'yes')
return 'minecraft:door:open';
if(v === 'old')
if(ev.detail.value === 'old')
return 'minecraft:door:open-old';
return soundCtx.pack.getEventSound('join');
})());
});
settings.watch('enableNotifications', v => {
if(!v || !('Notification' in window)
settings.watch('enableNotifications', ev => {
if(!ev.detail.value || !('Notification' in window)
|| (Notification.permission === 'granted' && Notification.permission !== 'denied'))
return;
@ -270,20 +271,20 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
});
});
settings.watch('playJokeSounds', v => {
if(!v) return;
settings.watch('playJokeSounds', ev => {
if(!ev.detail.value) return;
if(!textTriggers.hasTriggers())
futami.getJson('texttriggers').then(trigInfos => textTriggers.addTriggers(trigInfos));
});
settings.watch('weeaboo', v => {
if(v) Weeaboo.init();
settings.watch('weeaboo', ev => {
if(ev.detail.value) Weeaboo.init();
});
settings.watch('osuKeysV2', (v, n, i) => {
settings.watch('osuKeysV2', ev => {
// migrate old value
if(i) {
if(ev.detail.initial) {
if(settings.has('osuKeys')) {
settings.set('osuKeysV2', settings.get('osuKeys') ? 'yes' : 'no');
settings.delete('osuKeys');
@ -291,8 +292,8 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
}
}
OsuKeys.setEnable(v !== 'no');
OsuKeys.setRandomRate(v === 'rng');
OsuKeys.setEnable(ev.detail.value !== 'no');
OsuKeys.setRandomRate(ev.detail.value === 'rng');
});
@ -356,8 +357,8 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
settings.toggle('autoScroll');
}
}, 'Autoscroll');
settings.watch('autoScroll', function(value) {
Umi.UI.Toggles.Get('scroll').classList[value ? 'remove' : 'add']('sidebar__selector-mode--scroll-off');
settings.watch('autoScroll', ev => {
Umi.UI.Toggles.Get('scroll').classList.toggle('sidebar__selector-mode--scroll-off', !ev.detail.value);
});
if(window.innerWidth < 768)
@ -368,8 +369,8 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
settings.toggle('soundEnable');
}
}, 'Sounds');
settings.watch('soundEnable', function(value) {
Umi.UI.Toggles.Get('audio').classList[value ? 'remove' : 'add']('sidebar__selector-mode--audio-off');
settings.watch('soundEnable', ev => {
Umi.UI.Toggles.Get('audio').classList.toggle('sidebar__selector-mode--audio-off', !ev.detail.value);
});
Umi.UI.Toggles.Add('unembed', {
@ -587,8 +588,8 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
MamiCompat('Umi.Server', { get: () => sockChat, configurable: true });
let dumpEvents = false;
settings.watch('dumpEvents', value => dumpEvents = value);
settings.watch('dumpPackets', value => sockChat.setDumpPackets(value));
settings.watch('dumpEvents', ev => dumpEvents = ev.detail.value);
settings.watch('dumpPackets', ev => sockChat.setDumpPackets(ev.detail.value));
Umi.UI.Hooks.SetCallbacks(sockChat.sendMessage, sockChat.switchChannel);
@ -596,60 +597,60 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
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 });
sockChat.watch('conn:init', init => {
if(dumpEvents) console.log('conn:init', init);
sockChat.watch('conn:init', ev => {
if(dumpEvents) console.log('conn:init', ev);
let message = 'Connecting to server...';
if(init.attempt > 2)
if(ev.detail.attempt > 2)
message += ` (Attempt ${connectAttempts})`;
getLoadingOverlay('spinner', 'Loading...', message);
});
sockChat.watch('conn:ready', ready => {
if(dumpEvents) console.log('conn:ready', ready);
sockChat.watch('conn:ready', ev => {
if(dumpEvents) console.log('conn:ready', ev);
getLoadingOverlay('spinner', 'Loading...', 'Authenticating...');
const authInfo = MamiMisuzuAuth.getInfo();
sockChat.sendAuth(authInfo.method, authInfo.token);
});
sockChat.watch('conn:lost', lost => {
if(dumpEvents) console.log('conn:lost', lost);
sockChat.watch('conn:lost', ev => {
if(dumpEvents) console.log('conn:lost', ev);
getLoadingOverlay(
'unlink', 'Disconnected!',
wsCloseReasons[`_${lost.code}`] ?? `Something caused an unexpected connection loss. (${lost.code})`
wsCloseReasons[`_${ev.detail.code}`] ?? `Something caused an unexpected connection loss. (${ev.detail.code})`
);
});
sockChat.watch('conn:error', error => {
console.error('conn:error', error);
sockChat.watch('conn:error', ev => {
console.error('conn:error', ev);
});
sockChat.watch('ping:send', send => {
if(dumpEvents) console.log('ping:send', send);
sockChat.watch('ping:send', ev => {
if(dumpEvents) console.log('ping:send', ev);
});
sockChat.watch('ping:long', long => {
if(dumpEvents) console.log('ping:long', long);
sockChat.watch('ping:long', ev => {
if(dumpEvents) console.log('ping:long', ev);
pingToggle.title = '+2000ms';
pingIndicator.setStrength(0);
});
sockChat.watch('ping:recv', recv => {
if(dumpEvents) console.log('ping:recv', recv);
sockChat.watch('ping:recv', ev => {
if(dumpEvents) console.log('ping:recv', ev);
let strength = 3;
if(recv.diff >= 1000) --strength;
if(recv.diff >= 250) --strength;
if(ev.detail.diff >= 1000) --strength;
if(ev.detail.diff >= 250) --strength;
pingToggle.title = `${recv.diff.toLocaleString()}ms`;
pingToggle.title = `${ev.detail.diff.toLocaleString()}ms`;
pingIndicator.setStrength(strength);
});
sockChat.watch('session:start', start => {
if(dumpEvents) console.log('session:start', start);
sockChat.watch('session:start', ev => {
if(dumpEvents) console.log('session:start', ev);
const userInfo = new Umi.User(start.user.id, start.user.name, start.user.colour, start.user.permsRaw);
const userInfo = new Umi.User(ev.detail.user.id, ev.detail.user.name, ev.detail.user.colour, ev.detail.user.permsRaw);
Umi.User.setCurrentUser(userInfo);
Umi.Users.Add(userInfo);
@ -675,84 +676,84 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
},
}));
});
sockChat.watch('session:fail', fail => {
if(dumpEvents) console.log('session:fail', fail);
sockChat.watch('session:fail', ev => {
if(dumpEvents) console.log('session:fail', ev);
if(fail.baka !== undefined) {
new MamiForceDisconnectNotice(fail.baka).pushOn(views);
if(ev.detail.baka !== undefined) {
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(views);
return;
}
getLoadingOverlay(
'cross', 'Failed!',
sessFailReasons[fail.session.reason] ?? `Unknown reason: ${fail.session.reason}`
sessFailReasons[ev.detail.session.reason] ?? `Unknown reason: ${ev.detail.session.reason}`
);
if(fail.session.needsAuth)
if(ev.detail.session.needsAuth)
setTimeout(() => location.assign(futami.get('login')), 1000);
});
sockChat.watch('session:term', term => {
if(dumpEvents) console.log('session:term', term);
sockChat.watch('session:term', ev => {
if(dumpEvents) console.log('session:term', ev);
new MamiForceDisconnectNotice(term.baka).pushOn(views);
new MamiForceDisconnectNotice(ev.detail.baka).pushOn(views);
});
sockChat.watch('user:add', add => {
if(dumpEvents) console.log('user:add', add);
sockChat.watch('user:add', ev => {
if(dumpEvents) console.log('user:add', ev);
if(add.user.self)
if(ev.detail.user.self)
return;
const userInfo = new Umi.User(add.user.id, add.user.name, add.user.colour, add.user.permsRaw);
const userInfo = new Umi.User(ev.detail.user.id, ev.detail.user.name, ev.detail.user.colour, ev.detail.user.permsRaw);
Umi.Users.Add(userInfo);
if(add.msg !== undefined)
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
add.msg.id, add.msg.time, undefined, '', add.msg.channel, false,
ev.detail.msg.id, ev.detail.msg.time, undefined, '', ev.detail.msg.channel, false,
{
isError: false,
type: add.msg.botInfo.type,
args: add.msg.botInfo.args,
type: ev.detail.msg.botInfo.type,
args: ev.detail.msg.botInfo.args,
target: userInfo,
}
));
});
sockChat.watch('user:remove', remove => {
if(dumpEvents) console.log('user:remove', remove);
sockChat.watch('user:remove', ev => {
if(dumpEvents) console.log('user:remove', ev);
const userInfo = Umi.Users.Get(remove.user.id);
const userInfo = Umi.Users.Get(ev.detail.user.id);
if(userInfo === null)
return;
if(remove.msg !== undefined)
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
remove.msg.id,
remove.msg.time,
ev.detail.msg.id,
ev.detail.msg.time,
undefined,
'',
remove.msg.channel,
ev.detail.msg.channel,
false,
{
isError: false,
type: remove.msg.botInfo.type,
args: remove.msg.botInfo.args,
type: ev.detail.msg.botInfo.type,
args: ev.detail.msg.botInfo.args,
target: userInfo,
},
));
Umi.Users.Remove(userInfo);
});
sockChat.watch('user:update', update => {
if(dumpEvents) console.log('user:update', update);
sockChat.watch('user:update', ev => {
if(dumpEvents) console.log('user:update', ev);
const userInfo = Umi.Users.Get(update.user.id);
userInfo.setName(update.user.name);
userInfo.setColour(update.user.colour);
userInfo.setPermissions(update.user.permsRaw);
const userInfo = Umi.Users.Get(ev.detail.user.id);
userInfo.setName(ev.detail.user.name);
userInfo.setColour(ev.detail.user.colour);
userInfo.setPermissions(ev.detail.user.permsRaw);
Umi.Users.Update(userInfo.getId(), userInfo);
});
sockChat.watch('user:clear', () => {
if(dumpEvents) console.log('user:clear');
sockChat.watch('user:clear', ev => {
if(dumpEvents) console.log('user:clear', ev);
const self = Umi.User.currentUser;
Umi.Users.Clear();
@ -760,48 +761,48 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
Umi.Users.Add(self);
});
sockChat.watch('chan:add', add => {
if(dumpEvents) console.log('chan:add', add);
sockChat.watch('chan:add', ev => {
if(dumpEvents) console.log('chan:add', ev);
Umi.Channels.Add(new Umi.Channel(
add.channel.name,
add.channel.hasPassword,
add.channel.isTemporary,
ev.detail.channel.name,
ev.detail.channel.hasPassword,
ev.detail.channel.isTemporary,
));
});
sockChat.watch('chan:remove', remove => {
if(dumpEvents) console.log('chan:remove', remove);
sockChat.watch('chan:remove', ev => {
if(dumpEvents) console.log('chan:remove', ev);
Umi.Channels.Remove(Umi.Channels.Get(remove.channel.name));
Umi.Channels.Remove(Umi.Channels.Get(ev.detail.channel.name));
});
sockChat.watch('chan:update', update => {
if(dumpEvents) console.log('chan:update', update);
sockChat.watch('chan:update', ev => {
if(dumpEvents) console.log('chan:update', ev);
const chanInfo = Umi.Channels.Get(update.channel.previousName);
chanInfo.setName(update.channel.name);
chanInfo.setHasPassword(update.channel.hasPassword);
chanInfo.setTemporary(update.channel.isTemporary);
Umi.Channels.Update(update.channel.previousName, chanInfo);
const chanInfo = Umi.Channels.Get(ev.detail.channel.previousName);
chanInfo.setName(ev.detail.channel.name);
chanInfo.setHasPassword(ev.detail.channel.hasPassword);
chanInfo.setTemporary(ev.detail.channel.isTemporary);
Umi.Channels.Update(ev.detail.channel.previousName, chanInfo);
});
sockChat.watch('chan:clear', () => {
if(dumpEvents) console.log('chan:clear');
sockChat.watch('chan:clear', ev => {
if(dumpEvents) console.log('chan:clear', ev);
Umi.Channels.Clear();
});
sockChat.watch('chan:focus', focus => {
if(dumpEvents) console.log('chan:focus', focus);
sockChat.watch('chan:focus', ev => {
if(dumpEvents) console.log('chan:focus', ev);
Umi.Channels.Switch(Umi.Channels.Get(focus.channel.name));
Umi.Channels.Switch(Umi.Channels.Get(ev.detail.channel.name));
});
sockChat.watch('chan:join', join => {
if(dumpEvents) console.log('chan:join', join);
sockChat.watch('chan:join', ev => {
if(dumpEvents) console.log('chan:join', ev);
const userInfo = new Umi.User(join.user.id, join.user.name, join.user.colour, join.user.permsRaw);
const userInfo = new Umi.User(ev.detail.user.id, ev.detail.user.name, ev.detail.user.colour, ev.detail.user.permsRaw);
Umi.Users.Add(userInfo);
if(join.msg !== undefined)
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
join.msg.id, null, undefined, '', join.msg.channel, false,
ev.detail.msg.id, null, undefined, '', ev.detail.msg.channel, false,
{
isError: false,
type: leave.msg.botInfo.type,
@ -810,22 +811,22 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
},
));
});
sockChat.watch('chan:leave', leave => {
if(dumpEvents) console.log('chan:leave', leave);
sockChat.watch('chan:leave', ev => {
if(dumpEvents) console.log('chan:leave', ev);
if(leave.user.self)
if(ev.detail.user.self)
return;
const userInfo = Umi.Users.Get(leave.user.id);
const userInfo = Umi.Users.Get(ev.detail.user.id);
if(userInfo === null)
return;
if(leave.msg !== undefined)
if(ev.detail.msg !== undefined)
Umi.Messages.Add(new Umi.Message(
leave.msg.id, null, undefined, '', leave.msg.channel, false,
ev.detail.msg.id, null, undefined, '', ev.detail.msg.channel, false,
{
isError: false,
type: leave.msg.botInfo.type,
type: ev.detail.msg.botInfo.type,
args: [ userInfo.getName() ],
target: userInfo,
},
@ -834,16 +835,16 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
Umi.Users.Remove(userInfo);
});
sockChat.watch('msg:add', add => {
if(dumpEvents) console.log('msg:add', add);
sockChat.watch('msg:add', ev => {
if(dumpEvents) console.log('msg:add', ev);
const senderInfo = add.msg.sender;
const senderInfo = ev.detail.msg.sender;
const userInfo = senderInfo.name === undefined
? Umi.Users.Get(senderInfo.id)
: new Umi.User(senderInfo.id, senderInfo.name, senderInfo.colour, senderInfo.permsRaw);
// hack
let channelName = add.msg.channel;
let channelName = ev.detail.msg.channel;
if(channelName !== undefined && channelName.startsWith('@~')) {
const chanUserInfo = Umi.Users.Get(channelName.substring(2));
if(chanUserInfo !== null)
@ -851,7 +852,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
}
// also hack
if(add.msg.flags.isPM) {
if(ev.detail.msg.flags.isPM) {
if(Umi.Channels.Get(channelName) === null)
Umi.Channels.Add(new Umi.Channel(channelName, false, true, true));
@ -860,24 +861,24 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
}
Umi.Messages.Add(new Umi.Message(
add.msg.id,
add.msg.time,
ev.detail.msg.id,
ev.detail.msg.time,
userInfo,
add.msg.text,
ev.detail.msg.text,
channelName,
false,
add.msg.botInfo,
add.msg.flags.isAction,
add.msg.silent,
ev.detail.msg.botInfo,
ev.detail.msg.flags.isAction,
ev.detail.msg.silent,
));
});
sockChat.watch('msg:remove', remove => {
if(dumpEvents) console.log('msg:remove', remove);
sockChat.watch('msg:remove', ev => {
if(dumpEvents) console.log('msg:remove', ev);
Umi.Messages.Remove(Umi.Messages.Get(remove.msg.id));
Umi.Messages.Remove(Umi.Messages.Get(ev.detail.msg.id));
});
sockChat.watch('msg:clear', () => {
if(dumpEvents) console.log('msg:clear');
sockChat.watch('msg:clear', ev => {
if(dumpEvents) console.log('msg:clear', ev);
Umi.UI.Messages.RemoveAll();
});

View file

@ -1,4 +1,4 @@
#include watcher.js
#include eventtarget.js
#include settings/scoped.js
#include settings/virtual.js
#include settings/webstorage.js
@ -15,9 +15,16 @@ const MamiSettings = function(storageOrPrefix) {
throw 'required methods do not exist in storageOrPrefix object';
const storage = new MamiSettingsVirtualStorage(storageOrPrefix);
const watchers = new MamiWatchers;
const settings = new Map;
const eventTarget = new MamiEventTarget('mami:setting');
const createUpdateEvent = (name, value, initial) => eventTarget.create(name, {
name: name,
value: value,
initial: !!initial,
});
const dispatchUpdate = (name, value) => eventTarget.dispatchEvent(createUpdateEvent(name, value));
const broadcast = new BroadcastChannel(`${MAMI_JS}:settings:${storage.name()}`);
const broadcastUpdate = (name, value) => {
setTimeout(() => broadcast.postMessage({ act: 'update', name: name, value: value }), 0);
@ -43,7 +50,7 @@ const MamiSettings = function(storageOrPrefix) {
return;
storage.delete(setting.name);
watchers.call(setting.name, setting.fallback, setting.name);
dispatchUpdate(setting.name, setting.fallback);
broadcastUpdate(setting.name, setting.fallback);
};
@ -89,7 +96,7 @@ const MamiSettings = function(storageOrPrefix) {
} else
storage.set(setting.name, value);
watchers.call(setting.name, value, setting.name);
dispatchUpdate(setting.name, value);
broadcastUpdate(setting.name, value);
};
@ -98,7 +105,7 @@ const MamiSettings = function(storageOrPrefix) {
return;
if(ev.data.act === 'update' && typeof ev.data.name === 'string') {
watchers.call(ev.data.name, ev.data.value, ev.data.name);
dispatchUpdate(ev.data.name, ev.data.value);
return;
}
};
@ -122,8 +129,6 @@ const MamiSettings = function(storageOrPrefix) {
if(virtual === true)
storage.virtualise(name);
watchers.define(name);
},
info: name => getSetting(name),
names: () => Array.from(settings.keys()),
@ -143,7 +148,7 @@ const MamiSettings = function(storageOrPrefix) {
},
touch: name => {
const setting = getSetting(name);
watchers.call(setting.name, getValue(setting), setting.name);
dispatchUpdate(setting.name, getValue(setting));
},
clear: (criticalOnly, prefix) => {
for(const setting of settings.values())
@ -152,10 +157,11 @@ const MamiSettings = function(storageOrPrefix) {
},
watch: (name, handler) => {
const setting = getSetting(name);
watchers.watch(setting.name, handler, getValue(setting), setting.name);
eventTarget.watch(setting.name, handler);
handler(createUpdateEvent(setting.name, getValue(setting), true));
},
unwatch: (name, handler) => {
watchers.unwatch(getSetting(name).name, handler);
eventTarget.unwatch(name, handler);
},
virtualise: name => storage.virtualise(getSetting(name).name),
scope: name => new MamiSettingsScoped(pub, name),

View file

@ -1,18 +1,10 @@
#include common.js
#include eventtarget.js
#include servers.js
#include watcher.js
#include websock.js
Umi.Protocol.SockChat.Protocol = function() {
const watchers = new MamiWatchers(false);
watchers.define([
'conn:init', 'conn:ready', 'conn:lost', 'conn:error',
'ping:send', 'ping:long', 'ping:recv',
'session:start', 'session:fail', 'session:term',
'user:add', 'user:remove', 'user:update', 'user:clear',
'chan:add', 'chan:remove', 'chan:update', 'chan:clear', 'chan:focus', 'chan:join', 'chan:leave',
'msg:add', 'msg:remove', 'msg:clear',
]);
const eventTarget = new MamiEventTarget('mami:proto');
const parseUserColour = str => {
// todo
@ -61,7 +53,7 @@ Umi.Protocol.SockChat.Protocol = function() {
stopPingWatcher();
if(lastPong === undefined)
watchers.call('ping:long');
eventTarget.dispatch('ping:long');
}, 2000);
};
@ -81,7 +73,7 @@ Umi.Protocol.SockChat.Protocol = function() {
if(selfUserId === undefined)
return;
watchers.call('ping:send');
eventTarget.dispatch('ping:send');
startPingWatcher();
lastPong = undefined;
@ -111,10 +103,10 @@ Umi.Protocol.SockChat.Protocol = function() {
isRestarting = false;
// see if these are neccesary
watchers.call('user:clear');
watchers.call('chan:clear');
eventTarget.dispatch('user:clear');
eventTarget.dispatch('chan:clear');
watchers.call('conn:ready', { wasConnected: wasConnected });
eventTarget.dispatch('conn:ready', { wasConnected: wasConnected });
};
const onClose = ev => {
@ -136,7 +128,7 @@ Umi.Protocol.SockChat.Protocol = function() {
} else if(code === 1012)
isRestarting = true;
watchers.call('conn:lost', {
eventTarget.dispatch('conn:lost', {
wasConnected: wasConnected,
isRestarting: isRestarting,
code: code,
@ -148,7 +140,7 @@ Umi.Protocol.SockChat.Protocol = function() {
};
const onError = ex => {
watchers.call('conn:error', ex);
eventTarget.dispatch('conn:error', ex);
};
const unfuckText = text => {
@ -181,7 +173,7 @@ Umi.Protocol.SockChat.Protocol = function() {
// pong handler
handlers['0'] = () => {
lastPong = Date.now();
watchers.call('ping:recv', {
eventTarget.dispatch('ping:recv', {
ping: lastPing,
pong: lastPong,
diff: lastPong - lastPing,
@ -194,7 +186,7 @@ Umi.Protocol.SockChat.Protocol = function() {
selfUserId = userIdOrReason;
selfChannelName = chanNameOrMsgId;
watchers.call('session:start', {
eventTarget.dispatch('session:start', {
wasConnected: wasConnected,
session: { success: true },
ctx: {
@ -235,11 +227,11 @@ Umi.Protocol.SockChat.Protocol = function() {
until: userNameOrExpiry === '-1' ? undefined : new Date(parseInt(userNameOrExpiry) * 1000),
};
watchers.call('session:fail', failInfo);
eventTarget.dispatch('session:fail', failInfo);
return;
}
watchers.call('user:add', {
eventTarget.dispatch('user:add', {
msg: {
id: chanNameOrMsgId,
time: new Date(parseInt(successOrTimeStamp) * 1000),
@ -300,12 +292,12 @@ Umi.Protocol.SockChat.Protocol = function() {
};
}
watchers.call('msg:add', msgInfo);
eventTarget.dispatch('msg:add', msgInfo);
};
// user leave
handlers['3'] = (userId, userName, reason, timeStamp, msgId) => {
watchers.call('user:remove', {
eventTarget.dispatch('user:remove', {
leave: { type: reason },
msg: {
id: msgId,
@ -329,7 +321,7 @@ Umi.Protocol.SockChat.Protocol = function() {
// channel add
handlers['4']['0'] = (name, hasPass, isTemp) => {
watchers.call('chan:add', {
eventTarget.dispatch('chan:add', {
channel: {
name: name,
hasPassword: hasPass !== '0',
@ -340,7 +332,7 @@ Umi.Protocol.SockChat.Protocol = function() {
// channel update
handlers['4']['1'] = (prevName, name, hasPass, isTemp) => {
watchers.call('chan:update', {
eventTarget.dispatch('chan:update', {
channel: {
previousName: prevName,
name: name,
@ -352,7 +344,7 @@ Umi.Protocol.SockChat.Protocol = function() {
// channel remove
handlers['4']['2'] = name => {
watchers.call('chan:remove', {
eventTarget.dispatch('chan:remove', {
channel: { name: name },
});
};
@ -362,7 +354,7 @@ Umi.Protocol.SockChat.Protocol = function() {
// user join channel
handlers['5']['0'] = (userId, userName, userColour, userPerms, msgId) => {
watchers.call('chan:join', {
eventTarget.dispatch('chan:join', {
user: {
id: userId,
self: userId === selfUserId,
@ -384,7 +376,7 @@ Umi.Protocol.SockChat.Protocol = function() {
// user leave channel
handlers['5']['1'] = (userId, msgId) => {
watchers.call('chan:leave', {
eventTarget.dispatch('chan:leave', {
user: {
id: userId,
self: userId === selfUserId,
@ -404,14 +396,14 @@ Umi.Protocol.SockChat.Protocol = function() {
handlers['5']['2'] = name => {
selfChannelName = name;
watchers.call('chan:focus', {
eventTarget.dispatch('chan:focus', {
channel: { name: selfChannelName },
});
};
// message delete
handlers['6'] = msgId => {
watchers.call('msg:remove', {
eventTarget.dispatch('msg:remove', {
msg: {
id: msgId,
channel: selfChannelName,
@ -429,7 +421,7 @@ Umi.Protocol.SockChat.Protocol = function() {
for(let i = 0; i < count; ++i) {
const offset = 5 * i;
watchers.call('user:add', {
eventTarget.dispatch('user:add', {
user: {
id: args[offset],
self: args[offset] === selfUserId,
@ -479,7 +471,7 @@ Umi.Protocol.SockChat.Protocol = function() {
};
}
watchers.call('msg:add', info);
eventTarget.dispatch('msg:add', info);
};
// existing channels
@ -489,7 +481,7 @@ Umi.Protocol.SockChat.Protocol = function() {
for(let i = 0; i < count; ++i) {
const offset = 3 * i;
watchers.call('chan:add', {
eventTarget.dispatch('chan:add', {
channel: {
name: args[offset],
hasPassword: args[offset + 1] !== '0',
@ -499,7 +491,7 @@ Umi.Protocol.SockChat.Protocol = function() {
});
}
watchers.call('chan:focus', {
eventTarget.dispatch('chan:focus', {
channel: { name: selfChannelName },
});
};
@ -507,13 +499,13 @@ Umi.Protocol.SockChat.Protocol = function() {
// context clear
handlers['8'] = mode => {
if(mode === '0' || mode === '3' || mode === '4')
watchers.call('msg:clear');
eventTarget.dispatch('msg:clear');
if(mode === '1' || mode === '3' || mode === '4')
watchers.call('user:clear');
eventTarget.dispatch('user:clear');
if(mode === '2' || mode === '4')
watchers.call('chan:clear');
eventTarget.dispatch('chan:clear');
};
// baka (ban/kick)
@ -533,12 +525,12 @@ Umi.Protocol.SockChat.Protocol = function() {
bakaInfo.baka.until = expiry === '-1' ? undefined : new Date(parseInt(expiry) * 1000);
}
watchers.call('session:term', bakaInfo);
eventTarget.dispatch('session:term', bakaInfo);
};
// user update
handlers['10'] = (userId, userName, userColour, userPerms) => {
watchers.call('user:update', {
eventTarget.dispatch('user:update', {
user: {
id: userId,
self: userId === selfUserId,
@ -558,7 +550,7 @@ Umi.Protocol.SockChat.Protocol = function() {
return;
UmiServers.getServer(server => {
watchers.call('conn:init', {
eventTarget.dispatch('conn:init', {
server: server,
wasConnected: wasConnected,
attempt: ++connectAttempts,
@ -604,8 +596,8 @@ Umi.Protocol.SockChat.Protocol = function() {
noReconnect = true;
sock?.close();
},
watch: (name, handler) => watchers.watch(name, handler),
unwatch: (name, handler) => watchers.unwatch(name, handler),
watch: (name, handler) => eventTarget.watch(name, handler),
unwatch: (name, handler) => eventTarget.unwatch(name, handler),
setDumpPackets: state => dumpPackets = !!state,
switchChannel: channelInfo => {
if(selfUserId === undefined)

View file

@ -454,7 +454,7 @@ Umi.UI.Settings = (function() {
input.disabled = true;
if(display.type === 'checkbox') {
mami.settings.watch(setting.name, v => input.checked = v);
mami.settings.watch(setting.name, ev => input.checked = ev.detail.value);
input.addEventListener('change', () => {
if(display.confirm !== undefined && input.checked !== setting.fallback && !confirm(display.confirm)) {
input.checked = setting.fallback;
@ -464,7 +464,7 @@ Umi.UI.Settings = (function() {
mami.settings.toggle(setting.name);
});
} else {
mami.settings.watch(setting.name, v => input.value = v);
mami.settings.watch(setting.name, ev => input.value = ev.detail.value);
input.addEventListener('change', () => mami.settings.set(setting.name, input.value));
}
}

View file

@ -1,77 +0,0 @@
#include utility.js
const MamiWatcher = function(initCall) {
if(typeof initCall !== 'boolean')
initCall = true;
const handlers = [];
const watch = (handler, ...args) => {
if(typeof handler !== 'function')
throw 'handler must be a function';
if(handlers.includes(handler))
throw 'handler already registered';
handlers.push(handler);
if(initCall) {
args.push(true);
handler(...args);
}
};
const unwatch = handler => {
$ari(handlers, handler);
};
return {
watch: watch,
unwatch: unwatch,
call: (...args) => {
if(initCall)
args.push(false);
for(const handler of handlers)
handler(...args);
},
};
};
const MamiWatchers = function(initCall) {
if(typeof initCall !== 'boolean')
initCall = true;
const watchers = new Map;
const getWatcher = name => {
const watcher = watchers.get(name);
if(watcher === undefined)
throw 'undefined watcher name';
return watcher;
};
const watch = (name, handler, ...args) => {
getWatcher(name).watch(handler, ...args);
};
const unwatch = (name, handler) => {
getWatcher(name).unwatch(handler);
};
return {
watch: watch,
unwatch: unwatch,
define: names => {
if(typeof names === 'string')
watchers.set(names, new MamiWatcher(initCall));
else if(Array.isArray(names))
for(const name of names)
watchers.set(name, new MamiWatcher(initCall));
else
throw 'names must be an array of names or a single name';
},
call: (name, ...args) => {
getWatcher(name).call(...args);
},
};
};