diff --git a/client/css/style.css b/client/css/style.css index 3c4532a4..fa476860 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -268,6 +268,14 @@ kbd { #sidebar .chan.lobby::before, #chat .lobby .title::before { content: "\f0a0"; /* http://fontawesome.io/icon/hdd-o/ */ } +#sidebar .not-secure .chan.lobby::before { + content: "\f09c"; /* https://fontawesome.com/v4.7.0/icon/unlock/ */ +} + +#sidebar .not-connected .chan.lobby::before { + content: "\f127"; /* https://fontawesome.com/v4.7.0/icon/chain-broken/ TODO v5: unlink */ +} + .context-menu-query::before, .context-menu-action-query::before, #sidebar .chan.query::before, @@ -557,17 +565,35 @@ kbd { width: 100%; } -#sidebar .chan:first-child { +#sidebar .chan.lobby { color: #84ce88; font-size: 15px; font-weight: bold; } -#sidebar .chan:first-child:hover, -#sidebar .chan:first-child.active { +#sidebar .chan.lobby:hover, +#sidebar .chan.lobby.active { color: #c0f8c3; } +#sidebar .not-secure .chan.lobby { + color: #f39c12; +} + +#sidebar .not-secure .chan.lobby:hover, +#sidebar .not-secure .chan.lobby.active { + color: #f8c572; +} + +#sidebar .not-connected .chan.lobby { + color: #e74c3c; +} + +#sidebar .not-connected .chan.lobby:hover, +#sidebar .not-connected .chan.lobby.active { + color: #f1978e; +} + #sidebar .chan::before, #chat .title::before { margin-right: 12px; diff --git a/client/js/socket-events/network.js b/client/js/socket-events/network.js index a55b0433..af294d4c 100644 --- a/client/js/socket-events/network.js +++ b/client/js/socket-events/network.js @@ -20,3 +20,10 @@ socket.on("network", function(data) { socket.on("network_changed", function(data) { sidebar.find("#network-" + data.network).data("options", data.serverOptions); }); + +socket.on("network:status", function(data) { + sidebar + .find("#network-" + data.network) + .toggleClass("not-connected", !data.connected) + .toggleClass("not-secure", !data.secure); +}); diff --git a/client/views/network.tpl b/client/views/network.tpl index 05885d47..0f0ade56 100644 --- a/client/views/network.tpl +++ b/client/views/network.tpl @@ -1,5 +1,11 @@ {{#each networks}} -
+
{{> chan}}
{{/each}} diff --git a/src/models/network.js b/src/models/network.js index ea120bc1..dfeb21e1 100644 --- a/src/models/network.js +++ b/src/models/network.js @@ -84,7 +84,7 @@ Network.prototype.setNick = function(nick) { * @see {@link Chan#getFilteredClone} */ Network.prototype.getFilteredClone = function(lastActiveChannel, lastMessage) { - return Object.keys(this).reduce((newNetwork, prop) => { + const filteredNetwork = Object.keys(this).reduce((newNetwork, prop) => { if (prop === "channels") { // Channels objects perform their own cloning newNetwork[prop] = this[prop].map((channel) => channel.getFilteredClone(lastActiveChannel, lastMessage)); @@ -95,6 +95,28 @@ Network.prototype.getFilteredClone = function(lastActiveChannel, lastMessage) { return newNetwork; }, {}); + + filteredNetwork.status = this.getNetworkStatus(); + + return filteredNetwork; +}; + +Network.prototype.getNetworkStatus = function() { + const status = { + connected: false, + secure: false, + }; + + if (this.irc && this.irc.connection && this.irc.connection.transport) { + const transport = this.irc.connection.transport; + + if (transport.socket) { + status.connected = transport.isConnected(); + status.secure = (transport.socket.encrypted && transport.socket.authorized) || false; + } + } + + return status; }; Network.prototype.export = function() { diff --git a/src/plugins/irc-events/connection.js b/src/plugins/irc-events/connection.js index 3db6b065..fb93b7fb 100644 --- a/src/plugins/irc-events/connection.js +++ b/src/plugins/irc-events/connection.js @@ -62,6 +62,8 @@ module.exports = function(irc, network) { network.channels[0].pushMessage(client, new Msg({ text: "Connected to the network.", }), true); + + sendStatus(); }); irc.on("close", function() { @@ -85,6 +87,8 @@ module.exports = function(irc, network) { network.channels.forEach((chan) => { chan.state = Chan.State.PARTED; }); + + sendStatus(); }); if (Helper.config.debug.ircFramework) { @@ -142,4 +146,11 @@ module.exports = function(irc, network) { serverOptions: network.serverOptions, }); }); + + function sendStatus() { + const status = network.getNetworkStatus(); + status.network = network.id; + + client.emit("network:status", status); + } }; diff --git a/test/models/network.js b/test/models/network.js index 99b28263..ab4306bb 100644 --- a/test/models/network.js +++ b/test/models/network.js @@ -109,8 +109,9 @@ describe("Network", function() { it("should keep necessary properties", function() { const network = new Network(); + const clone = network.getFilteredClone(); - expect(network.getFilteredClone()).to.be.an("object").that.has.all.keys( + expect(clone).to.be.an("object").that.has.all.keys( "channels", "commands", "host", @@ -121,9 +122,15 @@ describe("Network", function() { "port", "realname", "serverOptions", + "status", "tls", "username" ); + + expect(clone.status).to.be.an("object").that.has.all.keys( + "connected", + "secure" + ); }); }); });