options_element.inc in Options Element 6
Same filename and directory in other branches
All logic for options_element form elements.
File
options_element.incView source
<?php
/**
* @file
* All logic for options_element form elements.
*/
/**
* Theme an options element.
*/
function theme_options($element) {
drupal_add_js('misc/tabledrag.js');
drupal_add_js(drupal_get_path('module', 'options_element') . '/options_element.js');
drupal_add_css(drupal_get_path('module', 'options_element') . '/options_element.css');
$classes = array();
if (isset($element['#attributes']['class'])) {
$classes[] = $element['#attributes']['class'];
}
$classes[] = 'form-options';
$classes[] = 'options-key-type-' . $element['#key_type'];
if ($element['#key_type_toggled']) {
$classes[] = 'options-key-custom';
}
if (isset($element['#optgroups']) && $element['#optgroups']) {
$classes[] = 'options-optgroups';
}
if (isset($element['#multiple']) && $element['#multiple']) {
$classes[] = 'options-multiple';
}
// Replace the error class from wrapper div, which doesn't display well with
// complex elements like Options Element.
if ($key = array_search('error', $classes, TRUE)) {
$classes[$key] = 'options-error';
}
$options = '';
$options .= drupal_render($element['options_field']);
if (isset($element['default_value_field'])) {
$options .= drupal_render($element['default_value_field']);
}
if (isset($element['default_value_pattern'])) {
$options .= drupal_render($element['default_value_pattern']);
}
$settings = '';
if (isset($element['custom_keys'])) {
$settings .= drupal_render($element['custom_keys']);
}
if (isset($element['multiple'])) {
$settings .= drupal_render($element['multiple']);
}
if (isset($element['option_settings'])) {
$settings .= drupal_render($element['option_settings']);
}
$output = '';
$output .= '<div class="' . implode(' ', $classes) . '">';
$output .= theme('fieldset', array(
'#title' => t('Options'),
'#collapsible' => FALSE,
'#children' => $options,
'#attributes' => array(
'class' => 'options',
),
));
if (!empty($settings)) {
$output .= theme('fieldset', array(
'#title' => t('Option settings'),
'#collapsible' => FALSE,
'#children' => $settings,
'#attributes' => array(
'class' => 'option-settings',
),
));
}
$output .= '</div>';
return $output;
}
/**
* Logic function for form_options_expand(). Do not call directly.
*
* @see form_options_expand()
*/
function _form_options_expand($element) {
$element['#options'] = isset($element['#options']) ? $element['#options'] : array();
$element['#multiple'] = isset($element['#multiple']) ? $element['#multiple'] : FALSE;
$element['#tree'] = TRUE;
$element['#theme'] = 'options';
// Add the key type toggle checkbox.
if (!isset($element['custom_keys']) && $element['#key_type'] != 'custom' && !empty($element['#key_type_toggle'])) {
$element['custom_keys'] = array(
'#title' => is_string($element['#key_type_toggle']) ? $element['#key_type_toggle'] : t('Customize keys'),
'#type' => 'checkbox',
'#default_value' => $element['#key_type_toggled'],
'#attributes' => array(
'class' => 'key-type-toggle',
),
'#description' => t('Customizing the keys will allow you to save one value internally while showing a different option to the user.'),
);
}
// Add the multiple value toggle checkbox.
if (!isset($element['multiple']) && !empty($element['#multiple_toggle'])) {
$element['multiple'] = array(
'#title' => is_string($element['#multiple_toggle']) ? $element['#multiple_toggle'] : t('Allow multiple values'),
'#type' => 'checkbox',
'#default_value' => !empty($element['#multiple']),
'#attributes' => array(
'class' => 'multiple-toggle',
),
'#description' => t('Multiple values will let users select multiple items in this list.'),
);
}
// If the element had a custom interface for toggling whether or not multiple
// values are accepted, make sure that form_type_options_value() knows to use
// it.
if (isset($element['multiple']) && empty($element['#multiple_toggle'])) {
$element['#multiple_toggle'] = TRUE;
}
// Add the main textarea for adding options.
if (!isset($element['options'])) {
$element['options_field'] = array(
'#type' => 'textarea',
'#resizable' => TRUE,
'#cols' => 60,
'#rows' => 5,
'#required' => isset($element['#required']) ? $element['#required'] : FALSE,
'#description' => t('List options one option per line.'),
'#attributes' => $element['#options_readonly'] ? array(
'readonly' => 'readonly',
) : array(),
'#wysiwyg' => FALSE,
);
// If validation fails, reload the user's text even if it's not valid.
if (isset($element['#value']['options_text'])) {
$element['options_field']['#value'] = $element['#value']['options_text'];
}
else {
$element['options_field']['#value'] = isset($element['#options']) ? form_options_to_text($element['#options'], $element['#key_type']) : '';
}
if ($element['#key_type'] == 'mixed' || $element['#key_type'] == 'numeric' || $element['#key_type'] == 'custom') {
$element['options_field']['#description'] .= ' ' . t('Key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>.');
}
elseif ($element['#key_type_toggle']) {
$element['options_field']['#description'] .= ' ' . t('If the %toggle field is checked, key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>.', array(
'%toggle' => $element['custom_keys']['#title'],
));
}
if ($element['#key_type'] == 'numeric') {
$element['options_field']['#description'] .= ' ' . t('This field requires all specified keys to be integers.');
}
}
// Add the field for storing default values.
if ($element['#default_value_allowed'] && !isset($element['default_value_field'])) {
$element['default_value_field'] = array(
'#title' => t('Default value'),
'#type' => 'textfield',
'#size' => 60,
'#maxlength' => 1024,
'#value' => isset($element['#default_value']) ? $element['#multiple'] ? implode(', ', (array) $element['#default_value']) : $element['#default_value'] : '',
'#description' => t('Specify the keys that should be selected by default.'),
);
if ($element['#multiple']) {
$element['default_value_field']['#description'] .= ' ' . t('Multiple default values may be specified by separating keys with commas.');
}
}
// Add the field for storing a default value pattern.
if ($element['#default_value_pattern']) {
$element['default_value_pattern'] = array(
'#type' => 'hidden',
'#value' => $element['#default_value_pattern'],
'#attributes' => array(
'class' => 'default-value-pattern',
),
);
}
// Remove properties that will confuse the FAPI.
unset($element['#options']);
return $element;
}
/**
* Logic function for form_options_validate(). Do not call directly.
*
* @see form_options_validate()
*/
function _form_options_validate($element, &$form_state) {
// Even though we already have the converted options in #value['options'], run
// the conversion again to check for duplicates in the user-defined list.
$duplicates = array();
$options = form_options_from_text($element['#value']['options_text'], $element['#key_type'], empty($element['#optgroups']), $duplicates);
// Check if a key is used multiple times.
if (count($duplicates) == 1) {
form_error($element, t('The key %key has been used multiple times. Each key must be unique to display properly.', array(
'%key' => reset($duplicates),
)));
}
elseif (!empty($duplicates)) {
array_walk($duplicates, 'check_plain');
$duplicate_list = theme('item_list', $duplicates);
form_error($element, t('The following keys have been used multiple times. Each key must be unique to display properly.') . $duplicate_list);
}
// Add the list of duplicates to the page so that we can highlight the fields.
if (!empty($duplicates)) {
drupal_add_js(array(
'optionsElement' => array(
'errors' => drupal_map_assoc($duplicates),
),
), 'setting');
}
// Check if no options are specified.
if (empty($options) && $element['#required']) {
form_error($element, t('At least one option must be specified.'));
}
// Check for numeric keys if needed.
if ($element['#key_type'] == 'numeric') {
foreach ($options as $key => $value) {
if (!is_int($key)) {
form_error($element, t('The keys for the %title field must be integers.', array(
'%title' => $element['#title'],
)));
break;
}
}
}
// Check that the limit of options has not been exceeded.
if (!empty($element['#limit'])) {
$count = 0;
foreach ($options as $value) {
if (is_array($value)) {
$count += count($value);
}
else {
$count++;
}
}
if ($count > $element['#limit']) {
form_error($element, t('The %title field supports a maximum of @count options. Please reduce the number of options.', array(
'%title' => $element['#title'],
'@count' => $element['#limit'],
)));
}
}
}
/**
* Logic function for form_type_options_value(). Do not call directly.
*
* @see form_type_options_value()
*/
function _form_type_options_value(&$element, $edit = FALSE) {
if ($edit === FALSE) {
return array(
'options' => isset($element['#options']) ? $element['#options'] : array(),
'default_value' => isset($element['#default_value']) ? $element['#default_value'] : '',
);
}
else {
// Convert text to an array of options.
$duplicates = array();
$options = form_options_from_text($edit['options_field'], $element['#key_type'], empty($element['#optgroups']), $duplicates);
// Convert default value.
if (isset($edit['default_value_field'])) {
// If the element supports toggling whether or not it will accept
// multiple values, use the value that was passed in via $edit (keeping
// in mind that this value may not be set, if a checkbox was used to
// configure it). Otherwise, use the current setting stored with the
// element itself.
$multiple = !empty($element['#multiple_toggle']) ? !empty($edit['multiple']) : !empty($element['#multiple']);
if ($multiple) {
$default_value = array();
$default_items = explode(',', $edit['default_value_field']);
foreach ($default_items as $key) {
$key = trim($key);
$value = _form_options_search($key, $options, $element['#default_value_pattern']);
if (!is_null($value)) {
$default_value[] = $value;
}
}
}
else {
$default_value = _form_options_search(trim($edit['default_value_field']), $options, $element['#default_value_pattern']);
}
}
else {
$default_value = NULL;
}
$return = array(
'options' => $options,
'default_value' => $default_value,
'options_text' => $edit['options_field'],
);
if (isset($edit['default_value_field'])) {
$return['default_value_text'] = $edit['default_value_field'];
}
return $return;
}
}
/**
* Logic function for form_options_to_text(). Do not call directly.
*
* @see form_options_to_text()
*/
function _form_options_to_text($options, $key_type) {
$output = '';
$previous_key = false;
foreach ($options as $key => $value) {
// Convert groups.
if (is_array($value)) {
$output .= '<' . $key . '>' . "\n";
foreach ($value as $subkey => $subvalue) {
$output .= ($key_type == 'mixed' || $key_type == 'numeric' || $key_type == 'custom' ? $subkey . '|' : '') . $subvalue . "\n";
}
$previous_key = $key;
}
else {
// Exit out of any groups.
if (isset($options[$previous_key]) && is_array($options[$previous_key])) {
$output .= "<>\n";
}
// Skip empty rows.
if ($options[$key] !== '') {
if ($key_type == 'mixed' || $key_type == 'numeric' || $key_type == 'custom') {
$output .= $key . '|' . $value . "\n";
}
else {
$output .= $value . "\n";
}
}
$previous_key = $key;
}
}
return $output;
}
/**
* Logic function for form_options_from_text(). Do not call directly.
*
* @see form_options_from_text()
*/
function _form_options_from_text($text, $key_type, $flat = FALSE, &$duplicates = array()) {
$keys = array();
$items = array();
$rows = array_filter(explode("\n", trim($text)), 'strlen');
$group = FALSE;
foreach ($rows as $row) {
$row = trim($row);
$matches = array();
// Check for a simple empty row.
if (!strlen($row)) {
continue;
}
elseif (!$flat && preg_match('/^\\<((([^>|]*)\\|)?([^>]*))\\>$/', $row, $matches)) {
if ($matches[1] === '') {
$group = FALSE;
}
else {
$group = $matches[4] ? $matches[4] : '';
$keys[] = $group;
}
}
elseif (($key_type == 'mixed' || $key_type == 'custom' || $key_type == 'numeric') && preg_match('/^([^|]+)\\|(.*)$/', $row, $matches)) {
$key = $matches[1];
$value = $matches[2];
$keys[] = $key;
$items[] = array(
'key' => $key,
'value' => $value,
'group' => $group,
);
}
else {
$items[] = array(
'key' => NULL,
'value' => $row,
'group' => $group,
);
}
}
// Expand the list into a nested array, assign keys and check duplicates.
$options = array();
$new_key = 1;
foreach ($items as $item) {
$int_key = $item['key'] * 1;
if (is_int($int_key)) {
$new_key = max($int_key, $new_key);
}
}
foreach ($items as $item) {
// Assign a key if needed.
if ($key_type == 'none') {
$item['key'] = $new_key++;
}
elseif (!isset($item['key'])) {
while (in_array($new_key, $keys)) {
$new_key++;
}
$keys[] = $new_key;
$item['key'] = $new_key;
}
if ($item['group']) {
if (isset($options[$item['group']][$item['key']])) {
$duplicates[] = $item['key'];
}
$options[$item['group']][$item['key']] = $item['value'];
}
else {
if (isset($options[$item['key']])) {
$duplicates[] = $item['key'];
}
$options[$item['key']] = $item['value'];
}
}
return $options;
}
/**
* Recursive function for finding default value keys. Matches on keys or values.
*/
function _form_options_search($needle, $haystack, $include_pattern) {
if (isset($haystack[$needle])) {
return $needle;
}
elseif ($include_pattern && preg_match('/' . $include_pattern . '/', $needle)) {
return $needle;
}
foreach ($haystack as $key => $value) {
if (is_array($value)) {
return _form_options_search($needle, $value, $include_pattern);
}
elseif ($value == $needle) {
return $key;
}
}
}
Functions
Name | Description |
---|---|
theme_options | Theme an options element. |
_form_options_expand | Logic function for form_options_expand(). Do not call directly. |
_form_options_from_text | Logic function for form_options_from_text(). Do not call directly. |
_form_options_search | Recursive function for finding default value keys. Matches on keys or values. |
_form_options_to_text | Logic function for form_options_to_text(). Do not call directly. |
_form_options_validate | Logic function for form_options_validate(). Do not call directly. |
_form_type_options_value | Logic function for form_type_options_value(). Do not call directly. |