Last active
February 16, 2017 04:16
-
-
Save rodrigo-frenk/43aa1738e0e6d3f51493ce92198bea23 to your computer and use it in GitHub Desktop.
socket.io chat
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { | |
outline: 1px solid #def; | |
} | |
ul, li { | |
margin: 0; | |
padding: 0; | |
} | |
li { | |
list-style: none; | |
} | |
.hidden { | |
display: none; | |
} | |
#login-window { | |
margin-top: 30vh; | |
height: 40vh; | |
background-color: #eee; | |
-webkit-box-shadow: 3px 3px 3px rgba(0,0,0,0.4); | |
box-shadow: 3px 3px 3px rgba(0,0,0,0.4); | |
} | |
#chat-window > header, #chat-window > footer { | |
height: 4em; | |
} | |
#chat-window > #users-messages-container { | |
height: calc(100vh - 8em); | |
} | |
@media screen and (min-width: 0px) { | |
#chat-window > header, #chat-window > footer { | |
height: 3em; | |
} | |
#chat-window > #users-messages-container { | |
height: calc(100vh - 6em); | |
} | |
.h-xs-30 { | |
height: 30%; | |
display: block; | |
} | |
.h-xs-70 { | |
height: 70%; | |
display: block; | |
} | |
} | |
@media screen and (min-width: 960px) { | |
.h-md-100 { | |
height: 100%; | |
display: block; | |
} | |
} | |
#chat-window { | |
display: none; | |
} | |
.user .username, | |
.user .number-messages, | |
.message .username, | |
.message .message-text { | |
width: auto; | |
padding: 4px; | |
font-size: 14px; | |
} | |
.user .number-messages { | |
display: none; | |
} | |
.user .number-messages[active] { | |
display: inline-block; | |
margin-bottom: 8px; | |
padding: 4px; | |
background-color: red; | |
/*bdrs*/ | |
border-radius: 50%; | |
/*fz10*/ | |
font-size: 9px; | |
/*fwb*/ | |
font-weight: bold; | |
color: white | |
} | |
.message, .user { | |
padding: 16px; | |
} | |
.message .username { | |
color: #aaa; | |
font-weight: bold; | |
} | |
.message:nth-child(odd) { | |
background-color: #eaeaea; | |
} | |
.message:nth-child(even) { | |
background-color: #fafafa; | |
} | |
.scroll-y { | |
overflow-y: auto; | |
} | |
.notification { | |
font-size: 9px; | |
color: #888; | |
padding: 8px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!doctype html> | |
<html> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<meta http-equiv="X-UA-Compatible" content="ie=edge"> | |
<title>CHATSNAP</title> | |
<link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap.min.css"> | |
<link rel="stylesheet" href="/bower_components/bootstrap/dist/css/bootstrap-theme.min.css"> | |
<link rel="stylesheet" href="/assets/css/base-style.css"> | |
<link rel="stylesheet" href="/assets/css/mi-estilo.css"> | |
</head> | |
<body class=""> | |
<!-- | |
<ul id="messages"></ul> | |
<form id="formulario-nombre" action=""> | |
<input id="n" autocomplete="off"/><button>Send</button> | |
</form> | |
<form id="formulario-mensaje" action=""> | |
<input id="m" autocomplete="off"/><button>Send</button> | |
</form> | |
--> | |
<form | |
id="login-window" | |
class="col-xs-10 col-md-6 col-lg-4 | |
col-xs-offset-1 col-md-offset-3 col-lg-offset-4"> | |
<h1>Bienvenid@</h1> | |
<p>Ingresa tu nombre de usuario</p> | |
<input type="text" placeholder="nombredeusuario"> | |
<button type="submit"> | |
Entrar | |
</button> | |
</form> | |
<div id="chat-window" class="container-fluid"> | |
<!-- header+sidebar+main+footer --> | |
<header class="row"> | |
<div class="col-xs-6 col-md-4 col-lg-3"> | |
<h6> | |
</h6> | |
</div> | |
<div class="col-xs-6 col-md-4 col-lg-3 col-md-offset-4 col-lg-offset-6 text-right"> | |
<button id="button-group-chat"> | |
Chat Grupal | |
</button> | |
</div> | |
</header> | |
<div id="users-messages-container"> | |
<aside id="users" class="col-md-3 h-xs-30 h-md-100 scroll-y"> | |
<ul> | |
<li class="user model hidden"> | |
<span class="username"> | |
username | |
</span> | |
<span class="number-messages"> | |
0 | |
</span> | |
</li> | |
</ul> | |
</aside> | |
<main id="messages" class="col-md-9 h-xs-70 h-md-100 scroll-y"> | |
<ul> | |
<li class="message model hidden"> | |
<span class="username"> | |
username | |
</span> | |
<!-- span.message>lorem16 --> | |
<span class="message-text"> | |
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima similique, provident atque voluptatem accusantium soluta enim. | |
</span> | |
</li> | |
</ul> | |
</main> | |
</div> | |
<footer class="row"> | |
<form id="message-form" action=""> | |
<!-- input#message.col-xs-9.col-md-10.col-lg-11 --> | |
<input type="text" id="message" class="col-xs-9 col-md-10 col-lg-11"> | |
<!-- button.col-xs-3.col-md-2.col-lg-1[type=submit]{Enviar} --> | |
<button class="col-xs-3 col-md-2 col-lg-1" type="submit"> | |
Enviar | |
</button> | |
</form> | |
</footer> | |
</div> | |
<script src="/socket.io/socket.io.js"></script> | |
<script src="/bower_components/jquery/dist/jquery.min.js"></script> | |
<script src="/bower_components/bootstrap/dist/js/bootstrap.min.js"></script> | |
<script> | |
var socket = io(); | |
var currentActiveUsers | |
var targetUserId | |
// Interacciones de usuario | |
$('#login-window').submit(function(){ | |
username = $('#login-window input[type="text"]').val() | |
var payload = { | |
id: socket.id, | |
message: username | |
} | |
socket.emit('set username', payload ) | |
$('#chat-window header h6').html( username ) | |
$('#login-window').fadeOut(300, function(){ | |
$('#chat-window').fadeIn(300) | |
}) | |
return false; | |
}); | |
$('#message-form').submit(function(){ | |
message = $('#message').val() | |
var payload = { | |
id: socket.id, | |
message: message | |
} | |
// si hay un usuario seleccionado, acompañar mensaje con ID de usuario destino | |
if( typeof(targetUserId) != "undefined" ) { | |
payload.targetId = targetUserId | |
} | |
socket.emit('chat message', payload ) | |
$('#message').val('') | |
return false | |
}); | |
// Funciones que responderán a socket.io | |
socket.on('chat message', function(payload){ | |
printMessage({ | |
username: currentActiveUsers[ payload.sourceId ].username, | |
text: payload.message | |
}, 'chat-message' ) | |
}); | |
socket.on('user list changed', function(payload) { | |
currentActiveUsers = payload.activeUsers | |
$('#users ul .user:not(.model)').remove() | |
for(i in currentActiveUsers) { | |
var userHtml = $('.user.model').clone().detach() | |
userHtml.find('.username').html( currentActiveUsers[i].username ) | |
userHtml.attr( 'data-id', currentActiveUsers[i].id ) | |
userHtml.removeClass('hidden model') | |
userHtml.appendTo('#users ul') | |
} | |
setupUserClick() | |
}) | |
socket.on('user login', function(payload) { | |
printMessage({ | |
username: payload.username, | |
text: 'Entró al chat.' | |
}, 'notification' ) | |
}) | |
socket.on('user logout', function(payload) { | |
printMessage({ | |
username: payload.username, | |
text: 'Salió del chat.' | |
}, 'notification' ) | |
}) | |
function printMessage( message, cssClasses ) { | |
newMessage = $('#messages .message.model').clone().detach() | |
newMessage.find('.username').html( message.username ) | |
newMessage.find('.message-text').html( message.text ) | |
newMessage.addClass( cssClasses ) | |
newMessage.removeClass('model hidden') | |
newMessage.appendTo('#messages ul') | |
} | |
function setupUserClick() { | |
// clicar un usuario para abrir conversación con él | |
$('#users .user').click(function(){ | |
// obtener su ID a partir de atributo 'data-id' del 'li' clicado | |
targetUserId = $(this).data('id') | |
console.log( "selected:", targetUserId ) | |
// al abrir conversación con usuario | |
// marcar mensajes como Leidos | |
// mostrar los mensajes previos con ese usuario | |
}) | |
} | |
$('#button-group-chat').click(function(){ | |
targetUserId = undefined; | |
}) | |
// si recibimos mensaje de un usuario | |
// si tenemos la ventana de ese usuario abierta | |
// mostrar mensaje en ventana | |
// de otro modo, | |
// aumentar numero de mensajes no leidos de ese usuario en la lista de usuarios | |
</script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var express = require('express') | |
var app = express() | |
var http = require('http').Server(app); | |
var io = require('socket.io')(http); | |
// línea necesaria para poder servir recursos desde nuestro HTML: | |
// establecer el nombre de una locacion, y mapearla al directorio servido por express | |
app.use('/bower_components', express.static('bower_components') ) | |
app.use('/assets', express.static('public/assets') ) | |
var clients = [] | |
app.get('/', function(req, res){ | |
res.sendFile( __dirname + '/views/index.html') | |
}); | |
// io es un gestor de conexiones: | |
// declararemos funcion "callback" a ejecutarse al conectarse un cliente | |
/* | |
// cada mensaje enviado por un usuario está | |
// estructurado en un Objeto así: | |
payload = { | |
id: id_de_socket, | |
message: "..." | |
} | |
*/ | |
io.on('connection', function(socket){ | |
console.log('a user connected'); | |
clients[socket.id] = { | |
socket: socket, | |
id: socket.id, | |
username: "Sin Nombre", | |
lastLogin: new Date() | |
} | |
socket.on('set username', function(payload){ | |
clients[socket.id].username = payload.message | |
userLogin(socket) | |
userListChanged() | |
}); | |
socket.on('disconnect', function(){ | |
userLogout(socket) | |
userListChanged() | |
}); | |
socket.on('chat message', function(payload){ | |
console.log('message: ' + payload.message); | |
// obtener usuario a partir de la ID de la conexion: | |
// debido a la naturaleza asincrónica de la app, | |
// tendremos que detectar qué socket está activo | |
// utilizando su Id y buscándola en nuestra lista | |
targetId = 0 | |
var messagePayload = { | |
sourceId: payload.id, | |
message: payload.message | |
} | |
if(typeof( payload.targetId ) === "undefined") { | |
console.log( "TYPEOF", typeof( payload.targetId ) ) | |
// mensaje grupal | |
io.emit('chat message', messagePayload ) | |
} else { | |
//mesnaje privado | |
messagePayload.targetId = payload.targetId | |
clients[ payload.targetId ].socket.emit('chat message', messagePayload ) | |
} | |
}); | |
}); | |
http.listen(3000, function(){ | |
console.log('listening on *:3000'); | |
}); | |
function userListChanged() { | |
// recuperar lista de todos los usuarios | |
var activeUsers = getActiveUsers() | |
var payload = { | |
activeUsers: activeUsers | |
} | |
io.emit('user list changed', payload) | |
} | |
function userLogin(socket) { | |
io.emit('user login', getUserPayload(socket)) | |
} | |
function userLogout(socket) { | |
io.emit('user logout', getUserPayload(socket)) | |
delete clients[socket.id] | |
} | |
function getUserPayload(socket) { | |
var payload = { | |
id: socket.id, | |
username: clients[socket.id].username, | |
time: new Date() | |
} | |
return payload | |
} | |
// funciones lógicas | |
function getActiveUsers() { | |
var activeUsersList = {} | |
// popular una nueva lista de clientes | |
for( i in clients ) { | |
// preparar los datos relevantes | |
activeUser = { | |
id: clients[i].id, | |
username: clients[i].username, | |
} | |
// insertar cada usuario en el objeto | |
activeUsersList[ clients[i].id ] = activeUser | |
} | |
return activeUsersList | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment