diff --git a/client/html/endless_pager.hbs b/client/html/endless_pager.hbs
index a47cd96..6870f9a 100644
--- a/client/html/endless_pager.hbs
+++ b/client/html/endless_pager.hbs
@@ -1,5 +1,5 @@
diff --git a/client/js/controllers/page_controller.js b/client/js/controllers/page_controller.js
index 8c75c83..7b589a3 100644
--- a/client/js/controllers/page_controller.js
+++ b/client/js/controllers/page_controller.js
@@ -9,6 +9,7 @@ class PageController {
constructor() {
events.listen(events.SettingsChange, () => {
this.update();
+ return true;
});
this.update();
}
diff --git a/client/js/controllers/tags_controller.js b/client/js/controllers/tags_controller.js
index 931a32c..b49bffd 100644
--- a/client/js/controllers/tags_controller.js
+++ b/client/js/controllers/tags_controller.js
@@ -40,7 +40,7 @@ class TagsController {
Promise.all(promises).then(
() => {
events.notify(events.TagsChange);
- events.notify(events.Success, 'Changes saved successfully');
+ events.notify(events.Success, 'Changes saved.');
},
response => {
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 51d3002..cab1a4d 100644
--- a/client/js/controllers/top_nav_controller.js
+++ b/client/js/controllers/top_nav_controller.js
@@ -43,7 +43,9 @@ class TopNavController {
this.topNavView.activate(this.activeItem);
};
- events.listen(events.Authentication, rerender);
+ events.listen(
+ events.Authentication,
+ () => { rerender(); return true; });
rerender();
}
diff --git a/client/js/controllers/users_controller.js b/client/js/controllers/users_controller.js
index c824eb3..529f490 100644
--- a/client/js/controllers/users_controller.js
+++ b/client/js/controllers/users_controller.js
@@ -195,25 +195,23 @@ class UsersController {
_delete(user) {
const isLoggedIn = api.isLoggedIn(user);
- return new Promise((resolve, reject) => {
- api.delete('/user/' + user.name)
- .then(response => {
- if (isLoggedIn) {
- api.forget();
- api.logout();
- }
- resolve();
- if (api.hasPrivilege('users:list')) {
- page('/users');
- } else {
- page('/');
- }
- events.notify(events.Success, 'Account deleted');
- }, response => {
- reject();
- events.notify(events.Error, response.description);
- });
- });
+ return api.delete('/user/' + user.name)
+ .then(response => {
+ if (isLoggedIn) {
+ api.forget();
+ api.logout();
+ }
+ if (api.hasPrivilege('users:list')) {
+ page('/users');
+ } else {
+ page('/');
+ }
+ events.notify(events.Success, 'Account deleted.');
+ return Promise.resolve();
+ }, response => {
+ events.notify(events.Error, response.description);
+ return Promise.reject();
+ });
}
_show(user, section) {
diff --git a/client/js/events.js b/client/js/events.js
index 0493c3b..0dd010a 100644
--- a/client/js/events.js
+++ b/client/js/events.js
@@ -1,34 +1,48 @@
'use strict';
-let listeners = [];
+let pendingMessages = new Map();
+let listeners = new Map();
function unlisten(messageClass) {
- listeners[messageClass] = [];
+ listeners.set(messageClass, []);
}
function listen(messageClass, handler) {
- if (!(messageClass in listeners)) {
- listeners[messageClass] = [];
+ if (pendingMessages.has(messageClass)) {
+ let newPendingMessages = [];
+ for (let message of pendingMessages.get(messageClass)) {
+ if (!handler(message)) {
+ newPendingMessages.push(message);
+ }
+ }
+ pendingMessages.set(messageClass, newPendingMessages);
}
- listeners[messageClass].push(handler);
+ if (!listeners.has(messageClass)) {
+ listeners.set(messageClass, []);
+ }
+ listeners.get(messageClass).push(handler);
}
function notify(messageClass, message) {
- if (!(messageClass in listeners)) {
+ if (!listeners.has(messageClass) || !listeners.get(messageClass).length) {
+ if (!pendingMessages.has(messageClass)) {
+ pendingMessages.set(messageClass, []);
+ }
+ pendingMessages.get(messageClass).push(message);
return;
}
- for (let handler of listeners[messageClass]) {
+ for (let handler of listeners.get(messageClass)) {
handler(message);
}
}
module.exports = {
- Success: 1,
- Error: 2,
- Info: 3,
- Authentication: 4,
- SettingsChange: 5,
- TagsChange: 6,
+ Success: 'success',
+ Error: 'error',
+ Info: 'info',
+ Authentication: 'auth',
+ SettingsChange: 'settings-change',
+ TagsChange: 'tags-change',
notify: notify,
listen: listen,
diff --git a/client/js/main.js b/client/js/main.js
index 6fb92c3..1636e96 100644
--- a/client/js/main.js
+++ b/client/js/main.js
@@ -29,10 +29,16 @@ controllers.push(require('./controllers/home_controller.js'));
const tags = require('./tags.js');
const events = require('./events.js');
+const views = require('./util/views.js');
for (let controller of controllers) {
controller.registerRoutes();
}
+page.exit((ctx, next) => {
+ views.unlistenToMessages();
+ next();
+});
+
const api = require('./api.js');
Promise.all([tags.refreshExport(), api.loginFromCookies()])
.then(() => {
diff --git a/client/js/tags.js b/client/js/tags.js
index 5b1c3b0..3098104 100644
--- a/client/js/tags.js
+++ b/client/js/tags.js
@@ -60,7 +60,9 @@ function getExport() {
return _export || {};
}
-events.listen(events.TagsChange, refreshExport);
+events.listen(
+ events.TagsChange,
+ () => { refreshExport(); return true; });
module.exports = {
getExport: getExport,
diff --git a/client/js/util/views.js b/client/js/util/views.js
index 8dd4115..5f61a49 100644
--- a/client/js/util/views.js
+++ b/client/js/util/views.js
@@ -37,31 +37,31 @@ function makeThumbnail(url) {
function makeRadio(options) {
return makeVoidElement(
- 'input',
- {
- id: options.id,
- name: options.name,
- value: options.value,
- type: 'radio',
- checked: options.selectedValue === options.value,
- required: options.required,
- }) +
- _makeLabel(options, {class: 'radio'});
+ 'input',
+ {
+ id: options.id,
+ name: options.name,
+ value: options.value,
+ type: 'radio',
+ checked: options.selectedValue === options.value,
+ required: options.required,
+ }) +
+ _makeLabel(options, {class: 'radio'});
}
function makeCheckbox(options) {
return makeVoidElement(
- 'input',
- {
- id: options.id,
- name: options.name,
- value: options.value,
- type: 'checkbox',
- checked: options.checked !== undefined ?
- options.checked : false,
- required: options.required,
- }) +
- _makeLabel(options, {class: 'checkbox'});
+ 'input',
+ {
+ id: options.id,
+ name: options.name,
+ value: options.value,
+ type: 'checkbox',
+ checked: options.checked !== undefined ?
+ options.checked : false,
+ required: options.required,
+ }) +
+ _makeLabel(options, {class: 'checkbox'});
}
function makeSelect(options) {
@@ -143,26 +143,6 @@ function makeFlexboxAlign(options) {
.map(() => '').join('');
}
-function _messageHandler(target, message, className) {
- if (!message) {
- message = 'Unknown message';
- }
- const messagesHolder = target.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);
- const wrapper = document.createElement('div');
- wrapper.classList.add('message-wrapper');
- wrapper.appendChild(node);
- messagesHolder.appendChild(wrapper);
-}
-
function _serializeElement(name, attributes) {
return [name]
.concat(Object.keys(attributes).map(key => {
@@ -186,16 +166,44 @@ function makeVoidElement(name, attributes) {
return '<{0}/>'.format(_serializeElement(name, attributes));
}
-function listenToMessages(target) {
+function _messageHandler(target, message, className) {
+ if (!message) {
+ message = 'Unknown message';
+ }
+ const messagesHolder = target.querySelector('.messages');
+ if (!messagesHolder) {
+ return false;
+ }
+ /* TODO: animate this */
+ const node = document.createElement('div');
+ node.innerHTML = message.replace(/\n/g, '
');
+ node.classList.add('message');
+ node.classList.add(className);
+ const wrapper = document.createElement('div');
+ wrapper.classList.add('message-wrapper');
+ wrapper.appendChild(node);
+ messagesHolder.appendChild(wrapper);
+ return true;
+}
+
+function unlistenToMessages() {
events.unlisten(events.Success);
events.unlisten(events.Error);
events.unlisten(events.Info);
- events.listen(
- events.Success, msg => { _messageHandler(target, msg, 'success'); });
- events.listen(
- events.Error, msg => { _messageHandler(target, msg, 'error'); });
- events.listen(
- events.Info, msg => { _messageHandler(target, msg, 'info'); });
+}
+
+function listenToMessages(target) {
+ unlistenToMessages();
+ const listen = (eventType, className) => {
+ events.listen(
+ eventType,
+ msg => {
+ return _messageHandler(target, msg, className);
+ });
+ };
+ listen(events.Success, 'success');
+ listen(events.Error, 'error');
+ listen(events.Info, 'info');
}
function clearMessages(target) {
@@ -314,6 +322,7 @@ module.exports = {
enableForm: enableForm,
disableForm: disableForm,
listenToMessages: listenToMessages,
+ unlistenToMessages: unlistenToMessages,
clearMessages: clearMessages,
decorateValidator: decorateValidator,
makeVoidElement: makeVoidElement,
diff --git a/client/js/views/empty_view.js b/client/js/views/empty_view.js
index d4e36b6..2142fb8 100644
--- a/client/js/views/empty_view.js
+++ b/client/js/views/empty_view.js
@@ -10,7 +10,7 @@ class EmptyView {
render(ctx) {
const target = document.getElementById('content-holder');
const source = this.template;
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/endless_page_view.js b/client/js/views/endless_page_view.js
index d961a0f..784d58c 100644
--- a/client/js/views/endless_page_view.js
+++ b/client/js/views/endless_page_view.js
@@ -15,7 +15,7 @@ class EndlessPageView {
const source = this.holderTemplate();
const pageHeaderHolder = source.querySelector('.page-header-holder');
const pagesHolder = source.querySelector('.pages-holder');
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
this.active = true;
this.working = 0;
diff --git a/client/js/views/help_view.js b/client/js/views/help_view.js
index f43a1a6..b4ff278 100644
--- a/client/js/views/help_view.js
+++ b/client/js/views/help_view.js
@@ -61,7 +61,7 @@ class HelpView {
}
}
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
views.scrollToHash();
diff --git a/client/js/views/home_view.js b/client/js/views/home_view.js
index b27fb14..c0d5df1 100644
--- a/client/js/views/home_view.js
+++ b/client/js/views/home_view.js
@@ -16,7 +16,7 @@ class HomeView {
buildDate: config.meta.buildDate,
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/login_view.js b/client/js/views/login_view.js
index 10ba67a..112cdab 100644
--- a/client/js/views/login_view.js
+++ b/client/js/views/login_view.js
@@ -36,7 +36,7 @@ class LoginView {
.always(() => { views.enableForm(form); });
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/manual_page_view.js b/client/js/views/manual_page_view.js
index a74729c..53f0c4b 100644
--- a/client/js/views/manual_page_view.js
+++ b/client/js/views/manual_page_view.js
@@ -99,13 +99,13 @@ class ManualPageView {
}));
}
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
if (response.total <= (currentPage - 1) * response.pageSize) {
events.notify(events.Info, 'No data to show');
}
}, response => {
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
events.notify(events.Error, response.description);
});
diff --git a/client/js/views/password_reset_view.js b/client/js/views/password_reset_view.js
index 14f0737..67043c5 100644
--- a/client/js/views/password_reset_view.js
+++ b/client/js/views/password_reset_view.js
@@ -24,7 +24,7 @@ class PasswordResetView {
.catch(() => { views.enableForm(form); });
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/registration_view.js b/client/js/views/registration_view.js
index 4a3178f..bcd8c74 100644
--- a/client/js/views/registration_view.js
+++ b/client/js/views/registration_view.js
@@ -33,7 +33,7 @@ class RegistrationView {
.always(() => { views.enableForm(form); });
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/settings_view.js b/client/js/views/settings_view.js
index 19bf591..6809ee8 100644
--- a/client/js/views/settings_view.js
+++ b/client/js/views/settings_view.js
@@ -25,7 +25,7 @@ class SettingsView {
});
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/tag_categories_view.js b/client/js/views/tag_categories_view.js
index f00c86f..7dd7115 100644
--- a/client/js/views/tag_categories_view.js
+++ b/client/js/views/tag_categories_view.js
@@ -101,7 +101,7 @@ class TagListHeaderView {
this._saveButtonClickHandler(e, ctx, target);
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/user_delete_view.js b/client/js/views/user_delete_view.js
index 740c205..c9e2be7 100644
--- a/client/js/views/user_delete_view.js
+++ b/client/js/views/user_delete_view.js
@@ -19,10 +19,11 @@ class UserDeleteView {
e.preventDefault();
views.clearMessages(target);
views.disableForm(form);
- ctx.delete();
+ ctx.delete()
+ .catch(() => { views.enableForm(form); });
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/user_edit_view.js b/client/js/views/user_edit_view.js
index bb5eb9c..0f9d858 100644
--- a/client/js/views/user_edit_view.js
+++ b/client/js/views/user_edit_view.js
@@ -54,7 +54,7 @@ class UserEditView {
.always(() => { views.enableForm(form); });
});
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/user_summary_view.js b/client/js/views/user_summary_view.js
index 9369376..c740cce 100644
--- a/client/js/views/user_summary_view.js
+++ b/client/js/views/user_summary_view.js
@@ -10,7 +10,7 @@ class UserSummaryView {
render(ctx) {
const target = ctx.target;
const source = this.template(ctx);
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}
diff --git a/client/js/views/user_view.js b/client/js/views/user_view.js
index 7cc8533..aac2e08 100644
--- a/client/js/views/user_view.js
+++ b/client/js/views/user_view.js
@@ -38,7 +38,7 @@ class UserView {
ctx.target = source.querySelector('#user-content-holder');
view.render(ctx);
- views.listenToMessages(target);
+ views.listenToMessages(source);
views.showView(target, source);
}
}