options_element.inc

  1. cis7 sites/all/modules/ulmus/options_element/options_element.inc
  2. cle7 sites/all/modules/ulmus/options_element/options_element.inc
  3. ecd7 sites/all/modules/ulmus/options_element/options_element.inc
  4. elmsmedia7 sites/all/modules/ulmus/options_element/options_element.inc
  5. harmony7 sites/all/modules/ulmus/options_element/options_element.inc
  6. icor7 sites/all/modules/ulmus/options_element/options_element.inc
  7. meedjum_blog7 sites/all/modules/ulmus/options_element/options_element.inc
  8. mooc7 sites/all/modules/ulmus/options_element/options_element.inc

All logic for options_element form elements.

Functions

Namesort descending Description
theme_options Theme an options element.
_form_options_expand Logic function for form_options_expand(). Do not call directly.
_form_options_from_text Logic function for form_options_from_text(). Do not call directly.
_form_options_search Recursive function for finding default value keys. Matches on keys or values.
_form_options_to_text Logic function for form_options_to_text(). Do not call directly.
_form_options_validate Logic function for form_options_validate(). Do not call directly.
_form_type_options_value Logic function for form_type_options_value(). Do not call directly.

File

sites/all/modules/ulmus/options_element/options_element.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * All logic for options_element form elements.
  5. */
  6. /**
  7. * Theme an options element.
  8. */
  9. function theme_options($variables) {
  10. $element = $variables['element'];
  11. element_set_attributes($element, array('id'));
  12. _form_set_class($element, array('form-options'));
  13. $classes = &$element['#attributes']['class'];
  14. $classes[] = 'options-key-type-'. $element['#key_type'];
  15. if ($element['#key_type_toggled']) {
  16. $classes[] = 'options-key-custom';
  17. }
  18. if (isset($element['#optgroups']) && $element['#optgroups']) {
  19. $classes[] = 'options-optgroups';
  20. }
  21. if (isset($element['#multiple']) && $element['#multiple']) {
  22. $classes[] = 'options-multiple';
  23. }
  24. // Replace the error class from wrapper div, which doesn't display well with
  25. // complex elements like Options Element.
  26. if ($key = array_search('error', $classes, TRUE)) {
  27. $classes[$key] = 'options-error';
  28. }
  29. $options = '';
  30. $options .= drupal_render($element['options_field']);
  31. if (isset($element['default_value_field'])) {
  32. $options .= drupal_render($element['default_value_field']);
  33. }
  34. if (isset($element['default_value_pattern'])) {
  35. $options .= drupal_render($element['default_value_pattern']);
  36. }
  37. $settings = '';
  38. if (isset($element['custom_keys'])) {
  39. $settings .= drupal_render($element['custom_keys']);
  40. }
  41. if (isset($element['multiple'])) {
  42. $settings .= drupal_render($element['multiple']);
  43. }
  44. if (isset($element['option_settings'])) {
  45. $settings .= drupal_render($element['option_settings']);
  46. }
  47. $output = '';
  48. $output .= '<div' . drupal_attributes($element['#attributes']) . '>';
  49. $output .= theme('container', array('element' => array(
  50. '#title' => t('Options'),
  51. '#collapsible' => FALSE,
  52. '#children' => $options,
  53. '#attributes' => array('class' => array('options')),
  54. )));
  55. if (!empty($settings)) {
  56. $output .= theme('fieldset', array('element' => array(
  57. '#title' => t('Option settings'),
  58. '#collapsible' => FALSE,
  59. '#children' => $settings,
  60. '#attributes' => array('class' => array('option-settings')),
  61. )));
  62. }
  63. $output .= '</div>';
  64. return $output;
  65. }
  66. /**
  67. * Logic function for form_options_expand(). Do not call directly.
  68. *
  69. * @see form_options_expand()
  70. */
  71. function _form_options_expand($element) {
  72. $element['#options'] = isset($element['#options']) ? $element['#options'] : array();
  73. $element['#multiple'] = isset($element['#multiple']) ? $element['#multiple'] : FALSE;
  74. $element['#tree'] = TRUE;
  75. $element['#theme'] = 'options';
  76. $path = drupal_get_path('module', 'options_element');
  77. $element['#attached']['js'] = array(
  78. 'misc/tabledrag.js' => array('group' => JS_LIBRARY, 'weight' => 5),
  79. 'misc/jquery.cookie.js' => array('group' => JS_LIBRARY),
  80. $path . '/options_element.js',
  81. );
  82. $element['#attached']['css'] = array(
  83. $path . '/options_element.css',
  84. );
  85. // Add the key type toggle checkbox.
  86. if (!isset($element['custom_keys']) && $element['#key_type'] != 'custom' && !empty($element['#key_type_toggle'])) {
  87. $element['custom_keys'] = array(
  88. '#title' => is_string($element['#key_type_toggle']) ? $element['#key_type_toggle'] : t('Customize keys'),
  89. '#type' => 'checkbox',
  90. '#default_value' => $element['#key_type_toggled'],
  91. '#attributes' => array('class' => array('key-type-toggle')),
  92. '#description' => t('Customizing the keys will allow you to save one value internally while showing a different option to the user.'),
  93. );
  94. }
  95. // Add the multiple value toggle checkbox.
  96. if (!isset($element['multiple']) && !empty($element['#multiple_toggle'])) {
  97. $element['multiple'] = array(
  98. '#title' => is_string($element['#multiple_toggle']) ? $element['#multiple_toggle'] : t('Allow multiple values'),
  99. '#type' => 'checkbox',
  100. '#default_value' => !empty($element['#multiple']),
  101. '#attributes' => array('class' => array('multiple-toggle')),
  102. '#description' => t('Multiple values will let users select multiple items in this list.'),
  103. );
  104. }
  105. // If the element had a custom interface for toggling whether or not multiple
  106. // values are accepted, make sure that form_type_options_value() knows to use
  107. // it.
  108. if (isset($element['multiple']) && empty($element['#multiple_toggle'])) {
  109. $element['#multiple_toggle'] = TRUE;
  110. }
  111. // Add the main textarea for adding options.
  112. if (!isset($element['options'])) {
  113. $element['options_field'] = array(
  114. '#type' => 'textarea',
  115. '#resizable' => TRUE,
  116. '#cols' => 60,
  117. '#rows' => 5,
  118. '#required' => isset($element['#required']) ? $element['#required'] : FALSE,
  119. '#description' => t('List options one option per line.'),
  120. '#attributes' => $element['#options_readonly'] ? array('readonly' => 'readonly') : array(),
  121. '#wysiwyg' => FALSE, // Prevent CKeditor from trying to hijack.
  122. );
  123. // If validation fails, reload the user's text even if it's not valid.
  124. if (isset($element['#value']['options_text'])) {
  125. $element['options_field']['#value'] = $element['#value']['options_text'];
  126. }
  127. // Most of the time, we'll be converting the options array into the text.
  128. else {
  129. $element['options_field']['#value'] = isset($element['#options']) ? form_options_to_text($element['#options'], $element['#key_type']) : '';
  130. }
  131. if ($element['#key_type'] == 'mixed' || $element['#key_type'] == 'numeric' || $element['#key_type'] == 'custom') {
  132. $element['options_field']['#description'] .= ' ' . t('Key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>.');
  133. }
  134. elseif ($element['#key_type_toggle']) {
  135. $element['options_field']['#description'] .= ' ' . t('If the %toggle field is checked, key-value pairs may be specified by separating each option with pipes, such as <em>key|value</em>.', array('%toggle' => $element['custom_keys']['#title']));
  136. }
  137. if ($element['#key_type'] == 'numeric') {
  138. $element['options_field']['#description'] .= ' ' . t('This field requires all specified keys to be integers.');
  139. }
  140. }
  141. // Add the field for storing default values.
  142. if ($element['#default_value_allowed'] && !isset($element['default_value_field'])) {
  143. $element['default_value_field'] = array(
  144. '#title' => t('Default value'),
  145. '#type' => 'textfield',
  146. '#size' => 60,
  147. '#maxlength' => 1024,
  148. '#value' => isset($element['#default_value']) ? ($element['#multiple'] ? implode(', ', (array) $element['#default_value']) : $element['#default_value']) : '',
  149. '#description' => t('Specify the keys that should be selected by default.'),
  150. );
  151. if ($element['#multiple']) {
  152. $element['default_value_field']['#description'] .= ' ' . t('Multiple default values may be specified by separating keys with commas.');
  153. }
  154. }
  155. // Add the field for storing a default value pattern.
  156. if ($element['#default_value_pattern']) {
  157. $element['default_value_pattern'] = array(
  158. '#type' => 'hidden',
  159. '#value' => $element['#default_value_pattern'],
  160. '#attributes' => array('class' => array('default-value-pattern')),
  161. );
  162. }
  163. // Remove properties that will confuse the FAPI.
  164. unset($element['#options']);
  165. return $element;
  166. }
  167. /**
  168. * Logic function for form_options_validate(). Do not call directly.
  169. *
  170. * @see form_options_validate()
  171. */
  172. function _form_options_validate($element, &$form_state) {
  173. // Even though we already have the converted options in #value['options'], run
  174. // the conversion again to check for duplicates in the user-defined list.
  175. $duplicates = array();
  176. $options = form_options_from_text($element['#value']['options_text'], $element['#key_type'], empty($element['#optgroups']), $duplicates);
  177. // Check if a key is used multiple times.
  178. if (count($duplicates) == 1) {
  179. form_error($element, t('The key %key has been used multiple times. Each key must be unique to display properly.', array('%key' => reset($duplicates))));
  180. }
  181. elseif (!empty($duplicates)) {
  182. array_walk($duplicates, 'check_plain');
  183. $duplicate_list = theme('item_list', array('items' => $duplicates));
  184. form_error($element, t('The following keys have been used multiple times. Each key must be unique to display properly.') . $duplicate_list);
  185. }
  186. // Add the list of duplicates to the page so that we can highlight the fields.
  187. if (!empty($duplicates)) {
  188. drupal_add_js(array('optionsElement' => array('errors' => drupal_map_assoc($duplicates))), 'setting');
  189. }
  190. // Check if no options are specified.
  191. if (empty($options) && $element['#required']) {
  192. form_error($element, t('At least one option must be specified.'));
  193. }
  194. // Check for numeric keys if needed.
  195. if ($element['#key_type'] == 'numeric') {
  196. foreach ($options as $key => $value) {
  197. if (!is_int($key)) {
  198. form_error($element, t('The keys for the %title field must be integers.', array('%title' => $element['#title'])));
  199. break;
  200. }
  201. }
  202. }
  203. // Check that the limit of options has not been exceeded.
  204. if (!empty($element['#limit'])) {
  205. $count = 0;
  206. foreach ($options as $value) {
  207. if (is_array($value)) {
  208. $count += count($value);
  209. }
  210. else {
  211. $count++;
  212. }
  213. }
  214. if ($count > $element['#limit']) {
  215. form_error($element, t('The %title field supports a maximum of @count options. Please reduce the number of options.', array('%title' => $element['#title'], '@count' => $element['#limit'])));
  216. }
  217. }
  218. }
  219. /**
  220. * Logic function for form_type_options_value(). Do not call directly.
  221. *
  222. * @see form_type_options_value()
  223. */
  224. function _form_type_options_value(&$element, $edit = FALSE) {
  225. if ($edit === FALSE) {
  226. return array(
  227. 'options' => isset($element['#options']) ? $element['#options'] : array(),
  228. 'default_value' => isset($element['#default_value']) ? $element['#default_value'] : '',
  229. );
  230. }
  231. else {
  232. // Convert text to an array of options.
  233. $duplicates = array();
  234. $options = form_options_from_text($edit['options_field'], $element['#key_type'], empty($element['#optgroups']), $duplicates);
  235. // Convert default value.
  236. if (isset($edit['default_value_field'])) {
  237. // If the element supports toggling whether or not it will accept
  238. // multiple values, use the value that was passed in via $edit (keeping
  239. // in mind that this value may not be set, if a checkbox was used to
  240. // configure it). Otherwise, use the current setting stored with the
  241. // element itself.
  242. $multiple = !empty($element['#multiple_toggle']) ? !empty($edit['multiple']) : !empty($element['#multiple']);
  243. if ($multiple) {
  244. $default_value = array();
  245. $default_items = explode(',', $edit['default_value_field']);
  246. foreach ($default_items as $key) {
  247. $key = trim($key);
  248. $value = _form_options_search($key, $options, $element['#default_value_pattern']);
  249. if (!is_null($value)) {
  250. $default_value[] = $value;
  251. }
  252. }
  253. }
  254. else {
  255. $default_value = _form_options_search(trim($edit['default_value_field']), $options, $element['#default_value_pattern']);
  256. }
  257. }
  258. else {
  259. $default_value = NULL;
  260. }
  261. $return = array(
  262. 'options' => $options,
  263. 'default_value' => $default_value,
  264. 'options_text' => $edit['options_field'],
  265. );
  266. if (isset($edit['default_value_field'])) {
  267. $return['default_value_text'] = $edit['default_value_field'];
  268. }
  269. return $return;
  270. }
  271. }
  272. /**
  273. * Logic function for form_options_to_text(). Do not call directly.
  274. *
  275. * @see form_options_to_text()
  276. */
  277. function _form_options_to_text($options, $key_type) {
  278. $output = '';
  279. $previous_key = false;
  280. foreach ($options as $key => $value) {
  281. // Convert groups.
  282. if (is_array($value)) {
  283. $output .= '<' . $key . '>' . "\n";
  284. foreach ($value as $subkey => $subvalue) {
  285. $output .= (($key_type == 'mixed' || $key_type == 'numeric' || $key_type == 'custom') ? $subkey . '|' : '') . $subvalue . "\n";
  286. }
  287. $previous_key = $key;
  288. }
  289. // Typical key|value pairs.
  290. else {
  291. // Exit out of any groups.
  292. if (isset($options[$previous_key]) && is_array($options[$previous_key])) {
  293. $output .= "<>\n";
  294. }
  295. // Skip empty rows.
  296. if ($options[$key] !== '') {
  297. if ($key_type == 'mixed' || $key_type == 'numeric' || $key_type == 'custom') {
  298. $output .= $key . '|' . $value . "\n";
  299. }
  300. else {
  301. $output .= $value . "\n";
  302. }
  303. }
  304. $previous_key = $key;
  305. }
  306. }
  307. return $output;
  308. }
  309. /**
  310. * Logic function for form_options_from_text(). Do not call directly.
  311. *
  312. * @see form_options_from_text()
  313. */
  314. function _form_options_from_text($text, $key_type, $flat = FALSE, &$duplicates = array()) {
  315. $keys = array();
  316. $items = array();
  317. $rows = array_filter(explode("\n", trim($text)), 'strlen');
  318. $group = FALSE;
  319. foreach ($rows as $row) {
  320. $row = trim($row);
  321. $matches = array();
  322. // Check for a simple empty row.
  323. if (!strlen($row)) {
  324. continue;
  325. }
  326. // Check if this row is a group.
  327. elseif (!$flat && preg_match('/^\<((([^>|]*)\|)?([^>]*))\>$/', $row, $matches)) {
  328. if ($matches[1] === '') {
  329. $group = FALSE;
  330. }
  331. else {
  332. $group = $matches[4] ? $matches[4] : '';
  333. $keys[] = $group;
  334. }
  335. }
  336. // Check if this row is a key|value pair.
  337. elseif (($key_type == 'mixed' || $key_type == 'custom' || $key_type == 'numeric') && preg_match('/^([^|]+)\|(.*)$/', $row, $matches)) {
  338. $key = $matches[1];
  339. $value = $matches[2];
  340. $keys[] = $key;
  341. $items[] = array(
  342. 'key' => $key,
  343. 'value' => $value,
  344. 'group' => $group,
  345. );
  346. }
  347. // Set this this row as a straight value.
  348. else {
  349. $items[] = array(
  350. 'key' => NULL,
  351. 'value' => $row,
  352. 'group' => $group,
  353. );
  354. }
  355. }
  356. // Expand the list into a nested array, assign keys and check duplicates.
  357. $options = array();
  358. $new_key = 1;
  359. foreach ($items as $item) {
  360. $int_key = $item['key'] * 1;
  361. if (is_int($int_key)) {
  362. $new_key = max($int_key, $new_key);
  363. }
  364. }
  365. foreach ($items as $item) {
  366. // Assign a key if needed.
  367. if ($key_type == 'none') {
  368. $item['key'] = $new_key++;
  369. }
  370. elseif (!isset($item['key'])) {
  371. while (in_array($new_key, $keys)) {
  372. $new_key++;
  373. }
  374. $keys[] = $new_key;
  375. $item['key'] = $new_key;
  376. }
  377. if ($item['group']) {
  378. if (isset($options[$item['group']][$item['key']])) {
  379. $duplicates[] = $item['key'];
  380. }
  381. $options[$item['group']][$item['key']] = $item['value'];
  382. }
  383. else {
  384. if (isset($options[$item['key']])) {
  385. $duplicates[] = $item['key'];
  386. }
  387. $options[$item['key']] = $item['value'];
  388. }
  389. }
  390. return $options;
  391. }
  392. /**
  393. * Recursive function for finding default value keys. Matches on keys or values.
  394. */
  395. function _form_options_search($needle, $haystack, $include_pattern) {
  396. if (isset($haystack[$needle])) {
  397. return $needle;
  398. }
  399. elseif ($include_pattern && preg_match('/' . $include_pattern . '/', $needle)) {
  400. return $needle;
  401. }
  402. foreach ($haystack as $key => $value) {
  403. if (is_array($value)) {
  404. return _form_options_search($needle, $value, $include_pattern);
  405. }
  406. elseif ($value == $needle) {
  407. return $key;
  408. }
  409. }
  410. }