Skip to content

Instantly share code, notes, and snippets.

@mattneary
Created December 11, 2012 00:33
Show Gist options
  • Save mattneary/4254672 to your computer and use it in GitHub Desktop.
Save mattneary/4254672 to your computer and use it in GitHub Desktop.
Simple JS Chat displaying Prototypes
<!-- Socket.io Library Include -->
<script src="https://raw.github.com/LearnBoost/socket.io-client/master/dist/socket.io.min.js"></script>
<!-- Page Structure -->
<ol id="messages"></ol>
<input type="text" id="message">
<input type="button" id="send" value="Send">
<!-- Styling -->
<style>
.msg_to, .msg_from {
list-style: none;
display: block;
padding: 3px;
}
.msg_to {
background: gray;
}
.msg_from {
background: green;
}
</style>
<script>
// base UI class
var View = (function() {
var View = function(el) {
this.view = el;
};
View.prototype = {
content: function(text) {
if( arguments.length ) {
this.view.innerHTML = text;
} else {
return this.view.innerHTML;
}
}, val: function(text) {
if( arguments.length ) {
this.view.value = text;
} else {
return this.view.value;
}
}, insert: function(insertionView) {
this.view.appendChild(insertionView.view);
}, listen: function(event, cb) {
this.view.addEventListener(event, cb);
}, append: function(view) {
this.view.appendChild(view.view);
}
};
return View;
})();
// Models
var MessageStore = (function() {
var MessageStore = function() {
this.messages = [];
};
MessageStore.prototype = {
insertSent: function(message) {
this.messages.push(new Message(message, "from"));
}, insertReceived: function(message) {
this.messages.push(new Message(message, "to"));
}, each: function(cb) {
this.messages.map(cb);
}
};
return MessageStore;
})();
var Message = (function() {
var Message = function(content, direction) {
this._content = content;
this._direction = direction;
};
Message.prototype = {
content: function() {
return this._content;
}, direction: function() {
return this._direction;
}
};
return Message;
})();
// Views
var MessageView = (function() {
var MessageView = function(message) {
// make an `li` with traits based on message
var li = document.createElement("li");
li.innerHTML = message.content();
li.className = "msg_"+message.direction();
this.view = li;
};
MessageView.prototype = View.prototype; // inherit
return MessageView;
})();
var MessageListView = (function() {
var MessageListView = function(el) {
this.view = el;
};
MessageListView.prototype = View.prototype; // inherit
MessageListView.prototype.render = function(messageStore) {
// set list content to every message in store
var view = this;
view.content("");
messageStore.each(function(message, index) {
view.append((new MessageView(message)));
});
};
return MessageListView;
})();
var MessageBoxView = (function() {
var MessageBoxView = function(boxEl, sendEl) {
this.view = boxEl;
this.sendEl = sendEl;
};
MessageBoxView.prototype = View.prototype; // inherit
MessageBoxView.prototype.onSubmit = function(cb) {
(new View(this.sendEl)).listen('click', cb);
};
return MessageBoxView;
})();
// Controllers
var SocketHandler = (function() {
var listeners = {};
var SocketHandler = function(server, channel) {
// on init save channel, make socket and initiate channel
this._channel = channel;
this.socket = io.connect(server, {
'reconnect': true,
'reconnection delay': 500,
'max reconnection attempts': 10
});
this.socket.on(channel, function(packet) {
listeners[packet.event](packet.content);
});
};
SocketHandler.prototype = {
send: function(event, content) {
this.socket.emit(this._channel, {
event: event,
content: content
});
}, listen: function(event, cb) {
listeners[event] = cb;
}, init: function() {
this.socket.emit('initiate', { channel: this._channel });
}
};
return SocketHandler;
})();
var Messenger = function(boxView, listView) {
// `main` controller has no class methods
var messageStore = new MessageStore(),
socketHandler = new SocketHandler('http://localhost:8081', 'group');
socketHandler.init();
socketHandler.listen('message', function(content) {
messageStore.insertReceived(content);
listView.render(messageStore);
});
boxView.onSubmit(function(event) {
var content = boxView.val();
messageStore.insertSent(content);
listView.render(messageStore);
socketHandler.send('message', content);
});
};
// Setup
(function() {
// get document elements
var messageListEl = document.getElementById('messages');
var messageBoxEl = document.getElementById('message');
var messageSendEl = document.getElementById('send');
// abstract over these elements
var messageBoxView = new MessageBoxView(messageBoxEl, messageSendEl);
var messageListView = new MessageListView(messageListEl);
// initiate a controller of these views
Messenger(messageBoxView, messageListView);
})();
</script>
var http = require('http'),
fs = require('fs');
var io = require('socket.io').listen(8081);
io.sockets.on('connection', function (socket) {
var channels = [], channelUserGroups = {};
var handler = function(channel) {
// rebroadcast data to users on an arbitrary channel
return function(data) {
channelUserGroups[channel].map(function(socket){ socket.emit(channel, data); });
};
};
var listen = function(channel) {
socket.on(channel, handler(channel));
};
socket.on('initiate', function (data) {
// listen to a channel if not already
if( channels.indexOf(data.channel) == -1 ) {
listen(data.channel);
channels.push(data.channel);
}
channelUserGroups[data.channel] = channelUserGroups[data.channel] || [];
channelUserGroups[data.channel].push(socket);
});
// TODO: handle logoff
});
http.createServer(function(req, res) {
res.writeHead(200, {
'Content-Type': 'text/html'
});
fs.createReadStream(__dirname + '/index.html').pipe(res);
}).listen(8080);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment