client/general: clean up, refactor

This commit is contained in:
rr- 2016-08-05 20:09:11 +02:00
parent 9304e309f6
commit 1b62daed9a
16 changed files with 283 additions and 169 deletions

View file

@ -4,13 +4,26 @@
<div class='input'>
<ul>
<li>
<%= ctx.makeTextInput({text: 'User name', id: 'user-name', name: 'name', required: true, pattern: ctx.userNamePattern}) %>
<%= ctx.makeTextInput({
text: 'User name',
name: 'name',
required: true,
pattern: ctx.userNamePattern,
}) %>
</li>
<li>
<%= ctx.makePasswordInput({text: 'Password', id: 'user-password', name: 'password', required: true, pattern: ctx.passwordPattern}) %>
<%= ctx.makePasswordInput({
text: 'Password',
name: 'password',
required: true,
pattern: ctx.passwordPattern,
}) %>
</li>
<li>
<%= ctx.makeCheckbox({text: 'Remember me', id: 'remember-user', name: 'remember-user'}) %>
<%= ctx.makeCheckbox({
text: 'Remember me',
name: 'remember-user',
}) %>
</li>
</ul>
</div>

View file

@ -4,7 +4,11 @@
<div class='input'>
<ul>
<li>
<%= ctx.makeTextInput({text: 'User name or e-mail address', id: 'user-name', name: 'user-name', required: true}) %>
<%= ctx.makeTextInput({
text: 'User name or e-mail address',
name: 'user-name',
required: true,
}) %>
</li>
</ul>
</div>

View file

@ -2,32 +2,62 @@
<form>
<strong>Browsing settings</strong>
<p>These settings are saved to the browser's local storage and are not coupled to the user account, so they don't apply to other devices or browsers alike.</p>
<div class='input'>
<ul>
<li>
<%= ctx.makeCheckbox({text: 'Enable keyboard shortcuts', id: 'keyboard-shortcuts', name: 'keyboard-shortcuts', checked: ctx.browsingSettings.keyboardShortcuts}) %>
<a class='append icon' href='/help/keyboard'><i class='fa fa-question-circle-o'></i></a>
</li>
<li>
<%= ctx.makeNumericInput({text: 'Number of posts per page', id: 'posts-per-page', name: 'posts-per-page', checked: ctx.browsingSettings.postCount, min: 10, max: 100, value: ctx.browsingSettings.postsPerPage}) %>
</li>
<li>
<%= ctx.makeCheckbox({text: 'Upscale small posts', id: 'upscale-small-posts', name: 'upscale-small-posts', checked: ctx.browsingSettings.upscaleSmallPosts}) %>
</li>
<li>
<%= ctx.makeCheckbox({text: 'Endless scroll', id: 'endless-scroll', name: 'endless-scroll', checked: ctx.browsingSettings.endlessScroll}) %>
<p class='hint'>Rather than using a paged navigation, smoothly scrolls through the content.</p>
</li>
<li>
<%= ctx.makeCheckbox({text: 'Enable transparency grid', id: 'transparency-grid', name: 'transparency-grid', checked: ctx.browsingSettings.transparencyGrid}) %>
<p class='hint'>Renders a checkered pattern behind posts with transparent background.</p>
</li>
<li>
<%= ctx.makeCheckbox({text: 'Show tag suggestions', id: 'tag-suggestions', name: 'tag-suggestions', checked: ctx.browsingSettings.tagSuggestions}) %>
<p class='hint'>Shows a popup with suggested tags in edit forms.</p>
</li>
</ul>
</div>
<ul class='input'>
<li>
<%= ctx.makeCheckbox({
text: 'Enable keyboard shortcuts',
name: 'keyboard-shortcuts',
checked: ctx.browsingSettings.keyboardShortcuts,
}) %>
<a class='append icon' href='/help/keyboard'><i class='fa fa-question-circle-o'></i></a>
</li>
<li>
<%= ctx.makeNumericInput({
text: 'Number of posts per page',
name: 'posts-per-page',
checked: ctx.browsingSettings.postCount,
value: ctx.browsingSettings.postsPerPage,
min: 10,
max: 100,
}) %>
</li>
<li>
<%= ctx.makeCheckbox({
text: 'Upscale small posts',
name: 'upscale-small-posts',
checked: ctx.browsingSettings.upscaleSmallPosts}) %>
</li>
<li>
<%= ctx.makeCheckbox({
text: 'Endless scroll',
name: 'endless-scroll',
checked: ctx.browsingSettings.endlessScroll,
}) %>
<p class='hint'>Rather than using a paged navigation, smoothly scrolls through the content.</p>
</li>
<li>
<%= ctx.makeCheckbox({
text: 'Enable transparency grid',
name: 'transparency-grid',
checked: ctx.browsingSettings.transparencyGrid,
}) %>
<p class='hint'>Renders a checkered pattern behind posts with transparent background.</p>
</li>
<li>
<%= ctx.makeCheckbox({
text: 'Show tag suggestions',
name: 'tag-suggestions',
checked: ctx.browsingSettings.tagSuggestions,
}) %>
<p class='hint'>Shows a popup with suggested tags in edit forms.</p>
</li>
</ul>
<div class='messages'></div>
<div class='buttons'>
<input type='submit' value='Save settings'/>

View file

@ -4,7 +4,11 @@
<ul>
<li>
<%= ctx.makeCheckbox({id: 'confirm-deletion', name: 'confirm-deletion', required: true, text: 'I confirm that I want to delete this tag.'}) %>
<%= ctx.makeCheckbox({
name: 'confirm-deletion',
text: 'I confirm that I want to delete this tag.',
required: true,
}) %>
</li>
</ul>

View file

@ -3,7 +3,11 @@
<div class='input'>
<ul>
<li>
<%= ctx.makeCheckbox({id: 'confirm-deletion', name: 'confirm-deletion', required: true, text: 'I confirm that I want to delete this account.'}) %>
<%= ctx.makeCheckbox({
name: 'confirm-deletion',
text: 'I confirm that I want to delete this account.',
required: true,
}) %>
</li>
</ul>
</div>

View file

@ -1,27 +1,46 @@
<div id='user-edit'>
<form>
<ul>
<ul class='input'>
<% if (ctx.canEditName) { %>
<li>
<%= ctx.makeTextInput({text: 'User name', id: 'user-name', name: 'name', value: ctx.user.name, pattern: ctx.userNamePattern}) %>
<%= ctx.makeTextInput({
text: 'User name',
name: 'name',
value: ctx.user.name,
pattern: ctx.userNamePattern,
}) %>
</li>
<% } %>
<% if (ctx.canEditPassword) { %>
<li>
<%= ctx.makePasswordInput({text: 'Password', id: 'user-password', name: 'password', placeholder: 'leave blank if not changing', pattern: ctx.passwordPattern}) %>
<%= ctx.makePasswordInput({
text: 'Password',
name: 'password',
placeholder: 'leave blank if not changing',
pattern: ctx.passwordPattern,
}) %>
</li>
<% } %>
<% if (ctx.canEditEmail) { %>
<li>
<%= ctx.makeEmailInput({text: 'Email', id: 'user-email', name: 'email', value: ctx.user.email}) %>
<%= ctx.makeEmailInput({
text: 'Email',
name: 'email',
value: ctx.user.email,
}) %>
</li>
<% } %>
<% if (ctx.canEditRank) { %>
<li>
<%= ctx.makeSelect({text: 'Rank', id: 'user-rank', name: 'rank', keyValues: ctx.ranks, selectedKey: ctx.user.rank}) %>
<%= ctx.makeSelect({
text: 'Rank',
name: 'rank',
keyValues: ctx.ranks,
selectedKey: ctx.user.rank,
}) %>
</li>
<% } %>
@ -30,8 +49,19 @@
<label>Avatar</label>
<div id='avatar-content'></div>
<div id='avatar-radio'>
<%= ctx.makeRadio({text: 'Gravatar', id: 'gravatar-radio', name: 'avatar-style', value: 'gravatar', selectedValue: ctx.user.avatarStyle}) %>
<%= ctx.makeRadio({text: 'Manual avatar', id: 'avatar-radio', name: 'avatar-style', value: 'manual', selectedValue: ctx.user.avatarStyle}) %>
<%= ctx.makeRadio({
text: 'Gravatar',
name: 'avatar-style',
value: 'gravatar',
selectedValue: ctx.user.avatarStyle,
}) %>
<%= ctx.makeRadio({
text: 'Manual avatar',
name: 'avatar-style',
value: 'manual',
selectedValue: ctx.user.avatarStyle,
}) %>
</div>
</li>
<% } %>

View file

@ -4,14 +4,33 @@
<div class='input'>
<ul>
<li>
<%= ctx.makeTextInput({text: 'User name', id: 'user-name', name: 'user-name', placeholder: 'letters, digits, _, -', required: true, pattern: ctx.userNamePattern}) %>
<%= ctx.makeTextInput({
text: 'User name',
name: 'name',
placeholder: 'letters, digits, _, -',
required: true,
pattern: ctx.userNamePattern,
}) %>
</li>
<li>
<%= ctx.makePasswordInput({text: 'Password', id: 'user-password', name: 'user-password', placeholder: '5+ characters', required: true, pattern: ctx.passwordPattern}) %>
<%= ctx.makePasswordInput({
text: 'Password',
name: 'password',
placeholder: '5+ characters',
required: true,
pattern: ctx.passwordPattern,
}) %>
</li>
<li>
<%= ctx.makeEmailInput({text: 'Email', id: 'user-email', name: 'user-email', placeholder: 'optional'}) %>
<p class='hint'>Used for password reminder and to show a <a href='http://gravatar.com/'>Gravatar</a>. Leave blank for random Gravatar.</p>
<%= ctx.makeEmailInput({
text: 'Email',
name: 'email',
placeholder: 'optional',
}) %>
<p class='hint'>
Used for password reminder and to show a <a href='http://gravatar.com/'>Gravatar</a>.
Leave blank for random Gravatar.
</p>
</li>
</ul>
</div>

View file

@ -16,7 +16,7 @@ class SettingsController {
_evtChange(e) {
this._view.clearMessages();
settings.save(e.detail.settings);
settings.save(e.detail);
this._view.showSuccess('Settings saved.');
}
};

View file

@ -111,14 +111,14 @@ function getSuggestions(tagName) {
return actualTag.suggestions || [];
}
module.exports = {
getAllCategories: getAllCategories,
getAllTags: getAllTags,
getTagByName: getTagByName,
getCategoryByName: getCategoryByName,
getNameToTagMap: getNameToTagMap,
getOriginalTagName: getOriginalTagName,
refreshExport: refreshExport,
getAllImplications: getAllImplications,
getSuggestions: getSuggestions,
};
module.exports = misc.arrayToObject([
getAllCategories,
getAllTags,
getTagByName,
getCategoryByName,
getNameToTagMap,
getOriginalTagName,
refreshExport,
getAllImplications,
getSuggestions,
], func => func.name);

View file

@ -260,21 +260,35 @@ function arraysDiffer(source1, source2) {
source2.filter(value => !source1.includes(value)).length > 0);
}
module.exports = {
range: range,
formatUrlParameters: formatUrlParameters,
parseUrlParameters: parseUrlParameters,
parseUrlParametersRoute: parseUrlParametersRoute,
formatRelativeTime: formatRelativeTime,
formatFileSize: formatFileSize,
formatMarkdown: formatMarkdown,
unindent: unindent,
enableExitConfirmation: enableExitConfirmation,
disableExitConfirmation: disableExitConfirmation,
confirmPageExit: confirmPageExit,
escapeHtml: escapeHtml,
makeCssName: makeCssName,
splitByWhitespace: splitByWhitespace,
arraysDiffer: arraysDiffer,
decamelize: decamelize,
};
function arrayToObject(array, keySelector, valueSelector) {
if (keySelector === undefined) {
keySelector = item => item;
}
if (valueSelector === undefined) {
valueSelector = item => item;
}
return array.reduce((obj, item) => {
obj[keySelector(item)] = valueSelector(item);
return obj;
}, {});
}
module.exports = arrayToObject([
range,
formatUrlParameters,
parseUrlParameters,
parseUrlParametersRoute,
formatRelativeTime,
formatFileSize,
formatMarkdown,
unindent,
enableExitConfirmation,
disableExitConfirmation,
confirmPageExit,
escapeHtml,
makeCssName,
splitByWhitespace,
arraysDiffer,
decamelize,
arrayToObject,
], func => func.name);

View file

@ -204,7 +204,7 @@ function makeUserLink(user) {
}
function makeFlexboxAlign(options) {
return Array.from(misc.range(20))
return [...misc.range(20)]
.map(() => '<li class="flexbox-dummy"></li>').join('');
}
@ -326,31 +326,31 @@ function getTemplate(templatePath) {
if (!ctx) {
ctx = {};
}
Object.assign(ctx, {
getPostUrl: getPostUrl,
getPostEditUrl: getPostEditUrl,
makeRelativeTime: makeRelativeTime,
makeFileSize: makeFileSize,
makeMarkdown: makeMarkdown,
makeThumbnail: makeThumbnail,
makeRadio: makeRadio,
makeCheckbox: makeCheckbox,
makeSelect: makeSelect,
makeInput: makeInput,
makeButton: makeButton,
makeTextarea: makeTextarea,
makeTextInput: makeTextInput,
makePasswordInput: makePasswordInput,
makeEmailInput: makeEmailInput,
makeColorInput: makeColorInput,
makePostLink: makePostLink,
makeTagLink: makeTagLink,
makeUserLink: makeUserLink,
makeFlexboxAlign: makeFlexboxAlign,
makeAccessKey: makeAccessKey,
makeCssName: misc.makeCssName,
makeNumericInput: makeNumericInput,
});
Object.assign(ctx, misc.arrayToObject([
getPostUrl,
getPostEditUrl,
makeRelativeTime,
makeFileSize,
makeMarkdown,
makeThumbnail,
makeRadio,
makeCheckbox,
makeSelect,
makeInput,
makeButton,
makeTextarea,
makeTextInput,
makePasswordInput,
makeEmailInput,
makeColorInput,
makePostLink,
makeTagLink,
makeUserLink,
makeFlexboxAlign,
makeAccessKey,
misc.makeCssName,
makeNumericInput,
], func => func.name));
return htmlToDom(templateFactory(ctx));
};
}
@ -389,7 +389,7 @@ function replaceContent(target, source) {
target.removeChild(target.lastChild);
}
if (source instanceof NodeList) {
for (let child of Array.from(source)) {
for (let child of [...source]) {
target.appendChild(child);
}
} else if (source instanceof Node) {
@ -468,21 +468,21 @@ document.addEventListener('input', e => {
}
});
module.exports = {
htmlToDom: htmlToDom,
getTemplate: getTemplate,
replaceContent: replaceContent,
enableForm: enableForm,
disableForm: disableForm,
decorateValidator: decorateValidator,
makeVoidElement: makeVoidElement,
makeNonVoidElement: makeNonVoidElement,
syncScrollPosition: syncScrollPosition,
slideDown: slideDown,
slideUp: slideUp,
monitorNodeRemoval: monitorNodeRemoval,
clearMessages: clearMessages,
showError: showError,
showSuccess: showSuccess,
showInfo: showInfo,
};
module.exports = misc.arrayToObject([
htmlToDom,
getTemplate,
replaceContent,
enableForm,
disableForm,
decorateValidator,
makeVoidElement,
makeNonVoidElement,
syncScrollPosition,
slideDown,
slideUp,
monitorNodeRemoval,
clearMessages,
showError,
showSuccess,
showInfo,
], func => func.name);

View file

@ -19,15 +19,15 @@ class LoginView extends events.EventTarget {
views.syncScrollPosition();
views.decorateValidator(this._formNode);
this._userNameFieldNode.setAttribute('pattern', config.userNameRegex);
this._passwordFieldNode.setAttribute('pattern', config.passwordRegex);
this._userNameInputNode.setAttribute('pattern', config.userNameRegex);
this._passwordInputNode.setAttribute('pattern', config.passwordRegex);
this._formNode.addEventListener('submit', e => {
e.preventDefault();
this.dispatchEvent(new CustomEvent('submit', {
detail: {
name: this._userNameFieldNode.value,
password: this._passwordFieldNode.value,
remember: this._rememberFieldNode.checked,
name: this._userNameInputNode.value,
password: this._passwordInputNode.value,
remember: this._rememberInputNode.checked,
},
}));
});
@ -37,16 +37,16 @@ class LoginView extends events.EventTarget {
return this._hostNode.querySelector('form');
}
get _userNameFieldNode() {
return this._formNode.querySelector('#user-name');
get _userNameInputNode() {
return this._formNode.querySelector('[name=name]');
}
get _passwordFieldNode() {
return this._formNode.querySelector('#user-password');
get _passwordInputNode() {
return this._formNode.querySelector('[name=password]');
}
get _rememberFieldNode() {
return this._formNode.querySelector('#remember-user');
get _rememberInputNode() {
return this._formNode.querySelector('[name=remember-user]');
}
disableForm() {

View file

@ -49,7 +49,7 @@ class PasswordResetView extends events.EventTarget {
}
get _userNameOrEmailFieldNode() {
return this._formNode.querySelector('#user-name');
return this._formNode.querySelector('[name=user-name]');
}
}

View file

@ -51,15 +51,15 @@ class RegistrationView extends events.EventTarget {
}
get _userNameFieldNode() {
return this._formNode.querySelector('#user-name');
return this._formNode.querySelector('[name=name]');
}
get _passwordFieldNode() {
return this._formNode.querySelector('#user-password');
return this._formNode.querySelector('[name=password]');
}
get _emailFieldNode() {
return this._formNode.querySelector('#user-email');
return this._formNode.querySelector('[name=email]');
}
}

View file

@ -30,20 +30,12 @@ class SettingsView extends events.EventTarget {
e.preventDefault();
this.dispatchEvent(new CustomEvent('change', {
detail: {
settings: {
upscaleSmallPosts: this._formNode.querySelector(
'#upscale-small-posts').checked,
endlessScroll: this._formNode.querySelector(
'#endless-scroll').checked,
keyboardShortcuts: this._formNode.querySelector(
'#keyboard-shortcuts').checked,
transparencyGrid: this._formNode.querySelector(
'#transparency-grid').checked,
tagSuggestions: this._formNode.querySelector(
'#tag-suggestions').checked,
postsPerPage: this._formNode.querySelector(
'#posts-per-page').value,
},
upscaleSmallPosts: this._find('upscale-small-posts').checked,
endlessScroll: this._find('endless-scroll').checked,
keyboardShortcuts: this._find('keyboard-shortcuts').checked,
transparencyGrid: this._find('transparency-grid').checked,
tagSuggestions: this._find('tag-suggestions').checked,
postsPerPage: this._find('posts-per-page').value,
},
}));
}
@ -51,6 +43,10 @@ class SettingsView extends events.EventTarget {
get _formNode() {
return this._hostNode.querySelector('form');
}
_find(nodeName) {
return this._formNode.querySelector('[name=' + nodeName + ']');
}
}
module.exports = SettingsView;

View file

@ -20,9 +20,9 @@ class UserEditView extends events.EventTarget {
views.decorateValidator(this._formNode);
this._avatarContent = null;
if (this._avatarContentFieldNode) {
if (this._avatarContentInputNode) {
new FileDropperControl(
this._avatarContentFieldNode,
this._avatarContentInputNode,
{
lock: true,
resolve: files => {
@ -62,24 +62,24 @@ class UserEditView extends events.EventTarget {
detail: {
user: this._user,
name: this._userNameFieldNode ?
this._userNameFieldNode.value :
name: this._userNameInputNode ?
this._userNameInputNode.value :
undefined,
email: this._emailFieldNode ?
this._emailFieldNode.value :
email: this._emailInputNode ?
this._emailInputNode.value :
undefined,
rank: this._rankFieldNode ?
this._rankFieldNode.value :
rank: this._rankInputNode ?
this._rankInputNode.value :
undefined,
avatarStyle: this._avatarStyleFieldNode ?
this._avatarStyleFieldNode.value :
avatarStyle: this._avatarStyleInputNode ?
this._avatarStyleInputNode.value :
undefined,
password: this._passwordFieldNode ?
this._passwordFieldNode.value :
password: this._passwordInputNode ?
this._passwordInputNode.value :
undefined,
avatarContent: this._avatarContent,
@ -91,27 +91,27 @@ class UserEditView extends events.EventTarget {
return this._hostNode.querySelector('form');
}
get _rankFieldNode() {
return this._formNode.querySelector('#user-rank');
get _rankInputNode() {
return this._formNode.querySelector('[name=rank]');
}
get _emailFieldNode() {
return this._formNode.querySelector('#user-email');
get _emailInputNode() {
return this._formNode.querySelector('[name=email]');
}
get _userNameFieldNode() {
return this._formNode.querySelector('#user-name');
get _userNameInputNode() {
return this._formNode.querySelector('[name=name]');
}
get _passwordFieldNode() {
return this._formNode.querySelector('#user-password');
get _passwordInputNode() {
return this._formNode.querySelector('[name=password]');
}
get _avatarContentFieldNode() {
get _avatarContentInputNode() {
return this._formNode.querySelector('#avatar-content');
}
get _avatarStyleFieldNode() {
get _avatarStyleInputNode() {
return this._formNode.querySelector('[name=avatar-style]:checked');
}
}