<?php
/**
* This file implements the recursive chapter list.
*
* This file is part of the evoCore framework - {@link http://evocore.net/}
* See also {@link https://github.com/b2evolution/b2evolution}.
*
* @license GNU GPL v2 - {@link http://b2evolution.net/about/gnu-gpl-license}
*
* @copyright (c)2003-2020 by Francois Planque - {@link http://fplanque.com/}
*
* @package admin
*/
if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
//____________________ Callbacks functions to display categories list _____________________
load_class( '_core/ui/_table.class.php', 'Table' );
/**
* @var Blog
*/
global $Collection, $Blog;
global $Settings;
global $ChapterCache;
global $line_class;
global $permission_to_edit;
global $subset_ID;
global $current_default_cat_ID;
global $Session, $AdminUI;
$result_fadeout = $Session->get( 'fadeout_array' );
$current_default_cat_ID = $Blog->get_default_cat_ID();
$line_class = 'odd';
/**
* Generate category line when it has children
*
* @param object Chapter we want to display
* @param integer Level of the category in the recursive tree
* @return string HTML
*/
function cat_line( $Chapter, $level )
{
global $line_class, $permission_to_edit, $Settings, $admin_url;
global $ChapterCache, $current_default_cat_ID;
global $number_of_posts_in_cat;
global $Session;
$result_fadeout = $Session->get( 'fadeout_array' );
$line_class = $line_class == 'even' ? 'odd' : 'even';
// Check if current item's row should be highlighted:
$is_highlighted = ( param( 'highlight_id', 'integer', NULL ) == $Chapter->ID ) ||
( isset( $result_fadeout ) && in_array( $Chapter->ID, $result_fadeout ) );
// ID
$r = '<tr id="tr-'.$Chapter->ID.'"class="'.$line_class.
' chapter_parent_'.( $Chapter->parent_ID ? $Chapter->parent_ID : '0' ).
( $is_highlighted ? ' evo_highlight' : '' ).'">
<td class="firstcol shrinkwrap">'.$Chapter->ID.'</td>';
// Default
if( $Chapter->get( 'meta' ) )
{ // Deny to use meta chapter as default:
$makedef_icon = '';
}
elseif( $current_default_cat_ID == $Chapter->ID )
{ // This chapter is default currently:
$makedef_icon = get_icon( 'enabled', 'imgtag', array( 'title' => format_to_output( T_( 'This is the default category' ), 'htmlattr' ) ) );
}
else
{ // Display action icon to make this chapter default:
$makedef_url = regenerate_url( 'action,cat_ID', 'cat_ID='.$Chapter->ID.'&action=make_default&'.url_crumb('element') );
$makedef_title = format_to_output( T_('Click to make this the default category'), 'htmlattr' );
$makedef_icon = '<a href="'.$makedef_url.'" title="'.$makedef_title.'">'.get_icon( 'disabled', 'imgtag', array( 'title' => $makedef_title ) ).'</a>';
}
$r .= '<td class="center">'.$makedef_icon.'</td>';
// Image:
$r .= '<td>'.$Chapter->get_image_tag().'</td>';
// Name
if( $permission_to_edit )
{ // We have permission permission to edit:
$edit_url = regenerate_url( 'action,cat_ID', 'cat_ID='.$Chapter->ID.'&action=edit' );
$r .= '<td>
<strong style="padding-left: '.($level).'em;"><a href="'.$edit_url.'" title="'.T_('Edit...').'">'.$Chapter->dget('name').'</a></strong>
</td>';
}
else
{
$r .= '<td>
<strong style="padding-left: '.($level).'em;">'.$Chapter->dget('name').'</strong>
</td>';
}
// URL "slug"
$edit_url = regenerate_url( 'action,cat_ID', 'cat_ID='.$Chapter->ID.'&action=edit' );
$r .= '<td><a href="'.htmlspecialchars($Chapter->get_permanent_url()).'">'.$Chapter->dget('urlname').'</a></td>';
// Order
if( $Chapter->get_parent_subcat_ordering() == 'manual' )
{ // Manual ordering
$r .= '<td class="center jeditable_cell cat_order_edit" rel="'.$Chapter->ID.'">'
.'<a href="#">'.( $Chapter->get( 'order' ) === NULL ? '-' : $Chapter->dget( 'order' ) ).'</a>'
.'</td>';
}
else
{ // Alphabetic ordering
$r .= '<td class="center">'.T_('Alphabetic').'</td>';
}
if( $permission_to_edit )
{ // We have permission permission to edit, so display these columns:
// Meta
if( $current_default_cat_ID == $Chapter->ID )
{ // Deny to use default chapter as meta:
$makemeta_icon = false;
}
elseif( $Chapter->meta )
{ // This chapter is meta:
$makemeta_icon = 'enabled';
$makemeta_title = format_to_output( T_('Click to revert this from meta category'), 'htmlattr' );
$action = 'unset_meta';
}
else
{ // This chapter is NOT meta:
$makemeta_icon = 'disabled';
$makemeta_title = format_to_output( T_('Click to make this as meta category'), 'htmlattr' );
$action = 'set_meta';
}
if( $makemeta_icon )
{ // Display action icon to change meta property of this chapter:
$makemeta_url = regenerate_url( 'action,cat_ID', 'cat_ID='.$Chapter->ID.'&action='.$action.'&'.url_crumb('element') );
$r .= '<td class="center"><a href="'.$makemeta_url.'" title="'.$makemeta_title.'">'.get_icon( $makemeta_icon, 'imgtag', array( 'title' => $makemeta_title ) ).'</a></td>';
}
else
{
$r .= '<td></td>';
}
// Default Item Type:
if( $Chapter->get( 'meta' ) )
{ // Don't allow default Item Type for meta category because it cannot has items:
$r .= '<td> </td>';
}
else
{ // Normal category can has items, Allow to change its default Item Type:
if( $Chapter->get( 'ityp_ID' ) === NULL )
{ // Same as collection default:
$cat_item_type_name = T_('Same as collection default');
}
elseif( $Chapter->get( 'ityp_ID' ) == '0' )
{ // No default type:
$cat_item_type_name = '<b>'.T_('No default type').'</b>';
}
elseif( ( $ItemTypeCache = & get_ItemTypeCache() ) &&
( $cat_ItemType = & $ItemTypeCache->get_by_ID( $Chapter->get( 'ityp_ID' ), false, false ) ) )
{ // Custom Item Type:
$cat_item_type_name = $cat_ItemType->get( 'name' );
if( ! $cat_ItemType->is_enabled( $Chapter->get( 'blog_ID' ) ) )
{ // Mark not enabled Item Type with red color:
$cat_item_type_name = '<span class="red">'.$cat_item_type_name.'</span>';
}
}
else
{ // Not found Item Type in DB:
$cat_item_type_name = '<span class="red">'.T_('Not Found').' #'.$Chapter->get( 'ityp_ID' ).'</span>';
}
if( ( $cat_Blog = & $Chapter->get_Blog() ) &&
$cat_Blog->get_default_cat_ID() == $Chapter->ID )
{ // For default category use a separate options without "No default type":
$cat_cell_edit_class = 'default_cat_ityp_ID_edit';
}
else
{ // For not default categories use full options list:
$cat_cell_edit_class = 'cat_ityp_ID_edit';
}
$r .= '<td class="jeditable_cell '.$cat_cell_edit_class.'"><a href="#" rel="_'.$Chapter->get( 'ityp_ID' ).'">'.$cat_item_type_name.'</a></td>';
}
// Lock
if( $Chapter->lock )
{
$makelock_icon = 'file_not_allowed';
$makelock_title = format_to_output( T_('Unlock category'), 'htmlattr' );
$action = 'unlock';
}
else
{
$makelock_icon = 'file_allowed';
$makelock_title = format_to_output( T_('Lock category'), 'htmlattr' );
$action = 'lock';
}
$makelock_url = regenerate_url( 'action,cat_ID', 'cat_ID='.$Chapter->ID.'&action='.$action.'&'.url_crumb('element') );
$r .= '<td class="center"><a href="'.$makelock_url.'" title="'.$makelock_title.'">'.get_icon( $makelock_icon, 'imgtag', array( 'title' => $makelock_title ) ).'</a></td>';
}
// Posts
if( isset($number_of_posts_in_cat[$Chapter->ID]) )
{
$r .= '<td class="center"><a href="'.$admin_url.'?ctrl=items&blog='.$Chapter->get( 'blog_ID' ).'&catsel[]='.$Chapter->ID.'">'.(int)$number_of_posts_in_cat[$Chapter->ID].'</a></td>';
}
else
{ // no posts in this category
$r .= '<td class="center"> - </td>';
}
// Actions
$r .= '<td class="lastcol shrinkwrap">';
if( $permission_to_edit )
{ // We have permission permission to edit, so display action column:
$r .= action_icon( T_('Edit...'), 'edit', $edit_url );
if( $Settings->get('allow_moving_chapters') )
{ // If moving cats between blogs is allowed:
$r .= action_icon( T_('Move to a different blog...'), 'file_move', regenerate_url( 'action,cat_ID', 'cat_ID='.$Chapter->ID.'&action=move' ), T_('Move') );
}
$r .= action_icon( T_('New').'...', 'new', regenerate_url( 'action,cat_ID,cat_parent_ID', 'cat_parent_ID='.$Chapter->ID.'&action=new' ) )
.action_icon( T_('Delete').'...', 'delete', regenerate_url( 'action,cat_ID', 'cat_ID='.$Chapter->ID.'&action=delete&'.url_crumb('element') ) );
}
$r .= '</td>';
$r .= '</tr>';
return $r;
}
/**
* Generate category line when it has no children
*
* @param object Chapter generic category we want to display
* @param integer Level of the category in the recursive tree
* @return string HTML
*/
function cat_no_children( $Chapter, $level )
{
return '';
}
/**
* Generate code when entering a new level
*
* @param int level of the category in the recursive tree
* @return string HTML
*/
function cat_before_level( $level )
{
return '';
}
/**
* Generate code when exiting from a level
*
* @param int level of the category in the recursive tree
* @return string HTML
*/
function cat_after_level( $level )
{
return '';
}
$callbacks = array(
'line' => 'cat_line',
'no_children' => 'cat_no_children',
'before_level' => 'cat_before_level',
'after_level' => 'cat_after_level'
);
//____________________________________ Display generic categories _____________________________________
$Table = new Table();
$Table->title = sprintf( T_('Categories for blog: %s'), $Blog->get_maxlen_name( 50 ).get_manual_link( 'categories-tab' ) );
$Table->global_icon( T_('Refresh'), 'refresh', regenerate_url( 'action,'.$ChapterCache->dbIDname ), T_('Refresh'), 3, 4, array( 'class' => 'action_icon btn-warning' ) );
$Table->global_icon( T_('Create a new category...'), 'new', regenerate_url( 'action,'.$ChapterCache->dbIDname, 'action=new' ), T_('New category').' »', 3, 4, array( 'class' => 'action_icon btn-primary' ) );
$Table->cols[] = array(
'th' => T_('ID'),
);
$Table->cols[] = array(
'th' => T_('Default'),
'th_class' => 'shrinkwrap',
);
$Table->cols[] = array(
'th' => T_('Image'),
'th_class' => 'shrinkwrap',
);
$Table->cols[] = array(
'th' => T_('Name'),
);
$Table->cols[] = array(
'th' => T_('URL "slug"'),
);
$Table->cols[] = array(
'th' => T_('Order'),
'th_class' => 'shrinkwrap',
);
if( $permission_to_edit )
{ // We have permission permission to edit, so display these columns:
$Table->cols[] = array(
'th' => T_('Meta'),
'th_class' => 'shrinkwrap',
);
$Table->cols[] = array(
'th' => T_('Default<br />Item Type'),
'th_class' => 'shrinkwrap',
);
$Table->cols[] = array(
'th' => T_('Lock'),
'th_class' => 'shrinkwrap',
);
}
// TODO: dh> would be useful to sort by this
$Table->cols[] = array(
'th' => T_('Posts'),
'th_class' => 'shrinkwrap',
);
if( $permission_to_edit )
{ // We have permission permission to edit, so display action column:
$Table->cols[] = array(
'th' => T_('Actions'),
);
}
// Get # of posts for each category
global $number_of_posts_in_cat;
$number_of_posts_in_cat = $DB->get_assoc('
SELECT cat_ID, count(postcat_post_ID) c
FROM T_categories LEFT JOIN T_postcats ON postcat_cat_ID = cat_id
WHERE cat_blog_ID = '.$DB->quote($subset_ID).'
GROUP BY cat_ID');
$Table->display_init( array( 'list_attrib' => 'id="chapter_list"' ), $result_fadeout );
$results_params = $AdminUI->get_template( 'Results' );
echo $results_params['before'];
$Table->display_head();
echo $Table->params['content_start'];
$Table->display_list_start();
$Table->display_col_headers();
$Table->display_body_start();
echo $ChapterCache->recurse( $callbacks, $subset_ID, NULL, 0, 0, array( 'sorted' => true ) );
$Table->display_body_end();
$Table->display_list_end();
echo $Table->params['content_end'];
echo $results_params['after'];
/* fp> TODO: maybe... (a general group move of posts would be more useful actually)
echo '<p class="note">'.T_('<strong>Note:</strong> Deleting a category does not delete posts from that category. It will just assign them to the parent category. When deleting a root category, posts will be assigned to the oldest remaining category in the same collection (smallest category number).').'</p>';
*/
global $Settings, $admin_url;
// Use a wrapper div to have margin around the form
echo '<div id="form_wrapper" style="margin: 2ex auto 1ex">';
$Form = new Form( NULL, 'cat_order_checkchanges', 'post', 'compact' );
$Form->begin_form( 'fform', T_('Category order').get_manual_link('categories-order') );
$Form->add_crumb( 'collection' );
$Form->hidden( 'ctrl', 'coll_settings' );
$Form->hidden( 'action', 'update' );
$Form->hidden( 'blog', $Blog->ID );
$Form->hidden( 'tab', 'chapters' );
$Form->radio_input( 'category_ordering', $Blog->get_setting('category_ordering'), array(
array( 'value'=>'alpha', 'label'=>T_('Alphabetically') ),
array( 'value'=>'manual', 'label'=>T_('Manually') ),
), T_('Sort categories'), array( 'note'=>'('.T_('Note: can be overridden for sub-categories').')' ) );
$Form->end_form( array( array( 'submit', 'submit', T_('Save Changes!'), 'SaveButton', 'data-shortcut' => 'ctrl+s,command+s,ctrl+enter,command+enter' ) ) );
echo '</div>'; // form wrapper end
if( ! $Settings->get('allow_moving_chapters') )
{ // TODO: check perm
echo '<p class="alert alert-info">'.sprintf( T_('<strong>Note:</strong> Moving categories across blogs is currently disabled in the %sblogs settings%s.'), '<a href="'.$admin_url.'?ctrl=collections&tab=blog_settings#fieldset_wrapper_categories">', '</a>' ).'</p> ';
}
//Flush fadeout
$Session->delete( 'fadeout_array');
// Print JS to edit order of the chapters inline
echo_editable_column_js( array(
'column_selector' => '.cat_order_edit',
'ajax_url' => get_htsrv_url().'async.php?action=cat_order_edit&blogid='.$Blog->ID.'&'.url_crumb( 'catorder' ),
'new_field_name' => 'new_cat_order',
'ID_value' => 'jQuery( this ).attr( "rel" )',
'ID_name' => 'cat_ID',
'field_type' => 'text' ) );
if( $permission_to_edit )
{ // Print JS to edit default Item Type of category:
echo_editable_column_js( $cat_ityp_ID_edit_params = array(
'column_selector' => '.cat_ityp_ID_edit',
'ajax_url' => get_htsrv_url().'async.php?action=cat_ityp_ID_edit&blogid='.$Blog->ID.'&'.url_crumb( 'catityp' ),
'options' => collection_item_type_titles( $Blog->ID, NULL, '_' ),
'new_field_name' => 'new_ityp_ID',
'ID_value' => 'jQuery( ":first", jQuery( this ).parent() ).text()',
'ID_name' => 'cat_ID' ) );
// Separate options without "No default type" for default category of the collection:
$cat_ityp_ID_edit_params['column_selector'] = '.default_cat_ityp_ID_edit';
$cat_ityp_ID_edit_params['options'] = collection_item_type_titles( $Blog->ID, NULL, '_', false );
echo_editable_column_js( $cat_ityp_ID_edit_params );
}
?>