PortaleOrdiniGruppo/PortalStudio/Notimoo.js
2025-03-24 15:28:26 +01:00

369 lines
14 KiB
JavaScript

/*
---
name: Notimoo
description: Notification system using Mootools (1.2+)
license: MIT-style
authors:
- PaquitoSoft
requires: [Core/Element.Style, Core/Element.Event, Core/Element.Dimension, Core/Fx.Tween, Core/Fx.Morph]
provides: [Notimoo]
version: 1.3
...
*/
/*
Script: Notimoo.js
Notimoo - Notification system using Mootools (1.2)
License:
MIT-style license.
Copyright (c) 2009 PaquitoSoft
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions of
the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Author:
PaquitoSoft (http://paquitosoft.com/).
Code & Documentation:
PaquitoSoft blog (http://paquitosoft.com/?page_id=53)
Inspiration:
- Growl by Growl team (http://growl.info/)
- Window.Growl by Daniel Mota (http://icebeat.bitacoras.com/mootools/growl/)
*/
var Notimoo = new Class({
/**
* Notification elements list.
*/
elements: [],
/**
* Needed Mootools functionality
*/
Implements: [Options, Events],
/**
* Used to properly work with the scroll relocation transition
*/
scrollTimeOut: null,
/**
* Options to configure the notification manager.
* @param String parent -> parent element where notifications are to be inserted (defaults to 'body' tag)
* @param Number height -> height of the notification DOM element (in pixels -defaults to 50-)
* @param Number width -> width of the notification DOM element (in pixels -defaults to 300-)
* @param Number visibleTime -> time the notification is displayed (in miliseconds -defaults to 5000-)
* @param String locationVType -> whether you want the notifications to be shown on the top or the bottom of the parent element (defaults to 'top')
* @param String locationHType -> whether you want the notification to be shown at the left or right of the parent element (defaults to 'right')
* @param Number locationVBase -> vertical base position for the notifications (in pixels -defaults to 10-)
* @param Number locationHBase -> horizontal base position for the notifications (in pixels -defaults to 10-)
* @param Number notificationsMargin -> margin between notifications (in pixels -defaults to 5-)
* @param Number opacityTransitionTime -> duration for notification opacity transition (in miliseconds -defaults to 750-)
* @param Number closeRelocationTransitionTime -> duration for notification relocation transition when one of them is close (in miliseconds -defaults to 750-)
* @param Number scrollRelocationTransitionTime -> duration for notification relocation transition when parent scroll is moved (in miliseconds -defaults to 250-)
* @param Number notificationOpacity -> opacity used when the notification is displayed (defaults to 0.95)
* @param Function onShow -> callback to be executed when the notification is displayed. The notification element is passed as a parameter.
* @param Function onClose -> callback to be executed when the notification id closed. The notification element is passed as a parameter.
*/
options: {
parent: '', // This value needs to be set into the initializer
height: 50,
width: 300,
visibleTime: 5000, // notifications are visible for 5 seconds by default
locationVType: 'top',
locationHType: 'right',
locationVBase: 10,
locationHBase: 10,
notificationsMargin: 5,
opacityTransitionTime : 750,
closeRelocationTransitionTime: 500,
scrollRelocationTransitionTime: 500,
notificationOpacity : 0.85 /*,
onShow: $empty,
onClose: $empty */
},
/**
* Initilize instance.
* @param Hash options -> (see code above)
*/
initialize: function(options) {
this.options.parent = document.id(document.body);
if (options) {
if (options.parent) options.parent = document.id(options.parent);
this.setOptions(options);
}
var manager = this;
// Track scroll in parent element
this.options.parent.addEvent('scroll', function() {
clearTimeout(this.scrollTimeOut);
this.scrollTimeOut = (function() { manager._relocateActiveNotifications(manager.TYPE_RELOCATE_SCROLL) }).delay(200);
}, this);
window.addEvent('scroll', function() {
clearTimeout(manager.scrollTimeOut);
manager.scrollTimeOut = (function() { manager._relocateActiveNotifications(manager.TYPE_RELOCATE_SCROLL) }).delay(200);
});
// Insert default element into array
this.elements.push(this.createNotificationElement());
},
/**
* Creates and initializes an element to show the notification
*/
createNotificationElement: function() {
var el = new Element('div', {
'class': 'notimoo',
styles: {
width: this.options.width,
height: this.options.height,
opacity: 0
},
tween: {
link: 'chain',
duration: this.options.opacityTransitionTime
},
events: {
// Close the notification when the user click inside
click: function(e) {
e.stop();
this.close(el);
}.bind(this)
}
})
.setStyle(this.options.locationVType, this.options.locationVBase)
.setStyle(this.options.locationHType, this.options.locationHBase)
.adopt(new Element('span', { 'class': 'nt-title' }))
.adopt(new Element('div', { 'class': 'nt-message' }));
// Element default tween instance is used to handle opacity
el.store('working', false);
// This tween instance is used to move the notification when another one is closed
var fx1 = new Fx.Tween(el, {
property: this.options.locationVType,
link: 'chain',
duration: this.options.closeRelocationTransitionTime
});
el.store('baseTween', fx1);
// This tween instance is used to move the notification when scroll is moved
var fx2 = new Fx.Tween(el, {
property: this.options.locationVType,
link: 'chain',
duration: this.options.scrollRelocationTransitionTime
});
el.store('scrollTween', fx2);
return el;
},
/**
* Function to actually show a notification.
* @param String title (required) -> Title for the notification
* @param String message (required) -> Message for the notification
* @param booleam sticky (optional) -> Whether the notification won't be removed until user interaction (defaults to false)
* @param int visibleTime (optional) -> Time for the notification to be displayed (in milliseconds). If this isn't provided, the global one will be used.
* @param int width (optional) -> Width fot the notification (in pixels). If this isn't provided, the global one will be used.
* @param String customClass (optional) -> Custom class you want to apply to this notification. (It can be a list of classes separated by a blank space)
*/
show: function(options) {
var manager = this;
// Get the base for the notification
var nextBase = this._applyScrollPosition(this.options.locationVBase);
var el = this.elements.filter(function(el) {
var w = el.retrieve('working');
if (w) {
nextBase = el.getStyle(this.options.locationVType).toInt() + el.getSize().y + this.options.notificationsMargin;
}
return !w;
}, this).getLast();
// Create element if there is no available one
if (!el) {
el = this.createNotificationElement();
this.elements.push(el);
}
// Set base and 'working' flag
el.setStyle(this.options.locationVType, nextBase);
el.store('working', true);
// Check if a custom width has been provided
if (options.width) el.setStyle('width', options.width);
// Set notification content
// Since title is optional and we're reusing notifications, we need to check
el.getElement('span.nt-title').set('text', (options.title) ? options.title : '');
el.getElement('div.nt-message').set('text', options.message);
// Add custom classes
if (options.customClass) el.addClass(options.customClass);
// Once the notification is populated, we check to see if there is any link inside so we can
// configure it in order not to close the notification when it's clicked
el.getElements('a').addEvent('click', function(event) {
event.stopPropagation();
});
// Insert the element into the DOM
this.options.parent.adopt(el);
// This must be done after the element is inserted into DOM. Previously (on Lost!) the element does not have coordinates (obviously)
this._checkSize(el);
// Show the element with a lot of style
el.get('tween').start('opacity', this.options.notificationOpacity).chain(function() {
// Set close notification with options visibleTime delay
if ((options.sticky) ? !options.sticky : true) {
manager.close.delay((options.visibleTime) ? options.visibleTime : manager.options.visibleTime, manager,el);
//(function() { manager.close(el); } ).delay((options.visibleTime) ? options.visibleTime : manager.options.visibleTime, manager);
}
// Fire callback
manager.fireEvent('show', el);
});
},
/**
* Function to close the notification.
* It also deals with moving other still visible notifications.
* @param Element element -> element to be removed
*/
close: function(element) {
// Hide and reset notification. Destroy it when it's not the last one.
var manager = this;
var nots = manager.elements;
element.get('tween')
.addEvent('onComplete',function(){
element.destroy();
//element.dispose();
})
.start('opacity', 0).chain(function() {
var toDelete=false;
if (nots.length > 1) {
nots.elements = nots.erase(element);
toDelete=true;
} else {
manager._resetNotificationElement(element);
}
// If there are more notifications on screen, move them!
manager._relocateActiveNotifications(manager.TYPE_RELOCATE_CLOSE);
manager.fireEvent('close', element);
if (toDelete) element.destroy();
//element.dispose();
});
},
/**
* Function to relocate active notifications when needed
* (notification closed or scroll moved).
* @param int sourceEvent -> the event that cause the movement (see events at the bottom)
* 1.- notification closed
* 2.- scroll moved
*/
_relocateActiveNotifications: function(sourceEvent) {
var base = this._applyScrollPosition(this.options.locationVBase);
for (var index = 0; index < this.elements.length; index++) {
var el = this.elements[index];
if (el.retrieve('working')) {
if (this.TYPE_RELOCATE_CLOSE == sourceEvent) {
el.retrieve('baseTween').start(base);
} else {
el.retrieve('scrollTween').start(base);
}
base += el.getSize().y + this.options.notificationsMargin;
}
}
},
/**
* Function to check if the size of the notification element has space enough
* to show the message.
* In case it hasn't, the element is resized.
*/
_checkSize: function(element) {
var notificationElHeight = element.getStyle('height').toInt();
var titleHeight = element.getElement('span.nt-title').getSize().y;
var messageHeight = element.getElement('div.nt-message').getSize().y;
if (messageHeight > (notificationElHeight - titleHeight)) {
element.setStyle('height', notificationElHeight + (messageHeight - (notificationElHeight - titleHeight)));
}
},
/**
* Function used to reset the attributes of a used element to the original state.
* It only resets the attributes that could be changed before.
*/
_resetNotificationElement: function(element) {
var styles = {
height: this.options.height,
widht: this.options.width
};
styles[this.options.locationVType] = this.options.locationVBase;
element.setStyles(styles).store('working', false);
},
/**
* Helper function to apply scroll location to element base.
*/
_applyScrollPosition: function(base) {
var y = this.options.parent.getScroll().y;
if(this.options.locationVType != 'top') y = -y;
return base + y;
},
/*
* Constants for transitions
*/
TYPE_RELOCATE_CLOSE: 1,
TYPE_RELOCATE_SCROLL: 2
});