You are here

nodequeue_reference.module in Nodequeue reference 7

Form field type for node queues.

File

nodequeue_reference.module
View source
<?php

/**
 * @file
 * Form field type for node queues.
 */

/**
 * Implements hook_menu().
 */
function nodequeue_reference_menu() {
  $items['nodequeue_reference/autocomplete/%/%/%'] = array(
    'page callback' => 'nodequeue_reference_autocomplete',
    'page arguments' => array(
      2,
      3,
      4,
    ),
    'access callback' => 'nodequeue_reference_autocomplete_access',
    'access arguments' => array(
      2,
      3,
      4,
    ),
    'type' => MENU_CALLBACK,
  );
  if (module_exists('references_dialog')) {
    $items['nodequeue-reference/dialog/redirect'] = array(
      'page callback' => 'nodequeue_reference_dialog_redirect_page',
      'page arguments' => array(
        3,
      ),
      'access callback' => TRUE,
      'file' => 'includes/nodequeue_reference.dialog_pages.inc',
      'type' => MENU_CALLBACK,
    );
  }
  return $items;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function nodequeue_reference_form_nodequeue_edit_queue_form_alter(&$form, &$form_state, $form_id) {
  if (module_exists('references_dialog') && references_dialog_in_dialog() && references_dialog_close_on_submit()) {
    $form['#submit'][] = 'nodequeue_reference_nodequeue_edit_submit';
  }
}

/**
 * Submit callback for closing the dialog tab.
 * If creating a new Nodequeue, we will be directed to the callback for modifing the nodequeue nodes.
 * The menu callback will output javascript that will close the dialog, and pass paramenters to the main window.
 * Note that the field value will be overriden in the end.
 */
function nodequeue_reference_nodequeue_edit_submit($form, &$form_state) {
  $qid = $form_state['values']['qid'];
  $is_new = !empty($_GET['nodequeue-new-dialog']);
  if ($is_new) {

    // If creating a new nodequeue, go to the nodequeue view for adding nodes.
    $subqueues = nodequeue_load_subqueues_by_queue($qid);
    $keys = array_keys($subqueues);
    $sqid = reset($keys);
    $_GET['destination'] = "admin/structure/nodequeue/{$qid}/view/{$sqid}" . '?render=references-dialog';
  }
  else {
    $_GET['destination'] = "nodequeue-reference/dialog/redirect/{$qid}" . '?render=references-dialog&references-dialog-close=1';
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function nodequeue_reference_form_nodequeue_arrange_subqueue_form_alter(&$form, &$form_state, $form_id) {
  if (module_exists('references_dialog') && references_dialog_in_dialog() && references_dialog_close_on_submit()) {
    $form['actions']['submit']['#submit'][] = 'nodequeue_reference_nodequeue_view_submit';
  }
}

/**
 * Submit callback for modifying nodequeue nodes from the dialog
 * The menu callback will output javascript that will close the dialog, and pass paramenters to the main window.
 * Note that the field value will be overriden in the end.
 */
function nodequeue_reference_nodequeue_view_submit($form, &$form_state) {
  if (references_dialog_in_dialog() && references_dialog_close_on_submit()) {
    $qid = $form['nodes']['#queue']['qid'];
    $_GET['destination'] = "nodequeue-reference/dialog/redirect/{$qid}" . '?render=references-dialog&references-dialog-close=1';
  }
}

/**
 * Menu access callback for nodequeue reference autocomplete paths.
 *
 * Check for both 'edit' and 'view' access in the unlikely event
 * a user has edit but not view access.
 */
function nodequeue_reference_autocomplete_access($entity_type, $bundle, $field_name, $entity = NULL, $account = NULL) {
  return user_access('access content', $account) && ($field = field_info_field($field_name)) && field_info_instance($entity_type, $field_name, $bundle) && field_access('view', $field, $entity_type, $entity, $account) && field_access('edit', $field, $entity_type, $entity, $account);
}

/**
 * Implements hook_field_info().
 */
function nodequeue_reference_field_info() {
  return array(
    'nodequeue_reference' => array(
      'label' => t('Nodequeue reference'),
      'description' => t('This field stores a reference to a nodequeue'),
      'default_widget' => 'options_select',
      'default_formatter' => 'nodequeue_reference_formatter',
      'settings' => array(),
    ),
  );
}

/**
 * Implements hook_field_widget_info().
 */
function nodequeue_reference_field_widget_info() {
  return array(
    'nodequeue_reference_autocomplete' => array(
      'label' => t('Autocomplete nodequeue field'),
      'field types' => array(
        'nodequeue_reference',
      ),
      'settings' => array(
        'size' => 60,
        'autocomplete_path' => 'nodequeue_reference/autocomplete',
        'autocomplete_match' => 'contains',
        'link' => 0,
      ),
      'property_type' => 'integer',
    ),
  );
}

/**
 * Implements hook_field_widget_settings_form().
 */
function nodequeue_reference_field_widget_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $defaults = field_info_widget_settings($widget['type']);
  $settings = array_merge($defaults, $widget['settings']);
  $form = array();
  if ($widget['type'] == 'nodequeue_reference_autocomplete') {
    $form['autocomplete_match'] = array(
      '#type' => 'select',
      '#title' => t('Autocomplete matching'),
      '#default_value' => $settings['autocomplete_match'],
      '#options' => array(
        'starts_with' => t('Starts with'),
        'contains' => t('Contains'),
      ),
      '#description' => t('Select the method used to collect autocomplete suggestions. Note that <em>Contains</em> can cause performance issues on sites with thousands of nodes.'),
    );
    $form['size'] = array(
      '#type' => 'textfield',
      '#title' => t('Size of textfield'),
      '#default_value' => $settings['size'],
      '#element_validate' => array(
        '_element_validate_integer_positive',
      ),
      '#required' => TRUE,
    );
  }
  return $form;
}

/**
 * Implements hook_field_widget_info_alter().
 */
function nodequeue_reference_field_widget_info_alter(&$info) {
  $info['options_select']['field types'][] = 'nodequeue_reference';
  $info['options_buttons']['field types'][] = 'nodequeue_reference';
}

/**
 * Implements hook_field_is_empty().
 */
function nodequeue_reference_field_is_empty($item, $field) {
  return empty($item['qid']);
}

/**
 * Implements hook_field_formatter_info().
 */
function nodequeue_reference_field_formatter_info() {
  return array(
    'nodequeue_reference_default' => array(
      'label' => t('Default'),
      'field types' => array(
        'nodequeue_reference',
      ),
    ),
    'nodequeue_reference_qid' => array(
      'label' => t('Qid Nodequeue'),
      'field types' => array(
        'nodequeue_reference',
      ),
    ),
    'nodequeue_list_nodes' => array(
      'label' => t('List of nodes'),
      'field types' => array(
        'nodequeue_reference',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_view().
 */
function nodequeue_reference_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  switch ($display['type']) {
    case 'nodequeue_reference_default':
      foreach ($items as $delta => $item) {
        if ($item['qid']) {
          $nodequeue = nodequeue_load($item['qid']);
          $output = $nodequeue->title;
          $element[$delta] = array(
            '#markup' => $output,
          );
        }
      }
      break;
    case 'nodequeue_reference_qid':
      foreach ($items as $delta => $item) {
        $element[$delta] = array(
          '#markup' => $item['qid'],
        );
      }
      break;
    case 'nodequeue_list_nodes':
      foreach ($items as $delta => $item) {
        $result = array();
        $queue = nodequeue_load($item['qid']);
        $nodes = nodequeue_load_nodes($item['qid'], $queue->reverse, 0, $queue->count);
        foreach ($nodes as $node) {
          $label = entity_label('node', $node);
          $uri = entity_uri('node', $node);
          $result[] = l($label, $uri['path'], array(
            'attributes' => array(
              'class' => array(
                'node-link',
              ),
            ),
          ));
        }
        $element[$delta]['#markup'] = theme('item_list', array(
          'items' => $result,
        ));
      }
      break;
  }
  return $element;
}

/**
 * Implements hook_field_widget_form().
 */
function nodequeue_reference_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $widget = $instance['widget'];
  $defaults = field_info_widget_settings($widget['type']);
  $settings = array_merge($defaults, $widget['settings']);
  global $user;
  switch ($instance['widget']['type']) {
    case 'nodequeue_reference_autocomplete':
      $element += array(
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]['qid']) ? $items[$delta]['qid'] : NULL,
        '#autocomplete_path' => $settings['autocomplete_path'] . '/' . $instance['entity_type'] . '/' . $instance['bundle'] . '/' . $field['field_name'],
        '#size' => $settings['size'],
        '#maxlength' => NULL,
        '#element_validate' => array(
          'nodequeue_reference_autocomplete_validate',
        ),
        '#value_callback' => 'nodequeue_reference_autocomplete_value',
      );
      break;
  }
  return array(
    'qid' => $element,
  );
}

/**
 * Value callback for a nodequeue_reference autocomplete element.
 *
 * Replace the queue qid with a queue title.
 */
function nodequeue_reference_autocomplete_value($element, $input = FALSE) {
  if ($input === FALSE) {
    $qid = $element['#default_value'];
    if (!empty($qid)) {
      $queue = nodequeue_load($qid);
      $value = $queue->title;
      $value .= ' [qid: ' . $qid . ']';
      return $value;
    }
  }
}

/**
 * Validation callback for a nodequeue_reference autocomplete element.
 */
function nodequeue_reference_autocomplete_validate($element, &$form_state, $form) {
  $field = field_widget_field($element, $form_state);
  $instance = field_widget_instance($element, $form_state);
  $value = $element['#value'];
  $qid = NULL;
  if (!empty($value)) {

    // Check whether we have an explicit "[qid:n]" input.
    preg_match('/^(?:\\s*|(.*) )?\\[\\s*qid*:\\s*(\\d+)\\s*\\]$/', $value, $matches);
    if (!empty($matches)) {

      // Explicit qid. Check that the 'title' part matches the actual title for
      // the qid.
      list(, $title, $qid) = $matches;
      if (!empty($title)) {
        $real_title = db_select('nodequeue_queue', 'q')
          ->fields('q', array(
          'title',
        ))
          ->condition('q.qid', $qid)
          ->execute()
          ->fetchField();
        if (trim($title) != trim($real_title)) {
          form_error($element, t('%name: title mismatch. Please check your selection.', array(
            '%name' => $instance['label'],
          )));
        }
      }
    }
    else {
      form_error($element, t('%name: found no valid nodequeue with that title.', array(
        '%name' => $instance['label'],
      )));
    }
  }

  // Set the element's value as the nodequeue id that was extracted from the entered
  // input.
  form_set_value($element, $qid, $form_state);
}

/**
 * Implements hook_field_widget_error().
 */
function nodequeue_reference_field_widget_error($element, $error, $form, &$form_state) {
  form_error($element, $error['message']);
}

/**
 * Implements hook_options_list().
 */
function nodequeue_reference_options_list($field, $instance, $entity_type, $entity) {
  $result = db_query("SELECT qid, title FROM {nodequeue_queue} ORDER BY title");
  $options = array();
  foreach ($result as $queue) {
    $options[$queue->qid] = $queue->title;
  }
  return $options;
}

/**
 * Menu callback for the autocomplete results.
 */
function nodequeue_reference_autocomplete($entity_type, $bundle, $field_name, $string = '') {
  $field = field_info_field($field_name);
  $instance = field_info_instance($entity_type, $field_name, $bundle);
  $options = array(
    'string' => $string,
    'match' => $instance['widget']['settings']['autocomplete_match'],
    'limit' => 10,
    'ids' => array(),
  );
  $results =& drupal_static(__FUNCTION__, array());

  // Create unique id for static cache.
  $cid = $field['field_name'] . ':' . $options['match'] . ':' . ($options['string'] !== '' ? $options['string'] : implode('-', $options['ids'])) . ':' . $options['limit'];
  if (!isset($results[$cid])) {
    $references = FALSE;
    $query = db_select('nodequeue_queue', 'q');
    $queue_qid_alias = $query
      ->addField('q', 'qid');
    $queue_title_alias = $query
      ->addField('q', 'title');
    if ($options['string'] !== '') {
      switch ($options['match']) {
        case 'contains':
          $query
            ->condition('title', '%' . $options['string'] . '%', 'LIKE');
          break;
        case 'starts_with':
          $query
            ->condition('q.title', $options['string'] . '%', 'LIKE');
          break;
        case 'equals':
        default:

          // no match type or incorrect match type: use "="
          $query
            ->condition('q.title', $options['string']);
          break;
      }
    }
    if ($options['ids']) {
      $query
        ->condition('q.qid', $options['ids'], 'IN');
    }
    if ($options['limit']) {
      $query
        ->range(0, $options['limit']);
    }
    $query
      ->orderBy($queue_title_alias);
    $result = $query
      ->execute()
      ->fetchAll();
    $references = array();
    foreach ($result as $queue) {
      $references[$queue->qid] = array(
        'title' => $queue->title,
        'rendered' => check_plain($queue->title),
      );
    }

    // Store the results.
    $results[$cid] = !empty($references) ? $references : array();
  }
  $references = $results[$cid];
  $matches = array();
  foreach ($references as $id => $row) {

    // Markup is fine in autocompletion results (might happen when rendered
    // through Views) but we want to remove hyperlinks.
    $suggestion = preg_replace('/<a href="([^<]*)">([^<]*)<\\/a>/', '$2', $row['rendered']);

    // Add a class wrapper for a few required CSS overrides.
    $matches[$row['title'] . " [qid: {$id}]"] = '<div class="reference-autocomplete">' . $suggestion . '</div>';
  }
  drupal_json_output($matches);
}

Functions

Namesort descending Description
nodequeue_reference_autocomplete Menu callback for the autocomplete results.
nodequeue_reference_autocomplete_access Menu access callback for nodequeue reference autocomplete paths.
nodequeue_reference_autocomplete_validate Validation callback for a nodequeue_reference autocomplete element.
nodequeue_reference_autocomplete_value Value callback for a nodequeue_reference autocomplete element.
nodequeue_reference_field_formatter_info Implements hook_field_formatter_info().
nodequeue_reference_field_formatter_view Implements hook_field_formatter_view().
nodequeue_reference_field_info Implements hook_field_info().
nodequeue_reference_field_is_empty Implements hook_field_is_empty().
nodequeue_reference_field_widget_error Implements hook_field_widget_error().
nodequeue_reference_field_widget_form Implements hook_field_widget_form().
nodequeue_reference_field_widget_info Implements hook_field_widget_info().
nodequeue_reference_field_widget_info_alter Implements hook_field_widget_info_alter().
nodequeue_reference_field_widget_settings_form Implements hook_field_widget_settings_form().
nodequeue_reference_form_nodequeue_arrange_subqueue_form_alter Implements hook_form_FORM_ID_alter().
nodequeue_reference_form_nodequeue_edit_queue_form_alter Implements hook_form_FORM_ID_alter().
nodequeue_reference_menu Implements hook_menu().
nodequeue_reference_nodequeue_edit_submit Submit callback for closing the dialog tab. If creating a new Nodequeue, we will be directed to the callback for modifing the nodequeue nodes. The menu callback will output javascript that will close the dialog, and pass paramenters to the main…
nodequeue_reference_nodequeue_view_submit Submit callback for modifying nodequeue nodes from the dialog The menu callback will output javascript that will close the dialog, and pass paramenters to the main window. Note that the field value will be overriden in the end.
nodequeue_reference_options_list Implements hook_options_list().