diff --git a/Gruntfile.js b/Gruntfile.js index 8cacec0..f86beb1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,187 +1,187 @@ -/* global module */ - -module.exports = function (grunt) { - grunt.loadNpmTasks('grunt-bump'); - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-concat'); - grunt.loadNpmTasks('grunt-contrib-connect'); - grunt.loadNpmTasks('grunt-contrib-copy'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-jscs'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-karma'); - grunt.loadNpmTasks('grunt-open'); - - grunt.registerTask('default', [ - 'build', - 'test', - 'package' - ]); - - grunt.registerTask('build', [ - 'jshint', - 'jscs', - 'clean:build', - 'copy:build' - ]); - grunt.registerTask('test', [ - 'karma:browser_unit' - ]); - grunt.registerTask('test:dev', [ - 'karma:headless_unit' - ]); - grunt.registerTask('test:debug', [ - 'karma:browser_unit_debug' - ]); - grunt.registerTask('package', [ - 'clean:package', - 'concat:package', - 'uglify:package' - ]); - grunt.registerTask('workflow:dev', [ - 'connect:dev', - 'build', - 'test:dev', - 'open:dev', - 'watch:dev' - ]); - - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - env: grunt.option('env') || 'dev', - - app: { - name: 'angular-http-loader', - source_dir: 'app/src', - build_dir: 'app/build', - package_dir: 'app/package' - }, - - clean: { - build: '<%= app.build_dir %>', - package: '<%= app.package_dir %>' - }, - - jshint: { - source: [ - '*.js', - '<%= app.source_dir %>/js/**/*.js' - ], - options: { - jshintrc: '.jshintrc' - } - }, - - jscs: { - source: [ - '*.js', - '<%= app.source_dir %>/js/**/*.js' - ], - options: { - config: '.jscsrc' - } - }, - - copy: { - build: { - files: [ - { - expand: true, - cwd: '<%= app.source_dir %>', - src: ['**'], - dest: '<%= app.build_dir %>' - }, - { - expand: true, - src: ['bower.json', 'package.json'], - dest: '<%= app.build_dir %>' - } - ] - } - }, - - karma: { - headless_unit: { - options: { - configFile: 'karma-unit.conf.js', - browsers: ['PhantomJS'] - } - }, - browser_unit: { - options: { - configFile: 'karma-unit.conf.js' - } - }, - browser_unit_debug: { - options: { - configFile: 'karma-unit.conf.js', - singleRun: false, - browsers: ['Chrome'] - } - } - }, - - concat: { - package: { - src: [ - '<%= app.build_dir %>/js/**/*.js', - '!<%= app.build_dir %>/js/**/*.spec.js' - ], - dest: '<%= app.package_dir %>/js/<%= app.name %>.js' - } - }, - - uglify: { - package: { - files: { - '<%= app.package_dir %>/js/<%= app.name %>.min.js': [ - '<%= app.package_dir %>/js/<%= app.name %>.js' - ] - } - } - }, - - bump: { - options: { - files: ['bower.json', 'package.json'], - commitFiles: ['bower.json', 'package.json'], - pushTo: 'origin' - } - }, - - connect: { - options: { - hostname: '*' - }, - dev: { - options: { - port: 9000, - base: '<%= app.build_dir %>' - } - }, - package: { - options: { - port: 9001, - base: '<%= app.package_dir %>' - } - } - }, - - open: { - dev: { - url: 'http://127.0.0.1:<%= connect.dev.options.port %>/demo.html' - } - }, - - watch: { - dev: { - files: ['<%= app.source_dir %>/**/*'], - tasks: ['build', 'test:dev'], - options: { - livereload: true - } - } - } - }); -}; +/* global module */ + +module.exports = function (grunt) { + grunt.loadNpmTasks('grunt-bump'); + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-concat'); + grunt.loadNpmTasks('grunt-contrib-connect'); + grunt.loadNpmTasks('grunt-contrib-copy'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-jscs'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-karma'); + grunt.loadNpmTasks('grunt-open'); + + grunt.registerTask('default', [ + 'build', + 'test', + 'package' + ]); + + grunt.registerTask('build', [ + 'jshint', + 'jscs', + 'clean:build', + 'copy:build' + ]); + grunt.registerTask('test', [ + 'karma:browser_unit' + ]); + grunt.registerTask('test:dev', [ + 'karma:headless_unit' + ]); + grunt.registerTask('test:debug', [ + 'karma:browser_unit_debug' + ]); + grunt.registerTask('package', [ + 'clean:package', + 'concat:package', + 'uglify:package' + ]); + grunt.registerTask('workflow:dev', [ + 'connect:dev', + 'build', + 'test:dev', + 'open:dev', + 'watch:dev' + ]); + + grunt.initConfig({ + pkg: grunt.file.readJSON('package.json'), + env: grunt.option('env') || 'dev', + + app: { + name: 'angular-http-loader', + source_dir: 'app/src', + build_dir: 'app/build', + package_dir: 'app/package' + }, + + clean: { + build: '<%= app.build_dir %>', + package: '<%= app.package_dir %>' + }, + + jshint: { + source: [ + '*.js', + '<%= app.source_dir %>/js/**/*.js' + ], + options: { + jshintrc: '.jshintrc' + } + }, + + jscs: { + source: [ + '*.js', + '<%= app.source_dir %>/js/**/*.js' + ], + options: { + config: '.jscsrc' + } + }, + + copy: { + build: { + files: [ + { + expand: true, + cwd: '<%= app.source_dir %>', + src: ['**'], + dest: '<%= app.build_dir %>' + }, + { + expand: true, + src: ['bower.json', 'package.json'], + dest: '<%= app.build_dir %>' + } + ] + } + }, + + karma: { + headless_unit: { + options: { + configFile: 'karma-unit.conf.js', + browsers: ['PhantomJS'] + } + }, + browser_unit: { + options: { + configFile: 'karma-unit.conf.js' + } + }, + browser_unit_debug: { + options: { + configFile: 'karma-unit.conf.js', + singleRun: false, + browsers: ['Chrome'] + } + } + }, + + concat: { + package: { + src: [ + '<%= app.build_dir %>/js/**/*.js', + '!<%= app.build_dir %>/js/**/*.spec.js' + ], + dest: '<%= app.package_dir %>/js/<%= app.name %>.js' + } + }, + + uglify: { + package: { + files: { + '<%= app.package_dir %>/js/<%= app.name %>.min.js': [ + '<%= app.package_dir %>/js/<%= app.name %>.js' + ] + } + } + }, + + bump: { + options: { + files: ['bower.json', 'package.json'], + commitFiles: ['bower.json', 'package.json'], + pushTo: 'origin' + } + }, + + connect: { + options: { + hostname: '*' + }, + dev: { + options: { + port: 9000, + base: '<%= app.build_dir %>' + } + }, + package: { + options: { + port: 9001, + base: '<%= app.package_dir %>' + } + } + }, + + open: { + dev: { + url: 'http://127.0.0.1:<%= connect.dev.options.port %>/demo.html' + } + }, + + watch: { + dev: { + files: ['<%= app.source_dir %>/**/*'], + tasks: ['build', 'test:dev'], + options: { + livereload: true + } + } + } + }); +}; diff --git a/app/package/js/angular-http-loader.js b/app/package/js/angular-http-loader.js index ef55405..c2460b9 100644 --- a/app/package/js/angular-http-loader.js +++ b/app/package/js/angular-http-loader.js @@ -1,249 +1,266 @@ -/* global angular */ - -angular - .module('ng.httpLoader', [ - 'ng.httpLoader.httpMethodInterceptor' - ]) - - .directive('ngHttpLoader', [ - '$rootScope', - '$parse', - '$timeout', - function ($rootScope, $parse, $timeout) { - - /** - * Usage example: - * - * Multiple method loader - * - *
- * - * Single method loader - * - * - * - * Adding a title [optional] - * - * - */ - return { - /** - * Available attributes - * - * @param {array|string} methods - * @param {string} template - * @param {string} title - * @param {number} time to live in seconds - */ - scope: { - methods: '@', - template: '@', - title: '@', - ttl: '@' - }, - template: '', - link: function ($scope) { - var methods = $parse($scope.methods)() || $scope.methods; - methods = angular.isUndefined(methods) ? [] : methods; - methods = angular.isArray(methods) ? methods : [methods]; - angular.forEach(methods, function (method, index) { - methods[index] = method.toUpperCase(); - }); - - var ttl = $parse($scope.ttl)() || $scope.ttl; - ttl = angular.isUndefined(ttl) ? 0 : ttl; - ttl = Number(ttl) * 1000; - ttl = angular.isNumber(ttl) ? ttl : 0; - - - // add minimal indexOf polyfill - if (!Array.prototype.indexOf) { - methods.indexOf = function (value) { - for (var i = this.length; i--;) { - if (this[i] === value) { - return i; - } - } - - return -1; - }; - } - - /** - * Loader is hidden by default - * @type {boolean} - */ - $scope.showLoader = false; - - var timeoutId, - showLoader = $scope.showLoader; - - /** - * Toggle the show loader. - * Contains the logic to show or hide the loader depending - * on the passed method - * - * @param {object} event - * @param {string} method - */ - var toggleShowLoader = function (event, method) { - if (methods.indexOf(method.toUpperCase()) !== -1) { - showLoader = (event.name === 'loaderShow'); - } else if (methods.length === 0) { - showLoader = (event.name === 'loaderShow'); - } - - if (ttl <= 0 || (!timeoutId && !showLoader)) { - $scope.showLoader = showLoader; - return; - } - if (timeoutId) { - return; - } - - $scope.showLoader = showLoader; - timeoutId = $timeout(function () { - if (!showLoader) { - $scope.showLoader = showLoader; - } - timeoutId = undefined; - }, ttl); - }; - - $rootScope.$on('loaderShow', toggleShowLoader); - $rootScope.$on('loaderHide', toggleShowLoader); - } - }; - } - ]); - -/* global angular */ - -/** - * Http method interceptor. Broadcast events for show or hide the loader. - */ -angular - .module('ng.httpLoader.httpMethodInterceptor', []) - - .provider('httpMethodInterceptor', function () { - var domains = [], - whitelistLocalRequests = false; - - /** - * Add domains to the white list - * - * @param {string} domain - * Added Domain to the white list domains collection - */ - this.whitelistDomain = function (domain) { - domains.push(domain); - }; - - /** - * White list requests to the local domain - */ - this.whitelistLocalRequests = function () { - whitelistLocalRequests = true; - }; - - this.$get = [ - '$q', - '$rootScope', - function ($q, $rootScope) { - var numLoadings = 0; - - /** - * Check if the url domain is on the whitelist - * - * @param {string} url - * - * @returns {boolean} - */ - var isUrlOnWhitelist = function (url) { - if (url.substring(0, 2) !== '//' && - url.indexOf('://') === -1 && - whitelistLocalRequests) { - return true; - } - - for (var i = domains.length; i--;) { - if (url.indexOf(domains[i]) !== -1) { - return true; - } - } - - return false; - }; - - /** - * Emit hide loader logic - * - * @param {object} config - * The response configuration - */ - var checkAndHide = function (config) { - if (isUrlOnWhitelist(config.url) && - (--numLoadings) === 0) { - $rootScope.$emit('loaderHide', config.method); - } - }; - - return { - /** - * Broadcast the loader show event - * - * @param {object} config - * - * @returns {object|Promise} - */ - request: function (config) { - if (isUrlOnWhitelist(config.url)) { - numLoadings++; - $rootScope.$emit('loaderShow', config.method); - } - - return config || $q.when(config); - }, - - /** - * Broadcast the loader hide event - * - * @param {object} response - * - * @returns {object|Promise} - */ - response: function (response) { - checkAndHide(response.config); - - return response || $q.when(response); - }, - - /** - * Handle errors - * - * @param {object} response - * - * @returns {Promise} - */ - responseError: function (response) { - checkAndHide(response.config); - - return $q.reject(response); - } - }; - } - ]; - }) - - .config(['$httpProvider', function ($httpProvider) { - $httpProvider.interceptors.unshift('httpMethodInterceptor'); - }]); +/* global angular */ + +angular + .module('ng.httpLoader', [ + 'ng.httpLoader.httpMethodInterceptor' + ]) + + .directive('ngHttpLoader', [ + '$rootScope', + '$parse', + '$timeout', + function ($rootScope, $parse, $timeout) { + + /** + * Usage example: + * + * Multiple method loader + * + * + * + * Single method loader + * + * + * + * Adding a title [optional] + * + * + */ + return { + /** + * Available attributes + * + * @param {array|string} methods + * @param {string} template + * @param {string} title + * @param {number} time to live in seconds + */ + scope: { + methods: '@', + template: '@', + title: '@', + ttl: '@' + }, + template: '', + link: function ($scope) { + var methods = $parse($scope.methods)() || $scope.methods; + methods = angular.isUndefined(methods) ? [] : methods; + methods = angular.isArray(methods) ? methods : [methods]; + angular.forEach(methods, function (method, index) { + methods[index] = method.toUpperCase(); + }); + + var ttl = $parse($scope.ttl)() || $scope.ttl; + ttl = angular.isUndefined(ttl) ? 0 : ttl; + ttl = Number(ttl) * 1000; + ttl = angular.isNumber(ttl) ? ttl : 0; + + + // add minimal indexOf polyfill + if (!Array.prototype.indexOf) { + methods.indexOf = function (value) { + for (var i = this.length; i--;) { + if (this[i] === value) { + return i; + } + } + + return -1; + }; + } + + /** + * Loader is hidden by default + * @type {boolean} + */ + $scope.showLoader = false; + + var timeoutId, + showLoader = $scope.showLoader; + + /** + * Toggle the show loader. + * Contains the logic to show or hide the loader depending + * on the passed method + * + * @param {object} event + * @param {string} method + */ + var toggleShowLoader = function (event, method) { + if (methods.indexOf(method.toUpperCase()) !== -1) { + showLoader = (event.name === 'loaderShow'); + } else if (methods.length === 0) { + showLoader = (event.name === 'loaderShow'); + } + + if (ttl <= 0 || (!timeoutId && !showLoader)) { + $scope.showLoader = showLoader; + return; + } + if (timeoutId) { + return; + } + + $scope.showLoader = showLoader; + timeoutId = $timeout(function () { + if (!showLoader) { + $scope.showLoader = showLoader; + } + timeoutId = undefined; + }, ttl); + }; + + $rootScope.$on('loaderShow', toggleShowLoader); + $rootScope.$on('loaderHide', toggleShowLoader); + } + }; + } + ]); + +/* global angular */ + +/** + * Http method interceptor. Broadcast events for show or hide the loader. + */ +angular + .module('ng.httpLoader.httpMethodInterceptor', []) + + .provider('httpMethodInterceptor', function () { + var domains = [], + blackdomains = [], + whitelistLocalRequests = false; + + /** + * Add domains to the white list + * + * @param {string} domain + * Added Domain to the white list domains collection + */ + this.whitelistDomain = function (domain) { + domains.push(domain); + }; + + /** + * Add domains to the black list + * + * @param {string} domain + * Added Domain to the black list domains collection + */ + this.blacklistDomain = function (domain) { + blackdomains.push(domain); + }; + + /** + * White list requests to the local domain + */ + this.whitelistLocalRequests = function () { + whitelistLocalRequests = true; + }; + + this.$get = [ + '$q', + '$rootScope', + function ($q, $rootScope) { + var numLoadings = 0; + + /** + * Check if the url domain is on the whitelist + * + * @param {string} url + * + * @returns {boolean} + */ + var isUrlOnWhitelist = function (url) { + if (url.substring(0, 2) !== '//' && + url.indexOf('://') === -1 && + whitelistLocalRequests) { + return true; + } + + for (var i = domains.length; i--;) { + if (url.indexOf(domains[i]) !== -1) { + return true; + } + } + + for (var j = blackdomains.length; j--;) { + if (url.indexOf(blackdomains[j]) !== -1) { + return false; + } + } + + return false; + }; + + /** + * Emit hide loader logic + * + * @param {object} config + * The response configuration + */ + var checkAndHide = function (config) { + if (isUrlOnWhitelist(config.url) && + (--numLoadings) === 0) { + $rootScope.$emit('loaderHide', config.method); + } + }; + + return { + /** + * Broadcast the loader show event + * + * @param {object} config + * + * @returns {object|Promise} + */ + request: function (config) { + if (isUrlOnWhitelist(config.url)) { + numLoadings++; + $rootScope.$emit('loaderShow', config.method); + } + + return config || $q.when(config); + }, + + /** + * Broadcast the loader hide event + * + * @param {object} response + * + * @returns {object|Promise} + */ + response: function (response) { + checkAndHide(response.config); + + return response || $q.when(response); + }, + + /** + * Handle errors + * + * @param {object} response + * + * @returns {Promise} + */ + responseError: function (response) { + checkAndHide(response.config); + + return $q.reject(response); + } + }; + } + ]; + }) + + .config(['$httpProvider', function ($httpProvider) { + $httpProvider.interceptors.unshift('httpMethodInterceptor'); + }]); diff --git a/app/package/js/angular-http-loader.min.js b/app/package/js/angular-http-loader.min.js index fc4fe41..c391a1e 100644 --- a/app/package/js/angular-http-loader.min.js +++ b/app/package/js/angular-http-loader.min.js @@ -1 +1 @@ -angular.module("ng.httpLoader",["ng.httpLoader.httpMethodInterceptor"]).directive("ngHttpLoader",["$rootScope","$parse","$timeout",function(a,b,c){return{scope:{methods:"@",template:"@",title:"@",ttl:"@"},template:'',link:function(d){var e=b(d.methods)()||d.methods;e=angular.isUndefined(e)?[]:e,e=angular.isArray(e)?e:[e],angular.forEach(e,function(a,b){e[b]=a.toUpperCase()});var f=b(d.ttl)()||d.ttl;f=angular.isUndefined(f)?0:f,f=1e3*Number(f),f=angular.isNumber(f)?f:0,Array.prototype.indexOf||(e.indexOf=function(a){for(var b=this.length;b--;)if(this[b]===a)return b;return-1}),d.showLoader=!1;var g,h=d.showLoader,i=function(a,b){return-1!==e.indexOf(b.toUpperCase())?h="loaderShow"===a.name:0===e.length&&(h="loaderShow"===a.name),0>=f||!g&&!h?void(d.showLoader=h):void(g||(d.showLoader=h,g=c(function(){h||(d.showLoader=h),g=void 0},f)))};a.$on("loaderShow",i),a.$on("loaderHide",i)}}}]),angular.module("ng.httpLoader.httpMethodInterceptor",[]).provider("httpMethodInterceptor",function(){var a=[],b=!1;this.whitelistDomain=function(b){a.push(b)},this.whitelistLocalRequests=function(){b=!0},this.$get=["$q","$rootScope",function(c,d){var e=0,f=function(c){if("//"!==c.substring(0,2)&&-1===c.indexOf("://")&&b)return!0;for(var d=a.length;d--;)if(-1!==c.indexOf(a[d]))return!0;return!1},g=function(a){f(a.url)&&0===--e&&d.$emit("loaderHide",a.method)};return{request:function(a){return f(a.url)&&(e++,d.$emit("loaderShow",a.method)),a||c.when(a)},response:function(a){return g(a.config),a||c.when(a)},responseError:function(a){return g(a.config),c.reject(a)}}}]}).config(["$httpProvider",function(a){a.interceptors.unshift("httpMethodInterceptor")}]); \ No newline at end of file +angular.module("ng.httpLoader",["ng.httpLoader.httpMethodInterceptor"]).directive("ngHttpLoader",["$rootScope","$parse","$timeout",function(a,b,c){return{scope:{methods:"@",template:"@",title:"@",ttl:"@"},template:'',link:function(d){var e=b(d.methods)()||d.methods;e=angular.isUndefined(e)?[]:e,e=angular.isArray(e)?e:[e],angular.forEach(e,function(a,b){e[b]=a.toUpperCase()});var f=b(d.ttl)()||d.ttl;f=angular.isUndefined(f)?0:f,f=1e3*Number(f),f=angular.isNumber(f)?f:0,Array.prototype.indexOf||(e.indexOf=function(a){for(var b=this.length;b--;)if(this[b]===a)return b;return-1}),d.showLoader=!1;var g,h=d.showLoader,i=function(a,b){return-1!==e.indexOf(b.toUpperCase())?h="loaderShow"===a.name:0===e.length&&(h="loaderShow"===a.name),0>=f||!g&&!h?void(d.showLoader=h):void(g||(d.showLoader=h,g=c(function(){h||(d.showLoader=h),g=void 0},f)))};a.$on("loaderShow",i),a.$on("loaderHide",i)}}}]),angular.module("ng.httpLoader.httpMethodInterceptor",[]).provider("httpMethodInterceptor",function(){var a=[],b=[],c=!1;this.whitelistDomain=function(b){a.push(b)},this.blacklistDomain=function(a){b.push(a)},this.whitelistLocalRequests=function(){c=!0},this.$get=["$q","$rootScope",function(d,e){var f=0,g=function(d){if("//"!==d.substring(0,2)&&-1===d.indexOf("://")&&c)return!0;for(var e=a.length;e--;)if(-1!==d.indexOf(a[e]))return!0;for(var f=b.length;f--;)if(-1!==d.indexOf(b[f]))return!1;return!1},h=function(a){g(a.url)&&0===--f&&e.$emit("loaderHide",a.method)};return{request:function(a){return g(a.url)&&(f++,e.$emit("loaderShow",a.method)),a||d.when(a)},response:function(a){return h(a.config),a||d.when(a)},responseError:function(a){return h(a.config),d.reject(a)}}}]}).config(["$httpProvider",function(a){a.interceptors.unshift("httpMethodInterceptor")}]); \ No newline at end of file diff --git a/app/src/demo.html b/app/src/demo.html index 1e8beab..d046fa8 100644 --- a/app/src/demo.html +++ b/app/src/demo.html @@ -4,7 +4,7 @@