1 /**
  2  * Creates a new notification and attaches it to the target selector. If the
  3  * selector matches more than one element, the first one is taken.
  4  * 
  5  * @constructor
  6  * @param {String} targetSelector
  7  * @param [options] the options
  8  * @param {String} [options.title] the title of the notification
  9  * @param {String} [options.content] the content
 10  * @param {String} [options.position] possible values: topLeft, topMiddle,
 11  *            topRight, rightTop, rightMiddle, rightBottom, bottomLeft,
 12  *            bottomMiddle, bottomRight, leftTop, leftMiddle, leftBottom
 13  * @param {Integer} [options.padding]
 14  * @param {Integer} [options.expires]
 15  * @param {Boolean} [options.closeButton]
 16  * @param {Integer} [options.maxWidth]
 17  * @param {String} [options.type] possible values: info, warn, error
 18  */
 19 mindmaps.Notification = function(targetSelector, options) {
 20 	var self = this;
 21 	options = $.extend({}, mindmaps.Notification.Defaults, options);
 22 
 23 	// render template
 24 	var $notification = this.$el = $("#template-notification").tmpl(options)
 25 			.css({
 26 				"max-width" : options.maxWidth
 27 			}).addClass(options.type);
 28 
 29 	// notification target
 30 	var $target = $(targetSelector);
 31 	if ($target.length === 0) {
 32 		/**
 33 		 * Return unfinished, invisible notification if selector didn't match.
 34 		 * It will simply not show up, and does not have to be handled specially
 35 		 * by the caller.
 36 		 */
 37 		return this;
 38 	}
 39 
 40 	var offset = $target.offset();
 41 	var targetLeft = offset.left;
 42 	var targetTop = offset.top;
 43 	var targetWidth = $target.outerWidth();
 44 	var targetHeight = $target.outerHeight();
 45 
 46 	// add to dom. we need measurings
 47 	$notification.appendTo($("body"));
 48 	var notiWidth = $notification.outerWidth();
 49 	var notiHeight = $notification.outerHeight();
 50 	var notiLeft, notiTop;
 51 	var padding = options.padding;
 52 
 53 	// position
 54 	switch (options.position) {
 55 
 56 	case "topLeft":
 57 		notiTop = targetTop - padding - notiHeight;
 58 		notiLeft = targetLeft;
 59 		break;
 60 	case "topMiddle":
 61 		notiTop = targetTop - padding - notiHeight;
 62 		if (notiWidth < targetWidth) {
 63 			notiLeft = targetLeft + (targetWidth - notiWidth) / 2;
 64 		} else {
 65 			notiLeft = targetLeft - (notiWidth - targetWidth) / 2;
 66 		}
 67 		break;
 68 	case "topRight":
 69 		notiTop = targetTop - padding - notiHeight;
 70 		notiLeft = targetLeft + targetWidth - notiWidth;
 71 		break;
 72 	case "rightTop":
 73 		notiTop = targetTop;
 74 
 75 		break;
 76 	case "rightMiddle":
 77 		if (notiHeight < targetHeight) {
 78 			notiTop = targetTop + (targetHeight - notiHeight) / 2;
 79 		} else {
 80 			notiTop = targetTop - (notiHeight - targetHeight) / 2;
 81 		}
 82 		notiLeft = targetLeft + padding + targetWidth;
 83 		break;
 84 	case "rightBottom":
 85 		notiTop = targetTop + targetHeight - notiHeight;
 86 		notiLeft = targetLeft + padding + targetWidth;
 87 		break;
 88 	case "bottomLeft":
 89 		notiTop = targetTop + padding + targetHeight;
 90 		notiLeft = targetLeft;
 91 		break;
 92 	case "bottomMiddle":
 93 		notiTop = targetTop + padding + targetHeight;
 94 		if (notiWidth < targetWidth) {
 95 			notiLeft = targetLeft + (targetWidth - notiWidth) / 2;
 96 		} else {
 97 			notiLeft = targetLeft - (notiWidth - targetWidth) / 2;
 98 		}
 99 		break;
100 	case "bottomRight":
101 		notiTop = targetTop + padding + targetHeight;
102 		notiLeft = targetLeft + targetWidth - notiWidth;
103 		break;
104 	case "leftTop":
105 		notiTop = targetTop;
106 		notiLeft = targetLeft - padding - notiWidth;
107 		break;
108 	case "leftMiddle":
109 		if (notiHeight < targetHeight) {
110 			notiTop = targetTop + (targetHeight - notiHeight) / 2;
111 		} else {
112 			notiTop = targetTop - (notiHeight - targetHeight) / 2;
113 		}
114 		notiLeft = targetLeft - padding - notiWidth;
115 		break;
116 	case "leftBottom":
117 		notiTop = targetTop + targetHeight - notiHeight;
118 		notiLeft = targetLeft - padding - notiWidth;
119 		break;
120 	}
121 
122 	$notification.offset({
123 		left : notiLeft,
124 		top : notiTop
125 	});
126 
127 	// fadeout?
128 	if (options.expires) {
129 		setTimeout(function() {
130 			self.close();
131 		}, options.expires);
132 	}
133 
134 	// close button
135 	if (options.closeButton) {
136 		$notification.find(".close-button").click(function() {
137 			self.close();
138 		});
139 	}
140 
141 	// display
142 	$notification.fadeIn(600);
143 };
144 
145 mindmaps.Notification.prototype = {
146 	/**
147 	 * Removes the notification.
148 	 */
149 	close : function() {
150 		var n = this.$el;
151 		n.fadeOut(800, function() {
152 			n.remove();
153 			this.removed = true;
154 		});
155 	},
156 	/**
157 	 * Returns whether the notification is still on screen.
158 	 * 
159 	 * @returns {Boolean}
160 	 */
161 	isVisible : function() {
162 		return !this.removed;
163 	},
164 	/**
165 	 * Returns the element as a jQuery object.
166 	 * 
167 	 * @returns {jQuery}
168 	 */
169 	$ : function() {
170 		return this.$el;
171 	}
172 };
173 
174 /**
175  * The default options.
176  */
177 mindmaps.Notification.Defaults = {
178 	title : null,
179 	content : "New Notification",
180 	position : "topLeft",
181 	padding : 10,
182 	expires : 0,
183 	closeButton : false,
184 	maxWidth : 500,
185 	type : "info"
186 };