diff --git a/admin/batch_manager.php b/admin/batch_manager.php index 0312876d4..e3e702677 100644 --- a/admin/batch_manager.php +++ b/admin/batch_manager.php @@ -189,6 +189,73 @@ if (isset($_POST['submitFilter'])) } } + if (isset($_POST['filter_filetype_use']) && !empty($_POST['filter_filetype'])) + { + + check_input_parameter('filter_filetype', $_POST, true, '/^[a-z0-9]+$/'); + $_SESSION['bulk_manager_filter']['filetype'] = array_map('trim', $_POST['filter_filetype']); + } + + if (isset($_POST['filter_date_posted_use'])) + { + foreach (array('min_date', 'max_date') as $bound) + { + $field = 'filter_date_posted_'.$bound; + if (!empty($_POST[$field]) and !is_valid_mysql_datetime($_POST[$field])) + { + fatal_error('[Hacking attempt] the input parameter "'.$field.'" is not valid'); + } + } + + $min_date = $_POST['filter_date_posted_min_date']; + $max_date = $_POST['filter_date_posted_max_date']; + + if (!empty($_POST['filter_date_posted_single']) && $_POST['filter_date_posted_single'] == '1') + { + $_SESSION['bulk_manager_filter']['date_posted'] = array( + 'single' => true, + 'min_date' => $min_date, + ); + } + else + { + $_SESSION['bulk_manager_filter']['date_posted'] = array( + 'min_date' => $min_date, + 'max_date' => $max_date, + ); + } + } + + if (isset($_POST['filter_date_created_use'])) + { + foreach (array('min_date', 'max_date') as $bound) + { + $field = 'filter_date_created_'.$bound; + if (!empty($_POST[$field]) and !is_valid_mysql_datetime($_POST[$field])) + { + fatal_error('[Hacking attempt] the input parameter "'.$field.'" is not valid'); + } + } + + $min_date = $_POST['filter_date_created_min_date']; + $max_date = $_POST['filter_date_created_max_date']; + + if (!empty($_POST['filter_date_created_single']) && $_POST['filter_date_created_single'] == '1') + { + $_SESSION['bulk_manager_filter']['date_created'] = array( + 'single' => true, + 'min_date' => $min_date, + ); + } + else + { + $_SESSION['bulk_manager_filter']['date_created'] = array( + 'min_date' => $min_date, + 'max_date' => $max_date, + ); + } + } + if (isset($_POST['filter_search_use'])) { $_SESSION['bulk_manager_filter']['search']['q'] = $_POST['q']; @@ -626,6 +693,104 @@ SELECT id $filter_sets[] = query2array($query, null, 'id'); } +if (isset($_SESSION['bulk_manager_filter']['filetype'])) +{ + $where_clauses = array(); + foreach ($_SESSION['bulk_manager_filter']['filetype'] as $ext) + { + $where_clauses[] = 'path LIKE \'%.'.$ext.'\''; + } + + $query = ' +SELECT id + FROM '.IMAGES_TABLE.' AS i + WHERE ('.implode(' OR ', $where_clauses).') + '.$conf['order_by'].' +;'; + + $filter_sets[] = query2array($query, null, 'id'); +} + +if (isset($_SESSION['bulk_manager_filter']['date_posted'])) +{ + $filter = $_SESSION['bulk_manager_filter']['date_posted']; + $min_date = pwg_db_real_escape_string($filter['min_date'] ?? null); + $max_date = pwg_db_real_escape_string($filter['max_date'] ?? null); + $where_clauses = array(); + + if (!empty($filter['single'])) + { + if (!empty($min_date)) + { + $where_clauses[] = 'date_available >= \''.$min_date.' 00:00:00\''; + $where_clauses[] = 'date_available <= \''.$min_date.' 23:59:59\''; + } + } + else + { + if (!empty($min_date)) + { + $where_clauses[] = 'date_available >= \''.$min_date.' 00:00:00\''; + } + if (!empty($max_date)) + { + $where_clauses[] = 'date_available <= \''.$max_date.' 23:59:59\''; + } + } + + if (!empty($where_clauses)) + { + $query = ' +SELECT id + FROM '.IMAGES_TABLE.' + WHERE '.implode(' AND ', $where_clauses).' + '.$conf['order_by'].' +;'; + + $filter_sets[] = query2array($query, null, 'id'); + } +} + +if (isset($_SESSION['bulk_manager_filter']['date_created'])) +{ + $filter = $_SESSION['bulk_manager_filter']['date_created']; + $min_date = pwg_db_real_escape_string($filter['min_date'] ?? null); + $max_date = pwg_db_real_escape_string($filter['max_date'] ?? null); + $where_clauses = array(); + + if (!empty($filter['single'])) + { + if (!empty($min_date)) + { + $where_clauses[] = 'date_creation >= \''.$min_date.' 00:00:00\''; + $where_clauses[] = 'date_creation <= \''.$min_date.' 23:59:59\''; + } + } + else + { + if (!empty($min_date)) + { + $where_clauses[] = 'date_creation >= \''.$min_date.' 00:00:00\''; + } + if (!empty($max_date)) + { + $where_clauses[] = 'date_creation <= \''.$max_date.' 23:59:59\''; + } + } + + if (!empty($where_clauses)) + { + $query = ' +SELECT id + FROM '.IMAGES_TABLE.' + WHERE '.implode(' AND ', $where_clauses).' + '.$conf['order_by'].' +;'; + + $filter_sets[] = query2array($query, null, 'id'); + } +} + if (isset($_SESSION['bulk_manager_filter']['search']) && strlen($_SESSION['bulk_manager_filter']['search']['q'])) { @@ -841,6 +1006,115 @@ foreach (array_keys($filesize['bounds']) as $type) $template->assign('filesize', $filesize); +// +-----------------------------------------------------------------------+ +// | filetype | +// +-----------------------------------------------------------------------+ + +$filetype = array( + 'all' => array(), + 'selected' => array() +); + +$query = ' +SELECT + LOWER(SUBSTRING_INDEX(path, ".", -1)) AS ext, + COUNT(id) AS counter + FROM '.IMAGES_TABLE.' + WHERE path IS NOT NULL AND path != "" + GROUP BY ext + ORDER BY counter DESC +;'; + +$result = pwg_query($query); +while ($row = pwg_db_fetch_assoc($result)) +{ + $filetype['all'][$row['ext']] = $row['counter']; +} + +if (isset($_SESSION['bulk_manager_filter']['filetype'])) +{ + $filetype['selected'] = $_SESSION['bulk_manager_filter']['filetype']; +} + +$template->assign('filetype', $filetype); + +// +-----------------------------------------------------------------------+ +// | date_posted | +// +-----------------------------------------------------------------------+ + +$date_posted = array( + 'bounds' => array('min_date' => '', 'max_date' => ''), + 'selected' => array('min_date' => '', 'max_date' => '', 'single' => false), +); + +$query = ' +SELECT + MIN(date_available) AS min_date, + MAX(date_available) AS max_date + FROM '.IMAGES_TABLE.' +;'; + +$row = pwg_db_fetch_assoc(pwg_query($query)); + +if ($row) +{ + $date_posted['bounds']['min_date'] = substr($row['min_date'], 0, 10); + $date_posted['bounds']['max_date'] = substr($row['max_date'], 0, 10); +} + +$date_posted['selected']['min_date'] = isset($_SESSION['bulk_manager_filter']['date_posted']['min_date']) + ? $_SESSION['bulk_manager_filter']['date_posted']['min_date'] + : $date_posted['bounds']['min_date']; + +$date_posted['selected']['max_date'] = isset($_SESSION['bulk_manager_filter']['date_posted']['max_date']) + ? $_SESSION['bulk_manager_filter']['date_posted']['max_date'] + : $date_posted['bounds']['max_date']; + +$date_posted['selected']['single'] = isset($_SESSION['bulk_manager_filter']['date_posted']['single']) + ? $_SESSION['bulk_manager_filter']['date_posted']['single'] + : false; + +$template->assign('date_posted', $date_posted); + +// +-----------------------------------------------------------------------+ +// | date_created | +// +-----------------------------------------------------------------------+ + +$date_created = array( + 'bounds' => array('min_date' => '', 'max_date' => ''), + 'selected' => array('min_date' => '', 'max_date' => '', 'single' => false), +); + +$query = ' +SELECT + MIN(date_creation) AS min_date, + MAX(date_creation) AS max_date + FROM '.IMAGES_TABLE.' + WHERE date_creation IS NOT NULL +;'; + +$row = pwg_db_fetch_assoc(pwg_query($query)); + +if ($row) +{ + $date_created['bounds']['min_date'] = substr($row['min_date'], 0, 10); + $date_created['bounds']['max_date'] = substr($row['max_date'], 0, 10); +} + +$date_created['selected']['min_date'] = isset($_SESSION['bulk_manager_filter']['date_created']['min_date']) + ? $_SESSION['bulk_manager_filter']['date_created']['min_date'] + : $date_created['bounds']['min_date']; + +$date_created['selected']['max_date'] = isset($_SESSION['bulk_manager_filter']['date_created']['max_date']) + ? $_SESSION['bulk_manager_filter']['date_created']['max_date'] + : $date_created['bounds']['max_date']; + +$date_created['selected']['single'] = isset($_SESSION['bulk_manager_filter']['date_created']['single']) + ? $_SESSION['bulk_manager_filter']['date_created']['single'] + : false; + +$template->assign('date_created', $date_created); + // +-----------------------------------------------------------------------+ // | open specific mode | // +-----------------------------------------------------------------------+ diff --git a/admin/themes/clear/theme.css b/admin/themes/clear/theme.css index 1613e5cb0..a4a89264c 100644 --- a/admin/themes/clear/theme.css +++ b/admin/themes/clear/theme.css @@ -704,7 +704,7 @@ li.plupload_delete a.remove-format:hover{color: #474747;} .addFilesButtonChanged:hover {background-color: #BBB;} #checkActions a, .deleteDerivButtons a {background-color: #E8E8E8;} -#filterList select, .pictureLevels select, #permitAction select, .sort-by select {background-color: #FFF; color: #4E4E4E; border: 2px solid #7070704f !important; outline: none !important;} +#filterList select, .pictureLevels select, #permitAction select, .sort-by select, #batchManagerGlobal #filterList li#filter_filetype .custom-select-title {background-color: #FFF; color: #4E4E4E; border: 2px solid #7070704f !important; outline: none !important;} #filter_category .selectize-input.items.full.has-options.has-items, #filter_tags .selectize-input.items.not-full.has-options, #filter_tags .selectize-input.items.not-full, #filter_search input, #action_move .selectize-input.items.full.has-options.has-items, #action_dissociate .selectize-input.items.full.has-options.has-items { @@ -715,8 +715,8 @@ li.plupload_delete a.remove-format:hover{color: #474747;} #action_move a:last-child {background: #FFF; border: 1px solid #787777a6; box-shadow: none;} #forbidAction, .selectionEmptyBlock, .noFilter {background-color: #f3f3f3;} #action_title .large, #action_author .large {background-color: #FFF; color: #4E4E4E;} -#filter_dimension .slider-choice, #filter_filesize .slider-choice {background-color: #EEE; color: #777;} -#filter_dimension .slider-choice:hover, #filter_filesize .slider-choice:hover, .dimension-cancel:hover { +#filter_dimension .slider-choice, #filter_filesize .slider-choice, #filter_date_posted .slider-choice, #filter_date_created .slider-choice {background-color: #EEE; color: #777;} +#filter_dimension .slider-choice:hover, #filter_filesize .slider-choice:hover, .dimension-cancel:hover, #filter_date_posted .slider-choice:hover, #filter_date_created .slider-choice:hover, #filter_date_posted .slider-choice.active, #filter_date_created .slider-choice.active { text-decoration: none; background-color: #ffa646 !important; color: initial; } #filterList .ui-slider .ui-slider-range {background: rgba(255,166,70, 0.9); margin-top: -1px; border: 1px solid #ffaf58;} diff --git a/admin/themes/default/js/batchManagerFilter.js b/admin/themes/default/js/batchManagerFilter.js index 8e2bbf6ec..da95aa4e1 100644 --- a/admin/themes/default/js/batchManagerFilter.js +++ b/admin/themes/default/js/batchManagerFilter.js @@ -98,7 +98,93 @@ $(document).ready(function () { } }); + // Filetype filter + $(document).on('click', function(e) { + if (!$(e.target).closest('#filter_filetype .custom-select-dropdown').length) { + $('#filter_filetype .custom-select-dropdown').removeAttr('open'); + } + }); + function updateFiletypeSelectedText() { + const checked = $('#filter_filetype input[name="filter_filetype[]"]:checked'); + const label = $('#filter_filetype .selected-text'); + const defaultPlaceholder = label.data('placeholder'); + + if (checked.length === 0) { + label.text(defaultPlaceholder); + } else { + const selectedTypes = checked.map(function() { + return $(this).closest('label').text().trim().split(' ')[0]; + }).get(); + + label.text(selectedTypes.join(', ')); + } + } + + $('#filter_filetype').on('change', 'input[name="filter_filetype[]"]', function() { + updateFiletypeSelectedText(); + }); + + updateFiletypeSelectedText(); + + // Date posted filter + $('#date_posted_min_date, #date_posted_max_date').on('click', function() { + if (typeof this.showPicker === 'function') { + this.showPicker(); + } + }); + + $('#filter_date_posted').on('click', '.slider-choice', function(e) { + e.preventDefault(); + + const $choice = $(this); + const $parent = $choice.closest('li'); + const isSingle = $choice.data('value') == 1; + + $parent.find('.slider-choice').removeClass('active'); + $choice.addClass('active'); + + $parent.find('#filter_date_posted_single').val(isSingle ? '1' : '0'); + + if (isSingle) { + $parent.find('.date-label-between-posted, .date-label-and-posted, #date_posted_max_date').hide(); + $parent.find('.date-label-single-posted').show(); + $parent.find('#date_posted_max_date').val(''); + } else { + $parent.find('.date-label-single-posted').hide(); + $parent.find('.date-label-between-posted, .date-label-and-posted, #date_posted_max_date').show(); + } + }); + + // Date created filter + $('#date_created_min_date, #date_created_max_date').on('click', function() { + if (typeof this.showPicker === 'function') { + this.showPicker(); + } + }); + + $('#filter_date_created').on('click', '.slider-choice', function(e) { + e.preventDefault(); + + const $choice = $(this); + const $parent = $choice.closest('li'); + const isSingle = $choice.data('value') == 1; + + $parent.find('.slider-choice').removeClass('active'); + $choice.addClass('active'); + + $parent.find('#filter_date_created_single').val(isSingle ? '1' : '0'); + + if (isSingle) { + $parent.find('.date-label-between-created, .date-label-and-created, #date_created_max_date').hide(); + $parent.find('.date-label-single-created').show(); + $parent.find('#date_created_max_date').val(''); + } else { + $parent.find('.date-label-single-created').hide(); + $parent.find('.date-label-between-created, .date-label-and-created, #date_created_max_date').show(); + } + }); + // Filter JS Validation $('.filterBlock select[data-selectize="tags"]').on('change', function() { if ($(this).val()) { @@ -106,6 +192,24 @@ $(document).ready(function () { } }) + $('#date_posted_min_date, #date_posted_max_date').on('change input', function() { + if ($('#date_posted_min_date').val() || $('#date_posted_max_date').val()) { + hide_filters_error(str_select_date); + } + }); + + $('#date_created_min_date, #date_created_max_date').on('change input', function() { + if ($('#date_created_min_date').val() || $('#date_created_max_date').val()) { + hide_filters_error(str_select_date); + } + }); + + $('#filter_filetype').on('change', 'input[name="filter_filetype[]"]', function() { + if ($('#filter_filetype input[name="filter_filetype[]"]:checked').length > 0) { + hide_filters_error(str_select_filetype); + } + }); + $('#applyFilter').on('click', function(e) { if ($('#filter_tags').is(':visible')) { const tags = $('.filterBlock select[data-selectize="tags"]'); @@ -128,6 +232,51 @@ $(document).ready(function () { }); } } + + if ($('#filter_filetype').is(':visible')) { + const checkedFiletypes = $('#filter_filetype input[name="filter_filetype[]"]:checked'); + const isValid = checkedFiletypes.length > 0; + + if (!isValid) { + e.preventDefault(); + show_filters_error(str_select_filetype); + $('#filter_filetype .removeFilter').off('click.apply').on('click.apply', function() { + hide_filters_error(str_select_filetype); + }); + } + } + + if ($('#filter_date_posted').is(':visible')) { + const minDate = $('#date_posted_min_date').val(); + const maxDate = $('#date_posted_max_date').val(); + const isSingle = $('#filter_date_posted_single').val() === '1'; + + const isValid = isSingle ? !!minDate : (!!minDate || !!maxDate); + + if (!isValid) { + e.preventDefault(); + show_filters_error(str_select_date); + $('#filter_date_posted .removeFilter').off('click.apply').on('click.apply', function() { + hide_filters_error(str_select_date); + }); + } + } + + if ($('#filter_date_created').is(':visible')) { + const minDate = $('#date_created_min_date').val(); + const maxDate = $('#date_created_max_date').val(); + const isSingle = $('#filter_date_created_single').val() === '1'; + + const isValid = isSingle ? !!minDate : (!!minDate || !!maxDate); + + if (!isValid) { + e.preventDefault(); + show_filters_error(str_select_date); + $('#filter_date_created .removeFilter').off('click.apply').on('click.apply', function() { + hide_filters_error(str_select_date); + }); + } + } }); $('.help-popin-search').on('click', function() { diff --git a/admin/themes/default/template/include/batch_manager_filter.inc.tpl b/admin/themes/default/template/include/batch_manager_filter.inc.tpl index 65e3892fd..49153db01 100644 --- a/admin/themes/default/template/include/batch_manager_filter.inc.tpl +++ b/admin/themes/default/template/include/batch_manager_filter.inc.tpl @@ -4,6 +4,7 @@ {combine_script id='jquery.ui.slider' require='jquery.ui' load='async' 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='LocalStorageCache' load='footer' path='admin/themes/default/js/LocalStorageCache.js'} +{combine_script id='jquery.ui.datepicker' require='jquery.ui' load='footer' path='themes/default/js/ui/minified/jquery.ui.datepicker.min.js'} {footer_script} @@ -52,6 +53,8 @@ const selected_filter_cat_ids = []; const str_select_album = "{'Select at least one album'|@translate|escape:javascript}"; const str_select_tag = "{'Select at least one tag'|@translate|escape:javascript}"; +const str_select_date = "{'Select at least one date'|@translate|escape:javascript}"; +const str_select_filetype = "{'Select at least one type'|@translate|escape:javascript}"; let errorFilters = ''; {/footer_script} @@ -241,6 +244,114 @@ let errorFilters = ''; + +
{'File type'|translate}
+ [x] + +{'Post date'|@translate}
+ [x] + + + +| + {'Start-Date'|@translate} + | + ++ + | +
| + {'End-Date'|@translate} + | ++ + | + +
{'Creation date'|@translate}
+ [x] + + + +| + {'Start-Date'|@translate} + | + ++ + | +
| + {'End-Date'|@translate} + | ++ + | + +