'',
'form_key' => NULL,
'email' => 1,
'mandatory' => 0,
'pid' => 0,
'weight' => 0,
'value' => '',
'extra' => array(
'items' => '',
'email' => 0,
'multiple' => NULL,
'aslist' => NULL,
'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_select($currfield) {
$edit_fields = array();
$edit_fields['extra']['items'] = array(
'#type' => 'textarea',
'#title' => t('Options'),
'#default_value' => $currfield['extra']['items'],
'#description' => t('A list of selectable options. One option per line. Key-value pairs may be entered seperated by pipes, such as "safe_key|Some readable option". Option groups for lists and menus may be specified with <Group Name>. <> can be used to insert items at the root of the menu after specifying a group.') . theme('webform_token_help'),
'#cols' => 60,
'#rows' => 5,
'#weight' => -2,
'#required' => TRUE,
'#validate' => array('_webform_edit_validate_select' => array()),
);
$edit_fields['value'] = array(
'#type' => 'textfield',
'#title' => t('Default value'),
'#default_value' => $currfield['value'],
'#description' => t('The default value of the field. For multiple selects use commas to separate multiple defaults.') . theme('webform_token_help'),
'#size' => 60,
'#maxlength' => 256,
'#weight' => 0,
);
$edit_fields['extra']['multiple'] = array(
'#type' => 'checkbox',
'#title' => t('Multiple'),
'#return_value' => 'Y',
'#default_value' => $currfield['extra']['multiple'],
'#description' => t('Check this option if the user should be allowed to choose multiple values.'),
);
$edit_fields['extra']['aslist'] = array(
'#type' => 'checkbox',
'#title' => t('Listbox'),
'#return_value' => 'Y',
'#default_value' => $currfield['extra']['aslist'],
'#description' => t('Check this option if you want the select component to be of listbox type instead of radiobuttons or checkboxes.'),
);
$edit_fields['extra']['email'] = array(
'#type' => 'checkbox',
'#title' => t('E-mail a submission copy'),
'#return_value' => 1,
'#default_value' => $currfield['extra']['email'],
'#description' => t('Check this option if this component contains an e-mail address that should get a copy of the submission. Emails are sent individually so other emails will not be shown to the recipient.') .' '.
t('To use the option with a select component, you must use key-value pairs seperated by pipes. i.e. user@example.com|Sample user.'),
);
return $edit_fields;
}
/**
* Element validation callback. Ensure keys are not duplicated.
*/
function _webform_edit_validate_select($element) {
// TODO: Validate e-mail addresses when used as keys?\
// Check for duplicate key values to prevent unexpected data loss.
if (!empty($element['#value'])) {
$lines = explode("\n", $element['#value']);
$existing_keys = array();
$duplicate_keys = array();
$group = '';
foreach ($lines as $line) {
$matches = array();
$line = trim($line);
if (preg_match('/^\<([^>]*)\>$/', $line, $matches)) {
$group = $matches[1];
$key = NULL; // No need to store group names.
}
elseif (preg_match('/^([^|]+)\|(.*)$/', $line, $matches)) {
$key = $matches[1];
}
else {
$key = $line;
}
if (isset($key)) {
if (isset($existing_keys[$group][$key])) {
$duplicate_keys[$key] = $key;
}
else {
$existing_keys[$group][$key] = $key;
}
}
}
if (!empty($duplicate_keys)) {
form_error($element, t('Options within the select list must be unique. The following keys have been used multiple times:') . theme('item_list', $duplicate_keys));
}
}
return TRUE;
}
/**
* Build a form item array containing all the properties of this component.
* @param $component
* An array of information describing the component, directly correlating to
* the webform_component database schema.
* @return
* An array of a form item to be displayed on the client-side webform.
*/
function _webform_render_select($component) {
$form_item = array(
'#title' => $component['name'],
'#required' => $component['mandatory'],
'#weight' => $component['weight'],
'#description' => _webform_filter_descriptions($component['extra']['description']),
'#prefix' => '
',
'#suffix' => '
',
);
// Convert the user-entered options list into an array.
$default_value = _webform_filter_values($component['value'], NULL, NULL, FALSE);
$options = _webform_select_options($component['extra']['items'], $component['extra']['aslist'] !== 'Y');
if ($component['extra']['aslist'] === 'Y' && $component['extra']['multiple'] !== 'Y' && !($component['mandatory'] && !empty($component['value']))) {
$options = array('' => t('select...')) + $options;
}
// Set the component options.
$form_item['#options'] = $options;
// Set the default value.
if ($default_value != '') {
// Convert default value to a list if necessary.
if ($component['extra']['multiple'] === 'Y') {
$varray = array_filter(explode(',', $default_value));
foreach ($varray as $key => $v) {
$form_item['#default_value'][] = $v;
}
}
else {
$form_item['#default_value'] = $default_value;
}
}
if ($component['extra']['aslist'] === 'Y') {
// Set display as a select list:
$form_item['#type'] = 'select';
if ($component['extra']['multiple'] === 'Y') {
$form_item['#multiple'] = TRUE;
}
}
else {
if ($component['extra']['multiple'] === 'Y') {
// Set display as a checkbox set.
$form_item['#type'] = 'checkboxes';
// Drupal 5 hack to correct default values.
$form_item['#process'] = array('webform_expand_checkboxes' => array());
}
else {
// Set display as a radio set.
$form_item['#type'] = 'radios';
}
}
return $form_item;
}
/**
* Drupal 5 hack that properly sets checkbox values in multistep forms. The
* checkboxes element get the proper values set by FAPI, but individual
* checkboxes are always set to 0 in a multistep form.
*/
function webform_expand_checkboxes($element) {
$element = expand_checkboxes($element);
foreach (element_children($element) as $key) {
if (empty($element['#value'][$key])) {
$element[$key]['#value'] = 0;
}
else {
$element[$key]['#value'] = 1;
}
}
return $element;
}
/**
* Display 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.
* @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_select($data, $component, $enabled = FALSE) {
$form_item = _webform_render_select($component);
if ($component['extra']['multiple'] === 'Y') {
// Set the value as an array.
$form_item['#default_value'] = array();
foreach ((array)$data['value'] as $key => $value) {
$form_item['#default_value'][] = $value;
}
}
else {
// Set the value as a single string.
$form_item['#default_value'] = '';
foreach ((array)$data['value'] as $value) {
$form_item['#default_value'] = $value;
}
}
$form_item['#disabled'] = !$enabled;
return $form_item;
}
/**
* Convert FAPI 0/1 values into something saveable.
*
* @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_select(&$data, $component) {
$options = drupal_map_assoc(array_flip(_webform_select_options($component['extra']['items'], TRUE)));
if (is_array($data)) {
foreach ($data as $key => $value) {
if ($value != '') {
$data[$key] = $options[$key];
}
// Checkboxes submit a value of 0 when not checked.
elseif ($value == 0 && $component['extra']['aslist'] !== 'Y' && $component['extra']['multiple'] === 'Y') {
unset($data[$key]);
}
else {
unset($data[$key]);
}
}
}
}
/**
* 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_select($data, $component) {
// Convert submitted 'safe' values to un-edited, original form.
$options = _webform_select_options($component['extra']['items'], TRUE);
// Generate the output.
$output = '';
if ($component['extra']['multiple']) {
$output .= $component['name'] .":\n";
foreach ((array)$data as $value) {
if ($value) {
if ($options[$value]) {
$output .= ' - '. $options[$value] ."\n";
}
}
}
}
else {
if ($data !== '' && $options[$data]) {
$output .= $component['name'] .': '. $options[$data] ."\n";
}
}
return $output;
}
/**
* Module specific instance of hook_help().
*/
function _webform_help_select($section) {
switch ($section) {
case 'admin/settings/webform#select_description':
return t('Allows creation of checkboxes, radio buttons, or select menus.');
}
}
/**
* 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_select($component, $sids = array()) {
$options = _webform_select_options($component['extra']['items'], TRUE);
$placeholders = count($sids) ? array_fill(0, count($sids), "'%s'") : array();
$sidfilter = count($sids) ? " AND sid in (".implode(",", $placeholders).")" : "";
$query = 'SELECT data, count(data) as datacount '.
' FROM {webform_submitted_data} '.
' WHERE nid = %d '.
' AND cid = %d '.
" AND data != '0' AND data != '' $sidfilter ".
' GROUP BY data ';
$result = db_query($query, array_merge(array($component['nid'], $component['cid']), $sids));
$rows = array();
while ($data = db_fetch_array($result)) {
if (isset($options[$data['data']])) {
$display_option = $options[$data['data']];
}
else {
$display_option = $data['data'];
}
$rows[] = array($display_option, $data['datacount']);
}
return $rows;
}
/**
* 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
* @return
* Textual output formatted for human reading.
*/
function _webform_table_data_select($data) {
$output = '';
// Set the value as a single string.
if (is_array($data['value'])) {
foreach ($data['value'] as $value) {
if ($value !== '0') {
$output .= check_plain($value) .'
';
}
}
}
else {
$output .= check_plain(empty($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_select($component) {
$headers = array(
0 => array(),
1 => array(),
2 => array(),
);
if ($component['extra']['multiple']) {
$headers[0][] = '';
$headers[1][] = $component['name'];
$items = _webform_select_options($component['extra']['items'], TRUE);
$count = 0;
foreach ($items as $key => $item) {
// Empty column per sub-field in main header.
if ($count != 0) {
$headers[0][] = '';
$headers[1][] = '';
}
$headers[2][] = $key;
$count++;
}
}
else {
$headers[0][] = '';
$headers[1][] = '';
$headers[2][] = $component['name'];
}
return $headers;
}
/**
* 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_select($data, $component) {
$value = _webform_filter_values($component['value'], NULL, NULL, FALSE);
$options = _webform_select_options($component['extra']['items'], TRUE);
$return = array();
if ($component['extra']['multiple']) {
foreach ($options as $key => $item) {
if (in_array($key, (array)$data['value']) === TRUE) {
$return[] = 'X';
}
else {
$return[] = '';
}
}
}
else {
$return = $data['value'][0];
}
return $return;
}
/**
* Utility function to split user-entered values from new-line seperated
* text into an array of options.
*
* @param $text
* Text to be converted into a select option array.
* @param $flat
* Optional. If specified, return the option array and exclude any optgroups.
*/
function _webform_select_options($text, $flat = FALSE) {
$options = array();
$rows = array_filter(explode("\n", trim($text)));
$group = NULL;
foreach ($rows as $option) {
$option = trim($option);
/**
* If the Key of the option is within < >, treat as an optgroup
*
*
* creates an optgroup with the label "Group 1"
*
* <>
* Unsets the current group, allowing items to be inserted at the root element.
*/
if (preg_match('/^\<([^>]*)\>$/', $option, $matches)) {
if (empty($matches[1])) {
unset($group);
}
elseif (!$flat) {
$group = _webform_filter_values($matches[1], NULL, NULL, FALSE);
}
}
elseif (preg_match('/^([^|]+)\|(.*)$/', $option, $matches)) {
$key = _webform_filter_values($matches[1], NULL, NULL, FALSE);
$value = _webform_filter_values($matches[2], NULL, NULL, FALSE);
isset($group) ? $options[$group][$key] = $value : $options[$key] = $value;
}
else {
$filtered_option = _webform_filter_values($option, NULL, NULL, FALSE);
isset($group) ? $options[$group][$filtered_option] = $filtered_option : $options[$filtered_option] = $filtered_option;
}
}
return $options;
}