Implemented mass tag
This commit is contained in:
parent
f2b5124d54
commit
74e6e008dc
11 changed files with 142 additions and 16 deletions
1
TODO
1
TODO
|
@ -24,7 +24,6 @@ everything related to users:
|
|||
everything related to tags:
|
||||
- tags.json refresh when editing post
|
||||
- basic tags
|
||||
- mass tag
|
||||
- merging
|
||||
- tag editing
|
||||
- name
|
||||
|
|
|
@ -56,6 +56,7 @@ changePostRelations = regularUser, powerUser, moderator, administrator
|
|||
changePostFlags = regularUser, powerUser, moderator, administrator
|
||||
|
||||
listTags = anonymous, regularUser, powerUser, moderator, administrator
|
||||
massTag = powerUser, moderator, administrator
|
||||
|
||||
listComments = anonymous, regularUser, powerUser, moderator, administrator
|
||||
addComments = regularUser, powerUser, moderator, administrator
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.post-small {
|
||||
position: relative;
|
||||
}
|
||||
.post-small a {
|
||||
display: inline-block;
|
||||
margin: 0.4em;
|
||||
|
@ -112,3 +115,42 @@
|
|||
.post-small.post-type-flash a:after {
|
||||
content: 'flash';
|
||||
}
|
||||
|
||||
.post-small .action {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.post-small .action button {
|
||||
padding: 0.5em 1em;
|
||||
height: 1em;
|
||||
line-height: 1em;
|
||||
display: block;
|
||||
margin: -1em auto 0 auto;
|
||||
box-sizing: content-box;
|
||||
opacity: .7;
|
||||
}
|
||||
|
||||
.tagged .action button,
|
||||
.untagged .action button {
|
||||
border: 1px solid black;
|
||||
font-weight: bold;
|
||||
box-shadow: none;
|
||||
}
|
||||
.untagged .action button {
|
||||
background: red;
|
||||
color: white;
|
||||
}
|
||||
.tagged .action button {
|
||||
background: lime;
|
||||
color: black;
|
||||
}
|
||||
.untagged .post-small img,
|
||||
.tagged .post-small img {
|
||||
opacity: .85;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ App.Auth = function(_, jQuery, util, api, appState, promise) {
|
|||
deleteAllComments: 'deleteAllComments',
|
||||
|
||||
listTags: 'listTags',
|
||||
massTag: 'massTag',
|
||||
|
||||
viewHistory: 'viewHistory',
|
||||
};
|
||||
|
|
|
@ -57,7 +57,7 @@ App.Pager = function(
|
|||
|
||||
function retrieve() {
|
||||
return promise.make(function(resolve, reject) {
|
||||
promise.wait(api.get(url, _.extend({page: pageNumber}, searchParams)))
|
||||
promise.wait(api.get(url, _.extend({}, searchParams, {page: pageNumber})))
|
||||
.then(function(response) {
|
||||
var pageSize = response.json.pageSize;
|
||||
var totalRecords = response.json.totalRecords;
|
||||
|
|
|
@ -7,6 +7,7 @@ App.Presenters.PostListPresenter = function(
|
|||
util,
|
||||
promise,
|
||||
auth,
|
||||
api,
|
||||
keyboard,
|
||||
pagerPresenter,
|
||||
topNavigationPresenter) {
|
||||
|
@ -16,6 +17,7 @@ App.Presenters.PostListPresenter = function(
|
|||
var templates = {};
|
||||
var $el = jQuery('#content');
|
||||
var $searchInput;
|
||||
var privileges = {};
|
||||
|
||||
var params;
|
||||
|
||||
|
@ -25,6 +27,8 @@ App.Presenters.PostListPresenter = function(
|
|||
params = _params;
|
||||
params.query = params.query || {};
|
||||
|
||||
privileges.canMassTag = auth.hasPrivilege(auth.privileges.massTag);
|
||||
|
||||
promise.wait(
|
||||
util.promiseTemplate('post-list'),
|
||||
util.promiseTemplate('post-list-item'))
|
||||
|
@ -52,6 +56,7 @@ App.Presenters.PostListPresenter = function(
|
|||
function reinit(params, loaded) {
|
||||
pagerPresenter.reinit({query: params.query});
|
||||
loaded();
|
||||
softRender();
|
||||
}
|
||||
|
||||
function deinit() {
|
||||
|
@ -59,13 +64,14 @@ App.Presenters.PostListPresenter = function(
|
|||
}
|
||||
|
||||
function render() {
|
||||
$el.html(templates.list());
|
||||
$el.html(templates.list({massTag: params.query.massTag, privileges: privileges}));
|
||||
$searchInput = $el.find('input[name=query]');
|
||||
App.Controls.AutoCompleteInput($searchInput);
|
||||
|
||||
$searchInput.val(params.query.query);
|
||||
$searchInput.keydown(searchInputKeyPressed);
|
||||
$el.find('form').submit(searchFormSubmitted);
|
||||
$el.find('[name=mass-tag]').click(massTagButtonClicked);
|
||||
|
||||
keyboard.keyup('p', function() {
|
||||
$el.find('.posts li a').eq(0).focus();
|
||||
|
@ -76,6 +82,19 @@ App.Presenters.PostListPresenter = function(
|
|||
});
|
||||
}
|
||||
|
||||
function softRender() {
|
||||
$searchInput.val(params.query.query);
|
||||
|
||||
var $massTagInfo = $el.find('.mass-tag-info');
|
||||
if (params.query.massTag) {
|
||||
$massTagInfo.show();
|
||||
$massTagInfo.find('span').text(params.query.massTag);
|
||||
} else {
|
||||
$massTagInfo.hide();
|
||||
}
|
||||
_.map($el.find('.posts .post-small'), function(postNode) { softRenderPost(jQuery(postNode).parents('li')); });
|
||||
}
|
||||
|
||||
function renderPosts(posts, clear) {
|
||||
var $target = $el.find('.posts');
|
||||
|
||||
|
@ -84,13 +103,59 @@ App.Presenters.PostListPresenter = function(
|
|||
}
|
||||
|
||||
_.each(posts, function(post) {
|
||||
var $post = renderPost(post);
|
||||
softRenderPost($post);
|
||||
$target.append($post);
|
||||
});
|
||||
}
|
||||
|
||||
function renderPost(post) {
|
||||
var $post = jQuery('<li>' + templates.listItem({
|
||||
util: util,
|
||||
query: params.query,
|
||||
post: post,
|
||||
}) + '</li>');
|
||||
$post.data('post', post);
|
||||
util.loadImagesNicely($post.find('img'));
|
||||
$target.append($post);
|
||||
return $post;
|
||||
}
|
||||
|
||||
function softRenderPost($post) {
|
||||
var classes = [];
|
||||
if (params.query.massTag) {
|
||||
var post = $post.data('post');
|
||||
if (_.contains(_.map(post.tags, function(tag) { return tag.name.toLowerCase(); }), params.query.massTag.toLowerCase())) {
|
||||
classes.push('tagged');
|
||||
} else {
|
||||
classes.push('untagged');
|
||||
}
|
||||
}
|
||||
$post.toggleClass('tagged', _.contains(classes, 'tagged'));
|
||||
$post.toggleClass('untagged', _.contains(classes, 'untagged'));
|
||||
$post.find('.action').toggle(_.any(classes));
|
||||
$post.find('.action button').text(_.contains(classes, 'tagged') ? 'Tagged' : 'Untagged').unbind('click').click(postTagButtonClicked);
|
||||
}
|
||||
|
||||
function postTagButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
var $post = jQuery(e.target).parents('li');
|
||||
var post = $post.data('post');
|
||||
var tags = _.pluck(post.tags, 'name');
|
||||
if (_.contains(_.map(tags, function(tag) { return tag.toLowerCase(); }), params.query.massTag.toLowerCase())) {
|
||||
tags = _.filter(tags, function(tag) { return tag.toLowerCase() !== params.query.massTag.toLowerCase(); });
|
||||
} else {
|
||||
tags.push(params.query.massTag);
|
||||
}
|
||||
var formData = {};
|
||||
formData.seenEditTime = post.lastEditTime;
|
||||
formData.tags = tags.join(' ');
|
||||
promise.wait(api.put('/posts/' + post.id, formData))
|
||||
.then(function(response) {
|
||||
post = response.json;
|
||||
$post.data('post', post);
|
||||
softRenderPost($post);
|
||||
}).fail(function(response) {
|
||||
console.log(response);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -101,6 +166,12 @@ App.Presenters.PostListPresenter = function(
|
|||
updateSearch();
|
||||
}
|
||||
|
||||
function massTagButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
params.query.massTag = window.prompt('Enter tag to tag with:');
|
||||
pagerPresenter.setQuery(params.query);
|
||||
}
|
||||
|
||||
function searchFormSubmitted(e) {
|
||||
e.preventDefault();
|
||||
updateSearch();
|
||||
|
@ -121,4 +192,4 @@ App.Presenters.PostListPresenter = function(
|
|||
|
||||
};
|
||||
|
||||
App.DI.register('postListPresenter', ['_', 'jQuery', 'util', 'promise', 'auth', 'keyboard', 'pagerPresenter', 'topNavigationPresenter'], App.Presenters.PostListPresenter);
|
||||
App.DI.register('postListPresenter', ['_', 'jQuery', 'util', 'promise', 'auth', 'api', 'keyboard', 'pagerPresenter', 'topNavigationPresenter'], App.Presenters.PostListPresenter);
|
||||
|
|
|
@ -32,4 +32,8 @@
|
|||
</div>
|
||||
<% } %>
|
||||
</a>
|
||||
|
||||
<div class="action">
|
||||
<button>Action</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
<div class="post-list">
|
||||
<form class="search">
|
||||
<input type="text" name="query" placeholder="Search query..."/>
|
||||
<button type="submit">Search</button>
|
||||
<button type="submit" name="search">Search</button>
|
||||
|
||||
<% if (privileges.canMassTag) { %>
|
||||
<button name="mass-tag">Mass tag</button>
|
||||
<% } %>
|
||||
</form>
|
||||
|
||||
<p class="mass-tag-info">Tagging with <span class="mass-tag"><%= massTag %></span></p>
|
||||
|
||||
<div class="pagination-target">
|
||||
<div class="wrapper">
|
||||
<ul class="posts">
|
||||
|
|
|
@ -22,6 +22,7 @@ class PostEditFormData implements IValidatable
|
|||
{
|
||||
$this->content = $inputReader->decodeBase64($inputReader->content);
|
||||
$this->thumbnail = $inputReader->decodebase64($inputReader->thumbnail);
|
||||
if ($inputReader->safety)
|
||||
$this->safety = EnumHelper::postSafetyFromString($inputReader->safety);
|
||||
$this->source = $inputReader->source;
|
||||
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
|
||||
|
|
|
@ -35,6 +35,7 @@ class Privilege
|
|||
const CHANGE_POST_FLAGS = 'changePostFlags';
|
||||
|
||||
const LIST_TAGS = 'listTags';
|
||||
const MASS_TAG = 'massTag';
|
||||
|
||||
const LIST_COMMENTS = 'listComments';
|
||||
const ADD_COMMENTS = 'addComments';
|
||||
|
|
|
@ -61,7 +61,7 @@ class TagService
|
|||
{
|
||||
$tagNameGetter = function($tag)
|
||||
{
|
||||
return $tag->getName();
|
||||
return strtolower($tag->getName());
|
||||
};
|
||||
|
||||
$tagNames = array_map($tagNameGetter, $tags);
|
||||
|
@ -86,10 +86,10 @@ class TagService
|
|||
$result = [];
|
||||
foreach ($tags as $key => $tag)
|
||||
{
|
||||
if (isset($tagsNotToCreate[$tag->getName()]))
|
||||
$tag = $tagsNotToCreate[$tag->getName()];
|
||||
if (isset($tagsNotToCreate[$tagNameGetter($tag)]))
|
||||
$tag = $tagsNotToCreate[$tagNameGetter($tag)];
|
||||
else
|
||||
$tag = $createdTags[$tag->getName()];
|
||||
$tag = $createdTags[$tagNameGetter($tag)];
|
||||
$result[$key] = $tag;
|
||||
}
|
||||
return $result;
|
||||
|
|
Loading…
Reference in a new issue