bff5175dfcd4841247c483a07745df07867fc445
[KiwiIRC.git] / client / assets / dev / model_application.js
1 _kiwi.model.Application = function () {
2 // Set to a reference to this object within initialize()
3 var that = null;
4
5 // The auto connect details entered into the server select box
6 var auto_connect_details = {};
7
8
9 var model = function () {
10 /** _kiwi.view.Application */
11 this.view = null;
12
13 /** _kiwi.view.StatusMessage */
14 this.message = null;
15
16 /* Address for the kiwi server */
17 this.kiwi_server = null;
18
19 this.initialize = function (options) {
20 that = this;
21
22 if (options[0].container) {
23 this.set('container', options[0].container);
24 }
25
26 // The base url to the kiwi server
27 this.set('base_path', options[0].base_path ? options[0].base_path : '/kiwi');
28
29 // Any options sent down from the server
30 this.server_settings = options[0].server_settings || {};
31
32 // Best guess at where the kiwi server is
33 this.detectKiwiServer();
34
35 // Takes instances of model_network
36 this.connections = new _kiwi.model.NetworkPanelList();
37 };
38
39
40 this.start = function () {
41 // Only debug if set in the querystring
42 if (!getQueryVariable('debug')) {
43 manageDebug(false);
44 } else {
45 //manageDebug(true);
46 }
47
48 // Set the gateway up
49 _kiwi.gateway = new _kiwi.model.Gateway();
50 this.bindGatewayCommands(_kiwi.gateway);
51
52 this.initializeClient();
53 this.initializeGlobals();
54
55 this.view.barsHide(true);
56
57 this.connections.getByConnectionId(0).panels.server.server_login.bind('server_connect', function (event) {
58 var server_login = this,
59 transport_path = '';
60 auto_connect_details = event;
61
62 server_login.networkConnecting();
63
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());
66
67 $script(transport_path, function () {
68 if (!window.io) {
69 kiwiServerNotFound();
70 return;
71 }
72 _kiwi.gateway.set('kiwi_server', that.kiwi_server + '/kiwi');
73 _kiwi.gateway.set('nick', event.nick);
74
75 _kiwi.gateway.connect(event.server, event.port, event.ssl, event.password, function (error) {
76 if (error) {
77 kiwiServerNotFound();
78 }
79 });
80 });
81 });
82
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();
87 }, 0);
88 };
89
90
91 function kiwiServerNotFound (e) {
92 that.connections.getByConnectionId(0).panels.server.server_login.showError();
93 }
94
95
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';
100 } else {
101 // Assume the kiwi server is on the same server
102 this.kiwi_server = window.location.protocol + '//' + window.location.host;
103 }
104 };
105
106
107 this.initializeClient = function () {
108 this.view = new _kiwi.view.Application({model: this, el: this.get('container')});
109
110 /**
111 * This is temporary.
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
115 */
116 var connection = new _kiwi.model.Network({connection_id: 0});
117 this.connections.add(connection);
118
119 /**
120 * Set the UI components up
121 */
122 this.controlbox = new _kiwi.view.ControlBox({el: $('#controlbox')[0]});
123 this.bindControllboxCommands(this.controlbox);
124
125 this.topicbar = new _kiwi.view.TopicBar({el: $('#topic')[0]});
126
127 new _kiwi.view.AppToolbar({el: $('#toolbar .app_tools')[0]});
128
129 this.message = new _kiwi.view.StatusMessage({el: $('#status_message')[0]});
130
131 this.resize_handle = new _kiwi.view.ResizeHandler({el: $('#memberlists_resize_handle')[0]});
132
133 this.connections.getByConnectionId(0).panels.server.view.show();
134
135 // Rejigg the UI sizes
136 this.view.doLayout();
137
138 this.populateDefaultServerSettings();
139 };
140
141
142 this.initializeGlobals = function () {
143 _kiwi.global.connections = this.connections;
144
145 _kiwi.global.components.Applet = _kiwi.model.Applet;
146 _kiwi.global.components.Panel =_kiwi.model.Panel;
147 };
148
149
150 this.populateDefaultServerSettings = function () {
151 var parts;
152 var defaults = {
153 nick: getQueryVariable('nick') || '',
154 server: '',
155 port: 6667,
156 ssl: false,
157 channel: window.location.hash || '#chat',
158 channel_key: ''
159 };
160 var uricheck;
161
162
163 /**
164 * Get any settings set by the server
165 * These settings may be changed in the server selection dialog
166 */
167 if (this.server_settings.client) {
168 if (this.server_settings.client.nick)
169 defaults.nick = this.server_settings.client.nick;
170
171 if (this.server_settings.client.server)
172 defaults.server = this.server_settings.client.server;
173
174 if (this.server_settings.client.port)
175 defaults.port = this.server_settings.client.port;
176
177 if (this.server_settings.client.ssl)
178 defaults.ssl = this.server_settings.client.ssl;
179
180 if (this.server_settings.client.channel)
181 defaults.channel = this.server_settings.client.channel;
182 }
183
184
185
186 /**
187 * Get any settings passed in the URL
188 * These settings may be changed in the server selection dialog
189 */
190
191 // Process the URL part by part, extracting as we go
192 parts = window.location.pathname.toString().replace(this.get('base_path'), '').split('/');
193
194 if (parts.length > 0) {
195 parts.shift();
196
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]);
204 /*
205 uricheck[1] = ssl (optional)
206 uricheck[2] = host
207 uricheck[3] = port (optional)
208 uricheck[4] = channel (optional)
209 uricheck[5] = channel key (optional, channel must also be set)
210 */
211 if (uricheck) {
212 if (typeof uricheck[1] !== 'undefined') {
213 defaults.ssl = true;
214 if (defaults.port === 6667) {
215 defaults.port = 6697;
216 }
217 }
218 defaults.server = uricheck[2];
219 if (typeof uricheck[3] !== 'undefined') {
220 defaults.port = uricheck[3];
221 }
222 if (typeof uricheck[4] !== 'undefined') {
223 defaults.channel = '#' + uricheck[4];
224 if (typeof uricheck[5] !== 'undefined') {
225 defaults.channel_key = uricheck[5];
226 }
227 }
228 }
229 parts = [];
230 } else {
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);
237 defaults.ssl = true;
238 } else {
239 defaults.ssl = false;
240 }
241
242 } else {
243 defaults.server = parts[0];
244 }
245
246 parts.shift();
247 }
248 }
249
250 if (parts.length > 0 && parts[0]) {
251 defaults.channel = '#' + parts[0];
252 parts.shift();
253 }
254 }
255
256 // If any settings have been given by the server.. override any auto detected settings
257 /**
258 * Get any server restrictions as set in the server config
259 * These settings can not be changed in the server selection dialog
260 */
261 if (this.server_settings && this.server_settings.connection) {
262 if (this.server_settings.connection.server) {
263 defaults.server = this.server_settings.connection.server;
264 }
265
266 if (this.server_settings.connection.port) {
267 defaults.port = this.server_settings.connection.port;
268 }
269
270 if (this.server_settings.connection.ssl) {
271 defaults.ssl = this.server_settings.connection.ssl;
272 }
273
274 if (this.server_settings.connection.channel) {
275 defaults.channel = this.server_settings.connection.channel;
276 }
277
278 if (this.server_settings.connection.nick) {
279 defaults.nick = this.server_settings.connection.nick;
280 }
281 }
282
283 // Set any random numbers if needed
284 defaults.nick = defaults.nick.replace('?', Math.floor(Math.random() * 100000).toString());
285
286 // Populate the server select box with defaults
287 this.connections.getByConnectionId(0).panels.server.server_login.populateFields(defaults);
288 };
289
290
291 this.panels = (function() {
292 var fn = function() {
293 // Get a complete list of panels
294 var panels = this.connections.panels();
295
296 // Active panels / server
297 panels.active = this.connections.active_panel;
298 panels.server = this.connections.active_connection.panels.server;
299
300 return panels;
301 };
302
303 _.extend(fn, Backbone.Events);
304
305 return fn;
306 })();
307
308
309 this.bindGatewayCommands = function (gw) {
310 gw.on('onconnect', function (event) {
311 that.view.barsShow();
312
313 if (auto_connect_details.channel) {
314 that.controlbox.processInput('/JOIN ' + auto_connect_details.channel + ' ' + auto_connect_details.channel_key);
315 }
316 });
317
318
319 (function () {
320 var gw_stat = 0;
321
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});
325
326 that.view.$el.removeClass('connected');
327
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');
332 });
333 _kiwi.app.connections.getByConnectionId(0).panels.server.addMsg('', msg, 'action quit');
334
335 gw_stat = 1;
336 });
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');
340 });
341 gw.on('onconnect', function (event) {
342 that.view.$el.addClass('connected');
343 if (gw_stat !== 1) return;
344
345 var msg = 'It\'s OK, you\'re connected again :)';
346 that.message.text(msg, {timeout: 5000});
347
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');
352 });
353 _kiwi.app.connections.getByConnectionId(0).panels.server.addMsg('', msg, 'action join');
354
355 gw_stat = 0;
356 });
357 })();
358
359 };
360
361
362
363 /**
364 * Bind to certain commands that may be typed into the control box
365 */
366 this.bindControllboxCommands = function (controlbox) {
367 // Default aliases
368 $.extend(controlbox.preprocessor.aliases, {
369 // General aliases
370 '/p': '/part $1+',
371 '/me': '/action $1+',
372 '/j': '/join $1+',
373 '/q': '/query $1+',
374
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+',
383
384 // Misc aliases
385 '/slap': '/me slaps $1 around a bit with a large trout'
386 });
387
388 controlbox.on('unknown_command', unknownCommand);
389
390 controlbox.on('command', allCommands);
391 controlbox.on('command:msg', msgCommand);
392
393 controlbox.on('command:action', actionCommand);
394
395 controlbox.on('command:join', joinCommand);
396
397 controlbox.on('command:part', partCommand);
398
399 controlbox.on('command:nick', function (ev) {
400 _kiwi.gateway.changeNick(ev.params[0]);
401 });
402
403 controlbox.on('command:query', queryCommand);
404
405 controlbox.on('command:topic', topicCommand);
406
407 controlbox.on('command:notice', noticeCommand);
408
409 controlbox.on('command:quote', quoteCommand);
410
411 controlbox.on('command:kick', kickCommand);
412
413 controlbox.on('command:clear', clearCommand);
414
415 controlbox.on('command:ctcp', ctcpCommand);
416
417
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);
422 });
423 });
424
425 controlbox.on('command:js', function (ev) {
426 if (!ev.params[0]) return;
427 $script(ev.params[0] + '?' + (new Date().getTime()));
428 });
429
430
431 controlbox.on('command:set', function (ev) {
432 if (!ev.params[0]) return;
433
434 var setting = ev.params[0],
435 value;
436
437 // Do we have a second param to set a value?
438 if (ev.params[1]) {
439 ev.params.shift();
440
441 value = ev.params.join(' ');
442
443 // If we're setting a true boolean value..
444 if (value === 'true')
445 value = true;
446
447 // If we're setting a false boolean value..
448 if (value === 'false')
449 value = false;
450
451 // If we're setting a number..
452 if (parseInt(value, 10).toString() === value)
453 value = parseInt(value, 10);
454
455 _kiwi.global.settings.set(setting, value);
456 }
457
458 // Read the value to the user
459 _kiwi.app.panels().active.addMsg('', setting + ' = ' + _kiwi.global.settings.get(setting).toString());
460 });
461
462
463 controlbox.on('command:save', function (ev) {
464 _kiwi.global.settings.save();
465 _kiwi.app.panels().active.addMsg('', 'Settings have been saved');
466 });
467
468
469 controlbox.on('command:alias', function (ev) {
470 var name, rule;
471
472 // No parameters passed so list them
473 if (!ev.params[1]) {
474 $.each(controlbox.preprocessor.aliases, function (name, rule) {
475 _kiwi.app.panels().server.addMsg(' ', name + ' => ' + rule);
476 });
477 return;
478 }
479
480 // Deleting an alias?
481 if (ev.params[0] === 'del' || ev.params[0] === 'delete') {
482 name = ev.params[1];
483 if (name[0] !== '/') name = '/' + name;
484 delete controlbox.preprocessor.aliases[name];
485 return;
486 }
487
488 // Add the alias
489 name = ev.params[0];
490 ev.params.shift();
491 rule = ev.params.join(' ');
492
493 // Make sure the name starts with a slash
494 if (name[0] !== '/') name = '/' + name;
495
496 // Now actually add the alias
497 controlbox.preprocessor.aliases[name] = rule;
498 });
499
500
501 controlbox.on('command:ignore', function (ev) {
502 var list = _kiwi.gateway.get('ignore_list');
503
504 // No parameters passed so list them
505 if (!ev.params[0]) {
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);
510 });
511 } else {
512 _kiwi.app.panels().active.addMsg(' ', 'Not ignoring anybody');
513 }
514 return;
515 }
516
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]);
521 });
522
523
524 controlbox.on('command:unignore', function (ev) {
525 var list = _kiwi.gateway.get('ignore_list');
526
527 if (!ev.params[0]) {
528 _kiwi.app.panels().active.addMsg(' ', 'Specifiy which nick you wish to stop ignoring');
529 return;
530 }
531
532 list = _.reject(list, function(pattern) {
533 return pattern === ev.params[0];
534 });
535
536 _kiwi.gateway.set('ignore_list', list);
537
538 _kiwi.app.panels().active.addMsg(' ', 'Stopped ignoring ' + ev.params[0]);
539 });
540
541
542 controlbox.on('command:applet', appletCommand);
543 controlbox.on('command:settings', settingsCommand);
544 controlbox.on('command:script', scriptCommand);
545 };
546
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);
552 }
553
554 function allCommands (ev) {}
555
556 function joinCommand (ev) {
557 var channel, channel_names;
558
559 channel_names = ev.params.join(' ').split(',');
560
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] || '';
566
567 // Trim any whitespace off the name
568 channel_name = channel_name.trim();
569
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});
574 return;
575 }
576
577 // Check if we have the panel already. If not, create it
578 channel = that.connections.active_connection.panels.getByName(channel_name);
579 if (!channel) {
580 channel = new _kiwi.model.Channel({name: channel_name});
581 _kiwi.app.connections.active_connection.panels.add(channel);
582 }
583
584 _kiwi.gateway.join(channel_name, channel_key);
585 });
586
587 if (channel) channel.view.show();
588
589 }
590
591 function queryCommand (ev) {
592 var destination, panel;
593
594 destination = ev.params[0];
595
596 // Check if we have the panel already. If not, create it
597 panel = that.connections.active_connection.panels.getByName(destination);
598 if (!panel) {
599 panel = new _kiwi.model.Query({name: destination});
600 that.connections.active_connection.panels.add(panel);
601 }
602
603 if (panel) panel.view.show();
604
605 }
606
607 function msgCommand (ev) {
608 var destination = ev.params[0],
609 panel = that.connections.active_connection.panels.getByName(destination) || that.panels().server;
610
611 ev.params.shift();
612
613 panel.addMsg(_kiwi.app.connections.active_connection.get('nick'), ev.params.join(' '));
614 _kiwi.gateway.privmsg(destination, ev.params.join(' '));
615 }
616
617 function actionCommand (ev) {
618 if (_kiwi.app.panels().active.isServer()) {
619 return;
620 }
621
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(' '));
625 }
626
627 function partCommand (ev) {
628 if (ev.params.length === 0) {
629 _kiwi.gateway.part(_kiwi.app.panels().active.get('name'));
630 } else {
631 _.each(ev.params, function (channel) {
632 _kiwi.gateway.part(channel);
633 });
634 }
635 }
636
637 function topicCommand (ev) {
638 var channel_name;
639
640 if (ev.params.length === 0) return;
641
642 if (that.isChannelName(ev.params[0])) {
643 channel_name = ev.params[0];
644 ev.params.shift();
645 } else {
646 channel_name = _kiwi.app.panels().active.get('name');
647 }
648
649 _kiwi.gateway.topic(channel_name, ev.params.join(' '));
650 }
651
652 function noticeCommand (ev) {
653 var destination;
654
655 // Make sure we have a destination and some sort of message
656 if (ev.params.length <= 1) return;
657
658 destination = ev.params[0];
659 ev.params.shift();
660
661 _kiwi.gateway.notice(destination, ev.params.join(' '));
662 }
663
664 function quoteCommand (ev) {
665 var raw = ev.params.join(' ');
666 _kiwi.gateway.raw(raw);
667 }
668
669 function kickCommand (ev) {
670 var nick, panel = _kiwi.app.panels().active;
671
672 if (!panel.isChannel()) return;
673
674 // Make sure we have a nick
675 if (ev.params.length === 0) return;
676
677 nick = ev.params[0];
678 ev.params.shift();
679
680 _kiwi.gateway.kick(panel.get('name'), nick, ev.params.join(' '));
681 }
682
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()) {
686 return;
687 }
688
689 if (_kiwi.app.panels().active.clearMessages) {
690 _kiwi.app.panels().active.clearMessages();
691 }
692 }
693
694 function ctcpCommand(ev) {
695 var target, type;
696
697 // Make sure we have a target and a ctcp type (eg. version, time)
698 if (ev.params.length < 2) return;
699
700 target = ev.params[0];
701 ev.params.shift();
702
703 type = ev.params[0];
704 ev.params.shift();
705
706 _kiwi.gateway.ctcp(true, type, target, ev.params.join(' '));
707 }
708
709 function settingsCommand (ev) {
710 var settings = _kiwi.model.Applet.loadOnce('kiwi_settings');
711 settings.view.show();
712 }
713
714 function scriptCommand (ev) {
715 var editor = _kiwi.model.Applet.loadOnce('kiwi_script_editor');
716 editor.view.show();
717 }
718
719 function appletCommand (ev) {
720 if (!ev.params[0]) return;
721
722 var panel = new _kiwi.model.Applet();
723
724 if (ev.params[1]) {
725 // Url and name given
726 panel.load(ev.params[0], ev.params[1]);
727 } else {
728 // Load a pre-loaded applet
729 if (_kiwi.applets[ev.params[0]]) {
730 panel.load(new _kiwi.applets[ev.params[0]]());
731 } else {
732 _kiwi.app.panels().server.addMsg('', 'Applet "' + ev.params[0] + '" does not exist');
733 return;
734 }
735 }
736
737 _kiwi.app.connections.active_connection.panels.add(panel);
738 panel.view.show();
739 }
740
741
742
743
744
745 this.isChannelName = function (channel_name) {
746 var channel_prefix = _kiwi.gateway.get('channel_prefix');
747
748 if (!channel_name || !channel_name.length) return false;
749 return (channel_prefix.indexOf(channel_name[0]) > -1);
750 };
751
752
753
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')
758 return;
759
760 _.each(this.connections.models, function(connection) {
761 _.each(connection.panels.model, fn);
762 });
763 };
764
765 };
766
767
768 model = Backbone.Model.extend(new model());
769
770 return new model(arguments);
771 };