Apply channel linking before colour linking so colours aren't interpreted as channels
[KiwiIRC.git] / js / front.js
1 /*jslint nomen: true, devel: true, undef: true, browser: true, continue: true, sloppy: true, forin: true, newcap: true, plusplus: true, maxerr: 50, indent: 4 */
2 /*global gateway, io, $, iScroll, agent, touchscreen, init_data, plugs, plugins, registerTouches, randomString */
3 kiwi.front = {
4 revision: 38,
5
6 cur_channel: '',
7 windows: {},
8 tabviews: {},
9 utilityviews: {},
10 boxes: {},
11
12 buffer: [],
13 buffer_pos: 0,
14
15 cache: {},
16
17 original_topic: '',
18
19 init: function () {
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;
24
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("onnick", kiwi.front.onNick);
34 $(kiwi.gateway).bind("onuserlist", kiwi.front.onUserList);
35 $(kiwi.gateway).bind("onuserlist_end", kiwi.front.onUserListEnd);
36 $(kiwi.gateway).bind("onlist_start", kiwi.front.onChannelListStart);
37 $(kiwi.gateway).bind("onlist_channel", kiwi.front.onChannelList);
38 $(kiwi.gateway).bind("onlist_end", kiwi.front.onChannelListEnd);
39 $(kiwi.gateway).bind("onjoin", kiwi.front.onJoin);
40 $(kiwi.gateway).bind("ontopic", kiwi.front.onTopic);
41 $(kiwi.gateway).bind("onpart", kiwi.front.onPart);
42 $(kiwi.gateway).bind("onkick", kiwi.front.onKick);
43 $(kiwi.gateway).bind("onquit", kiwi.front.onQuit);
44 $(kiwi.gateway).bind("onmode", kiwi.front.onMode);
45 $(kiwi.gateway).bind("onwhois", kiwi.front.onWhois);
46 $(kiwi.gateway).bind("onsync", kiwi.front.onSync);
47 $(kiwi.gateway).bind("onchannel_redirect", kiwi.front.onChannelRedirect);
48 $(kiwi.gateway).bind("ondebug", kiwi.front.onDebug);
49 $(kiwi.gateway).bind("onctcp_request", kiwi.front.onCTCPRequest);
50 $(kiwi.gateway).bind("onctcp_response", kiwi.front.onCTCPResponse);
51 $(kiwi.gateway).bind("onirc_error", kiwi.front.onIRCError);
52 $(kiwi.gateway).bind("onkiwi", kiwi.front.onKiwi);
53
54 this.buffer = [];
55
56 // Build the about box
57 kiwi.front.boxes.about = new Box("about");
58 about_info = 'UI adapted for ' + agent;
59 if (touchscreen) {
60 about_info += ' touchscreen ';
61 }
62 about_info += 'usage';
63 $('#tmpl_about_box').tmpl({
64 about: about_info,
65 front_revision: kiwi.front.revision,
66 gateway_revision: kiwi.gateway.revision
67 }).appendTo(kiwi.front.boxes.about.content);
68
69 //$(window).bind("beforeunload", function(){ kiwi.gateway.quit(); });
70
71 if (touchscreen) {
72 $('#kiwi').addClass('touchscreen');
73
74 // Single touch scrolling through scrollback for touchscreens
75 scroll_opts = {};
76 touch_scroll = new iScroll('windows', scroll_opts);
77 }
78
79 kiwi.front.registerKeys();
80
81 $('#kiwi .toolbars').resize(kiwi.front.doLayoutSize);
82 $(window).resize(kiwi.front.doLayoutSize);
83
84 // Add the resizer for the userlist
85 $('<div id="nicklist_resize" style="position:absolute; cursor:w-resize; width:5px;"></div>').appendTo('#kiwi');
86 $('#nicklist_resize').draggable({axis: "x", drag: function () {
87 var t = $(this),
88 new_width = $(document).width() - parseInt(t.css('left'), 10);
89
90 new_width = new_width - parseInt($('#kiwi .userlist').css('margin-left'), 10);
91 new_width = new_width - parseInt($('#kiwi .userlist').css('margin-right'), 10);
92
93 // Make sure we don't remove the userlist alltogether
94 console.log(new_width);
95 if (new_width < 20) {
96 $(this).data('draggable').offset.click.left = 10;
97 console.log('whoaa');
98 }
99
100 kiwi.front.cur_channel.setUserlistWidth(new_width);
101 }});
102
103
104 $('#kiwi .formconnectwindow').submit(function () {
105 var netsel = $('#kiwi .formconnectwindow .network'),
106 nick = $('#kiwi .formconnectwindow .nick'),
107 tmp;
108
109 if (nick.val() === '') {
110 nick.val('Nick please!');
111 nick.focus();
112 return false;
113 }
114
115 tmp = nick.val().split(' ');
116 kiwi.gateway.nick = tmp[0];
117
118 init_data.channel = $('#channel').val();
119
120 kiwi.front.doLayout();
121 try {
122 kiwi.front.run('/connect ' + netsel.val());
123 } catch (e) {}
124
125 $('#kiwi .connectwindow').slideUp('', kiwi.front.barsShow);
126 $('#windows').click(function () { $('#kiwi_msginput').focus(); });
127
128 return false;
129 });
130
131 supportsOrientationChange = (typeof window.onorientationchange !== undefined);
132 orientationEvent = supportsOrientationChange ? "orientationchange" : "resize";
133 if (window.addEventListener) {
134 window.addEventListener(orientationEvent, kiwi.front.doLayoutSize, false);
135 } else {
136 // < IE9
137 window.attachEvent(orientationEvent, kiwi.front.doLayoutSize, false);
138 }
139 //$('#kiwi').bind("resize", kiwi.front.doLayoutSize, false);
140
141 kiwi.front.doLayout();
142 kiwi.front.barsHide();
143
144 kiwi.front.tabviewAdd('server');
145 kiwi.front.tabviews.server.userlist_width = 0; // Disable the userlist
146
147 // Any pre-defined nick?
148 if (typeof window.init_data.nick === "string") {
149 $('#kiwi .formconnectwindow .nick').val(init_data.nick);
150 }
151
152 // Any pre-defined channels?
153 if (typeof window.init_data.channel === 'string') {
154 $('#channel').val(init_data.channel);
155 }
156
157 // Fix for Opera inserting a spurious <br/>
158 $('#kiwi .cur_topic br').remove();
159
160 $('#kiwi .cur_topic').keydown(function (e) {
161 if (e.which === 13) {
162 // enter
163 e.preventDefault();
164 $(this).change();
165 $('#kiwi_msginput').focus();
166 } else if (e.which === 27) {
167 // escape
168 e.preventDefault();
169 $(this).text(kiwi.front.original_topic);
170 $('#kiwi_msginput').focus();
171 }
172 });
173 /*$('.cur_topic').live('keypress', function(e) {
174 if (e.keyCode === 13) {
175 // enter
176 e.preventDefault();
177 $(this).change();
178 $('#kiwi_msginput').focus();
179 } else if (e.keyCode === 27) {
180 // escape
181 e.preventDefault();
182 $(this).text(kiwi.front.original_topic);
183 }
184 });*/
185 $('.cur_topic').live('change', function () {
186 var chan, text;
187 text = $(this).text();
188 if (text !== kiwi.front.original_topic) {
189 chan = kiwi.front.cur_channel.name;
190 kiwi.gateway.setTopic(chan, text);
191 }
192 });
193
194
195 $('#windows a.chan').live('click', function () {
196 kiwi.front.joinChannel($(this).text());
197 return false;
198 });
199
200 kiwi.data.set('chanList', []);
201
202 (function () {
203 var i;
204 for (i in plugins) {
205 kiwi.plugs.loadPlugin(plugins[i]);
206 }
207 }());
208 },
209
210 doLayoutSize: function () {
211 var kiwi, toolbars, ul, n_top, n_bottom, nl;
212 kiwi = $('#kiwi');
213
214 if (kiwi.width() < 330 && !kiwi.hasClass('small_kiwi')) {
215 console.log("switching to small kiwi");
216 kiwi.removeClass('large_kiwi');
217 kiwi.addClass('small_kiwi');
218 } else if (kiwi.width() >= 330 && !kiwi.hasClass('large_kiwi')) {
219 kiwi.removeClass('small_kiwi');
220 kiwi.addClass('large_kiwi');
221 }
222
223 toolbars = $('#kiwi .cur_topic');
224 ul = $('#kiwi .userlist');
225
226 n_top = parseInt(toolbars.offset().top, 10) + parseInt(toolbars.outerHeight(true), 10);
227 n_bottom = $(document).height() - parseInt($('#kiwi .control').offset().top, 10);
228
229 $('#kiwi .windows').css({top: n_top + 'px', bottom: n_bottom + 'px'});
230 ul.css({top: n_top + 'px', bottom: n_bottom + 'px'});
231
232 nl = $('#nicklist_resize');
233 nl.css({top: n_top + 'px', bottom: n_bottom + 'px', left: $(document).width() - ul.outerWidth(true)});
234 },
235
236
237 doLayout: function () {
238 $('#kiwi .msginput .nick a').text(kiwi.gateway.nick);
239 $('#kiwi_msginput').val(' ');
240 $('#kiwi_msginput').focus();
241 },
242
243
244 joinChannel: function (chan_name) {
245 var chans = chan_name.split(','),
246 i,
247 chan;
248 for (i in chans) {
249 chan = chans[i];
250 if (kiwi.front.tabviews[chan.toLowerCase()] === undefined || (kiwi.front.tabviews[chan.toLowerCase()] !== undefined && kiwi.front.tabviews[chan.toLowerCase()].safe_to_close === true)) {
251 kiwi.gateway.join(chan);
252 kiwi.front.tabviewAdd(chan);
253 } else {
254 kiwi.front.tabviews[chan.toLowerCase()].show();
255 }
256 }
257 },
258
259
260 run: function (msg) {
261 var parts, dest, t, pos, textRange, d, plugin_event, msg_sliced;
262
263 // Run through any plugins
264 plugin_event = {command: msg};
265 plugin_event = kiwi.plugs.run('command_run', plugin_event);
266 if (!plugin_event || typeof plugin_event.command === 'undefined') {
267 return;
268 }
269
270 // Update msg if it's been changed by any plugins
271 msg = plugin_event.command.toString();
272
273 console.log("running " + msg);
274 if (msg.substring(0, 1) === '/') {
275 parts = msg.split(' ');
276 switch (parts[0].toLowerCase()) {
277 case '/j':
278 case '/join':
279 kiwi.front.joinChannel(parts[1]);
280 break;
281
282 case '/connect':
283 case '/server':
284 if (parts[1] === undefined) {
285 alert('Usage: /connect servername [port]');
286 break;
287 }
288
289 if (parts[2] === undefined) {
290 parts[2] = 6667;
291 }
292 kiwi.front.cur_channel.addMsg(null, ' ', '=== Connecting to ' + parts[1] + '...', 'status');
293 kiwi.gateway.connect(parts[1], parts[2], 0);
294 break;
295
296 case '/nick':
297 console.log("/nick");
298 if (parts[1] === undefined) {
299 console.log("calling show nick");
300 kiwi.front.showChangeNick();
301 } else {
302 console.log("sending raw");
303 kiwi.gateway.raw(msg.substring(1));
304 }
305 break;
306
307 case '/part':
308 if (typeof parts[1] === "undefined") {
309 if (kiwi.front.cur_channel.safe_to_close) {
310 kiwi.front.cur_channel.close();
311 } else {
312 kiwi.gateway.raw(msg.substring(1) + ' ' + kiwi.front.cur_channel.name);
313 }
314 } else {
315 kiwi.gateway.raw(msg.substring(1));
316 }
317 break;
318
319 case '/names':
320 if (typeof parts[1] !== "undefined") {
321 kiwi.gateway.raw(msg.substring(1));
322 }
323 break;
324
325 case '/debug':
326 kiwi.gateway.debug();
327 break;
328
329 case '/q':
330 case '/query':
331 if (typeof parts[1] !== "undefined") {
332 kiwi.front.tabviewAdd(parts[1]);
333 }
334 break;
335
336
337 case '/m':
338 case '/msg':
339 if (typeof parts[1] !== "undefined") {
340 msg_sliced = msg.split(' ').slice(2).join(' ');
341 kiwi.gateway.msg(parts[1], msg_sliced);
342
343 if (!kiwi.front.tabviewExists(parts[1])) {
344 kiwi.front.tabviewAdd(parts[1]);
345 }
346 kiwi.front.tabviews[parts[1].toLowerCase()].addMsg(null, kiwi.gateway.nick, msg_sliced);
347 }
348 break;
349
350 case '/k':
351 case '/kick':
352 if (typeof parts[1] === 'undefined') {
353 return;
354 }
355 kiwi.gateway.raw('KICK ' + kiwi.front.cur_channel.name + ' ' + msg.split(' ', 2)[1]);
356 break;
357
358 case '/quote':
359 kiwi.gateway.raw(msg.replace(/^\/quote /i, ''));
360 break;
361
362 case '/me':
363 kiwi.gateway.action(kiwi.front.cur_channel.name, msg.substring(4));
364 //kiwi.front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* '+data.nick+' '+data.msg, 'color:green;');
365 kiwi.front.cur_channel.addMsg(null, ' ', '* ' + kiwi.gateway.nick + ' ' + msg.substring(4), 'action', 'color:#555;');
366 break;
367
368 case '/notice':
369 dest = parts[1];
370 msg = parts.slice(2).join(' ');
371
372 kiwi.gateway.notice(dest, msg);
373 this.onNotice({}, {nick: kiwi.gateway.nick, channel: dest, msg: msg});
374 break;
375
376 case '/win':
377 if (parts[1] !== undefined) {
378 kiwi.front.windowsShow(parseInt(parts[1], 10));
379 }
380 break;
381
382 case '/quit':
383 kiwi.gateway.quit(msg.split(" ", 2)[1]);
384 break;
385
386 case '/topic':
387 if (parts[1] === undefined) {
388 t = $('.cur_topic');
389 if (t.createTextRange) {
390 pos = t.text().length();
391 textRange = t.createTextRange();
392 textRange.collapse(true);
393 textRange.moveEnd(pos);
394 textRange.moveStart(pos);
395 textRange.select();
396 } else if (t.setSelectionRange) {
397 t.setSelectionRange(pos, pos);
398 }
399 } else {
400 kiwi.gateway.setTopic(kiwi.front.cur_channel.name, msg.split(' ', 2)[1]);
401 //kiwi.gateway.raw('TOPIC ' + kiwi.front.cur_channel.name + ' :' + msg.split(' ', 2)[1]);
402 }
403 break;
404
405 case '/kiwi':
406 kiwi.gateway.kiwi(kiwi.front.cur_channel.name, msg.substring(6));
407 break;
408
409 default:
410 //kiwi.front.cur_channel.addMsg(null, ' ', '--> Invalid command: '+parts[0].substring(1));
411 kiwi.gateway.raw(msg.substring(1));
412 }
413
414 } else {
415 //alert('Sending message: '+msg);
416 if (msg.trim() === '') {
417 return;
418 }
419 if (kiwi.front.cur_channel.name !== 'server') {
420 kiwi.gateway.msg(kiwi.front.cur_channel.name, msg);
421 d = new Date();
422 d = d.getHours() + ":" + d.getMinutes();
423 //kiwi.front.addMsg(d, kiwi.gateway.nick, msg);
424 kiwi.front.cur_channel.addMsg(null, kiwi.gateway.nick, msg);
425 }
426 }
427 },
428
429
430 onMsg: function (e, data) {
431 var destination, plugin_event;
432 // Is this message from a user?
433 if (data.channel === kiwi.gateway.nick) {
434 destination = data.nick.toLowerCase();
435 } else {
436 destination = data.channel.toLowerCase();
437 }
438
439 plugin_event = {nick: data.nick, msg: data.msg, destination: destination};
440 plugin_event = kiwi.plugs.run('msg_recieved', plugin_event);
441 if (!plugin_event) {
442 return;
443 }
444
445 if (!kiwi.front.tabviewExists(plugin_event.destination)) {
446 kiwi.front.tabviewAdd(plugin_event.destination);
447 }
448 kiwi.front.tabviews[plugin_event.destination].addMsg(null, plugin_event.nick, plugin_event.msg);
449 },
450
451 onDebug: function (e, data) {
452 if (!kiwi.front.tabviewExists('kiwi_debug')) {
453 kiwi.front.tabviewAdd('kiwi_debug');
454 }
455 kiwi.front.tabviews.kiwi_debug.addMsg(null, ' ', data.msg);
456 },
457
458 onAction: function (e, data) {
459 var destination;
460 // Is this message from a user?
461 if (data.channel === kiwi.gateway.nick) {
462 destination = data.nick;
463 } else {
464 destination = data.channel;
465 }
466
467 if (!kiwi.front.tabviewExists(destination)) {
468 kiwi.front.tabviewAdd(destination);
469 }
470 kiwi.front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* ' + data.nick + ' ' + data.msg, 'action', 'color:#555;');
471 },
472
473 onTopic: function (e, data) {
474 if (kiwi.front.tabviewExists(data.channel)) {
475 kiwi.front.tabviews[data.channel.toLowerCase()].changeTopic(data.topic);
476 }
477 },
478
479 onNotice: function (e, data) {
480 var nick = (data.nick === undefined) ? '' : data.nick,
481 enick = '[' + nick + ']';
482
483 if (kiwi.front.tabviewExists(data.target)) {
484 kiwi.front.tabviews[data.target.toLowerCase()].addMsg(null, enick, data.msg, 'notice');
485 } else if (kiwi.front.tabviewExists(nick)) {
486 kiwi.front.tabviews[nick.toLowerCase()].addMsg(null, enick, data.msg, 'notice');
487 } else {
488 kiwi.front.tabviews.server.addMsg(null, enick, data.msg, 'notice');
489 }
490 },
491
492 onCTCPRequest: function (e, data) {
493 var msg = data.msg.split(" ", 2);
494 switch (msg[0]) {
495 case 'PING':
496 if (typeof msg[1] === 'undefined') {
497 msg[1] = '';
498 }
499 kiwi.gateway.notice(data.nick, String.fromCharCode(1) + 'PING ' + msg[1] + String.fromCharCode(1));
500 break;
501 case 'TIME':
502 kiwi.gateway.notice(data.nick, String.fromCharCode(1) + 'TIME ' + (new Date()).toLocaleString() + String.fromCharCode(1));
503 break;
504 }
505 kiwi.front.tabviews.server.addMsg(null, 'CTCP [' + data.nick + ']', data.msg, 'ctcp');
506 },
507
508 onCTCPResponse: function (e, data) {
509 },
510
511 onKiwi: function (e, data) {
512 //console.log(data);
513 },
514
515 onConnect: function (e, data) {
516 if (data.connected) {
517 if (kiwi.gateway.nick !== data.nick) {
518 kiwi.gateway.nick = data.nick;
519 kiwi.front.doLayout();
520 }
521
522 kiwi.front.tabviews.server.addMsg(null, ' ', '=== Connected OK :)', 'status');
523 if (typeof init_data.channel === "string") {
524 kiwi.front.joinChannel(init_data.channel);
525 }
526 kiwi.plugs.run('connect', {success: true});
527 } else {
528 kiwi.front.tabviews.server.addMsg(null, ' ', '=== Failed to connect :(', 'status');
529 kiwi.plugs.run('connect', {success: false});
530 }
531 },
532 onConnectFail: function (e, data) {
533 var reason = (typeof data.reason === 'string') ? data.reason : '';
534 kiwi.front.tabviews.server.addMsg(null, '', 'There\'s a problem connecting! (' + reason + ')', 'error');
535 kiwi.plugs.run('connect', {success: false});
536 },
537 onDisconnect: function (e, data) {
538 var tab;
539 for (tab in kiwi.front.tabviews) {
540 kiwi.front.tabviews[tab].addMsg(null, '', 'Disconnected from server!', 'error');
541 }
542 kiwi.plugs.run('disconnect', {success: false});
543 },
544 onOptions: function (e, data) {
545 if (typeof kiwi.gateway.network_name === "string" && kiwi.gateway.network_name !== "") {
546 kiwi.front.tabviews.server.tab.text(kiwi.gateway.network_name);
547 }
548 },
549 onMOTD: function (e, data) {
550 kiwi.front.tabviews.server.addMsg(null, data.server, data.msg, 'motd');
551 },
552 onWhois: function (e, data) {
553 var d;
554 if (data.msg) {
555 kiwi.front.cur_channel.addMsg(null, data.nick, data.msg, 'whois');
556 } else if (data.logon) {
557 d = new Date();
558 d.setTime(data.logon * 1000);
559 d = d.toLocaleString();
560 kiwi.front.cur_channel.addMsg(null, data.nick, 'idle for ' + data.idle + ' second' + ((data.idle !== 1) ? 's' : '') + ', signed on ' + d, 'whois');
561 } else {
562 kiwi.front.cur_channel.addMsg(null, data.nick, 'idle for ' + data.idle + ' seconds', 'whois');
563 }
564 },
565 onMode: function (e, data) {
566 var i, new_nick_text;
567
568 // TODO: Store the modes in the elements data, then work out the current
569 // mode symbol from the highest mode. Eg. -h may leave +o from previous modes; It
570 // doesn't simply clear it! ~Darren
571 if (typeof data.channel === 'string' && typeof data.effected_nick === 'string') {
572 kiwi.front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '[' + data.mode + '] ' + data.effected_nick + ' by ' + data.nick, 'mode', '');
573 kiwi.front.tabviews[data.channel.toLowerCase()].userlist.children().each(function () {
574 if (kiwi.front.nickStripPrefix($(this).text()) === data.effected_nick) {
575
576 if (data.mode.split('')[0] === '+') {
577 for (i = 0; i < kiwi.gateway.user_prefixes.length; i++) {
578 if (kiwi.gateway.user_prefixes[i].mode === data.mode.split('')[1]) {
579 new_nick_text = kiwi.gateway.user_prefixes[i].symbol + data.effected_nick;
580 break;
581 }
582 }
583 } else if (data.mode.split('')[0] === '-') {
584 new_nick_text = data.effected_nick;
585 }
586
587 if (new_nick_text !== '') {
588 $(this).text(new_nick_text);
589 return false;
590 }
591
592 }
593 });
594 }
595 },
596 onUserList: function (e, data) {
597 var ul, nick, mode;
598 if (kiwi.front.tabviews[data.channel.toLowerCase()] === undefined) {
599 return;
600 }
601 ul = kiwi.front.tabviews[data.channel.toLowerCase()].userlist;
602
603 if (!document.userlist_updating) {
604 document.userlist_updating = true;
605 ul.empty();
606 }
607
608 $.each(data.users, function (i, item) {
609 nick = i; //i.match(/^.+!/g);
610 mode = item;
611 $('<li><a class="nick" onclick="kiwi.front.userClick(this);">' + mode + nick + '</a></li>').appendTo(ul);
612 });
613
614 kiwi.front.tabviews[data.channel.toLowerCase()].userlistSort();
615 },
616 onUserListEnd: function (e, data) {
617 document.userlist_updating = false;
618 },
619
620 onChannelListStart: function (e, data) {
621 var tab, table;
622 console.log('/list start');
623 console.profile('list');
624
625 tab = new Utilityview('Channel List');
626 tab.div.css('overflow-y', 'scroll');
627 table = $('<table><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>');
628 tab.div.append(table);
629
630 kiwi.front.cache.list = {chans: [], tab: tab, table: table,
631 update: function (newChans) {
632 var body = this.table.children('tbody:first').detach(),
633 chan,
634 html;
635
636 html = '';
637 for (chan in newChans) {
638 this.chans.push(newChans[chan]);
639 html += newChans[chan].html;
640 }
641 body.append(html);
642 this.table.append(body);
643
644 },
645 finalise: function () {
646 var body = this.table.children('tbody:first').detach(),
647 list,
648 chan;
649
650 list = $.makeArray($(body).children());
651
652 for (chan in list) {
653 list[chan] = $(list[chan]).detach();
654 }
655
656 list = _.sortBy(list, function (channel) {
657 return parseInt(channel.children('.num_users').first().text(), 10);
658 }).reverse();
659
660 for (chan in list) {
661 body.append(list[chan]);
662 }
663
664 this.table.append(body);
665
666 }};
667 },
668 onChannelList: function (e, data) {
669 var chans;
670 console.log(data);
671 data = data.chans;
672 //data = [data];
673 for (chans in data) {
674 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>'};
675 }
676 kiwi.front.cache.list.update(data);
677 },
678 onChannelListEnd: function (e, data) {
679 kiwi.front.cache.list.finalise();
680 kiwi.front.cache.list.tab.show();
681 console.profileEnd();
682 console.log('/list end.');
683 },
684
685
686 onJoin: function (e, data) {
687 if (!kiwi.front.tabviewExists(data.channel)) {
688 kiwi.front.tabviewAdd(data.channel.toLowerCase());
689 }
690
691 if (data.nick === kiwi.gateway.nick) {
692 return; // Not needed as it's already in nicklist
693 }
694 kiwi.front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '--> ' + data.nick + ' has joined', 'action join', 'color:#009900;');
695 $('<li><a class="nick" onclick="kiwi.front.userClick(this);">' + data.nick + '</a></li>').appendTo(kiwi.front.tabviews[data.channel.toLowerCase()].userlist);
696 kiwi.front.tabviews[data.channel.toLowerCase()].userlistSort();
697 },
698 onPart: function (e, data) {
699 if (kiwi.front.tabviewExists(data.channel)) {
700 // If this is us, close the tabview
701 if (data.nick === kiwi.gateway.nick) {
702 kiwi.front.tabviews[data.channel.toLowerCase()].close();
703 kiwi.front.tabviews.server.show();
704 return;
705 }
706
707 kiwi.front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '<-- ' + data.nick + ' has left (' + data.message + ')', 'action part', 'color:#990000;');
708 kiwi.front.tabviews[data.channel.toLowerCase()].userlist.children().each(function () {
709 if ($(this).text() === data.nick) {
710 $(this).remove();
711 }
712 });
713 }
714 },
715 onKick: function (e, data) {
716 if (kiwi.front.tabviewExists(data.channel)) {
717 // If this is us, close the tabview
718 if (data.kicked === kiwi.gateway.nick) {
719 //kiwi.front.tabviews[data.channel.toLowerCase()].close();
720 kiwi.front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '=== You have been kicked from ' + data.channel + '. ' + data.message, 'status kick');
721 kiwi.front.tabviews[data.channel.toLowerCase()].safe_to_close = true;
722 $('li', kiwi.front.tabviews[data.channel.toLowerCase()].userlist).remove();
723 return;
724 }
725
726 kiwi.front.tabviews[data.channel.toLowerCase()].addMsg(null, ' ', '<-- ' + data.kicked + ' kicked by ' + data.nick + '(' + data.message + ')', 'action kick', 'color:#990000;');
727 kiwi.front.tabviews[data.channel.toLowerCase()].userlist.children().each(function () {
728 if ($(this).text() === data.nick) {
729 $(this).remove();
730 }
731 });
732 }
733 },
734 onNick: function (e, data) {
735 if (data.nick === kiwi.gateway.nick) {
736 kiwi.gateway.nick = data.newnick;
737 kiwi.front.doLayout();
738 }
739
740 $.each(kiwi.front.tabviews, function (i, item) {
741 $.each(kiwi.front.tabviews, function (i, item) {
742 item.changeNick(data.newnick, data.nick);
743 });
744 });
745 },
746 onQuit: function (e, data) {
747 $.each(kiwi.front.tabviews, function (i, item) {
748 $.each(kiwi.front.tabviews, function (i, item) {
749 item.userlist.children().each(function () {
750 if ($(this).text() === data.nick) {
751 $(this).remove();
752 item.addMsg(null, ' ', '<-- ' + data.nick + ' has quit (' + data.message + ')', 'action quit', 'color:#990000;');
753 }
754 });
755 });
756 });
757 },
758 onChannelRedirect: function (e, data) {
759 kiwi.front.tabviews[data.from.toLowerCase()].close();
760 kiwi.front.tabviewAdd(data.to.toLowerCase());
761 kiwi.front.tabviews[data.to.toLowerCase()].addMsg(null, ' ', '=== Redirected from ' + data.from, 'action');
762 },
763
764 onIRCError: function (e, data) {
765 var t_view;
766 if (data.channel !== undefined && kiwi.front.tabviewExists(data.channel)) {
767 t_view = data.channel;
768 } else {
769 t_view = 'server';
770 }
771
772 switch (data.error) {
773 case 'banned_from_channel':
774 kiwi.front.tabviews[t_view].addMsg(null, ' ', '=== You are banned from ' + data.channel + '. ' + data.reason, 'status');
775 if (t_view !== 'server') {
776 kiwi.front.tabviews[t_view].safe_to_close = true;
777 }
778 break;
779 case 'bad_channel_key':
780 kiwi.front.tabviews[t_view].addMsg(null, ' ', '=== Bad channel key for ' + data.channel, 'status');
781 if (t_view !== 'server') {
782 kiwi.front.tabviews[t_view].safe_to_close = true;
783 }
784 break;
785 case 'invite_only_channel':
786 kiwi.front.tabviews[t_view].addMsg(null, ' ', '=== ' + data.channel + ' is invite only.', 'status');
787 if (t_view !== 'server') {
788 kiwi.front.tabviews[t_view].safe_to_close = true;
789 }
790 break;
791 case 'channel_is_full':
792 kiwi.front.tabviews[t_view].addMsg(null, ' ', '=== ' + data.channel + ' is full.', 'status');
793 if (t_view !== 'server') {
794 kiwi.front.tabviews[t_view].safe_to_close = true;
795 }
796 break;
797 case 'chanop_privs_needed':
798 kiwi.front.tabviews[data.channel].addMsg(null, ' ', '=== ' + data.reason, 'status');
799 break;
800 case 'no_such_nick':
801 kiwi.front.tabviews.server.addMsg(null, ' ', '=== ' + data.nick + ': ' + data.reason, 'status');
802 break;
803 case 'nickname_in_use':
804 kiwi.front.tabviews.server.addMsg(null, ' ', '=== The nickname ' + data.nick + ' is already in use. Please select a new nickname', 'status');
805 kiwi.front.showChangeNick();
806 break;
807 default:
808 // We don't know what data contains, so don't do anything with it.
809 //kiwi.front.tabviews.server.addMsg(null, ' ', '=== ' + data, 'status');
810 }
811 },
812
813 registerKeys: function () {
814 $('#kiwi_msginput').bind('keydown', function (e) {
815 var windows, meta, num, msg, data, candidates, word_pos, word, i;
816 windows = $('#windows');
817 //var meta = e.altKey;
818 meta = e.ctrlKey;
819
820 switch (true) {
821 case (e.which >= 48) && (e.which <= 57):
822 if (meta) {
823 num = e.which - 48;
824 if (num === 0) {
825 num = 10;
826 }
827 num = num - 1;
828 kiwi.front.windowsShow(num);
829 return false;
830 }
831 break;
832 case e.which === 27: // escape
833 return false;
834 case e.which === 13: // return
835 msg = $('#kiwi_msginput').val();
836 msg = msg.trim();
837
838 kiwi.front.buffer.push(msg);
839 kiwi.front.buffer_pos = kiwi.front.buffer.length;
840
841 kiwi.front.run(msg);
842 $('#kiwi_msginput').val('');
843
844 break;
845 case e.which === 33: // page up
846 console.log("page up");
847 windows[0].scrollTop = windows[0].scrollTop - windows.height();
848 return false;
849 case e.which === 34: // page down
850 windows[0].scrollTop = windows[0].scrollTop + windows.height();
851 return false;
852 case e.which === 37: // left
853 if (meta) {
854 kiwi.front.windowsPrevious();
855 return false;
856 }
857 break;
858 case e.which === 38: // up
859 if (kiwi.front.buffer_pos > 0) {
860 kiwi.front.buffer_pos--;
861 $('#kiwi_msginput').val(kiwi.front.buffer[kiwi.front.buffer_pos]);
862 }
863 break;
864 case e.which === 39: // right
865 if (meta) {
866 kiwi.front.windowsNext();
867 return false;
868 }
869 break;
870 case e.which === 40: // down
871 if (kiwi.front.buffer_pos < kiwi.front.buffer.length) {
872 kiwi.front.buffer_pos++;
873 $('#kiwi_msginput').val(kiwi.front.buffer[kiwi.front.buffer_pos]);
874 }
875 break;
876
877 case e.which === 9: // tab
878 // Get possible autocompletions
879 data = [];
880 kiwi.front.cur_channel.userlist.children().each(function () {
881 var nick;
882 nick = kiwi.front.nickStripPrefix($('a.nick', this).text());
883 data.push(nick);
884 });
885
886 // Do the autocomplete
887 if (this.value.length === this.selectionStart && this.value.length === this.selectionEnd) {
888 candidates = [];
889
890 word_pos = this.value.lastIndexOf(' ');
891 word = "";
892 if (word_pos === -1) {
893 word = this.value;
894 } else {
895 word = this.value.substr(word_pos);
896 }
897 word = word.trim();
898
899 // filter data to find only strings that start with existing value
900 for (i = 0; i < data.length; i++) {
901 if (data[i].indexOf(word) === 0 && data[i].length > word.length) {
902 candidates.push(data[i]);
903 }
904 }
905
906 if (candidates.length > 0) {
907 // some candidates for autocompletion are found
908 this.value = this.value.substring(0, word_pos) + ' ' + candidates[0] + ': ';
909 this.selectionStart = this.value.length;
910 }
911 }
912 return false;
913 }
914 });
915
916
917 $('#kiwi .control .msginput .nick').click(function () {
918 kiwi.front.showChangeNick();
919 });
920
921
922
923
924
925 $('#kiwi .plugins .load_plugin_file').click(function () {
926 if (typeof kiwi.front.boxes.plugins !== "undefined") {
927 return;
928 }
929
930 kiwi.front.boxes.plugins = new Box("plugin_file");
931 $('#tmpl_plugins').tmpl({}).appendTo(kiwi.front.boxes.plugins.content);
932 kiwi.front.boxes.plugins.box.css('top', -(kiwi.front.boxes.plugins.height + 40));
933
934 // Populate the plugin list..
935 function enumPlugins() {
936 var lst, j, txt;
937 lst = $('#plugin_list');
938 lst.find('option').remove();
939 for (j in kiwi.plugs.loaded) {
940 txt = kiwi.plugs.loaded[j].name;
941 lst.append('<option value="' + txt + '">' + txt + '</option>');
942 }
943 }
944 enumPlugins();
945
946 // Event bindings
947 $('#kiwi .plugin_file').submit(function () {
948 $('<div></div>').load($('.txtpluginfile').val(), function (e) {
949 enumPlugins();
950 });
951 return false;
952 });
953 $('#kiwi .cancelpluginfile').click(function () {
954 kiwi.front.boxes.plugins.destroy();
955 });
956
957 $('#kiwi #plugins_list_unload').click(function () {
958 var selected_plugin;
959 selected_plugin = $('#plugin_list').val();
960 kiwi.plugs.unloadPlugin(selected_plugin);
961 enumPlugins();
962 });
963
964 $('#kiwi .txtpluginfile').focus();
965
966 });
967
968 $('#kiwi .plugins .reload_css').click(function () {
969 var links = document.getElementsByTagName("link"),
970 i;
971 for (i = 0; i < links.length; i++) {
972 if (links[i].rel === "stylesheet") {
973 if (links[i].href.indexOf("?") === -1) {
974 links[i].href += "?";
975 }
976 links[i].href += "x";
977 }
978 }
979 });
980
981
982 $('#kiwi .about .about_close').click(function () {
983 $('#kiwi .about').css('display', 'none');
984 });
985
986
987 $('#kiwi .poweredby').click(function () {
988 $('#kiwi .about').css('display', 'block');
989 });
990
991 },
992
993
994 showChangeNick: function () {
995 $('#kiwi').append($('#tmpl_change_nick').tmpl({}));
996
997 $('#kiwi .form_newnick').submit(function () {
998 kiwi.front.run('/NICK ' + $('#kiwi .txtnewnick').val());
999 $('#kiwi .newnick').remove();
1000 return false;
1001 });
1002
1003 $('#kiwi .txtnewnick').keypress(function (ev) {
1004 if (!this.first_press) {
1005 this.first_press = true;
1006 return false;
1007 }
1008 });
1009
1010 $('#kiwi .txtnewnick').keydown(function (ev) {
1011 if (ev.which === 27) { // ESC
1012 $('#kiwi_msginput').focus();
1013 $('#kiwi .newnick').remove();
1014 }
1015 });
1016
1017 $('#kiwi .cancelnewnick').click(function () {
1018 $('#kiwi .newnick').remove();
1019 });
1020
1021 $('#kiwi .txtnewnick').focus();
1022 },
1023
1024
1025 tabviewExists: function (name) {
1026 return (typeof kiwi.front.tabviews[name.toLowerCase()] !== 'undefined');
1027 },
1028
1029 tabviewAdd: function (v_name) {
1030 /*global Tabview */
1031 var re, htmlsafe_name, tmp_divname, tmp_userlistname, tmp_tabname, userlist_enabled = true;
1032
1033 if (v_name.charAt(0) === kiwi.gateway.channel_prefix) {
1034 re = new RegExp(kiwi.gateway.channel_prefix, "g");
1035 htmlsafe_name = v_name.replace(re, 'pre');
1036 htmlsafe_name = "chan_" + htmlsafe_name;
1037 } else {
1038 htmlsafe_name = 'query_' + v_name;
1039 userlist_enabled = false;
1040 }
1041
1042 tmp_divname = 'kiwi_window_' + htmlsafe_name;
1043 tmp_userlistname = 'kiwi_userlist_' + htmlsafe_name;
1044 tmp_tabname = 'kiwi_tab_' + htmlsafe_name;
1045
1046 if (!kiwi.front.tabviewExists(v_name)) {
1047 $('#kiwi .windows .scroller').append('<div id="' + tmp_divname + '" class="messages"></div>');
1048 $('#kiwi .userlist').append('<ul id="' + tmp_userlistname + '"></ul>');
1049 $('#kiwi .windowlist ul').append('<li id="' + tmp_tabname + '" onclick="kiwi.front.tabviews[\'' + v_name.toLowerCase() + '\'].show();">' + v_name + '</li>');
1050 }
1051 //$('#kiwi .windowlist ul .window_'+v_name).click(function(){ kiwi.front.windowShow(v_name); });
1052 //kiwi.front.windowShow(v_name);
1053
1054 kiwi.front.tabviews[v_name.toLowerCase()] = new Tabview();
1055 kiwi.front.tabviews[v_name.toLowerCase()].name = v_name;
1056 kiwi.front.tabviews[v_name.toLowerCase()].div = $('#' + tmp_divname);
1057 kiwi.front.tabviews[v_name.toLowerCase()].userlist = $('#' + tmp_userlistname);
1058 kiwi.front.tabviews[v_name.toLowerCase()].tab = $('#' + tmp_tabname);
1059 if (!userlist_enabled) {
1060 kiwi.front.tabviews[v_name.toLowerCase()].userlist_width = 0;
1061 }
1062 kiwi.front.tabviews[v_name.toLowerCase()].show();
1063
1064 if (typeof registerTouches === "function") {
1065 //alert("Registering touch interface");
1066 //registerTouches($('#'+tmp_divname));
1067 registerTouches(document.getElementById(tmp_divname));
1068 }
1069 /*
1070 kiwi.front.tabviews[v_name.toLowerCase()].userlist.click(function(){
1071 alert($(this).attr('id'));
1072 });
1073 */
1074
1075 kiwi.front.doLayoutSize();
1076 },
1077
1078
1079 userClick: function (item) {
1080 var li = $(item).parent();
1081
1082 // Remove any existing userboxes
1083 $('#kiwi .userbox').remove();
1084
1085 if ($(li).data('userbox') === item) {
1086 $(li).removeData('userbox');
1087 } else {
1088 $('#tmpl_user_box').tmpl({nick: kiwi.front.nickStripPrefix($(item).text())}).appendTo(li);
1089
1090 $('#kiwi .userbox .userbox_query').click(function (ev) {
1091 var nick = $('#kiwi .userbox_nick').val();
1092 kiwi.front.run('/query ' + nick);
1093 });
1094
1095 $('#kiwi .userbox .userbox_whois').click(function (ev) {
1096 var nick = $('#kiwi .userbox_nick').val();
1097 kiwi.front.run('/whois ' + nick);
1098 });
1099 $(li).data('userbox', item);
1100 }
1101 },
1102
1103
1104 sync: function () {
1105 kiwi.gateway.sync();
1106 },
1107
1108 onSync: function (e, data) {
1109 // Set any settings
1110 if (data.nick !== undefined) {
1111 kiwi.gateway.nick = data.nick;
1112 }
1113
1114 // Add the tabviews
1115 if (data.tabviews !== undefined) {
1116 $.each(data.tabviews, function (i, tab) {
1117 if (!kiwi.front.tabviewExists(tab.name)) {
1118 kiwi.front.tabviewAdd(kiwi.gateway.channel_prefix + tab.name);
1119
1120 if (tab.userlist !== undefined) {
1121 kiwi.front.onUserList({'channel': kiwi.gateway.channel_prefix + tab.name, 'users': tab.userlist});
1122 }
1123 }
1124 });
1125 }
1126
1127 kiwi.front.doLayout();
1128 },
1129
1130
1131 setTopicText: function (new_topic) {
1132 kiwi.front.original_topic = new_topic;
1133 $('#kiwi .cur_topic .topic').text(kiwi.front.format(new_topic));
1134 kiwi.front.doLayoutSize();
1135 },
1136
1137 nickStripPrefix: function (nick) {
1138 var tmp = nick, i, prefix;
1139
1140 prefix = tmp.charAt(0);
1141 for (i in kiwi.gateway.user_prefixes) {
1142 if (kiwi.gateway.user_prefixes[i].symbol === prefix) {
1143 return tmp.substring(1);
1144 }
1145 }
1146
1147 return tmp;
1148 },
1149
1150 nickGetPrefix: function (nick) {
1151 var tmp = nick, i, prefix;
1152
1153 prefix = tmp.charAt(0);
1154 for (i in kiwi.gateway.user_prefixes) {
1155 if (kiwi.gateway.user_prefixes[i].symbol === prefix) {
1156 return prefix;
1157 }
1158 }
1159
1160 return '';
1161 },
1162
1163 isChannel: function (name) {
1164 var prefix, is_chan;
1165 prefix = name.charAt(0);
1166 if (kiwi.gateway.channel_prefix.indexOf(prefix) > -1) {
1167 is_chan = true;
1168 } else {
1169 is_chan = false;
1170 }
1171
1172 return is_chan;
1173 },
1174
1175 tabviewsNext: function () {
1176 var wl = $('#kiwi .windowlist ul'),
1177 next_left = parseInt(wl.css('text-indent').replace('px', ''), 10) + 170;
1178 wl.css('text-indent', next_left);
1179 },
1180
1181 tabviewsPrevious: function () {
1182 var wl = $('#kiwi .windowlist ul'),
1183 next_left = parseInt(wl.css('text-indent').replace('px', ''), 10) - 170;
1184 wl.css('text-indent', next_left);
1185 },
1186
1187 windowsNext: function () {
1188 var tab, next;
1189 next = false;
1190 for (tab in kiwi.front.tabviews) {
1191 if (!next) {
1192 if (kiwi.front.tabviews[tab] === kiwi.front.cur_channel) {
1193 next = true;
1194 continue;
1195 }
1196 } else {
1197 kiwi.front.tabviews[tab].show();
1198 return;
1199 }
1200 }
1201 },
1202
1203 windowsPrevious: function () {
1204 var tab, prev_tab, next;
1205 next = false;
1206 for (tab in kiwi.front.tabviews) {
1207 if (kiwi.front.tabviews[tab] === kiwi.front.cur_channel) {
1208 if (prev_tab) {
1209 prev_tab.show();
1210 }
1211 return;
1212 }
1213 prev_tab = kiwi.front.tabviews[tab];
1214 }
1215 },
1216
1217 windowsShow: function (num) {
1218 num = parseInt(num, 10);
1219 console.log('Showing window ' + num.toString());
1220 var i = 0, tab;
1221 for (tab in kiwi.front.tabviews) {
1222 if (i === num) {
1223 kiwi.front.tabviews[tab].show();
1224 return;
1225 }
1226 i++;
1227 }
1228 },
1229
1230
1231
1232 barsShow: function () {
1233 $('#kiwi .toolbars').slideDown();
1234 $('#kiwi .control').slideDown();
1235 },
1236
1237 barsHide: function () {
1238 $('#kiwi .toolbars').slideUp();
1239 $('#kiwi .control').slideUp();
1240 },
1241
1242 format: function (msg) {
1243 var re;
1244
1245 if ((!msg) || (typeof msg !== 'string')) {
1246 return;
1247 }
1248
1249 // bold
1250 if (msg.indexOf(String.fromCharCode(2)) !== -1) {
1251 next = '<b>';
1252 while (msg.indexOf(String.fromCharCode(2)) !== -1) {
1253 msg = msg.replace(String.fromCharCode(2), next);
1254 next = (next === '<b>') ? '</b>' : '<b>';
1255 }
1256 if (next === '</b>') {
1257 msg = msg + '</b>';
1258 }
1259 }
1260
1261 // underline
1262 if (msg.indexOf(String.fromCharCode(31)) !== -1) {
1263 next = '<u>';
1264 while (msg.indexOf(String.fromCharCode(31)) !== -1) {
1265 msg = msg.replace(String.fromCharCode(31), next);
1266 next = (next === '<u>') ? '</u>' : '<u>';
1267 }
1268 if (next === '</u>') {
1269 msg = msg + '</u>';
1270 }
1271 }
1272
1273 // colour
1274 re = /\x03([0-9][0-5]?)(,([0-9][0-5]?))?(.*?)\x03/g;
1275
1276 msg = msg.replace(re, function (str, p1, p2, p3, p4) {
1277 var fg, bg,
1278 col = function (num) {
1279 switch (parseInt(num, 10)) {
1280 case 0:
1281 return '#FFFFFF';
1282 case 1:
1283 return '#000000';
1284 case 2:
1285 return '#000080';
1286 case 3:
1287 return '#008000';
1288 case 4:
1289 return '#FF0000';
1290 case 5:
1291 return '#800040';
1292 case 6:
1293 return '#800080';
1294 case 7:
1295 return '#FF8040';
1296 case 8:
1297 return '#FFFF00';
1298 case 9:
1299 return '#80FF00';
1300 case 10:
1301 return '#008080';
1302 case 11:
1303 return '#00FFFF';
1304 case 12:
1305 return '#0000FF';
1306 case 13:
1307 return '#FF55FF';
1308 case 14:
1309 return '#808080';
1310 case 15:
1311 return '#C0C0C0';
1312 default:
1313 return null;
1314 }
1315 };
1316 fg = col(p1);
1317 bg = col(p3);
1318 return '<span style="' + ((fg !== null) ? 'color: ' + fg + '; ' : '') + ((bg !== null) ? 'background-color: ' + bg + ';' : '') + '">' + p4 + '</span>';
1319 });
1320 return msg;
1321 }
1322
1323 };
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340 /*
1341 * MISC VIEW
1342 */
1343
1344 var Utilityview = function (name) {
1345 var rand_name = randomString(15),
1346 tmp_divname = 'kiwi_window_' + rand_name,
1347 tmp_userlistname = 'kiwi_userlist_' + rand_name,
1348 tmp_tabname = 'kiwi_tab_' + rand_name;
1349
1350 this.name = rand_name;
1351 this.title = name;
1352 this.topic = ' ';
1353
1354 $('#kiwi .windows .scroller').append('<div id="' + tmp_divname + '" class="messages"></div>');
1355
1356 this.tab = $('<li id="' + tmp_tabname + '">' + this.title + '</li>');
1357 this.tab.click(function () {
1358 kiwi.front.utilityviews[rand_name.toLowerCase()].show();
1359 });
1360 $('#kiwi .utilityviewlist ul').append(this.tab);
1361
1362 this.div = $('#' + tmp_divname);
1363 this.div.css('overflow', 'hidden');
1364
1365 kiwi.front.utilityviews[rand_name.toLowerCase()] = this;
1366 };
1367
1368 Utilityview.prototype.name = null;
1369 Utilityview.prototype.title = null;
1370 Utilityview.prototype.div = null;
1371 Utilityview.prototype.tab = null;
1372 Utilityview.prototype.topic = ' ';
1373 Utilityview.prototype.show = function () {
1374 $('#kiwi .messages').removeClass("active");
1375 $('#kiwi .userlist ul').removeClass("active");
1376 $('#kiwi .toolbars ul li').removeClass("active");
1377
1378 $('#windows').css('overflow-y', 'hidden');
1379 $('#windows').css('right', 0);
1380 // Activate this tab!
1381 this.div.addClass('active');
1382 this.tab.addClass('active');
1383
1384 this.addPartImage();
1385
1386 kiwi.front.setTopicText(this.topic);
1387 kiwi.front.cur_channel = this;
1388
1389 // If we're using fancy scrolling, refresh it
1390 if (touch_scroll) {
1391 touch_scroll.refresh();
1392 }
1393 };
1394
1395 Utilityview.prototype.close = function () {
1396 this.div.remove();
1397 this.tab.remove();
1398
1399 if (kiwi.front.cur_channel === this) {
1400 kiwi.front.tabviews.server.show();
1401 }
1402 delete kiwi.front.utilityviews[this.name.toLowerCase()];
1403 };
1404
1405 Utilityview.prototype.addPartImage = function () {
1406 this.clearPartImage();
1407
1408 // We can't close this tab, so don't have the close image
1409 if (this.name === 'server') {
1410 return;
1411 }
1412
1413 var del_html = '<img src="/img/redcross.png" class="tab_part" />';
1414 this.tab.append(del_html);
1415
1416 $('.tab_part', this.tab).click(function () {
1417 if (kiwi.front.cur_channel.name !== 'server') {
1418 kiwi.front.cur_channel.close();
1419 }
1420 });
1421 };
1422
1423 Utilityview.prototype.clearPartImage = function () {
1424 $('#kiwi .toolbars .tab_part').remove();
1425 };
1426
1427
1428
1429
1430
1431 /*
1432 *
1433 * TABVIEWS
1434 *
1435 */
1436
1437
1438 var Tabview = function () {};
1439 Tabview.prototype.name = null;
1440 Tabview.prototype.div = null;
1441 Tabview.prototype.userlist = null;
1442 Tabview.prototype.userlist_width = 100; // 0 for disabled
1443 Tabview.prototype.tab = null;
1444 Tabview.prototype.topic = "";
1445 Tabview.prototype.safe_to_close = false; // If we have been kicked/banned/etc from this channel, don't wait for a part message
1446
1447 Tabview.prototype.show = function () {
1448 var w, u;
1449
1450 $('#kiwi .messages').removeClass("active");
1451 $('#kiwi .userlist ul').removeClass("active");
1452 $('#kiwi .toolbars ul li').removeClass("active");
1453
1454 w = $('#windows');
1455 u = $('#kiwi .userlist');
1456
1457 w.css('overflow-y', 'scroll');
1458
1459 // Set the window size accordingly
1460 this.setUserlistWidth();
1461
1462 // Activate this tab!
1463 this.div.addClass('active');
1464 if (this.userlist_width > 0) {
1465 this.userlist.addClass('active');
1466 // Enable the userlist resizer
1467 $('#nicklist_resize').css('display', 'block');
1468 } else {
1469 // Disable the userlist resizer
1470 $('#nicklist_resize').css('display', 'none');
1471 }
1472 this.tab.addClass('active');
1473
1474 // Add the part image to the tab
1475 this.addPartImage();
1476
1477 this.clearHighlight();
1478 kiwi.front.setTopicText(this.topic);
1479 kiwi.front.cur_channel = this;
1480
1481 // If we're using fancy scrolling, refresh it
1482 if (touch_scroll) {
1483 touch_scroll.refresh();
1484 }
1485
1486 this.scrollBottom();
1487 if (!touchscreen) {
1488 $('#kiwi_msginput').focus();
1489 }
1490 };
1491
1492 Tabview.prototype.close = function () {
1493 this.div.remove();
1494 this.userlist.remove();
1495 this.tab.remove();
1496
1497 if (kiwi.front.cur_channel === this) {
1498 kiwi.front.tabviews.server.show();
1499 }
1500 delete kiwi.front.tabviews[this.name.toLowerCase()];
1501 };
1502
1503 Tabview.prototype.setUserlistWidth = function (new_width) {
1504 var w, u;
1505 if (typeof new_width === 'number') {
1506 this.userlist_width = new_width;
1507 }
1508
1509 w = $('#windows');
1510 u = $('#kiwi .userlist');
1511
1512 // Set the window size accordingly
1513 if (this.userlist_width > 0) {
1514 u.width(this.userlist_width);
1515 w.css('right', u.outerWidth(true));
1516 } else {
1517 w.css('right', 0);
1518 }
1519 };
1520
1521 Tabview.prototype.addPartImage = function () {
1522 this.clearPartImage();
1523
1524 // We can't close this tab, so don't have the close image
1525 if (this.name === 'server') {
1526 return;
1527 }
1528
1529 var del_html = '<img src="/img/redcross.png" class="tab_part" />';
1530 this.tab.append(del_html);
1531
1532 $('.tab_part', this.tab).click(function () {
1533 if (kiwi.front.isChannel($(this).parent().text())) {
1534 kiwi.front.run("/part");
1535 } else {
1536 // Make sure we don't close the server tab
1537 if (kiwi.front.cur_channel.name !== 'server') {
1538 kiwi.front.cur_channel.close();
1539 }
1540 }
1541 });
1542 };
1543
1544 Tabview.prototype.clearPartImage = function () {
1545 $('#kiwi .toolbars .tab_part').remove();
1546 };
1547
1548 Tabview.prototype.addMsg = function (time, nick, msg, type, style) {
1549 var self, tmp, plugin_ret, i, d, re, line_msg, next;
1550
1551 self = this;
1552
1553 tmp = {msg: msg, time: time, nick: nick, tabview: this.name};
1554 tmp = kiwi.plugs.run('addmsg', tmp);
1555 if (!tmp) {
1556 return;
1557 }
1558
1559
1560 msg = tmp.msg;
1561 time = tmp.time;
1562 nick = tmp.nick;
1563
1564 if (time === null) {
1565 d = new Date();
1566 time = d.getHours().toString().lpad(2, "0") + ":" + d.getMinutes().toString().lpad(2, "0") + ":" + d.getSeconds().toString().lpad(2, "0");
1567 }
1568
1569 // The CSS class (action, topic, notice, etc)
1570 if (typeof type !== "string") {
1571 type = '';
1572 }
1573
1574 // Make sure we don't have NaN or something
1575 if (typeof msg !== "string") {
1576 msg = '';
1577 }
1578
1579 // Make the channels clickable
1580 re = new RegExp('\\B(' + kiwi.gateway.channel_prefix + '[^ ,.\\007]+)', 'g');
1581 msg = msg.replace(re, function (match) {
1582 return '<a class="chan">' + match + '</a>';
1583 });
1584
1585 msg = kiwi.front.format(msg);
1586
1587 // Build up and add the line
1588 line_msg = $('<div class="msg ' + type + '"><div class="time">' + time + '</div><div class="nick">' + nick + '</div><div class="text" style="' + style + '">' + msg + ' </div></div>');
1589 this.div.append(line_msg);
1590
1591 if (!touchscreen) {
1592 this.scrollBottom();
1593 } else {
1594 touch_scroll.refresh();
1595 //console.log(this.div.attr("scrollHeight") +" - "+ $('#windows').height());
1596 this.scrollBottom();
1597 //if(this.div.attr("scrollHeight") > $('#windows').height()){
1598 // touch_scroll.scrollTo(0, this.div.height());
1599 //}
1600 }
1601 };
1602
1603 Tabview.prototype.scrollBottom = function () {
1604 var w = $('#windows');
1605 w[0].scrollTop = w[0].scrollHeight;
1606 };
1607
1608 Tabview.prototype.changeNick = function (newNick, oldNick) {
1609 this.userlist.children().each(function () {
1610 var item = $('a.nick', this);
1611 if (kiwi.front.nickStripPrefix(item.text()) === oldNick) {
1612 item.text(kiwi.front.nickGetPrefix(item.text()) + newNick);
1613 document.temp_chan = 1;
1614 }
1615 });
1616
1617 if (typeof document.temp_chan !== "undefined") {
1618 this.addMsg(null, ' ', '=== ' + oldNick + ' is now known as ' + newNick, 'action changenick');
1619 delete document.temp_chan;
1620 this.userlistSort();
1621 }
1622 };
1623
1624 Tabview.prototype.userlistSort = function () {
1625 var ul = this.userlist,
1626 listitems = ul.children('li').get(),
1627 prefix;
1628 listitems.sort(function (a, b) {
1629 var compA = $(a).text().toUpperCase(),
1630 compB = $(b).text().toUpperCase(),
1631 i;
1632
1633 // Sort by prefixes first
1634 for (i in kiwi.gateway.user_prefixes) {
1635 prefix = kiwi.gateway.user_prefixes[i].symbol;
1636
1637 if (compA.charAt(0) === prefix && compB.charAt(0) === prefix) {
1638 // Both have the same prefix, string compare time
1639 return 0;
1640 }
1641
1642 if (compA.charAt(0) === prefix && compB.charAt(0) !== prefix) {
1643 return -1;
1644 }
1645
1646 if (compA.charAt(0) !== prefix && compB.charAt(0) === prefix) {
1647 return 1;
1648 }
1649 }
1650
1651 // No prefixes, compare by string
1652 return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
1653 });
1654 $.each(listitems, function (idx, itm) { ul.append(itm); });
1655 };
1656
1657 Tabview.prototype.highlight = function () {
1658 this.tab.addClass('highlight');
1659 };
1660 Tabview.prototype.activity = function () {
1661 this.tab.addClass('activity');
1662 };
1663 Tabview.prototype.clearHighlight = function () {
1664 this.tab.removeClass('highlight');
1665 this.tab.removeClass('activity');
1666 };
1667 Tabview.prototype.changeTopic = function (new_topic) {
1668 this.topic = new_topic;
1669 this.addMsg(null, ' ', '=== Topic for ' + this.name + ' is: ' + new_topic, 'topic');
1670 if (kiwi.front.cur_channel.name === this.name) {
1671 kiwi.front.setTopicText(new_topic);
1672 }
1673 };
1674
1675
1676
1677
1678
1679 var Box = function (classname) {
1680 this.id = randomString(10);
1681 var tmp = $('<div id="' + this.id + '" class="box ' + classname + '"><div class="boxarea"></div></div>');
1682 $('#kiwi').append(tmp);
1683 this.box = $('#' + this.id);
1684 this.content = $('#' + this.id + ' .boxarea');
1685
1686 this.box.draggable({ stack: ".box" });
1687 this.content.click(function () {});
1688 //this.box.click(function(){ $(this)..css });
1689 };
1690 Box.prototype.create = function (name, classname) {
1691
1692 };
1693 Box.prototype.id = null;
1694 Box.prototype.box = null;
1695 Box.prototype.content = null;
1696 Box.prototype.destroy = function () {
1697 var name;
1698 this.box.remove();
1699 for (name in kiwi.front.boxes) {
1700 if (kiwi.front.boxes[name].id === this.id) {
1701 delete kiwi.front.boxes[name];
1702 }
1703 }
1704 };
1705 Box.prototype.height = function () {
1706 return this.box.height();
1707 };