From a1f56c73956a18e1ec07a1e4c097b114c501ca41 Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Sun, 25 Sep 2016 09:41:10 +0300 Subject: [PATCH] Improve support for opening multiple clients at once - Synchornize unread counter with the server - Fix unread marker on no attached clients - Increase unread counter for server messages --- client/js/lounge.js | 32 +++++++++++----------- client/views/chan.tpl | 2 +- src/client.js | 40 +++++++++++++++++++++------- src/models/chan.js | 17 +++++++++--- src/plugins/irc-events/connection.js | 14 +++++----- src/plugins/irc-events/error.js | 6 ++--- src/plugins/irc-events/message.js | 6 +---- src/plugins/irc-events/nick.js | 2 +- src/plugins/irc-events/unhandled.js | 2 +- src/server.js | 9 +++++-- 10 files changed, 81 insertions(+), 49 deletions(-) diff --git a/client/js/lounge.js b/client/js/lounge.js index 164e6134..21f64fa2 100644 --- a/client/js/lounge.js +++ b/client/js/lounge.js @@ -184,6 +184,13 @@ $(function() { } }); + socket.on("open", function(id) { + // Another client opened the channel, clear the unread counter + sidebar.find("[data-id='" + id + "'] .badge") + .removeClass("highlight") + .empty(); + }); + socket.on("join", function(data) { var id = data.network; var network = sidebar.find("#network-" + id); @@ -359,7 +366,7 @@ $(function() { .append(msg) .trigger("msg", [ target, - data.msg + data ]); if (data.msg.self) { @@ -846,7 +853,6 @@ $(function() { self.addClass("active") .find(".badge") .removeClass("highlight") - .data("count", 0) .empty(); if (sidebar.find(".highlight").length === 0) { @@ -955,6 +961,9 @@ $(function() { }); chat.on("msg", ".messages", function(e, target, msg) { + var unread = msg.unread; + msg = msg.msg; + if (msg.self) { return; } @@ -1004,23 +1013,14 @@ $(function() { return; } - var whitelistedActions = [ - "message", - "notice", - "action", - ]; - if (whitelistedActions.indexOf(msg.type) === -1) { + if (!unread) { return; } - var badge = button.find(".badge"); - if (badge.length !== 0) { - var i = (badge.data("count") || 0) + 1; - badge.data("count", i); - badge.html(Handlebars.helpers.roundBadgeNumber(i)); - if (msg.highlight) { - badge.addClass("highlight"); - } + var badge = button.find(".badge").html(Handlebars.helpers.roundBadgeNumber(unread)); + + if (msg.highlight) { + badge.addClass("highlight"); } }); diff --git a/client/views/chan.tpl b/client/views/chan.tpl index 22a6c3cc..626eb228 100644 --- a/client/views/chan.tpl +++ b/client/views/chan.tpl @@ -1,6 +1,6 @@ {{#each channels}}
- {{#if unread}}{{roundBadgeNumber unread}}{{/if}} + {{#if unread}}{{roundBadgeNumber unread}}{{/if}} {{name}}
diff --git a/src/client.js b/src/client.js index 6e08d814..77db906b 100644 --- a/src/client.js +++ b/src/client.js @@ -63,7 +63,8 @@ function Client(manager, name, config) { config = {}; } _.merge(this, { - activeChannel: -1, + lastActiveChannel: -1, + attachedClients: {}, config: config, id: id++, name: name, @@ -201,7 +202,7 @@ Client.prototype.connect = function(args) { network.channels[0].pushMessage(client, new Msg({ type: Msg.Type.ERROR, text: "Hostname you specified is not allowed." - })); + }), true); return; } @@ -214,7 +215,7 @@ Client.prototype.connect = function(args) { network.channels[0].pushMessage(client, new Msg({ type: Msg.Type.ERROR, text: "You must specify a hostname to connect." - })); + }), true); return; } @@ -319,6 +320,13 @@ Client.prototype.inputLine = function(data) { var client = this; var text = data.text; var target = client.find(data.target); + if (!target) { + return; + } + + // Sending a message to a channel is higher priority than merely opening one + // so that reloading the page will open this channel + this.lastActiveChannel = target.chan.id; // This is either a normal message or a command escaped with a leading '/' if (text.charAt(0) !== "/" || text.charAt(1) === "/") { @@ -366,14 +374,20 @@ Client.prototype.more = function(data) { }); }; -Client.prototype.open = function(data) { +Client.prototype.open = function(socketId, data) { var target = this.find(data); - if (target) { - target.chan.firstUnread = 0; - target.chan.unread = 0; - target.chan.highlight = false; - this.activeChannel = target.chan.id; + if (!target) { + return; } + + target.chan.firstUnread = 0; + target.chan.unread = 0; + target.chan.highlight = false; + + this.attachedClients[socketId] = target.chan.id; + this.lastActiveChannel = target.chan.id; + + this.emit("open", target.chan.id); }; Client.prototype.sort = function(data) { @@ -442,6 +456,14 @@ Client.prototype.quit = function() { }); }; +Client.prototype.clientAttach = function(socketId) { + this.attachedClients[socketId] = this.lastActiveChannel; +}; + +Client.prototype.clientDetach = function(socketId) { + delete this.attachedClients[socketId]; +}; + var timer; Client.prototype.save = function(force) { var client = this; diff --git a/src/models/chan.js b/src/models/chan.js index a8c10474..69e582ab 100644 --- a/src/models/chan.js +++ b/src/models/chan.js @@ -28,11 +28,20 @@ function Chan(attr) { }); } -Chan.prototype.pushMessage = function(client, msg) { - client.emit("msg", { +Chan.prototype.pushMessage = function(client, msg, increasesUnread) { + var obj = { chan: this.id, msg: msg - }); + }; + + // If this channel is open in any of the clients, do not increase unread counter + var isOpen = _.includes(client.attachedClients, this.id); + + if ((increasesUnread || msg.highlight) && !isOpen) { + obj.unread = ++this.unread; + } + + client.emit("msg", obj); // Never store messages in public mode as the session // is completely destroyed when the page gets closed @@ -46,7 +55,7 @@ Chan.prototype.pushMessage = function(client, msg) { this.messages.splice(0, this.messages.length - Helper.config.maxHistory); } - if (!msg.self && this.id !== client.activeChannel) { + if (!msg.self && !isOpen) { if (!this.firstUnread) { this.firstUnread = msg.id; } diff --git a/src/plugins/irc-events/connection.js b/src/plugins/irc-events/connection.js index a5507d93..2d843086 100644 --- a/src/plugins/irc-events/connection.js +++ b/src/plugins/irc-events/connection.js @@ -11,13 +11,13 @@ module.exports = function(irc, network) { network.channels[0].pushMessage(client, new Msg({ text: "Network created, connecting to " + network.host + ":" + network.port + "..." - })); + }), true); irc.on("registered", function() { if (network.irc.network.cap.enabled.length > 0) { network.channels[0].pushMessage(client, new Msg({ text: "Enabled capabilities: " + network.irc.network.cap.enabled.join(", ") - })); + }), true); } var delay = 1000; @@ -54,13 +54,13 @@ module.exports = function(irc, network) { network.channels[0].pushMessage(client, new Msg({ text: "Connected to the network." - })); + }), true); }); irc.on("close", function() { network.channels[0].pushMessage(client, new Msg({ text: "Disconnected from the network, and will not reconnect. Use /connect to reconnect again." - })); + }), true); }); if (identd.isEnabled()) { @@ -91,19 +91,19 @@ module.exports = function(irc, network) { network.channels[0].pushMessage(client, new Msg({ type: Msg.Type.ERROR, text: "Socket error: " + err - })); + }), true); }); irc.on("reconnecting", function(data) { network.channels[0].pushMessage(client, new Msg({ text: "Disconnected from the network. Reconnecting in " + Math.round(data.wait / 1000) + " seconds… (Attempt " + data.attempt + " of " + data.max_retries + ")" - })); + }), true); }); irc.on("ping timeout", function() { network.channels[0].pushMessage(client, new Msg({ text: "Ping timeout, disconnecting…" - })); + }), true); }); irc.on("server options", function(data) { diff --git a/src/plugins/irc-events/error.js b/src/plugins/irc-events/error.js index 477645fb..d08e033c 100644 --- a/src/plugins/irc-events/error.js +++ b/src/plugins/irc-events/error.js @@ -15,7 +15,7 @@ module.exports = function(irc, network) { type: Msg.Type.ERROR, text: text, }); - lobby.pushMessage(client, msg); + lobby.pushMessage(client, msg, true); }); irc.on("nick in use", function(data) { @@ -24,7 +24,7 @@ module.exports = function(irc, network) { type: Msg.Type.ERROR, text: data.nick + ": " + (data.reason || "Nickname is already in use."), }); - lobby.pushMessage(client, msg); + lobby.pushMessage(client, msg, true); if (irc.connection.registered === false) { var random = (data.nick || irc.user.nick) + Math.floor(10 + (Math.random() * 89)); @@ -43,7 +43,7 @@ module.exports = function(irc, network) { type: Msg.Type.ERROR, text: data.nick + ": " + (data.reason || "Nickname is invalid."), }); - lobby.pushMessage(client, msg); + lobby.pushMessage(client, msg, true); if (irc.connection.registered === false) { var random = "i" + Math.random().toString(36).substr(2, 10); // 'i' so it never begins with a number diff --git a/src/plugins/irc-events/message.js b/src/plugins/irc-events/message.js index 558964e6..5eb231fe 100644 --- a/src/plugins/irc-events/message.js +++ b/src/plugins/irc-events/message.js @@ -79,10 +79,6 @@ module.exports = function(irc, network) { highlight = network.highlightRegex.test(data.message); } - if (!self && chan.id !== client.activeChannel) { - chan.unread++; - } - var msg = new Msg({ type: data.type, time: data.time, @@ -92,6 +88,6 @@ module.exports = function(irc, network) { self: self, highlight: highlight }); - chan.pushMessage(client, msg); + chan.pushMessage(client, msg, !self); } }; diff --git a/src/plugins/irc-events/nick.js b/src/plugins/irc-events/nick.js index 5096c7a2..c8519530 100644 --- a/src/plugins/irc-events/nick.js +++ b/src/plugins/irc-events/nick.js @@ -15,7 +15,7 @@ module.exports = function(irc, network) { msg = new Msg({ text: "You're now known as " + data.new_nick, }); - lobby.pushMessage(client, msg); + lobby.pushMessage(client, msg, true); self = true; client.save(); client.emit("nick", { diff --git a/src/plugins/irc-events/unhandled.js b/src/plugins/irc-events/unhandled.js index 46b98f22..a07a48ee 100644 --- a/src/plugins/irc-events/unhandled.js +++ b/src/plugins/irc-events/unhandled.js @@ -15,6 +15,6 @@ module.exports = function(irc, network) { type: Msg.Type.UNHANDLED, command: command.command, params: command.params - })); + }), true); }); }; diff --git a/src/server.js b/src/server.js index 2ce7be08..bea7776b 100644 --- a/src/server.js +++ b/src/server.js @@ -147,6 +147,11 @@ function init(socket, client) { } else { socket.emit("authorized"); + socket.on("disconnect", function() { + client.clientDetach(socket.id); + }); + client.clientAttach(socket.id); + socket.on( "input", function(data) { @@ -215,7 +220,7 @@ function init(socket, client) { socket.on( "open", function(data) { - client.open(data); + client.open(socket.id, data); } ); socket.on( @@ -232,7 +237,7 @@ function init(socket, client) { ); socket.join(client.id); socket.emit("init", { - active: client.activeChannel, + active: client.lastActiveChannel, networks: client.networks, token: client.config.token || null });