client/posts: add bulk safety editing (#122)
This commit is contained in:
parent
0dc7a4058e
commit
1caf76b1b2
7 changed files with 242 additions and 47 deletions
|
@ -84,6 +84,37 @@
|
||||||
&[data-disabled]
|
&[data-disabled]
|
||||||
background: rgba(200, 200, 200, 0.7)
|
background: rgba(200, 200, 200, 0.7)
|
||||||
|
|
||||||
|
.safety-flipper a
|
||||||
|
display: inline-block
|
||||||
|
margin: 0.1em
|
||||||
|
box-sizing: border-box
|
||||||
|
border: 0
|
||||||
|
display: inline-block
|
||||||
|
width: 1.2em
|
||||||
|
height: 1.2em
|
||||||
|
text-align: center
|
||||||
|
line-height: 1em
|
||||||
|
font-size: 20pt
|
||||||
|
border: 3px solid
|
||||||
|
&.safety-safe
|
||||||
|
background-color: darken($safety-safe, 5%)
|
||||||
|
border-color: @background-color
|
||||||
|
&:not(.active)
|
||||||
|
background-color: alpha(@background-color, 0.3)
|
||||||
|
&.safety-sketchy
|
||||||
|
background-color: $safety-sketchy
|
||||||
|
border-color: @background-color
|
||||||
|
&:not(.active)
|
||||||
|
background-color: alpha(@background-color, 0.3)
|
||||||
|
&.safety-unsafe
|
||||||
|
background-color: $safety-unsafe
|
||||||
|
border-color: @background-color
|
||||||
|
&:not(.active)
|
||||||
|
background-color: alpha(@background-color, 0.3)
|
||||||
|
&[data-disabled]
|
||||||
|
background: rgba(200, 200, 200, 0.7)
|
||||||
|
|
||||||
|
|
||||||
.thumbnail
|
.thumbnail
|
||||||
background-position: 50% 30%
|
background-position: 50% 30%
|
||||||
width: 100%
|
width: 100%
|
||||||
|
@ -122,20 +153,25 @@
|
||||||
.append
|
.append
|
||||||
font-size: 0.95em
|
font-size: 0.95em
|
||||||
color: $inactive-link-color
|
color: $inactive-link-color
|
||||||
.bulk-edit-tags
|
.bulk-edit
|
||||||
&:not(.opened)
|
&:not(.opened)
|
||||||
[type=text],
|
|
||||||
.start,
|
|
||||||
.close
|
.close
|
||||||
display: none
|
display: none
|
||||||
.hint
|
|
||||||
display: none
|
|
||||||
&.opened
|
&.opened
|
||||||
.open
|
.open
|
||||||
display: none
|
display: none
|
||||||
|
&.hidden
|
||||||
|
display: none
|
||||||
|
.bulk-edit-tags
|
||||||
|
&:not(.opened)
|
||||||
|
[type=text],
|
||||||
|
.start
|
||||||
|
display: none
|
||||||
|
.hint
|
||||||
|
display: none
|
||||||
input[name=tag]
|
input[name=tag]
|
||||||
width: 12em
|
width: 12em
|
||||||
.hint, .open
|
.hint
|
||||||
margin-right: 1em
|
margin-right: 1em
|
||||||
|
|
||||||
.safety
|
.safety
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
%><a class='mousetrap button append' href='<%- ctx.formatClientLink('help', 'search', 'posts') %>'>Syntax help</a><%
|
%><a class='mousetrap button append' href='<%- ctx.formatClientLink('help', 'search', 'posts') %>'>Syntax help</a><%
|
||||||
%></form><%
|
%></form><%
|
||||||
%><% if (ctx.canBulkEditTags) { %><%
|
%><% if (ctx.canBulkEditTags) { %><%
|
||||||
%><form class='horizontal bulk-edit-tags'><%
|
%><form class='horizontal bulk-edit bulk-edit-tags'><%
|
||||||
%><span class='append hint'>Tagging with:</span><%
|
%><span class='append hint'>Tagging with:</span><%
|
||||||
%><a href class='mousetrap button append open'>Mass tag</a><%
|
%><a href class='mousetrap button append open'>Mass tag</a><%
|
||||||
%><wbr/><%
|
%><wbr/><%
|
||||||
|
@ -20,4 +20,10 @@
|
||||||
%><a href class='mousetrap button append close'>Stop tagging</a><%
|
%><a href class='mousetrap button append close'>Stop tagging</a><%
|
||||||
%></form><%
|
%></form><%
|
||||||
%><% } %><%
|
%><% } %><%
|
||||||
|
%><% if (ctx.canBulkEditSafety) { %><%
|
||||||
|
%><form class='horizontal bulk-edit bulk-edit-safety'><%
|
||||||
|
%><a href class='mousetrap button append open'>Mass edit safety</a><%
|
||||||
|
%><a href class='mousetrap button append close'>Stop editing safety</a><%
|
||||||
|
%></form><%
|
||||||
|
%><% } %><%
|
||||||
%></div>
|
%></div>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<% if (ctx.response.results.length) { %>
|
<% if (ctx.response.results.length) { %>
|
||||||
<ul>
|
<ul>
|
||||||
<% for (let post of ctx.response.results) { %>
|
<% for (let post of ctx.response.results) { %>
|
||||||
<li>
|
<li data-post-id='<%= post.id %>'>
|
||||||
<a class='thumbnail-wrapper <%= post.tags.length > 0 ? "tags" : "no-tags" %>'
|
<a class='thumbnail-wrapper <%= post.tags.length > 0 ? "tags" : "no-tags" %>'
|
||||||
title='@<%- post.id %> (<%- post.type %>) Tags: <%- post.tags.map(tag => '#' + tag).join(' ') || 'none' %>'
|
title='@<%- post.id %> (<%- post.type %>) Tags: <%- post.tags.map(tag => '#' + tag).join(' ') || 'none' %>'
|
||||||
href='<%= ctx.canViewPosts ? ctx.getPostUrl(post.id, ctx.parameters) : '' %>'>
|
href='<%= ctx.canViewPosts ? ctx.getPostUrl(post.id, ctx.parameters) : '' %>'>
|
||||||
|
@ -35,9 +35,17 @@
|
||||||
</a>
|
</a>
|
||||||
<span class='edit-overlay'>
|
<span class='edit-overlay'>
|
||||||
<% if (ctx.canBulkEditTags && ctx.parameters && ctx.parameters.tag) { %>
|
<% if (ctx.canBulkEditTags && ctx.parameters && ctx.parameters.tag) { %>
|
||||||
<a href data-post-id='<%= post.id %>' class='tag-flipper'>
|
<a href class='tag-flipper'>
|
||||||
</a>
|
</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
<% if (ctx.canBulkEditSafety && ctx.parameters && ctx.parameters.safety) { %>
|
||||||
|
<span class='safety-flipper'>
|
||||||
|
<% for (let safety of ['safe', 'sketchy', 'unsafe']) { %>
|
||||||
|
<a href data-safety='<%- safety %>' class='safety-<%- safety %><%- post.safety === safety ? ' active' : '' %>'>
|
||||||
|
</a>
|
||||||
|
<% } %>
|
||||||
|
</span>
|
||||||
|
<% } %>
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
|
@ -11,7 +11,7 @@ const PostsPageView = require('../views/posts_page_view.js');
|
||||||
const EmptyView = require('../views/empty_view.js');
|
const EmptyView = require('../views/empty_view.js');
|
||||||
|
|
||||||
const fields = [
|
const fields = [
|
||||||
'id', 'thumbnailUrl', 'type',
|
'id', 'thumbnailUrl', 'type', 'safety',
|
||||||
'score', 'favoriteCount', 'commentCount', 'tags', 'version'];
|
'score', 'favoriteCount', 'commentCount', 'tags', 'version'];
|
||||||
|
|
||||||
class PostListController {
|
class PostListController {
|
||||||
|
@ -32,6 +32,7 @@ class PostListController {
|
||||||
hostNode: this._pageController.view.pageHeaderHolderNode,
|
hostNode: this._pageController.view.pageHeaderHolderNode,
|
||||||
parameters: ctx.parameters,
|
parameters: ctx.parameters,
|
||||||
canBulkEditTags: api.hasPrivilege('posts:bulkEdit:tags'),
|
canBulkEditTags: api.hasPrivilege('posts:bulkEdit:tags'),
|
||||||
|
canBulkEditSafety: api.hasPrivilege('posts:bulkEdit:safety'),
|
||||||
bulkEdit: {
|
bulkEdit: {
|
||||||
tags: this._bulkEditTags
|
tags: this._bulkEditTags
|
||||||
},
|
},
|
||||||
|
@ -73,6 +74,11 @@ class PostListController {
|
||||||
e.detail.post.save().catch(error => window.alert(error.message));
|
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) {
|
_decorateSearchQuery(text) {
|
||||||
const browsingSettings = settings.get();
|
const browsingSettings = settings.get();
|
||||||
let disabledSafety = [];
|
let disabledSafety = [];
|
||||||
|
@ -106,6 +112,8 @@ class PostListController {
|
||||||
Object.assign(pageCtx, {
|
Object.assign(pageCtx, {
|
||||||
canViewPosts: api.hasPrivilege('posts:view'),
|
canViewPosts: api.hasPrivilege('posts:view'),
|
||||||
canBulkEditTags: api.hasPrivilege('posts:bulkEdit:tags'),
|
canBulkEditTags: api.hasPrivilege('posts:bulkEdit:tags'),
|
||||||
|
canBulkEditSafety:
|
||||||
|
api.hasPrivilege('posts:bulkEdit:safety'),
|
||||||
bulkEdit: {
|
bulkEdit: {
|
||||||
tags: this._bulkEditTags,
|
tags: this._bulkEditTags,
|
||||||
},
|
},
|
||||||
|
@ -113,6 +121,8 @@ class PostListController {
|
||||||
const view = new PostsPageView(pageCtx);
|
const view = new PostsPageView(pageCtx);
|
||||||
view.addEventListener('tag', e => this._evtTag(e));
|
view.addEventListener('tag', e => this._evtTag(e));
|
||||||
view.addEventListener('untag', e => this._evtUntag(e));
|
view.addEventListener('untag', e => this._evtUntag(e));
|
||||||
|
view.addEventListener(
|
||||||
|
'changeSafety', e => this._evtChangeSafety(e));
|
||||||
return view;
|
return view;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,26 +11,19 @@ const TagAutoCompleteControl =
|
||||||
|
|
||||||
const template = views.getTemplate('posts-header');
|
const template = views.getTemplate('posts-header');
|
||||||
|
|
||||||
class BulkTagEditor extends events.EventTarget {
|
class BulkEditor extends events.EventTarget {
|
||||||
constructor(hostNode) {
|
constructor(hostNode) {
|
||||||
super();
|
super();
|
||||||
this._hostNode = hostNode;
|
this._hostNode = hostNode;
|
||||||
|
|
||||||
this._autoCompleteControl = new TagAutoCompleteControl(
|
|
||||||
this._inputNode, {addSpace: false});
|
|
||||||
this._openLinkNode.addEventListener(
|
this._openLinkNode.addEventListener(
|
||||||
'click', e => this._evtOpenLinkClick(e));
|
'click', e => this._evtOpenLinkClick(e));
|
||||||
this._closeLinkNode.addEventListener(
|
this._closeLinkNode.addEventListener(
|
||||||
'click', e => this._evtCloseLinkClick(e));
|
'click', e => this._evtCloseLinkClick(e));
|
||||||
this._hostNode.addEventListener('submit', e => this._evtFormSubmit(e));
|
|
||||||
}
|
|
||||||
|
|
||||||
get value() {
|
|
||||||
return this._inputNode.value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get opened() {
|
get opened() {
|
||||||
return this._hostNode.classList.contains('opened');
|
return this._hostNode.classList.contains('opened') &&
|
||||||
|
!this._hostNode.classList.contains('hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
get _openLinkNode() {
|
get _openLinkNode() {
|
||||||
|
@ -41,6 +34,53 @@ class BulkTagEditor extends events.EventTarget {
|
||||||
return this._hostNode.querySelector('.close');
|
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() {
|
get _inputNode() {
|
||||||
return this._hostNode.querySelector('input[name=tag]');
|
return this._hostNode.querySelector('input[name=tag]');
|
||||||
}
|
}
|
||||||
|
@ -54,10 +94,6 @@ class BulkTagEditor extends events.EventTarget {
|
||||||
this._inputNode.blur();
|
this._inputNode.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleOpen(state) {
|
|
||||||
this._hostNode.classList.toggle('opened', state);
|
|
||||||
}
|
|
||||||
|
|
||||||
_evtFormSubmit(e) {
|
_evtFormSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.dispatchEvent(new CustomEvent('submit', {detail: {}}));
|
this.dispatchEvent(new CustomEvent('submit', {detail: {}}));
|
||||||
|
@ -99,18 +135,38 @@ class PostsHeaderView extends events.EventTarget {
|
||||||
safetyButtonNode.addEventListener(
|
safetyButtonNode.addEventListener(
|
||||||
'click', e => this._evtSafetyButtonClick(e));
|
'click', e => this._evtSafetyButtonClick(e));
|
||||||
}
|
}
|
||||||
this._formNode.addEventListener(
|
this._formNode.addEventListener('submit', e => this._evtFormSubmit(e));
|
||||||
'submit', e => this._evtFormSubmit(e));
|
|
||||||
|
|
||||||
|
this._bulkEditors = [];
|
||||||
if (this._bulkEditTagsNode) {
|
if (this._bulkEditTagsNode) {
|
||||||
this._bulkTagEditor = new BulkTagEditor(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._bulkTagEditor.addEventListener('submit', e => {
|
||||||
this._navigate();
|
this._navigate();
|
||||||
});
|
});
|
||||||
this._bulkTagEditor.addEventListener('close', e => {
|
editor.addEventListener('open', e => {
|
||||||
|
this._hideBulkEditorsExcept(editor);
|
||||||
this._navigate();
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +186,31 @@ class PostsHeaderView extends events.EventTarget {
|
||||||
return this._hostNode.querySelector('.bulk-edit-tags');
|
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) {
|
_evtSafetyButtonClick(e, url) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.target.classList.toggle('disabled');
|
e.target.classList.toggle('disabled');
|
||||||
|
@ -164,6 +245,9 @@ class PostsHeaderView extends events.EventTarget {
|
||||||
} else {
|
} else {
|
||||||
parameters.tag = null;
|
parameters.tag = null;
|
||||||
}
|
}
|
||||||
|
parameters.safety = (
|
||||||
|
this._bulkSafetyEditor &&
|
||||||
|
this._bulkSafetyEditor.opened ? '1' : null);
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('navigate', {detail: {parameters: parameters}}));
|
new CustomEvent('navigate', {detail: {parameters: parameters}}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,26 +18,48 @@ class PostsPageView extends events.EventTarget {
|
||||||
post.addEventListener('change', e => this._evtPostChange(e));
|
post.addEventListener('change', e => this._evtPostChange(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._postIdToLinkNode = {};
|
this._postIdToListItemNode = {};
|
||||||
for (let linkNode of this._tagFlipperNodes) {
|
for (let listItemNode of this._listItemNodes) {
|
||||||
const postId = linkNode.getAttribute('data-post-id');
|
const postId = listItemNode.getAttribute('data-post-id');
|
||||||
const post = this._postIdToPost[postId];
|
const post = this._postIdToPost[postId];
|
||||||
this._postIdToLinkNode[postId] = linkNode;
|
this._postIdToListItemNode[postId] = listItemNode;
|
||||||
linkNode.addEventListener(
|
|
||||||
|
const tagFlipperNode = this._getTagFlipperNode(listItemNode);
|
||||||
|
if (tagFlipperNode) {
|
||||||
|
tagFlipperNode.addEventListener(
|
||||||
'click', e => this._evtBulkEditTagsClick(e, post));
|
'click', e => this._evtBulkEditTagsClick(e, post));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._syncTagFlippersHighlights();
|
const safetyFlipperNode = this._getSafetyFlipperNode(listItemNode);
|
||||||
|
if (safetyFlipperNode) {
|
||||||
|
for (let linkNode of safetyFlipperNode.querySelectorAll('a')) {
|
||||||
|
linkNode.addEventListener(
|
||||||
|
'click', e => this._evtBulkEditSafetyClick(e, post));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get _tagFlipperNodes() {
|
this._syncBulkEditorsHighlights();
|
||||||
return this._hostNode.querySelectorAll('.tag-flipper');
|
}
|
||||||
|
|
||||||
|
get _listItemNodes() {
|
||||||
|
return this._hostNode.querySelectorAll('li');
|
||||||
|
}
|
||||||
|
|
||||||
|
_getTagFlipperNode(listItemNode) {
|
||||||
|
return listItemNode.querySelector('.tag-flipper');
|
||||||
|
}
|
||||||
|
|
||||||
|
_getSafetyFlipperNode(listItemNode) {
|
||||||
|
return listItemNode.querySelector('.safety-flipper');
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtPostChange(e) {
|
_evtPostChange(e) {
|
||||||
const linkNode = this._postIdToLinkNode[e.detail.post.id];
|
const listItemNode = this._postIdToListItemNode[e.detail.post.id];
|
||||||
linkNode.removeAttribute('data-disabled');
|
for (let node of listItemNode.querySelectorAll('[data-disabled]')) {
|
||||||
this._syncTagFlippersHighlights();
|
node.removeAttribute('data-disabled');
|
||||||
|
}
|
||||||
|
this._syncBulkEditorsHighlights();
|
||||||
}
|
}
|
||||||
|
|
||||||
_evtBulkEditTagsClick(e, post) {
|
_evtBulkEditTagsClick(e, post) {
|
||||||
|
@ -53,15 +75,43 @@ class PostsPageView extends events.EventTarget {
|
||||||
{detail: {post: post}}));
|
{detail: {post: post}}));
|
||||||
}
|
}
|
||||||
|
|
||||||
_syncTagFlippersHighlights() {
|
_evtBulkEditSafetyClick(e, post) {
|
||||||
for (let linkNode of this._tagFlipperNodes) {
|
e.preventDefault();
|
||||||
const postId = linkNode.getAttribute('data-post-id');
|
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];
|
const post = this._postIdToPost[postId];
|
||||||
|
|
||||||
|
const tagFlipperNode = this._getTagFlipperNode(listItemNode);
|
||||||
|
if (tagFlipperNode) {
|
||||||
let tagged = true;
|
let tagged = true;
|
||||||
for (let tag of this._ctx.bulkEdit.tags) {
|
for (let tag of this._ctx.bulkEdit.tags) {
|
||||||
tagged = tagged & post.isTaggedWith(tag);
|
tagged = tagged & post.isTaggedWith(tag);
|
||||||
}
|
}
|
||||||
linkNode.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,7 @@ privileges:
|
||||||
'posts:merge': moderator
|
'posts:merge': moderator
|
||||||
'posts:favorite': regular
|
'posts:favorite': regular
|
||||||
'posts:bulk-edit:tags': power
|
'posts:bulk-edit:tags': power
|
||||||
|
'posts:bulk-edit:safety': power
|
||||||
|
|
||||||
'tags:create': regular
|
'tags:create': regular
|
||||||
'tags:edit:names': power
|
'tags:edit:names': power
|
||||||
|
|
Loading…
Reference in a new issue