diff --git a/modules/App.js b/modules/App.js index 3775745..f96becf 100644 --- a/modules/App.js +++ b/modules/App.js @@ -1,14 +1,12 @@ var module = angular.module('App', ['ui.router', 'App.Authentication', 'App.Guest']); -module.config( ($urlRouterProvider, $rootScope) => { - +module.config(function($urlRouterProvider, $rootScope) { // Default URL if no matches - $urlRouterProvider.otherwise("/projects"); + $urlRouterProvider.otherwise('/projects'); // Global catching of uiRouter errors (for development) $rootScope.$on('stateChangeError', (event, toState, toParams, fromState, fromParams, error) => { console.log( event, toState, toParams, fromState, fromParams, error ); }); - }); diff --git a/modules/Authentication/Authenticated.js b/modules/Authentication/Authenticated.js index d6402a2..87769d9 100644 --- a/modules/Authentication/Authenticated.js +++ b/modules/Authentication/Authenticated.js @@ -5,31 +5,29 @@ Authentication Module Most of the actual app is located under here. This abstract module primarily tackles authenticating the user */ -var module = angular.module('App.Authenticated', ['ui.router']) +var module = angular.module('App.Authenticated', ['ui.router']); -module.config(function($stateProvider) +module.config(function($stateProvider) { $stateProvider.state('authenticated', { templateUrl: 'modules/Authenticated/Authenticated.html', abstract: true, resolve: { - user: (User, Authentication, $state, $q) => { - return Authentication.checkCredentials().then((response) => { - return new User(response.data); - }, (error) => { - // must return a rejected promise in order to stay in rejected-mode - return $q.reject( $state.go('login') ); - }); - }, - // layout variable for breadcrumb nav (populated by children) - breadcrumbs: () => { - return []; - } + user: (User, Authentication, $state, $q) => { + return Authentication.checkCredentials() + .then( + (response) => new User(response.data), + // must return a rejected promise in order to stay in rejected-mode + (error) => $q.reject($state.go('login')) + ); + }, + // layout variable for breadcrumb nav (populated by children) + breadcrumbs: () => [] }, - onEnter: (user) => { - user.open(); + onEnter(user) { + user.open(); }, - onExit: (user) => { - user.close(); + onExit(user) { + user.close(); } }); }); diff --git a/modules/Authentication/Login.js b/modules/Authentication/Login.js index 07ab921..f54166e 100644 --- a/modules/Authentication/Login.js +++ b/modules/Authentication/Login.js @@ -9,16 +9,14 @@ $modal is part of ui.bootstrap // Tracks the previous location and allows you to redirect back to that location var previousLocation; -var module = angular.module('App.Login', ['ui.router', 'ui.bootstrap']) +var module = angular.module('App.Login', ['ui.router', 'ui.bootstrap']); -module.config( ($stateProvider) => { +module.config(function($stateProvider) { $stateProvider.state('login', { parent: 'guest', url: '/login', resolve: { - user: (User) => { - return new User(); - }, + user: (User) => new User(), redirect: ($location) => { return () => { // Note we're returning a function to be called later, that has the redirect info pre-filled @@ -26,23 +24,21 @@ module.config( ($stateProvider) => { $location.path( previousLocation ); }; }, - modal: ($modal) => { - return $modal.open({ - templateUrl: "modules/Authentication/Login.html", - controller: 'Login', - }); - } + modal: ($modal) => $modal.open({ + templateUrl: 'modules/Authentication/Login.html', + controller: 'Login', + }) }, - onExit: (modal) => { + onExit(modal) { modal.close(); } }); }); -module.run( ($rootScope, $location) => { +module.run(function($rootScope, $location) { $rootScope.$on('$stateChangeStart', (event, toState, toParams, fromState, fromParams) => { // TODO: Change to state code - previousLocation = $location.path() + previousLocation = $location.path(); }); }); @@ -50,10 +46,7 @@ module.controller('Login', ($scope, UserObject, Authentication, user, redirect) $scope.user = user; $scope.login = () => { - Authentication.login($scope.user, $scope.rememberMe).then( () => { - redirect(); - }, (response) => { - $scope.error = response; - }); + Authentication.login($scope.user, $scope.rememberMe) + .then( redirect, (response) => $scope.error = response); }; }); diff --git a/modules/Guest/Guest.js b/modules/Guest/Guest.js index 5b3f05e..6ef85f5 100644 --- a/modules/Guest/Guest.js +++ b/modules/Guest/Guest.js @@ -1,6 +1,6 @@ var module = angular.module('App.Guest', ['ui.router']); -module.config( ($stateProvider) => { +module.config(function($stateProvider) { $stateProvider.state('guest', { templateUrl: 'modules/Guest/Guest.html', abstract: true diff --git a/modules/Object.js b/modules/Object.js index 2094e2a..107e7f5 100644 --- a/modules/Object.js +++ b/modules/Object.js @@ -1,12 +1,17 @@ var module = angular.module('App'); module.factory('BaseObject', () => { - class BaseObject { - constructor(data = {}) { - for (property in data) { - this[property] = data[property]; - } + /* + Creates a new instance from JSON. + */ + static new(data) { + return new this(data); + } + + + constructor(data) { + Object.assign(this, data); } /* diff --git a/modules/Paginator.js b/modules/Paginator.js index b0c5455..083d331 100644 --- a/modules/Paginator.js +++ b/modules/Paginator.js @@ -1,8 +1,8 @@ /** * Paginator - Simple paginator utility example that abstracts logic in a controllable pattern - * + * * @param paginate {function} Query function that takes paginationOptions - * + * * @example * resolve: { * // Prepares the paginator @@ -15,7 +15,7 @@ * return paginator.next(); * } * } - * + * * @example * resolve: { * taskPaginator: function(Paginator, Task, $stateParams) { @@ -29,9 +29,7 @@ * } */ angular.module('App').factory('Paginator', function($q){ - class Paginator { - constructor(paginate, options) { this.paginate = paginate; this.items = []; @@ -42,24 +40,26 @@ angular.module('App').factory('Paginator', function($q){ offset: 0 }, options); } - + next() { if (this.hasMore) { this.loading = true; - - return this.paginate(this.options).then((response) => { - //If the results are less than the required limit then the results are finished - this.hasMore = response.data.results.length >= this.options.limit; - - this.items = this.items.concat(response.data.results); - this.options.offset = this.items.length; - return this.items; - }).finally(() => this.loading = false); + + return this.paginate(this.options) + .then((response) => { + //If the results are less than the required limit then the results are finished + this.hasMore = response.data.results.length >= this.options.limit; + + this.items = this.items.concat(response.data.results); + this.options.offset = this.items.length; + + return this.items; + }) + .finally(() => this.loading = false); } else { return $q.when(this.items); } } - } return Paginator; diff --git a/modules/Project/Project.js b/modules/Project/Project.js index 4496b4d..4d47a1b 100644 --- a/modules/Project/Project.js +++ b/modules/Project/Project.js @@ -4,39 +4,35 @@ Project Module */ var module = angular.module('App.Project', ['ui.router', 'ui.bootstrap']) -module.config( ($stateProvider) => { +module.config(function($stateProvider) { $stateProvider.state( 'projects', { parent: 'authenticated', url: '/projects', templateUrl: 'modules/Project/Projects.html', controller: 'Projects', resolve: { - projects: (authenticatedUser, Project) => { - return Project.list(authenticatedUser.id); - } + projects: (authenticatedUser, Project) => Project.list(authenticatedUser.id) }, // `breadcrumbs` resolved in `authenticated` state - onEnter: function(breadcrumbs) { + onEnter(breadcrumbs) { breadcrumbs.push({ label: 'Projects', sref: 'projects' }); }, - onExit: function(breadcrumbs) { + onExit(breadcrumbs) { breadcrumbs.pop(); }, }); $stateProvider.state( 'projects.new', { url: '/new', // /projects/new (state must be defined BEFORE /:projectId) resolve: { - project: (authenticatedUser, Project) => { - return new Project({ user_id: authenticatedUser.id }); - } + project: (authenticatedUser, Project) => new Project({ user_id: authenticatedUser.id }) }, templateUrl: 'modules/Project/Form.html', controller: 'ProjectForm', // `breadcrumbs` resolved in `authenticated` state - onEnter: function(breadcrumbs) { + onEnter(breadcrumbs) { breadcrumbs.push({ label: 'New', sref: 'projects.new' }); }, - onExit: function(breadcrumbs) { + onExit(breadcrumbs) { breadcrumbs.pop(); } }); @@ -54,15 +50,13 @@ module.config( ($stateProvider) => { } }, resolve: { - project: ($stateParams, Project) => { - return Project.get($stateParams.projectId); - } + project: ($stateParams, Project) => Project.get($stateParams.projectId) }, - onEnter: (project, breadcrumbs) => { + onEnter(project, breadcrumbs) { project.open(); breadcrumbs.push({ label: project.name, sref: 'project' }); // Params inferred when going up }, - onExit: (project, breadcrumbs) => { + onExit(project, breadcrumbs) { project.close(); breadcrumbs.pop(); } @@ -92,37 +86,29 @@ module.controller( 'ProjectForm', ($scope, project) => { module.factory('ProjectObject', (BaseObject, $http) => { class Project extends BaseObject { - static list(userId) { - return $http.get('/api/projects', { params: { user_id: userId } }).then( (response) => { - return response.data.map( (project) => { - return new Project(project); - }); - }); + return $http.get('/api/projects', { params: { user_id: userId } }) + .then( (response) => response.data.map(Project.new)); } - + static get(id) { - return $http.get('/api/projects/' + id).then( (response) => { - return new Project(response.data); - }); + return $http.get(`/api/projects/${id}`) + .then( (response) => new Project(response.data)); } - + create() { - return $http.post('/api/projects', this ).then( (response) => { - this.id = response.data.id; - return response.data; - }); + return $http.post('/api/projects', this ) + .then( (response) => { + this.id = response.data.id; + return response.data; + }); } update() { - return $http.put('/api/projects/' + this.id, this ); - } - - close() { - super.close(); + return $http.put(`/api/projects/${this.id}`, this); } } - return ProjectObject; + return Project; }); diff --git a/modules/Socket.js b/modules/Socket.js index 89970e7..ed84183 100644 --- a/modules/Socket.js +++ b/modules/Socket.js @@ -1,77 +1,66 @@ var module = angular.module('App'); module.factory('Socket', (Stream, $rootScope) => { - - class Socket { - constructor(url) { - this.url = url; - - this.queue = []; - - this.open(); - } - - - setupQueryStream() { - // opening a socket === async and a queue may form - this.socket.onopen = () => { - this.flush(); - } - - if (!this.queryStream) { - this.queryStream = new Stream(); - - this.queryStream.listen( (data) => { - // Stringify now in case data changes while waiting in this.queue - data = JSON.stringify(data); - - if (this.socket.readyState === WebSocket.OPEN) { - this.send(data); - } else { - this.queue.push(data); - if (this.socket.readyState === WebSocket.CLOSE) - this.open(); - } - }); - - } - } - - - setupEventStream() { - this.eventStream = this.eventStream || new Stream(); - - this.socket.onmesssage = (data) => { - // Now Entering AngularJS... - $rootScope.$apply( () => { - this.eventStream.push( JSON.parse(data) ); - }); - } - } - - - close() { - this.socket.close(); - } - - open() { - this.socket = new WebSocket(this.url); - this.setupQueryStream(); - this.setupEventStream(); - } - - - send(data) { - return this.socket.send( data ); - } - - flush() { - while (item = this.queue.pop()) { - this.send(item); - } - } - } - - // Singleton - return new Socket('/api'); + class Socket { + constructor(url) { + this.url = url; + this.queue = []; + this.open(); + } + + setupQueryStream() { + // opening a socket === async and a queue may form + this.socket.onopen = () => this.flush(); + + if (!this.queryStream) { + this.queryStream = new Stream(); + + this.queryStream.listen( (data) => { + // Stringify now in case data changes while waiting in this.queue + data = JSON.stringify(data); + + if (this.socket.readyState === WebSocket.OPEN) { + this.send(data); + } else { + this.queue.push(data); + if (this.socket.readyState === WebSocket.CLOSE) + this.open(); + } + }); + + } + } + + setupEventStream() { + this.eventStream = this.eventStream || new Stream(); + + this.socket.onmesssage = (data) => { + // Now Entering AngularJS... + $rootScope.$apply( () => this.eventStream.push( JSON.parse(data) )); + }; + } + + close() { + this.socket.close(); + } + + open() { + this.socket = new WebSocket(this.url); + this.setupQueryStream(); + this.setupEventStream(); + } + + send(data) { + return this.socket.send( data ); + } + + flush() { + while (item = this.queue.pop()) { + this.send(item); + } + } + } + + // Singleton + return new Socket('/api'); }); diff --git a/modules/Stream.js b/modules/Stream.js index d6f1b07..1738a73 100644 --- a/modules/Stream.js +++ b/modules/Stream.js @@ -1,7 +1,6 @@ var module = angular.module('App'); module.factory('Stream', () => { - class Stream { constructor() { this.listeners = []; @@ -13,23 +12,19 @@ module.factory('Stream', () => { // unsubscriber return () => { - this.listeners = this.listeners.filter( (item) => { - return item !== listener; - }); + this.listeners = this.listeners.filter( (item) => item !== listener ); }; } push(data) { // allow listeners to modify the data (use sparingly) - changeData = (newValue) => { - data = newValue; - } + let changeData = (newValue) => data = newValue; - for (listener in this.listeners) { + for (let listener in this.listeners) { data = this.listeners[listener](data, changeData) || data; } - for (childStream in this.children) { + for (let childStream in this.children) { this.children[childStream].push(data); } } @@ -45,9 +40,7 @@ module.factory('Stream', () => { // unsubscriber return () => { - this.children = this.children.filter( (child) => { - stream != child; - }); + this.children = this.children.filter( (child) => stream !== child); }; } } diff --git a/modules/Task/Task.js b/modules/Task/Task.js index 25d6c85..73a215a 100644 --- a/modules/Task/Task.js +++ b/modules/Task/Task.js @@ -2,19 +2,16 @@ Task Module ============ */ -var module = angular.module('App.Task', ['App.Project', 'ui.router']) +var module = angular.module('App.Task', ['App.Project', 'ui.router']); module.config( ($stateProvider) => { - $stateProvider.state( 'tasks', { parent: 'project', url: '/tasks', templateUrl: 'modules/Task/Tasks.html', controller: 'Tasks', resolve: { - tasks: (Task, project) => { - return Task.list(project.id); - } + tasks: (Task, project) => Task.list(project.id) }, // breadcrumbs resolved in authenticated state onEnter: function(breadcrumbs) { @@ -28,9 +25,7 @@ module.config( ($stateProvider) => { $stateProvider.state( 'tasks.new', { url: '/new', // /projects/:projectId/tasks/new (state must be defined BEFORE /:taskId) resolve: { - task: (project) => { - return project.newTask(); - } + task: (project) => project.newTask() }, templateUrl: 'modules/Task/Form.html', controller: 'TaskForm', @@ -42,6 +37,7 @@ module.config( ($stateProvider) => { breadcrumbs.pop(); } }); + $stateProvider.state( 'task', { parent: 'tasks', url: '/:taskId', // /projects/:projectId/tasks/:taskId (state must be defined AFTER /new) @@ -56,15 +52,13 @@ module.config( ($stateProvider) => { } }, resolve: { - task: (project, $stateParams) => { - return project.getTask($stateParams.taskId); - } + task: (project, $stateParams) => project.getTask($stateParams.taskId) }, - onEnter: (task, breadcrumbs) => { + onEnter: function(task, breadcrumbs) { task.open(); breadcrumbs.push({ label: task.name, sref: 'task' }); }, - onExit: (task, breadcrumbs) => { + onExit: function(task, breadcrumbs) { task.close(); breadcrumbs.pop(); } @@ -81,7 +75,6 @@ module.controller( 'Tasks', ($scope, tasks, project) => { $scope.tasks = project; }); - module.controller( 'Task', ($scope, task) => { $scope.task = task; }); @@ -98,26 +91,24 @@ module.controller( 'TaskForm', ($scope, task) => { module.factory( 'Task', (BaseObject, $http) => { class Task extends BaseObject { - static list(projectId) { - return $http.get('/api/tasks', { params: { project_id: projectId } }).then( (response) => { - return response.data.map( (task) => { - return new Task(task); - }); - }); + return $http.get('/api/tasks', { params: { project_id: projectId } }) + .then( (response) => response.data.map(Task.new)); } - - + + create() { - return $http.post('/api/tasks', this).then( (response) => { - this.id = response.data.id; - return response.data; - }); + return $http.post('/api/tasks', this) + .then( (response) => { + this.id = response.data.id; + return response.data; + }); } update() { - return $http.put('/api/tasks/' + this.id); + return $http.put(`/api/tasks/${this.id}`, this); } } + return Task; }); diff --git a/modules/User/User.js b/modules/User/User.js index eece446..0e4db9c 100644 --- a/modules/User/User.js +++ b/modules/User/User.js @@ -7,16 +7,14 @@ ui.validate is part of angular-ui-validate */ var module = angular.module('App.User', ['ui.router', 'ui.validate']); -module.config( ($stateProvider) => { +module.config(function($stateProvider) { $stateProvider.state( 'users', { parent: 'admin', url: '/users', templateUrl: 'modules/User/Users.html', controller: 'Users', resolve: { - users: (User) => { - return User.list(); - } + users: (User) => User.list() } }); @@ -26,12 +24,8 @@ module.config( ($stateProvider) => { url: '/register', resolve: { // shared & accessible from all steps (and their controllers if necessary) - user: (User) => { - return new User(); - }, - wizard: (user, RegistrationWizard) => { - return new RegistrationWizard(user); - } + user: (User) => new User(), + wizard: (user, RegistrationWizard) => new RegistrationWizard(user) }, templateUrl: 'modules/User/Register.html', controller: 'UserForm' @@ -61,7 +55,7 @@ module.config( ($stateProvider) => { // prevent accessing step prematurely validate: (wizard, $state) => { if (!wizard.stepsCompleted(2)) - $state.go('register.step2') + $state.go('register.step2'); } } }); @@ -78,20 +72,16 @@ module.controller( 'UserForm', ($scope, user, wizard) => { module.factory( 'User', (BaseObject, $http) => { class User extends BaseObject { - static list() { - return $http.get('/api/users').then( (response) => { - return response.data.map( (user) => { - return new User(user); - }); - }); + return $http.get('/api/users') + .then( (response) => response.data.map(User.new)); } - - + + // checks validity of the property (probably should be in BaseObject) validate(property) { - if (!rules[property]) - return true + if (!User.rules[property]) + return true; var pattern = new RegExp(User.rules[property]); return pattern.test(this[property]);