You are here

button_field.module in Button Field 7

Same filename and directory in other branches
  1. 8 button_field.module
  2. 6 button_field.module

Defines a field, widget and formatter for the button field type.

File

button_field.module
View source
<?php

/**
 * @file
 * Defines a field, widget and formatter for the button field type.
 */

/**
 * Implements button_field_views_api().
 */
function button_field_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'button_field') . '/includes/views',
  );
}

/**
 * Form builder callback for the dummy form used to render button field's on a
 * display that is not editable.
 */
function button_field_dummy_form($form, &$form_state) {

  // Set the form's language.
  $langcode = field_language($form_state['#entity_type'], $form_state['#' . $form_state['#entity_type']], $form_state['#field']['field_name']);
  $form['language']['#value'] = $langcode;

  // Add the field and the instance to the form state.
  $field_name = $form_state['#field']['field_name'];
  $form_state['field'][$field_name][$langcode]['field'] =& $form_state['#field'];
  $form_state['field'][$field_name][$langcode]['instance'] =& $form_state['#instance'];

  // Add the field element to the form.
  $form[$field_name][$langcode][0] = $form_state['#element'];
  return $form;
}

/**
 * Callback function for the FAPI ajax framework, used on edit forms.
 */
function button_field_callback_ajax(&$form, &$form_state) {

  // Get the field that was clicked.
  $language = $form['language']['#value'];
  $field_name = $form_state['triggering_element']['#array_parents'][0];
  $field = $form_state['field'][$field_name][$language]['field'];

  // Get the entity and its type.
  list($entity_type, $entity) = _button_field_callback_get_entity($form, $form_state, $field_name, $language);

  // Trigger the rules event.
  $entity_wrapper = entity_metadata_wrapper($entity_type, $entity);
  rules_invoke_all('button_field_clicked', $field, $entity_wrapper);
  return _button_field_ajax_response();
}

/**
 * Creates a Drupal Ajax buttonFieldLocation command.
 *
 * @param string $url
 *   New location for the page
 */
function button_field_ajax_command_location($url) {
  return array(
    'command' => 'buttonFieldLocation',
    'url' => $url,
  );
}

/**
 * Implements hook_field_info().
 */
function button_field_field_info() {
  return array(
    'button_field' => array(
      'label' => t('Button'),
      'description' => t('Displays a button that, when clicked, fires a rules event'),
      'default_widget' => 'button_field_html',
      'default_formatter' => 'button_field_default',
    ),
  );
}

/**
 * Implements hook_field_schema().
 */
function button_field_field_schema($field) {
  return array(
    'columns' => array(
      'value' => array(
        'type' => 'varchar',
        'length' => 255,
        'not null' => TRUE,
      ),
    ),
    'indexes' => array(
      'value' => array(
        'value',
      ),
    ),
  );
}

/**
 * Implements hook_field_is_empty().
 */
function button_field_field_is_empty($item, $field) {
  return TRUE;
}

/**
 * Implements hook_field_formatter_info().
 */
function button_field_field_formatter_info() {
  return array(
    'button_field_default' => array(
      'label' => t('Default'),
      'field types' => array(
        'button_field',
      ),
    ),
  );
}

/**
 * Implements hook_field_formatter_view().
 */
function button_field_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $ids = entity_extract_ids($entity_type, $entity);
  $entity_id = $ids[0];

  // Build the field element.
  $delta = isset($display['views_row_id']) ? $display['views_row_id'] : 0;
  $id = _button_field_build_id($field, 'view', $delta, $langcode);
  $element = _button_field_build_element($id, $field, $instance, $entity_type, $entity);
  $form_state = array(
    'build_info' => array(
      'args' => array(
        &$entity,
      ),
    ),
    '#entity_type' => $entity_type,
    '#' . $entity_type => &$entity,
    '#field' => &$field,
    '#instance' => &$instance,
    '#element' => $element,
  );
  $form = drupal_build_form('button_field_dummy_form', $form_state);
  $element = ajax_process_form($element, $form_state);
  $form[$field['field_name']] = $element;
  $form_state['#element'] = $element;
  form_set_cache($form['#build_id'], $form, $form_state);
  $form = _button_field_get_dummy_form($entity_type, $entity, $field, $instance, $element);
  return $form;
}

/**
 * Implements hook_field_widget_info().
 */
function button_field_field_widget_info() {
  return array(
    'button_field_html' => array(
      'label' => 'HTML Button',
      'field types' => array(
        'button_field',
      ),
      'settings' => array(
        'text' => NULL,
        'additional_classes' => NULL,
        'edit_hidden' => 1,
      ),
    ),
    'button_field_image' => array(
      'label' => 'Image Button',
      'field types' => array(
        'button_field',
      ),
      'settings' => array(
        'image_path' => NULL,
        'alt_text' => NULL,
        'title_text' => NULL,
        'additional_classes' => NULL,
        'edit_hidden' => 1,
      ),
    ),
  );
}

/**
 * Implements hook_field_settings_form().
 */
function button_field_field_settings_form($field, $instance, $has_data) {
  return array(
    'confirmation' => array(
      '#type' => 'textfield',
      '#title' => t('Confirmation message'),
      '#default_value' => isset($field['settings']['confirmation']) ? $field['settings']['confirmation'] : FALSE,
      '#description' => t('You may enter a confirmation message to be ' . 'displayed to the user before running any rules. If you do not ' . 'want the user to see a confirmation message you can leave this ' . 'setting empty.'),
    ),
  );
}

/**
 * Implements hook_field_widget_settings_form().
 */
function button_field_field_widget_settings_form($field, $instance) {
  $widget = $instance['widget'];
  $form = array(
    'additional_classes' => array(
      '#type' => 'textfield',
      '#title' => t('Additional classes'),
      '#default_value' => $widget['settings']['additional_classes'],
      '#description' => t('Optionally, specify any classes to be applied to ' . 'the element. All button field elements will always have the ' . '"button_field" class. Seperate multiple classes with a space.'),
    ),
    'edit_hidden' => array(
      '#type' => 'checkbox',
      '#title' => t('Hide on edit form'),
      '#default_value' => $widget['settings']['edit_hidden'],
      '#description' => t('Whether or not this field will be rendered on ' . 'the node edit and add forms. Note: Nodes do not get assisgned a ' . 'node id on the add form; therefore, any Rules that require the ' . 'node to be available on button click will not function properly.'),
    ),
  );
  $widget_settings = array();
  switch ($instance['widget']['type']) {
    case 'button_field_html':
      $widget_settings['text'] = array(
        '#type' => 'textfield',
        '#title' => t('Button Text'),
        '#default_value' => !empty($widget['settings']['text']) ? $widget['settings']['text'] : $instance['label'],
        '#required' => TRUE,
      );
      break;
    case 'button_field_image':
      $widget_settings['image_path'] = array(
        '#type' => 'textfield',
        '#title' => t('Image path'),
        '#default_value' => $widget['settings']['image_path'],
        '#required' => TRUE,
      );
      $widget_settings['alt_text'] = array(
        '#type' => 'textfield',
        '#title' => t('Alt text'),
        '#default_value' => !empty($widget['settings']['alt_text']) ? $widget['settings']['alt_text'] : $instance['label'],
        '#required' => TRUE,
      );
      $widget_settings['title_text'] = array(
        '#type' => 'textfield',
        '#title' => t('Title text'),
        '#default_value' => !empty($widget['settings']['title_text']) ? $widget['settings']['title_text'] : $instance['label'],
        '#required' => FALSE,
      );
      break;
  }
  return array_merge($widget_settings, $form);
}

/**
 * Implements hook_form_FORM_ID_alter().
 *
 * Hides the required and cardinality fields and removes the default value from
 * the field_ui_field_edit_form because it does not apply to this field type.
 */
function button_field_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
  if ($form['#field']['type'] == 'button_field') {

    // Hide the required field and set it to false.
    $form['instance']['required']['#type'] = 'hidden';
    $form['instance']['required']['#value'] = FALSE;

    // Hide the cardinality and set it to one.
    $form['field']['cardinality']['#type'] = 'hidden';
    $form['field']['cardinality']['#value'] = 1;

    // No need for a default value.
    unset($form['instance']['default_value_widget']);
  }
}

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

  // If this field is to be hidden on the edit form then we have nothing to do.
  if (!empty($instance['widget']['settings']['edit_hidden'])) {
    return $element;
  }
  $entity_type = $element['#entity_type'];
  $entity_id = $entity = NULL;
  if (isset($form_state[$entity_type])) {
    $entity =& $form_state[$entity_type];
    $ids = entity_extract_ids($entity_type, $entity);
    $entity_id = $ids[0];
  }
  $id = _button_field_build_id($field, 'edit', $delta, $langcode);
  $element = _button_field_build_element($id, $field, $instance, $entity_type, $entity);
  return $element;
}

/**
 * Gets the entity and its type from the form or form state during the ajax
 * callback.
 *
 * @param array $form
 *   The form to get the entity from.
 * @param array $form_state
 *   The current state of the form.
 * @param string $field_name
 *   Machine name of the field that triggered the callback.
 * @param string $language
 *   The form's language
 *
 * @return array
 *   Entity and entity type.
 */
function _button_field_callback_get_entity($form, $form_state, $field_name, $language) {

  // If the field element is present in the form state (which should only occur
  // if the button is on a non-ediatable display) then we can get the entity and
  // its type directly from there. Otherwise, we need to get it from the field
  // on the form.
  if (!empty($form_state['#element'])) {
    $entity_type = $form_state['#element']['#entity_type'];
    $entity = $form_state['#element']['#entity'];
  }
  else {
    $entity_type = $form[$field_name][$language][0]['#entity_type'];
    $entity =& $form[$field_name][$language][0]['#entity'];
  }
  return array(
    $entity_type,
    &$entity,
  );
}

/**
 * Builds the response for an ajax callback.
 */
function _button_field_ajax_response() {

  // Check to see if a page redirect action was used.
  $commands = array();
  $url = NULL;
  $force = FALSE;
  if (isset($GLOBALS['_rules_action_drupal_goto_do'])) {
    list($url, $force) = $GLOBALS['_rules_action_drupal_goto_do'];
  }

  // Check to see if we have a destination set and we are not forced to use a
  // redirect action.
  if (!$force && isset($_REQUEST['destination']) && !empty($_REQUEST['destination'])) {
    $url = urldecode($_REQUEST['destination']);
  }

  // If we have a url that we need to set the location to, get an ajax location
  // command to that url.
  if (!empty($url)) {
    $commands[] = button_field_ajax_command_location($url);
  }
  return array(
    '#type' => 'ajax',
    '#commands' => $commands,
  );
}

/**
 * Builds the renderable array for a button field widget.
 *
 * @param string $id
 *   Id for the field element.
 * @param array $field
 *   The field being rendered.
 * @param array $instance
 *   The instance of the field being rendered.
 * @param string $entity_type
 *   The type of entity that the button field is being rendered for.
 * @param stdClass $entity
 *   The entity that the button field is being rendered for.
 *
 * @return array
 *   Renderable array of the button form element.
 */
function _button_field_build_element($id, $field, $instance, $entity_type, $entity) {
  $class = array(
    'button_field',
  );
  if (isset($instance['additional_class'])) {
    $class = array_merge($classes, explode(' ', $instance['additional_class']));
  }

  // Check for confirmation message and build js settings if appropriate.
  if (isset($field['settings']['confirmation']) && !empty($field['settings']['confirmation'])) {

    // Add the script that will handle the confirmation before making the ajax
    // callback.
    drupal_add_js(drupal_get_path('module', 'button_field') . '/js/button_field.js');

    // Build the settings and add them to the page.
    $class[] = 'button_field_confirm';
    $settings[$id] = array(
      'confirmation' => $field['settings']['confirmation'],
    );
    drupal_add_js($settings, 'setting');
  }
  $element = array(
    '#type' => 'button',
    '#id' => $id,
    '#name' => $id,
    '#attributes' => array(
      'class' => $class,
    ),
    '#value' => isset($instance['widget']['settings']['text']) ? $instance['widget']['settings']['text'] : $instance['label'],
    // Button elements do not obey the #description index, so we need to add
    // our own suffix here.
    '#suffix' => '<div class="description">' . (!empty($instance['description']) ? $instance['description'] : '') . '</div>',
    '#entity_type' => $entity_type,
    '#entity' => $entity,
    '#ajax' => array(
      'callback' => 'button_field_callback_ajax',
    ),
  );

  // If this is an image button then we need to set the type appropriatly as
  // well as the image source.
  if ('button_field_image' == $instance['widget']['type']) {
    $element['#type'] = 'image_button';
    $element['#src'] = $instance['widget']['settings']['image_path'];
  }
  return $element;
}

/**
 * Builds the id for a button field instance.
 *
 * @param array $field
 *   Field info array.
 * @param string $mode
 *   Mode that the field will be rendered in (view|edit).
 * @param integer $delta
 *   Delta of the instance being rendered.
 * @param string $language
 *   Language of the current field.
 *
 * @return string
 *   Id to be used for the field.
 */
function _button_field_build_id($field, $mode = 'edit', $delta = 0, $language = LANGUAGE_NONE) {
  $parts = array(
    $mode,
    str_replace('_', '-', $field['field_name']),
    $language,
    $delta,
    'value',
  );
  return implode('-', $parts);
}

/**
 * Gets the dummy form to be used with button fields on a view form.
 *
 * @param string $entity_type
 *   The type of entity that the button field is being rendered for.
 * @param stdClass $entity
 *   The entity that the button field is being rendered for.
 * @param array $field
 *   The button field that is being rendered.
 * @param array $instance
 *   The current instance of the button field that is being rendered.
 * @param array $element
 *   The renderable array element for the button field.
 *
 * @return array
 *   The form as a renderable array.
 */
function _button_field_get_dummy_form($entity_type, $entity, $field, $instance, $element) {
  $form_state = array(
    'build_info' => array(
      'args' => array(
        &$entity,
      ),
    ),
    '#entity_type' => $entity_type,
    '#' . $entity_type => &$entity,
    '#field' => &$field,
    '#instance' => &$instance,
    '#element' => $element,
  );

  // Build the form and add it to the cache.
  $form = drupal_build_form('button_field_dummy_form', $form_state);
  form_set_cache($form['#build_id'], $form, $form_state);
  return $form;
}

Functions

Namesort descending Description
button_field_ajax_command_location Creates a Drupal Ajax buttonFieldLocation command.
button_field_callback_ajax Callback function for the FAPI ajax framework, used on edit forms.
button_field_dummy_form Form builder callback for the dummy form used to render button field's on a display that is not editable.
button_field_field_formatter_info Implements hook_field_formatter_info().
button_field_field_formatter_view Implements hook_field_formatter_view().
button_field_field_info Implements hook_field_info().
button_field_field_is_empty Implements hook_field_is_empty().
button_field_field_schema Implements hook_field_schema().
button_field_field_settings_form Implements hook_field_settings_form().
button_field_field_widget_form Implements hook_field_widget_form().
button_field_field_widget_info Implements hook_field_widget_info().
button_field_field_widget_settings_form Implements hook_field_widget_settings_form().
button_field_form_field_ui_field_edit_form_alter Implements hook_form_FORM_ID_alter().
button_field_views_api Implements button_field_views_api().
_button_field_ajax_response Builds the response for an ajax callback.
_button_field_build_element Builds the renderable array for a button field widget.
_button_field_build_id Builds the id for a button field instance.
_button_field_callback_get_entity Gets the entity and its type from the form or form state during the ajax callback.
_button_field_get_dummy_form Gets the dummy form to be used with button fields on a view form.