1 /** Provides a managed notification/toast display area.
  2  *	@constructor Creates a new Notifier instance.
  3  *	@augments puredom.EventEmitter
  4  *	@param {Object} [options]	Hashmap of options
  5  *	@param {puredom.NodeSelection} [options.parent]		Construct the display area within a given element.
  6  */
  7 puredom.Notifier = function(options) {
  8 	var self = this;
  9 	
 10 	puredom.EventEmitter.call(this);
 11 	this._data = {
 12 		counter : 0,
 13 		list : {}
 14 	};
 15 	
 16 	this._notificationClickHandler = function(e) {
 17 		self._performAction(puredom.el(this).attr('data-notification-id'), 'notificationclick', e);
 18 		return puredom.cancelEvent(e);
 19 	};
 20 	
 21 	options = options || {};
 22 	if (options.parent) {
 23 		this._createBase(options.parent);
 24 	}
 25 };
 26 
 27 
 28 puredom.inherits(puredom.Notifier, puredom.EventEmitter);
 29 
 30 
 31 puredom.extend(puredom.Notifier.prototype, /** @lends puredom.Notifier# */ {
 32 
 33 	/**	Show a notification.
 34 	 *	@param {Object} config	Describes what to display
 35 	 *	@param {Object} [config.message]	The text to display
 36 	 *	@param {Object} [config.icon]		Icon/image to show next to the text
 37 	 *	@param {Object} [config.image]		Icon/image to show next to the text
 38 	 *	@param {Object} [config.timeout=Notifier.timeout]	How many seconds to wait before auto-dismissing the notification
 39 	 */
 40 	show : function(config) {
 41 		var notify;
 42 		if (config) {
 43 			this._data.counter += 1;
 44 			notify = {
 45 				id : this._data.counter + '',
 46 				timeout : config.timeout || this.timeout
 47 			};
 48 			this._data.list[notify.id] = notify;
 49 			
 50 			notify.base = this._build(notify.id, config);
 51 			this._show(notify.id);
 52 			
 53 			if (notify.timeout) {
 54 				this._resetTimeout(notify.id);
 55 			}
 56 			return notify;
 57 		}
 58 		return false;
 59 	},
 60 	
 61 
 62 	/**	@private */
 63 	_createBase : function(parent) {
 64 		if (this.notifications_base) {
 65 			this.notifications_base.remove();
 66 			this.notifications_base.appendTo(parent);
 67 		}
 68 		else {
 69 			this.notifications_base = puredom.el({
 70 				className : 'notifications_base'
 71 			}, parent);
 72 		}
 73 	},
 74 	
 75 
 76 	/**	@private */
 77 	_build : function(id, options) {
 78 		var base, iconSrc;
 79 		base = puredom.el({
 80 			className : "notification",
 81 			css : 'height:0; opacity:0;',
 82 			attributes : {
 83 				'data-notification-id' : id
 84 			},
 85 			children : [
 86 				{ className:'notification_top' },
 87 				{
 88 					className : 'notification_inner',
 89 					children : [
 90 						{ className:'notification_inner_top' },
 91 						{
 92 							className : 'notification_closeButton',
 93 							children : [
 94 								{ className:'label', innerHTML:this.closeButtonLabel || '×' }
 95 							]
 96 						},
 97 						{
 98 							className : 'notification_message',
 99 							children : [
100 								{ className:'label', innerHTML:options.message || options.text }
101 							]
102 						},
103 						{ className:'notification_inner_bottom' }
104 					]
105 				},
106 				{ className:'notification_bottom' }
107 			],
108 			onclick : this._notificationClickHandler
109 		}, this.notifications_base);
110 		
111 		// add an icon if specified
112 		iconSrc = options.icon || options.image;
113 		if (iconSrc!==false && this.defaultIcon) {
114 			iconSrc = this.defaultIcon;
115 		}
116 		if (iconSrc) {
117 			puredom.el({
118 				type : 'img',
119 				className : 'notification_message',
120 				attributes : {
121 					src : options.icon || options.image || this.defaultIcon
122 				}
123 			}, base.query('.notification_inner'));
124 		}
125 		
126 		if (options.userDismiss===false) {
127 			base.query('.notification_closeButton').hide(true);
128 		}
129 		
130 		return base;
131 	},
132 	
133 
134 	/**	@private */
135 	_show : function(id) {
136 		var notify = this.get(id);
137 		if (notify) {
138 			notify.base.css({
139 				opacity : 0
140 			}).css({
141 				opacity : 1,
142 				height : notify.base.children().height()
143 			}, {tween:this.showTween || 'medium'});
144 		}
145 	},
146 	
147 
148 	/**	@private*/
149 	_hide : function(id) {
150 		var notify = this.get(id);
151 		if (notify) {
152 			notify.base.css({
153 				opacity : 0,
154 				height : 0
155 			}, {tween:this.hideTween || 'medium', callback:function() {
156 				notify.base.remove();
157 				notify = null;
158 			}});
159 		}
160 	},
161 	
162 
163 	/**	@private */
164 	_resetTimeout : function(id) {
165 		var notify = this.get(id),
166 			self = this;
167 		if (notify) {
168 			if (notify._hideTimer) {
169 				clearTimeout(notify._hideTimer);
170 			}
171 			if (notify.timeout) {
172 				notify._hideTimer = setTimeout(function() {
173 					self._hide(id);
174 					self = id = null;
175 				}, notify.timeout*1000);
176 			}
177 			notify = null;
178 		}
179 	},
180 	
181 
182 	/** Get a notification by ID */
183 	get : function(id) {
184 		return id && this._data.list.hasOwnProperty(id+'') && this._data.list[id+''] || false;
185 	},
186 	
187 
188 	/**	@private */
189 	_performAction : function(id, action, args) {
190 		var notify = this.get(id),
191 			ret;
192 		if (!puredom.isArray(args)) {
193 			args = [args];
194 		}
195 		if (action && notify) {
196 			args = [id].concat(args);
197 			ret = this.fireEvent(action, args);
198 			if (ret!==false) {
199 				switch (action.toLowerCase()) {
200 					case 'notificationclick':
201 					case 'notificationclicked':
202 						this._hide(id);
203 						break;
204 				}
205 			}
206 		}
207 	},
208 	
209 
210 	/**	@private */
211 	timeout : 15,
212 	
213 
214 	/**	@private */
215 	_data : {
216 		counter : 0,
217 		list : {}
218 	}
219 });