webform_table_element.module in Webform Table Element 6
Same filename and directory in other branches
Table element for webform
File
webform_table_element.moduleView source
<?php
/**
* @file
* Table element for webform
*/
// Table element depends on functions provided by select.
webform_component_include('select');
/**
* Implements hook_webform_component_info
*/
function webform_table_element_webform_component_info() {
$components = array();
$components['table_element'] = array(
'label' => t('Table element'),
'description' => t('Table element for webform'),
'features' => array(
'csv' => TRUE,
'required' => FALSE,
'conditional' => FALSE,
'group' => TRUE,
),
);
return $components;
}
/**
* Implementation of _webform_defaults_component().
*/
function _webform_defaults_table_element() {
return array(
'name' => '',
'form_key' => NULL,
'pid' => 0,
'weight' => 0,
'extra' => array(
'title_display' => 0,
'description' => '',
'switch_layout' => 0,
),
);
}
/**
* Implementation of _webform_render_component().
*/
function _webform_render_table_element($component, $value = NULL, $filter = TRUE) {
$class = 'webform-component-' . str_replace('_', '-', $component['type']);
$element = array(
'#type' => $component['type'],
'#title' => $filter ? _webform_filter_xss($component['name']) : $component['name'],
'#title_display' => $component['extra']['title_display'] ? $component['extra']['title_display'] : NULL,
'#weight' => $component['weight'],
'#description' => $filter ? _webform_filter_descriptions($component['extra']['description']) : $component['extra']['description'],
'#attributes' => array(
'class' => $class,
),
'#pre_render' => array(
'webform_element_title_display',
),
'#webform_component' => $component,
'#theme_wrappers' => array(
'webform_element_wrapper',
),
'#pre_render' => array(
'webform_element_title_display',
),
'#post_render' => array(
'webform_element_wrapper',
),
'#translatable' => array(
'title',
'description',
),
'#rows' => _webform_select_options_from_text($component['extra']['rows'], TRUE),
'#switch_layout' => $component['extra']['switch_layout'],
'#process' => array(
'_table_element_expand',
),
'#children_values' => is_array($value) ? $value['rows'] : NULL,
);
$element['#element_validate'][] = '_table_element_validate';
return $element;
}
function _table_element_expand($element) {
$children = element_children($element);
if (!$element['#switch_layout']) {
_table_element_expand_rows($element, $children);
}
else {
_table_element_expand_columns($element, $children);
}
foreach ($children as $child) {
unset($element[$child]);
}
return $element;
}
function _table_element_expand_rows(&$element, $children) {
$rows = $element['#rows'];
$elkey = $element['#webform_component']['form_key'];
foreach ($rows as $rowkey => $val) {
//empty(0) returns true...
if (!empty($rowkey) || $rowkey === 0) {
foreach ($children as $child) {
$i = 0;
//form_builder renders elements without cids, so give a temp cid...
if (!isset($element[$child]['#webform_component']['cid'])) {
$cid = $i++ . 'a';
}
else {
$cid = $element[$child]['#webform_component']['cid'];
}
if (!is_null($element['#children_values'])) {
if ($element[$child]['#type'] == 'date') {
$element['#children_values'][$rowkey][$child] = webform_date_array($element['#children_values'][$rowkey][$child]);
$element[$child]['#value'] = $element['#children_values'][$rowkey][$child];
$element[$child]['#default_value'] = $element['#children_values'][$rowkey][$child];
$element[$child] = webform_expand_date($element[$child]);
}
$element[$child]['#value'] = isset($element['#children_values'][$rowkey][$child]) ? $element['#children_values'][$rowkey][$child] : '';
$element[$child]['#default_value'] = isset($element['#children_values'][$rowkey][$child]) ? $element['#children_values'][$rowkey][$child] : '';
}
$element["row__{$elkey}__{$rowkey}"]["row__{$elkey}__{$rowkey}__{$cid}"] = $element[$child];
$element["row__{$elkey}__{$rowkey}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#title'] = "";
$element["row__{$elkey}__{$rowkey}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#error_title'] = $element[$child]['#title'];
$element["row__{$elkey}__{$rowkey}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#name'] = "row__{$elkey}__{$rowkey}__{$cid}";
if (isset($_POST["row__{$elkey}__{$rowkey}__{$cid}"])) {
$element["row__{$elkey}__{$rowkey}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#value'] = check_plain(_webform_table_element_checkboxes_to_string($_POST["row__{$elkey}__{$rowkey}__{$cid}"], array()));
}
$element['#row_titles']["row__{$elkey}__{$rowkey}__{$cid}"] = $element[$child]['#title'];
$element['#column_titles']["row__{$elkey}__{$rowkey}__{$cid}"] = 'row-title ' . _webform_table_element_clean_css_identifier(drupal_strtolower($child));
}
$element["row__{$elkey}__{$rowkey}"]['#row_title'] = $val;
$element['#name'] = "row__{$elkey}__{$rowkey}";
}
}
}
function _table_element_expand_columns(&$element, $children) {
$rows = $element['#rows'];
$elkey = $element['#webform_component']['form_key'];
foreach ($children as $child) {
//empty(0) returns true...
foreach ($rows as $rowkey => $val) {
if (!empty($rowkey) || $rowkey === 0) {
$i = 0;
//form_builder renders elements without cids, so give a temp cid...
if (!isset($element[$child]['#webform_component']['cid'])) {
$cid = $i++ . 'a';
}
else {
$cid = $element[$child]['#webform_component']['cid'];
}
if (!is_null($element['#children_values'])) {
if ($element[$child]['#type'] == 'date') {
$element['#children_values'][$child][$rowkey] = webform_date_array($element['#children_values'][$child][$rowkey]);
$element[$child]['#value'] = $element['#children_values'][$child][$rowkey];
$element[$child]['#default_value'] = $element['#children_values'][$child][$rowkey];
$element[$child] = webform_expand_date($element[$child]);
}
$element[$child]['#value'] = isset($element['#children_values'][$child][$rowkey]) ? $element['#children_values'][$child][$rowkey] : '';
$element[$child]['#default_value'] = isset($element['#children_values'][$child][$rowkey]) ? $element['#children_values'][$child][$rowkey] : '';
}
$element["row__{$elkey}__{$cid}"]["row__{$elkey}__{$rowkey}__{$cid}"] = $element[$child];
$element["row__{$elkey}__{$cid}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#weight'] = $element[$child]['#weight']++;
$element["row__{$elkey}__{$cid}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#title'] = "";
$element["row__{$elkey}__{$cid}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#error_title'] = $element[$child]['#title'];
$element["row__{$elkey}__{$cid}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#name'] = "row__{$elkey}__{$rowkey}__{$cid}";
if (isset($_POST["row__{$elkey}__{$rowkey}__{$cid}"])) {
$element["row__{$elkey}__{$cid}"]["row__{$elkey}__{$rowkey}__{$cid}"]['#value'] = check_plain($_POST["row__{$elkey}__{$rowkey}__{$cid}"]);
}
$element['#row_titles']["row__{$elkey}__{$rowkey}__{$cid}"] = $val;
$element['#column_titles']["row__{$elkey}__{$rowkey}__{$cid}"] = 'row-title ' . _webform_table_element_clean_css_identifier(drupal_strtolower($val));
$element["row__{$elkey}__{$cid}"]['#row_title'] = $element[$child]['#title'];
$element['#name'] = "row__{$elkey}__{$cid}";
}
}
}
}
function _table_element_validate($form_element, &$form_state) {
$table_element_cids = array(
$form_element['#webform_component']['cid'] => $form_element['#webform_component']['form_key'],
);
_webform_table_element_restructure_post($_POST, $table_element_cids);
foreach (element_children($form_element) as $child) {
if (isset($form_element[$child]['#required_children']) && !empty($form_element[$child]['#required_children'])) {
foreach ($form_element[$child]['#required_children'] as $required_child) {
if (!isset($_POST[$required_child]) || empty($_POST[$required_child])) {
if (!$form_element['#switch_layout']) {
form_error($form_element[$child][$required_child], t('!name field is required in row !rowname.', array(
'!name' => $form_element[$child][$required_child]['#error_title'],
'!rowname' => $form_element[$child]['#row_title'],
)));
}
else {
form_error($form_element[$child][$required_child], t('!name field is required in column !rowname.', array(
'!name' => $form_element[$child][$required_child]['#error_title'],
'!rowname' => $form_element['#row_titles'][$required_child],
)));
}
}
}
}
}
}
/**
* Implements hook_elements
*/
function webform_table_element_elements() {
return array(
'table_element' => array(
'#input' => 'TRUE',
),
'table_element_row' => array(
'#input' => 'FALSE',
),
);
}
/**
* Implements _webform_theme_component
*/
function _webform_theme_table_element() {
return array(
'table_element' => array(
'arguments' => array(
'element' => NULL,
),
),
'table_element_row' => array(
'arguments' => array(
'element' => NULL,
),
),
'table_element_display' => array(
'arguments' => array(
'element' => NULL,
),
),
);
}
/**
* Theme callback
*/
function theme_table_element($element) {
$header = array();
$header_complete = false;
foreach (element_children($element) as $child) {
$child_element = $element[$child];
$row = array(
$child_element['#row_title'],
);
foreach (element_children($child_element) as $grandchild) {
if (!$header_complete && isset($element['#row_titles'])) {
$header[] = array(
'data' => $element['#row_titles'][$grandchild],
'class' => $element['#column_titles'][$grandchild],
);
}
unset($child_element[$grandchild]['#printed']);
$row[] = array(
'data' => drupal_render($child_element[$grandchild]),
);
}
$header_complete = true;
$rows[] = $row;
}
array_unshift($header, array(
'class' => 'row-title',
'data' => ' ',
));
$element['#attributes']['id'] = $element['#id'];
return theme('form_element', $element, theme('table', $header, $rows, $element['#attributes']));
}
/**
* Theme callback
*/
function theme_table_element_display($element) {
if (isset($element['#webform_component']['children'])) {
foreach ($element['#webform_component']['children'] as $child) {
unset($element[$child['form_key']]);
}
}
}
/**
* Implementation of _webform_display_component().
*/
function _webform_display_table_element($component, $value, $format = 'html') {
if (isset($component['children'])) {
foreach ($component['children'] as $child) {
if ($child['type'] == 'date') {
foreach ($value['rows'] as $key => $val) {
if (empty($val[$child['form_key']])) {
$value['rows'][$key][$child['form_key']] = "";
}
else {
$date_arr = webform_date_array($val[$child['form_key']]);
$timestamp = webform_strtotime($date_arr['month'] . '/' . $date_arr['day'] . '/' . $date_arr['year']);
$date_format = webform_date_format('medium');
$value['rows'][$key][$child['form_key']] = format_date($timestamp, 'custom', $date_format, 0);
}
}
}
}
}
if (empty($value['rows'])) {
$value['headers'] = array();
}
if ($format == 'html') {
$element = array(
'#title' => $component['name'],
'#weight' => $component['weight'],
'#format' => $format,
'#theme' => 'table_element_display',
'#theme_wrappers' => $format == 'html' ? array(
'webform_element',
'webform_element_wrapper',
) : array(
'webform_element_text',
),
'#pre_render' => array(
'webform_element_title_display',
),
'#post_render' => array(
'webform_element_wrapper',
),
'#translatable' => array(
'title',
'description',
),
'#sorted' => TRUE,
'#value' => theme_table($value['header'], $value['rows']),
'#webform_component' => $component,
);
}
else {
if (empty($value['header'])) {
$length = 0;
}
else {
$length = max(array_map('strlen', $value['header']));
}
foreach ($value['rows'] as $row) {
$length = max($length, max(array_map('_webform_table_element_strlen_array', $row)));
}
$length += 3;
$output = "";
if ($component['extra']['title_display'] == 'before') {
$output .= $component['name'] . ":\n";
}
if ($component['extra']['title_display'] == 'inline') {
$output .= $component['name'] . ': ';
$namelength = strlen($component['name']) + 4;
}
foreach ($value['header'] as $header) {
$output .= sprintf("%-{$length}s", strip_tags($header));
}
$output .= "\n";
foreach ($value['rows'] as $row) {
if ($component['extra']['title_display'] == 'inline') {
$output .= sprintf("%-{$namelength}s", '');
}
foreach ($row as $cell) {
if (is_array($cell)) {
$cell = _webform_table_element_checkboxes_to_string($cell, array());
}
$output .= sprintf("%-{$length}s", strip_tags($cell));
}
$output .= "\n";
}
$element = array(
'#type' => 'markup',
'#value' => $output,
'#weight' => $component['weight'],
);
}
return $element;
}
/**
* Implementation of _webform_edit_component().
*/
function _webform_edit_table_element($component) {
$form['extra']['rows'] = array(
'#type' => 'textarea',
'#title' => t('Rows'),
'#default_value' => $component['extra']['rows'],
'#description' => t('One row or column per line. <strong>Key-value pairs MUST be specified as "safe_key|Some readable option"</strong>') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => -2,
'#required' => TRUE,
'#wysiwyg' => FALSE,
);
$form['extra']['switch_layout'] = array(
'#type' => 'checkbox',
'#title' => t('Switch Rows & Columns'),
'#description' => t('If checked, rows and columns will be switched.'),
'#default_value' => $component['extra']['switch_layout'],
'#weight' => -3,
);
drupal_add_js(drupal_get_path('module', 'webform_table_element') . '/webform_table_element.js', 'module', 'footer');
return $form;
}
function webform_table_element_webform_submission_presave($node, &$submission) {
$values = array();
$comp_array = array();
// remove invalid data
foreach ($submission->data as $key => $data) {
if ($key == '') {
unset($submission->data[$key]);
}
}
// grab all table_elements
$table_element_cids = array();
foreach ($node->webform['components'] as $component) {
if ($component['type'] == 'table_element') {
$rows = _webform_select_options_from_text($component['extra']['rows']);
$comp_array[$component['form_key']]['rows'] = $rows;
$comp_array[$component['form_key']]['cid'] = $component['cid'];
$table_element_cids[$component['cid']] = $component['form_key'];
// clear submitted data
unset($submission->data[$component['cid']]);
}
}
//restructure $_POST array to support date fields
if (isset($_POST['submitted'])) {
_webform_table_element_restructure_post($_POST, $table_element_cids);
foreach ($table_element_cids as $tcid => $form_key) {
if (isset($_POST['submitted'][$form_key])) {
foreach ($_POST['submitted'][$form_key] as $row) {
$_POST += $row;
}
}
}
}
// loop through posted values
$values += _webform_table_element_get_post_values($_POST, $comp_array);
// serialize data
foreach ($values as $cid => &$val) {
if ($node->webform['components'][$cid]['type'] == 'date') {
foreach ($val['value'][0] as $rowid => $datefield) {
$dateval = "";
if (!empty($datefield['month']) && !empty($datefield['day']) && !empty($datefield['year'])) {
$dateval = mktime(0, 0, 0, $datefield['month'], $datefield['day'], $datefield['year']);
$dateval = date('Y-m-d', $dateval);
}
$val['value'][0][$rowid] = $dateval;
}
}
$val['value'][0] = serialize($val['value'][0]);
}
// merge
$submission->data = $submission->data + $values;
}
function _webform_table_element_restructure_post(&$post_array, $table_element_cids) {
foreach ($table_element_cids as $tcid => $form_key) {
_webform_table_element_restructure_post_recursive($post_array['submitted'], $form_key);
}
}
function _webform_table_element_restructure_post_recursive(&$post_array, $form_key) {
if (isset($post_array[$form_key]) && is_array($post_array[$form_key])) {
foreach ($post_array[$form_key] as $row) {
$_POST += $row;
}
}
else {
foreach (element_children($post_array) as $child) {
if (is_array($post_array[$child])) {
_webform_table_element_restructure_post_recursive($post_array[$child], $form_key);
}
}
}
}
function _webform_table_element_get_post_values($post_array, $comp_array) {
$values = array();
foreach ($post_array as $name => $val) {
$name_array = explode('__', $name);
if (is_array($name_array)) {
if ($name_array[0] == 'row' && array_key_exists($name_array[1], $comp_array)) {
// check if value exists
if (array_key_exists($name_array[2], $comp_array[$name_array[1]]['rows'])) {
$values[$name_array[3]]['value'][0][$name_array[2]] = $val;
}
}
}
}
return $values;
}
function webform_table_element_webform_submission_load(&$submissions) {
foreach ($submissions as &$submission) {
$node = node_load($submission->nid);
foreach ($node->webform['components'] as $component) {
if ($component['type'] == 'table_element') {
$table_children = array();
foreach ($node->webform['components'] as $comp) {
if ($comp['pid'] == $component['cid']) {
$table_children[] = $comp;
}
}
_webform_table_element_alter_submission($submission, $table_children, $component);
}
}
}
}
function _webform_table_element_alter_submission(&$submission, $table_children, $parent) {
webform_component_include('select');
if (!$parent['extra']['switch_layout']) {
$row_names = _webform_select_options_from_text($parent['extra']['rows'], TRUE);
$headers = array(
"",
);
$rows = array();
foreach ($table_children as $child) {
if (isset($submission->data[$child['cid']]) && is_array($submission->data[$child['cid']]['value'])) {
foreach ($submission->data[$child['cid']]['value'] as $val) {
$val = unserialize($val);
$headers[] = $child['name'];
foreach ($val as $rowkey => $rowval) {
$rows[$rowkey][$child['form_key']] = $rowval;
}
unset($submission->data[$child['cid']]);
}
}
}
foreach ($rows as $key => $row) {
array_unshift($rows[$key], "<strong>" . $row_names[$key] . "</strong>");
}
}
else {
$col_names = _webform_select_options_from_text($parent['extra']['rows'], TRUE);
$headers = array(
"",
);
$rows = array();
foreach ($table_children as $child) {
if (isset($submission->data[$child['cid']]) && is_array($submission->data[$child['cid']]['value'])) {
$rows[$child['form_key']] = array(
"<strong>" . $child['name'] . "</strong>",
);
foreach ($submission->data[$child['cid']]['value'] as $val) {
$val = unserialize($val);
foreach ($val as $rowkey => $rowval) {
$headers[$rowkey] = $col_names[$rowkey];
$rows[$child['form_key']][$rowkey] = $rowval;
}
unset($submission->data[$child['cid']]);
}
}
}
}
$submission->data[$parent['cid']]['value'] = array(
'header' => $headers,
'rows' => $rows,
);
}
function webform_table_element_webform_submission_render_alter(&$renderable) {
//this is necessary, otherwise there will be labels of other elements below the table element
_webform_table_element_render_alter_recurse($renderable);
}
function _webform_table_element_render_alter_recurse(&$renderable) {
foreach (element_children($renderable) as $child) {
if ($renderable[$child]['#webform_component']['type'] == 'table_element') {
foreach (element_children($renderable[$child]) as $table_child) {
unset($renderable[$child][$table_child]['#theme_wrappers']);
}
}
else {
_webform_table_element_render_alter_recurse($renderable[$child]);
}
}
}
function webform_table_element_form_alter($form, $form_state, $form_id) {
if (strpos($form_id, 'webform_client_form') !== FALSE) {
foreach ($form['#node']->webform['components'] as $component) {
if ($component['type'] == 'table_element') {
$form['#after_build'][] = '_webform_table_element_form_after_build';
$form['#submit'][] = '_webform_table_element_form_submit_after';
break;
}
}
}
}
function _webform_table_element_form_submit_after($form, &$form_state) {
if ((!isset($form_state['redirect']) || empty($form_state['redirect'])) && $form_state['webform_completed']) {
drupal_goto($_GET['q']);
}
}
function _webform_table_element_form_after_build(&$form, &$form_state) {
_webform_table_element_after_build_recurse($form, $form_state);
return $form;
}
function _webform_table_element_after_build_recurse(&$element, &$form_state) {
foreach (element_children($element) as $child) {
if (isset($element[$child]['#row_title'])) {
foreach (element_children($element[$child]) as $rowchild) {
if ($element[$child][$rowchild]['#required']) {
$element[$child]['#required_children'][] = $rowchild;
$element[$child][$rowchild]['#required'] = FALSE;
}
}
}
_webform_table_element_after_build_recurse($element[$child], $form_state);
}
}
/**
* Implements _webform_table_component().
*/
function _webform_table_table_element($component, $value) {
return theme('table', $value['header'], $value['rows']);
}
/**
* Implements _webform_csv_headers_component().
*/
function _webform_csv_headers_table_element($component, $export_options) {
$header = array();
$header[0] = array(
'',
);
$header[1] = array(
$component['name'],
);
$header[2] = array(
t('Row name'),
);
if (!$component['extra']['switch_layout']) {
$query = db_query("SELECT wc.cid, wc.name, wc.weight\n FROM {webform_component} wc\n WHERE wc.pid = %d AND wc.nid = %d\n GROUP BY wc.cid\n ORDER BY wc.weight", array(
$component['cid'],
$component['nid'],
));
$result = array();
while ($res = db_fetch_array($query)) {
$header[2][] = $res['name'];
}
}
else {
webform_component_include('select');
$header[2] += _webform_select_options_from_text($component['extra']['rows'], TRUE);
}
return $header;
}
/**
* Implements _webform_csv_data_component().
*/
function _webform_csv_data_table_element($component, $export_options, $value) {
$table = array();
$node = node_load($component['nid']);
foreach ($value['rows'] as $key => $val) {
$all_data = array_values($val);
$all_keys = array_keys($val);
foreach ($all_data as $key => $data) {
$cid = webform_get_cid($node, $all_keys[$key], $component['cid']);
if ($node->webform['components'][$cid]['type'] == 'select') {
if (!$node->webform['components'][$cid]['extra']['multiple']) {
$data = _webform_csv_data_select($node->webform['components'][$cid], $export_options, array(
$data,
));
}
else {
$temp_component = $node->webform['components'][$cid];
$temp_component['extra']['multiple'] = FALSE;
foreach ($data as &$dat) {
$dat = _webform_csv_data_select($temp_component, $export_options, array(
$dat,
));
}
}
}
$table[$key][] = is_array($data) ? strip_tags(implode(',', $data)) . ";" : strip_tags($data) . ";";
}
}
foreach ($table as $key => $row) {
$table[$key] = implode("", $row);
}
return $table;
}
/**
* Custom strlen implementation to handle checkboxes.
* Checkboxes are stored as an array, not as a string.
*/
function _webform_table_element_strlen_array($data) {
if (is_array($data)) {
$data = key($data);
}
return strlen($data);
}
/**
* Checkbox to string
*/
function _webform_table_element_checkboxes_to_string($checkboxes, $items) {
$data = array();
if (is_array($checkboxes)) {
if (empty($items)) {
$data = array_keys($checkboxes);
}
else {
foreach ($checkboxes as $k) {
$data[] = $items[$k];
}
}
}
else {
$data[] = $checkboxes;
}
return implode(', ', $data);
}
function _webform_table_element_clean_css_identifier($identifier, $filter = array(
' ' => '-',
'_' => '-',
'/' => '-',
'[' => '-',
']' => '',
)) {
// By default, we filter using Drupal's coding standards.
$identifier = strtr($identifier, $filter);
// Valid characters in a CSS identifier are:
// - the hyphen (U+002D)
// - a-z (U+0030 - U+0039)
// - A-Z (U+0041 - U+005A)
// - the underscore (U+005F)
// - 0-9 (U+0061 - U+007A)
// - ISO 10646 characters U+00A1 and higher
// We strip out any character not in the above list.
$identifier = preg_replace('/[^\\x{002D}\\x{0030}-\\x{0039}\\x{0041}-\\x{005A}\\x{005F}\\x{0061}-\\x{007A}\\x{00A1}-\\x{FFFF}]/u', '', $identifier);
return $identifier;
}