├── README.md ├── bower.json ├── notification.css ├── notification.js ├── notification.min.css └── notification.scss /README.md: -------------------------------------------------------------------------------- 1 | ## Angular-Notifications 2 | 3 | **This Repository is not maintained** 4 | 5 | ### v0.1 6 | 7 | This particular component provides a service for creating notifications, and an 8 | easy to use directive for displaying those notifications. Also provides the ability 9 | to use Chrome Notifications instead. 10 | 11 | This is an early release, and I'm going to be changing a lot of stuff soon. 12 | 13 | ### Demo 14 | You can check out a really simple [Demo right here](http://derekries.github.io/angular-notifications). Documentation beyond this README coming soon. 15 | 16 | ### Dependencies 17 | This component is an angularjs component so it should be obvious it depends on angular. 18 | Also for the default notifications **font-awesome 3.1.1** is required to display the icons. 19 | 20 | ### Installation 21 | After you've downloaded this repository, include both the css and javascript file 22 | and then declare the notifications module as a dependency of your app module. 23 | 24 | e.g `angular.module('ngcomponentsApp', ['notifications'])` 25 | 26 | Once you've finished that business you should be able to use the notifications service. 27 | If you want those notifications to show up on the screen however (optional), you 28 | will need to add a div to your body tag somewhere and give it a notifications directive 29 | specifying its position like so: 30 | 31 | `
` 32 | 33 | You should now magically get notifications 34 | 35 | ### Usage 36 | 37 | In order to use the API you need to inject the `$notification` service into 38 | your controllers. From there you can use one of the many different notifications 39 | like: 40 | 41 | * info 42 | * warning 43 | * error 44 | * success 45 | 46 | You can use these methods with the following line of code 47 | 48 | `$notification.info(title, content, userData);` 49 | `$notification.warning(title, content, userData);` 50 | `$notification.error(title, content, userData);` 51 | `$notification.success(title, content, userData);` 52 | 53 | **Title** is of course the title displayed in a large, bold text on the notification. 54 | **Content** is the additional detail text for that notification. The **userData** parameter 55 | is optional but allows you to store some data with a particular notification. 56 | 57 | You can also use a generic notify method more inline with the standard chrome desktop 58 | notifications by specifying an image to display in the notification. 59 | `$notification.notify('image.jpg', 'My Title', 'My notification description text');` 60 | 61 | ### HTML5 Notifications 62 | If you want to use HTML5 notifications with the same API then you can call 63 | `$notification.enableHtml5Mode()`. **Note:** You will need permissions in 64 | order to use HTML5 notifications so for this reason you should call enableHtml5Mode 65 | in a click event listener or something. 66 | 67 | 68 | ### Coming Soon 69 | 70 | * Animations - Using ng-animate, will require a minimum of angular 1.1.4 for these 71 | * Better Looking, More Easily Styleable Notifications 72 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": { 3 | "name": "https://github.com/Derekries" 4 | }, 5 | "name": "angular-notifications", 6 | "version": "0.1.0", 7 | "main": "notification.js", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "components" 12 | ], 13 | "dependencies": { 14 | "angular": "~1.0.7" 15 | } 16 | } -------------------------------------------------------------------------------- /notification.css: -------------------------------------------------------------------------------- 1 | .dr-notification-container { 2 | position: absolute; 3 | z-index: 10000; 4 | } 5 | 6 | .dr-notification-container.bottom { 7 | bottom: 20px; 8 | } 9 | 10 | .dr-notification-container.right { 11 | right: 20px; 12 | } 13 | 14 | .dr-notification-container.left { 15 | left: 20px; 16 | } 17 | 18 | .dr-notification-container.top { 19 | top: 20px; 20 | } 21 | 22 | .dr-notification-container.center { 23 | left: 50%; 24 | margin-left: -190px; 25 | } 26 | 27 | .dr-notification-wrapper { 28 | width: 380px; 29 | position: relative; 30 | margin: 10px 0; 31 | } 32 | 33 | .dr-notification { 34 | width: 380px; 35 | background-color: rgba(2, 45, 59, 0.85); 36 | clear: both; 37 | min-height: 80px; 38 | max-height: 90px; 39 | -webkit-border-radius: 5px; 40 | -moz-border-radius: 5px; 41 | -ms-border-radius: 5px; 42 | border-radius: 5px; 43 | color: #bfe2de; 44 | border: 1px solid rgba(4, 94, 123, 0.85); 45 | overflow: hidden; 46 | } 47 | 48 | .dr-notification-close-btn { 49 | -webkit-border-radius: 20px; 50 | -moz-border-radius: 20px; 51 | -ms-border-radius: 20px; 52 | border-radius: 20px; 53 | display: inline-block; 54 | padding: 3px; 55 | background-color: rgba(1, 26, 34, 0.85); 56 | font-size: 14px; 57 | color: #adfaff; 58 | border: 1px solid rgba(4, 94, 123, 0.85); 59 | position: absolute; 60 | right: -11px; 61 | top: 5px; 62 | -webkit-transition: all 0.35s cubic-bezier(0.31, 0.39, 0.21, 1.65); 63 | -moz-transition: all 0.35s cubic-bezier(0.31, 0.39, 0.21, 1.65); 64 | transition: all 0.35s cubic-bezier(0.31, 0.39, 0.21, 1.65); 65 | cursor: pointer; 66 | } 67 | .dr-notification-close-btn i { 68 | padding-left: 3px; 69 | } 70 | .dr-notification-close-btn:hover { 71 | -webkit-transform: scale3d(1.25, 1.25, 1); 72 | -moz-transform: scale3d(1.25, 1.25, 1); 73 | -ms-transform: scale3d(1.25, 1.25, 1); 74 | transform: scale3d(1.25, 1.25, 1); 75 | } 76 | 77 | .dr-notification-image { 78 | width: 80px; 79 | height: 80px; 80 | border-right: 1px solid rgba(4, 94, 123, 0.85); 81 | float: left; 82 | display: block; 83 | font-size: 40px; 84 | color: white; 85 | text-align: center; 86 | } 87 | .dr-notification-image i { 88 | display: block; 89 | width: 100%; 90 | padding-top: 25px; 91 | } 92 | .dr-notification-image img { 93 | margin: 15px; 94 | max-width: 70px; 95 | min-width: 48px; 96 | } 97 | 98 | .dr-notification-image.dr-notification-type-info { 99 | color: #FFF; 100 | } 101 | 102 | .dr-notification-image.dr-notification-type-warning { 103 | color: #FFA226; 104 | } 105 | 106 | .dr-notification-image.dr-notification-type-error { 107 | color: #FF4B4F; 108 | } 109 | 110 | .dr-notification-image.dr-notification-type-success { 111 | color: #B4D455; 112 | } 113 | 114 | .dr-notification-image.success { 115 | color: #B4D455; 116 | } 117 | 118 | .dr-notification-content { 119 | padding-left: 100px; 120 | padding-right: 15px; 121 | padding-top: 10px; 122 | } 123 | 124 | .dr-notification-title { 125 | color: white; 126 | margin: 0px; 127 | padding: 0px; 128 | font-size: 20px; 129 | } 130 | 131 | p.dr-notification-text { 132 | margin-top: -5px; 133 | font-size: 12px; 134 | } 135 | -------------------------------------------------------------------------------- /notification.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('notifications', []). 4 | factory('$notification', ['$timeout',function($timeout){ 5 | 6 | console.log('notification service online'); 7 | var notifications = JSON.parse(localStorage.getItem('$notifications')) || [], 8 | queue = []; 9 | 10 | var settings = { 11 | info: { duration: 5000, enabled: true }, 12 | warning: { duration: 5000, enabled: true }, 13 | error: { duration: 5000, enabled: true }, 14 | success: { duration: 5000, enabled: true }, 15 | progress: { duration: 0, enabled: true }, 16 | custom: { duration: 35000, enabled: true }, 17 | details: true, 18 | localStorage: false, 19 | html5Mode: false, 20 | html5DefaultIcon: 'icon.png' 21 | }; 22 | 23 | function html5Notify(icon, title, content, ondisplay, onclose){ 24 | if(window.webkitNotifications.checkPermission() === 0){ 25 | if(!icon){ 26 | icon = 'favicon.ico'; 27 | } 28 | var noti = window.webkitNotifications.createNotification(icon, title, content); 29 | if(typeof ondisplay === 'function'){ 30 | noti.ondisplay = ondisplay; 31 | } 32 | if(typeof onclose === 'function'){ 33 | noti.onclose = onclose; 34 | } 35 | noti.show(); 36 | } 37 | else { 38 | settings.html5Mode = false; 39 | } 40 | } 41 | 42 | 43 | return { 44 | 45 | /* ========== SETTINGS RELATED METHODS =============*/ 46 | 47 | disableHtml5Mode: function(){ 48 | settings.html5Mode = false; 49 | }, 50 | 51 | disableType: function(notificationType){ 52 | settings[notificationType].enabled = false; 53 | }, 54 | 55 | enableHtml5Mode: function(){ 56 | // settings.html5Mode = true; 57 | settings.html5Mode = this.requestHtml5ModePermissions(); 58 | }, 59 | 60 | enableType: function(notificationType){ 61 | settings[notificationType].enabled = true; 62 | }, 63 | 64 | getSettings: function(){ 65 | return settings; 66 | }, 67 | 68 | toggleType: function(notificationType){ 69 | settings[notificationType].enabled = !settings[notificationType].enabled; 70 | }, 71 | 72 | toggleHtml5Mode: function(){ 73 | settings.html5Mode = !settings.html5Mode; 74 | }, 75 | 76 | requestHtml5ModePermissions: function(){ 77 | if (window.webkitNotifications){ 78 | console.log('notifications are available'); 79 | if (window.webkitNotifications.checkPermission() === 0) { 80 | return true; 81 | } 82 | else{ 83 | window.webkitNotifications.requestPermission(function(){ 84 | if(window.webkitNotifications.checkPermission() === 0){ 85 | settings.html5Mode = true; 86 | } 87 | else{ 88 | settings.html5Mode = false; 89 | } 90 | }); 91 | return false; 92 | } 93 | } 94 | else{ 95 | console.log('notifications are not supported'); 96 | return false; 97 | } 98 | }, 99 | 100 | 101 | /* ============ QUERYING RELATED METHODS ============*/ 102 | 103 | getAll: function(){ 104 | // Returns all notifications that are currently stored 105 | return notifications; 106 | }, 107 | 108 | getQueue: function(){ 109 | return queue; 110 | }, 111 | 112 | /* ============== NOTIFICATION METHODS ==============*/ 113 | 114 | info: function(title, content, userData){ 115 | console.log(title, content); 116 | return this.awesomeNotify('info','info', title, content, userData); 117 | }, 118 | 119 | error: function(title, content, userData){ 120 | return this.awesomeNotify('error', 'remove', title, content, userData); 121 | }, 122 | 123 | success: function(title, content, userData){ 124 | return this.awesomeNotify('success', 'ok', title, content, userData); 125 | }, 126 | 127 | warning: function(title, content, userData){ 128 | return this.awesomeNotify('warning', 'exclamation', title, content, userData); 129 | }, 130 | 131 | awesomeNotify: function(type, icon, title, content, userData){ 132 | /** 133 | * Supposed to wrap the makeNotification method for drawing icons using font-awesome 134 | * rather than an image. 135 | * 136 | * Need to find out how I'm going to make the API take either an image 137 | * resource, or a font-awesome icon and then display either of them. 138 | * Also should probably provide some bits of color, could do the coloring 139 | * through classes. 140 | */ 141 | // image = ''; 142 | return this.makeNotification(type, false, icon, title, content, userData); 143 | }, 144 | 145 | notify: function(image, title, content, userData){ 146 | // Wraps the makeNotification method for displaying notifications with images 147 | // rather than icons 148 | return this.makeNotification('custom', image, true, title, content, userData); 149 | }, 150 | 151 | makeNotification: function(type, image, icon, title, content, userData){ 152 | var notification = { 153 | 'type': type, 154 | 'image': image, 155 | 'icon': icon, 156 | 'title': title, 157 | 'content': content, 158 | 'timestamp': +new Date(), 159 | 'userData': userData 160 | }; 161 | notifications.push(notification); 162 | 163 | if(settings.html5Mode){ 164 | html5Notify(image, title, content, function(){ 165 | console.log("inner on display function"); 166 | }, function(){ 167 | console.log("inner on close function"); 168 | }); 169 | } 170 | else{ 171 | queue.push(notification); 172 | $timeout(function removeFromQueueTimeout(){ 173 | queue.splice(queue.indexOf(notification), 1); 174 | }, settings[type].duration); 175 | 176 | } 177 | 178 | this.save(); 179 | return notification; 180 | }, 181 | 182 | 183 | /* ============ PERSISTENCE METHODS ============ */ 184 | 185 | save: function(){ 186 | // Save all the notifications into localStorage 187 | // console.log(JSON); 188 | if(settings.localStorage){ 189 | localStorage.setItem('$notifications', JSON.stringify(notifications)); 190 | } 191 | // console.log(localStorage.getItem('$notifications')); 192 | }, 193 | 194 | restore: function(){ 195 | // Load all notifications from localStorage 196 | }, 197 | 198 | clear: function(){ 199 | notifications = []; 200 | this.save(); 201 | } 202 | 203 | }; 204 | }]). 205 | directive('notifications', ['$notification', '$compile', function($notification, $compile){ 206 | /** 207 | * 208 | * It should also parse the arguments passed to it that specify 209 | * its position on the screen like "bottom right" and apply those 210 | * positions as a class to the container element 211 | * 212 | * Finally, the directive should have its own controller for 213 | * handling all of the notifications from the notification service 214 | */ 215 | console.log('this is a new directive'); 216 | var html = 217 | '
' + 218 | '
' + 219 | '' + 220 | '
' + 221 | '
' + 222 | '
' + 223 | '' + 224 | '' + 225 | '
' + 226 | '
' + 227 | '

{{noti.title}}

' + 228 | '

{{noti.content}}

' + 229 | '
' + 230 | '
' + 231 | '
'; 232 | 233 | 234 | function link(scope, element, attrs){ 235 | var position = attrs.notifications; 236 | position = position.split(' '); 237 | element.addClass('dr-notification-container'); 238 | for(var i = 0; i < position.length ; i++){ 239 | element.addClass(position[i]); 240 | } 241 | } 242 | 243 | 244 | return { 245 | restrict: 'A', 246 | scope: {}, 247 | template: html, 248 | link: link, 249 | controller: ['$scope', function NotificationsCtrl( $scope ){ 250 | $scope.queue = $notification.getQueue(); 251 | 252 | $scope.removeNotification = function(noti){ 253 | $scope.queue.splice($scope.queue.indexOf(noti), 1); 254 | }; 255 | } 256 | ] 257 | 258 | }; 259 | }]); 260 | -------------------------------------------------------------------------------- /notification.min.css: -------------------------------------------------------------------------------- 1 | .dr-notification-container{position:absolute;z-index:10000}.dr-notification-container.bottom{bottom:20px}.dr-notification-container.right{right:20px}.dr-notification-container.left{left:20px}.dr-notification-container.top{top:20px}.dr-notification-container.center{left:50%;margin-left:-190px}.dr-notification-wrapper{width:380px;position:relative;margin:10px 0}.dr-notification{width:380px;background-color:rgba(2,45,59,0.85);clear:both;min-height:80px;max-height:90px;-webkit-border-radius:5px;-moz-border-radius:5px;-ms-border-radius:5px;border-radius:5px;color:#bfe2de;border:1px solid rgba(4,94,123,0.85);overflow:hidden}.dr-notification-close-btn{-webkit-border-radius:20px;-moz-border-radius:20px;-ms-border-radius:20px;border-radius:20px;display:inline-block;padding:3px;background-color:rgba(1,26,34,0.85);font-size:14px;color:#adfaff;border:1px solid rgba(4,94,123,0.85);position:absolute;right:-11px;top:5px;-webkit-transition:all .35s cubic-bezier(0.31,0.39,0.21,1.65);-moz-transition:all .35s cubic-bezier(0.31,0.39,0.21,1.65);transition:all .35s cubic-bezier(0.31,0.39,0.21,1.65);cursor:pointer}.dr-notification-close-btn i{padding-left:3px}.dr-notification-close-btn:hover{-webkit-transform:scale3d(1.25,1.25,1);-moz-transform:scale3d(1.25,1.25,1);-ms-transform:scale3d(1.25,1.25,1);transform:scale3d(1.25,1.25,1)}.dr-notification-image{width:80px;height:80px;border-right:1px solid rgba(4,94,123,0.85);float:left;display:block;font-size:40px;color:white;text-align:center}.dr-notification-image i{display:block;width:100%;padding-top:25px}.dr-notification-image img{margin:15px;max-width:70px;min-width:48px}.dr-notification-image.dr-notification-type-info{color:#FFF}.dr-notification-image.dr-notification-type-warning{color:#ffa226}.dr-notification-image.dr-notification-type-error{color:#ff4b4f}.dr-notification-image.dr-notification-type-success{color:#b4d455}.dr-notification-image.success{color:#b4d455}.dr-notification-content{padding-left:100px;padding-right:15px;padding-top:10px}.dr-notification-title{color:white;margin:0;padding:0;font-size:20px}p.dr-notification-text{margin-top:-5px;font-size:12px} -------------------------------------------------------------------------------- /notification.scss: -------------------------------------------------------------------------------- 1 | $bg-color: rgba(2,45,59,0.85); 2 | $border-color: lighten($bg-color, 13%); 3 | $title-color: #FFF; 4 | $text-color: #BFE2DE; 5 | $logo-color: #adfaff; 6 | $height: 80px; 7 | $width: 380px; 8 | $bounce-in: cubic-bezier(0.310, 0.390, 0.210, 1.650); 9 | 10 | 11 | 12 | .dr-notification-container { 13 | position:absolute; 14 | z-index:10000; 15 | } 16 | 17 | .dr-notification-container.bottom { 18 | bottom: 20px; 19 | } 20 | 21 | .dr-notification-container.right { 22 | right: 20px; 23 | } 24 | 25 | .dr-notification-container.left { 26 | left: 20px; 27 | } 28 | 29 | .dr-notification-container.top { 30 | top: 20px; 31 | } 32 | 33 | .dr-notification-container.center { 34 | left: 50%; 35 | margin-left:-190px; 36 | } 37 | 38 | .dr-notification-wrapper { 39 | width: $width; 40 | position:relative; 41 | margin: 10px 0; 42 | } 43 | 44 | .dr-notification { 45 | width: $width; 46 | background-color: $bg-color; 47 | clear:both; 48 | min-height: $height; 49 | max-height: 90px; 50 | @include border-radius(5px); 51 | color: $text-color; 52 | border: 1px solid $border-color; 53 | overflow:hidden; 54 | } 55 | 56 | .dr-notification-close-btn { 57 | @include border-radius(20px); 58 | display:inline-block; 59 | padding:3px; 60 | background-color: darken($bg-color, 5%); 61 | font-size:14px; 62 | color: $logo-color; 63 | border:1px solid $border-color; 64 | position:absolute; 65 | i { 66 | padding-left:3px; 67 | } 68 | right:-11px; 69 | top:5px; 70 | @include transition(all 0.35s $bounce-in); 71 | cursor: pointer; 72 | &:hover { 73 | @include scale3d(1.25,1.25,1); 74 | } 75 | } 76 | 77 | .dr-notification-image { 78 | width: $height; 79 | height: $height; 80 | border-right: 1px solid $border-color; 81 | float:left; 82 | display:block; 83 | font-size: 40px; 84 | color: $title-color; 85 | text-align:center; 86 | i { 87 | display:block; 88 | width:100%; 89 | padding-top:25px; 90 | } 91 | img { 92 | margin:15px; 93 | // width: 100%; 94 | max-width:70px; 95 | min-width:48px; 96 | } 97 | } 98 | 99 | .dr-notification-image.dr-notification-type-info { 100 | color: #FFF; 101 | } 102 | 103 | .dr-notification-image.dr-notification-type-warning { 104 | color: #FFA226; 105 | } 106 | 107 | .dr-notification-image.dr-notification-type-error { 108 | color: #FF4B4F; 109 | } 110 | 111 | .dr-notification-image.dr-notification-type-success { 112 | color: #B4D455; 113 | } 114 | 115 | .dr-notification-image.success { 116 | color: #B4D455; 117 | } 118 | 119 | .dr-notification-content { 120 | padding-left: 100px; 121 | padding-right:15px; 122 | padding-top:10px; 123 | } 124 | 125 | .dr-notification-title { 126 | color: $title-color; 127 | margin: 0px; 128 | padding:0px; 129 | font-size:20px; 130 | } 131 | 132 | p.dr-notification-text { 133 | margin-top: -5px; 134 | font-size:12px; 135 | } 136 | --------------------------------------------------------------------------------