\n"; $required = !empty($element['#required']) ? '*' : ''; if (!empty($element['#title'])) { $title = $element['#title']; if (!empty($element['#id'])) { $output .= ' \n"; } else { $output .= ' \n"; } } $output .= " $value\n"; if (!empty($element['#description'])) { $output .= '
'. $element['#description'] ."
\n"; } $output .= "\n"; return $output; } /** * Format a hierarchical select. * * @param $element * An associative array containing the properties of the element. * @return * A themed HTML string representing the form element. */ function theme_hierarchical_select($element) { $output = ''; // Update $element['#attributes']['class']. if (!isset($element['#attributes']['class'])) { $element['#attributes']['class'] = ''; } $hsid = $element['hsid']['#value']; $level_labels_style = variable_get('hierarchical_select_level_labels_style', 'none'); $classes = array( 'hierarchical-select-wrapper', "hierarchical-select-level-labels-style-$level_labels_style", // Classes that make it possible to override the styling of specific // instances of Hierarchical Select, based on either the ID of the form // element or the config that it uses. 'hierarchical-select-wrapper-for-name-' . $element['#id'], (isset($element['#config']['config_id'])) ? 'hierarchical-select-wrapper-for-config-' . $element['#config']['config_id'] : NULL, ); $element['#attributes']['class'] .= ' '. implode(' ', $classes); $element['#attributes']['id'] = "hierarchical-select-$hsid-wrapper"; $element['#id'] = "hierarchical-select-$hsid-wrapper"; // This ensures the label's for attribute is correct. $output .= theme( 'hierarchical_select_form_element', array( '#title' => $element['#title'], '#description' => $element['#description'], '#id' => $element['#id'], '#required' => $element['#required'], '#error' => isset($element['#error']) ? $element['#error'] : '', ), '
'. $element['#children'] .'
' ); return $output; } /** * Format the container for all selects in the hierarchical select. * * @param $element * An associative array containing the properties of the element. * @return * A themed HTML string representing the form element. */ function theme_hierarchical_select_selects_container($element) { $output = ''; $output .= '
'; $output .= drupal_render($element); $output .= '
'; return $output; } /** * Format a select in the .hierarchial-select div: prevent it from being * wrapped in a div. This simplifies the CSS and JS code. * * @param $element * An associative array containing the properties of the element. * @return * A themed HTML string representing the form element. */ function theme_hierarchical_select_select($element) { $select = ''; $size = $element['#size'] ? ' size="'. $element['#size'] .'"' : ''; $class = array('form-select'); if (form_get_error($element) === '') { $class = array_merge($class, array('error')); } _form_set_class($element, $class); $multiple = isset($element['#multiple']) && $element['#multiple']; return ''; } /** * Format a special option in a Hierarchical Select select. For example the * "none" option or the "create new item" option. This theme function allows * you to change how a special option is indicated textually. * * @param $option * A special option. * @return * A textually indicated special option. */ function theme_hierarchical_select_special_option($option) { return '<'. $option .'>'; } /** * Format a textfield in the .hierarchial-select div: prevent it from being * wrapped in a div. This simplifies the CSS and JS code. * * @param $element * An associative array containing the properties of the element. * @return * A themed HTML string representing the form element. */ // TODO: check if this has changed in D6. function theme_hierarchical_select_textfield($element) { $size = $element['#size'] ? ' size="'. $element['#size'] .'"' : ''; $class = array('form-text'); $extra = ''; $output = ''; if ($element['#autocomplete_path']) { drupal_add_js('misc/autocomplete.js'); $class[] = 'form-autocomplete'; $extra = ''; } _form_set_class($element, $class); if (isset($element['#field_prefix'])) { $output .= ''. $element['#field_prefix'] .' '; } $output .= ''; if (isset($element['#field_suffix'])) { $output .= ' '. $element['#field_suffix'] .''; } return $output . $extra; } /** * Forms API theming callback for the dropbox. Renders the dropbox as a table. * * @param $element * An element for which the #theme property was set to this function. * @return * A themed HTML string. */ function theme_hierarchical_select_dropbox_table($element) { $output = ''; $class = 'dropbox'; if (form_get_error($element) === '') { $class .= ' error'; } $title = $element['title']['#value']; $separator = $element['separator']['#value']; $is_empty = $element['is_empty']['#value']; $separator_html = ''. $separator .''; $output .= '
'; $output .= ''; $output .= ''; $output .= ''; if (!$is_empty) { // Each lineage in the dropbox corresponds to an entry in the dropbox table. $lineage_count = count(element_children($element['lineages'])); for ($x = 0; $x < $lineage_count; $x++) { $db_entry = $element['lineages'][$x]; $zebra = $db_entry['#zebra']; $first = $db_entry['#first']; $last = $db_entry['#last']; // The deepest level is the number of child levels minus one. This "one" // is the element for the "Remove" checkbox. $deepest_level = count(element_children($db_entry)) - 1; $output .= ''; $output .= ''; $output .= ''; $output .= ''; } } else { $output .= ''; } $output .= ''; $output .= '
'. $title .'
'; // Each item in a lineage is separated by the separator string. for ($depth = 0; $depth < $deepest_level; $depth++) { $output .= drupal_render($db_entry[$depth]); if ($depth < $deepest_level - 1) { $output .= $separator_html; } } $output .= ''. drupal_render($db_entry['remove']) .'
'; $output .= t('Nothing has been selected.'); $output .= '
'; $output .= '
'; return $output; } /** * Themeing function to render the level_labels settings as a table. */ // TODO: rename $form to $element for consistency (and update hook_theme() after that), make the comment consistent. function theme_hierarchical_select_common_config_form_level_labels($form) { // Recover the stored strings. $strings = $form['#strings']; $output = ''; $header = array(t('Level'), t('Label')); $rows = array(); $output .= drupal_render($form['status']); $output .= '
'; if (isset($form['labels']) && count(element_children($form['labels']))) { foreach (element_children($form['labels']) as $depth) { $row = array(); $row[]['data'] = ($depth == 0) ? t('Root level') : t('Sublevel !depth', array('!depth' => $depth)); $row[]['data'] = drupal_render($form['labels'][$depth]); $rows[] = $row; } // Render the table. $output .= theme('table', $header, $rows, array('style' => 'width: auto;')); } else { // No levels exist yet in the hierarchy! $output .= '

'; $output .= t('There are no levels yet in this !hierarchy!', array('!hierarchy' => $strings['hierarchy'])); $output .= '

'; } $output .= '
'; // Render the remaining form items. $output .= drupal_render($form); return $output; } /** * Themeing function to render the per-level editability settings as a table, * (these are the item_types and allowed_levels settings). */ // TODO: rename $form to $element for consistency (and update hook_theme() after that), make the comment consistent. function theme_hierarchical_select_common_config_form_editability($form) { // Recover the stored strings. $strings = $form['#strings']; $output = ''; $header = array(t('Level'), t('Allow'), t('!item_type', array('!item_type' => drupal_ucfirst($strings['item_type'])))); $rows = array(); $output .= drupal_render($form['status']); $output .= '
'; if (isset($form['item_types']) && count(element_children($form['item_types']))) { foreach (element_children($form['item_types']) as $depth) { $row = array(); $row[]['data'] = ($depth == 0) ? t('Root level') : t('Sublevel !depth', array('!depth' => $depth)); $row[]['data'] = drupal_render($form['allowed_levels'][$depth]); $row[]['data'] = drupal_render($form['item_types'][$depth]); $rows[] = $row; } // Render the table and description. $output .= theme('table', $header, $rows, array('style' => 'width: auto;'), ''. t('Per-level settings for creating new !items.', array('!items' => $strings['items']))); $output .= '
'; $output .= t( 'The %item_type you enter for each level is what will be used in each level to replace a "<create new item>" option with a "<create new %item_type>" option, which is often more intuitive.', array( '%item_type' => $strings['item_type'], ) ); $output .= '
'; } else { // No levels exist yet in the hierarchy! $output .= '

'; $output .= t('There are no levels yet in this !hierarchy!', array('!hierarchy' => $strings['hierarchy'])); $output .= '

'; } $output .= '
'; // Render the remaining form items. $output .= drupal_render($form); return $output; } /** * Themeing function to render a selection (of items) according to a given * Hierarchical Select configuration as one or more lineages. * * @param $selection * A selection of items of a hierarchy. * @param $config * A config array with at least the following settings: * - module * - save_lineage * - params */ function theme_hierarchical_select_selection_as_lineages($selection, $config) { $output = ''; $selection = (!is_array($selection)) ? array($selection) : $selection; // Generate a dropbox out of the selection. This will automatically // calculate all lineages for us. $selection = array_keys($selection); $dropbox = _hierarchical_select_dropbox_generate($config, $selection); // Actual formatting. foreach ($dropbox->lineages as $id => $lineage) { if ($id > 0) { $output .= '
'; } $items = array(); foreach ($lineage as $level => $item) { $items[] = $item['label']; } $output .= implode('', $items); } // Add the CSS. drupal_add_css(drupal_get_path('module', 'hierarchical_select') .'/hierarchical_select.css'); return $output; } /** * @} End of "ingroup themeable". */ //---------------------------------------------------------------------------- // Private functions. /** * This is an altered clone of form_select_options(). The reason: I need to be * able to set a class on an option element if it contains a level label, to * allow for level label styles. * TODO: rename to _hierarchical_select_select_options(). */ function _hierarchical_select_options($element) { if (!isset($choices)) { $choices = $element['#options']; } // array_key_exists() accommodates the rare event where $element['#value'] is NULL. // isset() fails in this situation. $value_valid = isset($element['#value']) || array_key_exists('#value', $element); $value_is_array = is_array($element['#value']); $options = ''; foreach ($choices as $key => $choice) { $key = (string)$key; if ($value_valid && (!$value_is_array && (string)$element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) { $selected = ' selected="selected"'; } else { $selected = ''; } // If an option DOES NOT have child info, then it's a special option: // - label_\d+ (level label) // - none ("") // - create_new_item ("") // Only when it's a level label, we have to add a class to this option. if (!isset($element['#childinfo'][$key])) { $class = (preg_match('/label_\d+/', $key)) ? ' level-label' : ''; } else { $class = ($element['#childinfo'][$key] == 0) ? 'has-no-children' : 'has-children'; } $options .= ''; } return $options; }