source: sipes/0.3-modules/hs_content_taxonomy_description/hs_content_taxonomy_description.module @ 92213c1

stableversion-3.0
Last change on this file since 92213c1 was 303fae2, checked in by José Gregorio Puentes <jpuentes@…>, 9 años ago

se agregaron los modulos

  • Propiedad mode establecida a 100755
File size: 20.3 KB
Línea 
1<?php
2
3/**
4 * @file
5 * Implementation of the Hierarchical Select API for the Content Taxonomy
6 * module.
7 */
8
9/**
10 * TRICKY: Content Taxonomy's depth setting:
11 * - 0 means the entire tree
12 * - 1 means only the root level
13 * - 2 means the first two levels
14 * - etc.
15 */
16
17//----------------------------------------------------------------------------
18// Core hooks.
19define('HS_CONTENT_TAXONOMY_DESCRIPTION_SEP',  ' - ');
20/**
21 * Implementation of hook_menu().
22 */
23function hs_content_taxonomy_description_menu() {
24  $items['admin/content/node-type/%/fields/%/hsd_config'] = array(
25    'title'            => t('HSD config'),
26    'access arguments' => array('administer content types'),
27    'page callback'    => 'drupal_get_form',
28    'page arguments'   => array('hs_content_taxonomy_description_config_form', 3, 5),
29    'type'             => MENU_NORMAL_ITEM,
30    'file'             => 'hs_content_taxonomy_description.admin.inc',
31  );
32  return $items;
33}
34
35/**
36 * Implementation of hook_form_alter().
37 */
38function hs_content_taxonomy_description_form_alter(&$form, $form_state, $form_id) {
39  if (isset($form['type']) && isset($form['type']['#value']) && $form['type']['#value'] .'_node_form' == $form_id) {
40    if (isset($form['#field_info']) && count($form['#field_info']) > 0) {
41      foreach ($form['#field_info'] as $field_name => &$field_info) {
42        if ($field_info['widget']['type'] == 'content_taxonomy_hsd') {
43          $form['#submit'][] = 'hs_content_taxonomy_form_submit';
44          break;
45        }
46      }
47    }
48  }
49}
50
51/**
52 * Implementation of hook_form_FORM_ID_alter()
53 */
54function hs_content_taxonomy_description_form_content_field_edit_form_alter(&$form, &$form_state) { 
55  if ($form['#field']['widget']['type'] == 'content_taxonomy_hsd') {
56    $form['field']['multiple']['#attributes'] = array('disabled' => 'disabled');
57    $form['field']['multiple']['#description'] = t(
58      'This setting is now managed by the Hierarchical Select widget configuration!'
59    );     
60  }
61}
62
63
64//----------------------------------------------------------------------------
65// Forms API callbacks.
66
67/**
68 * Submit handler for HS CT field form
69 */
70function hs_content_taxonomy_description_form_submit(&$form, &$form_state) {
71  foreach ($form['#field_info'] as $field_name => $field_info) {
72    if ($field_info['widget']['type'] == 'content_taxonomy_hsd') {
73      // Change format of values to the one Content Taxonomy expects
74      if (is_array($form_state['values'][$field_name]['tids'])) {
75        $values = array();
76        foreach($form_state['values'][$field_name]['tids'] as $tid) {
77          $values[] = array('value' => $tid);
78          array_unshift($form_state['values'][$field_name], array('value' => $tid));
79        }
80        $form_state['values'][$field_name]['tids'] = $values;
81      }
82      else {
83        $values[] = array('value' => $form_state['values'][$field_name]['tids']);
84        array_unshift($form_state['values'][$field_name],array('value' => $form_state['values'][$field_name]['tids']));
85        $form_state['values'][$field_name]['tids'] = $values;
86      }
87    }
88  }
89}
90
91//----------------------------------------------------------------------------
92// CCK hooks.
93
94/**
95 * Implementation of hook_widget_info().
96 */
97function hs_content_taxonomy_description_widget_info() {
98  return array(
99    'content_taxonomy_hsd' => array( // 'content_taxonomy_hsd' instead of 'content_taxonomy_hierarchical_select' due to CCK limitations.
100      'label'       => 'Hierarchical Select Description',
101      'field types' => array('content_taxonomy'),
102      // Set multiple settings to be handled by widget rather than by CCK itself
103      'multiple values' => CONTENT_HANDLE_MODULE,
104      'callbacks' => array(
105        'default value' => CONTENT_CALLBACK_DEFAULT,
106      ),
107    ),
108  );
109}
110
111/**
112 * Implementation of hook_widget_settings().
113 */
114function hs_content_taxonomy_description_widget_settings($op, $widget) {
115  switch ($op) {
116    case 'form':
117      drupal_add_css(drupal_get_path('module', 'hs_content_taxonomy_description') .'/hs_content_taxonomy_description.css');
118      $context = _hs_content_taxonomy_description_parse_context_from_url();
119      list($content_type_name, $field_name) = $context;
120      $url = 'admin/content/node-type/'. $content_type_name .'/fields/'. $field_name .'/hsd_config';
121      $items[] = t(
122        "Due to limitations of CCK, there is a separate form to <a href=\"!url\">
123        configure this Hierarchical Select widget's settings.</a>",array('!url' => url($url))
124      );
125      $placeholders = array(
126        '%multiple_values'    => t('Multiple values'),
127        '%enable_the_dropbox' => t('Enable the dropbox'),
128        '%save_term_lineage'  => t('Save term lineage'),
129      );
130      $items[] = t(
131        'The %multiple_values field setting is now managed by the Hierarchical
132        Select module: it will be enabled when either the %enable_the_dropbox
133        or %save_term_lineage settings (or both) are enabled.', $placeholders
134      );
135      $form['hsd_config'] = array(
136        '#type' => 'fieldset',
137        '#title' => t('Hierarchical Select configuration'),
138        '#description' => '<p class="cck-hierarchical-select-warning">'.
139          '<span class="highlight">Important!</span>'.
140          '</p>'. theme('item_list', $items),
141        '#collapsible' => FALSE,
142      );
143      return $form;
144
145    case 'callbacks':
146      return array('default value' => CONTENT_CALLBACK_NONE);
147  }
148}
149
150/**
151 * Implementation of hook_widget().
152 */
153function hs_content_taxonomy_description_widget(&$form, &$form_state, $field, $items, $delta = 0) {
154  $field_name = $field['field_name'];
155  $vid        = $field['vid'];
156  $tid        = content_taxonomy_field_get_parent($field);
157  $depth      = (empty($field['depth'])) ? 0 : $field['depth'];
158  require_once(drupal_get_path('module', 'hierarchical_select') .'/includes/common.inc');
159  $node = &$form['#node'];
160
161  // Extremely ugly checks because CCK/Content Taxonomy is a big failure.
162  $selected_items = array();
163  if (isset($items[$field_name])) {
164    // New node: "default value" is the default value from field settings.
165    if (isset($items[$field_name]['tids'])) {
166      // Multiple default values as a field setting.
167      if (is_array($items[$field_name]['tids'])) {
168        foreach ($items[$field_name]['tids'] as $item) {
169          $selected_items[] = $item['value'];
170        }
171      }
172      // Single default value as a field setting.
173      else {
174        $selected_items[] = $items[$field_name]['tids'];
175      }
176    }
177  }
178  else {
179    // Existing node: "default value" are the previously selected terms.
180    foreach ($items as $item) {
181      $selected_items[] = $item['value'];
182    }
183  }
184
185  $node_field = &$node->$field_name;
186  $form[$field_name]['#tree'] = TRUE;
187  $form[$field_name]['#weight'] = $field['widget']['weight'];
188  $form[$field_name]['tids'] = array(
189    '#title' => t($field['widget']['label']),
190    '#type' => 'hierarchical_select',
191    '#weight' => $field['widget']['weight'],
192    '#config' => array(
193      'module' => 'hs_content_taxonomy_description',
194      'params' => array(
195        'vid'   => $vid,
196        'tid'   => $tid,
197        'depth' => $depth,
198      ),
199    ),
200    '#required' => $field['required'],
201    '#description' => t($field['widget']['description']),
202    '#default_value' => !empty($selected_items) ? array_values($selected_items) : array(),
203  );
204  unset($form[$field_name]['#options']); // Unset to prevent passing around of possibly huge HTML.
205  unset($form[$field_name]['#theme']);   // Unset to prevent theme_taxonomy_term_select() from running.
206  hierarchical_select_common_config_apply($form[$field_name]['tids'], "content-taxonomy-$field_name");
207  return $form;
208}
209
210//-------------------------------------------------------------------------------------------------------
211// HS Content Taxonomy CCK formatters
212
213/**
214 * Implementation of hook_theme().
215 */
216function hs_content_taxonomy_description_theme() {
217  return array(
218    'hs_content_taxonomy_description_formatter_hierarchical_text' => array(
219      'arguments' => array('element' => NULL),
220      'function' => 'theme_hs_content_taxonomy_description_formatter_hierarchical',
221    ),
222    'hs_content_taxonomy_description_formatter_hierarchical_links' => array(
223      'arguments' => array('element' => NULL),
224      'function' => 'theme_hs_content_taxonomy_description_formatter_hierarchical',
225    ),
226    'hs_content_taxonomy_description_row' => array(
227      'arguments' => array('row' => NULL, 'type' => NULL),
228    ),
229  );
230}
231
232/**
233 * Implementation of hook_field_formatter_info().
234 */
235function hs_content_taxonomy_description_field_formatter_info() {
236  return array(
237    'hierarchical_text' => array(
238      'label' => t('As hierarchical text'),
239      'field types' => array('content_taxonomy'),
240      'multiple values' => CONTENT_HANDLE_MODULE,
241    ),
242    'hierarchical_links' => array(
243      'label' => t('As hierarchical links'),
244      'field types' => array('content_taxonomy'),
245      'multiple values' => CONTENT_HANDLE_MODULE,
246    ),
247  );
248}
249
250/**
251 *  Theme function to output single row (lineage) of CT field
252 *
253 *  Giving levels different classes so some funny theming is possible:
254 *  for example, different font size depending on level (like tagadelic)
255 */
256function theme_hs_content_taxonomy_description_row($row, $type) {
257  $separator = '<span class="hierarchical-select-item-separator">›</span>';
258  $output = '';
259  if (empty($row)) {
260    return $output;
261  }
262  $items = array();
263  foreach ($row as $level => $item ) {
264    $term  = taxonomy_get_term($item['value']);
265    _content_taxonomy_localize_term($term);
266    $line  = '<span class="lineage-item lineage-item-level-'. $level .'">';
267    // Depending on which formatter is active, create links or use labels.
268    switch ($type) {
269      case 'hierarchical_links':
270        $line .= l($term->name . HS_CONTENT_TAXONOMY_DESCRIPTION_SEP . $term->description, taxonomy_term_path($term), array('rel' => 'tag', 'title' => $term->description));
271        break;
272      case 'hierarchical_text':
273        $line .= $item['label'] . HS_CONTENT_TAXONOMY_DESCRIPTION_SEP . $term->description;
274        break;
275    }
276    $line .= '</span>';
277    $items[] = $line;
278  }
279  $output = implode($separator , $items);
280  return $output;
281}
282
283/**
284 * Theme function for HS Content Taxonomy formatters.
285 *
286 */
287function theme_hs_content_taxonomy_description_formatter_hierarchical($element) {
288  $output = '';
289
290  // Extract required field information.
291  // $element contains only field name; so we use cck function to get more info.
292  $field = content_fields($element['#field_name'], $element['#type_name']);
293  $field_name = $field['field_name'];
294  $vid        = $field['vid'];
295  $tid        = (empty($field['tid'])) ? 0 : $field['tid'];
296  $depth      = (empty($field['depth'])) ? 0 : $field['depth'];
297
298  // Get the config for this field.
299  require_once(drupal_get_path('module', 'hierarchical_select') .'/includes/common.inc');
300  $config_id = "content-taxonomy-$field_name";
301  $config = hierarchical_select_common_config_get($config_id);
302  $config += array(
303    'module' => 'hs_content_taxonomy_description',
304    'params' => array(
305      'vid'   => $vid,
306      'tid'   => $tid,
307      'depth' => $depth,
308    ),
309  );
310  $selection = array();
311
312  // Cycle through elements.
313  foreach (element_children($element) as $key) {
314    if (isset($element[$key]['#item']['value'])) {
315      $selection[] = $element[$key]['#item']['value'];
316    }
317  }
318  // It is said that formatter theme function is called even if field is empty.
319  if (empty($selection)) {
320    return $output;
321  }
322
323  // Generate a dropbox out of the selection. This will automatically
324  // calculate all lineages for us.
325  $dropbox = _hierarchical_select_dropbox_generate($config, $selection);
326
327  // Actual formatting.
328  // In 6.x formatter is fully themable
329  // We theme each lineage using additional theme function
330  $num_items = count($dropbox->lineages);
331  $flip = array('even' => 'odd', 'odd' => 'even');
332  $class = 'even';
333
334  $output = '<ul class="hierarchical-select-lineages">';
335  foreach ($dropbox->lineages as $i => $lineage) {
336    $class = $flip[$class];
337    $classes = ' '. $class;
338    if ($i == 0) {
339      $classes .= ' first';
340    }
341    if ($i == $num_items - 1) {
342      $classes .= ' last';
343    }
344    $output .= '<li class="lineage-'. $i . $classes .'">';
345    $output .= theme('hs_content_taxonomy_description_row', $lineage, $element['#formatter']);
346    $output .= '</li>';
347  }
348  $output .= '</ul>';
349
350  // Add the CSS.
351  drupal_add_css(drupal_get_path('module', 'hierarchical_select') .'/hierarchical_select.css');
352  return $output;
353}
354
355//----------------------------------------------------------------------------
356// Hierarchical Select hooks.
357
358/**
359 * Implementation of hook_hierarchical_select_params().
360 */
361function hs_content_taxonomy_description_hierarchical_select_params() {
362  $params = array(
363    'vid',   // The vocabulary id.
364    'tid',   // The root term's term id.
365    'depth', // The depth of the tree.
366  );
367  return $params;
368}
369
370/**
371 * Implementation of hook_hierarchical_select_root_level().
372 */
373function hs_content_taxonomy_description_hierarchical_select_root_level($params) {
374  $tid = $params['tid'];
375  $terms = _hs_taxonomy_hierarchical_select_get_tree($params['vid'], $tid, -1, 1);
376  return _hs_content_taxonomy_description_select_terms_to_options($terms);
377}
378
379/**
380 * Implementation of hook_hierarchical_select_children().
381 */
382function hs_content_taxonomy_description_hierarchical_select_children($parent, $params) {
383  static $tree;
384  $vid = $params['vid'];
385  $tid = $params['tid'];
386  $depth = $params['depth'];
387
388  // Keep a static cache of the entire tree, this allows us to quickly look up
389  // if a term is not too deep – because if it's too deep, we don't want to
390  // return any children.
391  if (!isset($tree[$vid][$tid])) {
392    $raw_tree = _hs_taxonomy_hierarchical_select_get_tree($vid, $tid);
393    foreach ($raw_tree as $term) {
394      $tree[$vid][$tid][$term->tid] = $term->depth;
395    }
396  }
397  $terms = ($depth > 0 && $tree[$vid][$tid][$parent] + 1 >= $depth) ? array() : _hs_taxonomy_hierarchical_select_get_tree($vid, $parent, -1, 1);
398  return _hs_content_taxonomy_description_select_terms_to_options($terms);
399}
400
401/**
402 * Transform an array of terms into an associative array of options, for use
403 * in a select form item.
404 *
405 * @param $terms
406 *  An array of term objects.
407 * @return
408 *  An associative array of options, keys are tids, values are term names.
409 */
410function _hs_content_taxonomy_description_select_terms_to_options($terms) {
411  $options = array();
412  foreach ($terms as $key => $term) {
413    // Use the translated term when available!
414    $term->name .= HS_CONTENT_TAXONOMY_DESCRIPTION_SEP . $term->description;
415    if (module_exists('i18ntaxonomy') && isset($term->vid) && i18ntaxonomy_vocabulary($term->vid) == I18N_TAXONOMY_LOCALIZE) {
416      $options[$term->tid] = tt("taxonomy:term:$term->tid:name", $term->name);
417    }
418    else {
419      $options[$term->tid] = t($term->name);
420    }
421  }
422  return $options;
423}
424
425/**
426 * Implementation of hook_hierarchical_select_lineage().
427 */
428function hs_content_taxonomy_description_hierarchical_select_lineage($item, $params) {
429  $lineage = hs_taxonomy_hierarchical_select_lineage($item, $params);
430
431  // If there is NO root term, then the tid parameter is set to 0. In that
432  // case, there is no need to remove any of the terms before the root term,
433  // because there won't be any.
434  if ($params['tid'] != 0) {
435    // TRICKY: When the root term has been *changed* over time, it *might* not
436    // be in the lineage, because the lineage. This means the lineage is not
437    // inside the tree below the defined root term. So we have to reset the
438    // lineage.
439    if (!in_array($params['tid'], $lineage)) {
440      $lineage = array();
441    }
442    else {
443      // Remove all terms before the root term and then the root term itself, too.
444      while (count($lineage) && $lineage[0] != $params['tid']) {
445        array_shift($lineage);
446      }
447      array_shift($lineage);
448    }
449  }
450  return $lineage;
451}
452
453/**
454 * Implementation of hook_hierarchical_select_valid_item().
455 */
456function hs_content_taxonomy_description_hierarchical_select_valid_item($item, $params) {
457  if (!is_numeric($item) || $item < 1) {
458    return FALSE;
459  }
460  $term = taxonomy_get_term($item);
461  _content_taxonomy_localize_term($term);
462  // Bug: tid isn't set to zero for some reason when root term is not set, so we make workaround for this
463  //$params['tid'] = $params['tid'] ? $params['tid']: 0;
464  return ($term->vid == $params['vid'] && _hs_content_taxonomy_description_term_within_allowed_depth($term->tid, $term->vid, $params['tid'], $params['depth']));
465}
466
467/**
468 * Implementation of hook_hierarchical_select_item_get_label().
469 */
470function hs_content_taxonomy_description_hierarchical_select_item_get_label($item, $params) {
471  return hs_taxonomy_hierarchical_select_item_get_label($item, $params);
472}
473
474/**
475 * Implementation of hook_hierarchical_select_create_item().
476 */
477function hs_content_taxonomy_description_hierarchical_select_create_item($label, $parent, $params) {
478  // TRICKY: no depth check is necessary because HS's internal validation
479  // prevents an invalid parent.
480  return hs_taxonomy_hierarchical_select_create_item($label, $parent, $params);
481}
482
483/**
484 * Implementation of hook_hierarchical_select_entity_count().
485 */
486function hs_content_taxonomy_description_hierarchical_select_entity_count($item, $params) {
487  return hs_taxonomy_hierarchical_select_entity_count($item, $params);
488}
489
490/**
491 * Implementation of hook_hierarchical_select_implementation_info().
492 */
493function hs_content_taxonomy_description_hierarchical_select_implementation_info() {
494  return array(
495    'hierarchy type' => t('Content Taxonomy'),
496    'entity type'    => t('Node'),
497  );
498}
499
500/**
501 * Implementation of hook_hierarchical_select_config_info().
502 */
503function hs_content_taxonomy_description_hierarchical_select_config_info() {
504  static $config_info;
505
506  if (!isset($config_info)) {
507    $config_info = array();
508
509    $content_types = content_types();
510    $fields = content_fields();
511
512    foreach ($fields as $field_name => $field) {
513      if ($field['type'] == 'content_taxonomy') {
514        foreach ($content_types as $content_type_name => $content_type) {
515          if (isset($content_type['fields'][$field_name]) && $content_type['fields'][$field_name]['widget']['type'] == 'content_taxonomy_hsd') {
516            $vocabulary = taxonomy_vocabulary_load($field['vid']);
517
518            $config_id = "content-taxonomy-$field_name";
519            $config_info["$config_id|$content_type_name"] = array(
520              'config_id'      => $config_id,
521              'hierarchy type' => t('Content Taxonomy'),
522              'hierarchy'      => t($vocabulary->name) ." ($field_name)",
523              'entity type'    => t('Node'),
524              'entity'         => t($content_type['name']),
525              'context type'   => t('Node form'),
526              'context'        => '',
527              'edit link'      => "admin/content/node-type/$content_type_name/fields/$field_name/hsd_config",
528            );
529          }
530        }
531      }
532    }
533  }
534  return  $config_info;
535}
536
537
538//----------------------------------------------------------------------------
539// Private functions.
540
541/**
542 * Parse the context (the content type and the field name) from the URL.
543 *
544 * @return
545 *   - FALSE if no context could be found
546 *   - array($content_type_name, $field_name) otherwise
547 */
548function _hs_content_taxonomy_description_parse_context_from_url() {
549  if (arg(0) == 'admin' && arg(1) == 'content' && arg(2) == 'node-type') {
550    $content_type = content_types(arg(3));
551
552    $field_name = arg(5);
553
554    if (arg(4) == 'fields' && !empty($field_name) && isset($content_type['fields'][$field_name])) {
555      if ($content_type['fields'][$field_name]['type'] == 'content_taxonomy' && $content_type['fields'][$field_name]['widget']['type'] == 'content_taxonomy_hsd') {
556        return array($content_type['type'], $field_name);
557      }
558    }
559  }
560
561  return FALSE;
562}
563
564function _hs_content_taxonomy_description_term_within_allowed_depth($tid, $vid, $root_tid, $allowed_depth) {
565  // If the allowed depth is zero, then every term is allowed!
566  if ($allowed_depth == 0) {
567    return TRUE;
568  }
569
570  // Otherwise, only allow terms that are within the allowed depth.
571  static $valid_tids;
572  if (!isset($valid_tids[$vid][$root_tid][$allowed_depth])) {
573    $valid_tids[$vid][$root_tid][$allowed_depth] = array();
574    $tree = _hs_taxonomy_hierarchical_select_get_tree($vid, $root_tid);
575    foreach ($tree as $term) {
576      if ($term->depth < $allowed_depth) {
577        $valid_tids[$vid][$root_tid][$allowed_depth][] = $term->tid;
578      }
579    }
580  }
581  return in_array($tid, $valid_tids[$vid][$root_tid][$allowed_depth]);
582}
Nota: Vea TracBrowser para ayuda de uso del navegador del repositorio.