├── .gitignore ├── Gruntfile.js ├── LICENSE ├── README.md ├── bootstrap-notify.js ├── bootstrap-notify.min.js ├── bower.json ├── composer.json ├── jshintrc.json ├── package.js ├── package.json ├── test_meteor.js └── typings └── bootstrap-notify └── notify.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | // Project configuration. 3 | grunt.initConfig({ 4 | pkg: grunt.file.readJSON('package.json'), 5 | uglify: { 6 | options: { 7 | compress: { 8 | drop_console: true 9 | }, 10 | preserveComments: 'some' 11 | }, 12 | default: { 13 | files: { 14 | 'bootstrap-notify.min.js': ['bootstrap-notify.js'] 15 | } 16 | } 17 | }, 18 | jshint: { 19 | options: { 20 | jshintrc: 'jshintrc.json' 21 | }, 22 | default: { 23 | src: 'bootstrap-notify.js' 24 | } 25 | }, 26 | exec: { 27 | 'meteor-test': 'node_modules/.bin/spacejam test-packages ./' 28 | } 29 | }); 30 | 31 | grunt.loadNpmTasks('grunt-contrib-uglify'); 32 | grunt.loadNpmTasks('grunt-contrib-jshint'); 33 | grunt.loadNpmTasks('grunt-exec'); 34 | 35 | grunt.registerTask('test', ['jshint', 'exec:meteor-test']); 36 | grunt.registerTask('default', ['uglify']); 37 | }; 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Robert McIntosh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap Notify 2 | This is a simple plugin that turns standard Bootstrap alerts into "Growl-like" notifications. 3 | 4 | ## Manual Download - Stable Release 5 | If toy would like to download the latest stable release please follow the link below 6 | - [Stable Release](https://github.com/mouse0270/bootstrap-notify/releases/latest) 7 | 8 | Please keep in mind that the master branch may contain bugs or broken code. Please use the link above if you are not able to debug and correct issues in the master branch. Thank you. 9 | 10 | ## Bower Officially Supported 11 | I would like to thank [Błażej Krysiak](https://github.com/IjinPL) for doing this! 12 | ``` 13 | bower install remarkable-bootstrap-notify 14 | ``` 15 | 16 | ## Meteor Officially Supported 17 | Meteor integration by [zimme](https://github.com/zimme). 18 | 19 | ```sh 20 | meteor add mouse0270:bootstrap-notify 21 | ``` 22 | 23 | ## Changelog 24 | #### Version 3.1.5 provided by [chrismbarr](https://github.com/chrismbarr) - *Testing* 25 | - Cleaned Up Code 26 | - Fixed Spelling 27 | - Added Option to prevent Duplicate Notifications 28 | - TypeScript Definitions File 29 | 30 | ##### Version 3.1.3 - *Stable Release* 31 | - Added Meteor Support 32 | - Fixed issue with Glyphicons Pro 33 | - Updating version pattern. 34 | ``` 35 | x.y.z 36 | x = Main version of the plugin 37 | y = New features were added to the plugin 38 | z = Fixes/patches to existing features of the plugin 39 | ``` 40 | 41 | ##### [Version 3.0.2](http://bootstrap-notify.remabledesigns.com/3.0.2/) 42 | - Fixed update for backwards compatibility 43 | 44 | ##### [Version 3.0.1](http://bootstrap-notify.remabledesigns.com/3.0.1/) 45 | - Add the ability to update multiple values in one call 46 | - Turn off Progress bar 47 | - Set Progress bar value / Progress bar not shown by default 48 | ``` javascript 49 | //Update 50 | var notify = $.notify('Saving Do not close this page...', { allow_dismiss: false }); 51 | notify.update({ type: 'success', 'Success Your page has been saved!' }); 52 | 53 | // Turn of Progress bar on 54 | $.notify('I have a progress bar', { showProgressbar: true }); 55 | 56 | // Update Progress bar 57 | var notify = $.notify('Saving Do not close this page...', { allow_dismiss: false }); 58 | notify.update({ type: 'warning', 'Oops Something happened. Correcting Now', progress: 20 }); 59 | ``` 60 | 61 | ##### [Version 3.0.0](http://bootstrap-notify.remabledesigns.com/3.0.0/) 62 | - New template structure 63 | - Better event handling for onShow, onShown, onClose, onClosed 64 | - updating notification content will reposition growls below it 65 | - Fixed updating icon images 66 | - Fixed IE Issues with Growl URL not being able to be clicked on 67 | - Added the ability to show progress bars 68 | - Added the ability to pass position in the settings 69 | - Added *_newest_on_top_* option that allows new growls to push down old growls 70 | - Added Transition CSS to plugin 71 | ```css 72 | transition: all 0.5 ease-in-out; 73 | ``` 74 | - Remember to read to documentation. I use custom css style's for the progress bar that you can find there. This was left out of the plugin so you could choose to use the default progressbar styles provided for bootstrap or write your own. 75 | 76 | ##### [Version 2.0.1](http://bootstrap-growl.remabledesigns.com/2.0.1/) 77 | - Added the ability to set an X and Y value within the offset option 78 | - Added callback options onShow, onShown, onHide and onHidden 79 | - Added a close all method to close all open growls 80 | 81 | ##### [Version 2.0.0a3](http://bootstrap-growl.remabledesigns.com/2.0.0a3/) 82 | - Fixed issue with growl not closing if there was no CSS animations 83 | 84 | ##### [Version 2.0.0a2](http://bootstrap-growl.remabledesigns.com/2.0.0a2/) (with IE8 Support) 85 | - Changed animate.in to animate.enter for IE8 compatibility 86 | - Changed animate.out to animate.exit for IE8 compatibility 87 | - Modified .is(':hover') for IE8 compatibility 88 | 89 | ##### [Version 2.0.0a1](http://bootstrap-growl.remabledesigns.com/2.0.0a1/) 90 | - Better Minification 91 | 92 | ##### [Version 2.0.0a](http://bootstrap-growl.remabledesigns.com/2.0.0a1/) 93 | - Major rewright of the plugin file. 94 | - Added the ability to pass the growl a link making it clickable. 95 | - Added the ability to control the growl animations in and out using css. 96 | - Added the ability to set growl settings globally. 97 | - Removed jQuery fadeIn (use css to control growl animations) 98 | 99 | ##### [Version 1.0.6](http://bootstrap-growl.remabledesigns.com/1.0.6/) 100 | - Added onGrowlShow and onGrowlShown callback functionality. 101 | 102 | ##### Version 1.0.5 103 | - Better positioning when using CSS animations after growl closes. 104 | 105 | ##### Version 1.0.4 106 | - Updated $.growl() to return a wrapper object with a small API to let you control individual notifications after they have been created. 107 | - Added onGrowlClose and onGrowlClosed callback functionality. 108 | 109 | ##### Version 1.0.3 110 | - Made jQuery $.extend() Recursive so when you change just one option under position or template the script wont fail 111 | 112 | ##### Version 1.0.2 113 | - Fixed an issue where $.growl("message") would thrown an exception | Provided by [DannyJo](https://github.com/DannyJo/bootstrap-growl) 114 | 115 | ##### Version 1.0.0 116 | - Initial Release 117 | 118 | ## Demo and Documentation 119 | - [Demo](http://bootstrap-growl.remabledesigns.com/) 120 | - [Documentation](http://bootstrap-notify.remabledesigns.com/#documentation) 121 | 122 | NOTE: Some users have reported an issue where the demo/documentation links repsond with only `pageok` in the body. If that occurs for you, try emptying your browser cache or an alternate browser. 123 | 124 | ## Dependencies 125 | - [jQuery v1.10.2](http://jquery.com/) 126 | - [Bootstrap v2.0.0 - 3.2.0](http://getbootstrap.com/) 127 | 128 | ## Copyright and License 129 | The MIT License (MIT) 130 | Copyright (c) 2015 Robert McIntosh 131 | 132 | Permission is hereby granted, free of charge, to any person obtaining a copy of 133 | this software and associated documentation files (the "Software"), to deal in 134 | the Software without restriction, including without limitation the rights to 135 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 136 | the Software, and to permit persons to whom the Software is furnished to do so, 137 | subject to the following conditions: 138 | 139 | The above copyright notice and this permission notice shall be included in all 140 | copies or substantial portions of the Software. 141 | 142 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 143 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 144 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 145 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 146 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 147 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 148 | -------------------------------------------------------------------------------- /bootstrap-notify.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Project: Bootstrap Notify = v3.1.5 3 | * Description: Turns standard Bootstrap alerts into "Growl-like" notifications. 4 | * Author: Mouse0270 aka Robert McIntosh 5 | * License: MIT License 6 | * Website: https://github.com/mouse0270/bootstrap-growl 7 | */ 8 | 9 | /* global define:false, require: false, jQuery:false */ 10 | 11 | (function (factory) { 12 | if (typeof define === 'function' && define.amd) { 13 | // AMD. Register as an anonymous module. 14 | define(['jquery'], factory); 15 | } else if (typeof exports === 'object') { 16 | // Node/CommonJS 17 | factory(require('jquery')); 18 | } else { 19 | // Browser globals 20 | factory(jQuery); 21 | } 22 | }(function ($) { 23 | // Create the defaults once 24 | var defaults = { 25 | element: 'body', 26 | position: null, 27 | type: "info", 28 | allow_dismiss: true, 29 | allow_duplicates: true, 30 | newest_on_top: false, 31 | showProgressbar: false, 32 | placement: { 33 | from: "top", 34 | align: "right" 35 | }, 36 | offset: 20, 37 | spacing: 10, 38 | z_index: 1031, 39 | delay: 5000, 40 | timer: 1000, 41 | url_target: '_blank', 42 | mouse_over: null, 43 | animate: { 44 | enter: 'animated fadeInDown', 45 | exit: 'animated fadeOutUp' 46 | }, 47 | onShow: null, 48 | onShown: null, 49 | onClose: null, 50 | onClosed: null, 51 | onClick: null, 52 | icon_type: 'class', 53 | template: '' 54 | }; 55 | 56 | String.format = function () { 57 | var args = arguments; 58 | var str = arguments[0]; 59 | return str.replace(/(\{\{\d\}\}|\{\d\})/g, function (str) { 60 | if (str.substring(0, 2) === "{{") return str; 61 | var num = parseInt(str.match(/\d/)[0]); 62 | return args[num + 1]; 63 | }); 64 | }; 65 | 66 | function isDuplicateNotification(notification) { 67 | var isDupe = false; 68 | 69 | $('[data-notify="container"]').each(function (i, el) { 70 | var $el = $(el); 71 | var title = $el.find('[data-notify="title"]').html().trim(); 72 | var message = $el.find('[data-notify="message"]').html().trim(); 73 | 74 | // The input string might be different than the actual parsed HTML string! 75 | // (
vs
for example) 76 | // So we have to force-parse this as HTML here! 77 | var isSameTitle = title === $("
" + notification.settings.content.title + "
").html().trim(); 78 | var isSameMsg = message === $("
" + notification.settings.content.message + "
").html().trim(); 79 | var isSameType = $el.hasClass('alert-' + notification.settings.type); 80 | 81 | if (isSameTitle && isSameMsg && isSameType) { 82 | //we found the dupe. Set the var and stop checking. 83 | isDupe = true; 84 | } 85 | return !isDupe; 86 | }); 87 | 88 | return isDupe; 89 | } 90 | 91 | function Notify(element, content, options) { 92 | // Setup Content of Notify 93 | var contentObj = { 94 | content: { 95 | message: typeof content === 'object' ? content.message : content, 96 | title: content.title ? content.title : '', 97 | icon: content.icon ? content.icon : '', 98 | url: content.url ? content.url : '#', 99 | target: content.target ? content.target : '-' 100 | } 101 | }; 102 | 103 | options = $.extend(true, {}, contentObj, options); 104 | this.settings = $.extend(true, {}, defaults, options); 105 | this._defaults = defaults; 106 | if (this.settings.content.target === "-") { 107 | this.settings.content.target = this.settings.url_target; 108 | } 109 | this.animations = { 110 | start: 'webkitAnimationStart oanimationstart MSAnimationStart animationstart', 111 | end: 'webkitAnimationEnd oanimationend MSAnimationEnd animationend' 112 | }; 113 | 114 | if (typeof this.settings.offset === 'number') { 115 | this.settings.offset = { 116 | x: this.settings.offset, 117 | y: this.settings.offset 118 | }; 119 | } 120 | 121 | //if duplicate messages are not allowed, then only continue if this new message is not a duplicate of one that it already showing 122 | if (this.settings.allow_duplicates || (!this.settings.allow_duplicates && !isDuplicateNotification(this))) { 123 | this.init(); 124 | } 125 | } 126 | 127 | $.extend(Notify.prototype, { 128 | init: function () { 129 | var self = this; 130 | 131 | this.buildNotify(); 132 | if (this.settings.content.icon) { 133 | this.setIcon(); 134 | } 135 | if (this.settings.content.url != "#") { 136 | this.styleURL(); 137 | } 138 | this.styleDismiss(); 139 | this.placement(); 140 | this.bind(); 141 | 142 | this.notify = { 143 | $ele: this.$ele, 144 | update: function (command, update) { 145 | var commands = {}; 146 | if (typeof command === "string") { 147 | commands[command] = update; 148 | } else { 149 | commands = command; 150 | } 151 | for (var cmd in commands) { 152 | switch (cmd) { 153 | case "type": 154 | this.$ele.removeClass('alert-' + self.settings.type); 155 | this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass('progress-bar-' + self.settings.type); 156 | self.settings.type = commands[cmd]; 157 | this.$ele.addClass('alert-' + commands[cmd]).find('[data-notify="progressbar"] > .progress-bar').addClass('progress-bar-' + commands[cmd]); 158 | break; 159 | case "icon": 160 | var $icon = this.$ele.find('[data-notify="icon"]'); 161 | if (self.settings.icon_type.toLowerCase() === 'class') { 162 | $icon.removeClass(self.settings.content.icon).addClass(commands[cmd]); 163 | } else { 164 | if (!$icon.is('img')) { 165 | $icon.find('img'); 166 | } 167 | $icon.attr('src', commands[cmd]); 168 | } 169 | self.settings.content.icon = commands[command]; 170 | break; 171 | case "progress": 172 | var newDelay = self.settings.delay - (self.settings.delay * (commands[cmd] / 100)); 173 | this.$ele.data('notify-delay', newDelay); 174 | this.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', commands[cmd]).css('width', commands[cmd] + '%'); 175 | break; 176 | case "url": 177 | this.$ele.find('[data-notify="url"]').attr('href', commands[cmd]); 178 | break; 179 | case "target": 180 | this.$ele.find('[data-notify="url"]').attr('target', commands[cmd]); 181 | break; 182 | default: 183 | this.$ele.find('[data-notify="' + cmd + '"]').html(commands[cmd]); 184 | } 185 | } 186 | var posX = this.$ele.outerHeight() + parseInt(self.settings.spacing) + parseInt(self.settings.offset.y); 187 | self.reposition(posX); 188 | }, 189 | close: function () { 190 | self.close(); 191 | } 192 | }; 193 | 194 | }, 195 | buildNotify: function () { 196 | var content = this.settings.content; 197 | this.$ele = $(String.format(this.settings.template, this.settings.type, content.title, content.message, content.url, content.target)); 198 | this.$ele.attr('data-notify-position', this.settings.placement.from + '-' + this.settings.placement.align); 199 | if (!this.settings.allow_dismiss) { 200 | this.$ele.find('[data-notify="dismiss"]').css('display', 'none'); 201 | } 202 | if ((this.settings.delay <= 0 && !this.settings.showProgressbar) || !this.settings.showProgressbar) { 203 | this.$ele.find('[data-notify="progressbar"]').remove(); 204 | } 205 | }, 206 | setIcon: function () { 207 | if (this.settings.icon_type.toLowerCase() === 'class') { 208 | this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon); 209 | } else { 210 | if (this.$ele.find('[data-notify="icon"]').is('img')) { 211 | this.$ele.find('[data-notify="icon"]').attr('src', this.settings.content.icon); 212 | } else { 213 | this.$ele.find('[data-notify="icon"]').append('Notify Icon'); 214 | } 215 | } 216 | }, 217 | styleDismiss: function () { 218 | this.$ele.find('[data-notify="dismiss"]').css({ 219 | position: 'absolute', 220 | right: '10px', 221 | top: '5px', 222 | zIndex: this.settings.z_index + 2 223 | }); 224 | }, 225 | styleURL: function () { 226 | this.$ele.find('[data-notify="url"]').css({ 227 | backgroundImage: 'url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)', 228 | height: '100%', 229 | left: 0, 230 | position: 'absolute', 231 | top: 0, 232 | width: '100%', 233 | zIndex: this.settings.z_index + 1 234 | }); 235 | }, 236 | placement: function () { 237 | var self = this, 238 | offsetAmt = this.settings.offset.y, 239 | css = { 240 | display: 'inline-block', 241 | margin: '0px auto', 242 | position: this.settings.position ? this.settings.position : (this.settings.element === 'body' ? 'fixed' : 'absolute'), 243 | transition: 'all .5s ease-in-out', 244 | zIndex: this.settings.z_index 245 | }, 246 | hasAnimation = false, 247 | settings = this.settings; 248 | 249 | $('[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])').each(function () { 250 | offsetAmt = Math.max(offsetAmt, parseInt($(this).css(settings.placement.from)) + parseInt($(this).outerHeight()) + parseInt(settings.spacing)); 251 | }); 252 | if (this.settings.newest_on_top === true) { 253 | offsetAmt = this.settings.offset.y; 254 | } 255 | css[this.settings.placement.from] = offsetAmt + 'px'; 256 | 257 | switch (this.settings.placement.align) { 258 | case "left": 259 | case "right": 260 | css[this.settings.placement.align] = this.settings.offset.x + 'px'; 261 | break; 262 | case "center": 263 | css.left = 0; 264 | css.right = 0; 265 | break; 266 | } 267 | this.$ele.css(css).addClass(this.settings.animate.enter); 268 | $.each(Array('webkit-', 'moz-', 'o-', 'ms-', ''), function (index, prefix) { 269 | self.$ele[0].style[prefix + 'AnimationIterationCount'] = 1; 270 | }); 271 | 272 | $(this.settings.element).append(this.$ele); 273 | 274 | if (this.settings.newest_on_top === true) { 275 | offsetAmt = (parseInt(offsetAmt) + parseInt(this.settings.spacing)) + this.$ele.outerHeight(); 276 | this.reposition(offsetAmt); 277 | } 278 | 279 | if ($.isFunction(self.settings.onShow)) { 280 | self.settings.onShow.call(this.$ele); 281 | } 282 | 283 | this.$ele.one(this.animations.start, function () { 284 | hasAnimation = true; 285 | }).one(this.animations.end, function () { 286 | self.$ele.removeClass(self.settings.animate.enter); 287 | if ($.isFunction(self.settings.onShown)) { 288 | self.settings.onShown.call(this); 289 | } 290 | }); 291 | 292 | setTimeout(function () { 293 | if (!hasAnimation) { 294 | if ($.isFunction(self.settings.onShown)) { 295 | self.settings.onShown.call(this); 296 | } 297 | } 298 | }, 600); 299 | }, 300 | bind: function () { 301 | var self = this; 302 | 303 | this.$ele.find('[data-notify="dismiss"]').on('click', function () { 304 | self.close(); 305 | }); 306 | 307 | if ($.isFunction(self.settings.onClick)) { 308 | this.$ele.on('click', function (event) { 309 | if (event.target != self.$ele.find('[data-notify="dismiss"]')[0]) { 310 | self.settings.onClick.call(this, event); 311 | } 312 | }); 313 | } 314 | 315 | this.$ele.mouseover(function () { 316 | $(this).data('data-hover', "true"); 317 | }).mouseout(function () { 318 | $(this).data('data-hover', "false"); 319 | }); 320 | this.$ele.data('data-hover', "false"); 321 | 322 | if (this.settings.delay > 0) { 323 | self.$ele.data('notify-delay', self.settings.delay); 324 | var timer = setInterval(function () { 325 | var delay = parseInt(self.$ele.data('notify-delay')) - self.settings.timer; 326 | if ((self.$ele.data('data-hover') === 'false' && self.settings.mouse_over === "pause") || self.settings.mouse_over != "pause") { 327 | var percent = ((self.settings.delay - delay) / self.settings.delay) * 100; 328 | self.$ele.data('notify-delay', delay); 329 | self.$ele.find('[data-notify="progressbar"] > div').attr('aria-valuenow', percent).css('width', percent + '%'); 330 | } 331 | if (delay <= -(self.settings.timer)) { 332 | clearInterval(timer); 333 | self.close(); 334 | } 335 | }, self.settings.timer); 336 | } 337 | }, 338 | close: function () { 339 | var self = this, 340 | posX = parseInt(this.$ele.css(this.settings.placement.from)), 341 | hasAnimation = false; 342 | 343 | this.$ele.attr('data-closing', 'true').addClass(this.settings.animate.exit); 344 | self.reposition(posX); 345 | 346 | if ($.isFunction(self.settings.onClose)) { 347 | self.settings.onClose.call(this.$ele); 348 | } 349 | 350 | this.$ele.one(this.animations.start, function () { 351 | hasAnimation = true; 352 | }).one(this.animations.end, function () { 353 | $(this).remove(); 354 | if ($.isFunction(self.settings.onClosed)) { 355 | self.settings.onClosed.call(this); 356 | } 357 | }); 358 | 359 | setTimeout(function () { 360 | if (!hasAnimation) { 361 | self.$ele.remove(); 362 | if ($.isFunction(self.settings.onClosed)) { 363 | self.settings.onClosed.call(this); 364 | } 365 | } 366 | }, 600); 367 | }, 368 | reposition: function (posX) { 369 | var self = this, 370 | notifies = '[data-notify-position="' + this.settings.placement.from + '-' + this.settings.placement.align + '"]:not([data-closing="true"])', 371 | $elements = this.$ele.nextAll(notifies); 372 | if (this.settings.newest_on_top === true) { 373 | $elements = this.$ele.prevAll(notifies); 374 | } 375 | $elements.each(function () { 376 | $(this).css(self.settings.placement.from, posX); 377 | posX = (parseInt(posX) + parseInt(self.settings.spacing)) + $(this).outerHeight(); 378 | }); 379 | } 380 | }); 381 | 382 | $.notify = function (content, options) { 383 | var plugin = new Notify(this, content, options); 384 | return plugin.notify; 385 | }; 386 | $.notifyDefaults = function (options) { 387 | defaults = $.extend(true, {}, defaults, options); 388 | return defaults; 389 | }; 390 | 391 | $.notifyClose = function (selector) { 392 | 393 | if (typeof selector === "undefined" || selector === "all") { 394 | $('[data-notify]').find('[data-notify="dismiss"]').trigger('click'); 395 | }else if(selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger'){ 396 | $('.alert-' + selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click'); 397 | } else if(selector){ 398 | $(selector + '[data-notify]').find('[data-notify="dismiss"]').trigger('click'); 399 | } 400 | else { 401 | $('[data-notify-position="' + selector + '"]').find('[data-notify="dismiss"]').trigger('click'); 402 | } 403 | }; 404 | 405 | $.notifyCloseExcept = function (selector) { 406 | 407 | if(selector === 'success' || selector === 'info' || selector === 'warning' || selector === 'danger'){ 408 | $('[data-notify]').not('.alert-' + selector).find('[data-notify="dismiss"]').trigger('click'); 409 | } else{ 410 | $('[data-notify]').not(selector).find('[data-notify="dismiss"]').trigger('click'); 411 | } 412 | }; 413 | 414 | 415 | })); 416 | 417 | 418 | -------------------------------------------------------------------------------- /bootstrap-notify.min.js: -------------------------------------------------------------------------------- 1 | !function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){function s(s){var e=!1;return t('[data-notify="container"]').each(function(i,n){var a=t(n),o=a.find('[data-notify="title"]').text().trim(),r=a.find('[data-notify="message"]').html().trim(),l=o===t("
"+s.settings.content.title+"
").html().trim(),d=r===t("
"+s.settings.content.message+"
").html().trim(),g=a.hasClass("alert-"+s.settings.type);return l&&d&&g&&(e=!0),!e}),e}function e(e,n,a){var o={content:{message:"object"==typeof n?n.message:n,title:n.title?n.title:"",icon:n.icon?n.icon:"",url:n.url?n.url:"#",target:n.target?n.target:"-"}};a=t.extend(!0,{},o,a),this.settings=t.extend(!0,{},i,a),this._defaults=i,"-"===this.settings.content.target&&(this.settings.content.target=this.settings.url_target),this.animations={start:"webkitAnimationStart oanimationstart MSAnimationStart animationstart",end:"webkitAnimationEnd oanimationend MSAnimationEnd animationend"},"number"==typeof this.settings.offset&&(this.settings.offset={x:this.settings.offset,y:this.settings.offset}),(this.settings.allow_duplicates||!this.settings.allow_duplicates&&!s(this))&&this.init()}var i={element:"body",position:null,type:"info",allow_dismiss:!0,allow_duplicates:!0,newest_on_top:!1,showProgressbar:!1,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:null,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},onShow:null,onShown:null,onClose:null,onClosed:null,icon_type:"class",template:''};String.format=function(){for(var t=arguments[0],s=1;s .progress-bar').removeClass("progress-bar-"+t.settings.type),t.settings.type=i[n],this.$ele.addClass("alert-"+i[n]).find('[data-notify="progressbar"] > .progress-bar').addClass("progress-bar-"+i[n]);break;case"icon":var a=this.$ele.find('[data-notify="icon"]');"class"===t.settings.icon_type.toLowerCase()?a.removeClass(t.settings.content.icon).addClass(i[n]):(a.is("img")||a.find("img"),a.attr("src",i[n]));break;case"progress":var o=t.settings.delay-t.settings.delay*(i[n]/100);this.$ele.data("notify-delay",o),this.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i[n]).css("width",i[n]+"%");break;case"url":this.$ele.find('[data-notify="url"]').attr("href",i[n]);break;case"target":this.$ele.find('[data-notify="url"]').attr("target",i[n]);break;default:this.$ele.find('[data-notify="'+n+'"]').html(i[n])}var r=this.$ele.outerHeight()+parseInt(t.settings.spacing)+parseInt(t.settings.offset.y);t.reposition(r)},close:function(){t.close()}}},buildNotify:function(){var s=this.settings.content;this.$ele=t(String.format(this.settings.template,this.settings.type,s.title,s.message,s.url,s.target)),this.$ele.attr("data-notify-position",this.settings.placement.from+"-"+this.settings.placement.align),this.settings.allow_dismiss||this.$ele.find('[data-notify="dismiss"]').css("display","none"),(this.settings.delay<=0&&!this.settings.showProgressbar||!this.settings.showProgressbar)&&this.$ele.find('[data-notify="progressbar"]').remove()},setIcon:function(){"class"===this.settings.icon_type.toLowerCase()?this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon):this.$ele.find('[data-notify="icon"]').is("img")?this.$ele.find('[data-notify="icon"]').attr("src",this.settings.content.icon):this.$ele.find('[data-notify="icon"]').append('Notify Icon')},styleDismiss:function(){this.$ele.find('[data-notify="dismiss"]').css({position:"absolute",right:"10px",top:"5px",zIndex:this.settings.z_index+2})},styleURL:function(){this.$ele.find('[data-notify="url"]').css({backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)",height:"100%",left:0,position:"absolute",top:0,width:"100%",zIndex:this.settings.z_index+1})},placement:function(){var s=this,e=this.settings.offset.y,i={display:"inline-block",margin:"0px auto",position:this.settings.position?this.settings.position:"body"===this.settings.element?"fixed":"absolute",transition:"all .5s ease-in-out",zIndex:this.settings.z_index},n=!1,a=this.settings;switch(t('[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])').each(function(){e=Math.max(e,parseInt(t(this).css(a.placement.from))+parseInt(t(this).outerHeight())+parseInt(a.spacing))}),this.settings.newest_on_top===!0&&(e=this.settings.offset.y),i[this.settings.placement.from]=e+"px",this.settings.placement.align){case"left":case"right":i[this.settings.placement.align]=this.settings.offset.x+"px";break;case"center":i.left=0,i.right=0}this.$ele.css(i).addClass(this.settings.animate.enter),t.each(Array("webkit-","moz-","o-","ms-",""),function(t,e){s.$ele[0].style[e+"AnimationIterationCount"]=1}),t(this.settings.element).append(this.$ele),this.settings.newest_on_top===!0&&(e=parseInt(e)+parseInt(this.settings.spacing)+this.$ele.outerHeight(),this.reposition(e)),t.isFunction(s.settings.onShow)&&s.settings.onShow.call(this.$ele),this.$ele.one(this.animations.start,function(){n=!0}).one(this.animations.end,function(){s.$ele.removeClass(s.settings.animate.enter),t.isFunction(s.settings.onShown)&&s.settings.onShown.call(this)}),setTimeout(function(){n||t.isFunction(s.settings.onShown)&&s.settings.onShown.call(this)},600)},bind:function(){var s=this;if(this.$ele.find('[data-notify="dismiss"]').on("click",function(){s.close()}),this.$ele.mouseover(function(){t(this).data("data-hover","true")}).mouseout(function(){t(this).data("data-hover","false")}),this.$ele.data("data-hover","false"),this.settings.delay>0){s.$ele.data("notify-delay",s.settings.delay);var e=setInterval(function(){var t=parseInt(s.$ele.data("notify-delay"))-s.settings.timer;if("false"===s.$ele.data("data-hover")&&"pause"===s.settings.mouse_over||"pause"!=s.settings.mouse_over){var i=(s.settings.delay-t)/s.settings.delay*100;s.$ele.data("notify-delay",t),s.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i).css("width",i+"%")}t<=-s.settings.timer&&(clearInterval(e),s.close())},s.settings.timer)}},close:function(){var s=this,e=parseInt(this.$ele.css(this.settings.placement.from)),i=!1;this.$ele.attr("data-closing","true").addClass(this.settings.animate.exit),s.reposition(e),t.isFunction(s.settings.onClose)&&s.settings.onClose.call(this.$ele),this.$ele.one(this.animations.start,function(){i=!0}).one(this.animations.end,function(){t(this).remove(),t.isFunction(s.settings.onClosed)&&s.settings.onClosed.call(this)}),setTimeout(function(){i||(s.$ele.remove(),s.settings.onClosed&&s.settings.onClosed(s.$ele))},600)},reposition:function(s){var e=this,i='[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])',n=this.$ele.nextAll(i);this.settings.newest_on_top===!0&&(n=this.$ele.prevAll(i)),n.each(function(){t(this).css(e.settings.placement.from,s),s=parseInt(s)+parseInt(e.settings.spacing)+t(this).outerHeight()})}}),t.notify=function(t,s){var i=new e(this,t,s);return i.notify},t.notifyDefaults=function(s){return i=t.extend(!0,{},i,s)},t.notifyClose=function(s){"warning"===s&&(s="danger"),"undefined"==typeof s||"all"===s?t("[data-notify]").find('[data-notify="dismiss"]').trigger("click"):"success"===s||"info"===s||"warning"===s||"danger"===s?t(".alert-"+s+"[data-notify]").find('[data-notify="dismiss"]').trigger("click"):s?t(s+"[data-notify]").find('[data-notify="dismiss"]').trigger("click"):t('[data-notify-position="'+s+'"]').find('[data-notify="dismiss"]').trigger("click")},t.notifyCloseExcept=function(s){"warning"===s&&(s="danger"),"success"===s||"info"===s||"warning"===s||"danger"===s?t("[data-notify]").not(".alert-"+s).find('[data-notify="dismiss"]').trigger("click"):t("[data-notify]").not(s).find('[data-notify="dismiss"]').trigger("click")}}); -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remarkable-bootstrap-notify", 3 | "main": "bootstrap-notify.js", 4 | "version": "3.1.7", 5 | "homepage": "http://bootstrap-notify.remabledesigns.com/", 6 | "authors": [ 7 | "mouse0270 " 8 | ], 9 | "description": "This is a simple plugin that turns standard Bootstrap alerts into \"Growl-like\" notifications.", 10 | "keywords": [ 11 | "remarkable", 12 | "bootstrap", 13 | "jquery", 14 | "notify", 15 | "notification", 16 | "notifications", 17 | "growl", 18 | "message", 19 | "notice" 20 | ], 21 | "dependencies": { 22 | "jquery": ">=1.10.2", 23 | "bootstrap": ">=2.0.0" 24 | }, 25 | "license": "MIT", 26 | "ignore": [] 27 | } 28 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mouse0270/bootstrap-notify", 3 | "version": "3.1.5", 4 | "type": "library", 5 | "description": "This is a simple pluging that turns standard Bootstrap alerts into \"Growl-like\" notifications.", 6 | "keywords": [ 7 | "bootstrap", 8 | "jquery", 9 | "notify", 10 | "notification", 11 | "notifications", 12 | "growl", 13 | "message", 14 | "notice" 15 | ], 16 | "authors": [ 17 | { 18 | "name": "mouse0270", 19 | "email": "rmcintosh@remabledesigns.com", 20 | "homepage": "http://bootstrap-notify.remabledesigns.com/", 21 | "role": "Developer" 22 | } 23 | ], 24 | "homepage": "http://bootstrap-notify.remabledesigns.com/", 25 | "license": "MIT", 26 | "autoload": {} 27 | } -------------------------------------------------------------------------------- /jshintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "forin": true, 6 | "freeze": true, 7 | "immed": true, 8 | "latedef": true, 9 | "noarg": true, 10 | "noempty": true, 11 | "nonbsp": true, 12 | "nonew": true, 13 | "undef": true, 14 | "unused": true, 15 | "strict": false, 16 | "trailing": true, 17 | "maxparams": 5, 18 | "sub": true, 19 | "devel": true, 20 | "browser": true, 21 | 22 | "globals": { 23 | "jQuery": false 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | git: 'git://github.com/mouse0270/bootstrap-notify.git', 3 | name: 'mouse0270:bootstrap-notify', 4 | summary: 'Turns standard Bootstrap alerts into "Growl-like" notifications', 5 | version: '3.1.5', 6 | }); 7 | 8 | Package.onUse(function (api) { 9 | api.versionsFrom('1.0'); 10 | api.use('jquery', 'client'); 11 | api.addFiles('bootstrap-notify.js', 'client'); 12 | }); 13 | 14 | Package.onTest(function (api) { 15 | api.use('mouse0270:bootstrap-notify', 'client'); 16 | api.use('tinytest', 'client'); 17 | 18 | api.addFiles('test_meteor.js', 'client'); 19 | }); 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-notify", 3 | "version": "3.1.7", 4 | "description": "This is a simple plugin that turns standard Bootstrap alerts into \"Growl-like\" notifications.", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/mouse0270/bootstrap-notify.git" 8 | }, 9 | "keywords": [ 10 | "bootstrap", 11 | "jquery", 12 | "notify", 13 | "notification", 14 | "notifications", 15 | "growl", 16 | "message", 17 | "notice" 18 | ], 19 | "author": "mouse0270 ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/mouse0270/bootstrap-notify/issues" 23 | }, 24 | "homepage": "http://bootstrap-notify.remabledesigns.com/", 25 | "main": "bootstrap-notify.js", 26 | "files": [ 27 | "bootstrap-notify.js", 28 | "bootstrap-notify.min.js" 29 | ], 30 | "dependencies": {}, 31 | "devDependencies": { 32 | "grunt": "^0.4.5", 33 | "grunt-cli": "^0.1.13", 34 | "grunt-contrib-jshint": "^0.10.0", 35 | "grunt-contrib-uglify": "^0.4.0", 36 | "grunt-exec": "^0.4.6", 37 | "spacejam": "^1.1.4" 38 | }, 39 | "scripts": { 40 | "test": "grunt test" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /test_meteor.js: -------------------------------------------------------------------------------- 1 | Tinytest.add('Instantiation', function(test) { 2 | test.notEqual($.notify, undefined); 3 | }); 4 | -------------------------------------------------------------------------------- /typings/bootstrap-notify/notify.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | /* tslint:disable: interface-name no-any */ 4 | 5 | interface JQueryStatic { 6 | /* tslint:enable: interface-name */ 7 | notify(message: string): INotifyReturn; 8 | notify(opts: INotifyOptions, settings?: INotifySettings): INotifyReturn; 9 | notifyDefaults(settings: INotifySettings): void; 10 | notifyClose(): void; 11 | notifyClose(command: string): void; 12 | } 13 | 14 | interface INotifyOptions { 15 | message: string; 16 | title?: string; 17 | icon?: string; 18 | url?: string; 19 | target?: string; 20 | } 21 | 22 | interface INotifySettings { 23 | element?: string; 24 | position?: string; 25 | type?: string; 26 | allow_dismiss?: boolean; 27 | allow_duplicates?: boolean; 28 | newest_on_top?: boolean; 29 | showProgressbar?: boolean; 30 | placement?: { 31 | from?: string; 32 | align?: string; 33 | }; 34 | offset?: number; 35 | spacing?: number; 36 | z_index?: number; 37 | delay?: number; 38 | timer?: number; 39 | url_target?: string; 40 | mouse_over?: Function; 41 | animate?: { 42 | enter?: string; 43 | exit?: string; 44 | }; 45 | onShow?: () => void; 46 | onShown?: () => void; 47 | onClose?: () => void; 48 | onClosed?: () => void; 49 | icon_type?: string; 50 | template?: string; 51 | } 52 | 53 | interface UpdateCommands { 54 | type?: string; 55 | progress?: number; 56 | message?: string; 57 | icon?: string; 58 | } 59 | 60 | interface NotifyReturn { 61 | $ele: JQueryStatic; 62 | close(): void; 63 | update(commands: UpdateCommands|Record): void; 64 | update(command: string, update: any): void; 65 | } 66 | --------------------------------------------------------------------------------