1 // Holds anything kiwi client specific (ie. front, gateway, _kiwi.plugs..)
14 * A global container for third party access
15 * Will be used to access a limited subset of kiwi functionality
16 * and data (think: plugins)
19 build_version
: '', // Kiwi IRC version this is built from (Set from index.html)
20 settings
: undefined, // Instance of _kiwi.model.DataStore
21 plugins
: undefined, // Instance of _kiwi.model.PluginManager
22 events
: undefined, // Instance of PluginInterface
23 utils
: {}, // References to misc. re-usable helpers / functions
25 initUtils: function() {
26 this.utils
.randomString
= randomString
;
27 this.utils
.secondsToTime
= secondsToTime
;
28 this.utils
.parseISO8601
= parseISO8601
;
29 this.utils
.escapeRegex
= escapeRegex
;
30 this.utils
.formatIRCMsg
= formatIRCMsg
;
31 this.utils
.styleText
= styleText
;
32 this.utils
.hsl2rgb
= hsl2rgb
;
36 if (!_kiwi
.gateway
.rpc
) {
37 throw 'RPC unavailable. Is Kiwi connected to the server yet?';
40 return _kiwi
.gateway
.rpc
.apply(_kiwi
.gateway
.rpc
, arguments
);
43 rpcNamespace: function(namespace) {
44 if (!_kiwi
.gateway
.rpc
) {
45 throw 'RPC unavailable. Is Kiwi connected to the server yet?';
48 return _kiwi
.gateway
.rpc
.namespace(namespace);
51 addMediaMessageType: function(match
, buildHtml
) {
52 _kiwi
.view
.MediaMessage
.addType(match
, buildHtml
);
55 // Event managers for plugins
57 EventComponent: function(event_source
, proxy_event_name
) {
59 * proxyEvent() listens for events then re-triggers them on its own
60 * event emitter. Why? So we can .off() on this emitter without
61 * effecting the source of events. Handy for plugins that we don't
62 * trust meddling with the core events.
64 * If listening for 'all' events the arguments are as follows:
65 * 1. Name of the triggered event
67 * For all other events, we only have one argument:
70 * When this is used via `new kiwi.components.Network()`, this listens
71 * for 'all' events so the first argument is the event name which is
72 * the connection ID. We don't want to re-trigger this event name so
73 * we need to juggle the arguments to find the real event name we want
76 function proxyEvent(event_name
, event_data
) {
77 if (proxy_event_name
== 'all') {
79 event_data
= event_name
.event_data
;
80 event_name
= event_name
.event_name
;
83 this.trigger(event_name
, event_data
);
86 // The event we are to proxy
87 proxy_event_name
= proxy_event_name
|| 'all';
89 _
.extend(this, Backbone
.Events
);
90 this._source
= event_source
;
92 // Proxy the events to this dispatcher
93 event_source
.on(proxy_event_name
, proxyEvent
, this);
95 // Clean up this object
96 this.dispose = function () {
97 event_source
.off(proxy_event_name
, proxyEvent
);
99 delete this.event_source
;
103 Network: function(connection_id
) {
104 var connection_event
;
106 // If no connection id given, use all connections
107 if (typeof connection_id
!== 'undefined') {
108 connection_event
= 'connection:' + connection_id
.toString();
110 connection_event
= 'connection';
113 // Helper to get the network object
114 var getNetwork = function() {
115 var network
= typeof connection_id
=== 'undefined' ?
116 _kiwi
.app
.connections
.active_connection
:
117 _kiwi
.app
.connections
.getByConnectionId(connection_id
);
124 // Create the return object (events proxy from the gateway)
125 var obj
= new this.EventComponent(_kiwi
.gateway
, connection_event
);
127 // Proxy several gateway functions onto the return object
129 kiwi
: 'kiwi', raw
: 'raw', kick
: 'kick', topic
: 'topic',
130 part
: 'part', join
: 'join', action
: 'action', ctcp
: 'ctcp',
131 ctcpRequest
: 'ctcpRequest', ctcpResponse
: 'ctcpResponse',
132 notice
: 'notice', msg
: 'privmsg', changeNick
: 'changeNick',
133 channelInfo
: 'channelInfo', mode
: 'mode', quit
: 'quit'
136 _
.each(funcs
, function(gateway_fn
, func_name
) {
137 obj
[func_name
] = function() {
138 var fn_name
= gateway_fn
;
140 // Add connection_id to the argument list
141 var args
= Array
.prototype.slice
.call(arguments
, 0);
142 args
.unshift(connection_id
);
144 // Call the gateway function on behalf of this connection
145 return _kiwi
.gateway
[fn_name
].apply(_kiwi
.gateway
, args
);
149 // Add the networks getters/setters
150 obj
.get = function(name
) {
151 var network
, restricted_keys
;
153 network
= getNetwork();
161 if (restricted_keys
.indexOf(name
) > -1) {
165 return network
.get(name
);
168 obj
.set = function() {
169 var network
= getNetwork();
174 return network
.set.apply(network
, arguments
);
180 ControlInput: function() {
181 var obj
= new this.EventComponent(_kiwi
.app
.controlbox
);
183 run
: 'processInput', addPluginIcon
: 'addPluginIcon'
186 _
.each(funcs
, function(controlbox_fn
, func_name
) {
187 obj
[func_name
] = function() {
188 var fn_name
= controlbox_fn
;
189 return _kiwi
.app
.controlbox
[fn_name
].apply(_kiwi
.app
.controlbox
, arguments
);
197 // Entry point to start the kiwi application
198 init: function (opts
, callback
) {
199 var jobs
, locale
, localeLoaded
, textThemeLoaded
, text_theme
;
204 jobs
= new JobManager();
205 jobs
.onFinish(function(locale
, s
, xhr
) {
206 _kiwi
.app
= new _kiwi
.model
.Application(opts
);
208 // Start the client up
209 _kiwi
.app
.initializeInterfaces();
211 // Event emitter to let plugins interface with parts of kiwi
212 _kiwi
.global
.events
= new PluginInterface();
214 // Now everything has started up, load the plugin manager for third party plugins
215 _kiwi
.global
.plugins
= new _kiwi
.model
.PluginManager();
220 textThemeLoaded = function(text_theme
, s
, xhr
) {
221 opts
.text_theme
= text_theme
;
223 jobs
.finishJob('load_text_theme');
226 localeLoaded = function(locale
, s
, xhr
) {
228 _kiwi
.global
.i18n
= new Jed(locale
);
230 _kiwi
.global
.i18n
= new Jed();
233 jobs
.finishJob('load_locale');
236 // Set up the settings datastore
237 _kiwi
.global
.settings
= _kiwi
.model
.DataStore
.instance('kiwi.settings');
238 _kiwi
.global
.settings
.load();
240 // Set the window title
241 window
.document
.title
= opts
.server_settings
.client
.window_title
|| 'Kiwi IRC';
243 jobs
.registerJob('load_locale');
244 locale
= _kiwi
.global
.settings
.get('locale');
246 $.getJSON(opts
.base_path
+ '/assets/locales/magic.json', localeLoaded
);
248 $.getJSON(opts
.base_path
+ '/assets/locales/' + locale
+ '.json', localeLoaded
);
251 jobs
.registerJob('load_text_theme');
252 text_theme
= opts
.server_settings
.client
.settings
.text_theme
|| 'default';
253 $.getJSON(opts
.base_path
+ '/assets/text_themes/' + text_theme
+ '.json', textThemeLoaded
);
257 _kiwi
.app
.showStartup();
260 // Allow plugins to change the startup applet
261 registerStartupApplet: function(startup_applet_name
) {
262 _kiwi
.app
.startup_applet_name
= startup_applet_name
;
266 * Open a new IRC connection
267 * @param {Object} connection_details {nick, host, port, ssl, password, options}
268 * @param {Function} callback function(err, network){}
270 newIrcConnection: function(connection_details
, callback
) {
271 _kiwi
.gateway
.newConnection(connection_details
, callback
);
276 * Taking settings from the server and URL, extract the default server/channel/nick settings
278 defaultServerSettings: function () {
292 * Get any settings set by the server
293 * These settings may be changed in the server selection dialog or via URL parameters
295 if (_kiwi
.app
.server_settings
.client
) {
296 if (_kiwi
.app
.server_settings
.client
.nick
)
297 defaults
.nick
= _kiwi
.app
.server_settings
.client
.nick
;
299 if (_kiwi
.app
.server_settings
.client
.server
)
300 defaults
.server
= _kiwi
.app
.server_settings
.client
.server
;
302 if (_kiwi
.app
.server_settings
.client
.port
)
303 defaults
.port
= _kiwi
.app
.server_settings
.client
.port
;
305 if (_kiwi
.app
.server_settings
.client
.ssl
)
306 defaults
.ssl
= _kiwi
.app
.server_settings
.client
.ssl
;
308 if (_kiwi
.app
.server_settings
.client
.channel
)
309 defaults
.channel
= _kiwi
.app
.server_settings
.client
.channel
;
311 if (_kiwi
.app
.server_settings
.client
.channel_key
)
312 defaults
.channel_key
= _kiwi
.app
.server_settings
.client
.channel_key
;
318 * Get any settings passed in the URL
319 * These settings may be changed in the server selection dialog
322 // Any query parameters first
323 if (getQueryVariable('nick'))
324 defaults
.nick
= getQueryVariable('nick');
326 if (window
.location
.hash
)
327 defaults
.channel
= window
.location
.hash
;
330 // Process the URL part by part, extracting as we go
331 parts
= window
.location
.pathname
.toString().replace(_kiwi
.app
.get('base_path'), '').split('/');
333 if (parts
.length
> 0) {
336 if (parts
.length
> 0 && parts
[0]) {
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.
338 uricheck
= parts
[0].substr(0, 7).toLowerCase();
339 if ((uricheck
=== 'ircs%3a') || (uricheck
.substr(0,6) === 'irc%3a')) {
340 parts
[0] = decodeURIComponent(parts
[0]);
341 // irc[s]://<host>[:<port>]/[<channel>[?<password>]]
342 uricheck
= /^irc(s)?:(?:\/\/?)?([^:\/]+)(?::([0-9]+))?(?:(?:\/)([^\?]*)(?:(?:\?)(.*))?)?$/.exec(parts
[0]);
344 uricheck[1] = ssl (optional)
346 uricheck[3] = port (optional)
347 uricheck[4] = channel (optional)
348 uricheck[5] = channel key (optional, channel must also be set)
351 if (typeof uricheck
[1] !== 'undefined') {
353 if (defaults
.port
=== 6667) {
354 defaults
.port
= 6697;
357 defaults
.server
= uricheck
[2];
358 if (typeof uricheck
[3] !== 'undefined') {
359 defaults
.port
= uricheck
[3];
361 if (typeof uricheck
[4] !== 'undefined') {
362 defaults
.channel
= '#' + uricheck
[4];
363 if (typeof uricheck
[5] !== 'undefined') {
364 defaults
.channel_key
= uricheck
[5];
370 // Extract the port+ssl if we find one
371 if (parts
[0].search(/:/) > 0) {
372 defaults
.port
= parts
[0].substring(parts
[0].search(/:/) + 1);
373 defaults
.server
= parts
[0].substring(0, parts
[0].search(/:/));
374 if (defaults
.port
[0] === '+') {
375 defaults
.port
= parseInt(defaults
.port
.substring(1), 10);
378 defaults
.ssl
= false;
382 defaults
.server
= parts
[0];
389 if (parts
.length
> 0 && parts
[0]) {
390 defaults
.channel
= '#' + parts
[0];
395 // If any settings have been given by the server.. override any auto detected settings
397 * Get any server restrictions as set in the server config
398 * These settings can not be changed in the server selection dialog
400 if (_kiwi
.app
.server_settings
&& _kiwi
.app
.server_settings
.connection
) {
401 if (_kiwi
.app
.server_settings
.connection
.server
) {
402 defaults
.server
= _kiwi
.app
.server_settings
.connection
.server
;
405 if (_kiwi
.app
.server_settings
.connection
.port
) {
406 defaults
.port
= _kiwi
.app
.server_settings
.connection
.port
;
409 if (_kiwi
.app
.server_settings
.connection
.ssl
) {
410 defaults
.ssl
= _kiwi
.app
.server_settings
.connection
.ssl
;
413 if (_kiwi
.app
.server_settings
.connection
.channel
) {
414 defaults
.channel
= _kiwi
.app
.server_settings
.connection
.channel
;
417 if (_kiwi
.app
.server_settings
.connection
.channel_key
) {
418 defaults
.channel_key
= _kiwi
.app
.server_settings
.connection
.channel_key
;
421 if (_kiwi
.app
.server_settings
.connection
.nick
) {
422 defaults
.nick
= _kiwi
.app
.server_settings
.connection
.nick
;
426 // Set any random numbers if needed
427 defaults
.nick
= defaults
.nick
.replace('?', Math
.floor(Math
.random() * 100000).toString());
429 if (getQueryVariable('encoding'))
430 defaults
.encoding
= getQueryVariable('encoding');
438 // If within a closure, expose the kiwi globals
439 if (typeof global
!== 'undefined') {
440 global
.kiwi
= _kiwi
.global
;
442 // Not within a closure so set a var in the current scope
443 var kiwi
= _kiwi
.global
;