From 01af0d83e990e0c7756e5fa68a0c4f1ed9314adb Mon Sep 17 00:00:00 2001 From: Evert Date: Sat, 24 Sep 2016 15:25:47 +0300 Subject: [PATCH] stupid mode handling, pls fix --- public/css/main.css | 168 +++++++++++++++++++++++++++++++++++++++ public/index.html | 9 ++- public/js/colorparser.js | 81 +++++++++++++++++++ public/js/main.js | 165 +++++++++++++++++++++++++++++++++----- public/main.styl | 66 +++++++++++++++ server/irc.js | 31 ++++++++ teemant.js | 12 ++- 7 files changed, 500 insertions(+), 32 deletions(-) create mode 100644 public/js/colorparser.js diff --git a/public/css/main.css b/public/css/main.css index 41ec308..456ffbb 100644 --- a/public/css/main.css +++ b/public/css/main.css @@ -387,6 +387,174 @@ body { .message.m_action .actionee { color: #3f51b5; } +.message .irc-bg00, +.topicbar .irc-bg00, +.message .irc-bg0, +.topicbar .irc-bg0 { + background-color: #fff; +} +.message .irc-bg01, +.topicbar .irc-bg01, +.message .irc-bg1, +.topicbar .irc-bg1 { + background-color: #000; +} +.message .irc-bg02, +.topicbar .irc-bg02, +.message .irc-bg2, +.topicbar .irc-bg2 { + background-color: #000080; +} +.message .irc-bg03, +.topicbar .irc-bg03, +.message .irc-bg3, +.topicbar .irc-bg3 { + background-color: #008000; +} +.message .irc-bg04, +.topicbar .irc-bg04, +.message .irc-bg4, +.topicbar .irc-bg4 { + background-color: #f00; +} +.message .irc-bg05, +.topicbar .irc-bg05, +.message .irc-bg5, +.topicbar .irc-bg5 { + background-color: #a52a2a; +} +.message .irc-bg06, +.topicbar .irc-bg06, +.message .irc-bg6, +.topicbar .irc-bg6 { + background-color: #800080; +} +.message .irc-bg07, +.topicbar .irc-bg07, +.message .irc-bg7, +.topicbar .irc-bg7 { + background-color: #ffa500; +} +.message .irc-bg08, +.topicbar .irc-bg08, +.message .irc-bg8, +.topicbar .irc-bg8 { + background-color: #ff0; +} +.message .irc-bg09, +.topicbar .irc-bg09, +.message .irc-bg9, +.topicbar .irc-bg9 { + background-color: #0f0; +} +.message .irc-bg10, +.topicbar .irc-bg10 { + background-color: #008080; +} +.message .irc-bg11, +.topicbar .irc-bg11 { + background-color: #0ff; +} +.message .irc-bg12, +.topicbar .irc-bg12 { + background-color: #00f; +} +.message .irc-bg13, +.topicbar .irc-bg13 { + background-color: #ffc0cb; +} +.message .irc-bg14, +.topicbar .irc-bg14 { + background-color: #808080; +} +.message .irc-bg15, +.topicbar .irc-bg15 { + background-color: #d3d3d3; +} +.message .irc-fg00, +.topicbar .irc-fg00, +.message .irc-fg0, +.topicbar .irc-fg0 { + color: #fff; +} +.message .irc-fg01, +.topicbar .irc-fg01, +.message .irc-fg1, +.topicbar .irc-fg1 { + color: #000; +} +.message .irc-fg02, +.topicbar .irc-fg02, +.message .irc-fg2, +.topicbar .irc-fg2 { + color: #000080; +} +.message .irc-fg03, +.topicbar .irc-fg03, +.message .irc-fg3, +.topicbar .irc-fg3 { + color: #008000; +} +.message .irc-fg04, +.topicbar .irc-fg04, +.message .irc-fg4, +.topicbar .irc-fg4 { + color: #f00; +} +.message .irc-fg05, +.topicbar .irc-fg05, +.message .irc-fg5, +.topicbar .irc-fg5 { + color: #a52a2a; +} +.message .irc-fg06, +.topicbar .irc-fg06, +.message .irc-fg6, +.topicbar .irc-fg6 { + color: #800080; +} +.message .irc-fg07, +.topicbar .irc-fg07, +.message .irc-fg7, +.topicbar .irc-fg7 { + color: #ffa500; +} +.message .irc-fg08, +.topicbar .irc-fg08, +.message .irc-fg8, +.topicbar .irc-fg8 { + color: #dcdc00; +} +.message .irc-fg09, +.topicbar .irc-fg09, +.message .irc-fg9, +.topicbar .irc-fg9 { + color: #00e600; +} +.message .irc-fg10, +.topicbar .irc-fg10 { + color: #008080; +} +.message .irc-fg11, +.topicbar .irc-fg11 { + color: #00d2d2; +} +.message .irc-fg12, +.topicbar .irc-fg12 { + color: #00f; +} +.message .irc-fg13, +.topicbar .irc-fg13 { + color: #ffc0cb; +} +.message .irc-fg14, +.topicbar .irc-fg14 { + color: #808080; +} +.message .irc-fg15, +.topicbar .irc-fg15 { + color: #d3d3d3; +} @media all and (max-width: 600px) { .vnicks .nicklist { display: none !important; diff --git a/public/index.html b/public/index.html index 588c3a0..1dcadd1 100644 --- a/public/index.html +++ b/public/index.html @@ -2,12 +2,15 @@ - TeemantIRC - - + TeemantIRC + + + + + diff --git a/public/js/colorparser.js b/public/js/colorparser.js new file mode 100644 index 0000000..40b0047 --- /dev/null +++ b/public/js/colorparser.js @@ -0,0 +1,81 @@ +// Shamelessly copied from https://github.com/megawac/irc-style-parser/ +// Lol, I just gave credit, didn't I.. +// Dammit, well, there's that. + +let styleCheck_Re = /[\x00-\x1F]/, back_re = /^(\d{1,2})(,(\d{1,2}))?/, + colourKey = "\x03", colour_re = /\x03/g, + styleBreak = "\x0F"; // breaks all open styles ^O (\x0F) + +let styles = [ + ["normal", "\x00", ""], ["underline", "\x1F"], + ["bold", "\x02"], ["italic", "\x1D"] +].map(function(style) { + var escaped = encodeURI(style[1]).replace("%", "\\x"); + return { + name: style[0], + style: style[2] != null ? style[2] : "irc-" + style[0], + key: style[1], + keyregex: new RegExp(escaped + "(.*?)(" + escaped + "|$)") + }; +}); + +//http://www.mirc.com/colors.html +let colors = [ + "white", "black", "navy", "green", "red", "brown", + "purple", "olive", "yellow", "lightgreen", "teal", + "cyan", "blue", "pink", "gray", "lightgrey" +].reduce(function(memo, name, index) { + memo[index] = { + name: name, + fore: "irc-fg" + index, + back: "irc-bg" + index, + key: index + }; + return memo; +}, {}); + +function stylize(line) { + // Recheck + if (!styleCheck_Re.test(line)) return line; + + // split up by the irc style break character ^O + if (line.indexOf(styleBreak) >= 0) { + return line.split(styleBreak).map(stylize).join(""); + } + + var result = line; + var parseArr = result.split(colourKey); + var text, match, colour, background = ""; + for (var i = 0; i < parseArr.length; i++) { + text = parseArr[i]; + match = text.match(back_re); + colour = match && colors[+match[1]]; + if (!match || !colour) { + // ^C (no colour) ending. Escape current colour and carry on + background = ""; + continue; + } + // set the background colour + // we don't overide the background local var to support nesting + if (colors[+match[3]]) { + background = " " + colors[+match[3]].back; + } + // update the parsed text result + result = result.replace(colourKey + text, + "{1}".format(colour.fore + background, text.slice(match[0].length))); + } + + // Matching styles (italics/bold/underline) + // if only colors were this easy... + styles.forEach(function(style) { + if (result.indexOf(style.key) < 0) return; + result = result.replace(style.keyregex, function(match, text) { + return "{1}".format(style.style, text) + }); + }); + + //replace the reminent colour terminations and be done with it + return result.replace(colour_re, ""); +} + +window.colorizer.stylize = stylize; diff --git a/public/js/main.js b/public/js/main.js index b6d6536..265795b 100644 --- a/public/js/main.js +++ b/public/js/main.js @@ -5,11 +5,26 @@ window.irc = { timestampFormat: "HH:mm:ss", serverData: {}, serverChatQueue: {}, - chatType: "simple" + chatType: "simple", }; window.clientdom = {connector: {}}; +window.colorizer = { + theme: { + H: [1, 360], + S: [30, 100], + L: [30, 70] + }, + get_random_color: function(nickname) { + Math.seedrandom(nickname); + let h = rand(colorizer.theme.H[0], colorizer.theme.H[1]); // color hue between 1 and 360 + let s = rand(colorizer.theme.S[0], colorizer.theme.S[1]); // saturation 30-100% + let l = rand(colorizer.theme.L[0], colorizer.theme.L[1]); // lightness 30-70% + return 'hsl(' + h + ',' + s + '%,' + l + '%)'; + } +} + /*********************\ |** **| |** UTILITIES **| @@ -126,6 +141,19 @@ Date.prototype.format = function (format, utc){ return format; }; +function rand(min, max) { + return parseInt(Math.random() * (max-min+1), 10) + min; +} + +if (!String.prototype.format) { + String.prototype.format = function() { + var args = arguments; + return this.replace(/{(\d+)}/g, function(match, number) { + return typeof args[number] != undefined ? args[number] : match; + }); + }; +} + function linkify(text) { // see http://daringfireball.net/2010/07/improved_regex_for_matching_urls let re = /\b((?:https?:\/\/|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/gi; @@ -160,6 +188,15 @@ function toggleClass(element, cl) { addClass(element, cl); } +function objectGetKey(obj, value) { + let key = null; + for(let f in obj) { + if(obj[f] == value) + key = f; + } + return key; +} + let composer = { message: { simple: function(time, sender, message, type) { @@ -169,21 +206,23 @@ let composer = { if(irc.timestamps) element.innerHTML += ""+time.format(irc.timestampFormat)+" "; + message = colorizer.stylize(message); message = linkify(message); switch(type) { + case "mode": case "action": - element.innerHTML += "* "+sender+" "; + element.innerHTML += "* "+sender+" "; element.innerHTML += ""+message+""; break; case "part": case "quit": case "kick": - element.innerHTML += " "+sender+""; + element.innerHTML += " "+sender+""; element.innerHTML += " "+message+""; break; case "join": - element.innerHTML += " "+sender+""; + element.innerHTML += " "+sender+""; element.innerHTML += " "+message+""; break; default: @@ -195,6 +234,18 @@ let composer = { } break; } + + if(sender){ + let sndr1 = element.querySelector('.sender'); + let sndr2 = element.querySelectorAll('.nick'); + if(sndr1) + sndr1.style.color = colorizer.get_random_color(sndr1.innerHTML); + else if(sndr2.length > 0) + for(let a in sndr2) + if(sndr2[a] && sndr2[a]['style']) + sndr2[a].style.color = colorizer.get_random_color(sndr2[a].innerHTML); + } + return element; } } @@ -313,10 +364,24 @@ class Nicklist { else return; - for(let mode in irc.modeTranslation) { - let prefix = irc.modeTranslation[m]; - if(newMode == mode) - this.nicks[nickIndex].prefix = prefix; + let modeTranslations = irc.serverData[this.buffer.server].modeTranslation; + let prefixes = irc.serverData[this.buffer.server].supportedPrefixes; + + nick.modes.push(newMode); + + for(let mode in modeTranslations) { + let prefix = modeTranslations[mode]; + if(nick.modes.indexOf(mode) == -1) continue; + let a = nick.modes.indexOf(mode) - 1; + if(a >= 0) { + if(prefixes.indexOf(modeTranslations[nick.modes[a]]) < prefixes.indexOf(prefix)) { + nick.prefix = modeTranslations[nick.modes[a]]; + break; + } + } else { + nick.prefix = prefix; + break; + } } this.render(); @@ -331,12 +396,29 @@ class Nicklist { else return; - for(let mode in irc.modeTranslation) { - let prefix = irc.modeTranslation[m]; - if(newMode == mode) - this.nicks[nickIndex].prefix = ""; + let modeTranslations = irc.serverData[this.buffer.server].modeTranslation; + let prefixes = irc.serverData[this.buffer.server].supportedPrefixes; + + remove_str(nick.modes, oldMode); + + let currentLowest = ""; + + for(let n in nick.modes) { + let mode = nick.modes[n]; + let nextMode = nick.modes[n+1]; + if(!nextMode && mode) { + currentLowest = modeTranslations[mode]; + break; + } else if(nextMode) { + if(prefixes.indexOf(modeTranslations[nextMode]) > prefixes.indexOf(modeTranslations[mode])) + currentLowest = modeTranslations[nextMode]; + } else { + break; + } } + nick.prefix = currentLowest; + this.render(); } } @@ -442,7 +524,7 @@ class Buffer { if(this.topic != null && this.topic != "") { addClass(clientdom.chat, 'vtopic'); - clientdom.topicbar.innerHTML = linkify(this.topic); + clientdom.topicbar.innerHTML = linkify(colorizer.stylize(this.topic)); } this.renderMessages(); @@ -473,7 +555,7 @@ class Buffer { topicChange(topic) { if(this.active) { - clientdom.topicbar.innerHTML = linkify(topic); + clientdom.topicbar.innerHTML = linkify(colorizer.stylize(topic)); if(this.topic == null) addClass(clientdom.chat, "vtopic"); @@ -519,10 +601,7 @@ class IRCConnector { this.formLocked = true; - let success = this.validateForm(e); - - if(!success) - this.formLocked = false; + this.validateForm(e); } } @@ -589,6 +668,8 @@ class IRCConnector { authMessage(message, error) { clientdom.connector.messenger.innerHTML = ""+message+""; + if(error) + this.formLocked = false; } authComplete() { @@ -662,6 +743,16 @@ class IRCChatWindow { return result; } + getServerBuffer(server) { + let result = null; + for (let t in this.buffers) { + let buf = this.buffers[t]; + if(buf.server == server) + result = buf; + } + return result; + } + getBuffersByServer(server) { let result = []; for (let t in this.buffers) { @@ -778,11 +869,12 @@ class IRCChatWindow { return; for(let n in nicks) { - let nick = {nickname: "", prefix: ""}; + let nick = {nickname: "", prefix: "", modes: []}; 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); + nick.modes = [objectGetKey(irc.serverData[buf.server].modeTranslation, nick.prefix)]; } else { nick.nickname = nicks[n]; } @@ -860,9 +952,9 @@ class IRCChatWindow { if(!buffer) return; if(kicker) - buffer.addMessage("has kicked "+user+" "+reason+"", kicker.nickname, "part"); + buffer.addMessage("has kicked "+user+" "+reason+"", kicker.nickname, "part"); else - buffer.addMessage(""+user.username+"@"+user.hostname+" has left"+ + buffer.addMessage(""+user.username+"@"+user.hostname+" has left "+ channel+(reason != null ? " "+reason+"" : ""), user.nickname, "part"); if(kicker) buffer.nicklist.nickRemove(user); @@ -870,6 +962,30 @@ class IRCChatWindow { buffer.nicklist.nickRemove(user.nickname); } + handleMode(data) { + let buf = null; + console.log(data); + if(data.target == irc.serverData[data.server].my_nick) + buf = this.getServerBuffer(data.server); + else + buf = this.getBufferByServerName(data.server, data.target); + + if(!buf) return; + + if(data.type == "mode_add") { + buf.nicklist.modeAdded(data.modeTarget, data.mode); + buf.addMessage("set mode "+data.target+" +"+data.mode+" "+ + data.modeTarget+"", data.user.nickname, "mode"); + } else if(data.type == "mode_del") { + buf.nicklist.modeRemoved(data.modeTarget, data.mode); + buf.addMessage("set mode "+data.target+" -"+data.mode+" "+ + data.modeTarget+"", data.user.nickname, "mode"); + } else { + buf.addMessage("set mode "+data.target+" "+data.message+"", + data.user.nickname, "mode"); + } + } + render(buffer) { let activeNow = this.getActiveBuffer(); @@ -962,9 +1078,14 @@ window.onload = function() { case "nick_change": irc.chat.nickChange(data.server, data.nick, data.newNick); break; + case "mode_add": + case "mode_del": + case "mode": + irc.chat.handleMode(data); + break; case "server_message": if(data['error']) data.messageType = "error"; - if(irc.chat.getBuffersByServer(data.server).length == 0) { + if(irc.chat.getServerBuffer(data.server) == null) { if(!irc.serverChatQueue[data.server]) { irc.serverChatQueue[data.server] = []; } else { diff --git a/public/main.styl b/public/main.styl index 607d462..ccc90fe 100644 --- a/public/main.styl +++ b/public/main.styl @@ -330,6 +330,72 @@ body &.m_action .actionee color: #3f51b5; +.message, .topicbar + .irc-bg00,.irc-bg0 + background-color: white + .irc-bg01,.irc-bg1 + background-color: black + .irc-bg02,.irc-bg2 + background-color: navy + .irc-bg03,.irc-bg3 + background-color: green + .irc-bg04,.irc-bg4 + background-color: red + .irc-bg05,.irc-bg5 + background-color: brown + .irc-bg06,.irc-bg6 + background-color: purple + .irc-bg07,.irc-bg7 + background-color: orange + .irc-bg08,.irc-bg8 + background-color: yellow + .irc-bg09,.irc-bg9 + background-color: lime + .irc-bg10 + background-color: teal + .irc-bg11 + background-color: cyan + .irc-bg12 + background-color: blue + .irc-bg13 + background-color: pink + .irc-bg14 + background-color: grey + .irc-bg15 + background-color: lightgrey + .irc-fg00,.irc-fg0 + color: white + .irc-fg01,.irc-fg1 + color: black + .irc-fg02,.irc-fg2 + color: navy + .irc-fg03,.irc-fg3 + color: green + .irc-fg04,.irc-fg4 + color: red + .irc-fg05,.irc-fg5 + color: brown + .irc-fg06,.irc-fg6 + color: purple + .irc-fg07,.irc-fg7 + color: orange + .irc-fg08,.irc-fg8 + color: #dcdc00 + .irc-fg09,.irc-fg9 + color: #00e600 + .irc-fg10 + color: teal + .irc-fg11 + color: #00d2d2 + .irc-fg12 + color: blue + .irc-fg13 + color: pink + .irc-fg14 + color: grey + .irc-fg15 + color: lightgrey + @media all and (max-width: 600px) .vnicks .nicklist diff --git a/server/irc.js b/server/irc.js index dc5853a..e0410d8 100644 --- a/server/irc.js +++ b/server/irc.js @@ -142,6 +142,9 @@ class IRCConnectionHandler { line.trailing = line.trailing.substring(8); line.trailing.substring(0, line.trailing.length-1); type = "action"; + } else if(line.trailing.indexOf('\x01') == 0) { + // TODO: handle CTCPs + return; } if(line.user.nickname != "") @@ -186,6 +189,34 @@ class IRCConnectionHandler { case "042": this.conn.emit('pass_to_client', {type: "server_message", messageType: "regular", message: line.arguments[1] +" "+ line.trailing, server: serverName, from: realServerName}); break; + case "MODE": + let isChannelMode = false; + let method = '+'; + if(line.arguments[0].indexOf('#') != -1) + isChannelMode = true; + + let modes = line.arguments[1]; + method = modes.substring(0, 1); + modes = modes.substring(1).split(''); + let pass = []; + + if(isChannelMode) { + for(let i in modes) { + let mode = modes[i]; + if(this.conn.data.supportedModes[mode]) + this.conn.emit('pass_to_client', {type: "mode_"+(method=='+'?'add':'del'), target: line.arguments[0], mode: mode, + modeTarget: line.arguments[2+parseInt(i)], server: serverName, user: line.user}); + else + pass.push(mode); + } + } else { + pass = modes; + } + + if(pass.length > 0) + this.conn.emit('pass_to_client', {type: "mode", target: line.arguments[0], message: line.arguments.slice(1).join(" "), + server: serverName, user: line.user}); + break; } } } diff --git a/teemant.js b/teemant.js index 5bca625..ec4e3c8 100755 --- a/teemant.js +++ b/teemant.js @@ -76,13 +76,11 @@ io.sockets.on('connection', function (socket) { newConnection.on('connerror', (data) => { let message = "An error occured"; - let inconnect = false; - - console.log(newConnection.authenticated); - + let inconnect = true; + if(newConnection.authenticated == false) { message = "Failed to connect to the server!"; - inconnect = true; + inconnect = false; } socket.emit('act_client', {type: (inconnect == true ? 'server_message' : 'connect_message'), message: message, error: true}); @@ -94,11 +92,11 @@ io.sockets.on('connection', function (socket) { newConnection.on('closed', (data) => { let message = "Connection closed"; - let inconnect = false; + let inconnect = true; if(newConnection.authenticated == false) { message = "Failed to connect to the server!"; - inconnect = true; + inconnect = false; } socket.emit('act_client', {type: (inconnect == true ? 'server_message' : 'connect_message'), message: message, error: true});