From 3982aac8453999d3ef2865af6b6fd861b8639738 Mon Sep 17 00:00:00 2001 From: Ben Evans Date: Fri, 25 Sep 2015 18:34:27 +0100 Subject: [PATCH 01/17] Add a Dockerfile Building: docker build -t shout . Running: docker run --name shout -d --publish 9000:9000 shout --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..2e5e170c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM node:0.12-onbuild +EXPOSE 9000 +ENTRYPOINT ./index.js From 7c54a97fad9822c5f7534fabb3c2868f011f0b79 Mon Sep 17 00:00:00 2001 From: Ben Evans Date: Tue, 29 Sep 2015 00:24:47 +0100 Subject: [PATCH 02/17] Expressive Entrypoint in Dockerfile Updated to https://github.com/erming/shout/pull/477#issuecomment-143636577 comment --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2e5e170c..4c90e25d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,3 @@ FROM node:0.12-onbuild EXPOSE 9000 -ENTRYPOINT ./index.js +ENTRYPOINT ["node", "index.js"] From 0d6b3b00c3bf9329d86bc0eb5d2997c24496e9f2 Mon Sep 17 00:00:00 2001 From: Alexander Gould Date: Wed, 14 Oct 2015 16:15:57 -0400 Subject: [PATCH 03/17] slashes are replaced with %'s when writing log files --- src/log.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/log.js b/src/log.js index 7da01d72..70e5a91a 100644 --- a/src/log.js +++ b/src/log.js @@ -34,7 +34,9 @@ module.exports.write = function(user, network, chan, msg) { } fs.appendFile( - path + "/" + chan + ".log", + // Quick fix to escape pre-escape channel names that contain % using %%, + // and / using %. **This does not escape all reserved words** + path + "/" + chan.replace(/%/g, "%%").replace(/\//g, "%") + ".log", line + "\n", function(e) { if (e) { From f2c40234d3e241d25dbed4b307a041d5be2e8b69 Mon Sep 17 00:00:00 2001 From: William Boman Date: Mon, 19 Oct 2015 13:22:59 +0200 Subject: [PATCH 04/17] package.json: add `grunt-cli` This is needed to run npm scripts that uses grunt. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 87bd8451..c210b5a0 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ }, "devDependencies": { "grunt": "~0.4.5", + "grunt-cli": "^0.1.13", "grunt-contrib-uglify": "~0.5.0", "grunt-contrib-watch": "^0.6.1", "handlebars": "^2.0.0", From 15415967a165729865b285cb8293ae8658647817 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Astori?= Date: Tue, 20 Oct 2015 23:50:28 -0400 Subject: [PATCH 05/17] Add @floogulinc as a project maintainer Welcome Paul!! --- CONTRIBUTING.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a07788aa..eb43ae7b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,3 +86,4 @@ several labels. Here is what they mean: - [Mattias Erming](https://github.com/erming) (`erming` on IRC) - [Jocelyn Delalande](https://github.com/JocelynDelalande) (`JocelynD` on IRC) - [Jérémie Astori](https://github.com/astorije) (`astorije` on IRC) +- [Paul Friederichsen](https://github.com/floogulinc) (`floogulinc` on IRC) From 5d8669112de73a3c60aa0b557aa9cea438032d0d Mon Sep 17 00:00:00 2001 From: Ben Evans Date: Sat, 24 Oct 2015 20:45:44 +0100 Subject: [PATCH 06/17] Added @Xe's tips on the Dockerfile https://github.com/Shuo-IRC/Shuo/pull/87 --- Dockerfile | 26 ++++++++++++++++++++++++-- docker-compose.yml | 4 ++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 docker-compose.yml diff --git a/Dockerfile b/Dockerfile index 4c90e25d..f4de8984 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,25 @@ -FROM node:0.12-onbuild +# +# Thanks to @Xe for the Dockerfile template +# https://github.com/Shuo-IRC/Shuo/pull/87/files +# + +FROM node:4.0-onbuild + +# Create a non-root user for shout to run in. +RUN useradd --create-home shout + +# Needed for setup of Node.js +ENV HOME /home/shout + +# Customize this to specify where Shout puts its data. +# To link a data container, have it expose /home/shout/data +ENV SHOUT_HOME /home/shout/data + +# Expose HTTP EXPOSE 9000 -ENTRYPOINT ["node", "index.js"] + +# Drop root. +USER shout + +# Don't use an entrypoint here. It makes debugging difficult. +CMD node index.js --home $SHOUT_HOME diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..44e6ab81 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,4 @@ +shout: + build: . + ports: + - "9000:9000" From a69992f6b2f546c21e0785788b457e7625a530a3 Mon Sep 17 00:00:00 2001 From: William Boman Date: Thu, 1 Oct 2015 00:15:19 +0200 Subject: [PATCH 07/17] Add .eslintrc --- .eslintignore | 3 +++ .eslintrc | 32 ++++++++++++++++++++++++++++++++ package.json | 4 +++- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 .eslintignore create mode 100644 .eslintrc diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..3ff6b7b1 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +client/js/libs.min.js +client/js/libs/**/*.js +client/js/shout.templates.js diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..78cb50d3 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,32 @@ +--- + +root: true + +env: + browser: true + mocha: true + node: true + +rules: + comma-dangle: 0 + curly: [2, multi-line] + eqeqeq: 2 + indent: [2, tab] + linebreak-style: [2, unix] + object-curly-spacing: [2, never] + semi: [2, always] + space-after-keywords: [2, always] + space-before-function-paren: [2, never] + spaced-comment: [2, always] + no-console: 0 + no-trailing-spaces: 2 + quotes: [2, double] + +globals: + $: false + Favico: false + Handlebars: false + io: false + Mousetrap: false + +extends: eslint:recommended diff --git a/package.json b/package.json index 87bd8451..582488fb 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "scripts": { "start": "node index", "build": "grunt", - "test": "HOME=test/fixtures mocha test/**/*.js" + "test": "HOME=test/fixtures mocha test/**/*.js", + "lint": "eslint index.js Gruntfile.js src/ test/ client/ defaults/" }, "keywords": [ "browser", @@ -40,6 +41,7 @@ "socket.io": "~1.0.6" }, "devDependencies": { + "eslint": "^1.5.1", "grunt": "~0.4.5", "grunt-contrib-uglify": "~0.5.0", "grunt-contrib-watch": "^0.6.1", From 8fdfd70c7ebe86608fb0115f5782ce30b445ea29 Mon Sep 17 00:00:00 2001 From: William Boman Date: Thu, 1 Oct 2015 00:39:57 +0200 Subject: [PATCH 08/17] Comply with ESLint --- client/js/shout.js | 38 ++++++++-------- index.js | 2 +- src/client.js | 15 +++---- src/clientManager.js | 14 +++--- src/command-line/add.js | 2 +- src/command-line/config.js | 3 -- src/command-line/start.js | 1 - src/helper.js | 2 +- src/identd.js | 2 +- src/log.js | 6 +-- src/models/chan.js | 2 +- src/plugins/inputs/action.js | 10 ++--- src/plugins/inputs/connect.js | 2 +- src/plugins/inputs/invite.js | 2 +- src/plugins/inputs/join.js | 2 +- src/plugins/inputs/kick.js | 2 +- src/plugins/inputs/mode.js | 14 +++--- src/plugins/inputs/msg.js | 5 +-- src/plugins/inputs/nick.js | 2 +- src/plugins/inputs/notice.js | 2 +- src/plugins/inputs/part.js | 4 +- src/plugins/inputs/quit.js | 8 ++-- src/plugins/inputs/raw.js | 2 +- src/plugins/inputs/services.js | 2 +- src/plugins/inputs/topic.js | 6 +-- src/plugins/inputs/whois.js | 2 +- src/plugins/irc-events/ctcp.js | 4 +- src/plugins/irc-events/error.js | 2 +- src/plugins/irc-events/join.js | 2 +- src/plugins/irc-events/kick.js | 4 +- src/plugins/irc-events/link.js | 28 ++++++------ src/plugins/irc-events/message.js | 8 ++-- src/plugins/irc-events/mode.js | 2 +- src/plugins/irc-events/nick.js | 2 +- src/plugins/irc-events/notice.js | 4 +- src/plugins/irc-events/part.js | 2 +- src/plugins/irc-events/whois.js | 1 - src/server.js | 10 ++--- test/plugins/link.js | 72 +++++++++++++++---------------- test/util.js | 62 +++++++++++++------------- 40 files changed, 172 insertions(+), 183 deletions(-) diff --git a/client/js/shout.js b/client/js/shout.js index a23dc7de..c3560284 100644 --- a/client/js/shout.js +++ b/client/js/shout.js @@ -35,11 +35,12 @@ $(function() { $("html").addClass("web-app-mode"); } + var pop; try { - var pop = new Audio(); + pop = new Audio(); pop.src = "/audio/pop.ogg"; - } catch(e) { - var pop = { + } catch (e) { + pop = { play: $.noop }; } @@ -73,7 +74,7 @@ $(function() { }); }); - socket.on("auth", function(data) { + socket.on("auth", function(/* data */) { var body = $("body"); var login = $("#sign-in"); if (!login.length) { @@ -183,7 +184,7 @@ $(function() { socket.on("msg", function(data) { var target = "#chan-" + data.chan; - if (data.msg.type == "error") { + if (data.msg.type === "error") { target = "#chan-" + chat.find(".active").data("id"); } @@ -202,7 +203,7 @@ $(function() { } var type = data.msg.type; - if (type == "message" || type == "action") { + if (type === "message" || type === "action") { var nicks = chan.find(".users").data("nicks"); if (nicks) { var find = nicks.indexOf(from); @@ -220,7 +221,7 @@ $(function() { .find(".messages") .prepend(render("msg", {messages: data.messages})) .end(); - if (data.messages.length != 100) { + if (data.messages.length !== 100) { chan.find(".show-more").removeClass("show"); } }); @@ -274,7 +275,7 @@ $(function() { }); if (next !== null) { - var id = next.data("id"); + id = next.data("id"); sidebar.find("[data-id=" + id + "]").click(); } else { sidebar.find(".chan") @@ -374,7 +375,7 @@ $(function() { ].indexOf(name) !== -1) { chat.toggleClass("hide-" + name, !self.prop("checked")); } - if (name == "colors") { + if (name === "colors") { chat.toggleClass("no-colors", !self.prop("checked")); } }).find("input") @@ -383,7 +384,7 @@ $(function() { $("#badge").on("change", function() { var self = $(this); if (self.prop("checked")) { - if (Notification.permission != "granted") { + if (Notification.permission !== "granted") { Notification.requestPermission(); } } @@ -407,7 +408,6 @@ $(function() { .tab(complete, {hint: false}); var form = $("#form"); - var submit = $("#submit"); form.on("submit", function(e) { e.preventDefault(); @@ -428,7 +428,7 @@ $(function() { var text = ""; if (window.getSelection) { text = window.getSelection().toString(); - } else if (document.selection && document.selection.type != "Control") { + } else if (document.selection && document.selection.type !== "Control") { text = document.selection.createRange().text; } if (!text) { @@ -580,7 +580,7 @@ $(function() { pop.play(); } favico.badge("!"); - if (settings.badge && Notification.permission == "granted") { + if (settings.badge && Notification.permission === "granted") { var notify = new Notification(msg.from + " says:", { body: msg.text.trim(), icon: "/img/logo-64.png" @@ -640,7 +640,7 @@ $(function() { var content = self.parent().next(".toggle-content"); if (bottom && !content.hasClass("show")) { var img = content.find("img"); - if (img.length != 0 && !img.width()) { + if (img.length !== 0 && !img.width()) { img.on("load", function() { chat.scrollBottom(); }); @@ -678,7 +678,7 @@ $(function() { form.find(".btn") .attr("disabled", true) .end(); - if (form.closest(".window").attr("id") == "connect") { + if (form.closest(".window").attr("id") === "connect") { event = "conn"; } var values = {}; @@ -732,8 +732,8 @@ $(function() { Mousetrap.bind([ "command+k", "ctrl+shift+l" - ], function (e) { - if(e.target === input[0]) { + ], function(e) { + if (e.target === input[0]) { clear(); e.preventDefault(); } @@ -771,7 +771,7 @@ $(function() { words.push(nicks[i]); } - var channels = sidebar.find(".chan") + sidebar.find(".chan") .each(function() { var self = $(this); if (!self.hasClass("lobby")) { @@ -875,7 +875,7 @@ $(function() { } array.splice(new_index, 0, array.splice(old_index, 1)[0]); return array; - }; + } document.addEventListener( "visibilitychange", diff --git a/index.js b/index.js index 1fae1ba0..e5646d68 100755 --- a/index.js +++ b/index.js @@ -1,3 +1,3 @@ #!/usr/bin/env node process.chdir(__dirname); -var cli = require("./src/command-line"); +require("./src/command-line"); diff --git a/src/client.js b/src/client.js index 95a050b0..0a33ef95 100644 --- a/src/client.js +++ b/src/client.js @@ -80,11 +80,11 @@ Client.prototype.emit = function(event, data) { } var config = this.config || {}; if (config.log === true) { - if (event == "msg") { + if (event === "msg") { var target = this.find(data.chan); if (target) { var chan = target.chan.name; - if (target.chan.type == Chan.Type.LOBBY) { + if (target.chan.type === Chan.Type.LOBBY) { chan = target.network.host; } log.write( @@ -131,7 +131,7 @@ Client.prototype.connect = function(args) { if (config.bind) { server.localAddress = config.bind; - if(args.tls) { + if (args.tls) { var socket = net.connect(server); server.socket = socket; } @@ -152,7 +152,7 @@ Client.prototype.connect = function(args) { }); var nick = args.nick || "shout-user"; - var username = args.username || nick.replace(/[^a-zA-Z0-9]/g, ''); + var username = args.username || nick.replace(/[^a-zA-Z0-9]/g, ""); var realname = args.realname || "Shout User"; var irc = slate(stream); @@ -273,10 +273,10 @@ Client.prototype.sort = function(data) { var type = data.type; var order = data.order || []; + var sorted = []; switch (type) { case "networks": - var sorted = []; _.each(order, function(i) { var find = _.find(self.networks, {id: i}); if (find) { @@ -292,7 +292,6 @@ Client.prototype.sort = function(data) { if (!network) { return; } - var sorted = []; _.each(order, function(i) { var find = _.find(network.channels, {id: i}); if (find) { @@ -328,7 +327,7 @@ Client.prototype.save = function(force) { var client = this; var config = Helper.getConfig(); - if(config.public) { + if (config.public) { return; } @@ -360,7 +359,7 @@ Client.prototype.save = function(force) { try { json = JSON.parse(data); json.networks = networks; - } catch(e) { + } catch (e) { console.log(e); return; } diff --git a/src/clientManager.js b/src/clientManager.js index df4f08a9..624dd9d7 100644 --- a/src/clientManager.js +++ b/src/clientManager.js @@ -3,7 +3,6 @@ var fs = require("fs"); var Client = require("./client"); var mkdirp = require("mkdirp"); var Helper = require("./helper"); -var moment = require("moment"); module.exports = ClientManager; @@ -14,7 +13,7 @@ function ClientManager() { ClientManager.prototype.findClient = function(name) { for (var i in this.clients) { var client = this.clients[i]; - if (client.name == name) { + if (client.name === name) { return client; } } @@ -35,7 +34,7 @@ ClientManager.prototype.loadUser = function(name) { "utf-8" ); json = JSON.parse(json); - } catch(e) { + } catch (e) { console.log(e); return; } @@ -62,7 +61,7 @@ ClientManager.prototype.getUsers = function() { users.push(file.replace(".json", "")); } }); - } catch(e) { + } catch (e) { console.log(e); return; } @@ -88,7 +87,7 @@ ClientManager.prototype.addUser = function(name, password) { JSON.stringify(user, null, " "), {mode: "0777"} ); - } catch(e) { + } catch (e) { throw e; } return true; @@ -102,15 +101,14 @@ ClientManager.prototype.removeUser = function(name) { try { var path = Helper.HOME + "/users/" + name + ".json"; fs.unlinkSync(path); - } catch(e) { + } catch (e) { throw e; } return true; }; -ClientManager.prototype.autoload = function(sockets) { +ClientManager.prototype.autoload = function(/* sockets */) { var self = this; - var loaded = []; setInterval(function() { var loaded = _.pluck( self.clients, diff --git a/src/command-line/add.js b/src/command-line/add.js index 830b8022..153328e7 100644 --- a/src/command-line/add.js +++ b/src/command-line/add.js @@ -8,7 +8,7 @@ var Helper = require("../helper"); program .command("add ") .description("Add a new user") - .action(function(name, password) { + .action(function(name/* , password */) { var path = Helper.HOME + "/users"; try { mkdirp.sync(path); diff --git a/src/command-line/config.js b/src/command-line/config.js index 4080ff8f..e2658bdd 100644 --- a/src/command-line/config.js +++ b/src/command-line/config.js @@ -1,7 +1,4 @@ -var fs = require("fs"); -var path = require("path"); var program = require("commander"); -var mkdirp = require("mkdirp"); var child = require("child_process"); var Helper = require("../helper"); diff --git a/src/command-line/start.js b/src/command-line/start.js index 7637712d..676fccb1 100644 --- a/src/command-line/start.js +++ b/src/command-line/start.js @@ -1,4 +1,3 @@ -var _ = require("lodash"); var ClientManager = new require("../clientManager"); var program = require("commander"); var shout = require("../server"); diff --git a/src/helper.js b/src/helper.js index 565df801..b0006105 100644 --- a/src/helper.js +++ b/src/helper.js @@ -7,4 +7,4 @@ module.exports = { function getConfig() { return require(path.resolve(this.HOME) + "/config"); -}; +} diff --git a/src/identd.js b/src/identd.js index 7e32c422..76773568 100644 --- a/src/identd.js +++ b/src/identd.js @@ -4,7 +4,7 @@ var net = require("net"); var users = {}; module.exports.start = function(port) { - var server = net.createServer(init).listen(port || 113); + net.createServer(init).listen(port || 113); }; module.exports.hook = function(stream, user) { diff --git a/src/log.js b/src/log.js index 7da01d72..f07c6f45 100644 --- a/src/log.js +++ b/src/log.js @@ -7,7 +7,7 @@ module.exports.write = function(user, network, chan, msg) { try { var path = Helper.HOME + "/logs/" + user + "/" + network; mkdirp.sync(path); - } catch(e) { + } catch (e) { console.log(e); return; } @@ -20,7 +20,7 @@ module.exports.write = function(user, network, chan, msg) { var line = "[" + time + "] "; var type = msg.type.trim(); - if (type == "message" || type == "highlight") { + if (type === "message" || type === "highlight") { // Format: // [2014-01-01 00:00:00] Put that cookie down.. Now!! line += "<" + msg.from + "> " + msg.text; @@ -38,7 +38,7 @@ module.exports.write = function(user, network, chan, msg) { line + "\n", function(e) { if (e) { - console.log("Log#write():\n" + e) + console.log("Log#write():\n" + e); } } ); diff --git a/src/models/chan.js b/src/models/chan.js index 0121cc19..b493341b 100644 --- a/src/models/chan.js +++ b/src/models/chan.js @@ -37,7 +37,7 @@ Chan.prototype.sortUsers = function() { modes.forEach(function(mode) { this.users = _.remove( this.users, - function(u) { return u.mode == mode; } + function(u) { return u.mode === mode; } ).concat(this.users); }, this); }; diff --git a/src/plugins/inputs/action.js b/src/plugins/inputs/action.js index 8584a76e..b04b1463 100644 --- a/src/plugins/inputs/action.js +++ b/src/plugins/inputs/action.js @@ -1,13 +1,13 @@ var Msg = require("../../models/msg"); module.exports = function(network, chan, cmd, args) { - if (cmd != "slap" && cmd != "me") { + if (cmd !== "slap" && cmd !== "me") { return; } - + var client = this; var irc = network.irc; - + switch (cmd) { case "slap": var slap = "slaps " + args[0] + " around a bit with a large trout"; @@ -16,13 +16,13 @@ module.exports = function(network, chan, cmd, args) { if (args.length === 0) { break; } - + var text = slap || args.join(" "); irc.action( chan.name, text ); - + var msg = new Msg({ type: Msg.Type.ACTION, from: irc.me, diff --git a/src/plugins/inputs/connect.js b/src/plugins/inputs/connect.js index 86f02dc8..7bdcb0fe 100644 --- a/src/plugins/inputs/connect.js +++ b/src/plugins/inputs/connect.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "connect" && cmd != "server") { + if (cmd !== "connect" && cmd !== "server") { return; } if (args.length !== 0) { diff --git a/src/plugins/inputs/invite.js b/src/plugins/inputs/invite.js index 4042f25c..769edd0a 100644 --- a/src/plugins/inputs/invite.js +++ b/src/plugins/inputs/invite.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "invite") { + if (cmd !== "invite") { return; } var irc = network.irc; diff --git a/src/plugins/inputs/join.js b/src/plugins/inputs/join.js index 79c9553d..57c51455 100644 --- a/src/plugins/inputs/join.js +++ b/src/plugins/inputs/join.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "join") { + if (cmd !== "join") { return; } if (args.length !== 0) { diff --git a/src/plugins/inputs/kick.js b/src/plugins/inputs/kick.js index c994da2b..c1544576 100644 --- a/src/plugins/inputs/kick.js +++ b/src/plugins/inputs/kick.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "kick") { + if (cmd !== "kick") { return; } if (args.length !== 0) { diff --git a/src/plugins/inputs/mode.js b/src/plugins/inputs/mode.js index 45703098..2cd1b22c 100644 --- a/src/plugins/inputs/mode.js +++ b/src/plugins/inputs/mode.js @@ -1,19 +1,19 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "mode" && cmd != "op" && cmd != "voice" && cmd != "deop" && cmd != "devoice") { + if (cmd !== "mode" && cmd !== "op" && cmd !== "voice" && cmd !== "deop" && cmd !== "devoice") { return; } else if (args.length === 0) { return; } - + var mode; var user; - if (cmd != "mode") { + if (cmd !== "mode") { user = args[0]; mode = { - "op": "+o", - "voice": "+v", - "deop": "-o", - "devoice": "-v" + "op": "+o", + "voice": "+v", + "deop": "-o", + "devoice": "-v" }[cmd]; } else if (args.length === 1) { return; diff --git a/src/plugins/inputs/msg.js b/src/plugins/inputs/msg.js index 7757be9f..3a7c2476 100644 --- a/src/plugins/inputs/msg.js +++ b/src/plugins/inputs/msg.js @@ -1,16 +1,15 @@ var _ = require("lodash"); module.exports = function(network, chan, cmd, args) { - if (cmd != "say" && cmd != "msg") { + if (cmd !== "say" && cmd !== "msg") { return; } if (args.length === 0 || args[0] === "") { return; } - var client = this; var irc = network.irc; var target = ""; - if (cmd == "msg") { + if (cmd === "msg") { target = args.shift(); if (args.length === 0) { return; diff --git a/src/plugins/inputs/nick.js b/src/plugins/inputs/nick.js index 6ed6a77d..9f8bfee0 100644 --- a/src/plugins/inputs/nick.js +++ b/src/plugins/inputs/nick.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "nick") { + if (cmd !== "nick") { return; } if (args.length !== 0) { diff --git a/src/plugins/inputs/notice.js b/src/plugins/inputs/notice.js index 5a8e9fd3..b273ae4b 100644 --- a/src/plugins/inputs/notice.js +++ b/src/plugins/inputs/notice.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "notice" || !args[1]) { + if (cmd !== "notice" || !args[1]) { return; } var irc = network.irc; diff --git a/src/plugins/inputs/part.js b/src/plugins/inputs/part.js index 12a8a14d..b95083d4 100644 --- a/src/plugins/inputs/part.js +++ b/src/plugins/inputs/part.js @@ -1,11 +1,11 @@ var _ = require("lodash"); module.exports = function(network, chan, cmd, args) { - if (cmd != "part" && cmd != "leave" && cmd != "close") { + if (cmd !== "part" && cmd !== "leave" && cmd !== "close") { return; } var client = this; - if (chan.type == "query") { + if (chan.type === "query") { network.channels = _.without(network.channels, chan); client.emit("part", { chan: chan.id diff --git a/src/plugins/inputs/quit.js b/src/plugins/inputs/quit.js index 04e0e741..1bae1965 100644 --- a/src/plugins/inputs/quit.js +++ b/src/plugins/inputs/quit.js @@ -1,19 +1,19 @@ var _ = require("lodash"); module.exports = function(network, chan, cmd, args) { - if (cmd != "quit" && cmd != "disconnect") { + if (cmd !== "quit" && cmd !== "disconnect") { return; } - + var client = this; var irc = network.irc; var quitMessage = args[0] ? args.join(" ") : ""; - + client.networks = _.without(client.networks, network); client.save(); client.emit("quit", { network: network.id }); - + irc.quit(quitMessage); }; diff --git a/src/plugins/inputs/raw.js b/src/plugins/inputs/raw.js index 3594082f..6a5c1534 100644 --- a/src/plugins/inputs/raw.js +++ b/src/plugins/inputs/raw.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "raw" && cmd != "send" && cmd != "quote") { + if (cmd !== "raw" && cmd !== "send" && cmd !== "quote") { return; } if (args.length !== 0) { diff --git a/src/plugins/inputs/services.js b/src/plugins/inputs/services.js index 515fd3e9..6c0db36d 100644 --- a/src/plugins/inputs/services.js +++ b/src/plugins/inputs/services.js @@ -1,7 +1,7 @@ var _ = require("lodash"); module.exports = function(network, chan, cmd, args) { - if (cmd != "ns" && cmd != "cs" && cmd != "hs") { + if (cmd !== "ns" && cmd !== "cs" && cmd !== "hs") { return; } var target = ({ diff --git a/src/plugins/inputs/topic.js b/src/plugins/inputs/topic.js index 8f4c2bbf..01d373b7 100644 --- a/src/plugins/inputs/topic.js +++ b/src/plugins/inputs/topic.js @@ -1,12 +1,12 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "topic") { + if (cmd !== "topic") { return; } - + var msg = "TOPIC"; msg += " " + chan.name; msg += args[0] ? (" :" + args.join(" ")) : ""; - + var irc = network.irc; irc.write(msg); }; diff --git a/src/plugins/inputs/whois.js b/src/plugins/inputs/whois.js index fd24430f..4170338b 100644 --- a/src/plugins/inputs/whois.js +++ b/src/plugins/inputs/whois.js @@ -1,5 +1,5 @@ module.exports = function(network, chan, cmd, args) { - if (cmd != "whois" && cmd != "query") { + if (cmd !== "whois" && cmd !== "query") { return; } if (args.length !== 0) { diff --git a/src/plugins/irc-events/ctcp.js b/src/plugins/irc-events/ctcp.js index 7174cfba..42b7fed8 100644 --- a/src/plugins/irc-events/ctcp.js +++ b/src/plugins/irc-events/ctcp.js @@ -1,6 +1,6 @@ var pkg = require(process.cwd() + "/package.json"); -module.exports = function(irc, network) { +module.exports = function(irc/* , network */) { irc.on("message", function(data) { if (data.message.indexOf("\001") !== 0) { return; @@ -15,7 +15,7 @@ module.exports = function(irc, network) { ); break; case "PING": - if (split.length == 2) { + if (split.length === 2) { irc.ctcp(data.from, "PING " + split[1]); } break; diff --git a/src/plugins/irc-events/error.js b/src/plugins/irc-events/error.js index b6bd17d4..c56a36cc 100644 --- a/src/plugins/irc-events/error.js +++ b/src/plugins/irc-events/error.js @@ -13,7 +13,7 @@ module.exports = function(irc, network) { msg: msg }); if (!network.connected) { - if (data.cmd == "ERR_NICKNAMEINUSE") { + if (data.cmd === "ERR_NICKNAMEINUSE") { var random = irc.me + Math.floor(10 + (Math.random() * 89)); irc.nick(random); } diff --git a/src/plugins/irc-events/join.js b/src/plugins/irc-events/join.js index d4079900..edb7c245 100644 --- a/src/plugins/irc-events/join.js +++ b/src/plugins/irc-events/join.js @@ -26,7 +26,7 @@ module.exports = function(irc, network) { users: users }); var self = false; - if (data.nick.toLowerCase() == irc.me.toLowerCase()) { + if (data.nick.toLowerCase() === irc.me.toLowerCase()) { self = true; } var msg = new Msg({ diff --git a/src/plugins/irc-events/kick.js b/src/plugins/irc-events/kick.js index 88e37292..5daf252e 100644 --- a/src/plugins/irc-events/kick.js +++ b/src/plugins/irc-events/kick.js @@ -12,7 +12,7 @@ module.exports = function(irc, network) { return; } - if (data.client == irc.me) { + if (data.client === irc.me) { chan.users = []; } else { chan.users = _.without(chan.users, _.findWhere(chan.users, {name: data.client})); @@ -24,7 +24,7 @@ module.exports = function(irc, network) { }); var self = false; - if (data.nick.toLowerCase() == irc.me.toLowerCase()) { + if (data.nick.toLowerCase() === irc.me.toLowerCase()) { self = true; } diff --git a/src/plugins/irc-events/link.js b/src/plugins/irc-events/link.js index 908b7875..b0f3cca2 100644 --- a/src/plugins/irc-events/link.js +++ b/src/plugins/irc-events/link.js @@ -3,7 +3,7 @@ var cheerio = require("cheerio"); var Msg = require("../../models/msg"); var request = require("request"); var Helper = require("../../helper"); -var es = require('event-stream'); +var es = require("event-stream"); process.setMaxListeners(0); @@ -28,7 +28,7 @@ module.exports = function(irc, network) { return; } - var self = data.to.toLowerCase() == irc.me.toLowerCase(); + var self = data.to.toLowerCase() === irc.me.toLowerCase(); var chan = _.findWhere(network.channels, {name: self ? data.from : data.to}); if (typeof chan === "undefined") { return; @@ -67,12 +67,12 @@ function parse(msg, url, res, client) { toggle.type = "link"; toggle.head = $("title").text(); toggle.body = - $('meta[name=description]').attr('content') - || $('meta[property="og:description"]').attr('content') + $("meta[name=description]").attr("content") + || $("meta[property=\"og:description\"]").attr("content") || "No description found."; toggle.thumb = - $('meta[property="og:image"]').attr('content') - || $('meta[name="twitter:image:src"]').attr('content') + $("meta[property=\"og:image\"]").attr("content") + || $("meta[name=\"twitter:image:src\"]").attr("content") || ""; break; @@ -93,18 +93,18 @@ function parse(msg, url, res, client) { function fetch(url, cb) { try { var req = request.get(url); - } catch(e) { + } catch (e) { return; } var length = 0; var limit = 1024 * 10; req - .on('response', function(res) { - if (!(/(text\/html|application\/json)/.test(res.headers['content-type']))) { - res.req.abort(); + .on("response", function(res) { + if (!(/(text\/html|application\/json)/.test(res.headers["content-type"]))) { + res.req.abort(); } }) - .on('error', function() {}) + .on("error", function() {}) .pipe(es.map(function(data, next) { length += data.length; if (length > limit) { @@ -118,12 +118,12 @@ function fetch(url, cb) { var type; try { body = JSON.parse(data); - } catch(e) { + } catch (e) { body = {}; } try { - type = req.response.headers['content-type'].split(/ *; */).shift(); - } catch(e) { + type = req.response.headers["content-type"].split(/ *; */).shift(); + } catch (e) { type = {}; } data = { diff --git a/src/plugins/irc-events/message.js b/src/plugins/irc-events/message.js index aa990bb7..18b48e93 100644 --- a/src/plugins/irc-events/message.js +++ b/src/plugins/irc-events/message.js @@ -5,13 +5,13 @@ var Msg = require("../../models/msg"); module.exports = function(irc, network) { var client = this; irc.on("message", function(data) { - if (data.message.indexOf("\u0001") === 0 && data.message.substring(0, 7) != "\u0001ACTION") { + if (data.message.indexOf("\u0001") === 0 && data.message.substring(0, 7) !== "\u0001ACTION") { // Hide ctcp messages. return; } var target = data.to; - if (target.toLowerCase() == irc.me.toLowerCase()) { + if (target.toLowerCase() === irc.me.toLowerCase()) { target = data.from; } @@ -40,11 +40,11 @@ module.exports = function(irc, network) { }); var self = false; - if (data.from.toLowerCase() == irc.me.toLowerCase()) { + if (data.from.toLowerCase() === irc.me.toLowerCase()) { self = true; } - if (chan.id != client.activeChannel) { + if (chan.id !== client.activeChannel) { chan.unread++; } diff --git a/src/plugins/irc-events/mode.js b/src/plugins/irc-events/mode.js index 96648375..b4acc82a 100644 --- a/src/plugins/irc-events/mode.js +++ b/src/plugins/irc-events/mode.js @@ -14,7 +14,7 @@ module.exports = function(irc, network) { from = data.target; } var self = false; - if (from.toLowerCase() == irc.me.toLowerCase()) { + if (from.toLowerCase() === irc.me.toLowerCase()) { self = true; } var msg = new Msg({ diff --git a/src/plugins/irc-events/nick.js b/src/plugins/irc-events/nick.js index e884cded..fc65c4f2 100644 --- a/src/plugins/irc-events/nick.js +++ b/src/plugins/irc-events/nick.js @@ -6,7 +6,7 @@ module.exports = function(irc, network) { irc.on("nick", function(data) { var self = false; var nick = data["new"]; - if (nick == irc.me) { + if (nick === irc.me) { var lobby = network.channels[0]; var msg = new Msg({ text: "You're now known as " + nick, diff --git a/src/plugins/irc-events/notice.js b/src/plugins/irc-events/notice.js index 0f8c057f..a4b9d877 100644 --- a/src/plugins/irc-events/notice.js +++ b/src/plugins/irc-events/notice.js @@ -5,7 +5,7 @@ module.exports = function(irc, network) { var client = this; irc.on("notice", function(data) { var target = data.to; - if (target.toLowerCase() == irc.me.toLowerCase()) { + if (target.toLowerCase() === irc.me.toLowerCase()) { target = data.from; } @@ -15,7 +15,7 @@ module.exports = function(irc, network) { } var from = data.from || ""; - if (data.to == "*" || data.from.indexOf(".") !== -1) { + if (data.to === "*" || data.from.indexOf(".") !== -1) { from = ""; } var msg = new Msg({ diff --git a/src/plugins/irc-events/part.js b/src/plugins/irc-events/part.js index 42c0b355..a7ba317c 100644 --- a/src/plugins/irc-events/part.js +++ b/src/plugins/irc-events/part.js @@ -9,7 +9,7 @@ module.exports = function(irc, network) { return; } var from = data.nick; - if (from == irc.me) { + if (from === irc.me) { network.channels = _.without(network.channels, chan); client.save(); client.emit("part", { diff --git a/src/plugins/irc-events/whois.js b/src/plugins/irc-events/whois.js index 5a66540a..7e014368 100644 --- a/src/plugins/irc-events/whois.js +++ b/src/plugins/irc-events/whois.js @@ -26,7 +26,6 @@ module.exports = function(irc, network) { channels: "on", server: "using" }; - var i = 0; for (var k in data) { var key = prefix[k]; if (!key || data[k].toString() === "") { diff --git a/src/server.js b/src/server.js index 39a67106..5beb6707 100644 --- a/src/server.js +++ b/src/server.js @@ -26,7 +26,7 @@ module.exports = function(options) { var protocol = https.enable ? "https" : "http"; var port = config.port; var host = config.host; - var transports = config.transports || ['websocket', 'polling']; + var transports = config.transports || ["websocket", "polling"]; if (!https.enable){ server = require("http"); @@ -36,7 +36,7 @@ module.exports = function(options) { server = server.createServer({ key: fs.readFileSync(https.key), cert: fs.readFileSync(https.certificate) - }, app).listen(port, host) + }, app).listen(port, host); } if ((config.identd || {}).enable) { @@ -71,7 +71,7 @@ module.exports = function(options) { }; function index(req, res, next) { - if (req.url.split("?")[0] != "/") return next(); + if (req.url.split("?")[0] !== "/") return next(); return fs.readFile("client/index.html", "utf-8", function(err, file) { var data = _.merge( require("../package.json"), @@ -144,10 +144,10 @@ function auth(data) { var success = false; _.each(manager.clients, function(client) { if (data.token) { - if (data.token == client.token) { + if (data.token === client.token) { success = true; } - } else if (client.config.user == data.user) { + } else if (client.config.user === data.user) { if (bcrypt.compareSync(data.password || "", client.config.password)) { success = true; } diff --git a/test/plugins/link.js b/test/plugins/link.js index 6cef635d..278a2713 100644 --- a/test/plugins/link.js +++ b/test/plugins/link.js @@ -1,37 +1,37 @@ -var assert = require('assert'); - -var util = require('../util'); -var link = require('../../src/plugins/irc-events/link.js'); - -describe('Link plugin', function() { - before(function(done) { - this.app = util.createWebserver(); - this.connection = this.app.listen(9002, done); - }); - - after(function(done) { - this.connection.close(done); - }); - - beforeEach(function() { - this.irc = util.createClient(); - this.network = util.createNetwork(); - }); - - it('should be able to fetch basic information about URLs', function(done) { - var plugin = link.call(this.irc, this.irc, this.network); - - this.app.get('/basic', function(req, res) { - res.send('test'); - }); - - this.irc.createMessage({ - message: 'http://localhost:9002/basic' - }); - - this.irc.once('toggle', function(data) { - assert.equal(data.head, 'test'); - done(); - }) - }); +var assert = require("assert"); + +var util = require("../util"); +var link = require("../../src/plugins/irc-events/link.js"); + +describe("Link plugin", function() { + before(function(done) { + this.app = util.createWebserver(); + this.connection = this.app.listen(9002, done); + }); + + after(function(done) { + this.connection.close(done); + }); + + beforeEach(function() { + this.irc = util.createClient(); + this.network = util.createNetwork(); + }); + + it("should be able to fetch basic information about URLs", function(done) { + link.call(this.irc, this.irc, this.network); + + this.app.get("/basic", function(req, res) { + res.send("test"); + }); + + this.irc.createMessage({ + message: "http://localhost:9002/basic" + }); + + this.irc.once("toggle", function(data) { + assert.equal(data.head, "test"); + done(); + }); + }); }); diff --git a/test/util.js b/test/util.js index b7adeee4..cda4a419 100644 --- a/test/util.js +++ b/test/util.js @@ -1,43 +1,41 @@ -var EventEmitter = require('events').EventEmitter; -var util = require('util'); -var _ = require('lodash'); -var express = require('express'); +var EventEmitter = require("events").EventEmitter; +var util = require("util"); +var _ = require("lodash"); +var express = require("express"); function MockClient(opts) { - this.me = 'test-user'; + this.me = "test-user"; - for(k in opts) { - this[k] = opts[k]; - } + for (var k in opts) { + this[k] = opts[k]; + } } util.inherits(MockClient, EventEmitter); MockClient.prototype.createMessage = function(opts) { - var message = _.extend({ - message: 'dummy message', - from: 'test-user', - to: 'test-channel' - }, opts); + var message = _.extend({ + message: "dummy message", + from: "test-user", + to: "test-channel" + }, opts); - this.emit('message', message); -} + this.emit("message", message); +}; module.exports = { - createClient: function() { - return new MockClient(); - }, - createNetwork: function() { - return { - channels: [{ - name: 'test-channel', - messages: [] - }] - } - }, - createWebserver: function() { - return express(); - } -} - - + createClient: function() { + return new MockClient(); + }, + createNetwork: function() { + return { + channels: [{ + name: "test-channel", + messages: [] + }] + }; + }, + createWebserver: function() { + return express(); + } +}; From 12ba15acf251391e67799572aeeefea6d0efac30 Mon Sep 17 00:00:00 2001 From: William Boman Date: Mon, 26 Oct 2015 02:06:33 +0100 Subject: [PATCH 09/17] package.json: add linting to `test` script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 582488fb..d444ac5a 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "scripts": { "start": "node index", "build": "grunt", - "test": "HOME=test/fixtures mocha test/**/*.js", + "test": "HOME=test/fixtures mocha test/**/*.js && npm run lint", "lint": "eslint index.js Gruntfile.js src/ test/ client/ defaults/" }, "keywords": [ From b9121d8321adc0e43834c4e5c54ac1f8d99d1fe6 Mon Sep 17 00:00:00 2001 From: William Boman Date: Thu, 1 Oct 2015 00:12:04 +0200 Subject: [PATCH 10/17] Add .editorconfig http://editorconfig.org/ --- .editorconfig | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..7907cdff --- /dev/null +++ b/.editorconfig @@ -0,0 +1,24 @@ +# EditorConfig helps developers define and maintain consistent +# coding styles between different editors and IDEs +# editorconfig.org + +root = true + +[*] +indent_style = tab + +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[*.{json,yml}] +indent_style = space +indent_size = 2 + +[.eslintrc] +indent_style = space +indent_size = 2 From e5858744a212f6acbcdc14368ff51927b7ebb28e Mon Sep 17 00:00:00 2001 From: Olivier Lambert Date: Thu, 1 Oct 2015 00:15:53 +0200 Subject: [PATCH 11/17] Limit preview for large image files (fix #500) --- defaults/config.js | 11 +++++++++++ src/plugins/irc-events/link.js | 15 +++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/defaults/config.js b/defaults/config.js index 6727538d..1a342d1a 100644 --- a/defaults/config.js +++ b/defaults/config.js @@ -64,6 +64,17 @@ module.exports = { // prefetch: false, + // + // Prefetch URLs Image Preview size limit + // + // If prefetch is enabled, Shout will only display content under the maximum size. + // Default value is 512 (in kB) + // + // @type int + // @default 512 + // + prefetchMaxImageSize: 512, + // // Display network // diff --git a/src/plugins/irc-events/link.js b/src/plugins/irc-events/link.js index b0f3cca2..2a2c06d2 100644 --- a/src/plugins/irc-events/link.js +++ b/src/plugins/irc-events/link.js @@ -52,6 +52,7 @@ module.exports = function(irc, network) { }; function parse(msg, url, res, client) { + var config = Helper.getConfig(); var toggle = msg.toggle = { id: msg.id, type: "", @@ -61,6 +62,9 @@ function parse(msg, url, res, client) { link: url }; + if (!config.prefetchMaxImageSize) { + config.prefetchMaxImageSize = 512; + } switch (res.type) { case "text/html": var $ = cheerio.load(res.text); @@ -80,7 +84,12 @@ function parse(msg, url, res, client) { case "image/gif": case "image/jpg": case "image/jpeg": - toggle.type = "image"; + if (res.size < (config.prefetchMaxImageSize * 1024)) { + toggle.type = "image"; + } + else { + return; + } break; default: @@ -116,6 +125,7 @@ function fetch(url, cb) { if (err) return; var body; var type; + var size = req.response.headers["content-length"]; try { body = JSON.parse(data); } catch (e) { @@ -129,7 +139,8 @@ function fetch(url, cb) { data = { text: data, body: body, - type: type + type: type, + size: size }; cb(data); })); From 936bb8141dcf1f30a5bdee711429922f2fc79194 Mon Sep 17 00:00:00 2001 From: Jan-Christoph Borchardt Date: Mon, 9 Nov 2015 17:11:21 +0100 Subject: [PATCH 12/17] fix development setup command, fix #535 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b2ff9c1b..bff7749a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ To run the app from source, just clone the code and run this in your terminal: ``` npm install npm run build -npm start -- --port 8080 +npm start ``` ## License From 87277e251ee5ac82ae20a2cca7be1a652bd7ade9 Mon Sep 17 00:00:00 2001 From: JocelynDelalande Date: Tue, 1 Dec 2015 22:19:55 +0100 Subject: [PATCH 13/17] Allow simple-quotes strings if it avoids escaping --- .eslintrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc b/.eslintrc index 78cb50d3..56d584f0 100644 --- a/.eslintrc +++ b/.eslintrc @@ -20,7 +20,7 @@ rules: spaced-comment: [2, always] no-console: 0 no-trailing-spaces: 2 - quotes: [2, double] + quotes: [2, double, avoid-escape] globals: $: false From a25cd007413b4b01ee3ac75acc292398b8b0ae03 Mon Sep 17 00:00:00 2001 From: JocelynDelalande Date: Tue, 1 Dec 2015 23:14:50 +0100 Subject: [PATCH 14/17] State that we prefer rebasing over merging PRs --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eb43ae7b..96acc851 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,6 +32,10 @@ Also, make sure that your PRs do not contain unnecessary commits. If you think some of your commits should be merged into a single one, feel free to [squash them](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History). +Please [rebase](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) outdated +PRs on master to help with the reviews (rebasing is preferred over merging to +keep a clean history in a branch/PR). + Additionally, give extra care to your commit messages, as they will help us review your PRs as well as help other contributors in the future, when exploring the history. The general rules are to [use the imperative present From 58d4a2fda16ce4883d3a11d0e8c9a6549632fecb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Finn=20Gl=C3=B6e?= Date: Sat, 28 Mar 2015 18:47:15 +0000 Subject: [PATCH 15/17] made channel names in chat clickable; lets users join channels --- client/css/style.css | 6 ++++++ client/js/shout.js | 28 +++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/client/css/style.css b/client/css/style.css index 7ce8ea86..a81f1adf 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -608,6 +608,12 @@ button { display: none; font-style: normal; } +#chat .msg .inline-channel { + cursor: pointer; +} +#chat .msg .inline-channel:hover { + opacity: .6; +} #chat .time, #chat .from, #chat .text { diff --git a/client/js/shout.js b/client/js/shout.js index a23dc7de..d8884c56 100644 --- a/client/js/shout.js +++ b/client/js/shout.js @@ -190,13 +190,39 @@ $(function() { var chan = chat.find(target); var from = data.msg.from; + var msg = $(render("msg", {messages: [data.msg]})); chan.find(".messages") - .append(render("msg", {messages: [data.msg]})) + .append(msg) .trigger("msg", [ target, data.msg ]); + var text = msg.find(".text"); + if (text.find("i").size() === 1) { + text = text.find("i"); + } + // Channels names are strings (beginning with a '&' or '#' character) + // of length up to 200 characters. + // See https://tools.ietf.org/html/rfc1459#section-1.3 + text.html(text.html().replace(/(^|\s)([#&][^\x07\x2C\s]{0,199})/ig, + '$1$2')); + text.find("span.inline-channel") + .on("click", function() { + var chan = $(".network") + .find(".chan.active") + .parent(".network") + .find(".chan[data-title='" + $(this).data("chan") + "']"); + if (chan.size() === 1) { + chan.click(); + } else { + socket.emit("input", { + target: chat.data("id"), + text: "/join " + $(this).data("chan") + }); + } + }); + if (!chan.hasClass("channel")) { return; } From 5c9d09b388e2d0e05373f42399fc72a7a0161a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Astori?= Date: Thu, 7 Jan 2016 06:40:26 +0000 Subject: [PATCH 16/17] Add CHANGELOG info for version 0.53.0 --- CHANGELOG.md | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f9ff2f9..abe7fb84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,24 @@ +0.53.0 / 2016-01-07 +=================== + +[See the full changelog](https://github.com/erming/shout/compare/v0.52.0...v0.53.0) + +* Added a Dockerfile ([PR #477](https://github.com/erming/shout/pull/477) by [@bencevans](https://github.com/bencevans)) +* Fixed a bug preventing logging on channels that contain slashes ([PR #519](https://github.com/erming/shout/pull/519) by [@lyra833](https://github.com/lyra833)) +* Added missing `grunt-cli` as a required development dependencies ([PR #522](https://github.com/erming/shout/pull/522) by [@williamboman](https://github.com/williamboman)) +* Added [@floogulinc](https://github.com/floogulinc) as a project maintainer +* Added consistent coding style enforcement using `ESLint` ([PR #504](https://github.com/erming/shout/pull/504) by [@williamboman](https://github.com/williamboman), [PR #547](https://github.com/erming/shout/pull/547) by [@JocelynDelalande](https://github.com/JocelynDelalande)) +* Added an `.editorconfig` file ([PR #526](https://github.com/erming/shout/pull/526) by [@williamboman](https://github.com/williamboman)) +* Added a size limit for image previews ([PR #503](https://github.com/erming/shout/pull/503) by [@olivierlambert](https://github.com/olivierlambert), [issue #500](https://github.com/erming/shout/issues/500)) +* Fixed the development setup command ([PR #536](https://github.com/erming/shout/pull/536) by [@jancborchardt](https://github.com/jancborchardt), [issue #535](https://github.com/erming/shout/issues/535)) +* Improved the [CONTRIBUTING.md](https://github.com/erming/shout/blob/master/CONTRIBUTING.md) file regarding rebasing ([PR #548](https://github.com/erming/shout/pull/548) by [@JocelynDelalande](https://github.com/JocelynDelalande)) +* Made channel names in chat clickable to let users join them ([PR #385](https://github.com/erming/shout/pull/385) by [@AmShaegar13](https://github.com/AmShaegar13), [issue #361](https://github.com/erming/shout/issues/361)) + +0.52.0 / ??? +============ + +??? + 0.51.2 / 2015-09-18 ================== @@ -15,24 +36,24 @@ * Link preview now ignores links from localhost * Added 'displayNetwork' setting -0.49.3 / 2015-01-04 +0.49.3 / 2015-01-04 =================== * Fully expand chat when userlist is hidden * Remove vertical whitespace in chat windows * Support @mention -0.49.2 / 2015-01-04 +0.49.2 / 2015-01-04 =================== * Fix crash on broken links -0.49.1 / 2015-01-04 +0.49.1 / 2015-01-04 =================== * Fix undefined content-type (link plugin) -0.49.0 / 2014-12-23 +0.49.0 / 2014-12-23 =================== * Replaced superagent with request @@ -108,7 +129,7 @@ =================== * Disable login button on authentication - * Fix 'shout edit' command + * Fix 'shout edit' command 0.43.0 / 2014-10-08 =================== From baadc3df3534fb22515a8c2ea29218fbbc1228b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9mie=20Astori?= Date: Thu, 7 Jan 2016 06:40:34 +0000 Subject: [PATCH 17/17] 0.53.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a015a547..b0894b27 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "shout", "description": "The self-hosted Web IRC client", - "version": "0.52.0", + "version": "0.53.0", "author": "Mattias Erming", "preferGlobal": true, "bin": {