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