diff --git a/client/js/api.js b/client/js/api.js
index 497525e..24d4a7a 100644
--- a/client/js/api.js
+++ b/client/js/api.js
@@ -2,14 +2,13 @@
const request = require('superagent');
const config = require('./config.js');
-const EventListener = require('./event_listener.js');
+const events = require('./events.js');
class Api {
constructor() {
this.user = null;
this.userName = null;
this.userPassword = null;
- this.authenticated = new EventListener();
}
get(url) {
@@ -70,11 +69,11 @@ class Api {
.then(response => {
this.user = response.user;
resolve();
- this.authenticated.fire();
+ events.notify(events.Authentication);
}).catch(response => {
reject(response.description);
this.logout();
- this.authenticated.fire();
+ events.notify(events.Authentication);
});
});
}
@@ -83,7 +82,7 @@ class Api {
this.user = null;
this.userName = null;
this.userPassword = null;
- this.authenticated.fire();
+ events.notify(events.Authentication);
}
isLoggedIn() {
diff --git a/client/js/controllers/auth_controller.js b/client/js/controllers/auth_controller.js
index 04cfec5..d68cdb8 100644
--- a/client/js/controllers/auth_controller.js
+++ b/client/js/controllers/auth_controller.js
@@ -3,6 +3,7 @@
const cookies = require('js-cookie');
const page = require('page');
const api = require('../api.js');
+const events = require('../events.js');
const topNavController = require('../controllers/top_nav_controller.js');
const LoginView = require('../views/login_view.js');
const PasswordResetView = require('../views/password_reset_view.js');
@@ -11,16 +12,21 @@ class AuthController {
constructor() {
this.loginView = new LoginView();
this.passwordResetView = new PasswordResetView();
+ }
- const auth = cookies.getJSON('auth');
- if (auth && auth.user && auth.password) {
- api.login(auth.user, auth.password).catch(errorMessage => {
- page('/');
- this.loginView.notifyError(
- 'An error happened while trying to log you in: ' +
- errorMessage);
- });
- }
+ login() {
+ return new Promise((resolve, reject) => {
+ const auth = cookies.getJSON('auth');
+ if (auth && auth.user && auth.password) {
+ api.login(auth.user, auth.password)
+ .then(resolve)
+ .catch(errorMessage => {
+ reject(errorMessage);
+ });
+ } else {
+ resolve();
+ }
+ });
}
registerRoutes() {
@@ -51,7 +57,7 @@ class AuthController {
options);
resolve();
page('/');
- this.loginView.notifySuccess('Logged in');
+ events.notify(events.Success, 'Logged in');
}).catch(errorMessage => { reject(errorMessage); });
});
}});
@@ -61,7 +67,7 @@ class AuthController {
api.logout();
cookies.remove('auth');
page('/');
- this.loginView.notifySuccess('Logged out');
+ events.notify(events.Success, 'Logged out');
}
passwordResetRoute() {
@@ -89,15 +95,15 @@ class AuthController {
cookies.set(
'auth', {'user': name, 'password': password}, {});
page('/');
- this.passwordResetView.notifySuccess(
+ events.notify(events.Success,
'New password: ' + password);
}).catch(errorMessage => {
page('/');
- this.passwordResetView.notifyError(errorMessage);
+ events.notify(events.Error, errorMessage);
});
}).catch(response => {
page('/');
- this.passwordResetView.notifyError(response.description);
+ events.notify(events.Error, response.description);
});
}
}
diff --git a/client/js/controllers/top_nav_controller.js b/client/js/controllers/top_nav_controller.js
index a6da22f..9ee7f07 100644
--- a/client/js/controllers/top_nav_controller.js
+++ b/client/js/controllers/top_nav_controller.js
@@ -1,6 +1,7 @@
'use strict';
const api = require('../api.js');
+const events = require('../events.js');
const TopNavView = require('../views/top_nav_view.js');
class NavigationItem {
@@ -31,11 +32,13 @@ class TopNavController {
'help': new NavigationItem('E', 'Help', '/help'),
};
- api.authenticated.listen(() => {
- this.updateVisibility();
- this.topNavView.render(this.items, this.activeItem);
- this.topNavView.activate(this.activeItem);
- });
+ events.listen(
+ events.Authentication,
+ () => {
+ this.updateVisibility();
+ this.topNavView.render(this.items, this.activeItem);
+ this.topNavView.activate(this.activeItem);
+ });
this.updateVisibility();
this.topNavView.render(this.items, this.activeItem);
diff --git a/client/js/controllers/users_controller.js b/client/js/controllers/users_controller.js
index b7d3e2b..ce23f70 100644
--- a/client/js/controllers/users_controller.js
+++ b/client/js/controllers/users_controller.js
@@ -3,6 +3,7 @@
const cookies = require('js-cookie');
const page = require('page');
const api = require('../api.js');
+const events = require('../events.js');
const topNavController = require('../controllers/top_nav_controller.js');
const RegistrationView = require('../views/registration_view.js');
const UserView = require('../views/user_view.js');
@@ -50,7 +51,7 @@ class UsersController {
cookies.set('auth', {'user': name, 'password': password});
resolve();
page('/');
- this.registrationView.notifySuccess('Welcome aboard!');
+ events.notify(events.Success, 'Welcome aboard!');
}).catch(response => {
reject(response.description);
});
@@ -74,7 +75,7 @@ class UsersController {
next();
}).catch(response => {
this.userView.empty();
- this.userView.notifyError(response.description);
+ events.notify(events.Error, response.description);
});
}
}
diff --git a/client/js/event_listener.js b/client/js/event_listener.js
deleted file mode 100644
index e7eebff..0000000
--- a/client/js/event_listener.js
+++ /dev/null
@@ -1,24 +0,0 @@
-class EventListener {
- constructor() {
- this.listeners = [];
- }
-
- listen(callback) {
- this.listeners.push(callback);
- }
-
- unlisten(callback) {
- const index = this.listeners.indexOf(callback);
- if (index !== -1) {
- this.listeners.splice(index, 1);
- }
- }
-
- fire(data) {
- for (let listener of this.listeners) {
- listener(data);
- }
- }
-}
-
-module.exports = EventListener;
diff --git a/client/js/events.js b/client/js/events.js
new file mode 100644
index 0000000..8fb42d4
--- /dev/null
+++ b/client/js/events.js
@@ -0,0 +1,28 @@
+'use strict';
+
+let listeners = [];
+
+function listen(messageClass, handler) {
+ if (!(messageClass in listeners)) {
+ listeners[messageClass] = [];
+ }
+ listeners[messageClass].push(handler);
+}
+
+function notify(messageClass, message) {
+ if (!(messageClass in listeners)) {
+ return;
+ }
+ for (let handler of listeners[messageClass]) {
+ handler(message);
+ }
+}
+
+module.exports = {
+ Success: 1,
+ Error: 2,
+ Authentication: 3,
+
+ notify: notify,
+ listen: listen,
+};
diff --git a/client/js/main.js b/client/js/main.js
index b3706db..03b73cc 100644
--- a/client/js/main.js
+++ b/client/js/main.js
@@ -3,18 +3,29 @@
require('./util/handlebars-helpers.js');
let controllers = [];
+const authController = require('./controllers/auth_controller.js');
+controllers.push(authController);
controllers.push(require('./controllers/posts_controller.js'));
controllers.push(require('./controllers/users_controller.js'));
controllers.push(require('./controllers/help_controller.js'));
-controllers.push(require('./controllers/auth_controller.js'));
controllers.push(require('./controllers/comments_controller.js'));
controllers.push(require('./controllers/history_controller.js'));
controllers.push(require('./controllers/tags_controller.js'));
controllers.push(require('./controllers/home_controller.js'));
+const events = require('./events.js');
const page = require('page');
for (let controller of controllers) {
controller.registerRoutes();
}
-page();
+
+authController.login().then(() => {
+ page();
+}).catch(errorMessage => {
+ page();
+ page('/');
+ events.notify(
+ events.Error,
+ 'An error happened while trying to log you in: ' + errorMessage);
+});
diff --git a/client/js/views/base_view.js b/client/js/views/base_view.js
index c805d8a..c5ed465 100644
--- a/client/js/views/base_view.js
+++ b/client/js/views/base_view.js
@@ -1,13 +1,32 @@
'use strict';
const handlebars = require('handlebars');
+const events = require('../events.js');
+const contentHolder = document.getElementById('content-holder');
+
+function messageHandler(message, className) {
+ const messagesHolder = contentHolder.querySelector('.messages');
+ if (!messagesHolder) {
+ alert(message);
+ return;
+ }
+ /* TODO: animate this */
+ const node = document.createElement('div');
+ node.innerHTML = message.replace(/\n/g, '
');
+ node.classList.add('message');
+ node.classList.add(className);
+ messagesHolder.appendChild(node);
+}
+
+events.listen(events.Success, msg => { messageHandler(msg, 'success'); });
+events.listen(events.Error, msg => { messageHandler(msg, 'error'); });
// fix iterating over NodeList in Chrome and Opera
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
class BaseView {
constructor() {
- this.contentHolder = document.getElementById('content-holder');
+ this.contentHolder = contentHolder;
}
getTemplate(templatePath) {
@@ -20,24 +39,6 @@ class BaseView {
return handlebars.compile(templateText);
}
- notifyError(message) {
- this.notify(message, 'error');
- }
-
- notifySuccess(message) {
- this.notify(message, 'success');
- }
-
- notify(message, className) {
- const messagesHolder = this.contentHolder.querySelector('.messages');
- /* TODO: animate this */
- const node = document.createElement('div');
- node.innerHTML = message.replace(/\n/g, '
');
- node.classList.add('message');
- node.classList.add(className);
- messagesHolder.appendChild(node);
- }
-
clearMessages() {
const messagesHolder = this.contentHolder.querySelector('.messages');
/* TODO: animate that */
diff --git a/client/js/views/login_view.js b/client/js/views/login_view.js
index 3708e65..1d963e5 100644
--- a/client/js/views/login_view.js
+++ b/client/js/views/login_view.js
@@ -1,6 +1,7 @@
'use strict';
const config = require('../config.js');
+const events = require('../events.js');
const BaseView = require('./base_view.js');
class LoginView extends BaseView {
@@ -34,7 +35,7 @@ class LoginView extends BaseView {
})
.catch(errorMessage => {
this.enableForm(form);
- this.notifyError(errorMessage);
+ events.notify(events.Error, errorMessage);
});
});
}
diff --git a/client/js/views/password_reset_view.js b/client/js/views/password_reset_view.js
index 23b17ee..0bba9c8 100644
--- a/client/js/views/password_reset_view.js
+++ b/client/js/views/password_reset_view.js
@@ -1,5 +1,6 @@
'use strict';
+const events = require('../events.js');
const BaseView = require('./base_view.js');
class PasswordResetView extends BaseView {
@@ -22,13 +23,14 @@ class PasswordResetView extends BaseView {
options
.proceed(userNameOrEmailField.value)
.then(() => {
- this.notifySuccess(
+ events.notify(
+ events.Success,
'E-mail has been sent. To finish the procedure, ' +
'please click the link it contains.');
})
.catch(errorMessage => {
this.enableForm(form);
- this.notifyError(errorMessage);
+ events.notify(events.Error, errorMessage);
});
});
}
diff --git a/client/js/views/registration_view.js b/client/js/views/registration_view.js
index 1a1583e..597ade9 100644
--- a/client/js/views/registration_view.js
+++ b/client/js/views/registration_view.js
@@ -1,6 +1,7 @@
'use strict';
const config = require('../config.js');
+const events = require('../events.js');
const BaseView = require('./base_view.js');
class RegistrationView extends BaseView {
@@ -11,12 +12,13 @@ class RegistrationView extends BaseView {
render(options) {
this.showView(this.template());
- const form = document.querySelector('#content-holder form');
- this.decorateValidator(form);
- const userNameField = document.getElementById('user-name');
- const passwordField = document.getElementById('user-password');
- const emailField = document.getElementById('user-email');
+ const form = this.contentHolder.querySelector('form');
+ const userNameField = this.contentHolder.querySelector('#user-name');
+ const passwordField = this.contentHolder.querySelector('#user-password');
+ const emailField = this.contentHolder.querySelector('#user-email');
+
+ this.decorateValidator(form);
userNameField.setAttribute('pattern', config.userNameRegex);
passwordField.setAttribute('pattern', config.passwordRegex);
@@ -34,7 +36,7 @@ class RegistrationView extends BaseView {
})
.catch(errorMessage => {
this.enableForm(form);
- this.notifyError(errorMessage);
+ events.notify(events.Error, errorMessage);
});
});
}