diff --git a/bower.json b/bower.json
index 9738f46d..ecfe2fc4 100644
--- a/bower.json
+++ b/bower.json
@@ -10,6 +10,7 @@
"angular-messages": "~1.5.0",
"angular-mocks": "~1.5.0",
"angular-resource": "~1.5.0",
+ "angular-ui-notification": "~0.2.0",
"angular-ui-router": "~0.2.18",
"bootstrap": "~3.3.6",
"ng-file-upload": "^12.1.0",
diff --git a/config/assets/default.js b/config/assets/default.js
index a2ea678f..ff8cb81f 100644
--- a/config/assets/default.js
+++ b/config/assets/default.js
@@ -9,7 +9,8 @@ module.exports = {
// bower:css
'public/lib/bootstrap/dist/css/bootstrap.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.css',
- 'public/lib/ng-img-crop/compile/unminified/ng-img-crop.css'
+ 'public/lib/ng-img-crop/compile/unminified/ng-img-crop.css',
+ 'public/lib/angular-ui-notification/dist/angular-ui-notification.css'
// endbower
],
js: [
@@ -22,6 +23,7 @@ module.exports = {
'public/lib/angular-messages/angular-messages.js',
'public/lib/angular-mocks/angular-mocks.js',
'public/lib/angular-resource/angular-resource.js',
+ 'public/lib/angular-ui-notification/dist/angular-ui-notification.js',
'public/lib/angular-ui-router/release/angular-ui-router.js',
'public/lib/owasp-password-strength-test/owasp-password-strength-test.js',
// endbower
diff --git a/config/assets/production.js b/config/assets/production.js
index 7ad2b2f1..ed52e98e 100644
--- a/config/assets/production.js
+++ b/config/assets/production.js
@@ -10,6 +10,7 @@ module.exports = {
'public/lib/bootstrap/dist/css/bootstrap.min.css',
'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
'public/lib/ng-img-crop/compile/minified/ng-img-crop.css',
+ 'public/lib/angular-ui-notification/dist/angular-ui-notification.min.css'
// endbower
],
js: [
@@ -20,6 +21,7 @@ module.exports = {
'public/lib/angular-messages/angular-messages.min.js',
'public/lib/angular-mocks/angular-mocks.js',
'public/lib/angular-resource/angular-resource.min.js',
+ 'public/lib/angular-ui-notification/dist/angular-ui-notification.min.js',
'public/lib/angular-ui-router/release/angular-ui-router.min.js',
'public/lib/ng-file-upload/ng-file-upload.min.js',
'public/lib/ng-img-crop/compile/minified/ng-img-crop.js',
diff --git a/gulpfile.js b/gulpfile.js
index deca1aef..2f8dc8f5 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -68,29 +68,29 @@ gulp.task('nodemon-nodebug', function () {
// Watch Files For Changes
gulp.task('watch', function () {
// Start livereload
- plugins.livereload.listen();
+ plugins.refresh.listen();
// Add watch rules
- gulp.watch(defaultAssets.server.views).on('change', plugins.livereload.changed);
- gulp.watch(defaultAssets.server.allJS, ['eslint']).on('change', plugins.livereload.changed);
- gulp.watch(defaultAssets.client.js, ['eslint']).on('change', plugins.livereload.changed);
- gulp.watch(defaultAssets.client.css, ['csslint']).on('change', plugins.livereload.changed);
- gulp.watch(defaultAssets.client.sass, ['sass', 'csslint']).on('change', plugins.livereload.changed);
- gulp.watch(defaultAssets.client.less, ['less', 'csslint']).on('change', plugins.livereload.changed);
+ gulp.watch(defaultAssets.server.views).on('change', plugins.refresh.changed);
+ gulp.watch(defaultAssets.server.allJS, ['eslint']).on('change', plugins.refresh.changed);
+ gulp.watch(defaultAssets.client.js, ['eslint']).on('change', plugins.refresh.changed);
+ gulp.watch(defaultAssets.client.css, ['csslint']).on('change', plugins.refresh.changed);
+ gulp.watch(defaultAssets.client.sass, ['sass', 'csslint']).on('change', plugins.refresh.changed);
+ gulp.watch(defaultAssets.client.less, ['less', 'csslint']).on('change', plugins.refresh.changed);
if (process.env.NODE_ENV === 'production') {
gulp.watch(defaultAssets.server.gulpConfig, ['templatecache', 'eslint']);
- gulp.watch(defaultAssets.client.views, ['templatecache']).on('change', plugins.livereload.changed);
+ gulp.watch(defaultAssets.client.views, ['templatecache']).on('change', plugins.refresh.changed);
} else {
gulp.watch(defaultAssets.server.gulpConfig, ['eslint']);
- gulp.watch(defaultAssets.client.views).on('change', plugins.livereload.changed);
+ gulp.watch(defaultAssets.client.views).on('change', plugins.refresh.changed);
}
});
// Watch server test files
gulp.task('watch:server:run-tests', function () {
// Start livereload
- plugins.livereload.listen();
+ plugins.refresh.listen();
// Add Server Test file rules
gulp.watch([testAssets.tests.server, defaultAssets.server.allJS], ['test:server']).on('change', function (file) {
@@ -108,7 +108,7 @@ gulp.task('watch:server:run-tests', function () {
});
});
- plugins.livereload.changed();
+ plugins.refresh.changed();
});
});
diff --git a/modules/articles/client/config/articles-admin.client.routes.js b/modules/articles/client/config/articles-admin.client.routes.js
index b15d918c..b493d0e0 100644
--- a/modules/articles/client/config/articles-admin.client.routes.js
+++ b/modules/articles/client/config/articles-admin.client.routes.js
@@ -16,7 +16,7 @@
})
.state('admin.articles.list', {
url: '',
- templateUrl: 'modules/articles/client/views/admin/list-articles.client.view.html',
+ templateUrl: '/modules/articles/client/views/admin/list-articles.client.view.html',
controller: 'ArticlesAdminListController',
controllerAs: 'vm',
data: {
@@ -25,7 +25,7 @@
})
.state('admin.articles.create', {
url: '/create',
- templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
+ templateUrl: '/modules/articles/client/views/admin/form-article.client.view.html',
controller: 'ArticlesAdminController',
controllerAs: 'vm',
data: {
@@ -37,7 +37,7 @@
})
.state('admin.articles.edit', {
url: '/:articleId/edit',
- templateUrl: 'modules/articles/client/views/admin/form-article.client.view.html',
+ templateUrl: '/modules/articles/client/views/admin/form-article.client.view.html',
controller: 'ArticlesAdminController',
controllerAs: 'vm',
data: {
diff --git a/modules/articles/client/config/articles.client.routes.js b/modules/articles/client/config/articles.client.routes.js
index a16926e5..4a94fa2e 100644
--- a/modules/articles/client/config/articles.client.routes.js
+++ b/modules/articles/client/config/articles.client.routes.js
@@ -16,7 +16,7 @@
})
.state('articles.list', {
url: '',
- templateUrl: 'modules/articles/client/views/list-articles.client.view.html',
+ templateUrl: '/modules/articles/client/views/list-articles.client.view.html',
controller: 'ArticlesListController',
controllerAs: 'vm',
data: {
@@ -25,7 +25,7 @@
})
.state('articles.view', {
url: '/:articleId',
- templateUrl: 'modules/articles/client/views/view-article.client.view.html',
+ templateUrl: '/modules/articles/client/views/view-article.client.view.html',
controller: 'ArticlesController',
controllerAs: 'vm',
resolve: {
diff --git a/modules/articles/client/controllers/admin/article.client.controller.js b/modules/articles/client/controllers/admin/article.client.controller.js
index 219390df..97f730d3 100644
--- a/modules/articles/client/controllers/admin/article.client.controller.js
+++ b/modules/articles/client/controllers/admin/article.client.controller.js
@@ -5,14 +5,13 @@
.module('articles.admin')
.controller('ArticlesAdminController', ArticlesAdminController);
- ArticlesAdminController.$inject = ['$scope', '$state', '$window', 'articleResolve', 'Authentication'];
+ ArticlesAdminController.$inject = ['$scope', '$state', '$window', 'articleResolve', 'Authentication', 'Notification'];
- function ArticlesAdminController($scope, $state, $window, article, Authentication) {
+ function ArticlesAdminController($scope, $state, $window, article, Authentication, Notification) {
var vm = this;
vm.article = article;
vm.authentication = Authentication;
- vm.error = null;
vm.form = {};
vm.remove = remove;
vm.save = save;
@@ -22,6 +21,7 @@
if ($window.confirm('Are you sure you want to delete?')) {
vm.article.$remove(function() {
$state.go('admin.articles.list');
+ Notification.success({ message: ' Article deleted successfully!' });
});
}
}
@@ -40,10 +40,11 @@
function successCallback(res) {
$state.go('admin.articles.list'); // should we send the User to the list or the updated Article's view?
+ Notification.success({ message: ' Article saved successfully!' });
}
function errorCallback(res) {
- vm.error = res.data.message;
+ Notification.error({ message: res.data.message, title: ' Article save error!' });
}
}
}
diff --git a/modules/articles/client/controllers/articles.client.controller.js b/modules/articles/client/controllers/articles.client.controller.js
index 58d2c7d5..40708dd9 100644
--- a/modules/articles/client/controllers/articles.client.controller.js
+++ b/modules/articles/client/controllers/articles.client.controller.js
@@ -12,7 +12,6 @@
vm.article = article;
vm.authentication = Authentication;
- vm.error = null;
}
}());
diff --git a/modules/articles/client/services/articles.client.service.js b/modules/articles/client/services/articles.client.service.js
index e10e00fa..5e653ca4 100644
--- a/modules/articles/client/services/articles.client.service.js
+++ b/modules/articles/client/services/articles.client.service.js
@@ -5,10 +5,10 @@
.module('articles.services')
.factory('ArticlesService', ArticlesService);
- ArticlesService.$inject = ['$resource'];
+ ArticlesService.$inject = ['$resource', '$log'];
- function ArticlesService($resource) {
- var Article = $resource('api/articles/:articleId', {
+ function ArticlesService($resource, $log) {
+ var Article = $resource('/api/articles/:articleId', {
articleId: '@_id'
}, {
update: {
@@ -47,7 +47,7 @@
function handleError(error) {
// Log error
- console.log(error);
+ $log.error(error);
}
}
}());
diff --git a/modules/articles/client/views/admin/form-article.client.view.html b/modules/articles/client/views/admin/form-article.client.view.html
index f7d20e8f..15f05dbe 100644
--- a/modules/articles/client/views/admin/form-article.client.view.html
+++ b/modules/articles/client/views/admin/form-article.client.view.html
@@ -24,9 +24,6 @@
-
-
-
diff --git a/modules/articles/server/controllers/articles.server.controller.js b/modules/articles/server/controllers/articles.server.controller.js
index 18d6a3b9..ddba5fe1 100644
--- a/modules/articles/server/controllers/articles.server.controller.js
+++ b/modules/articles/server/controllers/articles.server.controller.js
@@ -17,7 +17,7 @@ exports.create = function (req, res) {
article.save(function (err) {
if (err) {
- return res.status(400).send({
+ return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -51,7 +51,7 @@ exports.update = function (req, res) {
article.save(function (err) {
if (err) {
- return res.status(400).send({
+ return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -68,7 +68,7 @@ exports.delete = function (req, res) {
article.remove(function (err) {
if (err) {
- return res.status(400).send({
+ return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
@@ -83,7 +83,7 @@ exports.delete = function (req, res) {
exports.list = function (req, res) {
Article.find().sort('-created').populate('user', 'displayName').exec(function (err, articles) {
if (err) {
- return res.status(400).send({
+ return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
diff --git a/modules/articles/tests/client/admin.articles.client.controller.tests.js b/modules/articles/tests/client/admin.articles.client.controller.tests.js
index 2b99aa48..32964a8f 100644
--- a/modules/articles/tests/client/admin.articles.client.controller.tests.js
+++ b/modules/articles/tests/client/admin.articles.client.controller.tests.js
@@ -9,7 +9,8 @@
$state,
Authentication,
ArticlesService,
- mockArticle;
+ mockArticle,
+ Notification;
// The $resource service augments the response object with methods for updating and deleting the resource.
// If we were to use the standard toEqual matcher, our tests would fail because the test values would not match
@@ -36,7 +37,7 @@
// The injector ignores leading and trailing underscores here (i.e. _$httpBackend_).
// This allows us to inject a service but then attach it to a variable
// with the same name as the service.
- beforeEach(inject(function ($controller, $rootScope, _$state_, _$httpBackend_, _Authentication_, _ArticlesService_) {
+ beforeEach(inject(function ($controller, $rootScope, _$state_, _$httpBackend_, _Authentication_, _ArticlesService_, _Notification_) {
// Set a new global scope
$scope = $rootScope.$new();
@@ -45,6 +46,10 @@
$state = _$state_;
Authentication = _Authentication_;
ArticlesService = _ArticlesService_;
+ Notification = _Notification_;
+
+ // Ignore parent template get on state transitions
+ $httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
// create mock article
mockArticle = new ArticlesService({
@@ -66,6 +71,8 @@
// Spy on state go
spyOn($state, 'go');
+ spyOn(Notification, 'error');
+ spyOn(Notification, 'success');
}));
describe('vm.save() as create', function () {
@@ -83,26 +90,28 @@
it('should send a POST request with the form input values and then locate to new object URL', inject(function (ArticlesService) {
// Set POST response
- $httpBackend.expectPOST('api/articles', sampleArticlePostData).respond(mockArticle);
+ $httpBackend.expectPOST('/api/articles', sampleArticlePostData).respond(mockArticle);
// Run controller functionality
$scope.vm.save(true);
$httpBackend.flush();
+ // Test Notification success was called
+ expect(Notification.success).toHaveBeenCalledWith({ message: ' Article saved successfully!' });
// Test URL redirection after the article was created
expect($state.go).toHaveBeenCalledWith('admin.articles.list');
}));
- it('should set $scope.vm.error if error', function () {
+ it('should call Notification.error if error', function () {
var errorMessage = 'this is an error message';
- $httpBackend.expectPOST('api/articles', sampleArticlePostData).respond(400, {
+ $httpBackend.expectPOST('/api/articles', sampleArticlePostData).respond(400, {
message: errorMessage
});
$scope.vm.save(true);
$httpBackend.flush();
- expect($scope.vm.error).toBe(errorMessage);
+ expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: ' Article save error!' });
});
});
@@ -120,11 +129,13 @@
$scope.vm.save(true);
$httpBackend.flush();
+ // Test Notification success was called
+ expect(Notification.success).toHaveBeenCalledWith({ message: ' Article saved successfully!' });
// Test URL location to new object
expect($state.go).toHaveBeenCalledWith('admin.articles.list');
}));
- it('should set $scope.vm.error if error', inject(function (ArticlesService) {
+ it('should call Notification.error if error', inject(function (ArticlesService) {
var errorMessage = 'error';
$httpBackend.expectPUT(/api\/articles\/([0-9a-fA-F]{24})$/).respond(400, {
message: errorMessage
@@ -133,7 +144,7 @@
$scope.vm.save(true);
$httpBackend.flush();
- expect($scope.vm.error).toBe(errorMessage);
+ expect(Notification.error).toHaveBeenCalledWith({ message: errorMessage, title: ' Article save error!' });
}));
});
@@ -152,6 +163,7 @@
$scope.vm.remove();
$httpBackend.flush();
+ expect(Notification.success).toHaveBeenCalledWith({ message: ' Article deleted successfully!' });
expect($state.go).toHaveBeenCalledWith('admin.articles.list');
});
diff --git a/modules/articles/tests/client/admin.articles.client.routes.tests.js b/modules/articles/tests/client/admin.articles.client.routes.tests.js
index e699ae45..0a7873e4 100644
--- a/modules/articles/tests/client/admin.articles.client.routes.tests.js
+++ b/modules/articles/tests/client/admin.articles.client.routes.tests.js
@@ -53,7 +53,7 @@
});
it('Should have templateUrl', function () {
- expect(liststate.templateUrl).toBe('modules/articles/client/views/admin/list-articles.client.view.html');
+ expect(liststate.templateUrl).toBe('/modules/articles/client/views/admin/list-articles.client.view.html');
});
});
@@ -64,7 +64,7 @@
beforeEach(inject(function ($controller, $state, $templateCache) {
createstate = $state.get('admin.articles.create');
- $templateCache.put('modules/articles/client/views/admin/form-article.client.view.html', '');
+ $templateCache.put('/modules/articles/client/views/admin/form-article.client.view.html', '');
// Create mock article
mockArticle = new ArticlesService();
@@ -99,7 +99,7 @@
});
it('Should have templateUrl', function () {
- expect(createstate.templateUrl).toBe('modules/articles/client/views/admin/form-article.client.view.html');
+ expect(createstate.templateUrl).toBe('/modules/articles/client/views/admin/form-article.client.view.html');
});
});
@@ -110,7 +110,7 @@
beforeEach(inject(function ($controller, $state, $templateCache) {
editstate = $state.get('admin.articles.edit');
- $templateCache.put('modules/articles/client/views/admin/form-article.client.view.html', '');
+ $templateCache.put('/modules/articles/client/views/admin/form-article.client.view.html', '');
// Create mock article
mockArticle = new ArticlesService({
@@ -150,7 +150,7 @@
});
it('Should have templateUrl', function () {
- expect(editstate.templateUrl).toBe('modules/articles/client/views/admin/form-article.client.view.html');
+ expect(editstate.templateUrl).toBe('/modules/articles/client/views/admin/form-article.client.view.html');
});
xit('Should go to unauthorized route', function () {
diff --git a/modules/articles/tests/client/admin.list.articles.client.controller.tests.js b/modules/articles/tests/client/admin.list.articles.client.controller.tests.js
index e4e99dbb..90bd19f1 100644
--- a/modules/articles/tests/client/admin.list.articles.client.controller.tests.js
+++ b/modules/articles/tests/client/admin.list.articles.client.controller.tests.js
@@ -46,6 +46,10 @@
Authentication = _Authentication_;
ArticlesService = _ArticlesService_;
+ // Ignore parent template get on state transitions
+ $httpBackend.whenGET('/modules/articles/client/views/list-articles.client.view.html').respond(200, '');
+ $httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
+
// create mock article
mockArticle = new ArticlesService({
_id: '525a8422f6d0f87f0e407a33',
@@ -76,7 +80,7 @@
it('should send a GET request and return all articles', inject(function (ArticlesService) {
// Set POST response
- $httpBackend.expectGET('api/articles').respond(mockArticleList);
+ $httpBackend.expectGET('/api/articles').respond(mockArticleList);
$httpBackend.flush();
diff --git a/modules/articles/tests/client/articles.client.routes.tests.js b/modules/articles/tests/client/articles.client.routes.tests.js
index 650223d8..7b724a5c 100644
--- a/modules/articles/tests/client/articles.client.routes.tests.js
+++ b/modules/articles/tests/client/articles.client.routes.tests.js
@@ -53,7 +53,7 @@
});
it('Should have templateUrl', function () {
- expect(liststate.templateUrl).toBe('modules/articles/client/views/list-articles.client.view.html');
+ expect(liststate.templateUrl).toBe('/modules/articles/client/views/list-articles.client.view.html');
});
});
@@ -64,7 +64,7 @@
beforeEach(inject(function ($controller, $state, $templateCache) {
viewstate = $state.get('articles.view');
- $templateCache.put('modules/articles/client/views/view-article.client.view.html', '');
+ $templateCache.put('/modules/articles/client/views/view-article.client.view.html', '');
// create mock article
mockArticle = new ArticlesService({
@@ -104,12 +104,14 @@
});
it('Should have templateUrl', function () {
- expect(viewstate.templateUrl).toBe('modules/articles/client/views/view-article.client.view.html');
+ expect(viewstate.templateUrl).toBe('/modules/articles/client/views/view-article.client.view.html');
});
});
describe('Handle Trailing Slash', function () {
- beforeEach(inject(function ($state, $rootScope) {
+ beforeEach(inject(function ($state, $rootScope, $templateCache) {
+ $templateCache.put('/modules/articles/client/views/list-articles.client.view.html', '');
+
$state.go('articles.list');
$rootScope.$digest();
}));
@@ -119,7 +121,7 @@
$rootScope.$digest();
expect($location.path()).toBe('/articles');
- expect($state.current.templateUrl).toBe('modules/articles/client/views/list-articles.client.view.html');
+ expect($state.current.templateUrl).toBe('/modules/articles/client/views/list-articles.client.view.html');
}));
});
});
diff --git a/modules/articles/tests/client/list-articles.client.controller.tests.js b/modules/articles/tests/client/list-articles.client.controller.tests.js
index ee654f47..b5e37c9f 100644
--- a/modules/articles/tests/client/list-articles.client.controller.tests.js
+++ b/modules/articles/tests/client/list-articles.client.controller.tests.js
@@ -76,8 +76,10 @@
it('should send a GET request and return all articles', inject(function (ArticlesService) {
// Set POST response
- $httpBackend.expectGET('api/articles').respond(mockArticleList);
+ $httpBackend.expectGET('/api/articles').respond(mockArticleList);
+ // Ignore parent template get on state transition
+ $httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
$httpBackend.flush();
diff --git a/modules/articles/tests/server/admin.article.server.routes.tests.js b/modules/articles/tests/server/admin.article.server.routes.tests.js
index e56119da..0322dd14 100644
--- a/modules/articles/tests/server/admin.article.server.routes.tests.js
+++ b/modules/articles/tests/server/admin.article.server.routes.tests.js
@@ -170,7 +170,7 @@ describe('Article Admin CRUD tests', function () {
// Save a new article
agent.post('/api/articles')
.send(article)
- .expect(400)
+ .expect(422)
.end(function (articleSaveErr, articleSaveRes) {
// Set message assertion
(articleSaveRes.body.message).should.match('Title cannot be blank');
diff --git a/modules/chat/client/config/chat.client.routes.js b/modules/chat/client/config/chat.client.routes.js
index 4ec07d8b..f69aff61 100644
--- a/modules/chat/client/config/chat.client.routes.js
+++ b/modules/chat/client/config/chat.client.routes.js
@@ -11,7 +11,7 @@
$stateProvider
.state('chat', {
url: '/chat',
- templateUrl: 'modules/chat/client/views/chat.client.view.html',
+ templateUrl: '/modules/chat/client/views/chat.client.view.html',
controller: 'ChatController',
controllerAs: 'vm',
data: {
diff --git a/modules/chat/client/views/chat.client.view.html b/modules/chat/client/views/chat.client.view.html
index 3b9174c6..ad45efa5 100644
--- a/modules/chat/client/views/chat.client.view.html
+++ b/modules/chat/client/views/chat.client.view.html
@@ -18,7 +18,7 @@
-
+
diff --git a/modules/chat/tests/client/chat.client.controller.tests.js b/modules/chat/tests/client/chat.client.controller.tests.js
index 50139f68..693ceb3b 100644
--- a/modules/chat/tests/client/chat.client.controller.tests.js
+++ b/modules/chat/tests/client/chat.client.controller.tests.js
@@ -11,7 +11,8 @@
ChatController,
$timeout,
$state,
- Authentication;
+ Authentication,
+ $httpBackend;
// Load the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
@@ -39,12 +40,17 @@
});
describe('when user logged in', function () {
- beforeEach(inject(function ($controller, $rootScope, _Socket_, _Authentication_, _$timeout_, _$state_) {
+ beforeEach(inject(function ($controller, $rootScope, _$httpBackend_, _Socket_, _Authentication_, _$timeout_, _$state_) {
Authentication.user = {
name: 'user',
roles: ['user']
};
+ $httpBackend = _$httpBackend_;
+
+ // Ignore parent template get on state transitions
+ $httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
+
ChatController = $controller('ChatController as vm', {
$scope: $scope
});
diff --git a/modules/chat/tests/client/chat.client.routes.tests.js b/modules/chat/tests/client/chat.client.routes.tests.js
index bbd447ee..2f16e8db 100644
--- a/modules/chat/tests/client/chat.client.routes.tests.js
+++ b/modules/chat/tests/client/chat.client.routes.tests.js
@@ -4,7 +4,8 @@
describe('Chat Route Tests', function () {
// Initialize global variables
var $scope,
- Authentication;
+ Authentication,
+ $httpBackend;
// We can start by loading the main application module
beforeEach(module(ApplicationConfiguration.applicationModuleName));
@@ -34,27 +35,35 @@
});
it('Should have templateUrl', function () {
- expect(mainstate.templateUrl).toBe('modules/chat/client/views/chat.client.view.html');
+ expect(mainstate.templateUrl).toBe('/modules/chat/client/views/chat.client.view.html');
});
});
describe('Handle Trailing Slash', function () {
- beforeEach(inject(function ($state, $rootScope, _Authentication_) {
+ beforeEach(inject(function ($state, $rootScope, _$httpBackend_, _Authentication_) {
Authentication.user = {
name: 'user',
roles: ['user']
};
+ $httpBackend = _$httpBackend_;
+
+ // Ignore parent template get on state transition
+ $httpBackend.whenGET('/modules/chat/client/views/chat.client.view.html').respond(200);
+ $httpBackend.whenGET('/modules/core/client/views/home.client.view.html').respond(200, '');
+
$state.go('chat');
$rootScope.$digest();
}));
- it('Should remove trailing slash', inject(function ($state, $location, $rootScope) {
+ it('Should remove trailing slash', inject(function ($state, $location, $rootScope, $templateCache) {
+ $templateCache.put('/modules/chat/client/views/chat.client.view.html', '');
+
$location.path('chat/');
$rootScope.$digest();
expect($location.path()).toBe('/chat');
- expect($state.current.templateUrl).toBe('modules/chat/client/views/chat.client.view.html');
+ expect($state.current.templateUrl).toBe('/modules/chat/client/views/chat.client.view.html');
}));
});
diff --git a/modules/core/client/app/config.js b/modules/core/client/app/config.js
index 754a6cbc..a8a093a5 100644
--- a/modules/core/client/app/config.js
+++ b/modules/core/client/app/config.js
@@ -6,7 +6,7 @@
var service = {
applicationEnvironment: window.env,
applicationModuleName: applicationModuleName,
- applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'ngFileUpload', 'ngImgCrop'],
+ applicationModuleVendorDependencies: ['ngResource', 'ngAnimate', 'ngMessages', 'ui.router', 'ui.bootstrap', 'ngFileUpload', 'ngImgCrop', 'ui-notification'],
registerModule: registerModule
};
@@ -20,4 +20,17 @@
// Add the module to the AngularJS configuration file
angular.module(applicationModuleName).requires.push(moduleName);
}
+
+ // Angular-ui-notification configuration
+ angular.module('ui-notification').config(function(NotificationProvider) {
+ NotificationProvider.setOptions({
+ delay: 2000,
+ startTop: 20,
+ startRight: 10,
+ verticalSpacing: 20,
+ horizontalSpacing: 20,
+ positionX: 'right',
+ positionY: 'bottom'
+ });
+ });
}(window));
diff --git a/modules/core/client/app/init.js b/modules/core/client/app/init.js
index 45c5b06b..8ffaef33 100644
--- a/modules/core/client/app/init.js
+++ b/modules/core/client/app/init.js
@@ -10,17 +10,22 @@
.module(app.applicationModuleName)
.config(bootstrapConfig);
- function bootstrapConfig($compileProvider, $locationProvider, $httpProvider) {
- $locationProvider.html5Mode(true).hashPrefix('!');
+ bootstrapConfig.$inject = ['$compileProvider', '$locationProvider', '$httpProvider', '$logProvider'];
+
+ function bootstrapConfig($compileProvider, $locationProvider, $httpProvider, $logProvider) {
+ $locationProvider.html5Mode({
+ enabled: true,
+ requireBase: false
+ }).hashPrefix('!');
$httpProvider.interceptors.push('authInterceptor');
// Disable debug data for production environment
// @link https://docs.angularjs.org/guide/production
$compileProvider.debugInfoEnabled(app.applicationEnvironment !== 'production');
+ $logProvider.debugEnabled(app.applicationEnvironment !== 'production');
}
- bootstrapConfig.$inject = ['$compileProvider', '$locationProvider', '$httpProvider'];
// Then define the init function for starting up the application
angular.element(document).ready(init);
diff --git a/modules/core/client/config/core.client.routes.js b/modules/core/client/config/core.client.routes.js
index 6fc0d79f..c00f8807 100644
--- a/modules/core/client/config/core.client.routes.js
+++ b/modules/core/client/config/core.client.routes.js
@@ -29,29 +29,43 @@
$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',
- templateUrl: 'modules/core/client/views/404.client.view.html',
+ templateUrl: '/modules/core/client/views/404.client.view.html',
+ controller: 'ErrorController',
+ controllerAs: 'vm',
+ params: {
+ message: function($stateParams) {
+ return $stateParams.message;
+ }
+ },
data: {
ignoreState: true,
- pageTitle: 'Not-Found'
+ pageTitle: 'Not Found'
}
})
.state('bad-request', {
url: '/bad-request',
- templateUrl: 'modules/core/client/views/400.client.view.html',
+ templateUrl: '/modules/core/client/views/400.client.view.html',
+ controller: 'ErrorController',
+ controllerAs: 'vm',
+ params: {
+ message: function($stateParams) {
+ return $stateParams.message;
+ }
+ },
data: {
ignoreState: true,
- pageTitle: 'Bad-Request'
+ pageTitle: 'Bad Request'
}
})
.state('forbidden', {
url: '/forbidden',
- templateUrl: 'modules/core/client/views/403.client.view.html',
+ templateUrl: '/modules/core/client/views/403.client.view.html',
data: {
ignoreState: true,
pageTitle: 'Forbidden'
diff --git a/modules/core/client/controllers/error.client.controller.js b/modules/core/client/controllers/error.client.controller.js
new file mode 100644
index 00000000..5968f343
--- /dev/null
+++ b/modules/core/client/controllers/error.client.controller.js
@@ -0,0 +1,18 @@
+(function () {
+ 'use strict';
+
+ angular
+ .module('core')
+ .controller('ErrorController', ErrorController);
+
+ ErrorController.$inject = ['$stateParams'];
+
+ function ErrorController($stateParams) {
+ var vm = this;
+ vm.errorMessage = null;
+
+ // Display custom message if it was set
+ if ($stateParams.message) vm.errorMessage = $stateParams.message;
+ }
+}());
+
diff --git a/modules/core/client/directives/autofocus.client.directives.js b/modules/core/client/directives/auto-focus.client.directive.js
similarity index 100%
rename from modules/core/client/directives/autofocus.client.directives.js
rename to modules/core/client/directives/auto-focus.client.directive.js
diff --git a/modules/core/client/directives/show-errors.client.directives.js b/modules/core/client/directives/show-errors.client.directive.js
similarity index 100%
rename from modules/core/client/directives/show-errors.client.directives.js
rename to modules/core/client/directives/show-errors.client.directive.js
diff --git a/modules/core/client/services/interceptors/auth-interceptor.client.service.js b/modules/core/client/services/interceptors/auth-interceptor.client.service.js
index 29294028..89bae6f0 100644
--- a/modules/core/client/services/interceptors/auth-interceptor.client.service.js
+++ b/modules/core/client/services/interceptors/auth-interceptor.client.service.js
@@ -17,6 +17,9 @@
function responseError(rejection) {
if (!rejection.config.ignoreAuthModule) {
switch (rejection.status) {
+ case 400:
+ $injector.get('$state').go('bad-request', { message: rejection.data.message });
+ break;
case 401:
// Deauthenticate the global user
Authentication.user = null;
@@ -25,6 +28,13 @@
case 403:
$injector.get('$state').transitionTo('forbidden');
break;
+ case 404:
+ $injector.get('$state').go('not-found', { message: rejection.data.message });
+ break;
+ case -1: // Handle error if no response from server(Network Lost or Server not responding)
+ var Notification = $injector.get('Notification');
+ Notification.error({ message: 'No response received from server. Please try again later.', title: 'Error processing request!', delay: 5000 });
+ break;
}
}
// otherwise, default behaviour
diff --git a/modules/core/client/views/400.client.view.html b/modules/core/client/views/400.client.view.html
index efc28045..f1192d49 100644
--- a/modules/core/client/views/400.client.view.html
+++ b/modules/core/client/views/400.client.view.html
@@ -1,6 +1,9 @@
-
Bad Request
+
Error:
- You made a bad request
+
+ You made a bad request
diff --git a/modules/core/client/views/403.client.view.html b/modules/core/client/views/403.client.view.html
index 151968d5..320980c9 100644
--- a/modules/core/client/views/403.client.view.html
+++ b/modules/core/client/views/403.client.view.html
@@ -1,4 +1,6 @@
-
Forbidden
+
Error:
diff --git a/modules/core/client/views/404.client.view.html b/modules/core/client/views/404.client.view.html
index e8e6d82c..c19e9be6 100644
--- a/modules/core/client/views/404.client.view.html
+++ b/modules/core/client/views/404.client.view.html
@@ -1,5 +1,8 @@
-
Page Not Found
+
- Error: Page Not Found
+
+ Page Not Found
diff --git a/modules/core/client/views/header.client.view.html b/modules/core/client/views/header.client.view.html
index c09e9770..d35f961d 100644
--- a/modules/core/client/views/header.client.view.html
+++ b/modules/core/client/views/header.client.view.html
@@ -32,7 +32,7 @@