/[drupal]/contributions/modules/category/category.admin.inc
ViewVC logotype

Contents of /contributions/modules/category/category.admin.inc

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Wed Aug 5 04:52:53 2009 UTC (3 months, 3 weeks ago) by jaza
Branch: MAIN
CVS Tags: DRUPAL-6--2-0-RC1, HEAD
Changes since 1.4: +7 -9 lines
File MIME type: text/x-php
#158598 by JirkaRybka: a massive collection of bug fixes, D6 upgrades, and performance / usability improvements and other tasks for the category package. This commit includes patches from the following threads:
 - #370641: Port category_views to D6
 - #370633: Port category_breadcrumb to D6
 - #484624: Fix all broken category/container previews, and add category_display defaults
 - #481280: Generated menu items vs. menu administration and weights
 - #457688: Get rid of Menu wrapper, moving functionality to category_menu
 - #484084: Update README.txt and friends
 - #483978: Remove t() from database schema descriptions
 - #501378: PERFORMANCE! Central caching for category API functions
 - #521680: Missing argument error on category/### paths
 - #521714: Missing JavaScript file in Taxonomy wrapper
Lots and lots of thanks go to JirkaRybka for this monumental cleanup effort.
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 }

  ViewVC Help
Powered by ViewVC 1.1.2