fixes #2353 update images with upload form (#2385)

Add a mode to update photos with the upload form. Modify the upload formats form, so that it will update the photo with the same file extension.
This commit is contained in:
Perrom
2025-07-31 10:41:01 +02:00
committed by GitHub
parent bc4acec569
commit d0ac05d951
9 changed files with 385 additions and 38 deletions
+31 -3
View File
@@ -520,8 +520,36 @@ SELECT
'filesize' => $file_infos['filesize'],
);
single_insert(IMAGE_FORMAT_TABLE, $insert);
$format_id = pwg_db_insert_id(IMAGE_FORMAT_TABLE);
$query = '
SELECT
format_id
FROM '.IMAGE_FORMAT_TABLE.'
WHERE image_id = '.$format_of.'
AND ext = "'.$format_ext.'"
;';
$formats = query2array($query);
if($formats)
{
$set_fields = array(
'filesize' => $file_infos['filesize'],
);
$where_fields = array(
'format_id' => $formats[0]['format_id'],
'image_id' => $format_of,
'ext' => $format_ext,
);
single_update(IMAGE_FORMAT_TABLE, $set_fields, $where_fields);
$format_id = $formats[0]['format_id'];
$add_status = "update";
}
else
{
single_insert(IMAGE_FORMAT_TABLE, $insert);
$format_id = pwg_db_insert_id(IMAGE_FORMAT_TABLE);
$add_status = "add";
}
pwg_activity('photo', $format_of, 'edit', array('action'=>'add format', 'format_ext'=>$format_ext, 'format_id'=>$format_id));
@@ -530,7 +558,7 @@ SELECT
trigger_notify('loc_end_add_format', $format_infos);
return $format_id;
return $add_status;
}
add_event_handler('upload_file', 'upload_file_pdf');
+6 -1
View File
@@ -85,6 +85,7 @@ $display_formats = $conf['enable_formats'] && isset($_GET['formats']);
$have_formats_original = false;
$formats_original_info = array();
$formats_ext_info = null;
// If URL parameter isn't empty
if ($display_formats && $_GET['formats'])
@@ -109,13 +110,16 @@ SELECT *
if (!empty($formats))
{
$format_strings = array();
$formats_exts = array();
foreach ($formats as $format)
{
$format_strings[] = sprintf('%s (%.2fMB)', $format['ext'], $format['filesize']/1024);
$formats_exts[] = strtolower($format['ext']);
}
$formats_original_info['formats'] = l10n('Formats: %s', implode(', ', $format_strings));
$formats_ext_info = json_encode($formats_exts);
}
$extTab = explode('.',$formats_original_info['file']);
@@ -150,7 +154,8 @@ $template->assign(array(
'DISPLAY_FORMATS' => $display_formats,
'HAVE_FORMATS_ORIGINAL' => $have_formats_original,
'FORMATS_ORIGINAL_INFO' => $formats_original_info,
'SWITCH_MODE_URL' => get_root_url().'admin.php?page=photos_add'.($display_formats ? '':'&formats'),
'FORMATS_EXT_INFO' => $formats_ext_info,
'SWITCH_FORMAT_MODE_URL' => get_root_url().'admin.php?page=photos_add'.($display_formats ? '':'&formats'),
'format_ext' => implode(',', $conf['format_ext']),
'str_format_ext' => implode(', ', $conf['format_ext']),
));
+10
View File
@@ -665,6 +665,9 @@ a#showPermissions:hover {border-color: #A5A5A5;}
.plupload_filelist_footer {background-color: #F5F5F5!important;}
li.plupload_delete a {background: url("images/cancel.svg")!important; background-size: cover!important;}
li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important; background-size: cover!important;}
li.plupload_delete a span {background: #FFF;}
li.plupload_delete a:hover span {background: #FFF;}
li.plupload_delete a.remove-format:hover{color: #474747;}
.addAlbumEmpty {color: #3C3C3C;}
#permitAction p {background: #FFF;}
@@ -714,6 +717,13 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important;
#batchManagerGlobal .ui-slider-range.ui-widget-header.ui-corner-all {border: 1px solid #ffaf58;}
#batchManagerGlobal .font-checkbox.selected {color: #777;}
/* Picture add */
.upload-options, .upload-options-content {
background-color: #f5f5f5;
color: #777777;
}
/* Category List */
.categoryContainer {
margin: 0;
+142 -9
View File
@@ -16,6 +16,8 @@ const selectedAlbumEdit = $('#selectedAlbumEdit');
const btnAddFiles = $('#addFiles');
const chooseAlbumFirst = $('#chooseAlbumFirst');
const uploaderPhotos = $('#uploader');
const formatsUpdated = [];
const formats = [];
/*--------------
On DOM load
@@ -85,6 +87,12 @@ $(function () {
return false;
});
$("#uploadOptionsContent").hide();
$("#uploadOptions").on("click", function(){
$("#uploadOptionsContent").slideToggle();
$(".moxie-shim-html5").css("display", "none");
})
$("#uploader").pluploadQueue({
// General settings
browse_button: 'addFiles',
@@ -153,11 +161,37 @@ $(function () {
FilesAdded: async function (up, files) {
// Création de la liste avec plupload_id : image_name
fileNames = {};
exts = {};
files.forEach((file) => {
fileNames[file.id] = file.name;
exts[file.id] = file.name.substr(file.name.lastIndexOf('.') + 1);
});
if (formatMode) {
formats.forEach((forms) => {
$("#"+forms[0]+" > .plupload_file_name").append(`
<a target=\"_blank\" href=\"admin.php?page=photo-${forms[1].trim()}-properties\">
<span class=\"icon-eye\">
</span>
</a>`);
if(formatsUpdated.includes(forms[0])){
$("#"+forms[0]+" > .plupload_file_name").after(`
<a target=\"_blank\" href=\"admin.php?page=photo-${forms[1].trim()}-formats\">
<span class=\"icon-attention update-warning\">
${format_update_warning}
</span>
</a>
<a class="remove-format" id=\"remove_${forms[0]}\">
<span class = \"icon-cancel-circled\">
</span>
${format_remove}
</a>`);
$("#remove_"+forms[0]).on("click", function(){
up.removeFile(forms[0]);
});
}
});
// If no original image is specified
if (!haveFormatsOriginal) {
const images_search = await new Promise((res, rej) => {
@@ -166,8 +200,6 @@ $(function () {
url: "ws.php?format=json&method=pwg.images.formats.searchImage",
type: "POST",
data: {
// category_id: $("select[name=category] option:selected").val(), // id category to modify
category_id: ab.get_selected_albums()[0],
filename_list: JSON.stringify(fileNames),
},
success: function (result) {
@@ -182,8 +214,33 @@ $(function () {
files.forEach((f) => {
const search = images_search[f.id];
if (search.status == "found")
if (search.status == "found"){
f.format_of = search.image_id;
formats.push([f.id,f.format_of]);
$("#"+f.id+" > .plupload_file_name").append(`
<a target=\"_blank\" href=\"admin.php?page=photo-${f.format_of.trim()}-properties\">
<span class=\"icon-eye\">
</span>
</a>`);
if (search.format_exist)
{
$("#"+f.id+" > .plupload_file_name").after(`
<a target=\"_blank\" href=\"admin.php?page=photo-${f.format_of.trim()}-formats\">
<span class=\"icon-attention update-warning\">
${format_update_warning}
</span>
</a>
<a class="remove-format" id=\"remove_${f.id}\">
<span class = \"icon-cancel-circled\">
</span>
${format_remove}
</a>`);
formatsUpdated.push(f.id);
$("#remove_"+f.id).on("click", function(){
up.removeFile(f.id);
});
}
}
else {
if (search.status == "multiple")
multiple.push(f.name);
@@ -218,14 +275,72 @@ $(function () {
...jConfirm_warning_options
})
}
} else { //If an original image is specified
} else {
if (imageFormatsExtensions)
{
$forms_exts = JSON.parse(imageFormatsExtensions);
}
else
{
$forms_exts = [];
}
files.forEach((f) => {
f.format_of = originalImageId;
formats.push([f.id,f.format_of]);
$("#"+f.id+" > .plupload_file_name").append(`
<a target=\"_blank\" href=\"admin.php?page=photo-${f.format_of.trim()}-properties\">
<span class=\"icon-eye\">
</span>
</a>`);
if ($forms_exts.indexOf(exts[f.id]) != -1)
{
$("#"+f.id+" > .plupload_file_name").after(`
<a target=\"_blank\" href=\"admin.php?page=photo-${originalImageId.trim()}-formats\">
<span class=\"icon-attention update-warning\">
${format_update_warning}
</span>
</a>
<a class="remove-format" id=\"remove_${f.id}\">
<span class = \"icon-cancel-circled\">
</span>
${format_remove}
</a>`);
formatsUpdated.push(f.id);
$("#remove_"+f.id).on("click", function(){
up.removeFile(f.id);
});
}
})
}
}
},
FilesRemoved: function(up, file){
formats.forEach((forms) => {
$("#"+forms[0]+" > .plupload_file_name").append(`
<a target=\"_blank\" href=\"admin.php?page=photo-${forms[1].trim()}-properties\">
<span class=\"icon-eye\">
</span>
</a>`);
if(formatsUpdated.includes(forms[0])){
$("#"+forms[0]+" > .plupload_file_name").after(`
<a target=\"_blank\" href=\"admin.php?page=photo-${forms[1].trim()}-formats\">
<span class=\"icon-attention update-warning\">
${format_update_warning}
</span>
</a>
<a class="remove-format" id=\"remove_${forms[0]}\">
<span class = \"icon-cancel-circled\">
</span>
${format_remove}
</a>`);
$("#remove_"+forms[0]).on("click", function(){
up.removeFile(forms[0]);
});
}
});
},
UploadProgress: function (up, file) {
$('#uploadingActions .progressbar').width(up.total.percent + '%');
Piecon.setProgress(up.total.percent);
@@ -265,6 +380,8 @@ $(function () {
options.name = file.name;
}
options.update_mode = $('#toggleUpdateMode').is(':checked');
up.setOption('multipart_params', options);
},
@@ -289,6 +406,12 @@ $(function () {
// do not remove file, or it will reset the progress bar :-/
// up.removeFile(file);
uploadedPhotos.push(parseInt(data.result.image_id));
if(data.result.add_status=="add"){
addedPhotos.push(parseInt(data.result.image_id));
}
else{
updatedPhotos.push(parseInt(data.result.image_id));
}
if (!formatMode)
uploadCategory = data.result.category;
},
@@ -322,12 +445,23 @@ $(function () {
$("#uploadForm, #permissions, .showFieldset").hide();
const infoText = formatMode ?
sprintf(formatsUploaded_label, uploadedPhotos.length, [...new Set(files.map(f => f.format_of))].length)
: sprintf(photosUploaded_label, uploadedPhotos.length)
const infoTextAdd = formatMode ?
sprintf(formatsAdded_label, addedPhotos.length, [...new Set(addedPhotos)].length)
: sprintf(photosAdded_label, addedPhotos.length);
$(".infos").append('<ul><li>' + infoText + '</li></ul>');
const infoTextUpdate = formatMode ?
sprintf(formatsUpdated_label, updatedPhotos.length, [...new Set(updatedPhotos)].length)
: sprintf(photosUpdated_label, updatedPhotos.length);
if (addedPhotos.length && updatedPhotos.length)
{
$(".infos").append( '<ul><li>' + infoTextAdd + ', ' + infoTextUpdate + '</li></ul>');
}
else
{
const infoText = addedPhotos.length ? infoTextAdd : infoTextUpdate;
$(".infos").append('<ul><li>' + infoText + '</li></ul>');
}
if (!formatMode) {
html = sprintf(
@@ -357,7 +491,6 @@ $(function () {
}
}
});
});
/*--------------
@@ -35,25 +35,32 @@
const formatMode = {if $DISPLAY_FORMATS}true{else}false{/if};
const haveFormatsOriginal = {if $HAVE_FORMATS_ORIGINAL}true{else}false{/if};
const originalImageId = haveFormatsOriginal? '{if isset($FORMATS_ORIGINAL_INFO['id'])} {$FORMATS_ORIGINAL_INFO['id']} {else} -1 {/if}' : -1;
const imageFormatsExtensions = '{$FORMATS_EXT_INFO}';
const nb_albums = {$NB_ALBUMS|escape:javascript};
const chunk_size = '{$chunk_size}kb';
const max_file_size = '{$max_file_size}mb';
const format_update_warning = "{'This format already exists, it will be overwritten !'|translate}";
const format_remove = "{'Remove'|translate}";
var pwg_token = '{$pwg_token}';
var photosUploaded_label = "{'%d photos uploaded'|translate|escape:javascript}";
var formatsUploaded_label = "{'%d formats uploaded for %d photos'|translate|escape:javascript}";
var batch_Label = "{'Manage this set of %d photos'|translate|escape:javascript}";
var albumSummary_label = "{'Album "%s" now contains %d photos'|translate|escape:javascript}";
var str_format_warning = "{'Error when trying to detect formats'|translate|escape:javascript}";
var str_ok = "{'Ok'|translate|escape:javascript}";
var str_format_warning_multiple = "{'There is multiple image in the database with the following names : %s.'|translate|escape:javascript}";
var str_format_warning_notFound = "{'No picture found with the following name : %s.'|translate|escape:javascript}";
var str_and_X_others = "{'and %d more'|translate|escape:javascript}";
const photosAdded_label = "{'%d photos uploaded'|translate|escape:javascript}";
const photosUpdated_label = "{'%d photos updated'|translate|escape:javascript}";
const formatsAdded_label = "{'%d formats added for %d photos'|translate|escape:javascript}";
const formatsUpdated_label = "{'%d formats updated for %d photos'|translate|escape:javascript}";
const batch_Label = "{'Manage this set of %d photos'|translate|escape:javascript}";
const albumSummary_label = "{'Album "%s" now contains %d photos'|translate|escape:javascript}";
const str_format_warning = "{'Error when trying to detect formats'|translate|escape:javascript}";
const str_ok = "{'Ok'|translate|escape:javascript}";
const str_format_warning_multiple = "{'There is multiple image in the database with the following names : %s.'|translate|escape:javascript}";
const str_format_warning_notFound = "{'No picture found with the following name : %s.'|translate|escape:javascript}";
const str_and_X_others = "{'and %d more'|translate|escape:javascript}";
const str_upload_in_progress = "{'Upload in progress'|translate|escape:javascript}";
const str_drop_album_ab = '{'Drop into album'|@translate|escape:javascript}';
var file_ext = "{$file_exts}";
var format_ext = "{$format_ext}";
var uploadedPhotos = [];
var uploadCategory = null;
const file_ext = "{$file_exts}";
const format_ext = "{$format_ext}";
const uploadedPhotos = [];
let uploadCategory = null;
const addedPhotos = [];
const updatedPhotos = [];
let related_categories_ids = {$selected_category|json_encode};
{/footer_script}
@@ -103,7 +110,7 @@ let related_categories_ids = {$selected_category|json_encode};
{if $ENABLE_FORMATS and $can_upload}
<div class="format-mode-group-manager">
<label class="switch" onClick="window.location.replace('{$SWITCH_MODE_URL}'); $('.switch .slider').addClass('loading');">
<label class="switch" onClick="window.location.replace('{$SWITCH_FORMAT_MODE_URL}'); $('.switch .slider').addClass('loading');">
<input type="checkbox" id="toggleFormatMode" {if $DISPLAY_FORMATS}checked{/if}>
<span class="slider round"></span>
</label>
@@ -171,7 +178,29 @@ let related_categories_ids = {$selected_category|json_encode};
</fieldset>
*}
<fieldset class="selectFiles">
<legend><span class="icon-file-image icon-yellow"></span>{'Select files'|@translate}</legend>
<legend>
<div style="display:flex;align-items: center;">
<span class="icon-file-image icon-yellow"></span>{'Select files'|@translate}
{if !$DISPLAY_FORMATS}
<div id="uploadOptions" class="upload-options">
<span class="icon-equalizer rotate-element upload-options-icon"></span>{'Options'|@translate}
</div>
{/if}
</div>
{if !$DISPLAY_FORMATS}
<div class="upload-options-content" id="uploadOptionsContent">
<label class="switch">
<input type="checkbox" id="toggleUpdateMode">
<span class="slider round"></span>
</label>
<div style="margin-left: 6px;">
<p>{'If file already exists, update it'|@translate}</p>
</div>
</div>
{/if}
</legend>
<div class="selectFilesButtonBlock">
<button id="addFiles" class="buttonLike icon-plus-circled" {if !$can_upload}disabled{/if}>
{if not $DISPLAY_FORMATS}{'Add Photos'|translate}{else}{'Add formats'|@translate}{/if}
+79
View File
@@ -1893,6 +1893,36 @@ img.ui-datepicker-trigger {
padding-right: 5px;
}
.upload-options{
cursor: pointer;
align-items: center;
margin-left: 25px;
padding: 2.5px 10px 7.5px 0;
display: flex;
}
.upload-options-icon{
margin-right: 0 !important;
padding-top: 0 !important;
}
.upload-options-content{
display: flex;
position: relative;
font-weight: normal;
padding : 23px 0px 22px 24px;
width: calc(101vw - 100%);
margin-right: 1em;
}
#toggleUpdateMode + .slider.round{
margin-right: 0;
}
.rotate-element{
transform: rotate(90deg);
}
#uploadFormSettings input[type="text"] {
text-align:right;
}
@@ -1901,6 +1931,45 @@ img.ui-datepicker-trigger {
width:50%;
}
.plupload_file_name span:not(.icon-eye){
max-width: 180px;
white-space: nowrap;
text-overflow: ellipsis;
display: inline-block;
overflow: hidden;
}
.plupload_file_name a{
margin-left: 5px;
position: relative;
bottom: 3px;
}
.plupload_file_name + a{
margin-left: 15%;
}
.update-warning{
margin-right: 5px;
color:#ED5F59;
text-decoration: underline;
}
.update-warning:hover{
color:#BE4949;
}
li.plupload_delete a.remove-format{
margin-left: 5px;
background: none !important;
color: #A4A4A4;
}
li.plupload_delete a.remove-format:hover{
background: none !important;
text-decoration: none;
}
html, body {height:100; min-height: 100%; margin:0; padding:0;}
#the_page {min-height:100%; position:absolute; width:100%; padding:0;margin:0;}
@@ -5407,10 +5476,20 @@ input[type="text"].dError {border-color:#ff7070; background-color:#FFe5e5;}
}
}
input:checked + .slider.small::before {
-webkit-transform: translateX(12px);
-ms-transform: translateX(12px);
transform: translateX(12px);
}
input:checked + .slider:before, input:checked + .slider::after {
margin-left: 33px;
}
input:checked + .slider.small:before, input:checked + .slider.small::after {
margin-left: 0px;
}
.slider.loading::before {
opacity: 0;
}
+14 -1
View File
@@ -421,6 +421,16 @@ div.token-input-dropdown ul li.token-input-selected-dropdown-item {background-co
background: #3c3939;
}
/* Picture add */
.upload-options, .upload-options-content {
background-color: #343434;
}
.upload-options-content .switch .slider {
background-color: #444444
}
/* Picture edit */
#picture-content input[type=text], #picture-content textarea, #picture-content .selectize-input, #picture-content select {
background-color: #444444;
@@ -710,7 +720,7 @@ input:checked + .slider::after{
}
input:checked + .slider {
background-color: #ffa646;
background-color: #ffa646 !important;
}
input:focus + .slider {
@@ -998,6 +1008,9 @@ a#showPermissions:hover {border-color: #A5A5A5;}
.plupload_filelist_footer {background-color: #3c3939!important; border: 0!important; color: #A5A5A5!important}
li.plupload_delete a {background: url("images/cancel.svg")!important; background-size: cover!important;}
li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important; background-size: cover!important;}
li.plupload_delete a span {background: #444444;}
li.plupload_delete a:hover span {background: #444444;}
li.plupload_delete a.remove-format:hover{color: #c0c0c0;}
.addAlbumEmpty {color: #c1c1c1;}
.buttonSeparator {color: #c1c1c1;}
+54 -8
View File
@@ -1780,6 +1780,7 @@ function ws_images_upload($params, $service)
@fclose($out);
@fclose($in);
$add_status = "add";
// Check if file has been uploaded
if (!$chunks || $chunk == $chunks - 1)
{
@@ -1803,22 +1804,44 @@ SELECT *
$image = $images[0];
add_format($filePath, $format_ext, $image['id']);
$add_status = add_format($filePath, $format_ext, $image['id']);
return array(
'image_id' => $image['id'],
'src' => DerivativeImage::thumb_url($image),
'square_src' => DerivativeImage::url(ImageStdParams::get_by_type(IMG_SQUARE), $image),
'name' => $image['name'],
);
'add_status' => $add_status,
);
}
$name = pwg_db_real_escape_string(stripslashes($params['name']));
$id_image = null; //null by default
if ($params['update_mode'])
{
$query = '
SELECT
id
FROM '.IMAGES_TABLE.' AS i
INNER JOIN '.IMAGE_CATEGORY_TABLE.' as ic ON ic.image_id = i.id
WHERE i.file = \''.$name.'\'
AND ic.category_id = '.$params['category'][0].'
;';
$images = query2array($query);
if ($images != null)
{
$id_image = $images[0]['id']; //take the id of the already existing image to replace it
$add_status = "update";
}
}
$image_id = add_uploaded_file(
$filePath,
stripslashes($params['name']), // function add_uploaded_file will secure before insert
$name, // function add_uploaded_file will secure before insert
$params['category'],
$params['level'],
null // image_id = not provided, this is a new photo
$id_image
);
$query = '
@@ -1845,6 +1868,7 @@ SELECT
COUNT(*)
FROM '.LOUNGE_TABLE.'
WHERE category_id = '.$params['category'][0].'
AND image_id NOT IN (Select image_id from '.IMAGE_CATEGORY_TABLE.')
;';
list($nb_photos_lounge) = pwg_db_fetch_row(pwg_query($query));
@@ -1859,7 +1883,8 @@ SELECT
'id' => $params['category'][0],
'nb_photos' => $category_infos['nb_photos'] + $nb_photos_lounge,
'label' => $category_name,
)
),
'add_status' => $add_status
);
}
}
@@ -2220,7 +2245,6 @@ SELECT id, file
*
* @since 13
* @param mixed[] $params
* @option string category_id (optional)
* @option string filename_list
*/
function ws_images_formats_searchImage($params, $service)
@@ -2251,6 +2275,19 @@ SELECT
return strlen($b) - strlen($a);
});
$query = '
SELECT
image_id,
ext
FROM '.IMAGE_FORMAT_TABLE.'
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$format_image_id = $row['image_id'];
@$format_db[ $format_image_id ][] = $row['ext'];
}
$result = array();
foreach ($candidates as $format_external_id => $format_filename)
@@ -2275,8 +2312,17 @@ SELECT
$result[$format_external_id] = array('status' => 'multiple');
continue;
}
$result[$format_external_id] = array('status' => 'found', 'image_id' => $unique_filenames_db[$candidate_filename_wo_ext][0]);
$img_id = $unique_filenames_db[$candidate_filename_wo_ext][0];
$mult_form = false;
if (isset($format_db[$img_id]))
{
$format_ext = pathinfo($format_filename, PATHINFO_EXTENSION);
if (array_search($format_ext, $format_db[$img_id])!==false)
{
$mult_form = true;
}
}
$result[$format_external_id] = array('status' => 'found', 'image_id' => $img_id, 'format_exist' => $mult_form);
continue;
}
+5 -1
View File
@@ -262,7 +262,6 @@ function ws_addDefaultMethods( $arr )
'pwg.images.formats.searchImage',
'ws_images_formats_searchImage',
array(
'category_id' => array('type'=>WS_TYPE_ID, 'default'=>null),
'filename_list' => array(),
),
'Search for image ids matching the provided filenames. <b>filename_list</b> must be a JSON encoded associative array of unique_id:filename.<br><br>The method returns a list of unique_id:image_id.',
@@ -500,6 +499,11 @@ function ws_addDefaultMethods( $arr )
'type' => WS_TYPE_ID,
'info' => 'id of the extended image (name/category/level are not used if format_of is provided)',
),
'update_mode' => array(
'default' => false,
'type' => WS_TYPE_BOOL,
'info' => 'true if the update mode is active',
),
'pwg_token' => array(),
),
'Add an image.