Implemented views

This commit is contained in:
Mattias Erming 2014-03-05 05:46:16 -08:00
parent 3fe9022d3e
commit b1023bf76c
8 changed files with 494 additions and 27 deletions

49
app.js
View File

@ -8,6 +8,49 @@ if (argv.port) {
} }
// Run the server! // Run the server!
var Server = var server = new (require("./lib/server.js"))();
new (require("./lib/server.js"))() server.listen(PORT);
.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);

129
client/css/style.css Normal file
View File

@ -0,0 +1,129 @@
html,
body {
font: 12px Consolas, monospace;
height: 100%;
margin: 0;
}
a {
color: inherit;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
ul,
li {
list-style: none;
margin: 0;
padding: 0;
}
h1,
h2 {
font: inherit;
margin: 0;
}
#sidebar {
background: #f0f0f0;
border-right: 1px solid #ccc;
float: left;
height: 100%;
line-height: 20px;
width: 199px;
}
#sidebar .channel {
clear: both;
color: #f00;
float: left;
margin-left: 20px;
}
#sidebar .network {
color: #000;
margin-top: 10px;
overflow: hidden;
}
#chat {
bottom: 0;
left: 200px;
line-height: 16px;
min-width: 400px;
overflow: hidden;
position: absolute;
right: 0;
top: 0;
}
#chat form {
border-top: 1px solid #ccc;
bottom: 0;
height: 26px;
left: 0;
position: absolute;
right: 0;
}
#chat form input {
border: 0;
font: inherit;
height: 26px;
margin: 0;
outline: none;
padding: 0 6px;
width: 100%;
}
#chat .channel,
#chat .network {
background: #fff;
height: 100%;
position: absolute;
width: 100%;
}
#chat .network .users {
display: none;
}
#chat .network .messages {
right: 0;
}
#chat .title {
background: #f5f5f5;
border-bottom: 1px solid #eee;
color: #333;
font-size: 18px;
height: 36px;
line-height: 36px;
padding-left: 10px;
position: absolute;
top: 0;
width: 100%;
}
#chat .users {
border-left: 1px solid #ccc;
float: right;
height: 100%;
margin-top: 36px;
overflow-y: auto;
padding-top: 6px;
width: 159px;
}
#chat .users .user {
clear: both;
color: #f00;
float: left;
padding: 0px 8px;
}
#chat .messages {
left: 0;
overflow-y: auto;
padding: 6px 0;
position: absolute;
right: 160px;
top: 36px;
z-index: 0;
bottom: 26px;
}
#chat .messages .message {
padding: 0 8px;
}
#chat .messages .time {
color: #bbb;
}
#chat .messages .user {
color: #f00;
}

View File

@ -1,13 +1,66 @@
<!doctype html> <!doctype html>
<html> <html>
<head></head> <head>
<link rel="stylesheet" href="/css/style.css"/>
</head>
<body> <body>
Hello, world. <aside id="sidebar"></aside>
<div id="chat"></div>
<script type="text/html" id="networks">
{{#networks}}
<div class="network">
{{#channels}}
<div class="channel {{type}}" data-id="{{id}}">
{{name}}
</div>
{{/channels}}
</div>
{{/networks}}
</script>
<script type="text/html" id="channels">
{{#channels}}
<div class="window {{type}}" data-id="{{id}}">
<h1 class="title">{{name}}</h1>
<div class="users">
{{> users}}
</div>
<div class="messages">
{{> messages}}
</div>
<form onSubmit="return false;">
<input type="text"/>
<input type="submit" style="display: none;"/>
</form>
</div>
{{/channels}}
</script>
<script type="text/html" id="users">
{{#users}}
<div class="user" data-id="{{id}}">
{{name}}
</div>
{{/users}}
</script>
<script type="text/html" id="messages">
{{#messages}}
<div class="message">
<span class="time">{{time}}</span>
<span class="user">{{user}}</span>
{{text}}
</div>
{{/messages}}
</script>
<script src="//code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="/socket.io/socket.io.js"></script> <script src="/socket.io/socket.io.js"></script>
<script src="/js/lib/mustache.min.js"></script>
<script src="/js/lib/jquery-2.1.0.min.js"></script>
<script src="/js/models.js"></script> <script src="/js/models.js"></script>
<script src="/js/client.js"></script> <script src="/js/client.js"></script>

View File

@ -15,13 +15,22 @@ function Client() {
var self = this; var self = this;
/** /**
* List of networks. * The sidebar view.
* *
* @type {Array<Network>} * @type {Sidebar}
* @public * @private
*/ */
this.networks = []; var sidebar = new views.Sidebar();
/**
* The chat view.
*
* @type {Chat}
* @private
*/
var chat = new views.Chat();
/** /**
* The active socket. * The active socket.
@ -32,18 +41,39 @@ function Client() {
this.socket; this.socket;
/**
* List of networks.
*
* @type {Array<Network>}
* @public
*/
this.networks = [];
/**
* Initialize new socket connections.
*
* @param {Array<Network>}
* @public
*/
this.init = function(networks) {
this.networks = networks;
this.socket.on("event", self.handleEvent);
chat.render(this.networks);
sidebar.render(this.networks);
};
/** /**
* Connect to the server via WebSockets and start listening * Connect to the server via WebSockets and start listening
* to events sent by the server. * for the `init` event.
* *
* @param {String} host * @param {String} host
* @public * @public
*/ */
this.connect = function(host) { this.connect = function(host) {
this.socket = io.connect(host) this.socket = io.connect(host).on("init", self.init)
.on("init", function(networks) { self.networks = networks; })
.on("event", this.handleEvent);
}; };
/** /**
@ -57,4 +87,156 @@ function Client() {
// Debug // Debug
console.log(event); console.log(event);
}; };
};
/**
* Views namespace.
*
* @namespace
*/
var views = {};
/**
* Sidebar view.
*
* @public
*/
views.Sidebar = function() {
/**
* Template container.
*
* @private
*/
var tpl = {
networks: $("#networks").html()
};
/**
* Render the view.
*
* @param {Array<Network>} networks
* @public
*/
this.render = function(networks) {
$("#sidebar").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<Network>} 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();
};
}; };

4
client/js/lib/jquery-2.1.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

1
client/js/lib/mustache.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,15 @@
typeof window === "undefined" ? exports typeof window === "undefined" ? exports
: window.models = {}; : window.models = {};
/**
* Use this to create unique identifiers.
*
* @type {Int}
* @private
*/
var id = 0;
/** /**
* Network model. * Network model.
* *
@ -18,6 +27,15 @@
models.Network = function() { models.Network = function() {
/**
* Unique identifier.
*
* @type {Int}
* @public
*/
this.id = id++;
/** /**
* The network address. * The network address.
* *
@ -36,6 +54,15 @@
this.channels = []; this.channels = [];
/**
* User nickname.
*
* @type {String}
* @public
*/
this.nick = "";
}; };
/** /**
@ -46,6 +73,15 @@
models.Channel = function() { models.Channel = function() {
/**
* Unique identifier.
*
* @type {Int}
* @public
*/
this.id = id++;
/** /**
* The channel name. * The channel name.
* *
@ -55,6 +91,16 @@
this.name = ""; this.name = "";
/**
* The channel type.
* This property should be either `network` or `channel`.
*
* @type {String}
* @public
*/
this.type = "channel";
/** /**
* The current channel topic. * The current channel topic.
* *
@ -92,6 +138,15 @@
models.User = function() { models.User = function() {
/**
* Unique identifier.
*
* @type {Int}
* @public
*/
this.id = id++;
/** /**
* The user name. * The user name.
* *
@ -171,11 +226,11 @@
/** /**
* The target network or channel. * The target network or channel.
* *
* @type {String} * @type {Int|String|Object}
* @public * @public
*/ */
this.target = undefined; this.target = "";
/** /**
* The data. * The data.

View File

@ -30,15 +30,6 @@ function Server() {
var self = this; var self = this;
/**
* List of networks.
*
* @type {Array<Network>}
* @public
*/
this.networks = [];
/** /**
* Active sockets managed by socket.io. * Active sockets managed by socket.io.
* *
@ -48,6 +39,15 @@ function Server() {
this.sockets; this.sockets;
/**
* List of networks.
*
* @type {Array<Network>}
* @public
*/
this.networks = [];
/** /**
* Start the server and listen for connections * Start the server and listen for connections
* on the specified port. * on the specified port.