theme.inc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <?php
  2. /**
  3. * @file
  4. * All theme functions for the Hierarchical Select module.
  5. */
  6. /**
  7. * @ingroup themeable
  8. * @{
  9. */
  10. /**
  11. * Return a themed Hierarchical Select form element.
  12. *
  13. * @param array $variables
  14. * An associative array containing the properties of the element.
  15. * Properties used: title, description, id, required
  16. *
  17. * @return string
  18. * A string representing the form element.
  19. *
  20. * @ingroup themeable
  21. */
  22. function theme_hierarchical_select_form_element($variables) {
  23. $element = $variables['element'];
  24. $value = $variables['value'];
  25. $output = '<div class="form-item hierarchical-select-wrapper-wrapper"';
  26. if (!empty($element['#id'])) {
  27. $output .= ' id="' . $element['#id'] . '-wrapper"';
  28. }
  29. $output .= ">\n";
  30. $required = !empty($element['#required']) ? '<span class="form-required" title="' . t('This field is required.') . '">*</span>' : '';
  31. if (!empty($element['#title'])) {
  32. $title = $element['#title'];
  33. if (!empty($element['#id'])) {
  34. $output .= ' <label for="' . $element['#id'] . '">' . t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) . "</label>\n";
  35. }
  36. else {
  37. $output .= ' <label>' . t('!title: !required', array('!title' => filter_xss_admin($title), '!required' => $required)) . "</label>\n";
  38. }
  39. }
  40. $output .= " $value\n";
  41. if (!empty($element['#description'])) {
  42. $output .= ' <div class="description">' . $element['#description'] . "</div>\n";
  43. }
  44. $output .= "</div>\n";
  45. return $output;
  46. }
  47. /**
  48. * Format a hierarchical select.
  49. *
  50. * @param array $variables
  51. * An associative array containing the properties of the element.
  52. * @return string
  53. * A themed HTML string representing the form element.
  54. */
  55. function theme_hierarchical_select($variables) {
  56. $element = $variables['element'];
  57. $output = '';
  58. // Update $element['#attributes']['class'].
  59. if (!isset($element['#attributes']['class'])) {
  60. $element['#attributes']['class'] = array();
  61. }
  62. $hsid = $element['hsid']['#value'];
  63. $level_labels_style = variable_get('hierarchical_select_level_labels_style', 'none');
  64. $classes = array(
  65. 'hierarchical-select-wrapper',
  66. "hierarchical-select-level-labels-style-$level_labels_style",
  67. // Classes that make it possible to override the styling of specific
  68. // instances of Hierarchical Select, based on either the ID of the form
  69. // element or the config that it uses.
  70. 'hierarchical-select-wrapper-for-name-' . $element['#id'],
  71. (isset($element['#config']['config_id'])) ? 'hierarchical-select-wrapper-for-config-' . $element['#config']['config_id'] : NULL,
  72. );
  73. $element['#attributes']['class'] = array_merge($element['#attributes']['class'], $classes);
  74. $element['#attributes']['id'] = "hierarchical-select-$hsid-wrapper";
  75. $element['#id'] = "hierarchical-select-$hsid-wrapper"; // This ensures the label's for attribute is correct.
  76. return '<div ' . drupal_attributes($element['#attributes']) . '>' . drupal_render_children($element) . '</div>';
  77. }
  78. /**
  79. * Format the container for all selects in the hierarchical select.
  80. *
  81. * @param array $variables
  82. * An associative array containing the properties of the element.
  83. * @return string
  84. * A themed HTML string representing the form element.
  85. */
  86. function theme_hierarchical_select_selects_container($variables) {
  87. $element = $variables['element'];
  88. $output = '';
  89. $output .= '<div class="hierarchical-select clearfix">';
  90. $output .= drupal_render_children($element);
  91. $output .= '</div>';
  92. return $output;
  93. }
  94. /**
  95. * Format a select in the .hierarchial-select div: prevent it from being
  96. * wrapped in a div. This simplifies the CSS and JS code.
  97. *
  98. * @param array $variables
  99. * An associative array containing the properties of the element.
  100. * @return string
  101. * A themed HTML string representing the form element.
  102. */
  103. function theme_hierarchical_select_select($variables) {
  104. $element = $variables['element'];
  105. element_set_attributes($element, array('id', 'name', 'size'));
  106. _form_set_class($element, array('form-select'));
  107. return '<select' . drupal_attributes($element['#attributes']) . '>' . _hierarchical_select_options($element) . '</select>';
  108. }
  109. /**
  110. * Format an item separator (for use in a lineage).
  111. */
  112. function theme_hierarchical_select_item_separator($variables) {
  113. $output = '';
  114. $output .= '<span class="hierarchical-select-item-separator">';
  115. $output .= '›';
  116. $output .= '</span>';
  117. return $output;
  118. }
  119. /**
  120. * Format a special option in a Hierarchical Select select. For example the
  121. * "none" option or the "create new item" option. This theme function allows
  122. * you to change how a special option is indicated textually.
  123. *
  124. * @param array $variables
  125. * A special option.
  126. * @return string
  127. * A textually indicated special option.
  128. */
  129. function theme_hierarchical_select_special_option($variables) {
  130. $option = $variables['option'];
  131. return '<' . $option . '>';
  132. }
  133. /**
  134. * Forms API theming callback for the dropbox. Renders the dropbox as a table.
  135. *
  136. * @param array $variables
  137. * An element for which the #theme property was set to this function.
  138. * @return string
  139. * A themed HTML string.
  140. */
  141. function theme_hierarchical_select_dropbox_table($variables) {
  142. $element = $variables['element'];
  143. $output = '';
  144. $class = 'dropbox';
  145. if (form_get_error($element) === '') {
  146. $class .= ' error';
  147. }
  148. $title = $element['title']['#value'];
  149. $separator = $element['separator']['#value'];
  150. $is_empty = $element['is_empty']['#value'];
  151. $separator_html = '<span class="hierarchical-select-item-separator">' . $separator . '</span>';
  152. $output .= '<div class="' . $class . '">';
  153. $output .= '<table>';
  154. $output .= '<caption class="dropbox-title">' . $title . '</caption>';
  155. $output .= '<tbody>';
  156. if (!$is_empty) {
  157. // Each lineage in the dropbox corresponds to an entry in the dropbox table.
  158. $lineage_count = count(element_children($element['lineages']));
  159. for ($x = 0; $x < $lineage_count; $x++) {
  160. $db_entry = $element['lineages']["lineage-$x"];
  161. $zebra = $db_entry['#zebra'];
  162. $first = $db_entry['#first'];
  163. $last = $db_entry['#last'];
  164. // The deepest level is the number of child levels minus one. This "one"
  165. // is the element for the "Remove" checkbox.
  166. $deepest_level = count(element_children($db_entry)) - 1;
  167. $output .= '<tr class="dropbox-entry ' . $first . ' ' . $last . ' ' . $zebra . '">';
  168. $output .= '<td>';
  169. // Each item in a lineage is separated by the separator string.
  170. for ($depth = 0; $depth < $deepest_level; $depth++) {
  171. $output .= drupal_render($db_entry[$depth]);
  172. if ($depth < $deepest_level - 1) {
  173. $output .= $separator_html;
  174. }
  175. }
  176. $output .= '</td>';
  177. $output .= '<td class="dropbox-remove">' . drupal_render($db_entry['remove']) . '</td>';
  178. $output .= '</tr>';
  179. }
  180. }
  181. else {
  182. $output .= '<tr class="dropbox-entry first last dropbox-is-empty"><td>';
  183. $output .= t('Nothing has been selected.');
  184. $output .= '</td></tr>';
  185. }
  186. $output .= '</tbody>';
  187. $output .= '</table>';
  188. $output .= '</div>';
  189. return $output;
  190. }
  191. /**
  192. * Themeing function to render the level_labels settings as a table.
  193. */
  194. // TODO: rename $form to $element for consistency (and update hook_theme() after that), make the comment consistent.
  195. /**
  196. * @todo Please document this function.
  197. * @see http://drupal.org/node/1354
  198. */
  199. function theme_hierarchical_select_common_config_form_level_labels($variables) {
  200. $form = $variables['form'];
  201. // Recover the stored strings.
  202. $strings = $form['#strings'];
  203. $output = '';
  204. $header = array(t('Level'), t('Label'));
  205. $rows = array();
  206. $output .= drupal_render($form['status']);
  207. $output .= '<div class="level-labels-settings">';
  208. if (isset($form['labels']) && count(element_children($form['labels']))) {
  209. foreach (element_children($form['labels']) as $depth) {
  210. $row = array();
  211. $row[]['data'] = ($depth == 0) ? t('Root level') : t('Sublevel !depth', array('!depth' => $depth));
  212. $row[]['data'] = drupal_render($form['labels'][$depth]);
  213. $rows[] = $row;
  214. }
  215. // Render the table.
  216. $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('style' => 'width: auto;')));
  217. }
  218. else {
  219. // No levels exist yet in the hierarchy!
  220. $output .= '<p><strong>';
  221. $output .= t('There are no levels yet in this !hierarchy!', array('!hierarchy' => $strings['hierarchy']));
  222. $output .= '</strong></p>';
  223. }
  224. $output .= '</div>';
  225. // Render the remaining form items.
  226. $output .= drupal_render_children($form);
  227. return $output;
  228. }
  229. /**
  230. * Themeing function to render the per-level editability settings as a table,
  231. * (these are the item_types and allowed_levels settings).
  232. */
  233. // TODO: rename $form to $element for consistency (and update hook_theme() after that), make the comment consistent.
  234. /**
  235. * @todo Please document this function.
  236. * @see http://drupal.org/node/1354
  237. */
  238. function theme_hierarchical_select_common_config_form_editability($variables) {
  239. $form = $variables['form'];
  240. // Recover the stored strings.
  241. $strings = $form['#strings'];
  242. $output = '';
  243. $header = array(t('Level'), t('Allow'), t('!item_type', array('!item_type' => drupal_ucfirst($strings['item_type']))));
  244. $rows = array();
  245. $output .= drupal_render($form['status']);
  246. $output .= '<div class="editability-per-level-settings">';
  247. if (isset($form['item_types']) && count(element_children($form['item_types']))) {
  248. foreach (element_children($form['item_types']) as $depth) {
  249. $row = array();
  250. $row[]['data'] = ($depth == 0) ? t('Root level') : t('Sublevel !depth', array('!depth' => $depth));
  251. $row[]['data'] = drupal_render($form['allowed_levels'][$depth]);
  252. $row[]['data'] = drupal_render($form['item_types'][$depth]);
  253. $rows[] = $row;
  254. }
  255. // Render the table and description.
  256. $output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('style' => 'width: auto;'), 'caption' => '<em>' . t('Per-level settings for creating new !items.', array('!items' => $strings['items']))));
  257. $output .= '<div class="description">';
  258. $output .= t(
  259. 'The %item_type you enter for each level is what will be used in
  260. each level to replace a "&lt;create new item&gt;" option with a
  261. "&lt;create new %item_type&gt;" option, which is often more
  262. intuitive.',
  263. array(
  264. '%item_type' => $strings['item_type'],
  265. )
  266. );
  267. $output .= '</div>';
  268. }
  269. else {
  270. // No levels exist yet in the hierarchy!
  271. $output .= '<p><strong>';
  272. $output .= t('There are no levels yet in this !hierarchy!', array('!hierarchy' => $strings['hierarchy']));
  273. $output .= '</strong></p>';
  274. }
  275. $output .= '</div>';
  276. // Render the remaining form items.
  277. $output .= drupal_render_children($form);
  278. return $output;
  279. }
  280. /**
  281. * Themeing function to render a selection (of items) according to a given
  282. * Hierarchical Select configuration as one or more lineages.
  283. *
  284. * @param $selection
  285. * A selection of items of a hierarchy.
  286. * @param $config
  287. * A config array with at least the following settings:
  288. * - module
  289. * - save_lineage
  290. * - params
  291. */
  292. function theme_hierarchical_select_selection_as_lineages($variables) {
  293. $selection = $variables['selection'];
  294. $config = $variables['config'];
  295. $output = '';
  296. $selection = (!is_array($selection)) ? array($selection) : $selection;
  297. // Generate a dropbox out of the selection. This will automatically
  298. // calculate all lineages for us.
  299. $selection = array_keys($selection);
  300. $dropbox = _hierarchical_select_dropbox_generate($config, $selection);
  301. // Actual formatting.
  302. foreach ($dropbox->lineages as $id => $lineage) {
  303. if ($id > 0) {
  304. $output .= '<br />';
  305. }
  306. $items = array();
  307. foreach ($lineage as $level => $item) {
  308. $items[] = $item['label'];
  309. }
  310. $output .= implode('<span class="hierarchical-select-item-separator">›</span>', $items);
  311. }
  312. // Add the CSS.
  313. drupal_add_css(drupal_get_path('module', 'hierarchical_select') . '/hierarchical_select.css');
  314. return $output;
  315. }
  316. /**
  317. * @} End of "ingroup themeable".
  318. */
  319. //----------------------------------------------------------------------------
  320. // Private functions.
  321. /**
  322. * This is an altered clone of form_select_options(). The reason: I need to be
  323. * able to set a class on an option element if it contains a level label, to
  324. * allow for level label styles.
  325. * TODO: rename to _hierarchical_select_select_options().
  326. */
  327. function _hierarchical_select_options($element) {
  328. if (!isset($choices)) {
  329. $choices = $element['#options'];
  330. }
  331. // array_key_exists() accommodates the rare event where $element['#value'] is NULL.
  332. // isset() fails in this situation.
  333. $value_valid = isset($element['#value']) || array_key_exists('#value', $element);
  334. $value_is_array = isset($element['#value']) && is_array($element['#value']);
  335. $options = '';
  336. foreach ($choices as $key => $choice) {
  337. $key = (string) $key;
  338. if ($value_valid && (!$value_is_array && (string) $element['#value'] === $key || ($value_is_array && in_array($key, $element['#value'])))) {
  339. $selected = ' selected="selected"';
  340. }
  341. else {
  342. $selected = '';
  343. }
  344. // If an option DOES NOT have child info, then it's a special option:
  345. // - label_\d+ (level label)
  346. // - none ("<none>")
  347. // - create_new_item ("<create new item>")
  348. // Only when it's a level label, we have to add a class to this option.
  349. if (!isset($element['#childinfo'][$key])) {
  350. $class = (preg_match('/label_\d+/', $key)) ? ' level-label' : '';
  351. }
  352. else {
  353. $class = ($element['#childinfo'][$key] == 0) ? 'has-no-children' : 'has-children';
  354. }
  355. $options .= '<option value="' . check_plain($key) . '" class="' . $class . '"' . $selected . '>' . check_plain($choice) . '</option>';
  356. }
  357. return $options;
  358. }