1 /*jslint white:true, regexp: true, nomen: true, devel: true, undef: true, browser: true, continue: true, sloppy: true, forin: true, newcap: true, plusplus: true, maxerr: 50, indent: 4 */
2 /*global kiwi, _, io, $, iScroll, agent, touchscreen, init_data, plugs, plugins, registerTouches, randomString */
20 /*global Box, touch_scroll:true */
21 var about_info
, supportsOrientationChange
, orientationEvent
, scroll_opts
;
22 kiwi
.gateway
.nick
= 'kiwi_' + Math
.ceil(100 * Math
.random()) + Math
.ceil(100 * Math
.random());
23 kiwi
.gateway
.session_id
= null;
25 $(kiwi
.gateway
).bind("onmsg", kiwi
.front
.onMsg
);
26 $(kiwi
.gateway
).bind("onnotice", kiwi
.front
.onNotice
);
27 $(kiwi
.gateway
).bind("onaction", kiwi
.front
.onAction
);
28 $(kiwi
.gateway
).bind("onmotd", kiwi
.front
.onMOTD
);
29 $(kiwi
.gateway
).bind("onoptions", kiwi
.front
.onOptions
);
30 $(kiwi
.gateway
).bind("onconnect", kiwi
.front
.onConnect
);
31 $(kiwi
.gateway
).bind("onconnect_fail", kiwi
.front
.onConnectFail
);
32 $(kiwi
.gateway
).bind("ondisconnect", kiwi
.front
.onDisconnect
);
33 $(kiwi
.gateway
).bind("onreconnecting", kiwi
.front
.onReconnecting
);
34 $(kiwi
.gateway
).bind("onnick", kiwi
.front
.onNick
);
35 $(kiwi
.gateway
).bind("onuserlist", kiwi
.front
.onUserList
);
36 $(kiwi
.gateway
).bind("onuserlist_end", kiwi
.front
.onUserListEnd
);
37 $(kiwi
.gateway
).bind("onlist_start", kiwi
.front
.onChannelListStart
);
38 $(kiwi
.gateway
).bind("onlist_channel", kiwi
.front
.onChannelList
);
39 $(kiwi
.gateway
).bind("onlist_end", kiwi
.front
.onChannelListEnd
);
40 $(kiwi
.gateway
).bind("onjoin", kiwi
.front
.onJoin
);
41 $(kiwi
.gateway
).bind("ontopic", kiwi
.front
.onTopic
);
42 $(kiwi
.gateway
).bind("onpart", kiwi
.front
.onPart
);
43 $(kiwi
.gateway
).bind("onkick", kiwi
.front
.onKick
);
44 $(kiwi
.gateway
).bind("onquit", kiwi
.front
.onQuit
);
45 $(kiwi
.gateway
).bind("onmode", kiwi
.front
.onMode
);
46 $(kiwi
.gateway
).bind("onwhois", kiwi
.front
.onWhois
);
47 $(kiwi
.gateway
).bind("onsync", kiwi
.front
.onSync
);
48 $(kiwi
.gateway
).bind("onchannel_redirect", kiwi
.front
.onChannelRedirect
);
49 $(kiwi
.gateway
).bind("ondebug", kiwi
.front
.onDebug
);
50 $(kiwi
.gateway
).bind("onctcp_request", kiwi
.front
.onCTCPRequest
);
51 $(kiwi
.gateway
).bind("onctcp_response", kiwi
.front
.onCTCPResponse
);
52 $(kiwi
.gateway
).bind("onirc_error", kiwi
.front
.onIRCError
);
53 $(kiwi
.gateway
).bind("onkiwi", kiwi
.front
.onKiwi
);
57 // Build the about box
58 kiwi
.front
.boxes
.about
= new Box("about");
59 about_info
= 'UI adapted for ' + agent
;
61 about_info
+= ' touchscreen ';
63 about_info
+= 'usage';
64 $('#tmpl_about_box').tmpl({
66 front_revision
: kiwi
.front
.revision
,
67 gateway_revision
: kiwi
.gateway
.revision
68 }).appendTo(kiwi
.front
.boxes
.about
.content
);
70 //$(window).bind("beforeunload", function(){ kiwi.gateway.quit(); });
73 $('#kiwi').addClass('touchscreen');
75 // Single touch scrolling through scrollback for touchscreens
77 touch_scroll
= new iScroll('windows', scroll_opts
);
80 kiwi
.front
.registerKeys();
82 $('#kiwi .toolbars').resize(kiwi
.front
.doLayoutSize
);
83 $(window
).resize(kiwi
.front
.doLayoutSize
);
85 // Add the resizer for the userlist
86 $('<div id="nicklist_resize" style="position:absolute; cursor:w-resize; width:5px;"></div>').appendTo('#kiwi');
87 $('#nicklist_resize').draggable({axis
: "x", drag: function () {
89 ul
= $('#kiwi .userlist'),
90 new_width
= $(document
).width() - parseInt(t
.css('left'), 10);
92 new_width
= new_width
- parseInt(ul
.css('margin-left'), 10);
93 new_width
= new_width
- parseInt(ul
.css('margin-right'), 10);
95 // Make sure we don't remove the userlist alltogether
97 $(this).data('draggable').offset
.click
.left
= 10;
101 kiwi
.front
.cur_channel
.userlist
.setWidth(new_width
);
102 $('#windows').css('right', ul
.outerWidth(true));
106 $('#kiwi .formconnectwindow').submit(function () {
107 var netsel
= $('#kiwi .formconnectwindow .network'),
108 netport
= $('#kiwi .formconnectwindow .port'),
109 netssl
= $('#kiwi .formconnectwindow .ssl'),
110 nick
= $('#kiwi .formconnectwindow .nick'),
113 if (nick
.val() === '') {
114 nick
.val('Nick please!');
119 tmp
= nick
.val().split(' ');
120 kiwi
.gateway
.nick
= tmp
[0];
122 init_data
.channel
= $('#channel').val();
124 kiwi
.front
.doLayout();
126 kiwi
.front
.run('/connect ' + netsel
.val() + ' ' + netport
.val() + ' ' + (netssl
.attr('checked') ? 'true' : ''));
131 $('#kiwi .connectwindow').slideUp('', kiwi
.front
.barsShow
);
132 $('#windows').click(function () { $('#kiwi_msginput').focus(); });
137 supportsOrientationChange
= (typeof window
.onorientationchange
!== undefined);
138 orientationEvent
= supportsOrientationChange
? "orientationchange" : "resize";
139 if (window
.addEventListener
) {
140 window
.addEventListener(orientationEvent
, kiwi
.front
.doLayoutSize
, false);
143 window
.attachEvent(orientationEvent
, kiwi
.front
.doLayoutSize
, false);
145 //$('#kiwi').bind("resize", kiwi.front.doLayoutSize, false);
147 kiwi
.front
.doLayout();
148 kiwi
.front
.barsHide();
150 var server_tabview
= new Tabview('server');
151 server_tabview
.userlist
.setWidth(0); // Disable the userlist
153 // Any pre-defined nick?
154 if (typeof window
.init_data
.nick
=== "string") {
155 $('#kiwi .formconnectwindow .nick').val(init_data
.nick
);
158 // Any pre-defined channels?
159 if (typeof window
.init_data
.channel
=== 'string') {
160 $('#channel').val(init_data
.channel
);
163 // Fix for Opera inserting a spurious <br/>
164 $('#kiwi .cur_topic br').remove();
166 $('#kiwi .cur_topic').keydown(function (e
) {
167 if (e
.which
=== 13) {
171 $('#kiwi_msginput').focus();
172 } else if (e
.which
=== 27) {
175 $(this).text(kiwi
.front
.original_topic
);
176 $('#kiwi_msginput').focus();
179 /*$('.cur_topic').live('keypress', function(e) {
180 if (e.keyCode === 13) {
184 $('#kiwi_msginput').focus();
185 } else if (e.keyCode === 27) {
188 $(this).text(kiwi.front.original_topic);
191 $('.cur_topic').live('change', function () {
193 text
= $(this).text();
194 if (text
!== kiwi
.front
.original_topic
) {
195 chan
= kiwi
.front
.cur_channel
.name
;
196 kiwi
.gateway
.setTopic(chan
, text
);
201 $('#windows a.chan').live('click', function () {
202 kiwi
.front
.joinChannel($(this).text());
206 kiwi
.data
.set('chanList', []);
211 kiwi
.plugs
.loadPlugin(plugins
[i
]);
216 doLayoutSize: function () {
217 var kiwi
, toolbars
, ul
, n_top
, n_bottom
, nl
;
220 if (kiwi
.width() < 330 && !kiwi
.hasClass('small_kiwi')) {
221 console
.log("switching to small kiwi");
222 kiwi
.removeClass('large_kiwi');
223 kiwi
.addClass('small_kiwi');
224 } else if (kiwi
.width() >= 330 && !kiwi
.hasClass('large_kiwi')) {
225 kiwi
.removeClass('small_kiwi');
226 kiwi
.addClass('large_kiwi');
229 toolbars
= $('#kiwi .cur_topic');
230 ul
= $('#kiwi .userlist');
232 n_top
= parseInt(toolbars
.offset().top
, 10) + parseInt(toolbars
.outerHeight(true), 10);
233 n_bottom
= $(document
).height() - parseInt($('#kiwi .control').offset().top
, 10);
235 $('#kiwi .windows').css({top
: n_top
+ 'px', bottom
: n_bottom
+ 'px'});
236 ul
.css({top
: n_top
+ 'px', bottom
: n_bottom
+ 'px'});
238 nl
= $('#nicklist_resize');
239 nl
.css({top
: n_top
+ 'px', bottom
: n_bottom
+ 'px', left
: $(document
).width() - ul
.outerWidth(true)});
243 doLayout: function () {
244 $('#kiwi .msginput .nick a').text(kiwi
.gateway
.nick
);
245 $('#kiwi_msginput').val(' ');
246 $('#kiwi_msginput').focus();
250 joinChannel: function (chan_name
) {
251 var chans
= chan_name
.split(','),
256 if (kiwi
.front
.tabviews
[chan
.toLowerCase()] === undefined || (kiwi
.front
.tabviews
[chan
.toLowerCase()] !== undefined && kiwi
.front
.tabviews
[chan
.toLowerCase()].safe_to_close
=== true)) {
257 kiwi
.gateway
.join(chan
);
258 kiwi
.front
.tabviewAdd(chan
);
260 kiwi
.front
.tabviews
[chan
.toLowerCase()].show();
266 run: function (msg
) {
267 var parts
, dest
, t
, pos
, textRange
, d
, plugin_event
, msg_sliced
;
269 // Run through any plugins
270 plugin_event
= {command
: msg
};
271 plugin_event
= kiwi
.plugs
.run('command_run', plugin_event
);
272 if (!plugin_event
|| typeof plugin_event
.command
=== 'undefined') {
276 // Update msg if it's been changed by any plugins
277 msg
= plugin_event
.command
.toString();
280 if (msg
.substring(0, 1) === '/') {
281 console
.log("running " + msg
);
282 parts
= msg
.split(' ');
283 switch (parts
[0].toLowerCase()) {
286 kiwi
.front
.joinChannel(parts
[1]);
291 if (typeof parts
[1] === 'undefined') {
292 alert('Usage: /connect servername [port] [ssl]');
296 if (typeof parts
[2] === 'undefined') {
300 if ((typeof parts
[3] === 'undefined') || !parts
[3] || (parts
[3] === 'false') || (parts
[3] === 'no')) {
306 kiwi
.front
.cur_channel
.addMsg(null, ' ', '=== Connecting to ' + parts
[1] + ' on port ' + parts
[2] + (parts
[3] ? ' using SSL' : '') + '...', 'status');
307 kiwi
.gateway
.connect(parts
[1], parts
[2], parts
[3]);
311 console
.log("/nick");
312 if (parts
[1] === undefined) {
313 console
.log("calling show nick");
314 kiwi
.front
.showChangeNick();
316 console
.log("sending raw");
317 kiwi
.gateway
.raw(msg
.substring(1));
322 if (typeof parts
[1] === "undefined") {
323 if (kiwi
.front
.cur_channel
.safe_to_close
) {
324 kiwi
.front
.cur_channel
.close();
326 kiwi
.gateway
.raw(msg
.substring(1) + ' ' + kiwi
.front
.cur_channel
.name
);
329 kiwi
.gateway
.raw(msg
.substring(1));
334 if (typeof parts
[1] !== "undefined") {
335 kiwi
.gateway
.raw(msg
.substring(1));
340 kiwi
.gateway
.debug();
345 if (typeof parts
[1] !== "undefined") {
346 kiwi
.front
.tabviewAdd(parts
[1]);
353 if (typeof parts
[1] !== "undefined") {
354 msg_sliced
= msg
.split(' ').slice(2).join(' ');
355 kiwi
.gateway
.msg(parts
[1], msg_sliced
);
357 if (!kiwi
.front
.tabviewExists(parts
[1])) {
358 kiwi
.front
.tabviewAdd(parts
[1]);
360 kiwi
.front
.tabviews
[parts
[1].toLowerCase()].addMsg(null, kiwi
.gateway
.nick
, msg_sliced
);
366 if (typeof parts
[1] === 'undefined') {
369 kiwi
.gateway
.raw('KICK ' + kiwi
.front
.cur_channel
.name
+ ' ' + msg
.split(' ', 2)[1]);
373 kiwi
.gateway
.raw(msg
.replace(/^\/quote /i, ''));
377 kiwi
.gateway
.action(kiwi
.front
.cur_channel
.name
, msg
.substring(4));
378 //kiwi.front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* '+data.nick+' '+data.msg, 'color:green;');
379 kiwi
.front
.cur_channel
.addMsg(null, ' ', '* ' + kiwi
.gateway
.nick
+ ' ' + msg
.substring(4), 'action', 'color:#555;');
384 msg
= parts
.slice(2).join(' ');
386 kiwi
.gateway
.notice(dest
, msg
);
387 this.onNotice({}, {nick
: kiwi
.gateway
.nick
, channel
: dest
, msg
: msg
});
391 if (parts
[1] !== undefined) {
392 kiwi
.front
.windowsShow(parseInt(parts
[1], 10));
397 kiwi
.gateway
.quit(parts
.slice(1).join(' '));
401 if (parts
[1] === undefined) {
403 if (t
.createTextRange
) {
404 pos
= t
.text().length();
405 textRange
= t
.createTextRange();
406 textRange
.collapse(true);
407 textRange
.moveEnd(pos
);
408 textRange
.moveStart(pos
);
410 } else if (t
.setSelectionRange
) {
411 t
.setSelectionRange(pos
, pos
);
414 kiwi
.gateway
.setTopic(kiwi
.front
.cur_channel
.name
, msg
.split(' ', 2)[1]);
415 //kiwi.gateway.raw('TOPIC ' + kiwi.front.cur_channel.name + ' :' + msg.split(' ', 2)[1]);
420 kiwi
.gateway
.kiwi(kiwi
.front
.cur_channel
.name
, msg
.substring(6));
424 parts
= parts
.slice(1);
425 dest
= parts
.shift();
426 msg
= parts
.join(' ');
428 kiwi
.gateway
.msg(dest
, String
.fromCharCode(1) + msg
+ String
.fromCharCode(1));
429 kiwi
.front
.tabviews
.server
.addMsg(null, 'CTCP Request', '[to ' + dest
+ '] ' + msg
, 'ctcp');
432 //kiwi.front.cur_channel.addMsg(null, ' ', '--> Invalid command: '+parts[0].substring(1));
433 kiwi
.gateway
.raw(msg
.substring(1));
437 //alert('Sending message: '+msg);
438 if (msg
.trim() === '') {
441 if (kiwi
.front
.cur_channel
.name
!== 'server') {
442 kiwi
.gateway
.msg(kiwi
.front
.cur_channel
.name
, msg
);
444 d
= d
.getHours() + ":" + d
.getMinutes();
445 //kiwi.front.addMsg(d, kiwi.gateway.nick, msg);
446 kiwi
.front
.cur_channel
.addMsg(null, kiwi
.gateway
.nick
, msg
);
452 onMsg: function (e
, data
) {
453 var destination
, plugin_event
;
454 // Is this message from a user?
455 if (data
.channel
=== kiwi
.gateway
.nick
) {
456 destination
= data
.nick
.toLowerCase();
458 destination
= data
.channel
.toLowerCase();
461 plugin_event
= {nick
: data
.nick
, msg
: data
.msg
, destination
: destination
};
462 plugin_event
= kiwi
.plugs
.run('msg_recieved', plugin_event
);
467 if (!kiwi
.front
.tabviewExists(plugin_event
.destination
)) {
468 kiwi
.front
.tabviewAdd(plugin_event
.destination
);
470 kiwi
.front
.tabviews
[plugin_event
.destination
].addMsg(null, plugin_event
.nick
, plugin_event
.msg
);
473 onDebug: function (e
, data
) {
474 if (!kiwi
.front
.tabviewExists('kiwi_debug')) {
475 kiwi
.front
.tabviewAdd('kiwi_debug');
477 kiwi
.front
.tabviews
.kiwi_debug
.addMsg(null, ' ', data
.msg
);
480 onAction: function (e
, data
) {
482 // Is this message from a user?
483 if (data
.channel
=== kiwi
.gateway
.nick
) {
484 destination
= data
.nick
;
486 destination
= data
.channel
;
489 if (!kiwi
.front
.tabviewExists(destination
)) {
490 kiwi
.front
.tabviewAdd(destination
);
492 kiwi
.front
.tabviews
[destination
.toLowerCase()].addMsg(null, ' ', '* ' + data
.nick
+ ' ' + data
.msg
, 'action', 'color:#555;');
495 onTopic: function (e
, data
) {
496 if (kiwi
.front
.tabviewExists(data
.channel
)) {
497 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].changeTopic(data
.topic
);
501 onNotice: function (e
, data
) {
502 var nick
= (data
.nick
=== undefined) ? '' : data
.nick
,
503 enick
= '[' + nick
+ ']';
505 if (kiwi
.front
.tabviewExists(data
.target
)) {
506 kiwi
.front
.tabviews
[data
.target
.toLowerCase()].addMsg(null, enick
, data
.msg
, 'notice');
507 } else if (kiwi
.front
.tabviewExists(nick
)) {
508 kiwi
.front
.tabviews
[nick
.toLowerCase()].addMsg(null, enick
, data
.msg
, 'notice');
510 kiwi
.front
.tabviews
.server
.addMsg(null, enick
, data
.msg
, 'notice');
514 onCTCPRequest: function (e
, data
) {
515 var msg
= data
.msg
.split(" ", 2);
518 if (typeof msg
[1] === 'undefined') {
521 kiwi
.gateway
.notice(data
.nick
, String
.fromCharCode(1) + 'PING ' + msg
[1] + String
.fromCharCode(1));
524 kiwi
.gateway
.notice(data
.nick
, String
.fromCharCode(1) + 'TIME ' + (new Date()).toLocaleString() + String
.fromCharCode(1));
527 kiwi
.front
.tabviews
.server
.addMsg(null, 'CTCP Request', '[from ' + data
.nick
+ '] ' + data
.msg
, 'ctcp');
530 onCTCPResponse: function (e
, data
) {
531 kiwi
.front
.tabviews
.server
.addMsg(null, 'CTCP Reply', '[from ' + data
.nick
+ '] ' + data
.msg
, 'ctcp');
534 onKiwi: function (e
, data
) {
538 onConnect: function (e
, data
) {
539 var err_box
, channels
;
541 if (data
.connected
) {
542 // Did we disconnect?
543 err_box
= $('.messages .msg.error.disconnect .text');
544 if (typeof err_box
[0] !== 'undefined') {
545 err_box
.text('Reconnected OK :)');
546 err_box
.removeClass('disconnect');
550 $.each(kiwi
.front
.tabviews
, function (i
, tabview
) {
551 if (tabview
.name
=== 'server') {
554 channels
+= tabview
.name
+ ',';
556 console
.log('Rejoining: ' + channels
);
557 kiwi
.gateway
.join(channels
);
561 if (kiwi
.gateway
.nick
!== data
.nick
) {
562 kiwi
.gateway
.nick
= data
.nick
;
563 kiwi
.front
.doLayout();
566 kiwi
.front
.tabviews
.server
.addMsg(null, ' ', '=== Connected OK :)', 'status');
567 if (typeof init_data
.channel
=== "string") {
568 kiwi
.front
.joinChannel(init_data
.channel
);
570 kiwi
.plugs
.run('connect', {success
: true});
572 kiwi
.front
.tabviews
.server
.addMsg(null, ' ', '=== Failed to connect :(', 'status');
573 kiwi
.plugs
.run('connect', {success
: false});
576 onConnectFail: function (e
, data
) {
577 var reason
= (typeof data
.reason
=== 'string') ? data
.reason
: '';
578 kiwi
.front
.tabviews
.server
.addMsg(null, '', 'There\'s a problem connecting! (' + reason
+ ')', 'error');
579 kiwi
.plugs
.run('connect', {success
: false});
581 onDisconnect: function (e
, data
) {
583 for (tab
in kiwi
.front
.tabviews
) {
584 kiwi
.front
.tabviews
[tab
].addMsg(null, '', 'Disconnected from server!', 'error disconnect');
586 kiwi
.plugs
.run('disconnect', {success
: false});
588 onReconnecting: function (e
, data
) {
591 err_box
= $('.messages .msg.error.disconnect .text');
598 case 1: return 'First';
599 case 2: return 'Second';
600 case 3: return 'Third';
601 case 4: return 'Fourth';
602 case 5: return 'Fifth';
603 case 6: return 'Sixth';
604 case 7: return 'Seventh';
605 default: return 'Next';
609 // TODO: convert seconds to mins:secs
610 msg
= f(data
.attempts
) + ' attempt at reconnecting in ' + (data
.delay
/ 1000).toString() + ' seconds..';
613 onOptions: function (e
, data
) {
614 if (typeof kiwi
.gateway
.network_name
=== "string" && kiwi
.gateway
.network_name
!== "") {
615 kiwi
.front
.tabviews
.server
.tab
.text(kiwi
.gateway
.network_name
);
618 onMOTD: function (e
, data
) {
619 kiwi
.front
.tabviews
.server
.addMsg(null, data
.server
, data
.msg
, 'motd');
621 onWhois: function (e
, data
) {
624 kiwi
.front
.cur_channel
.addMsg(null, data
.nick
, data
.msg
, 'whois');
625 } else if (data
.logon
) {
627 d
.setTime(data
.logon
* 1000);
628 d
= d
.toLocaleString();
629 kiwi
.front
.cur_channel
.addMsg(null, data
.nick
, 'idle for ' + data
.idle
+ ' second' + ((data
.idle
!== 1) ? 's' : '') + ', signed on ' + d
, 'whois');
631 kiwi
.front
.cur_channel
.addMsg(null, data
.nick
, 'idle for ' + data
.idle
+ ' seconds', 'whois');
634 onMode: function (e
, data
) {
636 if ((typeof data
.channel
=== 'string') && (typeof data
.effected_nick
=== 'string')) {
637 tab
= kiwi
.front
.tabviews
[data
.channel
.toLowerCase()];
638 tab
.addMsg(null, ' ', '[' + data
.mode
+ '] ' + data
.effected_nick
+ ' by ' + data
.nick
, 'mode', '');
639 if (tab
.userlist
.hasUser(data
.effected_nick
)) {
640 tab
.userlist
.changeUserMode(data
.effected_nick
, data
.mode
.substr(1), (data
.mode
[0] === '+'));
644 // TODO: Other mode changes that aren't +/- qaohv. - JA
646 onUserList: function (e
, data
) {
649 tab
= kiwi
.front
.tabviews
[data
.channel
.toLowerCase()];
650 if (typeof tab
=== 'undefined') {
654 if ((!kiwi
.front
.cache
.userlist
) || (!kiwi
.front
.cache
.userlist
.updating
)) {
655 if (!kiwi
.front
.cache
.userlist
) {
656 kiwi
.front
.cache
.userlist
= {updating
: true};
658 kiwi
.front
.cache
.userlist
.updating
= true;
660 tab
.userlist
.empty();
663 tab
.userlist
.addUser(data
.users
);
666 onUserListEnd: function (e
, data
) {
667 if (!kiwi
.front
.cache
.userlist
) {
668 kiwi
.front
.cache
.userlist
= {};
670 kiwi
.front
.cache
.userlist
.updating
= false;
673 onChannelListStart: function (e
, data
) {
674 /*global Utilityview */
677 tab
= new Utilityview('Channel List');
678 tab
.div
.css('overflow-y', 'scroll');
679 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>');
680 tab
.div
.append(table
);
682 kiwi
.front
.cache
.list
= {chans
: [], tab
: tab
, table
: table
,
683 update: function (newChans
) {
684 var body
= this.table
.children('tbody:first').detach(),
689 for (chan
in newChans
) {
690 this.chans
.push(newChans
[chan
]);
691 html
+= newChans
[chan
].html
;
694 this.table
.append(body
);
697 finalise: function () {
698 var body
= this.table
.children('tbody:first').detach(),
702 list
= $.makeArray($(body
).children());
705 list
[chan
] = $(list
[chan
]).detach();
708 list
= _
.sortBy(list
, function (channel
) {
709 return parseInt(channel
.children('.num_users').first().text(), 10);
713 body
.append(list
[chan
]);
716 this.table
.append(body
);
720 onChannelList: function (e
, data
) {
724 for (chans
in data
) {
725 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>'};
727 kiwi
.front
.cache
.list
.update(data
);
729 onChannelListEnd: function (e
, data
) {
730 kiwi
.front
.cache
.list
.finalise();
731 kiwi
.front
.cache
.list
.tab
.show();
735 onJoin: function (e
, data
) {
736 if (!kiwi
.front
.tabviewExists(data
.channel
)) {
737 kiwi
.front
.tabviewAdd(data
.channel
.toLowerCase());
740 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '--> ' + data
.nick
+ ' has joined', 'action join', 'color:#009900;');
742 if (data
.nick
=== kiwi
.gateway
.nick
) {
743 return; // Not needed as it's already in nicklist
746 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].userlist
.addUser({nick
: data
.nick
, modes
: []});
748 onPart: function (e
, data
) {
749 if (kiwi
.front
.tabviewExists(data
.channel
)) {
750 // If this is us, close the tabview
751 if (data
.nick
=== kiwi
.gateway
.nick
) {
752 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].close();
753 kiwi
.front
.tabviews
.server
.show();
757 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '<-- ' + data
.nick
+ ' has left (' + data
.message
+ ')', 'action part', 'color:#990000;');
758 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].userlist
.removeUser(data
.nick
);
761 onKick: function (e
, data
) {
762 if (kiwi
.front
.tabviewExists(data
.channel
)) {
763 // If this is us, close the tabview
764 if (data
.kicked
=== kiwi
.gateway
.nick
) {
765 //kiwi.front.tabviews[data.channel.toLowerCase()].close();
766 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '=== You have been kicked from ' + data
.channel
+ '. ' + data
.message
, 'status kick');
767 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].safe_to_close
= true;
768 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].userlist
.remove();
772 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '<-- ' + data
.kicked
+ ' kicked by ' + data
.nick
+ '(' + data
.message
+ ')', 'action kick', 'color:#990000;');
773 kiwi
.front
.tabviews
[data
.channel
.toLowerCase()].userlist
.removeUser(data
.nick
);
776 onNick: function (e
, data
) {
777 if (data
.nick
=== kiwi
.gateway
.nick
) {
778 kiwi
.gateway
.nick
= data
.newnick
;
779 kiwi
.front
.doLayout();
782 $.each(kiwi
.front
.tabviews
, function (i
, item
) {
783 $.each(kiwi
.front
.tabviews
, function (i
, item
) {
784 if (item
.userlist
.hasUser(data
.nick
)) {
785 item
.userlist
.renameUser(data
.nick
, data
.newnick
);
786 item
.addMsg(null, ' ', '=== ' + data
.nick
+ ' is now known as ' + data
.newnick
, 'action changenick');
791 onQuit: function (e
, data
) {
792 $.each(kiwi
.front
.tabviews
, function (i
, item
) {
793 $.each(kiwi
.front
.tabviews
, function (i
, item
) {
794 if (item
.userlist
.hasUser(data
.nick
)) {
795 item
.userlist
.removeUser(data
.nick
);
796 item
.addMsg(null, ' ', '<-- ' + data
.nick
+ ' has quit (' + data
.message
+ ')', 'action quit', 'color:#990000;');
801 onChannelRedirect: function (e
, data
) {
802 kiwi
.front
.tabviews
[data
.from.toLowerCase()].close();
803 kiwi
.front
.tabviewAdd(data
.to
.toLowerCase());
804 kiwi
.front
.tabviews
[data
.to
.toLowerCase()].addMsg(null, ' ', '=== Redirected from ' + data
.from, 'action');
807 onIRCError: function (e
, data
) {
809 if (data
.channel
!== undefined && kiwi
.front
.tabviewExists(data
.channel
)) {
810 t_view
= data
.channel
;
815 switch (data
.error
) {
816 case 'banned_from_channel':
817 kiwi
.front
.tabviews
[t_view
].addMsg(null, ' ', '=== You are banned from ' + data
.channel
+ '. ' + data
.reason
, 'status');
818 if (t_view
!== 'server') {
819 kiwi
.front
.tabviews
[t_view
].safe_to_close
= true;
822 case 'bad_channel_key':
823 kiwi
.front
.tabviews
[t_view
].addMsg(null, ' ', '=== Bad channel key for ' + data
.channel
, 'status');
824 if (t_view
!== 'server') {
825 kiwi
.front
.tabviews
[t_view
].safe_to_close
= true;
828 case 'invite_only_channel':
829 kiwi
.front
.tabviews
[t_view
].addMsg(null, ' ', '=== ' + data
.channel
+ ' is invite only.', 'status');
830 if (t_view
!== 'server') {
831 kiwi
.front
.tabviews
[t_view
].safe_to_close
= true;
834 case 'channel_is_full':
835 kiwi
.front
.tabviews
[t_view
].addMsg(null, ' ', '=== ' + data
.channel
+ ' is full.', 'status');
836 if (t_view
!== 'server') {
837 kiwi
.front
.tabviews
[t_view
].safe_to_close
= true;
840 case 'chanop_privs_needed':
841 kiwi
.front
.tabviews
[data
.channel
].addMsg(null, ' ', '=== ' + data
.reason
, 'status');
844 kiwi
.front
.tabviews
.server
.addMsg(null, ' ', '=== ' + data
.nick
+ ': ' + data
.reason
, 'status');
846 case 'nickname_in_use':
847 kiwi
.front
.tabviews
.server
.addMsg(null, ' ', '=== The nickname ' + data
.nick
+ ' is already in use. Please select a new nickname', 'status');
848 kiwi
.front
.showChangeNick('That nick is already taken');
851 // We don't know what data contains, so don't do anything with it.
852 //kiwi.front.tabviews.server.addMsg(null, ' ', '=== ' + data, 'status');
856 registerKeys: function () {
857 var tabcomplete
= {active
: false, data
: [], prefix
: ''};
858 $('#kiwi_msginput').bind('keydown', function (e
) {
859 var windows
, meta
, num
, msg
, data
, self
;
860 windows
= $('#windows');
861 //var meta = e.altKey;
865 tabcomplete
.active
= false;
866 tabcomplete
.data
= [];
867 tabcomplete
.prefix
= '';
871 case (e
.which
>= 48) && (e
.which
<= 57):
878 kiwi
.front
.windowsShow(num
);
882 case e
.which
=== 27: // escape
884 case e
.which
=== 13: // return
885 msg
= $('#kiwi_msginput').val();
888 kiwi
.front
.buffer
.push(msg
);
889 kiwi
.front
.buffer_pos
= kiwi
.front
.buffer
.length
;
892 $('#kiwi_msginput').val('');
895 case e
.which
=== 33: // page up
896 console
.log("page up");
897 windows
[0].scrollTop
= windows
[0].scrollTop
- windows
.height();
899 case e
.which
=== 34: // page down
900 windows
[0].scrollTop
= windows
[0].scrollTop
+ windows
.height();
902 case e
.which
=== 37: // left
904 kiwi
.front
.windowsPrevious();
908 case e
.which
=== 38: // up
909 if (kiwi
.front
.buffer_pos
> 0) {
910 kiwi
.front
.buffer_pos
--;
911 $('#kiwi_msginput').val(kiwi
.front
.buffer
[kiwi
.front
.buffer_pos
]);
914 case e
.which
=== 39: // right
916 kiwi
.front
.windowsNext();
920 case e
.which
=== 40: // down
921 if (kiwi
.front
.buffer_pos
< kiwi
.front
.buffer
.length
) {
922 kiwi
.front
.buffer_pos
++;
923 $('#kiwi_msginput').val(kiwi
.front
.buffer
[kiwi
.front
.buffer_pos
]);
927 case e
.which
=== 9: // tab
928 tabcomplete
.active
= true;
929 if (_
.isEqual(tabcomplete
.data
, [])) {
930 // Get possible autocompletions
932 kiwi
.front
.cur_channel
.userlist
.listUsers(false).each(function () {
934 nick
= kiwi
.front
.nickStripPrefix($('a.nick', this).text());
937 data
= _
.sortBy(data
, function (nick
) {
940 tabcomplete
.data
= data
;
943 if (this.value
[this.selectionStart
- 1] === ' ') {
948 var tokens
= self
.value
.substring(0, self
.selectionStart
).split(" "),
953 nick
= tokens
[tokens
.length
- 1];
954 if (tabcomplete
.prefix
=== '') {
955 tabcomplete
.prefix
= nick
;
958 tabcomplete
.data
= _
.select(tabcomplete
.data
, function (n
) {
959 return (n
.toLowerCase().indexOf(tabcomplete
.prefix
.toLowerCase()) === 0);
962 if (tabcomplete
.data
.length
> 0) {
963 p1
= self
.selectionStart
- (nick
.length
);
964 val
= self
.value
.substr(0, p1
);
965 newnick
= tabcomplete
.data
.shift();
966 tabcomplete
.data
.push(newnick
);
968 val
+= self
.value
.substr(self
.selectionStart
);
970 if (self
.setSelectionRange
) {
971 self
.setSelectionRange(p1
+ newnick
.length
, p1
+ newnick
.length
);
972 } else if (self
.createTextRange
) { // not sure if this bit is actually needed....
973 range
= self
.createTextRange();
974 range
.collapse(true);
975 range
.moveEnd('character', p1
+ newnick
.length
);
976 range
.moveStart('character', p1
+ newnick
.length
);
986 $('#kiwi .control .msginput .nick').click(function () {
987 kiwi
.front
.showChangeNick();
994 $('#kiwi .plugins .load_plugin_file').click(function () {
995 if (typeof kiwi
.front
.boxes
.plugins
!== "undefined") {
999 kiwi
.front
.boxes
.plugins
= new Box("plugin_file");
1000 $('#tmpl_plugins').tmpl({}).appendTo(kiwi
.front
.boxes
.plugins
.content
);
1001 kiwi
.front
.boxes
.plugins
.box
.css('top', -(kiwi
.front
.boxes
.plugins
.height
+ 40));
1003 // Populate the plugin list..
1004 function enumPlugins() {
1006 lst
= $('#plugin_list');
1007 lst
.find('option').remove();
1008 for (j
in kiwi
.plugs
.loaded
) {
1009 txt
= kiwi
.plugs
.loaded
[j
].name
;
1010 lst
.append('<option value="' + txt
+ '">' + txt
+ '</option>');
1016 $('#kiwi .plugin_file').submit(function () {
1017 $('<div></div>').load($('.txtpluginfile').val(), function (e
) {
1022 $('#kiwi .cancelpluginfile').click(function () {
1023 kiwi
.front
.boxes
.plugins
.destroy();
1026 $('#kiwi #plugins_list_unload').click(function () {
1027 var selected_plugin
;
1028 selected_plugin
= $('#plugin_list').val();
1029 kiwi
.plugs
.unloadPlugin(selected_plugin
);
1033 $('#kiwi .txtpluginfile').focus();
1037 $('#kiwi .plugins .reload_css').click(function () {
1038 var links
= document
.getElementsByTagName("link"),
1040 for (i
= 0; i
< links
.length
; i
++) {
1041 if (links
[i
].rel
=== "stylesheet") {
1042 if (links
[i
].href
.indexOf("?") === -1) {
1043 links
[i
].href
+= "?";
1045 links
[i
].href
+= "x";
1051 $('#kiwi .about .about_close').click(function () {
1052 $('#kiwi .about').css('display', 'none');
1056 $('#kiwi .poweredby').click(function () {
1057 $('#kiwi .about').css('display', 'block');
1063 showChangeNick: function (caption
) {
1064 caption
= (typeof caption
!== 'undefined') ? caption
: '';
1066 $('#kiwi').append($('#tmpl_change_nick').tmpl({}));
1068 $('#kiwi .newnick .caption').text(caption
);
1070 $('#kiwi .form_newnick').submit(function () {
1071 kiwi
.front
.run('/NICK ' + $('#kiwi .txtnewnick').val());
1072 $('#kiwi .newnick').remove();
1076 $('#kiwi .txtnewnick').keypress(function (ev
) {
1077 if (!this.first_press
) {
1078 this.first_press
= true;
1083 $('#kiwi .txtnewnick').keydown(function (ev
) {
1084 if (ev
.which
=== 27) { // ESC
1085 $('#kiwi_msginput').focus();
1086 $('#kiwi .newnick').remove();
1090 $('#kiwi .cancelnewnick').click(function () {
1091 $('#kiwi .newnick').remove();
1094 $('#kiwi .txtnewnick').focus();
1098 tabviewExists: function (name
) {
1099 return (typeof kiwi
.front
.tabviews
[name
.toLowerCase()] !== 'undefined');
1102 tabviewAdd: function (v_name
) {
1103 return new Tabview(v_name
);
1108 kiwi
.gateway
.sync();
1111 onSync: function (e
, data
) {
1113 if (data
.nick
!== undefined) {
1114 kiwi
.gateway
.nick
= data
.nick
;
1118 if (data
.tabviews
!== undefined) {
1119 $.each(data
.tabviews
, function (i
, tab
) {
1120 if (!kiwi
.front
.tabviewExists(tab
.name
)) {
1121 kiwi
.front
.tabviewAdd(kiwi
.gateway
.channel_prefix
+ tab
.name
);
1123 if (tab
.userlist
!== undefined) {
1124 kiwi
.front
.onUserList({'channel': kiwi
.gateway
.channel_prefix
+ tab
.name
, 'users': tab
.userlist
.getUsers(false)});
1130 kiwi
.front
.doLayout();
1134 setTopicText: function (new_topic
) {
1135 kiwi
.front
.original_topic
= new_topic
;
1136 $('#kiwi .cur_topic .topic').text(new_topic
);
1137 kiwi
.front
.doLayoutSize();
1140 nickStripPrefix: function (nick
) {
1141 var tmp
= nick
, i
, j
, k
;
1143 for (j
= 0; j
< nick
.length
; j
++) {
1144 for (k
= 0; k
< kiwi
.gateway
.user_prefixes
.length
; k
++) {
1145 if (nick
.charAt(j
) === kiwi
.gateway
.user_prefixes
[k
].symbol
) {
1152 return tmp
.substr(i
);
1155 nickGetPrefix: function (nick
) {
1156 var tmp
= nick
, i
, j
, k
;
1158 for (j
= 0; j
< nick
.length
; j
++) {
1159 for (k
= 0; k
< kiwi
.gateway
.user_prefixes
.length
; k
++) {
1160 if (nick
.charAt(j
) === kiwi
.gateway
.user_prefixes
[k
].symbol
) {
1167 return tmp
.substr(0, i
);
1170 isChannel: function (name
) {
1171 var prefix
, is_chan
;
1172 prefix
= name
.charAt(0);
1173 if (kiwi
.gateway
.channel_prefix
.indexOf(prefix
) > -1) {
1182 tabviewsNext: function () {
1183 var wl
= $('#kiwi .windowlist ul'),
1184 next_left
= parseInt(wl
.css('text-indent').replace('px', ''), 10) + 170;
1185 wl
.css('text-indent', next_left
);
1188 tabviewsPrevious: function () {
1189 var wl
= $('#kiwi .windowlist ul'),
1190 next_left
= parseInt(wl
.css('text-indent').replace('px', ''), 10) - 170;
1191 wl
.css('text-indent', next_left
);
1194 windowsNext: function () {
1197 for (tab
in kiwi
.front
.tabviews
) {
1199 if (kiwi
.front
.tabviews
[tab
] === kiwi
.front
.cur_channel
) {
1204 kiwi
.front
.tabviews
[tab
].show();
1210 windowsPrevious: function () {
1211 var tab
, prev_tab
, next
;
1213 for (tab
in kiwi
.front
.tabviews
) {
1214 if (kiwi
.front
.tabviews
[tab
] === kiwi
.front
.cur_channel
) {
1220 prev_tab
= kiwi
.front
.tabviews
[tab
];
1224 windowsShow: function (num
) {
1225 num
= parseInt(num
, 10);
1226 console
.log('Showing window ' + num
.toString());
1228 for (tab
in kiwi
.front
.tabviews
) {
1230 kiwi
.front
.tabviews
[tab
].show();
1239 barsShow: function () {
1240 $('#kiwi .toolbars').slideDown();
1241 $('#kiwi .control').slideDown();
1244 barsHide: function () {
1245 $('#kiwi .toolbars').slideUp();
1246 $('#kiwi .control').slideUp();
1249 format: function (msg
) {
1252 if ((!msg
) || (typeof msg
!== 'string')) {
1257 if (msg
.indexOf(String
.fromCharCode(2)) !== -1) {
1259 while (msg
.indexOf(String
.fromCharCode(2)) !== -1) {
1260 msg
= msg
.replace(String
.fromCharCode(2), next
);
1261 next
= (next
=== '<b>') ? '</b>' : '<b>';
1263 if (next
=== '</b>') {
1269 if (msg
.indexOf(String
.fromCharCode(31)) !== -1) {
1271 while (msg
.indexOf(String
.fromCharCode(31)) !== -1) {
1272 msg
= msg
.replace(String
.fromCharCode(31), next
);
1273 next
= (next
=== '<u>') ? '</u>' : '<u>';
1275 if (next
=== '</u>') {
1281 re
= /\x03([0-9][0-5]?)(,([0-9][0-5]?))?(.*?)\x03/g;
1283 msg
= msg
.replace(re
, function (str
, p1
, p2
, p3
, p4
) {
1285 col = function (num
) {
1286 switch (parseInt(num
, 10)) {
1325 return '<span style="' + ((fg
!== null) ? 'color: ' + fg
+ '; ' : '') + ((bg
!== null) ? 'background-color: ' + bg
+ ';' : '') + '">' + p4
+ '</span>';
1341 var UserList = function (name
) {
1342 var userlist
, list_html
, sortUsers
, sortModes
, getPrefix
;
1346 $('#kiwi .userlist').append($('<ul id="kiwi_userlist_' + name
+ '"></ul>'));
1347 list_html
= $('#kiwi_userlist_' + name
);
1348 $('a.nick', list_html
[0]).live('click', this.clickHandler
);
1350 sortUsers = function () {
1352 parent
= list_html
.parent();
1353 list_html
= list_html
.detach();
1355 // Not sure this is needed.
1356 // It's O(n^2) as well, so need to test to see if it works without.
1357 // Alternative to test: list_html.children('li').detach();
1358 list_html
.children().each(function (child
) {
1361 nick
= child
.data('nick');
1362 for (i
= 0; i
< userlist
.length
; i
++) {
1363 if (userlist
[i
].nick
=== nick
) {
1364 userlist
[i
].html
= child
.detach();
1370 userlist
.sort(function (a
, b
) {
1371 var i
, a_idx
, b_idx
, a_nick
, b_nick
;
1372 // Try to sort by modes first
1373 if (a
.modes
.length
> 0) {
1374 // a has modes, but b doesn't so a should appear first
1375 if (b
.modes
.length
=== 0) {
1379 // Compare the first (highest) mode
1380 for (i
= 0; i
< kiwi
.gateway
.user_prefixes
.length
; i
++) {
1381 if (kiwi
.gateway
.user_prefixes
[i
].mode
=== a
.modes
[0]) {
1385 for (i
= 0; i
< kiwi
.gateway
.user_prefixes
.length
; i
++) {
1386 if (kiwi
.gateway
.user_prefixes
[i
].mode
=== b
.modes
[0]) {
1390 if (a_idx
< b_idx
) {
1392 } else if (a_idx
> b_idx
) {
1395 // If we get to here both a and b have the same highest mode so have to resort to lexicographical sorting
1397 } else if (b
.modes
.length
> 0) {
1398 // b has modes but a doesn't so b should appear first
1401 a_nick
= a
.nick
.toLocaleUpperCase();
1402 b_nick
= b
.nick
.toLocaleUpperCase();
1403 // Lexicographical sorting
1404 if (a_nick
< b_nick
) {
1406 } else if (a_nick
> b_nick
) {
1409 // This should never happen; both users have the same nick.
1410 console
.log('Something\'s gone wrong somewhere - two users have the same nick!');
1414 _
.each(userlist
, function (user
) {
1415 user
.html
= user
.html
.appendTo(list_html
);
1418 list_html
= list_html
.appendTo(parent
);
1421 sortModes = function (modes
) {
1422 return modes
.sort(function (a
, b
) {
1423 var a_idx
, b_idx
, i
;
1424 for (i
= 0; i
< kiwi
.gateway
.user_prefixes
.length
; i
++) {
1425 if (kiwi
.gateway
.user_prefixes
[i
].mode
=== a
) {
1429 for (i
= 0; i
< kiwi
.gateway
.user_prefixes
.length
; i
++) {
1430 if (kiwi
.gateway
.user_prefixes
[i
].mode
=== b
) {
1434 if (a_idx
< b_idx
) {
1436 } else if (a_idx
> b_idx
) {
1444 getPrefix = function (modes
) {
1446 if (typeof modes
[0] !== 'undefined') {
1447 prefix
= _
.detect(kiwi
.gateway
.user_prefixes
, function (prefix
) {
1448 return prefix
.mode
=== modes
[0];
1450 prefix
= (prefix
) ? prefix
.symbol
: '';
1455 this.addUser = function (users
) {
1456 if (!_
.isArray(users
)) {
1459 _
.each(users
, function (user
) {
1460 var html
, prefix
= '';
1461 user
.nick
= kiwi
.front
.nickStripPrefix(user
.nick
);
1462 user
.modes
= sortModes(user
.modes
);
1463 if (typeof user
.modes
[0] !== 'undefined') {
1464 prefix
= _
.detect(kiwi
.gateway
.user_prefixes
, function (prefix
) {
1465 return prefix
.mode
=== user
.modes
[0];
1467 prefix
= (prefix
) ? prefix
.symbol
: '';
1469 html
= $('<li><a class="nick">' + prefix
+ user
.nick
+ '</a></li>');
1470 userlist
.push({nick
: user
.nick
, modes
: user
.modes
, html
: html
});
1477 this.removeUser = function (nicks
) {
1479 if (!_
.isArray(nicks
)) {
1482 toRemove
= _
.select(userlist
, function (user
) {
1483 return _
.any(nicks
, function (n
) {
1484 return n
=== user
.nick
;
1488 _
.each(toRemove
, function (user
) {
1492 userlist
= _
.difference(userlist
, toRemove
);
1497 this.renameUser = function (oldNick
, newNick
) {
1498 var user
= _
.detect(userlist
, function (u
) {
1499 return u
.nick
=== oldNick
;
1502 user
.nick
= newNick
;
1503 user
.html
.text(getPrefix(user
.modes
) + newNick
);
1511 this.listUsers = function (modesort
, modes
) {
1512 var users
= userlist
;
1514 users
= _
.select(users
, function (user
) {
1515 return _
.any(modes
, function (m
) {
1516 return _
.any(user
.modes
, function (um
) {
1522 if ((modesort
=== true) || (typeof modesort
=== undefined)) {
1525 return _
.sortBy(users
, function (user
) {
1531 this.remove = function () {
1537 this.empty = function () {
1538 list_html
.children().remove();
1544 this.hasUser = function (nick
) {
1545 return _
.any(userlist
, function (user
) {
1546 return user
.nick
=== nick
;
1550 this.active = function (active
) {
1551 if ((arguments
.length
=== 0) || (active
)) {
1552 list_html
.addClass('active');
1555 list_html
.removeClass('active');
1562 this.changeUserMode = function (nick
, mode
, add
) {
1564 if (this.hasUser(nick
)) {
1565 user
= _
.detect(userlist
, function (u
) {
1566 return u
.nick
=== nick
;
1569 if ((arguments
.length
< 3) || (add
)) {
1570 user
.modes
.push(mode
);
1572 user
.modes
= _
.reject(user
.modes
, function (m
) {
1576 user
.modes
= sortModes(user
.modes
);
1577 user
.html
.children('a:first').text(getPrefix(user
.modes
) + user
.nick
);
1584 UserList
.prototype.width
= 100; // 0 to disable
1585 UserList
.prototype.setWidth = function (newWidth
) {
1587 if (typeof newWidth
=== 'number') {
1588 this.width
= newWidth
;
1592 u
= $('#kiwi .userlist');
1594 u
.width(this.width
);
1599 UserList
.prototype.clickHandler = function () {
1600 var li
= $(this).parent();
1602 // Remove any existing userboxes
1603 $('#kiwi .userbox').remove();
1605 if ($(li
).data('userbox') === this) {
1606 $(li
).removeData('userbox');
1608 $('#tmpl_user_box').tmpl({nick
: kiwi
.front
.nickStripPrefix($(this).text())}).appendTo(li
);
1610 $('#kiwi .userbox .userbox_query').click(function (ev
) {
1611 var nick
= $('#kiwi .userbox_nick').val();
1612 kiwi
.front
.run('/query ' + nick
);
1615 $('#kiwi .userbox .userbox_whois').click(function (ev
) {
1616 var nick
= $('#kiwi .userbox_nick').val();
1617 kiwi
.front
.run('/whois ' + nick
);
1619 $(li
).data('userbox', this);
1631 var Utilityview = function (name
) {
1632 var rand_name
= randomString(15),
1633 tmp_divname
= 'kiwi_window_' + rand_name
,
1634 tmp_tabname
= 'kiwi_tab_' + rand_name
;
1636 this.name
= rand_name
;
1639 this.panel
= $('#panel1');
1641 if (typeof $('.scroller', this.panel
)[0] === 'undefined') {
1642 this.panel
.append('<div id="' + tmp_divname
+ '" class="messages"></div>');
1644 $('.scroller', this.panel
).append('<div id="' + tmp_divname
+ '" class="messages"></div>');
1647 this.tab
= $('<li id="' + tmp_tabname
+ '">' + this.title
+ '</li>');
1648 this.tab
.click(function () {
1649 kiwi
.front
.utilityviews
[rand_name
.toLowerCase()].show();
1651 $('#kiwi .utilityviewlist ul').append(this.tab
);
1652 kiwi
.front
.doLayoutSize();
1654 this.div
= $('#' + tmp_divname
);
1655 this.div
.css('overflow', 'hidden');
1657 kiwi
.front
.utilityviews
[rand_name
.toLowerCase()] = this;
1660 Utilityview
.prototype.name
= null;
1661 Utilityview
.prototype.title
= null;
1662 Utilityview
.prototype.div
= null;
1663 Utilityview
.prototype.tab
= null;
1664 Utilityview
.prototype.topic
= ' ';
1665 Utilityview
.prototype.panel
= null;
1666 Utilityview
.prototype.show = function () {
1667 $('.messages', this.panel
).removeClass("active");
1668 $('#kiwi .userlist ul').removeClass("active");
1669 $('#kiwi .toolbars ul li').removeClass("active");
1671 this.panel
.css('overflow-y', 'hidden');
1672 $('#windows').css('right', 0);
1673 // Activate this tab!
1674 this.div
.addClass('active');
1675 this.tab
.addClass('active');
1677 this.addPartImage();
1679 kiwi
.front
.setTopicText(this.topic
);
1680 kiwi
.front
.cur_channel
= this;
1682 // If we're using fancy scrolling, refresh it
1684 touch_scroll
.refresh();
1688 Utilityview
.prototype.setPanel = function (new_panel
) {
1690 this.panel
= new_panel
;
1691 this.panel
.append(this.div
);
1695 Utilityview
.prototype.close = function () {
1699 if (kiwi
.front
.cur_channel
=== this) {
1700 kiwi
.front
.tabviews
.server
.show();
1702 delete kiwi
.front
.utilityviews
[this.name
.toLowerCase()];
1705 Utilityview
.prototype.addPartImage = function () {
1706 this.clearPartImage();
1708 // We can't close this tab, so don't have the close image
1709 if (this.name
=== 'server') {
1713 var del_html
= '<img src="/img/redcross.png" class="tab_part" />';
1714 this.tab
.append(del_html
);
1716 $('.tab_part', this.tab
).click(function () {
1717 if (kiwi
.front
.cur_channel
.name
!== 'server') {
1718 kiwi
.front
.cur_channel
.close();
1723 Utilityview
.prototype.clearPartImage = function () {
1724 $('#kiwi .toolbars .tab_part').remove();
1738 var Tabview = function (v_name
) {
1739 /*global Tabview, UserList */
1740 var re
, htmlsafe_name
, tmp_divname
, tmp_userlistname
, tmp_tabname
, userlist_enabled
= true;
1741 console
.log(v_name
);
1742 console
.log(v_name
[0]);
1743 console
.log('charAt(0): ' + v_name
.charAt(0));
1745 if (v_name
[0] === kiwi
.gateway
.channel_prefix
) {
1746 re
= new RegExp(kiwi
.gateway
.channel_prefix
, "g");
1747 htmlsafe_name
= v_name
.replace(re
, 'pre');
1748 htmlsafe_name
= "chan_" + htmlsafe_name
;
1750 htmlsafe_name
= 'query_' + v_name
;
1751 userlist_enabled
= false;
1754 tmp_divname
= 'kiwi_window_' + htmlsafe_name
;
1755 tmp_userlistname
= 'kiwi_userlist_' + htmlsafe_name
;
1756 tmp_tabname
= 'kiwi_tab_' + htmlsafe_name
;
1758 if (!kiwi
.front
.tabviewExists(v_name
)) {
1759 $('#kiwi .windows .scroller').append('<div id="' + tmp_divname
+ '" class="messages"></div>');
1760 //$('#kiwi .userlist').append('<ul id="' + tmp_userlistname + '"></ul>');
1761 $('#kiwi .windowlist ul').append('<li id="' + tmp_tabname
+ '" onclick="kiwi.front.tabviews[\'' + v_name
.toLowerCase() + '\'].show();">' + v_name
+ '</li>');
1763 //$('#kiwi .windowlist ul .window_'+v_name).click(function(){ kiwi.front.windowShow(v_name); });
1764 //kiwi.front.windowShow(v_name);
1766 kiwi
.front
.tabviews
[v_name
.toLowerCase()] = new Tabview();
1768 this.div
= $('#' + tmp_divname
);
1769 this.userlist
= new UserList(htmlsafe_name
);
1770 this.tab
= $('#' + tmp_tabname
);
1771 this.panel
= $('#panel1');
1773 if (!userlist_enabled
) {
1774 this.userlist
.setWidth(0);
1778 if (typeof registerTouches
=== "function") {
1779 //alert("Registering touch interface");
1780 //registerTouches($('#'+tmp_divname));
1781 registerTouches(document
.getElementById(tmp_divname
));
1784 kiwi
.front
.doLayoutSize();
1786 Tabview
.prototype.name
= null;
1787 Tabview
.prototype.div
= null;
1788 Tabview
.prototype.userlist
= null;
1789 Tabview
.prototype.tab
= null;
1790 Tabview
.prototype.topic
= "";
1791 Tabview
.prototype.safe_to_close
= false; // If we have been kicked/banned/etc from this channel, don't wait for a part message
1792 Tabview
.prototype.panel
= null;
1794 Tabview
.prototype.show = function () {
1797 $('.messages', this.panel
).removeClass("active");
1798 $('#kiwi .userlist ul').removeClass("active");
1799 $('#kiwi .toolbars ul li').removeClass("active");
1802 u
= $('#kiwi .userlist');
1804 this.panel
.css('overflow-y', 'scroll');
1806 // Set the window size accordingly
1807 if (this.userlist
.width
> 0) {
1808 this.userlist
.setWidth();
1809 w
.css('right', u
.outerWidth(true));
1810 this.userlist
.active(true);
1811 // Enable the userlist resizer
1812 $('#nicklist_resize').css('display', 'block');
1815 // Disable the userlist resizer
1816 $('#nicklist_resize').css('display', 'none');
1819 this.div
.addClass('active');
1820 this.tab
.addClass('active');
1822 // Add the part image to the tab
1823 this.addPartImage();
1825 this.clearHighlight();
1826 kiwi
.front
.setTopicText(this.topic
);
1827 kiwi
.front
.cur_channel
= this;
1829 // If we're using fancy scrolling, refresh it
1831 touch_scroll
.refresh();
1834 this.scrollBottom();
1836 $('#kiwi_msginput').focus();
1840 Tabview
.prototype.close = function () {
1842 this.userlist
.remove();
1843 this.userlist
= null;
1846 if (kiwi
.front
.cur_channel
=== this) {
1847 kiwi
.front
.tabviews
.server
.show();
1849 delete kiwi
.front
.tabviews
[this.name
.toLowerCase()];
1852 Tabview
.prototype.addPartImage = function () {
1853 this.clearPartImage();
1855 // We can't close this tab, so don't have the close image
1856 if (this.name
=== 'server') {
1860 var del_html
= '<img src="/img/redcross.png" class="tab_part" />';
1861 this.tab
.append(del_html
);
1863 $('.tab_part', this.tab
).click(function () {
1864 if (kiwi
.front
.isChannel($(this).parent().text())) {
1865 kiwi
.front
.run("/part");
1867 // Make sure we don't close the server tab
1868 if (kiwi
.front
.cur_channel
.name
!== 'server') {
1869 kiwi
.front
.cur_channel
.close();
1875 Tabview
.prototype.clearPartImage = function () {
1876 $('#kiwi .toolbars .tab_part').remove();
1879 Tabview
.prototype.addMsg = function (time
, nick
, msg
, type
, style
) {
1880 var self
, tmp
, d
, re
, line_msg
;
1884 tmp
= {msg
: msg
, time
: time
, nick
: nick
, tabview
: this.name
};
1885 tmp
= kiwi
.plugs
.run('addmsg', tmp
);
1895 if (time
=== null) {
1897 time
= d
.getHours().toString().lpad(2, "0") + ":" + d
.getMinutes().toString().lpad(2, "0") + ":" + d
.getSeconds().toString().lpad(2, "0");
1900 // The CSS class (action, topic, notice, etc)
1901 if (typeof type
!== "string") {
1905 // Make sure we don't have NaN or something
1906 if (typeof msg
!== "string") {
1910 // Make the channels clickable
1911 re
= new RegExp('\\B(' + kiwi
.gateway
.channel_prefix
+ '[^ ,.\\007]+)', 'g');
1912 msg
= msg
.replace(re
, function (match
) {
1913 return '<a class="chan">' + match
+ '</a>';
1916 msg
= kiwi
.front
.format(msg
);
1918 // Build up and add the line
1919 line_msg
= $('<div class="msg ' + type
+ '"><div class="time">' + time
+ '</div><div class="nick">' + nick
+ '</div><div class="text" style="' + style
+ '">' + msg
+ ' </div></div>');
1920 this.div
.append(line_msg
);
1923 this.scrollBottom();
1925 touch_scroll
.refresh();
1926 //console.log(this.div.attr("scrollHeight") +" - "+ $('#windows').height());
1927 this.scrollBottom();
1928 //if(this.div.attr("scrollHeight") > $('#windows').height()){
1929 // touch_scroll.scrollTo(0, this.div.height());
1934 Tabview
.prototype.scrollBottom = function () {
1935 var panel
= this.panel
;
1936 panel
[0].scrollTop
= panel
[0].scrollHeight
;
1939 Tabview
.prototype.changeNick = function (newNick
, oldNick
) {
1940 var inChan
= this.userlist
.hasUser(oldNick
);
1942 this.userlist
.renameUser(oldNick
, newNick
);
1943 this.addMsg(null, ' ', '=== ' + oldNick
+ ' is now known as ' + newNick
, 'action changenick');
1946 Tabview
.prototype.highlight = function () {
1947 this.tab
.addClass('highlight');
1949 Tabview
.prototype.activity = function () {
1950 this.tab
.addClass('activity');
1952 Tabview
.prototype.clearHighlight = function () {
1953 this.tab
.removeClass('highlight');
1954 this.tab
.removeClass('activity');
1956 Tabview
.prototype.changeTopic = function (new_topic
) {
1957 this.topic
= new_topic
;
1958 this.addMsg(null, ' ', '=== Topic for ' + this.name
+ ' is: ' + new_topic
, 'topic');
1959 if (kiwi
.front
.cur_channel
.name
=== this.name
) {
1960 kiwi
.front
.setTopicText(new_topic
);
1968 var Box = function (classname
) {
1969 this.id
= randomString(10);
1970 var tmp
= $('<div id="' + this.id
+ '" class="box ' + classname
+ '"><div class="boxarea"></div></div>');
1971 $('#kiwi').append(tmp
);
1972 this.box
= $('#' + this.id
);
1973 this.content
= $('#' + this.id
+ ' .boxarea');
1975 this.box
.draggable({ stack
: ".box" });
1976 this.content
.click(function () {});
1977 //this.box.click(function(){ $(this)..css });
1979 Box
.prototype.create = function (name
, classname
) {
1982 Box
.prototype.id
= null;
1983 Box
.prototype.box
= null;
1984 Box
.prototype.content
= null;
1985 Box
.prototype.destroy = function () {
1988 for (name
in kiwi
.front
.boxes
) {
1989 if (kiwi
.front
.boxes
[name
].id
=== this.id
) {
1990 delete kiwi
.front
.boxes
[name
];
1994 Box
.prototype.height = function () {
1995 return this.box
.height();