]> jfr.im git - irc/quakenet/qwebirc.git/commitdiff
Add command parsing and lots of other stuff...
authorChris Porter <redacted>
Sun, 15 Jun 2008 02:10:17 +0000 (03:10 +0100)
committerChris Porter <redacted>
Sun, 15 Jun 2008 02:10:17 +0000 (03:10 +0100)
CommandParser splitting needs refactoring really...

qwebirc/ajaxengine.py
qwebirc/ircclient.py
static/js/irc/baseirc.js
static/js/irc/commandparser.js [new file with mode: 0644]
static/js/irc/ircclient.js
static/js/jslib.js
static/js/ui/basetheme.js
static/js/ui/uglyui.js
static/uitest.html

index 0757931e9c24e9aaa881c6eaa39353d6ffeadf7a..dd252c960543d65abad2b8b9b83b2d655f863e9c 100644 (file)
@@ -41,6 +41,13 @@ class IRCSession:
       if not self.schedule:\r
         self.schedule = reactor.callLater(self.throttle - t, self.flush, True)\r
       return\r
+    else:\r
+      # process the rest of the packet\r
+      if not scheduled:\r
+        if not self.schedule:\r
+          self.schedule = reactor.callLater(0, self.flush, True)\r
+        return\r
+        \r
     self.throttle = t + config.UPDATE_FREQ\r
 \r
     encdata = simplejson.dumps(self.buffer)\r
index 6cc62ba44aabeddc9573a3384140818a641bbd9b..2794d75739cee540dae2dbdc66e0c3fdc029d014 100644 (file)
@@ -51,8 +51,8 @@ class QWebIRCClient(basic.LineReceiver):
     nick, ident, ip, realname = f["nick"], f["ident"], f["ip"], f["realname"]\r
     \r
     hmac = hmacfn(ident, ip)\r
-    self.write("NICK %s" % nick)\r
     self.write("USER %s bleh bleh %s %s :%s" % (ident, ip, hmac, realname))\r
+    self.write("NICK %s" % nick)\r
     \r
     self.factory.client = self\r
     self("connect")\r
index 0a97712a8a7956f714c22e457419ae61de8c50f6..641a9194d1049d4791cabcb17267ea44241310fa 100644 (file)
@@ -1,4 +1,12 @@
-Numerics = {"001": "RPL_WELCOME", "433": "ERR_NICKNAMEINUSE", "004": "RPL_MYINFO", "005": "RPL_ISUPPORT", "353": "RPL_NAMREPLY", "366": "RPL_ENDOFNAMES", "331": "RPL_NOTOPIC", "332": "RPL_TOPIC", "333": "RPL_TOPICWHOTIME"}\r
+Numerics = {"001": "RPL_WELCOME", "433": "ERR_NICKNAMEINUSE", "004": "RPL_MYINFO", "005": "RPL_ISUPPORT", "353": "RPL_NAMREPLY", "366": "RPL_ENDOFNAMES", "331": "RPL_NOTOPIC", "332": "RPL_TOPIC", "333": "RPL_TOPICWHOTIME"};\r
+\r
+registeredCTCPs = {\r
+  "VERSION": function(x) { return "qwebirc 0.01. Copyright (C) Chris Porter 2008"; },\r
+  "USERINFO": function(x) { return "qwebirc"; },\r
+  "TIME": function(x) { function pad(x) { x = "" + x; if(x.length == 1) x = "0" + x; return x; }var d = new Date(); return DaysOfWeek[d.getDay()] + " " + MonthsOfYear[d.getMonth()] + " " + pad(d.getDate()) + " "  + pad(d.getHours()) + ":" + pad(d.getMinutes()) + ":" + pad(d.getSeconds()) + " " + d.getFullYear() },\r
+  "PING": function(x) { return x; },\r
+  "CLIENTINFO": function(x) { return "PING VERSION TIME USERINFO CLIENTINFO"; },\r
+};\r
 \r
 function BaseIRCClient(nickname, view) {\r
   var self = this;\r
@@ -6,6 +14,7 @@ function BaseIRCClient(nickname, view) {
   this.signedOn = false;\r
   this.pmodes = ["b", "k,", "o", "l", "v"];\r
   this.channels = {}\r
+  var nextctcp = 0;\r
   \r
   /* attempt javascript inheritence! */\r
   this.dispatch = function(data) {\r
@@ -59,7 +68,7 @@ function BaseIRCClient(nickname, view) {
   \r
   this.irc_NICK = function(prefix, params) {\r
     var user = prefix;\r
-    var oldnick = user.split("!", 1);\r
+    var oldnick = hosttonick(user);\r
     var newnick = params[0];\r
     \r
     if(self.nickname == oldnick)\r
@@ -136,15 +145,45 @@ function BaseIRCClient(nickname, view) {
     return true;\r
   }\r
   \r
+  var processCTCP = function(message) {\r
+    if(message.charAt(0) == "\x01") {\r
+      if(message.charAt(message.length - 1) == "\x01") {\r
+        message = message.substr(1, message.length - 2);\r
+      } else {\r
+        message = message.substr(1);\r
+      }\r
+      return message.splitMax(" ", 2);\r
+    }\r
+  }\r
+  \r
   this.irc_PRIVMSG = function(prefix, params) {\r
     var user = prefix;\r
     var target = params[0];\r
     var message = ANI(params, -1);\r
     \r
-    if(target == self.nickname) {\r
-      view.userPrivmsg(user, message);\r
+    var ctcp = processCTCP(message);\r
+    if(ctcp) {\r
+      var type = ctcp[0].toUpperCase();\r
+      \r
+      var replyfn = registeredCTCPs[type];\r
+      if(replyfn) {\r
+        var t = new Date().getTime() / 1000;\r
+        if(t > nextctcp)\r
+          self.send("NOTICE " + hosttonick(user) + " :\x01" + type + " " + replyfn(ctcp[1]) + "\x01");\r
+        nextctcp = t + 5;\r
+      }\r
+      \r
+      if(target == self.nickname) {\r
+        view.userCTCP(user, type, ctcp[1]);\r
+      } else {\r
+        view.channelCTCP(user, target, type, ctcp[1]);\r
+      }\r
     } else {\r
-      view.channelPrivmsg(user, target, message);\r
+      if(target == self.nickname) {\r
+        view.userPrivmsg(user, message);\r
+      } else {\r
+        view.channelPrivmsg(user, target, message);\r
+      }\r
     }\r
     \r
     return true;\r
@@ -158,7 +197,12 @@ function BaseIRCClient(nickname, view) {
     if(user == "") {\r
       view.serverNotice(message);\r
     } else if(target == self.nickname) {\r
-      view.userNotice(user, message);\r
+      var ctcp = processCTCP(message);\r
+      if(ctcp) {\r
+        view.userCTCPReply(user, ctcp[0], ctcp[1]);\r
+      } else {\r
+        view.userNotice(user, message);\r
+      }\r
     } else {\r
       view.channelNotice(user, target, message);\r
     }\r
@@ -225,7 +269,7 @@ function BaseIRCClient(nickname, view) {
     var supportedhash = {};\r
     \r
     for(var i=0;i<supported.length;i++) {\r
-      var l = supported[i].split("=", 2);\r
+      var l = supported[i].splitMax("=", 2);\r
       view.supported(l[0], l[1]);\r
     }\r
   }\r
diff --git a/static/js/irc/commandparser.js b/static/js/irc/commandparser.js
new file mode 100644 (file)
index 0000000..84c6588
--- /dev/null
@@ -0,0 +1,167 @@
+function CommandParser(ui, send) {\r
+  var self = this;\r
+  var aliases = {\r
+    "J": "JOIN",\r
+    "K": "KICK",\r
+    "MSG": "PRIVMSG",\r
+    "Q": "QUERY"\r
+  };\r
+  \r
+  this.dispatch = function(line) {\r
+    if(line.length == 0)\r
+      return;\r
+\r
+    if(line.charAt(0) != "/") {\r
+      self.cmd_SAY(line);\r
+      return;\r
+    }\r
+    \r
+    var line = line.substr(1);\r
+    var allargs = line.splitMax(" ", 2);\r
+    var command = allargs[0].toUpperCase();\r
+    var args = allargs[1];\r
+        \r
+    var aliascmd = aliases[command];\r
+    if(aliascmd)\r
+      command = aliascmd;\r
+    \r
+    var commando = self["cmd_" + command];\r
+    if(!commando) {\r
+      if(args) {\r
+        send(command + " " + args);\r
+      } else {\r
+        send(command);\r
+      }\r
+    } else {\r
+      commando(args);\r
+    }\r
+  }\r
+  \r
+  this.cmd_KICK = function(args) {\r
+    var allargs = args.splitMax(" ", 3);\r
+    \r
+    if(allargs.length < 2) {\r
+      ui.errorMessage("Insufficient arguments for command.")\r
+      return;\r
+    }\r
+\r
+    var channel = allargs[0];\r
+    var target = allargs[1];\r
+    var message = allargs[2];\r
+    if(!message)\r
+      message = "";\r
+      \r
+    send("KICK " + channel + " " + target + " :" + message);\r
+  }\r
+\r
+  var newTargetLine = function(target, type, message, extra) {\r
+    if(!extra)\r
+      extra = {}\r
+      \r
+    extra["n"] = ui.getNickname();\r
+    extra["m"] = message;\r
+    extra["t"] = target;\r
+    \r
+    var window = ui.getWindow(target);\r
+    var channel;\r
+    if(!window) {\r
+      type = "TARGETED" + type;\r
+      target = false;\r
+    } else if(window.ischannel) {\r
+      type = "CHAN" + type;\r
+    } else {\r
+      type = "PRIV" + type;\r
+    }\r
+    ui.newLine(target, "OUR" + type, extra);\r
+  }\r
+    \r
+  this.cmd_ME = function(args) {\r
+    var w = ui.getActiveWindow();\r
+    if(!w || w.name == "") {\r
+      ui.errorMessage("Can't use this command in this window");\r
+      return;\r
+    }\r
+    if(args == undefined)\r
+      args = "";\r
+    \r
+    send("PRIVMSG " + w.name + " :\x01ACTION " + args + "\x01");\r
+    newTargetLine(w.name, "ACTION", args);\r
+  }\r
+  \r
+  this.cmd_CTCP = function(args) {\r
+    var allargs = args.splitMax(" ", 3);\r
+    if(allargs.length < 2) {\r
+      ui.errorMessage("Insufficient arguments for command.");\r
+      return;\r
+    }\r
+    \r
+    var target = allargs[0];\r
+    var type = allargs[1].toUpperCase();\r
+    var message = allargs[2];\r
+    if(message == undefined)\r
+      message = "";\r
+\r
+    if(message == "") {\r
+      send("PRIVMSG " + target + " :\x01" + type + "\x01");\r
+    } else {\r
+      send("PRIVMSG " + target + " :\x01" + type + " " + message + "\x01");\r
+    }\r
+    \r
+    newTargetLine(target, "CTCP", message, {"x": type});\r
+  }\r
+  \r
+  this.cmd_PRIVMSG = function(args) {\r
+    var allargs = args.splitMax(" ", 2);\r
+    \r
+    if(allargs.length < 2) {\r
+      ui.errorMessage("Insufficient arguments for command.")\r
+      return;\r
+    }\r
+\r
+    var target = allargs[0];\r
+    var message = allargs[1];\r
+    \r
+    newTargetLine(target, "MSG", message);\r
+    send("PRIVMSG " + target + " :" + message);\r
+  }\r
+  \r
+  this.cmd_NOTICE = function(args) {\r
+    var allargs = args.splitMax(" ", 2);\r
+    \r
+    if(allargs.length < 2) {\r
+      ui.errorMessage("Insufficient arguments for command.")\r
+      return;\r
+    }\r
+    \r
+    var target = allargs[0];\r
+    var message = allargs[1];\r
+\r
+    newTargetLine(target, "NOTICE", message);\r
+    send("NOTICE " + target + " :" + message);\r
+  }\r
+  \r
+  this.cmd_QUERY = function(args) {\r
+    var allargs = args.splitMax(" ", 2);\r
+\r
+    if(allargs.length < 1) {\r
+      ui.errorMessage("Insufficient arguments for command.")\r
+      return;\r
+    }\r
+          \r
+    ui.newWindow(allargs[0]);\r
+    ui.selectTab(allargs[0]);\r
+    \r
+    if((allargs.length > 1) && (allargs[1] != ""))\r
+      self.cmd_PRIVMSG(args);\r
+  }\r
+  \r
+  this.cmd_SAY = function(args) {\r
+    var w = ui.getActiveWindow();\r
+    if(!w || w.name == "") {\r
+      ui.errorMessage("Can't use this command in this window");\r
+      return;\r
+    }\r
+    \r
+    self.cmd_PRIVMSG(w.name + " " + args);\r
+  }\r
+}\r
index 2e68763eb5eff5bf6a609650e22f5bc7dbfc0a93..0e0a2a8367b160ee6dba8bca960801b4951b0082 100644 (file)
@@ -3,27 +3,32 @@ function IRCClient(nickname, ui) {
   this.prefixes = "@+";\r
   this.modeprefixes = "ov";\r
   \r
-  newLine = function(window, type, data) {\r
+  var newLine = function(window, type, data) {\r
     if(!data)\r
       data = {};\r
       \r
     ui.newLine(window, type, data);\r
   }\r
   \r
-  newChanLine = function(channel, type, user, extra) {\r
+  var newChanLine = function(channel, type, user, extra) {\r
     if(!extra)\r
       extra = {};\r
 \r
     extra["n"] = hosttonick(user);\r
     extra["h"] = hosttohost(user);\r
     extra["c"] = channel;\r
+    extra["-"] = self.nickname;\r
     \r
     newLine(channel, type, extra);\r
   }\r
   \r
-  newServerLine = function(type, data) {\r
+  var newServerLine = function(type, data) {\r
     newLine("", type, data);\r
   }\r
+\r
+  var newActiveLine = function(type, data) {\r
+    newLine(false, type, data);\r
+  }\r
   \r
   this.rawNumeric = function(numeric, prefix, params) {\r
     newServerLine("RAW", {"n": "numeric", "m": params.slice(1).join(" ")});\r
@@ -143,7 +148,7 @@ function IRCClient(nickname, ui) {
     var clist = [];\r
     for(var c in channels) {\r
       clist.push(c);\r
-      newChanLine(c, "QUIT", user);\r
+      newChanLine(c, "QUIT", user, {"m": message});\r
     }\r
     \r
     self.tracker.removeNick(nick);\r
@@ -171,7 +176,7 @@ function IRCClient(nickname, ui) {
   }\r
   \r
   this.channelTopic = function(user, channel, topic) {\r
-    newChanLine(channel, "TOPIC", user, {"m": topic});    \r
+    newChanLine(channel, "TOPIC", user, {"m": topic});\r
     ui.updateTopic(channel, topic);\r
   }\r
   \r
@@ -179,6 +184,50 @@ function IRCClient(nickname, ui) {
     ui.updateTopic(channel, topic);\r
   }\r
   \r
+  this.chanCTCP = function(user, channel, type, args) {\r
+    if(args == undefined)\r
+      args = "";\r
+\r
+    if(type == "ACTION") {\r
+      newChanLine(channel, "CHANACTION", user, {"m": args, "c": channel});\r
+      return;\r
+    }\r
+    \r
+    newChanLine(channel, "CHANCTCP", user, {"x": type, "m": args, "c": channel});\r
+  }\r
+  \r
+  this.userCTCP = function(user, type, args) {\r
+    var nick = hosttonick(user);\r
+    var host = hosttohost(user);\r
+    if(args == undefined)\r
+      args = "";\r
+    \r
+    if(type == "ACTION") {      \r
+      ui.newWindow(nick, false);\r
+      newLine(nick, "PRIVACTION", {"m": args, "x": type, "h": host, "n": nick});\r
+      return;\r
+    }\r
+    \r
+    if(ui.getWindow(nick)) {\r
+      newLine(nick, "PRIVCTCP", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});\r
+    } else {\r
+      newActiveLine("PRIVCTCP", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});\r
+    }\r
+  }\r
+  \r
+  this.userCTCPReply = function(user, type, args) {\r
+    var nick = hosttonick(user);\r
+    var host = hosttohost(user);\r
+    if(args == undefined)\r
+      args = "";\r
+    \r
+    if(ui.getWindow(nick)) {\r
+      newLine(nick, "CTCPREPLY", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});\r
+    } else {\r
+      newActiveLine("CTCPREPLY", {"m": args, "x": type, "h": host, "n": nick, "-": self.nickname});\r
+    }\r
+  }\r
+  \r
   this.channelPrivmsg = function(user, channel, message) {\r
     newChanLine(channel, "CHANMSG", user, {"m": message});\r
   }\r
@@ -190,7 +239,6 @@ function IRCClient(nickname, ui) {
   this.userPrivmsg = function(user, message) {\r
     var nick = hosttonick(user);\r
     var host = hosttohost(user);\r
-\r
     ui.newWindow(nick, false);\r
     newLine(nick, "PRIVMSG", {"m": message, "h": host, "n": nick});\r
   }\r
@@ -203,7 +251,11 @@ function IRCClient(nickname, ui) {
     var nick = hosttonick(user);\r
     var host = hosttohost(user);\r
 \r
-    newServerLine("NOTICE", {"m": message, "h": host, "n": nick});\r
+    if(ui.getWindow(nick)) {\r
+      newLine(nick, "PRIVNOTICE", {"m": message, "h": host, "n": nick});\r
+    } else {\r
+      newActiveLine("PRIVNOTICE", {"m": message, "h": host, "n": nick});\r
+    }\r
   }\r
   \r
   this.userInvite = function(user, channel) {\r
@@ -265,6 +317,10 @@ function IRCClient(nickname, ui) {
   }\r
   \r
   this.disconnected = function() {\r
+    for(var x in this.parent.channels) {\r
+      ui.closeWindow(x);\r
+    }\r
+\r
     self.tracker = undefined;\r
     \r
     newServerLine("DISCONNECT");\r
@@ -289,7 +345,12 @@ function IRCClient(nickname, ui) {
   }\r
   \r
   this.parent = new BaseIRCClient(nickname, this);\r
-  ui.send = this.parent.send;\r
+  this.commandparser = new CommandParser(ui, this.parent.send);\r
+  ui.send = this.commandparser.dispatch;\r
+  ui.getNickname = function() {\r
+    return self.nickname;\r
+  }\r
+  \r
   this.connect = this.parent.connect;\r
   this.disconnect = this.parent.disconnect;\r
 }\r
index 5742b034759540adab655118c87e3b5dedcb481d..107dca2e4169584ce039157f2cc6bf6e3ba8d83c 100644 (file)
@@ -53,3 +53,52 @@ String.prototype.replaceAll = function(f, t) {
   }\r
   return c;\r
 }\r
+\r
+/* how horribly inefficient (again) */\r
+String.prototype.splitMax = function(by, max) {\r
+  var items = this.split(by);\r
+  var newitems = items.slice(0, max-1);\r
+\r
+  if(items.length >= max)\r
+    newitems.push(items.slice(max-1).join(by));\r
+  \r
+  return newitems;\r
+}\r
+\r
+alert("a".splitMax(" ", 2));\r
+alert("a b".splitMax(" ", 2));\r
+alert("a b c".splitMax(" ", 2));\r
+alert("a b".splitMax(" ", 3));\r
+alert("a b c".splitMax(" ", 3));\r
+alert("a".splitMax(" ", 4));\r
+alert("a b".splitMax(" ", 4));\r
+alert("a b c".splitMax(" ", 4));\r
+alert("a".splitMax(" ", 1));\r
+alert("a b".splitMax(" ", 1));\r
+alert("a b c".splitMax(" ", 1));\r
+\r
+DaysOfWeek = {\r
+  0: "Sun",\r
+  1: "Mon",\r
+  2: "Tue",\r
+  3: "Wed",\r
+  4: "Thu",\r
+  5: "Fri",\r
+  6: "Sat"\r
+}\r
+\r
+MonthsOfYear = {\r
+  0: "Jan",\r
+  1: "Feb",\r
+  2: "Mar",\r
+  3: "Apr",\r
+  4: "May",\r
+  5: "Jun",\r
+  6: "Jul",\r
+  7: "Aug",\r
+  8: "Sep",\r
+  9: "Oct",\r
+  10: "Nov",\r
+  11: "Dec"\r
+}\r
+\r
index 79e991e63e55f9ac7b4560ea36f1fb8e9198c680..fa6bfad651babb677d52576096599f815dc2d94d 100644 (file)
@@ -72,7 +72,55 @@ var DefaultTheme = {
   "CHANNOTICE": [\r
     "-$n:$c- $m"\r
   ],\r
-  "NOTICE": [\r
+  "PRIVNOTICE": [\r
     "-$n- $m"\r
+  ],\r
+  "OURCHANMSG": [\r
+    "<$n> $m"\r
+  ],\r
+  "OURPRIVMSG": [\r
+    "<$n> $m"\r
+  ],\r
+  "OURTARGETEDMSG": [\r
+    "*$t* $m"\r
+  ],\r
+  "OURTARGETEDNOTICE": [\r
+    "[notice($t)] $m"\r
+  ],\r
+  "OURCHANNOTICE": [\r
+    "-$n:$t- $m"\r
+  ],\r
+  "OURPRIVNOTICE": [\r
+    "-$n- $m"\r
+  ],\r
+  "OURCHANACTION": [\r
+    " * $n $m"\r
+  ],\r
+  "OURPRIVACTION": [\r
+    " * $n $m"\r
+  ],\r
+  "CHANACTION": [\r
+    " * $n $m"\r
+  ],\r
+  "PRIVACTION": [\r
+    " * $n $m"\r
+  ],\r
+  "CHANCTCP": [\r
+    "$n [$h] requested CTCP $x from $c: $m"\r
+  ],\r
+  "PRIVCTCP": [\r
+    "$n [$h] requested CTCP $x from $-: $m"\r
+  ],\r
+  "CTCPREPLY": [\r
+    "CTCP $x reply from $n: $m"\r
+  ],\r
+  "OURCHANCTCP": [\r
+    "[ctcp($t)] $x $m"\r
+  ],\r
+  "OURPRIVCTCP": [\r
+    "[ctcp($t)] $x $m"\r
+  ],\r
+  "OURTARGETEDCTCP": [\r
+    "[ctcp($t)] $x $m"\r
   ]\r
 }\r
index d0319798716a2c3e6511cdf3d029c401b9d8a944..203dc196c86ca78cc6c29fd4d5709703c1002e0b 100644 (file)
@@ -2,7 +2,7 @@ function UglyUI(parent, theme) {
   var self = this;\r
   var active;\r
   \r
-  var tabs = new Element("div", {"styles": { "border": "1px solid black", "padding": "4px" } });\r
+  var tabs = new Element("div", {"styles": { "border": "1px solid black", "padding": "4px", "font-family": "Lucida Console" } });\r
   parent.appendChild(tabs);\r
   var tabhash = {};\r
   \r
@@ -61,20 +61,25 @@ function UglyUI(parent, theme) {
     tabs.appendChild(tab);\r
     \r
     if(windowname != "") {\r
-      var tabclose = new Element("span", {"styles": { "border": "1px black solid" } });\r
+      var tabclose = new Element("span", {"styles": { "border": "1px black solid", "margin-left": "5px", "padding": "2px", "font-size": "0.5em" } });\r
       tabclose.addEvent("click", function() {\r
         if(ischannel)\r
-          self.send("PART " + windowname);\r
+          self.send("/PART " + windowname);\r
+\r
         self.closeWindow(windowname);\r
       });\r
       tabclose.setText("X");\r
       tab.appendChild(tabclose);\r
     }\r
-    tabhash[windowname] = { "container": container, "tab": tab, "element": e, "lastcolour": false, "nicklist": nicklist, "topic": topic };\r
+    tabhash[windowname] = { "name": windowname, "container": container, "tab": tab, "element": e, "lastcolour": false, "nicklist": nicklist, "topic": topic, "ischannel": ischannel };\r
     \r
     return tabhash[windowname];\r
   }\r
   \r
+  this.getWindow = function(windowname) {\r
+    return tabhash[windowname];\r
+  }\r
+  \r
   this.updateNickList = function(windowname, nicks) {\r
     var w = tabhash[windowname];\r
     if(!w)\r
@@ -105,23 +110,32 @@ function UglyUI(parent, theme) {
   }\r
   \r
   this.selectTab = function(windowname) {\r
+    var w = tabhash[windowname];\r
+    if(!w)\r
+      return;\r
+      \r
     for(var i in tabhash) {\r
       var o = tabhash[i];\r
       o.container.setStyle("display", "none");\r
       o.tab.setStyle("background", "#eee");\r
     }\r
     \r
-    tabhash[windowname].container.setStyle("display", "block");\r
-    tabhash[windowname].tab.setStyle("background", "#dff");\r
-    tabhash[windowname].tab.setStyle("color", "");\r
+    w.container.setStyle("display", "block");\r
+    w.tab.setStyle("background", "#dff");\r
+    w.tab.setStyle("color", "");\r
     self.active = windowname;\r
   }\r
   \r
-  this.newLine = function(windowname,  type, line, colour) {\r
+  this.newLine = function(windowname, type, line, colour) {\r
     var window = tabhash[windowname];\r
     if(!window) {\r
-      window = tabhash[""];\r
-      windowname = "";\r
+      if(windowname == false) {\r
+        windowname = self.active;\r
+        window = tabhash[self.active];\r
+      } else {\r
+        window = tabhash[""];\r
+        windowname = "";\r
+      }\r
     }\r
     \r
     var wx = window;\r
@@ -148,6 +162,10 @@ function UglyUI(parent, theme) {
       wx.tab.setStyle("color", "red");\r
   }\r
   \r
+  this.getActiveWindow = function() {\r
+    return tabhash[self.active];\r
+  }\r
+  \r
   this.closeWindow = function(windowname) {\r
     var w = tabhash[windowname];\r
     if(!w)\r
@@ -155,8 +173,14 @@ function UglyUI(parent, theme) {
     \r
     window.removeChild(w.container);\r
     tabs.removeChild(w.tab);\r
-    self.selectTab("");\r
+    \r
+    if(self.active == windowname)\r
+      self.selectTab("");\r
     \r
     delete tabhash[windowname];\r
   }\r
+  \r
+  this.errorMessage = function(message) {\r
+    self.newLine(false, "", message, "red");\r
+  }\r
 }\r
index 68a9891040283454438b93104baf907b60ec4936..3f690dece344bd5a7ea930ddb44b27a2906899ed 100644 (file)
@@ -13,6 +13,7 @@
   <script type="text/javascript" src="js/irc/irclib.js"></script>\r
   <script type="text/javascript" src="js/irc/baseirc.js"></script>\r
   <script type="text/javascript" src="js/irc/irctracker.js"></script>\r
+  <script type="text/javascript" src="js/irc/commandparser.js"></script>\r
   <script type="text/javascript" src="js/irc/ircclient.js"></script>\r
   <script type="text/javascript">  \r
     var ui;\r
       ui = new UglyUI($("ircui"), theme);\r
       \r
       ui.newWindow("", false, "Status");\r
-      ui.newLine("", "", "Welcome to QuakeNet webIRC", "#f99");\r
       ui.selectTab("");\r
+      ui.newLine("", "", "Welcome to QuakeNet webIRC -- comments/bugs to slug@quakenet.org.", "#f99");\r
 \r
-      var IRC = new IRCClient(prompt("Nickname","moofishaax"), ui);\r
+      var IRC = new IRCClient(prompt("Nickname","uberfish"), ui);\r
       IRC.connect();\r
     });\r
 \r