MDL-30811 output: Add support for session notifications
[moodle.git] / lib / amd / src / notification.js
CommitLineData
9bdcf579
DW
1// This file is part of Moodle - http://moodle.org/
2//
3// Moodle is free software: you can redistribute it and/or modify
4// it under the terms of the GNU General Public License as published by
5// the Free Software Foundation, either version 3 of the License, or
6// (at your option) any later version.
7//
8// Moodle is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
15
16/**
0346323c
AN
17 * A system for displaying notifications to users from the session.
18 *
9bdcf579
DW
19 * Wrapper for the YUI M.core.notification class. Allows us to
20 * use the YUI version in AMD code until it is replaced.
21 *
22 * @module core/notification
23 * @class notification
24 * @package core
25 * @copyright 2015 Damyon Wiese <damyon@moodle.com>
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 * @since 2.9
28 */
0346323c
AN
29define(['core/yui', 'jquery', 'theme_bootstrapbase/bootstrap', 'core/templates', 'core/ajax', 'core/log'],
30function(Y, $, bootstrap, templates, ajax, log) {
31 var notificationModule = {
32 types: {
33 'success': 'core/notification_success',
34 'info': 'core/notification_info',
35 'warning': 'core/notification_warning',
36 'error': 'core/notification_error',
37 },
9bdcf579 38
0346323c
AN
39 fieldName: 'user-notifications',
40
41 fetchNotifications: function() {
42 var promises = ajax.call([{
43 methodname: 'core_fetch_notifications',
44 args: {
45 contextid: notificationModule.contextid
46 }
47 }]);
48
49 promises[0]
50 .done(notificationModule.addNotifications)
51 ;
52
53 },
54
55 addNotifications: function(notifications) {
56 if (!notifications) {
57 notifications = [];
58 }
59
60 $.each(notifications, function(i, notification) {
61 notificationModule.renderNotification(notification.template, notification.variables);
62 });
63 },
64
65 setupTargetRegion: function() {
66 var targetRegion = $('#' + notificationModule.fieldName);
67 if (targetRegion.length) {
68 return;
69 }
70
71 var newRegion = $('<span>').attr('id', notificationModule.fieldName);
72
73 targetRegion = $('#region-main');
74 if (targetRegion.length) {
75 return targetRegion.prepend(newRegion);
76 }
77
78 targetRegion = $('[role="main"]');
79 if (targetRegion.length) {
80 return targetRegion.prepend(newRegion);
81 }
82
83 targetRegion = $('body');
84 return targetRegion.prepend(newRegion);
85 },
86
87 addNotification: function(notification) {
88 var template = notificationModule.types.error;
89
90 notification = $.extend({
91 closebutton: true,
92 announce: true,
93 type: 'error'
94 }, notification);
95
96 if (notification.template) {
97 template = notification.template;
98 delete notification.template;
99 } else if (notification.type){
100 if (typeof notificationModule.types[notification.type] !== 'undefined') {
101 template = notificationModule.types[notification.type];
102 }
103 delete notification.type;
104 }
105
106 return notificationModule.renderNotification(template, notification);
107 },
108
109 renderNotification: function(template, variables) {
110 if (typeof variables.message === 'undefined' || !variables.message) {
111 log.debug('Notification received without content. Skipping.');
112 return;
113 }
114 templates.render(template, variables)
115 .done(function(html) {
116 $('#' + notificationModule.fieldName).prepend(html);
117 })
118 .fail(notificationModule.exception)
119 ;
120 },
9bdcf579 121
9bdcf579
DW
122 alert: function(title, message, yesLabel) {
123 // Here we are wrapping YUI. This allows us to start transitioning, but
124 // wait for a good alternative without having inconsistent dialogues.
125 Y.use('moodle-core-notification-alert', function () {
126 var alert = new M.core.alert({
127 title : title,
128 message : message,
129 yesLabel: yesLabel
130 });
131
132 alert.show();
133 });
134 },
135
9bdcf579
DW
136 confirm: function(title, question, yesLabel, noLabel, callback) {
137 // Here we are wrapping YUI. This allows us to start transitioning, but
138 // wait for a good alternative without having inconsistent dialogues.
139 Y.use('moodle-core-notification-confirm', function () {
140 var modal = new M.core.confirm({
141 title : title,
142 question : question,
143 yesLabel: yesLabel,
144 noLabel: noLabel
145 });
146
147 modal.on('complete-yes', function() {
148 callback();
149 });
150 modal.show();
151 });
152 },
153
9bdcf579
DW
154 exception: function(ex) {
155 // Fudge some parameters.
156 if (ex.backtrace) {
157 ex.lineNumber = ex.backtrace[0].line;
158 ex.fileName = ex.backtrace[0].file;
159 ex.fileName = '...' + ex.fileName.substr(ex.fileName.length - 20);
160 ex.stack = ex.debuginfo;
161 ex.name = ex.errorcode;
162 }
163 Y.use('moodle-core-notification-exception', function () {
164 var modal = new M.core.exception(ex);
165
166 modal.show();
167 });
168 }
169 };
0346323c
AN
170
171 return /** @alias module:core/notification */{
172 init: function(contextid, notifications) {
173 notificationModule.contextid = contextid;
174
175 // Setup the message target region if it isn't setup already
176 notificationModule.setupTargetRegion();
177
178 // Setup closing of bootstrap alerts.
179 $().alert();
180
181 // Add provided notifications.
182 notificationModule.addNotifications(notifications);
183
184 // Poll for any new notifications.
185 notificationModule.fetchNotifications();
186 },
187
188 /**
189 * Poll the server for any new notifications.
190 *
191 * @method fetchNotifications
192 */
193 fetchNotifications: notificationModule.fetchNotifications,
194
195 /**
196 * Add a notification to the page.
197 *
198 * Note: This does not cause the notification to be added to the session.
199 *
200 * @method addNotification
201 * @param {Object} notification The notification to add.
202 * @param {string} notification.message The body of the notification
203 * @param {string} notification.type The type of notification to add (error, warning, info, success).
204 * @param {Boolean} notification.closebutton Whether to show the close button.
205 * @param {Boolean} notification.announce Whether to announce to screen readers.
206 */
207 addNotification: notificationModule.addNotification,
208
209 /**
210 * Wrap M.core.alert.
211 *
212 * @method alert
213 * @param {string} title
214 * @param {string} message
215 * @param {string} yesLabel
216 */
217 alert: notificationModule.alert,
218
219 /**
220 * Wrap M.core.confirm.
221 *
222 * @method confirm
223 * @param {string} title
224 * @param {string} question
225 * @param {string} yesLabel
226 * @param {string} noLabel
227 * @param {function} callback
228 */
229 confirm: notificationModule.confirm,
230
231 /**
232 * Wrap M.core.exception.
233 *
234 * @method exception
235 * @param {Error} ex
236 */
237 exception: notificationModule.exception
238 };
9bdcf579 239});