diff --git a/admin/comments.php b/admin/comments.php index cb2f4a7d2..133b545de 100644 --- a/admin/comments.php +++ b/admin/comments.php @@ -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')); // +-----------------------------------------------------------------------+ diff --git a/admin/themes/clear/theme.css b/admin/themes/clear/theme.css index ed5b8b726..e7a4f494a 100644 --- a/admin/themes/clear/theme.css +++ b/admin/themes/clear/theme.css @@ -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; } diff --git a/admin/themes/default/js/comments.js b/admin/themes/default/js/comments.js new file mode 100644 index 000000000..f7254c1bb --- /dev/null +++ b/admin/themes/default/js/comments.js @@ -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 = '...'; +const commentsPaginItems = '%d'; +const commentsPaginItemsCurrent = '%d'; +const commentsOptionsFiltersAuthor = ''; +const commentsSelectedList = '
${comment.file}
+${comment.image_date_available}
+ `); + 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); +} \ No newline at end of file diff --git a/admin/themes/default/template/comments.tpl b/admin/themes/default/template/comments.tpl index 8ff26389b..de680e204 100644 --- a/admin/themes/default/template/comments.tpl +++ b/admin/themes/default/template/comments.tpl @@ -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(""+{$nb_total}+""); - - 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} + +{'Select'|@translate}
+{'All'|@translate}
+{'None'|@translate}
+{'Invert'|@translate}
+
#%d