You are here

entityreference_dragdrop.module in Entity Reference Drag & Drop 7

Same filename and directory in other branches
  1. 8 entityreference_dragdrop.module
  2. 2.x entityreference_dragdrop.module

Provides a Drag & Drop widget for entity-reference fields.

File

entityreference_dragdrop.module
View source
<?php

/**
 * @file
 * Provides a Drag & Drop widget for entity-reference fields.
 */

/**
 * Implements hook_field_widget_info().
 */
function entityreference_dragdrop_field_widget_info() {
  return array(
    'entityreference_dragdrop' => array(
      'label' => t('Drag & Drop'),
      'field types' => array(
        'entityreference',
      ),
      'settings' => array(
        'view_mode' => 'title',
        'available_entities_label' => t('Available entities'),
        'selected_entities_label' => t('Selected entities'),
        'display_filter' => 0,
      ),
      'behaviors' => array(
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
      ),
    ),
  );
}

/**
 * Implements hook_field_widget_form().
 */
function entityreference_dragdrop_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {

  // If we have more than one element per page,
  // this element-counter keeps them separated.
  $ec =& drupal_static(__FUNCTION__, 0);
  $handler = entityreference_get_selection_handler($field, $instance);
  $options = $handler
    ->getReferencableEntities();
  $selected = entityreference_dragdrop_get_selected_options($items, $options);
  $available = entityreference_dragdrop_get_available_options($items, $options);
  $markup_available = entityreference_dragdrop_build_html($available, $field, $instance, $ec, array(
    'entityreference-dragdrop-available',
  ));
  $markup_selected = entityreference_dragdrop_build_html($selected, $field, $instance, $ec, array(
    'entityreference-dragdrop-selected',
  ));
  $label = '<div class="entityreference-dragdrop-label">' . $instance['label'] . '</div>';
  $message = $field['cardinality'] == -1 ? '' : '<div class="entityreference-dragdrop-message" data-ec="' . $ec . '">' . t("This field cannot hold more than @card values.", array(
    '@card' => $field['cardinality'],
  )) . '</div>';
  $filter_1 = $filter_2 = array();
  if ($instance['widget']['settings']['display_filter']) {
    $filter_1 = $filter_2 = array(
      '#type' => 'textfield',
      '#attributes' => array(
        'class' => array(
          'entityreference-dragdrop-filter',
        ),
      ),
    );
  }
  $html_1 = '<div class="entityreference-dragdrop-container entityreference-dragdrop-container-available">';
  $html_1 .= '<div class="entityreference-dragdrop-list-header">';
  $html_1 .= $instance['widget']['settings']['available_entities_label'];
  $html_1 .= '</div>';
  $html_1 .= drupal_render($filter_1);
  $html_1 .= $markup_available;
  $html_1 .= '</div>';
  $html_2 = '<div class="entityreference-dragdrop-container entityreference-dragdrop-container-selected">';
  $html_2 .= '<div class="entityreference-dragdrop-list-header">';
  $html_2 .= $instance['widget']['settings']['selected_entities_label'];
  $html_2 .= '</div>';
  $html_2 .= drupal_render($filter_2);
  $html_2 .= $markup_selected;
  $html_2 .= '</div>';
  $element += array(
    '#type' => 'hidden',
    '#default_value' => implode(',', array_keys($selected)),
    '#element_validate' => array(
      'entityreference_dragdrop_element_validate',
    ),
    '#suffix' => $label . '<div class="entityreference-dragdrop-widget-wrapper">' . $html_1 . $html_2 . '</div>' . $message . '<div class="entityreference-dragdrop-clear"></div>',
    '#attached' => array(
      'js' => array(
        drupal_get_path('module', 'entityreference_dragdrop') . '/entityreference_dragdrop.js',
        array(
          'data' => array(
            'entityreference_dragdrop' => array(
              $ec => $field['cardinality'],
            ),
          ),
          'type' => 'setting',
        ),
      ),
      'css' => array(
        drupal_get_path('module', 'entityreference_dragdrop') . '/entityreference_dragdrop.css',
      ),
      'library' => array(
        array(
          'system',
          'ui.sortable',
        ),
      ),
    ),
    '#attributes' => array(
      'class' => array(
        'entityreference-dragdrop-values',
      ),
      'data-ec' => array(
        $ec,
      ),
    ),
  );

  // Increment the element-counter
  $ec++;
  return $element;
}

/**
 * Formats the value array properly.
 */
function entityreference_dragdrop_element_validate($element, &$form_state) {
  $value = array();
  if (!empty($element['#value'])) {
    $ids = explode(',', $element['#value']);
    $value = array();
    foreach ($ids as $id) {
      $value[] = array(
        'target_id' => $id,
      );
    }
  }

  // Update the value of this element so the field can validate the product IDs.
  form_set_value($element, $value, $form_state);
}

/**
 * Implements hook_field_widget_settings_form().
 */
function entityreference_dragdrop_field_widget_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $settings = $widget['settings'];
  $info = entity_get_info($field['settings']['target_type']);
  $options = array(
    'title' => t('Title'),
    'default' => t('Default'),
  );
  foreach ($info['view modes'] as $view_mode_id => $view_mode) {
    if ($view_mode['custom settings']) {
      $options += array(
        $view_mode_id => t($view_mode['label']),
      );
    }
  }
  $form = array();
  if ($widget['type'] == 'entityreference_dragdrop') {
    $form['view_mode'] = array(
      '#type' => 'select',
      '#title' => t('View mode'),
      '#default_value' => $settings['view_mode'],
      '#options' => $options,
      '#description' => t('Select one of available target entity view mode.'),
    );
    $form['available_entities_label'] = array(
      '#type' => 'textfield',
      '#title' => t('Available entities label'),
      '#default_value' => $settings['available_entities_label'],
      '#description' => t('Type a label that will be displayed above block with available entities.'),
    );
    $form['selected_entities_label'] = array(
      '#type' => 'textfield',
      '#title' => t('Selected entities label'),
      '#default_value' => $settings['selected_entities_label'],
      '#description' => t('Type a label that will be displayed above block with selected entities.'),
    );
    $form['display_filter'] = array(
      '#type' => 'checkbox',
      '#title' => t('Display item filter'),
      '#default_value' => $settings['display_filter'],
    );
  }
  return $form;
}

/**
 * Returns available options.
 */
function entityreference_dragdrop_get_available_options($items, $options) {

  // Build an array of available items in id => label format.
  $available = array();
  foreach ($options as $bundle => $entities) {
    foreach ($entities as $id => $label) {
      $is_available = TRUE;
      foreach ($items as $item) {
        if ($id == $item['target_id']) {
          $is_available = FALSE;
        }
      }
      if ($is_available) {
        $available[$id] = $label;
      }
    }
  }
  return $available;
}

/**
 * Returns selected options.
 */
function entityreference_dragdrop_get_selected_options($items, $options) {

  // Build an array of selected items in id => label format.
  $selected = array();
  foreach ($items as $item) {
    foreach ($options as $bundle => $entities) {
      if (array_key_exists($item['target_id'], $entities)) {
        $selected[$item['target_id']] = $entities[$item['target_id']];
      }
    }
  }
  return $selected;
}

/**
 * Builds HTML for dragable list of items.
 */
function entityreference_dragdrop_build_html($options, $field, $instance, $ec, $classes = array()) {
  $view_mode = $instance['widget']['settings']['view_mode'];
  $target_type = $field['settings']['target_type'];
  $list_items = array();
  if ($view_mode != 'title') {
    if (!empty($options)) {
      $entities = entity_load($target_type, array_keys($options));
      $renderable_entities = entity_view($target_type, $entities, $view_mode);
      foreach ($renderable_entities[$target_type] as $id => $entity) {
        if (is_array($entity)) {
          $list_items[$id] = $entity;
        }
        else {
          $list_items[$id] = array(
            '#markup' => $options[$id],
          );
        }
      }
    }
  }
  else {
    foreach ($options as $id => $label) {
      $list_items[$id] = array(
        '#markup' => $label,
      );
    }
  }

  // Build HTML to represent options.
  $html = '<ul data-ec="' . $ec . '" class="entityreference-dragdrop ' . implode(" ", $classes) . '">';
  foreach ($list_items as $id => $item) {
    $html .= '<li data-ec="' . $ec . '" data-id="' . $id . '" data-label="' . $options[$id] . '">' . drupal_render($item) . '</li>';
  }
  $html .= '</ul>';
  return $html;
}