1 _kiwi
.model
.Application = function () {
2 // Set to a reference to this object within initialize()
5 // The auto connect details entered into the server select box
6 var auto_connect_details
= {};
9 var model = function () {
10 /** _kiwi.view.Application */
13 /** _kiwi.view.StatusMessage */
16 /* Address for the kiwi server */
17 this.kiwi_server
= null;
19 this.initialize = function (options
) {
22 if (options
[0].container
) {
23 this.set('container', options
[0].container
);
26 // The base url to the kiwi server
27 this.set('base_path', options
[0].base_path
? options
[0].base_path
: '/kiwi');
29 // Any options sent down from the server
30 this.server_settings
= options
[0].server_settings
|| {};
32 // Best guess at where the kiwi server is
33 this.detectKiwiServer();
35 // Takes instances of model_network
36 this.connections
= new _kiwi
.model
.NetworkPanelList();
40 this.start = function () {
41 // Only debug if set in the querystring
42 if (!getQueryVariable('debug')) {
49 _kiwi
.gateway
= new _kiwi
.model
.Gateway();
50 this.bindGatewayCommands(_kiwi
.gateway
);
52 this.initializeClient();
53 this.initializeGlobals();
55 this.view
.barsHide(true);
57 this.connections
.getByConnectionId(0).panels
.server
.server_login
.bind('server_connect', function (event
) {
58 var server_login
= this,
60 auto_connect_details
= event
;
62 server_login
.networkConnecting();
64 // Path to get the socket.io transport code
65 transport_path
= that
.kiwi_server
+ that
.get('base_path') + '/transport/socket.io.js?ts='+(new Date().getTime());
67 $script(transport_path
, function () {
72 _kiwi
.gateway
.set('kiwi_server', that
.kiwi_server
+ '/kiwi');
73 _kiwi
.gateway
.set('nick', event
.nick
);
75 _kiwi
.gateway
.connect(event
.server
, event
.port
, event
.ssl
, event
.password
, function (error
) {
83 // TODO: Shouldn't really be here but it's not working in the view.. :/
84 // Hack for firefox browers: Focus is not given on this event loop iteration
85 setTimeout(function(){
86 _kiwi
.app
.connections
.getByConnectionId(0).panels
.server
.server_login
.$el
.find('.nick').select();
91 function kiwiServerNotFound (e
) {
92 that
.connections
.getByConnectionId(0).panels
.server
.server_login
.showError();
96 this.detectKiwiServer = function () {
97 // If running from file, default to localhost:7777 by default
98 if (window
.location
.protocol
=== 'file:') {
99 this.kiwi_server
= 'http://localhost:7778';
101 // Assume the kiwi server is on the same server
102 this.kiwi_server
= window
.location
.protocol
+ '//' + window
.location
.host
;
107 this.initializeClient = function () {
108 this.view
= new _kiwi
.view
.Application({model
: this, el
: this.get('container')});
112 * While multiple server support is being worked on,
113 * we will keep this single server variable here until
114 * It all gets moved over
116 var connection
= new _kiwi
.model
.Network({connection_id
: 0});
117 this.connections
.add(connection
);
120 * Set the UI components up
122 this.controlbox
= new _kiwi
.view
.ControlBox({el
: $('#controlbox')[0]});
123 this.bindControllboxCommands(this.controlbox
);
125 this.topicbar
= new _kiwi
.view
.TopicBar({el
: $('#topic')[0]});
127 new _kiwi
.view
.AppToolbar({el
: $('#toolbar .app_tools')[0]});
129 this.message
= new _kiwi
.view
.StatusMessage({el
: $('#status_message')[0]});
131 this.resize_handle
= new _kiwi
.view
.ResizeHandler({el
: $('#memberlists_resize_handle')[0]});
133 this.connections
.getByConnectionId(0).panels
.server
.view
.show();
135 // Rejigg the UI sizes
136 this.view
.doLayout();
138 this.populateDefaultServerSettings();
142 this.initializeGlobals = function () {
143 _kiwi
.global
.connections
= this.connections
;
145 _kiwi
.global
.components
.Applet
= _kiwi
.model
.Applet
;
146 _kiwi
.global
.components
.Panel
=_kiwi
.model
.Panel
;
150 this.populateDefaultServerSettings = function () {
153 nick
: getQueryVariable('nick') || '',
157 channel
: window
.location
.hash
|| '#chat',
164 * Get any settings set by the server
165 * These settings may be changed in the server selection dialog
167 if (this.server_settings
.client
) {
168 if (this.server_settings
.client
.nick
)
169 defaults
.nick
= this.server_settings
.client
.nick
;
171 if (this.server_settings
.client
.server
)
172 defaults
.server
= this.server_settings
.client
.server
;
174 if (this.server_settings
.client
.port
)
175 defaults
.port
= this.server_settings
.client
.port
;
177 if (this.server_settings
.client
.ssl
)
178 defaults
.ssl
= this.server_settings
.client
.ssl
;
180 if (this.server_settings
.client
.channel
)
181 defaults
.channel
= this.server_settings
.client
.channel
;
187 * Get any settings passed in the URL
188 * These settings may be changed in the server selection dialog
191 // Process the URL part by part, extracting as we go
192 parts
= window
.location
.pathname
.toString().replace(this.get('base_path'), '').split('/');
194 if (parts
.length
> 0) {
197 if (parts
.length
> 0 && parts
[0]) {
198 // Check to see if we're dealing with an irc: uri, or whether we need to extract the server/channel info from the HTTP URL path.
199 uricheck
= parts
[0].substr(0, 7).toLowerCase();
200 if ((uricheck
=== 'ircs%3a') || (uricheck
.substr(0,6) === 'irc%3a')) {
201 parts
[0] = decodeURIComponent(parts
[0]);
202 // irc[s]://<host>[:<port>]/[<channel>[?<password>]]
203 uricheck
= /^irc(s)?:(?:\/\/?)?([^:\/]+)(?::([0-9]+))?(?:(?:\/)([^\?]*)(?:(?:\?)(.*))?)?$/.exec(parts
[0]);
205 uricheck[1] = ssl (optional)
207 uricheck[3] = port (optional)
208 uricheck[4] = channel (optional)
209 uricheck[5] = channel key (optional, channel must also be set)
212 if (typeof uricheck
[1] !== 'undefined') {
214 if (defaults
.port
=== 6667) {
215 defaults
.port
= 6697;
218 defaults
.server
= uricheck
[2];
219 if (typeof uricheck
[3] !== 'undefined') {
220 defaults
.port
= uricheck
[3];
222 if (typeof uricheck
[4] !== 'undefined') {
223 defaults
.channel
= '#' + uricheck
[4];
224 if (typeof uricheck
[5] !== 'undefined') {
225 defaults
.channel_key
= uricheck
[5];
231 // Extract the port+ssl if we find one
232 if (parts
[0].search(/:/) > 0) {
233 defaults
.port
= parts
[0].substring(parts
[0].search(/:/) + 1);
234 defaults
.server
= parts
[0].substring(0, parts
[0].search(/:/));
235 if (defaults
.port
[0] === '+') {
236 defaults
.port
= parseInt(defaults
.port
.substring(1), 10);
239 defaults
.ssl
= false;
243 defaults
.server
= parts
[0];
250 if (parts
.length
> 0 && parts
[0]) {
251 defaults
.channel
= '#' + parts
[0];
256 // If any settings have been given by the server.. override any auto detected settings
258 * Get any server restrictions as set in the server config
259 * These settings can not be changed in the server selection dialog
261 if (this.server_settings
&& this.server_settings
.connection
) {
262 if (this.server_settings
.connection
.server
) {
263 defaults
.server
= this.server_settings
.connection
.server
;
266 if (this.server_settings
.connection
.port
) {
267 defaults
.port
= this.server_settings
.connection
.port
;
270 if (this.server_settings
.connection
.ssl
) {
271 defaults
.ssl
= this.server_settings
.connection
.ssl
;
274 if (this.server_settings
.connection
.channel
) {
275 defaults
.channel
= this.server_settings
.connection
.channel
;
278 if (this.server_settings
.connection
.nick
) {
279 defaults
.nick
= this.server_settings
.connection
.nick
;
283 // Set any random numbers if needed
284 defaults
.nick
= defaults
.nick
.replace('?', Math
.floor(Math
.random() * 100000).toString());
286 // Populate the server select box with defaults
287 this.connections
.getByConnectionId(0).panels
.server
.server_login
.populateFields(defaults
);
291 this.panels
= (function() {
292 var fn = function() {
293 // Get a complete list of panels
294 var panels
= this.connections
.panels();
296 // Active panels / server
297 panels
.active
= this.connections
.active_panel
;
298 panels
.server
= this.connections
.active_connection
.panels
.server
;
303 _
.extend(fn
, Backbone
.Events
);
309 this.bindGatewayCommands = function (gw
) {
310 gw
.on('onconnect', function (event
) {
311 that
.view
.barsShow();
313 if (auto_connect_details
.channel
) {
314 that
.controlbox
.processInput('/JOIN ' + auto_connect_details
.channel
+ ' ' + auto_connect_details
.channel_key
);
322 gw
.on('disconnect', function (event
) {
323 var msg
= 'You have been disconnected. Attempting to reconnect for you..';
324 that
.message
.text(msg
, {timeout
: 10000});
326 that
.view
.$el
.removeClass('connected');
328 // Mention the disconnection on every channel
329 $.each(_kiwi
.app
.connections
.getByConnectionId(0).panels
.models
, function (idx
, panel
) {
330 if (!panel
|| !panel
.isChannel()) return;
331 panel
.addMsg('', msg
, 'action quit');
333 _kiwi
.app
.connections
.getByConnectionId(0).panels
.server
.addMsg('', msg
, 'action quit');
337 gw
.on('reconnecting', function (event
) {
338 msg
= 'You have been disconnected. Attempting to reconnect again in ' + (event
.delay
/1000) + ' seconds..';
339 _kiwi
.app
.connections
.getByConnectionId(0).panels
.server
.addMsg('', msg
, 'action quit');
341 gw
.on('onconnect', function (event
) {
342 that
.view
.$el
.addClass('connected');
343 if (gw_stat
!== 1) return;
345 var msg
= 'It\'s OK, you\'re connected again :)';
346 that
.message
.text(msg
, {timeout
: 5000});
348 // Mention the disconnection on every channel
349 $.each(_kiwi
.app
.connections
.getByConnectionId(0).panels
.models
, function (idx
, panel
) {
350 if (!panel
|| !panel
.isChannel()) return;
351 panel
.addMsg('', msg
, 'action join');
353 _kiwi
.app
.connections
.getByConnectionId(0).panels
.server
.addMsg('', msg
, 'action join');
364 * Bind to certain commands that may be typed into the control box
366 this.bindControllboxCommands = function (controlbox
) {
368 $.extend(controlbox
.preprocessor
.aliases
, {
371 '/me': '/action $1+',
375 // Op related aliases
376 '/op': '/quote mode $channel +o $1+',
377 '/deop': '/quote mode $channel -o $1+',
378 '/hop': '/quote mode $channel +h $1+',
379 '/dehop': '/quote mode $channel -h $1+',
380 '/voice': '/quote mode $channel +v $1+',
381 '/devoice': '/quote mode $channel -v $1+',
382 '/k': '/kick $channel $1+',
385 '/slap': '/me slaps $1 around a bit with a large trout'
388 controlbox
.on('unknown_command', unknownCommand
);
390 controlbox
.on('command', allCommands
);
391 controlbox
.on('command:msg', msgCommand
);
393 controlbox
.on('command:action', actionCommand
);
395 controlbox
.on('command:join', joinCommand
);
397 controlbox
.on('command:part', partCommand
);
399 controlbox
.on('command:nick', function (ev
) {
400 _kiwi
.gateway
.changeNick(ev
.params
[0]);
403 controlbox
.on('command:query', queryCommand
);
405 controlbox
.on('command:topic', topicCommand
);
407 controlbox
.on('command:notice', noticeCommand
);
409 controlbox
.on('command:quote', quoteCommand
);
411 controlbox
.on('command:kick', kickCommand
);
413 controlbox
.on('command:clear', clearCommand
);
415 controlbox
.on('command:ctcp', ctcpCommand
);
418 controlbox
.on('command:css', function (ev
) {
419 var queryString
= '?reload=' + new Date().getTime();
420 $('link[rel="stylesheet"]').each(function () {
421 this.href
= this.href
.replace(/\?.*|$/, queryString
);
425 controlbox
.on('command:js', function (ev
) {
426 if (!ev
.params
[0]) return;
427 $script(ev
.params
[0] + '?' + (new Date().getTime()));
431 controlbox
.on('command:set', function (ev
) {
432 if (!ev
.params
[0]) return;
434 var setting
= ev
.params
[0],
437 // Do we have a second param to set a value?
441 value
= ev
.params
.join(' ');
443 // If we're setting a true boolean value..
444 if (value
=== 'true')
447 // If we're setting a false boolean value..
448 if (value
=== 'false')
451 // If we're setting a number..
452 if (parseInt(value
, 10).toString() === value
)
453 value
= parseInt(value
, 10);
455 _kiwi
.global
.settings
.set(setting
, value
);
458 // Read the value to the user
459 _kiwi
.app
.panels().active
.addMsg('', setting
+ ' = ' + _kiwi
.global
.settings
.get(setting
).toString());
463 controlbox
.on('command:save', function (ev
) {
464 _kiwi
.global
.settings
.save();
465 _kiwi
.app
.panels().active
.addMsg('', 'Settings have been saved');
469 controlbox
.on('command:alias', function (ev
) {
472 // No parameters passed so list them
474 $.each(controlbox
.preprocessor
.aliases
, function (name
, rule
) {
475 _kiwi
.app
.panels().server
.addMsg(' ', name
+ ' => ' + rule
);
480 // Deleting an alias?
481 if (ev
.params
[0] === 'del' || ev
.params
[0] === 'delete') {
483 if (name
[0] !== '/') name
= '/' + name
;
484 delete controlbox
.preprocessor
.aliases
[name
];
491 rule
= ev
.params
.join(' ');
493 // Make sure the name starts with a slash
494 if (name
[0] !== '/') name
= '/' + name
;
496 // Now actually add the alias
497 controlbox
.preprocessor
.aliases
[name
] = rule
;
501 controlbox
.on('command:ignore', function (ev
) {
502 var list
= _kiwi
.gateway
.get('ignore_list');
504 // No parameters passed so list them
506 if (list
.length
> 0) {
507 _kiwi
.app
.panels().active
.addMsg(' ', 'Ignored nicks:');
508 $.each(list
, function (idx
, ignored_pattern
) {
509 _kiwi
.app
.panels().active
.addMsg(' ', ignored_pattern
);
512 _kiwi
.app
.panels().active
.addMsg(' ', 'Not ignoring anybody');
517 // We have a parameter, so add it
518 list
.push(ev
.params
[0]);
519 _kiwi
.gateway
.set('ignore_list', list
);
520 _kiwi
.app
.panels().active
.addMsg(' ', 'Ignoring ' + ev
.params
[0]);
524 controlbox
.on('command:unignore', function (ev
) {
525 var list
= _kiwi
.gateway
.get('ignore_list');
528 _kiwi
.app
.panels().active
.addMsg(' ', 'Specifiy which nick you wish to stop ignoring');
532 list
= _
.reject(list
, function(pattern
) {
533 return pattern
=== ev
.params
[0];
536 _kiwi
.gateway
.set('ignore_list', list
);
538 _kiwi
.app
.panels().active
.addMsg(' ', 'Stopped ignoring ' + ev
.params
[0]);
542 controlbox
.on('command:applet', appletCommand
);
543 controlbox
.on('command:settings', settingsCommand
);
544 controlbox
.on('command:script', scriptCommand
);
547 // A fallback action. Send a raw command to the server
548 function unknownCommand (ev
) {
549 var raw_cmd
= ev
.command
+ ' ' + ev
.params
.join(' ');
550 console
.log('RAW: ' + raw_cmd
);
551 _kiwi
.gateway
.raw(raw_cmd
);
554 function allCommands (ev
) {}
556 function joinCommand (ev
) {
557 var channel
, channel_names
;
559 channel_names
= ev
.params
.join(' ').split(',');
561 $.each(channel_names
, function (index
, channel_name_key
) {
562 // We may have a channel key so split it off
563 var spli
= channel_name_key
.split(' '),
564 channel_name
= spli
[0],
565 channel_key
= spli
[1] || '';
567 // Trim any whitespace off the name
568 channel_name
= channel_name
.trim();
570 // If not a valid channel name, display a warning
571 if (!that
.isChannelName(channel_name
)) {
572 _kiwi
.app
.panels().server
.addMsg('', channel_name
+ ' is not a valid channel name');
573 _kiwi
.app
.message
.text(channel_name
+ ' is not a valid channel name', {timeout
: 5000});
577 // Check if we have the panel already. If not, create it
578 channel
= that
.connections
.active_connection
.panels
.getByName(channel_name
);
580 channel
= new _kiwi
.model
.Channel({name
: channel_name
});
581 _kiwi
.app
.connections
.active_connection
.panels
.add(channel
);
584 _kiwi
.gateway
.join(channel_name
, channel_key
);
587 if (channel
) channel
.view
.show();
591 function queryCommand (ev
) {
592 var destination
, panel
;
594 destination
= ev
.params
[0];
596 // Check if we have the panel already. If not, create it
597 panel
= that
.connections
.active_connection
.panels
.getByName(destination
);
599 panel
= new _kiwi
.model
.Query({name
: destination
});
600 that
.connections
.active_connection
.panels
.add(panel
);
603 if (panel
) panel
.view
.show();
607 function msgCommand (ev
) {
608 var destination
= ev
.params
[0],
609 panel
= that
.connections
.active_connection
.panels
.getByName(destination
) || that
.panels().server
;
613 panel
.addMsg(_kiwi
.app
.connections
.active_connection
.get('nick'), ev
.params
.join(' '));
614 _kiwi
.gateway
.privmsg(destination
, ev
.params
.join(' '));
617 function actionCommand (ev
) {
618 if (_kiwi
.app
.panels().active
.isServer()) {
622 var panel
= _kiwi
.app
.panels().active
;
623 panel
.addMsg('', '* ' + _kiwi
.app
.connections
.active_connection
.get('nick') + ' ' + ev
.params
.join(' '), 'action');
624 _kiwi
.gateway
.action(panel
.get('name'), ev
.params
.join(' '));
627 function partCommand (ev
) {
628 if (ev
.params
.length
=== 0) {
629 _kiwi
.gateway
.part(_kiwi
.app
.panels().active
.get('name'));
631 _
.each(ev
.params
, function (channel
) {
632 _kiwi
.gateway
.part(channel
);
637 function topicCommand (ev
) {
640 if (ev
.params
.length
=== 0) return;
642 if (that
.isChannelName(ev
.params
[0])) {
643 channel_name
= ev
.params
[0];
646 channel_name
= _kiwi
.app
.panels().active
.get('name');
649 _kiwi
.gateway
.topic(channel_name
, ev
.params
.join(' '));
652 function noticeCommand (ev
) {
655 // Make sure we have a destination and some sort of message
656 if (ev
.params
.length
<= 1) return;
658 destination
= ev
.params
[0];
661 _kiwi
.gateway
.notice(destination
, ev
.params
.join(' '));
664 function quoteCommand (ev
) {
665 var raw
= ev
.params
.join(' ');
666 _kiwi
.gateway
.raw(raw
);
669 function kickCommand (ev
) {
670 var nick
, panel
= _kiwi
.app
.panels().active
;
672 if (!panel
.isChannel()) return;
674 // Make sure we have a nick
675 if (ev
.params
.length
=== 0) return;
680 _kiwi
.gateway
.kick(panel
.get('name'), nick
, ev
.params
.join(' '));
683 function clearCommand (ev
) {
684 // Can't clear a server or applet panel
685 if (_kiwi
.app
.panels().active
.isServer() || _kiwi
.app
.panels().active
.isApplet()) {
689 if (_kiwi
.app
.panels().active
.clearMessages
) {
690 _kiwi
.app
.panels().active
.clearMessages();
694 function ctcpCommand(ev
) {
697 // Make sure we have a target and a ctcp type (eg. version, time)
698 if (ev
.params
.length
< 2) return;
700 target
= ev
.params
[0];
706 _kiwi
.gateway
.ctcp(true, type
, target
, ev
.params
.join(' '));
709 function settingsCommand (ev
) {
710 var settings
= _kiwi
.model
.Applet
.loadOnce('kiwi_settings');
711 settings
.view
.show();
714 function scriptCommand (ev
) {
715 var editor
= _kiwi
.model
.Applet
.loadOnce('kiwi_script_editor');
719 function appletCommand (ev
) {
720 if (!ev
.params
[0]) return;
722 var panel
= new _kiwi
.model
.Applet();
725 // Url and name given
726 panel
.load(ev
.params
[0], ev
.params
[1]);
728 // Load a pre-loaded applet
729 if (_kiwi
.applets
[ev
.params
[0]]) {
730 panel
.load(new _kiwi
.applets
[ev
.params
[0]]());
732 _kiwi
.app
.panels().server
.addMsg('', 'Applet "' + ev
.params
[0] + '" does not exist');
737 _kiwi
.app
.connections
.active_connection
.panels
.add(panel
);
745 this.isChannelName = function (channel_name
) {
746 var channel_prefix
= _kiwi
.gateway
.get('channel_prefix');
748 if (!channel_name
|| !channel_name
.length
) return false;
749 return (channel_prefix
.indexOf(channel_name
[0]) > -1);
754 this.eachPanel = function (fn
) {
755 alert('Switch this call with _kiwi.app.panels! location in console.log');
756 console
.log('Switch this call with _kiwi.app.panels! location in console.log');
757 if (typeof fn
!== 'function')
760 _
.each(this.connections
.models
, function(connection
) {
761 _
.each(connection
.panels
.model
, fn
);
768 model
= Backbone
.Model
.extend(new model());
770 return new model(arguments
);