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 */
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;
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
);
51 // Build the about box
52 front
.boxes
.about
= new Box("about");
53 about_info
= 'UI adapted for ' + agent
;
55 about_info
+= ' touchscreen ';
57 about_info
+= 'usage';
58 $('#tmpl_about_box').tmpl({
60 front_revision
: front
.revision
,
61 gateway_revision
: gateway
.revision
62 }).appendTo(front
.boxes
.about
.content
);
64 //$(window).bind("beforeunload", function(){ gateway.quit(); });
67 $('#kiwi').addClass('touchscreen');
69 // Single touch scrolling through scrollback for touchscreens
71 touch_scroll
= new iScroll('windows', scroll_opts
);
76 $('#kiwi .toolbars').resize(front
.doLayoutSize
);
78 $('#kiwi .formconnectwindow').submit(function () {
79 var netsel
= $('#kiwi .formconnectwindow .network'),
80 nick
= $('#kiwi .formconnectwindow .nick'),
83 if (nick
.val() === '') {
84 nick
.val('Nick please!');
89 tmp
= nick
.val().split(' ');
90 gateway
.nick
= tmp
[0];
92 init_data
.channel
= $('#channel').val();
96 front
.run('/connect ' + netsel
.val());
101 $('#kiwi .connectwindow').slideUp('', front
.barsShow
);
102 $('#windows').click(function () { $('#kiwi_msginput').focus(); });
107 supportsOrientationChange
= (typeof window
.onorientationchange
!== undefined);
108 orientationEvent
= supportsOrientationChange
? "orientationchange" : "resize";
109 if (window
.addEventListener
) {
110 window
.addEventListener(orientationEvent
, front
.doLayoutSize
, false);
113 window
.attachEvent(orientationEvent
, front
.doLayoutSize
, false);
115 //$('#kiwi').bind("resize", front.doLayoutSize, false);
120 front
.tabviewAdd('server');
121 front
.tabviews
.server
.userlist_width
= 0; // Disable the userlist
123 // Any pre-defined nick?
124 if (typeof window
.init_data
.nick
=== "string") {
125 $('#kiwi .formconnectwindow .nick').val(init_data
.nick
);
128 // Any pre-defined channels?
129 if (typeof window
.init_data
.channel
=== 'string') {
130 $('#channel').val(init_data
.channel
);
133 // Fix for Opera inserting a spurious <br/>
134 $('#kiwi .cur_topic br').remove();
136 $('#kiwi .cur_topic').keydown(function (e
) {
137 if (e
.which
=== 13) {
141 $('#kiwi_msginput').focus();
142 } else if (e
.which
=== 27) {
145 $(this).text(front
.original_topic
);
146 $('#kiwi_msginput').focus();
149 /*$('.cur_topic').live('keypress', function(e) {
150 if (e.keyCode === 13) {
154 $('#kiwi_msginput').focus();
155 } else if (e.keyCode === 27) {
158 $(this).text(front.original_topic);
161 $('.cur_topic').live('change', function () {
163 text
= $(this).text();
164 if (text
!== front
.original_topic
) {
165 chan
= front
.cur_channel
.name
;
166 gateway
.setTopic(chan
, text
);
171 $('#windows a.chan').live('click', function () {
172 front
.joinChannel($(this).text());
179 plugs
.loadPlugin(plugins
[i
]);
184 doLayoutSize: function () {
185 var kiwi
, toolbars
, ul
, n_top
, n_bottom
;
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');
197 toolbars
= $('#kiwi .cur_topic');
198 ul
= $('#kiwi .userlist');
200 n_top
= parseInt(toolbars
.offset().top
, 10) + parseInt(toolbars
.outerHeight(true), 10);
201 n_bottom
= $(document
).height() - parseInt($('#kiwi .control').offset().top
, 10);
203 $('#kiwi .windows').css({top
: n_top
+ 'px', bottom
: n_bottom
+ 'px'});
204 $('#kiwi .userlist').css({top
: n_top
+ 'px', bottom
: n_bottom
+ 'px'});
208 doLayout: function () {
209 $('#kiwi .msginput .nick a').text(gateway
.nick
);
210 $('#kiwi_msginput').val(' ');
211 $('#kiwi_msginput').focus();
215 joinChannel: function (chan_name
) {
216 var chans
= chan_name
.split(','),
221 if (front
.tabviews
[chan
.toLowerCase()] === undefined || (front
.tabviews
[chan
.toLowerCase()] !== undefined && front
.tabviews
[chan
.toLowerCase()].safe_to_close
=== true)) {
223 front
.tabviewAdd(chan
);
225 front
.tabviews
[chan
.toLowerCase()].show();
231 run: function (msg
) {
232 var parts
, dest
, t
, pos
, textRange
, d
, plugin_event
, msg_sliced
;
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') {
241 // Update msg if it's been changed by any plugins
242 msg
= plugin_event
.command
.toString();
244 console
.log("running " + msg
);
245 if (msg
.substring(0, 1) === '/') {
246 parts
= msg
.split(' ');
247 switch (parts
[0].toLowerCase()) {
250 front
.joinChannel(parts
[1]);
255 if (parts
[1] === undefined) {
256 alert('Usage: /connect servername [port]');
260 if (parts
[2] === undefined) {
263 front
.cur_channel
.addMsg(null, ' ', '=== Connecting to ' + parts
[1] + '...', 'status');
264 gateway
.connect(parts
[1], parts
[2], 0);
268 console
.log("/nick");
269 if (parts
[1] === undefined) {
270 console
.log("calling show nick");
271 front
.showChangeNick();
273 console
.log("sending raw");
274 gateway
.raw(msg
.substring(1));
279 if (typeof parts
[1] === "undefined") {
280 if (front
.cur_channel
.safe_to_close
) {
281 front
.cur_channel
.close();
283 gateway
.raw(msg
.substring(1) + ' ' + front
.cur_channel
.name
);
286 gateway
.raw(msg
.substring(1));
291 if (typeof parts
[1] !== "undefined") {
292 gateway
.raw(msg
.substring(1));
302 if (typeof parts
[1] !== "undefined") {
303 front
.tabviewAdd(parts
[1]);
310 if (typeof parts
[1] !== "undefined") {
311 msg_sliced
= msg
.split(' ').slice(2).join(' ');
312 gateway
.msg(parts
[1], msg_sliced
);
314 if (!front
.tabviewExists(parts
[1])) {
315 front
.tabviewAdd(parts
[1]);
317 front
.tabviews
[parts
[1].toLowerCase()].addMsg(null, gateway
.nick
, msg_sliced
);
323 if (typeof parts
[1] === 'undefined') return;
324 gateway
.raw('KICK ' + front
.cur_channel
.name
+ ' ' + msg
.split(' ', 2)[1]);
328 gateway
.raw(msg
.replace(/^\/quote /i, ''));
332 gateway
.action(front
.cur_channel
.name
, msg
.substring(4));
333 //front.tabviews[destination.toLowerCase()].addMsg(null, ' ', '* '+data.nick+' '+data.msg, 'color:green;');
334 front
.cur_channel
.addMsg(null, ' ', '* ' + gateway
.nick
+ ' ' + msg
.substring(4), 'action', 'color:#555;');
339 msg
= parts
.slice(2).join(' ');
341 gateway
.notice(dest
, msg
);
342 this.onNotice({}, {nick
: gateway
.nick
, channel
: dest
, msg
: msg
});
346 if (parts
[1] !== undefined) {
347 front
.windowsShow(parseInt(parts
[1], 10));
352 gateway
.quit(msg
.split(" ", 2)[1]);
356 if (parts
[1] === undefined) {
358 if (t
.createTextRange
) {
359 pos
= t
.text().length();
360 textRange
= t
.createTextRange();
361 textRange
.collapse(true);
362 textRange
.moveEnd(pos
);
363 textRange
.moveStart(pos
);
365 } else if (t
.setSelectionRange
) {
366 t
.setSelectionRange(pos
, pos
);
369 gateway
.setTopic(front
.cur_channel
.name
, msg
.split(' ', 2)[1]);
370 //gateway.raw('TOPIC ' + front.cur_channel.name + ' :' + msg.split(' ', 2)[1]);
375 gateway
.kiwi(front
.cur_channel
.name
, msg
.substring(6));
379 //front.cur_channel.addMsg(null, ' ', '--> Invalid command: '+parts[0].substring(1));
380 gateway
.raw(msg
.substring(1));
384 //alert('Sending message: '+msg);
385 if (msg
.trim() === '') {
388 if (front
.cur_channel
.name
!== 'server') {
389 gateway
.msg(front
.cur_channel
.name
, msg
);
391 d
= d
.getHours() + ":" + d
.getMinutes();
392 //front.addMsg(d, gateway.nick, msg);
393 front
.cur_channel
.addMsg(null, gateway
.nick
, msg
);
399 onMsg: function (e
, data
) {
400 var destination
, plugin_event
;
401 // Is this message from a user?
402 if (data
.channel
=== gateway
.nick
) {
403 destination
= data
.nick
.toLowerCase();
405 destination
= data
.channel
.toLowerCase();
408 plugin_event
= {nick
: data
.nick
, msg
: data
.msg
, destination
: destination
};
409 plugin_event
= plugs
.run('msg_recieved', plugin_event
);
414 if (!front
.tabviewExists(plugin_event
.destination
)) {
415 front
.tabviewAdd(plugin_event
.destination
);
417 front
.tabviews
[plugin_event
.destination
].addMsg(null, plugin_event
.nick
, plugin_event
.msg
);
420 onDebug: function (e
, data
) {
421 if (!front
.tabviewExists('kiwi_debug')) {
422 front
.tabviewAdd('kiwi_debug');
424 front
.tabviews
.kiwi_debug
.addMsg(null, ' ', data
.msg
);
427 onAction: function (e
, data
) {
429 // Is this message from a user?
430 if (data
.channel
=== gateway
.nick
) {
431 destination
= data
.nick
;
433 destination
= data
.channel
;
436 if (!front
.tabviewExists(destination
)) {
437 front
.tabviewAdd(destination
);
439 front
.tabviews
[destination
.toLowerCase()].addMsg(null, ' ', '* ' + data
.nick
+ ' ' + data
.msg
, 'action', 'color:#555;');
442 onTopic: function (e
, data
) {
443 if (front
.tabviewExists(data
.channel
)) {
444 front
.tabviews
[data
.channel
.toLowerCase()].changeTopic(data
.topic
);
448 onNotice: function (e
, data
) {
449 var nick
= (data
.nick
=== undefined) ? '' : data
.nick
,
450 enick
= '[' + nick
+ ']';
452 if (front
.tabviewExists(data
.target
)) {
453 front
.tabviews
[data
.target
.toLowerCase()].addMsg(null, enick
, data
.msg
, 'notice');
454 } else if (front
.tabviewExists(nick
)) {
455 front
.tabviews
[nick
.toLowerCase()].addMsg(null, enick
, data
.msg
, 'notice');
457 front
.tabviews
.server
.addMsg(null, enick
, data
.msg
, 'notice');
461 onCTCPRequest: function (e
, data
) {
462 var msg
= data
.msg
.split(" ", 2);
465 if (typeof msg
[1] === 'undefined') {
468 gateway
.notice(data
.nick
, String
.fromCharCode(1) + 'PING ' + msg
[1] + String
.fromCharCode(1));
471 gateway
.notice(data
.nick
, String
.fromCharCode(1) + 'TIME ' + (new Date()).toLocaleString() + String
.fromCharCode(1));
474 front
.tabviews
.server
.addMsg(null, 'CTCP [' + data
.nick
+ ']', data
.msg
, 'ctcp');
477 onCTCPResponse: function (e
, data
) {
480 onKiwi: function (e
, data
) {
484 onConnect: function (e
, data
) {
485 if (data
.connected
) {
486 if (gateway
.nick
!== data
.nick
) {
487 gateway
.nick
= data
.nick
;
491 front
.tabviews
.server
.addMsg(null, ' ', '=== Connected OK :)', 'status');
492 if (typeof init_data
.channel
=== "string") {
493 front
.joinChannel(init_data
.channel
);
495 plugs
.run('connect', {success
: true});
497 front
.tabviews
.server
.addMsg(null, ' ', '=== Failed to connect :(', 'status');
498 plugs
.run('connect', {success
: false});
501 onConnectFail: function (e
, data
) {
502 var reason
= (typeof data
.reason
=== 'string') ? data
.reason
: '';
503 front
.tabviews
.server
.addMsg(null, '', 'There\'s a problem connecting! (' + reason
+ ')', 'error');
504 plugs
.run('connect', {success
: false});
506 onDisconnect: function (e
, data
) {
508 for (tab
in front
.tabviews
) {
509 front
.tabviews
[tab
].addMsg(null, '', 'Disconnected from server!', 'error');
511 plugs
.run('disconnect', {success
: false});
513 onOptions: function (e
, data
) {
514 if (typeof gateway
.network_name
=== "string" && gateway
.network_name
!== "") {
515 front
.tabviews
.server
.tab
.text(gateway
.network_name
);
518 onMOTD: function (e
, data
) {
519 front
.tabviews
.server
.addMsg(null, data
.server
, data
.msg
, 'motd');
521 onWhois: function (e
, data
) {
524 front
.cur_channel
.addMsg(null, data
.nick
, data
.msg
, 'whois');
525 } else if (data
.logon
) {
527 d
.setTime(data
.logon
* 1000);
528 d
= d
.toLocaleString();
529 front
.cur_channel
.addMsg(null, data
.nick
, 'idle for ' + data
.idle
+ ' second' + ((data
.idle
!== 1) ? 's' : '') + ', signed on ' + d
, 'whois');
531 front
.cur_channel
.addMsg(null, data
.nick
, 'idle for ' + data
.idle
+ ' seconds', 'whois');
534 onMode: function (e
, data
) {
535 var i
, new_nick_text
;
537 // TODO: Store the modes in the elements data, then work out the current
538 // mode symbol from the highest mode. Eg. -h may leave +o from previous modes; It
539 // doesn't simply clear it! ~Darren
540 if (typeof data
.channel
=== 'string' && typeof data
.effected_nick
=== 'string') {
541 front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '[' + data
.mode
+ '] ' + data
.effected_nick
+ ' by ' + data
.nick
, 'mode', '');
542 front
.tabviews
[data
.channel
.toLowerCase()].userlist
.children().each(function () {
543 if (front
.nickStripPrefix($(this).text()) === data
.effected_nick
) {
545 if (data
.mode
.split('')[0] === '+') {
546 for (i
in gateway
.user_prefixes
) {
547 if (gateway
.user_prefixes
[i
].mode
== data
.mode
.split('')[1]) {
548 new_nick_text
= gateway
.user_prefixes
[i
].symbol
+ data
.effected_nick
;
552 } else if (data
.mode
.split('')[0] === '-') {
553 new_nick_text
= data
.effected_nick
;
556 if (new_nick_text
!== '') {
557 $(this).text(new_nick_text
);
565 onUserList: function (e
, data
) {
567 if (front
.tabviews
[data
.channel
.toLowerCase()] === undefined) {
570 ul
= front
.tabviews
[data
.channel
.toLowerCase()].userlist
;
572 if (!document
.userlist_updating
) {
573 document
.userlist_updating
= true;
577 $.each(data
.users
, function (i
, item
) {
578 nick
= i
; //i.match(/^.+!/g);
580 $('<li><a class="nick" onclick="front.userClick(this);">' + mode
+ nick
+ '</a></li>').appendTo(ul
);
583 front
.tabviews
[data
.channel
.toLowerCase()].userlistSort();
585 onUserListEnd: function (e
, data
) {
586 document
.userlist_updating
= false;
589 onJoin: function (e
, data
) {
590 if (!front
.tabviewExists(data
.channel
)) {
591 front
.tabviewAdd(data
.channel
.toLowerCase());
594 if (data
.nick
=== gateway
.nick
) {
595 return; // Not needed as it's already in nicklist
597 front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '--> ' + data
.nick
+ ' has joined', 'action', 'color:#009900;');
598 $('<li><a class="nick" onclick="front.userClick(this);">' + data
.nick
+ '</a></li>').appendTo(front
.tabviews
[data
.channel
.toLowerCase()].userlist
);
599 front
.tabviews
[data
.channel
.toLowerCase()].userlistSort();
601 onPart: function (e
, data
) {
602 if (front
.tabviewExists(data
.channel
)) {
603 // If this is us, close the tabview
604 if (data
.nick
=== gateway
.nick
) {
605 front
.tabviews
[data
.channel
.toLowerCase()].close();
606 front
.tabviews
.server
.show();
610 front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '<-- ' + data
.nick
+ ' has left (' + data
.message
+ ')', 'action', 'color:#990000;');
611 front
.tabviews
[data
.channel
.toLowerCase()].userlist
.children().each(function () {
612 if ($(this).text() === data
.nick
) {
618 onKick: function (e
, data
) {
619 if (front
.tabviewExists(data
.channel
)) {
620 // If this is us, close the tabview
621 if (data
.kicked
=== gateway
.nick
) {
622 //front.tabviews[data.channel.toLowerCase()].close();
623 front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '=== You have been kicked from ' + data
.channel
+ '. ' + data
.message
, 'status');
624 front
.tabviews
[data
.channel
.toLowerCase()].safe_to_close
= true;
625 $('li', front
.tabviews
[data
.channel
.toLowerCase()].userlist
).remove();
629 front
.tabviews
[data
.channel
.toLowerCase()].addMsg(null, ' ', '<-- ' + data
.kicked
+ ' kicked by ' + data
.nick
+ '(' + data
.message
+ ')', 'action', 'color:#990000;');
630 front
.tabviews
[data
.channel
.toLowerCase()].userlist
.children().each(function () {
631 if ($(this).text() === data
.nick
) {
637 onNick: function (e
, data
) {
638 if (data
.nick
=== gateway
.nick
) {
639 gateway
.nick
= data
.newnick
;
643 $.each(front
.tabviews
, function (i
, item
) {
644 $.each(front
.tabviews
, function (i
, item
) {
645 item
.changeNick(data
.newnick
, data
.nick
);
649 onQuit: function (e
, data
) {
650 $.each(front
.tabviews
, function (i
, item
) {
651 $.each(front
.tabviews
, function (i
, item
) {
652 item
.userlist
.children().each(function () {
653 if ($(this).text() === data
.nick
) {
655 item
.addMsg(null, ' ', '<-- ' + data
.nick
+ ' has quit (' + data
.message
+ ')', 'action', 'color:#990000;');
661 onChannelRedirect: function (e
, data
) {
662 front
.tabviews
[data
.from.toLowerCase()].close();
663 front
.tabviewAdd(data
.to
.toLowerCase());
664 front
.tabviews
[data
.to
.toLowerCase()].addMsg(null, ' ', '=== Redirected from ' + data
.from, 'action');
667 onIRCError: function (e
, data
) {
669 if (data
.channel
!== undefined && front
.tabviewExists(data
.channel
)) {
670 t_view
= data
.channel
;
675 switch (data
.error
) {
676 case 'banned_from_channel':
677 front
.tabviews
[t_view
].addMsg(null, ' ', '=== You are banned from ' + data
.channel
+ '. ' + data
.reason
, 'status');
678 if (t_view
!== 'server') {
679 front
.tabviews
[t_view
].safe_to_close
= true;
682 case 'bad_channel_key':
683 front
.tabviews
[t_view
].addMsg(null, ' ', '=== Bad channel key for ' + data
.channel
, 'status');
684 if (t_view
!== 'server') {
685 front
.tabviews
[t_view
].safe_to_close
= true;
688 case 'invite_only_channel':
689 front
.tabviews
[t_view
].addMsg(null, ' ', '=== ' + data
.channel
+ ' is invite only.', 'status');
690 if (t_view
!== 'server') {
691 front
.tabviews
[t_view
].safe_to_close
= true;
694 case 'channel_is_full':
695 front
.tabviews
[t_view
].addMsg(null, ' ', '=== ' + data
.channel
+ ' is full.', 'status');
696 if (t_view
!== 'server') {
697 front
.tabviews
[t_view
].safe_to_close
= true;
700 case 'chanop_privs_needed':
701 front
.tabviews
[data
.channel
].addMsg(null, ' ', '=== ' + data
.reason
, 'status');
704 front
.tabviews
.server
.addMsg(null, ' ', '=== ' + data
.nick
+ ': ' + data
.reason
, 'status');
706 case 'nickname_in_use':
707 front
.tabviews
.server
.addMsg(null, ' ', '=== The nickname ' + data
.nick
+ ' is already in use. Please select a new nickname', 'status');
708 front
.showChangeNick();
711 // We don't know what data contains, so don't do anything with it.
712 //front.tabviews.server.addMsg(null, ' ', '=== ' + data, 'status');
716 registerKeys: function () {
717 $('#kiwi_msginput').bind('keydown', function (e
) {
718 var windows
, meta
, num
, msg
, data
, candidates
, word_pos
, word
, i
;
719 windows
= $('#windows');
720 //var meta = e.altKey;
724 case (e
.which
>= 48) && (e
.which
<= 57):
731 front
.windowsShow(num
);
735 case e
.which
=== 27: // escape
737 case e
.which
=== 13: // return
738 msg
= $('#kiwi_msginput').val();
741 front
.buffer
.push(msg
);
742 front
.buffer_pos
= front
.buffer
.length
;
745 $('#kiwi_msginput').val('');
748 case e
.which
=== 33: // page up
749 console
.log("page up");
750 windows
[0].scrollTop
= windows
[0].scrollTop
- windows
.height();
752 case e
.which
=== 34: // page down
753 windows
[0].scrollTop
= windows
[0].scrollTop
+ windows
.height();
755 case e
.which
=== 37: // left
757 front
.windowsPrevious();
761 case e
.which
=== 38: // up
762 if (front
.buffer_pos
> 0) {
764 $('#kiwi_msginput').val(front
.buffer
[front
.buffer_pos
]);
767 case e
.which
=== 39: // right
773 case e
.which
=== 40: // down
774 if (front
.buffer_pos
< front
.buffer
.length
) {
776 $('#kiwi_msginput').val(front
.buffer
[front
.buffer_pos
]);
780 case e
.which
=== 9: // tab
781 // Get possible autocompletions
783 front
.cur_channel
.userlist
.children().each(function () {
785 nick
= front
.nickStripPrefix($('a.nick', this).text());
789 // Do the autocomplete
790 if (this.value
.length
=== this.selectionStart
&& this.value
.length
=== this.selectionEnd
) {
793 word_pos
= this.value
.lastIndexOf(' ');
795 if (word_pos
=== -1) {
798 word
= this.value
.substr(word_pos
);
802 // filter data to find only strings that start with existing value
803 for (i
= 0; i
< data
.length
; i
++) {
804 if (data
[i
].indexOf(word
) === 0 && data
[i
].length
> word
.length
) {
805 candidates
.push(data
[i
]);
809 if (candidates
.length
> 0) {
810 // some candidates for autocompletion are found
811 this.value
= this.value
.substring(0, word_pos
) + ' ' + candidates
[0] + ': ';
812 this.selectionStart
= this.value
.length
;
820 $('#kiwi .control .msginput .nick').click(function () {
821 front
.showChangeNick();
828 $('#kiwi .plugins .load_plugin_file').click(function () {
829 if (typeof front
.boxes
.plugins
!== "undefined") {
833 front
.boxes
.plugins
= new Box("plugin_file");
834 $('#tmpl_plugins').tmpl({}).appendTo(front
.boxes
.plugins
.content
);
835 front
.boxes
.plugins
.box
.css('top', -(front
.boxes
.plugins
.height
+ 40));
837 // Populate the plugin list..
838 function enumPlugins() {
840 lst
= $('#plugin_list');
841 lst
.find('option').remove();
842 for (j
in plugs
.loaded
) {
843 txt
= plugs
.loaded
[j
].name
;
844 lst
.append('<option value="' + txt
+ '">' + txt
+ '</option>');
850 $('#kiwi .plugin_file').submit(function () {
851 $('<div></div>').load($('.txtpluginfile').val(), function (e
) {
856 $('#kiwi .cancelpluginfile').click(function () {
857 front
.boxes
.plugins
.destroy();
860 $('#kiwi #plugins_list_unload').click(function () {
862 selected_plugin
= $('#plugin_list').val();
863 plugs
.unloadPlugin(selected_plugin
);
867 $('#kiwi .txtpluginfile').focus();
871 $('#kiwi .plugins .reload_css').click(function () {
872 var links
= document
.getElementsByTagName("link"),
874 for (i
= 0; i
< links
.length
; i
++) {
875 if (links
[i
].rel
=== "stylesheet") {
876 if (links
[i
].href
.indexOf("?") === -1) {
877 links
[i
].href
+= "?";
879 links
[i
].href
+= "x";
885 $('#kiwi .about .about_close').click(function () {
886 $('#kiwi .about').css('display', 'none');
890 $('#kiwi .poweredby').click(function () {
891 $('#kiwi .about').css('display', 'block');
897 showChangeNick: function () {
898 $('#kiwi').append($('#tmpl_change_nick').tmpl({}));
900 $('#kiwi .form_newnick').submit(function () {
901 front
.run('/NICK ' + $('#kiwi .txtnewnick').val());
902 $('#kiwi .newnick').remove();
906 $('#kiwi .txtnewnick').keypress(function (ev
) {
907 if (!this.first_press
) {
908 this.first_press
= true;
913 $('#kiwi .txtnewnick').keydown(function (ev
) {
914 if (ev
.which
=== 27) { // ESC
915 $('#kiwi_msginput').focus();
916 $('#kiwi .newnick').remove();
920 $('#kiwi .cancelnewnick').click(function () {
921 $('#kiwi .newnick').remove();
924 $('#kiwi .txtnewnick').focus();
928 tabviewExists: function (name
) {
929 return (typeof front
.tabviews
[name
.toLowerCase()] !== 'undefined');
932 tabviewAdd: function (v_name
) {
934 var re
, htmlsafe_name
, tmp_divname
, tmp_userlistname
, tmp_tabname
, userlist_enabled
= true;
936 if (v_name
.charAt(0) === gateway
.channel_prefix
) {
937 re
= new RegExp(gateway
.channel_prefix
, "g");
938 htmlsafe_name
= v_name
.replace(re
, 'pre');
939 htmlsafe_name
= "chan_" + htmlsafe_name
;
941 htmlsafe_name
= 'query_' + v_name
;
942 userlist_enabled
= false;
945 tmp_divname
= 'kiwi_window_' + htmlsafe_name
;
946 tmp_userlistname
= 'kiwi_userlist_' + htmlsafe_name
;
947 tmp_tabname
= 'kiwi_tab_' + htmlsafe_name
;
949 if (!front
.tabviewExists(v_name
)) {
950 $('#kiwi .windows .scroller').append('<div id="' + tmp_divname
+ '" class="messages"></div>');
951 $('#kiwi .userlist').append('<ul id="' + tmp_userlistname
+ '"></ul>');
952 $('#kiwi .windowlist ul').append('<li id="' + tmp_tabname
+ '" onclick="front.tabviews[\'' + v_name
.toLowerCase() + '\'].show();">' + v_name
+ '</li>');
954 //$('#kiwi .windowlist ul .window_'+v_name).click(function(){ front.windowShow(v_name); });
955 //front.windowShow(v_name);
957 front
.tabviews
[v_name
.toLowerCase()] = new Tabview();
958 front
.tabviews
[v_name
.toLowerCase()].name
= v_name
;
959 front
.tabviews
[v_name
.toLowerCase()].div
= $('#' + tmp_divname
);
960 front
.tabviews
[v_name
.toLowerCase()].userlist
= $('#' + tmp_userlistname
);
961 front
.tabviews
[v_name
.toLowerCase()].tab
= $('#' + tmp_tabname
);
962 if (!userlist_enabled
) {
963 front
.tabviews
[v_name
.toLowerCase()].userlist_width
= 0;
965 front
.tabviews
[v_name
.toLowerCase()].show();
967 if (typeof registerTouches
=== "function") {
968 //alert("Registering touch interface");
969 //registerTouches($('#'+tmp_divname));
970 registerTouches(document
.getElementById(tmp_divname
));
973 front.tabviews[v_name.toLowerCase()].userlist.click(function(){
974 alert($(this).attr('id'));
978 front
.doLayoutSize();
982 userClick: function (item
) {
983 var li
= $(item
).parent();
985 // Remove any existing userboxes
986 $('#kiwi .userbox').remove();
988 if ($(li
).data('userbox') === item
) {
989 $(li
).removeData('userbox');
991 $('#tmpl_user_box').tmpl({nick
: front
.nickStripPrefix($(item
).text())}).appendTo(li
);
993 $('#kiwi .userbox .userbox_query').click(function (ev
) {
994 var nick
= $('#kiwi .userbox_nick').val();
995 front
.run('/query ' + nick
);
998 $('#kiwi .userbox .userbox_whois').click(function (ev
) {
999 var nick
= $('#kiwi .userbox_nick').val();
1000 front
.run('/whois ' + nick
);
1002 $(li
).data('userbox', item
);
1011 onSync: function (e
, data
) {
1013 if (data
.nick
!== undefined) {
1014 gateway
.nick
= data
.nick
;
1018 if (data
.tabviews
!== undefined) {
1019 $.each(data
.tabviews
, function (i
, tab
) {
1020 if (!front
.tabviewExists(tab
.name
)) {
1021 front
.tabviewAdd(gateway
.channel_prefix
+ tab
.name
);
1023 if (tab
.userlist
!== undefined) {
1024 front
.onUserList({'channel': gateway
.channel_prefix
+ tab
.name
, 'users': tab
.userlist
});
1034 setTopicText: function (new_topic
) {
1035 front
.original_topic
= new_topic
;
1036 $('#kiwi .cur_topic .topic').text(new_topic
);
1037 front
.doLayoutSize();
1046 nickStripPrefix: function (nick
) {
1047 var tmp
= nick
, i
, prefix
;
1049 prefix
= tmp
.charAt(0);
1050 for (i
in gateway
.user_prefixes
) {
1051 if (gateway
.user_prefixes
[i
].symbol
=== prefix
) {
1052 return tmp
.substring(1);
1059 nickGetPrefix: function (nick
) {
1060 var tmp
= nick
, i
, prefix
;
1062 prefix
= tmp
.charAt(0);
1063 for (i
in gateway
.user_prefixes
) {
1064 if (gateway
.user_prefixes
[i
].symbol
=== prefix
) {
1072 isChannel: function (name
) {
1073 var prefix
, is_chan
;
1074 prefix
= name
.charAt(0);
1075 if (gateway
.channel_prefix
.indexOf(prefix
) > -1) {
1084 tabviewsNext: function () {
1085 var wl
= $('#kiwi .windowlist ul'),
1086 next_left
= parseInt(wl
.css('text-indent').replace('px', ''), 10) + 170;
1087 wl
.css('text-indent', next_left
);
1090 tabviewsPrevious: function () {
1091 var wl
= $('#kiwi .windowlist ul'),
1092 next_left
= parseInt(wl
.css('text-indent').replace('px', ''), 10) - 170;
1093 wl
.css('text-indent', next_left
);
1096 windowsNext: function () {
1099 for (tab
in front
.tabviews
) {
1101 if (front
.tabviews
[tab
] === front
.cur_channel
) {
1106 front
.tabviews
[tab
].show();
1112 windowsPrevious: function () {
1113 var tab
, prev_tab
, next
;
1115 for (tab
in front
.tabviews
) {
1116 if (front
.tabviews
[tab
] === front
.cur_channel
) {
1122 prev_tab
= front
.tabviews
[tab
];
1126 windowsShow: function (num
) {
1127 num
= parseInt(num
, 10);
1128 console
.log('Showing window ' + num
.toString());
1130 for (tab
in front
.tabviews
) {
1132 front
.tabviews
[tab
].show();
1141 barsShow: function () {
1142 $('#kiwi .toolbars').slideDown();
1143 $('#kiwi .control').slideDown();
1146 barsHide: function () {
1147 $('#kiwi .toolbars').slideUp();
1148 $('#kiwi .control').slideUp();
1171 var Utilityview = function (name
) {
1172 var rand_name
= randomString(15),
1173 tmp_divname
= 'kiwi_window_' + rand_name
,
1174 tmp_userlistname
= 'kiwi_userlist_' + rand_name
,
1175 tmp_tabname
= 'kiwi_tab_' + rand_name
;
1177 this.name
= rand_name
;
1181 $('#kiwi .windows .scroller').append('<div id="' + tmp_divname
+ '" class="messages"></div>');
1183 this.tab
= $('<li id="' + tmp_tabname
+ '">' + this.title
+ '</li>');
1184 this.tab
.click(function () {
1185 front
.utilityviews
[rand_name
.toLowerCase()].show();
1187 $('#kiwi .utilityviewlist ul').append(this.tab
);
1189 this.div
= $('#' + tmp_divname
);
1190 this.div
.css('overflow', 'hidden');
1192 front
.utilityviews
[rand_name
.toLowerCase()] = this;
1195 Utilityview
.prototype.name
= null;
1196 Utilityview
.prototype.title
= null;
1197 Utilityview
.prototype.div
= null;
1198 Utilityview
.prototype.tab
= null;
1199 Utilityview
.prototype.topic
= ' ';
1200 Utilityview
.prototype.show = function () {
1201 $('#kiwi .messages').removeClass("active");
1202 $('#kiwi .userlist ul').removeClass("active");
1203 $('#kiwi .toolbars ul li').removeClass("active");
1205 $('#windows').css('overflow-y', 'hidden');
1206 $('#windows').css('right', 0);
1207 // Activate this tab!
1208 this.div
.addClass('active');
1209 this.tab
.addClass('active');
1211 this.addPartImage();
1213 front
.setTopicText(this.topic
);
1214 front
.cur_channel
= this;
1216 // If we're using fancy scrolling, refresh it
1218 touch_scroll
.refresh();
1222 Utilityview
.prototype.close = function () {
1226 if (front
.cur_channel
=== this) {
1227 front
.tabviews
.server
.show();
1229 delete front
.utilityviews
[this.name
.toLowerCase()];
1232 Utilityview
.prototype.addPartImage = function () {
1233 this.clearPartImage();
1235 // We can't close this tab, so don't have the close image
1236 if (this.name
=== 'server') {
1240 var del_html
= '<img src="/img/redcross.png" class="tab_part" />';
1241 this.tab
.append(del_html
);
1243 $('.tab_part', this.tab
).click(function () {
1244 if (front
.cur_channel
.name
!== 'server') {
1245 front
.cur_channel
.close();
1250 Utilityview
.prototype.clearPartImage = function () {
1251 $('#kiwi .toolbars .tab_part').remove();
1265 var Tabview = function () {};
1266 Tabview
.prototype.name
= null;
1267 Tabview
.prototype.div
= null;
1268 Tabview
.prototype.userlist
= null;
1269 Tabview
.prototype.userlist_width
= 100; // 0 for disabled
1270 Tabview
.prototype.tab
= null;
1271 Tabview
.prototype.topic
= "";
1272 Tabview
.prototype.safe_to_close
= false; // If we have been kicked/banned/etc from this channel, don't wait for a part message
1274 Tabview
.prototype.show = function () {
1277 $('#kiwi .messages').removeClass("active");
1278 $('#kiwi .userlist ul').removeClass("active");
1279 $('#kiwi .toolbars ul li').removeClass("active");
1282 u
= $('#kiwi .userlist');
1284 w
.css('overflow-y', 'scroll');
1286 // Set the window size accordingly
1287 if (this.userlist_width
> 0) {
1288 u
.width(this.userlist_width
);
1289 w
.css('right', u
.outerWidth(true));
1294 // Activate this tab!
1295 this.div
.addClass('active');
1296 if (this.userlist_width
> 0) {
1297 this.userlist
.addClass('active');
1299 this.tab
.addClass('active');
1301 // Add the part image to the tab
1302 this.addPartImage();
1304 this.clearHighlight();
1305 front
.setTopicText(this.topic
);
1306 front
.cur_channel
= this;
1308 // If we're using fancy scrolling, refresh it
1310 touch_scroll
.refresh();
1313 this.scrollBottom();
1315 $('#kiwi_msginput').focus();
1319 Tabview
.prototype.close = function () {
1321 this.userlist
.remove();
1324 if (front
.cur_channel
=== this) {
1325 front
.tabviews
.server
.show();
1327 delete front
.tabviews
[this.name
.toLowerCase()];
1330 Tabview
.prototype.addPartImage = function () {
1331 this.clearPartImage();
1333 // We can't close this tab, so don't have the close image
1334 if (this.name
=== 'server') {
1338 var del_html
= '<img src="/img/redcross.png" class="tab_part" />';
1339 this.tab
.append(del_html
);
1341 $('.tab_part', this.tab
).click(function () {
1342 if (front
.isChannel($(this).parent().text())) {
1345 // Make sure we don't close the server tab
1346 if (front
.cur_channel
.name
!== 'server') {
1347 front
.cur_channel
.close();
1353 Tabview
.prototype.clearPartImage = function () {
1354 $('#kiwi .toolbars .tab_part').remove();
1357 Tabview
.prototype.addMsg = function (time
, nick
, msg
, type
, style
) {
1358 var self
, tmp
, plugin_ret
, i
, d
, re
, line_msg
, next
;
1362 tmp
= {msg
: msg
, time
: time
, nick
: nick
, tabview
: this.name
};
1363 tmp
= plugs
.run('addmsg', tmp
);
1373 if (time
=== null) {
1375 time
= d
.getHours().toString().lpad(2, "0") + ":" + d
.getMinutes().toString().lpad(2, "0") + ":" + d
.getSeconds().toString().lpad(2, "0");
1378 // The CSS class (action, topic, notice, etc)
1379 if (typeof type
!== "string") {
1383 // Make sure we don't have NaN or something
1384 if (typeof msg
!== "string") {
1390 if (msg
.indexOf(String
.fromCharCode(2)) !== -1) {
1392 while (msg
.indexOf(String
.fromCharCode(2)) !== -1) {
1393 msg
= msg
.replace(String
.fromCharCode(2), next
);
1394 next
= (next
=== '<b>') ? '</b>' : '<b>';
1396 if (next
=== '</b>') {
1401 // Wierd thing noticed by Dux0r on the irc.esper.net server
1402 if (typeof msg
!== "string") {
1407 if (msg
.indexOf(String
.fromCharCode(31)) !== -1) {
1409 while (msg
.indexOf(String
.fromCharCode(31)) !== -1) {
1410 msg
= msg
.replace(String
.fromCharCode(31), next
);
1411 next
= (next
=== '<u>') ? '</u>' : '<u>';
1413 if (next
=== '</u>') {
1418 // Make the channels clickable
1419 re
= new RegExp('\\B(' + gateway
.channel_prefix
+ '[^ ,.\\007]+)', 'g');
1420 msg
= msg
.replace(re
, function (match
) {
1421 return '<a class="chan">' + match
+ '</a>';
1424 // Build up and add the line
1425 line_msg
= $('<div class="msg ' + type
+ '"><div class="time">' + time
+ '</div><div class="nick">' + nick
+ '</div><div class="text" style="' + style
+ '">' + msg
+ ' </div></div>');
1426 this.div
.append(line_msg
);
1429 this.scrollBottom();
1431 touch_scroll
.refresh();
1432 //console.log(this.div.attr("scrollHeight") +" - "+ $('#windows').height());
1433 this.scrollBottom();
1434 //if(this.div.attr("scrollHeight") > $('#windows').height()){
1435 // touch_scroll.scrollTo(0, this.div.height());
1440 Tabview
.prototype.scrollBottom = function () {
1441 var w
= $('#windows');
1442 w
[0].scrollTop
= w
[0].scrollHeight
;
1445 Tabview
.prototype.changeNick = function (newNick
, oldNick
) {
1446 this.userlist
.children().each(function () {
1447 var item
= $('a.nick', this);
1448 if (front
.nickStripPrefix(item
.text()) === oldNick
) {
1449 item
.text(front
.nickGetPrefix(item
.text()) + newNick
);
1450 document
.temp_chan
= 1;
1454 if (typeof document
.temp_chan
!== "undefined") {
1455 this.addMsg(null, ' ', '=== ' + oldNick
+ ' is now known as ' + newNick
, 'action');
1456 delete document
.temp_chan
;
1457 this.userlistSort();
1461 Tabview
.prototype.userlistSort = function () {
1462 var ul
= this.userlist
,
1463 listitems
= ul
.children('li').get(),
1465 listitems
.sort(function (a
, b
) {
1466 var compA
= $(a
).text().toUpperCase(),
1467 compB
= $(b
).text().toUpperCase(),
1470 // Sort by prefixes first
1471 for (i
in gateway
.user_prefixes
) {
1472 prefix
= gateway
.user_prefixes
[i
].symbol
;
1474 if (compA
.charAt(0) === prefix
&& compB
.charAt(0) === prefix
) {
1475 // Both have the same prefix, string compare time
1479 if (compA
.charAt(0) === prefix
&& compB
.charAt(0) !== prefix
) {
1483 if (compA
.charAt(0) !== prefix
&& compB
.charAt(0) === prefix
) {
1488 // No prefixes, compare by string
1489 return (compA
< compB
) ? -1 : (compA
> compB
) ? 1 : 0;
1491 $.each(listitems
, function (idx
, itm
) { ul
.append(itm
); });
1494 Tabview
.prototype.highlight = function () {
1495 this.tab
.addClass('highlight');
1497 Tabview
.prototype.activity = function () {
1498 this.tab
.addClass('activity');
1500 Tabview
.prototype.clearHighlight = function () {
1501 this.tab
.removeClass('highlight');
1502 this.tab
.removeClass('activity');
1504 Tabview
.prototype.changeTopic = function (new_topic
) {
1505 this.topic
= new_topic
;
1506 this.addMsg(null, ' ', '=== Topic for ' + this.name
+ ' is: ' + new_topic
, 'topic');
1507 if (front
.cur_channel
.name
=== this.name
) {
1508 front
.setTopicText(new_topic
);
1516 var Box = function (classname
) {
1517 this.id
= randomString(10);
1518 var tmp
= $('<div id="' + this.id
+ '" class="box ' + classname
+ '"><div class="boxarea"></div></div>');
1519 $('#kiwi').append(tmp
);
1520 this.box
= $('#' + this.id
);
1521 this.content
= $('#' + this.id
+ ' .boxarea');
1523 this.box
.draggable({ stack
: ".box" });
1524 this.content
.click(function () {});
1525 //this.box.click(function(){ $(this)..css });
1527 Box
.prototype.create = function (name
, classname
) {
1530 Box
.prototype.id
= null;
1531 Box
.prototype.box
= null;
1532 Box
.prototype.content
= null;
1533 Box
.prototype.destroy = function () {
1536 for (name
in front
.boxes
) {
1537 if (front
.boxes
[name
].id
=== this.id
) {
1538 delete front
.boxes
[name
];
1542 Box
.prototype.height = function () {
1543 return this.box
.height();