diff --git a/public/css/main.css b/public/css/main.css
index 8017350..d7dc6cc 100644
--- a/public/css/main.css
+++ b/public/css/main.css
@@ -228,7 +228,7 @@ body {
width: 100%;
background-color: #00c7e0;
}
-.ircclient #chat .ircwrapper .input .nickname {
+.ircclient #chat .ircwrapper .input .my_nickname {
background-color: #00efef;
margin: 5px;
padding: 7px;
@@ -256,7 +256,6 @@ body {
box-shadow: inset 4px 4px 8px #d8d8d8;
}
.message.type_simple .timestamp {
- margin-right: 5px;
color: #696969;
}
.message.type_simple .timestamp:before {
@@ -268,7 +267,6 @@ body {
content: "]";
}
.message.type_simple .sender {
- margin-right: 5px;
color: #3f51b5;
}
.message.type_simple .sender:before {
@@ -277,3 +275,14 @@ body {
.message.type_simple .sender:after {
content: ">";
}
+.m_topic .content {
+ color: #03a9f4;
+ font-weight: bold;
+}
+.m_nick .content {
+ color: #ff9800;
+ font-weight: bold;
+}
+.m_action .actionee {
+ color: #3f51b5;
+}
diff --git a/public/index.html b/public/index.html
index 78b2260..ac8b4f4 100644
--- a/public/index.html
+++ b/public/index.html
@@ -44,7 +44,7 @@
-
Test
+
Test
diff --git a/public/js/main.js b/public/js/main.js
index 2afaf23..fa44bb0 100644
--- a/public/js/main.js
+++ b/public/js/main.js
@@ -3,14 +3,11 @@ window.irc = {
primaryFrame: null,
timestamps: true,
timestampFormat: "HH:mm:ss",
- supportedPrefixes: "@%+",
- modeTranslation: {
- "o": "@",
- "h": "%",
- "v": "+"
- }
+ serverData: {}
};
+window.clientdom = {connector: {}};
+
/*********************\
|** **|
|** UTILITIES **|
@@ -147,21 +144,21 @@ function addClass(element, cl) {
\*********************/
class Nicklist {
- constructor(buffer, frame) {
+ constructor(buffer) {
this.buffer = buffer;
- this.frame = frame;
this.nicks = [];
}
sort() {
+ let spfx = irc.serverData[this.buffer.server].supportedPrefixes
this.nicks.sort(function (a,b) {
- let rex = new RegExp('^['+irc.supportedPrefixes+']');
+ let rex = new RegExp('^['+spfx+']');
let nicks = [a.prefix.replace(rex,'').toLowerCase(), b.prefix.replace(rex,'').toLowerCase()];
let prefix = [];
- if (rex.test(a.prefix)) prefix.push(irc.supportedPrefixes.indexOf(a.prefix[0]));
- else prefix.push(irc.supportedPrefixes.length+1);
- if (rex.test(b.prefix)) prefix.push(irc.supportedPrefixes.indexOf(b.prefix[0]));
- else prefix.push(irc.supportedPrefixes.length+1);
+ if (rex.test(a.prefix)) prefix.push(spfx.indexOf(a.prefix[0]));
+ else prefix.push(spfx.length+1);
+ if (rex.test(b.prefix)) prefix.push(spfx.indexOf(b.prefix[0]));
+ else prefix.push(spfx.length+1);
if (prefix[0] < prefix[1]) return -1;
if (prefix[0] > prefix[1]) return 1;
if (nicks[0] > nicks[1]) return 1;
@@ -177,13 +174,21 @@ class Nicklist {
let str = document.createElement("div");
str.className = "nick";
str.setAttribute('id', 'nick-'+nick.nickname);
- let construct = "
"+nick.prefix+""+nick.nickname+"";
+ let construct = "";
+
+ if(nick.prefix != "")
+ construct += "
"+nick.prefix+"";
+ else
+ construct += "
";
+
+ construct += "
"+nick.nickname+"";
str.innerHTML = construct;
- this.frame.appendChild(str);
+ clientdom.nicklist.appendChild(str);
}
render() {
- this.frame.innerHTML = "";
+ clientdom.nicklist.innerHTML = "";
+ this.sort();
for(let n in this.nicks) {
let nick = this.nicks[n];
this.appendToList(nick);
@@ -196,6 +201,10 @@ class Nicklist {
this.render();
}
+ nickAddObject(obj) {
+ this.nicks.push(obj);
+ }
+
nickRemove(nickname) {
let nickIndex = this.getNickIndex(nickname);
@@ -268,21 +277,33 @@ class Tab {
constructor(buffer) {
this.buffer = buffer;
this.element = null;
+ this.closeRequested = false;
}
// Create a tab element
- renderTab(frame) {
- let internals = "
"+ this.buffer.title +"x";
+ renderTab() {
+ let internals = "
"+ this.buffer.title +"";
+
let ttt = document.createElement('div');
ttt.innerHTML = internals;
ttt.className = "tab";
ttt.setAttribute('id', 'tab-'+this.name);
- frame.appendChild(ttt);
+ clientdom.tabby.appendChild(ttt);
this.element = ttt;
+ if(this.buffer.type != "server") {
+ ttt.innerHTML += "
x"
+ ttt.querySelector('#close').addEventListener('click', () => {
+ this.close();
+ }, false);
+ }
+
ttt.addEventListener('click', () => {
+ if(this.closeRequested) return;
+
if(this.buffer.active)
return;
+
irc.chat.render(this.buffer);
}, false);
}
@@ -309,7 +330,8 @@ class Tab {
}
close() {
- console.log('close requested for '+this.buffer.title);
+ this.closeRequested = true;
+ this.buffer.closeBuffer();
}
}
@@ -326,20 +348,13 @@ class Buffer {
this.name = buffername;
this.title = tabname;
this.type = type;
-
- this.nicklistDisplayed = false;
this.active = false;
this.tab = new Tab(this);
- this.tab.renderTab(irc.primaryFrame.querySelector('.tabby'));
+ this.tab.renderTab(clientdom.tabby);
- if(type == "channel") {
- this.nicklistDisplayed = true;
- this.nicklist = new Nicklist(this);
- }
-
- this.frame = irc.primaryFrame.querySelector('#chat');
- this.letterbox = this.frame.querySelector('.letterbox');
+ if(type == "channel")
+ this.nicklist = new Nicklist(this, clientdom.nicklist);
}
render() {
@@ -348,31 +363,30 @@ class Buffer {
this.unreadCount = 0;
this.tab.setUnreadCount(0);
- let chat = this.frame.querySelector('.chatarea');
- let topicbar = chat.querySelector('.topicbar');
- let nicklist = chat.querySelector('.nicklist');
+ clientdom.chat.className = "chatarea";
+ clientdom.nicklist.innerHTML = "";
+ clientdom.topicbar.innerHTML = "";
- chat.className = "chatarea";
- nicklist.innerHTML = "";
- topicbar.innerHTML = "";
-
- if(this.nicklistDisplayed) {
- addClass(chat, 'vnicks');
+ if(this.nicklist) {
+ addClass(clientdom.chat, 'vnicks');
+ this.nicklist.render();
}
if(this.topic != null && this.topic != "") {
- addClass(chat, 'vtopic');
- topicbar.innerHTML = this.topic;
+ addClass(clientdom.chat, 'vtopic');
+ clientdom.topicbar.innerHTML = this.topic;
}
this.renderMessages();
- this.letterbox.scrollTop = this.lastscroll;
+ clientdom.letterbox.scrollTop = this.lastscroll;
+
+ clientdom.currentNickname.innerHTML = irc.serverData[this.server].my_nick;
}
renderMessages() {
if(!this.active) return;
- this.letterbox.innerHTML = "";
+ clientdom.letterbox.innerHTML = "";
for(let t in this.messages) {
let mesg = this.messages[t];
@@ -386,21 +400,36 @@ class Buffer {
let construct = "";
if(irc.timestamps)
- construct += "
"+meta.time.format(irc.timestampFormat)+"";
+ construct += "
"+meta.time.format(irc.timestampFormat)+" ";
- if(meta.sender != null)
- construct += "
"+meta.sender+"";
- else
+ if(meta.sender != null && meta.type != "action") {
+ construct += "
"+meta.sender+" ";
+ } else {
+ construct += "
* ";
addClass(mesgConstr, "no_sender");
+ }
- construct += "
"+meta.message+"";
+ if(meta.type == "action")
+ construct += "
"+meta.sender+" "+meta.message+"";
+ else
+ construct += "
"+meta.message+"";
mesgConstr.innerHTML = construct;
- this.letterbox.appendChild(mesgConstr);
+ clientdom.letterbox.appendChild(mesgConstr);
- let lFactor = this.letterbox.offsetHeight + this.letterbox.scrollTop
- if(lFactor > this.letterbox.scrollHeight - 100)
- this.letterbox.scrollTop = this.letterbox.scrollHeight;
+ let lFactor = clientdom.letterbox.offsetHeight + clientdom.letterbox.scrollTop
+ if(lFactor > clientdom.letterbox.scrollHeight - 100)
+ clientdom.letterbox.scrollTop = clientdom.letterbox.scrollHeight;
+ }
+
+ topicChange(topic) {
+ if(this.active) {
+ clientdom.topicbar.innerHTML = topic;
+
+ if(this.topic == null)
+ addClass(clientdom.chat, "vtopic");
+ }
+ this.topic = topic;
}
addMessage(message, sender, type) {
@@ -417,28 +446,20 @@ class Buffer {
switchOff() {
this.tab.setActive(false);
- this.lastscroll = this.letterbox.scrollTop;
+ this.lastscroll = clientdom.letterbox.scrollTop;
this.active = false;
}
- close() {
-
+ closeBuffer() {
+ irc.chat.closeBuffer(this);
}
}
class IRCConnector {
- constructor(frame) {
- this.frame = frame;
- this.messenger = frame.querySelector('#connmsg');
- this.f_form = frame.querySelector('#IRCConnector');
-
- this.f_nickname = this.f_form.querySelector('#nickname');
- this.f_channel = this.f_form.querySelector('#channel');
- this.f_server = this.f_form.querySelector('#server');
- this.f_port = this.f_form.querySelector('#port');
+ constructor() {
this.formLocked = false;
- this.f_form.onsubmit = (e) => {
+ clientdom.connector.form.onsubmit = (e) => {
if(this.formLocked) {
e.preventDefault();
return false;
@@ -456,10 +477,10 @@ class IRCConnector {
validateForm(event) {
event.preventDefault();
- let nickname = this.f_nickname.value;
- let channel = this.f_channel.value;
- let server = this.f_server.value;
- let port = this.f_port.value;
+ let nickname = clientdom.connector.nickname.value;
+ let channel = clientdom.connector.channel.value;
+ let server = clientdom.connector.server.value;
+ let port = clientdom.connector.port.value;
if (!window.validators.nickname(nickname)) {
this.authMessage("Erroneous nickname!", true);
@@ -515,20 +536,19 @@ class IRCConnector {
}
authMessage(message, error) {
- this.messenger.innerHTML = "
"+message+"";
+ clientdom.connector.messenger.innerHTML = "
"+message+"";
}
authComplete() {
- this.frame.style.display = "none";
+ clientdom.connector.frame.style.display = "none";
this.formLocked = false;
}
}
class IRCChatWindow {
- constructor(frame) {
- this.frame = frame;
+ constructor() {
this.buffers = [];
- this.frame.style.display = "none";
+ clientdom.frame.style.display = "none";
this.firstServer = true;
this.currentBuffer = null;
}
@@ -563,7 +583,7 @@ class IRCChatWindow {
return result;
}
- getBufferByNameServer(server, channel) {
+ getBufferByServerName(server, channel) {
let result = null;
for (let t in this.buffers) {
let buf = this.buffers[t];
@@ -585,7 +605,20 @@ class IRCChatWindow {
newServerBuffer(serverinfo) {
if(this.firstServer) {
- this.frame.style.display = "block";
+ clientdom.frame.style.display = "block";
+ }
+
+ let prefixes = "";
+
+ for(let v in serverinfo.supportedModes) {
+ prefixes += serverinfo.supportedModes[v];
+ }
+
+ irc.serverData[serverinfo.address] = {
+ modeTranslation: serverinfo.supportedModes,
+ supportedPrefixes: prefixes,
+ network: serverinfo.network,
+ my_nick: serverinfo.nickname
}
let newServer = new Buffer(serverinfo.address, serverinfo.address, serverinfo.network, "server");
@@ -595,7 +628,7 @@ class IRCChatWindow {
}
createBuffer(server, name, type, autoswitch) {
- let buf = this.getBufferByNameServer(server, name);
+ let buf = this.getBufferByServerName(server, name);
if(buf) {
if(autoswitch)
this.render(buf);
@@ -610,11 +643,27 @@ class IRCChatWindow {
}
closeBuffer(buffer) {
- // todo: close
+ if(buffer.type == "server") return; // Don't close server buffers, lol
+ if(buffer.type == "channel") console.log("TODO: PART");
+ let bufIndex = this.buffers.indexOf(buffer);
+
+ if(buffer.active) {
+ console.log(bufIndex);
+ if (bufIndex == 0) {
+ if(this.buffers[bufIndex+1]) {
+ this.render(this.buffers[bufIndex+1]);
+ }
+ } else {
+ this.render(this.buffers[bufIndex-1]);
+ }
+ }
+
+ buffer.tab.element.remove();
+ this.buffers.splice(bufIndex, 1);
}
messageBuffer(name, server, message) {
- let buf = this.getBufferByNameServer(server, name);
+ let buf = this.getBufferByServerName(server, name);
if(buf == null)
buf = this.createBuffer(server, name, "message", false);
@@ -622,6 +671,65 @@ class IRCChatWindow {
buf.addMessage(message.message, message.from, message.type);
}
+ buildNicklist(channel, server, nicks) {
+ let buf = this.getBufferByServerName(server, channel);
+
+ if(buf == null)
+ return;
+
+ for(let n in nicks) {
+ let nick = {nickname: "", prefix: ""};
+
+ if(irc.serverData[buf.server].supportedPrefixes.split('').indexOf(nicks[n].substring(0, 1)) != -1) {
+ nick.prefix = nicks[n].substring(0, 1);
+ nick.nickname = nicks[n].substring(1);
+ } else {
+ nick.nickname = nicks[n];
+ }
+
+ buf.nicklist.nickAddObject(nick);
+ }
+
+ if(buf.active)
+ buf.nicklist.render();
+ }
+
+ nickChange(server, oldNick, newNick) {
+ let buffers = this.getBuffersByServer(server);
+
+ if(irc.serverData[server].my_nick == oldNick) {
+ irc.serverData[server].my_nick = newNick;
+
+ let activeBuf = this.getActiveBuffer();
+
+ if(activeBuf.server == server) {
+ activeBuf.my_nickname.innerHTML = newNick;
+ }
+ }
+
+ for(let i in buffers) {
+ let buffer = buffers[i];
+
+ if(buffer.type != "channel") continue;
+ if(buffer.nicklist.getNickIndex(oldNick) == null) continue;
+
+ buffer.nicklist.nickChange(oldNick, newNick);
+ buffer.addMessage(oldNick+" is now known as "+newNick, null, "nick");
+ }
+ }
+
+ topicChange(channel, server, topic, changer) {
+ let buf = this.getBufferByServerName(server, channel);
+
+ if (!buf) return;
+
+ buf.topicChange(topic);
+ if(changer)
+ buf.addMessage(changer+" set the topic of "+channel+ " to \""+topic+"\"", null, "topic");
+ else
+ buf.addMessage("Topic of "+channel+ " is \""+topic+"\"", null, "topic");
+ }
+
render(buffer) {
let activeNow = this.getActiveBuffer();
@@ -639,11 +747,27 @@ class IRCChatWindow {
\**************************/
window.onload = function() {
+ irc.primaryFrame = document.querySelector('.ircclient');
+
+ clientdom.connector['frame'] = irc.primaryFrame.querySelector('#authdialog');
+ clientdom.connector['messenger'] = clientdom.connector.frame.querySelector('#connmsg');
+ clientdom.connector['form'] = clientdom.connector.frame.querySelector('#IRCConnector');
+ clientdom.connector['nickname'] = clientdom.connector.form.querySelector('#nickname');
+ clientdom.connector['channel'] = clientdom.connector.form.querySelector('#channel');
+ clientdom.connector['server'] = clientdom.connector.form.querySelector('#server');
+ 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['topicbar'] = clientdom.chat.querySelector('.topicbar');
+
irc.socket = io.connect('http://localhost:8080');
- irc.primaryFrame = document.querySelector('.ircclient');
- irc.auther = new IRCConnector(irc.primaryFrame.querySelector("#authdialog"));
- irc.chat = new IRCChatWindow(irc.primaryFrame.querySelector("#chat"));
+ irc.auther = new IRCConnector();
+ irc.chat = new IRCChatWindow();
irc.socket.on('connect', function (data) {
irc.socketUp = true;
@@ -664,9 +788,26 @@ window.onload = function() {
case "event_join_channel":
irc.chat.createBuffer(data.server, data.name, "channel", true);
break;
- case "server_message":
+ case "message":
irc.chat.messageBuffer(data.to, data.server, {message: data.message, type: data.messageType, from: data.from});
break;
+ case "channel_nicks":
+ irc.chat.buildNicklist(data.channel, data.server, data.nicks);
+ break;
+ case "channel_topic":
+ if(data['topic'] && data['set_by'])
+ irc.chat.topicChange(data.channel, data.server, data.topic, data['set_by']);
+ else if(data['topic'])
+ irc.chat.topicChange(data.channel, data.server, data.topic, null);
+ else if(data['set_by'])
+ irc.chat.messageBuffer(data.channel, data.server, {message: "Topic set by "+data.set_by+" on "+new Date(data.time), type: "topic", from: null});
+ break;
+ case "nick_change":
+ irc.chat.nickChange(data.server, data.nick, data.newNick);
+ break;
+ case "server_message":
+ irc.chat.messageBuffer(data.server, data.server, {message: data.message, type: data.messageType, from: null});
+ break;
case "connect_message":
irc.auther.authMessage(data.data, data.error);
break;
diff --git a/public/main.styl b/public/main.styl
index ee394e5..73c9a6c 100644
--- a/public/main.styl
+++ b/public/main.styl
@@ -202,7 +202,7 @@ body
height: 46px;
width: 100%;
background-color: #00c7e0;
- .nickname
+ .my_nickname
background-color: #00efef;
margin: 5px;
padding: 7px;
@@ -230,7 +230,6 @@ body
.message.type_simple
.timestamp
- margin-right: 5px;
color: #696969;
&:before
color: #607D8B;
@@ -239,9 +238,19 @@ body
color: #607D8B;
content: "]";
.sender
- margin-right: 5px;
color: #3F51B5;
&:before
content: "<";
&:after
content: ">";
+
+.m_topic .content
+ color: #03A9F4;
+ font-weight: bold;
+
+.m_nick .content
+ color: #FF9800;
+ font-weight: bold;
+
+.m_action .actionee
+ color: #3f51b5;
diff --git a/teemant.js b/teemant.js
index 78f7b33..e394b5d 100755
--- a/teemant.js
+++ b/teemant.js
@@ -38,17 +38,32 @@ io.sockets.on('connection', function (socket) {
setTimeout(function() {
console.log("fake connect");
- socket.emit('act_client', {type: 'event_connect', address: connectiondata.server, network: "IcyNet", raw: connectiondata});
- socket.emit('act_client', {type: 'server_message', messageType: "notice", server: connectiondata.server, to: connectiondata.server, from: null, message: "Connection established"});
+ socket.emit('act_client', {type: 'event_connect', address: connectiondata.server, network: "IcyNet", supportedModes: {"o": "@", "h": "%", "v": "+"}, nickname: connectiondata.nickname, raw: connectiondata});
+ socket.emit('act_client', {type: 'server_message', messageType: "notice", server: connectiondata.server, message: "Connection established"});
}, 2000);
setTimeout(function() {
console.log("fake channel");
socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, name: "#channel"});
- // Spam the client with messages (for testing)
- setInterval(function() {
- socket.emit('act_client', {type: 'server_message', messageType: "privmsg", server: connectiondata.server, to: "#channel", from: "horse", message: "I like ponies"});
- }, 1000);
+ 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"});
+
+ 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"});
+ }, 3000)
+
+ setTimeout(function() {
+ socket.emit('act_client', {type: 'event_join_channel', server: connectiondata.server, name: "#poni"});
+ 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)
}, 4000);
});
});