From 4cc34d64568650bbee6575f81208ba959040eab9 Mon Sep 17 00:00:00 2001 From: Mattias Erming Date: Thu, 6 Mar 2014 07:11:25 -0800 Subject: [PATCH] Refactoring --- app.js | 51 +------- client/css/style.css | 3 +- client/index.html | 12 +- client/js/chat.js | 93 ++++++++++++++ client/js/client.js | 299 ------------------------------------------- client/js/models.js | 246 ----------------------------------- lib/models.js | 36 ++++++ lib/server.js | 162 ++++++++--------------- package.json | 1 + 9 files changed, 192 insertions(+), 711 deletions(-) create mode 100644 client/js/chat.js delete mode 100644 client/js/client.js delete mode 100644 client/js/models.js create mode 100644 lib/models.js diff --git a/app.js b/app.js index 685fe12d..d396b162 100644 --- a/app.js +++ b/app.js @@ -1,56 +1,11 @@ var argv = require("commander") .option("-p, --port ", "port to use", parseInt) - .parse(process.argv); + .parse(process.argv); PORT = 80; // Default port. if (argv.port) { PORT = argv.port; } -// Run the server! -var server = new (require("./lib/server.js"))(); -server.listen(PORT); - -// Temporary data - -var models = require("./client/js/models.js"); - -var network = new models.Network; -server.networks.push(network); - -var channel_1 = new models.Channel; -var channel_2 = new models.Channel; - -network.channels.push(channel_1); -network.channels.push(channel_2); - -network.nick = "user"; -network.address = "irc.freenode.org"; - -channel_1.name = "irc.freenode.org"; -channel_1.type = "network"; - -channel_2.name = "#chan"; - -var user_1 = new models.User; -var user_2 = new models.User; - -user_1.name = "john"; -user_2.name = "jane"; - -channel_2.users.push(user_1); -channel_2.users.push(user_2); - -var message_1 = new models.Message; -var message_2 = new models.Message; - -message_1.time = "00:00"; -message_1.user = "john"; -message_1.text = "Hi!"; - -message_2.time = "00:00"; -message_2.user = "jane"; -message_2.text = "Hello!"; - -channel_2.messages.push(message_1); -channel_2.messages.push(message_2); +// Run the server. +(require("./lib/server.js")).listen(PORT); diff --git a/client/css/style.css b/client/css/style.css index f4eaa1b6..65992539 100644 --- a/client/css/style.css +++ b/client/css/style.css @@ -40,8 +40,7 @@ h2 { #sidebar .channel:hover { color: #999; } -#sidebar .network { - color: #000; +#sidebar .channel.network { margin-top: 10px; overflow: hidden; } diff --git a/client/index.html b/client/index.html index 35402ff5..0203d051 100644 --- a/client/index.html +++ b/client/index.html @@ -12,7 +12,7 @@ - - - - + diff --git a/client/js/chat.js b/client/js/chat.js new file mode 100644 index 00000000..de6f01ff --- /dev/null +++ b/client/js/chat.js @@ -0,0 +1,93 @@ +$(function() { + var socket = io.connect(""); + socket.on( + "event", + function(event) { + View[event.action](event); + } + ); + + var chat = $("#chat"); + var sidebar = $("#sidebar"); + + // Templates + var networks = $("#networks").html(); + var channels = $("#channels").html(); + var messages = $("#messages").html(); + var users = $("#users").html() + + var View = {}; + + View.redraw = function(event) { + if (event.data == undefined || event.data == []) { + return; + } + chat.html(""); + event.data.forEach(function(network) { + chat.append(Mustache.render(channels, network, { + users: users, + messages: messages + })); + }); + sidebar.html( + Mustache.render(networks, { + networks: event.data + }) + ); + }; + + View.add = function(event) { + var target = ""; + var render = ""; + switch (event.type) { + case "user": + target = ".users"; + render = Mustache.render( + $("#users").html(), {users: event.data} + ); + break; + case "message": + target = ".messages"; + render = Mustache.render( + $("#messages").html(), {messages: event.data} + ); + break; + } + if (target != "") { + target = $("[data-id='" + event.target + "'] " + target); + target.append(render); + } + }; + + View.remove = function(event) { + $("[data-id='" + event.target + "']").remove(); + }; + + View.change = function(event) { + // .. + }; + + chat.on("submit", "form", function() { + var input = $(this).find(".input"); + var text = input.val(); + if (text != "") { + input.val(""); + socket.emit("input", { + id: input.data("target"), + text: text + }); + } + }); + + sidebar.on("click", ".channel", function() { + chat.find(".window[data-id='" + $(this).data("id") + "']") + .bringToTop(); + }); +}); + +(function() { + var highest = 1; + $.fn.bringToTop = function() { + this.css('z-index', highest++); + }; +})(); diff --git a/client/js/client.js b/client/js/client.js deleted file mode 100644 index b2596f79..00000000 --- a/client/js/client.js +++ /dev/null @@ -1,299 +0,0 @@ -/** - * The Client class. - * - * @public - */ - -function Client() { - - /** - * Self reference. - * - * @private - */ - - var self = this; - - /** - * The sidebar view. - * - * @type {Sidebar} - * @private - */ - - var sidebar = new views.Sidebar(); - - /** - * The chat view. - * - * @type {Chat} - * @private - */ - - var chat = new views.Chat(); - - /** - * The active socket. - * - * @type {Socket} - * @private - */ - - var socket; - - /** - * List of networks. - * - * @type {Array} - * @private - */ - - var networks = []; - - /** - * Initialize new socket connections. - * - * @param {Array} data - * @public - */ - - this.init = function(data) { - networks = data; - - chat.render(data); - sidebar.render(data); - - socket.on( - "event", - self.handleEvent - ); - }; - - /** - * Connect to the server via WebSockets and start listening - * for the `init` event. - * - * @param {String} host - * @public - */ - - this.connect = function(host) { - socket = io.connect(host).on("init", self.init) - }; - - /** - * Handle events sent by the server. - * - * @param {Event} event - * @public - */ - - this.handleEvent = function(event) { - // Debug - console.log(event); - }; - - /** - * Set up user events. - * - * @private - */ - - // Handle window focus. - sidebar.element.on("click", ".channel", function(e) { - e.preventDefault(); - var target = $(this).data("id"); - chat.element.find(".window[data-id='" + target + "']") - .bringToTop(); - }); - - // Emit events on user input. - chat.element.on("submit", "form", function() { - var form = $(this); - var input = form.find(".input"); - if (input.val() != "") { - var text = input.val(); - input.val(""); - socket.emit("input", { - target: form.closest(".window").data("id"), - text: text - }); - } - }); - -}; - -/** - * Views namespace. - * - * @namespace - */ - -var views = {}; - -/** - * Sidebar view. - * - * @public - */ - -views.Sidebar = function() { - - /** - * Template container. - * - * @private - */ - - var tpl = { - networks: $("#networks").html() - }; - - /** - * This is the target element where we will - * render the view. - * - * @type {jQuery.Object} - * @public - */ - - this.element = $("#sidebar"); - - /** - * Render the view. - * - * @param {Array} networks - * @public - */ - - this.render = function(networks) { - this.element.html(Mustache.render(tpl.networks, {networks: networks})); - }; - -}; - -/** - * Chat view. - * - * @public - */ - -views.Chat = function() { - - /** - * Template container. - * - * @private - */ - - var tpl = { - channels: $("#channels").html() - }; - - /** - * Partial templates. - * - * @private - */ - - var partials = { - users: $("#users").html(), - messages: $("#messages").html() - }; - - /** - * This is the target element where we will - * render the view. - * - * @type {jQuery.Object} - * @public - */ - - this.element = $("#chat"); - - /** - * Render the view. - * - * @param {Array} networks - * @public - */ - - this.render = function(networks) { - var render = ""; - networks.forEach(function(n) { - render += Mustache.render(tpl.channels, n, partials); - }); - this.element - .html(render); - }; - - /** - * Add to view. - * - * @param {Event} event - * @public - */ - - this.add = function(event) { - var render = ""; - var target = ""; - - switch(event.type) { - - case "channel": - render = Mustache.render( - tpl.channels, {channels: event.data} - ); - break; - - case "message": - target = ".messages"; - render = Mustache.render( - partials.messages, {messages: event.data} - ); - break; - - case "user": - target = ".users"; - render = Mustache.render( - partials.users, {users: event.data} - ); - break; - - } - - if (target == "") { - this.element - .append(render); - } else { - this.element - .find("[data-id='" + event.target + "'] " + target) - .append(render); - } - }; - - /** - * Remove from view. - * - * @param {Int} id - * @public - */ - - this.remove = function(id) { - this.element.find("[data-id='" + id + "']").remove(); - }; - -}; - -/** - * Bring element to top of the z-index stack. - * - * @public - */ - -(function() { - var highest = 1; - $.fn.bringToTop = function() { - this.css('z-index', highest++); - }; -})(); diff --git a/client/js/models.js b/client/js/models.js deleted file mode 100644 index 30201557..00000000 --- a/client/js/models.js +++ /dev/null @@ -1,246 +0,0 @@ -(function(exports) { - - /** - * Declare the namespace. - * - * @namespace - */ - - var models = - typeof window === "undefined" ? exports - : window.models = {}; - - /** - * Use this to create unique identifiers. - * - * @type {Int} - * @private - */ - - var id = 0; - - /** - * Network model. - * - * @public - */ - - models.Network = function() { - - /** - * Unique identifier. - * - * @type {Int} - * @public - */ - - this.id = id++; - - /** - * The network address. - * - * @type {String} - * @public - */ - - this.address = ""; - - /** - * List of channels. - * - * @type {Array} - * @public - */ - - this.channels = []; - - /** - * User nickname. - * - * @type {String} - * @public - */ - - this.nick = ""; - - }; - - /** - * Channel model. - * - * @public - */ - - models.Channel = function() { - - /** - * Unique identifier. - * - * @type {Int} - * @public - */ - - this.id = id++; - - /** - * The channel name. - * - * @type {String} - * @public - */ - - this.name = ""; - - /** - * The channel type. - * This property should be either `network` or `channel`. - * - * @type {String} - * @public - */ - - this.type = "channel"; - - /** - * The current channel topic. - * - * @type {String} - * @public - */ - - this.topic = ""; - - /** - * List of users. - * - * @type {Array} - * @public - */ - - this.users = []; - - /** - * List of messages. - * - * @type {Array} - * @public - */ - - this.messages = []; - - }; - - /** - * User model. - * - * @public - */ - - models.User = function() { - - /** - * Unique identifier. - * - * @type {Int} - * @public - */ - - this.id = id++; - - /** - * The user name. - * - * @type {String} - * @public - */ - - this.name = ""; - - }; - - /** - * Message model. - * - * @public - */ - - models.Message = function() { - - /** - * The timestamp. - * - * @type {String} - * @public - */ - - this.time = ""; - - /** - * The content of the message. - * - * @type {String} - * @public - */ - - this.text = ""; - - /** - * The author of the message. - * - * @type {String} - * @public - */ - - this.user = ""; - }; - - /** - * Event model. - * - * Used when pushing changes between the server - * and the clients. - * - * @public - */ - - models.Event = function() { - - /** - * Action to perform. - * - * @type {String} - * @public - */ - - this.action = ""; - - /** - * Model type. - * - * @type {String} - * @public - */ - - this.type = ""; - - /** - * The target network or channel. - * - * @type {Int|String|Object} - * @public - */ - - this.target = ""; - - /** - * The data. - * - * @type {Int|String|Object} - * @public - */ - - this.data = ""; - - }; - -})(this); diff --git a/lib/models.js b/lib/models.js new file mode 100644 index 00000000..83721805 --- /dev/null +++ b/lib/models.js @@ -0,0 +1,36 @@ +var models = exports; +var id = 0; + +models.Network = function() { + this.id = id++; + this.address = ""; + this.nick = ""; + this.channels = []; +}; + +models.Channel = function() { + this.id = id++; + this.name = ""; + this.type = "channel"; + this.topic = ""; + this.users = []; + this.messages = []; +}; + +models.User = function() { + this.id = id++; + this.name = ""; +}; + +models.Message = function() { + this.text = ""; + this.time = ""; + this.user = ""; +}; + +models.Event = function() { + this.action = ""; + this.data = ""; + this.target = ""; + this.type = ""; +}; diff --git a/lib/server.js b/lib/server.js index cd5bb621..b32154c1 100644 --- a/lib/server.js +++ b/lib/server.js @@ -1,115 +1,63 @@ -/** - * Module dependencies. - */ - +var _ = require("lodash"); var connect = require("connect"); var io = require("socket.io"); +var models = require("./models.js"); -// Local library. -var models = require("../client/js/models.js"); +exports.listen = listen; -/** - * Export module. - */ +var sockets; +var networks = []; -module.exports = Server; +var network = new models.Network; +var chan = _.assign(new models.Channel, { + name: "Network", + type: "network" +}); -/** - * The Server class. - * - * @public - */ - -function Server() { - - /** - * Self reference. - * - * @private - */ - - var self = this; - - /** - * Active sockets managed by socket.io. - * - * @type {Object} - * @private - */ - - var sockets; - - /** - * List of networks. - * - * @type {Array} - * @public - */ - - this.networks = []; - - /** - * Start the server and listen for connections - * on the specified port. - * - * @param {Int} port - * @public - */ - - this.listen = function(port) { - var app = connect() - .use(connect.static("client")) - .listen(port); - - sockets = - io.listen(app).on("connection", this.init) - .sockets; - }; - - /** - * Initiate new socket connections. - * - * @param {Socket} socket - * @public - */ - - this.init = function(socket) { - sockets.emit( - "init", - self.networks - ); - socket.on( - "input", - function(input) { - self.handleUserInput(input) - } - ); - }; - - /** - * Handle incoming inputs sent from clients. - * - * @param {String} input - * @public - */ - - this.handleUserInput = function(input) { - var text = input.text; - if (text.charAt(0) != "/") { - console.log("MESSAGE: " + text); - return; - } - - var args = text.substr(1).split(" "); - var cmd = args[0].toUpperCase(); - - switch (cmd) { - - default: - console.log("COMMAND: " + cmd); - break; - - } - }; +network.channels.push(chan); +networks.push(network); +function listen(port) { + var http = connect() + .use(connect.static("client")) + .listen(port); + sockets = io.listen(http).sockets; + sockets.on("connection", function(socket) { + init(socket); + }); +}; + +function init(socket) { + socket.on( + "input", + function(input) { + handleUserInput(input) + } + ); + sockets.emit("event", _.assign(new models.Event, { + action: "redraw", + data: networks + })); +}; + +function handleUserInput(input) { + var id = input.id; + var text = input.text; + + var message = _.assign(new models.Message, {text: text}); + var event = _.assign(new models.Event, { + action: "add", + type: "message", + data: message, + target: id + }); + + sockets.emit("event", event); + + _.each(networks, function(n) { + var chan = _.findWhere(n.channels, {id: id}); + if (chan !== "undefined") { + chan.messages.push(message); + } + }); }; diff --git a/package.json b/package.json index 5c5807eb..6e80df36 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "dependencies": { "commander": "2.1.0", "connect": "2.13.0", + "lodash": "2.4.1", "socket.io": "0.9.16" } }