Attempts at making message rendering and notifications more consistent and moved a lot of UI stuff out of the protocol handler.
This commit is contained in:
parent
c0246909c0
commit
cdabf80e1c
12 changed files with 491 additions and 765 deletions
|
@ -25,6 +25,7 @@ const MamiCompat = (current, path, handler) => {
|
|||
// Backwards compat for scripts
|
||||
// Keep in sync with <https://fii.moe/fp/13176> for as long as possible
|
||||
MamiCompat(Umi, 'Server.SendMessage', text => Umi.Server.sendMessage(text));
|
||||
MamiCompat(Umi, 'Protocol.SockChat.Protocol.Instance.SendMessage', text => Umi.Server.sendMessage(text));
|
||||
MamiCompat(Umi, 'Protocol.SockLegacy.Protocol.Instance.SendMessage', text => Umi.Server.sendMessage(text));
|
||||
MamiCompat(Umi, 'Parser.SockChatBBcode.EmbedStub', () => {}); // intentionally a no-op
|
||||
MamiCompat(Umi, 'UI.View.SetText', text => console.log(`Umi.UI.View.SetText(text: ${text})`));
|
||||
|
|
|
@ -98,7 +98,6 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
|||
settings.define('soundEnablePrivate', 'boolean', true);
|
||||
settings.define('soundEnableForceLeave', 'boolean', true);
|
||||
settings.define('minecraft', ['no', 'yes', 'old'], 'no');
|
||||
settings.define('playSoundOnConnect', 'boolean', false);
|
||||
settings.define('windowsLiveMessenger', 'boolean', false);
|
||||
settings.define('seinfeld', 'boolean', false);
|
||||
settings.define('flashTitle', 'boolean', true);
|
||||
|
@ -149,7 +148,7 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
|||
settings.touch('soundVolume');
|
||||
settings.touch('soundPack');
|
||||
|
||||
soundCtx.packPlayer.playEvent('server');
|
||||
soundCtx.library.play(soundCtx.pack.getEventSound('server'));
|
||||
}
|
||||
|
||||
soundCtx.muted = !v;
|
||||
|
@ -162,9 +161,8 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
|||
return;
|
||||
}
|
||||
|
||||
const player = soundCtx.packPlayer;
|
||||
player.loadPack(packs.get(v));
|
||||
if(!i) player.playEvent('server');
|
||||
soundCtx.pack = packs.get(v);
|
||||
if(!i) soundCtx.library.play(soundCtx.pack.getEventSound('server'));
|
||||
});
|
||||
|
||||
settings.watch('soundVolume', v => {
|
||||
|
@ -252,12 +250,18 @@ window.Umi = { UI: {}, Protocol: { SockChat: { Protocol: {} } } };
|
|||
settings.watch('tmpDisableOldThemeSys', (v, n, i) => { if(!i) Umi.UI.View.AccentReload(); });
|
||||
|
||||
settings.watch('minecraft', (v, n, i) => {
|
||||
if(v !== 'no') {
|
||||
if(i && v === 'no')
|
||||
return;
|
||||
|
||||
soundCtx.library.play((() => {
|
||||
if(i)
|
||||
soundCtx.library.play('minecraft:nether:enter');
|
||||
else
|
||||
Umi.Sound.Play('join');
|
||||
}
|
||||
return 'minecraft:nether:enter';
|
||||
if(v === 'yes')
|
||||
return 'minecraft:door:open';
|
||||
if(v === 'old')
|
||||
return 'minecraft:door:open-old';
|
||||
return mami.sound.pack.getEventSound('join');
|
||||
})());
|
||||
});
|
||||
|
||||
settings.watch('enableNotifications', v => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Umi.Message = function(msgId, time, user, text, channel, highlight, botInfo, isAction) {
|
||||
Umi.Message = function(msgId, time, user, text, channel, highlight, botInfo, isAction, isLog) {
|
||||
msgId = (msgId || '').toString();
|
||||
time = time === null ? new Date() : new Date(parseInt(time || 0) * 1000);
|
||||
user = user || {};
|
||||
|
@ -6,18 +6,23 @@ Umi.Message = function(msgId, time, user, text, channel, highlight, botInfo, isA
|
|||
channel = (channel || '').toString();
|
||||
highlight = !!highlight;
|
||||
isAction = !!isAction;
|
||||
isLog = !!isLog;
|
||||
hasSeen = isLog;
|
||||
|
||||
const msgIdInt = parseInt(msgId);
|
||||
|
||||
return {
|
||||
getId: function() { return msgId; },
|
||||
getIdInt: function() { return msgIdInt; },
|
||||
getTime: function() { return time; },
|
||||
getUser: function() { return user; },
|
||||
getText: function() { return text; },
|
||||
getChannel: function() { return channel; },
|
||||
shouldHighlight: function() { return highlight; },
|
||||
getBotInfo: function() { return botInfo; },
|
||||
isAction: function() { return isAction; },
|
||||
getId: () => msgId,
|
||||
getIdInt: () => msgIdInt,
|
||||
getTime: () => time,
|
||||
getUser: () => user,
|
||||
getText: () => text,
|
||||
getChannel: () => channel,
|
||||
shouldHighlight: () => highlight,
|
||||
getBotInfo: () => botInfo,
|
||||
isAction: () => isAction,
|
||||
isLog: () => isLog,
|
||||
hasSeen: () => hasSeen,
|
||||
markSeen: () => hasSeen = true,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,24 +1,16 @@
|
|||
#include channels.js
|
||||
#include server.js
|
||||
#include ui/messages.jsx
|
||||
|
||||
Umi.Messages = (function() {
|
||||
const msgs = new Map;
|
||||
|
||||
const onAdd = [],
|
||||
onRemove = [],
|
||||
onClear = [];
|
||||
|
||||
return {
|
||||
OnAdd: onAdd,
|
||||
OnRemove: onRemove,
|
||||
OnClear: onClear,
|
||||
Add: function(msg) {
|
||||
const msgId = msg.getId();
|
||||
if(!msgs.has(msgId)) {
|
||||
msgs.set(msgId, msg);
|
||||
|
||||
for(const i in onAdd)
|
||||
onAdd[i](msg);
|
||||
Umi.UI.Messages.Add(msg);
|
||||
|
||||
if(window.CustomEvent)
|
||||
window.dispatchEvent(new CustomEvent('umi:message_add', {
|
||||
|
@ -30,16 +22,12 @@ Umi.Messages = (function() {
|
|||
const msgId = msg.getId();
|
||||
if(msgs.has(msgId)) {
|
||||
msgs.delete(msgId);
|
||||
|
||||
for(const i in onRemove)
|
||||
onRemove[i](msg);
|
||||
Umi.UI.Messages.Remove(msg);
|
||||
}
|
||||
},
|
||||
Clear: function() {
|
||||
msgs.clear();
|
||||
|
||||
for(const i in onClear)
|
||||
onClear[i]();
|
||||
Umi.UI.Messages.RemoveAll();
|
||||
},
|
||||
All: function(channel, excludeNull) {
|
||||
if(!channel)
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include users.js
|
||||
#include parsing.js
|
||||
#include servers.js
|
||||
#include txtrigs.js
|
||||
#include websock.js
|
||||
#include ui/emotes.js
|
||||
#include ui/markup.js
|
||||
|
@ -16,11 +15,9 @@
|
|||
#include ui/messages.jsx
|
||||
#include ui/view.js
|
||||
#include ui/loading-overlay.jsx
|
||||
#include sound/umisound.js
|
||||
|
||||
Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
||||
const pub = {};
|
||||
Umi.Protocol.SockChat.Protocol.Instance = pub;
|
||||
|
||||
const chatBot = new Umi.User('-1', 'Server');
|
||||
|
||||
|
@ -165,7 +162,6 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
|
||||
getLoadingOverlay('unlink', 'Disconnected!', msg);
|
||||
|
||||
//Umi.Messages.Clear();
|
||||
Umi.Users.Clear();
|
||||
|
||||
connectAttempts = 0;
|
||||
|
@ -175,225 +171,6 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
}, 5000);
|
||||
};
|
||||
|
||||
const parseBotMessage = function(parts) {
|
||||
let text = '';
|
||||
|
||||
switch(parts[1]) {
|
||||
case 'silence':
|
||||
text = 'You have been silenced!';
|
||||
break;
|
||||
|
||||
case 'unsil':
|
||||
text = 'You are no longer silenced!';
|
||||
break;
|
||||
|
||||
case 'silok':
|
||||
text = '{0} is now silenced.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'usilok':
|
||||
text = '{0} is no longer silenced.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'flood':
|
||||
text = '{0} got kicked for flood protection.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'flwarn':
|
||||
text = 'You are about to hit the flood limit! If you continue you will be kicked.';
|
||||
break;
|
||||
|
||||
case 'unban':
|
||||
text = '{0} is no longer banned.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'banlist':
|
||||
const blentries = parts[2].split(', ');
|
||||
for(const i in blentries)
|
||||
blentries[i] = blentries[i].slice(92, -4);
|
||||
|
||||
text = 'Banned: {0}'.replace('{0}', blentries.join(', '));
|
||||
break;
|
||||
|
||||
case 'who':
|
||||
const wentries = parts[2].split(', ');
|
||||
for(const i in wentries) {
|
||||
const isSelf = wentries[i].includes(' style="font-weight: bold;"');
|
||||
wentries[i] = wentries[i].slice(isSelf ? 102 : 75, -4);
|
||||
if(isSelf) wentries[i] += ' (You)';
|
||||
}
|
||||
|
||||
text = 'Online: {0}'.replace('{0}', wentries.join(', '));
|
||||
break;
|
||||
|
||||
case 'whochan':
|
||||
const wcentries = (parts[3] || '').split(', ');
|
||||
for(const i in wcentries) {
|
||||
const isSelf = wcentries[i].includes(' style="font-weight: bold;"');
|
||||
wcentries[i] = wcentries[i].slice(isSelf ? 102 : 75, -4);
|
||||
if(isSelf) wcentries[i] += ' (You)';
|
||||
}
|
||||
|
||||
text = 'Online in {0}: {1}'.replace('{0}', parts[2]).replace('{1}', wcentries.join(', '));
|
||||
break;
|
||||
|
||||
case 'silerr':
|
||||
text = 'This user has already been silenced!';
|
||||
break;
|
||||
|
||||
case 'usilerr':
|
||||
text = "This user isn't silenced!";
|
||||
break;
|
||||
|
||||
case 'silperr':
|
||||
text = "You aren't allowed to silence this user!";
|
||||
break;
|
||||
|
||||
case 'usilperr':
|
||||
text = "You aren't allowed to remove the silence on this user!";
|
||||
break;
|
||||
|
||||
case 'silself':
|
||||
text = 'Why would you even try to silence yourself?';
|
||||
break;
|
||||
|
||||
case 'delerr':
|
||||
text = "You aren't allowed to delete this message!";
|
||||
break;
|
||||
|
||||
case 'notban':
|
||||
text = "{0} isn't banned!".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'whoerr':
|
||||
text = '{0} does not exist!'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'join':
|
||||
text = '{0} joined.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'jchan':
|
||||
text = '{0} joined the channel.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'leave':
|
||||
text = '{0} left.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'timeout':
|
||||
text = '{0} exploded.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'lchan':
|
||||
text = '{0} left the channel.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'kick':
|
||||
text = '{0} got kicked.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'nick':
|
||||
text = '{0} changed their name to {1}.'.replace('{0}', parts[2]).replace('{1}', parts[3]);
|
||||
break;
|
||||
|
||||
case 'crchan':
|
||||
text = '{0} has been created.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'delchan':
|
||||
text = '{0} has been deleted.'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'cpwdchan':
|
||||
text = 'Changed the channel password!';
|
||||
break;
|
||||
|
||||
case 'cprivchan':
|
||||
text = 'Change access level of the channel!';
|
||||
break;
|
||||
|
||||
case 'ipaddr':
|
||||
text = 'IP of {0}: {1}'.replace('{0}', parts[2]).replace('{1}', parts[3]);
|
||||
break;
|
||||
|
||||
case 'cmdna':
|
||||
text = "You aren't allowed to use '{0}'.".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'nocmd':
|
||||
text = "The command '{0}' does not exist.".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'cmderr':
|
||||
text = "You didn't format the command correctly!";
|
||||
break;
|
||||
|
||||
case 'usernf':
|
||||
text = "{0} isn't logged in to the chat right now!".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'kickna':
|
||||
text = "You aren't allowed to kick {0}!".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'samechan':
|
||||
text = 'You are already in {0}!'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'ipchan':
|
||||
case 'nochan':
|
||||
text = "{0} doesn't exist!".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'nopwchan':
|
||||
text = "{0} has a password! Use '/join {0} [password]'.".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'ipwchan':
|
||||
text = "Wrong password! Couldn't join {0}.".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'inchan':
|
||||
text = "Channel names can't start with @ or *!";
|
||||
break;
|
||||
|
||||
case 'nischan':
|
||||
text = '{0} already exists!'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'ndchan':
|
||||
text = "You aren't allowed to delete {0}!".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'namchan':
|
||||
text = "You aren't allowed to edit {0}!".replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'nameinuse':
|
||||
text = '{0} is currently taken!'.replace('{0}', parts[2]);
|
||||
break;
|
||||
|
||||
case 'rankerr':
|
||||
text = "You can't set the access level of a channel higher than your own!";
|
||||
break;
|
||||
|
||||
case 'reconnect':
|
||||
text = 'Connection lost! Attempting to reconnect...';
|
||||
break;
|
||||
|
||||
case 'generr':
|
||||
text = 'Something happened.';
|
||||
break;
|
||||
|
||||
case 'say':
|
||||
default:
|
||||
text = parts[2];
|
||||
}
|
||||
|
||||
return text;
|
||||
};
|
||||
|
||||
const unfuckText = function(text) {
|
||||
const elem = document.createElement('div');
|
||||
elem.innerHTML = text.replace(/ <br\/> /g, "\n");
|
||||
|
@ -437,9 +214,6 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
}));
|
||||
|
||||
startKeepAlive();
|
||||
|
||||
if(settings.get('playSoundOnConnect'))
|
||||
Umi.Sound.Play('join');
|
||||
} else {
|
||||
switch (data[2]) {
|
||||
case 'joinfail':
|
||||
|
@ -496,25 +270,13 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
}
|
||||
|
||||
Umi.Messages.Add(new Umi.Message(
|
||||
data[6],
|
||||
data[1],
|
||||
chatBot,
|
||||
'{0} joined.'.replace('{0}', juser.getName()),
|
||||
channelName,
|
||||
false,
|
||||
{
|
||||
type: 'join',
|
||||
isError: false,
|
||||
args: [juser.getName()],
|
||||
target: juser,
|
||||
}
|
||||
data[6], data[1], chatBot, '', channelName, false,
|
||||
{ type: 'join', isError: false, args: [juser.getName()], target: juser }
|
||||
));
|
||||
Umi.Sound.Play('join');
|
||||
break;
|
||||
|
||||
case '2': // message
|
||||
let text = data[3],
|
||||
sound = 'incoming';
|
||||
let text = data[3];
|
||||
const muser = Umi.Users.Get(data[2]) || chatBot,
|
||||
textParts = text.split("\f");
|
||||
isPM = data[5][4] !== '0',
|
||||
|
@ -526,16 +288,9 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
text = unfuckText(text);
|
||||
|
||||
if(isBot) {
|
||||
sound = 'server';
|
||||
botInfo.isError = textParts[0] !== '0';
|
||||
botInfo.type = textParts[1];
|
||||
botInfo.args = textParts.slice(2);
|
||||
text = parseBotMessage(textParts);
|
||||
|
||||
if(botInfo.isError)
|
||||
sound = 'error';
|
||||
else if(textParts[1] === 'unban')
|
||||
sound = 'unban';
|
||||
}
|
||||
|
||||
if(isPM) {
|
||||
|
@ -545,92 +300,27 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
text = tmpMsg.join(' ');
|
||||
}
|
||||
|
||||
if(muser.getName() !== pmUserName)
|
||||
sound = 'private';
|
||||
|
||||
if(Umi.Channels.Get(pmChannel) === null)
|
||||
Umi.Channels.Add(new Umi.Channel(pmChannel, false, true, true));
|
||||
|
||||
Umi.UI.Menus.Attention('channels');
|
||||
}
|
||||
|
||||
if(muser.getId() === userId)
|
||||
sound = 'outgoing';
|
||||
|
||||
if(settings.get('playJokeSounds'))
|
||||
try {
|
||||
const trigger = mami.textTriggers.getTrigger(text);
|
||||
if(trigger.isSoundType()) {
|
||||
sound = '';
|
||||
mami.sound.library.play(
|
||||
trigger.getRandomSoundName(),
|
||||
trigger.getVolume(),
|
||||
trigger.getRate()
|
||||
);
|
||||
}
|
||||
} catch(ex) {}
|
||||
|
||||
Umi.Messages.Add(new Umi.Message(
|
||||
data[4],
|
||||
data[1],
|
||||
muser,
|
||||
text,
|
||||
data[4], data[1], muser, text,
|
||||
isPM ? pmChannel : (data[6] || channelName),
|
||||
false,
|
||||
botInfo,
|
||||
isAction
|
||||
false, botInfo, isAction
|
||||
));
|
||||
|
||||
if(!settings.get('onlySoundOnMention') && sound !== '')
|
||||
Umi.Sound.Play(sound);
|
||||
break;
|
||||
|
||||
case '3': // leave
|
||||
const luser = Umi.Users.Get(data[1]);
|
||||
let ltext = '',
|
||||
lsound = null;
|
||||
|
||||
switch(data[3]) {
|
||||
case 'flood':
|
||||
ltext = '{0} got kicked for flood protection.';
|
||||
lsound = 'flood';
|
||||
break;
|
||||
|
||||
case 'timeout':
|
||||
ltext = '{0} exploded.';
|
||||
lsound = 'timeout';
|
||||
break;
|
||||
|
||||
case 'kick':
|
||||
ltext = '{0} got bludgeoned to death.';
|
||||
lsound = 'kick';
|
||||
break;
|
||||
|
||||
case 'leave':
|
||||
default:
|
||||
ltext = '{0} left.';
|
||||
lsound = 'leave';
|
||||
break;
|
||||
}
|
||||
|
||||
Umi.Messages.Add(new Umi.Message(
|
||||
data[5],
|
||||
data[4],
|
||||
chatBot,
|
||||
ltext.replace('{0}', luser.getName()),
|
||||
channelName,
|
||||
false,
|
||||
{
|
||||
type: data[3],
|
||||
isError: false,
|
||||
args: [luser.getName()],
|
||||
target: luser,
|
||||
}
|
||||
data[5], data[4], chatBot, '', channelName, false,
|
||||
{ type: data[3], isError: false, args: [luser.getName()], target: luser }
|
||||
));
|
||||
Umi.Users.Remove(luser);
|
||||
|
||||
if(lsound !== null)
|
||||
Umi.Sound.Play(lsound);
|
||||
break;
|
||||
|
||||
case '4': // channel
|
||||
|
@ -656,53 +346,25 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
case '5': // user move
|
||||
switch(data[1]) {
|
||||
case '0':
|
||||
const umuser = new Umi.User(data[2], data[3], data[4], data[5]),
|
||||
text = '{0} joined the channel.';
|
||||
const umuser = new Umi.User(data[2], data[3], data[4], data[5]);
|
||||
|
||||
Umi.Users.Add(umuser);
|
||||
Umi.Messages.Add(new Umi.Message(
|
||||
data[6],
|
||||
null,
|
||||
chatBot,
|
||||
text.replace('{0}', umuser.getName()),
|
||||
channelName,
|
||||
false,
|
||||
{
|
||||
type: 'jchan',
|
||||
isError: false,
|
||||
args: [
|
||||
umuser.getName()
|
||||
],
|
||||
target: umuser,
|
||||
}
|
||||
data[6], null, chatBot, '', channelName, false,
|
||||
{ type: 'jchan', isError: false, args: [ umuser.getName() ], target: umuser }
|
||||
));
|
||||
Umi.Sound.Play('join');
|
||||
break;
|
||||
|
||||
case '1':
|
||||
if(data[2] === userId)
|
||||
return;
|
||||
|
||||
const mouser = Umi.Users.Get(+data[2]),
|
||||
motext = '{0} has left the channel.';
|
||||
const mouser = Umi.Users.Get(+data[2]);
|
||||
|
||||
Umi.Messages.Add(new Umi.Message(
|
||||
data[3],
|
||||
null,
|
||||
chatBot,
|
||||
motext.replace('{0}', mouser.getName()),
|
||||
channelName,
|
||||
false,
|
||||
{
|
||||
type: 'lchan',
|
||||
isError: false,
|
||||
args: [
|
||||
mouser.getName()
|
||||
],
|
||||
target: mouser,
|
||||
}
|
||||
data[3], null, chatBot, '', channelName, false,
|
||||
{ type: 'lchan', isError: false, args: [ mouser.getName() ], target: mouser }
|
||||
));
|
||||
Umi.Sound.Play('leave');
|
||||
Umi.Users.Remove(mouser);
|
||||
break;
|
||||
|
||||
|
@ -737,8 +399,6 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
cmtextParts = cmtext.split("\f"),
|
||||
cmbotInfo = {};
|
||||
|
||||
cmtext = unfuckText(cmtext);
|
||||
|
||||
if(isNaN(cmid))
|
||||
cmid = -Math.ceil(Math.random() * 10000000000);
|
||||
|
||||
|
@ -746,18 +406,13 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
cmbotInfo.isError = cmtextParts[0] !== '0';
|
||||
cmbotInfo.type = cmtextParts[1];
|
||||
cmbotInfo.args = cmtextParts.slice(2);
|
||||
cmtext = parseBotMessage(cmtextParts);
|
||||
}
|
||||
cmtext = '';
|
||||
} else
|
||||
cmtext = unfuckText(cmtext);
|
||||
|
||||
Umi.Messages.Add(new Umi.Message(
|
||||
cmid,
|
||||
data[2],
|
||||
cmuser,
|
||||
cmtext,
|
||||
channelName,
|
||||
false,
|
||||
cmbotInfo,
|
||||
cmflags[1] !== '0' && cmflags[3] === '0',
|
||||
cmid, data[2], cmuser, cmtext, channelName, false, cmbotInfo,
|
||||
cmflags[1] !== '0' && cmflags[3] === '0', true
|
||||
));
|
||||
break;
|
||||
|
||||
|
@ -830,7 +485,6 @@ Umi.Protocol.SockChat.Protocol = function(views, settings) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
let icon, header;
|
||||
if(isBan) {
|
||||
icon = 'hammer';
|
||||
|
|
|
@ -8,7 +8,8 @@ const MamiSoundContext = function() {
|
|||
const manager = new MamiSoundManager(audioCtx);
|
||||
const library = new MamiSoundLibrary(manager);
|
||||
const packs = new MamiSoundPacks;
|
||||
const packPlayer = new MamiSoundPackPlayer(library);
|
||||
|
||||
let pack = new MamiSoundPack;
|
||||
|
||||
const pub = {};
|
||||
|
||||
|
@ -17,7 +18,16 @@ const MamiSoundContext = function() {
|
|||
manager: { value: manager, enumerable: true },
|
||||
library: { value: library, enumerable: true },
|
||||
packs: { value: packs, enumerable: true },
|
||||
packPlayer: { value: packPlayer, enumerable: true },
|
||||
|
||||
pack: {
|
||||
get: () => pack,
|
||||
set: value => {
|
||||
if(typeof value !== 'object' || typeof value.getEventSound !== 'function')
|
||||
throw 'value is not a valid soundpack';
|
||||
pack = value;
|
||||
},
|
||||
enumerable: true,
|
||||
},
|
||||
|
||||
ready: { get: audioCtx.isReady, enumerable: true },
|
||||
volume: { get: audioCtx.getVolume, set: audioCtx.setVolume, enumerable: true },
|
||||
|
|
|
@ -78,6 +78,9 @@ const MamiSoundLibrary = function(soundMgr) {
|
|||
loadBuffer: async name => await soundMgr.loadBuffer(getSoundSources(name)),
|
||||
loadSource: loadSoundSource,
|
||||
play: async (name, volume, rate) => {
|
||||
if(typeof name !== 'string')
|
||||
return;
|
||||
|
||||
const source = await loadSoundSource(name);
|
||||
|
||||
if(typeof volume === 'number')
|
||||
|
|
|
@ -6,6 +6,8 @@ const MamiSoundPack = function(name, isReadOnly, title, events) {
|
|||
title = (title || '').toString();
|
||||
events = events || new Map;
|
||||
|
||||
const hasEventSound = eventName => events.has(eventName);
|
||||
|
||||
return {
|
||||
getName: () => name,
|
||||
isReadOnly: () => isReadOnly,
|
||||
|
@ -16,11 +18,24 @@ const MamiSoundPack = function(name, isReadOnly, title, events) {
|
|||
title = (newTitle || '').toString();
|
||||
},
|
||||
getEventNames: () => Array.from(events.keys()),
|
||||
hasEventSound: eventName => events.has(eventName),
|
||||
getEventSound: eventName => {
|
||||
if(!events.has(eventName))
|
||||
throw 'event not registered';
|
||||
return events.get(eventName);
|
||||
hasEventSound: hasEventSound,
|
||||
getEventSound: eventNames => {
|
||||
let event;
|
||||
|
||||
if(Array.isArray(eventNames)) {
|
||||
for(const name of eventNames)
|
||||
if(hasEventSound(name)) {
|
||||
event = name;
|
||||
break;
|
||||
}
|
||||
} else if(hasEventSound(eventNames)) {
|
||||
event = eventNames;
|
||||
}
|
||||
|
||||
if(event === undefined)
|
||||
return;
|
||||
|
||||
return events.get(event);
|
||||
},
|
||||
setEventSound: (eventName, soundName) => {
|
||||
events.set(
|
||||
|
@ -40,47 +55,6 @@ const MamiSoundPack = function(name, isReadOnly, title, events) {
|
|||
};
|
||||
};
|
||||
|
||||
const MamiSoundPackPlayer = function(sndLibrary) {
|
||||
let pack;
|
||||
|
||||
return {
|
||||
loadPack: packInfo => {
|
||||
if(typeof packInfo !== 'object' || typeof packInfo.getEventSound !== 'function')
|
||||
throw 'pack is not a valid soundpack';
|
||||
pack = packInfo;
|
||||
},
|
||||
unloadPack: () => {
|
||||
pack = undefined;
|
||||
buffers.clear();
|
||||
},
|
||||
hasPack: () => pack !== undefined,
|
||||
|
||||
hasEvent: name => pack !== undefined && pack.hasEventSound(event),
|
||||
playEvent: async event => {
|
||||
if(pack === undefined)
|
||||
return;
|
||||
|
||||
if(Array.isArray(event)) {
|
||||
const names = event;
|
||||
event = undefined;
|
||||
|
||||
for(const name of names) {
|
||||
if(pack.hasEventSound(name)) {
|
||||
event = name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(event === undefined)
|
||||
return;
|
||||
} else if(!pack.hasEventSound(event))
|
||||
return;
|
||||
|
||||
await sndLibrary.play(pack.getEventSound(event));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const MamiSoundPacks = function() {
|
||||
const packs = new Map;
|
||||
|
||||
|
|
|
@ -1,124 +1,109 @@
|
|||
#include sound/seinfeld.js
|
||||
|
||||
Umi.Sound = (() => {
|
||||
return {
|
||||
Play: sound => {
|
||||
if(!sound || sound === 'none')
|
||||
const getLibrarySound = event => {
|
||||
if(!event || event === 'none')
|
||||
return;
|
||||
|
||||
const minecraft = mami.settings.get('minecraft');
|
||||
|
||||
if(event === 'join') {
|
||||
if(!mami.settings.get('soundEnableJoin'))
|
||||
return;
|
||||
|
||||
switch(sound) {
|
||||
case 'join':
|
||||
if(!mami.settings.get('soundEnableJoin'))
|
||||
return;
|
||||
if(mami.settings.get('seinfeld'))
|
||||
return Seinfeld.getRandom();
|
||||
|
||||
if(mami.settings.get('seinfeld')) {
|
||||
mami.sound.library.play(Seinfeld.getRandom());
|
||||
break;
|
||||
}
|
||||
if(minecraft === 'yes')
|
||||
return 'minecraft:door:open';
|
||||
|
||||
switch(mami.settings.get('minecraft')) {
|
||||
case 'yes':
|
||||
mami.sound.library.play('minecraft:door:open');
|
||||
break;
|
||||
if(minecraft === 'old')
|
||||
return 'minecraft:door:open-old';
|
||||
|
||||
case 'old':
|
||||
mami.sound.library.play('minecraft:door:open-old');
|
||||
break;
|
||||
return mami.sound.pack.getEventSound('join');
|
||||
}
|
||||
|
||||
default:
|
||||
mami.sound.packPlayer.playEvent('join');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
if(event === 'leave') {
|
||||
if(!mami.settings.get('soundEnableLeave'))
|
||||
return;
|
||||
|
||||
case 'leave':
|
||||
if(!mami.settings.get('soundEnableLeave'))
|
||||
return;
|
||||
if(minecraft === 'yes')
|
||||
return 'minecraft:door:close';
|
||||
|
||||
switch(mami.settings.get('minecraft')) {
|
||||
case 'yes':
|
||||
mami.sound.library.play('minecraft:door:close');
|
||||
break;
|
||||
if(minecraft === 'old')
|
||||
return 'minecraft:door:close-old';
|
||||
|
||||
case 'old':
|
||||
mami.sound.library.play('minecraft:door:close-old');
|
||||
break;
|
||||
return mami.sound.pack.getEventSound('leave');
|
||||
}
|
||||
|
||||
default:
|
||||
mami.sound.packPlayer.playEvent('leave');
|
||||
break;
|
||||
}
|
||||
break;
|
||||
if(event === 'error') {
|
||||
if(!mami.settings.get('soundEnableError'))
|
||||
return;
|
||||
|
||||
case 'error':
|
||||
if(!mami.settings.get('soundEnableError'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound('error');
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent('error');
|
||||
break;
|
||||
if(event === 'server') {
|
||||
if(!mami.settings.get('soundEnableServer'))
|
||||
return;
|
||||
|
||||
case 'server':
|
||||
if(!mami.settings.get('soundEnableServer'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound('server');
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent('server');
|
||||
break;
|
||||
if(event === 'unban') {
|
||||
if(!mami.settings.get('soundEnableServer'))
|
||||
return;
|
||||
|
||||
case 'unban':
|
||||
if(!mami.settings.get('soundEnableServer'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound(['unban', 'server']);
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent(['unban', 'server']);
|
||||
break;
|
||||
if(event === 'incoming') {
|
||||
if(!mami.settings.get('soundEnableIncoming'))
|
||||
return;
|
||||
|
||||
case 'incoming':
|
||||
if(!mami.settings.get('soundEnableIncoming'))
|
||||
return;
|
||||
|
||||
if(mami.settings.get('windowsLiveMessenger')) {
|
||||
mami.sound.library.play('msn:incoming');
|
||||
} else {
|
||||
mami.sound.packPlayer.playEvent('incoming');
|
||||
}
|
||||
break;
|
||||
if(mami.settings.get('windowsLiveMessenger'))
|
||||
return 'msn:incoming';
|
||||
|
||||
case 'outgoing':
|
||||
if(!mami.settings.get('soundEnableOutgoing'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound('incoming');
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent('outgoing');
|
||||
break;
|
||||
if(event === 'outgoing') {
|
||||
if(!mami.settings.get('soundEnableOutgoing'))
|
||||
return;
|
||||
|
||||
case 'private':
|
||||
case 'incoming-priv':
|
||||
if(!mami.settings.get('soundEnablePrivate'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound('outgoing');
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent(['incoming-priv', 'incoming']);
|
||||
break;
|
||||
if(event === 'private' || event === 'incoming-priv') {
|
||||
if(!mami.settings.get('soundEnablePrivate'))
|
||||
return;
|
||||
|
||||
case 'flood':
|
||||
if(!mami.settings.get('soundEnableForceLeave'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound(['incoming-priv', 'incoming']);
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent(['flood', 'kick', 'leave']);
|
||||
break;
|
||||
if(event === 'flood') {
|
||||
if(!mami.settings.get('soundEnableForceLeave'))
|
||||
return;
|
||||
|
||||
case 'timeout':
|
||||
if(!mami.settings.get('soundEnableForceLeave'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound(['flood', 'kick', 'leave']);
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent(['timeout', 'leave']);
|
||||
break;
|
||||
if(event === 'timeout') {
|
||||
if(!mami.settings.get('soundEnableForceLeave'))
|
||||
return;
|
||||
|
||||
case 'kick':
|
||||
case 'forceLeave':
|
||||
if(!mami.settings.get('soundEnableForceLeave'))
|
||||
return;
|
||||
return mami.sound.pack.getEventSound(['timeout', 'leave']);
|
||||
}
|
||||
|
||||
mami.sound.packPlayer.playEvent(['kick', 'leave']);
|
||||
break;
|
||||
}
|
||||
},
|
||||
if(event === 'kick' || event === 'forceLeave') {
|
||||
if(!mami.settings.get('soundEnableForceLeave'))
|
||||
return;
|
||||
|
||||
return mami.sound.pack.getEventSound(['kick', 'leave']);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
Convert: getLibrarySound,
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include channels.js
|
||||
#include common.js
|
||||
#include server.js
|
||||
#include title.js
|
||||
#include user.js
|
||||
#include utility.js
|
||||
#include sound/umisound.js
|
||||
|
@ -13,76 +12,6 @@
|
|||
Umi.UI.Hooks = (function() {
|
||||
return {
|
||||
AddHooks: function() {
|
||||
const title = new MamiWindowTitle({
|
||||
getName: () => futami.get('title'),
|
||||
});
|
||||
|
||||
window.addEventListener('focus', function() {
|
||||
title.clear();
|
||||
});
|
||||
|
||||
|
||||
Umi.Messages.OnRemove.push(function(msg) {
|
||||
Umi.UI.Messages.Remove(msg);
|
||||
});
|
||||
|
||||
Umi.Messages.OnClear.push(function() {
|
||||
Umi.UI.Messages.RemoveAll();
|
||||
});
|
||||
|
||||
Umi.Messages.OnAdd.push(function(msg) {
|
||||
Umi.UI.Channels.Unread(msg.getChannel());
|
||||
Umi.UI.Messages.Add(msg);
|
||||
|
||||
if(!document.hidden)
|
||||
return;
|
||||
|
||||
if(mami.settings.get('flashTitle')) {
|
||||
let titleText = ' ' + msg.getUser().getName(),
|
||||
channel = Umi.Channels.Current() || null;
|
||||
if(msg.getUser().isBot() && mami.settings.get('showServerMsgInTitle'))
|
||||
titleText = ' ' + msg.getText();
|
||||
|
||||
if(channel !== null && channel.getName() !== msg.getChannel())
|
||||
titleText += ' @ ' + channel.getName();
|
||||
|
||||
title.strobe([
|
||||
`[ @] ${titleText}`,
|
||||
`[@ ] ${titleText}`,
|
||||
]);
|
||||
}
|
||||
|
||||
if(mami.settings.get('enableNotifications') && Umi.User.getCurrentUser() !== null) {
|
||||
const triggers = (mami.settings.get('notificationTriggers') || '').toLowerCase().split(' '),
|
||||
options = {};
|
||||
|
||||
triggers.push((Umi.User.getCurrentUser() || { getName: function() { return ''; } }).getName().toLowerCase());
|
||||
options.body = 'Click here to see what they said.';
|
||||
|
||||
if(mami.settings.get('notificationShowMessage'))
|
||||
options.body += "\n" + msg.getText();
|
||||
|
||||
const avatarUrl = futami.get('avatar');
|
||||
if(avatarUrl.length > 0)
|
||||
options.icon = avatarUrl.replace('{user:id}', msg.getUser().getId()).replace('{resolution}', '80').replace('{user:avatar_change}', msg.getUser().getAvatarTime().toString());
|
||||
|
||||
for(const trigger of triggers) {
|
||||
const message = ' ' + msg.getText() + ' ';
|
||||
|
||||
if(trigger.trim() === '')
|
||||
continue;
|
||||
|
||||
if(message.toLowerCase().indexOf(' ' + trigger + ' ') >= 0) {
|
||||
new Notification('{0} mentioned you!'.replace('{0}', msg.getUser().getName()), options);
|
||||
if(mami.settings.get('onlySoundOnMention'))
|
||||
Umi.Sound.Play('incoming');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Umi.Users.OnAdd.push(function(user) {
|
||||
Umi.UI.Users.Add(user);
|
||||
});
|
||||
|
|
|
@ -1,48 +1,155 @@
|
|||
#include channels.js
|
||||
#include common.js
|
||||
#include parsing.js
|
||||
#include title.js
|
||||
#include txtrigs.js
|
||||
#include url.js
|
||||
#include users.js
|
||||
#include utility.js
|
||||
#include weeb.js
|
||||
#include sound/umisound.js
|
||||
#include ui/emotes.js
|
||||
|
||||
Umi.UI.Messages = (function() {
|
||||
let lastMsgUser = null,
|
||||
let forceUserInfo = false,
|
||||
lastMsgUser = null,
|
||||
lastMsgChannel = null,
|
||||
lastWasTiny = null;
|
||||
|
||||
const title = new MamiWindowTitle({
|
||||
getName: () => futami.get('title'),
|
||||
});
|
||||
|
||||
window.addEventListener('focus', function() {
|
||||
title.clear();
|
||||
});
|
||||
|
||||
const botMsgs = {
|
||||
'say': { text: '%0' },
|
||||
'generr': { text: 'Something unexpected happened.' },
|
||||
'flwarn': { text: 'You are about to hit the flood limit! If you continue you will be kicked.' },
|
||||
'unban': { text: '%0 is no longer banned.', sound: 'unban' },
|
||||
'delerr': { text: 'You are not allowed to delete this message.' },
|
||||
'notban': { text: '%0 is not banned.' },
|
||||
'whoerr': { text: '%0 does not exist.' },
|
||||
'join': { text: '%0 has joined.', action: 'has joined', sound: 'join' },
|
||||
'leave': { text: '%0 has disconnected.', action: 'has disconnected', avatar: 'greyscale', sound: 'leave' },
|
||||
'jchan': { text: '%0 has joined the channel.', action: 'has joined the channel', sound: 'join' },
|
||||
'lchan': { text: '%0 has left the channel.', action: 'has left the channel', avatar: 'greyscale', sound: 'leave' },
|
||||
'kick': { text: '%0 got bludgeoned to death.', action: 'got bludgeoned to death', avatar: 'invert', sound: 'kick' },
|
||||
'flood': { text: '%0 got kicked for flood protection.', action: 'got kicked for flood protection', avatar: 'invert', sound: 'flood' },
|
||||
'timeout': { text: '%0 exploded.', action: 'exploded', avatar: 'greyscale', sound: 'timeout' },
|
||||
'nick': { text: '%0 changed their name to %1.' },
|
||||
'crchan': { text: 'Channel %0 has been created.' },
|
||||
'delchan': { text: 'Channel %0 has been deleted.' },
|
||||
'cpwdchan': { text: 'Channel password has been changed.' },
|
||||
'cprivchan': { text: 'Channel access level has been changed.' },
|
||||
'ipaddr': { text: 'IP address of %0 is %1.' },
|
||||
'cmdna': { text: 'You are not allowed to use %0.' },
|
||||
'nocmd': { text: 'Command %0 does not exist.' },
|
||||
'cmderr': { text: 'You did not use that command correctly.' },
|
||||
'usernf': { text: '%0 is not logged in right now!' },
|
||||
'kickna': { text: 'You are not allowed to kick %0.' },
|
||||
'samechan': { text: 'You are already in channel %0.' },
|
||||
'ipchan': { text: 'You are not allowed to join channel %0.' },
|
||||
'nochan': { text: 'Channel %0 does not exist.' },
|
||||
'nopwchan': { text: 'Channel %0 requires a password. Use /join %0 <password>' },
|
||||
'ipwchan': { text: 'Wrong password for channel %0.' },
|
||||
'inchan': { text: 'Channel name contains invalid characters.' },
|
||||
'nischan': { text: 'A channel with the name %0 already exists.' },
|
||||
'ndchan': { text: 'You are not allowed to deleted channel %0.' },
|
||||
'namchan': { text: 'You are not allowed to edit channel %0.' },
|
||||
'nameinuse': { text: 'Someone else is already using the name %0.' },
|
||||
'rankerr': { text: 'You cannot set the access level of a channel higher than that of your own.' },
|
||||
'banlist': {
|
||||
text: 'Banned: %0',
|
||||
filter: args => {
|
||||
const bans = args[0].split(', ');
|
||||
for(const i in bans)
|
||||
bans[i] = bans[i].slice(92, -4);
|
||||
|
||||
args[0] = bans.join(', ');
|
||||
return args;
|
||||
},
|
||||
},
|
||||
'who': {
|
||||
text: 'Online: %0',
|
||||
filter: args => {
|
||||
const users = args[0].split(', ');
|
||||
for(const i in users) {
|
||||
const isSelf = users[i].includes(' style="font-weight: bold;"');
|
||||
users[i] = users[i].slice(isSelf ? 102 : 75, -4);
|
||||
if(isSelf) users[i] += ' (You)';
|
||||
}
|
||||
|
||||
args[0] = users.join(', ');
|
||||
return args;
|
||||
},
|
||||
},
|
||||
'whochan': {
|
||||
text: 'Online in %0: %1',
|
||||
filter: args => {
|
||||
const users = args[1].split(', ');
|
||||
for(const i in users) {
|
||||
const isSelf = users[i].includes(' style="font-weight: bold;"');
|
||||
users[i] = users[i].slice(isSelf ? 102 : 75, -4);
|
||||
if(isSelf) users[i] += ' (You)';
|
||||
}
|
||||
|
||||
args[1] = users.join(', ');
|
||||
return args;
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const formatTemplate = (template, args) => {
|
||||
if(typeof template !== 'string')
|
||||
template = '';
|
||||
|
||||
if(Array.isArray(args))
|
||||
for(let i = 0; i < args.length; ++i) {
|
||||
const arg = args[i] === undefined || args[i] === null ? '' : args[i].toString();
|
||||
template = template.replace(new RegExp(`%${i}`, 'g'), arg);
|
||||
}
|
||||
|
||||
return template;
|
||||
};
|
||||
|
||||
return {
|
||||
Add: function(msg) {
|
||||
if(msg.getChannel() !== null
|
||||
&& Umi.Channels.Current() !== null
|
||||
&& msg.getChannel() !== Umi.Channels.Current().getName())
|
||||
return;
|
||||
const currentChannel = Umi.Channels.Current();
|
||||
const channelName = msg.getChannel();
|
||||
const sender = msg.getUser();
|
||||
const isOutgoing = Umi.User.isCurrentUser(sender);
|
||||
const hasSeen = msg.hasSeen();
|
||||
const displayMessage = currentChannel === null || channelName === null || channelName === currentChannel.getName();
|
||||
const notifyPM = !displayMessage && !isOutgoing && !hasSeen && channelName.startsWith('@');
|
||||
|
||||
let isTiny = false,
|
||||
skipTextParsing = false,
|
||||
msgText = msg.getText();
|
||||
msgText = msg.getText(),
|
||||
msgTextLong = msgText;
|
||||
|
||||
let eBase = null,
|
||||
eAvatar = null,
|
||||
eText = null,
|
||||
eMeta = null,
|
||||
eUser = null;
|
||||
let eBase, eAvatar, eText, eMeta, eUser;
|
||||
|
||||
const sender = msg.getUser();
|
||||
let avatarUser = sender,
|
||||
avatarSize = '80';
|
||||
|
||||
const userClass = 'message--user-' + sender.getId();
|
||||
let soundName = isOutgoing ? 'outgoing' : 'incoming',
|
||||
soundVolume, soundRate, soundIsLegacy = true;
|
||||
|
||||
const userClass = `message--user-${sender.getId()}`;
|
||||
|
||||
const classes = ['message', userClass];
|
||||
const styles = {};
|
||||
|
||||
const avatarClasses = ['message__avatar'];
|
||||
|
||||
const msgIsFirst = lastMsgUser !== sender.getId() || lastMsgChannel !== msg.getChannel();
|
||||
if(msgIsFirst)
|
||||
const msgIsFirst = forceUserInfo || lastMsgUser !== sender.getId() || lastMsgChannel !== msg.getChannel();
|
||||
if(msgIsFirst) {
|
||||
forceUserInfo = false;
|
||||
classes.push('message--first');
|
||||
}
|
||||
|
||||
if(msg.shouldHighlight())
|
||||
classes.push('message--highlight');
|
||||
|
@ -60,164 +167,231 @@ Umi.UI.Messages = (function() {
|
|||
+ ':' + msgDateTimeObj.getMinutes().toString().padStart(2, '0')
|
||||
+ ':' + msgDateTimeObj.getSeconds().toString().padStart(2, '0');
|
||||
|
||||
if(sender.isBot() && mami.settings.get('fancyInfo')) {
|
||||
if(sender.isBot()) {
|
||||
const botInfo = msg.getBotInfo();
|
||||
soundName = botInfo.isError ? 'error' : 'server';
|
||||
|
||||
if(botInfo) {
|
||||
if(botInfo.type === 'join' || botInfo.type === 'jchan'
|
||||
|| botInfo.type === 'leave' || botInfo.type === 'lchan'
|
||||
|| botInfo.type === 'kick' || botInfo.type === 'flood'
|
||||
|| botInfo.type === 'timeout') {
|
||||
const target = botInfo.target || Umi.Users.FindExact(botInfo.args[0]);
|
||||
if(botMsgs.hasOwnProperty(botInfo.type)) {
|
||||
const bmInfo = botMsgs[botInfo.type];
|
||||
|
||||
let bArgs = botInfo.args;
|
||||
if(typeof bmInfo.filter === 'function')
|
||||
bArgs = bmInfo.filter(bArgs);
|
||||
|
||||
if(typeof bmInfo.sound === 'string')
|
||||
soundName = bmInfo.sound;
|
||||
|
||||
let actionSuccess = false;
|
||||
if(typeof bmInfo.action === 'string' && mami.settings.get('fancyInfo')) {
|
||||
const target = botInfo.target || Umi.Users.FindExact(bArgs[0]);
|
||||
|
||||
if(target) {
|
||||
actionSuccess = true;
|
||||
isTiny = true;
|
||||
skipTextParsing = true;
|
||||
avatarUser = target;
|
||||
msgText = 'did something';
|
||||
|
||||
$ari(classes, userClass);
|
||||
|
||||
switch(botInfo.type) {
|
||||
case 'join':
|
||||
msgText = 'has joined';
|
||||
break;
|
||||
case 'leave':
|
||||
msgText = 'has disconnected';
|
||||
avatarClasses.push('avatar-filter-greyscale');
|
||||
break;
|
||||
case 'jchan':
|
||||
msgText = 'has joined the channel';
|
||||
break;
|
||||
case 'lchan':
|
||||
msgText = 'has left the channel';
|
||||
avatarClasses.push('avatar-filter-greyscale');
|
||||
break;
|
||||
case 'kick':
|
||||
msgText = 'got bludgeoned to death';
|
||||
avatarClasses.push('avatar-filter-invert');
|
||||
break;
|
||||
case 'flood':
|
||||
msgText = 'got kicked for flood protection';
|
||||
avatarClasses.push('avatar-filter-invert');
|
||||
break;
|
||||
case 'timeout':
|
||||
msgText = 'exploded';
|
||||
avatarClasses.push('avatar-filter-greyscale');
|
||||
break;
|
||||
msgText = bmInfo.action;
|
||||
if(typeof bmInfo.avatar === 'string')
|
||||
avatarClasses.push(`avatar-filter-${bmInfo.avatar}`);
|
||||
}
|
||||
}
|
||||
|
||||
msgTextLong = formatTemplate(bmInfo.text, bArgs);
|
||||
|
||||
if(!actionSuccess)
|
||||
msgText = msgTextLong;
|
||||
} else
|
||||
msgText = msgTextLong = `!!! Received unsupported message type: ${botInfo.type} !!!`;
|
||||
} else {
|
||||
if(mami.settings.get('playJokeSounds'))
|
||||
try {
|
||||
const trigger = mami.textTriggers.getTrigger(msgText);
|
||||
if(trigger.isSoundType()) {
|
||||
soundIsLegacy = false;
|
||||
soundName = trigger.getRandomSoundName();
|
||||
soundVolume = trigger.getVolume();
|
||||
soundRate = trigger.getRate();
|
||||
}
|
||||
} catch(ex) {}
|
||||
}
|
||||
|
||||
let avatarUrl = futami.get('avatar');
|
||||
if(typeof avatarUrl !== 'string' || avatarUrl.length < 1)
|
||||
avatarUrl = undefined;
|
||||
else
|
||||
avatarUrl = avatarUrl.replace('{user:id}', avatarUser.getId())
|
||||
.replace('{resolution}', avatarSize)
|
||||
.replace('{user:avatar_change}', avatarUser.getAvatarTime().toString());
|
||||
|
||||
if(displayMessage) {
|
||||
if(isTiny) {
|
||||
if(!msgIsFirst) // small messages must always be "first"
|
||||
classes.push('message--first');
|
||||
classes.push('message-tiny');
|
||||
|
||||
avatarSize = '40';
|
||||
|
||||
if(msgText.indexOf("'") !== 0 || (msgText.match(/\'/g).length % 2) === 0)
|
||||
msgText = "\xA0" + msgText;
|
||||
|
||||
eBase = <div id={`message-${msg.getId()}`} class={classes} style={styles}>
|
||||
{eAvatar = <div class={avatarClasses}/>}
|
||||
<div class="message__container">
|
||||
{eMeta = <div class="message__meta">
|
||||
{eUser = <div class="message__user" style={{ color: avatarUser.getColour() }}>{avatarUser.getName()}</div>}
|
||||
{eText = <div class="message-tiny-text"/>}
|
||||
<div class="message__time">{msgDateTime}</div>
|
||||
</div>}
|
||||
</div>
|
||||
</div>;
|
||||
} else {
|
||||
eBase = <div id={`message-${msg.getId()}`} class={classes} style={styles}>
|
||||
{eAvatar = <div class={avatarClasses}/>}
|
||||
<div class="message__container">
|
||||
{eMeta = <div class="message__meta">
|
||||
{eUser = <div class="message__user" style={{ color: avatarUser.getColour() }}>{avatarUser.getName()}</div>}
|
||||
<div class="message__time">{msgDateTime}</div>
|
||||
</div>}
|
||||
{eText = <div class="message__text"/>}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
eText.innerText = msgText;
|
||||
|
||||
if(!skipTextParsing) {
|
||||
eText = Umi.UI.Emoticons.Parse(eText, msg);
|
||||
eText = Umi.Parsing.Parse(eText, msg);
|
||||
|
||||
const urls = [];
|
||||
|
||||
if(mami.settings.get('autoParseUrls')) {
|
||||
const textSplit = eText.innerText.split(' ');
|
||||
for(const textPart of textSplit) {
|
||||
const uri = Umi.URI.Parse(textPart);
|
||||
|
||||
if(uri !== null && uri.Slashes !== null) {
|
||||
urls.push(textPart);
|
||||
|
||||
const anchorElem = <a class="markup__link" href={textPart} target="_blank" rel="nofollow noreferrer noopener">{textPart}</a>;
|
||||
eText.innerHTML = eText.innerHTML.replace(textPart.replace(/&/g, '&'), anchorElem.outerHTML);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isTiny) {
|
||||
if(!msgIsFirst) // small messages must always be "first"
|
||||
classes.push('message--first');
|
||||
classes.push('message-tiny');
|
||||
if(mami.settings.get('weeaboo')) {
|
||||
eText.appendChild($t(Weeaboo.getTextSuffix(sender)));
|
||||
|
||||
avatarSize = '40';
|
||||
|
||||
if(msgText.indexOf("'") !== 0 || (msgText.match(/\'/g).length % 2) === 0)
|
||||
msgText = "\xA0" + msgText;
|
||||
|
||||
eBase = <div id={`message-${msg.getId()}`} class={classes} style={styles}>
|
||||
{eAvatar = <div class={avatarClasses}/>}
|
||||
<div class="message__container">
|
||||
{eMeta = <div class="message__meta">
|
||||
{eUser = <div class="message__user" style={{ color: avatarUser.getColour() }}>{avatarUser.getName()}</div>}
|
||||
{eText = <div class="message-tiny-text"/>}
|
||||
<div class="message__time">{msgDateTime}</div>
|
||||
</div>}
|
||||
</div>
|
||||
</div>;
|
||||
} else {
|
||||
eBase = <div id={`message-${msg.getId()}`} class={classes} style={styles}>
|
||||
{eAvatar = <div class={avatarClasses}/>}
|
||||
<div class="message__container">
|
||||
{eMeta = <div class="message__meta">
|
||||
{eUser = <div class="message__user" style={{ color: avatarUser.getColour() }}>{avatarUser.getName()}</div>}
|
||||
<div class="message__time">{msgDateTime}</div>
|
||||
</div>}
|
||||
{eText = <div class="message__text"/>}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
eText.innerText = msgText;
|
||||
|
||||
if(!skipTextParsing) {
|
||||
eText = Umi.UI.Emoticons.Parse(eText, msg);
|
||||
eText = Umi.Parsing.Parse(eText, msg);
|
||||
|
||||
const urls = [];
|
||||
|
||||
if(mami.settings.get('autoParseUrls')) {
|
||||
const textSplit = eText.innerText.split(' ');
|
||||
for(const textPart of textSplit) {
|
||||
const uri = Umi.URI.Parse(textPart);
|
||||
|
||||
if(uri !== null && uri.Slashes !== null) {
|
||||
urls.push(textPart);
|
||||
|
||||
const linkElement = $e({
|
||||
tag: 'a',
|
||||
attrs: {
|
||||
className: 'markup__link',
|
||||
href: textPart,
|
||||
target: '_blank',
|
||||
rel: 'nofollow noreferrer noopener',
|
||||
},
|
||||
child: textPart,
|
||||
});
|
||||
|
||||
eText.innerHTML = eText.innerHTML.replace(textPart.replace(/&/g, '&'), linkElement.outerHTML);
|
||||
const kaomoji = Weeaboo.getRandomKaomoji(true, msg);
|
||||
if(kaomoji) {
|
||||
eText.appendChild($t(' '));
|
||||
eText.appendChild($t(kaomoji));
|
||||
}
|
||||
}
|
||||
|
||||
if(mami.settings.get('weeaboo'))
|
||||
eUser.appendChild($t(Weeaboo.getNameSuffix(sender)));
|
||||
}
|
||||
|
||||
if(mami.settings.get('weeaboo')) {
|
||||
eText.appendChild($t(Weeaboo.getTextSuffix(sender)));
|
||||
if(isTiny !== lastWasTiny) {
|
||||
if(!msgIsFirst)
|
||||
eBase.classList.add('message--first');
|
||||
eBase.classList.add(isTiny ? 'message-tiny-fix' : 'message-big-fix');
|
||||
}
|
||||
lastWasTiny = isTiny;
|
||||
|
||||
const kaomoji = Weeaboo.getRandomKaomoji(true, msg);
|
||||
if(kaomoji) {
|
||||
eText.appendChild($t(' '));
|
||||
eText.appendChild($t(kaomoji));
|
||||
if(avatarUrl === undefined)
|
||||
eAvatar.classList.add('message__avatar--disabled');
|
||||
else
|
||||
eAvatar.style.backgroundImage = `url(${avatarUrl})`;
|
||||
|
||||
const msgsList = $i('umi-messages');
|
||||
|
||||
msgsList.appendChild(eBase);
|
||||
lastMsgUser = sender.getId();
|
||||
lastMsgChannel = msg.getChannel();
|
||||
|
||||
if(mami.settings.get('autoEmbedV1')) {
|
||||
const callEmbedOn = eBase.querySelectorAll('a[onclick^="Umi.Parser.SockChatBBcode.Embed"]');
|
||||
for(const embedElem of callEmbedOn)
|
||||
if(embedElem.dataset.embed !== '1')
|
||||
embedElem.click();
|
||||
}
|
||||
|
||||
if(mami.settings.get('autoScroll'))
|
||||
msgsList.scrollTop = msgsList.scrollHeight;
|
||||
}
|
||||
|
||||
let isMentioned = false;
|
||||
const mentionTriggers = (mami.settings.get('notificationTriggers') || '').toLowerCase().split(' ');
|
||||
const currentUser = Umi.User.getCurrentUser();
|
||||
if(typeof currentUser === 'object' && typeof currentUser.getName === 'function')
|
||||
mentionTriggers.push(currentUser.getName().toLowerCase());
|
||||
|
||||
const mentionText = ` ${msgTextLong} `.toLowerCase();
|
||||
for(const trigger of mentionTriggers) {
|
||||
if(trigger.trim() === '')
|
||||
continue;
|
||||
|
||||
if(mentionText.includes(` ${trigger} `)) {
|
||||
isMentioned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isMentioned && mami.settings.get('onlySoundOnMention'))
|
||||
soundName = undefined;
|
||||
|
||||
if(document.hidden) {
|
||||
if(mami.settings.get('flashTitle')) {
|
||||
let titleText = sender.isBot() && mami.settings.get('showServerMsgInTitle')
|
||||
? ` ${msgTextLong}`
|
||||
: ` ${sender.getName()}`;
|
||||
|
||||
// oops this won't work lol, we're filtering at the top
|
||||
if(currentChannel !== null && currentChannel.getName() !== channelName)
|
||||
titleText += ` @ ${channelName}`;
|
||||
|
||||
title.strobe([
|
||||
`[ @] ${titleText}`,
|
||||
`[@ ] ${titleText}`,
|
||||
]);
|
||||
}
|
||||
|
||||
if(!hasSeen) {
|
||||
Umi.UI.Channels.Unread(channelName);
|
||||
|
||||
if(mami.settings.get('enableNotifications') && isMentioned) {
|
||||
const options = {};
|
||||
|
||||
options.body = 'Click here to see what they said.';
|
||||
if(mami.settings.get('notificationShowMessage'))
|
||||
options.body += "\n" + msgTextLong;
|
||||
|
||||
if(avatarUrl !== undefined)
|
||||
options.icon = avatarUrl;
|
||||
|
||||
const notif = new Notification(`${sender.getName()} mentioned you!`, options);
|
||||
notif.addEventListener('click', () => {
|
||||
window.focus();
|
||||
});
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if(document.visibilityState === 'visible')
|
||||
notif.close();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if(mami.settings.get('weeaboo'))
|
||||
eUser.appendChild($t(Weeaboo.getNameSuffix(sender)));
|
||||
}
|
||||
|
||||
if(isTiny !== lastWasTiny) {
|
||||
if(!msgIsFirst)
|
||||
eBase.classList.add('message--first');
|
||||
eBase.classList.add(isTiny ? 'message-tiny-fix' : 'message-big-fix');
|
||||
if(soundName !== undefined && !hasSeen) {
|
||||
if(soundIsLegacy)
|
||||
soundName = Umi.Sound.Convert(soundName);
|
||||
|
||||
mami.sound.library.play(soundName, soundVolume, soundRate);
|
||||
}
|
||||
lastWasTiny = isTiny;
|
||||
|
||||
const avatarUrl = futami.get('avatar');
|
||||
if (avatarUrl !== null && avatarUrl.length > 1) {
|
||||
eAvatar.style.backgroundImage = 'url({0})'.replace('{0}', avatarUrl.replace('{user:id}', avatarUser.getId())
|
||||
.replace('{resolution}', avatarSize).replace('{user:avatar_change}', avatarUser.getAvatarTime().toString()));
|
||||
} else eAvatar.classList.add('message__avatar--disabled');
|
||||
|
||||
const msgsList = $i('umi-messages');
|
||||
|
||||
msgsList.appendChild(eBase);
|
||||
lastMsgUser = sender.getId();
|
||||
lastMsgChannel = msg.getChannel();
|
||||
|
||||
if(mami.settings.get('autoEmbedV1')) {
|
||||
const callEmbedOn = eBase.querySelectorAll('a[onclick^="Umi.Parser.SockChatBBcode.Embed"]');
|
||||
for(const embedElem of callEmbedOn)
|
||||
if(embedElem.dataset.embed !== '1')
|
||||
embedElem.click();
|
||||
}
|
||||
|
||||
if(mami.settings.get('autoScroll'))
|
||||
msgsList.scrollTop = msgsList.scrollHeight;
|
||||
|
||||
if(window.CustomEvent)
|
||||
window.dispatchEvent(new CustomEvent('umi:ui:message_add', {
|
||||
|
@ -226,14 +400,18 @@ Umi.UI.Messages = (function() {
|
|||
message: msg,
|
||||
},
|
||||
}));
|
||||
|
||||
msg.markSeen();
|
||||
},
|
||||
Remove: function(msg) {
|
||||
forceUserInfo = true;
|
||||
lastMsgUser = null;
|
||||
lastMsgChannel = null;
|
||||
lastWasTiny = null;
|
||||
$ri('message-' + msg.getId());
|
||||
$ri(`message-${msg.getId()}`);
|
||||
},
|
||||
RemoveAll: function() {
|
||||
forceUserInfo = true;
|
||||
lastMsgUser = null;
|
||||
lastMsgChannel = null;
|
||||
lastWasTiny = null;
|
||||
|
|
|
@ -209,11 +209,6 @@ Umi.UI.Settings = (function() {
|
|||
};
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'playSoundOnConnect',
|
||||
title: 'Play join sound on connect',
|
||||
type: 'checkbox',
|
||||
},
|
||||
{
|
||||
name: 'windowsLiveMessenger',
|
||||
title: 'Windows Live Messenger',
|
||||
|
|
Loading…
Reference in a new issue