├── .bowerrc ├── .editorconfig ├── .gitignore ├── .jshintrc ├── .travis.yml ├── LICENSE ├── README.md ├── bower.json ├── dist ├── angular-consent.js └── angular-consent.min.js ├── gulpfile.js ├── karma-dist-concatenated.conf.js ├── karma-dist-minified.conf.js ├── karma-src.conf.js ├── package.json ├── src └── angular-consent │ ├── consent.module.js │ ├── controllers │ └── consent.js │ └── directives │ └── consent.js └── test └── unit └── angular-consent ├── consent.js ├── controllers └── consent.js └── directives └── consent.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower" 3 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ._* 2 | .~lock.* 3 | .buildpath 4 | .DS_Store 5 | .idea 6 | .project 7 | .settings 8 | 9 | # Ignore node stuff 10 | node_modules/ 11 | npm-debug.log 12 | libpeerconnection.log 13 | 14 | # OS-specific 15 | .DS_Store 16 | 17 | # Bower components 18 | bower 19 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise": true, 3 | "camelcase": true, 4 | "curly": true, 5 | "eqeqeq": true, 6 | "es3": false, 7 | "forin": true, 8 | "freeze": true, 9 | "immed": true, 10 | "indent": 2, 11 | "latedef": "nofunc", 12 | "newcap": true, 13 | "noarg": true, 14 | "noempty": true, 15 | "nonbsp": true, 16 | "nonew": true, 17 | "plusplus": false, 18 | "quotmark": "single", 19 | "undef": true, 20 | "unused": false, 21 | "strict": false, 22 | "maxparams": 10, 23 | "maxdepth": 5, 24 | "maxstatements": 40, 25 | "maxcomplexity": 8, 26 | "maxlen": 120, 27 | 28 | "asi": false, 29 | "boss": false, 30 | "debug": false, 31 | "eqnull": true, 32 | "esnext": false, 33 | "evil": false, 34 | "expr": false, 35 | "funcscope": false, 36 | "globalstrict": false, 37 | "iterator": false, 38 | "lastsemic": false, 39 | "laxbreak": false, 40 | "laxcomma": false, 41 | "loopfunc": true, 42 | "maxerr": false, 43 | "moz": false, 44 | "multistr": false, 45 | "notypeof": false, 46 | "proto": false, 47 | "scripturl": false, 48 | "shadow": false, 49 | "sub": true, 50 | "supernew": false, 51 | "validthis": false, 52 | "noyield": false, 53 | 54 | "browser": true, 55 | "node": true, 56 | 57 | "globals": { 58 | "angular": false, 59 | "$": false 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: ["0.10"] 3 | before_script: 4 | - npm install -g bower 5 | - bower install 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Jurgen Van de Moere 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular Consent 2 | [![Build Status](https://travis-ci.org/jvandemo/angular-consent.png?branch=master)](https://travis-ci.org/jvandemo/angular-consent) 3 | 4 | Easily show consent messages that keep appearing until the user clicks them away. 5 | 6 | Useful if you need to show legal disclaimers (e.g. to conform to the EU Cookie Consent law). 7 | 8 | - very lightweight (~1KB) 9 | - use your own markup and CSS to make the messages fit perfectly in your application 10 | - supports multiple consent messages on the same page 11 | 12 | [Try online demo](http://angular-consent-demo.surge.sh/). 13 | 14 | Requirements: 15 | 16 | - [ngCookies](https://docs.angularjs.org/api/ngCookies/service/$cookies) 17 | 18 | [![Screenshot](https://cloud.githubusercontent.com/assets/1859381/9572079/6a1f3d22-4fa9-11e5-8afd-5685251bea8c.png)](http://angular-consent-demo.surge.sh/) 19 | 20 | ## Quick example 21 | 22 | ```xml 23 | 24 | 25 |
26 | 27 | 28 |
29 |

This web application uses cookies to store private data.

30 | 31 |
32 | 33 |
34 | ``` 35 | 36 | ## Usage 37 | 38 | First install the module using bower: 39 | 40 | ```bash 41 | $ bower install angular-cookies 42 | $ bower install angular-consent 43 | ``` 44 | 45 | and add the library to your application: 46 | 47 | ```xml 48 | 49 | 50 | ``` 51 | 52 | Then add the `ngCookies` and `angularConsent` modules to the dependencies of your AngularJS application module: 53 | 54 | ```javascript 55 | angular.module('yourApp', ['ngCookies', 'angularConsent']); 56 | ``` 57 | 58 | Now you can use the `consent` directive anywhere in your markup: 59 | 60 | ```xml 61 | 62 | 63 |
64 | 65 | 66 |
67 |

This web application uses cookies to store private data.

68 | 69 |
70 | 71 |
72 | ``` 73 | 74 | To create multiple consents in a single application, pass a unique key to the `consent` attribute: 75 | 76 | ```xml 77 | 78 |
79 |
80 |

This website uses cookies.

81 | 82 |
83 |
84 | 85 | 86 |
87 |
88 |

This website stores private data.

89 | 90 |
91 |
92 | ``` 93 | 94 | You can also re-use a consent across your page or application: 95 | 96 | 97 | ```xml 98 | 99 |
100 |
101 |

This website uses cookies.

102 |
103 |
104 | 105 | 106 | 109 | ``` 110 | 111 | By default cookies are stored for 360 days, but you can customize cookie options on a consent level: 112 | 113 | ```xml 114 | 115 |
116 |
117 |

This website uses cookies. The cookie will be stored until expiration date.

118 |
119 |
120 | ``` 121 | 122 | ## The $consent API 123 | 124 | The following methods are available on the `$consent` object: 125 | 126 | ### $consent.hasAlreadyAgreed() 127 | 128 | Whether or not the user has already agreed. 129 | 130 | ##### Arguments 131 | 132 | None. 133 | 134 | ##### Returns 135 | 136 | Boolean. 137 | 138 | ### $consent.hasNotAgreedYet() 139 | 140 | Whether or not the user still has to agree. 141 | 142 | ##### Arguments 143 | 144 | None. 145 | 146 | ##### Returns 147 | 148 | Boolean. 149 | 150 | ### $consent.agree() 151 | 152 | Marks the consent as agreed. 153 | 154 | ##### Arguments 155 | 156 | None. 157 | 158 | ##### Returns 159 | 160 | Void. 161 | 162 | ### $consent.reset() 163 | 164 | Resets a previous agreement. 165 | 166 | ##### Arguments 167 | 168 | None. 169 | 170 | ##### Returns 171 | 172 | Void. 173 | 174 | ### Example with all available methods 175 | 176 | ```xml 177 |
178 | 179 |
180 |

This message will keep appearing until you agree

181 |
183 | 184 |
185 |

This message will appear when user has already agreed

186 |
188 | 189 |
190 | ``` 191 | 192 | 193 | ## Contribute 194 | 195 | To update the build in the `dist` directory: 196 | 197 | ```bash 198 | $ gulp 199 | ``` 200 | 201 | To run the unit tests using the src files: 202 | 203 | ```bash 204 | $ gulp test-src 205 | ``` 206 | 207 | To run the unit tests using the unminified library: 208 | 209 | ```bash 210 | $ gulp test-dist-concatenated 211 | ``` 212 | 213 | To run the unit tests using the minified library: 214 | 215 | ```bash 216 | $ gulp test-dist-minified 217 | ``` 218 | 219 | ## Change log 220 | 221 | ### v2.2.0 222 | 223 | - Added main property to package.json (#5) 224 | 225 | ### v2.1.1 226 | 227 | - Added check to make sure expires is always set correctly to fix #4 228 | 229 | ### v2.1.0 230 | 231 | - Added support for AngularJS versions older than AngularJS 1.4 232 | 233 | ### v2.0.0 234 | 235 | - Cookies are now stored for 360 days by default (instead of session) 236 | - Added support for cookie options via `consent-cookie-options` attribute 237 | 238 | ### v1.0.0 239 | 240 | - Added support for multiple consent messages simultaneously 241 | - Updated documentation 242 | - Added demo 243 | 244 | ### v0.1.0 245 | 246 | - Added consent directive 247 | - Added unit tests 248 | - Added initial documentation 249 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-consent", 3 | "version": "2.1.0", 4 | "authors": [ 5 | { 6 | "name": "Jurgen Van de Moere", 7 | "email": "jurgen.van.de.moere@gmail.com" 8 | } 9 | ], 10 | "main": ["dist/angular-consent.js"], 11 | "ignore": [ 12 | "src", 13 | "test", 14 | "gulpfile.js", 15 | "**/.*" 16 | ], 17 | "dependencies": {}, 18 | "devDependencies": { 19 | "angular-mocks": ">=1.2.0", 20 | "angular-scenario": ">=1.2.0", 21 | "angular": ">=1.2.0", 22 | "angular-cookies": ">=1.2.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dist/angular-consent.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | // Create all modules and define dependencies to make sure they exist 4 | // and are loaded in the correct order to satisfy dependency injection 5 | // before all nested files are concatenated by Gulp 6 | 7 | // Config 8 | angular.module('angularConsent.config', []) 9 | .value('angularConsent.config', { 10 | debug: true 11 | }); 12 | 13 | // Modules 14 | angular.module('angularConsent.directives', []); 15 | angular.module('angularConsent.controllers', []); 16 | angular.module('angularConsent', 17 | [ 18 | 'angularConsent.config', 19 | 'angularConsent.directives', 20 | 'angularConsent.controllers', 21 | 'ngCookies' 22 | ]); 23 | 24 | })(angular); 25 | 26 | (function (angular) { 27 | 28 | angular 29 | .module('angularConsent.controllers') 30 | .controller('angularConsent.ConsentController', ConsentController); 31 | 32 | function ConsentController($cookies, $attrs, $scope){ 33 | 34 | this.getCookieKey = function(){ 35 | return 'angular-consent.' + ($attrs.consent || 'global'); 36 | }; 37 | 38 | this.getCookieOptions = function(){ 39 | var options = {}; 40 | if($attrs.consentCookieOptions){ 41 | options = $scope.$eval($attrs.consentCookieOptions); 42 | } 43 | if(!options.hasOwnProperty('expires')){ 44 | var now = new Date(); 45 | var expirationDate = new Date(); 46 | expirationDate.setTime(+ now + (360 * 24 * 60 * 60 * 1000)); // 360 days 47 | options.expires = expirationDate.toGMTString(); 48 | } 49 | return options; 50 | }; 51 | 52 | this.getCookieValue = function(){ 53 | try { 54 | return $cookies.get(this.getCookieKey()); 55 | } catch (e) { 56 | if (e instanceof TypeError){ 57 | return $cookies[this.getCookieKey()]; 58 | } 59 | } 60 | }; 61 | 62 | this.setCookieValue = function(value){ 63 | try { 64 | return $cookies.put(this.getCookieKey(), value, this.getCookieOptions()); 65 | } catch (e) { 66 | if (e instanceof TypeError){ 67 | $cookies[this.getCookieKey()] = value ; 68 | } 69 | } 70 | }; 71 | 72 | this.hasAlreadyAgreed = function(){ 73 | if(this.getCookieValue()){ 74 | return true; 75 | } 76 | return false; 77 | }; 78 | 79 | this.hasNotAgreedYet = function(){ 80 | return !this.hasAlreadyAgreed(); 81 | }; 82 | 83 | this.reset = function(){ 84 | try { 85 | $cookies.remove(this.getCookieKey()); 86 | } catch (e) { 87 | if (e instanceof TypeError){ 88 | delete $cookies[this.getCookieKey()]; 89 | } 90 | } 91 | }; 92 | 93 | this.agree = function(){ 94 | this.setCookieValue(Date.now()); 95 | }; 96 | } 97 | 98 | ConsentController.$inject = ['$cookies', '$attrs', '$scope']; 99 | 100 | })(angular); 101 | 102 | (function (angular) { 103 | 104 | angular 105 | .module('angularConsent.directives') 106 | .directive('consent', createDirectiveDDO); 107 | 108 | function createDirectiveDDO(){ 109 | return { 110 | restrict: 'A', 111 | scope: true, 112 | controller: 'angularConsent.ConsentController', 113 | controllerAs: '$consent' 114 | }; 115 | } 116 | 117 | })(angular); 118 | -------------------------------------------------------------------------------- /dist/angular-consent.min.js: -------------------------------------------------------------------------------- 1 | !function(e){e.module("angularConsent.config",[]).value("angularConsent.config",{debug:!0}),e.module("angularConsent.directives",[]),e.module("angularConsent.controllers",[]),e.module("angularConsent",["angularConsent.config","angularConsent.directives","angularConsent.controllers","ngCookies"])}(angular),function(e){function n(e,n,t){this.getCookieKey=function(){return"angular-consent."+(n.consent||"global")},this.getCookieOptions=function(){var e={};if(n.consentCookieOptions&&(e=t.$eval(n.consentCookieOptions)),!e.hasOwnProperty("expires")){var o=new Date,r=new Date;r.setTime(+o+31104e6),e.expires=r.toGMTString()}return e},this.getCookieValue=function(){try{return e.get(this.getCookieKey())}catch(n){if(n instanceof TypeError)return e[this.getCookieKey()]}},this.setCookieValue=function(n){try{return e.put(this.getCookieKey(),n,this.getCookieOptions())}catch(t){t instanceof TypeError&&(e[this.getCookieKey()]=n)}},this.hasAlreadyAgreed=function(){return this.getCookieValue()?!0:!1},this.hasNotAgreedYet=function(){return!this.hasAlreadyAgreed()},this.reset=function(){try{e.remove(this.getCookieKey())}catch(n){n instanceof TypeError&&delete e[this.getCookieKey()]}},this.agree=function(){this.setCookieValue(Date.now())}}e.module("angularConsent.controllers").controller("angularConsent.ConsentController",n),n.$inject=["$cookies","$attrs","$scope"]}(angular),function(e){function n(){return{restrict:"A",scope:!0,controller:"angularConsent.ConsentController",controllerAs:"$consent"}}e.module("angularConsent.directives").directive("consent",n)}(angular); -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var karma = require('karma').server; 3 | var concat = require('gulp-concat'); 4 | var uglify = require('gulp-uglify'); 5 | var rename = require('gulp-rename'); 6 | var path = require('path'); 7 | var plumber = require('gulp-plumber'); 8 | var runSequence = require('run-sequence'); 9 | var jshint = require('gulp-jshint'); 10 | 11 | /** 12 | * File patterns 13 | **/ 14 | 15 | // Root directory 16 | var rootDirectory = path.resolve('./'); 17 | 18 | // Source directory for build process 19 | var sourceDirectory = path.join(rootDirectory, './src'); 20 | 21 | var sourceFiles = [ 22 | 23 | // Make sure module files are handled first 24 | path.join(sourceDirectory, '/**/*.module.js'), 25 | 26 | // Then add all JavaScript files 27 | path.join(sourceDirectory, '/**/*.js') 28 | ]; 29 | 30 | var lintFiles = [ 31 | 'gulpfile.js', 32 | // Karma configuration 33 | 'karma-*.conf.js' 34 | ].concat(sourceFiles); 35 | 36 | gulp.task('build', function() { 37 | gulp.src(sourceFiles) 38 | .pipe(plumber()) 39 | .pipe(concat('angular-consent.js')) 40 | .pipe(gulp.dest('./dist/')) 41 | .pipe(uglify()) 42 | .pipe(rename('angular-consent.min.js')) 43 | .pipe(gulp.dest('./dist')); 44 | }); 45 | 46 | /** 47 | * Process 48 | */ 49 | gulp.task('process-all', function (done) { 50 | runSequence('jshint', 'test-src', 'build', done); 51 | }); 52 | 53 | /** 54 | * Watch task 55 | */ 56 | gulp.task('watch', function () { 57 | 58 | // Watch JavaScript files 59 | gulp.watch(sourceFiles, ['process-all']); 60 | }); 61 | 62 | /** 63 | * Validate source JavaScript 64 | */ 65 | gulp.task('jshint', function () { 66 | return gulp.src(lintFiles) 67 | .pipe(plumber()) 68 | .pipe(jshint()) 69 | .pipe(jshint.reporter('jshint-stylish')) 70 | .pipe(jshint.reporter('fail')); 71 | }); 72 | 73 | /** 74 | * Run test once and exit 75 | */ 76 | gulp.task('test-src', function (done) { 77 | karma.start({ 78 | configFile: __dirname + '/karma-src.conf.js', 79 | singleRun: true 80 | }, done); 81 | }); 82 | 83 | /** 84 | * Run test once and exit 85 | */ 86 | gulp.task('test-dist-concatenated', function (done) { 87 | karma.start({ 88 | configFile: __dirname + '/karma-dist-concatenated.conf.js', 89 | singleRun: true 90 | }, done); 91 | }); 92 | 93 | /** 94 | * Run test once and exit 95 | */ 96 | gulp.task('test-dist-minified', function (done) { 97 | karma.start({ 98 | configFile: __dirname + '/karma-dist-minified.conf.js', 99 | singleRun: true 100 | }, done); 101 | }); 102 | 103 | gulp.task('default', function () { 104 | runSequence('process-all', 'watch'); 105 | }); 106 | -------------------------------------------------------------------------------- /karma-dist-concatenated.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs2-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery' 23 | ], 24 | 25 | // list of files / patterns to load in the browser 26 | files: [ 27 | 'bower/angular/angular.js', 28 | 'bower/angular-cookies/angular-cookies.js', 29 | 'bower/angular-mocks/angular-mocks.js', 30 | 'dist/angular-consent.js', 31 | 'test/unit/**/*.js' 32 | ], 33 | 34 | 35 | // list of files to exclude 36 | exclude: [ 37 | ], 38 | 39 | 40 | // preprocess matching files before serving them to the browser 41 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 42 | preprocessors: { 43 | }, 44 | 45 | 46 | // test results reporter to use 47 | // possible values: 'dots', 'progress' 48 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 49 | reporters: ['progress'], 50 | 51 | 52 | // web server port 53 | port: 9876, 54 | 55 | 56 | // enable / disable colors in the output (reporters and logs) 57 | colors: true, 58 | 59 | 60 | // level of logging 61 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 62 | logLevel: config.LOG_INFO, 63 | 64 | 65 | // enable / disable watching file and executing tests whenever any file changes 66 | autoWatch: true, 67 | 68 | 69 | // start these browsers 70 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 71 | browsers: ['PhantomJS2'], 72 | 73 | 74 | // Continuous Integration mode 75 | // if true, Karma captures browsers, runs the tests and exits 76 | singleRun: false 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /karma-dist-minified.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs2-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery' 23 | ], 24 | 25 | // list of files / patterns to load in the browser 26 | files: [ 27 | 'bower/angular/angular.js', 28 | 'bower/angular-cookies/angular-cookies.js', 29 | 'bower/angular-mocks/angular-mocks.js', 30 | 'dist/angular-consent.min.js', 31 | 'test/unit/**/*.js' 32 | ], 33 | 34 | 35 | // list of files to exclude 36 | exclude: [ 37 | ], 38 | 39 | 40 | // preprocess matching files before serving them to the browser 41 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 42 | preprocessors: { 43 | }, 44 | 45 | 46 | // test results reporter to use 47 | // possible values: 'dots', 'progress' 48 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 49 | reporters: ['progress'], 50 | 51 | 52 | // web server port 53 | port: 9876, 54 | 55 | 56 | // enable / disable colors in the output (reporters and logs) 57 | colors: true, 58 | 59 | 60 | // level of logging 61 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 62 | logLevel: config.LOG_INFO, 63 | 64 | 65 | // enable / disable watching file and executing tests whenever any file changes 66 | autoWatch: true, 67 | 68 | 69 | // start these browsers 70 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 71 | browsers: ['PhantomJS2'], 72 | 73 | 74 | // Continuous Integration mode 75 | // if true, Karma captures browsers, runs the tests and exits 76 | singleRun: false 77 | }); 78 | }; 79 | -------------------------------------------------------------------------------- /karma-src.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Thu Aug 21 2014 10:24:39 GMT+0200 (CEST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | 11 | // frameworks to use 12 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 13 | frameworks: ['mocha', 'chai-jquery', 'jquery-1.8.3', 'sinon-chai'], 14 | 15 | plugins: [ 16 | 'karma-mocha', 17 | 'karma-chai', 18 | 'karma-sinon-chai', 19 | 'karma-chrome-launcher', 20 | 'karma-phantomjs2-launcher', 21 | 'karma-jquery', 22 | 'karma-chai-jquery' 23 | ], 24 | 25 | // list of files / patterns to load in the browser 26 | files: [ 27 | 'bower/angular/angular.js', 28 | 'bower/angular-cookies/angular-cookies.js', 29 | 'bower/angular-mocks/angular-mocks.js', 30 | 'src/**/*.module.js', 31 | 'src/**/*.js', 32 | 'test/unit/**/*.js' 33 | ], 34 | 35 | 36 | // list of files to exclude 37 | exclude: [ 38 | ], 39 | 40 | 41 | // preprocess matching files before serving them to the browser 42 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 43 | preprocessors: { 44 | }, 45 | 46 | 47 | // test results reporter to use 48 | // possible values: 'dots', 'progress' 49 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 50 | reporters: ['progress'], 51 | 52 | 53 | // web server port 54 | port: 9876, 55 | 56 | 57 | // enable / disable colors in the output (reporters and logs) 58 | colors: true, 59 | 60 | 61 | // level of logging 62 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 63 | logLevel: config.LOG_INFO, 64 | 65 | 66 | // enable / disable watching file and executing tests whenever any file changes 67 | autoWatch: true, 68 | 69 | 70 | // start these browsers 71 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 72 | browsers: ['PhantomJS2'], 73 | 74 | 75 | // Continuous Integration mode 76 | // if true, Karma captures browsers, runs the tests and exits 77 | singleRun: false 78 | }); 79 | }; 80 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-consent", 3 | "main": "dist/angular-consent.js", 4 | "version": "2.2.0", 5 | "author": { 6 | "name": "Jurgen Van de Moere", 7 | "email": "jurgen.van.de.moere@gmail.com" 8 | }, 9 | "scripts": { 10 | "test": "gulp test-dist-minified" 11 | }, 12 | "dependencies": {}, 13 | "devDependencies": { 14 | "chai": "^1.9.1", 15 | "chai-jquery": "^1.2.3", 16 | "gulp": "^3.8.7", 17 | "gulp-concat": "^2.3.4", 18 | "gulp-jshint": "^1.8.4", 19 | "gulp-plumber": "^0.6.6", 20 | "gulp-rename": "^1.2.0", 21 | "gulp-uglify": "^0.3.1", 22 | "jshint-stylish": "^0.4.0", 23 | "karma": "^0.12.22", 24 | "karma-chai": "^0.1.0", 25 | "karma-chai-jquery": "^1.0.0", 26 | "karma-chrome-launcher": "^0.1.4", 27 | "karma-jasmine": "^0.1.5", 28 | "karma-jquery": "^0.1.0", 29 | "karma-mocha": "^0.1.8", 30 | "karma-phantomjs2-launcher": "^0.5.0", 31 | "karma-sinon-chai": "^0.2.0", 32 | "mocha": "^1.21.4", 33 | "run-sequence": "^1.0.2", 34 | "sinon": "^1.10.3", 35 | "sinon-chai": "^2.5.0" 36 | }, 37 | "engines": { 38 | "node": ">=0.8.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/angular-consent/consent.module.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | // Create all modules and define dependencies to make sure they exist 4 | // and are loaded in the correct order to satisfy dependency injection 5 | // before all nested files are concatenated by Gulp 6 | 7 | // Config 8 | angular.module('angularConsent.config', []) 9 | .value('angularConsent.config', { 10 | debug: true 11 | }); 12 | 13 | // Modules 14 | angular.module('angularConsent.directives', []); 15 | angular.module('angularConsent.controllers', []); 16 | angular.module('angularConsent', 17 | [ 18 | 'angularConsent.config', 19 | 'angularConsent.directives', 20 | 'angularConsent.controllers', 21 | 'ngCookies' 22 | ]); 23 | 24 | })(angular); 25 | -------------------------------------------------------------------------------- /src/angular-consent/controllers/consent.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | angular 4 | .module('angularConsent.controllers') 5 | .controller('angularConsent.ConsentController', ConsentController); 6 | 7 | function ConsentController($cookies, $attrs, $scope){ 8 | 9 | this.getCookieKey = function(){ 10 | return 'angular-consent.' + ($attrs.consent || 'global'); 11 | }; 12 | 13 | this.getCookieOptions = function(){ 14 | var options = {}; 15 | if($attrs.consentCookieOptions){ 16 | options = $scope.$eval($attrs.consentCookieOptions); 17 | } 18 | if(!options.hasOwnProperty('expires')){ 19 | var now = new Date(); 20 | var expirationDate = new Date(); 21 | expirationDate.setTime(+ now + (360 * 24 * 60 * 60 * 1000)); // 360 days 22 | options.expires = expirationDate.toGMTString(); 23 | } 24 | return options; 25 | }; 26 | 27 | this.getCookieValue = function(){ 28 | try { 29 | return $cookies.get(this.getCookieKey()); 30 | } catch (e) { 31 | if (e instanceof TypeError){ 32 | return $cookies[this.getCookieKey()]; 33 | } 34 | } 35 | }; 36 | 37 | this.setCookieValue = function(value){ 38 | try { 39 | return $cookies.put(this.getCookieKey(), value, this.getCookieOptions()); 40 | } catch (e) { 41 | if (e instanceof TypeError){ 42 | $cookies[this.getCookieKey()] = value ; 43 | } 44 | } 45 | }; 46 | 47 | this.hasAlreadyAgreed = function(){ 48 | if(this.getCookieValue()){ 49 | return true; 50 | } 51 | return false; 52 | }; 53 | 54 | this.hasNotAgreedYet = function(){ 55 | return !this.hasAlreadyAgreed(); 56 | }; 57 | 58 | this.reset = function(){ 59 | try { 60 | $cookies.remove(this.getCookieKey()); 61 | } catch (e) { 62 | if (e instanceof TypeError){ 63 | delete $cookies[this.getCookieKey()]; 64 | } 65 | } 66 | }; 67 | 68 | this.agree = function(){ 69 | this.setCookieValue(Date.now()); 70 | }; 71 | } 72 | 73 | ConsentController.$inject = ['$cookies', '$attrs', '$scope']; 74 | 75 | })(angular); 76 | -------------------------------------------------------------------------------- /src/angular-consent/directives/consent.js: -------------------------------------------------------------------------------- 1 | (function (angular) { 2 | 3 | angular 4 | .module('angularConsent.directives') 5 | .directive('consent', createDirectiveDDO); 6 | 7 | function createDirectiveDDO(){ 8 | return { 9 | restrict: 'A', 10 | scope: true, 11 | controller: 'angularConsent.ConsentController', 12 | controllerAs: '$consent' 13 | }; 14 | } 15 | 16 | })(angular); 17 | -------------------------------------------------------------------------------- /test/unit/angular-consent/consent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('', function() { 4 | 5 | var module; 6 | var dependencies; 7 | dependencies = []; 8 | 9 | var hasModule = function(module) { 10 | return dependencies.indexOf(module) >= 0; 11 | }; 12 | 13 | beforeEach(function() { 14 | 15 | // Get module 16 | module = angular.module('angularConsent'); 17 | dependencies = module.requires; 18 | }); 19 | 20 | it('should load config module', function() { 21 | expect(hasModule('angularConsent.config')).to.be.ok; 22 | }); 23 | 24 | it('should load directives module', function() { 25 | expect(hasModule('angularConsent.directives')).to.be.ok; 26 | }); 27 | 28 | it('should load controllers module', function() { 29 | expect(hasModule('angularConsent.controllers')).to.be.ok; 30 | }); 31 | 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /test/unit/angular-consent/controllers/consent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('angular-consent controller', function() { 4 | 5 | var $controller; 6 | var $cookies; 7 | var $scope; 8 | var $rootScope; 9 | var ctrl; 10 | 11 | beforeEach(module('angularConsent')); 12 | 13 | beforeEach(inject(function(_$controller_, _$cookies_, _$rootScope_){ 14 | $controller = _$controller_; 15 | $cookies = _$cookies_; 16 | $rootScope = _$rootScope_; 17 | $scope = $rootScope.$new(); 18 | ctrl = $controller('angularConsent.ConsentController', { 19 | $attrs: {}, 20 | $scope: $scope 21 | }); 22 | })); 23 | 24 | it('should exist', function() { 25 | expect(ctrl).to.be.an('object'); 26 | }); 27 | 28 | describe('#agree()', function(){ 29 | 30 | it('should update cookie correctly', function() { 31 | ctrl.reset(); 32 | expect(ctrl.getCookieValue()).to.not.exist; 33 | ctrl.agree(); 34 | expect(ctrl.getCookieValue()).to.exist; 35 | }); 36 | 37 | }); 38 | 39 | describe('#reset()', function(){ 40 | 41 | it('should update cookie correctly', function() { 42 | ctrl.reset(); 43 | expect(ctrl.getCookieValue()).to.not.exist; 44 | ctrl.agree(); 45 | expect(ctrl.getCookieValue()).to.exist; 46 | ctrl.reset(); 47 | expect(ctrl.getCookieValue()).to.not.exist; 48 | }); 49 | 50 | }); 51 | 52 | 53 | }); 54 | -------------------------------------------------------------------------------- /test/unit/angular-consent/directives/consent.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('angular-consent directive', function() { 4 | 5 | var $compile; 6 | var $rootScope; 7 | var $cookies; 8 | 9 | beforeEach(module('angularConsent')); 10 | 11 | beforeEach(inject(function(_$rootScope_, _$compile_, _$cookies_){ 12 | $rootScope = _$rootScope_; 13 | $compile = _$compile_; 14 | $cookies = _$cookies_; 15 | })); 16 | 17 | it('should handle non-existing cookie correctly', function() { 18 | var markup = '
'; 19 | markup += '

Not agreed yet

'; 20 | markup += '

Already agreed

'; 21 | markup += '
'; 22 | var $scope = $rootScope.$new(); 23 | var element = $compile(markup)($scope); 24 | $rootScope.$digest(); 25 | expect(element.html()).to.contain('Not agreed yet'); 26 | expect(element.html()).to.not.contain('Already agreed'); 27 | }); 28 | 29 | it('should handle truthy value correctly', function() { 30 | $cookies.put('angular-consent.test', Date.now()); 31 | var markup = '
'; 32 | markup += '

Not agreed yet

'; 33 | markup += '

Already agreed

'; 34 | markup += '
'; 35 | var $scope = $rootScope.$new(); 36 | var element = $compile(markup)($scope); 37 | $rootScope.$digest(); 38 | expect(element.html()).to.not.contain('Not agreed yet'); 39 | expect(element.html()).to.contain('Already agreed'); 40 | }); 41 | 42 | it('should handle empty value correctly', function() { 43 | $cookies.put('angular-consent.test', ''); 44 | var markup = '
'; 45 | markup += '

Not agreed yet

'; 46 | markup += '

Already agreed

'; 47 | markup += '
'; 48 | var $scope = $rootScope.$new(); 49 | var element = $compile(markup)($scope); 50 | $rootScope.$digest(); 51 | expect(element.html()).to.contain('Not agreed yet'); 52 | expect(element.html()).to.not.contain('Already agreed'); 53 | }); 54 | 55 | }); 56 | --------------------------------------------------------------------------------