diff options
Diffstat (limited to 'client/js/views')
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} → ${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) { |