Merge branch 'development'
[KiwiIRC.git] / client / src / helpers / desktopnotifications.js
CommitLineData
5fb6968e 1_kiwi.utils.notifications = (function () {
99d8d2bf
NF
2 if (!window.Notification) {
3 return {
4 allowed: _.constant(false),
5 requestPermission: _.constant($.Deferred().reject())
6 };
7 }
8
9 var notifications = {
10 /**
11 * Check if desktop notifications have been allowed by the user.
12 *
13 * @returns {?Boolean} `true` - they have been allowed.
14 * `false` - they have been blocked.
15 * `null` - the user hasn't answered yet.
16 */
17 allowed: function () {
18 return Notification.permission === 'granted' ? true
19 : Notification.permission === 'denied' ? false
20 : null;
21 },
22
23 /**
24 * Ask the user their permission to display desktop notifications.
25 * This will return a promise which will be resolved if the user allows notifications, or rejected if they blocked
26 * notifictions or simply closed the dialog. If the user had previously given their preference, the promise will be
27 * immediately resolved or rejected with their previous answer.
28 *
29 * @example
30 * notifications.requestPermission().then(function () { 'allowed' }, function () { 'not allowed' });
31 *
32 * @returns {Promise}
33 */
34 requestPermission: function () {
35 var deferred = $.Deferred();
36 Notification.requestPermission(function (permission) {
37 deferred[(permission === 'granted') ? 'resolve' : 'reject']();
38 });
39 return deferred.promise();
40 },
41
42 /**
43 * Create a new notification. If the user has not yet given permission to display notifications, they will be asked
44 * to confirm first. The notification will show afterwards if they allow it.
45 *
46 * Notifications implement Backbone.Events (so you can use `on` and `off`). They trigger four different events:
47 * - 'click'
48 * - 'close'
49 * - 'error'
50 * - 'show'
51 *
52 * @example
53 * notifications
54 * .create('Cool notification', { icon: 'logo.png' })
55 * .on('click', function () {
56 * window.focus();
57 * })
58 * .closeAfter(5000);
59 *
60 * @param {String} title
61 * @param {Object} options
62 * @param {String=} options.body A string representing an extra content to display within the notification
63 * @param {String=} options.dir The direction of the notification; it can be auto, ltr, or rtl
64 * @param {String=} options.lang Specify the lang used within the notification. This string must be a valid BCP
65 * 47 language tag.
66 * @param {String=} options.tag An ID for a given notification that allows to retrieve, replace or remove it if necessary
67 * @param {String=} options.icon The URL of an image to be used as an icon by the notification
68 * @returns {Notifier}
69 */
70 create: function (title, options) {
71 return new Notifier(title, options);
72 }
73 };
74
75 function Notifier(title, options) {
76 createNotification.call(this, title, options);
77 }
78 _.extend(Notifier.prototype, Backbone.Events, {
79 closed: false,
80 _closeTimeout: null,
81
82 /**
83 * Close the notification after a given number of milliseconds.
84 * @param {Number} timeout
85 * @returns {this}
86 */
87 closeAfter: function (timeout) {
88 if (!this.closed) {
89 if (this.notification) {
90 this._closeTimeout = this._closeTimeout || setTimeout(_.bind(this.close, this), timeout);
91 } else {
92 this.once('show', _.bind(this.closeAfter, this, timeout));
93 }
94 }
95 return this;
96 },
97
98 /**
99 * Close the notification immediately.
100 * @returns {this}
101 */
102 close: function () {
103 if (this.notification && !this.closed) {
104 this.notification.close();
105 this.closed = true;
106 }
107 return this;
108 }
109 });
110
111 function createNotification(title, options) {
112 switch (notifications.allowed()) {
113 case true:
114 this.notification = new Notification(title, options);
115 _.each(['click', 'close', 'error', 'show'], function (eventName) {
116 this.notification['on' + eventName] = _.bind(this.trigger, this, eventName);
117 }, this);
118 break;
119 case null:
120 notifications.requestPermission().done(_.bind(createNotification, this, title, options));
121 break;
122 }
123 }
124
125 return notifications;
126}());