1/** 2 * notyfy - Yet another jQuery Notification Plugin v 3 * 4 * Based on the original notyfy plugin: https://needim.github.com/notyfy/ 5 * 6 * Examples and Documentation - http://craga89.github.com/notyfy/ 7 * 8 * Licensed under the MIT licenses: 9 * http://www.opensource.org/licenses/mit-license.php 10 * 11 **/ 12(function($) { 13 14 function NotyfyObject(options) { 15 var self = this; 16 17 $.extend(self, { 18 container: $('#notyfy_container_'+options.layout), 19 closed: true, 20 shown: false, 21 22 _triggerEvent: function(type, args) { 23 var callback = $.Event('notyfy'+type); 24 self.wrapper.trigger(callback, [self].concat(args || [])); 25 return !callback.isDefaultPrevented(); 26 }, 27 28 _generateID: function() { 29 var id; do{ 30 id = 'notyfy_' + (new Date().getTime() * Math.floor(Math.random() * 1000000)); 31 } 32 while(document.getElementById(id)); 33 return id; 34 }, 35 36 init: function() { 37 var adjuster; 38 39 // Mix in the passed in options with the default options 40 self.options = $.extend({}, $.notyfy.defaults, { id: self._generateID() }, options); 41 42 // Generate notyfy container ifneeded 43 if(!self.container.length) { 44 // Use custom container ifprovided 45 if(options.custom) { 46 self.container = options.custom.addClass('notyfy_container_inline'); 47 } 48 49 // Otherwise create one using jQuery 50 else { 51 self.container = $('<ul />', { 52 'id': 'notyfy_container_'+self.options.layout, 53 'class': 'notyfy_container' 54 }) 55 .appendTo(self.options.custom || document.body); 56 } 57 58 // Apply any layout adjuters on window resize 59 if((adjuster = $.notyfy.layouts[self.options.layout])) { 60 $(window).bind('resize.'+self.options.id, function(event) { 61 adjuster.call(self.container); 62 }) 63 .triggerHandler('resize.'+self.options.id); 64 } 65 66 // Add new class 67 self.container.addClass('i-am-new'); 68 } 69 70 // Not needed? Remove new class 71 else { self.container.removeClass('i-am-new'); } 72 73 // Build the notyfy dom initial structure 74 self._build(); 75 76 return self; 77 }, 78 79 _build: function() { 80 // Generate notyfy bar 81 var bar = $('<div />', { 82 'id': self.options.id, 83 'class': "notyfy_bar" 84 }) 85 .append(self.options.template) 86 .find('.notyfy_text') 87 .html(self.options.text).end(); 88 89 // Generate notyfy container 90 self.wrapper = $('<li />', { 91 'class': ['notyfy_wrapper', 'notyfy_'+self.options.type].join(' ') 92 }).hide().append(bar); 93 94 // Apply theme class 95 if(self.options.theme) { self.wrapper.addClass('notyfytheme_'+self.options.theme); } 96 97 // Set buttons ifavailable 98 if(self.options.buttons) { 99 self.options.closeWith = []; 100 self.options.timeout = true; 101 102 self.buttons = $('<div/>', { 103 'class': 'notyfy_buttons' 104 }) 105 .appendTo( $('.notyfy_bar', self.wrapper) ) 106 .append( 107 $.map(self.options.buttons, function(button, i) { 108 return $('<button/>', { 109 'class': button.addClass || 'gray', 110 'html': button.text, 111 'click': function() { 112 if($.isFunction(button.onClick)) { 113 button.onClick.call( $(this), self ); 114 } 115 } 116 })[0] 117 }) 118 ); 119 } 120 121 // Attach events 122 $.each(self.options.events, function(event, callback) { 123 if($.isFunction(callback)) { 124 self.wrapper.bind('notyfy'+event, callback); 125 } 126 }) 127 128 // For easy access 129 self.message = self.wrapper.find('.notyfy_message'); 130 self.closeButton = self.wrapper.find('.notyfy_close'); 131 132 // store notyfy for api 133 $.notyfy.store[self.options.id] = self; 134 }, 135 136 show: function(event) { 137 // Append the container 138 self.wrapper.appendTo(self.container); 139 140 // Add close handlers to notyfy/buttons 141 if($.inArray('click', self.options.closeWith) > -1) { 142 self.wrapper.css('cursor', 'pointer').one('click', self.close); 143 } 144 if($.inArray('hover', self.options.closeWith) > -1) { 145 self.wrapper.one('mouseenter', self.close); 146 } 147 if($.inArray('button', self.options.closeWith) > -1) { 148 self.closeButton.one('click', self.close); 149 } 150 if($.inArray('button', self.options.closeWith) == -1) { 151 self.closeButton.remove(); 152 } 153 154 // Trigger show event 155 self._triggerEvent('show'); 156 157 // After-animation methods 158 function after() { 159 self._triggerEvent('shown'); 160 self.shown = true; 161 } 162 163 // If an animation method was passed, use it and queue after() 164 if($.isFunction(self.options.showEffect)) { 165 self.wrapper.clearQueue().stop(); 166 self.options.showEffect.call(self, self.wrapper); 167 self.wrapper.queue(after); 168 } 169 170 // Otherwise just invoke show() and after() 171 else { self.wrapper.show(); after(); } 172 173 // If notyfy is have a timeout option 174 if(self.options.timeout) { 175 clearTimeout(self._delay); 176 self._delay = setTimeout(function() { 177 self.close(); 178 }, parseInt(self.options.timeout, 10)); 179 } 180self.close(); 181 return self; 182 183 }, 184 185 close: function(event) { 186 if(self.closed) return; 187 188 // If we are still waiting in the queue just delete from queue 189 if(!self.shown) { 190 $.notyfy.queue = $.map($.notyfy.queue, function(n ,i) { 191 if(n.options.id != self.options.id) { 192 return n; 193 } 194 }); 195 return; 196 } 197 198 // Add closing class 199 self.wrapper.addClass('i-am-closing-now'); 200 201 // Trigger hide event 202 self._triggerEvent('hide'); 203 204 function after() { 205 // Trigger hidden event 206 self._triggerEvent('hidden'); 207 208 // Modal Cleaning 209 if(self.options.modal) { renderer.hideModalFor(self); } 210 211 // Layout Cleaning 212 renderer.setLayoutCountFor(self, -1); 213 if(renderer.getLayoutCountFor(self) == 0) { self.wrapper.remove(); } 214 215 // Make sure self.wrapper has not been removed before attempting to remove it 216 if(typeof self.wrapper !== 'undefined' && self.wrapper !== null) { 217 self.wrapper.remove(); 218 self.wrapper = null; 219 self.closed = true; 220 } 221 222 // Delete notyfy reference from store 223 delete $.notyfy.store[self.options.id]; 224 225 // Queue render 226 if(!self.options.dismissQueue) { 227 $.notyfy.ontap = true; 228 renderer.render(); 229 } 230 } 231 232 // If an animation method was passed, use it and queue after() 233 if($.isFunction(self.options.hideEffect)) { 234 self.wrapper.clearQueue().stop(); 235 self.options.hideEffect.call(self, self.wrapper); 236 self.wrapper.queue(after); 237 } 238 239 // Otherwise just invoke show() and after() 240 else { self.wrapper.hide(); after(); } 241 242 }, 243 244 setText: function(text) { 245 if(!self.closed) { 246 self.options.text = text; 247 self.wrapper.find('.notyfy_text').html(text); 248 } 249 return self; 250 }, 251 252 setType: function(type) { 253 if(!self.closed) { 254 self.options.type = type; 255 } 256 return self; 257 } 258 }); 259 260 self.init(); 261 }; 262 263 var renderer = $.notyfyRenderer = { 264 _modal: $('<div/>', { 265 'id': 'notyfy_modal', 266 'data': { 'notyfy_modal_count': 0 } 267 }), 268 _modals: 0, 269 270 init: function(options) { 271 // Create new Noty 272 var notyfy = new NotyfyObject(options); 273 274 // Add it to the frontback of the queue depending on options 275 $.notyfy.queue[notyfy.options.force ? 'unshift' : 'push'](notyfy); 276 277 // Render the notyfy 278 renderer.render(); 279 280 return notyfy; 281 }, 282 283 render: function() { 284 var instance = $.notyfy.queue[0]; 285 286 if($.type(instance) === 'object') { 287 if(instance.options.dismissQueue) { 288 renderer.show($.notyfy.queue.shift()); 289 } else { 290 if($.notyfy.ontap) { 291 renderer.show($.notyfy.queue.shift()); 292 $.notyfy.ontap = false;
293 } 294 } 295 } 296 297 // Queue is over 298 else { $.notyfy.ontap = true; } 299 }, 300 301 show: function(notyfy) { 302 if(notyfy.options.modal) { 303 renderer.createModalFor(notyfy); 304 renderer.setModalCount(+1); 305 } 306 307 renderer.setLayoutCountFor(notyfy, +1); 308 309 notyfy.show(); 310 }, 311 312 createModalFor: function(notyfy) { 313 if(!renderer._modal[0].parentNode) { 314 renderer._modal.prependTo(document.body).fadeIn('fast'); 315 } 316 }, 317 318 hideModalFor: function(notyfy) { 319 renderer.setModalCount(-1); 320 321 if(renderer.getModalCount() == 0) { 322 renderer._modal.fadeOut('fast', function() { 323 renderer._modal.detach(); 324 }); 325 } 326 }, 327 328 getLayoutCountFor: function(notyfy) { 329 return notyfy.container.data('notyfy_layout_count') || 0; 330 }, 331 332 setLayoutCountFor: function(notyfy, arg) { 333 return notyfy.container.data('notyfy_layout_count', renderer.getLayoutCountFor(notyfy) + arg); 334 }, 335 336 getModalCount: function() { return renderer._modals; }, 337 setModalCount: function(arg) { return (renderer._modals += arg); } 338 }; 339 340 var win = $(window); 341 342 $.notyfy = { 343 ontap: true, 344 queue: [], 345 store: {}, 346 layouts: { 347 center: function() { 348 this[0].style.top = (win.height() / 2 - this.outerHeight() / 2) + 'px'; 349 this[0].style.left = (win.width() / 2 - this.outerWidth() / 2) + 'px'; 350 }, 351 centerLeft: function() { 352 this[0].style.top = (win.height() / 2 - this.outerHeight() / 2) + 'px'; 353 }, 354 centerRight: function() { 355 this[0].style.top = (win.height() / 2 - this.outerHeight() / 2) + 'px'; 356 }, 357 topCenter: function() { 358 this[0].style.left = (win.width() / 2 - this.outerWidth() / 2) + 'px'; 359 }, 360 bottomCenter: function() { 361 this[0].style.left = (win.width() / 2 - this.outerWidth() / 2) + 'px'; 362 } 363 }, 364 365 get: function(id) { 366 return $.notyfy.store.hasOwnProperty(id) ? $.notyfy.store[id] : false; 367 }, 368 369 close: function(id) { 370 return $.notyfy.get(id) ? $.notyfy.get(id).close() : false; 371 }, 372 373 setText: function(id, text) { 374 return $.notyfy.get(id) ? $.notyfy.get(id).setText(text) : false; 375 }, 376 377 setType: function(id, type) { 378 return $.notyfy.get(id) ? $.notyfy.get(id).setType(type) : false; 379 }, 380 381 clearQueue: function() { 382 $.notyfy.queue = []; 383 }, 384 385 closeAll: function() { 386 $.notyfy.clearQueue(); 387 $.each($.notyfy.store, function(id, notyfy) { 388 notyfy.close(); 389 }); 390 }, 391 392 consumeAlert: function(options) { 393 window.alert = function(text) { 394 if(options) { 395 options.text = text; 396 } 397 else { 398 options = { text: text }; 399 } 400 renderer.init(options); 401 }; 402 }, 403 404 stopConsumeAlert: function() { 405 delete window.alert; 406 }, 407 408 defaults: { 409 layout: 'top', 410 theme: false, 411 type: 'alert', 412 text: '', 413 dismissQueue: true, 414 template: '<div class="notyfy_message"><span class="notyfy_text"></span><div class="notyfy_close"></div></div>', 415 showEffect: function(bar) { bar.animate({ height: 'toggle' }, 500, 'swing'); }, 416 hideEffect: function(bar) { bar.animate({ height: 'toggle' }, 500, 'swing'); }, 417 timeout: true, 418 force: false, 419 modal: false,
420 buttons: false, 421 closeWith: ['click'], 422 events: { 423 show: null, 424 hide: null, 425 shown: null, 426 hidden: null 427 } 428 } 429 }; 430 431 // Helper method 432 window.notyfy = function(options) { 433 return renderer.init(options); 434 } 435 436 // This is for custom container 437 $.fn.notyfy = function(options) { 438 options.custom = $(this); 439 return renderer.init(options); 440 }; 441 442})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.