input handler, better message constructor

This commit is contained in:
Evert Prants 2016-09-23 17:26:31 +03:00
parent 5e1ac8134c
commit 3a648e9584
6 changed files with 285 additions and 72 deletions

View File

@ -114,6 +114,8 @@ body {
position: absolute;
left: 60px;
right: 0;
overflow-x: auto;
overflow-y: hidden;
}
.ircclient #chat .ircwrapper .toolbar .tabby .tab {
display: inline-block;
@ -182,6 +184,7 @@ body {
border-bottom: 1px solid #ddd;
padding: 12px;
display: none;
overflow: hidden;
}
.ircclient #chat .ircwrapper .chatarea .letterbox {
position: absolute;
@ -244,7 +247,7 @@ body {
position: absolute;
margin: 5px 0;
left: 210px;
right: 46px;
right: 55px;
top: 0;
}
.ircclient #chat .ircwrapper .input .inputwrapper input {
@ -255,6 +258,18 @@ body {
border-left: 0;
box-shadow: inset 4px 4px 8px #d8d8d8;
}
.ircclient #chat .ircwrapper .input .sendbutton {
background-image: url("/image/send.svg");
background-repeat: no-repeat;
background-size: contain;
width: 32px;
position: absolute;
height: 32px;
float: right;
top: 5px;
right: 5px;
cursor: pointer;
}
.message.type_simple .timestamp {
color: #696969;
}
@ -275,14 +290,53 @@ body {
.message.type_simple .sender:after {
content: ">";
}
.m_topic .content {
.message.type_simple .arrowin,
.message.type_simple .arrowout {
font-weight: bolder;
}
.message .reason:before,
.message .hostmask:before {
content: "(";
}
.message .reason:after,
.message .hostmask:after {
content: ")";
}
.message .reason:before,
.message .hostmask:before,
.message .reason:after,
.message .hostmask:after {
color: #009606;
font-weight: bold;
}
.message .reason {
color: #bf0000;
}
.message .hostmask {
color: #004c88;
}
.message .arrowin {
color: #00ab00;
}
.message .arrowout {
color: #dc0f00;
}
.message.m_quit,
.message.m_part,
.message.m_kick {
color: #f00;
}
.message.m_join {
color: #008000;
}
.message.m_topic .content {
color: #03a9f4;
font-weight: bold;
}
.m_nick .content {
.message.m_nick .content {
color: #ff9800;
font-weight: bold;
}
.m_action .actionee {
.message.m_action .actionee {
color: #3f51b5;
}

8
public/image/send.svg Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0px" y="0px" viewBox="0 0 495.003 495.003" style="enable-background:new 0 0 495.003 495.003;" xml:space="preserve" width="512px" height="512px">
<g id="XMLID_51_">
<path id="XMLID_53_" d="M164.711,456.687c0,2.966,1.647,5.686,4.266,7.072c2.617,1.385,5.799,1.207,8.245-0.468l55.09-37.616 l-67.6-32.22V456.687z" fill="#FFFFFF"/>
<path id="XMLID_52_" d="M492.431,32.443c-1.513-1.395-3.466-2.125-5.44-2.125c-1.19,0-2.377,0.264-3.5,0.816L7.905,264.422 c-4.861,2.389-7.937,7.353-7.904,12.783c0.033,5.423,3.161,10.353,8.057,12.689l125.342,59.724l250.62-205.99L164.455,364.414 l156.145,74.4c1.918,0.919,4.012,1.376,6.084,1.376c1.768,0,3.519-0.322,5.186-0.977c3.637-1.438,6.527-4.318,7.97-7.956 L494.436,41.257C495.66,38.188,494.862,34.679,492.431,32.443z" fill="#FFFFFF"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -46,9 +46,9 @@
<div class="input">
<div class="my_nickname">Test</div>
<div class="inputwrapper">
<input type="text" id="input">
<input type="text" class="userinput">
</div>
<span class="send"></span>
<span class="sendbutton"></span>
</div>
</div>
</div>

View File

@ -3,7 +3,8 @@ window.irc = {
primaryFrame: null,
timestamps: true,
timestampFormat: "HH:mm:ss",
serverData: {}
serverData: {},
chatType: "simple"
};
window.clientdom = {connector: {}};
@ -124,7 +125,6 @@ Date.prototype.format = function (format, utc){
return format;
};
function removeClass(element, cl) {
let classList = element.className.split(" ");
remove_str(classList, cl);
@ -137,6 +137,44 @@ function addClass(element, cl) {
element.className = classList.join(" ");
}
let composer = {
message: {
simple: function(time, sender, message, type) {
let element = document.createElement('div');
element.className = "message type_simple m_"+type;
if(irc.timestamps)
element.innerHTML += "<span class='timestamp'>"+time.format(irc.timestampFormat)+"</span>&nbsp;";
switch(type) {
case "action":
element.innerHTML += "<span class='asterisk'>*</span>&nbsp;<span class='actionee'>"+sender+"</span>&nbsp;";
element.innerHTML += "<span class='content'>"+message+"</span>";
break;
case "part":
case "quit":
case "kick":
element.innerHTML += "<span class='arrowout'><--</span>&nbsp;<span class='content'><span class='actionee'>"+sender+"</span>";
element.innerHTML += "&nbsp;"+message+"</span>";
break;
case "join":
element.innerHTML += "<span class='arrowin'>--></span>&nbsp;<span class='content'><span class='actionee'>"+sender+"</span>";
element.innerHTML += "&nbsp;"+message+"</span>";
break;
default:
if(sender) {
element.innerHTML += "<span class='sender'>"+sender+"</span>&nbsp;<span class='content'>"+message+"</span>";
} else {
element.innerHTML += "<span class='content'>"+message+"</span>";
addClass(element, "no_sender");
}
break;
}
return element;
}
}
}
/*********************\
|** **|
|** CLASSES **|
@ -187,6 +225,7 @@ class Nicklist {
}
render() {
if(!this.buffer.active) return;
clientdom.nicklist.innerHTML = "";
this.sort();
for(let n in this.nicks) {
@ -197,6 +236,7 @@ class Nicklist {
nickAdd(nickname) {
let newbie = { nickname: nickname, prefix: "", modes: [] }
if(this.getNickIndex(nickname) != null) return;
this.nicks.push(newbie);
this.render();
}
@ -213,7 +253,9 @@ class Nicklist {
else
return;
this.render();
if(!this.buffer.active) return;
let tt = clientdom.nicklist.querySelector('#nick-'+nickname);
if(tt) tt.remove();
}
nickChange(oldNickname, newNickname) {
@ -395,26 +437,7 @@ class Buffer {
}
appendMessage(meta) {
let mesgConstr = document.createElement('div');
mesgConstr.className = "message type_simple m_"+meta.type;
let construct = "";
if(irc.timestamps)
construct += "<span class='timestamp'>"+meta.time.format(irc.timestampFormat)+"</span>&nbsp;";
if(meta.sender != null && meta.type != "action") {
construct += "<span class='sender'>"+meta.sender+"</span>&nbsp;";
} else {
construct += "<span class='asterisk'>*</span>&nbsp;";
addClass(mesgConstr, "no_sender");
}
if(meta.type == "action")
construct += "<span class='actionee'>"+meta.sender+"</span>&nbsp;<span class='content'>"+meta.message+"</span>";
else
construct += "<span class='content'>"+meta.message+"</span>";
mesgConstr.innerHTML = construct;
let mesgConstr = composer.message[irc.chatType](meta.time, meta.sender, meta.message, meta.type);
clientdom.letterbox.appendChild(mesgConstr);
let lFactor = clientdom.letterbox.offsetHeight + clientdom.letterbox.scrollTop
@ -545,12 +568,42 @@ class IRCConnector {
}
}
class InputHandler {
constructor() {
this.history = [];
clientdom.input.onkeyup = (evt) => {
let key = evt.keyCode || evt.which || evt.charCode || 0;
if (key == 13) {
this.handleInput();
}
}
clientdom.send.onclick = (e) => {
this.handleInput();
}
}
handleInput() {
let inp = clientdom.input.value;
let buf = irc.chat.getActiveBuffer();
if(!buf) return;
if(inp.trim() == "") return;
irc.socket.emit("userinput", {target: buf.name, server: buf.server, message: inp, splitup: inp.split(" ")});
this.history.push(inp);
clientdom.input.value = "";
}
}
class IRCChatWindow {
constructor() {
this.buffers = [];
clientdom.frame.style.display = "none";
this.firstServer = true;
this.currentBuffer = null;
this.input_handler = new InputHandler();
}
getBufferByName(buffername) {
@ -730,6 +783,46 @@ class IRCChatWindow {
buf.addMessage("Topic of "+channel+ " is \""+topic+"\"", null, "topic");
}
handleQuit(server, user, reason) {
let buffers = this.getBuffersByServer(server);
for(let i in buffers) {
let buffer = buffers[i];
if(buffer.type != "channel") continue;
if(buffer.nicklist.getNickIndex(user.nickname) == null) continue;
buffer.nicklist.nickRemove(user.nickname);
buffer.addMessage("<span class='hostmask'>"+user.username+"@"+user.hostname+
"</span> has quit <span class='reason'>"+reason+"</span>", user.nickname, "quit");
}
}
handleJoin(server, user, channel) {
let buffer = this.getBufferByServerName(server, channel);
if(!buffer) return;
buffer.addMessage("<span class='hostmask'>"+user.username+"@"+user.hostname+"</span> has joined "+channel, user.nickname, "join");
buffer.nicklist.nickAdd(user.nickname);
}
handleLeave(server, user, channel, reason, kicker) {
let buffer = this.getBufferByServerName(server, channel);
if(!buffer) return;
if(kicker)
buffer.addMessage("has kicked "+user+" <span class='reason'>"+reason+"</span>", kicker.nickname, "part");
else
buffer.addMessage("<span class='hostmask'>"+user.username+"@"+user.hostname+"</span> has left "+
channel+(reason != null ? "<span class='reason'>"+reason+"</span>" : ""), user.nickname, "part");
if(kicker)
buffer.nicklist.nickRemove(user);
else
buffer.nicklist.nickRemove(user.nickname);
}
render(buffer) {
let activeNow = this.getActiveBuffer();
@ -758,10 +851,12 @@ window.onload = function() {
clientdom.connector['port'] = clientdom.connector.form.querySelector('#port');
clientdom['tabby'] = irc.primaryFrame.querySelector('.tabby')
clientdom['frame'] = irc.primaryFrame.querySelector('#chat');
clientdom['chat'] = clientdom.frame.querySelector('.chatarea');
clientdom['letterbox'] = clientdom.frame.querySelector('.letterbox');
clientdom['nicklist'] = clientdom.frame.querySelector('.nicklist');
clientdom['currentNickname'] = clientdom.frame.querySelector('.my_nickname');
clientdom['input'] = clientdom.frame.querySelector('.userinput');
clientdom['send'] = clientdom.frame.querySelector('.sendbutton');
clientdom['chat'] = clientdom.frame.querySelector('.chatarea');
clientdom['topicbar'] = clientdom.chat.querySelector('.topicbar');
irc.socket = io.connect('http://localhost:8080');
@ -786,10 +881,21 @@ window.onload = function() {
irc.chat.newServerBuffer(data);
break;
case "event_join_channel":
irc.chat.createBuffer(data.server, data.name, "channel", true);
if(data.user.nickname == irc.serverData[data.server].my_nick)
irc.chat.createBuffer(data.server, data.channel, "channel", true);
irc.chat.handleJoin(data.server, data.user, data.channel);
break;
case "event_kick_channel":
irc.chat.handleLeave(data.server, data.kickee, data.channel, data.reason, data.user);
break;
case "event_part_channel":
irc.chat.handleLeave(data.server, data.user, data.channel, data.reason);
break;
case "event_quit":
irc.chat.handleQuit(data.server, data.user, data.reason);
break;
case "message":
irc.chat.messageBuffer(data.to, data.server, {message: data.message, type: data.messageType, from: data.from});
irc.chat.messageBuffer(data.to, data.server, {message: data.message, type: data.messageType, from: data.user.nickname});
break;
case "channel_nicks":
irc.chat.buildNicklist(data.channel, data.server, data.nicks);

View File

@ -105,6 +105,8 @@ body
position: absolute;
left: 60px;
right: 0;
overflow-x: auto;
overflow-y: hidden;
.tab
display: inline-block;
min-width: 60px;
@ -164,6 +166,7 @@ body
border-bottom: 1px solid #ddd;
padding: 12px;
display: none;
overflow: hidden;
.letterbox
position: absolute;
top: 0;
@ -213,22 +216,34 @@ body
width: 183px;
text-overflow: clip;
.inputwrapper
display: inline-block;
position: absolute;
margin: 5px 0;
left: 210px;
right: 46px;
top: 0;
display: inline-block
position: absolute
margin: 5px 0
left: 210px
right: 55px
top: 0
input
width: 100%;
padding: 6px;
font-size: 120%;
border: 1px solid #929292;
border-left: 0;
box-shadow: inset 4px 4px 8px #d8d8d8;
width: 100%
padding: 6px
font-size: 120%
border: 1px solid #929292
border-left: 0
box-shadow: inset 4px 4px 8px #d8d8d8
.sendbutton
background-image: url(/image/send.svg);
background-repeat: no-repeat;
background-size: contain;
width: 32px;
position: absolute;
height: 32px;
float: right;
top: 5px;
right: 5px;
cursor: pointer;
.message.type_simple
.message
&.type_simple
.timestamp
color: #696969;
&:before
@ -243,14 +258,34 @@ body
content: "<";
&:after
content: ">";
.arrowin, .arrowout
font-weight: bolder;
.m_topic .content
.reason, .hostmask
&:before
content: "(";
&:after
content: ")";
&:before, &:after
color: #009606;
font-weight: bold;
.reason
color: #bf0000;
.hostmask
color: #004c88;
.arrowin
color: #00ab00;
.arrowout
color: #dc0f00;
&.m_quit, &.m_part, &.m_kick
color: red;
&.m_join
color: green;
&.m_topic .content
color: #03A9F4;
font-weight: bold;
.m_nick .content
&.m_nick .content
color: #FF9800;
font-weight: bold;
.m_action .actionee
&.m_action .actionee
color: #3f51b5;

View File

@ -23,6 +23,10 @@ io.sockets.on('connection', function (socket) {
console.log('clientID: '+socket.id+' connection: ', socket.request.connection._peername);
connections[socket.id] = {}
socket.on('userinput', function(data) {
console.log(data);
})
socket.on('disconnect', function() {
for (let d in connections[socket.id]) d.disconnect("Client exited");
@ -44,26 +48,32 @@ io.sockets.on('connection', function (socket) {
setTimeout(function() {
console.log("fake channel");
socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, name: "#channel"});
socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, channel: "#channel", user: {nickname: connectiondata.nickname, username: "teemant", hostname: socket.request.connection._peername.address}});
socket.emit('act_client', {type: 'channel_nicks', channel: "#channel", server: connectiondata.server, nicks: ["+horse", "@scoper", "@aspire", "+random", "lol"]});
socket.emit('act_client', {type: 'channel_topic', channel: "#channel", server: connectiondata.server, topic: "This channel is the best."});
socket.emit('act_client', {type: 'channel_topic', channel: "#channel", server: connectiondata.server, set_by: "horse", time: Date.now()});
socket.emit('act_client', {type: 'message', messageType: "privmsg", server: connectiondata.server, to: "#channel", from: "horse", message: "I like ponies"});
socket.emit('act_client', {type: 'message', messageType: "privmsg", server: connectiondata.server, to: "#channel", user: {nickname: "horse"}, message: "I like ponies"});
setTimeout(function() {
socket.emit('act_client', {type: 'nick_change', server: connectiondata.server, nick: "horse", newNick: "pony"});
}, 2000)
setTimeout(function() {
socket.emit('act_client', {type: 'message', messageType: "action", server: connectiondata.server, to: "#channel", from: "pony", message: "Is the greatest pony fan"});
socket.emit('act_client', {type: 'message', messageType: "action", server: connectiondata.server, to: "#channel", user: {nickname: "pony"}, message: "Is the greatest pony fan"});
}, 3000)
setTimeout(function() {
socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, name: "#poni"});
socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, channel: "#poni", user: {nickname: connectiondata.nickname, username: "teemant", hostname: socket.request.connection._peername.address}});
socket.emit('act_client', {type: 'channel_nicks', channel: "#poni", server: connectiondata.server, nicks: ["+horse", "@Diamond", "@aspire", "+random", "lol"]});
socket.emit('act_client', {type: 'channel_topic', channel: "#poni", server: connectiondata.server, topic: "This channel is the second best."});
socket.emit('act_client', {type: 'channel_topic', channel: "#poni", server: connectiondata.server, set_by: "Diamond", time: Date.now()});
}, 5000)
setTimeout(function() {
socket.emit('act_client', {type: 'event_kick_channel', server: connectiondata.server, channel: "#channel", user: {nickname: "scoper", username: "teemant", hostname: socket.request.connection._peername.address}, kickee: "random", reason: "Get out."});
socket.emit('act_client', {type: 'event_quit', server: connectiondata.server, user: {nickname: "lol", username: "teemant", hostname: socket.request.connection._peername.address}, reason: "Sleep."});
socket.emit('act_client', {type: 'event_part_channel', server: connectiondata.server, channel: "#poni", user: {nickname: "aspire", username: "teemant", hostname: socket.request.connection._peername.address}, reason: "Bye, lol."});
}, 6000);
}, 4000);
});
});