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