Abstract desktop notifications to a class
[KiwiIRC.git] / client / src / views / application.js
CommitLineData
50ac472f
D
1_kiwi.view.Application = Backbone.View.extend({
2 initialize: function () {
3 var that = this;
4
00203b94
D
5 this.$el = $($('#tmpl_application').html().trim());
6 this.el = this.$el[0];
7
8 $(this.model.get('container') || 'body').append(this.$el);
9aa4b87d 9
783fcf1f
D
10 this.elements = {
11 panels: this.$el.find('.panels'),
9936359c 12 right_bar: this.$el.find('.right_bar'),
783fcf1f
D
13 toolbar: this.$el.find('.toolbar'),
14 controlbox: this.$el.find('.controlbox'),
15 resize_handle: this.$el.find('.memberlists_resize_handle')
16 };
17
50ac472f 18 $(window).resize(function() { that.doLayout.apply(that); });
783fcf1f
D
19 this.elements.toolbar.resize(function() { that.doLayout.apply(that); });
20 this.elements.controlbox.resize(function() { that.doLayout.apply(that); });
50ac472f
D
21
22 // Change the theme when the config is changed
23 _kiwi.global.settings.on('change:theme', this.updateTheme, this);
24 this.updateTheme(getQueryVariable('theme'));
25
26 _kiwi.global.settings.on('change:channel_list_style', this.setTabLayout, this);
27 this.setTabLayout(_kiwi.global.settings.get('channel_list_style'));
28
29 _kiwi.global.settings.on('change:show_timestamps', this.displayTimestamps, this);
30 this.displayTimestamps(_kiwi.global.settings.get('show_timestamps'));
31
9aa4b87d 32 this.$el.appendTo($('body'));
50ac472f
D
33 this.doLayout();
34
35 $(document).keydown(this.setKeyFocus);
36
37 // Confirmation require to leave the page
38 window.onbeforeunload = function () {
39 if (_kiwi.gateway.isConnected()) {
247dd7ac 40 return _kiwi.global.i18n.translate('client_views_application_close_notice').fetch();
50ac472f
D
41 }
42 };
43
ee2f0962
D
44 // Keep tabs on the browser having focus
45 this.has_focus = true;
46
c012a0e5 47 $(window).on('focus', function windowOnFocus() {
ee2f0962
D
48 that.has_focus = true;
49 });
c93febfc 50
c012a0e5 51 $(window).on('blur', function windowOnBlur() {
c93febfc
D
52 var active_panel = that.model.panels().active;
53 if (active_panel && active_panel.view.updateLastSeenMarker) {
8859068c 54 active_panel.view.updateLastSeenMarker();
63b21ebe 55 }
c93febfc 56
ee2f0962
D
57 that.has_focus = false;
58 });
59
c012a0e5
D
60 // If we get a touchstart event, make note of it so we know we're using a touchscreen
61 $(window).on('touchstart', function windowOnTouchstart() {
62 that.$el.addClass('touch');
63 $(window).off('touchstart', windowOnTouchstart);
64 });
65
ee2f0962 66
0b7949de 67 this.favicon = new _kiwi.view.Favicon();
50ac472f 68 this.initSound();
68c7f7c0
CC
69
70 this.monitorPanelFallback();
50ac472f
D
71 },
72
73
74
75 updateTheme: function (theme_name) {
76 // If called by the settings callback, get the correct new_value
77 if (theme_name === _kiwi.global.settings) {
78 theme_name = arguments[1];
79 }
80
81 // If we have no theme specified, get it from the settings
05934d33
JA
82 if (!theme_name) theme_name = _kiwi.global.settings.get('theme') || 'relaxed';
83
84 theme_name = theme_name.toLowerCase();
50ac472f
D
85
86 // Clear any current theme
f80d5a6b 87 $('[data-theme]:not([disabled])').each(function (idx, link) {
05934d33 88 var $link = $(link);
15dc5f90 89 $link.attr('rel', 'alternate ' + $link.attr('rel')).attr('disabled', true)[0].disabled = true;
50ac472f
D
90 });
91
92 // Apply the new theme
f80d5a6b 93 var link = $('[data-theme][title=' + theme_name + ']');
05934d33 94 if (link.length > 0) {
15dc5f90 95 link.attr('rel', 'stylesheet').attr('disabled', false)[0].disabled = false;
05934d33 96 }
f7c668a5
D
97
98 this.doLayout();
50ac472f
D
99 },
100
101
102 setTabLayout: function (layout_style) {
103 // If called by the settings callback, get the correct new_value
104 if (layout_style === _kiwi.global.settings) {
105 layout_style = arguments[1];
106 }
ee2f0962 107
50ac472f
D
108 if (layout_style == 'list') {
109 this.$el.addClass('chanlist_treeview');
110 } else {
111 this.$el.removeClass('chanlist_treeview');
112 }
ee2f0962 113
50ac472f
D
114 this.doLayout();
115 },
116
117
118 displayTimestamps: function (show_timestamps) {
119 // If called by the settings callback, get the correct new_value
120 if (show_timestamps === _kiwi.global.settings) {
121 show_timestamps = arguments[1];
122 }
123
124 if (show_timestamps) {
125 this.$el.addClass('timestamps');
126 } else {
127 this.$el.removeClass('timestamps');
128 }
129 },
130
131
132 // Globally shift focus to the command input box on a keypress
133 setKeyFocus: function (ev) {
134 // If we're copying text, don't shift focus
135 if (ev.ctrlKey || ev.altKey || ev.metaKey) {
136 return;
137 }
138
139 // If we're typing into an input box somewhere, ignore
140 if ((ev.target.tagName.toLowerCase() === 'input') || (ev.target.tagName.toLowerCase() === 'textarea') || $(ev.target).attr('contenteditable')) {
141 return;
142 }
143
144 $('#kiwi .controlbox .inp').focus();
145 },
146
147
148 doLayout: function () {
89aa6dc0
D
149 var $kiwi = this.$el;
150 var $panels = this.elements.panels;
151 var $right_bar = this.elements.right_bar;
152 var $toolbar = this.elements.toolbar;
153 var $controlbox = this.elements.controlbox;
154 var $resize_handle = this.elements.resize_handle;
155
156 if (!$kiwi.is(':visible')) {
9aa4b87d
D
157 return;
158 }
159
50ac472f 160 var css_heights = {
89aa6dc0
D
161 top: $toolbar.outerHeight(true),
162 bottom: $controlbox.outerHeight(true)
50ac472f
D
163 };
164
165
166 // If any elements are not visible, full size the panals instead
89aa6dc0 167 if (!$toolbar.is(':visible')) {
50ac472f
D
168 css_heights.top = 0;
169 }
170
89aa6dc0 171 if (!$controlbox.is(':visible')) {
50ac472f
D
172 css_heights.bottom = 0;
173 }
174
175 // Apply the CSS sizes
89aa6dc0
D
176 $panels.css(css_heights);
177 $right_bar.css(css_heights);
178 $resize_handle.css(css_heights);
50ac472f
D
179
180 // If we have channel tabs on the side, adjust the height
89aa6dc0
D
181 if ($kiwi.hasClass('chanlist_treeview')) {
182 this.$el.find('.tabs', $kiwi).css(css_heights);
50ac472f
D
183 }
184
185 // Determine if we have a narrow window (mobile/tablet/or even small desktop window)
89aa6dc0
D
186 if ($kiwi.outerWidth() < 420) {
187 $kiwi.addClass('narrow');
95d37c14
D
188 if (this.model.rightbar && this.model.rightbar.keep_hidden !== true)
189 this.model.rightbar.toggle(true);
50ac472f 190 } else {
89aa6dc0 191 $kiwi.removeClass('narrow');
95d37c14
D
192 if (this.model.rightbar && this.model.rightbar.keep_hidden !== false)
193 this.model.rightbar.toggle(false);
50ac472f
D
194 }
195
196 // Set the panels width depending on the memberlist visibility
89aa6dc0 197 if (!$right_bar.hasClass('disabled')) {
50ac472f 198 // Panels to the side of the memberlist
89aa6dc0 199 $panels.css('right', $right_bar.outerWidth(true));
50ac472f 200 // The resize handle sits overlapping the panels and memberlist
89aa6dc0 201 $resize_handle.css('left', $right_bar.position().left - ($resize_handle.outerWidth(true) / 2));
50ac472f
D
202 } else {
203 // Memberlist is hidden so panels to the right edge
89aa6dc0 204 $panels.css('right', 0);
50ac472f 205 // And move the handle just out of sight to the right
89aa6dc0 206 $resize_handle.css('left', $panels.outerWidth(true));
50ac472f
D
207 }
208
2fe671c0 209 var input_wrap_width = parseInt($controlbox.find('.input_tools').outerWidth(), 10);
89aa6dc0 210 $controlbox.find('.input_wrap').css('right', input_wrap_width + 7);
50ac472f
D
211 },
212
213
214 alertWindow: function (title) {
215 if (!this.alertWindowTimer) {
216 this.alertWindowTimer = new (function () {
217 var that = this;
218 var tmr;
219 var has_focus = true;
220 var state = 0;
73b7cc44 221 var default_title = _kiwi.app.server_settings.client.window_title || 'Kiwi IRC';
50ac472f
D
222 var title = 'Kiwi IRC';
223
224 this.setTitle = function (new_title) {
225 new_title = new_title || default_title;
226 window.document.title = new_title;
227 return new_title;
228 };
229
230 this.start = function (new_title) {
231 // Don't alert if we already have focus
232 if (has_focus) return;
233
234 title = new_title;
235 if (tmr) return;
236 tmr = setInterval(this.update, 1000);
237 };
238
239 this.stop = function () {
240 // Stop the timer and clear the title
241 if (tmr) clearInterval(tmr);
242 tmr = null;
243 this.setTitle();
244
245 // Some browsers don't always update the last title correctly
246 // Wait a few seconds and then reset
247 setTimeout(this.reset, 2000);
248 };
249
250 this.reset = function () {
251 if (tmr) return;
252 that.setTitle();
253 };
254
255
256 this.update = function () {
257 if (state === 0) {
258 that.setTitle(title);
259 state = 1;
260 } else {
261 that.setTitle();
262 state = 0;
263 }
264 };
265
266 $(window).focus(function (event) {
267 has_focus = true;
268 that.stop();
269
270 // Some browsers don't always update the last title correctly
271 // Wait a few seconds and then reset
272 setTimeout(that.reset, 2000);
273 });
274
275 $(window).blur(function (event) {
276 has_focus = false;
277 });
278 })();
279 }
280
281 this.alertWindowTimer.start(title);
282 },
283
284
285 barsHide: function (instant) {
286 var that = this;
287
288 if (!instant) {
289 this.$el.find('.toolbar').slideUp({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});
290 $('#kiwi .controlbox').slideUp({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});
291 } else {
292 this.$el.find('.toolbar').slideUp(0);
293 $('#kiwi .controlbox').slideUp(0);
294 this.doLayout();
295 }
296 },
297
298 barsShow: function (instant) {
299 var that = this;
300
301 if (!instant) {
302 this.$el.find('.toolbar').slideDown({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});
303 $('#kiwi .controlbox').slideDown({queue: false, duration: 400, step: $.proxy(this.doLayout, this)});
304 } else {
305 this.$el.find('.toolbar').slideDown(0);
306 $('#kiwi .controlbox').slideDown(0);
307 this.doLayout();
308 }
309 },
310
311
312 initSound: function () {
313 var that = this,
314 base_path = this.model.get('base_path');
315
316 $script(base_path + '/assets/libs/soundmanager2/soundmanager2-nodebug-jsmin.js', function() {
317 if (typeof soundManager === 'undefined')
318 return;
319
320 soundManager.setup({
321 url: base_path + '/assets/libs/soundmanager2/',
322 flashVersion: 9, // optional: shiny features (default = 8)// optional: ignore Flash where possible, use 100% HTML5 mode
323 preferFlash: true,
324
325 onready: function() {
326 that.sound_object = soundManager.createSound({
327 id: 'highlight',
328 url: base_path + '/assets/sound/highlight.mp3'
329 });
330 }
331 });
332 });
333 },
334
335
336 playSound: function (sound_id) {
337 if (!this.sound_object) return;
338
339 if (_kiwi.global.settings.get('mute_sounds'))
340 return;
ee2f0962 341
50ac472f 342 soundManager.play(sound_id);
d70c63d4
K
343 },
344
ee2f0962
D
345
346 showNotification: function(title, message) {
98bc1a84 347 var icon = this.model.get('base_path') + '/assets/img/ico.png',
99d8d2bf 348 notifications = _kiwi.global.utils.notifications;
ee2f0962 349
99d8d2bf
NF
350 if (!this.has_focus && notifications.allowed()) {
351 notifications
352 .create(title, { icon: icon, body: message })
353 .closeAfter(5000)
354 .on('click', _.bind(window.focus, window));
ee2f0962 355 }
68c7f7c0
CC
356 },
357
358 monitorPanelFallback: function() {
359 var panel_access = [];
360
361 this.model.panels.on('active', function() {
362 var panel = _kiwi.app.panels().active,
363 panel_index;
364
365 // If the panel is already open, remove it so we can put it back in first place
366 panel_index = _.indexOf(panel_access, panel.cid);
367
368 if (panel_index > -1) {
369 panel_access.splice(panel_index, 1);
370 }
371
372 //Make this panel the most recently accessed
373 panel_access.unshift(panel.cid);
374 });
2fe671c0 375
d1925bdf
CC
376 this.model.panels.on('remove', function(panel) {
377 // If closing the active panel, switch to the last-accessed panel
378 if (panel_access[0] === panel.cid) {
379 panel_access.shift();
380
381 //Get the last-accessed panel model now that we removed the closed one
382 var model = _.find(_kiwi.app.panels('applets').concat(_kiwi.app.panels('connections')), {cid: panel_access[0]});
383
384 if (model) {
385 model.view.show();
386 }
387 }
388 });
50ac472f 389 }
d70c63d4 390});