Removing Backbone dependency. Closes #6

This commit is contained in:
Mattias Erming 2014-04-23 20:44:44 +02:00
parent 8ad659d7fa
commit 2852942241
13 changed files with 538 additions and 448 deletions

View File

@ -11,6 +11,7 @@ These are the commands currently implemented:
- `/kick`
- `/leave`
- `/mode`
- `/msg`
- `/nick`
- `/op`
- `/part`

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>Chat</title>
<title>Shout — The modern IRC client</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no">
@ -21,25 +21,23 @@
</div>
</div>
<script type="text/x-handlebars-template" id="networks">
<script type="text/html" id="networks">
{{#each networks}}
<ul id="network-{{id}}" class="network">
<div id="network-{{id}}" data-nick="{{nick}}" class="network">
{{partial "#channels"}}
</ul>
</div>
{{/each}}
</script>
<script type="text/x-handlebars-template" id="channels">
<script type="text/html" id="channels">
{{#each channels}}
<li>
<button id="channel-{{id}}" class="channel">
{{name}}
</button>
</li>
{{/each}}
</script>
<script type="text/x-handlebars-template" id="windows">
<script type="text/html" id="windows">
{{#each windows}}
<div id="window-{{id}}" class="window {{type}}">
<div class="title">
@ -59,7 +57,7 @@
{{/each}}
</script>
<script type="text/x-handlebars-template" id="users">
<script type="text/html" id="users">
<div class="count">
Users: {{users.length}}
</div>
@ -70,9 +68,9 @@
{{/each}}
</script>
<script type="text/x-handlebars-template" id="messages">
<script type="text/html" id="messages">
{{#each messages}}
<div class="{{type}}">
<div class="msg {{type}}">
<span class="time">
{{time}}
</span>

View File

@ -11,6 +11,7 @@ $(function() {
"/kick",
"/leave",
"/mode",
"/msg",
"/nick",
"/op",
"/part",
@ -23,133 +24,98 @@ $(function() {
];
var socket = io.connect("");
$.each(["network", "channel", "user", "message"], function(i, event) {
socket.on(event, function(json) {
handleEvent(event, json);
var events = [
"join",
"msg",
"networks",
"nick",
"part",
"users",
].forEach(function(e) {
socket.on(e, function(data) {
event(e, data);
});
});
var tpl = [];
function render(id, json) {
tpl[id] = tpl[id] || Handlebars.compile($(id).html());
return tpl[id](json);
function render(id, data) {
tpl[id] = tpl[id] || Handlebars.compile($(id).remove().html());
return tpl[id](data);
}
function handleEvent(event, json) {
var data = [].concat(json.data);
switch (event) {
function event(e, data) {
// Debug
console.log(arguments);
case "network":
var html = "";
data.forEach(function(n) {
html += render("#windows", {windows: n.channels});
});
chat[0].innerHTML = html;
sidebar.html(
render("#networks", {networks: data})
).find(".channel")
.first()
.addClass("active")
.end();
chat.find(".messages")
.scrollGlue({animate: 400})
.scrollToBottom()
.end();
chat.find(".window")
.find("input")
.tabComplete({after: " ", list: commands})
.inputHistory({submit: true})
.end()
.first()
.bringToTop()
.end();
break;
case "channel":
var id = data[0].id;
if (json.action == "remove") {
$("#channel-" + id + ", #window-" + id).remove();
var highest = 0;
var next = null;
$(".window").each(function() {
var z = $(this).css("z-index");
if (z == "auto") z = 0;
if (z > highest) {
highest = z;
next = $(this);
}
});
if (next != null) {
$("#channel-" + next.attr("id").replace("window-", "")).addClass("active");
next.bringToTop();
}
return;
}
sidebar.find(".channel").removeClass("active");
$("#network-" + json.target).append(
render("#channels", {channels: data})
).find(".channel")
switch (e) {
case "join":
chat.append(render("#windows", {
windows: [data.chan],
})).find(".window")
.last()
.addClass("active");
chat.append(
render("#windows", {windows: data})
).find(".window")
.last()
.find("input")
.find(".input")
.tabComplete({after: " ", list: commands})
.inputHistory({submit: true})
.end()
.bringToTop()
.find(".messages")
.scrollGlue({animate: 400})
.scrollGlue({speed: 400})
.end();
$("#network-" + data.id).append(render("#channels", {
channels: [data.chan],
})).find(".channel")
.last()
.uniqueClass("active")
.end();
break;
case "user":
var html = render("#users", {users: data});
var target = chat.find("#window-" + json.target + " .users").html(html);
case "msg":
$("#window-" + data.id).find(".messages").append(render("#messages", {
messages: [data.msg],
}));
break;
case "message":
var target = $("#window-" + json.target);
if (target.size() == 0) {
return;
}
if (data.type == "error") {
target = target.parent().find(".active");
}
var msg = $(render("#messages", {messages: data}));
target = target.find(".messages");
target.append(msg);
case "networks":
chat.html(render("#windows", {
windows: $.map(data.networks, function(n) { return n.channels; }),
})).find(".window")
.find(".input")
.tabComplete({after: " ", list: commands})
.inputHistory({submit: true})
.end()
.find(".messages")
.scrollGlue({speed: 400})
.end()
.last()
.bringToTop()
.end();
sidebar.html(render("#networks", {
networks: data.networks,
})).find(".channel")
.last()
.addClass("active")
.end();
break;
case "nick":
// Not yet implemented.
break;
case "part":
$("#channel-" + data.id + ", #window-" + data.id).remove();
break;
case "users":
$("#window-" + data.id).find(".users").html(render("#users", {
users: data.users,
}));
break;
}
}
sidebar.on("click", ".channel", function(e) {
e.preventDefault();
sidebar.find(".active").removeClass("active");
$("#viewport").removeClass();
var item = $(this)
.addClass("active")
.find(".badge")
.html("")
.end();
$("#window-" + item.attr("id").replace("channel-", ""))
.bringToTop();
});
chat.on("submit", "form", function() {
var input = $(this).find(".input");
var text = input.val();
var text = input.val();
if (text == "") {
return false;
}
@ -159,39 +125,36 @@ $(function() {
text: text,
});
});
chat.on("dblclick", ".user", function() {
var link = $(this);
var id = parseInt(link.closest(".window").attr("id").replace("window-", ""));
var name = link.text().trim();
chat.on("focus", ".input", function() {
var input = $(this).parents().eq(1).find(".messages").scrollToBottom();
});
chat.on("click", ".user", function(e) {
e.preventDefault();
var user = $(this);
var id = parseInt(user.closest(".window").attr("id").replace("window-", ""));
var name = user.text().trim();
if (name == "-!-" || name.indexOf(".") != -1) {
return;
}
socket.emit("input", {
id: id,
text: "/whois " + link.text().trim(),
text: "/whois " + name,
});
});
chat.on("focus", "input[type=text]", function() {
$(this).closest(".window").find(".messages").scrollToBottom();
sidebar.on("click", ".channel", function(e) {
e.preventDefault();
$("#window-" + $(this).attr("id").replace("channel-", ""))
.bringToTop();
});
var highest = 1;
$.fn.bringToTop = function() {
return this.css('z-index', highest++)
.addClass("active")
.find(".input")
.focus()
.end()
.siblings()
.removeClass("active")
.end();
};
// Utils
function uri(text) {
return URI.withinString(text, function(url) {
return "<a href='" + url + "' target='_blank'>" + url + "</a>";
return "<a href='" + url.replace(/^www/, "//www") + "' target='_blank'>" + url + "</a>";
});
}
@ -205,6 +168,8 @@ $(function() {
});
}
// Helpers
Handlebars.registerHelper(
"uri",
function(text) {

View File

@ -1,3 +1,27 @@
/*!
* uniqueClass
* https://gist.github.com/erming/11212325
*/
(function($) {
$.fn.uniqueClass = function(name) {
return this.addClass(name).siblings().removeClass(name).end();
};
})(jQuery);
/*!
* bringToTop
* https://gist.github.com/erming/11193183
*/
(function($) {
var highest = 1;
$.fn.bringToTop = function() {
return this.css('z-index', highest++).uniqueClass('active')
.find(".input")
.focus()
.end();
};
})(jQuery);
/*!
* inputHistory
* https://github.com/erming/inputHistory
@ -7,7 +31,6 @@
*
* Version 0.1.1
*/
(function($) {
$.fn.inputHistory = function(options) {
var settings = $.extend({
@ -72,13 +95,13 @@
* Copyright (c) 2014 Mattias Erming <mattias@mattiaserming.com>
* Licensed under the MIT License.
*
* Version 0.2.1
* Version 0.2.2
*/
(function($) {
$.fn.scrollGlue = function(options) {
var settings = $.extend({
speed: 0
speed: 0,
scrollToBottom: true,
}, options);
var self = this;
@ -87,6 +110,10 @@
$(this).scrollGlue(options);
});
}
if (settings.scrollToBottom) {
self.scrollToBottom();
}
$(window).on('resize', function() {
self.finish();
@ -147,7 +174,6 @@
*
* Version 0.2.2
*/
(function($) {
$.fn.tabComplete = function(options) {
var settings = $.extend({

View File

@ -49,10 +49,12 @@ li {
#sidebar .network {
margin: 20px;
}
#sidebar li {
#sidebar .channel {
display: block;
margin: 5px;
margin-left: 10px;
}
#sidebar li:first-child {
#sidebar .channel:first-child {
margin-left: 0;
}
#chat {
@ -83,11 +85,11 @@ li {
padding: 0 10px;
width: 100%;
}
#chat .network .users {
#chat .lobby .users {
display: none;
}
#chat .network .title,
#chat .network .messages {
#chat .lobby .title,
#chat .lobby .messages {
right: 0;
}
#chat .window {
@ -141,9 +143,15 @@ li {
#chat .notice,
#chat .part,
#chat .quit,
#chat .topic {
#chat .topic,
#chat .whois {
color: #999;
}
#chat .motd .type,
#chat .notice .type,
#chat .whois .type {
display: none;
}
#chat .users {
background: #fff;
border-left: 1px solid #ddd;

View File

@ -1,11 +1,13 @@
module.exports = {
port: 9000,
defaults: {
nick: "t_user",
realname: "Temp User",
nick: "j_doe",
realname: "John Doe",
},
servers: [{
networks: [{
host: "irc.freenode.org",
channels: ["#t_chan"],
port: 6667,
channels: [
"#t_chan",
],
}]
};

View File

@ -1,131 +0,0 @@
var _ = require("lodash");
var Backbone = require("backbone");
var id = 1;
var models =
module.exports =
{};
models.User = Backbone.Model.extend({
defaults: {
mode: "",
name: "",
}
});
models.Users = Backbone.Collection.extend({
model: models.User,
sort: function() {
this.models = _.sortBy(
this.models,
function(user) {
return user.get("name").toLowerCase();
}
);
this.trigger("sort", {}, this);
}
});
models.Message = Backbone.Model.extend({
defaults: {
type: "",
time: "",
from: "-!-",
text: "",
},
initialize: function() {
this.set("time", require("moment")().format("HH:mm"));
}
});
models.Messages = Backbone.Collection.extend({
model: models.Message
});
models.Channel = Backbone.Model.extend({
defaults: {
type: "channel",
name: "",
},
initialize: function() {
var users = new models.Users;
users.on("all", function(action, data) {
this.trigger("user", {
action: action,
target: this.get("id"),
data: users,
});
}, this);
var messages = new models.Messages;
messages.on("all", function(action, data) {
this.trigger("message", {
action: action,
target: this.get("id"),
data: data,
});
}, this);
this.set({
id: id++,
users: users,
messages: messages,
});
}
});
models.Channels = Backbone.Collection.extend({
model: models.Channel
});
models.Network = Backbone.Model.extend({
defaults: {
host: "",
client: null,
},
initialize: function() {
this.set({
id: id++,
channels: new models.Channels,
});
this.get("channels").on("all", function(action, data) {
if (action == "message"
|| action == "user") {
return this.trigger(action, data);
}
this.trigger("channel", {
action: action,
target: this.get("id"),
data: data,
});
}, this);
this.get("channels").add({
type: "network",
name: this.get("host")
});
},
toJSON: function() {
return _.omit(this.attributes, "client");
}
});
models.Networks = Backbone.Collection.extend({
model: models.Network,
initialize: function() {
this.add({host: "Status"});
},
find: function(id) {
var i = this.models.length;
while (i--) {
var find = this.models[i].get("channels").findWhere({id: id});
if (find) {
return {
network: this.models[i],
channel: find
};
}
}
}
});

13
lib/models/chan.js Normal file
View File

@ -0,0 +1,13 @@
var _ = require("lodash");
module.exports = Chan;
function Chan(attr) {
_.merge(this, _.extend({
id: global.id = ++global.id || 1,
name: "",
type: "",
messages: [],
users: [],
}, attr));
};

13
lib/models/msg.js Normal file
View File

@ -0,0 +1,13 @@
var _ = require("lodash");
var moment = require("moment");
module.exports = Msg;
function Msg(attr) {
_.merge(this, _.extend({
time: moment().format("HH:mm"),
type: "",
from: "",
text: "",
}, attr));
};

25
lib/models/network.js Normal file
View File

@ -0,0 +1,25 @@
var _ = require("lodash");
var Chan = require("./chan");
module.exports = Network;
function Network(attr) {
_.merge(this, _.extend({
id: global.id = ++global.id || 1,
client: null,
host: "",
nick: "",
channels: [],
}, attr));
// Add lobby
this.channels.unshift(
new Chan({name: this.host, type: "lobby"})
);
};
Network.prototype = {
toJSON: function() {
return _.omit(this, "client");
}
};

10
lib/models/user.js Normal file
View File

@ -0,0 +1,10 @@
var _ = require("lodash");
module.exports = User;
function User(attr) {
_.merge(this, _.extend({
mode: "",
name: "",
}, attr));
};

View File

@ -1,13 +1,21 @@
var models = require(__dirname + "/models.js");
var config = require(__dirname + "/../config.js");
var http = require("connect");
var io = require("socket.io");
var irc = require("slate-irc");
var net = require("net");
var _ = require("lodash");
var config = require("../config");
var http = require("connect");
var io = require("socket.io");
var irc = require("slate-irc");
var net = require("net");
var _ = require("lodash");
var sockets = null;
var networks = new models.Networks;
// Models
var Chan = require("./models/chan");
var Msg = require("./models/msg");
var Network = require("./models/network");
var User = require("./models/user");
var sockets = null;
var networks = [
new Network({host: "Status"})
];
var events = [
"join",
@ -25,26 +33,25 @@ var events = [
"whois",
];
module.exports = function listen() {
module.exports = listen;
function listen() {
var app = http()
.use(http.static("client"))
.listen(9000);
var self = this;
sockets = io.listen(app, {log: 0}).sockets.on("connection", function(s) {
s.on("input", input);
sockets.emit("network", {
data: networks,
s.emit("networks", {
networks: networks
});
});
networks.on("all", function() {
sockets.emit.apply(sockets, arguments);
config.networks.forEach(function(n) {
connect(n);
});
config.servers.forEach(function(s) {
connect(s);
});
};
}
function connect(params) {
params = _.extend(
@ -53,7 +60,7 @@ function connect(params) {
);
var host = params.host;
var port = params.port || 6667;
var port = params.port;
var stream = net.connect({
port: port,
@ -65,18 +72,20 @@ function connect(params) {
});
var client = irc(stream);
var network = networks.add({
var network = new Network({
host: host,
client: client,
}, {silent: true});
networks.trigger("network", {data: networks});
});
networks.push(network);
sockets.emit("networks", {
networks: networks
});
client.nick(params.nick);
client.user(params.nick, params.realname);
client.once("welcome", function() {
params.channels.forEach(function(c) {
(params.channels || []).forEach(function(c) {
client.join(c);
});
});
@ -88,41 +97,53 @@ function connect(params) {
});
}
function input(json) {
var target = networks.find(json.id);
function input(data) {
// Debug
console.log(arguments);
var target = find(data.id);
if (!target) {
return;
}
var network = target.network;
var channel = target.channel;
var chan = target.chan;
var client = network.get("client");
var id = json.id;
var text = json.text;
var client = network.client;
var id = data.id;
var text = data.text;
var args = text.replace(/^\//, '').split(" ");
var cmd = text.charAt(0) == "/" ? args[0].toLowerCase() : "";
var cmd = text.charAt(0) == "/" ? args[0].toLowerCase() : "";
switch (cmd) {
case "":
args.unshift(
"msg",
channel.get("name")
chan.name
);
console.log(args);
case "msg":
var user;
var message = _.tail(args, 2).join(" ");
var text = _.tail(args, 2).join(" ");
if (cmd == "msg") console.log(args);
if (client) {
user = client.me;
client.send(args[1], message);
client.send(args[1], text);
}
var chan = _.findWhere(network.channels, {name: args[1]});
if (typeof chan !== "undefined") {
var msg = new Msg({
from: user,
text: text,
});
chan.messages.push(msg)
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
}
channel.get("messages").add({
from: user,
text: message,
});
break;
case "server":
@ -141,21 +162,23 @@ function input(json) {
case "leave":
case "part":
if (channel.get("type") == "query") {
network.get("channels").remove(channel);
var id = chan.id;
if (chan.type == "query" || !chan.users.length) {
remove(id);
sockets.emit("part", {
id: id,
});
} else if (client) {
client.part(channel.get("name"));
client.part(chan.name);
}
break;
case "topic":
var chan = channel.get("name");
if (client) {
var str = "TOPIC " + chan;
if (args[1]) {
str += " :" + args.slice(1).join(" ");
}
client.write(str);
var msg = "TOPIC";
msg += " " + chan.name;
msg += args[1] ? " :" + args.slice(1).join(" ") : "";
client.write(msg);
}
break;
@ -168,7 +191,7 @@ function input(json) {
case "kick":
if (client && args[1]) {
client.kick(channel.get("name"), args[1]);
client.kick(chan.name, args[1]);
}
break;
@ -180,7 +203,6 @@ function input(json) {
if (!client || !args[1]) {
break;
}
var mode;
var user;
if (cmd != "mode") {
@ -197,9 +219,8 @@ function input(json) {
mode = args[1];
user = args[2];
}
client.mode(
channel.get("name"),
chan.name,
mode,
user
);
@ -207,191 +228,331 @@ function input(json) {
case "quit":
case "disconnect":
networks.remove(network);
networks.trigger("network", {data: networks});
if (client) {
client.quit();
networks = _.without(networks, network);
sockets.emit("networks", {
networks: networks
});
}
break;
}
}
function event(event, data) {
var channels = this.get("channels");
function event(e, data) {
// Debug
console.log(arguments);
switch (event) {
var data = _.last(data);
var channels = this.channels;
switch (e) {
case "join":
var chan = channels.findWhere({name: data[0].channel}) || channels.add({name: data[0].channel});
var users = chan.get("users");
users.add({name: data[0].nick}, {silent: true});
if (data[0].nick != this.get("client").me) {
users.sort();
var chan = _.findWhere(channels, {name: data.channel});
if (typeof chan === "undefined") {
chan = new Chan({
name: data.channel,
});
channels.push(chan);
sockets.emit("join", {
id: this.id,
chan: chan,
});
}
chan.get("messages").add({
from: data[0].nick,
var users = chan.users;
users.push(new User({name: data.nick}));
sockets.emit("users", {
id: chan.id,
users: users,
});
var msg = new Msg({
from: data.nick,
type: "join",
});
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
break;
case "kick":
var chan = channels.findWhere({name: data[0].channel});
var users = chan.get("users");
if (data[0].client != this.get("client").me) {
users.remove(users.findWhere({name: data[0].client}));
var chan = _.findWhere(channels, {name: data.channel});
if (data.client == this.client.me) {
chan.users = [];
} else {
users.reset();
chan.users = _.without(chan.users, _.findWhere(chan.users, {name: data.client}));
}
chan.get("messages").add({
from: data[0].nick,
text: data[0].client,
sockets.emit("users", {
id: chan.id,
users: chan.users,
});
var msg = new Msg({
type: "kick",
from: data.nick,
text: data.client,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
break;
case "mode":
var chan = channels.findWhere({name: data[0].target});
var chan = _.findWhere(channels, {name: data.target});
if (typeof chan !== "undefined") {
chan.get("messages").add({
from: data[0].nick,
text: data[0].mode + " " + data[0].client,
var msg = new Msg({
type: "mode",
from: data.nick,
text: data.mode + " " + data.client,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
}
break;
case "motd":
var messages = data[0].motd;
messages.forEach(function(msg) {
channels.first().get("messages").add({text: msg});
var chan = channels[0];
data.motd.forEach(function(m) {
var msg = new Msg({
type: "motd",
from: "-!-",
text: m,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
});
break;
case "message":
var chan = channels.findWhere({name: data[0].to}) || channels.add({type: "query", name: data[0].from});
var chan = _.findWhere(channels, {name: data.to});
if (typeof chan === "undefined") {
chan = new Chan({
name: data.from,
type: "query",
});
channels.push(chan);
sockets.emit("join", {
id: this.id,
chan: chan,
});
}
var type = "";
var text = data[0].message;
var text = data.message;
var network = this;
text.split(" ").forEach(function(w) {
if (w == network.get("client").me) type = "highlight";
if (w == network.client.me) type = "highlight";
});
chan.get("messages").add({
var msg = new Msg({
type: type,
from: data[0].from,
from: data.from,
text: text,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
break;
case "names":
var chan = channels.findWhere({name: data[0].channel});
var users = chan.get("users");
users.reset(
_.map(data[0].names, function(n) { return {name: n}; }),
{silent: true}
);
users.sort();
var chan = _.findWhere(channels, {name: data.channel});
chan.users = [];
data.names.forEach(function(n) {
chan.users.push(new User({name: n}));
});
sockets.emit("users", {
id: chan.id,
users: chan.users,
});
break;
case "nick":
if (data[0].new == this.get("client").me) {
channels.first().get("messages").add({
text: "You're now known as " + data[0]["new"],
if (data["new"] == this.client.me) {
var chan = channels[0];
var msg = new Msg({
from: "-!-",
text: "You're now known as " + data["new"],
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
}
channels.each(function(chan) {
var users = chan.get("users");
var user = users.findWhere({name: data[0].nick});
channels.forEach(function(chan) {
var user = _.findWhere(chan.users, {name: data.nick});
if (!user) {
return;
}
user.set("name", data[0]["new"]);
users.sort();
chan.get("messages").add({
from: data[0].nick,
text: data[0]["new"],
user.name = data["new"];
sockets.emit("users", {
id: chan.id,
users: chan.users,
});
var msg = new Msg({
type: "nick",
from: data.nick,
text: data["new"],
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
});
break;
case "notice":
if (data[0].to = "*") {
data[0].from = "-!-";
}
channels.first().get("messages").add({
case "notice":
var chan = channels[0];
var msg = new Msg({
type: "notice",
from: data[0].from,
text: data[0].message,
from: data.to == "*" ? "-!-" : data.from,
text: data.message,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
break;
case "part":
var chan = channels.findWhere({name: data[0].channels[0]});
if (data[0].nick == this.get("client").me) {
channels.remove(chan);
return;
var chan = _.findWhere(channels, {name: data.channels[0]});
if (data.nick == this.client.me) {
remove(chan.id);
sockets.emit("part", {
id: chan.id,
});
} else {
chan.users = _.without(chan.users, _.findWhere(chan.users, {name: data.nick}));
sockets.emit("users", {
id: chan.id,
users: chan.users,
});
var msg = new Msg({
type: "part",
from: data.nick,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
}
var users = chan.get("users");
users.remove(users.findWhere({name: data[0].nick}));
users.sort();
chan.get("messages").add({
from: data[0].nick,
type: "part",
});
break;
case "quit":
channels.each(function(chan) {
var users = chan.get("users");
var user = users.findWhere({name: data[0].nick});
if (user) {
users.remove(user);
users.sort();
chan.get("messages").add({
from: data[0].nick,
type: "quit",
});
channels.forEach(function(chan) {
var user = _.findWhere(chan.users, {name: data.nick});
if (!user) {
return;
}
chan.users = _.without(chan.users, user);
sockets.emit("users", {
id: chan.id,
users: chan.users,
});
var msg = new Msg({
type: "quit",
from: data.nick,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
});
break;
case "topic":
var chan = channels.findWhere({name: data[0].channel});
var from = data[0].nick || chan.get("name");
chan.get("messages").add({
from: from,
text: data[0].topic,
var chan = _.findWhere(channels, {name: data.channel});
var from = data.nick || chan.name;
var msg = new Msg({
type: "topic",
from: from,
text: data.topic,
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
break;
case "welcome":
channels.first().get("messages").add([
{text: "You're now connected to " + this.get("host")},
{text: "You're now known as " + data[0]}
]);
// Leaving this empty for now.
break;
case "whois":
if (data[1] == null) {
channels.first().get("messages").add({
if (!data) {
var chan = channels[0];
var msg = new Msg({
type: "error",
text: data[0]
text: "No such nick/channel.",
});
break;
}
var name = data[1].nickname;
var chan = channels.findWhere({name: name}) || channels.add({type: "query", name: name});
var i = 0;
for (var k in data[1]) {
if (i++ == 5) break;
chan.get("messages").add({
text: k + ": " + data[1][k]
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
} else {
var chan = _.findWhere(channels, {name: data.nickname});
if (typeof chan === "undefined") {
chan = new Chan({
type: "query",
name: data.nickname,
});
channels.push(chan);
sockets.emit("join", {
id: this.id,
chan: chan,
});
}
var i = 0;
for (var k in data) {
if (i++ == 5) break;
var msg = new Msg({
type: "whois",
from: "-!-",
text: k + ": " + data[k],
});
chan.messages.push(msg);
sockets.emit("msg", {
id: chan.id,
msg: msg,
});
}
}
break;
}
}
// Utils
function find(id) {
var result = false;
networks.forEach(function(n) {
result = {
network: n,
chan: _.findWhere(n.channels, {id: id}),
};
if (!result.chan) {
result = false;
}
});
return result;
}
function remove(id) {
networks.forEach(function(n) {
n.channels = _.without(n.channels, _.findWhere(n.channels, {id: id}));
});
}

View File

@ -8,7 +8,6 @@
},
"dependencies": {
"lodash": "~2.4.1",
"backbone": "~1.1.2",
"slate-irc": "~0.5.0",
"moment": "~2.5.1",
"connect": "~2.14.3",