diff --git a/admin/cat_move.php b/admin/cat_move.php index 019295852..3e134db3a 100644 --- a/admin/cat_move.php +++ b/admin/cat_move.php @@ -19,29 +19,95 @@ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); check_status(ACCESS_ADMINISTRATOR); // +-----------------------------------------------------------------------+ -// | functions | +// | categories auto order | // +-----------------------------------------------------------------------+ +$open_cat = -1; -// +-----------------------------------------------------------------------+ -// | categories movement | -// +-----------------------------------------------------------------------+ +$sort_orders = array( + 'name ASC', + 'name DESC', + 'date_creation DESC', + 'date_creation ASC', + 'date_available DESC', + 'date_available ASC' +); -if (isset($_POST['submit'])) +if (isset($_POST['simpleAutoOrder']) || isset($_POST['recursiveAutoOrder']) ) { - if (count($_POST['selection']) > 0) - { - check_input_parameter('selection', $_POST, true, PATTERN_ID); - check_input_parameter('parent', $_POST, false, PATTERN_ID); - move_categories($_POST['selection'], $_POST['parent']); - } - else + if (!in_array($_POST['order'],$sort_orders)) { - $page['errors'][] = l10n('Select at least one album'); + die('Invalid sort order'); } + + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE id_uppercat '. + (($_POST['id'] === '-1') ? 'IS NULL' : '= '.$_POST['id']).' +;'; + $category_ids = array_from_query($query, 'id'); + + if (isset($_POST['recursiveAutoOrder'])) + { + $category_ids = get_subcat_ids($category_ids); + } + + $categories = array(); + $sort = array(); + + list($order_by_field, $order_by_asc) = explode(' ', $_POST['order']); + + $order_by_date = false; + if (strpos($order_by_field, 'date_') === 0) + { + $order_by_date = true; + + $ref_dates = get_categories_ref_date( + $category_ids, + $order_by_field, + 'ASC' == $order_by_asc ? 'min' : 'max' + ); + } + + $query = ' +SELECT id, name, id_uppercat + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', $category_ids).') +;'; + $result = pwg_query($query); + while ($row = pwg_db_fetch_assoc($result)) + { + if ($order_by_date) + { + $sort[] = $ref_dates[ $row['id'] ]; + } + else + { + $sort[] = remove_accents($row['name']); + } + + $categories[] = array( + 'id' => $row['id'], + 'id_uppercat' => $row['id_uppercat'], + ); + } + + array_multisort( + $sort, + SORT_REGULAR, + 'ASC' == $order_by_asc ? SORT_ASC : SORT_DESC, + $categories + ); + + save_categories_order($categories); + + $open_cat = $_POST['id']; } +$template->assign('open_cat', $open_cat); + // +-----------------------------------------------------------------------+ // | template initialization | // +-----------------------------------------------------------------------+ @@ -65,30 +131,138 @@ include(PHPWG_ROOT_PATH.'admin/include/albums_tab.inc.php'); // | Album display | // +-----------------------------------------------------------------------+ +//Get all albums $query = ' -SELECT id,name,global_rank,status +SELECT id,name,rank,status, uppercats FROM '.CATEGORIES_TABLE.' ;'; $allAlbum = query2array($query); -$sortedAlbums = array(); -foreach ($allAlbum as $album) { - $parents = explode('.',$album['global_rank']); - $the_place = &$sortedAlbums[intval($parents[0])]; - for ($i=1; $i < count($parents); $i++) { - $the_place = &$the_place['children'][intval($parents[$i])]; +//Make an id tree +$associatedTree = array(); + +foreach ($allAlbum as $album) +{ + $parents = explode(',',$album['uppercats']); + $the_place = &$associatedTree[strval($parents[0])]; + for ($i=1; $i < count($parents); $i++) + { + $the_place = &$the_place['children'][strval($parents[$i])]; } - $the_place['name'] = $album['name']; - $the_place['status'] = $album['status']; - $the_place['id'] = $album['id']; + $the_place['cat'] = $album; } -$template->assign('album_data', $sortedAlbums); +//Make an ordered tree +function cmpCat($a, $b) +{ + if ($a['rank'] == $b['rank']) + { + return 0; + } + return ($a['rank'] < $b['rank']) ? -1 : 1; +} + +function assocToOrderedTree($assocT) +{ + $orderedTree = array(); + + foreach($assocT as $cat) + { + $orderedCat = array(); + $orderedCat['rank'] = $cat['cat']['rank']; + $orderedCat['name'] = $cat['cat']['name']; + $orderedCat['status'] = $cat['cat']['status']; + $orderedCat['id'] = $cat['cat']['id']; + if (isset($cat['children'])) + { + $orderedCat['children'] = assocToOrderedTree($cat['children']); + } + array_push($orderedTree, $orderedCat); + } + usort($orderedTree, 'cmpCat'); + return $orderedTree; +} + +$template->assign('album_data', assocToOrderedTree($associatedTree)); $template->assign('PWG_TOKEN', get_pwg_token()); // +-----------------------------------------------------------------------+ // | sending html code | // +-----------------------------------------------------------------------+ $template->assign_var_from_handle('ADMIN_CONTENT', 'cat_move'); + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ +function get_categories_ref_date($ids, $field='date_available', $minmax='max') +{ + // we need to work on the whole tree under each category, even if we don't + // want to sort sub categories + $category_ids = get_subcat_ids($ids); + + // search for the reference date of each album + $query = ' +SELECT + category_id, + '.$minmax.'('.$field.') as ref_date + FROM '.IMAGE_CATEGORY_TABLE.' + JOIN '.IMAGES_TABLE.' ON image_id = id + WHERE category_id IN ('.implode(',', $category_ids).') + GROUP BY category_id +;'; + $ref_dates = query2array($query, 'category_id', 'ref_date'); + + // the iterate on all albums (having a ref_date or not) to find the + // reference_date, with a search on sub-albums + $query = ' +SELECT + id, + uppercats + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.implode(',', $category_ids).') +;'; + $uppercats_of = query2array($query, 'id', 'uppercats'); + + foreach (array_keys($uppercats_of) as $cat_id) + { + // find the subcats + $subcat_ids = array(); + + foreach ($uppercats_of as $id => $uppercats) + { + if (preg_match('/(^|,)'.$cat_id.'(,|$)/', $uppercats)) + { + $subcat_ids[] = $id; + } + } + + $to_compare = array(); + foreach ($subcat_ids as $id) + { + if (isset($ref_dates[$id])) + { + $to_compare[] = $ref_dates[$id]; + } + } + + if (count($to_compare) > 0) + { + $ref_dates[$cat_id] = 'max' == $minmax ? max($to_compare) : min($to_compare); + } + else + { + $ref_dates[$cat_id] = null; + } + } + + // only return the list of $ids, not the sub-categories + $return = array(); + foreach ($ids as $id) + { + $return[$id] = $ref_dates[$id]; + } + + return $return; +} ?> diff --git a/admin/themes/default/js/cat_move.js b/admin/themes/default/js/cat_move.js index 6c499844c..6eb1ee4cd 100644 --- a/admin/themes/default/js/cat_move.js +++ b/admin/themes/default/js/cat_move.js @@ -1,8 +1,6 @@ $(document).ready(() => { - formatedData = $.map(data, function(value, index) { - return [formatInArray(value)]; - }); + formatedData = data; $('.tree').tree({ data: formatedData, @@ -23,11 +21,11 @@ $(document).ready(() => { +""+str_edit+"" +"" +''; - actions_tree =""+str_manage_sub_album+"" - +""+str_apply_order+""; + action_order = ""+str_apply_order+""; - cont = li.find('.jqtree-element') - cont.addClass('move-cat-container') + cont = li.find('.jqtree-element'); + cont.addClass('move-cat-container'); + cont.attr('id', 'cat-'+node.id) cont.html(''); cont.append($(icon.replace(/%icon%/g, 'icon-ellipsis-vert'))); @@ -37,9 +35,9 @@ $(document).ready(() => { cont.append($(icon.replace(/%icon%/g, 'icon-folder-open'))); } - cont.append($(title.replace(/%name%/g, node.name))) + cont.append($(title.replace(/%name%/g, node.name))); if (node.status == 'private') { - cont.append($(icon.replace(/%icon%/g, 'icon-lock'))) + cont.append($(icon.replace(/%icon%/g, 'icon-lock'))); } cont.append(actions); @@ -55,18 +53,15 @@ $(document).ready(() => { .replace(/%content%/g, toggler) .replace(/%id%/g, node.id))); - cont.find('.move-cat-action').append(actions_tree); + cont.find('.move-cat-action').append(action_order); } - - var colors = ["icon-red", "icon-blue", "icon-yellow", "icon-purple", "icon-green"]; var colorId = Number(node.id)%5; cont.find(".icon-folder-open, .icon-flow-tree").addClass(colors[colorId]); } $('.tree').on( 'click', '.move-cat-toogler', function(e) { - console.log('clic'); var node_id = $(this).attr('data-id'); var node = $('.tree').tree('getNodeById', node_id); if (node) { @@ -116,7 +111,7 @@ $(document).ready(() => { text: str_yes_change_parent, btnClass: 'btn-red', action: function () { - event.move_info.moved_node.status = 'private'; + makePrivateHierarchy(event.move_info.moved_node); applyMove(event); }, }, @@ -134,16 +129,32 @@ $(document).ready(() => { } } ); -}); -function formatInArray(obj) { - if (obj['children'] != null) { - obj['children'] = $.map(obj['children'], function(value, index) { - return [formatInArray(value)]; - }); + $('.tree').on( 'click', '.move-cat-order', function(e) { + var node_id = $(this).attr('data-id'); + var node = $('.tree').tree('getNodeById', node_id); + console.log(node); + if (node) { + $('.cat-move-order-popin').fadeIn(); + $('.cat-move-order-popin .album-name').html(getPathNode(node)); + $('.cat-move-order-popin input[name=id]').val(node_id); + } + }); + + $('.order-root').on( 'click', function() { + $('.cat-move-order-popin').fadeIn(); + $('.cat-move-order-popin .album-name').html(str_root); + $('.cat-move-order-popin input[name=id]').val(-1); + }); + + if (openCat != -1) { + var node = $('.tree').tree('getNodeById', openCat); + $('.tree').tree('openNode', node); + $([document.documentElement, document.body]).animate({ + scrollTop: $("#cat-"+openCat).offset().top + }, 500); } - return obj; -} +}); function getId(parent) { if (parent.getLevel() == 0) { @@ -170,6 +181,9 @@ function getRank(node, ignoreId = null) { } function applyMove(event) { + waitingTimeout = setTimeout(() => { + $('.waiting-message').addClass('visible'); + }, 500); id = event.move_info.moved_node.id; moveParent = null; moveRank = null; @@ -186,7 +200,11 @@ function applyMove(event) { } moveRank = 1; } - moveNode(id, moveRank, moveParent).then(() => event.move_info.do_move()) + moveNode(id, moveRank, moveParent).then(() => { + event.move_info.do_move(); + clearTimeout(waitingTimeout); + $('.waiting-message').removeClass('visible'); + }) .catch((message) => console.log('An error has occured : ' + message )); } @@ -198,7 +216,6 @@ function moveNode(node, rank, parent) { changeRank(node, rank).then(() => res()).catch(() => rej()) } }) - } function changeParent(node, parent) { @@ -249,3 +266,18 @@ function changeRank(node, rank) { }); }) } + +function makePrivateHierarchy (node) { + node.status = 'private'; + node.children.forEach(node => { + makePrivateHierarchy(node); + }); +} + +function getPathNode(node) { + if (node.parent.getLevel() != 0) { + return getPathNode(node.parent) + ' / ' + node.name; + } else { + return node.name; + } +} diff --git a/admin/themes/default/template/cat_move.tpl b/admin/themes/default/template/cat_move.tpl index 53f6d2dce..c23c98b96 100644 --- a/admin/themes/default/template/cat_move.tpl +++ b/admin/themes/default/template/cat_move.tpl @@ -6,9 +6,11 @@ var str_hide_sub = "{'Hide sub-albums'|@translate}"; var str_manage_sub_album = "{'Manage sub-albums'|@translate}"; var str_apply_order = "{'Apply an automatic order to sub-albums'|@translate}"; var str_edit = "{'Edit album'|@translate}"; -var str_are_you_sure = "{'Album \'%s\' status will change to private'}" -var str_yes_change_parent = "{'Yes, change parent anyway'|@translate}" -var str_no_change_parent = "{"No, I have changed my mind"|@translate}" +var str_are_you_sure = "{'Album \'%s\' status and his sub-albums will change to private. Are you sure ?'|@translate}"; +var str_yes_change_parent = "{'Yes change parent anyway'|@translate}" +var str_no_change_parent = "{'No, don\'t move this album here'|@translate}" +var str_root = "{'Root'|@translate}" +var openCat = {$open_cat}; {/footer_script} {combine_script id='jquery.confirm' load='footer' require='jquery' path='themes/default/js/plugins/jquery-confirm.min.js'} @@ -24,6 +26,58 @@ var str_no_change_parent = "{"No, I have changed my mind"|@translate}"

{'Move albums'|@translate}

+
Waiting for Piwigo response...
+ + +
+
+ +
+
+ +
+ + + + + + + + + + + +
+ + +
+
+
+
{'Drag and drop to reorder albums'|@translate}
{'Apply an automatic order to root albums'|@translate} diff --git a/admin/themes/default/theme.css b/admin/themes/default/theme.css index 1f5537e85..5bfe3f12a 100644 --- a/admin/themes/default/theme.css +++ b/admin/themes/default/theme.css @@ -446,6 +446,27 @@ TABLE.doubleSelect SELECT.categoryList { text-decoration: none; } +/* Waiting Message */ + +.waiting-message { + position: fixed; + right: 0px; + top: 0px; + margin: 10px; + z-index: 1000; + background-color: #FFBD4D; + color: white; + padding: 20px; + font-weight: bold; + border-radius: 34px; + transform: translateY(calc(-100% - 10px)); + transition: 0.5s ease; +} + +.waiting-message.visible { + transform: translateY(0%); +} + /* Statistic Page */ .stat-legend-container { @@ -2728,6 +2749,7 @@ FORM#categoryOrdering p.albumActions a { FORM#categoryOrdering p.albumActions a:hover {text-decoration: none;} FORM#categoryOrdering p.albumActions .userSeparator {margin:0 5px;} +/* Move Album */ .cat-move-header { display: flex; margin: 0px 30px; @@ -2740,11 +2762,22 @@ FORM#categoryOrdering p.albumActions .userSeparator {margin:0 5px;} font-size: 16px; } +.cat-move-header .cat-move-info { + position: relative; +} + .cat-move-header .cat-move-info::before { color: grey; font-size: 20px; } +.cat-move-header .cat-move-info .spinner { + position: absolute; + left: calc(100% + 6px); + font-size: 20px; + display: none; +} + .tree { margin: 20px; } @@ -2752,11 +2785,11 @@ FORM#categoryOrdering p.albumActions .userSeparator {margin:0 5px;} .move-cat-container { display: flex; align-items: center; - box-shadow: 0px 0px 4px #acacac; + box-shadow: 0px 2px 3px #00000024; background-color: #fafafa; border-radius: 5px; color: #777; - padding: 10px; + padding: 5px 10px; padding-left: 20px; } @@ -2771,7 +2804,7 @@ FORM#categoryOrdering p.albumActions .userSeparator {margin:0 5px;} display: inline-block; border-radius: 50%; font-size: 20px; - padding: 10px; + padding: 8px; margin: 5px; } @@ -2781,7 +2814,7 @@ FORM#categoryOrdering p.albumActions .userSeparator {margin:0 5px;} } .move-cat-container .move-cat-title { - font-size: 20px; + font-size: 16px; margin: 10px; max-width: 200px; overflow: hidden; @@ -2819,15 +2852,17 @@ FORM#categoryOrdering p.albumActions .userSeparator {margin:0 5px;} .move-cat-action { display: flex; align-items: center; - max-width: 70%; + max-width: 60%; } .move-cat-action a { - padding: 35px; - color: #777; - font-size: 12px; + padding: 30px 15px; font-weight: bold; cursor: pointer; + height: 100%; + border-left: 1px solid #00000012; + background-color: #00000003; + text-align: center; } .move-cat-action a:hover { @@ -2836,6 +2871,108 @@ FORM#categoryOrdering p.albumActions .userSeparator {margin:0 5px;} background-color: #FFA646; } +.cat-move-order-popin { + position: fixed; + z-index: 100; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgba(0,0,0,0.7); + display: none; +} + +.cat-move-order-popin .order-popin-container { + background-color: #f3f3f3; + border-radius: 10px; + display: block; + width: 30%; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -48%); + text-align: left; + padding: 30px; +} + +.cat-move-order-popin .album-name { + font-size: 20px; + color: #3C3C3C; +} + +.cat-move-order-popin .choice-container { + display: flex; + flex-direction: column; + padding: 15px 5px; +} + +.cat-move-order-popin label { + position: relative; + padding: 5px; + padding-left: 25px; +} + +.cat-move-order-popin .order-checkmark { + width:16px; + height: 16px; + border-radius: 100%; + background-color: #d5d5d5; + position: absolute; + top: 50%; + left: 0px; + transform: translate(0, -50%); + transition: ease 0.3s; +} + +.cat-move-order-popin .order-checkmark::before { + content: ""; + padding: 0px; + background-color: #ffa646; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + border-radius: 100%; + transition: ease 0.3s; + opacity: 0.15; +} + +.cat-move-order-popin input:checked + .order-checkmark::before { + padding: 15px; +} + +.cat-move-order-popin input:checked + .order-checkmark { + background-color: #ffa646; +} + +.cat-move-order-popin input[type=radio] { + opacity: 0; +} + +.cat-move-order-popin input[type=submit] { + width: 100%; + margin: 10px 0px; +} + +.cat-move-order-popin input[name=recursive] { + background-color: #d9d9d9; +} + +.cat-move-order-popin input[name=recursive]:hover { + background-color: #ffc17e; +} + +.cat-move-order-popin .close-popin { + position: absolute; + right: -40px; + top: -40px; + font-size: 30px; + color: white; +} + +.cat-move-order-popin .close-popin:hover { color: #ffa646;} + /*Overwrite JQtree CSS*/ .jqtree_common { diff --git a/admin/themes/roma/theme.css b/admin/themes/roma/theme.css index d95aced2e..e683865b2 100644 --- a/admin/themes/roma/theme.css +++ b/admin/themes/roma/theme.css @@ -1029,6 +1029,12 @@ li.plupload_delete a:hover {background: url("images/cancelhover.svg")!important; background-color:#f22; } +/* Album Move */ +.move-cat-container { + background-color: #333; + box-shadow: none; +} + /* Icon colors*/ .icon-red {