thelounge/client/js/socket-events/msg.js

218 lines
5.7 KiB
JavaScript
Raw Normal View History

2017-05-18 20:08:54 +00:00
"use strict";
const $ = require("jquery");
const socket = require("../socket");
const render = require("../render");
const utils = require("../utils");
const options = require("../options");
const helpers_roundBadgeNumber = require("../libs/handlebars/roundBadgeNumber");
const cleanIrcMessage = require("../libs/handlebars/ircmessageparser/cleanIrcMessage");
const webpush = require("../webpush");
2017-05-18 20:08:54 +00:00
const chat = $("#chat");
const sidebar = $("#sidebar");
let pop;
try {
pop = new Audio();
pop.src = "audio/pop.ogg";
} catch (e) {
pop = {
play: $.noop,
};
}
2017-05-18 20:08:54 +00:00
socket.on("msg", function(data) {
// We set a maximum timeout of 2 seconds so that messages don't take too long to appear.
utils.requestIdleCallback(() => processReceivedMessage(data), 2000);
});
function processReceivedMessage(data) {
2017-07-28 08:53:36 +00:00
let targetId = data.chan;
let target = "#chan-" + targetId;
let channel = chat.find(target);
let sidebarTarget = sidebar.find("[data-target='" + target + "']");
// Display received notices and errors in currently active channel.
// Reloading the page will put them back into the lobby window.
if (data.msg.showInActive) {
const activeOnNetwork = sidebarTarget.parent().find(".active");
// We only want to put errors/notices in active channel if they arrive on the same network
if (activeOnNetwork.length > 0) {
targetId = data.chan = activeOnNetwork.data("id");
2017-07-28 08:53:36 +00:00
target = "#chan-" + targetId;
channel = chat.find(target);
sidebarTarget = sidebar.find("[data-target='" + target + "']");
}
}
const scrollContainer = channel.find(".chat");
2017-07-28 08:53:36 +00:00
const container = channel.find(".messages");
const activeChannelId = chat.find(".chan.active").data("id");
2017-05-18 20:08:54 +00:00
if (data.msg.type === "channel_list" || data.msg.type === "ban_list") {
$(container).empty();
}
// Add message to the container
2017-06-22 20:08:36 +00:00
render.appendMessage(
container,
targetId,
channel.data("type"),
data.msg
2017-06-22 20:08:36 +00:00
);
if (activeChannelId === targetId) {
scrollContainer.trigger("keepToBottom");
}
notifyMessage(targetId, channel, data);
2017-05-18 20:08:54 +00:00
let shouldMoveMarker = data.msg.self;
if (!shouldMoveMarker) {
const lastChild = container.children().last();
// If last element is hidden (e.g. hidden status messages) check the element before it.
// If it's unread marker or date marker, then move unread marker to the bottom
// so that it isn't displayed as the last element in chat.
// display properly is checked instead of using `:hidden` selector because it doesn't work in non-active channels.
if (lastChild.css("display") === "none") {
const prevChild = lastChild.prev();
shouldMoveMarker =
prevChild.hasClass("unread-marker") ||
(prevChild.hasClass("date-marker") && prevChild.prev().hasClass("unread-marker"));
}
}
if (shouldMoveMarker) {
2017-05-18 20:08:54 +00:00
container
.find(".unread-marker")
.data("unread-id", 0)
2017-05-18 20:08:54 +00:00
.appendTo(container);
}
// Clear unread/highlight counter if self-message
if (data.msg.self) {
2017-07-28 08:53:36 +00:00
sidebarTarget.find(".badge").removeClass("highlight").empty();
}
let messageLimit = 0;
if (activeChannelId !== targetId) {
// If message arrives in non active channel, keep only 100 messages
messageLimit = 100;
} else if (scrollContainer.isScrollBottom()) {
// If message arrives in active channel, keep 500 messages if scroll is currently at the bottom
messageLimit = 500;
}
if (messageLimit > 0) {
render.trimMessageInChannel(channel, messageLimit);
}
2017-07-28 08:53:36 +00:00
if ((data.msg.type === "message" || data.msg.type === "action") && channel.hasClass("channel")) {
const nicks = channel.find(".userlist").data("nicks");
if (nicks) {
const find = nicks.indexOf(data.msg.from.nick);
if (find !== -1) {
nicks.splice(find, 1);
nicks.unshift(data.msg.from.nick);
}
}
}
}
function notifyMessage(targetId, channel, msg) {
const unread = msg.unread;
msg = msg.msg;
if (msg.self) {
return;
}
const button = sidebar.find(".chan[data-id='" + targetId + "']");
Offer optional syncing of client settings Write synced settings to localstorage. move settings and webpush init to init.js stub for server sending clientsettings get very basic setting sync working Also update client.config.clientSettings on settings:set Full setting sync with mandatory and excluded sync options Actually check client preferences. Further settings restructuring. Refactor options.js make storage act in a sane manner. Add new parameter to applySetting Do not sync if the setting is stored as a result of syncing General clean up, commenting and restructing. sync from server on checking "sync" offer initial sync Better deal with DOM being ready and instances of inital sync showing Don't try to disable autocompletion when not enabled. Restructure option.js to seperate functions from settings. More consistency in naming options vs settings Switch processSetting and applySetting names reflecting their functionality better. move options init back to configuration. simplify how settings are synced around. move options init after template building. Remove unneeded hasOwnProperty Use global for #theme and only apply theme in applySetting Return when no server side clientsettings excist. Autocompletion options to options.settings Make nocss param in url work again. Actually filter out empty highlight values. Clarify alwaysSync comment. Remove manual step for initial sync change attr to prop in options.js replace unbind with off in autocompletion.js Do not sync settings when the lounge is set to public. fix eslint error Fix merge error Do not show sync warning after page refresh when sync is enabled Move setting sync label in actual label. Improve server setting sync handling performance and failure potential. Don't give impression that the desktop notificiation is off when the browser permission is denied. Refine showing and hiding of notification warnings. rename all setting socket events to singular setting. add experimental note and icon to settingsync. fix css linting error
2017-12-11 19:01:15 +00:00
if (msg.highlight || (options.settings.notifyAllMessages && msg.type === "message")) {
if (!document.hasFocus() || !channel.hasClass("active")) {
Offer optional syncing of client settings Write synced settings to localstorage. move settings and webpush init to init.js stub for server sending clientsettings get very basic setting sync working Also update client.config.clientSettings on settings:set Full setting sync with mandatory and excluded sync options Actually check client preferences. Further settings restructuring. Refactor options.js make storage act in a sane manner. Add new parameter to applySetting Do not sync if the setting is stored as a result of syncing General clean up, commenting and restructing. sync from server on checking "sync" offer initial sync Better deal with DOM being ready and instances of inital sync showing Don't try to disable autocompletion when not enabled. Restructure option.js to seperate functions from settings. More consistency in naming options vs settings Switch processSetting and applySetting names reflecting their functionality better. move options init back to configuration. simplify how settings are synced around. move options init after template building. Remove unneeded hasOwnProperty Use global for #theme and only apply theme in applySetting Return when no server side clientsettings excist. Autocompletion options to options.settings Make nocss param in url work again. Actually filter out empty highlight values. Clarify alwaysSync comment. Remove manual step for initial sync change attr to prop in options.js replace unbind with off in autocompletion.js Do not sync settings when the lounge is set to public. fix eslint error Fix merge error Do not show sync warning after page refresh when sync is enabled Move setting sync label in actual label. Improve server setting sync handling performance and failure potential. Don't give impression that the desktop notificiation is off when the browser permission is denied. Refine showing and hiding of notification warnings. rename all setting socket events to singular setting. add experimental note and icon to settingsync. fix css linting error
2017-12-11 19:01:15 +00:00
if (options.settings.notification) {
try {
pop.play();
} catch (exception) {
// On mobile, sounds can not be played without user interaction.
}
}
utils.toggleNotificationMarkers(true);
Offer optional syncing of client settings Write synced settings to localstorage. move settings and webpush init to init.js stub for server sending clientsettings get very basic setting sync working Also update client.config.clientSettings on settings:set Full setting sync with mandatory and excluded sync options Actually check client preferences. Further settings restructuring. Refactor options.js make storage act in a sane manner. Add new parameter to applySetting Do not sync if the setting is stored as a result of syncing General clean up, commenting and restructing. sync from server on checking "sync" offer initial sync Better deal with DOM being ready and instances of inital sync showing Don't try to disable autocompletion when not enabled. Restructure option.js to seperate functions from settings. More consistency in naming options vs settings Switch processSetting and applySetting names reflecting their functionality better. move options init back to configuration. simplify how settings are synced around. move options init after template building. Remove unneeded hasOwnProperty Use global for #theme and only apply theme in applySetting Return when no server side clientsettings excist. Autocompletion options to options.settings Make nocss param in url work again. Actually filter out empty highlight values. Clarify alwaysSync comment. Remove manual step for initial sync change attr to prop in options.js replace unbind with off in autocompletion.js Do not sync settings when the lounge is set to public. fix eslint error Fix merge error Do not show sync warning after page refresh when sync is enabled Move setting sync label in actual label. Improve server setting sync handling performance and failure potential. Don't give impression that the desktop notificiation is off when the browser permission is denied. Refine showing and hiding of notification warnings. rename all setting socket events to singular setting. add experimental note and icon to settingsync. fix css linting error
2017-12-11 19:01:15 +00:00
if (options.settings.desktopNotifications && ("Notification" in window) && Notification.permission === "granted") {
let title;
let body;
if (msg.type === "invite") {
title = "New channel invite:";
body = msg.from.nick + " invited you to " + msg.channel;
} else {
title = msg.from.nick;
if (!button.hasClass("query")) {
title += " (" + button.attr("aria-label").trim() + ")";
}
if (msg.type === "message") {
title += " says:";
}
body = cleanIrcMessage(msg.text);
}
const timestamp = Date.parse(msg.time);
try {
if (webpush.hasServiceWorker) {
navigator.serviceWorker.ready.then((registration) => {
registration.active.postMessage({
type: "notification",
chanId: targetId,
timestamp: timestamp,
title: title,
body: body,
});
});
} else {
const notify = new Notification(title, {
tag: `chan-${targetId}`,
badge: "img/logo-64.png",
icon: "img/touch-icon-192x192.png",
body: body,
timestamp: timestamp,
});
notify.addEventListener("click", function() {
window.focus();
button.trigger("click");
this.close();
});
}
} catch (exception) {
// `new Notification(...)` is not supported and should be silenced.
}
}
}
}
if (!unread || button.hasClass("active")) {
return;
}
const badge = button.find(".badge").html(helpers_roundBadgeNumber(unread));
if (msg.highlight) {
badge.addClass("highlight");
}
}