jueves, 5 de marzo de 2020

Chat Privado con NodeJs parte 5 ( Creando estilo a ventana privada ) Final.

Continuando con el proyecto del chat privado con node js, es momento de finalizar, de antemano les agradezco el prestarme su tiempo para leerme y continuar con el proyecto, entrada tras entrada.


Comencemos, Es hora de dar fin al proyecto concluyendo con el estilo a la ventana privada de nuestro chat, para ello, nos vamos a nuestro archivo chatstyle.css agregando los siguientes estilos.

chatstyle.css

body {
    font: 13px Helvetica, Arial;
}
.contentUser {
    border: solid 1px;
    width: 300px;
    position: absolute;
    top: 10px;
    left: 10px;
    border-radius: 5px;
    height: 500px;
}
ul#usersActivos {
    list-style: none;
    padding: 0;
    height: 445px;
    overflow: hidden;
    overflow-y: scroll;
}
.title-users {
    padding: 1em;
    background-color: #2f2f5d;
    text-align: center;
    color: #f1f1f1;
    cursor: move;
}
#usersActivos li {
    border-bottom: solid 1px;
    padding: 0.75em;
    cursor: pointer;
}
#usersActivos li div {
    font-size: 1.15em;
}
.conv-privada {
    border: solid 1px #a0a0a0;
    width: 300px;
    position: absolute;
    left: 300px;
    background-color: #fafafa;
}
.cnt-title {
    padding: 0.5em;
    background-color: #2f2f5d;
    color: white;
    cursor: move;
}
.cnt-conv {
    height: 250px;
    overflow: hidden;
    background-color: #f7f4f4;
    overflow-y: scroll;
    margin-bottom: 0.25em;
}
.cntControl {
    border-top: solid 1px;
}
.conv {
    list-style: none;
    padding: 0.15em;
}
.conv li {
    margin: 0.15em;
    padding: 0.5em;
}

.msg-amigo {
    background-color: #bfbaf7;
}

.msg-propio {
    text-align: right;
    background-color: #a9c9e4;
}
.msg-amigo div, .msg-propio div {
    word-break: break-all;
}
.msg-propio span, .msg-amigo span {
    font-size: 0.75em;
}
.conv-close {
    position: absolute;
    right: 0.75em;
    font-style: initial;
    cursor: pointer;
    font-size: 1.25em;
    top: 0.25em;
}
.conv-finalizada {
    height: 26.15em;
    width: -webkit-fill-available;
    background: #3e3e3e5c;
    position: absolute;
    top: 2em;
}


Hagamos un resumen de lo expuesto.

La estructura del proyecto deberá haber quedado de la siguiente manera.


El archivo chatstyle.css quedará como lo muestro anteriormente, ahora, control.js queda de la siguiente manera:

Control.js

var socket = io();
var btnLogin = document.getElementById('btnLogin');
var lg = document.getElementById('login');
btnLogin.onclick=function(){
 var usr = document.getElementById('user');
 if((usr.value.trim()).length>0){
  socket.emit('connectUser',usr.value);
  window.datos={
   user:usr.value,
   clave: socket.id
  };
  window.document.title = usr.value;
 }
}
socket.on('isLogin',function(value){
 if(typeof window.datos != 'undefined'){
  lg.setAttribute('hidden','');
  var userActivos = document.getElementById('usersActivos');
  userActivos.parentNode.removeAttribute('hidden');
  userActivos.innerHTML = "";
  for(var i = 0; i0){
   ntf.textContent=dta.user+" is writing...";
  }else{
   ntf.textContent='';
  }
 }
});
socket.on('isDisconnected',function(dta){
 if(document.getElementById(dta.clave)!=null){
  var ntf = document.getElementById('isW_'+dta.clave);
  ntf.textContent=dta.user+" is disconnected";
  var block = create({type:'DIV',class:'conv-finalizada'});
  var cnt = document.getElementById(dta.clave);
  cnt.appendChild(block);
 }
});
function create(dta){
 var obj = Object.keys(dta);
 var elemento = document.createElement(dta.type);
 for( var i = 0; i < obj.length; i ++ ){
  if(obj[i]!='type'){
   elemento.setAttribute(obj[i],dta[obj[i]]);
  }
 }
 return elemento;
}
function draggable_2(title, content) {
    var px = 0, py = 0;
    var dragObj = null;
    var obj = content || title;
    obj.style.position = "absolute";
    title.addEventListener('mousedown', function () {
        obj.addEventListener('mousedown', onMouseDown);
        function onMouseDown(a) {
            px = a.layerX;
            py = a.layerY;
            dragObj = obj;
        }
        obj.addEventListener('mouseup', function (e) {
            obj.removeEventListener('mousedown', onMouseDown, false);
            dragObj = null;
        });
        obj.addEventListener('mousemove', function (e) {
            var x = e.pageX - px;
            var y = e.pageY - py;
            if (dragObj == null)
                return;
            dragObj.style.left = x + "px";
            dragObj.style.top = y + "px";
        });
    });
}
function armaVentanaPrivada(clave,to){
 if(document.getElementById(clave)==null){
  var cnt = create({type:'DIV','id':clave,class:'conv-privada'});
  var emClose = create({type:'EM',class:'conv-close'});
  var ttl = create({type:'DIV',class:'cnt-title'});
  var cntCnv = create({type:'DIV',class:'cnt-conv','id':'cntCnv_'+clave});
  var lista = create({type:'UL',class:'conv','id':'conv_'+clave});
  var cntCtr = create({type:'DIV',class:'cntControl'});
  var notificacion = create({type:'DIV',class:'is-writing',id:'isW_'+clave});
  var txtMsg = create({type:'TEXTAREA',name:'entrada',rows:'4','id':'inpMsg_'+clave,'style':'resize:none;width:225px;'});
  var btn = create({type:'BUTTON','id':'btn_'+clave,'style':'float: right;padding: 0.7em;margin-top: 0em;padding-top: 1.5em;padding-bottom: 2em;position: absolute;'});
  ttl.textContent=to;
  btn.textContent="Aceptar";
  emClose.textContent='X';
  cntCtr.appendChild(txtMsg);
  cntCtr.appendChild(btn);
  cntCnv.appendChild(lista);
  ttl.appendChild(emClose);
  cnt.appendChild(ttl);
  cnt.appendChild(cntCnv);
  cnt.appendChild(notificacion);
  cnt.appendChild(cntCtr);
  document.body.appendChild(cnt);
  draggable_2(ttl,cnt);
  txtMsg.onkeyup=function(){
   socket.emit('imWriting',{
    user:window.datos.user,
    clave:window.datos.clave,
    length: this.value.length,
    recibe:to
   });
  }
  emClose.onclick = function(){
   cnt.remove();
  }
  btn.onclick = function(){
   if((txtMsg.value.trim()).length>0){
    socket.emit('send_message',{
     recibe:to,
     envia:{user:window.datos.user,clave:window.datos.clave},
     message:txtMsg.value
    });
    agregaMensaje(lista,1,window.datos.user,txtMsg.value, cntCnv);
    txtMsg.value = '';
    txtMsg.focus();
   }
  }
  return {lista:lista,content:cntCnv};
 }else{
  return {lista:document.getElementById('conv_'+clave), content: document.getElementById('cntCnv_'+clave)};
 }
}
function agregaMensaje(ul,cve,de,msg,cntCnv){
 var dvm = create({type:'DIV'});
 var li = create({type:'LI',class:((cve==1)?'msg-propio':'msg-amigo')});
 var spn = create({type:'SPAN'});
 var fd = new Date();
 var time = fd.getHours()+":"+fd.getMinutes()+":"+fd.getSeconds();
 spn.textContent= ((cve==1)?time+" "+de:de+" "+time);
 dvm.textContent= msg;
 li.appendChild(spn);
 li.appendChild(dvm);
 ul.appendChild(li);
 cntCnv.scrollTo(0,cntCnv.scrollHeight);
}
draggable_2(document.getElementById('ttlUsersActivos'), document.getElementById('cntUsersActivos'));


El lado del cliente, es decir el index, debera quedar de la siguiente manera.

index.html

<!DOCTYPE html>
<html lang="en">
<head>
     <meta charset="UTF-8">
     <title>inovania</title>
          <script type="text/javascript" src="/socket.io/socket.io.js"></script>
          <link rel="stylesheet" type="text/css" href="/css/chatstyle.css">
     </head>
     <body>
          <div class="login" id="login">
               <input type="text" id="user" placeholder="UserName"><button id="btnLogin">Aceptar</button>
          </div>
          <div class="contentUser" id="cntUsersActivos" hidden>
               <div class="title-users" id="ttlUsersActivos">Usuarios Activos</div>
               <ul id="usersActivos"></ul>
          </div>
          <script type="text/javascript" src="/js/control.js"></script>
     </body>
</html>





y por ultimo el app.js queda de la siguiente manera.

app.js


var express = require("express");
var app = express();
var http = require("http").createServer(app);
var io = require("socket.io")(http);
var path = require("path");
var users = [];
app.get('/',function(req,res){
 res.sendFile(__dirname+"/pages/index.html");
});
var publicDir = path.join(__dirname,'/');
app.use(express.static(publicDir));
io.on('connection',function(socket){
 socket.on('disconnect',function(){
  var keys =  Object.keys(users);
  var existe = false;
  var disconnected = {};
  for( var i = 0;i < keys.length; i ++ ){
   if( users[keys[i]] == socket.id ){
    disconnected.user = keys[i];
    disconnected.clave = users[keys[i]];
    delete users[keys[i]];
    existe = true;
   }
  }
  if(disconnected.hasOwnProperty('user')){
   io.emit('isDisconnected',disconnected);
  }
  if(existe){
   var nKeys = Object.keys(users);
   var arrRtn = [];
   for( var i = 0;i < nKeys.length; i ++ ){
    arrRtn.push({'user':nKeys[i], 'clave': users[nKeys[i]]});
   }
   io.emit('isLogin',arrRtn);
  }
 });
 socket.on('connectUser',function(user){
  var existe = false;
  var keys =  Object.keys(users);
  var arrRtn=[];
  for( var i = 0;i < keys.length; i ++ ){
   arrRtn.push({'user':keys[i], 'clave': users[keys[i]]});
   if( users[keys[i]] == socket.id ){
    existe = true;
   }
  }
  if(!existe){
   users[user]=socket.id;
   arrRtn.push({'user':user, 'clave': socket.id});
  }
  io.emit('isLogin',arrRtn);
 });
 socket.on('send_message',function(data){
  var socketId = users[data.recibe];
  io.to(socketId).emit("newMessage",data);
 });
 socket.on('imWriting',function(dta){
  var socketId = users[dta.recibe];
  io.to(socketId).emit("isWriting",dta);
 });
});
http.listen(8420,function(){
 console.log('listening');
});



Anterior

Sin mas por el momento, me despido... Te invito a dejar tu comentario, que te parecio el tutorial, si quieres que le agregemos algo mas, o si tienes sugerencias al respecto.


Saludos, hasta la proxima.