'',
'form_key' => NULL,
'email' => 1,
'mandatory' => 0,
'pid' => 0,
'weight' => 0,
'extra' => array(
'options' => '',
'questions' => '',
'optrand' => 0,
'qrand' => 0,
'description' => '',
),
);
}
/**
* Create a set of form items to be displayed on the form for editing this component.
* Use care naming the form items, as this correlates directly to the database schema.
* The component "Name" and "Description" fields are added to every component type and
* are not necessary to specify here (although they may be overridden if desired).
* @return
* An array of form items to be displayed on the edit component page
*/
function _webform_edit_grid($currfield) {
$edit_fields = array();
$edit_fields['extra']['options'] = array(
'#type' => 'textarea',
'#title' => t('Options'),
'#default_value' => $currfield['extra']['options'],
'#description' => t('Options to select across the top. One option per line. Key-value pairs may be entered seperated by pipes. i.e. safe_key|Some readable option') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => -3,
'#required' => TRUE,
);
$edit_fields['extra']['questions'] = array(
'#type' => 'textarea',
'#title' => t('Questions'),
'#default_value' => $currfield['extra']['questions'],
'#description' => t('Questions list down the left side. One question per line.') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => -2,
'#required' => TRUE,
);
$edit_fields['extra']['optrand'] = array(
'#type' => 'checkbox',
'#title' => t('Randomize Options'),
'#default_value' => $currfield['extra']['optrand'],
'#description' => t('Randomizes the order of options on the top when they are displayed in the form.'),
);
$edit_fields['extra']['qrand'] = array(
'#type' => 'checkbox',
'#title' => t('Randomize Questions'),
'#default_value' => $currfield['extra']['qrand'],
'#description' => t('Randomize the order of the questions on the side when they are displayed in the form.'),
);
return $edit_fields;
}
function _webform_edit_validate_grid($form_values) {
// Currently no validation for selects.
return TRUE;
}
function _webform_render_grid($component, $random = TRUE) {
$form_item = array(
'#title' => $component['name'],
'#required' => $component['mandatory'],
'#weight' => $component['weight'],
'#theme' => 'webform_grid',
'#description' => _webform_filter_descriptions($component['extra']['description']),
);
$questions = _webform_grid_options($component['extra']['questions']);
$options = _webform_grid_options($component['extra']['options']);
if ($component['extra']['optrand'] && $random) {
// This maneuver shuffles the array keys, then uses them as
// the basis for ordering the options.
$aux = array();
$keys = array_keys($options);
shuffle($keys);
foreach ($keys as $key) {
$aux[$key] = $options[$key];
unset($options[$key]);
}
$options = $aux;
}
if ($component['extra']['qrand'] && $random) {
$aux = array();
$keys = array_keys($questions);
shuffle($keys);
foreach ($keys as $key) {
$aux[$key] = $questions[$key];
unset($questions[$key]);
}
$questions = $aux;
}
foreach ($questions as $question) {
if ($question != '') {
// Remove quotes from keys to prevent HTML breakage.
$form_item[str_replace(array('"', "'"), '', $question)] = array(
'#title' => $question,
'#required' => $component['mandatory'],
'#prefix' => '
',
'#suffix' => '
',
'#options' => $options,
'#type' => 'radios',
);
}
}
return $form_item;
}
/**
* Display the result of a grid submission. The output of this function will be
* displayed under the "results" tab then "submissions"
* @param $data
* An array of information containing the submission result, directly
* correlating to the webform_submitted_data database schema
* @param $component
* An array of information describing the component, directly correlating to
* the webform_component database schema
* @param $enabled
* If enabled, the value may be changed. Otherwise it will set to readonly.
* @return
* Textual output formatted for human reading.
*/
function _webform_submission_display_grid($data, $component, $enabled = FALSE) {
$form_item = _webform_render_grid($component, FALSE);
$cid = 0;
foreach (element_children($form_item) as $key) {
$form_item[$key]['#default_value'] = $data['value'][$cid++];
$form_item[$key]['#disabled'] = !$enabled;
}
return $form_item;
}
/**
* Translates the submitted 'safe' form values back into their un-edited
* original form.
*
* @param $data
* The POST data associated with the component
* @param $component
* An array of information describing the component, directly correlating to
* the webform_component database schema
* @return
* Nothing
*/
function _webform_submit_grid(&$data, $component) {
$options = drupal_map_assoc(array_flip(_webform_grid_options($component['extra']['options'])));
// Questions are a bit more tricky, since quotes were removed from them in
// _webform_render_grid(). Build a list of no_quotes => with_qoutes questions.
$questions = array();
foreach (_webform_grid_options($component['extra']['questions']) as $key => $question) {
$safe_question = str_replace(array('"', "'"), '', $question);
$questions[$safe_question] = $question;
}
if (is_array($data)) {
foreach ($data as $key => $value) {
if ($value !== '') {
$data[$key] = $options[$value];
}
}
}
elseif ($data !== '') {
$data = $options[$data];
}
// Put the form in the original option order before saving.
// Return the final data with the quotes back in place.
$ordered_data = array();
foreach ($questions as $safe_question => $question) {
if (isset($data[$safe_question])) {
$ordered_data[$question] = $data[$safe_question];
}
}
$data = $ordered_data;
}
/**
* Format the output of emailed data for this component.
*
* @param $data
* A string or array of the submitted data.
* @param $component
* An array of information describing the component, directly correlating to
* the webform_component database schema.
* @return
* Textual output to be included in the email.
*/
function theme_webform_mail_grid($data, $component) {
$questions = _webform_grid_options($component['extra']['questions']);
$output = $component['name'] .":\n";
foreach ($questions as $key => $question) {
$output .= ' - '. $question .':'. ($data[$question] == '' ? '' : ' '. $data[$question]) ."\n";
}
return $output;
}
/**
* Module specific instance of hook_help
*/
function _webform_help_grid($section) {
switch ($section) {
case 'admin/settings/webform#grid_description':
return t('Allows creation of grid questions, denoted by radio buttons.');
}
}
/**
* Calculate and returns statistics about results for this component from all
* submission to this webform. The output of this function will be displayed
* under the "results" tab then "analysis".
*
* @param $component
* An array of information describing the component, directly correlating to
* the webform_component database schema.
* @param $sids
* An optional array of submission IDs (sid). If supplied, the analysis will be limited
* to these sids.
* @return
* An array of data rows, each containing a statistic for this component's
* submissions.
*/
function _webform_analysis_rows_grid($component, $sids = array()) {
// Generate the list of options and questions.
$options = _webform_grid_options($component['extra']['options']);
$questions = array_values(_webform_grid_options($component['extra']['questions']));
// Generate a lookup table of results.
$placeholders = count($sids) ? array_fill(0, count($sids), "'%s'") : array();
$sidfilter = count($sids) ? " AND sid in (".implode(",", $placeholders).")" : "";
$query = 'SELECT no, data, count(data) as datacount '.
' FROM {webform_submitted_data} '.
' WHERE nid = %d '.
' AND cid = %d '.
" AND data != '' ". $sidfilter .
' GROUP BY no, data';
$result = db_query($query, array_merge(array($component['nid'], $component['cid']), $sids));
$counts = array();
while ($data = db_fetch_object($result)) {
$counts[$data->no][$data->data] = $data->datacount;
}
// Create an entire table to be put into the returned row.
$rows = array();
$header = array('');
// Add options as a header row.
foreach ($options as $option) {
$header[] = $option;
}
// Add questions as each row.
foreach ($questions as $qkey => $question) {
$row = array($question);
foreach ($options as $okey => $option) {
$row[] = !empty($counts[$qkey][$okey]) ? $counts[$qkey][$okey] : 0;
}
$rows[] = $row;
}
$output = theme('table', $header, $rows, array('class' => 'webform-grid'));
return array(array(array('data' => $output, 'colspan' => 2)));
}
/**
* function _webform_table_data_select
* Return the result of this component's submission for display in a table. The output of this function will be displayed under the "results" tab then "table"
* @param $data An array of information containing the submission result, directly correlating to the webform_submitted_data database schema
* @returns Textual output formatted for human reading.
*/
function _webform_table_data_grid($data, $component) {
$questions = array_values(_webform_grid_options($component['extra']['questions']));
$output = '';
// Set the value as a single string.
if (is_array($data['value'])) {
foreach ($data['value'] as $item => $value) {
if ($value !== '') {
$output .= $questions[$item] .': '. check_plain($value) .'
';
}
}
}
else {
$output = check_plain(!isset($data['value']['0']) ? '' : $data['value']['0']);
}
return $output;
}
/**
* Return the header information for this component to be displayed in a comma
* seperated value file. The output of this function will be displayed under
* the "results" tab then "download".
*
* @param $component
* An array of information describing the component, directly correlating to
* the webform_component database schema.
* @return
* An array of data to be displayed in the first three rows of a CSV file, not
* including either prefixed or trailing commas.
*/
function _webform_csv_headers_grid($component) {
$header = array();
$header[0] = array('');
$header[1] = array($component['name']);
$items = _webform_grid_options($component['extra']['questions']);
$count = 0;
foreach ($items as $key => $item) {
// Empty column per sub-field in main header.
if ($count != 0) {
$header[0][] = '';
$header[1][] = '';
}
// The value for this option.
$header[2][] = $item;
$count++;
}
return $header;
}
/**
* Return the result of a textfield submission. The output of this function will
* be displayed under the "results" tab then "submissions".
*
* @param $data
* An array of information containing the submission result, directly
* correlating to the webform_submitted_data database schema.
* @return
* Textual output formatted for CSV, not including either prefixed or trailing
* commas.
*/
function _webform_csv_data_grid($data, $component) {
$questions = array_keys(_webform_grid_options($component['extra']['questions']));
$return = array();
foreach ($questions as $key => $question) {
$return[] = isset($data['value'][$key]) ? $data['value'][$key] : '';
}
return $return;
}
function theme_webform_grid(&$grid_element) {
$rows = array();
$header = array('');
$first = TRUE;
foreach (element_children($grid_element) as $key) {
$question_element = $grid_element[$key];
// Set the header for the table.
if ($first) {
foreach ($question_element['#options'] as $option) {
$header[] = $option;
}
$first = FALSE;
}
// Create a row with the question title.
$row = array(check_plain($question_element['#title']));
// Render each radio button in the row.
$radios = expand_radios($question_element);
foreach (element_children($radios) as $key) {
unset($radios[$key]['#title']);
$row[] = drupal_render($radios[$key]);
}
$rows[] = $row;
}
return theme('form_element', $grid_element, theme('table', $header, $rows, array('class' => 'webform-grid')));
}
/**
* Utility function to split user-entered values from new-line separated
* text into an array of options.
*/
function _webform_grid_options($text) {
$options = array();
$rows = array_filter(explode("\n", _webform_filter_values(trim($text))));
foreach ($rows as $option) {
$option = trim($option);
if (preg_match('/^([^|]+)\|(.*)$/', $option, $matches)) {
$options[$matches[1]] = $matches[2];
}
else {
$options[$option] = $option;
}
}
return $options;
}