Logo accreditation
[KiwiIRC.git] / js / front.js
index f056ed74f75733115ff410b754e5f5e6a397d4b2..05591769935d26b0dcef9e765b17054d0c9febd3 100644 (file)
@@ -1,4 +1,4 @@
-/*jslint devel: true, undef: true, browser: true, continue: true, sloppy: true, forin: true, newcap: true, plusplus: true, maxerr: 50, indent: 4 */
+/*jslint regexp: true, nomen: true, devel: true, undef: true, browser: true, continue: true, sloppy: true, forin: true, newcap: true, plusplus: true, maxerr: 50, indent: 4 */
 /*global gateway, io, $, iScroll, agent, touchscreen, init_data, plugs, plugins, registerTouches, randomString */
 kiwi.front = {
     revision: 38,
@@ -12,6 +12,8 @@ kiwi.front = {
     buffer: [],
     buffer_pos: 0,
 
+    cache: {},
+    
     original_topic: '',
     
     init: function () {
@@ -31,6 +33,9 @@ kiwi.front = {
         $(kiwi.gateway).bind("onnick", kiwi.front.onNick);
         $(kiwi.gateway).bind("onuserlist", kiwi.front.onUserList);
         $(kiwi.gateway).bind("onuserlist_end", kiwi.front.onUserListEnd);
+        $(kiwi.gateway).bind("onlist_start", kiwi.front.onChannelListStart);
+        $(kiwi.gateway).bind("onlist_channel", kiwi.front.onChannelList);
+        $(kiwi.gateway).bind("onlist_end", kiwi.front.onChannelListEnd);
         $(kiwi.gateway).bind("onjoin", kiwi.front.onJoin);
         $(kiwi.gateway).bind("ontopic", kiwi.front.onTopic);
         $(kiwi.gateway).bind("onpart", kiwi.front.onPart);
@@ -74,9 +79,31 @@ kiwi.front = {
         kiwi.front.registerKeys();
         
         $('#kiwi .toolbars').resize(kiwi.front.doLayoutSize);
+        $(window).resize(kiwi.front.doLayoutSize);
+
+        // Add the resizer for the userlist
+        $('<div id="nicklist_resize" style="position:absolute; cursor:w-resize; width:5px;"></div>').appendTo('#kiwi');
+        $('#nicklist_resize').draggable({axis: "x", drag: function () {
+            var t = $(this),
+                new_width = $(document).width() - parseInt(t.css('left'), 10);
+            
+            new_width = new_width - parseInt($('#kiwi .userlist').css('margin-left'), 10);
+            new_width = new_width - parseInt($('#kiwi .userlist').css('margin-right'), 10);
+
+            // Make sure we don't remove the userlist alltogether
+            if (new_width < 20) {
+                $(this).data('draggable').offset.click.left = 10;
+                console.log('whoaa');
+            }
+
+            kiwi.front.cur_channel.setUserlistWidth(new_width);
+        }});
+
 
         $('#kiwi .formconnectwindow').submit(function () {
             var netsel = $('#kiwi .formconnectwindow .network'),
+                netport = $('#kiwi .formconnectwindow .port'),
+                netssl = $('#kiwi .formconnectwindow .ssl'),
                 nick = $('#kiwi .formconnectwindow .nick'),
                 tmp;
             
@@ -93,9 +120,9 @@ kiwi.front = {
 
             kiwi.front.doLayout();
             try {
-                kiwi.front.run('/connect ' + netsel.val());
+                kiwi.front.run('/connect ' + netsel.val() + ' ' + netport.val() + ' ' + (netssl.attr('checked') ? 'true' : ''));
             } catch (e) {
-                alert(e);
+                console.log(e);
             }
             
             $('#kiwi .connectwindow').slideUp('', kiwi.front.barsShow);
@@ -172,6 +199,8 @@ kiwi.front = {
             kiwi.front.joinChannel($(this).text());
             return false;
         });
+        
+        kiwi.data.set('chanList', []);
 
         (function () {
             var i;
@@ -182,7 +211,7 @@ kiwi.front = {
     },
     
     doLayoutSize: function () {
-        var kiwi, toolbars, ul, n_top, n_bottom;
+        var kiwi, toolbars, ul, n_top, n_bottom, nl;
         kiwi = $('#kiwi');
 
         if (kiwi.width() < 330 && !kiwi.hasClass('small_kiwi')) {
@@ -201,7 +230,10 @@ kiwi.front = {
         n_bottom = $(document).height() - parseInt($('#kiwi .control').offset().top, 10);
 
         $('#kiwi .windows').css({top: n_top + 'px', bottom: n_bottom + 'px'});
-        $('#kiwi .userlist').css({top: n_top + 'px', bottom: n_bottom + 'px'});
+        ul.css({top: n_top + 'px', bottom: n_bottom + 'px'});
+
+        nl = $('#nicklist_resize');
+        nl.css({top: n_top + 'px', bottom: n_bottom + 'px', left: $(document).width() - ul.outerWidth(true)});
     },
 
 
@@ -252,16 +284,23 @@ kiwi.front = {
                 
             case '/connect':
             case '/server':
-                if (parts[1] === undefined) {
-                    alert('Usage: /connect servername [port]');
+                if (typeof parts[1] === 'undefined') {
+                    alert('Usage: /connect servername [port] [ssl]');
                     break;
                 }
                 
-                if (parts[2] === undefined) {
+                if (typeof parts[2] === 'undefined') {
                     parts[2] = 6667;
                 }
-                kiwi.front.cur_channel.addMsg(null, ' ', '=== Connecting to ' + parts[1] + '...', 'status');
-                kiwi.gateway.connect(parts[1], parts[2], 0);
+                
+                if ((typeof parts[3] === 'undefined') || !parts[3] || (parts[3] === 'false') || (parts[3] === 'no')) {
+                    parts[3] = false;
+                } else {
+                    parts[3] = true;
+                }
+                
+                kiwi.front.cur_channel.addMsg(null, ' ', '=== Connecting to ' + parts[1] + ' on port ' + parts[2] + (parts[3] ? ' using SSL' : '') + '...', 'status');
+                kiwi.gateway.connect(parts[1], parts[2], parts[3]);
                 break;
                 
             case '/nick':
@@ -320,7 +359,9 @@ kiwi.front = {
             
             case '/k':
             case '/kick':
-                if (typeof parts[1] === 'undefined') return;
+                if (typeof parts[1] === 'undefined') {
+                    return;
+                }
                 kiwi.gateway.raw('KICK ' + kiwi.front.cur_channel.name + ' ' + msg.split(' ', 2)[1]);
                 break;
 
@@ -349,7 +390,7 @@ kiwi.front = {
                 break;
 
             case '/quit':
-                kiwi.gateway.quit(msg.split(" ", 2)[1]);
+                kiwi.gateway.quit(parts.slice(1).join(' '));
                 break;
 
             case '/topic':
@@ -377,7 +418,7 @@ kiwi.front = {
 
             default:
                 //kiwi.front.cur_channel.addMsg(null, ' ', '--> Invalid command: '+parts[0].substring(1));
-                kiwi.gateway.raw(msg.substring(1));
+                kiwi.gateway.raw(msg.substring(1)); 
             }
 
         } else {
@@ -543,8 +584,8 @@ kiwi.front = {
                 if (kiwi.front.nickStripPrefix($(this).text()) === data.effected_nick) {
 
                     if (data.mode.split('')[0] === '+') {
-                        for (i in kiwi.gateway.user_prefixes) {
-                            if (kiwi.gateway.user_prefixes[i].mode == data.mode.split('')[1]) {
+                        for (i = 0; i < kiwi.gateway.user_prefixes.length; i++) {
+                            if (kiwi.gateway.user_prefixes[i].mode === data.mode.split('')[1]) {
                                 new_nick_text = kiwi.gateway.user_prefixes[i].symbol + data.effected_nick;
                                 break;
                             }
@@ -586,6 +627,68 @@ kiwi.front = {
         document.userlist_updating = false;
     },
     
+    onChannelListStart: function (e, data) {
+        var tab, table;
+        
+        tab = new Utilityview('Channel List');
+        tab.div.css('overflow-y', 'scroll');
+        table = $('<table style="margin:1em 2em;"><thead style="font-weight: bold;"><tr><td>Channel Name</td><td>Members</td><td style="padding-left: 2em;">Topic</td></tr></thead><tbody style="vertical-align: top;"></tbody>');
+        tab.div.append(table);
+        
+        kiwi.front.cache.list = {chans: [], tab: tab, table: table,
+            update: function (newChans) {
+                var body = this.table.children('tbody:first').detach(),
+                    chan,
+                    html;
+                
+                html = '';
+                for (chan in newChans) {
+                    this.chans.push(newChans[chan]);
+                    html += newChans[chan].html;
+                }
+                body.append(html);
+                this.table.append(body);
+                
+            },
+            finalise: function () {
+                var body = this.table.children('tbody:first').detach(),
+                    list,
+                    chan;
+                
+                list = $.makeArray($(body).children());
+                
+                for (chan in list) {
+                    list[chan] = $(list[chan]).detach();
+                }
+                
+                list = _.sortBy(list, function (channel) {
+                    return parseInt(channel.children('.num_users').first().text(), 10);
+                }).reverse();
+                
+                for (chan in list) {
+                    body.append(list[chan]);
+                }
+                
+                this.table.append(body);
+                
+            }};
+    },
+    onChannelList: function (e, data) {
+        var chans;
+        console.log(data);
+        data = data.chans;
+        //data = [data];
+        for (chans in data) {
+            data[chans] = {data: data[chans], html: '<tr><td><a class="chan">' + data[chans].channel + '</a></td><td class="num_users" style="text-align: center;">' + data[chans].num_users + '</td><td style="padding-left: 2em;">' + kiwi.front.format(data[chans].topic) + '</td></tr>'};
+        }
+        kiwi.front.cache.list.update(data);
+    },
+    onChannelListEnd: function (e, data) {
+        kiwi.front.cache.list.finalise();
+        kiwi.front.cache.list.tab.show();
+    },
+
+
     onJoin: function (e, data) {
         if (!kiwi.front.tabviewExists(data.channel)) {
             kiwi.front.tabviewAdd(data.channel.toLowerCase());
@@ -714,12 +817,19 @@ kiwi.front = {
     },
     
     registerKeys: function () {
+        var tabcomplete = {active: false, data: [], prefix: ''};
         $('#kiwi_msginput').bind('keydown', function (e) {
-            var windows, meta, num, msg, data, candidates, word_pos, word, i;
+            var windows, meta, num, msg, data, candidates, word_pos, word, i, self;
             windows = $('#windows');
             //var meta = e.altKey;
             meta = e.ctrlKey;
             
+            if (e.which !== 9) {
+                tabcomplete.active = false;
+                tabcomplete.data = [];
+                tabcomplete.prefix = '';
+            }
+            
             switch (true) {
             case (e.which >= 48) && (e.which <= 57):
                 if (meta) {
@@ -778,40 +888,59 @@ kiwi.front = {
                 break;
                 
             case e.which === 9:                // tab
-                // Get possible autocompletions
-                data = [];
-                kiwi.front.cur_channel.userlist.children().each(function () {
-                    var nick;
-                    nick = kiwi.front.nickStripPrefix($('a.nick', this).text());
-                    data.push(nick);
-                });
+                tabcomplete.active = true;
+                if (_.isEqual(tabcomplete.data, [])) {
+                    // Get possible autocompletions
+                    data = [];
+                    kiwi.front.cur_channel.userlist.children().each(function () {
+                        var nick;
+                        nick = kiwi.front.nickStripPrefix($('a.nick', this).text());
+                        data.push(nick);
+                    });
+                    data = _.sortBy(data, function (nick) {
+                        return nick;
+                    });
+                    tabcomplete.data = data;
+                }
                 
-                // Do the autocomplete
-                if (this.value.length === this.selectionStart && this.value.length === this.selectionEnd) {
-                    candidates = [];
-                    
-                    word_pos = this.value.lastIndexOf(' ');
-                    word = "";
-                    if (word_pos === -1) {
-                        word = this.value;
-                    } else {
-                        word = this.value.substr(word_pos);
+                if (this.value[this.selectionStart - 1] === ' ') {
+                    return false;
+                }
+                self = this;
+                (function () {
+                    var tokens = self.value.substring(0, self.selectionStart).split(" "),
+                        val,
+                        p1,
+                        newnick,
+                        range;
+                    nick = tokens[tokens.length - 1];
+                    if (tabcomplete.prefix === '') {
+                        tabcomplete.prefix = nick;
                     }
-                    word = word.trim();
                     
-                    // filter data to find only strings that start with existing value
-                    for (i = 0; i < data.length; i++) {
-                        if (data[i].indexOf(word) === 0 && data[i].length > word.length) {
-                            candidates.push(data[i]);
-                        }
-                    }
+                    tabcomplete.data = _.select(tabcomplete.data, function (n) {
+                        return (n.toLowerCase().indexOf(tabcomplete.prefix.toLowerCase()) === 0);
+                    });
                     
-                    if (candidates.length > 0) {
-                        // some candidates for autocompletion are found
-                        this.value = this.value.substring(0, word_pos) + ' ' + candidates[0] + ': ';
-                        this.selectionStart = this.value.length;
+                    if (tabcomplete.data.length > 0) {
+                        p1 = self.selectionStart - (nick.length);
+                        val = self.value.substr(0, p1);
+                        newnick = tabcomplete.data.shift();
+                        tabcomplete.data.push(newnick);
+                        val += newnick;
+                        val += self.value.substr(self.selectionStart);
+                        self.value = val;
+                        if (self.setSelectionRange) {
+                            self.setSelectionRange(p1 + newnick.length, p1 + newnick.length);
+                        } else if (self.createTextRange) { // not sure if this bit is actually needed....
+                            range = self.createTextRange();
+                            range.collapse(true);
+                            range.moveEnd('character', p1 + newnick.length);
+                            range.moveStart('character', p1 + newnick.length);
+                            range.select();
+                        }
                     }
-                }
+                }());
                 return false;
             }
         });
@@ -1037,12 +1166,6 @@ kiwi.front = {
         kiwi.front.doLayoutSize();
     },
     
-    
-    
-    
-    
-    
-    
     nickStripPrefix: function (nick) {
         var tmp = nick, i, prefix;
         
@@ -1146,7 +1269,89 @@ kiwi.front = {
     barsHide: function () {
         $('#kiwi .toolbars').slideUp();
         $('#kiwi .control').slideUp();
+    },
+    
+    format: function (msg) {
+        var re;
+        
+        if ((!msg) || (typeof msg !== 'string')) {
+            return;
+        }
+        
+        // bold
+        if (msg.indexOf(String.fromCharCode(2)) !== -1) {
+            next = '<b>';
+            while (msg.indexOf(String.fromCharCode(2)) !== -1) {
+                msg = msg.replace(String.fromCharCode(2), next);
+                next = (next === '<b>') ? '</b>' : '<b>';
+            }
+            if (next === '</b>') {
+                msg = msg + '</b>';
+            }
+        }
+        
+        // underline
+        if (msg.indexOf(String.fromCharCode(31)) !== -1) {
+            next = '<u>';
+            while (msg.indexOf(String.fromCharCode(31)) !== -1) {
+                msg = msg.replace(String.fromCharCode(31), next);
+                next = (next === '<u>') ? '</u>' : '<u>';
+            }
+            if (next === '</u>') {
+                msg = msg + '</u>';
+            }
+        }
+        
+        // colour
+        re = /\x03([0-9][0-5]?)(,([0-9][0-5]?))?(.*?)\x03/g;
+        
+        msg = msg.replace(re, function (str, p1, p2, p3, p4) {
+            var fg, bg,
+                col = function (num) {
+                    switch (parseInt(num, 10)) {
+                    case 0:
+                        return '#FFFFFF';
+                    case 1:
+                        return '#000000';
+                    case 2:
+                        return '#000080';
+                    case 3:
+                        return '#008000';
+                    case 4:
+                        return '#FF0000';
+                    case 5:
+                        return '#800040';
+                    case 6:
+                        return '#800080';
+                    case 7:
+                        return '#FF8040';
+                    case 8:
+                        return '#FFFF00';
+                    case 9:
+                        return '#80FF00';
+                    case 10:
+                        return '#008080';
+                    case 11:
+                        return '#00FFFF';
+                    case 12:
+                        return '#0000FF';
+                    case 13:
+                        return '#FF55FF';
+                    case 14:
+                        return '#808080';
+                    case 15:
+                        return '#C0C0C0';
+                    default:
+                        return null;
+                    }
+                };
+            fg = col(p1);
+            bg = col(p3);
+            return '<span style="' + ((fg !== null) ? 'color: ' + fg + '; ' : '') + ((bg !== null) ? 'background-color: ' + bg + ';' : '') + '">' + p4 + '</span>';
+        });
+        return msg;
     }
+    
 };
 
 
@@ -1177,14 +1382,20 @@ var Utilityview = function (name) {
     this.name = rand_name;
     this.title = name;
     this.topic = ' ';
+    this.panel = $('#panel1');
 
-    $('#kiwi .windows .scroller').append('<div id="' + tmp_divname + '" class="messages"></div>');
+    if (typeof $('.scroller', this.panel)[0] === 'undefined') {
+        this.panel.append('<div id="' + tmp_divname + '" class="messages"></div>');
+    } else {
+        $('.scroller', this.panel).append('<div id="' + tmp_divname + '" class="messages"></div>');
+    }
 
     this.tab = $('<li id="' + tmp_tabname + '">' + this.title + '</li>');
     this.tab.click(function () {
         kiwi.front.utilityviews[rand_name.toLowerCase()].show();
     });
     $('#kiwi .utilityviewlist ul').append(this.tab);
+    kiwi.front.doLayoutSize();
     
     this.div = $('#' + tmp_divname);
     this.div.css('overflow', 'hidden');
@@ -1197,12 +1408,13 @@ Utilityview.prototype.title = null;
 Utilityview.prototype.div = null;
 Utilityview.prototype.tab = null;
 Utilityview.prototype.topic = ' ';
+Utilityview.prototype.panel = null;
 Utilityview.prototype.show = function () {
-    $('#kiwi .messages').removeClass("active");
+    $('.messages', this.panel).removeClass("active");
     $('#kiwi .userlist ul').removeClass("active");
     $('#kiwi .toolbars ul li').removeClass("active");
 
-    $('#windows').css('overflow-y', 'hidden');
+    this.panel.css('overflow-y', 'hidden');
     $('#windows').css('right', 0);
     // Activate this tab!
     this.div.addClass('active');
@@ -1219,6 +1431,13 @@ Utilityview.prototype.show = function () {
     }
 };
 
+Utilityview.prototype.setPanel = function (new_panel) {
+    this.div.detach();
+    this.panel = new_panel;
+    this.panel.append(this.div);
+    this.show();
+};
+
 Utilityview.prototype.close = function () {
     this.div.remove();
     this.tab.remove();
@@ -1262,7 +1481,9 @@ Utilityview.prototype.clearPartImage = function () {
  */
 
 
-var Tabview = function () {};
+var Tabview = function () {
+    this.panel = $('#panel1');
+};
 Tabview.prototype.name = null;
 Tabview.prototype.div = null;
 Tabview.prototype.userlist = null;
@@ -1270,31 +1491,32 @@ Tabview.prototype.userlist_width = 100;     // 0 for disabled
 Tabview.prototype.tab = null;
 Tabview.prototype.topic = "";
 Tabview.prototype.safe_to_close = false;                // If we have been kicked/banned/etc from this channel, don't wait for a part message
+Tabview.prototype.panel = null;
 
 Tabview.prototype.show = function () {
     var w, u;
 
-    $('#kiwi .messages').removeClass("active");
+    $('.messages', this.panel).removeClass("active");
     $('#kiwi .userlist ul').removeClass("active");
     $('#kiwi .toolbars ul li').removeClass("active");
     
     w = $('#windows');
     u = $('#kiwi .userlist');
 
-    w.css('overflow-y', 'scroll');
+    this.panel.css('overflow-y', 'scroll');
 
     // Set the window size accordingly
-    if (this.userlist_width > 0) {
-        u.width(this.userlist_width);
-        w.css('right', u.outerWidth(true));
-    } else {
-        w.css('right', 0);
-    }
+    this.setUserlistWidth();
 
     // Activate this tab!
     this.div.addClass('active');
     if (this.userlist_width > 0) {
         this.userlist.addClass('active');
+        // Enable the userlist resizer
+        $('#nicklist_resize').css('display', 'block');
+    } else {
+        // Disable the userlist resizer
+        $('#nicklist_resize').css('display', 'none');
     }
     this.tab.addClass('active');
     
@@ -1327,6 +1549,24 @@ Tabview.prototype.close = function () {
     delete kiwi.front.tabviews[this.name.toLowerCase()];
 };
 
+Tabview.prototype.setUserlistWidth = function (new_width) {
+    var w, u;
+    if (typeof new_width === 'number') {
+        this.userlist_width = new_width;
+    }
+
+    w = $('#windows');
+    u = $('#kiwi .userlist');
+
+    // Set the window size accordingly
+    if (this.userlist_width > 0) {
+        u.width(this.userlist_width);
+        w.css('right', u.outerWidth(true));
+    } else {
+        w.css('right', 0);
+    }    
+};
+
 Tabview.prototype.addPartImage = function () {
     this.clearPartImage();
     
@@ -1385,42 +1625,14 @@ Tabview.prototype.addMsg = function (time, nick, msg, type, style) {
         msg = '';
     }
     
-    // Text formatting
-    // bold
-    if (msg.indexOf(String.fromCharCode(2)) !== -1) {
-        next = '<b>';
-        while (msg.indexOf(String.fromCharCode(2)) !== -1) {
-            msg = msg.replace(String.fromCharCode(2), next);
-            next = (next === '<b>') ? '</b>' : '<b>';
-        }
-        if (next === '</b>') {
-            msg = msg + '</b>';
-        }
-    }
-    
-    // Wierd thing noticed by Dux0r on the irc.esper.net server
-    if (typeof msg !== "string") {
-        msg = '';
-    }
-    
-    // underline
-    if (msg.indexOf(String.fromCharCode(31)) !== -1) {
-        next = '<u>';
-        while (msg.indexOf(String.fromCharCode(31)) !== -1) {
-            msg = msg.replace(String.fromCharCode(31), next);
-            next = (next === '<u>') ? '</u>' : '<u>';
-        }
-        if (next === '</u>') {
-            msg = msg + '</u>';
-        }
-    }
-    
     // Make the channels clickable
     re = new RegExp('\\B(' + kiwi.gateway.channel_prefix + '[^ ,.\\007]+)', 'g');
     msg = msg.replace(re, function (match) {
         return '<a class="chan">' + match + '</a>';
     });
 
+    msg = kiwi.front.format(msg);
+    
     // Build up and add the line
     line_msg = $('<div class="msg ' + type + '"><div class="time">' + time + '</div><div class="nick">' + nick + '</div><div class="text" style="' + style + '">' + msg + ' </div></div>');
     this.div.append(line_msg);
@@ -1438,8 +1650,9 @@ Tabview.prototype.addMsg = function (time, nick, msg, type, style) {
 };
 
 Tabview.prototype.scrollBottom = function () {
-    var w = $('#windows');
-    w[0].scrollTop = w[0].scrollHeight;
+    var panel = this.panel;
+    console.log(panel);
+    panel[0].scrollTop = panel[0].scrollHeight;
 };
 
 Tabview.prototype.changeNick = function (newNick, oldNick) {