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