diff --git a/client/css/post-list-view.styl b/client/css/post-list-view.styl
index b817c29..ed57fe9 100644
--- a/client/css/post-list-view.styl
+++ b/client/css/post-list-view.styl
@@ -54,33 +54,35 @@
.icon:not(:first-of-type)
margin-left: 1em
- .tag-flipper
+ .edit-overlay
position: absolute
top: 0.5em
left: 0.5em
- display: inline-block
- padding: 0.5em
- box-sizing: border-box
- border: 0
- &:after
+
+ .tag-flipper
display: inline-block
- width: 1em
- height: 1em
- text-align: center
- line-height: 1em
- font-size: 20pt
- &.tagged
- background: rgba(0, 230, 0, 0.7)
+ padding: 0.5em
+ box-sizing: border-box
+ border: 0
&:after
- color: white
- content: '-'
- &:not(.tagged)
- background: rgba(255, 0, 0, 0.7)
- &:after
- color: white
- content: '+'
- &[data-disabled]
- background: rgba(200, 200, 200, 0.7)
+ display: inline-block
+ width: 1em
+ height: 1em
+ text-align: center
+ line-height: 1em
+ font-size: 20pt
+ &.tagged
+ background: rgba(0, 230, 0, 0.7)
+ &:after
+ color: white
+ content: '-'
+ &:not(.tagged)
+ background: rgba(255, 0, 0, 0.7)
+ &:after
+ color: white
+ content: '+'
+ &[data-disabled]
+ background: rgba(200, 200, 200, 0.7)
.thumbnail
background-position: 50% 30%
@@ -121,14 +123,14 @@
font-size: 0.95em
color: $inactive-link-color
.bulk-edit-tags
- &:not(.active)
+ &:not(.opened)
[type=text],
- .start-tagging,
- .stop-tagging
+ .start,
+ .close
display: none
.hint
display: none
- &.active
+ &.opened
.open
display: none
input[name=tag]
diff --git a/client/html/posts_header.tpl b/client/html/posts_header.tpl
index f90de34..b85b784 100644
--- a/client/html/posts_header.tpl
+++ b/client/html/posts_header.tpl
@@ -1,5 +1,5 @@
diff --git a/client/html/posts_page.tpl b/client/html/posts_page.tpl
index 1f0e664..a6c6cc5 100644
--- a/client/html/posts_page.tpl
+++ b/client/html/posts_page.tpl
@@ -33,10 +33,12 @@
<% } %>
- <% if (ctx.canBulkEditTags && ctx.parameters && ctx.parameters.tag) { %>
-
-
- <% } %>
+
+ <% if (ctx.canBulkEditTags && ctx.parameters && ctx.parameters.tag) { %>
+
+
+ <% } %>
+
<% } %>
<%= ctx.makeFlexboxAlign() %>
diff --git a/client/js/views/posts_header_view.js b/client/js/views/posts_header_view.js
index 0392ffd..0bc1dce 100644
--- a/client/js/views/posts_header_view.js
+++ b/client/js/views/posts_header_view.js
@@ -11,6 +11,74 @@ const TagAutoCompleteControl =
const template = views.getTemplate('posts-header');
+class BulkTagEditor 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');
+ }
+
+ get _openLinkNode() {
+ return this._hostNode.querySelector('.open');
+ }
+
+ get _closeLinkNode() {
+ return this._hostNode.querySelector('.close');
+ }
+
+ get _inputNode() {
+ return this._hostNode.querySelector('input[name=tag]');
+ }
+
+ focus() {
+ this._inputNode.focus();
+ }
+
+ blur() {
+ this._autoCompleteControl.hide();
+ this._inputNode.blur();
+ }
+
+ toggleOpen(state) {
+ this._hostNode.classList.toggle('opened', state);
+ }
+
+ _evtFormSubmit(e) {
+ e.preventDefault();
+ this.dispatchEvent(new CustomEvent('submit', {detail: {}}));
+ }
+
+ _evtOpenLinkClick(e) {
+ e.preventDefault();
+ this.toggleOpen(true);
+ this.focus();
+ this.dispatchEvent(new CustomEvent('open', {detail: {}}));
+ }
+
+ _evtCloseLinkClick(e) {
+ e.preventDefault();
+ this._inputNode.value = '';
+ this.toggleOpen(false);
+ this.blur();
+ this.dispatchEvent(new CustomEvent('close', {detail: {}}));
+ }
+}
+
class PostsHeaderView extends events.EventTarget {
constructor(ctx) {
super();
@@ -34,26 +102,20 @@ class PostsHeaderView extends events.EventTarget {
this._formNode.addEventListener(
'submit', e => this._evtFormSubmit(e));
- if (this._bulkEditTagsInputNode) {
- this._bulkEditTagsAutoCompleteControl = new TagAutoCompleteControl(
- this._bulkEditTagsInputNode, {addSpace: false});
- if (this._openBulkEditTagsLinkNode) {
- this._openBulkEditTagsLinkNode.addEventListener(
- 'click', e => this._evtBulkEditTagsClick(e));
- }
- this._stopBulkEditTagsLinkNode.addEventListener(
- 'click', e => this._evtStopTaggingClick(e));
- this._toggleBulkEditTagsVisibility(!!ctx.parameters.tag);
+ if (this._bulkEditTagsNode) {
+ this._bulkTagEditor = new BulkTagEditor(this._bulkEditTagsNode);
+ this._bulkTagEditor.toggleOpen(!!ctx.parameters.tag);
+ this._bulkTagEditor.addEventListener('submit', e => {
+ this._navigate();
+ });
+ this._bulkTagEditor.addEventListener('close', e => {
+ this._navigate();
+ });
}
}
- _toggleBulkEditTagsVisibility(state) {
- this._formNode.querySelector('.bulk-edit-tags')
- .classList.toggle('active', state);
- }
-
get _formNode() {
- return this._hostNode.querySelector('form');
+ return this._hostNode.querySelector('form.search');
}
get _safetyButtonNodes() {
@@ -64,34 +126,8 @@ class PostsHeaderView extends events.EventTarget {
return this._hostNode.querySelector('form [name=search-text]');
}
- get _bulkEditTagsInputNode() {
- return this._hostNode.querySelector('form .bulk-edit-tags [name=tag]');
- }
-
- get _openBulkEditTagsLinkNode() {
- return this._hostNode.querySelector('form .bulk-edit-tags .open');
- }
-
- get _stopBulkEditTagsLinkNode() {
- return this._hostNode.querySelector(
- 'form .bulk-edit-tags .stop-tagging');
- }
-
- _evtBulkEditTagsClick(e) {
- e.preventDefault();
- this._toggleBulkEditTagsVisibility(true);
- }
-
- _evtStopTaggingClick(e) {
- e.preventDefault();
- this._bulkEditTagsInputNode.value = '';
- this._toggleBulkEditTagsVisibility(false);
- this.dispatchEvent(new CustomEvent('navigate', {detail: {parameters: {
- query: this._ctx.parameters.query,
- offset: this._ctx.parameters.offset,
- limit: this._ctx.parameters.limit,
- tag: null,
- }}}));
+ get _bulkEditTagsNode() {
+ return this._hostNode.querySelector('.bulk-edit-tags');
}
_evtSafetyButtonClick(e, url) {
@@ -114,16 +150,17 @@ class PostsHeaderView extends events.EventTarget {
_evtFormSubmit(e) {
e.preventDefault();
+ this._navigate();
+ }
+
+ _navigate() {
this._queryAutoCompleteControl.hide();
- if (this._bulkEditTagsAutoCompleteControl) {
- this._bulkEditTagsAutoCompleteControl.hide();
- }
let parameters = {query: this._queryInputNode.value};
parameters.offset = parameters.query === this._ctx.parameters.query ?
this._ctx.parameters.offset : 0;
- if (this._bulkEditTagsInputNode) {
- parameters.tag = this._bulkEditTagsInputNode.value;
- this._bulkEditTagsInputNode.blur();
+ if (this._bulkTagEditor && this._bulkTagEditor.opened) {
+ parameters.tag = this._bulkTagEditor.value;
+ this._bulkTagEditor.blur();
} else {
parameters.tag = null;
}
diff --git a/client/js/views/posts_page_view.js b/client/js/views/posts_page_view.js
index b5ad5df..c2dbe90 100644
--- a/client/js/views/posts_page_view.js
+++ b/client/js/views/posts_page_view.js
@@ -27,7 +27,7 @@ class PostsPageView extends events.EventTarget {
'click', e => this._evtBulkEditTagsClick(e, post));
}
- this._syncBulkEditTagsHighlights();
+ this._syncTagFlippersHighlights();
}
get _tagFlipperNodes() {
@@ -37,19 +37,7 @@ class PostsPageView extends events.EventTarget {
_evtPostChange(e) {
const linkNode = this._postIdToLinkNode[e.detail.post.id];
linkNode.removeAttribute('data-disabled');
- this._syncBulkEditTagsHighlights();
- }
-
- _syncBulkEditTagsHighlights() {
- for (let linkNode of this._tagFlipperNodes) {
- const postId = linkNode.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);
- }
- linkNode.classList.toggle('tagged', tagged);
- }
+ this._syncTagFlippersHighlights();
}
_evtBulkEditTagsClick(e, post) {
@@ -64,6 +52,18 @@ class PostsPageView extends events.EventTarget {
linkNode.classList.contains('tagged') ? 'untag' : 'tag',
{detail: {post: post}}));
}
+
+ _syncTagFlippersHighlights() {
+ for (let linkNode of this._tagFlipperNodes) {
+ const postId = linkNode.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);
+ }
+ linkNode.classList.toggle('tagged', tagged);
+ }
+ }
}
module.exports = PostsPageView;