table_element.module in Table Element 7
Provides a table element for Drupal 7.
The table element for Drupal 8 was written by @sun. This module was derived from his patch {@link http://drupal.org/node/80855#comment-6792864}
@license GPL v2 http://www.fsf.org/licensing/licenses/gpl.html
File
table_element.moduleView source
<?php
/**
* @file
* Provides a table element for Drupal 7.
*
* The table element for Drupal 8 was written by @sun. This module was derived
* from his patch {@link http://drupal.org/node/80855#comment-6792864}
*
* @license GPL v2 http://www.fsf.org/licensing/licenses/gpl.html
*/
/**
* Implements hook_element_info().
*/
function table_element_element_info() {
$types = array();
$types['table'] = array(
'#header' => array(),
'#rows' => array(),
'#empty' => '',
'#input' => TRUE,
'#tree' => TRUE,
'#tableselect' => FALSE,
'#multiple' => TRUE,
'#js_select' => TRUE,
'#theme' => 'table',
'#process' => array(
'table_element_process_table',
),
'#element_validate' => array(
'table_element_validate_table',
),
'#pre_render' => array(
'table_element_pre_render_table',
),
'#value_callback' => 'table_element_table_value',
);
return $types;
}
/**
* Determines the value of a table form element.
*
* @param array $element
* The form element whose value is being populated.
* @param array|bool $input
* The incoming input to populate the form element. If this is FALSE,
* the element's default value should be returned.
*
* @return array
* The data that will appear in the $form_state['values'] collection
* for this element. Return nothing to use the default.
*/
function table_element_table_value(array $element, $input = FALSE) {
// If #multiple is FALSE, the regular default value of radio buttons is used.
if (!empty($element['#tableselect']) && !empty($element['#multiple'])) {
// Contrary to #type 'checkboxes', the default value of checkboxes in a
// table is built from the array keys (instead of array values) of the
// #default_value property.
if (FALSE === $input) {
$element += array(
'#default_value' => array(),
);
return drupal_map_assoc(array_keys(array_filter($element['#default_value'])));
}
elseif (is_array($input)) {
return drupal_map_assoc($input);
}
}
return array();
}
/**
* A #process callback for #type 'table' to add tableselect support.
*
* @param array $element
* An associative array containing the properties and children of the
* table element.
*
* @return array
* The processed element.
*
* @see form_process_tableselect()
* @see theme_tableselect()
*/
function table_element_process_table(array $element) {
if (!empty($element['#tableselect'])) {
if ($element['#multiple']) {
$value = is_array($element['#value']) ? $element['#value'] : array();
}
else {
$element['#js_select'] = FALSE;
}
// Add a "Select all" checkbox column to the header.
if ($element['#js_select']) {
$element['#attached']['library'][] = array(
'system',
'drupal.tableselect',
);
array_unshift($element['#header'], array(
'class' => array(
'select-all',
),
));
}
else {
array_unshift($element['#header'], '');
}
if (empty($element['#default_value'])) {
$element['#default_value'] = array();
}
// Create a checkbox or radio for each row in a way that the value of the
// tableselect element behaves as if it had been of #type checkboxes or
// radios.
foreach (element_children($element) as $key) {
// Do not overwrite manually created children.
if (!isset($element[$key]['select'])) {
// Determine option label; either an assumed 'title' column, or the
// first available column containing a #title or #markup.
$title = '';
if (!empty($element[$key]['title']['#title'])) {
$title = $element[$key]['title']['#title'];
}
else {
foreach (element_children($element[$key]) as $column) {
foreach (array(
'#title',
'#markup',
) as $property) {
if (isset($element[$key][$column][$property])) {
$title = $element[$key][$column][$property];
break;
}
}
}
}
if ('' !== $title) {
$title = t('Update !title', array(
'!title' => $title,
));
}
// Prepend the select column to existing columns.
$element[$key] = array(
'select' => array(),
) + $element[$key];
$element[$key]['select'] += array(
'#type' => $element['#multiple'] ? 'checkbox' : 'radio',
'#title' => $title,
'#title_display' => 'invisible',
// @todo If rows happen to use numeric indexes instead of string keys,
// this results in a first row with $key === 0, which is always FALSE.
'#return_value' => $key,
'#attributes' => $element['#attributes'],
);
$element_parents = array_merge($element['#parents'], array(
$key,
));
if ($element['#multiple']) {
$element[$key]['select']['#default_value'] = isset($value[$key]) ? $key : NULL;
$element[$key]['select']['#parents'] = $element_parents;
}
else {
$element[$key]['select']['#default_value'] = $element['#default_value'] == $key ? $key : NULL;
$element[$key]['select']['#parents'] = $element['#parents'];
$element[$key]['select']['#id'] = drupal_html_id('edit-' . implode('-', $element_parents));
}
}
}
}
return $element;
}
/**
* An #element_validate callback for #type 'table'.
*
* @param array $element
* An associative array containing the properties and children of the
* table element.
* @param array $form_state
* The current state of the form.
*/
function table_element_validate_table(array $element, &$form_state) {
// Skip this validation if the button to submit the form does not require
// selected table row data.
if (empty($form_state['triggering_element']['#tableselect'])) {
return;
}
if ($element['#multiple']) {
if (!is_array($element['#value']) || !count(array_filter($element['#value']))) {
form_error($element, t('No items selected.'));
}
}
elseif (empty($element['#value'])) {
form_error($element, t('No item selected.'));
}
}
/**
* A #pre_render callback to transform children of an element into #rows.
*
* Suitable for theme_table().
*
* This function converts sub-elements of an element of #type 'table' to be
* suitable for theme_table():
* - The first level of sub-elements are table rows. Only the #attributes
* property is taken into account.
* - The second level of sub-elements is converted into columns for the
* corresponding first-level table row.
*
* Simple example usage:
* @code
* $form['table'] = array(
* '#type' => 'table',
* '#header' => array(
* t('Title'),
* array('data' => t('Operations'), 'colspan' => '1'),
* ),
* // Optionally, to add tableDrag support:
* '#tabledrag' => array(
* array('order', 'sibling', 'thing-weight'),
* ),
* );
* foreach ($things as $row => $thing) {
* $form['table'][$row]['#weight'] = $thing['weight'];
*
* $form['table'][$row]['title'] = array(
* '#type' => 'textfield',
* '#default_value' => $thing['title'],
* );
*
* // Optionally, to add tableDrag support:
* $form['table'][$row]['#attributes']['class'][] = 'draggable';
* $form['table'][$row]['#cell']['colspan'] = '2';
* $form['table'][$row]['#cell']['class'][] = 'td-element-class';
* $form['table'][$row]['weight'] = array(
* '#type' => 'textfield',
* '#title' => t('Weight for @title', array('@title' => $thing['title'])),
* '#title_display' => 'invisible',
* '#size' => 4,
* '#default_value' => $thing['weight'],
* '#attributes' => array('class' => array('thing-weight')),
* );
*
* // The amount of link columns should be identical to the 'colspan'
* // attribute in #header above.
* $form['table'][$row]['edit'] = array(
* '#type' => 'link',
* '#title' => t('Edit'),
* '#href' => 'thing/' . $row . '/edit',
* );
* }
* @endcode
*
* @param array $element
* A structured array containing two sub-levels of elements. Properties used:
* - #tabledrag: The value is a list of arrays that are passed to
* drupal_add_tabledrag(). The HTML ID of the table is prepended to each set
* of arguments.
*
* @return array
* An array of row information.
*
* @see system_element_info()
* @see theme_table()
* @see drupal_process_attached()
* @see drupal_add_tabledrag()
*/
function table_element_pre_render_table(array $element) {
foreach (element_children($element) as $first) {
$row = array(
'data' => array(),
);
// Apply attributes of first-level elements as table row attributes.
if (isset($element[$first]['#attributes'])) {
$row += $element[$first]['#attributes'];
}
// Turn second-level elements into table row columns.
foreach (element_children($element[$first]) as $second) {
$cell =& $element[$first][$second];
$cell += array(
// If an access is not configured then will assume that is
// granted. As Drupal does.
'#access' => TRUE,
// If attributes for table cell is not set then initialize
// an empty value for them.
'#cell' => array(),
);
// Element with granted access and without "value" type could
// be rendered as table cell.
if (!empty($cell['#access']) && !(isset($cell['#type']) && 'value' === $cell['#type'])) {
// Assign the element by reference, so any potential changes to the
// original element are taken over.
$row['data'][] = array(
'data' => &$cell,
) + $cell['#cell'];
}
}
$element['#rows'][] = $row;
}
// Take over $element['#id'] as HTML ID attribute, if not already set.
element_set_attributes($element, array(
'id',
));
// If the custom #tabledrag is set and there is a HTML ID, inject the table's
// HTML ID as first callback argument and attach the behavior.
if (!empty($element['#tabledrag']) && isset($element['#attributes']['id'])) {
foreach ($element['#tabledrag'] as &$args) {
array_unshift($args, $element['#attributes']['id']);
}
$element['#attached']['drupal_add_tabledrag'] = $element['#tabledrag'];
}
return $element;
}
Functions
Name![]() |
Description |
---|---|
table_element_element_info | Implements hook_element_info(). |
table_element_pre_render_table | A #pre_render callback to transform children of an element into #rows. |
table_element_process_table | A #process callback for #type 'table' to add tableselect support. |
table_element_table_value | Determines the value of a table form element. |
table_element_validate_table | An #element_validate callback for #type 'table'. |