You are here

function tablefield_field_widget_form in TableField 7.2

Same name and namespace in other branches
  1. 7.3 tablefield.module \tablefield_field_widget_form()
  2. 7 tablefield.module \tablefield_field_widget_form()

Implements hook_widget_form().

File

./tablefield.module, line 786
Provides a set of fields that can be used to store tabular data with a node.

Code

function tablefield_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $form['#after_build'][] = 'tablefield_after_build';
  $settings = isset($instance['display']['default']['settings']) ? $instance['display']['default']['settings'] : FALSE;
  $element['#type'] = 'tablefield';
  $form['#attributes']['enctype'] = 'multipart/form-data';

  /* Tablefield is sometimes embedded within another form by other modules, such
   * as Field Collection. Because of that, we cannot rely on field_name and
   * $delta to provide a unique ID for this element. Instead we use a
   * concatenation of the field parents along with the current field name,
   * language, delta and tablefield key.
   */
  $tablefield_parents = isset($element['#field_parents']) ? $element['#field_parents'] : array();
  array_push($tablefield_parents, $element['#field_name'], $element['#language'], $element['#delta'], 'tablefield');
  $id = drupal_clean_css_identifier(implode('-', $tablefield_parents));

  // IDs to use for various buttons/wrapper for this element. When processing
  // an AJAX request, these IDs are used to build the field stack so we know
  // where the value we're adjusting is in the FormAPI array.
  $ajax_wrapper_id = "{$id}-wrapper";
  $rebuild_id = "{$id}-rebuild";
  $import_id = "{$id}-import";
  $pasted_id = "{$id}-pasted";

  // Default table size.
  $default_size['count_cols'] = isset($instance['default_value'][0]['tablefield']['rebuild']['count_cols']) ? $instance['default_value'][0]['tablefield']['rebuild']['count_cols'] : 5;
  $default_size['count_rows'] = isset($instance['default_value'][0]['tablefield']['rebuild']['count_rows']) ? $instance['default_value'][0]['tablefield']['rebuild']['count_rows'] : 5;

  // Default table cell values.
  $default_value = NULL;

  // If there's a triggering element get the values from form state.
  if (isset($form_state['triggering_element'])) {
    if ($form_state['triggering_element']['#name'] == $rebuild_id) {

      // Rebuilding table rows/cols.
      $default_value = drupal_array_get_nested_value($form_state['tablefield_rebuild'], $tablefield_parents);
      drupal_set_message(t('Table structure rebuilt.'), 'status', FALSE);
    }
    elseif ($form_state['triggering_element']['#name'] == $import_id) {

      // Importing CSV data.
      tablefield_import_csv($form, $form_state, $langcode, $import_id, $tablefield_parents);
      $default_value = drupal_array_get_nested_value($form_state['input'], $tablefield_parents);
    }
    elseif ($form_state['triggering_element']['#name'] == $pasted_id) {

      // Importing pasted data.
      tablefield_import_pasted($form, $form_state, $langcode, $pasted_id, $tablefield_parents);
      $default_value = drupal_array_get_nested_value($form_state['input'], $tablefield_parents);
      if (empty($default_value['rebuild'])) {
        $default_value['rebuild'] = $default_size;
      }
    }
    else {

      // The triggering element is neither a rebuild nor an import
      // e.g. a file upload.
      $default_value = drupal_array_get_nested_value($form_state['input'], $tablefield_parents);
    }
  }

  // If no values by now, get tablefield item value stored in database, if any.
  if (!$default_value) {

    // This could be set e.g. when using paragraphs module.
    if (isset($items[$delta]['tablefield'])) {
      $default_value = $items[$delta]['tablefield'];
    }
    elseif (isset($items[$delta]['value'])) {
      $default_value = unserialize($items[$delta]['value']);
    }
    elseif ($delta === 0 && isset($instance['default_value'][0]['tablefield'])) {
      $default_value = $instance['default_value'][0]['tablefield'];
    }
  }
  if (empty($default_value['rebuild'])) {
    $default_value['rebuild'] = $default_size;
  }
  else {
    $default_size = $default_value['rebuild'];
  }
  $count_rows = $default_size['count_rows'];
  $count_cols = $default_size['count_cols'];

  // Now we can build the widget.
  if (!empty($instance['description'])) {
    $help_text = $instance['description'];
  }
  else {
    if ($settings) {
      $display_settings = l(t('default display settings'), 'admin/structure/types/manage/' . $element['#bundle'] . '/display', array(
        'attributes' => array(
          'title' => t('Manage display settings'),
        ),
      ));
      if ($settings['hide_header'] == TRUE) {
        $help_text = t('This table will not have a header according to the !display_settings.', array(
          '!display_settings' => $display_settings,
        ));
      }
      else {
        $help_text = t('The first row will appear as the table header. Leave the first row blank if you do not need a header.');
      }
    }
  }
  $element['tablefield'] = array(
    '#title' => $element['#title'],
    '#description' => filter_xss_admin($help_text),
    '#attributes' => array(
      'id' => $id,
      'class' => array(
        'form-tablefield',
      ),
    ),
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#collapsible' => FALSE,
    '#prefix' => '<div id="' . $ajax_wrapper_id . '">',
    '#suffix' => '</div>',
  );
  if ($settings) {
    if ($settings['hide_header']) {
      $element['tablefield']['#attributes']['class'][] = 'table-no-headers';
    }
  }

  // Give the fieldset the appropriate class if it is required.
  if ($element['#required']) {
    $element['tablefield']['#title'] .= ' <span class="form-required" title="';
    $element['tablefield']['#title'] .= t('This field is required');
    $element['tablefield']['#title'] .= '">*</span>';
  }
  $arg0 = arg(0);
  if ($arg0 == 'admin') {
    $element['tablefield']['#description'] = t('This form defines the table field defaults, but the number of rows/columns and content can be overridden.');
    if ($settings) {
      if (!$settings['hide_header']) {
        $element['tablefield']['#description'] .= ' ' . t('The first row will appear as the table header. Leave the first row blank if you do not need a header.');
      }
    }
  }

  // Render the form table.
  $element['tablefield']['tabledata']['a_break'] = array(
    '#markup' => '<table id="tablefield-editor">',
  );
  $default_value = isset($default_value['tabledata']) ? $default_value['tabledata'] : $default_value;

  // Loop over all the rows.
  for ($i = 0; $i < $count_rows; $i++) {
    $zebra = $i % 2 == 0 ? 'even' : 'odd';
    $element['tablefield']['tabledata']['b_break' . $i] = array(
      '#markup' => '<tr class="draggable tablefield-row-' . $i . ' ' . $zebra . '"><td class="tablefield-row-count">' . ($i + 1) . '</td>',
    );

    // Loop over all the columns.
    for ($ii = 0; $ii < $count_cols; $ii++) {
      $instance_default = isset($instance['default_value'][0]['tablefield']['tabledata']["row_{$i}"]["col_{$ii}"]) ? $instance['default_value'][0]['tablefield']['tabledata']["row_{$i}"]["col_{$ii}"] : array();
      if (!empty($instance_default) && !empty($field['settings']['lock_values']) && $arg0 != 'admin') {

        // The value still needs to be send on every load in order for the
        // table to be saved correctly.
        $element['tablefield']['tabledata']['row_' . $i]['col_' . $ii] = array(
          '#type' => 'value',
          '#value' => $instance_default,
        );

        // Display the default value, since it's not editable.
        $element['tablefield']['tabledata']['row_' . $i]['col_' . $ii . '_display'] = array(
          '#type' => 'item',
          '#title' => $instance_default,
          '#prefix' => '<td>',
          '#suffix' => '</td>',
        );
      }
      else {
        $cell_default = isset($default_value['row_' . $i]['col_' . $ii]) ? $default_value['row_' . $i]['col_' . $ii] : '';
        $element['tablefield']['tabledata']['row_' . $i]['col_' . $ii] = array(
          '#type' => 'textfield',
          '#maxlength' => 2048,
          '#size' => 0,
          '#attributes' => array(
            'id' => $id . '-cell-' . $i . '-' . $ii,
            'class' => array(
              'tablefield-row-' . $i,
              'tablefield-col-' . $ii,
            ),
            'style' => 'min-width: 100%',
          ),
          '#default_value' => $cell_default,
          '#prefix' => '<td>',
          '#suffix' => '</td>',
        );
      }
    }

    // Add an extra column for the weight.
    $row_weight_default = isset($default_value[$i]['weight']) ? $default_value[$i]['weight'] : $i + 1;
    $element['tablefield']['tabledata']['row_' . $i]['weight'] = array(
      '#type' => 'weight',
      '#title' => t('Weight'),
      '#default_value' => $row_weight_default,
      '#delta' => $count_rows,
      '#attributes' => array(
        'class' => array(
          'tablefield-weight',
        ),
      ),
      '#prefix' => '<td class="tabledrag-hide">',
      '#suffix' => '</td>',
    );
    $element['tablefield']['c_break' . $i] = array(
      '#markup' => '</tr>',
    );
  }
  $element['tablefield']['t_break' . $i] = array(
    '#markup' => '</table>',
  );

  // Provide caption field to describe the data contained in the table.
  $element['tablefield']['caption'] = array(
    '#type' => 'textfield',
    '#title' => t('Table description'),
    '#default_value' => '',
    '#description' => t('This brief caption will be associated with the table and will help Assitive Technology, like screen readers, better describe the content within.'),
  );
  if (isset($items[$delta]['value'])) {
    $raw = unserialize($items[$delta]['value']);
    if (isset($raw['caption'])) {
      $element['tablefield']['caption']['#default_value'] = check_plain($raw['caption']);
    }
  }

  // If the user doesn't have rebuild perms, we pass along the data as a value.
  // Otherwise we provide form elements to specify the size and ajax rebuild.
  if (isset($field['settings']['restrict_rebuild']) && $field['settings']['restrict_rebuild'] && !user_access('rebuild tablefield')) {
    $element['tablefield']['rebuild'] = array(
      '#type' => 'value',
      '#tree' => TRUE,
      'count_cols' => array(
        '#type' => 'value',
        '#value' => $count_cols,
      ),
      'count_rows' => array(
        '#type' => 'value',
        '#value' => $count_rows,
      ),
      'rebuild' => array(
        '#type' => 'value',
        '#value' => t('Rebuild Table'),
      ),
    );
  }
  else {
    $element['tablefield']['rebuild'] = array(
      '#type' => 'fieldset',
      '#tree' => TRUE,
      '#title' => t('Change number of rows/columns.'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $element['tablefield']['rebuild']['count_cols'] = array(
      '#title' => t('How many Columns'),
      '#type' => 'textfield',
      '#size' => 5,
      '#prefix' => '<div class="clearfix">',
      '#suffix' => '</div>',
      '#value' => $count_cols,
    );
    $element['tablefield']['rebuild']['count_rows'] = array(
      '#title' => t('How many Rows'),
      '#type' => 'textfield',
      '#size' => 5,
      '#prefix' => '<div class="clearfix">',
      '#suffix' => '</div>',
      '#value' => $count_rows,
    );
    $element['tablefield']['rebuild']['rebuild'] = array(
      '#type' => 'button',
      '#validate' => array(),
      '#limit_validation_errors' => array(),
      '#executes_submit_callback' => TRUE,
      '#submit' => array(
        'tablefield_rebuild_form',
      ),
      '#value' => t('Rebuild Table'),
      '#name' => $rebuild_id,
      '#attributes' => array(
        'class' => array(
          'tablefield-rebuild',
        ),
      ),
      '#ajax' => array(
        'callback' => 'tablefield_rebuild_form_ajax',
        'wrapper' => $ajax_wrapper_id,
        'effect' => 'fade',
      ),
    );
  }

  // Allow the user to import a csv file.
  $element['tablefield']['import'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Upload CSV file'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $element['tablefield']['import']['file'] = array(
    '#name' => 'files[' . $import_id . ']',
    '#title' => t('File upload'),
    '#type' => 'file',
  );
  $element['tablefield']['import']['import'] = array(
    '#type' => 'button',
    '#validate' => array(),
    '#limit_validation_errors' => array(),
    '#executes_submit_callback' => TRUE,
    '#submit' => array(
      'tablefield_rebuild_form',
    ),
    '#value' => t('Upload CSV'),
    '#name' => $import_id,
    '#attributes' => array(
      'class' => array(
        'tablefield-rebuild',
      ),
    ),
    '#ajax' => array(
      'callback' => 'tablefield_rebuild_form_ajax',
      'wrapper' => $ajax_wrapper_id,
      'effect' => 'fade',
    ),
  );

  // Allow user to paste data (e.g. from Excel).
  $element['tablefield']['paste'] = array(
    '#type' => 'fieldset',
    '#tree' => TRUE,
    '#title' => t('Copy & Paste'),
    '#attributes' => array(
      'class' => array(
        'tablefield-extra tablefield-paste',
      ),
    ),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $delimiters = array(
    'TAB' => t('TAB'),
    ',' => t('Comma ,'),
    ';' => t('Semicolon ;'),
    '|' => t('Pipe |'),
    '+' => t('Plus +'),
    ':' => t('Colon :'),
  );
  $element['tablefield']['paste']['paste_delimiter'] = array(
    '#type' => 'select',
    '#tree' => TRUE,
    '#title' => t('Column separator'),
    '#name' => 'delimiter[' . $pasted_id . ']',
    '#options' => $delimiters,
    '#description' => t('Data copied from Excel will use TAB.'),
  );
  $element['tablefield']['paste']['data'] = array(
    '#type' => 'textarea',
    '#tree' => TRUE,
    '#name' => 'data[' . $pasted_id . ']',
    '#title' => t('Paste table data here:'),
  );
  $element['tablefield']['paste']['paste_import'] = array(
    '#type' => 'button',
    '#validate' => array(),
    '#limit_validation_errors' => array(),
    '#executes_submit_callback' => TRUE,
    '#submit' => array(
      'tablefield_rebuild_form',
    ),
    '#value' => t('Import & Rebuild'),
    '#name' => $pasted_id,
    '#ajax' => array(
      'callback' => 'tablefield_rebuild_form_ajax',
      'wrapper' => $ajax_wrapper_id,
      'effect' => 'fade',
    ),
  );

  // Allow the user to select input filters.
  if (!empty($field['settings']['cell_processing'])) {
    $element['#base_type'] = $element['#type'];
    $element['#type'] = 'text_format';
    $element['#format'] = isset($items[$delta]['format']) ? $items[$delta]['format'] : NULL;
    if (module_exists('wysiwyg')) {
      $element['#wysiwyg'] = FALSE;
    }
  }
  return $element;
}