fixes #2226 implement album selector in batch manager filter and action

This commit is contained in:
Linty
2024-09-23 12:44:00 +02:00
parent 9a46f14f1c
commit 91bb79c893
9 changed files with 289 additions and 152 deletions
+5 -4
View File
@@ -33,7 +33,8 @@ if (!empty($_POST))
trigger_notify('loc_begin_element_set_global');
check_input_parameter('del_tags', $_POST, true, PATTERN_ID);
check_input_parameter('associate', $_POST, false, PATTERN_ID);
check_input_parameter('associate', $_POST, true, PATTERN_ID);
check_input_parameter('move', $_POST, false, PATTERN_ID);
check_input_parameter('dissociate', $_POST, false, PATTERN_ID);
// +-----------------------------------------------------------------------+
@@ -165,7 +166,7 @@ DELETE
{
associate_images_to_categories(
$collection,
array($_POST['associate'])
$_POST['associate']
);
$_SESSION['page_infos'] = array(
@@ -190,7 +191,7 @@ DELETE
else if ('move' == $action)
{
move_images_to_categories($collection, array($_POST['associate']));
move_images_to_categories($collection, array($_POST['move']));
$_SESSION['page_infos'] = array(
l10n('Information data registered in database')
@@ -204,7 +205,7 @@ DELETE
else if ('no_virtual_album' == $page['prefilter'])
{
$category_info = get_cat_info($_POST['associate']);
$category_info = get_cat_info($_POST['move']);
if (empty($category_info['dir']))
{
$redirect = true;
+133 -129
View File
@@ -1,142 +1,146 @@
<?php
//prefilter
$prefilters = array(
array('ID' => 'caddie', 'NAME' => l10n('Caddie')),
array('ID' => 'favorites', 'NAME' => l10n('Your favorites')),
array('ID' => 'last_import', 'NAME' => l10n('Last import')),
array('ID' => 'no_album', 'NAME' => l10n('With no album').' ('.l10n('Orphans').')'),
array('ID' => 'no_tag', 'NAME' => l10n('With no tag')),
array('ID' => 'duplicates', 'NAME' => l10n('Duplicates')),
array('ID' => 'all_photos', 'NAME' => l10n('All'))
);
if ($conf['enable_synchronization'])
{
$prefilters[] = array('ID' => 'no_virtual_album', 'NAME' => l10n('With no virtual album'));
$prefilters[] = array('ID' => 'no_sync_md5sum', 'NAME' => l10n('With no checksum'));
}
function UC_name_compare($a, $b)
{
return strcmp(strtolower($a['NAME']), strtolower($b['NAME']));
}
$prefilters = trigger_change('get_batch_manager_prefilters', $prefilters);
// Sort prefilters by localized name.
usort($prefilters, function ($a, $b) {
return strcmp(strtolower($a['NAME']), strtolower($b['NAME']));
});
$template->assign(
array(
'conf_checksum_compute_blocksize' => $conf['checksum_compute_blocksize'],
'prefilters' => $prefilters,
'filter' => $_SESSION['bulk_manager_filter'],
'selection' => $collection,
'all_elements' => $page['cat_elements_id'],
'START' => $page['start'],
'PWG_TOKEN' => get_pwg_token(),
'U_DISPLAY'=>$base_url.get_query_string_diff(array('display')),
'F_ACTION'=>$base_url.get_query_string_diff(array('cat','start','tag','filter')),
'ADMIN_PAGE_TITLE' => l10n('Batch Manager'),
)
);
if (isset($page['no_md5sum_number']))
{
$template->assign(
array(
'NB_NO_MD5SUM' => $page['no_md5sum_number'],
)
);
} else {
$template->assign('NB_NO_MD5SUM', '');
}
// privacy level
foreach ($conf['available_permission_levels'] as $level)
{
$level_options[$level] = l10n(sprintf('Level %d', $level));
if (0 == $level)
{
$level_options[$level] = l10n('Everybody');
}
}
$template->assign(
array(
'filter_level_options'=> $level_options,
'filter_level_options_selected' => isset($_SESSION['bulk_manager_filter']['level'])
? $_SESSION['bulk_manager_filter']['level']
: 0,
)
);
// tags
$filter_tags = array();
if (!empty($_SESSION['bulk_manager_filter']['tags']))
{
$query = '
SELECT
id,
name
FROM '.TAGS_TABLE.'
WHERE id IN ('.implode(',', $_SESSION['bulk_manager_filter']['tags']).')
;';
$filter_tags = get_taglist($query);
}
$template->assign('filter_tags', $filter_tags);
// in the filter box, which category to select by default
$selected_category = array();
if (isset($_SESSION['bulk_manager_filter']['category']))
{
$selected_category = array($_SESSION['bulk_manager_filter']['category']);
}
else
{
// we need to know the category in which the last photo was added
$query = '
SELECT category_id
FROM '.IMAGE_CATEGORY_TABLE.'
ORDER BY image_id DESC
LIMIT 1
;';
$result = pwg_query($query);
if (pwg_db_num_rows($result) > 0)
{
$row = pwg_db_fetch_assoc($result);
$selected_category[] = $row['category_id'];
}
}
$template->assign('filter_category_selected', $selected_category);
// +-----------------------------------------------------------------------+
// | This file is part of Piwigo. |
// | |
// | For copyright and license information, please view the COPYING.txt |
// | file that was distributed with this source code. |
// +-----------------------------------------------------------------------+
// Dissociate from a category : categories listed for dissociation can only
// represent virtual links. We can't create orphans. Links to physical
// categories can't be broken.
$associated_categories = array();
if (!defined('PHPWG_ROOT_PATH'))
{
die ("Hacking attempt!");
}
if (count($page['cat_elements_id']) > 0)
{
$prefilters = array(
array('ID' => 'caddie', 'NAME' => l10n('Caddie')),
array('ID' => 'favorites', 'NAME' => l10n('Your favorites')),
array('ID' => 'last_import', 'NAME' => l10n('Last import')),
array('ID' => 'no_album', 'NAME' => l10n('With no album') . ' (' . l10n('Orphans') . ')'),
array('ID' => 'no_tag', 'NAME' => l10n('With no tag')),
array('ID' => 'duplicates', 'NAME' => l10n('Duplicates')),
array('ID' => 'all_photos', 'NAME' => l10n('All'))
);
if ($conf['enable_synchronization']) {
$prefilters[] = array('ID' => 'no_virtual_album', 'NAME' => l10n('With no virtual album'));
$prefilters[] = array('ID' => 'no_sync_md5sum', 'NAME' => l10n('With no checksum'));
}
function UC_name_compare($a, $b)
{
return strcmp(strtolower($a['NAME']), strtolower($b['NAME']));
}
$prefilters = trigger_change('get_batch_manager_prefilters', $prefilters);
// Sort prefilters by localized name.
usort($prefilters, function ($a, $b) {
return strcmp(strtolower($a['NAME']), strtolower($b['NAME']));
});
$template->assign(
array(
'conf_checksum_compute_blocksize' => $conf['checksum_compute_blocksize'],
'prefilters' => $prefilters,
'filter' => $_SESSION['bulk_manager_filter'],
'selection' => $collection,
'all_elements' => $page['cat_elements_id'],
'START' => $page['start'],
'PWG_TOKEN' => get_pwg_token(),
'U_DISPLAY' => $base_url . get_query_string_diff(array('display')),
'F_ACTION' => $base_url . get_query_string_diff(array('cat', 'start', 'tag', 'filter')),
'ADMIN_PAGE_TITLE' => l10n('Batch Manager'),
)
);
if (isset($page['no_md5sum_number'])) {
$template->assign(
array(
'NB_NO_MD5SUM' => $page['no_md5sum_number'],
)
);
} else {
$template->assign('NB_NO_MD5SUM', '');
}
// privacy level
foreach ($conf['available_permission_levels'] as $level) {
$level_options[$level] = l10n(sprintf('Level %d', $level));
if (0 == $level) {
$level_options[$level] = l10n('Everybody');
}
}
$template->assign(
array(
'filter_level_options' => $level_options,
'filter_level_options_selected' => isset($_SESSION['bulk_manager_filter']['level'])
? $_SESSION['bulk_manager_filter']['level']
: 0,
)
);
// tags
$filter_tags = array();
if (!empty($_SESSION['bulk_manager_filter']['tags'])) {
$query = '
SELECT
id,
name
FROM ' . TAGS_TABLE . '
WHERE id IN (' . implode(',', $_SESSION['bulk_manager_filter']['tags']) . ')
;';
$filter_tags = get_taglist($query);
}
$template->assign('filter_tags', $filter_tags);
// in the filter box, which category to select by default
$selected_category = array();
if (isset($_SESSION['bulk_manager_filter']['category'])) {
$selected_category = $_SESSION['bulk_manager_filter']['category'];
} else {
// we need to know the category in which the last photo was added
$query = '
SELECT category_id
FROM ' . IMAGE_CATEGORY_TABLE . '
ORDER BY image_id DESC
LIMIT 1
;';
$result = pwg_query($query);
if (pwg_db_num_rows($result) > 0) {
$row = pwg_db_fetch_assoc($result);
$selected_category = $row['category_id'];
}
}
$selected_category_name = get_cat_display_name_from_id(
$selected_category,
);
$template->assign('filter_category_selected_name', strip_tags($selected_category_name));
$template->assign('filter_category_selected', intval($selected_category));
// Dissociate from a category : categories listed for dissociation can only
// represent virtual links. We can't create orphans. Links to physical
// categories can't be broken.
$associated_categories = array();
if (count($page['cat_elements_id']) > 0) {
$query = '
SELECT
DISTINCT(category_id) AS id
FROM '.IMAGE_CATEGORY_TABLE.' AS ic
JOIN '.IMAGES_TABLE.' AS i ON i.id = ic.image_id
WHERE ic.image_id IN ('.implode(',', $page['cat_elements_id']).')
FROM ' . IMAGE_CATEGORY_TABLE . ' AS ic
JOIN ' . IMAGES_TABLE . ' AS i ON i.id = ic.image_id
WHERE ic.image_id IN (' . implode(',', $page['cat_elements_id']) . ')
AND (
ic.category_id != i.storage_category_id
OR i.storage_category_id IS NULL
)
;';
$associated_categories = query2array($query, 'id', 'id');
}
$associated_categories = query2array($query, 'id', 'id');
}
$template->assign('associated_categories', $associated_categories);
?>
$template->assign('associated_categories', $associated_categories);
+2 -2
View File
@@ -688,13 +688,13 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
#checkActions a, .deleteDerivButtons a {background-color: #E8E8E8;}
#filterList select, .pictureLevels select, #permitAction select, .sort-by select {background-color: #FFF; color: #4E4E4E; border: 2px solid #7070704f !important; outline: none !important;}
#filter_category .selectize-input.items.full.has-options.has-items, #filter_tags .selectize-input.items.not-full.has-options,
#filter_tags .selectize-input.items.not-full, #filter_search input, #action_associate .selectize-input.items.full.has-options.has-items,
#filter_tags .selectize-input.items.not-full, #filter_search input, #action_move .selectize-input.items.full.has-options.has-items,
#action_dissociate .selectize-input.items.full.has-options.has-items {
border: 2px solid #7070704f !important;
background: #FFF;
color: #3C3C3CBD;
}
#action_associate a:last-child {background: #FFF; border: 1px solid #787777a6; box-shadow: none;}
#action_move a:last-child {background: #FFF; border: 1px solid #787777a6; box-shadow: none;}
#forbidAction, .selectionEmptyBlock, .noFilter {background-color: #f3f3f3;}
#action_title .large, #action_author .large {background-color: #FFF; color: #4E4E4E;}
#filter_dimension .slider-choice, #filter_filesize .slider-choice {background-color: #EEE; color: #777;}
@@ -31,7 +31,22 @@ function filter_disable(filter) {
}
}
// Album Selector
function select_album_filter({ album, newSelectedAlbum, getSelectedAlbum }) {
$('#selectedAlbumNameFilter').html(album.full_name_with_admin_links);
newSelectedAlbum();
$('#filterCategoryValue').val(+getSelectedAlbum()[0]);
}
$(document).ready(function () {
const ab_filter = new AlbumSelector({
selectedCategoriesIds: selected_filter_cat_ids,
selectAlbum: select_album_filter,
adminMode: true,
});
$('#selectedAlbumEditFilter').on('click', function() {
ab_filter.open();
});
$(".removeFilter").addClass("icon-cancel-circled");
@@ -42,8 +42,46 @@ jQuery(document).ready(function() {
});
}
$('ul.thumbnails').enableShiftClick();
const ab_action = new AlbumSelector({
adminMode: true,
selectAlbum: select_album_action,
removeSelectedAlbum: remove_album_action,
});
$('#associate_as').on('click', function () {
ab_action.open();
});
$('.selected-associate-action').on('click', (e) => {
if (e.target.classList.contains("remove-associate")) {
ab_action.remove_selected_album($(e.target).attr('id'));
}
});
});
/* ********** Album Selector */
function select_album_action({ album, addSelectedAlbum, getSelectedAlbum }) {
$('#associate_as p').html(str_add_alb_associate);
$(".selected-associate-action").append(
`<div class="selected-associate-item">
<span>${album.name}</span><span id="${album.id}" class="remove-associate icon-cancel-circled"></span>
<input type="hidden" id="associate_input_${album.id}" name="associate[]" value="${album.id}">
</div>`
);
addSelectedAlbum();
}
function remove_album_action({ id_album, getSelectedAlbum }) {
$('.selected-associate-item').find(`#${id_album}`).parent().remove();
const selected = getSelectedAlbum();
if (!selected.length) {
$('#associate_as p').html(str_select_alb_associate);
}
}
jQuery("a.preview-box").colorbox( {photo: true} );
jQuery('.thumbnails img').tipTip({
@@ -472,3 +510,4 @@ function delete_orphans_block(blockSize) {
}
});
}
@@ -69,6 +69,8 @@ var all_elements = [{if !empty($all_elements)}{','|@implode:$all_elements}{/if}]
var selectedMessage_pattern = "{'%d of %d photos selected'|@translate}";
var selectedMessage_none = "{'No photo selected, %d photos in current set'|@translate}";
var selectedMessage_all = "{'All %d photos are selected'|@translate}";
const str_add_alb_associate = "{"Add Album"|@translate}";
const str_select_alb_associate = "{"Select an album"|@translate}";
$(document).ready(function() {
jQuery('.help-popin-search').colorbox({ width:"600px" });
@@ -134,9 +136,9 @@ $(document).ready(function() {
$("[id^=action_]").hide();
var action = $(this).prop("value");
if (action == 'move') {
{* if (action == 'move') {
action = 'associate';
}
} *}
$("#action_"+action).show();
@@ -447,10 +449,19 @@ UL.thumbnails SPAN.wrap2 {ldelim}
<div id="action_delete" class="bulkAction">
</div>
<!-- associate -->{* also used for "move" action *}
<!-- associate -->
<div id="action_associate" class="bulkAction">
<select data-selectize="categories" data-default="" name="associate" style="width:600px" placeholder="{'Select an album... or type it!'|@translate}"></select>
<a href="#" data-add-album="associate" title="{'create a new album'|@translate}" class="icon-plus"></a>
<div class="head-button-2 icon-plus-circled" id="associate_as">
<p>{"Select an album"|translate}</p>
</div>
<div class="selected-associate-action">
</div>
</div>
<!-- move -->
<div id="action_move" class="bulkAction">
<select data-selectize="categories" data-default="" name="move" style="width:600px" placeholder="{'Select an album... or type it!'|@translate}"></select>
<a href="#" data-add-album="move" title="{'create a new album'|@translate}" class="icon-plus"></a>
</div>
<!-- dissociate -->
@@ -566,9 +577,10 @@ UL.thumbnails SPAN.wrap2 {ldelim}
</form>
</div> <!-- #batchManagerGlobal -->
{include file='include/album_selector.inc.tpl'}
<style>
#action_associate .selectize-input {
#action_move .selectize-input {
min-width: 500px;
height: 44px;
}
@@ -44,6 +44,8 @@ var sliders = {
text: '{'between %s and %s MB'|translate|escape:'javascript'}'
}
};
const selected_filter_cat_ids = ["{$filter_category_selected|@json_encode|escape:html}"];
{/footer_script}
{combine_script id='batchManagerFilter' load='footer' path='admin/themes/default/js/batchManagerFilter.js'}
@@ -98,13 +100,18 @@ var sliders = {
<label class="font-checkbox"><span class="icon-check"></span><input type="checkbox" name="filter_duplicates_dimensions" {if isset($filter.duplicates_dimensions)}checked="checked"{/if}> {'width & height'|translate}</label>
</span>
</li>
{* categories *}
<li id="filter_category" {if !isset($filter.category)}style="display:none"{/if}>
<input type="checkbox" name="filter_category_use" class="useFilterCheckbox" {if isset($filter.category)}checked="checked"{/if}>
<p>{'Album'|@translate}</p>
<a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
<select data-selectize="categories" data-value="{$filter_category_selected|@json_encode|escape:html}"
data-default="first" name="filter_category"></select>
{* <select data-selectize="categories" data-value="{$filter_category_selected|@json_encode|escape:html}"
data-default="first" name="filter_category"></select> *}
<div class="selectedAlbum" id="selectedAlbumFilter">
<input type="hidden" name="filter_category" id="filterCategoryValue" value="{$filter_category_selected|@json_encode|escape:html}">
<span class="icon-sitemap" id="selectedAlbumNameFilter">{$filter_category_selected_name}</span>
<a class="icon-pencil" id="selectedAlbumEditFilter"></a>
</div>
<label class="font-checkbox"><span class="icon-check"></span><input type="checkbox" name="filter_category_recursive" {if isset($filter.category_recursive)}checked="checked"{/if}> {'include child albums'|@translate}</label>
</li>
@@ -244,3 +251,4 @@ var sliders = {
</div>
</div>
</fieldset>
{include file='include/album_selector.inc.tpl'}
+48 -6
View File
@@ -6448,18 +6448,33 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
align-items: baseline;
gap: 5px;
}
.selectedAlbum #selectedAlbumName {
.selectedAlbum #selectedAlbumName,
.selectedAlbum #selectedAlbumNameFilter {
padding: 10px 12px;
font-weight: bold;
text-align: center;
border-radius: 7px;
background-color:#f5f5f5
background-color:#f5f5f5;
}
.selectedAlbum #selectedAlbumEdit {
.selectedAlbum #selectedAlbumEdit,
.selectedAlbum #selectedAlbumEditFilter {
font-size: 16px;
cursor: pointer;
}
.selectedAlbum#selectedAlbumFilter {
margin-bottom: 5px;
align-items: center;
}
.selectedAlbum #selectedAlbumNameFilter {
background-color:#fff;
border: 2px solid #7070704f !important;
border-radius: 0px;
width: 100%;
text-align: start;
}
.selectedAlbum span.icon-sitemap::before, .afterUploadActions a.batchLink.icon-pencil::before, .afterUploadActions a.icon-plus-circled::before {
margin-right: 12px;
}
@@ -6492,15 +6507,17 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
.permitActionItem {margin-left: 30px; width: 225px;}
.permitActionItem .selectize-control.single.plugin-remove_button {width: auto !important;}
.permitActionItem .selectize-input.items.full.has-options.has-items {width: 500px !important; line-height: 23px;}
#action_associate {display: flex;}
#action_associate a:last-child {margin-left: 15px; padding: 10px;}
#action_move {display: flex;}
#action_move a:last-child {margin-left: 15px; padding: 10px;}
#action_associate .head-button-2 {width: fit-content;}
#action_associate .head-button-2 p {margin-left: 5px; background: transparent;}
#applyAction i {margin-right: 15px;}
#action_delete_derivatives, #action_generate_derivatives {display: flex; flex-wrap: wrap; margin-top: 0px;}
.deleteDerivButtons a {border-radius: 4px; padding: 4px 10px; margin: 5px;}
.deleteDerivButtons {margin-bottom: 15px; margin-right: 51px; width: 100%; text-align: center;}
#action_delete_derivatives label, #action_generate_derivatives label {display: flex; margin-top: 4px; width: 50%;}
#action_delete_derivatives input[name="del_derivatives_type[]"], #action_generate_derivatives input[name="generate_derivatives_type[]"] {margin-right: 3px;}
.actionButtons:first-child::after,#filter_prefilter::before,#filter_category::before,#filter_level::before,
.actionButtons:first-child::after,#filter_prefilter::before,#filter_level::before,
.permitActionListButton div::before, #action_level::after, .pictureLevels::before,
.user-property-select-container::before, .sort-by .select-container::before {
content: '\e835'; font-size: 17px; position: absolute; font-family: "fontello"; color: #6E6E6E; pointer-events: none;
@@ -6606,6 +6623,31 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
#batchManagerGlobal .font-checkbox.selected span:first-child::before {content: '\f192';}
#action_delete_derivatives .font-checkbox span, #action_delete_derivatives .font-checkbox span {margin-right: 5px;}
#action_generate_derivatives, #action_delete_derivatives {width: 320px;}
#associate_as {margin-bottom: 10px;}
.selected-associate-item {
background-color: #fafafa;
box-shadow: 0px 2px #00000024;
margin-top: 5px;
padding: 7px 10px;
border-radius: 5px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: space-between;
}
.selected-associate-item:hover {
background: #ffd7ad;
}
.selected-associate-item .remove-associate {
color: #000;
}
.selected-associate-item .remove-associate:hover {
cursor: pointer;
color: #ff7700;
}
/* album manager */
.selectedAlbum.cat-list-album-path {
+18 -2
View File
@@ -1020,7 +1020,7 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
#checkActions a, .deleteDerivButtons a {background-color: #393939;}
#addFilter, #filterList select, .pictureLevels select, #permitAction select, .sort-by select {background-color: #444444; color: #BFBFBF}
#filter_category .selectize-input.items.full.has-options.has-items, #filter_tags .selectize-input.items.not-full.has-options,
#filter_tags .selectize-input.items.not-full, #filter_search input, #action_associate .selectize-input.items.full.has-options.has-items,
#filter_tags .selectize-input.items.not-full, #filter_search input, #action_move .selectize-input.items.full.has-options.has-items,
#action_dissociate .selectize-input.items.full.has-options.has-items {
background-color: #444444;
color: #BFBFBF;
@@ -1032,7 +1032,7 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
background: #3C3C3C;
color: #C0C0C0;
}
#action_associate a:last-child {color: #C0C0C0; background-color: #464646;}
#action_move a:last-child {color: #C0C0C0; background-color: #464646;}
#filter_dimension .slider-choice, #filter_filesize .slider-choice {background-color: #393939;}
#filter_dimension .slider-choice:hover, #filter_filesize .slider-choice:hover, .dimension-cancel:hover {
text-decoration: none; background-color: #ffa646 !important; color: initial;
@@ -1069,6 +1069,22 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
#batchManagerGlobal #applyFilter:hover {
background-color: #202020;
}
.selected-associate-item {
background-color: #333;
box-shadow: 0px 2px #000000AA;
color: #777;
}
.selected-associate-item:hover {
background: #f9852c;
color: #000;
}
.selected-associate-item .remove-associate:hover {
color: #ae5d1e;
}
/*Error message*/
.errors {