/[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.81 - (show annotations) (download) (as text)
Tue Nov 3 05:27:18 2009 UTC (3 weeks, 5 days ago) by webchick
Branch: MAIN
Changes since 1.80: +6 -6 lines
File MIME type: text/x-php
#602522 by effulgentsia, sun, and moshe weitzman: Make links in renderable arrays and forms (e.g. 'Operations') alterable.
1 <?php
2 // $Id: taxonomy.admin.inc,v 1.80 2009/11/02 04:39:16 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 'vocabulary_machine_name' => $vocabulary->machine_name,
618 'tid' => NULL,
619 'weight' => 0,
620 );
621
622 // Take into account multi-step rebuilding.
623 if (isset($form_state['term'])) {
624 $edit = $form_state['term'] + $edit;
625 }
626
627 $parent = array_keys(taxonomy_get_parents($edit['tid']));
628 $form['#term'] = $edit;
629 $form['#term']['parent'] = $parent;
630 $form['#vocabulary'] = $vocabulary;
631 $form['#builder_function'] = 'taxonomy_form_term_submit_builder';
632
633 // Check for confirmation forms.
634 if (isset($form_state['confirm_delete'])) {
635 return array_merge($form, taxonomy_term_confirm_delete($form, $form_state, $edit['tid']));
636 }
637 elseif (isset($form_state['confirm_parents'])) {
638 return array_merge($form, taxonomy_term_confirm_parents($form, $form_state, $vocabulary));
639 }
640
641 $form['identification'] = array(
642 '#type' => 'fieldset',
643 '#title' => t('Identification'),
644 '#collapsible' => TRUE,
645 );
646 $form['identification']['name'] = array(
647 '#type' => 'textfield',
648 '#title' => t('Term name'),
649 '#default_value' => $edit['name'],
650 '#maxlength' => 255,
651 '#required' => TRUE);
652 $form['identification']['description'] = array(
653 '#type' => 'textarea',
654 '#title' => t('Description'),
655 '#default_value' => $edit['description'],
656 '#description' => t('A description of the term. To be displayed on taxonomy/term pages and RSS feeds.'));
657
658 $form['vocabulary_machine_name'] = array(
659 '#type' => 'textfield',
660 '#access' => FALSE,
661 '#value' => isset($edit['vocabulary_machine_name']) ? $edit['vocabulary_machine_name'] : $vocabulary->name,
662 );
663
664 field_attach_form('taxonomy_term', (object) $edit, $form, $form_state);
665
666 $form['advanced'] = array(
667 '#type' => 'fieldset',
668 '#title' => t('Advanced options'),
669 '#collapsible' => TRUE,
670 '#collapsed' => $vocabulary->hierarchy < 2,
671 );
672
673 // taxonomy_get_tree and taxonomy_get_parents may contain large numbers of
674 // items so we check for taxonomy_override_selector before loading the
675 // full vocabulary. Contrib modules can then intercept before
676 // hook_form_alter to provide scalable alternatives.
677 if (!variable_get('taxonomy_override_selector', FALSE)) {
678 $parent = array_keys(taxonomy_get_parents($edit['tid']));
679 $children = taxonomy_get_tree($vocabulary->vid, $edit['tid']);
680
681 // A term can't be the child of itself, nor of its children.
682 foreach ($children as $child) {
683 $exclude[] = $child->tid;
684 }
685 $exclude[] = $edit['tid'];
686
687 $tree = taxonomy_get_tree($vocabulary->vid);
688 $options = array('<' . t('root') . '>');
689 foreach ($tree as $term) {
690 if (!in_array($term->tid, $exclude)) {
691 $options[$term->tid] = str_repeat('-', $term->depth) . $term->name;
692 }
693 }
694 $form['advanced']['parent'] = array(
695 '#type' => 'select',
696 '#title' => t('Parent terms'),
697 '#options' => $options,
698 '#default_value' => $parent,
699 '#multiple' => TRUE,
700 );
701
702 }
703 $form['advanced']['weight'] = array(
704 '#type' => 'textfield',
705 '#title' => t('Weight'),
706 '#size' => 6,
707 '#default_value' => $edit['weight'],
708 '#description' => t('Terms are displayed in ascending order by weight.'),
709 '#required' => TRUE);
710 $form['vid'] = array(
711 '#type' => 'value',
712 '#value' => $vocabulary->vid);
713 $form['submit'] = array(
714 '#type' => 'submit',
715 '#value' => t('Save'));
716
717 if ($edit['tid']) {
718 $form['delete'] = array(
719 '#type' => 'submit',
720 '#value' => t('Delete'),
721 '#access' => user_access("delete terms in $vocabulary->vid") || user_access('administer taxonomy'),
722 );
723 $form['tid'] = array(
724 '#type' => 'value',
725 '#value' => $edit['tid']);
726 }
727 else {
728 $form_state['redirect'] = $_GET['q'];
729 }
730
731 return $form;
732 }
733
734 /**
735 * Validation handler for the term form.
736 *
737 * @see taxonomy_form_term()
738 */
739 function taxonomy_form_term_validate($form, &$form_state) {
740 field_attach_form_validate('taxonomy_term', (object) $form_state['values'], $form, $form_state);
741
742 // Ensure numeric values.
743 if (isset($form_state['values']['weight']) && !is_numeric($form_state['values']['weight'])) {
744 form_set_error('weight', t('Weight value must be numeric.'));
745 }
746 }
747
748 /**
749 * Submit handler to insert or update a term.
750 *
751 * @see taxonomy_form_term()
752 */
753 function taxonomy_form_term_submit($form, &$form_state) {
754 if ($form_state['clicked_button']['#value'] == t('Delete')) {
755 // Execute the term deletion.
756 if ($form_state['values']['delete'] === TRUE) {
757 return taxonomy_term_confirm_delete_submit($form, $form_state);
758 }
759 // Rebuild the form to confirm term deletion.
760 $form_state['rebuild'] = TRUE;
761 $form_state['confirm_delete'] = TRUE;
762 return;
763 }
764 // Rebuild the form to confirm enabling multiple parents.
765 elseif ($form_state['clicked_button']['#value'] == t('Save') && count($form_state['values']['parent']) > 1 && $form['#vocabulary']->hierarchy < 2) {
766 $form_state['rebuild'] = TRUE;
767 $form_state['confirm_parents'] = TRUE;
768 return;
769 }
770
771 $term = taxonomy_form_term_submit_builder($form, $form_state);
772
773 $status = taxonomy_term_save($term);
774 switch ($status) {
775 case SAVED_NEW:
776 drupal_set_message(t('Created new term %term.', array('%term' => $term->name)));
777 watchdog('taxonomy', 'Created new term %term.', array('%term' => $term->name), WATCHDOG_NOTICE, l(t('edit'), 'taxonomy/term/' . $term->tid . '/edit'));
778 break;
779 case SAVED_UPDATED:
780 drupal_set_message(t('Updated term %term.', array('%term' => $term->name)));
781 watchdog('taxonomy', 'Updated term %term.', array('%term' => $term->name), WATCHDOG_NOTICE, l(t('edit'), 'taxonomy/term/' . $term->tid . '/edit'));
782 break;
783 }
784
785 $current_parent_count = count($form_state['values']['parent']);
786 $previous_parent_count = count($form['#term']['parent']);
787 // Root doesn't count if it's the only parent.
788 if ($current_parent_count == 1 && isset($form_state['values']['parent'][0])) {
789 $current_parent_count = 0;
790 $form_state['values']['parent'] = array();
791 }
792
793 // If the number of parents has been reduced to one or none, do a check on the
794 // parents of every term in the vocabulary value.
795 if ($current_parent_count < $previous_parent_count && $current_parent_count < 2) {
796 taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
797 }
798 // If we've increased the number of parents and this is a single or flat
799 // hierarchy, update the vocabulary immediately.
800 elseif ($current_parent_count > $previous_parent_count && $form['#vocabulary']->hierarchy < 2) {
801 $form['#vocabulary']->hierarchy = $current_parent_count == 1 ? 1 : 2;
802 taxonomy_vocabulary_save($form['#vocabulary']);
803 }
804
805 $form_state['tid'] = $term->tid;
806 $form_state['redirect'] = 'admin/structure/taxonomy';
807 return;
808 }
809
810 /**
811 * Build a term by processing form values and prepare for a form rebuild.
812 */
813 function taxonomy_form_term_submit_builder($form, &$form_state) {
814 $term = (object) $form_state['values'];
815 field_attach_submit('taxonomy_term', $term, $form, $form_state);
816
817 $form_state['term'] = (array)$term;
818 $form_state['rebuild'] = TRUE;
819
820 return $term;
821 }
822
823 /**
824 * Form builder for the confirmation of multiple term parents.
825 *
826 * @ingroup forms
827 * @see taxonomy_form_term()
828 */
829 function taxonomy_term_confirm_parents($form, &$form_state, $vocabulary) {
830 foreach (element_children($form_state['values']) as $key) {
831 $form[$key] = array(
832 '#type' => 'value',
833 '#value' => $form_state['values'][$key],
834 );
835 }
836 $question = t('Set multiple term parents?');
837 $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>';
838 $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>';
839 return confirm_form($form, $question, drupal_get_destination(), $description, t('Set multiple parents'));
840 }
841
842 /**
843 * Form builder for the term delete form.
844 *
845 * @ingroup forms
846 * @see taxonomy_term_confirm_delete_submit()
847 */
848 function taxonomy_term_confirm_delete($form, &$form_state, $tid) {
849 $term = taxonomy_term_load($tid);
850
851 $form['type'] = array('#type' => 'value', '#value' => 'term');
852 $form['name'] = array('#type' => 'value', '#value' => $term->name);
853 $form['tid'] = array('#type' => 'value', '#value' => $tid);
854 $form['vocabulary_machine_name'] = array('#type' => 'value', '#value' => $term->vocabulary_machine_name);
855 $form['delete'] = array('#type' => 'value', '#value' => TRUE);
856 return confirm_form($form,
857 t('Are you sure you want to delete the term %title?',
858 array('%title' => $term->name)),
859 'admin/structure/taxonomy',
860 t('Deleting a term will delete all its children if there are any. This action cannot be undone.'),
861 t('Delete'),
862 t('Cancel'));
863 }
864
865 /**
866 * Submit handler to delete a term after confirmation.
867 *
868 * @see taxonomy_term_confirm_delete()
869 */
870 function taxonomy_term_confirm_delete_submit($form, &$form_state) {
871 taxonomy_term_delete($form_state['values']['tid']);
872 taxonomy_check_vocabulary_hierarchy($form['#vocabulary'], $form_state['values']);
873 drupal_set_message(t('Deleted term %name.', array('%name' => $form_state['values']['name'])));
874 watchdog('taxonomy', 'Deleted term %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
875 $form_state['redirect'] = 'admin/structure/taxonomy';
876 return;
877 }
878
879 /**
880 * Form builder for the vocabulary delete confirmation form.
881 *
882 * @ingroup forms
883 * @see taxonomy_vocabulary_confirm_delete_submit()
884 */
885 function taxonomy_vocabulary_confirm_delete($form, &$form_state, $vid) {
886 $vocabulary = taxonomy_vocabulary_load($vid);
887
888 $form['#id'] = 'taxonomy_vocabulary_confirm_delete';
889 $form['type'] = array('#type' => 'value', '#value' => 'vocabulary');
890 $form['vid'] = array('#type' => 'value', '#value' => $vid);
891 $form['name'] = array('#type' => 'value', '#value' => $vocabulary->name);
892 $form['#submit'] = array('taxonomy_vocabulary_confirm_delete_submit');
893 return confirm_form($form,
894 t('Are you sure you want to delete the vocabulary %title?',
895 array('%title' => $vocabulary->name)),
896 'admin/structure/taxonomy',
897 t('Deleting a vocabulary will delete all the terms in it. This action cannot be undone.'),
898 t('Delete'),
899 t('Cancel'));
900 }
901
902 /**
903 * Submit handler to delete a vocabulary after confirmation.
904 *
905 * @see taxonomy_vocabulary_confirm_delete()
906 */
907 function taxonomy_vocabulary_confirm_delete_submit($form, &$form_state) {
908 $status = taxonomy_vocabulary_delete($form_state['values']['vid']);
909 drupal_set_message(t('Deleted vocabulary %name.', array('%name' => $form_state['values']['name'])));
910 watchdog('taxonomy', 'Deleted vocabulary %name.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
911 $form_state['redirect'] = 'admin/structure/taxonomy';
912 return;
913 }
914
915 /**
916 * Form builder to confirm resetting a vocabulary to alphabetical order.
917 *
918 * @ingroup forms
919 * @see taxonomy_vocabulary_confirm_reset_alphabetical_submit()
920 */
921 function taxonomy_vocabulary_confirm_reset_alphabetical($form, &$form_state, $vid) {
922 $vocabulary = taxonomy_vocabulary_load($vid);
923
924 $form['type'] = array('#type' => 'value', '#value' => 'vocabulary');
925 $form['vid'] = array('#type' => 'value', '#value' => $vid);
926 $form['name'] = array('#type' => 'value', '#value' => $vocabulary->name);
927 $form['reset_alphabetical'] = array('#type' => 'value', '#value' => TRUE);
928 return confirm_form($form,
929 t('Are you sure you want to reset the vocabulary %title to alphabetical order?',
930 array('%title' => $vocabulary->name)),
931 'admin/structure/taxonomy/' . $vid,
932 t('Resetting a vocabulary will discard all custom ordering and sort items alphabetically.'),
933 t('Reset to alphabetical'),
934 t('Cancel'));
935 }
936
937 /**
938 * Submit handler to reset a vocabulary to alphabetical order after confirmation.
939 *
940 * @see taxonomy_vocabulary_confirm_reset_alphabetical()
941 */
942 function taxonomy_vocabulary_confirm_reset_alphabetical_submit($form, &$form_state) {
943 db_update('taxonomy_term_data')
944 ->fields(array('weight' => 0))
945 ->condition('vid', $form_state['values']['vid'])
946 ->execute();
947 drupal_set_message(t('Reset vocabulary %name to alphabetical order.', array('%name' => $form_state['values']['name'])));
948 watchdog('taxonomy', 'Reset vocabulary %name to alphabetical order.', array('%name' => $form_state['values']['name']), WATCHDOG_NOTICE);
949 $form_state['redirect'] = 'admin/structure/taxonomy/' . $form_state['values']['vid'];
950 }

  ViewVC Help
Powered by ViewVC 1.1.2