From a08388e46edc277b6029b2088f7117035b644f23 Mon Sep 17 00:00:00 2001 From: Leandro Ostera Date: Tue, 6 Aug 2013 19:19:46 +0100 Subject: [PATCH] feat(auth): Auth system. Closes #22. arch(requirejs): Implemented RequireJS. Closes #21. --- .gitignore | 4 +- app/index.html | 31 +- app/scripts/app.js | 30 ++ app/scripts/config.js | 25 ++ app/scripts/controllers.js | 1 + app/scripts/controllers/home.js | 19 +- app/scripts/controllers/login.js | 17 + app/scripts/controllers/users.js | 10 + app/scripts/directives.js | 1 + app/scripts/directives/string-to-number.js | 81 +++-- app/scripts/filters.js | 1 + app/scripts/filters/starts-with.js | 152 ++++---- app/scripts/init.js | 22 -- app/scripts/main.js | 88 +++++ app/scripts/routes.js | 110 +++--- app/scripts/services.js | 1 + app/scripts/services/auth.js | 276 ++++++++++++++ app/scripts/services/browser-detect.js | 344 +++++++++--------- app/scripts/services/country-list.js | 396 --------------------- app/scripts/services/debug.js | 14 + app/scripts/services/generic.js | 53 --- app/scripts/services/http-options.js | 75 ++-- app/scripts/services/resource-factory.js | 62 ++++ app/scripts/services/templates.js | 95 +++++ app/scripts/services/user.js | 56 +++ 25 files changed, 1078 insertions(+), 886 deletions(-) create mode 100644 app/scripts/app.js create mode 100644 app/scripts/config.js create mode 100644 app/scripts/controllers.js create mode 100644 app/scripts/controllers/login.js create mode 100644 app/scripts/controllers/users.js create mode 100644 app/scripts/directives.js create mode 100644 app/scripts/filters.js delete mode 100644 app/scripts/init.js create mode 100644 app/scripts/main.js create mode 100644 app/scripts/services.js create mode 100644 app/scripts/services/auth.js delete mode 100644 app/scripts/services/country-list.js create mode 100644 app/scripts/services/debug.js delete mode 100644 app/scripts/services/generic.js create mode 100644 app/scripts/services/resource-factory.js create mode 100644 app/scripts/services/templates.js create mode 100644 app/scripts/services/user.js diff --git a/.gitignore b/.gitignore index cff67ae..b788582 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,6 @@ dist app/components test-results.xml .DS_Store -docs/* \ No newline at end of file +docs/* +libpeerconnection.log +*.jar \ No newline at end of file diff --git a/app/index.html b/app/index.html index c5535a4..33c7251 100644 --- a/app/index.html +++ b/app/index.html @@ -2,21 +2,30 @@ - + - Title + ngSeed + - + + + + @@ -30,21 +39,7 @@
- - - - - - - - - - - - - - - + diff --git a/app/scripts/app.js b/app/scripts/app.js new file mode 100644 index 0000000..178cd58 --- /dev/null +++ b/app/scripts/app.js @@ -0,0 +1,30 @@ +define(['angular'],function (angular) { + + 'use strict'; + + var services = angular.module('app.services', + [ 'ngResource', + 'http-auth-interceptor' + ]); + + var directives = angular.module('app.directives', + [ + ]); + + var filters = angular.module('app.filters', + [ + ]); + + var resources = angular.module('app.resources', + [ + ]); + + var app = angular.module('app', + [ 'app.services', + 'app.directives', + 'app.filters', + 'app.resources' + ]); + + return app; +}); diff --git a/app/scripts/config.js b/app/scripts/config.js new file mode 100644 index 0000000..e1345f8 --- /dev/null +++ b/app/scripts/config.js @@ -0,0 +1,25 @@ +define(['angular', 'app'], function (angular, app) { + 'use strict'; + + app.config( + ['$locationProvider', '$httpProvider', '$authProvider', + function ($locationProvider, $httpProvider, $authProvider) { + + $httpProvider.defaults.withCredentials = true; + $locationProvider.html5Mode( true ); + }]); + + // Initialize $auth + // app.run(['$auth', '$resourceFactory', + // function ($auth, $resourceFactory) { + // You can register your resources here + // $resourceFactory('Resource#1') + // $resourceFactory('Resource#2') + // After this, they will be available to be injected + // in your controllers like regular services. + // }]); + // + app.run(['$auth', '$debug', function ($auth, $debug) { + }]); + +}); \ No newline at end of file diff --git a/app/scripts/controllers.js b/app/scripts/controllers.js new file mode 100644 index 0000000..9e95ffa --- /dev/null +++ b/app/scripts/controllers.js @@ -0,0 +1 @@ +// Empty file \ No newline at end of file diff --git a/app/scripts/controllers/home.js b/app/scripts/controllers/home.js index 57fce35..e22feb9 100644 --- a/app/scripts/controllers/home.js +++ b/app/scripts/controllers/home.js @@ -1,13 +1,6 @@ -var app = angular.module('app'); - -app.controller( 'HomeCtrl', - ['$scope', - function( $scope ) { - - 'use strict'; - - $scope.welcome = 'Hello!'; - - $scope.awesomeThings = [1,2,3]; - -}]); \ No newline at end of file +define(['app'], function (app) { + 'use strict'; + app.controller('Home', ['$scope', function ($scope) { + $scope.welcome = "Hello there!"; + }]); +}); \ No newline at end of file diff --git a/app/scripts/controllers/login.js b/app/scripts/controllers/login.js new file mode 100644 index 0000000..0871ea0 --- /dev/null +++ b/app/scripts/controllers/login.js @@ -0,0 +1,17 @@ +define(['app'], function (app) { + 'use strict'; + + app.controller('Login', ['$scope','$auth', function ($scope, $auth) { + $scope.login = function () { + $auth.login($scope.credentials); + } + + $scope.$on('$auth:loginFailure', function (event, data) { + console.log("LoginController:",event,data); + if(data === '403') { + alert('Invalid username/password'); + } + }); + + }]); +}); \ No newline at end of file diff --git a/app/scripts/controllers/users.js b/app/scripts/controllers/users.js new file mode 100644 index 0000000..b6edb02 --- /dev/null +++ b/app/scripts/controllers/users.js @@ -0,0 +1,10 @@ +define(['app'], function (app) { + 'use strict'; + + app.controller('Users', ['$scope', '$auth', function ($scope, $auth) { + + $scope.welcome = "This is a private area."; + + }]); + +}); \ No newline at end of file diff --git a/app/scripts/directives.js b/app/scripts/directives.js new file mode 100644 index 0000000..9e95ffa --- /dev/null +++ b/app/scripts/directives.js @@ -0,0 +1 @@ +// Empty file \ No newline at end of file diff --git a/app/scripts/directives/string-to-number.js b/app/scripts/directives/string-to-number.js index 47026ab..dd5d58a 100644 --- a/app/scripts/directives/string-to-number.js +++ b/app/scripts/directives/string-to-number.js @@ -1,44 +1,47 @@ -var directives = angular.module('ngSeed.directives'); - -/** - * @ngdoc directive - * @name ngSeed.directives:string2number - * @description - * Converts a string to a number. Useful in type="number" input - * elements that bind to a stringified number model. - */ -directives.directive('string2number', function() { - +define(['angular', 'app'], function (angular) { 'use strict'; - return { - restrict: 'A', - require: 'ngModel', - link: function(scope, element, attr, ngModel) { + /** + * @ngdoc directive + * @name ngSeed.directives:string2number + * @description + * Converts a string to a number. Useful in type="number" input + * elements that bind to a stringified number model. + */ + angular + .module('app.directives') + .directive('string2number', function() { + + return { + restrict: 'A', + require: 'ngModel', + link: function(scope, element, attr, ngModel) { + + /** + * @ngdoc method + * @name fromField + * @methodOf ngSeed.directives:string2number + * @param {Number, String} number Just the number that has been input. + * @return {Number} The number. + */ + function fromField(number) { + return Number(number); + } - /** - * @ngdoc method - * @name fromField - * @methodOf ngSeed.directives:string2number - * @param {Number, String} number Just the number that has been input. - * @return {Number} The number. - */ - function fromField(number) { - return Number(number); - } + /** + * @ngdoc method + * @name toField + * @methodOf ngSeed.directives:string2number + * @param {Number, String} number Just the number that has been input. + * @return {Number} The number or 0. + */ + function toField(text) { + return Number(text || 0); + } + ngModel.$parsers.push(fromField); + ngModel.$formatters.push(toField); + } + }; + }); - /** - * @ngdoc method - * @name toField - * @methodOf ngSeed.directives:string2number - * @param {Number, String} number Just the number that has been input. - * @return {Number} The number or 0. - */ - function toField(text) { - return Number(text || 0); - } - ngModel.$parsers.push(fromField); - ngModel.$formatters.push(toField); - } - }; }); \ No newline at end of file diff --git a/app/scripts/filters.js b/app/scripts/filters.js new file mode 100644 index 0000000..9e95ffa --- /dev/null +++ b/app/scripts/filters.js @@ -0,0 +1 @@ +// Empty file \ No newline at end of file diff --git a/app/scripts/filters/starts-with.js b/app/scripts/filters/starts-with.js index ce42d10..7a49e22 100644 --- a/app/scripts/filters/starts-with.js +++ b/app/scripts/filters/starts-with.js @@ -1,79 +1,81 @@ -var filters = angular.module('ngSeed.filters'); - -/** - * @ngdoc filter - * @name ngSeed.filters:startsWith - * @description - * - * Filters a collection with a simple regex. - * - * @example - - - -
-
- - - - - - - - -
Name
{{friend.name}}
-
-
- - it('should be reverse ordered by aged', function() { - expect(binding('predicate')).toBe('-age'); - expect(repeater('table.friend', 'friend in friends').column('friend.age')). - toEqual(['35', '29', '21', '19', '10']); - expect(repeater('table.friend', 'friend in friends').column('friend.name')). - toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']); - }); - - it('should reorder the table when user selects different predicate', function() { - element('.doc-example-live a:contains("Name")').click(); - expect(repeater('table.friend', 'friend in friends').column('friend.name')). - toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']); - expect(repeater('table.friend', 'friend in friends').column('friend.age')). - toEqual(['35', '10', '29', '19', '21']); - - element('.doc-example-live a:contains("Phone")').click(); - expect(repeater('table.friend', 'friend in friends').column('friend.phone')). - toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']); - expect(repeater('table.friend', 'friend in friends').column('friend.name')). - toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']); - }); - -
- */ - -filters.filter('startsWith', function() { - +define(['angular', 'app'], function (angular) { 'use strict'; + + /** + * @ngdoc filter + * @name ngSeed.filters:startsWith + * @description + * + * Filters a collection with a simple regex. + * + * @example + + + +
+
+ + + + + + + + +
Name
{{friend.name}}
+
+
+ + it('should be reverse ordered by aged', function() { + expect(binding('predicate')).toBe('-age'); + expect(repeater('table.friend', 'friend in friends').column('friend.age')). + toEqual(['35', '29', '21', '19', '10']); + expect(repeater('table.friend', 'friend in friends').column('friend.name')). + toEqual(['Adam', 'Julie', 'Mike', 'Mary', 'John']); + }); - return function(str, letter, prop){ - letter = letter || undefined; - if(!letter){ - return str; - } - var filtered = []; - str.forEach(function (i) { - if((new RegExp('^['+letter.toLowerCase()+letter.toUpperCase()+']')).test(i[prop])) { - filtered.push(i); - } + it('should reorder the table when user selects different predicate', function() { + element('.doc-example-live a:contains("Name")').click(); + expect(repeater('table.friend', 'friend in friends').column('friend.name')). + toEqual(['Adam', 'John', 'Julie', 'Mary', 'Mike']); + expect(repeater('table.friend', 'friend in friends').column('friend.age')). + toEqual(['35', '10', '29', '19', '21']); + + element('.doc-example-live a:contains("Phone")').click(); + expect(repeater('table.friend', 'friend in friends').column('friend.phone')). + toEqual(['555-9876', '555-8765', '555-5678', '555-4321', '555-1212']); + expect(repeater('table.friend', 'friend in friends').column('friend.name')). + toEqual(['Mary', 'Julie', 'Adam', 'Mike', 'John']); + }); + +
+ */ + angular + .module('app.filters') + .filter('startsWith', function() { + + return function(str, letter, prop){ + letter = letter || undefined; + if(!letter){ + return str; + } + var filtered = []; + str.forEach(function (i) { + if((new RegExp('^['+letter.toLowerCase()+letter.toUpperCase()+']')).test(i[prop])) { + filtered.push(i); + } + }); + return filtered; + }; }); - return filtered; - }; + }); \ No newline at end of file diff --git a/app/scripts/init.js b/app/scripts/init.js deleted file mode 100644 index a4e3424..0000000 --- a/app/scripts/init.js +++ /dev/null @@ -1,22 +0,0 @@ -window.ngSeed = angular.module('ngSeed', - [ 'ngSeed.directives', - 'ngSeed.services', - 'ngSeed.filters', - 'http-auth-interceptor', - 'ngResource' - ]); - -window.ngSeed.services = angular.module('ngSeed.services', - [ 'http-auth-interceptor', - 'ngResource' - ]); - -window.ngSeed.directives = angular.module('ngSeed.directives', - [ 'http-auth-interceptor' - ]); - -window.ngSeed.filters = angular.module('ngSeed.filters', []); - -window.app = angular.module('app', - [ 'ngSeed' - ]); \ No newline at end of file diff --git a/app/scripts/main.js b/app/scripts/main.js new file mode 100644 index 0000000..24bb4c9 --- /dev/null +++ b/app/scripts/main.js @@ -0,0 +1,88 @@ +require.config({ + paths: { + angular: '../components/angular-unstable/angular', + async: '../components/async/lib/async', + jquery: '../components/jquery/jquery', + underscore: '../components/underscore/underscore', + ngResource: '../components/angular-resource-unstable/angular-resource', + 'http-auth-interceptor': '../components/angular-http-auth/src/http-auth-interceptor' + }, + shim: { + app: { + deps: [ + 'angular', + 'ngResource', + 'http-auth-interceptor' + ] + }, + + angular: { + exports: 'angular' + }, + + 'http-auth-interceptor': { + deps: ['angular'] + }, + + ngResource: { + deps: ['angular'] + }, + + underscore: { + exports: '_' + }, + + + // Controllers + controllers: { + deps: [ + 'controllers/home', + 'controllers/login', + 'controllers/users' + ] + }, + + // Directives + directives: { + deps: [ + 'directives/string-to-number' + ] + }, + + // Filters + filters: { + deps: [ + // 'filters/starts-with' + ] + }, + + // Services + services: { + deps: [ + 'services/debug', + 'services/http-options', + 'services/auth', + 'services/user', + // 'services/browser-detect', + // 'services/generic' + ] + } + } +}); + +require([ + 'angular', + 'app', + 'services', + 'controllers', + 'directives', + 'filters', + 'config', + 'routes' +], function (angular) { + 'use strict'; + + angular.element(document).ready(function () { + angular.bootstrap(document, ['app']); + }); +}); diff --git a/app/scripts/routes.js b/app/scripts/routes.js index 6ec8f6a..314f3dc 100644 --- a/app/scripts/routes.js +++ b/app/scripts/routes.js @@ -1,61 +1,67 @@ - -var app = angular.module('app'); - -app.config( - ['$routeProvider', '$locationProvider', '$httpProvider', - function ($routeProvider, $locationProvider, $httpProvider) { - +define(['angular', 'app'], function (angular, app) { 'use strict'; - $httpProvider.defaults.withCredentials = true; + app.config( + ['$routeProvider', function ($routeProvider) { - var views = 'views/'; - var partials = 'views/partials/'; + var views = 'views/'; + var partials = 'views/partials/'; - /** - * @ngdoc method - * @name ngSeed.routes:view - * @param {String} viewName The name of the view. - * @return {String} The path to the view. - * @description - * Utility functions to get the path of a view. - */ - function view (viewName) { - return views+viewName+'.html'; - } + /** + * @ngdoc method + * @name ngSeed.routes:view + * @param {String} viewName The name of the view. + * @return {String} The path to the view. + * @description + * Utility functions to get the path of a view. + */ + function view (viewName) { + return views+viewName+'.html'; + } - /** - * @ngdoc method - * @name ngSeed.routes:partial - * @param {String} section The folder path to look into. - * @param {String} partialName The name of the partial. - * @return {String} The path to the partial. - * @description - * Utility functions to get the path of a partial. - */ - function partial (section, partialName) { - var url; - if(partialName === undefined) { - url = partials+section; - } else { - url = section+'/partials/'+partialName; + /** + * @ngdoc method + * @name ngSeed.routes:partial + * @param {String} section The folder path to look into. + * @param {String} partialName The name of the partial. + * @return {String} The path to the partial. + * @description + * Utility functions to get the path of a partial. + */ + function partial (section, partialName) { + var url; + if(partialName === undefined) { + url = partials+section; + } else { + url = section+'/partials/'+partialName; + } + url += '.html'; + return url; } - url += '.html'; - return url; - } - $locationProvider.html5Mode( true ); - $routeProvider - .when('/', { - templateUrl: view('home'), - controller: 'HomeCtrl' - }) - .when('/error', { - templateUrl: partial('error') - }) - .otherwise({ - redirectTo: '/' - }); + $routeProvider + .when('/', { + templateUrl: view('home'), + controller: 'Home', + public: true + }) + .when('/users', { + templateUrl: view('home'), + controller: 'Users' + }) + .when('/login', { + templateUrl: view('login'), + controller: 'Login', + public: true + }) + .when('/error', { + templateUrl: partial('error'), + public: true + }) + .otherwise({ + redirectTo: '/' + }); + }]); -}]); \ No newline at end of file +}); \ No newline at end of file diff --git a/app/scripts/services.js b/app/scripts/services.js new file mode 100644 index 0000000..9e95ffa --- /dev/null +++ b/app/scripts/services.js @@ -0,0 +1 @@ +// Empty file \ No newline at end of file diff --git a/app/scripts/services/auth.js b/app/scripts/services/auth.js new file mode 100644 index 0000000..4b0f05a --- /dev/null +++ b/app/scripts/services/auth.js @@ -0,0 +1,276 @@ +define(['angular', 'app'], function (angular, app) { + 'use strict'; + + /** + * @ngdoc service + * @name $auth + * @description + * Dead-easy auth checking. + * + * Please note that custom login requiring logic, on-location-change auth + * checking, and default login success behaviour can be configured + * using the authProvider on a config block. + * + * ### Configuring $authProvider: + * This is the default value, feel free to change it to something else if your app requires it: + * + * ```js + * $authProvider.setUserService('UserService'); + * + * $authProvider.setHandler('handleLoginStart', function (redirect) { + * $('#myLoginModal').open(); + * }); + * + * $authProvider.setHandler('handleLoginSuccess', function () { + * $('#myLoginModal').close(); + * }); + * ``` + * + * ### Securing Routes: + * Add a `public: false` property or a `public: true` property to your routes. In fact, + * any falsy value will end up requiring login. For instance: + * + * ```js + * $routeProvider + * .when('/', { + * templateUrl: view('home'), + * controller: 'HomeCtrl', + * public: true + * }) + * .when('/users', { + * templateUrl: view('users'), + * controller: 'UserCtrl', + * }) + * .when('/error', { + * templateUrl: partial('error'), + * public: true + * }) + * .otherwise({ + * redirectTo: '/' + * }); + * ``` + * + * This will give you a public home and error routes. If you try to access `/users`, you will + * immediately be prompted for authentication. + */ + + angular + .module('app.services') + .provider('$auth', function () { + /** + * @name currentUser + * @type {Object} + * @description the logged in user or undefined + */ + var currentUser = null; + + var userService = null; + + var userServiceName = 'UserService'; + + var handlers = { + loginStart: null, + loginSuccess: null, + locationChange: null + }; + + /** + * @description + * The actual service. + */ + return { + + $get: ['$rootScope', '$location', '$route', '$injector', + function ($rootScope, $location, $route, $injector) { + + if(!userService && userServiceName) { + userService = $injector.get(userServiceName); + } + + if (!userService) { + throw new Error('$auth: please configure a userService'); + } + + if (!handlers.loginStart) { + console.log('$auth: using default loginStart method') + } + + if (!handlers.loginSuccess) { + console.log('$auth: using default loginSuccess method') + } + + if (!handlers.locationChange) { + console.log('$auth: using default locationChange method') + } + + /** + * @name handleLoginStart + * @description + * Default login starting logic. + */ + handlers.loginStart = handlers.loginStart || function (redirect) { + console.log("$auth: redirecting to /login"); + $location.path('/login'); + $location.search({ + redirect: encodeURIComponent(redirect) + }); + return; + }; + + /** + * @name handleLoginSuccess + * @description + * This method redirects the user to the redirect search term if + * it exists. + */ + handlers.loginSuccess = handlers.loginSuccess || function () { + if($location.search().redirect) { + console.log("$auth: redirecting to", $location.search().redirect); + $location.path($location.search().redirect); + } + }; + + /** + * @name handleLocationChange + * @description + * This method takes a user navigating, does a quick auth check + * and if everything is alright proceeds. + */ + handlers.locationChange = handlers.locationChange || function (event, next, current) { + if(currentUser === null || !!currentUser){ + next = '/'+next.split('/').splice(3).join('/').split("?")[0]; + var route = $route.routes[next]; + console.log("$auth: Guest access to", next); + console.log("$auth:",next, "is", route.public ? "public" : "private"); + if(!route.public) { + $rootScope.$broadcast('$auth:loginStart'); + handlers.loginStart(next.substr(1)); + return; + } + console.log("$auth: proceeding to load", next); + } + }; + + /** + * @description + * $rootScope hookups + */ + $rootScope.$on('$locationChangeStart', function (event, next, current) { + if(!$route.current) { + console.log("$auth: Welcome newcomer!"); + console.log("$auth: Checking your session..."); + userService.getCurrentUser().then(function (user) { + console.log("$auth: we got", user) + if(typeof handlers.locationChange === 'function') { + handlers.locationChange(event, next, current); + } + }, function (err) { + console.log("$auth: request failed"); + console.log("$auth: proceeding as guest."); + if(typeof handlers.locationChange === 'function') { + handlers.locationChange(event, next, current); + } + }); + } else { + if(typeof handlers.locationChange === 'function') { + handlers.locationChange(event, next, current); + } + } + }); + + $rootScope.$on('$auth:loginSuccess', function (event, next, current) { + if(typeof handlers.locationChange === 'function') { + handlers.loginSuccess(event, next, current); + } + }); + + return { + /** + * @name getCurrentUser + * @return {Object} the current user + */ + getCurrentUser: function () { + return currentUser; + }, + + /** + * @name isLoggedIn + * @return {Boolean} true or false if there is or not a current user + */ + isLoggedIn: function () { + return !!currentUser; + }, + + /** + * @name login + * @param {Object} credentials the credentials to be passed to the login service + * @return {Promise} the promise your login service returns on login + */ + login: function (credentials) { + return userService.login(credentials).then(function (user) { + if(user) { + currentUser = user; + $rootScope.$broadcast('$auth:loginSuccess'); + } else { + $rootScope.$broadcast('$auth:loginFailure') + } + }, function() { + console.log("$auth: login error callback"); + currentUser = null; + $rootScope.$broadcast('$auth:loginFailure'); + }); + }, + + /** + * @name logout + * @return {Promise} the promise your login service returns on logout + */ + logout: function () { + $rootScope.$broadcast('$auth:logoutStart'); + return userService.logout().then(function () { + $rootScope.$broadcast('$auth:logoutSuccess'); + currentUser = undefined; + }, function () { + $rootScope.$broadcast('$auth:logoutFailure'); + }); + } + } + + }], + + /** + * @name setUserService + * @param {String} usr the user service name + */ + setUserService: function (usr) { + if(typeof usr !== 'string') { + throw new Error('$auth: setUserService expects a string to use $injector upon instantiation') + } + userServiceName = usr; + }, + + /** + * @name setHandler + * @param {String} key the handler name + * @param {Function} foo the handler function + * @description + * Replaces one of the default handlers. + */ + setHandler: function (key, foo) { + if( key.substr(0,6) !== 'handle' ) { + throw new Error('$auth: Expecting a handler name that starts with \'handle\'.'); + } + + if ( ! handlers.hasOwnProperty(key) ) { + throw new Error('$auth: handle name '+key+' is not a valid property.'); + } + + if ( typeof foo !== 'function') { + throw new Error('$auth: handle name '+key+' is not a valid property.'); + } + + handlers[key] = foo; + } + } + }); +}); \ No newline at end of file diff --git a/app/scripts/services/browser-detect.js b/app/scripts/services/browser-detect.js index 23356f1..7397a55 100644 --- a/app/scripts/services/browser-detect.js +++ b/app/scripts/services/browser-detect.js @@ -1,192 +1,174 @@ -var services = angular.module('ngSeed.services'); +define(['angular', 'app'], function (angular, app) { + angular.module('app.services').factory('$browserDetect', function () { + var browserDetect = { -/** - * @ngdoc service - * @name ngSeed.services:$browserDetect - * @description - * - * Detects the type of browser, the version and the OS. - * Easily usable in conjuction with ng-hide/ng-show. - * - * Example (jade): - * ```haml - * section(ng-show="$browserDetect.browser == 'Explorer' && $browserDetect.version < 10") - * span.warn This page is not supported in IE below 10 - * ``` - */ -services.factory('$browserDetect', function () { + /** + * @ngdoc function + * @name init + * @methodOf ngSeed.services:$browserDetect + * @description + * Initializes the properties and error messages. + * + * @return {Boolean} True if no errors. False if errors. + */ + init: function () { + // Errors array + this.errors = []; + // Copy of the navigator access + this.navigator = navigator; - 'use strict'; - - var browserDetect = { - - /** - * @ngdoc function - * @name init - * @methodOf ngSeed.services:$browserDetect - * @description - * Initializes the properties and error messages. - * - * @return {Boolean} True if no errors. False if errors. - */ - init: function () { - // Errors array - this.errors = []; - // Copy of the navigator access - this.navigator = navigator; - - this.browser = this.searchString(this.dataBrowser) || undefined; - // this.browser = "Explorer"; - - if(!this.browser) { - this.errors.push("Unknown browser"); - } + this.browser = this.searchString(this.dataBrowser) || undefined; + // this.browser = "Explorer"; + + if(!this.browser) { + this.errors.push("Unknown browser"); + } - this.version = this.searchVersion(navigator.userAgent) - || this.searchVersion(navigator.appVersion) - || undefined; - // this.version = 9; - - if(!this.version) { - this.errors.push("Unknown version"); - } - - this.OS = this.searchString(this.dataOS) || undefined; - - if(!this.OS) { - this.errors.push("Unkown OS"); - } + this.version = this.searchVersion(navigator.userAgent) + || this.searchVersion(navigator.appVersion) + || undefined; + // this.version = 9; + + if(!this.version) { + this.errors.push("Unknown version"); + } + + this.OS = this.searchString(this.dataOS) || undefined; + + if(!this.OS) { + this.errors.push("Unkown OS"); + } - if(this.errors.length) { - return false; - } else { - return true; - } - }, + if(this.errors.length) { + return false; + } else { + return true; + } + }, - searchString: function (data) { - for (var i=0;i