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