├── src
├── growl.js
├── growl.css
├── growlDirective.js
└── growlFactory.js
├── doc
└── screenshot.jpg
├── .gitignore
├── test
└── growlDirectiveTest.js
├── .jshintrc
├── bower.json
├── package.json
├── LICENSE
├── karma.conf.js
├── demo
├── demo.js
└── demo.html
├── gruntfile.js
└── README.md
/src/growl.js:
--------------------------------------------------------------------------------
1 | angular.module('angular-growl', []);
--------------------------------------------------------------------------------
/doc/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/marcorinck/angular-growl/HEAD/doc/screenshot.jpg
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | components
4 | bower_components
5 | .idea
6 | *.iml
7 | nbproject
8 |
--------------------------------------------------------------------------------
/test/growlDirectiveTest.js:
--------------------------------------------------------------------------------
1 | describe("growlDirective", function() {
2 | "use strict";
3 |
4 | it("should be true ", function() {
5 | expect(true).toBe(true);
6 | });
7 | });
--------------------------------------------------------------------------------
/src/growl.css:
--------------------------------------------------------------------------------
1 | .growl {
2 | position: fixed;
3 | top: 10px;
4 | right: 10px;
5 | float: right;
6 | width: 250px;
7 | }
8 |
9 | .growl-item.ng-enter,
10 | .growl-item.ng-leave {
11 | -webkit-transition:0.5s linear all;
12 | -moz-transition:0.5s linear all;
13 | -o-transition:0.5s linear all;
14 | transition:0.5s linear all;
15 | }
16 |
17 | .growl-item.ng-enter,
18 | .growl-item.ng-leave.ng-leave-active {
19 | opacity:0;
20 | }
21 | .growl-item.ng-leave,
22 | .growl-item.ng-enter.ng-enter-active {
23 | opacity:1;
24 |
25 | }
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "curly": true,
3 | "eqeqeq": true,
4 | "immed": true,
5 | "latedef": true,
6 | "newcap": true,
7 | "noarg": true,
8 | "sub": true,
9 | "undef": true,
10 | "boss": true,
11 | "eqnull": true,
12 | "unused": true,
13 | "strict": true,
14 | "bitwise": true,
15 | "trailing": true,
16 | "regexp": true,
17 | "nonew": true,
18 | "forin": true,
19 | "globals": {
20 | "angular": true,
21 | "console": true,
22 | "define": true,
23 | "require": true,
24 | "document": true,
25 | "describe": true,
26 | "it": true,
27 | "expect": true,
28 | "jasmine": true,
29 | "window": true,
30 | "beforeEach": true,
31 | "module": true,
32 | "inject": true
33 | }
34 | }
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "author": "Marco Rinck",
3 | "name": "angular-growl",
4 | "description": "growl like notifications for angularJS projects, using bootstrap alert classes",
5 | "version": "0.4.0",
6 | "homepage": "https://github.com/marcorinck/angular-growl",
7 | "repository": {
8 | "type": "git",
9 | "url": "https://github.com/marcorinck/angular-growl"
10 | },
11 | "license": "MIT",
12 | "main": "./build/angular-growl.js",
13 | "ignore": [
14 | "src",
15 | "test",
16 | ".jshintrc",
17 | "package.json",
18 | "gruntfile.js",
19 | "karma.conf.js",
20 | "bower.json",
21 | "demo",
22 | ".gitignore"
23 | ],
24 | "dependencies": {
25 | "angular": "1.2.1"
26 | },
27 | "devDependencies": {
28 | "angular-mocks": "1.2.1"
29 | }
30 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "angular-growl",
3 | "version": "0.4.0",
4 | "description": "growl like notifications for angularJS projects, using bootstrap alert classes",
5 | "repository": {
6 | "type": "git",
7 | "url": "https://github.com/marcorinck/angular-growl"
8 | },
9 | "author": {
10 | "name": "Marco Rinck"
11 | },
12 | "license": "MIT",
13 | "devDependencies": {
14 | "karma": "~0.10.x",
15 | "grunt": "~0.4.1",
16 | "grunt-contrib-clean": "~0.5.0",
17 | "grunt-contrib-copy": "~0.4.1",
18 | "grunt-contrib-concat": "~0.3.x",
19 | "grunt-contrib-jshint": "~0.6.x",
20 | "grunt-contrib-uglify": "~0.2.x",
21 | "grunt-contrib-watch": "~0.5.x",
22 | "grunt-bump": "0.0.2",
23 | "grunt-karma": "~0.7.x",
24 | "grunt-ngmin": "0.0.2",
25 | "grunt-push-release": "0.1.x",
26 | "matchdep": "0.1.2",
27 | "grunt-contrib-cssmin": "~0.6.2"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013 Marco Rinck
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Mon Sep 16 2013 12:55:41 GMT+0200 (W. Europe Daylight Time)
3 |
4 | module.exports = function (config) {
5 | config.set({
6 |
7 | // base path, that will be used to resolve files and exclude
8 | basePath: '',
9 |
10 |
11 | // frameworks to use
12 | frameworks: ['jasmine'],
13 |
14 |
15 | // list of files / patterns to load in the browser
16 | files: [
17 | 'bower_components/angular/angular.js',
18 | 'bower_components/angular-mocks/angular-mocks.js',
19 | 'src/**/*.js',
20 | 'test/**/*.js'
21 | ],
22 |
23 |
24 | // list of files to exclude
25 | exclude: [
26 |
27 | ],
28 |
29 |
30 | // test results reporter to use
31 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
32 | reporters: ['progress'],
33 |
34 |
35 | // web server port
36 | port: 9876,
37 |
38 |
39 | // enable / disable colors in the output (reporters and logs)
40 | colors: true,
41 |
42 |
43 | // level of logging
44 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
45 | logLevel: config.LOG_INFO,
46 |
47 |
48 | // enable / disable watching file and executing tests whenever any file changes
49 | autoWatch: false,
50 |
51 |
52 | // Start these browsers, currently available:
53 | // - Chrome
54 | // - ChromeCanary
55 | // - Firefox
56 | // - Opera
57 | // - Safari (only Mac)
58 | // - PhantomJS
59 | // - IE (only Windows)
60 | browsers: ['PhantomJS'],
61 |
62 |
63 | // If browser does not capture in given timeout [ms], kill it
64 | captureTimeout: 60000,
65 |
66 |
67 | // Continuous Integration mode
68 | // if true, it capture browsers, run tests and exit
69 | singleRun: true
70 | });
71 | };
72 |
--------------------------------------------------------------------------------
/demo/demo.js:
--------------------------------------------------------------------------------
1 | var app = angular.module("demo", ["angular-growl", "ngAnimate", "ngMockE2E"]);
2 |
3 | app.config(["growlProvider", "$httpProvider", function(growlProvider, $httpProvider) {
4 | growlProvider.globalTimeToLive(2000);
5 | growlProvider.messagesKey("my-messages");
6 | growlProvider.messageTextKey("messagetext");
7 | growlProvider.messageSeverityKey("severity-level");
8 | growlProvider.onlyUniqueMessages(true);
9 | $httpProvider.responseInterceptors.push(growlProvider.serverMessagesInterceptor);
10 |
11 |
12 | }]);
13 |
14 | app.run(function($httpBackend) {
15 | //mocking backend to simulate handling server messages
16 | $httpBackend.when('GET', '/mockbackend').respond({
17 | someData: "fhsdfshfshdfs",
18 | "my-messages": [
19 | {"messagetext":"this is a server message", "severity-level": "warn"},
20 | {"messagetext":"this is another server message", "severity-level": "info"},
21 | {"messagetext":"and another", "severity-level": "error"}
22 | ]
23 | });
24 | });
25 |
26 | app.controller("demoCtrl", function demoCtrl($scope, growl, $http) {
27 |
28 | $scope.createMessage = function () {
29 | var config = {};
30 | if ($scope.timeout) {
31 | config.ttl = $scope.timeout;
32 | }
33 | if ($scope.enableHtml) {
34 | config.enableHtml = $scope.enableHtml;
35 | }
36 |
37 | if ($scope.alertType === "success") {
38 | growl.addSuccessMessage($scope.message, config);
39 | }
40 |
41 | if ($scope.alertType === "warn") {
42 | growl.addWarnMessage($scope.message, config);
43 | }
44 |
45 | if ($scope.alertType === "info") {
46 | growl.addInfoMessage($scope.message, config);
47 | }
48 |
49 | if ($scope.alertType === "error") {
50 | growl.addErrorMessage($scope.message, config);
51 | }
52 | };
53 |
54 | $scope.simulateServerMessages= function() {
55 | $http.get("/mockbackend").then(function(data) {
56 | console.log(data);
57 | });
58 | };
59 | });
--------------------------------------------------------------------------------
/src/growlDirective.js:
--------------------------------------------------------------------------------
1 | angular.module("angular-growl").directive("growl", ["$rootScope", function ($rootScope) {
2 | "use strict";
3 |
4 | return {
5 | restrict: 'A',
6 | template: '
' +
7 | '
' +
8 | '
' +
9 | '
' +
10 | '
' +
11 | '
' +
12 | '
' +
13 | '
' +
14 | '
',
15 | replace: false,
16 | scope: true,
17 | controller: ['$scope', '$timeout', 'growl', function ($scope, $timeout, growl) {
18 | var onlyUnique = growl.onlyUnique();
19 |
20 | $scope.messages = [];
21 |
22 | function addMessage(message) {
23 | $scope.messages.push(message);
24 |
25 | if (message.ttl && message.ttl !== -1) {
26 | $timeout(function () {
27 | $scope.deleteMessage(message);
28 | }, message.ttl);
29 | }
30 | }
31 | $rootScope.$on("growlMessage", function (event, message) {
32 | var found;
33 | if (onlyUnique) {
34 | angular.forEach($scope.messages, function(msg) {
35 | if (message.text === msg.text && message.severity === msg.severity) {
36 | found = true;
37 | }
38 | });
39 |
40 | if (!found) {
41 | addMessage(message);
42 | }
43 | } else {
44 | addMessage(message);
45 | }
46 | });
47 |
48 | $scope.deleteMessage = function (message) {
49 | var index = $scope.messages.indexOf(message);
50 | if (index > -1) {
51 | $scope.messages.splice(index, 1);
52 | }
53 |
54 | };
55 |
56 | $scope.computeClasses = function (message) {
57 | return {
58 | 'alert-success': message.severity === "success",
59 | 'alert-error': message.severity === "error", //bootstrap 2.3
60 | 'alert-danger': message.severity === "error", //bootstrap 3
61 | 'alert-info': message.severity === "info",
62 | 'alert-warning': message.severity === "warn" //bootstrap 3, no effect in bs 2.3
63 | };
64 | };
65 | }]
66 | };
67 | }]);
68 |
--------------------------------------------------------------------------------
/demo/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | angular-growl demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
angular-growl Demo site
25 |
26 |
27 |
28 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function (grunt) {
2 | "use strict";
3 |
4 | grunt.initConfig({
5 |
6 | pkg: grunt.file.readJSON('bower.json'),
7 |
8 | language: grunt.option('lang') || 'en',
9 |
10 | meta: {
11 | banner: '/**\n * <%= pkg.title || pkg.name %> - v<%= pkg.version %> - ' +
12 | '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
13 | ' * <%= pkg.homepage %>\n' +
14 | ' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;' +
15 | ' Licensed <%= pkg.license %>\n */\n'
16 | },
17 |
18 | build_dir: 'build',
19 |
20 | lib_files: {
21 |
22 | core: [
23 | 'src/growl.js',
24 | 'src/growlDirective.js',
25 | 'src/growlFactory.js'
26 | ],
27 | css: [
28 | 'src/growl.css'
29 | ],
30 | test: ['test/**/*.js']
31 | },
32 |
33 | watch: {
34 |
35 | scripts: {
36 | files: ['gruntfile.js', '<%= lib_files.core %>', '<%= lib_files.test %>'],
37 | tasks: ['jshint:all', 'karma:unit']
38 | },
39 |
40 | livereload: {
41 | options: {
42 | livereload: true
43 | },
44 | files: ['src/**/*.*'],
45 | tasks: ['jshint', 'karma:unit']
46 | }
47 | },
48 |
49 | jshint: {
50 | options: {
51 | jshintrc: '.jshintrc'
52 | },
53 |
54 | all: ['gruntfile.js', '<%= lib_files.core %>', '<%= lib_files.test %>'],
55 |
56 | core: {
57 | files: {
58 | src: ['<%= lib_files.core %>']
59 | }
60 | },
61 |
62 | test: {
63 | files: {
64 | src: ['<%= lib_files.test %>']
65 | }
66 | }
67 | },
68 |
69 | concat: {
70 | banner: {
71 | options: {
72 | banner: '<%= meta.banner %>'
73 | },
74 | src: '<%= concat.core.dest %>',
75 | dest: '<%= concat.core.dest %>'
76 | },
77 |
78 | core: {
79 | src: ['<%= lib_files.core %>'],
80 | dest: '<%= build_dir %>/angular-growl.js'
81 | }
82 | },
83 |
84 | cssmin: {
85 | core: {
86 | files: {
87 | 'build/angular-growl.min.css': '<%= lib_files.css %>'
88 | },
89 | options: {
90 | 'banner': '<%= meta.banner %>',
91 | 'report': 'gzip'
92 | }
93 | }
94 | },
95 |
96 | uglify: {
97 | core: {
98 | files: {
99 | '<%= build_dir %>/angular-growl.min.js': '<%= concat.core.dest %>'
100 | },
101 | options: {
102 | banner: '<%= meta.banner %>',
103 | report: 'gzip'
104 | }
105 | }
106 | },
107 |
108 | karma: {
109 | unit: {
110 | configFile: 'karma.conf.js',
111 | singleRun: true
112 | }
113 | },
114 |
115 | ngmin: {
116 | core: {
117 | src: '<%= concat.core.dest %>',
118 | dest: '<%= concat.core.dest %>'
119 | }
120 | },
121 | push: {
122 | options: {
123 | files: ['package.json', 'bower.json'],
124 | add: true,
125 | addFiles: ['.'], // '.' for all files except ingored files in .gitignore
126 | commit: true,
127 | commitMessage: 'Release v%VERSION%',
128 | commitFiles: ['package.json', 'bower.json', 'build/angular-growl.js', 'build/angular-growl.min.js', 'build/angular-growl.min.css', 'README.md'], // '-a' for all files
129 | createTag: true,
130 | tagName: 'v%VERSION%',
131 | tagMessage: 'Version %VERSION%',
132 | push: true,
133 | pushTo: 'origin',
134 | npm: true,
135 | npmTag: 'Release v%VERSION%',
136 | gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d' // options to use with '$ git describe'
137 | }
138 | }
139 | });
140 |
141 |
142 | grunt.registerTask('default', ['jshint:all', 'karma']);
143 | grunt.registerTask('test', ['karma']);
144 |
145 | grunt.registerTask('build', [
146 | 'jshint:all',
147 | 'karma',
148 | 'build:core'
149 | ]);
150 |
151 | grunt.registerTask('build:core', [
152 | 'concat:core',
153 | 'ngmin:core',
154 | 'concat:banner',
155 | 'uglify:core',
156 | 'cssmin:core'
157 | ]);
158 |
159 | // For development purpose.
160 | grunt.registerTask('dev', ['jshint', 'karma:unit', 'watch:livereload']);
161 |
162 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
163 | };
--------------------------------------------------------------------------------
/src/growlFactory.js:
--------------------------------------------------------------------------------
1 | angular.module("angular-growl").provider("growl", function() {
2 | "use strict";
3 |
4 | var _ttl = null,
5 | _enableHtml = false,
6 | _messagesKey = 'messages',
7 | _messageTextKey = 'text',
8 | _messageSeverityKey = 'severity',
9 | _onlyUniqueMessages = true;
10 |
11 | /**
12 | * set a global timeout (time to live) after which messages will be automatically closed
13 | *
14 | * @param ttl in seconds
15 | */
16 | this.globalTimeToLive = function(ttl) {
17 | _ttl = ttl;
18 | };
19 |
20 | /**
21 | * set whether HTML in message content should be escaped (default) or binded as-is
22 | *
23 | * @param {bool} enableHtml true to make all messages not escapes
24 | */
25 | this.globalEnableHtml = function(enableHtml) {
26 | _enableHtml = enableHtml;
27 | };
28 |
29 | /**
30 | * sets the key in $http response the serverMessagesInterecptor is looking for server-sent messages, value of key
31 | * needs to be an array of objects
32 | *
33 | * @param {string} messagesKey default: messages
34 | */
35 | this.messagesKey = function(messagesKey) {
36 | _messagesKey = messagesKey;
37 | };
38 |
39 | /**
40 | * sets the key in server sent messages the serverMessagesInterecptor is looking for text of message
41 | *
42 | * @param {string} messageTextKey default: text
43 | */
44 | this.messageTextKey = function(messageTextKey) {
45 | _messageTextKey = messageTextKey;
46 | };
47 |
48 | /**
49 | * sets the key in server sent messages the serverMessagesInterecptor is looking for severity of message
50 | *
51 | * @param {string} messageSeverityKey default: severity
52 | */
53 | this.messageSeverityKey = function(messageSeverityKey) {
54 | _messageSeverityKey = messageSeverityKey;
55 | };
56 |
57 | this.onlyUniqueMessages = function(onlyUniqueMessages) {
58 | _onlyUniqueMessages = onlyUniqueMessages;
59 | };
60 |
61 | /**
62 | * $http interceptor that can be added to array of $http interceptors during config phase of application
63 | * via $httpProvider.responseInterceptors.push(...)
64 | *
65 | */
66 | this.serverMessagesInterceptor = ['$q', 'growl', function ($q, growl) {
67 | function checkResponse(response) {
68 | if (response.data[_messagesKey] && response.data[_messagesKey].length > 0) {
69 | growl.addServerMessages(response.data[_messagesKey]);
70 | }
71 | }
72 |
73 | function success(response) {
74 | checkResponse(response);
75 | return response;
76 | }
77 |
78 | function error(response) {
79 | checkResponse(response);
80 | return $q.reject(response);
81 | }
82 |
83 | return function (promise) {
84 | return promise.then(success, error);
85 | };
86 | }];
87 |
88 | this.$get = ["$rootScope", "$filter", function ($rootScope, $filter) {
89 | var translate;
90 |
91 | try {
92 | translate = $filter("translate");
93 | } catch (e) {
94 | //
95 | }
96 |
97 | function broadcastMessage(message) {
98 | if (translate) {
99 | message.text = translate(message.text);
100 | }
101 | $rootScope.$broadcast("growlMessage", message);
102 | }
103 |
104 | function sendMessage(text, config, severity) {
105 | var _config = config || {}, message;
106 |
107 | message = {
108 | text: text,
109 | severity: severity,
110 | ttl: _config.ttl || _ttl,
111 | enableHtml: _config.enableHtml || _enableHtml
112 | };
113 |
114 | broadcastMessage(message);
115 | }
116 |
117 | /**
118 | * add one warn message with bootstrap class: alert
119 | *
120 | * @param {string} text
121 | * @param {{ttl: number}} config
122 | */
123 | function addWarnMessage(text, config) {
124 | sendMessage(text, config, "warn");
125 | }
126 |
127 | /**
128 | * add one error message with bootstrap classes: alert, alert-error
129 | *
130 | * @param {string} text
131 | * @param {{ttl: number}} config
132 | */
133 | function addErrorMessage(text, config) {
134 | sendMessage(text, config, "error");
135 | }
136 |
137 | /**
138 | * add one info message with bootstrap classes: alert, alert-info
139 | *
140 | * @param {string} text
141 | * @param {{ttl: number}} config
142 | */
143 | function addInfoMessage(text, config) {
144 | sendMessage(text, config, "info");
145 | }
146 |
147 | /**
148 | * add one success message with bootstrap classes: alert, alert-success
149 | *
150 | * @param {string} text
151 | * @param {{ttl: number}} config
152 | */
153 | function addSuccessMessage(text, config) {
154 | sendMessage(text, config, "success");
155 | }
156 |
157 | /**
158 | * add a indefinite number of messages that a backend server may have sent as a validation result
159 | *
160 | * @param {Array.