From 49369fbbf9dce65a3ae1c07544bd4afb191e6261 Mon Sep 17 00:00:00 2001 From: MartinCozic Date: Fri, 23 Oct 2026 15:29:03 +0200 Subject: [PATCH] fixes #2595 batch manager: add multi-fields edition action --- admin/batch_manager_global.php | 181 ++++++++++++++++ admin/themes/clear/theme.css | 4 +- .../themes/default/css/components/general.css | 4 + admin/themes/default/js/batchManagerGlobal.js | 201 +++++++++++++++++- .../default/template/batch_manager_global.tpl | 122 +++++++++-- admin/themes/default/theme.css | 114 ++++++++++ admin/themes/roma/theme.css | 13 +- language/en_UK/admin.lang.php | 2 + language/en_UK/common.lang.php | 4 + language/fr_FR/admin.lang.php | 2 + language/fr_FR/common.lang.php | 4 + 11 files changed, 629 insertions(+), 22 deletions(-) diff --git a/admin/batch_manager_global.php b/admin/batch_manager_global.php index a4786c9f9..441a1ce6f 100644 --- a/admin/batch_manager_global.php +++ b/admin/batch_manager_global.php @@ -36,6 +36,7 @@ check_input_parameter('del_tags', $_POST, true, 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); +check_input_parameter('mf_albums', $_POST, true, PATTERN_ID); // +-----------------------------------------------------------------------+ // | current selection | @@ -419,6 +420,186 @@ DELETE } } + else if ('multi_fields' == $action) + { + $enabled = isset($_POST['mf_enable']) ? $_POST['mf_enable'] : array(); + $enabled = array_flip($enabled); + + if (count($enabled) == 0) + { + $page['errors'][] = l10n('Select at least one field'); + } + else + { + $base = array( + 'title' => array('col' => 'name', 'post' => 'mf_title', 'mode' => 'mf_title_mode'), + 'author' => array('col' => 'author', 'post' => 'mf_author', 'mode' => 'mf_author_mode'), + 'comment' => array('col' => 'comment', 'post' => 'mf_comment', 'mode' => 'mf_comment_mode'), + ); + + $update_cols = array(); + foreach ($base as $key => $def) + { + if (isset($enabled[$key])) + { + $update_cols[] = $def['col']; + } + } + + if (count($update_cols) > 0) + { + $datas = array(); + foreach ($collection as $image_id) + { + $row = array('id' => $image_id); + foreach ($base as $key => $def) + { + if (isset($enabled[$key])) + { + $mode = $_POST[$def['mode']]; + if ('empty' == $mode) + { + $row[$def['col']] = null; + } + else + { + $value = $_POST[$def['post']]; + $row[$def['col']] = ($value === '') ? null : $value; + } + } + } + $datas[] = $row; + } + + mass_updates( + IMAGES_TABLE, + array('primary' => array('id'), 'update' => $update_cols), + $datas + ); + } + + if (isset($enabled['albums'])) + { + check_input_parameter('mf_albums_mode', $_POST, false, '/^(associate|dissociate)$/'); + $mode = $_POST['mf_albums_mode']; + + if (empty($_POST['mf_albums'])) + { + $page['errors'][] = l10n('Select at least one album'); + } + else + { + $album_ids = $_POST['mf_albums']; + + if ('dissociate' == $mode) + { + foreach ($album_ids as $album_id) + { + dissociate_images_from_category($collection, $album_id); + } + $redirect = true; + } + else if ('associate' == $mode) + { + associate_images_to_categories($collection, $album_ids); + } + } + } + + if (isset($enabled['tags'])) + { + check_input_parameter('mf_tags_mode', $_POST, false, '/^(replace|add|empty|remove)$/'); + $mode = $_POST['mf_tags_mode']; + + if ('empty' == $mode) + { + $tags_of = array(); + foreach ($collection as $image_id) + { + $tags_of[$image_id] = array(); + } + set_tags_of($tags_of); + } + else if (empty($_POST['mf_tags'])) + { + $page['errors'][] = l10n('Select at least one tag'); + } + else + { + if ('remove' == $mode) + { + check_input_parameter('mf_tags', $_POST, true, PATTERN_ID); + $tag_ids = $_POST['mf_tags']; + } + else + { + $tag_ids = get_tag_ids($_POST['mf_tags']); + } + if ('replace' == $mode) + { + $tags_of = array(); + foreach ($collection as $image_id) + { + $tags_of[$image_id] = $tag_ids; + } + set_tags_of($tags_of); + } + else if ('remove' == $mode) + { + $taglist_before = get_image_tag_ids($collection); + + $query = ' +DELETE + FROM '.IMAGE_TAG_TABLE.' + WHERE image_id IN ('.implode(',', $collection).') + AND tag_id IN ('.implode(',', $tag_ids).') +;'; + pwg_query($query); + + $taglist_after = get_image_tag_ids($collection); + $images_to_update = compare_image_tag_lists($taglist_before, $taglist_after); + update_images_lastmodified($images_to_update); + + if (isset($_SESSION['bulk_manager_filter']['tags']) + && count(array_intersect($_SESSION['bulk_manager_filter']['tags'], $tag_ids))) + { + $redirect = true; + } + } + else if ('add' == $mode) + { + add_tags($tag_ids, $collection); + } + } + } + + $mode_rules = array( + 'title' => array('post' => 'mf_title_mode', 'allowed' => array('replace', 'empty'), 'default' => 'replace'), + 'author' => array('post' => 'mf_author_mode', 'allowed' => array('replace', 'empty'), 'default' => 'replace'), + 'comment' => array('post' => 'mf_comment_mode', 'allowed' => array('replace', 'empty'), 'default' => 'replace'), + 'albums' => array('post' => 'mf_albums_mode', 'allowed' => array('associate', 'dissociate'), 'default' => 'associate'), + 'tags' => array('post' => 'mf_tags_mode', 'allowed' => array('add', 'replace', 'empty', 'remove'), 'default' => 'add'), + ); + + $activity_fields = array(); + foreach ($mode_rules as $field => $rule) + { + if (isset($enabled[$field])) + { + $mode = isset($_POST[$rule['post']]) ? $_POST[$rule['post']] : $rule['default']; + $activity_fields[$field] = in_array($mode, $rule['allowed'], true) ? $mode : $rule['default']; + } + } + + pwg_activity('photo', $collection, 'edit', array('action' => 'multi_fields', 'fields' => $activity_fields)); + + if (empty($page['errors'])) + { + $page['infos'][] = l10n('Information data registered in database'); + } + } + } + if (!in_array($action, array('remove_from_caddie','add_to_caddie','delete_derivatives','generate_derivatives'))) { invalidate_user_cache(); diff --git a/admin/themes/clear/theme.css b/admin/themes/clear/theme.css index a4a89264c..4915230b1 100644 --- a/admin/themes/clear/theme.css +++ b/admin/themes/clear/theme.css @@ -834,7 +834,9 @@ li.plupload_delete a.remove-format:hover{color: #474747;} background-color: #fafafa; box-shadow: 0px 2px #00000024; } -.breadcrumb-item:hover { +.breadcrumb-item:hover, +#batchManagerGlobal .head-button-2:hover, +#batchManagerGlobal .head-button-2:hover p { background: #ffd7ad; } .breadcrumb-item .icon-cancel-circled:hover { diff --git a/admin/themes/default/css/components/general.css b/admin/themes/default/css/components/general.css index f86b0e027..962c007b4 100644 --- a/admin/themes/default/css/components/general.css +++ b/admin/themes/default/css/components/general.css @@ -19,6 +19,10 @@ or align-items: baseline; cursor: pointer; margin-right: 10px; + transition: all 125ms ease-out; +} +.head-button-2 p { + transition: all 125ms ease-out; } .head-button-1:active, .head-button-2:active { diff --git a/admin/themes/default/js/batchManagerGlobal.js b/admin/themes/default/js/batchManagerGlobal.js index 2e15e6ea5..5340d1117 100644 --- a/admin/themes/default/js/batchManagerGlobal.js +++ b/admin/themes/default/js/batchManagerGlobal.js @@ -59,6 +59,22 @@ jQuery(document).ready(function() { } }); + const ab_multi_fields = new AlbumSelector({ + adminMode: true, + selectAlbum: select_multi_fields_album, + removeSelectedAlbum: remove_multi_fields_album, + }); + + $('#multi_fields_select_album').on('click', function () { + ab_multi_fields.open(); + }); + + $('.multi-fields-selected-albums').on('click', (e) => { + if (e.target.classList.contains("remove-associate")) { + ab_multi_fields.remove_selected_album($(e.target).attr('id')); + } + }); + }); /* ********** Album Selector */ @@ -81,6 +97,47 @@ function remove_album_action({ id_album, getSelectedAlbum }) { } } +function select_multi_fields_album({ album, addSelectedAlbum }) { + $('#multi_fields_select_album p').html(str_add_alb_associate); + $('.multi-fields-selected-albums').append( + `
+ ${album.name} + +
` + ); + hideError("form"); + update_multi_fields_album_button(); + addSelectedAlbum(); +} + +function remove_multi_fields_album({ id_album, getSelectedAlbum }) { + $('.multi-fields-selected-albums').find(`#${id_album}`).parent().remove(); + const selected = getSelectedAlbum(); + if (!selected.length) { + $('#multi_fields_select_album p').html(str_select_alb_associate); + } + if (selected.length) { + hideError("form"); + } + update_multi_fields_album_button(); +} + +function update_multi_fields_album_button() { + const hasSelectedAlbums = $('.multi-fields-selected-albums').children().length > 0; + $('#multi_fields_select_album') + .toggleClass('head-button-2', !hasSelectedAlbums) + .toggleClass('head-button-1', hasSelectedAlbums); +} + +function displayError(error, text) { + var $error = $("[data-error='" + error + "']"); + $error.text(text).css("visibility", "visible"); +} + +function hideError(error) { + $("[data-error='" + error + "']").css("visibility", "hidden"); +} + jQuery("a.preview-box").colorbox( {photo: true} ); @@ -102,6 +159,112 @@ jQuery(function() { jQuery('[data-add-album]').pwgAddAlbum(); }); +jQuery(function() { + $("#action_multi_fields .mf-row").each(function() { + var $row = $(this); + var $toggle = $row.find(".switch input"); + var $mode = $row.find(".mf-modes input[type=radio]"); + var $content = $row.find(".mf-content"); + var $tagSelect = $content.find("select[name='mf_tags[]']"); + var tagsMode = null; + var selectizeCreate; + + function switchTagsList(mode) { + var selectize = $tagSelect[0] && $tagSelect[0].selectize; + if (!selectize) return; + + if (selectizeCreate === undefined) { + selectizeCreate = selectize.settings.create; + } + + var isRemove = (mode === "remove"); + if (tagsMode === isRemove) return; + tagsMode = isRemove; + + selectize.clear(true); + + if (isRemove) { + if (!selectize._allOptions) { + selectize._allOptions = $.extend(true, {}, selectize.options); + } + selectize.clearOptions(); + selectize.settings.create = false; + var delTagsSelectize = $("select[name='del_tags[]']")[0]; + var removeOptions = delTagsSelectize && delTagsSelectize.selectize + ? delTagsSelectize.selectize.options + : {}; + $.each(removeOptions, function (id, tag) { + selectize.addOption(tag); + }); + } else { + if (selectize._allOptions) { + selectize.clearOptions(); + $.each(selectize._allOptions, function (id, opt) { + selectize.addOption(opt); + }); + } + selectize.settings.create = selectizeCreate; + } + selectize.refreshOptions(false); + } + + function resetRow() { + $content.find("input[type=text], textarea").val(""); + $row.find(".multi-fields-selected-albums").empty(); + update_multi_fields_album_button(); + + $content.find("select").each(function() { + if (this.selectize) { + this.selectize.clear(); + } else { + $(this).val(null); + } + }); + + $mode.each(function() { + this.checked = this.defaultChecked; + }); + tagsMode = null; + switchTagsList($mode.filter(":checked").val()); + } + + function refresh() { + var on = $toggle.is(":checked"); + var mode = $mode.filter(":checked").val(); + $row.toggleClass("mf-active", on); + $row.find(".mf-modes").toggle(on); + $content.toggle(on && mode !== "empty"); + if ($row.data("field") === "tags") { + switchTagsList(mode); + } + } + + $toggle.on("change", function() { + hideError("form"); + if (!this.checked) { + resetRow(); + } + refresh(); + }); + + $mode.on("change", function() { + if ($row.data("field") === "tags" && $(this).val() === "empty") { + hideError("form"); + } + refresh(); + }); + + $tagSelect.on("change", function() { + var selectedTags = $(this).val(); + if (selectedTags && selectedTags.length) { + hideError("form"); + } + }); + + refresh(); + }); +}); + $("input[name=remove_author]").click(function () { if ($(this).is(':checked')) { $("input[name=author]").hide(); @@ -244,7 +407,35 @@ jQuery('#applyAction').click(function(e) { return true; } - if (jQuery('[name="selectAction"]').val() == 'metadata') { + var action = jQuery('[name="selectAction"]').val(); + if (action == 'multi_fields') { + var $enabledFields = jQuery('input[name="mf_enable[]"]:checked'); + var $tagsField = jQuery('input[name="mf_enable[]"][value="tags"]'); + var tagsMode = jQuery('input[name="mf_tags_mode"]:checked').val(); + + if (!$enabledFields.length) { + displayError("form", lang.selectField); + e.preventDefault(); + return false; + } + if (jQuery('input[name="mf_enable[]"][value="albums"]').is(':checked') + && !jQuery('input[name="mf_albums[]"]').length) { + displayError("form", str_select_album); + e.preventDefault(); + return false; + } + var selectedTags = jQuery('select[name="mf_tags[]"]').val(); + if ($tagsField.is(':checked') + && tagsMode !== 'empty' + && (!selectedTags || !selectedTags.length)) { + displayError("form", str_select_tag); + e.preventDefault(); + return false; + } + } + hideError("form"); + + if (action == 'metadata') { e.preventDefault(); e.stopPropagation(); jQuery('.bulkAction').hide(); @@ -318,7 +509,10 @@ jQuery('#applyAction').click(function(e) { if (jQuery('[name="selectAction"]').val() == 'delete') { if (!jQuery("#confirmDel input[name=confirm_deletion]").is(':checked')) { - jQuery("#confirmDel span.errors").css("visibility", "visible"); + displayError( + "form", + lang.confirmDeletion + ); return false; } e.stopPropagation(); @@ -422,7 +616,7 @@ function progress_bar(val, max, success) { } jQuery("#confirmDel input[name=confirm_deletion]").change(function() { - jQuery("#confirmDel span.errors").css("visibility", "hidden"); + hideError("form"); }); jQuery('#sync_md5sum').click(function(e) { @@ -524,4 +718,3 @@ function delete_orphans_block(blockSize) { } }); } - diff --git a/admin/themes/default/template/batch_manager_global.tpl b/admin/themes/default/template/batch_manager_global.tpl index 38bec6c9c..c84c70053 100644 --- a/admin/themes/default/template/batch_manager_global.tpl +++ b/admin/themes/default/template/batch_manager_global.tpl @@ -15,6 +15,8 @@ var lang = { deleteProgressMessage: "{'Deletion in progress'|translate|escape:'javascript'}", syncProgressMessage: "{'Synchronization in progress'|translate|escape:'javascript'}", AreYouSure: "{'Are you sure?'|translate|escape:'javascript'}", + confirmDeletion: "{'You need to confirm deletion'|translate|escape:'javascript'}", + selectField: "{'Select at least one field'|translate|escape:'javascript'}", generateMsg: "{'Generate multiple size images'|@translate}" }; @@ -242,7 +244,7 @@ $(document).ready(function() { } jQuery("input[name=confirm_deletion]").change(function() { - jQuery("#confirmDel span.errors").css("visibility", "hidden"); + hideError("form"); }); jQuery('#applyAction').click(function() { @@ -251,7 +253,10 @@ $(document).ready(function() { let d_count = $('#confirmDel input[type=checkbox]').filter(':checked').length let e_count = $('input[name="setSelected"]').is(':checked') ? nb_thumbs_set : $('.thumbnails input[type=checkbox]').filter(':checked').length; if (!jQuery("#confirmDel input[name=confirm_deletion]").is(':checked')) { - jQuery("#confirmDel span.errors").css("visibility", "visible"); + displayError( + "form", + lang.confirmDeletion + ); return false; } else { return true; @@ -420,6 +425,7 @@ UL.thumbnails SPAN.wrap2 {ldelim} {/if} + {if !empty($element_set_global_plugins_actions)} {foreach from=$element_set_global_plugins_actions item=action} @@ -432,7 +438,7 @@ UL.thumbnails SPAN.wrap2 {ldelim} {'Are you sure?'|@translate}

- +