| 1 |
<?php
|
| 2 |
// $Id: category.admin.inc,v 1.4 2009/05/31 10:16:11 jaza Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Administrative page callbacks for the category module.
|
| 7 |
*/
|
| 8 |
|
| 9 |
/**
|
| 10 |
* Form builder to list and manage containers.
|
| 11 |
*
|
| 12 |
* @ingroup forms
|
| 13 |
* @see category_overview_containers_submit()
|
| 14 |
* @see theme_category_overview_containers()
|
| 15 |
*/
|
| 16 |
function category_overview_containers(&$form_state) {
|
| 17 |
// Check for confirmation forms.
|
| 18 |
if (isset($form_state['confirm_reset_alphabetical'])) {
|
| 19 |
return category_container_confirm_reset_alphabetical($form_state);
|
| 20 |
}
|
| 21 |
|
| 22 |
$container_node_types = FALSE;
|
| 23 |
foreach (node_get_types() as $type) {
|
| 24 |
$behavior = variable_get('category_behavior_'. $type->type, 0);
|
| 25 |
if (!empty($behavior) && $behavior == 'container') {
|
| 26 |
$container_node_types = TRUE;
|
| 27 |
}
|
| 28 |
}
|
| 29 |
if (!$container_node_types) {
|
| 30 |
category_no_node_types();
|
| 31 |
}
|
| 32 |
|
| 33 |
$containers = category_get_containers();
|
| 34 |
$form = array('#tree' => TRUE);
|
| 35 |
$destination = drupal_get_destination();
|
| 36 |
foreach ($containers as $container) {
|
| 37 |
$container->parents = category_get_parents($container->cid);
|
| 38 |
$container->admin_title = !empty($container->has_admin_title) ? $container->admin_title : '';
|
| 39 |
$types = array();
|
| 40 |
foreach ($container->nodes as $type) {
|
| 41 |
$node_type = node_get_types('name', $type);
|
| 42 |
$types[] = $node_type ? check_plain($node_type) : check_plain($type);
|
| 43 |
}
|
| 44 |
sort($types);
|
| 45 |
$types_string = !empty($types) ? implode(', ', $types) : theme('placeholder', t('none'));
|
| 46 |
$form[$container->cid]['#container'] = (array)$container;
|
| 47 |
$form[$container->cid]['name'] = array('#value' => l($container->title, 'node/'. $container->nid));
|
| 48 |
$form[$container->cid]['types'] = array('#value' => $types_string);
|
| 49 |
if (variable_get('category_container_hierarchy', 0) > 0) {
|
| 50 |
$parents = array();
|
| 51 |
foreach ($container->parents as $parent) {
|
| 52 |
if ($parent->cid) {
|
| 53 |
$parents[] = l($parent->title, 'node/'. $parent->cid);
|
| 54 |
}
|
| 55 |
}
|
| 56 |
$form[$container->cid]['parents'] = array('#value' => implode(', ', $parents));
|
| 57 |
}
|
| 58 |
if (count($containers) > 1) {
|
| 59 |
$form[$container->cid]['weight'] = array('#type' => 'weight', '#delta' => 15, '#default_value' => $container->weight);
|
| 60 |
}
|
| 61 |
$form[$container->cid]['edit'] = array('#value' => l(t('edit container'), "node/$container->cid/edit", array('query' => $destination)));
|
| 62 |
$form[$container->cid]['list'] = array('#value' => l(t('list categories'), "admin/content/category/$container->cid"));
|
| 63 |
$form[$container->cid]['add'] = array('#value' => l(t('add categories'), "admin/content/category/$container->cid/add/category"));
|
| 64 |
}
|
| 65 |
|
| 66 |
// Only make this form include a submit button and weight if more than one
|
| 67 |
// container exists, and if no containers have multiple parents.
|
| 68 |
if (count($containers) > 1) {
|
| 69 |
$form['submit'] = array(
|
| 70 |
'#type' => 'submit',
|
| 71 |
'#value' => t('Save'),
|
| 72 |
);
|
| 73 |
$form['reset_alphabetical'] = array(
|
| 74 |
'#type' => 'submit',
|
| 75 |
'#value' => t('Reset to alphabetical'),
|
| 76 |
);
|
| 77 |
}
|
| 78 |
return $form;
|
| 79 |
}
|
| 80 |
|
| 81 |
/**
|
| 82 |
* Submit handler for containers overview. Updates changed container weights.
|
| 83 |
*
|
| 84 |
* @see category_overview_containers()
|
| 85 |
*/
|
| 86 |
function category_overview_containers_submit($form, &$form_state) {
|
| 87 |
if ($form_state['clicked_button']['#value'] == t('Reset to alphabetical')) {
|
| 88 |
// Execute the reset action.
|
| 89 |
if ($form_state['values']['reset_alphabetical'] === TRUE) {
|
| 90 |
return category_container_confirm_reset_alphabetical_submit($form, $form_state);
|
| 91 |
}
|
| 92 |
// Rebuild the form to confirm the reset action.
|
| 93 |
$form_state['rebuild'] = TRUE;
|
| 94 |
$form_state['confirm_reset_alphabetical'] = TRUE;
|
| 95 |
return;
|
| 96 |
}
|
| 97 |
|
| 98 |
foreach ($form_state['values'] as $cnid => $container) {
|
| 99 |
if (is_numeric($cnid) && $form[$cnid]['#container']['weight'] != $form_state['values'][$cnid]['weight']) {
|
| 100 |
$form[$cnid]['#container']['weight'] = $form_state['values'][$cnid]['weight'];
|
| 101 |
$node = new StdClass();
|
| 102 |
$node->nid = $cnid;
|
| 103 |
$node->category = $form[$cnid]['#container'];
|
| 104 |
category_save_container($node);
|
| 105 |
}
|
| 106 |
}
|
| 107 |
}
|
| 108 |
|
| 109 |
/**
|
| 110 |
* Theme the container overview as a sortable list of containers.
|
| 111 |
*
|
| 112 |
* @ingroup themeable
|
| 113 |
* @see category_overview_containers()
|
| 114 |
*/
|
| 115 |
function theme_category_overview_containers($form) {
|
| 116 |
$rows = array();
|
| 117 |
|
| 118 |
$cols = 4;
|
| 119 |
if (variable_get('category_container_hierarchy', 0) > 0) {
|
| 120 |
$cols++;
|
| 121 |
}
|
| 122 |
|
| 123 |
foreach (element_children($form) as $key) {
|
| 124 |
if (isset($form[$key]['name'])) {
|
| 125 |
$container = &$form[$key];
|
| 126 |
|
| 127 |
$row = array();
|
| 128 |
$row[] = drupal_render($container['name']);
|
| 129 |
$row[] = drupal_render($container['types']);
|
| 130 |
if (variable_get('category_container_hierarchy', 0) > 0) {
|
| 131 |
$row[] = drupal_render($container['parents']);
|
| 132 |
}
|
| 133 |
if (isset($form['submit'])) {
|
| 134 |
$container['weight']['#attributes']['class'] = 'container-weight';
|
| 135 |
$row[] = drupal_render($container['weight']);
|
| 136 |
$cols++;
|
| 137 |
}
|
| 138 |
$row[] = drupal_render($container['edit']);
|
| 139 |
$row[] = drupal_render($container['list']);
|
| 140 |
$row[] = drupal_render($container['add']);
|
| 141 |
$rows[] = array('data' => $row, 'class' => 'draggable');
|
| 142 |
}
|
| 143 |
}
|
| 144 |
if (empty($rows)) {
|
| 145 |
$rows[] = array(array('data' => t('No containers available.'), 'colspan' => $cols));
|
| 146 |
}
|
| 147 |
|
| 148 |
$header = array(t('Name'), t('Types'));
|
| 149 |
if (variable_get('category_container_hierarchy', 0) > 0) {
|
| 150 |
$header[] = t('Parents');
|
| 151 |
}
|
| 152 |
if (isset($form['submit'])) {
|
| 153 |
$header[] = t('Weight');
|
| 154 |
drupal_add_tabledrag('category', 'order', 'sibling', 'container-weight');
|
| 155 |
}
|
| 156 |
$header[] = array('data' => t('Operations'), 'colspan' => '3');
|
| 157 |
return theme('table', $header, $rows, array('id' => 'category')) . drupal_render($form);
|
| 158 |
}
|
| 159 |
|
| 160 |
/**
|
| 161 |
* Form builder to confirm resetting a container (or all containers) to alphabetical order.
|
| 162 |
*
|
| 163 |
* @ingroup forms
|
| 164 |
* @see category_container_confirm_reset_alphabetical_submit()
|
| 165 |
*/
|
| 166 |
function category_container_confirm_reset_alphabetical(&$form_state, $cnid = 0) {
|
| 167 |
$container = NULL;
|
| 168 |
if (!empty($cnid)) {
|
| 169 |
$container = category_get_container($cnid);
|
| 170 |
|
| 171 |
$form['type'] = array('#type' => 'value', '#value' => 'container');
|
| 172 |
$form['cnid'] = array('#type' => 'value', '#value' => $cnid);
|
| 173 |
$form['title'] = array('#type' => 'value', '#value' => $container->title);
|
| 174 |
}
|
| 175 |
$form['reset_alphabetical'] = array('#type' => 'value', '#value' => TRUE);
|
| 176 |
return confirm_form($form,
|
| 177 |
(!empty($cnid)
|
| 178 |
? t('Are you sure you want to reset the container %title to alphabetical order?', array('%title' => $container->title))
|
| 179 |
: t('Are you sure you want to reset your containers to alphabetical order?')
|
| 180 |
),
|
| 181 |
'admin/content/category'. (!empty($cnid) ? '/'. $cnid : ''),
|
| 182 |
(!empty($cnid)
|
| 183 |
? t('Resetting a container will discard all custom ordering and sort items alphabetically.')
|
| 184 |
: t('Resetting your containers will discard all custom ordering and sort items alphabetically.')
|
| 185 |
),
|
| 186 |
t('Reset to alphabetical'),
|
| 187 |
t('Cancel'));
|
| 188 |
}
|
| 189 |
|
| 190 |
/**
|
| 191 |
* Submit handler to reset a container (or all containers) to alphabetical order after confirmation.
|
| 192 |
*
|
| 193 |
* @see category_container_confirm_reset_alphabetical()
|
| 194 |
*/
|
| 195 |
function category_container_confirm_reset_alphabetical_submit($form, &$form_state) {
|
| 196 |
db_query('UPDATE {category} c SET weight = 0 WHERE cnid = %d', $form_state['values']['cnid']);
|
| 197 |
if (!empty($form_state['values']['cnid'])) {
|
| 198 |
drupal_set_message(t('Reset container %title to alphabetical order.', array('%title' => $form_state['values']['title'])));
|
| 199 |
watchdog('category', 'Reset container %title to alphabetical order.', array('%title' => $form_state['values']['title']), WATCHDOG_NOTICE);
|
| 200 |
$form_state['redirect'] = 'admin/content/category/'. $form_state['values']['cnid'];
|
| 201 |
}
|
| 202 |
else {
|
| 203 |
drupal_set_message(t('Reset all containers to alphabetical order.'));
|
| 204 |
watchdog('category', 'Reset all containers to alphabetical order.', WATCHDOG_NOTICE);
|
| 205 |
$form_state['redirect'] = 'admin/content/category';
|
| 206 |
}
|
| 207 |
}
|
| 208 |
|
| 209 |
/**
|
| 210 |
* Form builder for the over of categories from a particular container.
|
| 211 |
*
|
| 212 |
* Display a tree of all the categories in a container, with options to edit
|
| 213 |
* each one. The form is made drag and drop by the theme function.
|
| 214 |
*
|
| 215 |
* @ingroup forms
|
| 216 |
* @see category_overview_categories_submit()
|
| 217 |
* @see theme_category_overview_categories()
|
| 218 |
*/
|
| 219 |
function category_overview_categories(&$form_state, $cnid) {
|
| 220 |
global $pager_page_array, $pager_total, $pager_total_items;
|
| 221 |
$container = category_get_container($cnid);
|
| 222 |
|
| 223 |
// Check for confirmation forms.
|
| 224 |
if (isset($form_state['confirm_reset_alphabetical'])) {
|
| 225 |
return category_container_confirm_reset_alphabetical($form_state, $container->cid);
|
| 226 |
}
|
| 227 |
|
| 228 |
$category_node_types = FALSE;
|
| 229 |
foreach (node_get_types() as $type) {
|
| 230 |
$behavior = variable_get('category_behavior_'. $type->type, 0);
|
| 231 |
if (!empty($behavior) && $behavior == 'category') {
|
| 232 |
$category_node_types = TRUE;
|
| 233 |
}
|
| 234 |
}
|
| 235 |
if (!$category_node_types) {
|
| 236 |
category_no_node_types('category');
|
| 237 |
}
|
| 238 |
|
| 239 |
drupal_set_title(t('Categories in %container', array('%container' => $container->title)));
|
| 240 |
$form = array(
|
| 241 |
'#container' => (array)$container,
|
| 242 |
'#tree' => TRUE,
|
| 243 |
'#parent_fields' => FALSE,
|
| 244 |
);
|
| 245 |
|
| 246 |
$page = isset($_GET['page']) ? $_GET['page'] : 0;
|
| 247 |
$page_increment = 25; // Number of categories per page.
|
| 248 |
$page_entries = 0; // Elements shown on this page.
|
| 249 |
$before_entries = 0; // Elements at the root level before this page.
|
| 250 |
$after_entries = 0; // Elements at the root level after this page.
|
| 251 |
$root_entries = 0; // Elements at the root level on this page.
|
| 252 |
|
| 253 |
// Categories from previous and next pages are shown if the category tree would have
|
| 254 |
// been cut in the middle. Keep track of how many extra categories we show on each
|
| 255 |
// page of categories.
|
| 256 |
$back_peddle = NULL;
|
| 257 |
$forward_peddle = 0;
|
| 258 |
|
| 259 |
// An array of the categories to be displayed on this page.
|
| 260 |
$current_page = array();
|
| 261 |
|
| 262 |
// Case for free tagging.
|
| 263 |
if ($container->tags) {
|
| 264 |
// We are not calling category_get_tree because that might fail with a big
|
| 265 |
// number of tags in the freetagging container.
|
| 266 |
$results = pager_query(db_rewrite_sql('SELECT n.nid, n.title, c.*, h.parent FROM {category} c INNER JOIN {node} n ON c.cid = n.nid INNER JOIN {category_hierarchy} h ON c.cid = h.cid WHERE c.cnid = %d ORDER BY c.weight, n.title', 'n', 'nid'), $page_increment, 0, NULL, $container->cid);
|
| 267 |
$total_entries = db_query(db_rewrite_sql('SELECT count(*) FROM {category} c INNER JOIN {category_hierarchy} h ON c.cid = h.cid WHERE c.cnid = %d'), $page_increment, 0, NULL, $container->cid);
|
| 268 |
while ($category = db_fetch_object($results)) {
|
| 269 |
$key = 'cid:'. $category->cid .':0';
|
| 270 |
$current_page[$key] = $category;
|
| 271 |
$page_entries++;
|
| 272 |
}
|
| 273 |
}
|
| 274 |
// Case for restricted container.
|
| 275 |
else {
|
| 276 |
$category_deltas = array();
|
| 277 |
$tree = category_get_tree($container->cid);
|
| 278 |
$category = current($tree);
|
| 279 |
$processed_categories = array();
|
| 280 |
do {
|
| 281 |
// In case this tree is completely empty.
|
| 282 |
if (empty($category)) {
|
| 283 |
break;
|
| 284 |
}
|
| 285 |
// $processed_categories is for distant-parent use only: it ensures
|
| 286 |
// that categories with multiple distant parents are only printed once,
|
| 287 |
// in contrast to categories with multiple local parents.
|
| 288 |
if (!empty($container->allowed_parent)) {
|
| 289 |
if (isset($processed_categories[$category->cid])) {
|
| 290 |
continue;
|
| 291 |
}
|
| 292 |
else {
|
| 293 |
$processed_categories[$category->cid] = TRUE;
|
| 294 |
}
|
| 295 |
}
|
| 296 |
// Count entries before the current page.
|
| 297 |
if ($page && ($page * $page_increment) > $before_entries && !isset($back_peddle)) {
|
| 298 |
$before_entries++;
|
| 299 |
continue;
|
| 300 |
}
|
| 301 |
// Count entries after the current page.
|
| 302 |
elseif ($page_entries > $page_increment && isset($complete_tree)) {
|
| 303 |
$after_entries++;
|
| 304 |
continue;
|
| 305 |
}
|
| 306 |
|
| 307 |
// Do not let a category start the page that is not at the root.
|
| 308 |
if (isset($category->depth) && ($category->depth > 0) && !isset($back_peddle)) {
|
| 309 |
$back_peddle = 0;
|
| 310 |
while ($pcategory = prev($tree)) {
|
| 311 |
$before_entries--;
|
| 312 |
$back_peddle++;
|
| 313 |
if ($pcategory->depth == 0) {
|
| 314 |
prev($tree);
|
| 315 |
continue 2; // Jump back to the start of the root level parent.
|
| 316 |
}
|
| 317 |
}
|
| 318 |
}
|
| 319 |
$back_peddle = isset($back_peddle) ? $back_peddle : 0;
|
| 320 |
|
| 321 |
// Continue rendering the tree until we reach the a new root item.
|
| 322 |
if ($page_entries >= $page_increment + $back_peddle + 1 && $category->depth == 0 && $root_entries > 1) {
|
| 323 |
$complete_tree = TRUE;
|
| 324 |
// This new item at the root level is the first item on the next page.
|
| 325 |
$after_entries++;
|
| 326 |
continue;
|
| 327 |
}
|
| 328 |
if ($page_entries >= $page_increment + $back_peddle) {
|
| 329 |
$forward_peddle++;
|
| 330 |
}
|
| 331 |
|
| 332 |
// Finally, if we've gotten down this far, we're rendering a category on this page.
|
| 333 |
$page_entries++;
|
| 334 |
$category_deltas[$category->cid] = isset($category_deltas[$category->cid]) ? $category_deltas[$category->cid] + 1 : 0;
|
| 335 |
$key = 'cid:'. $category->cid .':'. $category_deltas[$category->cid];
|
| 336 |
|
| 337 |
// Keep track of the first category displayed on this page.
|
| 338 |
if ($page_entries == 1) {
|
| 339 |
$form['#first_cid'] = $category->cid;
|
| 340 |
}
|
| 341 |
// Keep a variable to make sure at least 2 root elements are displayed.
|
| 342 |
if ($category->parents[0] == 0 || $category->parents[0] == $cnid) {
|
| 343 |
$root_entries++;
|
| 344 |
}
|
| 345 |
$current_page[$key] = $category;
|
| 346 |
} while ($category = next($tree));
|
| 347 |
|
| 348 |
// Because we didn't use a pager query, set the necessary pager variables.
|
| 349 |
$total_entries = $before_entries + $page_entries + $after_entries;
|
| 350 |
$pager_total_items[0] = $total_entries;
|
| 351 |
$pager_page_array[0] = $page;
|
| 352 |
$pager_total[0] = ceil($total_entries / $page_increment);
|
| 353 |
}
|
| 354 |
|
| 355 |
// If this form was already submitted once, it's probably hit a validation
|
| 356 |
// error. Ensure the form is rebuilt in the same order as the user submitted.
|
| 357 |
if (!empty($form_state['post'])) {
|
| 358 |
$order = array_flip(array_keys($form_state['post'])); // Get the $_POST order.
|
| 359 |
$current_page = array_merge($order, $current_page); // Update our form with the new order.
|
| 360 |
foreach ($current_page as $key => $category) {
|
| 361 |
// Verify this is a category for the current page and set at the current depth.
|
| 362 |
if (is_array($form_state['post'][$key]) && is_numeric($form_state['post'][$key]['cid'])) {
|
| 363 |
$current_page[$key]->depth = $form_state['post'][$key]['depth'];
|
| 364 |
}
|
| 365 |
else {
|
| 366 |
unset($current_page[$key]);
|
| 367 |
}
|
| 368 |
}
|
| 369 |
}
|
| 370 |
|
| 371 |
// Build the actual form.
|
| 372 |
foreach ($current_page as $key => $category) {
|
| 373 |
// Save the category for the current page so we don't have to load it a second time.
|
| 374 |
$form[$key]['#category'] = (array)$category;
|
| 375 |
if (isset($category->parents)) {
|
| 376 |
$form[$key]['#category']['parent'] = $category->parent = $category->parents[0];
|
| 377 |
unset($form[$key]['#category']['parents'], $category->parents);
|
| 378 |
}
|
| 379 |
|
| 380 |
if (!$container->tags && ($container->hierarchy < 2 || $container->allowed_parent) && count($tree) > 1) {
|
| 381 |
$form['#parent_fields'] = TRUE;
|
| 382 |
$form[$key]['cid'] = array(
|
| 383 |
'#type' => 'hidden',
|
| 384 |
'#value' => $category->cid
|
| 385 |
);
|
| 386 |
$form[$key]['parent'] = array(
|
| 387 |
'#type' => 'hidden',
|
| 388 |
// Yes, default_value on a hidden. It needs to be changeable by the javascript.
|
| 389 |
'#default_value' => $category->parent,
|
| 390 |
);
|
| 391 |
$form[$key]['depth'] = array(
|
| 392 |
'#type' => 'hidden',
|
| 393 |
// Same as above, the depth is modified by javascript, so it's a default_value.
|
| 394 |
'#default_value' => $category->depth,
|
| 395 |
);
|
| 396 |
$form[$key]['title'] = array(
|
| 397 |
'#type' => 'textfield',
|
| 398 |
'#default_value' => $category->title,
|
| 399 |
'#maxlength' => 255,
|
| 400 |
'#size' => 40,
|
| 401 |
);
|
| 402 |
}
|
| 403 |
else {
|
| 404 |
$form[$key]['title'] = array('#value' => l($category->title, "node/$category->cid"));
|
| 405 |
}
|
| 406 |
if (!empty($container->allowed_parent)) {
|
| 407 |
$parents = array();
|
| 408 |
foreach (category_get_parents($category->cid, 'cid', TRUE) as $parent) {
|
| 409 |
if (!empty($parent->cid)) {
|
| 410 |
$parents[] = l($parent->title, 'node/'. $parent->cid);
|
| 411 |
}
|
| 412 |
}
|
| 413 |
$form[$key]['parents'] = array('#value' => implode(', ', $parents));
|
| 414 |
}
|
| 415 |
$form[$key]['view'] = array('#value' => l(t('view'), "node/$category->cid"));
|
| 416 |
$form[$key]['edit'] = array('#value' => l(t('edit'), "node/$category->cid/edit", array('query' => drupal_get_destination())));
|
| 417 |
$form[$key]['delete'] = array('#value' => l(t('delete'), "node/$category->cid/delete", array('query' => drupal_get_destination())));
|
| 418 |
}
|
| 419 |
|
| 420 |
$form['#total_entries'] = $total_entries;
|
| 421 |
$form['#page_increment'] = $page_increment;
|
| 422 |
$form['#page_entries'] = $page_entries;
|
| 423 |
$form['#back_peddle'] = $back_peddle;
|
| 424 |
$form['#forward_peddle'] = $forward_peddle;
|
| 425 |
$form['#empty_text'] = t('No categories available.');
|
| 426 |
|
| 427 |
if (!$container->tags && $container->hierarchy < 2 && count($tree) > 1) {
|
| 428 |
$form['submit'] = array(
|
| 429 |
'#type' => 'submit',
|
| 430 |
'#value' => t('Save')
|
| 431 |
);
|
| 432 |
$form['reset_alphabetical'] = array(
|
| 433 |
'#type' => 'submit',
|
| 434 |
'#value' => t('Reset to alphabetical')
|
| 435 |
);
|
| 436 |
$form['destination'] = array(
|
| 437 |
'#type' => 'hidden',
|
| 438 |
'#value' => $_GET['q'] . (isset($_GET['page']) ? '?page='. $_GET['page'] : '')
|
| 439 |
);
|
| 440 |
}
|
| 441 |
|
| 442 |
return $form;
|
| 443 |
}
|
| 444 |
|
| 445 |
/**
|
| 446 |
* Submit handler for categories overview form.
|
| 447 |
*
|
| 448 |
* Rather than using a textfield or weight field, this form depends entirely
|
| 449 |
* upon the order of form elements on the page to determine new weights.
|
| 450 |
*
|
| 451 |
* Because there might be hundreds or thousands of categories that need to
|
| 452 |
* be ordered, categories are weighted from 0 to the number of categories in the
|
| 453 |
* container, rather than the standard -10 to 10 scale. Numbers are sorted
|
| 454 |
* lowest to highest, but are not necessarily sequential. Numbers may be skipped
|
| 455 |
* when a category has children so that reordering is minimal when a child is
|
| 456 |
* added or removed from a category.
|
| 457 |
*
|
| 458 |
* @see category_overview_categories()
|
| 459 |
*/
|
| 460 |
function category_overview_categories_submit($form, &$form_state) {
|
| 461 |
if ($form_state['clicked_button']['#value'] == t('Reset to alphabetical')) {
|
| 462 |
// Execute the reset action.
|
| 463 |
if ($form_state['values']['reset_alphabetical'] === TRUE) {
|
| 464 |
return category_container_confirm_reset_alphabetical_submit($form, $form_state);
|
| 465 |
}
|
| 466 |
// Rebuild the form to confirm the reset action.
|
| 467 |
$form_state['rebuild'] = TRUE;
|
| 468 |
$form_state['confirm_reset_alphabetical'] = TRUE;
|
| 469 |
return;
|
| 470 |
}
|
| 471 |
|
| 472 |
$order = array_flip(array_keys($form['#post'])); // Get the $_POST order.
|
| 473 |
$form_state['values'] = array_merge($order, $form_state['values']); // Update our original form with the new order.
|
| 474 |
|
| 475 |
$container = $form['#container'];
|
| 476 |
$hierarchy = 0; // Update the current hierarchy type as we go.
|
| 477 |
|
| 478 |
$changed_categories = array();
|
| 479 |
$tree = category_get_tree($container['cid']);
|
| 480 |
|
| 481 |
if (empty($tree)) {
|
| 482 |
return;
|
| 483 |
}
|
| 484 |
|
| 485 |
// Build a list of all categories that need to be updated on previous pages.
|
| 486 |
$weight = 0;
|
| 487 |
$category = (array)$tree[0];
|
| 488 |
while ($category['cid'] != $form['#first_cid']) {
|
| 489 |
if ($category['parents'][0] == 0 && $category['weight'] != $weight) {
|
| 490 |
$category['parent'] = $category['parents'][0];
|
| 491 |
$category['weight'] = $weight;
|
| 492 |
$changed_categories[$category['cid']] = $category;
|
| 493 |
}
|
| 494 |
$weight++;
|
| 495 |
$hierarchy = !category_is_root_parent($category['parents'][0], $container['cid']) ? 1 : $hierarchy;
|
| 496 |
$category = (array)$tree[$weight];
|
| 497 |
}
|
| 498 |
|
| 499 |
// Renumber the current page weights and assign any new parents.
|
| 500 |
$level_weights = array();
|
| 501 |
foreach ($form_state['values'] as $cid => $values) {
|
| 502 |
if (isset($form[$cid]['#category'])) {
|
| 503 |
$category = $form[$cid]['#category'];
|
| 504 |
// Give categories at the root level a weight in sequence with categories on previous pages.
|
| 505 |
if ($values['parent'] == 0 && $category['weight'] != $weight) {
|
| 506 |
$category['weight'] = $weight;
|
| 507 |
$changed_categories[$category['cid']] = $category;
|
| 508 |
}
|
| 509 |
// Categories not at the root level can safely start from 0 because they're all on this page.
|
| 510 |
elseif ($values['parent'] > 0) {
|
| 511 |
$level_weights[$values['parent']] = isset($level_weights[$values['parent']]) ? $level_weights[$values['parent']] + 1 : 0;
|
| 512 |
if ($level_weights[$values['parent']] != $category['weight']) {
|
| 513 |
$category['weight'] = $level_weights[$values['parent']];
|
| 514 |
$changed_categories[$category['cid']] = $category;
|
| 515 |
}
|
| 516 |
}
|
| 517 |
// Update any changed parents.
|
| 518 |
if ($values['parent'] != $category['parent']) {
|
| 519 |
$category['parent'] = $values['parent'];
|
| 520 |
$changed_categories[$category['cid']] = $category;
|
| 521 |
}
|
| 522 |
$hierarchy = !category_is_root_parent($category['parent'], $container['cid']) ? 1 : $hierarchy;
|
| 523 |
$weight++;
|
| 524 |
|
| 525 |
// Update the title if changed.
|
| 526 |
if (!empty($values['title']) && $category['title'] != $values['title']) {
|
| 527 |
$category['original_title'] = $category['title'];
|
| 528 |
$category['title'] = $values['title'];
|
| 529 |
$category['title_changed'] = TRUE;
|
| 530 |
$changed_categories[$category['cid']] = $category;
|
| 531 |
}
|
| 532 |
}
|
| 533 |
}
|
| 534 |
|
| 535 |
// Build a list of all categories that need to be updated on following pages.
|
| 536 |
for ($weight; $weight < count($tree); $weight++) {
|
| 537 |
$category = (array)$tree[$weight];
|
| 538 |
if ($category['parents'][0] == 0 && $category['weight'] != $weight) {
|
| 539 |
$category['parent'] = $category['parents'][0];
|
| 540 |
$category['weight'] = $weight;
|
| 541 |
$changed_categories[$category['cid']] = $category;
|
| 542 |
}
|
| 543 |
$hierarchy = !category_is_root_parent($category['parents'][0], $container['cid']) ? 1 : $hierarchy;
|
| 544 |
}
|
| 545 |
|
| 546 |
// Save all updated categories.
|
| 547 |
foreach ($changed_categories as $category) {
|
| 548 |
$node = new StdClass();
|
| 549 |
$node->nid = $category['cid'];
|
| 550 |
$node->category = (array) category_get_category($category['cid']);
|
| 551 |
$node->category['weight'] = $category['weight'];
|
| 552 |
if (empty($container['allowed_parent'])) {
|
| 553 |
$parent = empty($category['parent']) ? $category['cnid'] : $category['parent'];
|
| 554 |
$node->category['parents'] = array($parent => $parent);
|
| 555 |
}
|
| 556 |
else {
|
| 557 |
$node->category['parents'] = _category_flatten_parents(category_get_parents($category['cid']));
|
| 558 |
}
|
| 559 |
category_save_category($node);
|
| 560 |
// Save the title change.
|
| 561 |
if (!empty($category['title_changed'])) {
|
| 562 |
$node = node_load($category['cid'], FALSE);
|
| 563 |
db_query("UPDATE {node} SET title = '%s' WHERE nid = %d", $category['title'], $category['cid']);
|
| 564 |
db_query("UPDATE {node_revisions} SET title = '%s' WHERE vid = %d", $category['title'], $node->vid);
|
| 565 |
watchdog('content', 'category: title changed from %original to %current.', array('%original' => $category['original_title'], '%current' => $category['title']), WATCHDOG_NOTICE, l(t('view'), 'node/'. $category['cid']));
|
| 566 |
}
|
| 567 |
}
|
| 568 |
|
| 569 |
// Update the container hierarchy to flat or single hierarchy.
|
| 570 |
if ($container['hierarchy'] != $hierarchy && empty($container['allowed_parent'])) {
|
| 571 |
$node = new StdClass();
|
| 572 |
$node->nid = $container['cid'];
|
| 573 |
$node->category = (array) category_get_container($container['cid']);
|
| 574 |
$node->category['parents'] = _category_flatten_parents(category_get_parents($container['cid']));
|
| 575 |
$node->category['hierarchy'] = $hierarchy;
|
| 576 |
category_save_container($node);
|
| 577 |
}
|
| 578 |
|
| 579 |
cache_clear_all();
|
| 580 |
}
|
| 581 |
|
| 582 |
/**
|
| 583 |
* Theme the categories overview as a sortable list of categories.
|
| 584 |
*
|
| 585 |
* @ingroup themeable
|
| 586 |
* @see category_overview_categories()
|
| 587 |
*/
|
| 588 |
function theme_category_overview_categories($form) {
|
| 589 |
$page_increment = $form['#page_increment'];
|
| 590 |
$page_entries = $form['#page_entries'];
|
| 591 |
$back_peddle = $form['#back_peddle'];
|
| 592 |
$forward_peddle = $form['#forward_peddle'];
|
| 593 |
|
| 594 |
// Add drag and drop if parent fields are present in the form.
|
| 595 |
if ($form['#parent_fields']) {
|
| 596 |
if (empty($form['#container']['allowed_parent'])) {
|
| 597 |
drupal_add_tabledrag('category', 'match', 'parent', 'category-parent', 'category-parent', 'category-id', FALSE);
|
| 598 |
}
|
| 599 |
drupal_add_tabledrag('category', 'depth', 'group', 'category-depth', NULL, NULL, FALSE);
|
| 600 |
drupal_add_js(drupal_get_path('module', 'category') .'/category.js');
|
| 601 |
drupal_add_js(array('category' => array('backPeddle' => $back_peddle, 'forwardPeddle' => $forward_peddle)), 'setting');
|
| 602 |
drupal_add_css(drupal_get_path('module', 'category') .'/category.css');
|
| 603 |
}
|
| 604 |
|
| 605 |
$errors = form_get_errors() != FALSE ? form_get_errors() : array();
|
| 606 |
$rows = array();
|
| 607 |
foreach (element_children($form) as $key) {
|
| 608 |
if (isset($form[$key]['#category'])) {
|
| 609 |
$category = &$form[$key];
|
| 610 |
|
| 611 |
$row = array();
|
| 612 |
$row[] = (isset($category['#category']['depth']) && $category['#category']['depth'] > 0 ? theme('indentation', $category['#category']['depth']) : '') . drupal_render($category['title']);
|
| 613 |
if ($form['#parent_fields']) {
|
| 614 |
$category['cid']['#attributes']['class'] = 'category-id';
|
| 615 |
$category['parent']['#attributes']['class'] = 'category-parent';
|
| 616 |
$category['depth']['#attributes']['class'] = 'category-depth';
|
| 617 |
$row[0] .= drupal_render($category['parent']) . drupal_render($category['cid']) . drupal_render($category['depth']);
|
| 618 |
}
|
| 619 |
if (!empty($form['#container']['allowed_parent'])) {
|
| 620 |
$row[] = drupal_render($category['parents']);
|
| 621 |
}
|
| 622 |
$row[] = drupal_render($category['view']);
|
| 623 |
$row[] = drupal_render($category['edit']);
|
| 624 |
$row[] = drupal_render($category['delete']);
|
| 625 |
|
| 626 |
$row = array('data' => $row);
|
| 627 |
$rows[$key] = $row;
|
| 628 |
}
|
| 629 |
}
|
| 630 |
|
| 631 |
// Add necessary classes to rows.
|
| 632 |
$row_position = 0;
|
| 633 |
foreach ($rows as $key => $row) {
|
| 634 |
$classes = array();
|
| 635 |
if (isset($form['#parent_fields'])) {
|
| 636 |
$classes[] = 'draggable';
|
| 637 |
}
|
| 638 |
|
| 639 |
// Add classes that mark which categories belong to previous and next pages.
|
| 640 |
if ($row_position < $back_peddle || $row_position >= $page_entries - $forward_peddle) {
|
| 641 |
$classes[] = 'category-category-preview';
|
| 642 |
}
|
| 643 |
|
| 644 |
if ($row_position !== 0 && $row_position !== count($rows) - 1) {
|
| 645 |
if ($row_position == $back_peddle - 1 || $row_position == $page_entries - $forward_peddle - 1) {
|
| 646 |
$classes[] = 'category-category-divider-top';
|
| 647 |
}
|
| 648 |
elseif ($row_position == $back_peddle || $row_position == $page_entries - $forward_peddle) {
|
| 649 |
$classes[] = 'category-category-divider-bottom';
|
| 650 |
}
|
| 651 |
}
|
| 652 |
|
| 653 |
// Add an error class if this row contains a form error.
|
| 654 |
foreach ($errors as $error_key => $error) {
|
| 655 |
if (strpos($error_key, $key) === 0) {
|
| 656 |
$classes[] = 'error';
|
| 657 |
}
|
| 658 |
}
|
| 659 |
$rows[$key]['class'] = implode(' ', $classes);
|
| 660 |
$row_position++;
|
| 661 |
}
|
| 662 |
$header = array(t('Name'));
|
| 663 |
$cols = 4;
|
| 664 |
if (!empty($form['#container']['allowed_parent'])) {
|
| 665 |
$header[] = t('Parents');
|
| 666 |
$cols++;
|
| 667 |
}
|
| 668 |
$header[] = array('data' => t('Operations'), 'colspan' => '3');
|
| 669 |
|
| 670 |
if (empty($rows)) {
|
| 671 |
$rows[] = array(array('data' => $form['#empty_text'], 'colspan' => $cols));
|
| 672 |
}
|
| 673 |
|
| 674 |
$output = theme('table', $header, $rows, array('id' => 'category'));
|
| 675 |
$output .= drupal_render($form);
|
| 676 |
$output .= theme('pager', NULL, $page_increment);
|
| 677 |
|
| 678 |
return $output;
|
| 679 |
}
|
| 680 |
|
| 681 |
/**
|
| 682 |
* Menu callback; presents a list of all node types with container behavior,
|
| 683 |
* and for each one, outputs a link to its 'node add' page. If there is only
|
| 684 |
* one node type with container behavior, then the user is immediately
|
| 685 |
* redirected to the 'node add' page for that node type.
|
| 686 |
*/
|
| 687 |
function category_add_container_page() {
|
| 688 |
$items = array();
|
| 689 |
$destination = 'admin/content/category';
|
| 690 |
$url = NULL;
|
| 691 |
foreach (node_get_types() as $type) {
|
| 692 |
$behavior = variable_get('category_behavior_'. $type->type, 0);
|
| 693 |
if (!empty($behavior) && $behavior == 'container') {
|
| 694 |
$url = 'node/add/'. str_replace('_', '-', $type->type);
|
| 695 |
$items[] = l($type->name, $url, array('query' => array('destination' => $destination)));
|
| 696 |
}
|
| 697 |
}
|
| 698 |
|
| 699 |
if (empty($items)) {
|
| 700 |
category_no_node_types();
|
| 701 |
}
|
| 702 |
if (count($items) == 1) {
|
| 703 |
drupal_goto($url, 'destination='. $destination);
|
| 704 |
}
|
| 705 |
return theme('item_list', $items);
|
| 706 |
}
|
| 707 |
|
| 708 |
/**
|
| 709 |
* Prints a warning message, indicating that there are no node types with
|
| 710 |
* category or container behavior available.
|
| 711 |
*/
|
| 712 |
function category_no_node_types($behavior = 'container') {
|
| 713 |
drupal_set_message(t('There are no content types with @behavior behavior available'. ($behavior == 'category' ? ' for use with this container' : '') .'. In order to create a @behavior, you must first go to the !content-types page, and assign @behavior behavior to one or more of your content types.', array('!content-types' => l(t('administer content types'), 'admin/content/types'), '@behavior' => $behavior)), 'warning');
|
| 714 |
}
|
| 715 |
|
| 716 |
/**
|
| 717 |
* Menu callback; presents a list of all node types with container behavior,
|
| 718 |
* and for each one, outputs a link to its 'node add' page. If there is only
|
| 719 |
* one node type with container behavior, then the user is immediately
|
| 720 |
* redirected to the 'node add' page for that node type.
|
| 721 |
*/
|
| 722 |
function category_add_category_page($cnid) {
|
| 723 |
$items = array();
|
| 724 |
$destination = 'admin/content/category/'. $cnid;
|
| 725 |
$url = NULL;
|
| 726 |
foreach (node_get_types() as $type) {
|
| 727 |
$behavior = variable_get('category_behavior_'. $type->type, 0);
|
| 728 |
if (!empty($behavior) && $behavior == 'category') {
|
| 729 |
$allowed_containers = variable_get('category_allowed_containers_'. $type->type, array());
|
| 730 |
if (empty($allowed_containers) || in_array($cnid, $allowed_containers)) {
|
| 731 |
$url = 'node/add/'. str_replace('_', '-', $type->type);
|
| 732 |
$items[] = l($type->name, $url, array('query' => array('destination' => $destination, 'parent' => $cnid)));
|
| 733 |
}
|
| 734 |
}
|
| 735 |
}
|
| 736 |
|
| 737 |
if (empty($items)) {
|
| 738 |
category_no_node_types('category');
|
| 739 |
}
|
| 740 |
if (count($items) == 1) {
|
| 741 |
drupal_goto($url, 'destination='. $destination .'&parent='. $cnid);
|
| 742 |
}
|
| 743 |
return theme('item_list', $items);
|
| 744 |
}
|
| 745 |
|
| 746 |
function category_wrapper_admin_page() {
|
| 747 |
$book_status = category_get_wrapper_status('book');
|
| 748 |
$taxonomy_status = category_get_wrapper_status('taxonomy');
|
| 749 |
$form['book_wrapper'] = array(
|
| 750 |
'#type' => 'item',
|
| 751 |
'#title' => t('Book wrapper status'),
|
| 752 |
'#value' => theme('category_wrapper_status', 'book', $book_status),
|
| 753 |
);
|
| 754 |
$form['taxonomy_wrapper'] = array(
|
| 755 |
'#type' => 'item',
|
| 756 |
'#title' => t('Taxonomy wrapper status'),
|
| 757 |
'#value' => theme('category_wrapper_status', 'taxonomy', $taxonomy_status),
|
| 758 |
);
|
| 759 |
|
| 760 |
return $form;
|
| 761 |
}
|
| 762 |
|
| 763 |
/**
|
| 764 |
* Themes the message indicating the status of the specified wrapper module.
|
| 765 |
*
|
| 766 |
* @param $type
|
| 767 |
* The type of wrapper interface being themed ('taxonomy' or 'book').
|
| 768 |
* @param $status
|
| 769 |
* Boolean indicating if the specified wrapper is currently installed.
|
| 770 |
*
|
| 771 |
* @return
|
| 772 |
* Themed output.
|
| 773 |
*/
|
| 774 |
function theme_category_wrapper_status($type, $status) {
|
| 775 |
drupal_add_css(drupal_get_path('module', 'category') .'/category.css');
|
| 776 |
$output = '<p>';
|
| 777 |
|
| 778 |
if (module_exists($type)) {
|
| 779 |
if ($status) {
|
| 780 |
$output .= t('The @type wrapper is currently <span class="category-wrapper-installed">installed</span>.', array('@type' => $type)) ."\n";
|
| 781 |
$output .= '<br/>'. l(t('Uninstall now'), "category/wrapper/$type/uninstall");
|
| 782 |
}
|
| 783 |
else {
|
| 784 |
$output .= '<p>'. t('The @type wrapper is currently <span class="category-wrapper-notinstalled">not installed</span>.', array('@type' => $type)) ."\n";
|
| 785 |
$output .= '<br/>'. l(t('Install now'), "category/wrapper/$type/install");
|
| 786 |
}
|
| 787 |
}
|
| 788 |
else {
|
| 789 |
$output .= t('The @type module (original or wrapper) is currently <span class="category-wrapper-notinstalled">not enabled</span>. You must enable it on the <a href="@module-admin-page">module administration page</a> before you can perform an install or an uninstall.', array('@type' => $type, '@module-admin-page' => url('admin/build/modules'))) ."\n";
|
| 790 |
}
|
| 791 |
$output .= '</p>';
|
| 792 |
return $output;
|
| 793 |
}
|