\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 array $variables * An associative array containing the properties of the element. * @return string * A themed HTML string representing the form element. */ function theme_hierarchical_select($variables) { $element = $variables['element']; $output = ''; // Update $element['#attributes']['class']. if (!isset($element['#attributes']['class'])) { $element['#attributes']['class'] = array(); } $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'] = array_merge($element['#attributes']['class'], $classes); $element['#attributes']['id'] = "hierarchical-select-$hsid-wrapper"; $element['#id'] = "hierarchical-select-$hsid-wrapper"; // This ensures the label's for attribute is correct. return '
' . drupal_render_children($element) . '
'; } /** * Format the container for all selects in the hierarchical select. * * @param array $variables * An associative array containing the properties of the element. * @return string * A themed HTML string representing the form element. */ function theme_hierarchical_select_selects_container($variables) { $element = $variables['element']; $output = ''; $output .= '
'; $output .= drupal_render_children($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 array $variables * An associative array containing the properties of the element. * @return string * A themed HTML string representing the form element. */ function theme_hierarchical_select_select($variables) { $element = $variables['element']; element_set_attributes($element, array('id', 'name', 'size')); _form_set_class($element, array('form-select')); return '' . _hierarchical_select_options($element) . ''; } /** * Format an item separator (for use in a lineage). */ function theme_hierarchical_select_item_separator($variables) { $output = ''; $output .= ''; $output .= '›'; $output .= ''; return $output; } /** * 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 array $variables * A special option. * @return string * A textually indicated special option. */ function theme_hierarchical_select_special_option($variables) { $option = $variables['option']; return '<' . $option . '>'; } /** * Forms API theming callback for the dropbox. Renders the dropbox as a table. * * @param array $variables * An element for which the #theme property was set to this function. * @return string * A themed HTML string. */ function theme_hierarchical_select_dropbox_table($variables) { $element = $variables['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']["lineage-$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. /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function theme_hierarchical_select_common_config_form_level_labels($variables) { $form = $variables['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', array('header' => $header, 'rows' => $rows, 'attributes' => 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_children($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. /** * @todo Please document this function. * @see http://drupal.org/node/1354 */ function theme_hierarchical_select_common_config_form_editability($variables) { $form = $variables['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', array('header' => $header, 'rows' => $rows, 'attributes' => array('style' => 'width: auto;'), 'caption' => '' . 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_children($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($variables) { $selection = $variables['selection']; $config = $variables['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 = isset($element['#value']) && 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; }