Issue #1193 : Improvement of tag's manager

* Hide Tag item when there are more than 5
 * Change data format in Ajax calls
 * Remove useless code in tag.php
 * Remove pwg_token in pwg.tags.add
 * Minor design fixes
This commit is contained in:
Zacharie
2020-06-18 11:16:14 +02:00
committed by plegall
parent a3ab495446
commit 5deba88a5c
6 changed files with 163 additions and 245 deletions

View File

@@ -27,193 +27,6 @@ $tabsheet->set_id('tags');
$tabsheet->select('');
$tabsheet->assign();
// +-----------------------------------------------------------------------+
// | dulicate tags |
// +-----------------------------------------------------------------------+
if (isset($_POST['duplic_submit']))
{
$query = '
SELECT name
FROM '.TAGS_TABLE.'
;';
$existing_names = array_from_query($query, 'name');
$current_name_of = array();
$query = '
SELECT id, name
FROM '.TAGS_TABLE.'
WHERE id IN ('.$_POST['edit_list'].')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$current_name_of[ $row['id'] ] = $row['name'];
}
$updates = array();
// we must not rename tag with an already existing name
foreach (explode(',', $_POST['edit_list']) as $tag_id)
{
$tag_name = stripslashes($_POST['tag_name-'.$tag_id]);
if ($tag_name != $current_name_of[$tag_id])
{
if (in_array($tag_name, $existing_names))
{
$page['errors'][] = l10n('Tag "%s" already exists', $tag_name);
}
else if (!empty($tag_name))
{
single_insert(
TAGS_TABLE,
array(
'name' => $tag_name,
'url_name' => trigger_change('render_tag_url', $tag_name),
)
);
$destination_tag_id = pwg_db_insert_id(TAGS_TABLE);
pwg_activity('tag', $destination_tag_id, 'add', array('action'=>'duplicate', 'source_tag'=>$tag_id));
$query = '
SELECT
image_id
FROM '.IMAGE_TAG_TABLE.'
WHERE tag_id = '.$tag_id.'
;';
$destination_tag_image_ids = array_from_query($query, 'image_id');
$inserts = array();
foreach ($destination_tag_image_ids as $image_id)
{
$inserts[] = array(
'tag_id' => $destination_tag_id,
'image_id' => $image_id
);
}
if (count($inserts) > 0)
{
mass_inserts(
IMAGE_TAG_TABLE,
array_keys($inserts[0]),
$inserts
);
}
$page['infos'][] = l10n(
'Tag "%s" is now a duplicate of "%s"',
stripslashes($tag_name),
$current_name_of[$tag_id]
);
}
}
}
mass_updates(
TAGS_TABLE,
array(
'primary' => array('id'),
'update' => array('name', 'url_name'),
),
$updates
);
}
// +-----------------------------------------------------------------------+
// | merge tags |
// +-----------------------------------------------------------------------+
if (isset($_POST['merge_submit']))
{
if (!isset($_POST['destination_tag']))
{
$page['errors'][] = l10n('No destination tag selected');
}
else
{
$destination_tag_id = $_POST['destination_tag'];
$tag_ids = explode(',', $_POST['merge_list']);
if (is_array($tag_ids) and count($tag_ids) > 1)
{
$name_of_tag = array();
$query = '
SELECT
id,
name
FROM '.TAGS_TABLE.'
WHERE id IN ('.implode(',', $tag_ids).')
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$name_of_tag[ $row['id'] ] = trigger_change('render_tag_name', $row['name'], $row);
}
$tag_ids_to_delete = array_diff(
$tag_ids,
array($destination_tag_id)
);
$query = '
SELECT
DISTINCT(image_id)
FROM '.IMAGE_TAG_TABLE.'
WHERE tag_id IN ('.implode(',', $tag_ids_to_delete).')
;';
$image_ids = array_from_query($query, 'image_id');
delete_tags($tag_ids_to_delete);
$query = '
SELECT
image_id
FROM '.IMAGE_TAG_TABLE.'
WHERE tag_id = '.$destination_tag_id.'
;';
$destination_tag_image_ids = array_from_query($query, 'image_id');
$image_ids_to_link = array_diff(
$image_ids,
$destination_tag_image_ids
);
$inserts = array();
foreach ($image_ids_to_link as $image_id)
{
$inserts[] = array(
'tag_id' => $destination_tag_id,
'image_id' => $image_id
);
}
if (count($inserts) > 0)
{
mass_inserts(
IMAGE_TAG_TABLE,
array_keys($inserts[0]),
$inserts
);
}
$tags_deleted = array();
foreach ($tag_ids_to_delete as $tag_id)
{
$tags_deleted[] = $name_of_tag[$tag_id];
}
$page['infos'][] = l10n(
'Tags <em>%s</em> merged into tag <em>%s</em>',
implode(', ', $tags_deleted),
$name_of_tag[$destination_tag_id]
);
}
}
}
// +-----------------------------------------------------------------------+
// | delete orphan tags |
// +-----------------------------------------------------------------------+

View File

@@ -78,7 +78,9 @@ function addTag(name) {
jQuery.ajax({
url: "ws.php?format=json&method=pwg.tags.add",
type: "POST",
data: "name=" + name + "&pwg_token=" + pwg_token,
data: {
name: name
},
success: function (raw_data) {
data = jQuery.parseJSON(raw_data);
if (data.stat === "ok") {
@@ -108,7 +110,6 @@ function createTagBox(id, name) {
if ($("#toggleSelectionMode").is(":checked")) {
newTag.addClass('selection');
newTag.find(".in-selection-mode").show();
newTag.find(".not-in-selection-mode").hide();
}
return newTag;
}
@@ -158,6 +159,7 @@ function setupTagbox(tagBox) {
tagBox.find('.tag-rename .icon-cancel').on('click', function() {
tagBox.removeClass('edit-name');
tagBox.find('.tag-name-editable').val(name);
})
tagBox.find('.tag-rename .validate').on('click', function() {
@@ -219,7 +221,10 @@ function removeTag(id, name) {
return jQuery.ajax({
url: "ws.php?format=json&method=pwg.tags.delete",
type: "POST",
data: "tag_id=" + id + "&pwg_token=" + pwg_token,
data: {
tag_id: id,
pwg_token: pwg_token
},
success: function (raw_data) {
data = jQuery.parseJSON(raw_data);
showMessage(str_tag_deleted.replace('%s', name));
@@ -238,12 +243,16 @@ function renameTag(id, new_name) {
jQuery.ajax({
url: "ws.php?format=json&method=pwg.tags.rename",
type: "POST",
data: "tag_id=" + id + "&new_name=" + new_name + "&pwg_token=" + pwg_token,
data: {
tag_id: id,
new_name: new_name,
pwg_token: pwg_token
},
success: function (raw_data) {
data = jQuery.parseJSON(raw_data);
if (data.stat === "ok") {
$('.tag-box[data-id='+id+'] p').html(data.result.name);
$('.tag-box[data-id='+id+'] .tag-name-editable').attr('placeholder', data.result.name);
$('.tag-box[data-id='+id+'] .tag-name-editable').attr('value', data.result.name);
resolve(data);
} else {
reject(str_already_exist.replace('%s', new_name))
@@ -278,7 +287,11 @@ function duplicateTag(id, name) {
jQuery.ajax({
url: "ws.php?format=json&method=pwg.tags.duplicate",
type: "POST",
data: "tag_id=" + id + "&copy_name=" + copy_name + "&pwg_token=" + pwg_token,
data: {
tag_id : id,
copy_name: copy_name,
pwg_token: pwg_token
},
success: function (raw_data) {
data = jQuery.parseJSON(raw_data);
if (data.stat === "ok") {
@@ -302,21 +315,27 @@ function duplicateTag(id, name) {
/*-------
Selection mode
-------*/
numberItemDisplayed = 5;
$("#toggleSelectionMode").attr("checked", false)
$("#toggleSelectionMode").click(function () {
if ($(this).is(":checked")) {
selectionMode($(this).is(":checked"))
});
function selectionMode(isSelection) {
if (isSelection) {
$(".in-selection-mode").show();
$(".not-in-selection-mode").removeAttr('style');
$(".not-in-selection-mode").hide();
$(".tag-box").addClass("selection");
$(".tag-box").removeClass('edit-name');
} else {
$(".in-selection-mode").removeAttr('style');
$(".not-in-selection-mode").show();
$(".not-in-selection-mode").removeAttr('style');
$(".tag-box").removeClass("selection");
$(".tag-box").attr("data-selected", '0');
updateListItem();
}
});
}
function updateListItem() {
@@ -362,6 +381,15 @@ function updateListItem() {
)
})
if (selected.length > 5) {
$('.selection-other-tags').show();
$('.selection-other-tags').html(str_and_others_tags.replace('%s', selected.length - 5))
} else {
$('.selection-other-tags').hide();
}
updateSelectionContent()
}
@@ -402,6 +430,27 @@ $('#CancelMerge').on('click', function() {
updateSelectionContent()
});
$('#selectAll').on('click', function() {
$('.tag-box').attr('data-selected', '1');
updateListItem();
});
$('#selectNone').on('click', function() {
$('.tag-box').attr('data-selected', '0');
updateListItem();
});
$('#selectInvert').on('click', function() {
$('.tag-box').each(function() {
if ($(this).attr('data-selected') == 1) {
$(this).attr('data-selected', '0');
} else {
$(this).attr('data-selected', '1');
}
});
updateListItem();
});
/*-------
Actions in selection mode
-------*/
@@ -415,7 +464,7 @@ $('#DeleteSelectionMode').on('click', function() {
})
$.confirm({
title: str_delete_tags.replace("%s",names.join(', ')),
title: str_delete_tags.replace("%s",tagListToString(names)),
buttons: {
confirm: {
text: str_yes_delete_confirmation,
@@ -433,7 +482,6 @@ $('#DeleteSelectionMode').on('click', function() {
})
function removeSelectedTags() {
str_id = "";
names = [];
ids = [];
@@ -441,18 +489,18 @@ function removeSelectedTags() {
id = $(this).data('id');
ids.push(id);
names.push($(this).find('.tag-name').html());
str_id += "tag_id[]=" + id + "&";
})
console.log(names);
$.alert({
title : str_tags_deleted.replace("%s",names.join(', ')),
title : str_tags_deleted.replace("%s",tagListToString(names)),
content: function() {
return jQuery.ajax({
url: "ws.php?format=json&method=pwg.tags.delete",
type: "POST",
data: str_id + "pwg_token=" + pwg_token,
data: {
tag_id: ids,
pwg_token: pwg_token
},
success: function (raw_data) {
data = jQuery.parseJSON(raw_data);
if (data.stat === "ok") {
@@ -460,7 +508,6 @@ function removeSelectedTags() {
$('.tag-box[data-id='+id+']').remove();
})
updateListItem();
showMessage(str_tags_deleted.replace('%s', names.join(', ')));
}
}
})
@@ -489,7 +536,7 @@ function mergeGroups(destination_id, merge_ids) {
})
str_message = str_merged_into
.replace('%s1', merge_name.join(', '))
.replace('%s1', tagListToString(merge_name))
.replace('%s2', destination_name)
$.alert({
@@ -498,13 +545,14 @@ function mergeGroups(destination_id, merge_ids) {
return jQuery.ajax({
url: "ws.php?format=json&method=pwg.tags.merge",
type: "POST",
data: "destination_tag_id=" + destination_id
+ "&merge_tag_id[]=" + merge_ids.join('&merge_tag_id[]=')
+ "&pwg_token=" + pwg_token,
data: {
destination_tag_id: destination_id,
merge_tag_id: merge_ids,
pwg_token: pwg_token
},
success: function (raw_data) {
data = jQuery.parseJSON(raw_data);
if (data.stat === "ok") {
console.log()
data.result.deleted_tag.forEach((id) => {
if (data.result.destination_tag != id)
$('.tag-box[data-id='+id+']').remove();
@@ -513,7 +561,6 @@ function mergeGroups(destination_id, merge_ids) {
tagBox = $('.tag-box[data-id='+data.result.destination_tag+']')
tagBox.find('.tag-dropdown-action.view, .tag-dropdown-action.manage').show();
}
showMessage(str_message);
$(".tag-box").attr("data-selected", '0');
updateListItem();
}
@@ -524,6 +571,16 @@ function mergeGroups(destination_id, merge_ids) {
});
}
function tagListToString(list) {
if (list.length > 5) {
return list.slice(0,5).join(', ')
+ ' '
+ str_and_others_tags.replace('%s', list.length - 5);
} else {
return list.join(', ');
}
}
/*-------
Filter research
-------*/
@@ -533,22 +590,22 @@ $("#search-tag .search-input").on("input", function() {
var searchNumber = 0;
$('.tag-box').each(function () {
if (text == "") {
$(this).fadeIn()
$(this).show()
searchNumber++;
} else {
let name = $(this).find("p").text().toLowerCase();
if (name.search(text) != -1){
$(this).delay(300).fadeIn()
$(this).delay(300).show()
searchNumber++;
} else {
$(this).fadeOut()
$(this).hide()
}
}
})
if (searchNumber == 0) {
$('.emptyResearch').delay(300).fadeIn();
$('.emptyResearch').show();
} else {
$('.emptyResearch').fadeOut();
$('.emptyResearch').hide();
}
})

View File

@@ -1,21 +1,22 @@
{footer_script}
var pwg_token = "{$PWG_TOKEN}";
var str_delete = '{'Delete tag "%s"?'|@translate}'
var str_delete_tags = '{'Delete tags \{%s\}?'|@translate}'
var str_yes_delete_confirmation = "{'Yes, delete'|@translate}"
var str_no_delete_confirmation = "{"No, I have changed my mind"|@translate}"
var str_tag_deleted = '{'Tag "%s" succesfully deleted'|@translate}'
var str_tags_deleted = '{'Tags \{%s\} succesfully deleted'|@translate}'
var str_already_exist = '{'Tag "%s" already exists'|@translate}'
var str_tag_created = '{'Tag "%s" created'|@translate}'
var str_tag_renamed = '{'Tag "%s1" renamed in "%s2"'|@translate}'
var str_delete_orphan_tags = '{'Delete orphan tags ?'|@translate}'
var str_delete = '{'Delete tag "%s"?'|@translate}';
var str_delete_tags = '{'Delete tags \{%s\}?'|@translate}';
var str_yes_delete_confirmation = "{'Yes, delete'|@translate}";
var str_no_delete_confirmation = "{"No, I have changed my mind"|@translate}";
var str_tag_deleted = '{'Tag "%s" succesfully deleted'|@translate}';
var str_tags_deleted = '{'Tags \{%s\} succesfully deleted'|@translate}';
var str_already_exist = '{'Tag "%s" already exists'|@translate}';
var str_tag_created = '{'Tag "%s" created'|@translate}';
var str_tag_renamed = '{'Tag "%s1" renamed in "%s2"'|@translate}';
var str_delete_orphan_tags = '{'Delete orphan tags ?'|@translate}';
var str_orphan_tags = '{'You have %s1 orphan : %s2'|@translate}';
var str_delete_them = '{'Delete them'|@translate}';
var str_keep_them = '{'Keep them'|@translate}';
var str_copy = '{' (copy)'|@translate}'
var str_other_copy = '{' (copy %s)'|@translate}'
var str_merged_into = '{'Tag(s) \{%s1\} succesfully merged into "%s2"'|@translate}'
var str_copy = '{' (copy)'|@translate}';
var str_other_copy = '{' (copy %s)'|@translate}';
var str_merged_into = '{'Tag(s) \{%s1\} succesfully merged into "%s2"'|@translate}';
var str_and_others_tags = '{'and %s others'|@translate}';
{/footer_script}
{combine_script id='common' load='footer' path='admin/themes/default/js/common.js'}
@@ -28,7 +29,7 @@ var str_merged_into = '{'Tag(s) \{%s1\} succesfully merged into "%s2"'|@translat
{function name=tagContent}
{function tagContent}
<p class='tag-name'>{$tag_name}</p>
<a class="icon-ellipsis-vert showOptions not-in-selection-mode"></a>
<a class="icon-ellipsis-vert showOptions"></a>
<div class="tag-dropdown-block">
<a class='tag-dropdown-action icon-eye view' href="{$tag_U_VIEW}" {if !$has_image} style='display:none' {/if}>{'View in gallery'|@translate}</a>
<a class='tag-dropdown-action icon-picture manage' href="{$tag_U_EDIT}" {if !$has_image} style='display:none' {/if}>{'Manage photos'|@translate}</a>
@@ -41,7 +42,7 @@ var str_merged_into = '{'Tag(s) \{%s1\} succesfully merged into "%s2"'|@translat
</span>
<div class="tag-rename">
<form>
<input type="text" class="tag-name-editable" placeholder="{$tag_name}">
<input type="text" class="tag-name-editable" value="{$tag_name}">
<input type="submit" hidden>
</form>
<span class="icon-ok validate"></span>
@@ -72,6 +73,7 @@ var str_merged_into = '{'Tag(s) \{%s1\} succesfully merged into "%s2"'|@translat
<div class="tag-list">
</div>
<div class="selection-other-tags"></div>
<button id="MergeSelectionMode" class="icon-object-group unavailable">{'Merge'|@translate}</button>
<button id="DeleteSelectionMode" class="icon-trash-1">{'Delete selected tags'|@translate}</button>
</div>
@@ -95,7 +97,7 @@ var str_merged_into = '{'Tag(s) \{%s1\} succesfully merged into "%s2"'|@translat
<span class='icon-filter'> </span>
<input class='search-input' type='text' placeholder='{'Search'|@translate}'>
</div>
<form id='add-tag'>
<form id='add-tag' class='not-in-selection-mode'>
<span class='icon-cancel'></span>
<span class='icon-plus-circled icon-validate'></span>
<label class='add-tag-container'>
@@ -104,6 +106,12 @@ var str_merged_into = '{'Tag(s) \{%s1\} succesfully merged into "%s2"'|@translat
<input type='submit' hidden>
</label>
</form>
<div class='selection-controller in-selection-mode'>
<p>{'Select:'|@translate}</p>
<a id="selectAll" class="icon-star">{'All'|@translate}</a>
<a id="selectNone" class="icon-star-empty">{'None'|@translate}</a>
<a id="selectInvert" class="icon-exchange">{'Invert'|@translate}</a>
</div>
{if $warning_tags != ""}
<div class='tag-warning tag-info icon-attention'><p> {$warning_tags} </p></div>
{/if}

View File

@@ -3244,6 +3244,7 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
background-color: #fafafa;
padding-left: 30px;
width: 300px;
margin: 4px;
}
.tag-header #search-tag span {
@@ -3348,6 +3349,32 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
opacity: 1;
}
.tag-header .selection-controller {
display: none;
margin: 0px 7px;
}
.tag-header .selection-controller p {
position: absolute;
transform: translateY(-40px);
}
.tag-header .selection-controller a {
margin: 0;
background-color: #fafafa;
padding: 10px;
box-shadow: 0px 2px #00000024;
color: #777;
font-weight: bold;
}
.tag-header .selection-controller a:hover {
background-color: #f0f0f0;
color: #3A3A3A;
text-decoration: none;
}
.tag-info {
height: 35px;
overflow: hidden;
@@ -3360,6 +3387,10 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
.tag-info p {
margin: auto;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
max-width: 300px;
text-align: initial;
}
.tag-info::before {
@@ -3431,10 +3462,19 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
display: none;
}
.tag-container .tag-box .showOptions {
color: #777;
}
.tag-container .tag-box.edit-name .showOptions {
display: none;
}
.tag-container .tag-box.selection .showOptions {
display: none;
}
.tag-container .tag-box .tag-dropdown-block {
display:none;
position:absolute;
@@ -3453,6 +3493,7 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
text-align: initial;
padding: 5px 10px;
font-size: 13px;
padding-right: 15px;
}
.tag-container .tag-box .tag-dropdown-block .tag-dropdown-action:hover {
@@ -3502,7 +3543,6 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
}
}
.tag-container .tag-box .tag-rename {
display: none;
}
@@ -3548,6 +3588,8 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
text-align: start;
font-weight: 700;
font-size: 15px;
overflow: hidden;
max-height: 160px;
}
.selection-mode-tag .tag-list p {
@@ -3563,4 +3605,9 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
display: flex;
margin: 10px;
text-align: start;
}
.selection-mode-tag .selection-other-tags {
color: #ffa646;
font-weight: bold;
}

View File

@@ -220,11 +220,6 @@ function ws_tags_add($params, &$service)
{
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
if (get_pwg_token() != $params['pwg_token'])
{
return new PwgError(403, 'Invalid security token');
}
$creation_output = create_tag($params['name']);
if (isset($creation_output['error']))
@@ -264,9 +259,6 @@ SELECT COUNT(*)
{
delete_tags($params['tag_id']);
return array('id' => $tag_ids);
foreach ($tag_ids as $ids) {
pwg_activity('tag', $creation_output['id'], 'delete');
}
} else {
return array('id' => array());
}
@@ -334,7 +326,8 @@ SELECT name
}
function ws_tags_duplicate($params, &$service) {
function ws_tags_duplicate($params, &$service)
{
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
@@ -415,7 +408,8 @@ SELECT image_id
);
}
function ws_tags_merge($params, &$service) {
function ws_tags_merge($params, &$service)
{
if (get_pwg_token() != $params['pwg_token'])
{

3
ws.php
View File

@@ -641,8 +641,7 @@ function ws_addDefaultMethods( $arr )
'pwg.tags.add',
'ws_tags_add',
array(
'name' => array(),
'pwg_token' => array(),
'name' => array()
),
'Adds a new tag.',
$ws_functions_root . 'pwg.tags.php',