MDL-37526 Fix lint issues in moodle-core-notification
[moodle.git] / lib / yui / notification / notification.js
1 YUI.add('moodle-core-notification', function(Y) {
3 var DIALOGUE_NAME = 'Moodle dialogue',
4     DIALOGUE_PREFIX = 'moodle-dialogue',
5     CONFIRM_NAME = 'Moodle confirmation dialogue',
6     EXCEPTION_NAME = 'Moodle exception',
7     AJAXEXCEPTION_NAME = 'Moodle AJAX exception',
8     ALERT_NAME = 'Moodle alert',
9     C = Y.Node.create,
10     BASE = 'notificationBase',
11     COUNT = 0,
12     CONFIRMYES = 'yesLabel',
13     CONFIRMNO = 'noLabel',
14     TITLE = 'title',
15     QUESTION = 'question',
16     CSS = {
17         BASE : 'moodle-dialogue-base',
18         WRAP : 'moodle-dialogue-wrap',
19         HEADER : 'moodle-dialogue-hd',
20         BODY : 'moodle-dialogue-bd',
21         CONTENT : 'moodle-dialogue-content',
22         FOOTER : 'moodle-dialogue-ft',
23         HIDDEN : 'hidden',
24         LIGHTBOX : 'moodle-dialogue-lightbox'
25     },
26     EXCEPTION,
27     ALERT,
28     CONFIRM,
29     AJAXEXCEPTION,
30     DIALOGUE;
32 DIALOGUE = function(config) {
33     COUNT++;
34     var id = 'moodle-dialogue-'+COUNT;
35     config.notificationBase =
36         new C('<div class="'+CSS.BASE+'">')
37               .append(new C('<div id="'+id+'" role="dialog" aria-labelledby="'+id+'-header-text" class="'+CSS.WRAP+'"></div>')
38               .append(new C('<div class="'+CSS.HEADER+' yui3-widget-hd"></div>'))
39               .append(new C('<div class="'+CSS.BODY+' yui3-widget-bd"></div>'))
40               .append(new C('<div class="'+CSS.FOOTER+' yui3-widget-ft"></div>')));
41     Y.one(document.body).append(config.notificationBase);
42     config.srcNode =    '#'+id;
43     config.width =      config.width || '400px';
44     config.visible =    config.visible || false;
45     config.center =     config.centered || true;
46     config.centered =   false;
48     // lightbox param to keep the stable versions API.
49     if (config.lightbox !== false) {
50         config.modal = true;
51     }
52     delete config.lightbox;
54     // closeButton param to keep the stable versions API.
55     if (config.closeButton === false) {
56         config.buttons = null;
57     } else {
58         config.buttons = [
59             {
60                 section: Y.WidgetStdMod.HEADER,
61                 classNames: 'closebutton',
62                 action: function (e) {
63                     this.hide();
64                 }
65             }
66         ];
67     }
68     DIALOGUE.superclass.constructor.apply(this, [config]);
70     if (config.closeButton !== false) {
71         // The buttons constructor does not allow custom attributes
72         this.get('buttons').header[0].setAttribute('title', this.get('closeButtonTitle'));
73     }
74 };
75 Y.extend(DIALOGUE, Y.Panel, {
76     initializer : function(config) {
77         this.after('visibleChange', this.visibilityChanged, this);
78         this.render();
79         this.show();
80     },
81     visibilityChanged : function(e) {
82         var titlebar;
83         if (e.attrName === 'visible') {
84             this.get('maskNode').addClass(CSS.LIGHTBOX);
85             if (this.get('center') && !e.prevVal && e.newVal) {
86                 this.centerDialogue();
87             }
88             if (this.get('draggable')) {
89                 titlebar = '#' + this.get('id') + ' .' + CSS.HEADER;
90                 this.plug(Y.Plugin.Drag, {handles : [titlebar]});
91                 Y.one(titlebar).setStyle('cursor', 'move');
92             }
93         }
94     },
95     centerDialogue : function() {
96         var bb = this.get('boundingBox'),
97             hidden = bb.hasClass(DIALOGUE_PREFIX+'-hidden'),
98             x, y;
99         if (hidden) {
100             bb.setStyle('top', '-1000px').removeClass(DIALOGUE_PREFIX+'-hidden');
101         }
102         x = Math.max(Math.round((bb.get('winWidth') - bb.get('offsetWidth'))/2), 15);
103         y = Math.max(Math.round((bb.get('winHeight') - bb.get('offsetHeight'))/2), 15) + Y.one(window).get('scrollTop');
105         if (hidden) {
106             bb.addClass(DIALOGUE_PREFIX+'-hidden');
107         }
108         bb.setStyle('left', x).setStyle('top', y);
109     }
110 }, {
111     NAME : DIALOGUE_NAME,
112     CSS_PREFIX : DIALOGUE_PREFIX,
113     ATTRS : {
114         notificationBase : {
116         },
117         lightbox : {
118             validator : Y.Lang.isBoolean,
119             value : true
120         },
121         closeButton : {
122             validator : Y.Lang.isBoolean,
123             value : true
124         },
125         closeButtonTitle : {
126             validator : Y.Lang.isString,
127             value : 'Close'
128         },
129         center : {
130             validator : Y.Lang.isBoolean,
131             value : true
132         },
133         draggable : {
134             validator : Y.Lang.isBoolean,
135             value : false
136         }
137     }
138 });
140 ALERT = function(config) {
141     config.closeButton = false;
142     ALERT.superclass.constructor.apply(this, [config]);
143 };
144 Y.extend(ALERT, DIALOGUE, {
145     _enterKeypress : null,
146     initializer : function() {
147         this.publish('complete');
148         var yes = C('<input type="button" id="id_yuialertconfirm-' + this.COUNT + '" value="'+this.get(CONFIRMYES)+'" />'),
149             content = C('<div class="confirmation-dialogue"></div>')
150                     .append(C('<div class="confirmation-message">'+this.get('message')+'</div>'))
151                     .append(C('<div class="confirmation-buttons"></div>')
152                             .append(yes));
153         this.get(BASE).addClass('moodle-dialogue-confirm');
154         this.setStdModContent(Y.WidgetStdMod.BODY, content, Y.WidgetStdMod.REPLACE);
155         this.setStdModContent(Y.WidgetStdMod.HEADER, '<h1 id="moodle-dialogue-'+COUNT+'-header-text">' + this.get(TITLE) + '</h1>', Y.WidgetStdMod.REPLACE);
156         this.after('destroyedChange', function(){this.get(BASE).remove();}, this);
157         this._enterKeypress = Y.on('key', this.submit, window, 'down:13', this);
158         yes.on('click', this.submit, this);
159     },
160     submit : function() {
161         this._enterKeypress.detach();
162         this.fire('complete');
163         this.hide();
164         this.destroy();
165     }
166 }, {
167     NAME : ALERT_NAME,
168     CSS_PREFIX : DIALOGUE_PREFIX,
169     ATTRS : {
170         title : {
171             validator : Y.Lang.isString,
172             value : 'Alert'
173         },
174         message : {
175             validator : Y.Lang.isString,
176             value : 'Confirm'
177         },
178         yesLabel : {
179             validator : Y.Lang.isString,
180             setter : function(txt) {
181                 if (!txt) {
182                     txt = 'Ok';
183                 }
184                 return txt;
185             },
186             value : 'Ok'
187         }
188     }
189 });
191 CONFIRM = function(config) {
192     CONFIRM.superclass.constructor.apply(this, [config]);
193 };
194 Y.extend(CONFIRM, DIALOGUE, {
195     _enterKeypress : null,
196     _escKeypress : null,
197     initializer : function() {
198         this.publish('complete');
199         this.publish('complete-yes');
200         this.publish('complete-no');
201         var yes = C('<input type="button" id="id_yuiconfirmyes-' + this.COUNT + '" value="'+this.get(CONFIRMYES)+'" />'),
202             no = C('<input type="button" id="id_yuiconfirmno-' + this.COUNT + '" value="'+this.get(CONFIRMNO)+'" />'),
203             content = C('<div class="confirmation-dialogue"></div>')
204                         .append(C('<div class="confirmation-message">'+this.get(QUESTION)+'</div>'))
205                         .append(C('<div class="confirmation-buttons"></div>')
206                             .append(yes)
207                             .append(no));
208         this.get(BASE).addClass('moodle-dialogue-confirm');
209         this.setStdModContent(Y.WidgetStdMod.BODY, content, Y.WidgetStdMod.REPLACE);
210         this.setStdModContent(Y.WidgetStdMod.HEADER, '<h1 id="moodle-dialogue-'+COUNT+'-header-text">' + this.get(TITLE) + '</h1>', Y.WidgetStdMod.REPLACE);
211         this.after('destroyedChange', function(){this.get(BASE).remove();}, this);
212         this._enterKeypress = Y.on('key', this.submit, window, 'down:13', this, true);
213         this._escKeypress = Y.on('key', this.submit, window, 'down:27', this, false);
214         yes.on('click', this.submit, this, true);
215         no.on('click', this.submit, this, false);
216     },
217     submit : function(e, outcome) {
218         this._enterKeypress.detach();
219         this._escKeypress.detach();
220         this.fire('complete', outcome);
221         if (outcome) {
222             this.fire('complete-yes');
223         } else {
224             this.fire('complete-no');
225         }
226         this.hide();
227         this.destroy();
228     }
229 }, {
230     NAME : CONFIRM_NAME,
231     CSS_PREFIX : DIALOGUE_PREFIX,
232     ATTRS : {
233         yesLabel : {
234             validator : Y.Lang.isString,
235             value : 'Yes'
236         },
237         noLabel : {
238             validator : Y.Lang.isString,
239             value : 'No'
240         },
241         title : {
242             validator : Y.Lang.isString,
243             value : 'Confirm'
244         },
245         question : {
246             validator : Y.Lang.isString,
247             value : 'Are you sure?'
248         }
249     }
250 });
251 Y.augment(CONFIRM, Y.EventTarget);
253 EXCEPTION = function(config) {
254     config.width = config.width || (M.cfg.developerdebug)?Math.floor(Y.one(document.body).get('winWidth')/3)+'px':null;
255     config.closeButton = true;
256     EXCEPTION.superclass.constructor.apply(this, [config]);
257 };
258 Y.extend(EXCEPTION, DIALOGUE, {
259     _hideTimeout : null,
260     _keypress : null,
261     initializer : function(config) {
262         var content,
263             self = this,
264             delay = this.get('hideTimeoutDelay');
265         this.get(BASE).addClass('moodle-dialogue-exception');
266         this.setStdModContent(Y.WidgetStdMod.HEADER, '<h1 id="moodle-dialogue-'+COUNT+'-header-text">' + config.name + '</h1>', Y.WidgetStdMod.REPLACE);
267         content = C('<div class="moodle-exception"></div>')
268                 .append(C('<div class="moodle-exception-message">'+this.get('message')+'</div>'))
269                 .append(C('<div class="moodle-exception-param hidden param-filename"><label>File:</label> '+this.get('fileName')+'</div>'))
270                 .append(C('<div class="moodle-exception-param hidden param-linenumber"><label>Line:</label> '+this.get('lineNumber')+'</div>'))
271                 .append(C('<div class="moodle-exception-param hidden param-stacktrace"><label>Stack trace:</label> <pre>'+this.get('stack')+'</pre></div>'));
272         if (M.cfg.developerdebug) {
273             content.all('.moodle-exception-param').removeClass('hidden');
274         }
275         this.setStdModContent(Y.WidgetStdMod.BODY, content, Y.WidgetStdMod.REPLACE);
277         if (delay) {
278             this._hideTimeout = setTimeout(function(){self.hide();}, delay);
279         }
280         this.after('visibleChange', this.visibilityChanged, this);
281         this.after('destroyedChange', function(){this.get(BASE).remove();}, this);
282         this._keypress = Y.on('key', this.hide, window, 'down:13,27', this);
283         this.centerDialogue();
284     },
285     visibilityChanged : function(e) {
286         if (e.attrName === 'visible' && e.prevVal && !e.newVal) {
287             if (this._keypress) {
288                 this._keypress.detach();
289             }
290             var self = this;
291             setTimeout(function(){self.destroy();}, 1000);
292         }
293     }
294 }, {
295     NAME : EXCEPTION_NAME,
296     CSS_PREFIX : DIALOGUE_PREFIX,
297     ATTRS : {
298         message : {
299             value : ''
300         },
301         name : {
302             value : ''
303         },
304         fileName : {
305             value : ''
306         },
307         lineNumber : {
308             value : ''
309         },
310         stack : {
311             setter : function(str) {
312                 var lines = str.split("\n"),
313                     pattern = new RegExp('^(.+)@('+M.cfg.wwwroot+')?(.{0,75}).*:(\\d+)$'),
314                     i;
315                 for (i in lines) {
316                     lines[i] = lines[i].replace(pattern,
317                             "<div class='stacktrace-line'>ln: $4</div><div class='stacktrace-file'>$3</div><div class='stacktrace-call'>$1</div>");
318                 }
319                 return lines.join('');
320             },
321             value : ''
322         },
323         hideTimeoutDelay : {
324             validator : Y.Lang.isNumber,
325             value : null
326         }
327     }
328 });
330 AJAXEXCEPTION = function(config) {
331     config.name = config.name || 'Error';
332     config.closeButton = true;
333     AJAXEXCEPTION.superclass.constructor.apply(this, [config]);
334 };
335 Y.extend(AJAXEXCEPTION, DIALOGUE, {
336     _keypress : null,
337     initializer : function(config) {
338         var content,
339             self = this,
340             delay = this.get('hideTimeoutDelay');
341         this.get(BASE).addClass('moodle-dialogue-exception');
342         this.setStdModContent(Y.WidgetStdMod.HEADER, '<h1 id="moodle-dialogue-'+COUNT+'-header-text">' + config.name + '</h1>', Y.WidgetStdMod.REPLACE);
343         content = C('<div class="moodle-ajaxexception"></div>')
344                 .append(C('<div class="moodle-exception-message">'+this.get('error')+'</div>'))
345                 .append(C('<div class="moodle-exception-param hidden param-debuginfo"><label>URL:</label> '+this.get('reproductionlink')+'</div>'))
346                 .append(C('<div class="moodle-exception-param hidden param-debuginfo"><label>Debug info:</label> '+this.get('debuginfo')+'</div>'))
347                 .append(C('<div class="moodle-exception-param hidden param-stacktrace"><label>Stack trace:</label> <pre>'+this.get('stacktrace')+'</pre></div>'));
348         if (M.cfg.developerdebug) {
349             content.all('.moodle-exception-param').removeClass('hidden');
350         }
351         this.setStdModContent(Y.WidgetStdMod.BODY, content, Y.WidgetStdMod.REPLACE);
353         if (delay) {
354             this._hideTimeout = setTimeout(function(){self.hide();}, delay);
355         }
356         this.after('visibleChange', this.visibilityChanged, this);
357         this._keypress = Y.on('key', this.hide, window, 'down:13, 27', this);
358         this.centerDialogue();
359     },
360     visibilityChanged : function(e) {
361         if (e.attrName === 'visible' && e.prevVal && !e.newVal) {
362             var self = this;
363             this._keypress.detach();
364             setTimeout(function(){self.destroy();}, 1000);
365         }
366     }
367 }, {
368     NAME : AJAXEXCEPTION_NAME,
369     CSS_PREFIX : DIALOGUE_PREFIX,
370     ATTRS : {
371         error : {
372             validator : Y.Lang.isString,
373             value : 'Unknown error'
374         },
375         debuginfo : {
376             value : null
377         },
378         stacktrace : {
379             value : null
380         },
381         reproductionlink : {
382             setter : function(link) {
383                 if (link !== null) {
384                     link = '<a href="'+link+'">'+link.replace(M.cfg.wwwroot, '')+'</a>';
385                 }
386                 return link;
387             },
388             value : null
389         },
390         hideTimeoutDelay : {
391             validator : Y.Lang.isNumber,
392             value : null
393         }
394     }
395 });
397 M.core = M.core || {};
398 M.core.dialogue = DIALOGUE;
399 M.core.alert = ALERT;
400 M.core.confirm = CONFIRM;
401 M.core.exception = EXCEPTION;
402 M.core.ajaxException = AJAXEXCEPTION;
404 }, '@VERSION@', {requires:['base','node','panel','event-key', 'moodle-core-notification-skin', 'dd-plugin']});