mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-22 07:16:13 +01:00
d35dbaaacc
Teach Gritter to accept anything that jQuery's `.append()` method accepts for the title and text of a popup message. This makes it easier to safely build HTML messages with proper escaping of special characters (to prevent XSS vulnerabilities).
353 lines
9.1 KiB
JavaScript
353 lines
9.1 KiB
JavaScript
/*
|
|
* Gritter for jQuery
|
|
* http://www.boedesign.com/
|
|
*
|
|
* Copyright (c) 2012 Jordan Boesch
|
|
* Dual licensed under the MIT and GPL licenses.
|
|
*
|
|
* Date: February 24, 2012
|
|
* Version: 1.7.4
|
|
*
|
|
* Edited by Sebastian Castro <sebastian.castro@protonmail.com> on 2020-03-31
|
|
*
|
|
* Edited by Richard Hansen <rhansen@rhansen.org> on 2020-10-19 to accept jQuery or DOM objects for
|
|
* notification title and text.
|
|
*/
|
|
|
|
(function($){
|
|
/**
|
|
* Set it up as an object under the jQuery namespace
|
|
*/
|
|
$.gritter = {};
|
|
|
|
/**
|
|
* Set up global options that the user can over-ride
|
|
*/
|
|
$.gritter.options = {
|
|
position: '',
|
|
class_name: '', // could be set to 'gritter-light' to use white notifications
|
|
time: 3000 // hang on the screen for...
|
|
}
|
|
|
|
/**
|
|
* Add a gritter notification to the screen
|
|
* @see Gritter#add();
|
|
*/
|
|
$.gritter.add = function(params){
|
|
|
|
try {
|
|
return Gritter.add(params || {});
|
|
} catch(e) {
|
|
|
|
var err = 'Gritter Error: ' + e;
|
|
(typeof(console) != 'undefined' && console.error) ?
|
|
console.error(err, params) :
|
|
alert(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Remove a gritter notification from the screen
|
|
* @see Gritter#removeSpecific();
|
|
*/
|
|
$.gritter.remove = function(id, params){
|
|
Gritter.removeSpecific(id.split('gritter-item-')[1], params || {});
|
|
}
|
|
|
|
/**
|
|
* Remove all notifications
|
|
* @see Gritter#stop();
|
|
*/
|
|
$.gritter.removeAll = function(params){
|
|
Gritter.stop(params || {});
|
|
}
|
|
|
|
/**
|
|
* Big fat Gritter object
|
|
* @constructor (not really since its object literal)
|
|
*/
|
|
var Gritter = {
|
|
|
|
// Public - options to over-ride with $.gritter.options in "add"
|
|
time: '',
|
|
|
|
// Private - no touchy the private parts
|
|
_custom_timer: 0,
|
|
_item_count: 0,
|
|
_is_setup: 0,
|
|
_tpl_wrap_top: '<div id="gritter-container" class="top"></div>',
|
|
_tpl_wrap_bottom: '<div id="gritter-container" class="bottom"></div>',
|
|
_tpl_close: '',
|
|
_tpl_title: $('<h3>').addClass('gritter-title'),
|
|
_tpl_item: ($('<div>').addClass('popup gritter-item')
|
|
.append($('<div>').addClass('popup-content')
|
|
.append($('<div>').addClass('gritter-content'))
|
|
.append($('<div>').addClass('gritter-close')
|
|
.append($('<i>').addClass('buttonicon buttonicon-times'))))),
|
|
|
|
|
|
/**
|
|
* Add a gritter notification to the screen
|
|
* @param {Object} params The object that contains all the options for drawing the notification
|
|
* @return {Integer} The specific numeric id to that gritter notification
|
|
*/
|
|
add: function(params){
|
|
// Handle straight text
|
|
if(typeof(params) == 'string'){
|
|
params = {text:params};
|
|
}
|
|
|
|
// We might have some issues if we don't have a title or text!
|
|
if(!params.text){
|
|
throw 'You must supply "text" parameter.';
|
|
}
|
|
|
|
// Check the options and set them once
|
|
if(!this._is_setup){
|
|
this._runSetup();
|
|
}
|
|
|
|
// Basics
|
|
var title = params.title,
|
|
text = params.text,
|
|
image = params.image || '',
|
|
position = params.position || 'top',
|
|
sticky = params.sticky || false,
|
|
item_class = params.class_name || $.gritter.options.class_name,
|
|
time_alive = params.time || '';
|
|
|
|
this._verifyWrapper();
|
|
|
|
if (sticky) {
|
|
item_class += " sticky";
|
|
}
|
|
|
|
this._item_count++;
|
|
var number = this._item_count;
|
|
|
|
// Assign callbacks
|
|
$(['before_open', 'after_open', 'before_close', 'after_close']).each(function(i, val){
|
|
Gritter['_' + val + '_' + number] = ($.isFunction(params[val])) ? params[val] : function(){}
|
|
});
|
|
|
|
// Reset
|
|
this._custom_timer = 0;
|
|
|
|
// A custom fade time set
|
|
if(time_alive){
|
|
this._custom_timer = time_alive;
|
|
}
|
|
|
|
// String replacements on the template
|
|
if(title){
|
|
title = this._tpl_title.clone().append(title);
|
|
}else{
|
|
title = '';
|
|
}
|
|
|
|
const tmp = this._tpl_item.clone();
|
|
tmp.attr('id', `gritter-item-${number}`);
|
|
tmp.addClass(item_class);
|
|
tmp.find('.gritter-content')
|
|
.append(title)
|
|
.append(typeof text === 'string' ? $('<p>').html(text) : text);
|
|
|
|
// If it's false, don't show another gritter message
|
|
if(this['_before_open_' + number]() === false){
|
|
return false;
|
|
}
|
|
|
|
if (['top', 'bottom'].indexOf(position) == -1) {
|
|
position = 'top';
|
|
}
|
|
|
|
$('#gritter-container.' + position).append(tmp);
|
|
|
|
var item = $('#gritter-item-' + this._item_count);
|
|
|
|
setTimeout(function() { item.addClass('popup-show'); }, 0);
|
|
Gritter['_after_open_' + number](item);
|
|
|
|
if(!sticky){
|
|
this._setFadeTimer(item, number);
|
|
// Bind the hover/unhover states
|
|
$(item).on('mouseenter', function(event) {
|
|
Gritter._restoreItemIfFading($(this), number);
|
|
});
|
|
$(item).on('mouseleave', function(event) {
|
|
Gritter._setFadeTimer($(this), number);
|
|
});
|
|
}
|
|
|
|
// Clicking (X) makes the perdy thing close
|
|
$(item).find('.gritter-close').click(function(){
|
|
Gritter.removeSpecific(number, {}, null, true);
|
|
});
|
|
|
|
return number;
|
|
|
|
},
|
|
|
|
/**
|
|
* If we don't have any more gritter notifications, get rid of the wrapper using this check
|
|
* @private
|
|
* @param {Integer} unique_id The ID of the element that was just deleted, use it for a callback
|
|
* @param {Object} e The jQuery element that we're going to perform the remove() action on
|
|
* @param {Boolean} manual_close Did we close the gritter dialog with the (X) button
|
|
*/
|
|
_countRemoveWrapper: function(unique_id, e, manual_close){
|
|
|
|
// Remove it then run the callback function
|
|
e.remove();
|
|
this['_after_close_' + unique_id](e, manual_close);
|
|
|
|
// Remove container if empty
|
|
$('#gritter-container').each(function() {
|
|
if ($(this).find('.gritter-item').length == 0) {
|
|
$(this).remove();
|
|
}
|
|
})
|
|
},
|
|
|
|
/**
|
|
* Fade out an element after it's been on the screen for x amount of time
|
|
* @private
|
|
* @param {Object} e The jQuery element to get rid of
|
|
* @param {Integer} unique_id The id of the element to remove
|
|
* @param {Object} params An optional list of params.
|
|
* @param {Boolean} unbind_events Unbind the mouseenter/mouseleave events if they click (X)
|
|
*/
|
|
_fade: function(e, unique_id, params, unbind_events){
|
|
|
|
var params = params || {},
|
|
fade = (typeof(params.fade) != 'undefined') ? params.fade : true,
|
|
manual_close = unbind_events;
|
|
|
|
this['_before_close_' + unique_id](e, manual_close);
|
|
|
|
// If this is true, then we are coming from clicking the (X)
|
|
if(unbind_events){
|
|
e.unbind('mouseenter mouseleave');
|
|
}
|
|
|
|
// Fade it out or remove it
|
|
if(fade){
|
|
e.removeClass('popup-show');
|
|
setTimeout(function() {
|
|
Gritter._countRemoveWrapper(unique_id, e, manual_close);
|
|
}, 300)
|
|
}
|
|
else {
|
|
|
|
this._countRemoveWrapper(unique_id, e);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
* Remove a specific notification based on an ID
|
|
* @param {Integer} unique_id The ID used to delete a specific notification
|
|
* @param {Object} params A set of options passed in to determine how to get rid of it
|
|
* @param {Object} e The jQuery element that we're "fading" then removing
|
|
* @param {Boolean} unbind_events If we clicked on the (X) we set this to true to unbind mouseenter/mouseleave
|
|
*/
|
|
removeSpecific: function(unique_id, params, e, unbind_events){
|
|
|
|
if(!e){
|
|
var e = $('#gritter-item-' + unique_id);
|
|
}
|
|
|
|
// We set the fourth param to let the _fade function know to
|
|
// unbind the "mouseleave" event. Once you click (X) there's no going back!
|
|
this._fade(e, unique_id, params || {}, unbind_events);
|
|
|
|
},
|
|
|
|
/**
|
|
* If the item is fading out and we hover over it, restore it!
|
|
* @private
|
|
* @param {Object} e The HTML element to remove
|
|
* @param {Integer} unique_id The ID of the element
|
|
*/
|
|
_restoreItemIfFading: function(e, unique_id){
|
|
|
|
clearTimeout(this['_int_id_' + unique_id]);
|
|
e.stop().css({ opacity: '', height: '' });
|
|
|
|
},
|
|
|
|
/**
|
|
* Setup the global options - only once
|
|
* @private
|
|
*/
|
|
_runSetup: function(){
|
|
|
|
for(opt in $.gritter.options){
|
|
this[opt] = $.gritter.options[opt];
|
|
}
|
|
this._is_setup = 1;
|
|
|
|
},
|
|
|
|
/**
|
|
* Set the notification to fade out after a certain amount of time
|
|
* @private
|
|
* @param {Object} item The HTML element we're dealing with
|
|
* @param {Integer} unique_id The ID of the element
|
|
*/
|
|
_setFadeTimer: function(item, unique_id){
|
|
|
|
var timer_str = (this._custom_timer) ? this._custom_timer : this.time;
|
|
this['_int_id_' + unique_id] = setTimeout(function(){
|
|
Gritter._fade(item, unique_id);
|
|
}, timer_str);
|
|
|
|
},
|
|
|
|
/**
|
|
* Bring everything to a halt
|
|
* @param {Object} params A list of callback functions to pass when all notifications are removed
|
|
*/
|
|
stop: function(params){
|
|
|
|
// callbacks (if passed)
|
|
var before_close = ($.isFunction(params.before_close)) ? params.before_close : function(){};
|
|
var after_close = ($.isFunction(params.after_close)) ? params.after_close : function(){};
|
|
|
|
var wrap = $('#gritter-container');
|
|
before_close(wrap);
|
|
wrap.fadeOut(function(){
|
|
$(this).remove();
|
|
after_close();
|
|
});
|
|
|
|
},
|
|
|
|
/**
|
|
* A check to make sure we have something to wrap our notices with
|
|
* @private
|
|
*/
|
|
_verifyWrapper: function(){
|
|
if ($('#gritter-container.top').length === 0) {
|
|
$('#editorcontainerbox').append(this._tpl_wrap_top);
|
|
}
|
|
|
|
if ($('#gritter-container.bottom').length === 0) {
|
|
$('#editorcontainerbox').append(this._tpl_wrap_bottom);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
})(jQuery);
|
|
|
|
// For Emacs:
|
|
// Local Variables:
|
|
// tab-width: 2
|
|
// indent-tabs-mode: t
|
|
// End:
|
|
|
|
// vi: ts=2:noet:sw=2
|