fixes #2364 redesign admin comments management

Replaces legacy PHP comment management with a new interface for listing, filtering, selecting, validating, and deleting user comments. Updates templates and CSS for a modern, interactive experience, adds advanced filters, selection mode, and modal comment viewing. Removes obsolete server-side logic from comments.php and introduces new api methods for comment actions.
This commit is contained in:
Linty
2025-08-26 14:35:31 +02:00
parent 93cc0e72a8
commit 57042cc475
10 changed files with 1606 additions and 1004 deletions
+2 -227
View File
@@ -13,70 +13,12 @@ if (!defined('PHPWG_ROOT_PATH'))
include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
if (isset($_GET['start']) and is_numeric($_GET['start']))
{
$page['start'] = $_GET['start'];
}
else
{
$page['start'] = 0;
}
// +-----------------------------------------------------------------------+
// | Check Access and exit when user status is not ok |
// +-----------------------------------------------------------------------+
check_status(ACCESS_ADMINISTRATOR);
// +-----------------------------------------------------------------------+
// | actions |
// +-----------------------------------------------------------------------+
if (!empty($_POST))
{
if (empty($_POST['comments']))
{
$template->assign(
array(
'save_warning' => l10n('Select at least one comment')
)
);
}
else
{
include_once( PHPWG_ROOT_PATH .'include/functions_comment.inc.php' );
check_input_parameter('comments', $_POST, true, PATTERN_ID);
if (isset($_POST['validate']))
{
validate_user_comment($_POST['comments']);
$template->assign(
array(
'save_success' => l10n_dec(
'%d user comment validated', '%d user comments validated',
count($_POST['comments'])
)
)
);
}
if (isset($_POST['reject']))
{
delete_user_comment($_POST['comments']);
$template->assign(
array(
'save_error' => l10n_dec(
'%d user comment rejected', '%d user comments rejected',
count($_POST['comments'])
)
)
);
}
}
}
// +-----------------------------------------------------------------------+
// | template init |
// +-----------------------------------------------------------------------+
@@ -85,7 +27,8 @@ $template->set_filenames(array('comments'=>'comments.tpl'));
$template->assign(
array(
'F_ACTION' => get_root_url().'admin.php?page=comments'
'F_ACTION' => get_root_url().'admin.php?page=comments',
'PWG_TOKEN' => get_pwg_token(),
)
);
@@ -102,174 +45,6 @@ $tabsheet->set_id('comments');
$tabsheet->select('');
$tabsheet->assign();
// +-----------------------------------------------------------------------+
// | comments display |
// +-----------------------------------------------------------------------+
$nb_total = 0;
$nb_pending = 0;
$nb_validated = 0;
$query = '
SELECT
COUNT(*) AS counter,
validated
FROM '.COMMENTS_TABLE.'
GROUP BY validated
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$nb_total+= $row['counter'];
if ('false' == $row['validated'])
{
$nb_pending = $row['counter'];
}
}
$nb_validated = $nb_total - $nb_pending;
if (!isset($_GET['filter']) and $nb_pending > 0)
{
$page['filter'] = 'pending';
}
else
{
$page['filter'] = 'all';
}
if (isset($_GET['filter']) and ('pending' == $_GET['filter'] or 'validated' == $_GET['filter']))
{
$page['filter'] = $_GET['filter'];
}
if (isset($_GET['status']))
{
$displayed_status = $_GET['status'];
}
else
{
$displayed_status = 'all';
}
if (isset($_GET['author']))
{
$author = $_GET['author'];
}
else
{
$author = 'all';
}
// by default, no filter by date is active
$start = $end = "";
if (isset($_GET['start_date'])){
$start = $_GET['start_date'];
}
if (isset($_GET['end_date'])){
$end = $_GET['end_date'];
}
$template->assign(
array(
'nb_total' => $nb_total,
'nb_pending' => $nb_pending,
'nb_validated' => $nb_validated,
'filter' => $page['filter'],
'displayed_status' => $displayed_status,
'displayed_author' => $author,
'START' => $start,
'END' => $end,
)
);
$where_clauses = array('1=1');
if ('pending' == $page['filter'])
{
$where_clauses[] = 'validated=\'false\'';
}
if ('validated' == $page['filter'])
{
$where_clauses[] = 'validated=\'true\'';
}
$query = '
SELECT
c.id,
c.image_id,
c.date,
c.author,
'.$conf['user_fields']['username'].' AS username,
ui.status,
c.content,
i.path,
i.representative_ext,
validated,
c.anonymous_id
FROM '.COMMENTS_TABLE.' AS c
INNER JOIN '.IMAGES_TABLE.' AS i
ON i.id = c.image_id
LEFT JOIN '.USERS_TABLE.' AS u
ON u.'.$conf['user_fields']['id'].' = c.author_id
LEFT JOIN '.USER_INFOS_TABLE.' AS ui
ON ui.user_id = c.author_id
WHERE '.implode(' AND ', $where_clauses).'
ORDER BY c.date DESC
LIMIT '.$page['start'].', '.$conf['comments_page_nb_comments'].'
;';
$result = pwg_query($query);
while ($row = pwg_db_fetch_assoc($result))
{
$thumb = DerivativeImage::thumb_url(
array(
'id'=>$row['image_id'],
'path'=>$row['path'],
'representative_ext'=>$row['representative_ext'],
)
);
if (empty($row['author_id']))
{
$author_name = $row['author'];
}
else
{
$author_name = stripslashes($row['username']);
}
$template->append(
'comments',
array(
'U_PICTURE' => get_root_url().'admin.php?page=photo-'.$row['image_id'],
'ID' => $row['id'],
'TN_SRC' => $thumb,
'AUTHOR' => trigger_change('render_comment_author', $author_name),
'AUTHOR_STATUS' => $row['status'],
'DATE' => format_date($row['date'], array('day_name','day','month','year','time')),
'CONTENT' => trigger_change('render_comment_content',$row['content']),
'IS_PENDING' => ('false' == $row['validated']),
'IP' => $row['anonymous_id'],
'NUMERICAL_DATE' => $row['date'],
)
);
$list[] = $row['id'];
}
// +-----------------------------------------------------------------------+
// | navigation bar |
// +-----------------------------------------------------------------------+
$navbar = create_navigation_bar(
get_root_url().'admin.php'.get_query_string_diff(array('start')),
('pending' == $page['filter'] ? $nb_pending : $nb_total),
$page['start'],
$conf['comments_page_nb_comments']
);
$template->assign('navbar', $navbar);
$template->assign('ADMIN_PAGE_TITLE', l10n('User comments'));
// +-----------------------------------------------------------------------+
+6 -3
View File
@@ -481,7 +481,8 @@ input:focus + .slider {
box-shadow: 0 0 1px #ffa646;
}
#selection-mode-block{
#selection-mode-block,
.selection-mode {
background-color: #FAFAFA;
border-left:1px solid #e6e6e6;
}
@@ -505,12 +506,14 @@ input:focus + .slider {
color:#a0a0a0;
}
#selection-mode-block button{
#selection-mode-block button,
#commentsSelection button{
border: 1px solid #e7e7e7;
}
#selection-mode-block button:hover{
#selection-mode-block button:hover,
#commentsSelection button:hover {
background-color: #ffa744;
border: 1px solid #ffa744;
}
+590
View File
@@ -0,0 +1,590 @@
const commentsContainer = $('#comments');
const advancedFilters = $('#advancedFilters');
const switchMode = $('#toggleSelectionMode');
const commentContainer = $('#commentContainer');
const commentsAll = $('#commentsAll');
const commentsValidated = $('#commentsValidated');
const commentsPending = $('#commentsPending');
const commentsList = $('#commentsList');
const commentsNb = $('#commentsNb a');
const filterAuthor = $('#filter_author');
const filterDateStart = $('#filter_date_start');
const filterDateEnd = $('#filter_date_end');
const commentsSelectController = $('#commentsSelectController');
const tabFilters = $('#tabFilters');
const commentsSelectedArea = $('#commentsSelected');
const commentsSelectedOthers = $('#commentsSelectedOthers');
const modalViewComment = $('#modalViewComment');
const commentsPaginElipsis = '<span>...</span>';
const commentsPaginItems = '<a id="comments_page_%d" class="comments-paging" data-page="%d">%d</a>';
const commentsPaginItemsCurrent = '<a id="comments_page_%d" class="comments-paging comment-paging-current" data-page="%d">%d</a>';
const commentsOptionsFiltersAuthor = '<option value="" selected="">--</option>';
const commentsSelectedList = '<div class="comments-selected-item"><a class="icon-cancel comments-selected-remove" id="deletecomment_%d"></a> <p>#%d</p></div>';
let commentsState = {};
let commentsParams = {
status: 'all',
page: 0,
per_page: 5,
}
let updateAuthorId = true;
let searchTimeOut = null;
let selectionMode = false;
let commentsSelected = [];
$(function() {
$('#commentFilters').on('click', function() {
$(this).toggleClass('advanced-filter-open');
advancedFilters.toggle();
});
switchMode.on('change', function() {
$('#contentSelectMode').toggle();
$('#headerSelectMode, #contentSelectMode').toggleClass('selection-mode');
commentContainer.toggleClass('active');
if (!commentContainer.hasClass('active')) {
selectionMode = false;
$('.comment-select-checkbox').hide();
$('.comment-buttons').show();
commentsSelectController.removeClass('show');
tabFilters.show();
commentsUnselectAll();
} else {
selectionMode = true;
$('.comment-select-checkbox').show();
$('.comment-buttons').hide();
tabFilters.hide();
commentsSelectController.addClass('show');
}
});
$('#selectAll').on('click', function() {
commentsSelectAll();
});
$('#selectNone').on('click', function() {
commentsUnselectAll();
});
$('#selectInvert').on('click', function() {
commentsInvertSelect();
});
$('.tab-filters input').on('change', function() {
commentsParams.status = $(this).attr('data-status');
commentsParams.page = 0;
getComments(commentsParams);
});
commentsNb.on('click', function() {
const nb = $(this).text();
updateNbComments(nb);
commentsParams.page = 0;
getComments(commentsParams);
});
$('#closeModalViewComment').on('click', function() {
closeModalViewComment();
});
$('#commentSearchInput').on('input', function() {
clearTimeout(searchTimeOut);
searchTimeOut = setTimeout(() => {
const search = $(this).val();
delete commentsParams.author_id;
delete commentsParams.f_min_date;
delete commentsParams.f_max_date;
commentsParams.search = search;
getComments(commentsParams);
}, 300);
});
$('#commentsResetFilters').on('click', function() {
commentsClearFilters();
});
// get comments and set display
commentsParams.per_page = window.localStorage.getItem('adminCommentsNB') ?? 5
updateNbComments(commentsParams.per_page);
getComments(commentsParams);
});
function getComments(params) {
$.ajax({
url: 'ws.php?format=json&method=pwg.userComments.getList',
type: 'GET',
dataType: 'json',
data: params,
success: (data) => {
if (data.stat === 'ok') {
// for debug
// console.log(data.result);
commentsState = {...data.result};
commentsDisplaySummary(data.result.summary);
displayComments(data.result.comments);
commentsDiplayPagination(data.result.paging);
commentsDisplayFilters(data.result.filters);
delete commentsParams.search;
}
},
error: (e) => {
console.log(e);
$.alert({ title: str_an_error_has, content: "" , ...jConfirm_warning_options});
}
})
}
function commentsDisplaySummary(summary) {
commentsAll.text(summary.all_comments);
commentsValidated.text(summary.validated);
commentsPending.text(summary.pending);
}
function displayComments(comments) {
commentsList.empty();
comments.forEach((comment) => {
const clone = $('.comment-template').clone();
clone.removeClass('comment-template').addClass('comment');
clone.attr('id', comment.id);
clone.find('.comment-img').attr('src', comment.medium_url);
const raw_lenght = comment.raw_content.length;
const preview = raw_lenght > 50 ? comment.raw_content.substring(0, 50) + '...' : comment.raw_content;
clone.find('.comment-msg').text('"' + preview + '"');
clone.find('.comment-author-name').text(comment.author);
clone.find('.comment-datetime').text(comment.date);
clone.find('.comment-delete').data('idx', comment.id);
clone.find('.comment-validate').data('idx', comment.id);
clone.find('.comment-content').data('idx', comment.id);
clone.find('.comment-hash').text(`#${comment.id}`);
clone.find('.comment-select-checkbox').val(comment.id);
clone.find('.comment-link').attr('href', comment.admin_link);
const authorIcons = clone.find('.comment-author-icon');
switch (comment.author_status) {
case "guest":
authorIcons.addClass('icon-user-secret icon-yellow');
break;
case "webmaster":
authorIcons.addClass('icon-user icon-purple');
break;
case "admin":
authorIcons.addClass('icon-user icon-green');
break;
case "main_user":
authorIcons.addClass('icon-king icon-blue');
break;
default:
authorIcons.addClass('icon-user icon-yellow');
break;
}
if (comment.is_pending) {
clone.find('.comment-validate').show();
} else {
clone.find('.comment-container').addClass('comment-validated');
}
commentsList.append(clone);
});
$('.comment-delete').off('click').on('click', function(e) {
e.stopPropagation();
const id = $(this).data('idx');
deleteComment([id]);
});
$('.comment-validate').off('click').on('click', function(e) {
e.stopPropagation();
const id = $(this).data('idx');
validateComment([id]);
});
$('.comment-content').off('click').on('click', function() {
const id = $(this).data('idx');
if (selectionMode) {
const checkbox = $(this).find('.comment-select-checkbox');
if (checkbox.hasClass('icon-circle-empty')) {
checkbox.removeClass('icon-circle-empty').addClass('icon-ok-circled');
$(`#${id}`).addClass('comment-selected');
commentsSelected.push(id);
} else {
checkbox.removeClass('icon-ok-circled').addClass('icon-circle-empty');
$(`#${id}`).removeClass('comment-selected');
commentsSelected = commentsSelected.filter((idx) => idx != id);
}
commentsUpdateSelection();
return;
}
showModalViewComment(id);
});
}
function commentsDiplayPagination(paging) {
const container = $('.pagination-item-container');
container.empty();
if (paging.total_pages == 0) {
const pageNumbers = paging.total_pages + 1;
const page = commentsPaginItems.replace(/%d/g, pageNumbers);
$(page).addClass('actual').appendTo(container);
} else if (paging.total_pages <= 2) {
Array.from(Array(paging.total_pages + 1)).forEach((_, i) => {
const page = commentsPaginItems.replace(/%d/g, i + 1);
$(page).appendTo(container);
});
$(`#comments_page_${paging.page + 1}`).addClass('actual');
} else {
const pageOne = commentsPaginItems.replace(/%d/g, 1);
const pageLast = commentsPaginItems.replace(/%d/g, paging.total_pages + 1);
const pageCurrent = commentsPaginItemsCurrent.replace(/%d/g, paging.page + 1);
switch (paging.page) {
case 0:
container.append([
pageCurrent,
commentsPaginElipsis,
pageLast
]);
break;
case paging.total_pages:
container.append([
pageOne,
commentsPaginElipsis,
pageCurrent
]);
break;
default:
container.append([
pageOne,
commentsPaginElipsis,
pageCurrent,
commentsPaginElipsis,
pageLast
]);
break;
}
$('.pagination-arrow').removeClass('unavailable')
.off('click').on('click', function() {
let newPage = commentsParams.page;
if ($(this).hasClass('left')) {
newPage = newPage - 1;
} else {
newPage = newPage + 1;
}
if (newPage == -1 || newPage > commentsState.paging.total_pages) {
return;
}
commentsParams.page = newPage;
getComments(commentsParams);
});
}
$('.comments-paging').off('click').on('click', function() {
const newPage = $(this).attr('data-page') - 1;
commentsParams.page = newPage;
getComments(commentsParams);
});
}
function commentsDisplayFilters(filters) {
if (updateAuthorId) {
commentsDisplayAuthors(filters.nb_authors);
}
// reset here to let decide filterAuthor onChange
updateAuthorId = true;
const minDate = filters.started_at.split(' ')[0] ?? '';
const maxDate = filters.ended_at.split(' ')[0] ?? ''
filterDateStart.val(minDate).attr({ 'min': minDate, 'max': maxDate });
filterDateEnd.val(maxDate).attr({ 'max': maxDate, 'min': minDate });
filterDateStart.off('change').on('change', function() {
const min = $(this).val();
if (!min) {
delete commentsParams.f_min_date;
} else {
commentsParams.f_min_date = min;
}
filterDateEnd.attr({ 'min': min });
commentsParams.page = 0;
getComments(commentsParams);
});
filterDateEnd.off('change').on('change', function() {
const max = $(this).val();
if (!max) {
delete commentsParams.f_max_date;
} else {
commentsParams.f_max_date = max;
}
filterDateStart.attr({ 'max': max });
commentsParams.page = 0;
getComments(commentsParams);
});
}
function commentsDisplayAuthors(nb_authors) {
filterAuthor.empty();
filterAuthor.append(commentsOptionsFiltersAuthor);
nb_authors.forEach((a) => {
filterAuthor.append(`
<option value="${a.author_id}">${a.author} (${a.nb_authors})</option>
`);
});
filterAuthor.off('change').on('change', function() {
const authorId = $(this).val();
if (!authorId) {
delete commentsParams.author_id;
} else {
commentsParams.author_id = authorId;
}
commentsParams.page = 0;
updateAuthorId = false;
getComments(commentsParams);
});
}
function updateNbComments(nb) {
commentsNb.removeClass('selected-pagination');
$(`#pagination-per-page-${nb}`).addClass('selected-pagination');
commentsParams.per_page = nb;
window.localStorage.setItem('adminCommentsNB', nb);
}
function showModalViewComment(id) {
const comment = commentsState.comments.filter((c) => c.id == id)[0] ?? null;
if (!comment) return;
const item = $(`#${id}`);
modalViewComment.find('.comment-datetime').text(comment.date);
modalViewComment.find('.comment-author').remove();
modalViewComment.find('.comments-modal-infos').prepend(item.find('.comment-author').clone());
modalViewComment.find('.comments-modal-img').attr('src', comment.medium_url);
modalViewComment.find('.comments-modal-img-i').empty()
.append(`
<p class="comments-modal-filename">${comment.file}</p>
<p class="icon-calendar">${comment.image_date_available}</p>
`);
modalViewComment.find('.comments-modal-body').html(comment.content)
modalViewComment.fadeIn();
}
function closeModalViewComment() {
modalViewComment.fadeOut();
}
function validateComment(id) {
$.ajax({
url: 'ws.php?format=json&method=pwg.userComments.validate',
type: 'POST',
dataType: 'json',
data: {
comment_id: id,
pwg_token: pwg_token
},
success: function (res) {
if (res.stat === 'ok') {
$.alert({
...{
title: str_comment_validated,
content: "",
},
...jConfirm_alert_options
});
getComments(commentsParams);
return;
}
$.alert({
...{
title: str_an_error_has,
content: "",
},
...jConfirm_warning_options
});
},
error: function (e) {
console.log(e)
$.alert({
...{
title: str_an_error_has,
content: "",
},
...jConfirm_warning_options
});
}
});
}
function deleteComment(id) {
$.confirm({
title: str_delete.replace("%s", id),
draggable: false,
titleClass: "jconfirmDeleteConfirm",
theme: "modern",
content: "",
animation: "zoom",
boxWidth: '30%',
useBootstrap: false,
type: 'red',
animateFromElement: false,
backgroundDismiss: true,
typeAnimated: false,
buttons: {
confirm: {
text: str_yes_delete_confirmation,
btnClass: 'btn-red',
action: function () {
$.ajax({
url: 'ws.php?format=json&method=pwg.userComments.delete',
type: 'POST',
dataType: 'json',
data: {
comment_id: id,
pwg_token
},
success: function(res) {
if (res.stat === 'ok') {
getComments(commentsParams);
}
},
error: function(e) {
console.log(e)
}
})
}
},
cancel: {
text: str_no_delete_confirmation
}
}
});
}
function commentsUnselectAll() {
$('.comment').removeClass('comment-selected');
$('.comment-select-checkbox')
.removeClass('icon-ok-circled')
.addClass('icon-circle-empty');
commentsSelected = [];
commentsUpdateSelection();
}
function commentsSelectAll(){
$('.comment').addClass('comment-selected');
$('.comment-select-checkbox')
.removeClass('icon-circle-empty')
.addClass('icon-ok-circled');
commentsSelected = [];
$('.comment-selected').each((i, el) => {
const id = $(el).attr('id');
commentsSelected.push(id);
});
commentsUpdateSelection();
}
function commentsInvertSelect() {
$('.comment').toggleClass('comment-selected');
$('.comment-select-checkbox')
.toggleClass('icon-ok-circled')
.toggleClass('icon-circle-empty');
commentsSelected = [];
$('.comment-selected').each((i, el) => {
const id = $(el).attr('id');
commentsSelected.push(id);
});
commentsUpdateSelection();
}
function commentsUpdateSelection() {
if (commentsSelected.length === 0) {
$('#commentsSelection').hide();
$('#commentsNoSelection').show();
$('.comments-selected-remove').off('click');
$('#ValisateSelectionMode').off('click');
$('#DeleteSelectionMode').off('click');
return;
}
commentsSelectedArea.empty();
let count = 0;
commentsSelected.forEach((id) => {
if (count === 5) {
commentsSelectedOthers.text(str_and_others.replace(/%s/g, commentsSelected.length - 5));
return;
}
commentsSelectedOthers.text('');
const item = commentsSelectedList.replace(/%d/g, id);
commentsSelectedArea.append(item);
count++
});
$('.comments-selected-remove').off('click').on('click', function() {
const id = $(this).attr('id').split('_')[1];
if (!id) return;
$(`#${id} .comment-content`).trigger('click');
});
$('#ValisateSelectionMode').off('click').on('click', function() {
validateComment(commentsSelected);
commentsUnselectAll();
});
$('#DeleteSelectionMode').off('click').on('click', function() {
deleteComment(commentsSelected);
commentsUnselectAll();
});
$('#commentsNoSelection').hide();
$('#commentsSelection').show();
}
function commentsClearFilters() {
delete commentsParams.author_id;
delete commentsParams.image_id;
delete commentsParams.search;
delete commentsParams.f_min_date;
delete commentsParams.f_max_date;
getComments(commentsParams);
}
+185 -398
View File
@@ -1,422 +1,209 @@
{combine_script id='jquery.ui.slider' require='jquery.ui' load='header' path='themes/default/js/ui/minified/jquery.ui.slider.min.js'}
{combine_css path="themes/default/js/ui/theme/jquery.ui.slider.css"}
{combine_script id="comments" load="footer" path="admin/themes/default/js/comments.js"}
{combine_script id='common' load='footer' path='admin/themes/default/js/common.js'}
{combine_script id='jquery.confirm' load='footer' require='jquery' path='themes/default/js/plugins/jquery-confirm.min.js'}
{combine_css path="themes/default/js/plugins/jquery-confirm.min.css"}
{footer_script}
jQuery(document).ready(function(){
$("h1").append("<span class='badge-number'>"+{$nb_total}+"</span>");
function highlighComments() {
jQuery(".comment").each(function() {
var parent = jQuery(this).parent('tr');
if (jQuery(this).children("input[type=checkbox]").is(':checked')) {
jQuery(parent).addClass('selectedComment');
}
else {
jQuery(parent).removeClass('selectedComment');
}
});
}
if ("{$filter}" == "pending"){
$("#seeWaiting").prop('checked', true);
}
if ("{$filter}" == "validated"){
$("#seeValidated").prop('checked', true);
}
$("#seeAll").on("change", function(){
if ($("#seeAll").prop('checked') == true){
window.location.replace("{$F_ACTION}&filter=all&status={$displayed_status}&author={$displayed_author}&start_date={$START}&end_date={$END}");
}
});
$("#seeWaiting").on("change", function(){
if ($("#seeWaiting").prop('checked') == true){
window.location.replace("{$F_ACTION}&filter=pending&status={$displayed_status}&author={$displayed_author}&start_date={$START}&end_date={$END}");
}
});
$("#seeValidated").on("change", function(){
if ($("#seeValidated").prop('checked') == true){
window.location.replace("{$F_ACTION}&filter=validated&status={$displayed_status}&author={$displayed_author}&start_date={$START}&end_date={$END}");
}
});
$("#status_filter").on("change", function(){
let location = "{$F_ACTION}&filter={$filter}&status=" + $("#status_filter").find(":selected").val().toString() + "&author={$displayed_author}&start_date={$START}&end_date={$END}";
window.location.replace(location);
});
$("#status_filter").val("{$displayed_status}");
$("#author_filter").on("change", function(){
let location = "{$F_ACTION}&filter={$filter}&status={$displayed_status}&author=" + $("#author_filter").find(":selected").val().toString() + "&start_date={$START}&end_date={$END}";
window.location.replace(location);
});
$("#author_filter").val("{$displayed_author}");
$("#start_unset").on("click", function(){
$("#start_date").val("");
let location = "{$F_ACTION}&filter={$filter}&status={$displayed_status}&author={$displayed_author}&start_date=&end_date={$END}";
window.location.replace(location);
});
$("#start_date").on("focus", function(){
$(this).data('previous', $(this).val());
});
$("#start_date").val("{$START}".replaceAll("_", "-"));
$("#start_date").on("change", function(){
if ($("#end_date").val() != "")
{
var previous = $(this).data('previous');
var current = new Date($(this).val());
var max = new Date($("#end_date").val());
if (current > max){
$(this).val(previous);
$(this).data('previous', $(this).val());
return
}
}
$(this).data('previous', $(this).val());
let location = "{$F_ACTION}&filter={$filter}&status={$displayed_status}&author={$displayed_author}&start_date=" + $(this).val().replaceAll("-", "_") + "&end_date={$END}";
window.location.replace(location);
});
$("#end_unset").on("click", function(){
$("#end_date").val("");
let location = "{$F_ACTION}&filter={$filter}&status={$displayed_status}&author={$displayed_author}&start_date={$START}&end_date=";
window.location.replace(location);
});
$("#end_date").on("focus", function(){
$(this).data('previous', $(this).val());
});
$("#end_date").val("{$END}".replaceAll("_", "-"));
$("#end_date").on("change", function(){
if ($("#start_date").val() != "")
{
var previous = $(this).data('previous');
var current = new Date($(this).val());
var min = new Date($("#start_date").val());
if (current < min){
$(this).val(previous);
$(this).data('previous', $(this).val());
return
}
}
$(this).data('previous', $(this).val());
let location = "{$F_ACTION}&filter={$filter}&status={$displayed_status}&author={$displayed_author}&start_date={$START}&end_date=" + $(this).val().replaceAll("-", "_");
window.location.replace(location);
});
jQuery(".checkComment").click(function(event) {
var checkbox = jQuery(this).children("input[type=checkbox]");
if (event.target.type !== 'checkbox') {
jQuery(checkbox).prop('checked', !jQuery(checkbox).prop('checked'));
}
highlighComments();
});
jQuery("#commentSelectAll").click(function () {
$(".comment-select-checkbox").prop('checked', true);
$(".comment-select-checkbox").trigger("change");
highlighComments();
return false;
});
jQuery("#commentSelectNone").click(function () {
$(".comment-select-checkbox").prop('checked', false);
$(".comment-select-checkbox").trigger("change");
highlighComments();
return false;
});
jQuery("#commentSelectInvert").click(function () {
$(".comment-select-checkbox").each(function() {
jQuery(this).prop('checked', !$(this).prop('checked'));
});
$(".comment-select-checkbox").trigger("change");
highlighComments();
return false;
});
$(".comment-select-checkbox").on("change", function(event) {
if ($(this).prop("checked")){
$(this).removeClass("icon-circle-empty")
$(this).addClass("icon-ok-circled")
}
else {
$(this).removeClass("icon-ok-circled")
$(this).addClass("icon-circle-empty")
}
});
$("#toggleSelectionMode").on("click", function() {
if ($(".comment-select-checkbox").css("visibility") == "visible") {
$(".comment-buttons-container").css("visibility", "visible");
$(".comment-select-checkbox").css("visibility", "hidden");
$(".comment-selection-content").hide();
$(".comment-container").css("margin-inline-end", "0em")
$("#advanced-filter-menu").css("margin-inline", "23px 10px")
$(".comment-select-checkbox").prop('checked', false);
$(".comment-select-checkbox").trigger("change");
highlighComments();
}
else {
$(".comment-select-checkbox").css("visibility", "visible");
$(".comment-buttons-container").css("visibility", "hidden");
$(".comment-selection-content").css("display", "flex")
$(".comment-container").css("margin-inline-end", "5em")
$("#advanced-filter-menu").css("margin-inline", "23px 270px")
}
})
$(".advanced-filter-btn").on("click", function() {
if ($("#advanced-filter-menu").css("display") == "none") {
$("#advanced-filter-menu").css("display", "flex")
$("#advanced-filter-menu").css("margin-bottom", "1em")
$(".commentFilter").css("margin-bottom", "0.2em")
$(".commentFilter .advanced-filter-btn").css("height", "100%")
$(".commentFilter .advanced-filter-btn").css("height", "100%")
}
else {
$("#advanced-filter-menu").css("display", "none")
$("#advanced-filter-menu").css("margin-bottom", "0.2em")
$(".commentFilter").css("margin-bottom", "1em")
$(".commentFilter .advanced-filter-btn").css("height", "20px")
}
})
if ("{$displayed_status}" != "all" || "{$displayed_author}" != "all" || "{$START}" != "" || "{$END}" != ""){
$(".advanced-filter-btn").trigger( "click" );
}
$(".delete-comment, #commentDeleteSelected").on("click", function() {
jQuery(this).parent().parent().children("input[type=checkbox]").prop('checked', true);
$("#pendingComments").trigger("submit")
})
$(".approve-comment, #commentValidateSelected").on("click", function() {
jQuery(this).parent().parent().children("input[type=checkbox]").prop('checked', true);
$("#pendingComments").trigger("submit")
})
$("#commentValidateSelected, #commentDeleteSelected").on("click", function() {
$("#pendingComments").trigger("submit")
})
});
const str_yes_delete_confirmation = "{'Yes, delete'|@translate|@escape:'javascript'}"
const str_no_delete_confirmation = "{"No, I have changed my mind"|@translate|@escape:'javascript'}"
const str_delete = "{'Are you sure you want to delete comment "%s"?'|@translate|@escape:'javascript'}"
const str_no_comments_selected = "{'No comments selected, no actions possible.'|@translate|@escape:'javascript'}"
const pwg_token = "{$PWG_TOKEN}"
const str_an_error_has = "{"An error has occured"|@translate|@escape:'javascript'}"
const str_comment_validated = "{"The comment has been validated."|@translate|@escape:'javascript'}"
const str_and_others = "{"and %s others"|@translate}"
{/footer_script}
<style>
#tabsheet {
margin: 0;
}
</style>
<div class="comments" id="comments">
<div class="comments-filters">
<div class="comments-tabs-filters">
<div class="tab-filters" id="tabFilters">
<input type="radio" name="p-filter" class="filter" data-status="all" id="seeAll" checked="">
<label for="seeAll">{"All"|translate}<span class="filter-badge" id="commentsAll"></span></label>
<div class="commentFilter">
<input type="radio" name="p-filter" class="filter" data-status="validated" id="seeValidated">
<label class="filterLabel" for="seeValidated">{"Validated"|translate}<span class="filter-badge"
id="commentsValidated"></span></label>
<div class="pluginTypeFilter">
<input type="radio" name="p-filter" class="filter" id="seeAll" checked=""><label for="seeAll" href="{$F_ACTION}&amp;filter=all">{'All'|@translate}<span class="filter-badge">{$nb_total}</span></label>
<input type="radio" name="p-filter" class="filter" id="seeValidated"><label class="filterLabel" for="seeValidated" href="{$F_ACTION}&amp;filter=validated">{'Validated'|@translate}<span class="filter-badge">{$nb_validated}</span></label>
<input type="radio" name="p-filter" class="filter" id="seeWaiting"><label class="filterLabel" for="seeWaiting" href="{$F_ACTION}&amp;filter=pending">{'Waiting'|@translate}<span class="filter-badge">{$nb_pending}</span></label>
</div>
<input type="radio" name="p-filter" class="filter" data-status="pending" id="seePending">
<label class="filterLabel" for="seePending">{"Waiting"|translate}<span class="filter-badge"
id="commentsPending"></span></label>
</div>
{if !empty($navbar) }{include file='navigation_bar.tpl'|@get_extent:'navbar'}{/if}
<div class='comments-selection-controller' id="commentsSelectController">
<p>{'Select'|@translate}</p>
<p class="comments-selection-btn" id="selectAll">{'All'|@translate}</p>
<p class="comments-selection-btn" id="selectNone">{'None'|@translate}</p>
<p class="comments-selection-btn" id="selectInvert">{'Invert'|@translate}</p>
</div>
<div class="commentFilter">
<div class="advanced-filter-btn icon-filter">
<span>{'Filters'|@translate}</span>
<span class="filter-counter"></span>
</div>
<div id='search-comment'>
<span class='icon-search search-icon'> </span>
<span class="icon-cancel search-cancel"></span>
<input class='search-input' type='text' placeholder='{'Search'|@translate}'>
</div>
<div class="userActions">
<label class="switch">
<input type="checkbox" id="toggleSelectionMode">
<span class="slider round"></span>
</label>
Mode sélection
</div>
</div>
</div>
<div id="advanced-filter-menu" class="advanced-filter advanced-filter-new-plugin advanced-filter-open" style="display: none; margin-inline: 23px 10px;">
<div class="advanced-filter-container">
<div class="advanced-filter-item advanced-filter-author-status">
<label class="advanced-filter-item-label" for="author-filter">{'Status'|@translate} {currentStatusDisplayed == "all"}</label>
<div class="advanced-filter-item-container">
<select id="status_filter" class="user-action-select advanced-filter-select doubleSelect" name="filter_status">
<option value="all" selected>{'All'|@translate}</option>
<option value="webmaster">{'Webmaster'|@translate}</option>
<option value="admin">{'Administrator'|@translate}</option>
<option value="normal">{'User'|@translate}</option>
<option value="guest">{'Guest'|@translate}</option>
</select>
<div class="comments-advanced-filter">
<div class="advanced-filter-btn icon-filter" id="commentFilters">
<span>{"Filters"|@translate}</span>
</div>
</div>
<div class="advanced-filter-item advanced-filter-author">
<label class="advanced-filter-item-label" for="tag-filter">{'Comment author'|@translate}</label>
<div class="advanced-filter-item-container">
<select id="author_filter" class="user-action-select advanced-filter-select doubleSelect" name="filter_status">
<option value="all" label="" selected>{'All'|@translate}</option>
{if !empty($comments) }
{foreach from=$comments item=comment name=comment}
<option value="{$comment.AUTHOR}">{$comment.AUTHOR}</option>
{/foreach}
{/if}
</select>
<div class="comments-search">
<span class="icon-search comments-search-icon"> </span>
<span class="icon-cancel comments-search-cancel"></span>
<input id="commentSearchInput" type="text" placeholder="{"Search"|translate}">
</div>
</div>
<div class="advanced-filter-item advanced-filter-date">
<label class="advanced-filter-item-label" for="tag-filter">{'Start-Date'|@translate}</label>
<div class="advanced-filter-item-container">
<input id="start_date" type="date" class="hasDatepicker">
<a href="#" class="icon-cancel-circled" id="start_unset"></a>
</div>
</div>
<div class="advanced-filter-item advanced-filter-date">
<label class="advanced-filter-item-label" for="tag-filter">{'End-Date'|@translate}</label>
<div class="advanced-filter-item-container">
<input id="end_date" type="date" class="hasDatepicker">
<a href="#" class="icon-cancel-circled" id="end_unset"></a>
</div>
</div>
<!--
<div class="advanced-filter-item advanced-filter-mentions">
<label class="advanced-filter-item-label" for="tag-filter">{'Mentions'|@translate}</label>
<div class="advanced-filter-item-container">
<select class="user-action-select advanced-filter-select doubleSelect" name="filter_status">
<option value="" label="" selected></option>
</select>
</div>
</div>
-->
<!--<div class="advanced-filter-item advanced-filter-revision-date">
<label class="advanced-filter-item-label" for="revision-date-filter">
{'Date of comment'|@translate}<span class="revision-date">{}</span>
<div class="comments-selection-mode" id="headerSelectMode">
<div class="comments-selection-switch">
<label class="switch">
<input type="checkbox" id="toggleSelectionMode">
<span class="slider round"></span>
</label>
<div class="advanced-filter-item-container">
<div id="revision-date" class="select-bar"></div>
<div class="slider-bar-wrapper">
<div class="slider-bar-container revision-date-filter-slider ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all" aria-disabled="false"><div class="ui-slider-range ui-widget-header ui-corner-all ui-slider-range-min" style="width: 0%;"></div><a class="ui-slider-handle ui-state-default ui-corner-all" href="#" style="left: 0%;"></a></div>
<span>{'Selection mode'|@translate}</span>
</div>
</div>
</div>
<div class="comments-container" id="commentContainer">
<div class="comments-area">
<div class="comments-advanced-filters" id="advancedFilters">
<div class="comments-filters-container">
<div class="advanced-filter-author">
<label class="advanced-filter-item-label" for="filter_author">{"Author"|translate}</label>
<div class="advanced-filter-select-container advanced-filter-item-container">
<select class="advanced-filter-select" id="filter_author">
<option value="" selected="">--</option>
</select>
</div>
</div>
<div class="advanced-filter-date-start">
<label class="advanced-filter-item-label" for="filter_date_start">{'Start-Date'|translate}</label>
<div class="">
<input id="filter_date_start" type="date" class="advanced-filter-select comments-filters-date" />
</div>
</div>
<div class="advanced-filter-date-end">
<label class="advanced-filter-item-label" for="filter_date_end">{'End-Date'|translate}</label>
<div class="">
<input id="filter_date_end" type="date" class="advanced-filter-select comments-filters-date" />
</div>
</div>
</div>
</div>-->
</div>
</div>
{if !empty($comments) }
<form method="post" action="{$F_ACTION}" id="pendingComments" class="comment-form">
<div class="comment-container">
{foreach from=$comments item=comment name=comment}
{if $displayed_status == "all" or $displayed_status == $comment.AUTHOR_STATUS}
{if $displayed_author == "all" or $comment.AUTHOR == $displayed_author}
{if $START == "" or (date_timestamp_get(DateTime::createFromFormat("Y-m-d H:i:s", $comment.NUMERICAL_DATE))) >= (date_timestamp_get(DateTime::createFromFormat("Y_m_d", $START)))}
{if $END == "" or (date_timestamp_get(DateTime::createFromFormat("Y-m-d H:i:s", $comment.NUMERICAL_DATE))) <= (date_timestamp_get(DateTime::createFromFormat("Y_m_d", $END)))}
<div valign="top" class={if $comment.IS_PENDING}"comment-box comment-box-validated"{else}"comment-box"{/if}>
<a class="illustration" href="{$comment.U_PICTURE}"><img src="{$comment.TN_SRC}"></a>
<div class="comment">
<input type="checkbox" name="comments[]" value="{$comment.ID}" class="comment-select-checkbox icon-circle-empty">
<blockquote class="comment_content"> " {$comment.CONTENT} "</blockquote>
<strong>
{if $comment.AUTHOR_STATUS == "webmaster"}
<span id="badge-user" class="badge-main-user icon-king"></span>
{elseif $comment.AUTHOR_STATUS == "admin"}
<span id="badge-user" class="badge-admin icon-star"></span>
{elseif $comment.AUTHOR_STATUS == "normal"}
<span id="badge-user" class="badge-user-1 icon-user"></span>
{elseif $comment.AUTHOR_STATUS == "guest"}
<span id="badge-user" class="badge-guest icon-user-secret"></span>
{/if}
{$comment.AUTHOR}
</strong>
<p> <span class="icon-calendar"></span> {$comment.DATE}</p>
<div class="comment-buttons-container">
{if $comment.IS_PENDING}
<button class="approve-comment" name="validate" value="{'Validate'|@translate}"><i class="icon-ok"></i> {'Validate'|@translate}</button>
{/if}
<button class="delete-comment" name="reject" value="{'Reject'|@translate}"><i class="icon-trash-1"></i> {'Delete'|@translate}</button>
</div>
</div>
</div>
{/if}
{/if}
{/if}
{/if}
{/foreach}
</div>
<div class="comment-selection-content">
<span class="checkActions">
<span class="badge-guest icon-check"></span> {'Select:'|@translate} <span class="badge-grey"> {$nb_total} </span>
</span>
<a href="#" id="commentSelectAll" class="selectButton">{'All'|@translate}</a>
<a href="#" id="commentSelectInvert" class="selectButton">{'Invert'|@translate}</a>
<p class="checkActions">
<span class="badge-red icon-cog"></span> {'Action:'|@translate}
</p>
<button id="commentValidateSelected" name="validate" value="{'Validate'|@translate}" class="selectButton2 icon-ok">{'Validate'|@translate}</a>
<button id="commentDeleteSelected" name="reject" value="{'Reject'|@translate}" class="selectButton2 icon-trash-1">{'Delete'|@translate}</a>
<div class="savebar-footer">
<div class="savebar-footer-start">
</div>
<div class="savebar-footer-end">
{if isset($save_success)}
<div class="savebar-footer-block">
<div class="badge info-message">
<i class="icon-ok"></i>{$save_success}
<div class="comments-reset-filters">
<p class="icon-ccw" id="commentsResetFilters"> {"Clear"|translate}
<p>
</div>
</div>
{/if}
{if isset($save_error)}
<div class="savebar-footer-block">
<div class="badge info-error">
<i class="icon-cancel-circled"></i>{$save_error}
<div class="comments-list" id="commentsList"></div>
<div class="user-pagination">
<div class="pagination-per-page" id="commentsNb">
<span class="thumbnailsActionsShow" style="font-weight: bold;">{"Display"|translate}</span>
<a id="pagination-per-page-5" class="selected-pagination">5</a>
<a id="pagination-per-page-10">10</a>
<a id="pagination-per-page-25">25</a>
<a id="pagination-per-page-50">50</a>
</div>
<div class="pagination-container">
<div class="pagination-arrow left unavailable">
<span class="icon-left-open"></span>
</div>
<div class="pagination-item-container">
{* <a data-page="1" class="actual">1</a> *}
</div>
<div class="user-update-spinner icon-spin6 animate-spin" style="display: none;"></div>
<div class="pagination-arrow rigth unavailable">
<span class="icon-left-open"></span>
</div>
</div>
</div>
{/if}
{if isset($save_warning)}
<div class="savebar-footer-block">
<div class="badge info-warning">
<i class="icon-attention"></i>{$save_warning}
</div>
</div>
{/if}
<div class="comments-selection" id="contentSelectMode">
<p class="comments-no-selection" id="commentsNoSelection">{"No comments selected, no actions possible."|translate}
</p>
<div class="comments-selections" id="commentsSelection">
<p>{'Your selection'|@translate}</p>
<div class="comments-selected" id="commentsSelected">
</div>
<div class="comments-and-others" id="commentsSelectedOthers">
</div>
<button id="ValisateSelectionMode" class="icon-ok">{'Validate'|@translate}</button>
<button id="DeleteSelectionMode" class="icon-trash-1">{'Delete'|@translate}</button>
</div>
</div>
</div>
</div>
</form>
{/if}
<div class="bg-modal" id="modalViewComment">
<div class="modal-content comments-modal">
<a class="icon-cancel close-modal" id="closeModalViewComment"></a>
<div class="comments-modal-container">
<div class="comments-modal-header">
<div class="comments-modal-infos">
<div class="comment-date">
<i class="icon-calendar"></i>
<p class="comment-datetime"></p>
</div>
</div>
<div class="comments-modal-img-info">
<div class="comments-modal-img-i">
</div>
<img class="comments-modal-img" src="" />
</div>
</div>
<div class="comments-modal-body">
</div>
<div class="comments-modal-footer">
</div>
</div>
</div>
</div>
<div class="comment-template">
<div class="comment-container">
<a class="comment-link" href=""><img class="comment-img" src="" /></a>
<div class="comment-content">
<div>
<div class="comment-msgs">
<p class="comment-msg"></p>
<input type="checkbox" name="comment-selected" value="" class="comment-select-checkbox icon-circle-empty">
</div>
<div class="comment-author">
<i class="comment-author-icon"></i>
<p class="comment-author-name"></p>
</div>
<div class="comment-date">
<i class="icon-calendar"></i>
<p class="comment-datetime"></p>
</div>
</div>
<div class="comment-footer">
<p class="comment-hash"></p>
<div class="comment-buttons">
<button class="comment-validate" type="button"><i class="icon-ok"></i> {"Validate"|translate}</button>
<button class="comment-delete" type="button"><i class="icon-trash-1"></i> {"Delete"|translate}</button>
</div>
</div>
</div>
</div>
</div>
+425 -313
View File
@@ -11,22 +11,6 @@
ul.categoryActions { margin: 0 2px; width: auto; list-style-position:outside;
padding: 0; text-indent: 0; list-style: none; text-align: center; }
.content div.titrePage { padding: 0 0 3px; }
.content div.comment { margin: 0 0 0.5em 0; padding: 0;
overflow: hidden; width: 100%; /* don't ask why. It's a very usefull trick */ }
.content DIV.comment A.illustration {
display: block;
float: left;
margin: 0.5em 30px 0 0.5em;
}
.content div.comment p.commentHeader {
text-align: right; margin: 0.5em 0.5em 0 0; }
.content div.comment ul.actions { text-align: center; margin: 0.2em; }
.content div.comment blockquote {
margin-right: 0.5em; overflow: visible; /*avoid a very strange margin behaviour (all browsers) */ }
.comment .pendingFlag {font-style:italic;color:red;margin-left: 0.5em;}
/* not used but should be */
#thePopuphelpPage .content { margin: 1em; }
@@ -546,265 +530,6 @@ LI.menuLi {
transform: translate(calc(-50% - 4px), -50%);
}
.comment-container{
display: flex;
flex-flow: row wrap;
align-items: center;
gap: 1.5em;
}
.commentFilter{
margin-bottom: 1em;
padding-inline: 1.5em;
display: flex;
flex-direction: row;
}
.commentFilter .commentFilter {
margin-inline-start: auto;
gap: 1em;
}
.commentFilter .advanced-filter-btn{
height: 20px;
padding: 10px 10px 5px 10px;
margin: 4px;
position: relative;
left: 3.17em;
}
.advanced-filter-date{
display: flex;
flex-direction: column;
}
.advanced-filter-date div {
flex: 1;
}
.advanced-filter-date div input{
height: 100%;
width: 74%;
border-color: #D4D4D4;
padding-inline: 1em;
}
.commentFilter .userActions{
align-self: center;
z-index: 99;
}
.commentFilter .pluginTypeFilter{
transform: none;
position: unset;
margin: 4px;
}
.commentFilter #search-comment{
padding-inline-end: 4em;
}
#search-comment .search-icon{
position: relative;
left: 37px;
top: 2px;
}
.comment-selection-content{
background-color: rgb(250, 250, 250);
border-left: 1px solid rgb(230, 230, 230);
position: absolute;
right: 0px;
width: 223px;
min-height: calc(87% - 171px);
top: 169.5px;
z-index: 10;
padding: 7em 1em 0em 1em;
display: none;
flex-direction: column;
}
.selectButton {
text-align: center;
background-color: #f0f0f0;
padding: 10px;
color: #777;
font-weight: bold;
margin: 4px;
border-radius: 5px;
}
.selectButton:hover {
background-color: #ddd;
color: #3A3A3A;
text-decoration: none !important;
}
.selectButton2 {
text-align: center;
padding: 10px;
color: #3C3C3C;
font-weight: bold;
margin: 4px;
border: solid;
border-width: 1px;
border-color: #E7E7E7;
}
.selectButton2:hover {
background-color: #ddd;
color: #000000;
text-decoration: none !important;
}
.comment-form{
display : flex;
}
.comment-box-validated, .comment-box-validated:focus{
border-color: #FFC17E !important;
}
.comment-box, .comment-box:focus{
background-color: #FAFAFA;
display: flex;
flex-direction: row;
align-items: center;
box-shadow: rgba(0, 0, 0, 0.14) 0px 2px 5px;
border-radius: 4px;
border-left: solid;
border-color: #999999;
border-width: 6px;
width: 29.8em;
height: 11.7em;
padding: 0em 1em 0em 0em;
}
.comment-box a img{
object-fit: cover;
height: 11.7em;
width: 11.7em;
margin-top: 0.3em;
margin-right: 3%;
}
.comment-box .comment{
display: flex;
flex-direction: column;
height: 100%;
color: #3C3C3C;
font-weight: 600;
}
.comment-box .comment blockquote{
align-self: flex-start;
font-style: italic;
margin : -1em 2% 0% 0%;
align-self: flex-start;
min-height: 0em;
}
.comment-box .comment strong, .comment-box .comment p{
align-self: flex-end;
text-align: right;
margin: 0% 2% 0% 0%;
}
.badge-grey{
padding-inline : 5px;
color: #898989;
background-color: #DBDBDB;
border-radius: 20px;
}
.badge-red{
color: #FF5252;
background-color: #FFCFCF;
border-radius: 20px;
}
.badge-guest{
color: #2883C3;
background-color: #CFEBFF;
border-radius: 20px;
}
.badge-user{
color: #FFA646;
background-color: #FFE9CF;
border-radius: 20px;
}
.badge-admin{
color: #896AF3;
background-color: #E0DAF4;
border-radius: 20px;
}
.badge-main-user{
color: #896AF3;
background-color: #E0DAF4;
border-radius: 20px;
}
.comment-select-checkbox, .comment-select-checkbox:focus{
appearance: none;
visibility: hidden;
outline: none;
position: relative;
top: 5px;
right: -85%;
width: 7%;
height: 10%;
color: #FFA646;
font-size: 2em;
background-color: #FAFAFA;
}
.comment div {
text-align: end;
min-height: 18%;
min-width: 100%;
margin-top: auto;
margin-bottom: 0.8em;
}
.comment-buttons-container{
visibility: visible;
}
.delete-comment{
border-width: 0px;
border-radius: 6px;
background-color: #EEEEEE;
color: #3C3C3C;
height: 100%;
font-weight: bold;
font-size: 12px;
}
.delete-comment:hover{
cursor: pointer;
text-decoration: none;
}
.approve-comment{
border-width: 0px;
border-radius: 6px;
background-color: #FFC17E;
color : #3C3C3C;
height: 100%;
font-size: 12px;
font-weight: bold;
margin-right: 3%;
}
.approve-comment:hover{
cursor: pointer;
text-decoration: none;
}
.cat-modify-content {
display: grid;
grid-template-rows: 70px 380px;
@@ -1070,7 +795,7 @@ LI.menuLi {
/* Search bar */
.search-input{
padding: 10px 10px 6px 10px;
padding: 10px;
box-shadow: 0px 2px #00000024;
border: none;
background-color: #fafafa !important;
@@ -2828,10 +2553,6 @@ div.jGrowl div.jGrowl-notification{
margin-left: 5px;
}
.advanced-filter-item{
text-align: left;
}
.advanced-filter-revision-date .advanced-filter-item-label {
display: inline !important;
@@ -3201,10 +2922,16 @@ div.jGrowl div.jGrowl-notification{
padding: 13px;
}
.tab-filters .filter,
.pluginTypeFilter .filter {
display: none;
}
.tab-filters {
display: flex;
align-items: center;
}
.pluginTypeFilter {
display: flex;
flex-direction: row;
@@ -3217,6 +2944,7 @@ div.jGrowl div.jGrowl-notification{
transform: translateY(13px);
}
.tab-filters label,
.pluginTypeFilter label {
display: flex;
flex-direction: row;
@@ -3233,6 +2961,7 @@ div.jGrowl div.jGrowl-notification{
font-weight: 600;
}
.tab-filters label .filter-badge,
.pluginTypeFilter label .filter-badge {
font-weight: normal;
border-radius: 20px;
@@ -3241,17 +2970,20 @@ div.jGrowl div.jGrowl-notification{
margin-left: 10px;
}
.tab-filters input:checked + label,
.pluginTypeFilter input:checked + label{
background: #ffa500;
color: white;
box-shadow: 0 2px #d18800;
}
.tab-filters input:checked + label .filter-badge,
.pluginTypeFilter input:checked + label .filter-badge {
background-color: #d18800;
color: #ffe5b6;
}
.tab-filters input + label .filter-badge,
.pluginTypeFilter input + label .filter-badge {
background-color: #dbdbdb;
color: #8c8c8c;
@@ -4448,7 +4180,8 @@ a#showPermissions:hover {text-decoration: none;}
cursor: pointer;
}
.tag-header .selection-controller {
.tag-header .selection-controller ,
.comments-selection-controller {
display: none;
align-items: baseline;
height: 38px;
@@ -4456,7 +4189,8 @@ a#showPermissions:hover {text-decoration: none;}
font-weight: bold;
}
.tag-header .selection-controller.show {
.tag-header .selection-controller.show,
.comments-selection-controller.show {
display: flex;
}
@@ -4465,7 +4199,8 @@ a#showPermissions:hover {text-decoration: none;}
color: #555;
}
.tag-header .selection-controller a {
.tag-header .selection-controller a,
.comments-selection-controller .comments-selection-btn {
margin: 0;
background-color: #f0f0f0;
padding: 10px;
@@ -4475,7 +4210,8 @@ a#showPermissions:hover {text-decoration: none;}
border-radius: 5px;
}
.tag-header .selection-controller a:hover {
.tag-header .selection-controller a:hover,
.comments-selection-controller .comments-selection-btn:hover {
background-color: #ddd;
color: #3A3A3A;
text-decoration: none;
@@ -4701,7 +4437,8 @@ a#showPermissions:hover {text-decoration: none;}
text-align: start;
}
.selection-mode-tag .selection-other-tags {
.selection-mode-tag .selection-other-tags,
.comments-and-others {
color: #ffa646;
font-weight: bold;
font-size: 15px;
@@ -5103,17 +4840,406 @@ a#showPermissions:hover {text-decoration: none;}
background-color: #ffd7ad;
}
/* Pending Comments */
#pendingComments {
padding:0 5px 0 10px;
/* Comments */
.comments {
display: grid;
grid-template-rows: auto 1fr;
min-height: calc(100svh - 169px);
padding-left: 20px;
}
#pendingComments table {
width:100%;
.comments p {
margin: 0;
}
#pendingComments .bottomButtons {
text-align:left;
.comments-selection,
.comment-validate,
.comments-selections,
.comment-template {
display: none;
}
.comments-selection-mode,
.comments-selection {
border-left: 1px solid transparent;
}
.comments-selection {
padding-top: 20px;
}
.comments-container.active {
display: grid;
grid-template-columns: 1fr 250px;
}
.comments-container.active .comment-content:hover {
background-color: #FFD9A7;
}
.comment.comment-selected .comment-content {
background-color: #FFD9A7;
}
.comments-container {
/* display: flex; */
width: 100%;
}
.comments-filters {
display: grid;
grid-template-columns: 1fr 250px;
}
.comments-filters {
align-items: center;
}
.comments-selection-mode {
height: 100%;
align-content: center;
text-align: start;
padding-left: 20px;
}
.comments-selection-switch {
margin-top: 20px;
}
.comments-search-cancel {
display: none;
}
.comments-advanced-filter,
.comments-tabs-filters,
.comments-search {
display: flex;
align-items: center;
}
.comments-advanced-filter {
gap: 10px;
}
.comments-tabs-filters {
padding: 20px 20px 0 0;
justify-content: space-between;
}
.comments-selection-btn {
cursor: pointer;
}
.comments-search {
height: 36px;
padding: 0 5px;
box-shadow: 0px 2px #00000024;
border: none;
background-color: #fafafa !important;
width: 200px;
}
.comments-search:hover {
background-color: #f0f0f0 !important
}
.comments-search-icon,
.comments-search-cancel {
font-size: 18px;
}
.comments-search-icon::before,
.comments-search-cancel::before {
margin-left: 0;
}
.comments-search input {
all: unset;
background-color: transparent !important;
width: 100%;
height: 100%;
line-height: 18px;
text-align: start;
}
.advanced-filter-dates-max .advanced-filter-select-container::before,
.advanced-filter-dates-min .advanced-filter-select-container::before {
content: "";
}
.advanced-filter-dates-max .advanced-filter-select,
.advanced-filter-dates-min .advanced-filter-select {
padding: 0 10px;
height: 32px;
}
.comments-advanced-filters .advanced-filter-select {
min-width: 150px;
-webkit-appearance: none;
appearance: none;
}
.comments-advanced-filters {
display: none;
background-color: #F3F3F3;
margin: 10px 20px 0 0;
position: relative;
z-index: 99;
}
.comments-filters-container {
display: flex;
align-items: center;
padding: 10px;
gap: 20px;
}
.comments-filters-date {
height: 33px !important;
padding: 0 5px !important;
}
.comments-list {
display: flex;
flex-wrap: wrap;
gap: 20px;
padding-top: 20px;
transition: flex-wrap 0.5s ease;
}
.comment-container {
background-color: #FAFAFA;
display: flex;
flex-direction: row;
align-items: stretch;
box-shadow: rgba(0, 0, 0, 0.14) 0px 2px 5px;
border-radius: 4px;
border-left: 6px solid #FFC17E;
/* width: 29.8em;
height: 11.7em; */
height: 150px;
width: 390px;
overflow: hidden;
}
.comment-validated {
border-left: 6px solid #999999 !important;
}
.comment-content {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 10px;
cursor: pointer;
}
.comment-buttons {
display: flex;
gap: 8px;
justify-content: flex-end;
}
.comment-footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.comment-hash {
color: #7a7a7a89;
}
.comment-msgs {
display: flex;
justify-content: space-between;
gap: 5px;
}
.comment-msg {
font-style: italic;
text-align: start;
padding-bottom: 5px;
font-size: 14px;
}
.comment-select-checkbox,
.comment-select-checkbox:focus {
display: none;
appearance: none;
outline: none;
position: relative;
right: 10px;
bottom: 8px;
width: 7%;
height: 10%;
color: #FFA646;
font-size: 2em;
background-color: #FAFAFA;
}
.comment-img {
height: 150px;
width: 150px;
object-fit: cover;
}
.comment-author,
.comment-date {
display: flex;
align-items: center;
gap: 5px;
font-weight: 600;
color: #3C3C3C;
justify-content: end;
font-size: 12px;
}
.comment-author-icon {
padding: 0px;
height: 16px;
width: 16px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
text-align: center;
font-size: 10px;
}
.comment-author-icon::before {
width: 12px;
height: 16px;
place-content: center;
}
.comment-buttons button {
border: 0;
border-radius: 6px;
padding: 5px 10px;
font-weight: bold;
font-size: 12px;
cursor: pointer;
}
.comment-validate {
background-color: #FFC17E;
color: #3C3C3C;
}
.comment-validate:hover {
background-color: #ff7700;
color: #493C21;
}
.comment-delete {
background-color: #EEEEEE;
color: #3C3C3C;
}
.comment-delete:hover {
background-color: #E3E3E3;
}
.comments .user-pagination {
padding: 20px 20px 0 0;
}
.comments-selected {
margin: 20px 30px;
}
.comments-no-selection {
margin: 0 30px !important;
}
.comments-selected-item {
display: flex;
align-items: center;
font-size: 16px;
gap: 5px;
}
.comment-paging-current {
color: #ffa646;
}
.comments-reset-filters {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
}
.comments-reset-filters:hover {
color: #232323;
}
.comments-modal {
width: 700px !important;
}
.comments-modal p {
margin: 0;
}
.comments-modal-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.comments-modal-infos {
display: flex;
flex-direction: column;
gap: 5px;
align-items: start;
}
.comments-modal-img-info {
display: flex;
align-items: start;
gap: 5px;
}
.comments-modal-img-i {
display: flex;
flex-direction: column;
gap: 5px;
align-items: self-end;
}
.comments-modal .comment-author {
justify-content: start;
font-size: 18px;
flex-direction: row-reverse;
font-weight: bold;
}
.comments-modal .comment-author-icon {
font-size: 16px;
height: 24px;
width: 24px;
}
.comments-modal .comment-author-icon::before {
width: 16px;
height: 20px;
}
.comments-modal-img {
width: 100px;
height: 100px;
object-fit: cover;
border-radius: 2px;
}
.comments-modal-body {
width: 100%;
max-height: 200px;
overflow-y: auto;
margin: 15px 0;
}
.bottomButtons.syncBtn {
@@ -5121,7 +5247,7 @@ a#showPermissions:hover {text-decoration: none;}
margin-left: 25px;
}
/* Category Ordering */
FORM#categoryOrdering p.albumTitle {margin:0; margin-left: 5px; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; margin-bottom: 4px;}
FORM#categoryOrdering p.albumTitle a {font-size: 14px; font-weight: 600;}
FORM#categoryOrdering p.albumTitle i {display: none;}
@@ -5859,7 +5985,8 @@ input:checked + .slider.small:before, input:checked + .slider.small::after {
white-space: nowrap;
}
#selection-mode-block button{
#selection-mode-block button,
#commentsSelection button {
display:block;
margin:20px auto;
font-size: 12px;
@@ -5869,7 +5996,8 @@ input:checked + .slider.small:before, input:checked + .slider.small::after {
width: 180px;
}
#selection-mode-block button:hover{
#selection-mode-block button:hover,
#commentsSelection button:hover {
cursor: pointer;
}
@@ -6836,23 +6964,6 @@ fieldset#environment legend i[class*="icon-"] {
color:#493C21;
}
.buttonSecondary{
font-size:12px;
border:none;
padding:13px 20px;
margin-left:0; font-weight: bold; transition: all 125ms ease-out;
color:#3C3C3C;
background-color:#ECECEC;
}
.buttonSecondary:hover{
cursor: pointer;
background-color: #FFA646;
text-decoration: none;
color:#3C3C3C;
}
#cboxLoadedContent input[type="submit"] {margin-bottom: 20px; float: none;}
#permissions, #uploadForm fieldset {border: 0;}
@@ -6875,7 +6986,7 @@ fieldset#environment legend i[class*="icon-"] {
.icon-plus.cboxElement:hover {box-shadow: 0 2px 4px rgba(0, 0, 0, 0.16);}
#albumSelection {margin-right: 20px;}
.selectize-control.single .selectize-input {border-radius: 0; font-weight: bold;font-size: 12px;}
.buttonLike, .buttonSecondary {padding: 8px 10px; margin-left: 5px;}
.buttonLike {padding: 8px 10px; margin-left: 5px;}
.changeUsername .buttonLike {padding: 1px 10px;}
.changePassword .buttonLike {padding: 1px 10px;}
.selectFilesButtonBlock {display: flex; margin-top: 10px;}
@@ -8063,6 +8174,7 @@ color:#FF7B00;
font-size: 30px;
}
.modal-content,
.new-album-modal-content {
display: flex;
flex-direction: column;
+70 -63
View File
@@ -727,7 +727,8 @@ input:focus + .slider {
box-shadow: 0 0 1px #FFC27F;
}
#selection-mode-block{
#selection-mode-block,
.selection-mode {
background-color: #232323;
border-left:1px solid #1a1a1a;
}
@@ -762,13 +763,15 @@ input:focus + .slider {
color:#c0c0c0;
}
#selection-mode-block button{
#selection-mode-block button,
#commentsSelection button {
border: 1px solid #e7e7e7;
color:#c0c0c0;
}
#selection-mode-block button:hover{
#selection-mode-block button:hover,
#commentsSelection button:hover {
background-color: #ffa744;
border: 1px solid #ffa744;
color:#3c3c3c;
@@ -1301,7 +1304,8 @@ background:#6C2D2D!important;
/* Tag Manager */
.tag-box,
.tag-header .selection-controller a{
.tag-header .selection-controller a,
.comments-selection-controller .comments-selection-btn {
background-color: #333 !important;
}
@@ -1494,6 +1498,7 @@ background:#6C2D2D!important;
transform: translateY(13px);
}
.tab-filters label,
.pluginTypeFilter label {
display: flex;
flex-direction: row;
@@ -1509,25 +1514,30 @@ background:#6C2D2D!important;
box-shadow: 0px 2px #00000066;
}
.tab-filters label:hover,
.pluginTypeFilter label:hover{
background: #1B1B1B;
}
.tab-filters input:checked + label,
.pluginTypeFilter input:checked + label{
background: #ffa646;
color: #444444;
box-shadow: 0 2px #925f00;
}
.tab-filters input:checked:hover + label,
.pluginTypeFilter input:checked:hover + label{
background: #ffc17e;
}
.tab-filters input:checked + label .filter-badge,
.pluginTypeFilter input:checked + label .filter-badge {
background-color: #d18800;
color: #444;
}
.tab-filters input + label .filter-badge,
.pluginTypeFilter input + label .filter-badge {
background-color: #3f3f3f;
color: #bababa;
@@ -2275,7 +2285,46 @@ ul.jqtree-tree li.jqtree-ghost span.jqtree-line {
opacity:60%!important;
}
.comment-container {
background-color: #333;
border-color: #ffa646;
}
.comment-validated {
border-color: #232323 !important;
}
.comment-author,
.comment-date {
color: #aaa;
}
.comment-validate {
background-color: #ffa646;
}
.comment-delete {
background-color: #232323;
}
.comment-delete:hover {
background-color: #111;
}
.comments-advanced-filters {
background-color: #333;
}
.comment.comment-selected .comment-content {
background-color: #1B1B1B;
}
.comments-container.active .comment-content:hover {
background-color: #1B1B1B;
}
/* Cat modify description modal */
.modal-content,
.desc-modal-content,
.new-album-modal-content {
background-color: #444;
@@ -2394,64 +2443,6 @@ ul.jqtree-tree li.jqtree-ghost span.jqtree-line {
background-color:#444;
}
.comment-box, .comment-box:focus{
background-color: #333;
color: #777;
border-color: #777;
}
.comment-box .comment{
color : #777;
}
.comment-selection-content{
background-color: rgb(51, 51, 51);
border-left: 1px solid #3A3A3A;
}
.badge-grey{
background-color: rgb(63, 63, 63);
color: rgb(186, 186, 186);
}
.selectButton{
background-color: rgb(85, 85, 85);
color: rgb(193, 193, 193);
}
.selectButton2{
border-color: rgb(85, 85, 85);
color: #C1C1C1;
}
.delete-comment{
background-color: rgb(85, 85, 85);
color: rgb(193, 193, 193);
}
.comment-select-checkbox, .comment-select-checkbox:focus{
background-color: #333;
}
.commentFilterSelected, .commentFilterSelected:hover {
color: #FFFFFF;
background-color: #FFA500;
border-bottom: solid #D18800;
}
.commentFilterUnselected, .commentFilterUnselected:hover {
color: #F3F3F3;
background-color: #898989;
border-bottom: solid #DBDBDB;
}
.buttonSecondary {
background-color: #2E2E2E;
color: #777777;
}
.buttonSecondary:hover {
background-color: #1B1B1B;
color: #777777;
/* Filters options */
.select-views{
background-color: #444444;
@@ -2480,4 +2471,20 @@ ul.jqtree-tree li.jqtree-ghost span.jqtree-line {
label:has(> .filters-icon-check:disabled){
color:#555;
}
}
.comments-advanced-filter .advanced-filter-btn {
box-shadow: 0px 2px #333;
}
.comments-search {
background-color: #333 !important;
}
.comments-search:hover {
background-color: #222 !important
}
.comments-search input:focus {
outline: none;
}
+243
View File
@@ -0,0 +1,243 @@
<?php
// +-----------------------------------------------------------------------+
// | This file is part of Piwigo. |
// | |
// | For copyright and license information, please view the COPYING.txt |
// | file that was distributed with this source code. |
// +-----------------------------------------------------------------------+
/**
* API method
* Get comments
* @since 16
* @param mixed[] $params
*
*/
function ws_userComments_getList($params, &$service)
{
global $conf;
if (!$conf['activate_comments'])
{
return new PwgError(403, 'Comments are disabled');
}
// accepted status values
$accepted_status = array('all', 'pending', 'validated');
if (!in_array($params['status'], $accepted_status))
{
return new PwgError(401, 'Status must be: all, pending or validated');
}
// accepted values must match pagination options (5,10,25,50)
$items_number = array(5, 10, 25, 50);
if (!in_array($params['per_page'], $items_number))
{
return new PwgError(401, 'Per page must be: 5, 10, 25 or 50');
}
$where_clauses = array('1=1');
if (isset($params['author_id']) and !empty($params['author_id']))
{
$where_clauses['author_id'] = 'author_id = \''. pwg_db_real_escape_string($params['author_id']) .'\'';
}
if (isset($params['image_id']) and !empty($params['image_id']))
{
$where_clauses[] = 'image_id = \''. pwg_db_real_escape_string($params['image_id']) .'\'';
}
if (!empty($params['f_min_date']))
{
$min = date_format(date_create($params['f_min_date']), "Y-m-d 00:00:00");
$where_clauses[] = 'date >= \''. $min .'\'';
}
if (!empty($params['f_max_date']))
{
$max = date_format(date_create($params['f_max_date']), "Y-m-d 23:59:59");
$where_clauses[] = 'date <= \''. $max .'\'';
}
// reset all filters during search
if (!empty($params['search']))
{
$where_clauses = array('1=1');
$where_clauses[] = 'content LIKE "%'. pwg_db_real_escape_string($params['search']) .'%"';
}
// summary
$query = '
SELECT
count(*) as all_comments,
sum(validated = \'true\') as validated,
sum(validated = \'false\') as pending
FROM '.COMMENTS_TABLE.'
WHERE '.implode(' AND ', $where_clauses).'
;';
$summary = pwg_db_fetch_assoc(pwg_query($query));
$total_comments = $summary['all_comments'];
switch($params['status'])
{
case 'pending':
$where_clauses[] = 'validated = \'false\'';
$total_comments = $summary['pending'];
break;
case 'validated':
$where_clauses[] = 'validated = \'true\'';
$total_comments = $summary['validated'];
break;
}
// comments
$query = '
SELECT
c.id,
c.image_id,
c.date,
c.author,
c.author_id,
'.$conf['user_fields']['username'].' AS username,
ui.status,
c.content,
i.path,
i.representative_ext,
i.file,
i.date_available,
validated,
c.anonymous_id
FROM '.COMMENTS_TABLE.' AS c
INNER JOIN '.IMAGES_TABLE.' AS i
ON i.id = c.image_id
LEFT JOIN '.USERS_TABLE.' AS u
ON u.'.$conf['user_fields']['id'].' = c.author_id
LEFT JOIN '.USER_INFOS_TABLE.' AS ui
ON ui.user_id = c.author_id
WHERE '.implode(' AND ', $where_clauses).'
ORDER BY c.date DESC
LIMIT '.$params['per_page'] * $params['page'].', '.$params['per_page'].'
;';
$result = pwg_query($query);
$list = array();
while ($row = pwg_db_fetch_assoc($result))
{
$medium = DerivativeImage::get_one(
IMG_MEDIUM,
array(
'id' => $row['image_id'],
'path' => $row['path'],
'representative_ext' => $row['representative_ext'],
)
)->get_url();
if (empty($row['author_id']))
{
$author_name = $row['author'];
}
else
{
$author_name = stripslashes($row['username']);
}
$list[] = array(
'id' => $row['id'],
'admin_link' => get_root_url().'admin.php?page=photo-'.$row['image_id'],
'medium_url' => $medium,
'file' => $row['file'],
'image_date_available' => format_date($row['date_available'], array('day_name','day','month','year','time')),
'author' => trigger_change('render_comment_author', $author_name),
'author_status' => $conf['webmaster_id'] == $row['author_id'] ? 'main_user' : $row['status'],
'date' => format_date($row['date'], array('day_name','day','month','year','time')),
'content' => trigger_change('render_comment_content', $row['content']),
'raw_content' => $row['content'],
'is_pending' => ('false' == $row['validated']),
);
}
// filters
$query = '
SELECT
MIN(date) AS started_at,
MAX(date) AS ended_at
FROM '.COMMENTS_TABLE.'
WHERE '.implode(' AND ', $where_clauses).'
;';
$dates = pwg_db_fetch_assoc(pwg_query($query));
unset($where_clauses['author_id']);
$query = '
SELECT
author,
author_id,
count(*) as nb_authors
FROM '.COMMENTS_TABLE.'
WHERE '.implode(' AND ', $where_clauses).'
GROUP BY author_id
;';
$nb_authors_in = query2array($query);
return array(
'summary' => $summary,
'comments' => $list,
'filters' => array(
'nb_authors' => $nb_authors_in,
'started_at' => $dates['started_at'],
'ended_at' => $dates['ended_at']
),
'paging' => array(
'page' => $params['page'],
'per_page' => $params['per_page'],
'total_pages' => max(0, ceil($total_comments / $params['per_page']) - 1),
),
);
}
/**
* API method
* Delete comments
* @since 16
* @param mixed[] $params
*
*/
function ws_userComments_delete($params, &$service)
{
include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php');
if (get_pwg_token() != $params['pwg_token'])
{
return new PwgError(403, l10n('Invalid security token'));
}
$params['comment_id'] = array_unique($params['comment_id']);
delete_user_comment($params['comment_id']);
return 'Comment successfully deleted';
}
/**
* API method
* Validate comments
* @since 16
* @param mixed[] $params
*
*/
function ws_userComments_validate($params, &$service)
{
include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php');
if (get_pwg_token() != $params['pwg_token'])
{
return new PwgError(403, l10n('Invalid security token'));
}
$params['comment_id'] = array_unique($params['comment_id']);
validate_user_comment($params['comment_id']);
return 'Comment successfully validated';
}
+3
View File
@@ -1411,5 +1411,8 @@ $lang['Save all photos'] = 'Save all photos';
$lang['Use standard Piwigo template for common pages.'] = 'Use standard Piwigo template for common pages.';
$lang['When enabled, a common template is used for the login, registration and forgotten password pages, regardless of the theme. Some themes might use these templates even if you uncheck this option'] = 'When enabled, a common template is used for the login, registration and forgotten password pages, regardless of the theme. Some themes might use these templates even if you uncheck this option';
$lang['We have found %d duplicate paths. Details provided by plugin Check Uploads'] = 'We have found %d duplicate paths. Details provided by plugin Check Uploads';
$lang['Are you sure you want to delete comment "%s"?'] = 'Are you sure you want to delete comment "%s"?';
$lang['No comments selected, no actions possible.'] = 'No comments selected, no actions possible.';
$lang['The comment has been validated.'] = 'The comment has been validated.';
// Leave this line empty
+3
View File
@@ -1413,4 +1413,7 @@ $lang['Save all photos'] = 'Enregistrer toutes les photos';
$lang['Use standard Piwigo template for common pages.'] = 'Utiliser le modèle standard de Piwigo pour les pages courantes.';
$lang['When enabled, a common template is used for the login, registration and forgotten password pages, regardless of the theme. Some themes might use these templates even if you uncheck this option'] = 'Lorsque cette option est activée, un modèle commun est utilisé pour les pages de connexion, d\'inscription et de mot de passe oublié, quel que soit le thème. Certains thèmes peuvent utiliser ces modèles même si cette option est décochée.';
$lang['We have found %d duplicate paths. Details provided by plugin Check Uploads'] = 'Nous avons trouvé %d chemins anormalement dupliqués. À contrôler avec le plugin Check Uploads.';
$lang['Are you sure you want to delete comment "%s"?'] = 'Êtes-vous sûr de vouloir supprimer le commentaire "%s" ?';
$lang['No comments selected, no actions possible.'] = 'Aucun commentaire sélectionné, aucune action possible.';
$lang['The comment has been validated.'] = 'Le commentaire a été validé.';
// Leave this line empty
+79
View File
@@ -1623,6 +1623,85 @@ enabled_high, registration_date, registration_date_string, registration_date_sin
$ws_functions_root . 'pwg.users.php',
array('admin_only'=>false, 'post_only'=>true)
);
$service->addMethod(
'pwg.userComments.getList',
'ws_userComments_getList',
array(
'status' => array(
'default' => 'all',
'info' => 'must be: all, validated or pending'
),
'search' => array(
'default' => null,
'info' => 'All other parameters are not used during a search.'
),
'author_id' => array(
'flags' => WS_PARAM_OPTIONAL,
'type' => WS_TYPE_ID,
),
'image_id' => array(
'flags' => WS_PARAM_OPTIONAL,
'type' => WS_TYPE_ID,
),
'f_min_date' => array(
'default' => null
),
'f_max_date' => array(
'default' => null
),
'page' => array(
'default' => 0,
'type' => WS_TYPE_INT | WS_TYPE_POSITIVE
),
'per_page' => array(
'default' => $conf['comments_page_nb_comments'],
'type' => WS_TYPE_INT | WS_TYPE_POSITIVE
)
),
'Get comments',
$ws_functions_root . 'pwg.comments.php',
array(
'admin_only' => true,
'post_only' => false
)
);
$service->addMethod(
'pwg.userComments.delete',
'ws_userComments_delete',
array(
'comment_id' => array(
'flags' => WS_PARAM_FORCE_ARRAY,
'type' => WS_TYPE_INT | WS_TYPE_POSITIVE,
),
'pwg_token' => array(),
),
'Delete comments',
$ws_functions_root . 'pwg.comments.php',
array(
'admin_only'=>true,
'post_only'=>true
)
);
$service->addMethod(
'pwg.userComments.validate',
'ws_userComments_validate',
array(
'comment_id' => array(
'flags' => WS_PARAM_FORCE_ARRAY,
'type' => WS_TYPE_INT | WS_TYPE_POSITIVE,
),
'pwg_token' => array(),
),
'Validate comments',
$ws_functions_root . 'pwg.comments.php',
array(
'admin_only'=>true,
'post_only'=>true
)
);
}
?>