/[drupal]/drupal/modules/taxonomy/taxonomy.admin.inc
ViewVC logotype

Contents of /drupal/modules/taxonomy/taxonomy.admin.inc

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


Revision 1.82 - (show annotations) (download) (as text)
Sat Nov 7 14:18:07 2009 UTC (3 weeks ago) by webchick
Branch: MAIN
Changes since 1.81: +9 -2 lines
File MIME type: text/x-php
#625460 by sun: Add input format to taxonomy term descriptions.
1 <?php
2 // $Id: taxonomy.admin.inc,v 1.81 2009/11/03 05:27:18 webchick Exp $
3
4 /**
5 * @file
6 * Administrative page callbacks for the taxonomy module.
7 */
8
9 /**
10 * Form builder to list and manage vocabularies.
11 *
12 * @ingroup forms
13 * @see taxonomy_overview_vocabularies_submit()
14 * @see theme_taxonomy_overview_vocabularies()
15 */
16 function taxonomy_overview_vocabularies($form) {
17 $vocabularies = taxonomy_get_vocabularies();
18 $form['#tree'] = TRUE;
19 foreach ($vocabularies as $vocabulary) {
20 $form[$vocabulary->vid]['#vocabulary'] = $vocabulary;
21 $form[$vocabulary->vid]['name'] = array('#markup' => check_plain($vocabulary->name));
22 $form[$vocabulary->vid]['weight'] = array('#type' => 'weight', '#delta' => 10, '#default_value' => $vocabulary->weight);
23 $form[$vocabulary->vid]['edit'] = array('#type' => 'link', '#title' => t('edit vocabulary'), '#href' => "admin/structure/taxonomy/$vocabulary->vid");
24 $form[$vocabulary->vid]['list'] = array('#type' => 'link', '#title' => t('list terms'), '#href' => "admin/structure/taxonomy/$vocabulary->vid/list");
25 $form[$vocabulary->vid]['add'] = array('#type' => 'link', '#title' => t('add terms'), '#href' => "admin/structure/taxonomy/$vocabulary->vid/list/add");
26 }
27
28 // Only make this form include a submit button and weight if more than one
29 // vocabulary exists.
30 if (count($vocabularies) > 1) {
31 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
32 }
33 elseif (isset($vocabulary)) {
34 unset($form[$vocabulary->vid]['weight']);
35 }
36 return $form;
37 }
38
39 /**
40 * Submit handler for vocabularies overview. Updates changed vocabulary weights.
41 *
42 * @see taxonomy_overview_vocabularies()
43 */
44 function taxonomy_overview_vocabularies_submit($form, &$form_state) {
45 foreach ($form_state['values'] as $vid => $vocabulary) {
46 if (is_numeric($vid) && $form[$vid]['#vocabulary']->weight != $form_state['values'][$vid]['weight']) {
47 $form[$vid]['#vocabulary']->weight = $form_state['values'][$vid]['weight'];
48 taxonomy_vocabulary_save($form[$vid]['#vocabulary']);
49 }
50 }
51 }
52
53 /**
54 * Theme the vocabulary overview as a sortable list of vocabularies.
55 *
56 * @ingroup themeable
57 * @see taxonomy_overview_vocabularies()
58 */
59 function theme_taxonomy_overview_vocabularies($variables) {
60 $form = $variables['form'];
61
62 $rows = array();
63
64 foreach (element_children($form) as $key) {
65 if (isset($form[$key]['name'])) {
66 $vocabulary = &$form[$key];
67
68 $row = array();
69 $row[] = drupal_render($vocabulary['name']);
70 if (isset($vocabulary['weight'])) {
71 $vocabulary['weight']['#attributes']['class'] = array('vocabulary-weight');
72 $row[] = drupal_render($vocabulary['weight']);
73 }
74 $row[] = drupal_render($vocabulary['edit']);
75 $row[] = drupal_render($vocabulary['list']);
76 $row[] = drupal_render($vocabulary['add']);
77 $rows[] = array('data' => $row, 'class' => array('draggable'));
78 }
79 }
80
81 if (empty($rows)) {
82 $rows[] = array(array('data' => t('No vocabularies available. <a href="@link">Add vocabulary</a>.', array('@link' => url('admin/structure/taxonomy/add'))), 'colspan' => '5'));
83 }
84
85 $header = array(t('Vocabulary name'));
86 if (isset($form['submit'])) {
87 $header[] = t('Weight');
88 drupal_add_tabledrag('taxonomy', 'order', 'sibling', 'vocabulary-weight');
89 }
90 $header[] = array('data' => t('Operations'), 'colspan' => '3');
91 return theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'taxonomy'))) . drupal_render_children($form);
92 }
93
94 /**
95 * Display form for adding and editing vocabularies.
96 *
97 * @ingroup forms
98 * @see taxonomy_form_vocabulary_submit()
99 */
100 function taxonomy_form_vocabulary($form, &$form_state, $edit = array()) {
101 if (!is_array($edit)) {
102 $edit = (array)$edit;
103 }
104 $edit += array(
105 'name' => '',
106 'machine_name' => '',
107 'description' => '',
108 'hierarchy' => 0,
109 'weight' => 0,
110 );
111 $form['#vocabulary'] = (object) $edit;
112 // Check whether we need a deletion confirmation form.
113 if (isset($form_state['confirm_delete']) && isset($form_state['values']['vid'])) {
114 return taxonomy_vocabulary_confirm_delete($form, $form_state, $form_state['values']['vid']);
115 }
116 $form['name'] = array(
117 '#type' => 'textfield',
118 '#title' => t('Name'),
119 '#default_value' => $edit['name'],
120 '#maxlength' => 255,
121 '#required' => TRUE,
122 '#field_suffix' => ' <small id="edit-name-suffix">&nbsp</small>',
123 );
124 $js_settings = array(
125 'type' => 'setting',
126 'data' => array(
127 'machineReadableValue' => array(
128 'name' => array(
129 'text' => t('Machine name'),
130 'target' => 'machine-name',
131 'searchPattern' => '[^a-z0-9]+',
132 'replaceToken' => '_',
133 ),
134 ),
135 ),
136 );
137 $form['machine_name'] = array(
138 '#type' => 'textfield',
139 '#title' => t('Machine readable name'),
140 '#default_value' => $edit['machine_name'],
141 '#maxlength' => 255,
142 '#description' => t('The unique machine readable name for this vocabulary, used for theme templates, can only contain lowercase letters, numbers and underscores.'),
143 '#required' => TRUE,
144 '#attached' => array(
145 'js' => array(drupal_get_path('module', 'system') . '/system.js', $js_settings),
146 ),
147 );
148 $form['description'] = array(
149 '#type' => 'textfield',
150 '#title' => t('Description'),
151 '#default_value' => $edit['description'],
152 );
153 // Set the hierarchy to "multiple parents" by default. This simplifies the
154 // vocabulary form and standardizes the term form.
155 $form['hierarchy'] = array(
156 '#type' => 'value',
157 '#value' => '0',
158 );
159
160 $form['submit'] = array('#type' => 'submit', '#value' => t('Save'));
161 if (isset($edit['vid'])) {
162 $form['delete'] = array('#type' => 'submit', '#value' => t('Delete'));
163 $form['vid'] = array('#type' => 'value', '#value' => $edit['vid']);
164 $form['module'] = array('#type' => 'value', '#value' => $edit['module']);
165 }
166 return $form;
167 }
168
169 /**
170 * Validation handler for the vocabulary form.
171 *
172 * @see taxonomy_form_vocabulary()
173 */
174 function taxonomy_form_vocabulary_validate($form, &$form_state) {
175 if ($form_state['clicked_button']['#value'] != t('Delete') && isset($form_state['values']['machine_name'])) {
176
177 // Restrict machine names to appropriate characters.
178 $machine_name = $form_state['values']['machine_name'];
179 if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['machine_name'])) {
180 form_set_error('machine_name', t('The machine-readable name must contain only lowercase letters, numbers, and underscores.'));
181 }
182 // Restrict machine names to 21 characters to avoid exceeding the limit
183 // for field names.
184 if (drupal_strlen($machine_name) > 21) {
185 form_set_error('machine_name', t('The machine-readable name must not exceed 21 characters.'));
186 }
187
188 // Do not allow duplicate machine names.
189 $vocabularies = taxonomy_get_vocabularies();
190 foreach ($vocabularies as $vocabulary) {
191 if ($machine_name == $vocabulary->machine_name && (!isset($form_state['values']['vid']) || $vocabulary->vid != $form_state['values']['vid'])) {
192 form_set_error('machine_name', t('This machine-readable name is already in use by another vocabulary and must be unique.'));
193 }
194 }
195 }
196 }
197 /**
198 * Accept the form submission for a vocabulary and save the results.
199 */
200 function taxonomy_form_vocabulary_submit($form, &$form_state) {
201 $old_vocabulary = $form['#vocabulary'];
202 if ($form_state['clicked_button']['#value'] == t('Delete')) {
203 // Rebuild the form to confirm vocabulary deletion.
204 $form_state['rebuild'] = TRUE;
205 $form_state['confirm_delete'] = TRUE;
206 return;
207 }
208 $vocabulary = (object) $form_state['values'];
209 if ($vocabulary->machine_name != $old_vocabulary->machine_name) {
210 field_attach_rename_bundle('taxonomy_term', $old_vocabulary->machine_name, $vocabulary->machine_name);
211 }
212 switch (taxonomy_vocabulary_save($vocabulary)) {
213 case SAVED_NEW:
214 drupal_set_message(t('Created new vocabulary %name.', array('%name' => $vocabulary->name)));
215 watchdog('taxonomy', 'Created new vocabulary %name.', array('%name' => $vocabulary->name), WATCHDOG_NOTICE, l(t('edit'), 'admin/structure/taxonomy/' . $vocabulary->vid));
216 break;
217 case SAVED_UPDATED:
218 drupal_set_message(t('Updated vocabulary %name.', array('%name' => $vocabulary->name)));
219 watchdog('taxonomy', 'Updated vocabulary %name.', array('%name' => $vocabulary->name), WATCHDOG_NOTICE, l(t('edit'), 'admin/structure/taxonomy/' . $vocabulary->vid));
220 break;
221 }
222
223 $form_state['vid'] = $vocabulary->vid;
224 $form_state['redirect'] = 'admin/structure/taxonomy';
225 return;
226 }
227
228 /**
229 * Form builder for the taxonomy terms overview.
230 *
231 * Display a tree of all the terms in a vocabulary, with options to edit
232 * each one. The form is made drag and drop by the theme function.
233 *
234 * @ingroup forms
235 * @see taxonomy_overview_terms_submit()
236 * @see theme_taxonomy_overview_terms()
237 */
238 function taxonomy_overview_terms($form, &$form_state, $vocabulary) {
239 global $pager_page_array, $pager_total, $pager_total_items;
240
241 // Check for confirmation forms.
242 if (isset($form_state['confirm_reset_alphabetical'])) {
243 return taxonomy_vocabulary_confirm_reset_alphabetical($form, $form_state, $vocabulary->vid);
244 }
245
246 $form['#vocabulary'] = $vocabulary;
247 $form['#tree'] = TRUE;
248 $form['#parent_fields'] = FALSE;
249
250 $page = isset($_GET['page']) ? $_GET['page'] : 0;
251 $page_increment = variable_get('taxonomy_terms_per_page_admin', 100); // Number of terms per page.
252 $page_entries = 0; // Elements shown on this page.
253 $before_entries = 0; // Elements at the root level before this page.
254 $after_entries = 0; // Elements at the root level after this page.
255 $root_entries = 0; // Elements at the root level on this page.
256
257 // Terms from previous and next pages are shown if the term tree would have
258 // been cut in the middle. Keep track of how many extra terms we show on each
259 // page of terms.
260 $back_peddle = NULL;
261 $forward_peddle = 0;
262
263 // An array of the terms to be displayed on this page.
264 $current_page = array();
265
266 $term_deltas = array();
267 $tree = taxonomy_get_tree($vocabulary->vid);
268 $term = current($tree);
269 do {
270 // In case this tree is completely empty.
271 if (empty($term)) {
272 break;
273 }
274 // Count entries before the current page.
275 if ($page && ($page * $page_increment) > $before_entries && !isset($back_peddle)) {
276 $before_entries++;
277 continue;
278 }
279 // Count entries after the current page.
280 elseif ($page_entries > $page_increment && isset($complete_tree)) {
281 $after_entries++;
282 continue;
283 }
284
285 // Do not let a term start the page that is not at the root.
286 if (isset($term->depth) && ($term->depth > 0) && !isset($back_peddle)) {
287 $back_peddle = 0;
288 while ($pterm = prev($tree)) {
289 $before_entries--;
290 $back_peddle++;
291 if ($pterm->depth == 0) {
292 prev($tree);
293 continue 2; // Jump back to the start of the root level parent.
294 }
295 }
296 }
297 $back_peddle = isset($back_peddle) ? $back_peddle : 0;
298
299 // Continue rendering the tree until we reach the a new root item.
300 if ($page_entries >= $page_increment + $back_peddle + 1 && $term->depth == 0 && $root_entries > 1) {
301 $complete_tree = TRUE;
302 // This new item at the root level is the first item on the next page.
303 $after_entries++;
304 continue;
305 }
306 if ($page_entries >= $page_increment + $back_peddle) {
307 $forward_peddle++;
308 }
309
310 // Finally, if we've gotten down this far, we're rendering a term on this page.
311 $page_entries++;
312 $term_deltas[$term->tid] = isset($term_deltas[$term->tid]) ? $term_deltas[$term->tid] + 1 : 0;
313 $key = 'tid:' . $term->tid . ':' . $term_deltas[$term->tid];
314
315 // Keep track of the first term displayed on this page.
316 if ($page_entries == 1) {
317 $form['#first_tid'] = $term->tid;
318 }
319 // Keep a variable to make sure at least 2 root elements are displayed.
320 if ($term->parents[0] == 0) {
321 $root_entries++;
322 }
323 $current_page[$key] = $term;
324 } while ($term = next($tree));
325
326 // Because we didn't use a pager query, set the necessary pager variables.
327 $total_entries = $before_entries + $page_entries + $after_entries;
328 $pager_total_items[0] = $total_entries;
329 $pager_page_array[0] = $page;
330 $pager_total[0] = ceil($total_entries / $page_increment);
331
332 // If this form was already submitted once, it's probably hit a validation
333 // error. Ensure the form is rebuilt in the same order as the user submitted.
334 if (!empty($form_state['input'])) {
335 $order = array_flip(array_keys($form_state['input'])); // Get the $_POST order.
336 $current_page = array_merge($order, $current_page); // Update our form with the new order.
337 foreach ($current_page as $key => $term) {
338 // Verify this is a term for the current page and set at the current depth.
339 if (is_array($form_state['input'][$key]) && is_numeric($form_state['input'][$key]['tid'])) {
340 $current_page[$key]->depth = $form_state['input'][$key]['depth'];
341 }
342 else {
343 unset($current_page[$key]);
344 }
345 }
346 }
347
348 // Build the actual form.
349 foreach ($current_page as $key => $term) {
350 // Save the term for the current page so we don't have to load it a second time.
351 $form[$key]['#term'] = (array)$term;
352 if (isset($term->parents)) {
353 $form[$key]['#term']['parent'] = $term->parent = $term->parents[0];
354 unset($form[$key]['#term']['parents'], $term->parents);
355 }
356
357 $form[$key]['view'] = array('#type' => 'link', '#title' => $term->name, '#href' => "taxonomy/term/$term->tid");
358 if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
359 $form['#parent_fields'] = TRUE;
360 $form[$key]['tid'] = array(
361 '#type' => 'hidden',
362 '#value' => $term->tid
363 );
364 $form[$key]['parent'] = array(
365 '#type' => 'hidden',
366 // Yes, default_value on a hidden. It needs to be changeable by the javascript.
367 '#default_value' => $term->parent,
368 );
369 $form[$key]['depth'] = array(
370 '#type' => 'hidden',
371 // Same as above, the depth is modified by javascript, so it's a default_value.
372 '#default_value' => $term->depth,
373 );
374 }
375 $form[$key]['edit'] = array('#type' => 'link', '#title' => t('edit'), '#href' => 'taxonomy/term/' . $term->tid . '/edit', '#options' => array('query' => drupal_get_destination()));
376 }
377
378 $form['#total_entries'] = $total_entries;
379 $form['#page_increment'] = $page_increment;
380 $form['#page_entries'] = $page_entries;
381 $form['#back_peddle'] = $back_peddle;
382 $form['#forward_peddle'] = $forward_peddle;
383 $form['#empty_text'] = t('No terms available. <a href="@link">Add term</a>.', array('@link' => url('admin/structure/taxonomy/' . $vocabulary->vid . '/list/add')));
384
385 if ($vocabulary->hierarchy < 2 && count($tree) > 1) {
386 $form['submit'] = array(
387 '#type' => 'submit',
388 '#value' => t('Save')
389 );
390 $form['reset_alphabetical'] = array(
391 '#type' => 'submit',
392 '#value' => t('Reset to alphabetical')
393 );
394 $form_state['redirect'] = array($_GET['q'], (isset($_GET['page']) ? array('query' => array('page' => $_GET['page'])) : array()));
395 }
396
397 return $form;
398 }
399
400 /**
401 * Submit handler for terms overview form.
402 *
403 * Rather than using a textfield or weight field, this form depends entirely
404 * upon the order of form elements on the page to determine new weights.
405 *
406 * Because there might be hundreds or thousands of taxonomy terms that need to
407 * be ordered, terms are weighted from 0 to the number of terms in the
408 * vocabulary, rather than the standard -10 to 10 scale. Numbers are sorted
409 * lowest to highest, but are not necessarily sequential. Numbers may be skipped
410 * when a term has children so that reordering is minimal when a child is
411 * added or removed from a term.
412 *
413 * @see taxonomy_overview_terms()
414 */
415 function taxonomy_overview_terms_submit($form, &$form_state) {
416 if ($form_state['clicked_button']['#value'] == t('Reset to alphabetical')) {
417 // Execute the reset action.
418 if ($form_state['values']['reset_alphabetical'] === TRUE) {
419 return taxonomy_vocabulary_confirm_reset_alphabetical_submit($form, $form_state);
420 }
421 // Rebuild the form to confirm the reset action.
422 $form_state['rebuild'] = TRUE;
423 $form_state['confirm_reset_alphabetical'] = TRUE;
424 return;
425 }
426
427 $order = array_flip(array_keys($form_state['input'])); // Get the $_POST order.
428 $form_state['values'] = array_merge($order, $form_state['values']); // Update our original form with the new order.
429
430 $vocabulary = $form['#vocabulary'];
431 $hierarchy = 0; // Update the current hierarchy type as we go.
432
433 $changed_terms = array();
434 $tree = taxonomy_get_tree($vocabulary->vid);
435
436 if (empty($tree)) {
437 return;
438 }
439
440 // Build a list of all terms that need to be updated on previous pages.
441 $weight = 0;
442 $term = (array)$tree[0];
443 while ($term['tid'] != $form['#first_tid']) {
444 if ($term['parents'][0] == 0 && $term['weight'] != $weight) {
445 $term['parent'] = $term['parents'][0];
446 $term['weight'] = $weight;
447 $changed_terms[$term['tid']] = $term;
448 }
449 $weight++;
450 $hierarchy = $term['parents'][0] != 0 ? 1 : $hierarchy;
451 $term = (array)$tree[$weight];
452 }
453
454 // Renumber the current page weights and assign any new parents.
455 $level_weights = array();
456 foreach ($form_state['values'] as $tid => $values) {
457 if (isset($form[$tid]['#term'])) {
458 $term = $form[$tid]['#term'];
459 // Give terms at the root level a weight in sequence with terms on previous pages.
460 if ($values['parent'] == 0 && $term['weight'] != $weight) {
461 $term['weight'] = $weight;
462 $changed_terms[$term['tid']] = $term;
463 }
464 // Terms not at the root level can safely start from 0 because they're all on this page.
465 elseif ($values['parent'] > 0) {
466 $level_weights[$values['parent']] = isset($level_weights[$values['parent']]) ? $level_weights[$values['parent']] + 1 : 0;
467 if ($level_weights[$values['parent']] != $term['weight']) {
468 $term['weight'] = $level_weights[$values['parent']];
469 $changed_terms[$term['tid']] = $term;
470 }
471 }
472 // Update any changed parents.
473 if ($values['parent'] != $term['parent']) {
474 $term['parent'] = $values['parent'];
475 $changed_terms[$term['tid']] = $term;
476 }
477 $hierarchy = $term['parent'] != 0 ? 1 : $hierarchy;
478 $weight++;
479 }
480 }
481
482 // Build a list of all terms that need to be updated on following pages.
483 for ($weight; $weight < count($tree); $weight++) {
484 $term = (array)$tree[$weight];
485 if ($term['parents'][0] == 0 && $term['weight'] != $weight) {
486 $term['parent'] = $term['parents'][0];
487 $term['weight'] = $weight;
488 $changed_terms[$term['tid']] = $term;
489 }
490 $hierarchy = $term['parents'][0] != 0 ? 1 : $hierarchy;
491 }
492
493 // Save all updated terms.
494 foreach ($changed_terms as $changed) {
495 $term = (object)$changed;
496 // Update term_hierachy and term_data directly since we don't have a
497 // fully populated term object to save.
498 db_update('taxonomy_term_hierarchy')
499 ->fields(array('parent' => $term->parent))
500 ->condition('tid', $term->tid, '=')
501 ->execute();
502
503 db_update('taxonomy_term_data')
504 ->fields(array('weight' => $term->weight))
505 ->condition('tid', $term->tid, '=')
506 ->execute();
507 }
508
509 // Update the vocabulary hierarchy to flat or single hierarchy.
510 if ($vocabulary->hierarchy != $hierarchy) {
511 $vocabulary->hierarchy = $hierarchy;
512 taxonomy_vocabulary_save($vocabulary);
513 }
514 }
515
516 /**
517 * Theme the terms overview as a sortable list of terms.
518 *
519 * @ingroup themeable
520 * @see taxonomy_overview_terms()
521 */
522 function theme_taxonomy_overview_terms($variables) {
523 $form = $variables['form'];
524
525 $page_increment = $form['#page_increment'];
526 $page_entries = $form['#page_entries'];
527 $back_peddle = $form['#back_peddle'];
528 $forward_peddle = $form['#forward_peddle'];
529
530 // Add drag and drop if parent fields are present in the form.
531 if ($form['#parent_fields']) {
532 drupal_add_tabledrag('taxonomy', 'match', 'parent', 'term-parent', 'term-parent', 'term-id', FALSE);
533 drupal_add_tabledrag('taxonomy', 'depth', 'group', 'term-depth', NULL, NULL, FALSE);
534 drupal_add_js(drupal_get_path('module', 'taxonomy') . '/taxonomy.js');
535 drupal_add_js(array('taxonomy' => array('backPeddle' => $back_peddle, 'forwardPeddle' => $forward_peddle)), 'setting');
536 drupal_add_css(drupal_get_path('module', 'taxonomy') . '/taxonomy.css');
537 }
538
539 $errors = form_get_errors() != FALSE ? form_get_errors() : array();
540 $rows = array();
541 foreach (element_children($form) as $key) {
542 if (isset($form[$key]['#term'])) {
543 $term = &$form[$key];
544
545 $row = array();
546 $row[] = (isset($term['#term']['depth']) && $term['#term']['depth'] > 0 ? theme('indentation', array('size' => $term['#term']['depth'])) : ''). drupal_render($term['view']);
547 if ($form['#parent_fields']) {
548 $term['tid']['#attributes']['class'] = array('term-id');
549 $term['parent']['#attributes']['class'] = array('term-parent');
550 $term['depth']['#attributes']['class'] = array('term-depth');
551 $row[0] .= drupal_render($term['parent']) . drupal_render($term['tid']) . drupal_render($term['depth']);
552 }
553 $row[] = drupal_render($term['edit']);
554
555 $row = array('data' => $row);
556 $rows[$key] = $row;
557 }
558 }
559
560 // Add necessary classes to rows.
561 $row_position = 0;
562 foreach ($rows as $key => $row) {
563 $rows[$key]['class'] = array();
564 if (isset($form['#parent_fields'])) {
565 $rows[$key]['class'][] = 'draggable';
566 }
567
568 // Add classes that mark which terms belong to previous and next pages.
569 if ($row_position < $back_peddle || $row_position >= $page_entries - $forward_peddle) {
570 $rows[$key]['class'][] = 'taxonomy-term-preview';
571 }
572
573 if ($row_position !== 0 && $row_position !== count($rows) - 1) {
574 if ($row_position == $back_peddle - 1 || $row_position == $page_entries - $forward_peddle - 1) {
575 $rows[$key]['class'][] = 'taxonomy-term-divider-top';
576 }
577 elseif ($row_position == $back_peddle || $row_position == $page_entries - $forward_peddle) {
578 $rows[$key]['class'][] = 'taxonomy-term-divider-bottom';
579 }
580 }
581
582 // Add an error class if this row contains a form error.
583 foreach ($errors as $error_key => $error) {
584 if (strpos($error_key, $key) === 0) {
585 $rows[$key]['class'][] = 'error';
586 }
587 }
588 $row_position++;
589 }
590
591 if (empty($rows)) {
592 $rows[] = array(array('data' => $form['#empty_text'], 'colspan' => '2'));
593 }
594
595 $header = array(t('Name'), t('Operations'));
596 $output = theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'taxonomy')));
597 $output .= drupal_render_children($form);
598 $output .= theme('pager', array('tags' => NULL));
599
600 return $output;
601 }
602
603 /**
604 * Form function for the term edit form.
605 *
606 * @ingroup forms
607 * @see taxonomy_form_term_submit()
608 */
609 function taxonomy_form_term($form, &$form_state, $edit = array(), $vocabulary = NULL) {
610 if (!isset($vocabulary) && is_object($edit)) {
611 $vocabulary = taxonomy_vocabulary_load($edit->vid);
612 $edit = (array)$edit;
613 }
614 $edit += array(
615 'name' => '',
616 'description' => '',
617 'format' => filter_default_format(),
618 'vocabulary_machine_name' => $vocabulary->machine_name,
619 'tid' => NULL,
620 'weight' => 0,
621 );
622
623 // Take into account multi-step rebuilding.
624 if (isset($form_state['term'])) {
625 $edit = $form_state['term'] + $edit;
626 }
627
628 $parent = array_keys(taxonomy_get_parents($edit['tid']));
629 $form['#term'] = $edit;
630 $form['#term']['parent'] = $parent;
631 $form['#vocabulary'] = $vocabulary;
632 $form['#builder_function'] = 'taxonomy_form_term_submit_builder';
633
634 // Check for confirmation forms.
635 if (isset($form_state['confirm_delete'])) {
636 return array_merge($form, taxonomy_term_confirm_delete($form, $form_state, $edit['tid']));
637 }
638 elseif (isset($form_state['confirm_parents'])) {
639 return array_merge($form, taxonomy_term_confirm_parents($form, $form_state, $vocabulary));
640 }
641
642 $form['identification'] = array(
643 '#type' => 'fieldset',
644 '#title' => t('Identification'),
645 '#collapsible' => TRUE,
646 );
647 $form['identification']['name'] = array(
648 '#type' => 'textfield',
649 '#title' => t('Term name'),
650 '#default_value' => $edit['name'],
651 '#maxlength' => 255,
652 '#required' => TRUE);
653 $form['identification']['description'] = array(
654 '#type' => 'textarea',
655 '#title' => t('Description'),
656 '#default_value' => $edit['description'],
657 '#description' => t('A description of the term. To be displayed on taxonomy/term pages and RSS feeds.'),
658 '#text_format' => $edit['format'],
659 );
660
661 $form['vocabulary_machine_name'] = array(
662 '#type' => 'textfield',
663 '#access' => FALSE,
664 '#value' => isset($edit['vocabulary_machine_name']) ? $edit['vocabulary_machine_name'] : $vocabulary->name,
665 );
666
667 field_attach_form('taxonomy_term', (object) $edit, $form, $form_state);
668
669 $form['advanced'] = array(
670 '#type' => 'fieldset',
671 '#title' => t('Advanced options'),
672 '#collapsible' => TRUE,
673 '#collapsed' => $vocabulary->hierarchy < 2,
674 );
675
676 // taxonomy_get_tree and taxonomy_get_parents may contain large numbers of
677 // items so we check for taxonomy_override_selector before loading the
678 // full vocabulary. Contrib modules can then intercept before
679 // hook_form_alter to provide scalable alternatives.
680 if (!variable_get('taxonomy_override_selector', FALSE)) {
681 $parent = array_keys(taxonomy_get_parents($edit['tid']));
682 $children = taxonomy_get_tree($vocabulary->vid, $edit['tid']);
683
684 // A term can't be the child of itself, nor of its children.
685 foreach ($children as $child) {
686 $exclude[] = $child->tid;
687 }
688 $exclude[] = $edit['tid'];
689
690 $tree = taxonomy_get_tree($vocabulary->vid);
691 $options = array('<' . t('root') . '>');
692 foreach ($tree as $term) {
693 if (!in_array($term->tid, $exclude)) {
694 $options[$term->tid] = str_repeat('-', $term->depth) . $term->name;
695 }
696 }
697 $form['advanced']['parent'] = array(
698 '#type' => 'select',
699 '#title' => t('Parent terms'),
700 '#options' => $options,
701 '#default_value' => $parent,
702 '#multiple' => TRUE,
703 );
704
705 }
706 $form['advanced']['weight'] = array(
707 '#type' => 'textfield',
708 '#title' => t('Weight'),
709 '#size' => 6,
710 '#default_value' => $edit['weight'],
711 '#description' => t('Terms are displayed in ascending order by weight.'),
712 '#required' => TRUE);
713 $form['vid'] = array(
714 '#type' => 'value',
715 '#value' => $vocabulary->vid);
716 $form['submit'] = array(
717 '#type' => 'submit',
718 '#value' => t('Save'));
719
720 if ($edit['tid']) {
721 $form['delete'] = array(
722 '#type' => 'submit',
723 '#value' => t('Delete'),
724 '#access' => user_access("delete terms in $vocabulary->vid") || user_access('administer taxonomy'),
725 );
726 $form['tid'] = array(
727 '#type' => 'value',
728 '#value' => $edit['tid']);
729 }
730 else {
731 $form_state['redirect'] = $_GET['q'];
732 }
733
734 return $form;
735 }
736
737 /**
738 * Validation handler for the term form.
739 *
740 * @see taxonomy_form_term()
741 */
742 function taxonomy_form_term_validate($form, &$form_state) {
743 field_attach_form_validate('taxonomy_term', (object) $form_state['values'], $form, $form_state);
744
745 // Ensure numeric values.
746 if (isset($form_state['values']['weight']) && !is_numeric($form_state['values']['weight'])) {
747 form_set_error('weight', t('Weight value must be numeric.'));
748 }
749 }
750
751 /**
752 * Submit handler to insert or update a term.
753 *
754 * @see taxonomy_form_term()
755 */
756 function taxonomy_form_term_submit($form, &$form_state) {
757 if ($form_state['clicked_button']['#value'] == t('Delete')) {
758 // Execute the term deletion.
759 if ($form_state['values']['delete'] === TRUE) {
760 return taxonomy_term_confirm_delete_submit($form, $form_state);
761 }
762 // Rebuild the form to confirm term deletion.
763 $form_state['rebuild'] = TRUE;
764 $form_state['confirm_delete'] = TRUE;
765 return;
766 }
767 // Rebuild the form to confirm enabling multiple parents.
768 elseif ($form_state['clicked_button']['#value'] == t('Save') && count($form_state['values']['parent']) > 1 && $form['#vocabulary']->hierarchy < 2) {
769 $form_state['rebuild'] = TRUE;
770 $form_state['confirm_parents'] = TRUE;
771 return;
772 }
773
774 // Massage #text_format.
775 $form_state['values']['format'] = $form_state['values']['description_format'];
776 unset($form_state['values']['description_format']);
777
778 $term = taxonomy_form_term_submit_builder($form, $form_state);
779
780 $status = taxonomy_term_save($term);
781 switch ($status) {
782 case SAVED_NEW:
783 drupal_set_message(t('Created new term %term.', array('%term' => $term->name)));
784 watchdog('taxonomy', 'Created new term %term.', array('%term' => $term->name), WATCHDOG_NOTICE, l(t('edit'), 'taxonomy/term/' . $term->tid . '/edit'));
785 break;
786 case SAVED_UPDATED:
787 drupal_set_message(t('Updated term %term.', array('%term' => $term->name)));
788 watchdog('taxonomy', 'Updated term %term.', array('%term' => $term->name), WATCHDOG_NOTICE, l(t('edit'), 'taxonomy/term/' . $term->tid . '/edit'));
789 break;
790 }
791
792 $current_parent_count = count($form_state['values']['parent']);
793 $previous_parent_count = count($form['#term']['parent']);
794 // Root doesn't count if it's the only parent.
795 if ($current_parent_count == 1 && isset($form_state['values']['parent'][0])) {
796 $current_parent_count = 0;
797 $form_state['values']['parent'] = array();
798 }
799
800 // If the number of parents has been reduced to one or none, do a check on the
801 // parents of every term in the vocabulary value.
802 if ($current_parent_count < $previous_parent_count && $current_parent_count < 2) {
803 taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
804 }
805 // If we've increased the number of parents and this is a single or flat
806 // hierarchy, update the vocabulary immediately.
807 elseif ($current_parent_count > $previous_parent_count && $form['#vocabulary']->hierarchy < 2) {
808 $form['#vocabulary']->hierarchy = $current_parent_count == 1 ? 1 : 2;
809 taxonomy_vocabulary_save($form['#vocabulary']);
810 }
811
812 $form_state['tid'] = $term->tid;
813 $form_state['redirect'] = 'admin/structure/taxonomy';
814 return;
815 }
816
817 /**
818 * Build a term by processing form values and prepare for a form rebuild.
819 */
820 function taxonomy_form_term_submit_builder($form, &$form_state) {
821 $term = (object) $form_state['values'];
822 field_attach_submit('taxonomy_term', $term, $form, $form_state);
823
824 $form_state['term'] = (array)$term;
825 $form_state['rebuild'] = TRUE;
826
827 return $term;
828 }
829
830 /**
831 * Form builder for the confirmation of multiple term parents.
832 *
833 * @ingroup forms
834 * @see taxonomy_form_term()
835 */
836 function taxonomy_term_confirm_parents($form, &$form_state, $vocabulary) {
837 foreach (element_children($form_state['values']) as $key) {
838 $form[$key] = array(
839 '#type' => 'value',
840 '#value' => $form_state['values'][$key],
841 );
842 }
843 $question = t('Set multiple term parents?');
844 $description = '<p>' . t("Adding multiple parents to a term will cause the %vocabulary vocabulary to look for multiple parents on every term. Because multiple parents are not supported when using the drag and drop outline interface, drag and drop will be disabled if you enable this option. If you choose to have multiple parents, you will only be able to set parents by using the term edit form.", array('%vocabulary' => $vocabulary->name)) . '</p>';
845 $description .= '<p>' . t("You may re-enable the drag and drop interface at any time by reducing multiple parents to a single parent for the terms in this vocabulary.") . '</p>';
846 return confirm_form($form, $question, drupal_get_destination(), $description, t('Set multiple parents'));
847 }
848
849 /**
850 * Form builder for the term delete form.
851 *
852 * @ingroup forms
853 * @see taxonomy_term_confirm_delete_submit()
854 */
855 function taxonomy_term_confirm_delete($form, &$form_state, $tid) {
856 $term = taxonomy_term_load($tid);
857
858 $form['type'] = array('#type' => 'value', '#value' => 'term');
859 $form['name'] = array('#type' => 'value', '#value' => $term->name);
860 $form['tid'] = array('#type' => 'value', '#value' => $tid);
861 $form['vocabulary_machine_name'] = array('#type' => 'value', '#value' => $term->vocabulary_machine_name);
862 $form['delete'] = array('#type' => 'value', '#value' => TRUE);
863 return confirm_form($form,
864 t('Are you sure you want to delete the term %title?',
865 array('%title' => $term->name)),
866 'admin/structure/taxonomy',
867 t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
868 t('Delete'),
869 t('Cancel'));
870 }
871
872 /**
873 * Submit handler to delete a term after confirmation.
874 *
875 * @see taxonomy_term_confirm_delete()
876 */
877 function taxonomy_term_confirm_delete_submit($form, &$form_state) {
878 taxonomy_term_delete($form_state['values']['tid']);
879 taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
880 drupal_set_message(t('Deleted term %name.', array('%name' => $form_state['values']['name'])));
881 watchdog('taxonomy', 'Deleted term %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
882 $form_state['redirect'] = 'admin/structure/taxonomy';
883 return;
884 }
885
886 /**
887 * Form builder for the vocabulary delete confirmation form.
888 *
889 * @ingroup forms
890 * @see taxonomy_vocabulary_confirm_delete_submit()
891 */
892 function taxonomy_vocabulary_confirm_delete($form, &$form_state, $vid) {
893 $vocabulary = taxonomy_vocabulary_load($vid);
894
895 $form['#id'] = 'taxonomy_vocabulary_confirm_delete';
896 $form['type'] = array('#type' => 'value', '#value' => 'vocabulary');
897 $form['vid'] = array('#type' => 'value', '#value' => $vid);
898 $form['name'] = array('#type' => 'value', '#value' => $vocabulary->name);
899 $form['#submit'] = array('taxonomy_vocabulary_confirm_delete_submit');
900 return confirm_form($form,
901 t('Are you sure you want to delete the vocabulary %title?',
902 array('%title' => $vocabulary->name)),
903 'admin/structure/taxonomy',
904 t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'),
905 t('Delete'),
906 t('Cancel'));
907 }
908
909 /**
910 * Submit handler to delete a vocabulary after confirmation.
911 *
912 * @see taxonomy_vocabulary_confirm_delete()
913 */
914 function taxonomy_vocabulary_confirm_delete_submit($form, &$form_state) {
915 $status = taxonomy_vocabulary_delete($form_state['values']['vid']);
916 drupal_set_message(t('Deleted vocabulary %name.', array('%name' => $form_state['values']['name'])));
917 watchdog('taxonomy', 'Deleted vocabulary %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
918 $form_state['redirect'] = 'admin/structure/taxonomy';
919 return;
920 }
921
922 /**
923 * Form builder to confirm resetting a vocabulary to alphabetical order.
924 *
925 * @ingroup forms
926 * @see taxonomy_vocabulary_confirm_reset_alphabetical_submit()
927 */
928 function taxonomy_vocabulary_confirm_reset_alphabetical($form, &$form_state, $vid) {
929 $vocabulary = taxonomy_vocabulary_load($vid);
930
931 $form['type'] = array('#type' => 'value', '#value' => 'vocabulary');
932 $form['vid'] = array('#type' => 'value', '#value' => $vid);
933 $form['name'] = array('#type' => 'value', '#value' => $vocabulary->name);
934 $form['reset_alphabetical'] = array('#type' => 'value', '#value' => TRUE);
935 return confirm_form($form,
936 t('Are you sure you want to reset the vocabulary %title to alphabetical order?',
937 array('%title' => $vocabulary->name)),
938 'admin/structure/taxonomy/' . $vid,
939 t('Resetting a vocabulary will discard all custom ordering and sort items alphabetically.'),
940 t('Reset to alphabetical'),
941 t('Cancel'));
942 }
943
944 /**
945 * Submit handler to reset a vocabulary to alphabetical order after confirmation.
946 *
947 * @see taxonomy_vocabulary_confirm_reset_alphabetical()
948 */
949 function taxonomy_vocabulary_confirm_reset_alphabetical_submit($form, &$form_state) {
950 db_update('taxonomy_term_data')
951 ->fields(array('weight' => 0))
952 ->condition('vid', $form_state['values']['vid'])
953 ->execute();
954 drupal_set_message(t('Reset vocabulary %name to alphabetical order.', array('%name' => $form_state['values']['name'])));
955 watchdog('taxonomy', 'Reset vocabulary %name to alphabetical order.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
956 $form_state['redirect'] = 'admin/structure/taxonomy/' . $form_state['values']['vid'];
957 }

  ViewVC Help
Powered by ViewVC 1.1.2