t('Better select'), 'description' => t('Configure better select settings.'), 'page callback' => 'drupal_get_form', 'page arguments' => array('betterselect_admin_settings'), 'access arguments' => array('administer site configuration'), 'type' => MENU_NORMAL_ITEM, ); return $items; } /** * Build settings form(). */ function betterselect_admin_settings() { $form['betterselect_general'] = array( '#type' => 'fieldset', '#title' => t('General options'), ); $form['betterselect_general']['betterselect_scroll'] = array( '#type' => 'checkbox', '#title' => t('Scrollable div'), '#description' => t('Place options in a scrollable div'), '#default_value' => variable_get('betterselect_scroll', FALSE), ); $form['betterselect_general']['betterselect_node_form_only'] = array( '#type' => 'checkbox', '#title' => t('Node form only'), '#description' => t('Only convert select lists on node forms'), '#default_value' => variable_get('betterselect_node_form_only', FALSE), ); $form['betterselect_taxonomy'] = array( '#type' => 'fieldset', '#title' => t('Taxonomy options'), ); $form['betterselect_taxonomy']['betterselect_save_lineage'] = array( '#type' => 'checkbox', '#title' => t('Save lineage'), '#description' => t('If a user selects a child term when saving a node, automatically save the parent term too.'), '#default_value' => variable_get('betterselect_save_lineage', FALSE), ); $form['betterselect_taxonomy']['betterselect_add_depth_classes'] = array( '#type' => 'checkbox', '#title' => t('Add depth classes'), '#description' => t('Add an extra div to each betterselect option, with a class indicating depth in taxonomy hierarchy. Good for styling parent/child.'), '#default_value' => variable_get('betterselect_add_depth_classes', FALSE), ); return system_settings_form($form); } /** * Implementation of hook_elements(). */ function betterselect_elements() { $type = array(); $type['select']['#process'] = array('betterselect_process'); return $type; } /** * Form process callback; translates multiselect fields into checkboxes. */ function betterselect_process($element, $edit, $form_state, $complete_form) { if (isset($element['#multiple']) && $element['#multiple'] == TRUE && !(variable_get('betterselect_node_form_only', FALSE) == TRUE && $complete_form['#id'] != 'node-form')) { // To handle deselection of checkboxes in exposed Views-filters we need this if ((substr($complete_form['#id'],0,18) == 'views-exposed-form') && isset($element['#value'][0])) { $element['#value'] = array(); } // If we're dealing with taxonomy, fix the option titles. if (is_object($element['#options'][0])) { // Build new array of options in format that theme_checkboxes expects. $options = array(); $defaults = array(); foreach ($element['#options'] as $option) { if (is_array($option->option)) { foreach ($option->option as $tid => $name) { $options[$tid] = check_plain($name); } } } $element['#options'] = $options; } // We now check that the element's options are correct. If they're not in // the right format, we abort. foreach($element['#options'] as $key => $val) { if (!is_numeric($key) || !is_string($val)) { return $element; } } // The default value should be an array, if it isn't expand_checkboxes() // will make it one. if (isset($element['#default_value']) && is_array($element['#default_value']) && count($element['#default_value'])) { // Fix the value arrays; checkboxes are the exact inverse of multiselect, // apparently for vindictive fun. // First make sure there's at least 1 non-blank array element $temp = $element['#default_value']; $temp = array_shift($element['#default_value']); if (!empty($temp)) { $element['#default_value'] = array_flip($element['#default_value']); $element['#value'] = array_flip($element['#value']); } } // Place options in a scrollable or non-scrollable div $div_class = variable_get('betterselect_scroll', FALSE) ? 'form-checkboxes-scroll' : 'form-checkboxes-noscroll'; $element['#attributes'] = array('class' => $div_class); // Switch display to checkboxes instead. $element['#type'] = 'checkboxes'; unset($element['#theme']); $element = expand_checkboxes($element); // Hide the silly "None" option. (assumes array element with a blank key is the "None" option) if (!$element['#required'] && is_array($element[''])) { $element['']['#prefix'] = '
'; $element['']['#suffix'] = '
'; } // Include the JS and CSS files. static $path; if (!isset($path)) { $path = drupal_get_path('module', 'betterselect'); drupal_add_css($path . '/betterselect.css'); drupal_add_js($path . '/betterselect.js'); } // Add classes to items that indicate depth, for taxonomy, useful for // styling parent terms differently. if (variable_get('betterselect_add_depth_classes', FALSE)) { $prev = NULL; $prev_depth = 0; foreach (element_children($element) as $key) { $title = $element[$key]['#title']; $trim_title = ltrim($title, '-'); $depth = strlen($title) - strlen($trim_title); $extra_class = 'checkbox-depth-' . $depth; $element[$key]['#prefix'] = '
'; $element[$key]['#suffix'] = '
'; // Put a class on each element that contains children. We do this // retroactively, in other words, we operate on the previous element. if ($prev != NULL) { if ($depth > $prev_depth) { // Gone down a level, so previous must get 'has-children' class $alt_classes = 'checkbox-depth-' . $prev_depth . ' has-children'; $prev['#prefix'] = '
'; $prev['#suffix'] = '
'; } } $prev = &$element[$key]; $prev_depth = $depth; } } // Add the necessary prefix/suffix to make JS/CSS work. $size = isset($element['#size']) ? $element['#size'] : 10; $prefix = isset($element['#prefix']) ? $element['#prefix'] : ''; $suffix = isset($element['#suffix']) ? $element['#suffix'] : ''; $fixheight = count($element['#options']) > $size ? ' betterfixed' : ''; $id = 'better-select-' . $element['#id']; $element['#prefix'] = '
' . $prefix; $element['#suffix'] = $suffix . '
'; } return $element; } /** * Implementation of hook_form_alter(). */ function betterselect_form_alter(&$form, $form_state, $form_id) { // Add this to handle checkboxes in exposed Views-filters if (substr($form['#id'],0,18) == 'views-exposed-form') { $form['#submit'][] = 'betterselect_views_filter_from_checkboxes'; } // Taxonomy stores its #options in a weird way; we need to move it back once we're done. if (($form['#id'] == 'node-form' && isset($form['taxonomy']))) { $form['#submit'][] = 'betterselect_taxonomy_from_checkboxes'; } elseif ($form_id == 'taxonomy_form_term' && !(variable_get('betterselect_node_form_only', FALSE))) { // This is the form that appears on the edit/term/xx page. Betterselect // has to process it before taxonomy module. array_unshift($form['#submit'], 'betterselect_taxonomy_form_term_from_checkboxes'); } } /** * Additional submit handler for the views filter form. */ function betterselect_views_filter_from_checkboxes($form, &$form_state) { // Create an array which is correct! $new_tid = array(); if (!array_key_exists(0, $form_state['values']['tid'])) { foreach ($form_state['values']['tid'] as $val) { if($val != 0) { $new_tid[$val] = $val; } } // This is for the of chance that we actually selected something ;) form_set_value($form['tid'], $new_tid, $form_state); $form_state['values']['tid'] = $new_tid; $form_state[view]->filter[tid]->validated_exposed_input = $new_tid; } } /** * Additional submit handler for the taxonomy term form. */ function betterselect_taxonomy_form_term_from_checkboxes($form, &$form_state) { $fix = array('parent', 'relations'); foreach ($fix as $select) { $options = array(); if (isset($form_state['values'][$select])) { foreach ($form_state['values'][$select] as $tid => $selected) { if ($selected) { $options[$tid] = $tid; } } $form_state['values'][$select] = $options; } } } /** * Restore submitted checkbox values back to format Taxonomy module expects. */ function betterselect_taxonomy_from_checkboxes($form, &$form_state) { foreach ($form_state['values']['taxonomy'] as $index => $properties) { if (is_numeric($index) && $form['taxonomy'][$index]['#multiple']) { $options = array(); foreach ($form_state['values']['taxonomy'][$index] as $tid => $selected) { if ($selected) { $options[$tid] = $tid; // Save lineage - automatically select all parents. if (variable_get('betterselect_save_lineage', FALSE)) { $parents = taxonomy_get_parents($tid); foreach ($parents as $key => $val) { $options[$key] = $key; } } } } $form_state['values']['taxonomy'][$index] = $options; } } }