Skip to content

Instantly share code, notes, and snippets.

@rodrigo-frenk
Last active February 16, 2017 04:16
Show Gist options
  • Save rodrigo-frenk/43aa1738e0e6d3f51493ce92198bea23 to your computer and use it in GitHub Desktop.
Save rodrigo-frenk/43aa1738e0e6d3f51493ce92198bea23 to your computer and use it in GitHub Desktop.
socket.io chat
* {
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;
}
<!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>
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