1 /*
  2  * jQuery Pines Notify (pnotify) Plugin 1.0.2-richfaces
  3  *
  4  * Copyright (c) 2009-2011 Hunter Perrin
  5  *
  6  * Triple license under the GPL, LGPL, and MPL:
  7  *    http://www.gnu.org/licenses/gpl.html
  8  *    http://www.gnu.org/licenses/lgpl.html
  9  *    http://www.mozilla.org/MPL/MPL-1.1.html
 10  *    
 11  * Modified by: RichFaces team
 12  */
 13 
 14 (function($, rf) {
 15     var history_handle_top, timer;
 16     var body;
 17     var jwindow;
 18     $.extend({
 19         pnotify_remove_all: function () {
 20             var body_data = body.data("pnotify");
 21             /* POA: Added null-check */
 22             if (body_data && body_data.length) {
 23                 $.each(body_data, function() {
 24                     if (this.pnotify_remove)
 25                         this.pnotify_remove();
 26                 });
 27             }
 28         },
 29         pnotify_position_all: function () {
 30             if (timer)
 31                 clearTimeout(timer);
 32             timer = null;
 33             var body_data = body.data("pnotify");
 34             if (!body_data || !body_data.length)
 35                 return;
 36             $.each(body_data, function() {
 37                 var s = this.opts.pnotify_stack;
 38                 if (!s) return;
 39                 if (!s.nextpos1)
 40                     s.nextpos1 = s.firstpos1;
 41                 if (!s.nextpos2)
 42                     s.nextpos2 = s.firstpos2;
 43                 if (!s.addpos2)
 44                     s.addpos2 = 0;
 45                 if (this.css("display") != "none") {
 46                     var curpos1, curpos2;
 47                     var animate = {};
 48                     // Calculate the current pos1 value.
 49                     var csspos1;
 50                     switch (s.dir1) {
 51                         case "down":
 52                             csspos1 = "top";
 53                             break;
 54                         case "up":
 55                             csspos1 = "bottom";
 56                             break;
 57                         case "left":
 58                             csspos1 = "right";
 59                             break;
 60                         case "right":
 61                             csspos1 = "left";
 62                             break;
 63                     }
 64                     curpos1 = parseInt(this.css(csspos1));
 65                     if (isNaN(curpos1))
 66                         curpos1 = 0;
 67                     // Remember the first pos1, so the first visible notice goes there.
 68                     if (typeof s.firstpos1 == "undefined") {
 69                         s.firstpos1 = curpos1;
 70                         s.nextpos1 = s.firstpos1;
 71                     }
 72                     // Calculate the current pos2 value.
 73                     var csspos2;
 74                     switch (s.dir2) {
 75                         case "down":
 76                             csspos2 = "top";
 77                             break;
 78                         case "up":
 79                             csspos2 = "bottom";
 80                             break;
 81                         case "left":
 82                             csspos2 = "right";
 83                             break;
 84                         case "right":
 85                             csspos2 = "left";
 86                             break;
 87                     }
 88                     curpos2 = parseInt(this.css(csspos2));
 89                     if (isNaN(curpos2))
 90                         curpos2 = 0;
 91                     // Remember the first pos2, so the first visible notice goes there.
 92                     if (typeof s.firstpos2 == "undefined") {
 93                         s.firstpos2 = curpos2;
 94                         s.nextpos2 = s.firstpos2;
 95                     }
 96                     // Check that it's not beyond the viewport edge.
 97                     if ((s.dir1 == "down" && s.nextpos1 + this.height() > jwindow.height()) ||
 98                             (s.dir1 == "up" && s.nextpos1 + this.height() > jwindow.height()) ||
 99                             (s.dir1 == "left" && s.nextpos1 + this.width() > jwindow.width()) ||
100                             (s.dir1 == "right" && s.nextpos1 + this.width() > jwindow.width())) {
101                         // If it is, it needs to go back to the first pos1, and over on pos2.
102                         s.nextpos1 = s.firstpos1;
103                         s.nextpos2 += s.addpos2 + 10;
104                         s.addpos2 = 0;
105                     }
106                     // Animate if we're moving on dir2.
107                     if (s.animation && s.nextpos2 < curpos2) {
108                         switch (s.dir2) {
109                             case "down":
110                                 animate.top = s.nextpos2 + "px";
111                                 break;
112                             case "up":
113                                 animate.bottom = s.nextpos2 + "px";
114                                 break;
115                             case "left":
116                                 animate.right = s.nextpos2 + "px";
117                                 break;
118                             case "right":
119                                 animate.left = s.nextpos2 + "px";
120                                 break;
121                         }
122                     } else
123                         this.css(csspos2, s.nextpos2 + "px");
124                     // Keep track of the widest/tallest notice in the column/row, so we can push the next column/row.
125                     switch (s.dir2) {
126                         case "down":
127                         case "up":
128                             if (this.outerHeight(true) > s.addpos2)
129                                 s.addpos2 = this.height();
130                             break;
131                         case "left":
132                         case "right":
133                             if (this.outerWidth(true) > s.addpos2)
134                                 s.addpos2 = this.width();
135                             break;
136                     }
137                     // Move the notice on dir1.
138                     if (s.nextpos1) {
139                         // Animate if we're moving toward the first pos.
140                         if (s.animation && (curpos1 > s.nextpos1 || animate.top || animate.bottom || animate.right || animate.left)) {
141                             switch (s.dir1) {
142                                 case "down":
143                                     animate.top = s.nextpos1 + "px";
144                                     break;
145                                 case "up":
146                                     animate.bottom = s.nextpos1 + "px";
147                                     break;
148                                 case "left":
149                                     animate.right = s.nextpos1 + "px";
150                                     break;
151                                 case "right":
152                                     animate.left = s.nextpos1 + "px";
153                                     break;
154                             }
155                         } else
156                             this.css(csspos1, s.nextpos1 + "px");
157                     }
158                     if (animate.top || animate.bottom || animate.right || animate.left)
159                         this.animate(animate, {duration: 500, queue: false});
160                     // Calculate the next dir1 position.
161                     switch (s.dir1) {
162                         case "down":
163                         case "up":
164                             s.nextpos1 += this.height() + 10;
165                             break;
166                         case "left":
167                         case "right":
168                             s.nextpos1 += this.width() + 10;
169                             break;
170                     }
171                 }
172             });
173             // Reset the next position data.
174             $.each(body_data, function() {
175                 var s = this.opts.pnotify_stack;
176                 if (!s) return;
177                 s.nextpos1 = s.firstpos1;
178                 s.nextpos2 = s.firstpos2;
179                 s.addpos2 = 0;
180                 s.animation = true;
181             });
182         },
183         pnotify: function(options) {
184             if (!body)
185                 body = $("body");
186             if (!jwindow)
187                 jwindow = $(window);
188 
189             var animating;
190 
191             // Build main options.
192             var opts;
193             if (typeof options != "object") {
194                 opts = $.extend({}, $.pnotify.defaults);
195                 opts.pnotify_text = options;
196             } else {
197                 opts = $.extend({}, $.pnotify.defaults, options);
198                 if (opts['pnotify_animation'] instanceof Object) {
199                     opts['pnotify_animation'] = $.extend({
200                         effect_in:$.pnotify.defaults.pnotify_animation,
201                         effect_out:$.pnotify.defaults.pnotify_animation
202                     }, opts['pnotify_animation']);
203                 }
204             }
205 
206             if (opts.pnotify_before_init) {
207                 if (opts.pnotify_before_init(opts) === false)
208                     return null;
209             }
210 
211             // This keeps track of the last element the mouse was over, so
212             // mouseleave, mouseenter, etc can be called.
213             var nonblock_last_elem;
214             // This is used to pass events through the notice if it is non-blocking.
215             var nonblock_pass = function(e, e_name) {
216                 pnotify.css("display", "none");
217                 var element_below = document.elementFromPoint(e.clientX, e.clientY);
218                 pnotify.css("display", "block");
219                 var jelement_below = $(element_below);
220                 var cursor_style = jelement_below.css("cursor");
221                 pnotify.css("cursor", cursor_style != "auto" ? cursor_style : "default");
222                 // If the element changed, call mouseenter, mouseleave, etc.
223                 if (!nonblock_last_elem || nonblock_last_elem.get(0) != element_below) {
224                     if (nonblock_last_elem) {
225                         dom_event.call(nonblock_last_elem.get(0), "mouseleave", e.originalEvent);
226                         dom_event.call(nonblock_last_elem.get(0), "mouseout", e.originalEvent);
227                     }
228                     dom_event.call(element_below, "mouseenter", e.originalEvent);
229                     dom_event.call(element_below, "mouseover", e.originalEvent);
230                 }
231                 dom_event.call(element_below, e_name, e.originalEvent);
232                 // Remember the latest element the mouse was over.
233                 nonblock_last_elem = jelement_below;
234             };
235 
236             // Create our widget.
237             // Stop animation, reset the removal timer, and show the close
238             // button when the user mouses over.
239             var pnotify = $("<div />", {
240                 "class": "rf-ntf " + opts.pnotify_addclass,
241                 "css": {"display": "none"},
242                 "mouseenter": function(e) {
243                     if (opts.pnotify_nonblock) e.stopPropagation();
244                     if (opts.pnotify_mouse_reset && animating == "out") {
245                         // If it's animating out, animate back in really quick.
246                         pnotify.stop(true);
247                         animating = "in";
248                         pnotify.css("height", "auto").animate({"width": opts.pnotify_width, "opacity": opts.pnotify_nonblock ? opts.pnotify_nonblock_opacity : opts.pnotify_opacity}, "fast");
249                     }
250                     if (opts.pnotify_nonblock) {
251                         // If it's non-blocking, animate to the other opacity.
252                         pnotify.animate({"opacity": opts.pnotify_nonblock_opacity}, "fast");
253                     }
254                     if (opts.pnotify_hide && opts.pnotify_mouse_reset) pnotify.pnotify_cancel_remove();
255                     //                    Do not update
256                     if (opts.pnotify_closer && !opts.pnotify_nonblock) pnotify.closer.css("visibility", "visible");
257                 },
258                 "mouseleave": function(e) {
259                     if (opts.pnotify_nonblock) e.stopPropagation();
260                     nonblock_last_elem = null;
261                     pnotify.css("cursor", "auto");
262                     if (opts.pnotify_nonblock && animating != "out")
263                         pnotify.animate({"opacity": opts.pnotify_opacity}, "fast");
264                     if (opts.pnotify_hide && opts.pnotify_mouse_reset) pnotify.pnotify_queue_remove();
265                     //                    Do not update
266                     pnotify.closer.css("visibility", "hidden");
267                     $.pnotify_position_all();
268                 },
269                 "mouseover": function(e) {
270                     if (opts.pnotify_nonblock) e.stopPropagation();
271                 },
272                 "mouseout": function(e) {
273                     if (opts.pnotify_nonblock) e.stopPropagation();
274                 },
275                 "mousemove": function(e) {
276                     if (opts.pnotify_nonblock) {
277                         e.stopPropagation();
278                         nonblock_pass(e, "onmousemove");
279                     }
280                 },
281                 "mousedown": function(e) {
282                     if (opts.pnotify_nonblock) {
283                         e.stopPropagation();
284                         e.preventDefault();
285                         nonblock_pass(e, "onmousedown");
286                     }
287                 },
288                 "mouseup": function(e) {
289                     if (opts.pnotify_nonblock) {
290                         e.stopPropagation();
291                         e.preventDefault();
292                         nonblock_pass(e, "onmouseup");
293                     }
294                 },
295                 "click": function(e) {
296                     if (opts.pnotify_nonblock) {
297                         e.stopPropagation();
298                         nonblock_pass(e, "onclick");
299                     }
300                 },
301                 "dblclick": function(e) {
302                     if (opts.pnotify_nonblock) {
303                         e.stopPropagation();
304                         nonblock_pass(e, "ondblclick");
305                     }
306                 }
307             });
308             pnotify.opts = opts;
309             // Create a drop shadow.
310             if (opts.pnotify_shadow && !rf.browser.msie)
311                 pnotify.shadow_container = $("<div />", {"class": "rf-ntf-shdw"}).prependTo(pnotify);
312             // Create a container for the notice contents.
313             pnotify.container = $("<div />", {"class": "rf-ntf-cnt"})
314                     .appendTo(pnotify);
315 
316             pnotify.pnotify_version = "1.0.2";
317 
318             // This function is for updating the notice.
319             pnotify.pnotify = function(options) {
320                 // Update the notice.
321                 var old_opts = opts;
322                 if (typeof options == "string")
323                     opts.pnotify_text = options;
324                 else
325                     opts = $.extend({}, opts, options);
326                 pnotify.opts = opts;
327                 // Update the shadow.
328                 if (opts.pnotify_shadow != old_opts.pnotify_shadow) {
329                     if (opts.pnotify_shadow && !rf.browser.msie)
330                         pnotify.shadow_container = $("<div />", {"class": "rf-ntf-shdw"}).prependTo(pnotify);
331                     else
332                         pnotify.children(".rf-ntf-shdw").remove();
333                 }
334                 // Update the additional classes.
335                 if (opts.pnotify_addclass === false)
336                     pnotify.removeClass(old_opts.pnotify_addclass);
337                 else if (opts.pnotify_addclass !== old_opts.pnotify_addclass)
338                     pnotify.removeClass(old_opts.pnotify_addclass).addClass(opts.pnotify_addclass);
339                 // Update the title.
340                 if (opts.pnotify_title === false)
341                     pnotify.title_container.hide("fast");
342                 else if (opts.pnotify_title !== old_opts.pnotify_title)
343                     pnotify.title_container.html(opts.pnotify_title).show(200);
344                 // Update the text.
345                 if (opts.pnotify_text === false) {
346                     pnotify.text_container.hide("fast");
347                 } else if (opts.pnotify_text !== old_opts.pnotify_text) {
348                     if (opts.pnotify_insert_brs)
349                         opts.pnotify_text = opts.pnotify_text.replace(/\n/g, "<br />");
350                     pnotify.text_container.html(opts.pnotify_text).show(200);
351                 }
352                 pnotify.pnotify_history = opts.pnotify_history;
353                 // Change the notice type.
354                 if (opts.pnotify_type != old_opts.pnotify_type)
355                     pnotify.container.toggleClass("rf-ntf-cnt rf-ntf-cnt-hov");
356                 if ((opts.pnotify_notice_icon != old_opts.pnotify_notice_icon && opts.pnotify_type == "notice") ||
357                         (opts.pnotify_error_icon != old_opts.pnotify_error_icon && opts.pnotify_type == "error") ||
358                         (opts.pnotify_type != old_opts.pnotify_type)) {
359                     // Remove any old icon.
360                     pnotify.container.find("div.rf-ntf-ico").remove();
361                     //					if ((opts.pnotify_error_icon && opts.pnotify_type == "error") || (opts.pnotify_notice_icon)) {
362                     // Build the new icon.
363                     $("<div />", {"class": "rf-ntf-ico"})
364                             .append($("<span />", {"class": opts.pnotify_type == "error" ? opts.pnotify_error_icon : opts.pnotify_notice_icon}))
365                             .prependTo(pnotify.container);
366                     //					}
367                 }
368                 // Update the width.
369                 if (opts.pnotify_width !== old_opts.pnotify_width)
370                     pnotify.animate({width: opts.pnotify_width});
371                 // Update the minimum height.
372                 if (opts.pnotify_min_height !== old_opts.pnotify_min_height)
373                     pnotify.container.animate({minHeight: opts.pnotify_min_height});
374                 // Update the opacity.
375                 if (opts.pnotify_opacity !== old_opts.pnotify_opacity)
376                     pnotify.fadeTo(opts.pnotify_animate_speed, opts.pnotify_opacity);
377                 if (!opts.pnotify_hide)
378                     pnotify.pnotify_cancel_remove();
379                 else if (!old_opts.pnotify_hide)
380                     pnotify.pnotify_queue_remove();
381                 pnotify.pnotify_queue_position();
382                 return pnotify;
383             };
384 
385             // Queue the position function so it doesn't run repeatedly and use
386             // up resources.
387             pnotify.pnotify_queue_position = function() {
388                 if (timer)
389                     clearTimeout(timer);
390                 timer = setTimeout($.pnotify_position_all, 10);
391             };
392 
393             // Display the notice.
394             pnotify.pnotify_display = function() {
395                 // If the notice is not in the DOM, append it.
396                 if (!pnotify.parent().length)
397                     pnotify.appendTo(body);
398                 // Run callback.
399                 if (opts.pnotify_before_open) {
400                     if (opts.pnotify_before_open(pnotify) === false)
401                         return;
402                 }
403                 pnotify.pnotify_queue_position();
404                 // First show it, then set its opacity, then hide it.
405                 if (opts.pnotify_animation == "fade" || opts.pnotify_animation.effect_in == "fade") {
406                     // If it's fading in, it should start at 0.
407                     pnotify.show().fadeTo(0, 0).hide();
408                 } else {
409                     // Or else it should be set to the opacity.
410                     if (opts.pnotify_opacity != 1)
411                         pnotify.show().fadeTo(0, opts.pnotify_opacity).hide();
412                 }
413                 pnotify.animate_in(function() {
414                     if (opts.pnotify_after_open)
415                         opts.pnotify_after_open(pnotify);
416 
417                     pnotify.pnotify_queue_position();
418 
419                     // Now set it to hide.
420                     if (opts.pnotify_hide)
421                         pnotify.pnotify_queue_remove();
422                 });
423             };
424 
425             // Remove the notice.
426             pnotify.pnotify_remove = function() {
427                 if (pnotify.timer) {
428                     window.clearTimeout(pnotify.timer);
429                     pnotify.timer = null;
430                 }
431                 // Run callback.
432                 if (opts.pnotify_before_close) {
433                     if (opts.pnotify_before_close(pnotify) === false)
434                         return;
435                 }
436                 pnotify.animate_out(function() {
437                     if (opts.pnotify_after_close) {
438                         if (opts.pnotify_after_close(pnotify) === false)
439                             return;
440                     }
441                     pnotify.pnotify_queue_position();
442                     // If we're supposed to remove the notice from the DOM, do it.
443                     if (opts.pnotify_remove)
444                         pnotify.detach();
445                 });
446             };
447 
448             // Animate the notice in.
449             pnotify.animate_in = function(callback) {
450                 // Declare that the notice is animating in. (Or has completed animating in.)
451                 animating = "in";
452                 var animation;
453                 if (typeof opts.pnotify_animation.effect_in != "undefined")
454                     animation = opts.pnotify_animation.effect_in;
455                 else
456                     animation = opts.pnotify_animation;
457                 if (animation == "none") {
458                     pnotify.show();
459                     callback();
460                 } else if (animation == "show")
461                     pnotify.show(opts.pnotify_animate_speed, callback);
462                 else if (animation == "fade")
463                     pnotify.show().fadeTo(opts.pnotify_animate_speed, opts.pnotify_opacity, callback);
464                 else if (animation == "slide")
465                     pnotify.slideDown(opts.pnotify_animate_speed, callback);
466                 else if (typeof animation == "function")
467                     animation("in", callback, pnotify);
468                 else if (pnotify.effect)
469                     pnotify.effect(animation, {}, opts.pnotify_animate_speed, callback);
470             };
471 
472             // Animate the notice out.
473             pnotify.animate_out = function(callback) {
474                 // Declare that the notice is animating out. (Or has completed animating out.)
475                 animating = "out";
476                 var animation;
477                 if (typeof opts.pnotify_animation.effect_out != "undefined")
478                     animation = opts.pnotify_animation.effect_out;
479                 else
480                     animation = opts.pnotify_animation;
481                 if (animation == "none") {
482                     pnotify.hide();
483                     callback();
484                 } else if (animation == "show")
485                     pnotify.hide(opts.pnotify_animate_speed, callback);
486                 else if (animation == "fade")
487                     pnotify.fadeOut(opts.pnotify_animate_speed, callback);
488                 else if (animation == "slide")
489                     pnotify.slideUp(opts.pnotify_animate_speed, callback);
490                 else if (typeof animation == "function")
491                     animation("out", callback, pnotify);
492                 else if (pnotify.effect)
493                     pnotify.effect(animation, {}, opts.pnotify_animate_speed, callback);
494             };
495 
496             // Cancel any pending removal timer.
497             pnotify.pnotify_cancel_remove = function() {
498                 if (pnotify.timer)
499                     window.clearTimeout(pnotify.timer);
500             };
501 
502             // Queue a removal timer.
503             pnotify.pnotify_queue_remove = function() {
504                 // Cancel any current removal timer.
505                 pnotify.pnotify_cancel_remove();
506                 pnotify.timer = window.setTimeout(function() {
507                     pnotify.pnotify_remove();
508                 }, (isNaN(opts.pnotify_delay) ? 0 : opts.pnotify_delay));
509             };
510 
511             // Provide a button to close the notice.
512             pnotify.closer = $("<div />", {
513                 "class": "rf-ntf-cls",
514                 "css": {"cursor": "pointer", "visibility": "hidden"},
515                 "click": function() {
516                     pnotify.pnotify_remove();
517                     //                    Do not update
518                     pnotify.closer.css("visibility", "hidden");
519                 }
520             })
521                     .append($("<span />", {"class": "rf-ntf-cls-ico"}))
522                     .appendTo(pnotify.container);
523 
524             // Add the appropriate icon.
525             //			if ((opts.pnotify_error_icon && opts.pnotify_type == "error") || (opts.pnotify_notice_icon)) {
526             $("<div />", {"class": "rf-ntf-ico"})
527                     .append($("<span />", {"class": opts.pnotify_type == "error" ? opts.pnotify_error_icon : opts.pnotify_notice_icon}))
528                     .appendTo(pnotify.container);
529             //			}
530 
531             // Add a title.
532             pnotify.title_container = $("<div />", {
533                 "class": "rf-ntf-sum",
534                 "html": opts.pnotify_title
535             })
536                     .appendTo(pnotify.container);
537             if (opts.pnotify_title === false)
538                 pnotify.title_container.hide();
539 
540             // Replace new lines with HTML line breaks.
541             if (opts.pnotify_insert_brs && typeof opts.pnotify_text == "string")
542                 opts.pnotify_text = opts.pnotify_text.replace(/\n/g, "<br />");
543             // Add text.
544             pnotify.text_container = $("<div />", {
545                 "class": "rf-ntf-det",
546                 "html": opts.pnotify_text
547             })
548                     .appendTo(pnotify.container);
549             if (opts.pnotify_text === false)
550                 pnotify.text_container.hide();
551 
552             //Append div with clear:both class
553             $("<div />", {"class":"rf-ntf-clr"}).appendTo(pnotify.container);
554 
555             // Set width and min height.
556             if (typeof opts.pnotify_width == "string")
557                 pnotify.css("width", opts.pnotify_width);
558             if (typeof opts.pnotify_min_height == "string")
559                 pnotify.container.css("min-height", opts.pnotify_min_height);
560 
561             // The history variable controls whether the notice gets redisplayed
562             // by the history pull down.
563             pnotify.pnotify_history = opts.pnotify_history;
564 
565             // Add the notice to the notice array.
566             var body_data = body.data("pnotify");
567             if (body_data == null || typeof body_data != "object")
568                 body_data = [];
569             if (opts.pnotify_stack.push == "top")
570                 body_data = $.merge([pnotify], body_data);
571             else
572                 body_data = $.merge(body_data, [pnotify]);
573             body.data("pnotify", body_data);
574 
575             // Run callback.
576             if (opts.pnotify_after_init)
577                 opts.pnotify_after_init(pnotify);
578 
579             if (opts.pnotify_history) {
580                 // If there isn't a history pull down, create one.
581                 var body_history = body.data("pnotify_history");
582                 if (typeof body_history == "undefined") {
583                     body_history = $("<div />", {
584                         "class": "rf-ntf-hstr",
585                         "mouseleave": function() {
586                             body_history.animate({top: "-" + history_handle_top + "px"}, {duration: 100, queue: false});
587                         }
588                     })
589                             .append($("<div />", {"class": "rf-ntf-hstr-hdr", "text": "Redisplay"}))
590                             .append($("<button />", {
591                         "class": "rf-ntf-hstr-all",
592                         "text": "All",
593                         //							"mouseenter": function(){
594                         //								$(this).addClass("ui-state-hover");
595                         //							},
596                         //							"mouseleave": function(){
597                         //								$(this).removeClass("ui-state-hover");
598                         //							},
599                         "click": function() {
600                             // Display all notices. (Disregarding non-history notices.)
601                             //                            Don't change it to pnotify's new version, cause using body_data here is a bug
602                             $.each(body.data("pnotify"), function() {
603                                 if (this.pnotify_history && this.pnotify_display)
604                                     this.pnotify_display();
605                             });
606                             return false;
607                         }
608                     }))
609                             .append($("<button />", {
610                         "class": "rf-ntf-hstr-last",
611                         "text": "Last",
612                         //							"mouseenter": function(){
613                         //								$(this).addClass("ui-state-hover");
614                         //							},
615                         //							"mouseleave": function(){
616                         //								$(this).removeClass("ui-state-hover");
617                         //							},
618                         "click": function() {
619                             // Look up the last history notice, and display it.
620                             var i = 1;
621                             var body_data = body.data("pnotify");
622                             while (!body_data[body_data.length - i] || !body_data[body_data.length - i].pnotify_history || body_data[body_data.length - i].is(":visible")) {
623                                 if (body_data.length - i === 0)
624                                     return false;
625                                 i++;
626                             }
627                             var n = body_data[body_data.length - i];
628                             if (n.pnotify_display)
629                                 n.pnotify_display();
630                             return false;
631                         }
632                     }))
633                             .appendTo(body);
634 
635                     // Make a handle so the user can pull down the history pull down.
636                     var handle = $("<span />", {
637                         "class": "rf-ntf-hstr-hndl",
638                         "mouseenter": function() {
639                             body_history.animate({top: "0"}, {duration: 100, queue: false});
640                         }
641                     })
642                             .appendTo(body_history);
643 
644                     // Get the top of the handle.
645                     history_handle_top = handle.offset().top + 2;
646                     // Hide the history pull down up to the top of the handle.
647                     body_history.css({top: "-" + history_handle_top + "px"});
648                     // Save the history pull down.
649                     body.data("pnotify_history", body_history);
650                 }
651             }
652 
653             // Mark the stack so it won't animate the new notice.
654             opts.pnotify_stack.animation = false;
655 
656             // Display the notice.
657             pnotify.pnotify_display();
658 
659             return pnotify;
660         }
661     });
662 
663     // Some useful regexes.
664     var re_on = /^on/;
665     var re_mouse_events = /^(dbl)?click$|^mouse(move|down|up|over|out|enter|leave)$|^contextmenu$/;
666     var re_ui_events = /^(focus|blur|select|change|reset)$|^key(press|down|up)$/;
667     var re_html_events = /^(scroll|resize|(un)?load|abort|error)$/;
668     // Fire a DOM event.
669     var dom_event = function(e, orig_e) {
670         var event_object;
671         e = e.toLowerCase();
672         if (document.createEvent && this.dispatchEvent) {
673             // FireFox, Opera, Safari, Chrome
674             e = e.replace(re_on, '');
675             if (e.match(re_mouse_events)) {
676                 // This allows the click event to fire on the notice. There is
677                 // probably a much better way to do it.
678                 $(this).offset();
679                 event_object = document.createEvent("MouseEvents");
680                 event_object.initMouseEvent(
681                         e, orig_e.bubbles, orig_e.cancelable, orig_e.view, orig_e.detail,
682                         orig_e.screenX, orig_e.screenY, orig_e.clientX, orig_e.clientY,
683                         orig_e.ctrlKey, orig_e.altKey, orig_e.shiftKey, orig_e.metaKey, orig_e.button, orig_e.relatedTarget
684                         );
685             } else if (e.match(re_ui_events)) {
686                 event_object = document.createEvent("UIEvents");
687                 event_object.initUIEvent(e, orig_e.bubbles, orig_e.cancelable, orig_e.view, orig_e.detail);
688             } else if (e.match(re_html_events)) {
689                 event_object = document.createEvent("HTMLEvents");
690                 event_object.initEvent(e, orig_e.bubbles, orig_e.cancelable);
691             }
692             if (!event_object) return;
693             this.dispatchEvent(event_object);
694         } else {
695             // Internet Explorer
696             if (!e.match(re_on)) e = "on" + e;
697             event_object = document.createEventObject(orig_e);
698             this.fireEvent(e, event_object);
699         }
700     };
701 
702     $.pnotify.defaults = {
703         // The notice's title.
704         pnotify_title: false,
705         // The notice's text.
706         pnotify_text: false,
707         // Additional classes to be added to the notice. (For custom styling.)
708         pnotify_addclass: "",
709         // Create a non-blocking notice. It lets the user click elements underneath it.
710         pnotify_nonblock: false,
711         // The opacity of the notice (if it's non-blocking) when the mouse is over it.
712         pnotify_nonblock_opacity: .2,
713         // Display a pull down menu to redisplay previous notices, and place the notice in the history.
714         pnotify_history: true,
715         // Width of the notice.
716         pnotify_width: "300px",
717         // Minimum height of the notice. It will expand to fit content.
718         pnotify_min_height: "16px",
719         // Type of the notice. "notice" or "error".
720         pnotify_type: "notice",
721         // The icon class to use if type is notice.
722         pnotify_notice_icon: "",
723         // The icon class to use if type is error.
724         pnotify_error_icon: "",
725         // The animation to use when displaying and hiding the notice. "none", "show", "fade", and "slide" are built in to jQuery. Others require jQuery UI. Use an object with effect_in and effect_out to use different effects.
726         pnotify_animation: "fade",
727         // Speed at which the notice animates in and out. "slow", "def" or "normal", "fast" or number of milliseconds.
728         pnotify_animate_speed: "slow",
729         // Opacity of the notice.
730         pnotify_opacity: 1,
731         // Display a drop shadow.
732         pnotify_shadow: false,
733         // Provide a button for the user to manually close the notice.
734         pnotify_closer: true,
735         // After a delay, remove the notice.
736         pnotify_hide: true,
737         // Delay in milliseconds before the notice is removed.
738         pnotify_delay: 8000,
739         // Reset the hide timer if the mouse moves over the notice.
740         pnotify_mouse_reset: true,
741         // Remove the notice's elements from the DOM after it is removed.
742         pnotify_remove: true,
743         // Change new lines to br tags.
744         pnotify_insert_brs: true,
745         // The stack on which the notices will be placed. Also controls the direction the notices stack.
746         pnotify_stack: {"dir1": "down", "dir2": "left", "push": "bottom"}
747     };
748 })(jQuery, RichFaces);