aboutsummaryrefslogtreecommitdiff
path: root/client/js/views
diff options
context:
space:
mode:
authorrr-2016-04-09 18:54:23 +0200
committerrr-2016-04-09 22:23:24 +0200
commit2e1823b7080aa0b3de986eb8f35f68837d04e023 (patch)
treeaad254b860d4078b9d5b829a50cf5ddd3b837deb /client/js/views
parent4821f2ac6ca1fd8e8a08d236815d8c964e473316 (diff)
client/views: replace inheritance with composition
Diffstat (limited to 'client/js/views')
-rw-r--r--client/js/views/base_view.js115
-rw-r--r--client/js/views/help_view.js20
-rw-r--r--client/js/views/home_view.js13
-rw-r--r--client/js/views/login_view.js21
-rw-r--r--client/js/views/password_reset_view.js21
-rw-r--r--client/js/views/registration_view.js21
-rw-r--r--client/js/views/top_nav_view.js9
-rw-r--r--client/js/views/user_deletion_view.js16
-rw-r--r--client/js/views/user_edit_view.js18
-rw-r--r--client/js/views/user_summary_view.js10
-rw-r--r--client/js/views/user_view.js12
11 files changed, 79 insertions, 197 deletions
diff --git a/client/js/views/base_view.js b/client/js/views/base_view.js
deleted file mode 100644
index 98ae406..0000000
--- a/client/js/views/base_view.js
+++ /dev/null
@@ -1,115 +0,0 @@
-'use strict';
-
-const handlebars = require('handlebars');
-const events = require('../events.js');
-const contentHolder = document.getElementById('content-holder');
-require('../util/polyfill.js');
-
-function messageHandler(message, className) {
- if (!message) {
- message = 'Unknown message';
- }
- const messagesHolder = contentHolder.querySelector('.messages');
- if (!messagesHolder) {
- alert(message);
- return;
- }
- /* TODO: animate this */
- const node = document.createElement('div');
- node.innerHTML = message.replace(/\n/g, '<br/>');
- 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'); });
-
-class BaseView {
- constructor() {
- this.contentHolder = contentHolder;
- this.domParser = new DOMParser();
- }
-
- htmlToDom(html) {
- const parsed = this.domParser.parseFromString(html, 'text/html').body;
- return parsed.childNodes.length > 1 ?
- parsed.childNodes :
- parsed.firstChild;
- }
-
- getTemplate(templatePath) {
- const templateElement = document.getElementById(templatePath);
- if (!templateElement) {
- console.error('Missing template: ' + templatePath);
- return null;
- }
- const templateText = templateElement.innerHTML.trim();
- const templateFactory = handlebars.compile(templateText);
- return (...args) => {
- return this.htmlToDom(templateFactory(...args));
- };
- }
-
- clearMessages() {
- const messagesHolder = this.contentHolder.querySelector('.messages');
- /* TODO: animate that */
- while (messagesHolder.lastChild) {
- messagesHolder.removeChild(messagesHolder.lastChild);
- }
- }
-
- decorateValidator(form) {
- // postpone showing form fields validity until user actually tries
- // to submit it (seeing red/green form w/o doing anything breaks POLA)
- const submitButton = form.querySelector('.buttons input');
- submitButton.addEventListener('click', e => {
- form.classList.add('show-validation');
- });
- form.addEventListener('submit', e => {
- form.classList.remove('show-validation');
- });
- }
-
- disableForm(form) {
- for (let input of form.querySelectorAll('input')) {
- input.disabled = true;
- }
- }
-
- enableForm(form) {
- for (let input of form.querySelectorAll('input')) {
- input.disabled = false;
- }
- }
-
- emptyView(target) {
- return this.showView(
- target,
- this.htmlToDom('<div class="messages"></div>'));
- }
-
- showView(target, source) {
- return new Promise((resolve, reject) => {
- let observer = new MutationObserver(mutations => {
- resolve();
- observer.disconnect();
- });
- observer.observe(target, {childList: true});
- while (target.lastChild) {
- target.removeChild(target.lastChild);
- }
- if (source instanceof NodeList) {
- for (let child of source) {
- target.appendChild(child);
- }
- } else if (source instanceof Node) {
- target.appendChild(source);
- } else {
- console.error('Invalid view source', source);
- }
- });
- }
-}
-
-module.exports = BaseView;
diff --git a/client/js/views/help_view.js b/client/js/views/help_view.js
index d3f198c..833e548 100644
--- a/client/js/views/help_view.js
+++ b/client/js/views/help_view.js
@@ -1,31 +1,30 @@
'use strict';
const config = require('../config.js');
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class HelpView extends BaseView {
+class HelpView {
constructor() {
- super();
- this.template = this.getTemplate('help-template');
+ this.template = views.getTemplate('help');
this.sectionTemplates = {};
const sectionKeys = ['about', 'keyboard', 'search', 'comments', 'tos'];
for (let section of sectionKeys) {
- const templateName = 'help-' + section + '-template';
- this.sectionTemplates[section] = this.getTemplate(templateName);
+ const templateName = 'help-' + section;
+ this.sectionTemplates[section] = views.getTemplate(templateName);
}
}
render(ctx) {
- const target = this.contentHolder;
+ const target = document.getElementById('content-holder');
const source = this.template();
ctx.section = ctx.section || 'about';
if (!(ctx.section in this.sectionTemplates)) {
- this.emptyView(this.contentHolder);
+ views.emptyView(target);
return;
}
- this.showView(
+ views.showView(
source.querySelector('.content'),
this.sectionTemplates[ctx.section]({
name: config.name,
@@ -40,7 +39,8 @@ class HelpView extends BaseView {
}
}
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/home_view.js b/client/js/views/home_view.js
index 341982a..b27fb14 100644
--- a/client/js/views/home_view.js
+++ b/client/js/views/home_view.js
@@ -1,22 +1,23 @@
'use strict';
const config = require('../config.js');
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class HomeView extends BaseView {
+class HomeView {
constructor() {
- super();
- this.template = this.getTemplate('home-template');
+ this.template = views.getTemplate('home');
}
render(ctx) {
- const target = this.contentHolder;
+ const target = document.getElementById('content-holder');
const source = this.template({
name: config.name,
version: config.meta.version,
buildDate: config.meta.buildDate,
});
- this.showView(target, source);
+
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/login_view.js b/client/js/views/login_view.js
index f0e90c0..9a1763c 100644
--- a/client/js/views/login_view.js
+++ b/client/js/views/login_view.js
@@ -1,17 +1,15 @@
'use strict';
const config = require('../config.js');
-const events = require('../events.js');
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class LoginView extends BaseView {
+class LoginView {
constructor() {
- super();
- this.template = this.getTemplate('login-template');
+ this.template = views.getTemplate('login');
}
render(ctx) {
- const target = this.contentHolder;
+ const target = document.getElementById('content-holder');
const source = this.template({canSendMails: config.canSendMails});
const form = source.querySelector('form');
@@ -19,22 +17,23 @@ class LoginView extends BaseView {
const passwordField = source.querySelector('#user-password');
const rememberUserField = source.querySelector('#remember-user');
- this.decorateValidator(form);
+ views.decorateValidator(form);
userNameField.setAttribute('pattern', config.userNameRegex);
passwordField.setAttribute('pattern', config.passwordRegex);
form.addEventListener('submit', e => {
e.preventDefault();
- this.clearMessages();
- this.disableForm(form);
+ views.clearMessages(target);
+ views.disableForm(form);
ctx.login(
userNameField.value,
passwordField.value,
rememberUserField.checked)
- .always(() => { this.enableForm(form); });
+ .always(() => { views.enableForm(form); });
});
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/password_reset_view.js b/client/js/views/password_reset_view.js
index 12729bc..14f0737 100644
--- a/client/js/views/password_reset_view.js
+++ b/client/js/views/password_reset_view.js
@@ -1,32 +1,31 @@
'use strict';
-const events = require('../events.js');
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class PasswordResetView extends BaseView {
+class PasswordResetView {
constructor() {
- super();
- this.template = this.getTemplate('password-reset-template');
+ this.template = views.getTemplate('password-reset');
}
render(ctx) {
- const target = this.contentHolder;
+ const target = document.getElementById('content-holder');
const source = this.template();
const form = source.querySelector('form');
const userNameOrEmailField = source.querySelector('#user-name');
- this.decorateValidator(form);
+ views.decorateValidator(form);
form.addEventListener('submit', e => {
e.preventDefault();
- this.clearMessages();
- this.disableForm(form);
+ views.clearMessages(target);
+ views.disableForm(form);
ctx.proceed(userNameOrEmailField.value)
- .catch(() => { this.enableForm(form); });
+ .catch(() => { views.enableForm(form); });
});
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/registration_view.js b/client/js/views/registration_view.js
index 7c58ab5..55ad0a1 100644
--- a/client/js/views/registration_view.js
+++ b/client/js/views/registration_view.js
@@ -1,17 +1,15 @@
'use strict';
const config = require('../config.js');
-const events = require('../events.js');
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class RegistrationView extends BaseView {
+class RegistrationView {
constructor() {
- super();
- this.template = this.getTemplate('user-registration-template');
+ this.template = views.getTemplate('user-registration');
}
render(ctx) {
- const target = this.contentHolder;
+ const target = document.getElementById('content-holder');
const source = this.template();
const form = source.querySelector('form');
@@ -19,22 +17,23 @@ class RegistrationView extends BaseView {
const passwordField = source.querySelector('#user-password');
const emailField = source.querySelector('#user-email');
- this.decorateValidator(form);
+ views.decorateValidator(form);
userNameField.setAttribute('pattern', config.userNameRegex);
passwordField.setAttribute('pattern', config.passwordRegex);
form.addEventListener('submit', e => {
e.preventDefault();
- this.clearMessages();
- this.disableForm(form);
+ views.clearMessages(target);
+ views.disableForm(form);
ctx.register(
userNameField.value,
passwordField.value,
emailField.value)
- .always(() => { this.enableForm(form); });
+ .always(() => { views.enableForm(form); });
});
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/top_nav_view.js b/client/js/views/top_nav_view.js
index 7e9c271..3210564 100644
--- a/client/js/views/top_nav_view.js
+++ b/client/js/views/top_nav_view.js
@@ -1,11 +1,10 @@
'use strict';
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class TopNavView extends BaseView {
+class TopNavView {
constructor() {
- super();
- this.template = this.getTemplate('top-nav-template');
+ this.template = views.getTemplate('top-nav');
this.navHolder = document.getElementById('top-nav-holder');
}
@@ -21,7 +20,7 @@ class TopNavView extends BaseView {
'<span class="access-key" data-accesskey="$1">$1</span>');
}
- this.showView(this.navHolder, source);
+ views.showView(this.navHolder, source);
}
activate(itemName) {
diff --git a/client/js/views/user_deletion_view.js b/client/js/views/user_deletion_view.js
index 3861685..20c950f 100644
--- a/client/js/views/user_deletion_view.js
+++ b/client/js/views/user_deletion_view.js
@@ -1,11 +1,10 @@
'use strict';
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class UserDeletionView extends BaseView {
+class UserDeletionView {
constructor() {
- super();
- this.template = this.getTemplate('user-deletion-template');
+ this.template = views.getTemplate('user-deletion');
}
render(ctx) {
@@ -14,16 +13,17 @@ class UserDeletionView extends BaseView {
const form = source.querySelector('form');
- this.decorateValidator(form);
+ views.decorateValidator(form);
form.addEventListener('submit', e => {
e.preventDefault();
- this.clearMessages();
- this.disableForm(form);
+ views.clearMessages(target);
+ views.disableForm(form);
ctx.delete();
});
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/user_edit_view.js b/client/js/views/user_edit_view.js
index 9d5c3ae..21ac7ba 100644
--- a/client/js/views/user_edit_view.js
+++ b/client/js/views/user_edit_view.js
@@ -1,12 +1,11 @@
'use strict';
const config = require('../config.js');
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class UserEditView extends BaseView {
+class UserEditView {
constructor() {
- super();
- this.template = this.getTemplate('user-edit-template');
+ this.template = views.getTemplate('user-edit');
}
render(ctx) {
@@ -19,7 +18,7 @@ class UserEditView extends BaseView {
const userNameField = source.querySelector('#user-name');
const passwordField = source.querySelector('#user-password');
- this.decorateValidator(form);
+ views.decorateValidator(form);
if (userNameField) {
userNameField.setAttribute(
@@ -41,17 +40,18 @@ class UserEditView extends BaseView {
form.addEventListener('submit', e => {
e.preventDefault();
- this.clearMessages();
- this.disableForm(form);
+ views.clearMessages(target);
+ views.disableForm(form);
ctx.edit(
userNameField.value,
passwordField.value,
emailField.value,
rankField.value)
- .always(() => { this.enableForm(form); });
+ .always(() => { views.enableForm(form); });
});
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/user_summary_view.js b/client/js/views/user_summary_view.js
index ef3029a..9369376 100644
--- a/client/js/views/user_summary_view.js
+++ b/client/js/views/user_summary_view.js
@@ -1,17 +1,17 @@
'use strict';
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
-class UserSummaryView extends BaseView {
+class UserSummaryView {
constructor() {
- super();
- this.template = this.getTemplate('user-summary-template');
+ this.template = views.getTemplate('user-summary');
}
render(ctx) {
const target = ctx.target;
const source = this.template(ctx);
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}
diff --git a/client/js/views/user_view.js b/client/js/views/user_view.js
index cb38fc1..c547549 100644
--- a/client/js/views/user_view.js
+++ b/client/js/views/user_view.js
@@ -1,21 +1,20 @@
'use strict';
-const BaseView = require('./base_view.js');
+const views = require('../util/views.js');
const UserDeletionView = require('./user_deletion_view.js');
const UserSummaryView = require('./user_summary_view.js');
const UserEditView = require('./user_edit_view.js');
-class UserView extends BaseView {
+class UserView {
constructor() {
- super();
- this.template = this.getTemplate('user-template');
+ this.template = views.getTemplate('user');
this.deletionView = new UserDeletionView();
this.summaryView = new UserSummaryView();
this.editView = new UserEditView();
}
render(ctx) {
- const target = this.contentHolder;
+ const target = document.getElementById('content-holder');
const source = this.template(ctx);
ctx.section = ctx.section || 'summary';
@@ -39,7 +38,8 @@ class UserView extends BaseView {
ctx.target = source.querySelector('#user-content-holder');
view.render(ctx);
- this.showView(target, source);
+ views.listenToMessages(target);
+ views.showView(target, source);
}
}

© 2015 - 2026 Jakob L. Kreuze