'. t('Provides a CCK widget for editing fields that allows users to select from a list of options in a left box and have them visually moved into the right box when options are chosen.') .'

'; break; } return $output; } /** * Implementation of hook_form_alter(). */ function multiselect_form_alter(&$form, $form_state, $form_id) { // Provide additional help for the field settings form. if ($form_id == 'content_field_edit_form' && isset($form['widget'])) { $widget_type = $form['#field']['widget']['type']; $field_type = $form['#field']['type']; $label = $form['#field']['widget']['label']; $output = '

'. t('Create a list of options as a list in Allowed values list or as an array in PHP code. These values will be the same for %field in all content types.', array('%field' => $label)) .'

'; if (in_array($widget_type, array('multiselect_select'))) { $form['field']['multiple']['#default_value'] = 1; // Default to the selection of "Unlimited" "Number of values". if (in_array($field_type, array('text', 'number_integer', 'number_float', 'number_decimal'))) { $form['field']['allowed_values_fieldset']['#collapsed'] = FALSE; $form['field']['allowed_values_fieldset']['#description'] = $output; // If no 'allowed values' were set yet, add a remainder in the messages area. if (empty($form_state['post']) && empty($form['field']['allowed_values_fieldset']['allowed_values']['#default_value']) && empty($form['field']['allowed_values_fieldset']['advanced_options']['allowed_values_php']['#default_value'])) { drupal_set_message(t("You need to specify the 'allowed values' for this field."), 'warning'); } } } } } /** * Implementation of hook_widget_info(). * This specifies the label and that it is a widget for the different field types. */ function multiselect_widget_info() { return array( 'multiselect_select' => array( 'label' => t('Multiselect'), 'field types' => array('nodereference', 'text', 'number_integer', 'number_decimal', 'number_float', 'userreference', 'content_taxonomy'), 'multiple values' => CONTENT_HANDLE_MODULE, 'callbacks' => array( 'default value' => CONTENT_CALLBACK_DEFAULT, ), ), ); } /** * Implementation of FAPI hook_elements(). * * Any FAPI callbacks needed for individual widgets can be declared here, * and the element will be passed to those callbacks for processing. */ function multiselect_elements() { return array( 'multiselect_select' => array( '#input' => TRUE, '#columns' => array('uid'), '#delta' => 0, '#process' => array('multiselect_select_process'), ), ); } /** * Implementation of hook_widget(). * * hook_widget is a CCK hook * * Attach a single form element to the form. It will be built out and * validated in the callback(s) listed in hook_elements. We build it * out in the callbacks rather than here in hook_widget so it can be * plugged into any module that can provide it with valid * $field information. * * Content module will set the weight, field name and delta values * for each form element. This is a change from earlier CCK versions * where the widget managed its own multiple values. * * If there are multiple values for this field, the content module will * call this function as many times as needed. * * @param $form * the entire form array, $form['#node'] holds node information * @param $form_state * the form_state, $form_state['values'] holds the form values. * @param $field * the field array * @param $delta * the order of this item in the array of subelements (0, 1, 2, etc) * * @return * the form item for a single element for this field */ function multiselect_widget(&$form, &$form_state, $field, $items, $delta = 0) { switch ($field['widget']['type']) { case 'multiselect_select': $element = array( '#type' => 'multiselect_select', '#default_value' => $items, ); break; } return $element; } /** * Process an individual element. * * Build the form element. When creating a form using FAPI #process, * note that $element['#value'] is already set. * * The $fields array is in $form['#field_info'][$element['#field_name']]. */ function multiselect_select_process($element, $edit, $form_state, $form) { // Insert Javascript and CSS for this widget. $path = drupal_get_path('module', 'multiselect'); drupal_add_js($path .'/multiselect.js'); drupal_add_css($path .'/multiselect.css', 'module', 'all', FALSE); //doesn't aggregate: as it's not used much(?) $field_name = $element['#field_name']; $field = $form['#field_info'][$field_name]; $field_key = $element['#columns'][0]; // See if this element is in the database format or the transformed format, // and transform it if necessary. if (is_array($element['#value']) && !array_key_exists($field_key, $element['#value'])) { $element['#value'] = optionwidgets_data2form($element, $element['#default_value'], $field); } // Get a list of all options for this field. $options = optionwidgets_options($field); // Create some arrays for use later in the function. $unselected_options = array(); $selected_options = array(); //if ($field['type'] == 'userreference') { //dsm($element); //dsm($options); //} // Add selected items to the array first foreach ($element['#value'][$field_key] as $key) { if (isset($options[$key])) { $selected_options[$key] = $options[$key]; } } // Add the remaining options to the arrays foreach ($options as $key => $value) { if (!isset($selected_options[$key])) { $unselected_options[$key] = $value; //$selected_options[$key] = $value; } } // Set up useful variables. $addbutton = $element['#field_name'] ."_add"; $removebutton = $element['#field_name'] ."_remove"; $selfield = $element['#field_name'] ."_sel"; $unselfield = $element['#field_name'] ."_unsel"; // Call methods to create prefix. (ie the non-selected table, etc) $prefix_pre = '
\n"; $prefix_pre .= "
". t('Available Options') .":
\n"; $prefix_pre .= "
". t('Selected Options') .":
\n
\n"; $prefix_pre .= "
"; $prefix_pre .= _multiselect_html_for_unselected_box_start($unselfield, $element['#field_name']); $prefix_options = _multiselect_html_for_unselected_box_options($unselected_options); $prefix_post = "\n
\n"; $prefix_post .= _html_for_buttons($element['#field_name']); $element[$field_key] = array( '#type' => 'select', //'#title' => $element['#title'], // Title is added in the prefix section. If added here, displays incorrectly. '#description' => $element['#description'], '#required' => isset($element['#required']) ? $element['#required'] : $field['required'], '#multiple' => isset($element['#multiple']) ? $element['#multiple'] : $field['multiple'], '#options' => $selected_options, '#size' => 10, '#prefix' => $prefix_pre . $prefix_options . $prefix_post, '#suffix' => "\n
\n", '#attributes' => array('class' => "$selfield multiselect_sel", 'id' => $element['#field_name']), '#default_value' => isset($element['#value'][$field_key]) ? $element['#value'][$field_key] : NULL, ); // Set #element_validate in a way that it will not wipe out other // validation functions already set by other modules. if (empty($element['#element_validate'])) { $element['#element_validate'] = array(); } array_unshift($element['#element_validate'], 'optionwidgets_validate'); return $element; } /** * Implementation of hook_theme(). */ function multiselect_theme() { return array( 'multiselect_select' => array( 'arguments' => array('element' => NULL), ), ); } /** * FAPI theme for an individual elements. * * The textfield or select is already rendered by the * textfield or select themes and the html output * lives in $element['#children']. Override this theme to * make custom changes to the output. * * $element['#field_name'] contains the field name * $element['#delta] is the position of this element in the group */ function theme_multiselect_select($element) { return $element['#children']; } /** * Provides html to draw the "not selected" box */ function _multiselect_html_for_unselected_box_start($unselfield, $fieldname) { $boxhtml = ''; $boxhtml .= "