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($_POST["row__{$elkey}__{$rowkey}__{$cid}"]);
}
$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('strlen', $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) {
$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. Key-value pairs MUST be specified as "safe_key|Some readable option"') . 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], "" . $row_names[$key] . "");
}
}
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("" . $child['name'] . "");
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
FROM {webform_component} wc
WHERE wc.pid = %d AND wc.nid = %d
GROUP BY wc.cid
ORDER BY wc.weight"
);
$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();
foreach ($value['rows'] as $val) {
$all_data = array_values($val);
foreach ($all_data as $key => $data) {
$table[$key][] = strip_tags($data) . "\n";
}
}
foreach ($table as $key => $row) {
$table[$key] = implode("\n", $row);
}
return $table;
}
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;
}