aboutsummaryrefslogtreecommitdiff
path: root/client/js/views
diff options
context:
space:
mode:
Diffstat (limited to 'client/js/views')
-rw-r--r--client/js/views/comments_page_view.js22
-rw-r--r--client/js/views/empty_view.js9
-rw-r--r--client/js/views/endless_page_view.js128
-rw-r--r--client/js/views/help_view.js79
-rw-r--r--client/js/views/home_view.js83
-rw-r--r--client/js/views/login_view.js61
-rw-r--r--client/js/views/manual_page_view.js129
-rw-r--r--client/js/views/not_found_view.js10
-rw-r--r--client/js/views/password_reset_view.js41
-rw-r--r--client/js/views/pool_categories_view.js174
-rw-r--r--client/js/views/pool_create_view.js140
-rw-r--r--client/js/views/pool_delete_view.js55
-rw-r--r--client/js/views/pool_edit_view.js151
-rw-r--r--client/js/views/pool_merge_view.js84
-rw-r--r--client/js/views/pool_summary_view.js23
-rw-r--r--client/js/views/pool_view.js108
-rw-r--r--client/js/views/pools_header_view.js60
-rw-r--r--client/js/views/pools_page_view.js13
-rw-r--r--client/js/views/post_detail_view.js40
-rw-r--r--client/js/views/post_main_view.js109
-rw-r--r--client/js/views/post_merge_view.js105
-rw-r--r--client/js/views/post_upload_view.js262
-rw-r--r--client/js/views/posts_header_view.js265
-rw-r--r--client/js/views/posts_page_view.js96
-rw-r--r--client/js/views/registration_view.js49
-rw-r--r--client/js/views/settings_view.js62
-rw-r--r--client/js/views/snapshots_page_view.js103
-rw-r--r--client/js/views/tag_categories_view.js97
-rw-r--r--client/js/views/tag_delete_view.js24
-rw-r--r--client/js/views/tag_edit_view.js105
-rw-r--r--client/js/views/tag_merge_view.js46
-rw-r--r--client/js/views/tag_summary_view.js6
-rw-r--r--client/js/views/tag_view.js73
-rw-r--r--client/js/views/tags_header_view.js44
-rw-r--r--client/js/views/tags_page_view.js6
-rw-r--r--client/js/views/top_navigation_view.js34
-rw-r--r--client/js/views/user_delete_view.js25
-rw-r--r--client/js/views/user_edit_view.js94
-rw-r--r--client/js/views/user_summary_view.js6
-rw-r--r--client/js/views/user_tokens_view.js103
-rw-r--r--client/js/views/user_view.js64
-rw-r--r--client/js/views/users_header_view.js30
-rw-r--r--client/js/views/users_page_view.js6
43 files changed, 2173 insertions, 1051 deletions
diff --git a/client/js/views/comments_page_view.js b/client/js/views/comments_page_view.js
index d5bb294..5648b3a 100644
--- a/client/js/views/comments_page_view.js
+++ b/client/js/views/comments_page_view.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const CommentListControl = require('../controls/comment_list_control.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const CommentListControl = require("../controls/comment_list_control.js");
-const template = views.getTemplate('comments-page');
+const template = views.getTemplate("comments-page");
class CommentsPageView extends events.EventTarget {
constructor(ctx) {
@@ -16,12 +16,14 @@ class CommentsPageView extends events.EventTarget {
for (let post of ctx.response.results) {
const commentListControl = new CommentListControl(
sourceNode.querySelector(
- `.comments-container[data-for="${post.id}"]`),
+ `.comments-container[data-for="${post.id}"]`
+ ),
post.comments,
- true);
- events.proxyEvent(commentListControl, this, 'submit');
- events.proxyEvent(commentListControl, this, 'score');
- events.proxyEvent(commentListControl, this, 'delete');
+ true
+ );
+ events.proxyEvent(commentListControl, this, "submit");
+ events.proxyEvent(commentListControl, this, "score");
+ events.proxyEvent(commentListControl, this, "delete");
}
views.replaceContent(this._hostNode, sourceNode);
diff --git a/client/js/views/empty_view.js b/client/js/views/empty_view.js
index 21843d7..59d336d 100644
--- a/client/js/views/empty_view.js
+++ b/client/js/views/empty_view.js
@@ -1,15 +1,16 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
const template = () => {
return views.htmlToDom(
- '<div class="wrapper"><div class="messages"></div></div>');
+ '<div class="wrapper"><div class="messages"></div></div>'
+ );
};
class EmptyView {
constructor() {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template());
views.syncScrollPosition();
}
diff --git a/client/js/views/endless_page_view.js b/client/js/views/endless_page_view.js
index ab40662..f94c371 100644
--- a/client/js/views/endless_page_view.js
+++ b/client/js/views/endless_page_view.js
@@ -1,25 +1,23 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const views = require('../util/views.js');
+const router = require("../router.js");
+const views = require("../util/views.js");
-const holderTemplate = views.getTemplate('endless-pager');
-const pageTemplate = views.getTemplate('endless-pager-page');
+const holderTemplate = views.getTemplate("endless-pager");
+const pageTemplate = views.getTemplate("endless-pager-page");
function isScrolledIntoView(element) {
let top = 0;
do {
top += element.offsetTop || 0;
element = element.offsetParent;
- } while(element);
- return (
- (top >= window.scrollY) &&
- (top <= window.scrollY + window.innerHeight));
+ } while (element);
+ return top >= window.scrollY && top <= window.scrollY + window.innerHeight;
}
class EndlessPageView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, holderTemplate());
}
@@ -40,12 +38,13 @@ class EndlessPageView {
this.defaultLimit = parseInt(ctx.parameters.limit || ctx.defaultLimit);
const initialOffset = parseInt(ctx.parameters.offset || 0);
- this._loadPage(ctx, initialOffset, this.defaultLimit, true)
- .then(pageNode => {
+ this._loadPage(ctx, initialOffset, this.defaultLimit, true).then(
+ (pageNode) => {
if (initialOffset !== 0) {
pageNode.scrollIntoView();
}
- });
+ }
+ );
this._timeout = window.setInterval(() => {
window.requestAnimationFrame(() => {
@@ -58,19 +57,19 @@ class EndlessPageView {
}
get pageHeaderHolderNode() {
- return this._hostNode.querySelector('.page-header-holder');
+ return this._hostNode.querySelector(".page-header-holder");
}
get topPageGuardNode() {
- return this._hostNode.querySelector('.page-guard.top');
+ return this._hostNode.querySelector(".page-guard.top");
}
get bottomPageGuardNode() {
- return this._hostNode.querySelector('.page-guard.bottom');
+ return this._hostNode.querySelector(".page-guard.bottom");
}
get _pagesHolderNode() {
- return this._hostNode.querySelector('.pages-holder');
+ return this._hostNode.querySelector(".pages-holder");
}
_destroy() {
@@ -82,9 +81,10 @@ class EndlessPageView {
let topPageNode = null;
let element = document.elementFromPoint(
window.innerWidth / 2,
- window.innerHeight / 2);
+ window.innerHeight / 2
+ );
while (element.parentNode !== null) {
- if (element.classList.contains('page')) {
+ if (element.classList.contains("page")) {
topPageNode = element;
break;
}
@@ -93,15 +93,17 @@ class EndlessPageView {
if (!topPageNode) {
return;
}
- let topOffset = parseInt(topPageNode.getAttribute('data-offset'));
- let topLimit = parseInt(topPageNode.getAttribute('data-limit'));
+ let topOffset = parseInt(topPageNode.getAttribute("data-offset"));
+ let topLimit = parseInt(topPageNode.getAttribute("data-limit"));
if (topOffset !== this.currentOffset) {
router.replace(
ctx.getClientUrlForPage(
topOffset,
- topLimit === ctx.defaultLimit ? null : topLimit),
+ topLimit === ctx.defaultLimit ? null : topLimit
+ ),
ctx.state,
- false);
+ false
+ );
this.currentOffset = topOffset;
}
}
@@ -115,43 +117,47 @@ class EndlessPageView {
return;
}
- if (this.minOffsetShown > 0 &&
- isScrolledIntoView(this.topPageGuardNode)) {
+ if (
+ this.minOffsetShown > 0 &&
+ isScrolledIntoView(this.topPageGuardNode)
+ ) {
this._loadPage(
ctx,
this.minOffsetShown - this.defaultLimit,
this.defaultLimit,
- false);
+ false
+ );
}
- if (this.maxOffsetShown < this.totalRecords &&
- isScrolledIntoView(this.bottomPageGuardNode)) {
- this._loadPage(
- ctx,
- this.maxOffsetShown,
- this.defaultLimit,
- true);
+ if (
+ this.maxOffsetShown < this.totalRecords &&
+ isScrolledIntoView(this.bottomPageGuardNode)
+ ) {
+ this._loadPage(ctx, this.maxOffsetShown, this.defaultLimit, true);
}
}
_loadPage(ctx, offset, limit, append) {
this._runningRequests++;
return new Promise((resolve, reject) => {
- ctx.requestPage(offset, limit).then(response => {
- if (!this._active) {
+ ctx.requestPage(offset, limit).then(
+ (response) => {
+ if (!this._active) {
+ this._runningRequests--;
+ return Promise.reject();
+ }
+ window.requestAnimationFrame(() => {
+ let pageNode = this._renderPage(ctx, append, response);
+ this._runningRequests--;
+ resolve(pageNode);
+ });
+ },
+ (error) => {
+ this.showError(error.message);
this._runningRequests--;
- return Promise.reject();
+ reject();
}
- window.requestAnimationFrame(() => {
- let pageNode = this._renderPage(ctx, append, response);
- this._runningRequests--;
- resolve(pageNode);
- });
- }, error => {
- this.showError(error.message);
- this._runningRequests--;
- reject();
- });
+ );
});
}
@@ -162,30 +168,35 @@ class EndlessPageView {
pageNode = pageTemplate({
totalPages: Math.ceil(response.total / response.limit),
page: Math.ceil(
- (response.offset + response.limit) / response.limit),
+ (response.offset + response.limit) / response.limit
+ ),
});
- pageNode.setAttribute('data-offset', response.offset);
- pageNode.setAttribute('data-limit', response.limit);
+ pageNode.setAttribute("data-offset", response.offset);
+ pageNode.setAttribute("data-limit", response.limit);
ctx.pageRenderer({
parameters: ctx.parameters,
response: response,
- hostNode: pageNode.querySelector('.page-content-holder'),
+ hostNode: pageNode.querySelector(".page-content-holder"),
});
this.totalRecords = response.total;
- if (response.offset < this.minOffsetShown ||
- this.minOffsetShown === null) {
+ if (
+ response.offset < this.minOffsetShown ||
+ this.minOffsetShown === null
+ ) {
this.minOffsetShown = response.offset;
}
- if (response.offset + response.results.length
- > this.maxOffsetShown ||
- this.maxOffsetShown === null) {
+ if (
+ response.offset + response.results.length >
+ this.maxOffsetShown ||
+ this.maxOffsetShown === null
+ ) {
this.maxOffsetShown =
response.offset + response.results.length;
}
- response.results.addEventListener('remove', e => {
+ response.results.addEventListener("remove", (e) => {
this.maxOffsetShown--;
this.totalRecords--;
});
@@ -200,10 +211,11 @@ class EndlessPageView {
window.scroll(
window.scrollX,
- window.scrollY + pageNode.offsetHeight);
+ window.scrollY + pageNode.offsetHeight
+ );
}
} else if (!response.results.length) {
- this.showInfo('No data to show');
+ this.showInfo("No data to show");
}
this._initialPageLoad = false;
diff --git a/client/js/views/help_view.js b/client/js/views/help_view.js
index 11f6a39..a88b016 100644
--- a/client/js/views/help_view.js
+++ b/client/js/views/help_view.js
@@ -1,72 +1,81 @@
-'use strict';
+"use strict";
-const api = require('../api.js');
-const views = require('../util/views.js');
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('help');
+const template = views.getTemplate("help");
const sectionTemplates = {
- 'about': views.getTemplate('help-about'),
- 'keyboard': views.getTemplate('help-keyboard'),
- 'search': views.getTemplate('help-search'),
- 'comments': views.getTemplate('help-comments'),
- 'tos': views.getTemplate('help-tos'),
+ about: views.getTemplate("help-about"),
+ keyboard: views.getTemplate("help-keyboard"),
+ search: views.getTemplate("help-search"),
+ comments: views.getTemplate("help-comments"),
+ tos: views.getTemplate("help-tos"),
};
const subsectionTemplates = {
- 'search': {
- 'default': views.getTemplate('help-search-general'),
- 'posts': views.getTemplate('help-search-posts'),
- 'users': views.getTemplate('help-search-users'),
- 'tags': views.getTemplate('help-search-tags'),
+ search: {
+ default: views.getTemplate("help-search-general"),
+ posts: views.getTemplate("help-search-posts"),
+ users: views.getTemplate("help-search-users"),
+ tags: views.getTemplate("help-search-tags"),
+ pools: views.getTemplate("help-search-pools"),
},
};
class HelpView {
constructor(section, subsection) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
const sourceNode = template();
const ctx = {
name: api.getName(),
};
- section = section || 'about';
+ section = section || "about";
if (section in sectionTemplates) {
views.replaceContent(
- sourceNode.querySelector('.content'),
- sectionTemplates[section](ctx));
+ sourceNode.querySelector(".content"),
+ sectionTemplates[section](ctx)
+ );
}
- subsection = subsection || 'default';
- if (section in subsectionTemplates &&
- subsection in subsectionTemplates[section]) {
+ subsection = subsection || "default";
+ if (
+ section in subsectionTemplates &&
+ subsection in subsectionTemplates[section]
+ ) {
views.replaceContent(
- sourceNode.querySelector('.subcontent'),
- subsectionTemplates[section][subsection](ctx));
+ sourceNode.querySelector(".subcontent"),
+ subsectionTemplates[section][subsection](ctx)
+ );
}
views.replaceContent(this._hostNode, sourceNode);
- for (let itemNode of
- sourceNode.querySelectorAll('.primary [data-name]')) {
+ for (let itemNode of sourceNode.querySelectorAll(
+ ".primary [data-name]"
+ )) {
itemNode.classList.toggle(
- 'active',
- itemNode.getAttribute('data-name') === section);
- if (itemNode.getAttribute('data-name') === section) {
+ "active",
+ itemNode.getAttribute("data-name") === section
+ );
+ if (itemNode.getAttribute("data-name") === section) {
itemNode.parentNode.scrollLeft =
itemNode.getBoundingClientRect().left -
- itemNode.parentNode.getBoundingClientRect().left
+ itemNode.parentNode.getBoundingClientRect().left;
}
}
- for (let itemNode of
- sourceNode.querySelectorAll('.secondary [data-name]')) {
+ for (let itemNode of sourceNode.querySelectorAll(
+ ".secondary [data-name]"
+ )) {
itemNode.classList.toggle(
- 'active',
- itemNode.getAttribute('data-name') === subsection);
- if (itemNode.getAttribute('data-name') === subsection) {
+ "active",
+ itemNode.getAttribute("data-name") === subsection
+ );
+ if (itemNode.getAttribute("data-name") === subsection) {
itemNode.parentNode.scrollLeft =
itemNode.getBoundingClientRect().left -
- itemNode.parentNode.getBoundingClientRect().left
+ itemNode.parentNode.getBoundingClientRect().left;
}
}
diff --git a/client/js/views/home_view.js b/client/js/views/home_view.js
index c926705..c91363b 100644
--- a/client/js/views/home_view.js
+++ b/client/js/views/home_view.js
@@ -1,22 +1,20 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const uri = require('../util/uri.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const PostContentControl = require('../controls/post_content_control.js');
-const PostNotesOverlayControl
- = require('../controls/post_notes_overlay_control.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+const router = require("../router.js");
+const uri = require("../util/uri.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const PostContentControl = require("../controls/post_content_control.js");
+const PostNotesOverlayControl = require("../controls/post_notes_overlay_control.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
-const template = views.getTemplate('home');
-const footerTemplate = views.getTemplate('home-footer');
-const featuredPostTemplate = views.getTemplate('home-featured-post');
+const template = views.getTemplate("home");
+const footerTemplate = views.getTemplate("home-footer");
+const featuredPostTemplate = views.getTemplate("home-featured-post");
class HomeView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._ctx = ctx;
const sourceNode = template(ctx);
@@ -27,12 +25,16 @@ class HomeView {
this._autoCompleteControl = new TagAutoCompleteControl(
this._searchInputNode,
{
- confirm: tag =>
+ confirm: (tag) =>
this._autoCompleteControl.replaceSelectedText(
- misc.escapeSearchTerm(tag.names[0]), true),
- });
- this._formNode.addEventListener(
- 'submit', e => this._evtFormSubmit(e));
+ misc.escapeSearchTerm(tag.names[0]),
+ true
+ ),
+ }
+ );
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
}
}
@@ -47,60 +49,67 @@ class HomeView {
setStats(stats) {
views.replaceContent(
this._footerContainerNode,
- footerTemplate(Object.assign({}, stats, this._ctx)));
+ footerTemplate(Object.assign({}, stats, this._ctx))
+ );
}
setFeaturedPost(postInfo) {
views.replaceContent(
- this._postInfoContainerNode, featuredPostTemplate(postInfo));
+ this._postInfoContainerNode,
+ featuredPostTemplate(postInfo)
+ );
if (this._postContainerNode && postInfo.featuredPost) {
this._postContentControl = new PostContentControl(
this._postContainerNode,
postInfo.featuredPost,
() => {
- return [
- window.innerWidth * 0.8,
- window.innerHeight * 0.7,
- ];
+ return [window.innerWidth * 0.8, window.innerHeight * 0.7];
},
- 'fit-both');
+ "fit-both"
+ );
this._postNotesOverlay = new PostNotesOverlayControl(
- this._postContainerNode.querySelector('.post-overlay'),
- postInfo.featuredPost);
+ this._postContainerNode.querySelector(".post-overlay"),
+ postInfo.featuredPost
+ );
- if (postInfo.featuredPost.type === 'video'
- || postInfo.featuredPost.type === 'flash') {
+ if (
+ postInfo.featuredPost.type === "video" ||
+ postInfo.featuredPost.type === "flash"
+ ) {
this._postContentControl.disableOverlay();
}
}
}
get _footerContainerNode() {
- return this._hostNode.querySelector('.footer-container');
+ return this._hostNode.querySelector(".footer-container");
}
get _postInfoContainerNode() {
- return this._hostNode.querySelector('.post-info-container');
+ return this._hostNode.querySelector(".post-info-container");
}
get _postContainerNode() {
- return this._hostNode.querySelector('.post-container');
+ return this._hostNode.querySelector(".post-container");
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _searchInputNode() {
- return this._formNode.querySelector('input[name=search-text]');
+ return this._formNode.querySelector("input[name=search-text]");
}
_evtFormSubmit(e) {
e.preventDefault();
this._searchInputNode.blur();
- router.show(uri.formatClientLink('posts', {
- query: this._searchInputNode.value}));
+ router.show(
+ uri.formatClientLink("posts", {
+ query: this._searchInputNode.value,
+ })
+ );
}
}
diff --git a/client/js/views/login_view.js b/client/js/views/login_view.js
index 2c05332..64d49f9 100644
--- a/client/js/views/login_view.js
+++ b/client/js/views/login_view.js
@@ -1,52 +1,63 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('login');
+const template = views.getTemplate("login");
class LoginView extends events.EventTarget {
constructor() {
super();
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
- views.replaceContent(this._hostNode, template({
- userNamePattern: api.getUserNameRegex(),
- passwordPattern: api.getPasswordRegex(),
- canSendMails: api.canSendMails(),
- }));
+ views.replaceContent(
+ this._hostNode,
+ template({
+ userNamePattern: api.getUserNameRegex(),
+ passwordPattern: api.getPasswordRegex(),
+ canSendMails: api.canSendMails(),
+ })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._userNameInputNode.setAttribute('pattern', api.getUserNameRegex());
- this._passwordInputNode.setAttribute('pattern', api.getPasswordRegex());
- this._formNode.addEventListener('submit', e => {
+ this._userNameInputNode.setAttribute(
+ "pattern",
+ api.getUserNameRegex()
+ );
+ this._passwordInputNode.setAttribute(
+ "pattern",
+ api.getPasswordRegex()
+ );
+ this._formNode.addEventListener("submit", (e) => {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- name: this._userNameInputNode.value,
- password: this._passwordInputNode.value,
- remember: this._rememberInputNode.checked,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ name: this._userNameInputNode.value,
+ password: this._passwordInputNode.value,
+ remember: this._rememberInputNode.checked,
+ },
+ })
+ );
});
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _userNameInputNode() {
- return this._formNode.querySelector('[name=name]');
+ return this._formNode.querySelector("[name=name]");
}
get _passwordInputNode() {
- return this._formNode.querySelector('[name=password]');
+ return this._formNode.querySelector("[name=password]");
}
get _rememberInputNode() {
- return this._formNode.querySelector('[name=remember-user]');
+ return this._formNode.querySelector("[name=remember-user]");
}
disableForm() {
diff --git a/client/js/views/manual_page_view.js b/client/js/views/manual_page_view.js
index 94394a3..390994d 100644
--- a/client/js/views/manual_page_view.js
+++ b/client/js/views/manual_page_view.js
@@ -1,15 +1,15 @@
-'use strict';
+"use strict";
-const router = require('../router.js');
-const keyboard = require('../util/keyboard.js');
-const views = require('../util/views.js');
+const router = require("../router.js");
+const keyboard = require("../util/keyboard.js");
+const views = require("../util/views.js");
-const holderTemplate = views.getTemplate('manual-pager');
-const navTemplate = views.getTemplate('manual-pager-nav');
+const holderTemplate = views.getTemplate("manual-pager");
+const navTemplate = views.getTemplate("manual-pager-nav");
function _removeConsecutiveDuplicates(a) {
return a.filter((item, pos, ary) => {
- return !pos || item != ary[pos - 1];
+ return !pos || item !== ary[pos - 1];
});
}
@@ -22,32 +22,36 @@ function _getVisiblePageNumbers(currentPage, totalPages) {
for (let i = totalPages - threshold; i <= totalPages; i++) {
pagesVisible.push(i);
}
- for (let i = currentPage - threshold;
- i <= currentPage + threshold;
- i++) {
+ for (let i = currentPage - threshold; i <= currentPage + threshold; i++) {
pagesVisible.push(i);
}
pagesVisible = pagesVisible.filter((item, pos, ary) => {
return item >= 1 && item <= totalPages;
});
- pagesVisible = pagesVisible.sort((a, b) => { return a - b; });
+ pagesVisible = pagesVisible.sort((a, b) => {
+ return a - b;
+ });
pagesVisible = _removeConsecutiveDuplicates(pagesVisible);
return pagesVisible;
}
function _getPages(
- currentPage, pageNumbers, limit, defaultLimit, removedItems) {
+ currentPage,
+ pageNumbers,
+ limit,
+ defaultLimit,
+ removedItems
+) {
const pages = new Map();
let prevPage = 0;
for (let page of pageNumbers) {
if (page !== prevPage + 1) {
- pages.set(page - 1, {ellipsis: true});
+ pages.set(page - 1, { ellipsis: true });
}
pages.set(page, {
number: page,
offset:
- (page - 1) * limit -
- (page > currentPage ? removedItems : 0),
+ (page - 1) * limit - (page > currentPage ? removedItems : 0),
limit: limit === defaultLimit ? null : limit,
active: currentPage === page,
});
@@ -58,7 +62,7 @@ function _getPages(
class ManualPageView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, holderTemplate());
}
@@ -68,52 +72,65 @@ class ManualPageView {
this.clearMessages();
views.emptyContent(this._pageNavNode);
- ctx.requestPage(offset, limit).then(response => {
- ctx.pageRenderer({
- parameters: ctx.parameters,
- response: response,
- hostNode: this._pageContentHolderNode,
- });
+ ctx.requestPage(offset, limit).then(
+ (response) => {
+ ctx.pageRenderer({
+ parameters: ctx.parameters,
+ response: response,
+ hostNode: this._pageContentHolderNode,
+ });
- keyboard.bind(['a', 'left'], () => {
- this._navigateToPrevNextPage('prev');
- });
- keyboard.bind(['d', 'right'], () => {
- this._navigateToPrevNextPage('next');
- });
+ keyboard.bind(["a", "left"], () => {
+ this._navigateToPrevNextPage("prev");
+ });
+ keyboard.bind(["d", "right"], () => {
+ this._navigateToPrevNextPage("next");
+ });
- let removedItems = 0;
- if (response.total) {
- this._refreshNav(
- offset, limit, response.total, removedItems, ctx);
- }
+ let removedItems = 0;
+ if (response.total) {
+ this._refreshNav(
+ offset,
+ limit,
+ response.total,
+ removedItems,
+ ctx
+ );
+ }
- if (!response.results.length) {
- this.showInfo('No data to show');
- }
+ if (!response.results.length) {
+ this.showInfo("No data to show");
+ }
- response.results.addEventListener('remove', e => {
- removedItems++;
- this._refreshNav(
- offset, limit, response.total, removedItems, ctx);
- });
+ response.results.addEventListener("remove", (e) => {
+ removedItems++;
+ this._refreshNav(
+ offset,
+ limit,
+ response.total,
+ removedItems,
+ ctx
+ );
+ });
- views.syncScrollPosition();
- }, response => {
- this.showError(response.message);
- });
+ views.syncScrollPosition();
+ },
+ (response) => {
+ this.showError(response.message);
+ }
+ );
}
get pageHeaderHolderNode() {
- return this._hostNode.querySelector('.page-header-holder');
+ return this._hostNode.querySelector(".page-header-holder");
}
get _pageContentHolderNode() {
- return this._hostNode.querySelector('.page-content-holder');
+ return this._hostNode.querySelector(".page-content-holder");
}
get _pageNavNode() {
- return this._hostNode.querySelector('.page-nav');
+ return this._hostNode.querySelector(".page-nav");
}
clearMessages() {
@@ -133,11 +150,11 @@ class ManualPageView {
}
_navigateToPrevNextPage(className) {
- const linkNode = this._hostNode.querySelector('a.' + className);
- if (linkNode.classList.contains('disabled')) {
+ const linkNode = this._hostNode.querySelector("a." + className);
+ if (linkNode.classList.contains("disabled")) {
return;
}
- router.show(linkNode.getAttribute('href'));
+ router.show(linkNode.getAttribute("href"));
}
_refreshNav(offset, limit, total, removedItems, ctx) {
@@ -145,7 +162,12 @@ class ManualPageView {
const totalPages = Math.ceil((total - removedItems) / limit);
const pageNumbers = _getVisiblePageNumbers(currentPage, totalPages);
const pages = _getPages(
- currentPage, pageNumbers, limit, ctx.defaultLimit, removedItems);
+ currentPage,
+ pageNumbers,
+ limit,
+ ctx.defaultLimit,
+ removedItems
+ );
views.replaceContent(
this._pageNavNode,
@@ -156,7 +178,8 @@ class ManualPageView {
currentPage: currentPage,
totalPages: totalPages,
pages: pages,
- }));
+ })
+ );
}
}
diff --git a/client/js/views/not_found_view.js b/client/js/views/not_found_view.js
index 487613b..c930b09 100644
--- a/client/js/views/not_found_view.js
+++ b/client/js/views/not_found_view.js
@@ -1,14 +1,14 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('not-found');
+const template = views.getTemplate("not-found");
class NotFoundView {
constructor(path) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
- const sourceNode = template({path: path});
+ const sourceNode = template({ path: path });
views.replaceContent(this._hostNode, sourceNode);
views.syncScrollPosition();
}
diff --git a/client/js/views/password_reset_view.js b/client/js/views/password_reset_view.js
index 685fe5a..82a7d50 100644
--- a/client/js/views/password_reset_view.js
+++ b/client/js/views/password_reset_view.js
@@ -1,30 +1,35 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('password-reset');
+const template = views.getTemplate("password-reset");
class PasswordResetView extends events.EventTarget {
constructor() {
super();
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
- views.replaceContent(this._hostNode, template({
- canSendMails: api.canSendMails(),
- contactEmail: api.getContactEmail(),
- }));
+ views.replaceContent(
+ this._hostNode,
+ template({
+ canSendMails: api.canSendMails(),
+ contactEmail: api.getContactEmail(),
+ })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => {
+ this._formNode.addEventListener("submit", (e) => {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- userNameOrEmail: this._userNameOrEmailFieldNode.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ userNameOrEmail: this._userNameOrEmailFieldNode.value,
+ },
+ })
+ );
});
}
@@ -49,11 +54,11 @@ class PasswordResetView extends events.EventTarget {
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _userNameOrEmailFieldNode() {
- return this._formNode.querySelector('[name=user-name]');
+ return this._formNode.querySelector("[name=user-name]");
}
}
diff --git a/client/js/views/pool_categories_view.js b/client/js/views/pool_categories_view.js
new file mode 100644
index 0000000..ac381d5
--- /dev/null
+++ b/client/js/views/pool_categories_view.js
@@ -0,0 +1,174 @@
+"use strict";
+
+const events = require("../events.js");
+const views = require("../util/views.js");
+const PoolCategory = require("../models/pool_category.js");
+
+const template = views.getTemplate("pool-categories");
+const rowTemplate = views.getTemplate("pool-category-row");
+
+class PoolCategoriesView extends events.EventTarget {
+ constructor(ctx) {
+ super();
+ this._ctx = ctx;
+ this._hostNode = document.getElementById("content-holder");
+
+ views.replaceContent(this._hostNode, template(ctx));
+ views.syncScrollPosition();
+ views.decorateValidator(this._formNode);
+
+ const categoriesToAdd = Array.from(ctx.poolCategories);
+ categoriesToAdd.sort((a, b) => {
+ if (b.isDefault) {
+ return 1;
+ } else if (a.isDefault) {
+ return -1;
+ }
+ return a.name.localeCompare(b.name);
+ });
+ for (let poolCategory of categoriesToAdd) {
+ this._addPoolCategoryRowNode(poolCategory);
+ }
+
+ if (this._addLinkNode) {
+ this._addLinkNode.addEventListener("click", (e) =>
+ this._evtAddButtonClick(e)
+ );
+ }
+
+ ctx.poolCategories.addEventListener("add", (e) =>
+ this._evtPoolCategoryAdded(e)
+ );
+
+ ctx.poolCategories.addEventListener("remove", (e) =>
+ this._evtPoolCategoryDeleted(e)
+ );
+
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtSaveButtonClick(e, ctx)
+ );
+ }
+
+ enableForm() {
+ views.enableForm(this._formNode);
+ }
+
+ disableForm() {
+ views.disableForm(this._formNode);
+ }
+
+ clearMessages() {
+ views.clearMessages(this._hostNode);
+ }
+
+ showSuccess(message) {
+ views.showSuccess(this._hostNode, message);
+ }
+
+ showError(message) {
+ views.showError(this._hostNode, message);
+ }
+
+ get _formNode() {
+ return this._hostNode.querySelector("form");
+ }
+
+ get _tableBodyNode() {
+ return this._hostNode.querySelector("tbody");
+ }
+
+ get _addLinkNode() {
+ return this._hostNode.querySelector("a.add");
+ }
+
+ _addPoolCategoryRowNode(poolCategory) {
+ const rowNode = rowTemplate(
+ Object.assign({}, this._ctx, { poolCategory: poolCategory })
+ );
+
+ const nameInput = rowNode.querySelector(".name input");
+ if (nameInput) {
+ nameInput.addEventListener("change", (e) =>
+ this._evtNameChange(e, rowNode)
+ );
+ }
+
+ const colorInput = rowNode.querySelector(".color input");
+ if (colorInput) {
+ colorInput.addEventListener("change", (e) =>
+ this._evtColorChange(e, rowNode)
+ );
+ }
+
+ const removeLinkNode = rowNode.querySelector(".remove a");
+ if (removeLinkNode) {
+ removeLinkNode.addEventListener("click", (e) =>
+ this._evtDeleteButtonClick(e, rowNode)
+ );
+ }
+
+ const defaultLinkNode = rowNode.querySelector(".set-default a");
+ if (defaultLinkNode) {
+ defaultLinkNode.addEventListener("click", (e) =>
+ this._evtSetDefaultButtonClick(e, rowNode)
+ );
+ }
+
+ this._tableBodyNode.appendChild(rowNode);
+
+ rowNode._poolCategory = poolCategory;
+ poolCategory._rowNode = rowNode;
+ }
+
+ _removePoolCategoryRowNode(poolCategory) {
+ const rowNode = poolCategory._rowNode;
+ rowNode.parentNode.removeChild(rowNode);
+ }
+
+ _evtPoolCategoryAdded(e) {
+ this._addPoolCategoryRowNode(e.detail.poolCategory);
+ }
+
+ _evtPoolCategoryDeleted(e) {
+ this._removePoolCategoryRowNode(e.detail.poolCategory);
+ }
+
+ _evtAddButtonClick(e) {
+ e.preventDefault();
+ this._ctx.poolCategories.add(new PoolCategory());
+ }
+
+ _evtNameChange(e, rowNode) {
+ rowNode._poolCategory.name = e.target.value;
+ }
+
+ _evtColorChange(e, rowNode) {
+ e.target.value = e.target.value.toLowerCase();
+ rowNode._poolCategory.color = e.target.value;
+ }
+
+ _evtDeleteButtonClick(e, rowNode, link) {
+ e.preventDefault();
+ if (e.target.classList.contains("inactive")) {
+ return;
+ }
+ this._ctx.poolCategories.remove(rowNode._poolCategory);
+ }
+
+ _evtSetDefaultButtonClick(e, rowNode) {
+ e.preventDefault();
+ this._ctx.poolCategories.defaultCategory = rowNode._poolCategory;
+ const oldRowNode = rowNode.parentNode.querySelector("tr.default");
+ if (oldRowNode) {
+ oldRowNode.classList.remove("default");
+ }
+ rowNode.classList.add("default");
+ }
+
+ _evtSaveButtonClick(e, ctx) {
+ e.preventDefault();
+ this.dispatchEvent(new CustomEvent("submit"));
+ }
+}
+
+module.exports = PoolCategoriesView;
diff --git a/client/js/views/pool_create_view.js b/client/js/views/pool_create_view.js
new file mode 100644
index 0000000..fc75f45
--- /dev/null
+++ b/client/js/views/pool_create_view.js
@@ -0,0 +1,140 @@
+"use strict";
+
+const events = require("../events.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const Pool = require("../models/pool.js");
+
+const template = views.getTemplate("pool-create");
+
+class PoolCreateView extends events.EventTarget {
+ constructor(ctx) {
+ super();
+
+ this._hostNode = document.getElementById("content-holder");
+ views.replaceContent(this._hostNode, template(ctx));
+
+ views.decorateValidator(this._formNode);
+
+ if (this._namesFieldNode) {
+ this._namesFieldNode.addEventListener("input", (e) =>
+ this._evtNameInput(e)
+ );
+ }
+
+ if (this._postsFieldNode) {
+ this._postsFieldNode.addEventListener("input", (e) =>
+ this._evtPostsInput(e)
+ );
+ }
+
+ for (let node of this._formNode.querySelectorAll(
+ "input, select, textarea, posts"
+ )) {
+ node.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ });
+ }
+
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
+ }
+
+ clearMessages() {
+ views.clearMessages(this._hostNode);
+ }
+
+ enableForm() {
+ views.enableForm(this._formNode);
+ }
+
+ disableForm() {
+ views.disableForm(this._formNode);
+ }
+
+ showSuccess(message) {
+ views.showSuccess(this._hostNode, message);
+ }
+
+ showError(message) {
+ views.showError(this._hostNode, message);
+ }
+
+ _evtNameInput(e) {
+ const regex = new RegExp(api.getPoolNameRegex());
+ const list = misc.splitByWhitespace(this._namesFieldNode.value);
+
+ if (!list.length) {
+ this._namesFieldNode.setCustomValidity(
+ "Pools must have at least one name."
+ );
+ return;
+ }
+
+ for (let item of list) {
+ if (!regex.test(item)) {
+ this._namesFieldNode.setCustomValidity(
+ `Pool name "${item}" contains invalid symbols.`
+ );
+ return;
+ }
+ }
+
+ this._namesFieldNode.setCustomValidity("");
+ }
+
+ _evtPostsInput(e) {
+ const regex = /^\d+$/;
+ const list = misc.splitByWhitespace(this._postsFieldNode.value);
+
+ for (let item of list) {
+ if (!regex.test(item)) {
+ this._postsFieldNode.setCustomValidity(
+ `Pool ID "${item}" is not an integer.`
+ );
+ return;
+ }
+ }
+
+ this._postsFieldNode.setCustomValidity("");
+ }
+
+ _evtSubmit(e) {
+ e.preventDefault();
+
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ names: misc.splitByWhitespace(this._namesFieldNode.value),
+ category: this._categoryFieldNode.value,
+ description: this._descriptionFieldNode.value,
+ posts: misc
+ .splitByWhitespace(this._postsFieldNode.value)
+ .map((i) => parseInt(i)),
+ },
+ })
+ );
+ }
+
+ get _formNode() {
+ return this._hostNode.querySelector("form");
+ }
+
+ get _namesFieldNode() {
+ return this._formNode.querySelector(".names input");
+ }
+
+ get _categoryFieldNode() {
+ return this._formNode.querySelector(".category select");
+ }
+
+ get _descriptionFieldNode() {
+ return this._formNode.querySelector(".description textarea");
+ }
+
+ get _postsFieldNode() {
+ return this._formNode.querySelector(".posts input");
+ }
+}
+
+module.exports = PoolCreateView;
diff --git a/client/js/views/pool_delete_view.js b/client/js/views/pool_delete_view.js
new file mode 100644
index 0000000..fa92a49
--- /dev/null
+++ b/client/js/views/pool_delete_view.js
@@ -0,0 +1,55 @@
+"use strict";
+
+const events = require("../events.js");
+const views = require("../util/views.js");
+
+const template = views.getTemplate("pool-delete");
+
+class PoolDeleteView extends events.EventTarget {
+ constructor(ctx) {
+ super();
+
+ this._hostNode = ctx.hostNode;
+ this._pool = ctx.pool;
+ views.replaceContent(this._hostNode, template(ctx));
+ views.decorateValidator(this._formNode);
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
+ }
+
+ clearMessages() {
+ views.clearMessages(this._hostNode);
+ }
+
+ enableForm() {
+ views.enableForm(this._formNode);
+ }
+
+ disableForm() {
+ views.disableForm(this._formNode);
+ }
+
+ showSuccess(message) {
+ views.showSuccess(this._hostNode, message);
+ }
+
+ showError(message) {
+ views.showError(this._hostNode, message);
+ }
+
+ _evtSubmit(e) {
+ e.preventDefault();
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ pool: this._pool,
+ },
+ })
+ );
+ }
+
+ get _formNode() {
+ return this._hostNode.querySelector("form");
+ }
+}
+
+module.exports = PoolDeleteView;
diff --git a/client/js/views/pool_edit_view.js b/client/js/views/pool_edit_view.js
new file mode 100644
index 0000000..b30ab9b
--- /dev/null
+++ b/client/js/views/pool_edit_view.js
@@ -0,0 +1,151 @@
+"use strict";
+
+const events = require("../events.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const Post = require("../models/post.js");
+
+const template = views.getTemplate("pool-edit");
+
+class PoolEditView extends events.EventTarget {
+ constructor(ctx) {
+ super();
+
+ this._pool = ctx.pool;
+ this._hostNode = ctx.hostNode;
+ views.replaceContent(this._hostNode, template(ctx));
+
+ views.decorateValidator(this._formNode);
+
+ if (this._namesFieldNode) {
+ this._namesFieldNode.addEventListener("input", (e) =>
+ this._evtNameInput(e)
+ );
+ }
+
+ if (this._postsFieldNode) {
+ this._postsFieldNode.addEventListener("input", (e) =>
+ this._evtPostsInput(e)
+ );
+ }
+
+ for (let node of this._formNode.querySelectorAll(
+ "input, select, textarea, posts"
+ )) {
+ node.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ });
+ }
+
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
+ }
+
+ clearMessages() {
+ views.clearMessages(this._hostNode);
+ }
+
+ enableForm() {
+ views.enableForm(this._formNode);
+ }
+
+ disableForm() {
+ views.disableForm(this._formNode);
+ }
+
+ showSuccess(message) {
+ views.showSuccess(this._hostNode, message);
+ }
+
+ showError(message) {
+ views.showError(this._hostNode, message);
+ }
+
+ _evtNameInput(e) {
+ const regex = new RegExp(api.getPoolNameRegex());
+ const list = misc.splitByWhitespace(this._namesFieldNode.value);
+
+ if (!list.length) {
+ this._namesFieldNode.setCustomValidity(
+ "Pools must have at least one name."
+ );
+ return;
+ }
+
+ for (let item of list) {
+ if (!regex.test(item)) {
+ this._namesFieldNode.setCustomValidity(
+ `Pool name "${item}" contains invalid symbols.`
+ );
+ return;
+ }
+ }
+
+ this._namesFieldNode.setCustomValidity("");
+ }
+
+ _evtPostsInput(e) {
+ const regex = /^\d+$/;
+ const list = misc.splitByWhitespace(this._postsFieldNode.value);
+
+ for (let item of list) {
+ if (!regex.test(item)) {
+ this._postsFieldNode.setCustomValidity(
+ `Pool ID "${item}" is not an integer.`
+ );
+ return;
+ }
+ }
+
+ this._postsFieldNode.setCustomValidity("");
+ }
+
+ _evtSubmit(e) {
+ e.preventDefault();
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ pool: this._pool,
+
+ names: this._namesFieldNode
+ ? misc.splitByWhitespace(this._namesFieldNode.value)
+ : undefined,
+
+ category: this._categoryFieldNode
+ ? this._categoryFieldNode.value
+ : undefined,
+
+ description: this._descriptionFieldNode
+ ? this._descriptionFieldNode.value
+ : undefined,
+
+ posts: this._postsFieldNode
+ ? misc.splitByWhitespace(this._postsFieldNode.value)
+ : undefined,
+ },
+ })
+ );
+ }
+
+ get _formNode() {
+ return this._hostNode.querySelector("form");
+ }
+
+ get _namesFieldNode() {
+ return this._formNode.querySelector(".names input");
+ }
+
+ get _categoryFieldNode() {
+ return this._formNode.querySelector(".category select");
+ }
+
+ get _descriptionFieldNode() {
+ return this._formNode.querySelector(".description textarea");
+ }
+
+ get _postsFieldNode() {
+ return this._formNode.querySelector(".posts input");
+ }
+}
+
+module.exports = PoolEditView;
diff --git a/client/js/views/pool_merge_view.js b/client/js/views/pool_merge_view.js
new file mode 100644
index 0000000..f0ca15a
--- /dev/null
+++ b/client/js/views/pool_merge_view.js
@@ -0,0 +1,84 @@
+"use strict";
+
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
+const PoolAutoCompleteControl = require("../controls/pool_auto_complete_control.js");
+
+const template = views.getTemplate("pool-merge");
+
+class PoolMergeView extends events.EventTarget {
+ constructor(ctx) {
+ super();
+
+ this._pool = ctx.pool;
+ this._hostNode = ctx.hostNode;
+ this._targetPoolId = null;
+ ctx.poolNamePattern = api.getPoolNameRegex();
+ views.replaceContent(this._hostNode, template(ctx));
+
+ views.decorateValidator(this._formNode);
+ if (this._targetPoolFieldNode) {
+ this._autoCompleteControl = new PoolAutoCompleteControl(
+ this._targetPoolFieldNode,
+ {
+ confirm: (pool) => {
+ this._targetPoolId = pool.id;
+ this._autoCompleteControl.replaceSelectedText(
+ pool.names[0],
+ false
+ );
+ },
+ }
+ );
+ }
+
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
+ }
+
+ clearMessages() {
+ views.clearMessages(this._hostNode);
+ }
+
+ enableForm() {
+ views.enableForm(this._formNode);
+ }
+
+ disableForm() {
+ views.disableForm(this._formNode);
+ }
+
+ showSuccess(message) {
+ views.showSuccess(this._hostNode, message);
+ }
+
+ showError(message) {
+ views.showError(this._hostNode, message);
+ }
+
+ _evtSubmit(e) {
+ e.preventDefault();
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ pool: this._pool,
+ targetPoolId: this._targetPoolId,
+ },
+ })
+ );
+ }
+
+ get _formNode() {
+ return this._hostNode.querySelector("form");
+ }
+
+ get _targetPoolFieldNode() {
+ return this._formNode.querySelector("input[name=target-pool]");
+ }
+
+ get _addAliasCheckboxNode() {
+ return this._formNode.querySelector("input[name=alias]");
+ }
+}
+
+module.exports = PoolMergeView;
diff --git a/client/js/views/pool_summary_view.js b/client/js/views/pool_summary_view.js
new file mode 100644
index 0000000..37ce1c2
--- /dev/null
+++ b/client/js/views/pool_summary_view.js
@@ -0,0 +1,23 @@
+"use strict";
+
+const views = require("../util/views.js");
+
+const template = views.getTemplate("pool-summary");
+
+class PoolSummaryView {
+ constructor(ctx) {
+ this._pool = ctx.pool;
+ this._hostNode = ctx.hostNode;
+ views.replaceContent(this._hostNode, template(ctx));
+ }
+
+ showSuccess(message) {
+ views.showSuccess(this._hostNode, message);
+ }
+
+ showError(message) {
+ views.showError(this._hostNode, message);
+ }
+}
+
+module.exports = PoolSummaryView;
diff --git a/client/js/views/pool_view.js b/client/js/views/pool_view.js
new file mode 100644
index 0000000..99c1b02
--- /dev/null
+++ b/client/js/views/pool_view.js
@@ -0,0 +1,108 @@
+"use strict";
+
+const events = require("../events.js");
+const views = require("../util/views.js");
+const misc = require("../util/misc.js");
+const PoolSummaryView = require("./pool_summary_view.js");
+const PoolEditView = require("./pool_edit_view.js");
+const PoolMergeView = require("./pool_merge_view.js");
+const PoolDeleteView = require("./pool_delete_view.js");
+const EmptyView = require("../views/empty_view.js");
+
+const template = views.getTemplate("pool");
+
+class PoolView extends events.EventTarget {
+ constructor(ctx) {
+ super();
+
+ this._ctx = ctx;
+ ctx.pool.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
+ ctx.getPrettyName = misc.getPrettyName;
+
+ this._hostNode = document.getElementById("content-holder");
+ this._install();
+ }
+
+ _install() {
+ const ctx = this._ctx;
+ views.replaceContent(this._hostNode, template(ctx));
+
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
+ item.classList.toggle(
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
+ item.parentNode.scrollLeft =
+ item.getBoundingClientRect().left -
+ item.parentNode.getBoundingClientRect().left;
+ }
+ }
+
+ ctx.hostNode = this._hostNode.querySelector(".pool-content-holder");
+ if (ctx.section === "edit") {
+ if (!this._ctx.canEditAnything) {
+ this._view = new EmptyView();
+ this._view.showError(
+ "You don't have privileges to edit pools."
+ );
+ } else {
+ this._view = new PoolEditView(ctx);
+ events.proxyEvent(this._view, this, "submit");
+ }
+ } else if (ctx.section === "merge") {
+ if (!this._ctx.canMerge) {
+ this._view = new EmptyView();
+ this._view.showError(
+ "You don't have privileges to merge pools."
+ );
+ } else {
+ this._view = new PoolMergeView(ctx);
+ events.proxyEvent(this._view, this, "submit", "merge");
+ }
+ } else if (ctx.section === "delete") {
+ if (!this._ctx.canDelete) {
+ this._view = new EmptyView();
+ this._view.showError(
+ "You don't have privileges to delete pools."
+ );
+ } else {
+ this._view = new PoolDeleteView(ctx);
+ events.proxyEvent(this._view, this, "submit", "delete");
+ }
+ } else {
+ this._view = new PoolSummaryView(ctx);
+ }
+
+ events.proxyEvent(this._view, this, "change");
+ views.syncScrollPosition();
+ }
+
+ clearMessages() {
+ this._view.clearMessages();
+ }
+
+ enableForm() {
+ this._view.enableForm();
+ }
+
+ disableForm() {
+ this._view.disableForm();
+ }
+
+ showSuccess(message) {
+ this._view.showSuccess(message);
+ }
+
+ showError(message) {
+ this._view.showError(message);
+ }
+
+ _evtChange(e) {
+ this._ctx.pool = e.detail.pool;
+ this._install(this._ctx);
+ }
+}
+
+module.exports = PoolView;
diff --git a/client/js/views/pools_header_view.js b/client/js/views/pools_header_view.js
new file mode 100644
index 0000000..cfc6c8b
--- /dev/null
+++ b/client/js/views/pools_header_view.js
@@ -0,0 +1,60 @@
+"use strict";
+
+const events = require("../events.js");
+const misc = require("../util/misc.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
+const PoolAutoCompleteControl = require("../controls/pool_auto_complete_control.js");
+
+const template = views.getTemplate("pools-header");
+
+class PoolsHeaderView extends events.EventTarget {
+ constructor(ctx) {
+ super();
+
+ this._hostNode = ctx.hostNode;
+ views.replaceContent(this._hostNode, template(ctx));
+
+ if (this._queryInputNode) {
+ this._autoCompleteControl = new PoolAutoCompleteControl(
+ this._queryInputNode,
+ {
+ confirm: (pool) =>
+ this._autoCompleteControl.replaceSelectedText(
+ misc.escapeSearchTerm(pool.names[0]),
+ true
+ ),
+ }
+ );
+ }
+
+ search.searchInputNodeFocusHelper(this._queryInputNode);
+
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
+ }
+
+ get _formNode() {
+ return this._hostNode.querySelector("form");
+ }
+
+ get _queryInputNode() {
+ return this._hostNode.querySelector("[name=search-text]");
+ }
+
+ _evtSubmit(e) {
+ e.preventDefault();
+ this._queryInputNode.blur();
+ this.dispatchEvent(
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: {
+ query: this._queryInputNode.value,
+ page: 1,
+ },
+ },
+ })
+ );
+ }
+}
+
+module.exports = PoolsHeaderView;
diff --git a/client/js/views/pools_page_view.js b/client/js/views/pools_page_view.js
new file mode 100644
index 0000000..6230ef6
--- /dev/null
+++ b/client/js/views/pools_page_view.js
@@ -0,0 +1,13 @@
+"use strict";
+
+const views = require("../util/views.js");
+
+const template = views.getTemplate("pools-page");
+
+class PoolsPageView {
+ constructor(ctx) {
+ views.replaceContent(ctx.hostNode, template(ctx));
+ }
+}
+
+module.exports = PoolsPageView;
diff --git a/client/js/views/post_detail_view.js b/client/js/views/post_detail_view.js
index 14786d3..587c41f 100644
--- a/client/js/views/post_detail_view.js
+++ b/client/js/views/post_detail_view.js
@@ -1,21 +1,21 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const PostMergeView = require('./post_merge_view.js');
-const EmptyView = require('../views/empty_view.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const PostMergeView = require("./post_merge_view.js");
+const EmptyView = require("../views/empty_view.js");
-const template = views.getTemplate('post-detail');
+const template = views.getTemplate("post-detail");
class PostDetailView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- ctx.post.addEventListener('change', e => this._evtChange(e));
- ctx.section = ctx.section || 'summary';
+ ctx.post.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._install();
}
@@ -23,28 +23,30 @@ class PostDetailView extends events.EventTarget {
const ctx = this._ctx;
views.replaceContent(this._hostNode, template(ctx));
- for (let item of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
item.classList.toggle(
- 'active', item.getAttribute('data-name') === ctx.section);
- if (item.getAttribute('data-name') === ctx.section) {
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
item.parentNode.scrollLeft =
item.getBoundingClientRect().left -
- item.parentNode.getBoundingClientRect().left
+ item.parentNode.getBoundingClientRect().left;
}
}
- ctx.hostNode = this._hostNode.querySelector('.post-content-holder');
- if (ctx.section === 'merge') {
+ ctx.hostNode = this._hostNode.querySelector(".post-content-holder");
+ if (ctx.section === "merge") {
if (!this._ctx.canMerge) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to merge posts.');
+ "You don't have privileges to merge posts."
+ );
} else {
this._view = new PostMergeView(ctx);
- events.proxyEvent(this._view, this, 'select');
- events.proxyEvent(this._view, this, 'submit', 'merge');
+ events.proxyEvent(this._view, this, "select");
+ events.proxyEvent(this._view, this, "submit", "merge");
}
-
} else {
// this._view = new PostSummaryView(ctx);
}
diff --git a/client/js/views/post_main_view.js b/client/js/views/post_main_view.js
index fbaabd2..5db8842 100644
--- a/client/js/views/post_main_view.js
+++ b/client/js/views/post_main_view.js
@@ -1,35 +1,33 @@
-'use strict';
+"use strict";
-const iosCorrectedInnerHeight = require('ios-inner-height');
-const router = require('../router.js');
-const views = require('../util/views.js');
-const uri = require('../util/uri.js');
-const keyboard = require('../util/keyboard.js');
-const Touch = require('../util/touch.js');
-const PostContentControl = require('../controls/post_content_control.js');
-const PostNotesOverlayControl =
- require('../controls/post_notes_overlay_control.js');
-const PostReadonlySidebarControl =
- require('../controls/post_readonly_sidebar_control.js');
-const PostEditSidebarControl =
- require('../controls/post_edit_sidebar_control.js');
-const CommentControl = require('../controls/comment_control.js');
-const CommentListControl = require('../controls/comment_list_control.js');
+const iosCorrectedInnerHeight = require("ios-inner-height");
+const router = require("../router.js");
+const views = require("../util/views.js");
+const uri = require("../util/uri.js");
+const keyboard = require("../util/keyboard.js");
+const Touch = require("../util/touch.js");
+const PostContentControl = require("../controls/post_content_control.js");
+const PostNotesOverlayControl = require("../controls/post_notes_overlay_control.js");
+const PostReadonlySidebarControl = require("../controls/post_readonly_sidebar_control.js");
+const PostEditSidebarControl = require("../controls/post_edit_sidebar_control.js");
+const CommentControl = require("../controls/comment_control.js");
+const CommentListControl = require("../controls/comment_list_control.js");
-const template = views.getTemplate('post-main');
+const template = views.getTemplate("post-main");
class PostMainView {
constructor(ctx) {
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
const sourceNode = template(ctx);
- const postContainerNode = sourceNode.querySelector('.post-container');
- const sidebarNode = sourceNode.querySelector('.sidebar');
+ const postContainerNode = sourceNode.querySelector(".post-container");
+ const sidebarNode = sourceNode.querySelector(".sidebar");
views.replaceContent(this._hostNode, sourceNode);
views.syncScrollPosition();
- const topNavigationNode =
- document.body.querySelector('#top-navigation');
+ const topNavigationNode = document.body.querySelector(
+ "#top-navigation"
+ );
this._postContentControl = new PostContentControl(
postContainerNode,
@@ -37,15 +35,18 @@ class PostMainView {
() => {
return [
postContainerNode.getBoundingClientRect().width,
- iosCorrectedInnerHeight() - postContainerNode.getBoundingClientRect().top,
+ iosCorrectedInnerHeight() -
+ postContainerNode.getBoundingClientRect().top,
];
- });
+ }
+ );
this._postNotesOverlayControl = new PostNotesOverlayControl(
- postContainerNode.querySelector('.post-overlay'),
- ctx.post);
+ postContainerNode.querySelector(".post-overlay"),
+ ctx.post
+ );
- if (ctx.post.type === 'video' || ctx.post.type === 'flash') {
+ if (ctx.post.type === "video" || ctx.post.type === "flash") {
this._postContentControl.disableOverlay();
}
@@ -72,17 +73,17 @@ class PostMainView {
}
};
- keyboard.bind('e', () => {
+ keyboard.bind("e", () => {
if (ctx.editMode) {
- router.show(uri.formatClientLink('post', ctx.post.id));
+ router.show(uri.formatClientLink("post", ctx.post.id));
} else {
- router.show(uri.formatClientLink('post', ctx.post.id, 'edit'));
+ router.show(uri.formatClientLink("post", ctx.post.id, "edit"));
}
});
- keyboard.bind(['a', 'left'], showPreviousImage);
- keyboard.bind(['d', 'right'], showNextImage);
- keyboard.bind('r', showRandomImage);
- keyboard.bind('del', (e) => {
+ keyboard.bind(["a", "left"], showPreviousImage);
+ keyboard.bind(["d", "right"], showNextImage);
+ keyboard.bind("r", showRandomImage);
+ keyboard.bind("del", (e) => {
if (ctx.editMode) {
this.sidebarControl._evtDeleteClick(e);
}
@@ -92,68 +93,82 @@ class PostMainView {
postContainerNode,
() => {
if (!ctx.editMode) {
- showNextImage()
+ showNextImage();
}
},
() => {
if (!ctx.editMode) {
- showPreviousImage()
+ showPreviousImage();
}
},
() => {},
(e) => {
if (!ctx.editMode && e.startScrollY === 0) {
- showRandomImage()
+ showRandomImage();
}
}
- )
+ );
}
_installSidebar(ctx) {
const sidebarContainerNode = document.querySelector(
- '#content-holder .sidebar-container');
+ "#content-holder .sidebar-container"
+ );
if (ctx.editMode) {
this.sidebarControl = new PostEditSidebarControl(
sidebarContainerNode,
ctx,
this._postContentControl,
- this._postNotesOverlayControl);
+ this._postNotesOverlayControl
+ );
} else {
this.sidebarControl = new PostReadonlySidebarControl(
- sidebarContainerNode, ctx, this._postContentControl);
+ sidebarContainerNode,
+ ctx,
+ this._postContentControl
+ );
}
}
_installCommentForm() {
const commentFormContainer = document.querySelector(
- '#content-holder .comment-form-container');
+ "#content-holder .comment-form-container"
+ );
if (!commentFormContainer) {
return null;
}
this.commentControl = new CommentControl(
- commentFormContainer, null, true);
+ commentFormContainer,
+ null,
+ true
+ );
return commentFormContainer;
}
_installAddCommentButton(commentForm) {
- const addCommentButton = document.querySelector('#add-comment-button');
+ const addCommentButton = document.querySelector("#add-comment-button");
if (!addCommentButton || !commentForm) {
return;
}
commentForm.hidden = true; // collapse by default
- addCommentButton.addEventListener('click', () => {commentForm.hidden = !commentForm.hidden});
+ addCommentButton.addEventListener("click", () => {
+ commentForm.hidden = !commentForm.hidden
+ });
}
_installComments(comments) {
const commentsContainerNode = document.querySelector(
- '#content-holder .comments-container');
+ "#content-holder .comments-container"
+ );
if (!commentsContainerNode) {
return;
}
this.commentListControl = new CommentListControl(
- commentsContainerNode, comments);
+ commentsContainerNode,
+ comments
+ );
}
}
diff --git a/client/js/views/post_merge_view.js b/client/js/views/post_merge_view.js
index 3e987b3..20924d3 100644
--- a/client/js/views/post_merge_view.js
+++ b/client/js/views/post_merge_view.js
@@ -1,11 +1,11 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
const KEY_RETURN = 13;
-const template = views.getTemplate('post-merge');
-const sideTemplate = views.getTemplate('post-merge-side');
+const template = views.getTemplate("post-merge");
+const sideTemplate = views.getTemplate("post-merge-side");
class PostMergeView extends events.EventTarget {
constructor(ctx) {
@@ -23,7 +23,7 @@ class PostMergeView extends events.EventTarget {
this._refreshLeftSide();
this._refreshRightSide();
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -52,48 +52,61 @@ class PostMergeView extends events.EventTarget {
}
_refreshLeftSide() {
- this._refreshSide(this._leftPost, this._leftSideNode, 'left', false);
+ this._refreshSide(this._leftPost, this._leftSideNode, "left", false);
}
_refreshRightSide() {
- this._refreshSide(this._rightPost, this._rightSideNode, 'right', true);
+ this._refreshSide(this._rightPost, this._rightSideNode, "right", true);
}
_refreshSide(post, sideNode, sideName, isEditable) {
views.replaceContent(
sideNode,
- sideTemplate(Object.assign({}, this._ctx, {
- post: post,
- name: sideName,
- editable: isEditable})));
+ sideTemplate(
+ Object.assign({}, this._ctx, {
+ post: post,
+ name: sideName,
+ editable: isEditable,
+ })
+ )
+ );
- let postIdNode = sideNode.querySelector('input[type=text]');
- let searchButtonNode = sideNode.querySelector('input[type=button]');
+ let postIdNode = sideNode.querySelector("input[type=text]");
+ let searchButtonNode = sideNode.querySelector("input[type=button]");
if (isEditable) {
- postIdNode.addEventListener(
- 'keydown', e => this._evtPostSearchFieldKeyDown(e));
- searchButtonNode.addEventListener(
- 'click', e => this._evtPostSearchButtonClick(e, postIdNode));
+ postIdNode.addEventListener("keydown", (e) =>
+ this._evtPostSearchFieldKeyDown(e)
+ );
+ searchButtonNode.addEventListener("click", (e) =>
+ this._evtPostSearchButtonClick(e, postIdNode)
+ );
}
}
_evtSubmit(e) {
e.preventDefault();
const checkedTargetPost = this._formNode.querySelector(
- '.target-post :checked').value;
+ ".target-post :checked"
+ ).value;
const checkedTargetPostContent = this._formNode.querySelector(
- '.target-post-content :checked').value;
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- post: checkedTargetPost == 'left' ?
- this._rightPost :
- this._leftPost,
- targetPost: checkedTargetPost == 'left' ?
- this._leftPost :
- this._rightPost,
- useOldContent: checkedTargetPostContent !== checkedTargetPost,
- },
- }));
+ ".target-post-content :checked"
+ ).value;
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ post:
+ checkedTargetPost === "left"
+ ? this._rightPost
+ : this._leftPost,
+ targetPost:
+ checkedTargetPost === "left"
+ ? this._leftPost
+ : this._rightPost,
+ useOldContent:
+ checkedTargetPostContent !== checkedTargetPost,
+ },
+ })
+ );
}
_evtPostSearchFieldKeyDown(e) {
@@ -103,33 +116,37 @@ class PostMergeView extends events.EventTarget {
}
e.target.blur();
e.preventDefault();
- this.dispatchEvent(new CustomEvent('select', {
- detail: {
- postId: e.target.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("select", {
+ detail: {
+ postId: e.target.value,
+ },
+ })
+ );
}
_evtPostSearchButtonClick(e, textNode) {
e.target.blur();
e.preventDefault();
- this.dispatchEvent(new CustomEvent('select', {
- detail: {
- postId: textNode.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("select", {
+ detail: {
+ postId: textNode.value,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _leftSideNode() {
- return this._hostNode.querySelector('.left-post-container');
+ return this._hostNode.querySelector(".left-post-container");
}
get _rightSideNode() {
- return this._hostNode.querySelector('.right-post-container');
+ return this._hostNode.querySelector(".right-post-container");
}
}
diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js
index 926344a..a9f4659 100644
--- a/client/js/views/post_upload_view.js
+++ b/client/js/views/post_upload_view.js
@@ -1,27 +1,30 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const FileDropperControl = require('../controls/file_dropper_control.js');
-const TagList = require('../models/tag_list.js');
-const TagInputControl = require('../controls/tag_input_control.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const FileDropperControl = require("../controls/file_dropper_control.js");
+const TagList = require("../models/tag_list.js");
+const TagInputControl = require("../controls/tag_input_control.js");
-const template = views.getTemplate('post-upload');
-const rowTemplate = views.getTemplate('post-upload-row');
+const template = views.getTemplate("post-upload");
+const rowTemplate = views.getTemplate("post-upload-row");
-const misc = require('../util/misc.js');
+const misc = require("../util/misc.js");
const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+ require("../controls/tag_auto_complete_control.js");
function _mimeTypeToPostType(mimeType) {
- return {
- 'application/x-shockwave-flash': 'flash',
- 'image/gif': 'image',
- 'image/jpeg': 'image',
- 'image/png': 'image',
- 'video/mp4': 'video',
- 'video/webm': 'video',
- }[mimeType] || 'unknown';
+ return (
+ {
+ "application/x-shockwave-flash": "flash",
+ "image/gif": "image",
+ "image/jpeg": "image",
+ "image/png": "image",
+ "image/webp": "image",
+ "video/mp4": "video",
+ "video/webm": "video",
+ }[mimeType] || "unknown"
+ );
}
class Uploadable extends events.EventTarget {
@@ -29,18 +32,17 @@ class Uploadable extends events.EventTarget {
super();
this.lookalikes = [];
this.lookalikesConfirmed = false;
- this.safety = 'safe';
+ this.safety = "safe";
this.flags = [];
this.tags = [];
this.relations = [];
this.anonymous = false;
}
- destroy() {
- }
+ destroy() {}
get mimeType() {
- return 'application/octet-stream';
+ return "application/octet-stream";
}
get type() {
@@ -48,17 +50,11 @@ class Uploadable extends events.EventTarget {
}
get key() {
- throw new Error('Not implemented');
+ throw new Error("Not implemented");
}
get name() {
- throw new Error('Not implemented');
- }
-
- _initComplete() {
- if (['video'].includes(this.type)) {
- this.flags.push('loop');
- }
+ throw new Error("Not implemented");
}
}
@@ -73,13 +69,13 @@ class File extends Uploadable {
} else {
let reader = new FileReader();
reader.readAsDataURL(file);
- reader.addEventListener('load', e => {
+ reader.addEventListener("load", (e) => {
this._previewUrl = e.target.result;
this.dispatchEvent(
- new CustomEvent('finish', {detail: {uploadable: this}}));
+ new CustomEvent("finish", { detail: { uploadable: this } })
+ );
});
}
- this._initComplete();
}
destroy() {
@@ -109,25 +105,25 @@ class Url extends Uploadable {
constructor(url) {
super();
this.url = url;
- this.dispatchEvent(new CustomEvent('finish'));
- this._initComplete();
+ this.dispatchEvent(new CustomEvent("finish"));
}
get mimeType() {
let mime = {
- 'swf': 'application/x-shockwave-flash',
- 'jpg': 'image/jpeg',
- 'png': 'image/png',
- 'gif': 'image/gif',
- 'mp4': 'video/mp4',
- 'webm': 'video/webm',
+ swf: "application/x-shockwave-flash",
+ jpg: "image/jpeg",
+ png: "image/png",
+ gif: "image/gif",
+ webp: "image/webp",
+ mp4: "video/mp4",
+ webm: "video/webm",
};
for (let extension of Object.keys(mime)) {
- if (this.url.toLowerCase().indexOf('.' + extension) !== -1) {
+ if (this.url.toLowerCase().indexOf("." + extension) !== -1) {
return mime[extension];
}
}
- return 'unknown';
+ return "unknown";
}
get previewUrl() {
@@ -147,7 +143,7 @@ class PostUploadView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template());
views.syncScrollPosition();
@@ -155,50 +151,56 @@ class PostUploadView extends events.EventTarget {
this._cancelButtonNode.disabled = true;
this._uploadables = [];
- this._uploadables.find = u => {
- return this._uploadables.findIndex(u2 => u.key === u2.key);
+ this._uploadables.find = (u) => {
+ return this._uploadables.findIndex((u2) => u.key === u2.key);
};
this._contentFileDropper = new FileDropperControl(
this._contentInputNode,
{
extraText:
- 'Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf',
+ "Allowed extensions: .jpg, .png, .gif, .webm, .mp4, .swf",
allowUrls: true,
allowMultiple: true,
lock: false,
- });
- this._contentFileDropper.addEventListener(
- 'fileadd', e => this._evtFilesAdded(e));
- this._contentFileDropper.addEventListener(
- 'urladd', e => this._evtUrlsAdded(e));
+ }
+ );
+ this._contentFileDropper.addEventListener("fileadd", (e) =>
+ this._evtFilesAdded(e)
+ );
+ this._contentFileDropper.addEventListener("urladd", (e) =>
+ this._evtUrlsAdded(e)
+ );
- this._skipDuplicatesCheckboxNode.addEventListener(
- 'change', e => this._evtSkipDuplicatesCheck(e, this._skipDuplicatesCheckboxNode.checked)
+ this._skipDuplicatesCheckboxNode.addEventListener("change", e =>
+ this._evtSkipDuplicatesCheck(e, this._skipDuplicatesCheckboxNode.checked)
);
this._copyTagsToOriginalsSpanNode.hidden = true;
- this._cancelButtonNode.addEventListener(
- 'click', e => this._evtCancelButtonClick(e));
- this._formNode.addEventListener('submit', e => this._evtFormSubmit(e));
- this._formNode.classList.add('inactive');
+ this._cancelButtonNode.addEventListener("click", (e) =>
+ this._evtCancelButtonClick(e)
+ );
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
+ this._formNode.classList.add("inactive");
if (this._tagInputNode) {
this._tagControl = new TagInputControl(
- this._tagInputNode, new TagList(), 'Type common tags…');
+ this._tagInputNode, new TagList(), "Type common tags…");
}
}
enableForm() {
views.enableForm(this._formNode);
this._cancelButtonNode.disabled = true;
- this._formNode.classList.remove('uploading');
+ this._formNode.classList.remove("uploading");
}
disableForm() {
views.disableForm(this._formNode);
this._cancelButtonNode.disabled = false;
- this._formNode.classList.add('uploading');
+ this._formNode.classList.add("uploading");
}
clearMessages() {
@@ -223,7 +225,7 @@ class PostUploadView extends events.EventTarget {
}
addUploadables(uploadables) {
- this._formNode.classList.remove('inactive');
+ this._formNode.classList.remove("inactive");
let duplicatesFound = 0;
for (let uploadable of uploadables) {
uploadable.safety = this._ctx.defaultSafety || uploadable.safety;
@@ -232,20 +234,22 @@ class PostUploadView extends events.EventTarget {
continue;
}
this._uploadables.push(uploadable);
- this._emit('change');
+ this._emit("change");
this._renderRowNode(uploadable);
- uploadable.addEventListener(
- 'finish', e => this._updateThumbnailNode(e.detail.uploadable));
+ uploadable.addEventListener("finish", (e) =>
+ this._updateThumbnailNode(e.detail.uploadable)
+ );
}
if (duplicatesFound) {
let message = null;
if (duplicatesFound < uploadables.length) {
- message = 'Some of the files were already added ' +
- 'and have been skipped.';
+ message =
+ "Some of the files were already added " +
+ "and have been skipped.";
} else if (duplicatesFound === 1) {
- message = 'This file was already added.';
+ message = "This file was already added.";
} else {
- message = 'These files were already added.';
+ message = "These files were already added.";
}
alert(message);
}
@@ -258,10 +262,10 @@ class PostUploadView extends events.EventTarget {
uploadable.destroy();
uploadable.rowNode.parentNode.removeChild(uploadable.rowNode);
this._uploadables.splice(this._uploadables.find(uploadable), 1);
- this._emit('change');
+ this._emit("change");
if (!this._uploadables.length) {
- this._formNode.classList.add('inactive');
- this._submitButtonNode.value = 'Upload all';
+ this._formNode.classList.add("inactive");
+ this._submitButtonNode.value = "Upload all";
}
}
@@ -271,11 +275,11 @@ class PostUploadView extends events.EventTarget {
}
_evtFilesAdded(e) {
- this.addUploadables(e.detail.files.map(file => new File(file)));
+ this.addUploadables(e.detail.files.map((file) => new File(file)));
}
_evtUrlsAdded(e) {
- this.addUploadables(e.detail.urls.map(url => new Url(url)));
+ this.addUploadables(e.detail.urls.map((url) => new Url(url)));
}
_evtSkipDuplicatesCheck(e, checked) {
@@ -289,7 +293,7 @@ class PostUploadView extends events.EventTarget {
_evtCancelButtonClick(e) {
e.preventDefault();
- this._emit('cancel');
+ this._emit("cancel");
}
_evtFormSubmit(e) {
@@ -297,47 +301,47 @@ class PostUploadView extends events.EventTarget {
for (let uploadable of this._uploadables) {
this._updateUploadableFromDom(uploadable);
}
- this._submitButtonNode.value = 'Resume upload';
- this._emit('submit');
+ this._submitButtonNode.value = "Resume upload";
+ this._emit("submit");
}
_updateUploadableFromDom(uploadable) {
const rowNode = uploadable.rowNode;
- const safetyNode = rowNode.querySelector('.safety input:checked');
+ const safetyNode = rowNode.querySelector(".safety input:checked");
if (safetyNode) {
uploadable.safety = safetyNode.value;
}
- const anonymousNode = rowNode.querySelector('.anonymous input:checked');
+ const anonymousNode = rowNode.querySelector(
+ ".anonymous input:checked"
+ );
if (anonymousNode) {
uploadable.anonymous = true;
}
- uploadable.flags = [];
- if (rowNode.querySelector('.loop-video input:checked')) {
- uploadable.flags.push('loop');
- }
-
uploadable.tags = [];
if (this._tagControl) {
uploadable.tags = this._tagControl.tags.map(tag => tag.names[0]);
}
-
+
uploadable.relations = [];
for (let [i, lookalike] of uploadable.lookalikes.entries()) {
let lookalikeNode = rowNode.querySelector(
- `.lookalikes li:nth-child(${i + 1})`);
- if ((lookalikeNode.querySelector('[name=copy-tags]') || '').checked) {
+ `.lookalikes li:nth-child(${i + 1})`
+ );
+ if ((lookalikeNode.querySelector("[name=copy-tags]") || "").checked) {
if (lookalike.distance === 0.0) {
// found exact match, copy tags to it instead
uploadable.foundOriginal = lookalike.post;
} else {
- uploadable.tags = uploadable.tags.concat(lookalike.post.tagNames);
+ uploadable.tags = uploadable.tags.concat(
+ lookalike.post.tagNames
+ );
uploadable.foundOriginal = undefined;
}
}
- if ((lookalikeNode.querySelector('[name=add-relation]') || '').checked) {
+ if ((lookalikeNode.querySelector("[name=add-relation]") || "").checked) {
uploadable.relations.push(lookalike.post.id);
}
}
@@ -364,91 +368,111 @@ class PostUploadView extends events.EventTarget {
this._uploadables[index + delta] = uploadable1;
if (delta === 1) {
this._listNode.insertBefore(
- uploadable2.rowNode, uploadable1.rowNode);
+ uploadable2.rowNode,
+ uploadable1.rowNode
+ );
} else {
this._listNode.insertBefore(
- uploadable1.rowNode, uploadable2.rowNode);
+ uploadable1.rowNode,
+ uploadable2.rowNode
+ );
}
}
}
_emit(eventType) {
this.dispatchEvent(
- new CustomEvent(
- eventType,
- {detail: {
+ new CustomEvent(eventType, {
+ detail: {
uploadables: this._uploadables,
skipDuplicates: this._skipDuplicatesCheckboxNode.checked,
- copyTagsToOriginals: this._copyTagsToOriginalsCheckboxNode.checked,
- }}));
+ copyTagsToOriginals:
+ this._copyTagsToOriginalsCheckboxNode.checked,
+ },
+ })
+ );
}
_renderRowNode(uploadable) {
- const rowNode = rowTemplate(Object.assign(
- {}, this._ctx, {uploadable: uploadable}));
+ const rowNode = rowTemplate(
+ Object.assign({}, this._ctx, { uploadable: uploadable })
+ );
if (uploadable.rowNode) {
uploadable.rowNode.parentNode.replaceChild(
- rowNode, uploadable.rowNode);
+ rowNode,
+ uploadable.rowNode
+ );
} else {
this._listNode.appendChild(rowNode);
}
uploadable.rowNode = rowNode;
- rowNode.querySelector('a.remove').addEventListener('click',
- e => this._evtRemoveClick(e, uploadable));
- rowNode.querySelector('a.move-up').addEventListener('click',
- e => this._evtMoveClick(e, uploadable, -1));
- rowNode.querySelector('a.move-down').addEventListener('click',
- e => this._evtMoveClick(e, uploadable, 1));
+ rowNode
+ .querySelector("a.remove")
+ .addEventListener("click", (e) =>
+ this._evtRemoveClick(e, uploadable)
+ );
+ rowNode
+ .querySelector("a.move-up")
+ .addEventListener("click", (e) =>
+ this._evtMoveClick(e, uploadable, -1)
+ );
+ rowNode
+ .querySelector("a.move-down")
+ .addEventListener("click", (e) =>
+ this._evtMoveClick(e, uploadable, 1)
+ );
}
_updateThumbnailNode(uploadable) {
- const rowNode = rowTemplate(Object.assign(
- {}, this._ctx, {uploadable: uploadable}));
+ const rowNode = rowTemplate(
+ Object.assign({}, this._ctx, { uploadable: uploadable })
+ );
views.replaceContent(
- uploadable.rowNode.querySelector('.thumbnail'),
- rowNode.querySelector('.thumbnail').childNodes);
+ uploadable.rowNode.querySelector(".thumbnail"),
+ rowNode.querySelector(".thumbnail").childNodes
+ );
}
get _uploading() {
- return this._formNode.classList.contains('uploading');
+ return this._formNode.classList.contains("uploading");
}
get _listNode() {
- return this._hostNode.querySelector('.uploadables-container');
+ return this._hostNode.querySelector(".uploadables-container");
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _skipDuplicatesCheckboxNode() {
- return this._hostNode.querySelector('form [name=skip-duplicates]');
+ return this._hostNode.querySelector("form [name=skip-duplicates]");
}
get _copyTagsToOriginalsSpanNode() {
- return this._hostNode.querySelector('.copy-tags-to-originals');
+ return this._hostNode.querySelector(".copy-tags-to-originals");
}
get _copyTagsToOriginalsCheckboxNode() {
- return this._hostNode.querySelector('form [name=copy-tags-to-originals]');
+ return this._hostNode.querySelector("form [name=copy-tags-to-originals]");
}
get _submitButtonNode() {
- return this._hostNode.querySelector('form [type=submit]');
+ return this._hostNode.querySelector("form [type=submit]");
}
get _cancelButtonNode() {
- return this._hostNode.querySelector('form .cancel');
+ return this._hostNode.querySelector("form .cancel");
}
get _contentInputNode() {
- return this._formNode.querySelector('.dropper-container');
+ return this._formNode.querySelector(".dropper-container");
}
get _tagInputNode() {
- return this._formNode.querySelector('.tags input');
+ return this._formNode.querySelector(".tags input");
}
}
diff --git a/client/js/views/posts_header_view.js b/client/js/views/posts_header_view.js
index d8a87ea..3df9cd9 100644
--- a/client/js/views/posts_header_view.js
+++ b/client/js/views/posts_header_view.js
@@ -1,72 +1,72 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const settings = require('../models/settings.js');
-const keyboard = require('../util/keyboard.js');
-const misc = require('../util/misc.js');
-const search = require('../util/search.js');
-const views = require('../util/views.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
-const MetricHeaderControl = require('../controls/metric_header_control');
+const events = require("../events.js");
+const settings = require("../models/settings.js");
+const keyboard = require("../util/keyboard.js");
+const misc = require("../util/misc.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
+const TagList = require("../models/tag_list.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
+const MetricHeaderControl = require("../controls/metric_header_control");
-const template = views.getTemplate('posts-header');
+const template = views.getTemplate("posts-header");
class BulkEditor extends events.EventTarget {
constructor(hostNode) {
super();
this._hostNode = hostNode;
- this._openLinkNode.addEventListener(
- 'click', e => this._evtOpenLinkClick(e));
- this._closeLinkNode.addEventListener(
- 'click', e => this._evtCloseLinkClick(e));
+ this._openLinkNode.addEventListener("click", (e) =>
+ this._evtOpenLinkClick(e)
+ );
+ this._closeLinkNode.addEventListener("click", (e) =>
+ this._evtCloseLinkClick(e)
+ );
}
get opened() {
- return this._hostNode.classList.contains('opened') &&
- !this._hostNode.classList.contains('hidden');
+ return (
+ this._hostNode.classList.contains("opened") &&
+ !this._hostNode.classList.contains("hidden")
+ );
}
get _openLinkNode() {
- return this._hostNode.querySelector('.open');
+ return this._hostNode.querySelector(".open");
}
get _closeLinkNode() {
- return this._hostNode.querySelector('.close');
+ return this._hostNode.querySelector(".close");
}
toggleOpen(state) {
- this._hostNode.classList.toggle('opened', state);
+ this._hostNode.classList.toggle("opened", state);
}
toggleHide(state) {
- this._hostNode.classList.toggle('hidden', state);
+ this._hostNode.classList.toggle("hidden", state);
}
_evtOpenLinkClick(e) {
- throw new Error('Not implemented');
+ throw new Error("Not implemented");
}
_evtCloseLinkClick(e) {
- throw new Error('Not implemented');
+ throw new Error("Not implemented");
}
}
class BulkSafetyEditor extends BulkEditor {
- constructor(hostNode) {
- super(hostNode);
- }
-
_evtOpenLinkClick(e) {
e.preventDefault();
this.toggleOpen(true);
- this.dispatchEvent(new CustomEvent('open', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("open", { detail: {} }));
}
_evtCloseLinkClick(e) {
e.preventDefault();
this.toggleOpen(false);
- this.dispatchEvent(new CustomEvent('close', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("close", { detail: {} }));
}
}
@@ -76,11 +76,32 @@ class BulkTagEditor extends BulkEditor {
this._autoCompleteControl = new TagAutoCompleteControl(
this._inputNode,
{
- confirm: tag =>
- this._autoCompleteControl.replaceSelectedText(
- tag.names[0], false),
- });
- this._hostNode.addEventListener('submit', e => this._evtFormSubmit(e));
+ confirm: (tag) => {
+ let tag_list = new TagList();
+ tag_list
+ .addByName(tag.names[0], true)
+ .then(
+ () => {
+ return tag_list
+ .map((s) => s.names[0])
+ .join(" ");
+ },
+ (err) => {
+ return tag.names[0];
+ }
+ )
+ .then((tag_str) => {
+ this._autoCompleteControl.replaceSelectedText(
+ tag_str,
+ false
+ );
+ });
+ },
+ }
+ );
+ this._hostNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
}
get value() {
@@ -88,7 +109,7 @@ class BulkTagEditor extends BulkEditor {
}
get _inputNode() {
- return this._hostNode.querySelector('input[name=tag]');
+ return this._hostNode.querySelector("input[name=tag]");
}
focus() {
@@ -102,22 +123,22 @@ class BulkTagEditor extends BulkEditor {
_evtFormSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("submit", { detail: {} }));
}
_evtOpenLinkClick(e) {
e.preventDefault();
this.toggleOpen(true);
this.focus();
- this.dispatchEvent(new CustomEvent('open', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("open", { detail: {} }));
}
_evtCloseLinkClick(e) {
e.preventDefault();
- this._inputNode.value = '';
+ this._inputNode.value = "";
this.toggleOpen(false);
this.blur();
- this.dispatchEvent(new CustomEvent('close', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("close", { detail: {} }));
}
}
@@ -129,13 +150,13 @@ class BulkAddRelationEditor extends BulkEditor {
_evtOpenLinkClick(e) {
e.preventDefault();
this.toggleOpen(true);
- this.dispatchEvent(new CustomEvent('open', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("open", { detail: {} }));
}
_evtCloseLinkClick(e) {
e.preventDefault();
this.toggleOpen(false);
- this.dispatchEvent(new CustomEvent('close', {detail: {}}));
+ this.dispatchEvent(new CustomEvent("close", { detail: {} }));
}
}
@@ -151,20 +172,28 @@ class PostsHeaderView extends events.EventTarget {
this._autoCompleteControl = new TagAutoCompleteControl(
this._queryInputNode,
{
- confirm: tag =>
+ confirm: (tag) =>
this._autoCompleteControl.replaceSelectedText(
- misc.escapeSearchTerm(tag.names[0]), true),
- });
+ misc.escapeSearchTerm(tag.names[0]),
+ true
+ ),
+ }
+ );
- keyboard.bind('p', () => this._focusFirstPostNode());
+ keyboard.bind("p", () => this._focusFirstPostNode());
search.searchInputNodeFocusHelper(this._queryInputNode);
for (let safetyButtonNode of this._safetyButtonNodes) {
- safetyButtonNode.addEventListener(
- 'click', e => this._evtSafetyButtonClick(e));
+ safetyButtonNode.addEventListener("click", (e) =>
+ this._evtSafetyButtonClick(e)
+ );
}
- this._formNode.addEventListener('submit', e => this._evtFormSubmit(e));
- this._randomizeButtonNode.addEventListener('click', e => this._evtRandomizeButtonClick(e));
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtFormSubmit(e)
+ );
+ this._randomizeButtonNode.addEventListener("click", (e) =>
+ this._evtRandomizeButtonClick(e)
+ );
this._bulkEditors = [];
if (this._bulkEditTagsNode) {
@@ -174,41 +203,47 @@ class PostsHeaderView extends events.EventTarget {
if (this._bulkEditSafetyNode) {
this._bulkSafetyEditor = new BulkSafetyEditor(
- this._bulkEditSafetyNode);
+ this._bulkEditSafetyNode
+ );
this._bulkEditors.push(this._bulkSafetyEditor);
}
if (this._bulkAddRelationNode) {
this._bulkAddRelationEditor = new BulkAddRelationEditor(
- this._bulkAddRelationNode);
+ this._bulkAddRelationNode
+ );
this._bulkEditors.push(this._bulkAddRelationEditor);
}
- this._bulkEditOpenButtonNode.addEventListener(
- 'click', e => this._evtOpenBulkEditBtnClick(e));
- this._bulkEditCloseButtonNode.addEventListener(
- 'click', e => this._evtCloseBulkEditBtnClick(e));
+ this._bulkEditOpenButtonNode.addEventListener("click", (e) =>
+ this._evtOpenBulkEditBtnClick(e)
+ );
+ this._bulkEditCloseButtonNode.addEventListener("click", (e) =>
+ this._evtCloseBulkEditBtnClick(e)
+ );
if (this._metricsButtonHolderNode) {
this._metricControl = new MetricHeaderControl(this._metricsBlockNode, ctx);
- this._metricControl.addEventListener('submit', e => {
- this._navigate();
- });
- this._metricsOpenButtonNode.addEventListener(
- 'click', e => this._evtOpenMetricsBtnClick(e));
- this._metricsCloseButtonNode.addEventListener(
- 'click', e => this._evtCloseMetricsBtnClick(e));
+ this._metricControl.addEventListener("submit", (e) =>
+ this._navigate()
+ );
+ this._metricsOpenButtonNode.addEventListener("click", (e) =>
+ this._evtOpenMetricsBtnClick(e)
+ );
+ this._metricsCloseButtonNode.addEventListener("click", (e) =>
+ this._evtCloseMetricsBtnClick(e)
+ );
}
for (let editor of this._bulkEditors) {
- editor.addEventListener('submit', e => {
+ editor.addEventListener("submit", (e) => {
this._navigate();
});
- editor.addEventListener('open', e => {
+ editor.addEventListener("open", (e) => {
this._hideBulkEditorsExcept(editor);
this._navigate();
});
- editor.addEventListener('close', e => {
+ editor.addEventListener("close", (e) => {
this._closeAndShowAllBulkEditors();
this._navigate();
});
@@ -227,63 +262,63 @@ class PostsHeaderView extends events.EventTarget {
}
get _formNode() {
- return this._hostNode.querySelector('form.search');
+ return this._hostNode.querySelector("form.search");
}
get _safetyButtonNodes() {
- return this._hostNode.querySelectorAll('form .safety');
+ return this._hostNode.querySelectorAll("form .safety");
}
get _queryInputNode() {
- return this._hostNode.querySelector('form [name=search-text]');
+ return this._hostNode.querySelector("form [name=search-text]");
}
get _randomizeButtonNode() {
- return this._hostNode.querySelector('#randomize-button');
+ return this._hostNode.querySelector("#randomize-button");
}
get _bulkEditBtnHolderNode() {
- return this._hostNode.querySelector('.bulk-edit-btn-holder');
+ return this._hostNode.querySelector(".bulk-edit-btn-holder");
}
get _bulkEditOpenButtonNode() {
- return this._hostNode.querySelector('.bulk-edit-btn.open');
+ return this._hostNode.querySelector(".bulk-edit-btn.open");
}
get _bulkEditCloseButtonNode() {
- return this._hostNode.querySelector('.bulk-edit-btn.close');
+ return this._hostNode.querySelector(".bulk-edit-btn.close");
}
get _bulkEditBlockNode() {
- return this._hostNode.querySelector('.bulk-edit-block');
+ return this._hostNode.querySelector(".bulk-edit-block");
}
get _bulkEditTagsNode() {
- return this._hostNode.querySelector('.bulk-edit-tags');
+ return this._hostNode.querySelector(".bulk-edit-tags");
}
get _bulkEditSafetyNode() {
- return this._hostNode.querySelector('.bulk-edit-safety');
+ return this._hostNode.querySelector(".bulk-edit-safety");
}
get _bulkAddRelationNode() {
- return this._hostNode.querySelector('.bulk-add-relation');
+ return this._hostNode.querySelector(".bulk-add-relation");
}
get _metricsButtonHolderNode() {
- return this._hostNode.querySelector('.metrics-btn-holder');
+ return this._hostNode.querySelector(".metrics-btn-holder");
}
get _metricsOpenButtonNode() {
- return this._hostNode.querySelector('.metrics-btn.open');
+ return this._hostNode.querySelector(".metrics-btn.open");
}
get _metricsCloseButtonNode() {
- return this._hostNode.querySelector('.metrics-btn.close');
+ return this._hostNode.querySelector(".metrics-btn.close");
}
get _metricsBlockNode() {
- return this._hostNode.querySelector('.metrics-block');
+ return this._hostNode.querySelector(".metrics-block");
}
_evtOpenBulkEditBtnClick(e) {
@@ -306,8 +341,8 @@ class PostsHeaderView extends events.EventTarget {
}
_toggleBulkEditBlock(open) {
- this._bulkEditBtnHolderNode.classList.toggle('opened', open);
- this._bulkEditBlockNode.classList.toggle('hidden', !open);
+ this._bulkEditBtnHolderNode.classList.toggle("opened", open);
+ this._bulkEditBlockNode.classList.toggle("hidden", !open);
}
_hideBulkEditorsExcept(editor) {
@@ -339,26 +374,29 @@ class PostsHeaderView extends events.EventTarget {
}
_toggleMetricsBlock(open) {
- this._metricsButtonHolderNode.classList.toggle('opened', open);
- this._metricsBlockNode.classList.toggle('hidden', !open);
+ this._metricsButtonHolderNode.classList.toggle("opened", open);
+ this._metricsBlockNode.classList.toggle("hidden", !open);
}
_evtSafetyButtonClick(e, url) {
e.preventDefault();
- e.target.classList.toggle('disabled');
- const safety = e.target.getAttribute('data-safety');
+ e.target.classList.toggle("disabled");
+ const safety = e.target.getAttribute("data-safety");
let browsingSettings = settings.get();
- browsingSettings.listPosts[safety] =
- !browsingSettings.listPosts[safety];
+ browsingSettings.listPosts[safety] = !browsingSettings.listPosts[
+ safety
+ ];
settings.save(browsingSettings, true);
this.dispatchEvent(
- new CustomEvent(
- 'navigate', {
- detail: {
- parameters: Object.assign(
- {}, this._ctx.parameters, {tag: null, offset: 0}),
- },
- }));
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: Object.assign({}, this._ctx.parameters, {
+ tag: null,
+ offset: 0,
+ }),
+ },
+ })
+ );
}
_evtFormSubmit(e) {
@@ -370,8 +408,8 @@ class PostsHeaderView extends events.EventTarget {
}
_evtRandomizeButtonClick(e) {
e.preventDefault();
- if (!this._queryInputNode.value.includes('sort:random')) {
- this._queryInputNode.value += ' sort:random';
+ if (!this._queryInputNode.value.includes("sort:random")) {
+ this._queryInputNode.value += " sort:random";
}
this._ctx.parameters.cachenumber = Math.round(Math.random() * 1000);
this._navigate();
@@ -382,29 +420,38 @@ class PostsHeaderView extends events.EventTarget {
let parameters = {
query: this._queryInputNode.value,
cachenumber: this._ctx.parameters.cachenumber,
- metrics: this._ctx.parameters.metrics,
+ metrics: this._ctx.parameters.metrics
};
- parameters.offset = parameters.query === this._ctx.parameters.query ?
- this._ctx.parameters.offset : 0;
+
+ // convert falsy values to an empty string "" so that we can correctly compare with the current query
+ const prevQuery = this._ctx.parameters.query
+ ? this._ctx.parameters.query
+ : "";
+ parameters.offset =
+ parameters.query === prevQuery ? this._ctx.parameters.offset : 0;
if (this._bulkTagEditor && this._bulkTagEditor.opened) {
parameters.tag = this._bulkTagEditor.value;
this._bulkTagEditor.blur();
} else {
parameters.tag = null;
}
- parameters.safety = (
- this._bulkSafetyEditor &&
- this._bulkSafetyEditor.opened ? '1' : null);
- parameters.relations = (
- this._bulkAddRelationEditor &&
- this._bulkAddRelationEditor.opened ? this._ctx.parameters.relations || ' ' : null);
+ parameters.safety =
+ this._bulkSafetyEditor && this._bulkSafetyEditor.opened
+ ? "1"
+ : null;
+ parameters.relations =
+ this._bulkAddRelationEditor && this._bulkAddRelationEditor.opened
+ ? this._ctx.parameters.relations || " "
+ : null;
this.dispatchEvent(
- new CustomEvent('navigate', {detail: {parameters: parameters}}));
+ new CustomEvent("navigate", { detail: { parameters: parameters } })
+ );
}
_focusFirstPostNode() {
- const firstPostNode =
- document.body.querySelector('.post-list li:first-child a');
+ const firstPostNode = document.body.querySelector(
+ ".post-list li:first-child a"
+ );
if (firstPostNode) {
firstPostNode.focus();
}
diff --git a/client/js/views/posts_page_view.js b/client/js/views/posts_page_view.js
index d7a64d6..9885602 100644
--- a/client/js/views/posts_page_view.js
+++ b/client/js/views/posts_page_view.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const tags = require('../tags.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const tags = require("../tags.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('posts-page');
+const template = views.getTemplate("posts-page");
class PostsPageView extends events.EventTarget {
constructor(ctx) {
@@ -16,32 +16,35 @@ class PostsPageView extends events.EventTarget {
this._postIdToPost = {};
for (let post of ctx.response.results) {
this._postIdToPost[post.id] = post;
- post.addEventListener('change', e => this._evtPostChange(e));
+ post.addEventListener("change", (e) => this._evtPostChange(e));
}
this._postIdToListItemNode = {};
for (let listItemNode of this._listItemNodes) {
- const postId = listItemNode.getAttribute('data-post-id');
+ const postId = listItemNode.getAttribute("data-post-id");
const post = this._postIdToPost[postId];
this._postIdToListItemNode[postId] = listItemNode;
const tagFlipperNode = this._getTagFlipperNode(listItemNode);
if (tagFlipperNode) {
- tagFlipperNode.addEventListener(
- 'click', e => this._evtBulkEditTagsClick(e, post));
+ tagFlipperNode.addEventListener("click", (e) =>
+ this._evtBulkEditTagsClick(e, post)
+ );
}
const relationFlipperNode = this._getRelationFlipperNode(listItemNode);
if (relationFlipperNode) {
- relationFlipperNode.addEventListener(
- 'click', e => this._evtBulkAddRelationClick(e, post));
+ relationFlipperNode.addEventListener("click", e =>
+ this._evtBulkAddRelationClick(e, post)
+ );
}
const safetyFlipperNode = this._getSafetyFlipperNode(listItemNode);
if (safetyFlipperNode) {
- for (let linkNode of safetyFlipperNode.querySelectorAll('a')) {
- linkNode.addEventListener(
- 'click', e => this._evtBulkEditSafetyClick(e, post));
+ for (let linkNode of safetyFlipperNode.querySelectorAll("a")) {
+ linkNode.addEventListener("click", (e) =>
+ this._evtBulkEditSafetyClick(e, post)
+ );
}
}
}
@@ -50,25 +53,25 @@ class PostsPageView extends events.EventTarget {
}
get _listItemNodes() {
- return this._hostNode.querySelectorAll('li');
+ return this._hostNode.querySelectorAll("li");
}
_getTagFlipperNode(listItemNode) {
- return listItemNode.querySelector('.tag-flipper');
+ return listItemNode.querySelector(".tag-flipper");
}
_getSafetyFlipperNode(listItemNode) {
- return listItemNode.querySelector('.safety-flipper');
+ return listItemNode.querySelector(".safety-flipper");
}
_getRelationFlipperNode(listItemNode) {
- return listItemNode.querySelector('.relation-flipper');
+ return listItemNode.querySelector(".relation-flipper");
}
_evtPostChange(e) {
const listItemNode = this._postIdToListItemNode[e.detail.post.id];
- for (let node of listItemNode.querySelectorAll('[data-disabled]')) {
- node.removeAttribute('data-disabled');
+ for (let node of listItemNode.querySelectorAll("[data-disabled]")) {
+ node.removeAttribute("data-disabled");
}
this._syncBulkEditorsHighlights();
}
@@ -76,48 +79,58 @@ class PostsPageView extends events.EventTarget {
_evtBulkEditTagsClick(e, post) {
e.preventDefault();
const linkNode = e.target;
- if (linkNode.getAttribute('data-disabled')) {
+ if (linkNode.getAttribute("data-disabled")) {
return;
}
- linkNode.setAttribute('data-disabled', true);
+ linkNode.setAttribute("data-disabled", true);
this.dispatchEvent(
new CustomEvent(
- linkNode.classList.contains('tagged') ? 'untag' : 'tag',
- {detail: {post: post}}));
+ linkNode.classList.contains("tagged") ? "untag" : "tag",
+ {
+ detail: { post: post },
+ }
+ )
+ );
}
_evtBulkAddRelationClick(e, post) {
e.preventDefault();
const linkNode = e.target;
- if (linkNode.getAttribute('data-disabled')) {
+ if (linkNode.getAttribute("data-disabled")) {
return;
}
- linkNode.setAttribute('data-disabled', true);
+ linkNode.setAttribute("data-disabled", true);
this.dispatchEvent(
new CustomEvent(
- linkNode.classList.contains('related') ? 'removeRelation' : 'addRelation',
- {detail: {post: post}}));
+ linkNode.classList.contains("related") ? "removeRelation" : "addRelation",
+ {
+ detail: { post: post }
+ }
+ )
+ );
}
_evtBulkEditSafetyClick(e, post) {
e.preventDefault();
const linkNode = e.target;
- if (linkNode.getAttribute('data-disabled')) {
+ if (linkNode.getAttribute("data-disabled")) {
return;
}
- const newSafety = linkNode.getAttribute('data-safety');
+ const newSafety = linkNode.getAttribute("data-safety");
if (post.safety === newSafety) {
return;
}
- linkNode.setAttribute('data-disabled', true);
+ linkNode.setAttribute("data-disabled", true);
this.dispatchEvent(
- new CustomEvent(
- 'changeSafety', {detail: {post: post, safety: newSafety}}));
+ new CustomEvent("changeSafety", {
+ detail: { post: post, safety: newSafety },
+ })
+ );
}
_syncBulkEditorsHighlights() {
for (let listItemNode of this._listItemNodes) {
- const postId = listItemNode.getAttribute('data-post-id');
+ const postId = listItemNode.getAttribute("data-post-id");
const post = this._postIdToPost[postId];
const tagFlipperNode = this._getTagFlipperNode(listItemNode);
@@ -125,23 +138,26 @@ class PostsPageView extends events.EventTarget {
let tagged = true;
for (let tag of this._ctx.bulkEdit.tags) {
let tagData = tags.parseTagAndCategory(tag);
- tagged = tagged & post.tags.isTaggedWith(tagData.name);
+ tagged &= post.tags.isTaggedWith(tagData.name);
}
- tagFlipperNode.classList.toggle('tagged', tagged);
+ tagFlipperNode.classList.toggle("tagged", tagged);
}
const safetyFlipperNode = this._getSafetyFlipperNode(listItemNode);
if (safetyFlipperNode) {
- for (let linkNode of safetyFlipperNode.querySelectorAll('a')) {
- const safety = linkNode.getAttribute('data-safety');
- linkNode.classList.toggle('active', post.safety == safety);
+ for (let linkNode of safetyFlipperNode.querySelectorAll("a")) {
+ const safety = linkNode.getAttribute("data-safety");
+ linkNode.classList.toggle(
+ "active",
+ post.safety === safety
+ );
}
}
const relationFlipperNode = this._getRelationFlipperNode(listItemNode);
if (relationFlipperNode) {
let related = this._ctx.parameters.relations.includes(post.id);
- relationFlipperNode.classList.toggle('related', related);
+ relationFlipperNode.classList.toggle("related", related);
}
}
}
diff --git a/client/js/views/registration_view.js b/client/js/views/registration_view.js
index 48034dd..0a08de2 100644
--- a/client/js/views/registration_view.js
+++ b/client/js/views/registration_view.js
@@ -1,22 +1,25 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('user-registration');
+const template = views.getTemplate("user-registration");
class RegistrationView extends events.EventTarget {
constructor() {
super();
- this._hostNode = document.getElementById('content-holder');
- views.replaceContent(this._hostNode, template({
- userNamePattern: api.getUserNameRegex(),
- passwordPattern: api.getPasswordRegex(),
- }));
+ this._hostNode = document.getElementById("content-holder");
+ views.replaceContent(
+ this._hostNode,
+ template({
+ userNamePattern: api.getUserNameRegex(),
+ passwordPattern: api.getPasswordRegex(),
+ })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -37,29 +40,31 @@ class RegistrationView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- name: this._userNameFieldNode.value,
- password: this._passwordFieldNode.value,
- email: this._emailFieldNode.value,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ name: this._userNameFieldNode.value,
+ password: this._passwordFieldNode.value,
+ email: this._emailFieldNode.value,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _userNameFieldNode() {
- return this._formNode.querySelector('[name=name]');
+ return this._formNode.querySelector("[name=name]");
}
get _passwordFieldNode() {
- return this._formNode.querySelector('[name=password]');
+ return this._formNode.querySelector("[name=password]");
}
get _emailFieldNode() {
- return this._formNode.querySelector('[name=email]');
+ return this._formNode.querySelector("[name=email]");
}
}
diff --git a/client/js/views/settings_view.js b/client/js/views/settings_view.js
index eb5fa6d..a19ac5f 100644
--- a/client/js/views/settings_view.js
+++ b/client/js/views/settings_view.js
@@ -1,21 +1,23 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('settings');
+const template = views.getTemplate("settings");
class SettingsView extends events.EventTarget {
constructor(ctx) {
super();
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(
- this._hostNode, template({browsingSettings: ctx.settings}));
+ this._hostNode,
+ template({ browsingSettings: ctx.settings })
+ );
views.syncScrollPosition();
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -28,34 +30,42 @@ class SettingsView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- 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,
- autoplayVideos: this._find('autoplay-videos').checked,
- postsPerPage: this._find('posts-per-page').value,
- uploadSafety: this._safetyButtonNodes.length ?
- Array.from(this._safetyButtonNodes)
- .filter(node => node.checked)[0]
- .value.toLowerCase() :
- undefined,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ 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,
+ autoplayVideos: this._find("autoplay-videos").checked,
+ postsPerPage: this._find("posts-per-page").value,
+ tagUnderscoresAsSpaces: this._find("underscores-as-spaces")
+ .checked,
+ darkTheme: this._find("dark-theme").checked,
+ postFlow: this._find("post-flow").checked,
+ uploadSafety: this._safetyButtonNodes.length ?
+ Array.from(this._safetyButtonNodes)
+ .filter(node => node.checked)[0]
+ .value.toLowerCase() :
+ undefined,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _safetyButtonNodes() {
- return this._formNode.querySelectorAll('.uploadSafety input');
+ return this._formNode.querySelectorAll(".uploadSafety input");
}
_find(nodeName) {
- return this._formNode.querySelector('[name=' + nodeName + ']');
+ return this._formNode.querySelector("[name=" + nodeName + "]");
}
}
diff --git a/client/js/views/snapshots_page_view.js b/client/js/views/snapshots_page_view.js
index 77fbe13..a665ea0 100644
--- a/client/js/views/snapshots_page_view.js
+++ b/client/js/views/snapshots_page_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('snapshots-page');
+const template = views.getTemplate("snapshots-page");
function _extend(target, source) {
target.push.apply(target, source);
@@ -10,18 +10,18 @@ function _extend(target, source) {
function _formatBasicChange(diff, text) {
const lines = [];
- if (diff.type === 'list change') {
+ if (diff.type === "list change") {
const addedItems = diff.added;
const removedItems = diff.removed;
if (addedItems && addedItems.length) {
- lines.push(`Added ${text} (${addedItems.join(', ')})`);
+ lines.push(`Added ${text} (${addedItems.join(", ")})`);
}
if (removedItems && removedItems.length) {
- lines.push(`Removed ${text} (${removedItems.join(', ')})`);
+ lines.push(`Removed ${text} (${removedItems.join(", ")})`);
}
- } else if (diff.type === 'primitive change') {
- const oldValue = diff['old-value'];
- const newValue = diff['new-value'];
+ } else if (diff.type === "primitive change") {
+ const oldValue = diff["old-value"];
+ const newValue = diff["new-value"];
lines.push(`Changed ${text} (${oldValue} &rarr; ${newValue})`);
} else {
lines.push(`Changed ${text}`);
@@ -30,12 +30,14 @@ function _formatBasicChange(diff, text) {
}
function _makeResourceLink(type, id) {
- if (type === 'post') {
+ if (type === "post") {
return views.makePostLink(id, true);
- } else if (type === 'tag') {
+ } else if (type === "tag") {
return views.makeTagLink(id, true);
- } else if (type === 'tag_category') {
+ } else if (type === "tag_category") {
return 'category "' + id + '"';
+ } else if (type === "pool") {
+ return views.makePoolLink(id, true);
}
}
@@ -48,83 +50,102 @@ function _makeItemCreation(type, data) {
let text = key[0].toUpperCase() + key.substr(1).toLowerCase();
if (Array.isArray(data[key])) {
if (data[key].length) {
- lines.push(`${text}: ${data[key].join(', ')}`);
+ lines.push(`${text}: ${data[key].join(", ")}`);
}
} else {
lines.push(`${text}: ${data[key]}`);
}
}
- return lines.join('<br/>');
+ return lines.join("<br/>");
}
function _makeItemModification(type, data) {
const lines = [];
const diff = data.value;
- if (type === 'tag_category') {
+ if (type === "tag_category") {
if (diff.name) {
- _extend(lines, _formatBasicChange(diff.name, 'name'));
+ _extend(lines, _formatBasicChange(diff.name, "name"));
}
if (diff.color) {
- _extend(lines, _formatBasicChange(diff.color, 'color'));
+ _extend(lines, _formatBasicChange(diff.color, "color"));
}
if (diff.default) {
- _extend(lines, ['Made into default category']);
+ _extend(lines, ["Made into default category"]);
}
-
- } else if (type === 'tag') {
+ } else if (type === "tag") {
if (diff.names) {
- _extend(lines, _formatBasicChange(diff.names, 'names'));
+ _extend(lines, _formatBasicChange(diff.names, "names"));
}
if (diff.category) {
- _extend(
- lines, _formatBasicChange(diff.category, 'category'));
+ _extend(lines, _formatBasicChange(diff.category, "category"));
}
if (diff.suggestions) {
_extend(
- lines, _formatBasicChange(diff.suggestions, 'suggestions'));
+ lines,
+ _formatBasicChange(diff.suggestions, "suggestions")
+ );
}
if (diff.implications) {
_extend(
- lines, _formatBasicChange(diff.implications, 'implications'));
+ lines,
+ _formatBasicChange(diff.implications, "implications")
+ );
}
-
- } else if (type === 'post') {
+ } else if (type === "post") {
if (diff.checksum) {
- _extend(lines, ['Changed content']);
+ _extend(lines, ["Changed content"]);
}
if (diff.featured) {
- _extend(lines, ['Featured on front page']);
+ _extend(lines, ["Featured on front page"]);
}
if (diff.source) {
- _extend(lines, _formatBasicChange(diff.source, 'source'));
+ _extend(lines, _formatBasicChange(diff.source, "source"));
}
if (diff.safety) {
- _extend(lines, _formatBasicChange(diff.safety, 'safety'));
+ _extend(lines, _formatBasicChange(diff.safety, "safety"));
}
if (diff.tags) {
- _extend(lines, _formatBasicChange(diff.tags, 'tags'));
+ _extend(lines, _formatBasicChange(diff.tags, "tags"));
}
if (diff.relations) {
- _extend(lines, _formatBasicChange(diff.relations, 'relations'));
+ _extend(lines, _formatBasicChange(diff.relations, "relations"));
}
if (diff.notes) {
- _extend(lines, ['Changed notes']);
+ _extend(lines, ["Changed notes"]);
}
if (diff.flags) {
- _extend(lines, ['Changed flags']);
+ _extend(lines, ["Changed flags"]);
+ }
+ } else if (type === "pool") {
+ if (diff.names) {
+ _extend(lines, _formatBasicChange(diff.names, "names"));
+ }
+ if (diff.category) {
+ _extend(lines, _formatBasicChange(diff.category, "category"));
+ }
+ if (diff.posts) {
+ _extend(lines, _formatBasicChange(diff.posts, "posts"));
}
}
- return lines.join('<br/>');
+ return lines.join("<br/>");
}
class SnapshotsPageView {
constructor(ctx) {
- views.replaceContent(ctx.hostNode, template(Object.assign({
- makeResourceLink: _makeResourceLink,
- makeItemCreation: _makeItemCreation,
- makeItemModification: _makeItemModification,
- }, ctx)));
+ views.replaceContent(
+ ctx.hostNode,
+ template(
+ Object.assign(
+ {
+ makeResourceLink: _makeResourceLink,
+ makeItemCreation: _makeItemCreation,
+ makeItemModification: _makeItemModification,
+ },
+ ctx
+ )
+ )
+ );
}
}
diff --git a/client/js/views/tag_categories_view.js b/client/js/views/tag_categories_view.js
index 7e1000d..e052fd4 100644
--- a/client/js/views/tag_categories_view.js
+++ b/client/js/views/tag_categories_view.js
@@ -1,17 +1,17 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const TagCategory = require('../models/tag_category.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const TagCategory = require("../models/tag_category.js");
-const template = views.getTemplate('tag-categories');
-const rowTemplate = views.getTemplate('tag-category-row');
+const template = views.getTemplate("tag-categories");
+const rowTemplate = views.getTemplate("tag-category-row");
class TagCategoriesView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
views.replaceContent(this._hostNode, template(ctx));
views.syncScrollPosition();
@@ -24,25 +24,31 @@ class TagCategoriesView extends events.EventTarget {
} else if (a.isDefault) {
return -1;
}
- return a.name.localeCompare(b.name);
+ return a.order == b.order
+ ? a.name.localeCompare(b.name)
+ : a.order - b.order;
});
for (let tagCategory of categoriesToAdd) {
this._addTagCategoryRowNode(tagCategory);
}
if (this._addLinkNode) {
- this._addLinkNode.addEventListener(
- 'click', e => this._evtAddButtonClick(e));
+ this._addLinkNode.addEventListener("click", (e) =>
+ this._evtAddButtonClick(e)
+ );
}
- ctx.tagCategories.addEventListener(
- 'add', e => this._evtTagCategoryAdded(e));
+ ctx.tagCategories.addEventListener("add", (e) =>
+ this._evtTagCategoryAdded(e)
+ );
- ctx.tagCategories.addEventListener(
- 'remove', e => this._evtTagCategoryDeleted(e));
+ ctx.tagCategories.addEventListener("remove", (e) =>
+ this._evtTagCategoryDeleted(e)
+ );
- this._formNode.addEventListener(
- 'submit', e => this._evtSaveButtonClick(e, ctx));
+ this._formNode.addEventListener("submit", (e) =>
+ this._evtSaveButtonClick(e, ctx)
+ );
}
enableForm() {
@@ -66,44 +72,55 @@ class TagCategoriesView extends events.EventTarget {
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _tableBodyNode() {
- return this._hostNode.querySelector('tbody');
+ return this._hostNode.querySelector("tbody");
}
get _addLinkNode() {
- return this._hostNode.querySelector('a.add');
+ return this._hostNode.querySelector("a.add");
}
_addTagCategoryRowNode(tagCategory) {
const rowNode = rowTemplate(
- Object.assign(
- {}, this._ctx, {tagCategory: tagCategory}));
+ Object.assign({}, this._ctx, { tagCategory: tagCategory })
+ );
- const nameInput = rowNode.querySelector('.name input');
+ const nameInput = rowNode.querySelector(".name input");
if (nameInput) {
- nameInput.addEventListener(
- 'change', e => this._evtNameChange(e, rowNode));
+ nameInput.addEventListener("change", (e) =>
+ this._evtNameChange(e, rowNode)
+ );
}
- const colorInput = rowNode.querySelector('.color input');
+ const colorInput = rowNode.querySelector(".color input");
if (colorInput) {
- colorInput.addEventListener(
- 'change', e => this._evtColorChange(e, rowNode));
+ colorInput.addEventListener("change", (e) =>
+ this._evtColorChange(e, rowNode)
+ );
}
- const removeLinkNode = rowNode.querySelector('.remove a');
+ const orderInput = rowNode.querySelector(".order input");
+ if (orderInput) {
+ orderInput.addEventListener("change", (e) =>
+ this._evtOrderChange(e, rowNode)
+ );
+ }
+
+ const removeLinkNode = rowNode.querySelector(".remove a");
if (removeLinkNode) {
- removeLinkNode.addEventListener(
- 'click', e => this._evtDeleteButtonClick(e, rowNode));
+ removeLinkNode.addEventListener("click", (e) =>
+ this._evtDeleteButtonClick(e, rowNode)
+ );
}
- const defaultLinkNode = rowNode.querySelector('.set-default a');
+ const defaultLinkNode = rowNode.querySelector(".set-default a");
if (defaultLinkNode) {
- defaultLinkNode.addEventListener(
- 'click', e => this._evtSetDefaultButtonClick(e, rowNode));
+ defaultLinkNode.addEventListener("click", (e) =>
+ this._evtSetDefaultButtonClick(e, rowNode)
+ );
}
this._tableBodyNode.appendChild(rowNode);
@@ -139,9 +156,13 @@ class TagCategoriesView extends events.EventTarget {
rowNode._tagCategory.color = e.target.value;
}
+ _evtOrderChange(e, rowNode) {
+ rowNode._tagCategory.order = e.target.value;
+ }
+
_evtDeleteButtonClick(e, rowNode, link) {
e.preventDefault();
- if (e.target.classList.contains('inactive')) {
+ if (e.target.classList.contains("inactive")) {
return;
}
this._ctx.tagCategories.remove(rowNode._tagCategory);
@@ -150,16 +171,16 @@ class TagCategoriesView extends events.EventTarget {
_evtSetDefaultButtonClick(e, rowNode) {
e.preventDefault();
this._ctx.tagCategories.defaultCategory = rowNode._tagCategory;
- const oldRowNode = rowNode.parentNode.querySelector('tr.default');
+ const oldRowNode = rowNode.parentNode.querySelector("tr.default");
if (oldRowNode) {
- oldRowNode.classList.remove('default');
+ oldRowNode.classList.remove("default");
}
- rowNode.classList.add('default');
+ rowNode.classList.add("default");
}
_evtSaveButtonClick(e, ctx) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit'));
+ this.dispatchEvent(new CustomEvent("submit"));
}
}
diff --git a/client/js/views/tag_delete_view.js b/client/js/views/tag_delete_view.js
index 4d27f15..4246ec3 100644
--- a/client/js/views/tag_delete_view.js
+++ b/client/js/views/tag_delete_view.js
@@ -1,9 +1,9 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('tag-delete');
+const template = views.getTemplate("tag-delete");
class TagDeleteView extends events.EventTarget {
constructor(ctx) {
@@ -13,7 +13,7 @@ class TagDeleteView extends events.EventTarget {
this._tag = ctx.tag;
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -38,15 +38,17 @@ class TagDeleteView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- tag: this._tag,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ tag: this._tag,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
}
diff --git a/client/js/views/tag_edit_view.js b/client/js/views/tag_edit_view.js
index 5b517d4..58c1bc4 100644
--- a/client/js/views/tag_edit_view.js
+++ b/client/js/views/tag_edit_view.js
@@ -1,12 +1,12 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const misc = require('../util/misc.js');
-const views = require('../util/views.js');
-const TagInputControl = require('../controls/tag_input_control.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const misc = require("../util/misc.js");
+const views = require("../util/views.js");
+const TagInputControl = require("../controls/tag_input_control.js");
-const template = views.getTemplate('tag-edit');
+const template = views.getTemplate("tag-edit");
class TagEditView extends events.EventTarget {
constructor(ctx) {
@@ -19,28 +19,33 @@ class TagEditView extends events.EventTarget {
views.decorateValidator(this._formNode);
if (this._namesFieldNode) {
- this._namesFieldNode.addEventListener(
- 'input', e => this._evtNameInput(e));
+ this._namesFieldNode.addEventListener("input", (e) =>
+ this._evtNameInput(e)
+ );
}
if (this._implicationsFieldNode) {
new TagInputControl(
- this._implicationsFieldNode, this._tag.implications);
+ this._implicationsFieldNode,
+ this._tag.implications
+ );
}
if (this._suggestionsFieldNode) {
new TagInputControl(
- this._suggestionsFieldNode, this._tag.suggestions);
+ this._suggestionsFieldNode,
+ this._tag.suggestions
+ );
}
for (let node of this._formNode.querySelectorAll(
- 'input, select, textarea')) {
- node.addEventListener(
- 'change', e => {
- this.dispatchEvent(new CustomEvent('change'));
- });
+ "input, select, textarea"
+ )) {
+ node.addEventListener("change", (e) => {
+ this.dispatchEvent(new CustomEvent("change"));
+ });
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -69,72 +74,80 @@ class TagEditView extends events.EventTarget {
if (!list.length) {
this._namesFieldNode.setCustomValidity(
- 'Tags must have at least one name.');
+ "Tags must have at least one name."
+ );
return;
}
for (let item of list) {
if (!regex.test(item)) {
this._namesFieldNode.setCustomValidity(
- `Tag name "${item}" contains invalid symbols.`);
+ `Tag name "${item}" contains invalid symbols.`
+ );
return;
}
}
- this._namesFieldNode.setCustomValidity('');
+ this._namesFieldNode.setCustomValidity("");
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- tag: this._tag,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ tag: this._tag,
- names: this._namesFieldNode ?
- misc.splitByWhitespace(this._namesFieldNode.value) :
- undefined,
+ names: this._namesFieldNode
+ ? misc.splitByWhitespace(this._namesFieldNode.value)
+ : undefined,
- category: this._categoryFieldNode ?
- this._categoryFieldNode.value :
- undefined,
+ category: this._categoryFieldNode
+ ? this._categoryFieldNode.value
+ : undefined,
- implications: this._implicationsFieldNode ?
- misc.splitByWhitespace(this._implicationsFieldNode.value) :
- undefined,
+ implications: this._implicationsFieldNode
+ ? misc.splitByWhitespace(
+ this._implicationsFieldNode.value
+ )
+ : undefined,
- suggestions: this._suggestionsFieldNode ?
- misc.splitByWhitespace(this._suggestionsFieldNode.value) :
- undefined,
+ suggestions: this._suggestionsFieldNode
+ ? misc.splitByWhitespace(
+ this._suggestionsFieldNode.value
+ )
+ : undefined,
- description: this._descriptionFieldNode ?
- this._descriptionFieldNode.value :
- undefined,
- },
- }));
+ description: this._descriptionFieldNode
+ ? this._descriptionFieldNode.value
+ : undefined,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _namesFieldNode() {
- return this._formNode.querySelector('.names input');
+ return this._formNode.querySelector(".names input");
}
get _categoryFieldNode() {
- return this._formNode.querySelector('.category select');
+ return this._formNode.querySelector(".category select");
}
get _implicationsFieldNode() {
- return this._formNode.querySelector('.implications input');
+ return this._formNode.querySelector(".implications input");
}
get _suggestionsFieldNode() {
- return this._formNode.querySelector('.suggestions input');
+ return this._formNode.querySelector(".suggestions input");
}
get _descriptionFieldNode() {
- return this._formNode.querySelector('.description textarea');
+ return this._formNode.querySelector(".description textarea");
}
}
diff --git a/client/js/views/tag_merge_view.js b/client/js/views/tag_merge_view.js
index c975a50..f823ca4 100644
--- a/client/js/views/tag_merge_view.js
+++ b/client/js/views/tag_merge_view.js
@@ -1,12 +1,11 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
-const template = views.getTemplate('tag-merge');
+const template = views.getTemplate("tag-merge");
class TagMergeView extends events.EventTarget {
constructor(ctx) {
@@ -22,13 +21,16 @@ class TagMergeView extends events.EventTarget {
this._autoCompleteControl = new TagAutoCompleteControl(
this._targetTagFieldNode,
{
- confirm: tag =>
+ confirm: (tag) =>
this._autoCompleteControl.replaceSelectedText(
- tag.names[0], false),
- });
+ tag.names[0],
+ false
+ ),
+ }
+ );
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -53,25 +55,27 @@ class TagMergeView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- tag: this._tag,
- targetTagName: this._targetTagFieldNode.value,
- addAlias: this._addAliasCheckboxNode.checked,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ tag: this._tag,
+ targetTagName: this._targetTagFieldNode.value,
+ addAlias: this._addAliasCheckboxNode.checked,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _targetTagFieldNode() {
- return this._formNode.querySelector('input[name=target-tag]');
+ return this._formNode.querySelector("input[name=target-tag]");
}
get _addAliasCheckboxNode() {
- return this._formNode.querySelector('input[name=alias]');
+ return this._formNode.querySelector("input[name=alias]");
}
}
diff --git a/client/js/views/tag_summary_view.js b/client/js/views/tag_summary_view.js
index 019e72b..11c6191 100644
--- a/client/js/views/tag_summary_view.js
+++ b/client/js/views/tag_summary_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('tag-summary');
+const template = views.getTemplate("tag-summary");
class TagSummaryView {
constructor(ctx) {
diff --git a/client/js/views/tag_view.js b/client/js/views/tag_view.js
index 3037a29..163d701 100644
--- a/client/js/views/tag_view.js
+++ b/client/js/views/tag_view.js
@@ -1,25 +1,27 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const TagSummaryView = require('./tag_summary_view.js');
-const TagEditView = require('./tag_edit_view.js');
-const TagMetricView = require('./tag_metric_view.js');
-const TagMergeView = require('./tag_merge_view.js');
-const TagDeleteView = require('./tag_delete_view.js');
-const EmptyView = require('../views/empty_view.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const misc = require("../util/misc.js");
+const TagSummaryView = require("./tag_summary_view.js");
+const TagEditView = require("./tag_edit_view.js");
+const TagMergeView = require("./tag_merge_view.js");
+const TagMetricView = require("./tag_metric_view.js");
+const TagDeleteView = require("./tag_delete_view.js");
+const EmptyView = require("../views/empty_view.js");
-const template = views.getTemplate('tag');
+const template = views.getTemplate("tag");
class TagView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- ctx.tag.addEventListener('change', e => this._evtChange(e));
- ctx.section = ctx.section || 'summary';
+ ctx.tag.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
+ ctx.getPrettyName = misc.getPrettyName;
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._install();
}
@@ -27,64 +29,67 @@ class TagView extends events.EventTarget {
const ctx = this._ctx;
views.replaceContent(this._hostNode, template(ctx));
- for (let item of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
item.classList.toggle(
- 'active', item.getAttribute('data-name') === ctx.section);
- if (item.getAttribute('data-name') === ctx.section) {
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
item.parentNode.scrollLeft =
item.getBoundingClientRect().left -
- item.parentNode.getBoundingClientRect().left
+ item.parentNode.getBoundingClientRect().left;
}
}
- ctx.hostNode = this._hostNode.querySelector('.tag-content-holder');
- if (ctx.section === 'edit') {
+ ctx.hostNode = this._hostNode.querySelector(".tag-content-holder");
+ if (ctx.section === "edit") {
if (!this._ctx.canEditAnything) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to edit tags.');
+ "You don't have privileges to edit tags."
+ );
} else {
this._view = new TagEditView(ctx);
- events.proxyEvent(this._view, this, 'submit');
+ events.proxyEvent(this._view, this, "submit");
}
- } else if (ctx.section === 'metric') {
+ } else if (ctx.section === "metric") {
const metricExists = this._ctx.tag.metric;
if (!metricExists && !this._ctx.canCreateMetric) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to create metrics.');
+ "You don\"t have privileges to create metrics.");
} else {
this._view = new TagMetricView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'metricUpdate');
- events.proxyEvent(this._view, this, 'delete', 'metricDelete');
+ events.proxyEvent(this._view, this, "submit", "metricUpdate");
+ events.proxyEvent(this._view, this, "delete", "metricDelete");
}
- } else if (ctx.section === 'merge') {
+ } else if (ctx.section === "merge") {
if (!this._ctx.canMerge) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to merge tags.');
+ "You don't have privileges to merge tags."
+ );
} else {
this._view = new TagMergeView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'merge');
+ events.proxyEvent(this._view, this, "submit", "merge");
}
-
- } else if (ctx.section === 'delete') {
+ } else if (ctx.section === "delete") {
if (!this._ctx.canDelete) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to delete tags.');
+ "You don't have privileges to delete tags."
+ );
} else {
this._view = new TagDeleteView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'delete');
+ events.proxyEvent(this._view, this, "submit", "delete");
}
-
} else {
this._view = new TagSummaryView(ctx);
}
- events.proxyEvent(this._view, this, 'change');
+ events.proxyEvent(this._view, this, "change");
views.syncScrollPosition();
}
diff --git a/client/js/views/tags_header_view.js b/client/js/views/tags_header_view.js
index 05b32f3..6dd7626 100644
--- a/client/js/views/tags_header_view.js
+++ b/client/js/views/tags_header_view.js
@@ -1,13 +1,12 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const misc = require('../util/misc.js');
-const search = require('../util/search.js');
-const views = require('../util/views.js');
-const TagAutoCompleteControl =
- require('../controls/tag_auto_complete_control.js');
+const events = require("../events.js");
+const misc = require("../util/misc.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
+const TagAutoCompleteControl = require("../controls/tag_auto_complete_control.js");
-const template = views.getTemplate('tags-header');
+const template = views.getTemplate("tags-header");
class TagsHeaderView extends events.EventTarget {
constructor(ctx) {
@@ -20,32 +19,41 @@ class TagsHeaderView extends events.EventTarget {
this._autoCompleteControl = new TagAutoCompleteControl(
this._queryInputNode,
{
- confirm: tag =>
+ confirm: (tag) =>
this._autoCompleteControl.replaceSelectedText(
- misc.escapeSearchTerm(tag.names[0]), true),
- });
+ misc.escapeSearchTerm(tag.names[0]),
+ true
+ ),
+ }
+ );
}
search.searchInputNodeFocusHelper(this._queryInputNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _queryInputNode() {
- return this._hostNode.querySelector('[name=search-text]');
+ return this._hostNode.querySelector("[name=search-text]");
}
_evtSubmit(e) {
e.preventDefault();
this._queryInputNode.blur();
- this.dispatchEvent(new CustomEvent('navigate', {detail: {parameters: {
- query: this._queryInputNode.value,
- page: 1,
- }}}));
+ this.dispatchEvent(
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: {
+ query: this._queryInputNode.value,
+ page: 1,
+ },
+ },
+ })
+ );
}
}
diff --git a/client/js/views/tags_page_view.js b/client/js/views/tags_page_view.js
index cd335a4..e2b2820 100644
--- a/client/js/views/tags_page_view.js
+++ b/client/js/views/tags_page_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('tags-page');
+const template = views.getTemplate("tags-page");
class TagsPageView {
constructor(ctx) {
diff --git a/client/js/views/top_navigation_view.js b/client/js/views/top_navigation_view.js
index 2f99187..efe75a9 100644
--- a/client/js/views/top_navigation_view.js
+++ b/client/js/views/top_navigation_view.js
@@ -1,24 +1,24 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('top-navigation');
+const template = views.getTemplate("top-navigation");
class TopNavigationView {
constructor() {
- this._hostNode = document.getElementById('top-navigation-holder');
+ this._hostNode = document.getElementById("top-navigation-holder");
}
get _mobileNavigationToggleNode() {
- return this._hostNode.querySelector('#mobile-navigation-toggle');
+ return this._hostNode.querySelector("#mobile-navigation-toggle");
}
get _navigationListNode() {
- return this._hostNode.querySelector('nav > ul');
+ return this._hostNode.querySelector("nav > ul");
}
get _navigationLinkNodes() {
- return this._navigationListNode.querySelectorAll('li > a');
+ return this._navigationListNode.querySelectorAll("li > a");
}
render(ctx) {
@@ -28,28 +28,32 @@ class TopNavigationView {
}
activate(key) {
- for (let itemNode of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let itemNode of this._hostNode.querySelectorAll("[data-name]")) {
itemNode.classList.toggle(
- 'active', itemNode.getAttribute('data-name') === key);
+ "active",
+ itemNode.getAttribute("data-name") === key
+ );
}
}
_bindMobileNavigationEvents() {
- this._mobileNavigationToggleNode.addEventListener(
- 'click', e => this._mobileNavigationToggleClick(e));
+ this._mobileNavigationToggleNode.addEventListener("click", (e) =>
+ this._mobileNavigationToggleClick(e)
+ );
for (let navigationLinkNode of this._navigationLinkNodes) {
- navigationLinkNode.addEventListener(
- 'click', e => this._navigationLinkClick(e));
+ navigationLinkNode.addEventListener("click", (e) =>
+ this._navigationLinkClick(e)
+ );
}
}
_mobileNavigationToggleClick(e) {
- this._navigationListNode.classList.toggle('opened');
+ this._navigationListNode.classList.toggle("opened");
}
_navigationLinkClick(e) {
- this._navigationListNode.classList.remove('opened');
+ this._navigationListNode.classList.remove("opened");
}
}
diff --git a/client/js/views/user_delete_view.js b/client/js/views/user_delete_view.js
index bdaf9e6..37de52f 100644
--- a/client/js/views/user_delete_view.js
+++ b/client/js/views/user_delete_view.js
@@ -1,9 +1,9 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('user-delete');
+const template = views.getTemplate("user-delete");
class UserDeleteView extends events.EventTarget {
constructor(ctx) {
@@ -14,7 +14,7 @@ class UserDeleteView extends events.EventTarget {
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -39,16 +39,17 @@ class UserDeleteView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- user: this._user,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ user: this._user,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
-
+ return this._hostNode.querySelector("form");
}
}
diff --git a/client/js/views/user_edit_view.js b/client/js/views/user_edit_view.js
index 8a6f1a4..4886726 100644
--- a/client/js/views/user_edit_view.js
+++ b/client/js/views/user_edit_view.js
@@ -1,11 +1,11 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const api = require('../api.js');
-const views = require('../util/views.js');
-const FileDropperControl = require('../controls/file_dropper_control.js');
+const events = require("../events.js");
+const api = require("../api.js");
+const views = require("../util/views.js");
+const FileDropperControl = require("../controls/file_dropper_control.js");
-const template = views.getTemplate('user-edit');
+const template = views.getTemplate("user-edit");
class UserEditView extends events.EventTarget {
constructor(ctx) {
@@ -22,24 +22,26 @@ class UserEditView extends events.EventTarget {
this._avatarContent = null;
if (this._avatarContentInputNode) {
this._avatarFileDropper = new FileDropperControl(
- this._avatarContentInputNode, {lock: true});
- this._avatarFileDropper.addEventListener('fileadd', e => {
+ this._avatarContentInputNode,
+ { lock: true }
+ );
+ this._avatarFileDropper.addEventListener("fileadd", (e) => {
this._hostNode.querySelector(
- '[name=avatar-style][value=manual]').checked = true;
+ "[name=avatar-style][value=manual]"
+ ).checked = true;
this._avatarContent = e.detail.files[0];
});
}
- for (let node of this._formNode.querySelectorAll('input, select')) {
- node.addEventListener(
- 'change', e => {
- if (!e.target.classList.contains('anticomplete')) {
- this.dispatchEvent(new CustomEvent('change'));
- }
- });
+ for (let node of this._formNode.querySelectorAll("input, select")) {
+ node.addEventListener("change", (e) => {
+ if (!e.target.classList.contains("anticomplete")) {
+ this.dispatchEvent(new CustomEvent("change"));
+ }
+ });
}
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
clearMessages() {
@@ -64,61 +66,63 @@ class UserEditView extends events.EventTarget {
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- user: this._user,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ user: this._user,
- name: this._userNameInputNode ?
- this._userNameInputNode.value :
- undefined,
+ name: this._userNameInputNode
+ ? this._userNameInputNode.value
+ : undefined,
- email: this._emailInputNode ?
- this._emailInputNode.value :
- undefined,
+ email: this._emailInputNode
+ ? this._emailInputNode.value
+ : undefined,
- rank: this._rankInputNode ?
- this._rankInputNode.value :
- undefined,
+ rank: this._rankInputNode
+ ? this._rankInputNode.value
+ : undefined,
- avatarStyle: this._avatarStyleInputNode ?
- this._avatarStyleInputNode.value :
- undefined,
+ avatarStyle: this._avatarStyleInputNode
+ ? this._avatarStyleInputNode.value
+ : undefined,
- password: this._passwordInputNode ?
- this._passwordInputNode.value :
- undefined,
+ password: this._passwordInputNode
+ ? this._passwordInputNode.value
+ : undefined,
- avatarContent: this._avatarContent,
- },
- }));
+ avatarContent: this._avatarContent,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _rankInputNode() {
- return this._formNode.querySelector('[name=rank]');
+ return this._formNode.querySelector("[name=rank]");
}
get _emailInputNode() {
- return this._formNode.querySelector('[name=email]');
+ return this._formNode.querySelector("[name=email]");
}
get _userNameInputNode() {
- return this._formNode.querySelector('[name=name]');
+ return this._formNode.querySelector("[name=name]");
}
get _passwordInputNode() {
- return this._formNode.querySelector('[name=password]');
+ return this._formNode.querySelector("[name=password]");
}
get _avatarContentInputNode() {
- return this._formNode.querySelector('#avatar-content');
+ return this._formNode.querySelector("#avatar-content");
}
get _avatarStyleInputNode() {
- return this._formNode.querySelector('[name=avatar-style]:checked');
+ return this._formNode.querySelector("[name=avatar-style]:checked");
}
}
diff --git a/client/js/views/user_summary_view.js b/client/js/views/user_summary_view.js
index d8463f3..eab827f 100644
--- a/client/js/views/user_summary_view.js
+++ b/client/js/views/user_summary_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('user-summary');
+const template = views.getTemplate("user-summary");
class UserSummaryView {
constructor(ctx) {
diff --git a/client/js/views/user_tokens_view.js b/client/js/views/user_tokens_view.js
index f6c8480..68707f0 100644
--- a/client/js/views/user_tokens_view.js
+++ b/client/js/views/user_tokens_view.js
@@ -1,9 +1,9 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('user-tokens');
+const template = views.getTemplate("user-tokens");
class UserTokenView extends events.EventTarget {
constructor(ctx) {
@@ -16,7 +16,7 @@ class UserTokenView extends events.EventTarget {
views.replaceContent(this._hostNode, template(ctx));
views.decorateValidator(this._formNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
this._decorateTokenForms();
this._decorateTokenNoteChangeLinks();
@@ -26,8 +26,9 @@ class UserTokenView extends events.EventTarget {
this._tokenFormNodes = [];
for (let i = 0; i < this._tokens.length; i++) {
let formNode = this._hostNode.querySelector(
- '.token[data-token-id=\"' + i + '\"]');
- formNode.addEventListener('submit', e => this._evtDelete(e));
+ '.token[data-token-id="' + i + '"]'
+ );
+ formNode.addEventListener("submit", (e) => this._evtDelete(e));
this._tokenFormNodes.push(formNode);
}
}
@@ -35,9 +36,11 @@ class UserTokenView extends events.EventTarget {
_decorateTokenNoteChangeLinks() {
for (let i = 0; i < this._tokens.length; i++) {
let linkNode = this._hostNode.querySelector(
- '.token-change-note[data-token-id=\"' + i + '\"]');
- linkNode.addEventListener(
- 'click', e => this._evtChangeNoteClick(e));
+ '.token-change-note[data-token-id="' + i + '"]'
+ );
+ linkNode.addEventListener("click", (e) =>
+ this._evtChangeNoteClick(e)
+ );
}
}
@@ -69,65 +72,75 @@ class UserTokenView extends events.EventTarget {
_evtDelete(e) {
e.preventDefault();
- const userToken = this._tokens[parseInt(
- e.target.getAttribute('data-token-id'))];
- this.dispatchEvent(new CustomEvent('delete', {
- detail: {
- user: this._user,
- userToken: userToken,
- },
- }));
+ const userToken = this._tokens[
+ parseInt(e.target.getAttribute("data-token-id"))
+ ];
+ this.dispatchEvent(
+ new CustomEvent("delete", {
+ detail: {
+ user: this._user,
+ userToken: userToken,
+ },
+ })
+ );
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('submit', {
- detail: {
- user: this._user,
+ this.dispatchEvent(
+ new CustomEvent("submit", {
+ detail: {
+ user: this._user,
- note: this._userTokenNoteInputNode ?
- this._userTokenNoteInputNode.value :
- undefined,
+ note: this._userTokenNoteInputNode
+ ? this._userTokenNoteInputNode.value
+ : undefined,
- expirationTime:
- (this._userTokenExpirationTimeInputNode
- && this._userTokenExpirationTimeInputNode.value) ?
- new Date(this._userTokenExpirationTimeInputNode.value)
- .toISOString() :
- undefined,
- },
- }));
+ expirationTime:
+ this._userTokenExpirationTimeInputNode &&
+ this._userTokenExpirationTimeInputNode.value
+ ? new Date(
+ this._userTokenExpirationTimeInputNode.value
+ ).toISOString()
+ : undefined,
+ },
+ })
+ );
}
_evtChangeNoteClick(e) {
e.preventDefault();
const userToken = this._tokens[
- parseInt(e.target.getAttribute('data-token-id'))];
+ parseInt(e.target.getAttribute("data-token-id"))
+ ];
const text = window.prompt(
- 'Please enter the new name:',
- userToken.note !== null ? userToken.note : undefined);
+ "Please enter the new name:",
+ userToken.note !== null ? userToken.note : undefined
+ );
if (!text) {
return;
}
- this.dispatchEvent(new CustomEvent('update', {
- detail: {
- user: this._user,
- userToken: userToken,
- note: text ? text : undefined,
- },
- }));
+ this.dispatchEvent(
+ new CustomEvent("update", {
+ detail: {
+ user: this._user,
+ userToken: userToken,
+ note: text ? text : undefined,
+ },
+ })
+ );
}
get _formNode() {
- return this._hostNode.querySelector('#create-token-form');
+ return this._hostNode.querySelector("#create-token-form");
}
get _userTokenNoteInputNode() {
- return this._formNode.querySelector('.note input');
+ return this._formNode.querySelector(".note input");
}
get _userTokenExpirationTimeInputNode() {
- return this._formNode.querySelector('.expirationTime input');
+ return this._formNode.querySelector(".expirationTime input");
}
}
diff --git a/client/js/views/user_view.js b/client/js/views/user_view.js
index 75fd154..2eebfe9 100644
--- a/client/js/views/user_view.js
+++ b/client/js/views/user_view.js
@@ -1,24 +1,24 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const views = require('../util/views.js');
-const UserDeleteView = require('./user_delete_view.js');
-const UserTokensView = require('./user_tokens_view.js');
-const UserSummaryView = require('./user_summary_view.js');
-const UserEditView = require('./user_edit_view.js');
-const EmptyView = require('../views/empty_view.js');
+const events = require("../events.js");
+const views = require("../util/views.js");
+const UserDeleteView = require("./user_delete_view.js");
+const UserTokensView = require("./user_tokens_view.js");
+const UserSummaryView = require("./user_summary_view.js");
+const UserEditView = require("./user_edit_view.js");
+const EmptyView = require("../views/empty_view.js");
-const template = views.getTemplate('user');
+const template = views.getTemplate("user");
class UserView extends events.EventTarget {
constructor(ctx) {
super();
this._ctx = ctx;
- ctx.user.addEventListener('change', e => this._evtChange(e));
- ctx.section = ctx.section || 'summary';
+ ctx.user.addEventListener("change", (e) => this._evtChange(e));
+ ctx.section = ctx.section || "summary";
- this._hostNode = document.getElementById('content-holder');
+ this._hostNode = document.getElementById("content-holder");
this._install();
}
@@ -26,52 +26,56 @@ class UserView extends events.EventTarget {
const ctx = this._ctx;
views.replaceContent(this._hostNode, template(ctx));
- for (let item of this._hostNode.querySelectorAll('[data-name]')) {
+ for (let item of this._hostNode.querySelectorAll("[data-name]")) {
item.classList.toggle(
- 'active', item.getAttribute('data-name') === ctx.section);
- if (item.getAttribute('data-name') === ctx.section) {
+ "active",
+ item.getAttribute("data-name") === ctx.section
+ );
+ if (item.getAttribute("data-name") === ctx.section) {
item.parentNode.scrollLeft =
item.getBoundingClientRect().left -
- item.parentNode.getBoundingClientRect().left
+ item.parentNode.getBoundingClientRect().left;
}
}
- ctx.hostNode = this._hostNode.querySelector('#user-content-holder');
- if (ctx.section == 'edit') {
+ ctx.hostNode = this._hostNode.querySelector("#user-content-holder");
+ if (ctx.section === "edit") {
if (!this._ctx.canEditAnything) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to edit users.');
+ "You don't have privileges to edit users."
+ );
} else {
this._view = new UserEditView(ctx);
- events.proxyEvent(this._view, this, 'submit');
+ events.proxyEvent(this._view, this, "submit");
}
- } else if (ctx.section == 'list-tokens') {
+ } else if (ctx.section === "list-tokens") {
if (!this._ctx.canListTokens) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to view user tokens.');
+ "You don't have privileges to view user tokens."
+ );
} else {
this._view = new UserTokensView(ctx);
- events.proxyEvent(this._view, this, 'delete', 'delete-token');
- events.proxyEvent(this._view, this, 'submit', 'create-token');
- events.proxyEvent(this._view, this, 'update', 'update-token');
+ events.proxyEvent(this._view, this, "delete", "delete-token");
+ events.proxyEvent(this._view, this, "submit", "create-token");
+ events.proxyEvent(this._view, this, "update", "update-token");
}
- } else if (ctx.section == 'delete') {
+ } else if (ctx.section === "delete") {
if (!this._ctx.canDelete) {
this._view = new EmptyView();
this._view.showError(
- 'You don\'t have privileges to delete users.');
+ "You don't have privileges to delete users."
+ );
} else {
this._view = new UserDeleteView(ctx);
- events.proxyEvent(this._view, this, 'submit', 'delete');
+ events.proxyEvent(this._view, this, "submit", "delete");
}
-
} else {
this._view = new UserSummaryView(ctx);
}
- events.proxyEvent(this._view, this, 'change');
+ events.proxyEvent(this._view, this, "change");
views.syncScrollPosition();
}
diff --git a/client/js/views/users_header_view.js b/client/js/views/users_header_view.js
index 08b7620..d6b7c6a 100644
--- a/client/js/views/users_header_view.js
+++ b/client/js/views/users_header_view.js
@@ -1,10 +1,10 @@
-'use strict';
+"use strict";
-const events = require('../events.js');
-const search = require('../util/search.js');
-const views = require('../util/views.js');
+const events = require("../events.js");
+const search = require("../util/search.js");
+const views = require("../util/views.js");
-const template = views.getTemplate('users-header');
+const template = views.getTemplate("users-header");
class UsersHeaderView extends events.EventTarget {
constructor(ctx) {
@@ -15,23 +15,29 @@ class UsersHeaderView extends events.EventTarget {
search.searchInputNodeFocusHelper(this._queryInputNode);
- this._formNode.addEventListener('submit', e => this._evtSubmit(e));
+ this._formNode.addEventListener("submit", (e) => this._evtSubmit(e));
}
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector("form");
}
get _queryInputNode() {
- return this._formNode.querySelector('[name=search-text]');
+ return this._formNode.querySelector("[name=search-text]");
}
_evtSubmit(e) {
e.preventDefault();
- this.dispatchEvent(new CustomEvent('navigate', {detail: {parameters: {
- query: this._queryInputNode.value,
- page: 1,
- }}}));
+ this.dispatchEvent(
+ new CustomEvent("navigate", {
+ detail: {
+ parameters: {
+ query: this._queryInputNode.value,
+ page: 1,
+ },
+ },
+ })
+ );
}
}
diff --git a/client/js/views/users_page_view.js b/client/js/views/users_page_view.js
index f772d4e..2689433 100644
--- a/client/js/views/users_page_view.js
+++ b/client/js/views/users_page_view.js
@@ -1,8 +1,8 @@
-'use strict';
+"use strict";
-const views = require('../util/views.js');
+const views = require("../util/views.js");
-const template = views.getTemplate('users-page');
+const template = views.getTemplate("users-page");
class UsersPageView {
constructor(ctx) {

© 2015 - 2026 Jakob L. Kreuze