view noderef_view.module @ 15:bf2615aab48c tip

Make the module Coder-clean
author Franck Deroche <franck@defr.org>
date Tue, 31 Mar 2009 17:31:55 +0200
parents e060ad73e358
children
line wrap: on
line source
<?php
// vim: set ts=2 sw=2 expandtab syntax=php:

/**
 * @file 
 * Fichier principale du module noderef_view
 * 
 * Ce module permet d'ajouter à tous les champs de type "Node Reference"
 * pour lesquels une vue définissant les nodes autorisés a été définie
 * un lien 'Search' affichant la vue dans une popup (via le module Popups API),
 * permettant de choisir les nodes à mettre dans le champ en disposant de la
 * puissance de Views pour la recherche (Exposed Filters notamment).
 */

/**
 * Implémentation de hook_view_action_info().
 * 
 * On crée une nouvelle action, nommée Select, et qui sera utilisée pour marquer
 * les nodes comme données à utiliser. L'utilisation concrète qui en est faite
 * dans ce module consiste à utiliser ces nœuds selectionés pour les ajouter
 * dans le champ Node Reference étant à l'origine de la recherche.
 */
function noderef_view_action_info() {
  return array(
    'noderef_view_select' => array(
      'description'  => t('Add selected values to field'),
      'type'         => 'node',
      'configurable' => FALSE,
      'hooks' => array(
        'nodeapi' => array()
      )
    )
  );
}

/**
 * Implémentation concrète de l'action de selection.
 * 
 * On vide toute eventuelle selection précédente, puis on passe dans le cookie
 * les informations sur la selection qui a été faite.
 */
function noderef_view_select($node, $context) {
  static $count = 0;
  if ($count == 0 && is_array($_COOKIE['noderef'])) {
    // Reset the cookies
    $before = time() - 300;
    foreach ($_COOKIE['noderef'] as $id => $val) {
      setcookie('noderef['. $id .']', 0, $before, '/');
    }
  }
  $count++;
  $five = time() + 300;
  setrawcookie('noderef['. $node->nid .']', rawurlencode($node->title), $five, '/');
  drupal_set_message(t('!title added to selection', 
    array('!title' => $node->title)));
}

/**
 * Implémentation de hook_form_alter().
 *
 * On parcoure tous les formulaires à la recherche d'éventuels champs
 * de type "Node Reference" sur lesquels appliqués nos transformations.
 */
function noderef_view_form_alter(&$form, $form_state, $form_id) {
  if (isset($form['type']) && $form_id == $form['type']['#value'] .'_node_form') {
    // That's a node form, get the fields and alter the form if needed
    $fields = content_fields();
    $alter = _noderef_view_walk_form($form, $fields, $form);
    if ($alter) {
      // We've changed the form, add the JS-behavior and Views CSS
      // (the latter to deal with exposed filters in the popup)
      $path = drupal_get_path('module', 'noderef_view');
      drupal_add_js($path .'/noderef_view.js');
      drupal_add_css($path .'/noderef_view.css');
      drupal_add_css(drupal_get_path('module', 'views') .'/css/views.css');
    }
  }
  elseif ($form_id == 'views_exposed_form' && isset($_GET['destination'])) {
    // Views "Exposed Filter" forms doesn't preserve destination by default.
    $form['destination'] = array(
      '#type' => 'hidden',
      '#value' => $_GET['destination']
    );
  }
}

/**
 * Parcoure le tableau contenant le formulaire à la recherche
 * d'élement à modifier.
 * @return
 *   TRUE si un élement a été modifié, FALSE sinon
 */
function _noderef_view_walk_form(&$form, $fields, $items) {
  $alter = FALSE;
  foreach ($items as $key => $item) {
    if (is_array($item)) {
      if (isset($fields[$key])) {
        $alter |= noderef_view_alter_item($form, $key, $fields[$key]);
      }
      else {
        $alter |= _noderef_view_walk_form($form, $fields, $item);
      }
    }
  }
  return $alter;
}

/**
 * Modification d'un élement en particulier du formulaire.
 *
 * @return 
 *   TRUE si l'element a été modifié, FALSE sinon.
 */
function noderef_view_alter_item(&$form, $key, $field) {
  if (is_array($field) && $field['type'] == 'nodereference') {
    $link = _noderef_view_get_link($field);
    if (!empty($link)) {
      return TRUE;
    }
  }
  return FALSE;
}

/**
 * Création d'un lien vers une éventuelle vue associé au champ.
 *
 * @return
 *  - Un lien vers la vue si une vue est associée
 *  - Une chaine vide sinon
 */ 
function _noderef_view_get_link($field) {
  $path = '';
  // Check if there's a view associated with this field
  if (isset($field['advanced_view']) && $field['advanced_view'] !== '--') {
    $view = views_get_view($field['advanced_view']);
    // Try to find a path for this view, looking at the displays
    if (!is_array($view->display)) {
      return '';
    }
    $path = '';
    foreach ($view->display as $display) {
      if (is_array($display->display_options) 
        && isset($display->display_options['path'])) {
        $path = $display->display_options['path'];
        break;
      }
    }
  }
  // If we found a view with a suitable display, then link to it
  if (!empty($path)) {
    popups_add_popups(array('.noderef_view_link' => array(
      'noUpdate' => FALSE,
      'noMessage' => FALSE 
    )));
    $options = array(
      'attributes' => array('class' => 'noderef_view_link'),
      'query' => array('destination' => 'node')
    );
    $path = l(t('Search'), $path, $options);
  }
  return $path;
}

function noderef_view_theme() {
  return array(
    'noderef_view_autocomplete' => array(
      'arguments' => array('element' => NULL)
    )
  );
}

function noderef_view_widget_info() {
  return array(
    'noderef_view_autocomplete' => array(
      'label' => t('Autocomplete text field with View'),
      'field types' => array('nodereference'),
      'multiple values' => CONTENT_HANDLE_CORE,
      'callbacks' => array(
        'default value' => CONTENT_CALLBACK_DEFAULT,
      ),
    ),
  );
}

function noderef_view_elements() {
  return array(
   'noderef_view_autocomplete' => array(
      '#input' => TRUE,
      '#columns' => array('name'), '#delta' => 0,
      '#process' => array('noderef_view_autocomplete_process'),
      '#autocomplete_path' => FALSE,
      ),
  );
}

function noderef_view_widget(&$form, &$form_state, $field, $items, $delta = 0) {
  switch ($field['widget']['type']) {
    case 'noderef_view_autocomplete':
      $element = array(
        '#type' => 'noderef_view_autocomplete',
        '#default_value' => isset($items[$delta]) ? $items[$delta] : NULL,
        '#value_callback' => 'nodereference_autocomplete_value',
      );
      break;
  }
  return $element;
}

/**
 * Process an individual element.
 *
 * Build the form element. When creating a form using FAPI #process,
 * note that $element['#value'] is already set.
 *
 */
function noderef_view_autocomplete_process($element, $edit, $form_state, $form) {
  // The nodereference autocomplete widget doesn't need to create its own
  // element, it can wrap around the text_textfield element and add an autocomplete
  // path and some extra processing to it.
  // Add a validation step where the value can be unwrapped.
  $fields     = content_fields();
  $link       = _noderef_view_get_link($fields[$element['#field_name']]);
  $field_key  = $element['#columns'][0];
  $element[$field_key] = array(
    '#type' => 'text_textfield',
    '#default_value' => isset($element['#value']) ? $element['#value'] : '',
    '#autocomplete_path' => 'nodereference/autocomplete/'. $element['#field_name'],
    // The following values were set by the content module and need
    // to be passed down to the nested element.
    '#title' => $element['#title'],
    '#required' => $element['#required'],
    '#description' => $element['#description'],
    '#field_name' => $element['#field_name'],
    '#type_name' => $element['#type_name'],
    '#delta' => $element['#delta'],
    '#columns' => $element['#columns'],
  );
  if ($link) {
    $element[$field_key]['#noderef_view_link'] = $link;
    $element[$field_key]['#prefix'] = "<div class='noderef-view-wrapper'>";
    $element[$field_key]['#suffix'] = $link ."</div>";
  }
  if (empty($element[$field_key]['#element_validate'])) {
    $element[$field_key]['#element_validate'] = array();
  }
  array_unshift($element[$field_key]['#element_validate'], 'nodereference_autocomplete_validate');

  // Used so that hook_field('validate') knows where to flag an error.
  $element['_error_element'] = array(
    '#type' => 'value',
    // Wrapping the element around a text_textfield element creates a
    // nested element, so the final id will look like 'field-name-0-nid-nid'.
    '#value' => implode('][', array_merge($element['#parents'], array($field_key, $field_key))),
  );
  return $element;
}

function theme_noderef_view_autocomplete($element) {
  return <<<EOT
<div class='noderef-view-wrapper'>
   {$element['#children']}
   {$element['#noderef_view_link']}
   <span class='clear-block'></span>
</div>
EOT;
}