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; }