From b2462ec86cc30c2f92ff330471fa2d6caed76a6d Mon Sep 17 00:00:00 2001 From: Ryan Hutchison Date: Thu, 11 Feb 2016 00:20:17 -0500 Subject: [PATCH] feat(core): Modify core module to implement style guidelines. Update the core module to implement the style guidelines. Reduce size of init.js - moved filter logic out to it's own config. Rename Menus to menuService --- .../articles/client/articles.client.module.js | 2 +- ...ent.config.js => articles.client.menus.js} | 10 +- modules/chat/client/chat.client.module.js | 2 +- ....client.config.js => chat.client.menus.js} | 6 +- modules/core/client/app/config.js | 27 ++- modules/core/client/app/init.js | 103 +++------ .../client/config/core-admin.client.menus.js | 16 +- .../client/config/core-admin.client.routes.js | 15 +- .../core/client/config/core.client.menus.js | 23 +-- .../client/config/core.client.route-filter.js | 57 +++++ .../core/client/config/core.client.routes.js | 19 +- .../controllers/header.client.controller.js | 39 ++-- .../controllers/home.client.controller.js | 15 +- modules/core/client/core.client.module.js | 12 +- .../show-errors.client.directives.js | 136 ++++++------ .../auth-interceptor.client.service.js | 34 +++ .../auth.interceptor.client.service.js | 24 --- .../client/services/menu.client.service.js | 195 ++++++++++++++++++ .../client/services/menus.client.service.js | 182 ---------------- .../services/socket.io.client.service.js | 65 +++--- .../core/client/views/header.client.view.html | 22 +- .../core/client/views/home.client.view.html | 2 +- .../client/header.client.controller.tests.js | 25 +-- .../client/home.client.controller.tests.js | 6 +- ...ts.js => auth-interceptor.client.tests.js} | 0 .../client/menus.client.service.tests.js | 94 ++++----- .../client/config/users-admin.client.menus.js | 6 +- modules/users/client/users.client.module.js | 6 +- 28 files changed, 610 insertions(+), 533 deletions(-) rename modules/articles/client/config/{articles.client.config.js => articles.client.menus.js} (65%) rename modules/chat/client/config/{chat.client.config.js => chat.client.menus.js} (59%) create mode 100644 modules/core/client/config/core.client.route-filter.js create mode 100644 modules/core/client/services/interceptors/auth-interceptor.client.service.js delete mode 100644 modules/core/client/services/interceptors/auth.interceptor.client.service.js create mode 100644 modules/core/client/services/menu.client.service.js delete mode 100644 modules/core/client/services/menus.client.service.js rename modules/core/tests/client/interceptors/{auth.interceptor.client.tests.js => auth-interceptor.client.tests.js} (100%) diff --git a/modules/articles/client/articles.client.module.js b/modules/articles/client/articles.client.module.js index 0e7dcb9cbb..6aab08ffc4 100644 --- a/modules/articles/client/articles.client.module.js +++ b/modules/articles/client/articles.client.module.js @@ -3,5 +3,5 @@ app.registerModule('articles', ['core']);// The core module is required for special route handling; see /core/client/config/core.client.routes app.registerModule('articles.services'); - app.registerModule('articles.routes', ['ui.router', 'articles.services']); + app.registerModule('articles.routes', ['ui.router', 'core.routes', 'articles.services']); }(ApplicationConfiguration)); diff --git a/modules/articles/client/config/articles.client.config.js b/modules/articles/client/config/articles.client.menus.js similarity index 65% rename from modules/articles/client/config/articles.client.config.js rename to modules/articles/client/config/articles.client.menus.js index 4437735020..47721a03b4 100644 --- a/modules/articles/client/config/articles.client.config.js +++ b/modules/articles/client/config/articles.client.menus.js @@ -5,10 +5,10 @@ .module('articles') .run(menuConfig); - menuConfig.$inject = ['Menus']; + menuConfig.$inject = ['menuService']; - function menuConfig(Menus) { - Menus.addMenuItem('topbar', { + function menuConfig(menuService) { + menuService.addMenuItem('topbar', { title: 'Articles', state: 'articles', type: 'dropdown', @@ -16,13 +16,13 @@ }); // Add the dropdown list item - Menus.addSubMenuItem('topbar', 'articles', { + menuService.addSubMenuItem('topbar', 'articles', { title: 'List Articles', state: 'articles.list' }); // Add the dropdown create item - Menus.addSubMenuItem('topbar', 'articles', { + menuService.addSubMenuItem('topbar', 'articles', { title: 'Create Article', state: 'articles.create', roles: ['user'] diff --git a/modules/chat/client/chat.client.module.js b/modules/chat/client/chat.client.module.js index 1a1c932ff3..78a905f6db 100644 --- a/modules/chat/client/chat.client.module.js +++ b/modules/chat/client/chat.client.module.js @@ -2,5 +2,5 @@ 'use strict'; app.registerModule('chat', ['core']); - app.registerModule('chat.routes', ['ui.router']); + app.registerModule('chat.routes', ['ui.router', 'core.routes']); }(ApplicationConfiguration)); diff --git a/modules/chat/client/config/chat.client.config.js b/modules/chat/client/config/chat.client.menus.js similarity index 59% rename from modules/chat/client/config/chat.client.config.js rename to modules/chat/client/config/chat.client.menus.js index c6a3542d2b..2226c9af29 100644 --- a/modules/chat/client/config/chat.client.config.js +++ b/modules/chat/client/config/chat.client.menus.js @@ -5,11 +5,11 @@ .module('chat') .run(menuConfig); - menuConfig.$inject = ['Menus']; + menuConfig.$inject = ['menuService']; - function menuConfig(Menus) { + function menuConfig(menuService) { // Set top bar menu items - Menus.addMenuItem('topbar', { + menuService.addMenuItem('topbar', { title: 'Chat', state: 'chat' }); diff --git a/modules/core/client/app/config.js b/modules/core/client/app/config.js index 6c38c50907..b5476213eb 100644 --- a/modules/core/client/app/config.js +++ b/modules/core/client/app/config.js @@ -1,23 +1,22 @@ -'use strict'; +(function (window) { + 'use strict'; -// Init the application configuration module for AngularJS application -var ApplicationConfiguration = (function () { - // Init module configuration options var applicationModuleName = 'mean'; - var applicationModuleVendorDependencies = ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'angularFileUpload']; + + var service = { + applicationModuleName: applicationModuleName, + applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'angularFileUpload'], + registerModule: registerModule + }; + + window.ApplicationConfiguration = service; // Add a new vertical module - var registerModule = function (moduleName, dependencies) { + function registerModule(moduleName, dependencies) { // Create angular module angular.module(moduleName, dependencies || []); // Add the module to the AngularJS configuration file angular.module(applicationModuleName).requires.push(moduleName); - }; - - return { - applicationModuleName: applicationModuleName, - applicationModuleVendorDependencies: applicationModuleVendorDependencies, - registerModule: registerModule - }; -}()); + } +}(window)); diff --git a/modules/core/client/app/init.js b/modules/core/client/app/init.js index 8d54b1cad6..dbfe916f95 100644 --- a/modules/core/client/app/init.js +++ b/modules/core/client/app/init.js @@ -1,80 +1,45 @@ -'use strict'; +(function (app) { + 'use strict'; -// Start by defining the main module and adding the module dependencies -angular.module(ApplicationConfiguration.applicationModuleName, ApplicationConfiguration.applicationModuleVendorDependencies); + // Start by defining the main module and adding the module dependencies + angular + .module(app.applicationModuleName, app.applicationModuleVendorDependencies); -// Setting HTML5 Location Mode -angular.module(ApplicationConfiguration.applicationModuleName).config(['$locationProvider', '$httpProvider', - function ($locationProvider, $httpProvider) { + // Setting HTML5 Location Mode + angular + .module(app.applicationModuleName) + .config(bootstrapConfig); + + function bootstrapConfig($locationProvider, $httpProvider) { $locationProvider.html5Mode(true).hashPrefix('!'); $httpProvider.interceptors.push('authInterceptor'); } -]); - -angular.module(ApplicationConfiguration.applicationModuleName).run(function ($rootScope, $state, Authentication) { - - // Check authentication before changing state - $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) { - if (toState.data && toState.data.roles && toState.data.roles.length > 0) { - var allowed = false; - toState.data.roles.forEach(function (role) { - if ((role === 'guest') || (Authentication.user && Authentication.user.roles !== undefined && Authentication.user.roles.indexOf(role) !== -1)) { - allowed = true; - return true; - } - }); - if (!allowed) { - event.preventDefault(); - if (Authentication.user !== undefined && typeof Authentication.user === 'object') { - $state.go('forbidden'); - } else { - $state.go('authentication.signin').then(function () { - storePreviousState(toState, toParams); - }); - } + bootstrapConfig.$inject = ['$locationProvider', '$httpProvider']; + + // Then define the init function for starting up the application + angular.element(document).ready(init); + + function init() { + // Fixing facebook bug with redirect + if (window.location.hash && window.location.hash === '#_=_') { + if (window.history && history.pushState) { + window.history.pushState('', document.title, window.location.pathname); + } else { + // Prevent scrolling by storing the page's current scroll offset + var scroll = { + top: document.body.scrollTop, + left: document.body.scrollLeft + }; + window.location.hash = ''; + // Restore the scroll offset, should be flicker free + document.body.scrollTop = scroll.top; + document.body.scrollLeft = scroll.left; } } - }); - // Record previous state - $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) { - storePreviousState(fromState, fromParams); - }); - - // Store previous state - function storePreviousState(state, params) { - // only store this state if it shouldn't be ignored - if (!state.data || !state.data.ignoreState) { - $state.previous = { - state: state, - params: params, - href: $state.href(state, params) - }; - } + // Then init the app + angular.bootstrap(document, [app.applicationModuleName]); } -}); - -// Then define the init function for starting up the application -angular.element(document).ready(function () { - // Fixing facebook bug with redirect - if (window.location.hash && window.location.hash === '#_=_') { - if (window.history && history.pushState) { - window.history.pushState('', document.title, window.location.pathname); - } else { - // Prevent scrolling by storing the page's current scroll offset - var scroll = { - top: document.body.scrollTop, - left: document.body.scrollLeft - }; - window.location.hash = ''; - // Restore the scroll offset, should be flicker free - document.body.scrollTop = scroll.top; - document.body.scrollLeft = scroll.left; - } - } - - // Then init the app - angular.bootstrap(document, [ApplicationConfiguration.applicationModuleName]); -}); +}(ApplicationConfiguration)); diff --git a/modules/core/client/config/core-admin.client.menus.js b/modules/core/client/config/core-admin.client.menus.js index b048f6f020..f1472d6cd2 100644 --- a/modules/core/client/config/core-admin.client.menus.js +++ b/modules/core/client/config/core-admin.client.menus.js @@ -1,12 +1,18 @@ -'use strict'; +(function () { + 'use strict'; -angular.module('core.admin').run(['Menus', - function (Menus) { - Menus.addMenuItem('topbar', { + angular + .module('core.admin') + .run(menuConfig); + + menuConfig.$inject = ['menuService']; + + function menuConfig(menuService) { + menuService.addMenuItem('topbar', { title: 'Admin', state: 'admin', type: 'dropdown', roles: ['admin'] }); } -]); +}()); diff --git a/modules/core/client/config/core-admin.client.routes.js b/modules/core/client/config/core-admin.client.routes.js index b7f5f45a6d..92232b900f 100644 --- a/modules/core/client/config/core-admin.client.routes.js +++ b/modules/core/client/config/core-admin.client.routes.js @@ -1,8 +1,13 @@ -'use strict'; +(function () { + 'use strict'; -// Setting up route -angular.module('core.admin.routes').config(['$stateProvider', - function ($stateProvider) { + angular + .module('core.admin.routes') + .config(routeConfig); + + routeConfig.$inject = ['$stateProvider']; + + function routeConfig($stateProvider) { $stateProvider .state('admin', { abstract: true, @@ -13,4 +18,4 @@ angular.module('core.admin.routes').config(['$stateProvider', } }); } -]); +}()); diff --git a/modules/core/client/config/core.client.menus.js b/modules/core/client/config/core.client.menus.js index 7cb277fc25..cd220853e0 100644 --- a/modules/core/client/config/core.client.menus.js +++ b/modules/core/client/config/core.client.menus.js @@ -2,44 +2,41 @@ 'use strict'; angular - .module('core') - .run(MenuConfig); + .module('core') + .run(menuConfig); - MenuConfig.$inject = ['Menus']; + menuConfig.$inject = ['menuService']; - function MenuConfig(Menus) { - - Menus.addMenu('account', { + function menuConfig(menuService) { + menuService.addMenu('account', { roles: ['user'] }); - Menus.addMenuItem('account', { + menuService.addMenuItem('account', { title: '', state: 'settings', type: 'dropdown', roles: ['user'] }); - Menus.addSubMenuItem('account', 'settings', { + menuService.addSubMenuItem('account', 'settings', { title: 'Edit Profile', state: 'settings.profile' }); - Menus.addSubMenuItem('account', 'settings', { + menuService.addSubMenuItem('account', 'settings', { title: 'Edit Profile Picture', state: 'settings.picture' }); - Menus.addSubMenuItem('account', 'settings', { + menuService.addSubMenuItem('account', 'settings', { title: 'Change Password', state: 'settings.password' }); - Menus.addSubMenuItem('account', 'settings', { + menuService.addSubMenuItem('account', 'settings', { title: 'Manage Social Accounts', state: 'settings.accounts' }); - } - }()); diff --git a/modules/core/client/config/core.client.route-filter.js b/modules/core/client/config/core.client.route-filter.js new file mode 100644 index 0000000000..a68b70231f --- /dev/null +++ b/modules/core/client/config/core.client.route-filter.js @@ -0,0 +1,57 @@ +(function () { + 'use strict'; + + angular + .module('core') + .run(routeFilter); + + routeFilter.$inject = ['$rootScope', '$state', 'Authentication']; + + function routeFilter($rootScope, $state, Authentication) { + $rootScope.$on('$stateChangeStart', stateChangeStart); + $rootScope.$on('$stateChangeSuccess', stateChangeSuccess); + + function stateChangeStart(event, toState, toParams, fromState, fromParams) { + // Check authentication before changing state + if (toState.data && toState.data.roles && toState.data.roles.length > 0) { + var allowed = false; + + for (var i = 0, roles = toState.data.roles; i < roles.length; i++) { + if ((roles[i] === 'guest') || (Authentication.user && Authentication.user.roles !== undefined && Authentication.user.roles.indexOf(roles[i]) !== -1)) { + allowed = true; + break; + } + } + + if (!allowed) { + event.preventDefault(); + if (Authentication.user !== undefined && typeof Authentication.user === 'object') { + $state.transitionTo('forbidden'); + } else { + $state.go('authentication.signin').then(function () { + // Record previous state + storePreviousState(toState, toParams); + }); + } + } + } + } + + function stateChangeSuccess(event, toState, toParams, fromState, fromParams) { + // Record previous state + storePreviousState(fromState, fromParams); + } + + // Store previous state + function storePreviousState(state, params) { + // only store this state if it shouldn't be ignored + if (!state.data || !state.data.ignoreState) { + $state.previous = { + state: state, + params: params, + href: $state.href(state, params) + }; + } + } + } +}()); diff --git a/modules/core/client/config/core.client.routes.js b/modules/core/client/config/core.client.routes.js index 432acc8cb8..6fc0d79fc0 100644 --- a/modules/core/client/config/core.client.routes.js +++ b/modules/core/client/config/core.client.routes.js @@ -1,9 +1,13 @@ -'use strict'; +(function () { + 'use strict'; -// Setting up route -angular.module('core').config(['$stateProvider', '$urlRouterProvider', - function ($stateProvider, $urlRouterProvider) { + angular + .module('core.routes') + .config(routeConfig); + routeConfig.$inject = ['$stateProvider', '$urlRouterProvider']; + + function routeConfig($stateProvider, $urlRouterProvider) { $urlRouterProvider.rule(function ($injector, $location) { var path = $location.path(); var hasTrailingSlash = path.length > 1 && path[path.length - 1] === '/'; @@ -22,11 +26,12 @@ angular.module('core').config(['$stateProvider', '$urlRouterProvider', }); }); - // Home state routing $stateProvider .state('home', { url: '/', - templateUrl: 'modules/core/client/views/home.client.view.html' + templateUrl: 'modules/core/client/views/home.client.view.html', + controller: 'HomeController', + controllerAs: 'vm' }) .state('not-found', { url: '/not-found', @@ -53,4 +58,4 @@ angular.module('core').config(['$stateProvider', '$urlRouterProvider', } }); } -]); +}()); diff --git a/modules/core/client/controllers/header.client.controller.js b/modules/core/client/controllers/header.client.controller.js index 817244e175..a1fadfad17 100644 --- a/modules/core/client/controllers/header.client.controller.js +++ b/modules/core/client/controllers/header.client.controller.js @@ -1,26 +1,25 @@ -'use strict'; +(function () { + 'use strict'; -angular.module('core').controller('HeaderController', ['$scope', '$state', 'Authentication', 'Menus', - function ($scope, $state, Authentication, Menus) { - // Expose view variables - $scope.$state = $state; - $scope.authentication = Authentication; + angular + .module('core') + .controller('HeaderController', HeaderController); - // Get the topbar menu - $scope.menu = Menus.getMenu('topbar'); + HeaderController.$inject = ['$scope', '$state', 'Authentication', 'menuService']; - // Get the account menu - $scope.accountMenu = Menus.getMenu('account').items[0]; + function HeaderController($scope, $state, Authentication, menuService) { + var vm = this; - // Toggle the menu items - $scope.isCollapsed = false; - $scope.toggleCollapsibleMenu = function () { - $scope.isCollapsed = !$scope.isCollapsed; - }; + vm.accountMenu = menuService.getMenu('account').items[0]; + vm.authentication = Authentication; + vm.isCollapsed = false; + vm.menu = menuService.getMenu('topbar'); - // Collapsing the menu after navigation - $scope.$on('$stateChangeSuccess', function () { - $scope.isCollapsed = false; - }); + $scope.$on('$stateChangeSuccess', stateChangeSuccess); + + function stateChangeSuccess() { + // Collapsing the menu after navigation + vm.isCollapsed = false; + } } -]); +}()); diff --git a/modules/core/client/controllers/home.client.controller.js b/modules/core/client/controllers/home.client.controller.js index a76343c7f1..f433066896 100644 --- a/modules/core/client/controllers/home.client.controller.js +++ b/modules/core/client/controllers/home.client.controller.js @@ -1,8 +1,11 @@ -'use strict'; +(function () { + 'use strict'; -angular.module('core').controller('HomeController', ['$scope', 'Authentication', - function ($scope, Authentication) { - // This provides Authentication context. - $scope.authentication = Authentication; + angular + .module('core') + .controller('HomeController', HomeController); + + function HomeController() { + var vm = this; } -]); +}()); diff --git a/modules/core/client/core.client.module.js b/modules/core/client/core.client.module.js index c841d37682..c94337d057 100644 --- a/modules/core/client/core.client.module.js +++ b/modules/core/client/core.client.module.js @@ -1,6 +1,8 @@ -'use strict'; +(function (app) { + 'use strict'; -// Use Application configuration module to register a new module -ApplicationConfiguration.registerModule('core'); -ApplicationConfiguration.registerModule('core.admin', ['core']); -ApplicationConfiguration.registerModule('core.admin.routes', ['ui.router']); + app.registerModule('core'); + app.registerModule('core.routes', ['ui.router']); + app.registerModule('core.admin', ['core']); + app.registerModule('core.admin.routes', ['ui.router']); +}(ApplicationConfiguration)); diff --git a/modules/core/client/directives/show-errors.client.directives.js b/modules/core/client/directives/show-errors.client.directives.js index c9473a837a..92c65c2409 100644 --- a/modules/core/client/directives/show-errors.client.directives.js +++ b/modules/core/client/directives/show-errors.client.directives.js @@ -1,79 +1,85 @@ -'use strict'; - -/** - * Edits by Ryan Hutchison - * Credit: https://github.com/paulyoder/angular-bootstrap-show-errors */ - -angular.module('core') - .directive('showErrors', ['$timeout', '$interpolate', function ($timeout, $interpolate) { - var linkFn = function (scope, el, attrs, formCtrl) { - var inputEl, - inputName, - inputNgEl, - options, - showSuccess, - toggleClasses, - initCheck = false, - showValidationMessages = false, - blurred = false; - - options = scope.$eval(attrs.showErrors) || {}; - showSuccess = options.showSuccess || false; - inputEl = el[0].querySelector('.form-control[name]') || el[0].querySelector('[name]'); - inputNgEl = angular.element(inputEl); - inputName = $interpolate(inputNgEl.attr('name') || '')(scope); - - if (!inputName) { - throw new Error('show-errors element has no child input elements with a \'name\' attribute class'); +(function () { + 'use strict'; + + // https://gist.github.com/rhutchison/c8c14946e88a1c8f9216 + + angular + .module('core') + .directive('showErrors', showErrors); + + showErrors.$inject = ['$timeout', '$interpolate']; + + function showErrors($timeout, $interpolate) { + var directive = { + restrict: 'A', + require: '^form', + compile: compile + }; + + return directive; + + function compile(elem, attrs) { + if (attrs.showErrors.indexOf('skipFormGroupCheck') === -1) { + if (!(elem.hasClass('form-group') || elem.hasClass('input-group'))) { + throw new Error('show-errors element does not have the \'form-group\' or \'input-group\' class'); + } } - var reset = function () { - return $timeout(function () { - el.removeClass('has-error'); - el.removeClass('has-success'); - showValidationMessages = false; - }, 0, false); - }; + return linkFn; - scope.$watch(function () { - return formCtrl[inputName] && formCtrl[inputName].$invalid; - }, function (invalid) { - return toggleClasses(invalid); - }); + function linkFn(scope, el, attrs, formCtrl) { + var inputEl, + inputName, + inputNgEl, + options, + showSuccess, + initCheck = false, + showValidationMessages = false; - scope.$on('show-errors-check-validity', function (event, name) { - if (angular.isUndefined(name) || formCtrl.$name === name) { - initCheck = true; - showValidationMessages = true; + options = scope.$eval(attrs.showErrors) || {}; + showSuccess = options.showSuccess || false; + inputEl = el[0].querySelector('.form-control[name]') || el[0].querySelector('[name]'); + inputNgEl = angular.element(inputEl); + inputName = $interpolate(inputNgEl.attr('name') || '')(scope); - return toggleClasses(formCtrl[inputName].$invalid); + if (!inputName) { + throw new Error('show-errors element has no child input elements with a \'name\' attribute class'); } - }); - scope.$on('show-errors-reset', function (event, name) { - if (angular.isUndefined(name) || formCtrl.$name === name) { - return reset(); + scope.$watch(function () { + return formCtrl[inputName] && formCtrl[inputName].$invalid; + }, toggleClasses); + + scope.$on('show-errors-check-validity', checkValidity); + scope.$on('show-errors-reset', reset); + + function checkValidity(event, name) { + if (angular.isUndefined(name) || formCtrl.$name === name) { + initCheck = true; + showValidationMessages = true; + + return toggleClasses(formCtrl[inputName].$invalid); + } } - }); - toggleClasses = function (invalid) { - el.toggleClass('has-error', showValidationMessages && invalid); - if (showSuccess) { - return el.toggleClass('has-success', showValidationMessages && !invalid); + function reset(event, name) { + if (angular.isUndefined(name) || formCtrl.$name === name) { + return $timeout(function () { + el.removeClass('has-error'); + el.removeClass('has-success'); + showValidationMessages = false; + }, 0, false); + } } - }; - }; - return { - restrict: 'A', - require: '^form', - compile: function (elem, attrs) { - if (attrs.showErrors.indexOf('skipFormGroupCheck') === -1) { - if (!(elem.hasClass('form-group') || elem.hasClass('input-group'))) { - throw new Error('show-errors element does not have the \'form-group\' or \'input-group\' class'); + function toggleClasses(invalid) { + el.toggleClass('has-error', showValidationMessages && invalid); + + if (showSuccess) { + return el.toggleClass('has-success', showValidationMessages && !invalid); } } - return linkFn; } - }; - }]); + } + } +}()); diff --git a/modules/core/client/services/interceptors/auth-interceptor.client.service.js b/modules/core/client/services/interceptors/auth-interceptor.client.service.js new file mode 100644 index 0000000000..2929402804 --- /dev/null +++ b/modules/core/client/services/interceptors/auth-interceptor.client.service.js @@ -0,0 +1,34 @@ +(function () { + 'use strict'; + + angular + .module('core') + .factory('authInterceptor', authInterceptor); + + authInterceptor.$inject = ['$q', '$injector', 'Authentication']; + + function authInterceptor($q, $injector, Authentication) { + var service = { + responseError: responseError + }; + + return service; + + function responseError(rejection) { + if (!rejection.config.ignoreAuthModule) { + switch (rejection.status) { + case 401: + // Deauthenticate the global user + Authentication.user = null; + $injector.get('$state').transitionTo('authentication.signin'); + break; + case 403: + $injector.get('$state').transitionTo('forbidden'); + break; + } + } + // otherwise, default behaviour + return $q.reject(rejection); + } + } +}()); diff --git a/modules/core/client/services/interceptors/auth.interceptor.client.service.js b/modules/core/client/services/interceptors/auth.interceptor.client.service.js deleted file mode 100644 index a4785f522c..0000000000 --- a/modules/core/client/services/interceptors/auth.interceptor.client.service.js +++ /dev/null @@ -1,24 +0,0 @@ -'use strict'; - -angular.module('core').factory('authInterceptor', ['$q', '$injector', 'Authentication', - function ($q, $injector, Authentication) { - return { - responseError: function(rejection) { - if (!rejection.config.ignoreAuthModule) { - switch (rejection.status) { - case 401: - // Deauthenticate the global user - Authentication.user = null; - $injector.get('$state').transitionTo('authentication.signin'); - break; - case 403: - $injector.get('$state').transitionTo('forbidden'); - break; - } - } - // otherwise, default behaviour - return $q.reject(rejection); - } - }; - } -]); diff --git a/modules/core/client/services/menu.client.service.js b/modules/core/client/services/menu.client.service.js new file mode 100644 index 0000000000..2e5a3f06b3 --- /dev/null +++ b/modules/core/client/services/menu.client.service.js @@ -0,0 +1,195 @@ +(function () { + 'use strict'; + + angular + .module('core') + .factory('menuService', menuService); + + function menuService() { + var shouldRender; + var service = { + addMenu: addMenu, + addMenuItem: addMenuItem, + addSubMenuItem: addSubMenuItem, + defaultRoles: ['user', 'admin'], + getMenu: getMenu, + menus: {}, + removeMenu: removeMenu, + removeMenuItem: removeMenuItem, + removeSubMenuItem: removeSubMenuItem, + validateMenuExistance: validateMenuExistance + }; + + init(); + + return service; + + // Add new menu object by menu id + function addMenu(menuId, options) { + options = options || {}; + + // Create the new menu + service.menus[menuId] = { + roles: options.roles || service.defaultRoles, + items: options.items || [], + shouldRender: shouldRender + }; + + // Return the menu object + return service.menus[menuId]; + } + + // Add menu item object + function addMenuItem(menuId, options) { + options = options || {}; + + // Validate that the menu exists + service.validateMenuExistance(menuId); + + // Push new menu item + service.menus[menuId].items.push({ + title: options.title || '', + state: options.state || '', + type: options.type || 'item', + class: options.class, + roles: ((options.roles === null || typeof options.roles === 'undefined') ? service.defaultRoles : options.roles), + position: options.position || 0, + items: [], + shouldRender: shouldRender + }); + + // Add submenu items + if (options.items) { + for (var i in options.items) { + if (options.items.hasOwnProperty(i)) { + service.addSubMenuItem(menuId, options.state, options.items[i]); + } + } + } + + // Return the menu object + return service.menus[menuId]; + } + + // Add submenu item object + function addSubMenuItem(menuId, parentItemState, options) { + options = options || {}; + + // Validate that the menu exists + service.validateMenuExistance(menuId); + + // Search for menu item + for (var itemIndex in service.menus[menuId].items) { + if (service.menus[menuId].items[itemIndex].state === parentItemState) { + // Push new submenu item + service.menus[menuId].items[itemIndex].items.push({ + title: options.title || '', + state: options.state || '', + roles: ((options.roles === null || typeof options.roles === 'undefined') ? service.menus[menuId].items[itemIndex].roles : options.roles), + position: options.position || 0, + shouldRender: shouldRender + }); + } + } + + // Return the menu object + return service.menus[menuId]; + } + + // Get the menu object by menu id + function getMenu(menuId) { + // Validate that the menu exists + service.validateMenuExistance(menuId); + + // Return the menu object + return service.menus[menuId]; + } + + function init() { + // A private function for rendering decision + shouldRender = function (user) { + if (this.roles.indexOf('*') !== -1) { + return true; + } else { + if (!user) { + return false; + } + + for (var userRoleIndex in user.roles) { + if (user.roles.hasOwnProperty(userRoleIndex)) { + for (var roleIndex in this.roles) { + if (this.roles.hasOwnProperty(roleIndex) && this.roles[roleIndex] === user.roles[userRoleIndex]) { + return true; + } + } + } + } + } + + return false; + }; + + // Adding the topbar menu + addMenu('topbar', { + roles: ['*'] + }); + } + + // Remove existing menu object by menu id + function removeMenu(menuId) { + // Validate that the menu exists + service.validateMenuExistance(menuId); + + delete service.menus[menuId]; + } + + // Remove existing menu object by menu id + function removeMenuItem(menuId, menuItemState) { + // Validate that the menu exists + service.validateMenuExistance(menuId); + + // Search for menu item to remove + for (var itemIndex in service.menus[menuId].items) { + if (service.menus[menuId].items.hasOwnProperty(itemIndex) && service.menus[menuId].items[itemIndex].state === menuItemState) { + service.menus[menuId].items.splice(itemIndex, 1); + } + } + + // Return the menu object + return service.menus[menuId]; + } + + // Remove existing menu object by menu id + function removeSubMenuItem(menuId, submenuItemState) { + // Validate that the menu exists + service.validateMenuExistance(menuId); + + // Search for menu item to remove + for (var itemIndex in service.menus[menuId].items) { + if (this.menus[menuId].items.hasOwnProperty(itemIndex)) { + for (var subitemIndex in service.menus[menuId].items[itemIndex].items) { + if (this.menus[menuId].items[itemIndex].items.hasOwnProperty(subitemIndex) && service.menus[menuId].items[itemIndex].items[subitemIndex].state === submenuItemState) { + service.menus[menuId].items[itemIndex].items.splice(subitemIndex, 1); + } + } + } + } + + // Return the menu object + return service.menus[menuId]; + } + + // Validate menu existance + function validateMenuExistance(menuId) { + if (menuId && menuId.length) { + if (service.menus[menuId]) { + return true; + } else { + throw new Error('Menu does not exist'); + } + } else { + throw new Error('MenuId was not provided'); + } + } + } +}()); diff --git a/modules/core/client/services/menus.client.service.js b/modules/core/client/services/menus.client.service.js deleted file mode 100644 index 64e6dd568d..0000000000 --- a/modules/core/client/services/menus.client.service.js +++ /dev/null @@ -1,182 +0,0 @@ -'use strict'; - -// Menu service used for managing menus -angular.module('core').service('Menus', [ - function () { - // Define a set of default roles - this.defaultRoles = ['user', 'admin']; - - // Define the menus object - this.menus = {}; - - // A private function for rendering decision - var shouldRender = function (user) { - if (!!~this.roles.indexOf('*')) { - return true; - } else { - if (!user) { - return false; - } - for (var userRoleIndex in user.roles) { - if (user.roles.hasOwnProperty(userRoleIndex)) { - for (var roleIndex in this.roles) { - if (this.roles.hasOwnProperty(roleIndex)) { - if (this.roles[roleIndex] === user.roles[userRoleIndex]) { - return true; - } - } - } - } - } - } - - return false; - }; - - // Validate menu existance - this.validateMenuExistance = function (menuId) { - if (menuId && menuId.length) { - if (this.menus[menuId]) { - return true; - } else { - throw new Error('Menu does not exist'); - } - } else { - throw new Error('MenuId was not provided'); - } - }; - - // Get the menu object by menu id - this.getMenu = function (menuId) { - // Validate that the menu exists - this.validateMenuExistance(menuId); - - // Return the menu object - return this.menus[menuId]; - }; - - // Add new menu object by menu id - this.addMenu = function (menuId, options) { - options = options || {}; - - // Create the new menu - this.menus[menuId] = { - roles: options.roles || this.defaultRoles, - items: options.items || [], - shouldRender: shouldRender - }; - - // Return the menu object - return this.menus[menuId]; - }; - - // Remove existing menu object by menu id - this.removeMenu = function (menuId) { - // Validate that the menu exists - this.validateMenuExistance(menuId); - - // Return the menu object - delete this.menus[menuId]; - }; - - // Add menu item object - this.addMenuItem = function (menuId, options) { - options = options || {}; - - // Validate that the menu exists - this.validateMenuExistance(menuId); - - // Push new menu item - this.menus[menuId].items.push({ - title: options.title || '', - state: options.state || '', - type: options.type || 'item', - class: options.class, - roles: ((options.roles === null || typeof options.roles === 'undefined') ? this.defaultRoles : options.roles), - position: options.position || 0, - items: [], - shouldRender: shouldRender - }); - - // Add submenu items - if (options.items) { - for (var i in options.items) { - if (options.items.hasOwnProperty(i)) { - this.addSubMenuItem(menuId, options.state, options.items[i]); - } - } - } - - // Return the menu object - return this.menus[menuId]; - }; - - // Add submenu item object - this.addSubMenuItem = function (menuId, parentItemState, options) { - options = options || {}; - - // Validate that the menu exists - this.validateMenuExistance(menuId); - - // Search for menu item - for (var itemIndex in this.menus[menuId].items) { - if (this.menus[menuId].items[itemIndex].state === parentItemState) { - // Push new submenu item - this.menus[menuId].items[itemIndex].items.push({ - title: options.title || '', - state: options.state || '', - roles: ((options.roles === null || typeof options.roles === 'undefined') ? this.menus[menuId].items[itemIndex].roles : options.roles), - position: options.position || 0, - shouldRender: shouldRender - }); - } - } - - // Return the menu object - return this.menus[menuId]; - }; - - // Remove existing menu object by menu id - this.removeMenuItem = function (menuId, menuItemState) { - // Validate that the menu exists - this.validateMenuExistance(menuId); - - // Search for menu item to remove - for (var itemIndex in this.menus[menuId].items) { - if (this.menus[menuId].items[itemIndex].state === menuItemState) { - this.menus[menuId].items.splice(itemIndex, 1); - } - } - - // Return the menu object - return this.menus[menuId]; - }; - - // Remove existing menu object by menu id - this.removeSubMenuItem = function (menuId, submenuItemState) { - // Validate that the menu exists - this.validateMenuExistance(menuId); - - // Search for menu item to remove - for (var itemIndex in this.menus[menuId].items) { - if (this.menus[menuId].items.hasOwnProperty(itemIndex)) { - for (var subitemIndex in this.menus[menuId].items[itemIndex].items) { - if (this.menus[menuId].items[itemIndex].items.hasOwnProperty(subitemIndex)) { - if (this.menus[menuId].items[itemIndex].items[subitemIndex].state === submenuItemState) { - this.menus[menuId].items[itemIndex].items.splice(subitemIndex, 1); - } - } - } - } - } - - // Return the menu object - return this.menus[menuId]; - }; - - // Adding the topbar menu - this.addMenu('topbar', { - roles: ['*'] - }); - } -]); diff --git a/modules/core/client/services/socket.io.client.service.js b/modules/core/client/services/socket.io.client.service.js index 7031a0d2de..a00299ae8a 100644 --- a/modules/core/client/services/socket.io.client.service.js +++ b/modules/core/client/services/socket.io.client.service.js @@ -1,40 +1,57 @@ -'use strict'; +(function () { + 'use strict'; + + // Create the Socket.io wrapper service + angular + .module('core') + .factory('Socket', Socket); + + Socket.$inject = ['Authentication', '$state', '$timeout']; + + function Socket(Authentication, $state, $timeout) { + var service = { + connect: connect, + emit: emit, + on: on, + removeListener: removeListener, + socket: null + }; + + connect(); + + return service; -// Create the Socket.io wrapper service -angular.module('core').service('Socket', ['Authentication', '$state', '$timeout', - function (Authentication, $state, $timeout) { // Connect to Socket.io server - this.connect = function () { + function connect() { // Connect only when authenticated if (Authentication.user) { - this.socket = io(); + service.socket = io(); } - }; - this.connect(); + } + + // Wrap the Socket.io 'emit' method + function emit(eventName, data) { + if (service.socket) { + service.socket.emit(eventName, data); + } + } // Wrap the Socket.io 'on' method - this.on = function (eventName, callback) { - if (this.socket) { - this.socket.on(eventName, function (data) { + function on(eventName, callback) { + if (service.socket) { + service.socket.on(eventName, function (data) { $timeout(function () { callback(data); }); }); } - }; - - // Wrap the Socket.io 'emit' method - this.emit = function (eventName, data) { - if (this.socket) { - this.socket.emit(eventName, data); - } - }; + } // Wrap the Socket.io 'removeListener' method - this.removeListener = function (eventName) { - if (this.socket) { - this.socket.removeListener(eventName); + function removeListener(eventName) { + if (service.socket) { + service.socket.removeListener(eventName); } - }; + } } -]); +}()); diff --git a/modules/core/client/views/header.client.view.html b/modules/core/client/views/header.client.view.html index 42b3d79cb1..28a354e05f 100644 --- a/modules/core/client/views/header.client.view.html +++ b/modules/core/client/views/header.client.view.html @@ -1,6 +1,6 @@ -
+
-