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