Skip to content

Instantly share code, notes, and snippets.

@frnsys
Forked from tresbailey/(client)controller.js
Created July 28, 2012 00:38
Show Gist options
  • Save frnsys/3191214 to your computer and use it in GitHub Desktop.
Save frnsys/3191214 to your computer and use it in GitHub Desktop.
Chat App using nodejs for server, socket.io for passing messages to/from the browser, coffeescript for some server-side files (for now), node-redis for persisting chats, express(node) for http wrapping, and jade for templating (for now), and backbone for
var NodeChatController = {
init: function() {
this.socket = io.connect('http://localhost');
var mysocket = this.socket;
this.model = new models.NodeChatModel();
this.view = new NodeChatView({model: this.model, socket: this.socket, el: $('#content')});
var view = this.view;
this.socket.on('message', function(msg) {
console.log('msg rcved'+msg);
view.msgReceived($.parseJSON(msg))
});
this.view.render();
return this;
}
};
$(document).ready(function () {
window.app = NodeChatController.init();
});
!!! 5
html(lang="en")
head
title nodechat
script(type="text/javascript", src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js")
script(type="text/javascript", src="lib/underscore.js")
script(type="text/javascript", src="lib/backbone.js")
script(type="text/javascript", src="/socket.io/socket.io.js")
script(type="text/javascript", src="models.js")
script(type="text/javascript", src="views/views.js")
script(type="text/javascript", src="controllers/controller.js")
body
#heading
h1 nodechat
#content
p
| connected clients
span#client_count 0
p
| Fun Chat Messages
ul#chat_list
form(method="post", action="#", onsubmit="return false;")#messageForm
p
label Name:
input(type="text", name="user_name")
p
label Message:
input(type="text", name="message")
input(type="submit", value="send")
#footer
var ChatView = Backbone.View.extend({
tagName: 'li',
initialize: function(options) {
_.bindAll(this, 'render');
this.model.bind('all', this.render);
},
render: function() {
$(this.el).html( this.model.get("name") + ": " + this.model.get("text"));
return this;
}
});
var ClientCountView = Backbone.View.extend({
initialize: function(options) {
_.bindAll(this, 'render');
this.model.bind('all', this.render);
},
render: function() {
$(this.el).html(" -> " + this.model.get('clients'));
return this;
}
});
var NodeChatView = Backbone.View.extend({
initialize: function(options) {
this.model.chats.bind('add', this.addChat);
this.socket = options.socket;
this.clientCountView = new ClientCountView({ model: new models.ClientCountModel(),
el: $('#client_count')
});
},
events: {
"submit #messageForm": "sendMessage"
},
addChat: function(chat) {
var view = new ChatView({ model: chat });
$('#chat_list').append(view.render().el);
},
msgReceived: function(message) {
switch(message.event) {
case 'initial':
this.model.mport(message.data);
break;
case 'chat':
var newChatEntry = new models.ChatEntry();
newChatEntry.mport(message.data);
this.model.chats.add(newChatEntry);
break;
case 'update':
this.clientCountView.model.mport(message.data);
break;
}
},
sendMessage: function(e) {
var inputField = $('input[name=message]');
var nameField = $('input[name=user_name]');
console.log(inputField);
var chatEntry = new models.ChatEntry({ name: nameField.val(),
text: inputField.val()
});
this.socket.send(JSON.stringify(chatEntry.xport()));
inputField.val('');
}
});
app = require('express').createServer()
jade = require 'jade'
_ = require('underscore')._
Backbone = require 'backbone'
redis = require 'redis'
rc = redis.createClient()
models = require './models'
$ = require('jquery')
app.set 'view engine', 'jade'
app.set 'view options', {layout: false}
app.listen 4000
app.get '/*.(js|css)', (req, res) ->
res.sendfile "./#{ req.url}"
app.get '/', (req, res) ->
res.render 'index'
activeClients = 0
clientCountModel = new models.ClientCountModel {clients: activeClients}
nodeChatModel = new models.NodeChatModel()
rc.lrange 'chatentries', -10, -1, (err, data) ->
if data
_.each data, (jsonChat) ->
chat = new models.ChatEntry()
chat.mport jsonChat
nodeChatModel.chats.add chat
console.log "Revived #{ JSON.stringify nodeChatModel.chats } chats"
else
console.log "No data returned for key"
io = require('socket.io').listen app
io.sockets.on 'connection', (client) ->
console.log "client count mode: #{ JSON.stringify clientCountModel }"
clientCountModel.incrClients()
console.log "client count mode: #{ JSON.stringify clientCountModel }"
client.on 'disconnect', () -> clientDisconnect(client)
client.on 'message', (msg) -> chatMessage(client, io, msg)
console.log "all clients are #{ JSON.stringify nodeChatModel.xport() }"
client.send JSON.stringify({
event: 'initial',
data: nodeChatModel.xport()
})
io.sockets.send JSON.stringify({
event: 'update',
data: clientCountModel.xport()
})
chatMessage = (client, socket, msg) ->
chat = new models.ChatEntry()
console.log "importing chat #{JSON.parse msg }"
chat.mport JSON.parse(msg)
console.log "imported chat #{ chat.get('name') }"
rc.incr 'next.chatentry.id', (err, newId) ->
chat.set {id: newId}
nodeChatModel.chats.add chat
console.log "(#{ client.sessionId}) #{ chat.get('id') } #{ chat.get('name') }: #{ chat.get('text') }"
rc.lpush 'chatentries', chat.xport(), redis.print
rc.bgsave()
console.log "socket increment with #{ JSON.stringify chat }"
emission = { event: 'chat', data: chat.xport() }
console.log "emitting #{ JSON.stringify emission }"
client.broadcast.send JSON.stringify(emission)
clientDisconnect = (client) ->
activeClients -= 1
io.sockets.send JSON.stringify({
event: 'update',
data: clientCountModel.xport()
})
// Generated by CoffeeScript 1.3.3
(function() {
(function() {
_this = this;
var server = false, models;
if (typeof exports !== "undefined" && exports !== null) {
_ = require('underscore')._;
Backbone = require('backbone');
$ = require('jquery');
models = exports;
server = true;
} else {
models = this.models = {};
}
models.ChatEntry = Backbone.Model.extend({});
models.ClientCountModel = Backbone.Model.extend({
defaults: {
clients: 5
},
updateClients: function(clients) {
return this.set({
clients: clients
});
},
incrClients: function() {
clients = this.get('clients');
return this.set({
clients: ++clients
});
}
});
models.NodeChatModel = Backbone.Model.extend({
defaults: {
clientId: 0
},
initialize: function() {
return this.chats = new models.ChatCollection();
}
});
models.ChatCollection = Backbone.Collection.extend({
model: models.ChatEntry
});
Backbone.Model.prototype.xport = function(opt) {
var process, result, settings;
result = {};
settings = _({
recurse: true
}).extend(opt || {});
process = function(targetObj, source) {
targetObj.id = source.id || null;
targetObj.cid = source.cid || null;
targetObj.attrs = source;
return _.each(source, function(value, key) {
if (settings.recurse) {
if (key !== 'collection' && source[key] instanceof Backbone.Collection) {
targetObj.collections = targetObj.collections || {};
targetObj.collections[key] = {};
targetObj.collections[key].models = [] || null;
targetObj.collections[key].id = source[key].id || null;
return _.each(source[key].models, function(mod, index) {
return process(targetObj.collections[key].models[index] = {}, mod);
});
} else if (source[key] instanceof Backbone.Model) {
targetObj.models = targetObj.models || {};
return process(targetObj.models[key] = {}, value);
}
}
});
};
process(result, this);
return result;
};
Backbone.Model.prototype.mport = function(data, silent) {
var process;
process = function(targetObj, data) {
// targetObj is the new instance of the model
// data is the imported JSON object of the server-side instance of that model
targetObj.id = data.id || null;
// Load imported instance's attributes into this new instance
targetObj.set( data.attrs, { silent: silent } );
// If the imported instance contains collections
if ( data.collections ) {
// Iterate over each collection
_.each( data.collections, function(collection, name) {
targetObj[name].id = collection.id || null;
// Iterate over each model in the collection
return _.each( collection.models, function(modelData, index) {
// Add a new model to the collection
/* Note: as long as a model is explicitly defined in the collection,
passing an empty set of params for .add() will create an
and instance of that model */
var newObj = targetObj[name].add( {}, { silent: silent } );
return process(newObj.models[index], modelData);
});
});
}
if ($.type(data.models) !== "undefined") {
return _.each(data.models, function(modelData, name) {
return process(targetObj[name], modelData);
});
}
}
if ($.type(data) == "string") {
process(this, JSON.parse(data));
} else {
process(this, data);
}
return this;
}
}).call(this);
@frnsys
Copy link
Author

frnsys commented Jul 28, 2012

I used your version of this .xport() and .mport() functions since the original didn't work after I upgraded Backbone and Underscore (to 0.9.2 and 1.3.3, respectively). However, I was still having a problem in the .mport() function (newObj was being passed as the full collection to process, when it should have just been a single model from the collection), but it should be working now.

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment