diff options
| author | rr- | 2017-02-11 21:58:18 +0100 |
|---|---|---|
| committer | rr- | 2017-02-11 22:03:38 +0100 |
| commit | 1caf76b1b2e2aaef507b1936a2c5a66c2df140f5 (patch) | |
| tree | 4fa544825fb1dc785c2d1eec4876aeb3cc86845f /client/js | |
| parent | 0dc7a4058e8e00b1dd878343f89b8c7a10cfcdaf (diff) | |
client/posts: add bulk safety editing (#122)
Diffstat (limited to 'client/js')
| -rw-r--r-- | client/js/controllers/post_list_controller.js | 12 | ||||
| -rw-r--r-- | client/js/views/posts_header_view.js | 120 | ||||
| -rw-r--r-- | client/js/views/posts_page_view.js | 88 |
3 files changed, 182 insertions, 38 deletions
diff --git a/client/js/controllers/post_list_controller.js b/client/js/controllers/post_list_controller.js index a0973e1..12b354f 100644 --- a/client/js/controllers/post_list_controller.js +++ b/client/js/controllers/post_list_controller.js @@ -11,7 +11,7 @@ const PostsPageView = require('../views/posts_page_view.js'); const EmptyView = require('../views/empty_view.js'); const fields = [ - 'id', 'thumbnailUrl', 'type', + 'id', 'thumbnailUrl', 'type', 'safety', 'score', 'favoriteCount', 'commentCount', 'tags', 'version']; class PostListController { @@ -32,6 +32,7 @@ class PostListController { hostNode: this._pageController.view.pageHeaderHolderNode, parameters: ctx.parameters, canBulkEditTags: api.hasPrivilege('posts:bulkEdit:tags'), + canBulkEditSafety: api.hasPrivilege('posts:bulkEdit:safety'), bulkEdit: { tags: this._bulkEditTags }, @@ -73,6 +74,11 @@ class PostListController { e.detail.post.save().catch(error => window.alert(error.message)); } + _evtChangeSafety(e) { + e.detail.post.safety = e.detail.safety; + e.detail.post.save().catch(error => window.alert(error.message)); + } + _decorateSearchQuery(text) { const browsingSettings = settings.get(); let disabledSafety = []; @@ -106,6 +112,8 @@ class PostListController { Object.assign(pageCtx, { canViewPosts: api.hasPrivilege('posts:view'), canBulkEditTags: api.hasPrivilege('posts:bulkEdit:tags'), + canBulkEditSafety: + api.hasPrivilege('posts:bulkEdit:safety'), bulkEdit: { tags: this._bulkEditTags, }, @@ -113,6 +121,8 @@ class PostListController { const view = new PostsPageView(pageCtx); view.addEventListener('tag', e => this._evtTag(e)); view.addEventListener('untag', e => this._evtUntag(e)); + view.addEventListener( + 'changeSafety', e => this._evtChangeSafety(e)); return view; }, }); diff --git a/client/js/views/posts_header_view.js b/client/js/views/posts_header_view.js index 0bc1dce..efa3d02 100644 --- a/client/js/views/posts_header_view.js +++ b/client/js/views/posts_header_view.js @@ -11,26 +11,19 @@ const TagAutoCompleteControl = const template = views.getTemplate('posts-header'); -class BulkTagEditor extends events.EventTarget { +class BulkEditor extends events.EventTarget { constructor(hostNode) { super(); this._hostNode = hostNode; - - this._autoCompleteControl = new TagAutoCompleteControl( - this._inputNode, {addSpace: false}); this._openLinkNode.addEventListener( 'click', e => this._evtOpenLinkClick(e)); this._closeLinkNode.addEventListener( 'click', e => this._evtCloseLinkClick(e)); - this._hostNode.addEventListener('submit', e => this._evtFormSubmit(e)); - } - - get value() { - return this._inputNode.value; } get opened() { - return this._hostNode.classList.contains('opened'); + return this._hostNode.classList.contains('opened') && + !this._hostNode.classList.contains('hidden'); } get _openLinkNode() { @@ -41,6 +34,53 @@ class BulkTagEditor extends events.EventTarget { return this._hostNode.querySelector('.close'); } + toggleOpen(state) { + this._hostNode.classList.toggle('opened', state); + } + + toggleHide(state) { + this._hostNode.classList.toggle('hidden', state); + } + + _evtOpenLinkClick(e) { + throw new Error('Not implemented'); + } + + _evtCloseLinkClick(e) { + 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: {}})); + } + + _evtCloseLinkClick(e) { + e.preventDefault(); + this.toggleOpen(false); + this.dispatchEvent(new CustomEvent('close', {detail: {}})); + } +} + +class BulkTagEditor extends BulkEditor { + constructor(hostNode) { + super(hostNode); + this._autoCompleteControl = new TagAutoCompleteControl( + this._inputNode, {addSpace: false}); + this._hostNode.addEventListener('submit', e => this._evtFormSubmit(e)); + } + + get value() { + return this._inputNode.value; + } + get _inputNode() { return this._hostNode.querySelector('input[name=tag]'); } @@ -54,10 +94,6 @@ class BulkTagEditor extends events.EventTarget { this._inputNode.blur(); } - toggleOpen(state) { - this._hostNode.classList.toggle('opened', state); - } - _evtFormSubmit(e) { e.preventDefault(); this.dispatchEvent(new CustomEvent('submit', {detail: {}})); @@ -99,19 +135,39 @@ class PostsHeaderView extends events.EventTarget { safetyButtonNode.addEventListener( 'click', e => this._evtSafetyButtonClick(e)); } - this._formNode.addEventListener( - 'submit', e => this._evtFormSubmit(e)); + this._formNode.addEventListener('submit', e => this._evtFormSubmit(e)); + this._bulkEditors = []; if (this._bulkEditTagsNode) { this._bulkTagEditor = new BulkTagEditor(this._bulkEditTagsNode); - this._bulkTagEditor.toggleOpen(!!ctx.parameters.tag); + this._bulkEditors.push(this._bulkTagEditor); + } + + if (this._bulkEditSafetyNode) { + this._bulkSafetyEditor = new BulkSafetyEditor( + this._bulkEditSafetyNode); + this._bulkEditors.push(this._bulkSafetyEditor); + } + + for (let editor of this._bulkEditors) { this._bulkTagEditor.addEventListener('submit', e => { this._navigate(); }); - this._bulkTagEditor.addEventListener('close', e => { + editor.addEventListener('open', e => { + this._hideBulkEditorsExcept(editor); + this._navigate(); + }); + editor.addEventListener('close', e => { + this._closeAndShowAllBulkEditors(); this._navigate(); }); } + + if (ctx.parameters.tag && this._bulkTagEditor) { + this._openBulkEditor(this._bulkTagEditor); + } else if (ctx.parameters.safety && this._bulkSafetyEditor) { + this._openBulkEditor(this._bulkSafetyEditor); + } } get _formNode() { @@ -130,6 +186,31 @@ class PostsHeaderView extends events.EventTarget { return this._hostNode.querySelector('.bulk-edit-tags'); } + get _bulkEditSafetyNode() { + return this._hostNode.querySelector('.bulk-edit-safety'); + } + + _openBulkEditor(editor) { + editor.toggleOpen(true); + this._hideBulkEditorsExcept(editor); + } + + _hideBulkEditorsExcept(editor) { + for (let otherEditor of this._bulkEditors) { + if (otherEditor !== editor) { + otherEditor.toggleOpen(false); + otherEditor.toggleHide(true); + } + } + } + + _closeAndShowAllBulkEditors() { + for (let otherEditor of this._bulkEditors) { + otherEditor.toggleOpen(false); + otherEditor.toggleHide(false); + } + } + _evtSafetyButtonClick(e, url) { e.preventDefault(); e.target.classList.toggle('disabled'); @@ -164,6 +245,9 @@ class PostsHeaderView extends events.EventTarget { } else { parameters.tag = null; } + parameters.safety = ( + this._bulkSafetyEditor && + this._bulkSafetyEditor.opened ? '1' : null); this.dispatchEvent( new CustomEvent('navigate', {detail: {parameters: parameters}})); } diff --git a/client/js/views/posts_page_view.js b/client/js/views/posts_page_view.js index c2dbe90..2610325 100644 --- a/client/js/views/posts_page_view.js +++ b/client/js/views/posts_page_view.js @@ -18,26 +18,48 @@ class PostsPageView extends events.EventTarget { post.addEventListener('change', e => this._evtPostChange(e)); } - this._postIdToLinkNode = {}; - for (let linkNode of this._tagFlipperNodes) { - const postId = linkNode.getAttribute('data-post-id'); + this._postIdToListItemNode = {}; + for (let listItemNode of this._listItemNodes) { + const postId = listItemNode.getAttribute('data-post-id'); const post = this._postIdToPost[postId]; - this._postIdToLinkNode[postId] = linkNode; - linkNode.addEventListener( - 'click', e => this._evtBulkEditTagsClick(e, post)); + this._postIdToListItemNode[postId] = listItemNode; + + const tagFlipperNode = this._getTagFlipperNode(listItemNode); + if (tagFlipperNode) { + tagFlipperNode.addEventListener( + 'click', e => this._evtBulkEditTagsClick(e, post)); + } + + const safetyFlipperNode = this._getSafetyFlipperNode(listItemNode); + if (safetyFlipperNode) { + for (let linkNode of safetyFlipperNode.querySelectorAll('a')) { + linkNode.addEventListener( + 'click', e => this._evtBulkEditSafetyClick(e, post)); + } + } } - this._syncTagFlippersHighlights(); + this._syncBulkEditorsHighlights(); + } + + get _listItemNodes() { + return this._hostNode.querySelectorAll('li'); } - get _tagFlipperNodes() { - return this._hostNode.querySelectorAll('.tag-flipper'); + _getTagFlipperNode(listItemNode) { + return listItemNode.querySelector('.tag-flipper'); + } + + _getSafetyFlipperNode(listItemNode) { + return listItemNode.querySelector('.safety-flipper'); } _evtPostChange(e) { - const linkNode = this._postIdToLinkNode[e.detail.post.id]; - linkNode.removeAttribute('data-disabled'); - this._syncTagFlippersHighlights(); + const listItemNode = this._postIdToListItemNode[e.detail.post.id]; + for (let node of listItemNode.querySelectorAll('[data-disabled]')) { + node.removeAttribute('data-disabled'); + } + this._syncBulkEditorsHighlights(); } _evtBulkEditTagsClick(e, post) { @@ -53,15 +75,43 @@ class PostsPageView extends events.EventTarget { {detail: {post: post}})); } - _syncTagFlippersHighlights() { - for (let linkNode of this._tagFlipperNodes) { - const postId = linkNode.getAttribute('data-post-id'); + _evtBulkEditSafetyClick(e, post) { + e.preventDefault(); + const linkNode = e.target; + if (linkNode.getAttribute('data-disabled')) { + return; + } + const newSafety = linkNode.getAttribute('data-safety'); + if (post.safety === newSafety) { + return; + } + linkNode.setAttribute('data-disabled', true); + this.dispatchEvent( + new CustomEvent( + 'changeSafety', {detail: {post: post, safety: newSafety}})); + } + + _syncBulkEditorsHighlights() { + for (let listItemNode of this._listItemNodes) { + const postId = listItemNode.getAttribute('data-post-id'); const post = this._postIdToPost[postId]; - let tagged = true; - for (let tag of this._ctx.bulkEdit.tags) { - tagged = tagged & post.isTaggedWith(tag); + + const tagFlipperNode = this._getTagFlipperNode(listItemNode); + if (tagFlipperNode) { + let tagged = true; + for (let tag of this._ctx.bulkEdit.tags) { + tagged = tagged & post.isTaggedWith(tag); + } + 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); + } } - linkNode.classList.toggle('tagged', tagged); } } } |