Correctly using /quit command without reconnecting #567
[KiwiIRC.git] / client / src / app.js
CommitLineData
eaaf73b0 1// Holds anything kiwi client specific (ie. front, gateway, _kiwi.plugs..)\r
9df70c63
D
2/**\r
3* @namespace\r
4*/\r
eaaf73b0 5var _kiwi = {};\r
9df70c63 6\r
41cba2fd 7_kiwi.misc = {};\r
eaaf73b0
D
8_kiwi.model = {};\r
9_kiwi.view = {};\r
10_kiwi.applets = {};\r
b62c8381
D
11\r
12\r
13/**\r
14 * A global container for third party access\r
15 * Will be used to access a limited subset of kiwi functionality\r
16 * and data (think: plugins)\r
17 */\r
eaaf73b0 18_kiwi.global = {\r
4c424593 19 build_version: '', // Kiwi IRC version this is built from (Set from index.html)\r
161b5673 20 settings: undefined, // Instance of _kiwi.model.DataStore\r
2a89ba11
D
21 plugins: undefined, // Instance of _kiwi.model.PluginManager\r
22 events: undefined, // Instance of PluginInterface\r
1e9f97d6
D
23 utils: {}, // References to misc. re-usable helpers / functions\r
24\r
25 initUtils: function() {\r
26 this.utils.randomString = randomString;\r
27 this.utils.secondsToTime = secondsToTime;\r
28 this.utils.parseISO8601 = parseISO8601;\r
29 this.utils.escapeRegex = escapeRegex;\r
30 this.utils.formatIRCMsg = formatIRCMsg;\r
31 this.utils.styleText = styleText;\r
32 this.utils.hsl2rgb = hsl2rgb;\r
33 },\r
34\r
ed8b91d6
D
35 rpc: function() {\r
36 _kiwi.gateway.rpc.call.call(_kiwi.gateway.rpc, arguments);\r
37 },\r
161b5673 38\r
f1452889
D
39 addMediaMessageType: function(match, buildHtml) {\r
40 _kiwi.view.MediaMessage.addType(match, buildHtml);\r
41 },\r
42\r
161b5673
D
43 // Event managers for plugins\r
44 components: {\r
45 EventComponent: function(event_source, proxy_event_name) {\r
9b609554
D
46 /*\r
47 * proxyEvent() listens for events then re-triggers them on its own\r
48 * event emitter. Why? So we can .off() on this emitter without\r
49 * effecting the source of events. Handy for plugins that we don't\r
50 * trust meddling with the core events.\r
51 *\r
52 * If listening for 'all' events the arguments are as follows:\r
53 * 1. Name of the triggered event\r
54 * 2. The event data\r
55 * For all other events, we only have one argument:\r
56 * 1. The event data\r
57 *\r
58 * When this is used via `new kiwi.components.Network()`, this listens\r
59 * for 'all' events so the first argument is the event name which is\r
60 * the connection ID. We don't want to re-trigger this event name so\r
61 * we need to juggle the arguments to find the real event name we want\r
62 * to emit.\r
63 */\r
161b5673 64 function proxyEvent(event_name, event_data) {\r
9b609554
D
65 if (proxy_event_name == 'all') {\r
66 event_name = event_data.event_name;\r
67 event_data = event_data.event_data;\r
68 } else {\r
161b5673 69 event_data = event_name.event_data;\r
f1452889 70 event_name = event_name.event_name;\r
161b5673 71 }\r
f1452889 72\r
161b5673
D
73 this.trigger(event_name, event_data);\r
74 }\r
75\r
76 // The event we are to proxy\r
77 proxy_event_name = proxy_event_name || 'all';\r
78\r
79\r
80 _.extend(this, Backbone.Events);\r
81 this._source = event_source;\r
82\r
83 // Proxy the events to this dispatcher\r
84 event_source.on(proxy_event_name, proxyEvent, this);\r
85\r
86 // Clean up this object\r
87 this.dispose = function () {\r
88 event_source.off(proxy_event_name, proxyEvent);\r
89 this.off();\r
90 delete this.event_source;\r
91 };\r
92 },\r
93\r
94 Network: function(connection_id) {\r
95 var connection_event;\r
96\r
97 if (typeof connection_id !== 'undefined') {\r
98 connection_event = 'connection:' + connection_id.toString();\r
18ae1a72
D
99 } else {\r
100 connection_event = 'connection';\r
161b5673
D
101 }\r
102\r
103 var obj = new this.EventComponent(_kiwi.gateway, connection_event);\r
104 var funcs = {\r
105 kiwi: 'kiwi', raw: 'raw', kick: 'kick', topic: 'topic',\r
106 part: 'part', join: 'join', action: 'action', ctcp: 'ctcp',\r
9de52d29 107 ctcpRequest: 'ctcpRequest', ctcpResponse: 'ctcpResponse',\r
72db27e4 108 notice: 'notice', msg: 'privmsg', changeNick: 'changeNick',\r
e32ff87b 109 channelInfo: 'channelInfo', mode: 'mode', quit: 'quit'\r
161b5673
D
110 };\r
111\r
112 // Proxy each gateway method\r
113 _.each(funcs, function(gateway_fn, func_name) {\r
114 obj[func_name] = function() {\r
115 var fn_name = gateway_fn;\r
116\r
117 // Add connection_id to the argument list\r
118 var args = Array.prototype.slice.call(arguments, 0);\r
119 args.unshift(connection_id);\r
120\r
121 // Call the gateway function on behalf of this connection\r
122 return _kiwi.gateway[fn_name].apply(_kiwi.gateway, args);\r
123 };\r
124 });\r
125\r
126 return obj;\r
127 },\r
128\r
129 ControlInput: function() {\r
130 var obj = new this.EventComponent(_kiwi.app.controlbox);\r
131 var funcs = {\r
d63a5832 132 run: 'processInput', addPluginIcon: 'addPluginIcon'\r
161b5673
D
133 };\r
134\r
135 _.each(funcs, function(controlbox_fn, func_name) {\r
136 obj[func_name] = function() {\r
137 var fn_name = controlbox_fn;\r
138 return _kiwi.app.controlbox[fn_name].apply(_kiwi.app.controlbox, arguments);\r
139 };\r
140 });\r
141\r
142 return obj;\r
143 }\r
144 },\r
145\r
146 // Entry point to start the kiwi application\r
6b8fbed0 147 init: function (opts, callback) {\r
c3d988bc 148 var jobs, locale, localeLoaded, textThemeLoaded, text_theme;\r
161b5673 149 opts = opts || {};\r
b62c8381 150\r
1e9f97d6
D
151 this.initUtils();\r
152\r
28990b2a 153 jobs = new JobManager();\r
c3d988bc 154 jobs.onFinish(function(locale, s, xhr) {\r
161b5673 155 _kiwi.app = new _kiwi.model.Application(opts);\r
0fa2ca42 156\r
161b5673 157 // Start the client up\r
6b8fbed0 158 _kiwi.app.initializeInterfaces();\r
62c18d2d 159\r
2a89ba11
D
160 // Event emitter to let plugins interface with parts of kiwi\r
161 _kiwi.global.events = new PluginInterface();\r
162\r
f66c4823
D
163 // Now everything has started up, load the plugin manager for third party plugins\r
164 _kiwi.global.plugins = new _kiwi.model.PluginManager();\r
165\r
c3d988bc
D
166 callback();\r
167 });\r
28990b2a 168\r
c3d988bc
D
169 textThemeLoaded = function(text_theme, s, xhr) {\r
170 opts.text_theme = text_theme;\r
28990b2a
D
171\r
172 jobs.finishJob('load_text_theme');\r
173 };\r
0fa2ca42 174\r
c3d988bc
D
175 localeLoaded = function(locale, s, xhr) {\r
176 if (locale) {\r
177 _kiwi.global.i18n = new Jed(locale);\r
178 } else {\r
179 _kiwi.global.i18n = new Jed();\r
180 }\r
181\r
182 jobs.finishJob('load_locale');\r
183 };\r
184\r
f66c4823
D
185 // Set up the settings datastore\r
186 _kiwi.global.settings = _kiwi.model.DataStore.instance('kiwi.settings');\r
187 _kiwi.global.settings.load();\r
188\r
d26a40c6 189 // Set the window title\r
2df39a5c 190 window.document.title = opts.server_settings.client.window_title || 'Kiwi IRC';\r
d26a40c6 191\r
28990b2a 192 jobs.registerJob('load_locale');\r
19c790f1 193 locale = _kiwi.global.settings.get('locale');\r
0fa2ca42 194 if (!locale) {\r
c3d988bc 195 $.getJSON(opts.base_path + '/assets/locales/magic.json', localeLoaded);\r
0fa2ca42 196 } else {\r
c3d988bc 197 $.getJSON(opts.base_path + '/assets/locales/' + locale + '.json', localeLoaded);\r
0fa2ca42 198 }\r
d2cf53f5 199\r
28990b2a 200 jobs.registerJob('load_text_theme');\r
3a146f27
D
201 text_theme = opts.server_settings.client.settings.text_theme || 'default';\r
202 $.getJSON(opts.base_path + '/assets/text_themes/' + text_theme + '.json', textThemeLoaded);\r
6b8fbed0
D
203 },\r
204\r
205 start: function() {\r
206 _kiwi.app.showStartup();\r
207 },\r
208\r
209 // Allow plugins to change the startup applet\r
210 registerStartupApplet: function(startup_applet_name) {\r
211 _kiwi.app.startup_applet_name = startup_applet_name;\r
e537d683
D
212 },\r
213\r
214 /**\r
215 * Open a new IRC connection\r
216 * @param {Object} connection_details {nick, host, port, ssl, password, options}\r
217 * @param {Function} callback function(err, network){}\r
218 */\r
219 newIrcConnection: function(connection_details, callback) {\r
220 _kiwi.gateway.newConnection(connection_details, callback);\r
d0734219
D
221 },\r
222\r
223\r
224 /**\r
225 * Taking settings from the server and URL, extract the default server/channel/nick settings\r
226 */\r
227 defaultServerSettings: function () {\r
228 var parts;\r
229 var defaults = {\r
230 nick: '',\r
231 server: '',\r
232 port: 6667,\r
233 ssl: false,\r
234 channel: '',\r
235 channel_key: ''\r
236 };\r
237 var uricheck;\r
238\r
239\r
240 /**\r
241 * Get any settings set by the server\r
242 * These settings may be changed in the server selection dialog or via URL parameters\r
243 */\r
244 if (_kiwi.app.server_settings.client) {\r
245 if (_kiwi.app.server_settings.client.nick)\r
246 defaults.nick = _kiwi.app.server_settings.client.nick;\r
247\r
248 if (_kiwi.app.server_settings.client.server)\r
249 defaults.server = _kiwi.app.server_settings.client.server;\r
250\r
251 if (_kiwi.app.server_settings.client.port)\r
252 defaults.port = _kiwi.app.server_settings.client.port;\r
253\r
254 if (_kiwi.app.server_settings.client.ssl)\r
255 defaults.ssl = _kiwi.app.server_settings.client.ssl;\r
256\r
257 if (_kiwi.app.server_settings.client.channel)\r
258 defaults.channel = _kiwi.app.server_settings.client.channel;\r
259\r
260 if (_kiwi.app.server_settings.client.channel_key)\r
261 defaults.channel_key = _kiwi.app.server_settings.client.channel_key;\r
262 }\r
263\r
264\r
265\r
266 /**\r
267 * Get any settings passed in the URL\r
268 * These settings may be changed in the server selection dialog\r
269 */\r
270\r
271 // Any query parameters first\r
272 if (getQueryVariable('nick'))\r
273 defaults.nick = getQueryVariable('nick');\r
274\r
275 if (window.location.hash)\r
276 defaults.channel = window.location.hash;\r
277\r
278\r
279 // Process the URL part by part, extracting as we go\r
280 parts = window.location.pathname.toString().replace(_kiwi.app.get('base_path'), '').split('/');\r
281\r
282 if (parts.length > 0) {\r
283 parts.shift();\r
284\r
285 if (parts.length > 0 && parts[0]) {\r
286 // 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.\r
287 uricheck = parts[0].substr(0, 7).toLowerCase();\r
288 if ((uricheck === 'ircs%3a') || (uricheck.substr(0,6) === 'irc%3a')) {\r
289 parts[0] = decodeURIComponent(parts[0]);\r
290 // irc[s]://<host>[:<port>]/[<channel>[?<password>]]\r
291 uricheck = /^irc(s)?:(?:\/\/?)?([^:\/]+)(?::([0-9]+))?(?:(?:\/)([^\?]*)(?:(?:\?)(.*))?)?$/.exec(parts[0]);\r
292 /*\r
293 uricheck[1] = ssl (optional)\r
294 uricheck[2] = host\r
295 uricheck[3] = port (optional)\r
296 uricheck[4] = channel (optional)\r
297 uricheck[5] = channel key (optional, channel must also be set)\r
298 */\r
299 if (uricheck) {\r
300 if (typeof uricheck[1] !== 'undefined') {\r
301 defaults.ssl = true;\r
302 if (defaults.port === 6667) {\r
303 defaults.port = 6697;\r
304 }\r
305 }\r
306 defaults.server = uricheck[2];\r
307 if (typeof uricheck[3] !== 'undefined') {\r
308 defaults.port = uricheck[3];\r
309 }\r
310 if (typeof uricheck[4] !== 'undefined') {\r
311 defaults.channel = '#' + uricheck[4];\r
312 if (typeof uricheck[5] !== 'undefined') {\r
313 defaults.channel_key = uricheck[5];\r
314 }\r
315 }\r
316 }\r
317 parts = [];\r
318 } else {\r
319 // Extract the port+ssl if we find one\r
320 if (parts[0].search(/:/) > 0) {\r
321 defaults.port = parts[0].substring(parts[0].search(/:/) + 1);\r
322 defaults.server = parts[0].substring(0, parts[0].search(/:/));\r
323 if (defaults.port[0] === '+') {\r
324 defaults.port = parseInt(defaults.port.substring(1), 10);\r
325 defaults.ssl = true;\r
326 } else {\r
327 defaults.ssl = false;\r
328 }\r
329\r
330 } else {\r
331 defaults.server = parts[0];\r
332 }\r
333\r
334 parts.shift();\r
335 }\r
336 }\r
337\r
338 if (parts.length > 0 && parts[0]) {\r
339 defaults.channel = '#' + parts[0];\r
340 parts.shift();\r
341 }\r
342 }\r
343\r
344 // If any settings have been given by the server.. override any auto detected settings\r
345 /**\r
346 * Get any server restrictions as set in the server config\r
347 * These settings can not be changed in the server selection dialog\r
348 */\r
349 if (_kiwi.app.server_settings && _kiwi.app.server_settings.connection) {\r
350 if (_kiwi.app.server_settings.connection.server) {\r
351 defaults.server = _kiwi.app.server_settings.connection.server;\r
352 }\r
353\r
354 if (_kiwi.app.server_settings.connection.port) {\r
355 defaults.port = _kiwi.app.server_settings.connection.port;\r
356 }\r
357\r
358 if (_kiwi.app.server_settings.connection.ssl) {\r
359 defaults.ssl = _kiwi.app.server_settings.connection.ssl;\r
360 }\r
361\r
362 if (_kiwi.app.server_settings.connection.channel) {\r
363 defaults.channel = _kiwi.app.server_settings.connection.channel;\r
364 }\r
365\r
366 if (_kiwi.app.server_settings.connection.channel_key) {\r
367 defaults.channel_key = _kiwi.app.server_settings.connection.channel_key;\r
368 }\r
369\r
370 if (_kiwi.app.server_settings.connection.nick) {\r
371 defaults.nick = _kiwi.app.server_settings.connection.nick;\r
372 }\r
373 }\r
374\r
375 // Set any random numbers if needed\r
376 defaults.nick = defaults.nick.replace('?', Math.floor(Math.random() * 100000).toString());\r
377\r
378 if (getQueryVariable('encoding'))\r
379 defaults.encoding = getQueryVariable('encoding');\r
380\r
381 return defaults;\r
382 },\r
b62c8381
D
383};\r
384\r
385\r
386\r
387// If within a closure, expose the kiwi globals\r
388if (typeof global !== 'undefined') {\r
161b5673 389 global.kiwi = _kiwi.global;\r
eaaf73b0 390} else {\r
161b5673
D
391 // Not within a closure so set a var in the current scope\r
392 var kiwi = _kiwi.global;\r
6636cc9e 393}\r