better_exposed_filters.theme

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

Provides theming functions to display exposed forms using different interfaces.

Functions

Namesort descending Description
bef_checkbox Build a BEF checkbox.
bef_replace_query_string_arg Replaces/adds a given query string argument to the current URL.
theme_secondary_exposed_elements Themes some exposed form elements in a collapsible fieldset.
theme_select_as_checkboxes Themes a select element as a set of checkboxes.
theme_select_as_checkboxes_fieldset Themes a select element as checkboxes enclosed in a collapsible fieldset.
theme_select_as_hidden Themes a select element as a series of hidden fields.
theme_select_as_links Themes a select drop-down as a collection of links.
theme_select_as_radios Themes a select drop-down as a collection of radio buttons.
theme_select_as_radios_fieldset Themes a select element as radio buttons enclosed in a collapsible fieldset.
theme_select_as_tree Themes a taxonomy-based exposed filter as a nested unordered list.

File

sites/all/modules/ulmus/better_exposed_filters/better_exposed_filters.theme
View source
  1. <?php
  2. /**
  3. * @file
  4. * Provides theming functions to display exposed forms using different
  5. * interfaces.
  6. */
  7. /**
  8. * Themes a select element as checkboxes enclosed in a collapsible fieldset.
  9. *
  10. * @param array $vars
  11. * An array of arrays, the 'element' item holds the properties of the element
  12. *
  13. * @return string
  14. * HTML representing the form element.
  15. */
  16. function theme_select_as_checkboxes_fieldset($vars) {
  17. // Merge incoming element with some default values. Prevents a lot of this.
  18. // $foo = isset($bar) ? $bar : $bar_default;
  19. $element = array_merge(
  20. array(
  21. '#bef_title' => '',
  22. '#bef_description' => '',
  23. '#bef_operator' => array(),
  24. ),
  25. $vars['element']
  26. );
  27. $fieldset = array(
  28. '#title' => $element['#bef_title'],
  29. '#description' => $element['#bef_description'],
  30. '#attributes' => array(
  31. 'class' => array(
  32. 'bef-select-as-checkboxes-fieldset',
  33. 'collapsible',
  34. ),
  35. ),
  36. );
  37. if (empty($element['#value'])) {
  38. // Using the FAPI #collapsible and #collapsed attribute doesn't work here
  39. // TODO: not sure why...
  40. $fieldset['#attributes']['class'][] = 'collapsed';
  41. }
  42. // We rendered the description as part of the fieldset element, don't render
  43. // it again along with the checkboxes.
  44. unset($element['#bef_description']);
  45. $children = '';
  46. if (!empty($element['#bef_operator'])) {
  47. // Put an exposed operator inside the fieldset.
  48. $children = drupal_render($element['#bef_operator']);
  49. }
  50. // Render the checkboxes.
  51. $children .= theme('select_as_checkboxes', array('element' => $element));
  52. $fieldset['#children'] = $children;
  53. return theme('fieldset', array('element' => $fieldset));
  54. }
  55. /**
  56. * Themes a select element as a set of checkboxes.
  57. *
  58. * @see http://api.drupal.org/api/function/theme_select/7
  59. *
  60. * @param array $vars
  61. * An array of arrays, the 'element' item holds the properties of the element.
  62. *
  63. * @return string
  64. * HTML representing the form element.
  65. */
  66. function theme_select_as_checkboxes($vars) {
  67. $element = $vars['element'];
  68. if (!empty($element['#bef_nested'])) {
  69. if (empty($element['#attributes']['class'])) {
  70. $element['#attributes']['class'] = array();
  71. }
  72. $element['#attributes']['class'][] = 'form-checkboxes';
  73. return theme('select_as_tree', array('element' => $element));
  74. }
  75. // The selected keys from #options.
  76. $selected_options = empty($element['#value']) ? $element['#default_value'] : $element['#value'];
  77. if (!is_array($selected_options)) {
  78. $selected_options = array($selected_options);
  79. }
  80. // Grab exposed filter description. We'll put it under the label where it
  81. // makes more sense.
  82. $description = '';
  83. if (!empty($element['#bef_description'])) {
  84. $description = '<div class="description">' . $element['#bef_description'] . '</div>';
  85. }
  86. $output = '<div class="bef-checkboxes">';
  87. foreach ($element['#options'] as $option => $elem) {
  88. if ('All' === $option) {
  89. // TODO: 'All' text is customizable in Views.
  90. // No need for an 'All' option -- either unchecking or checking all the
  91. // checkboxes is equivalent.
  92. continue;
  93. }
  94. // Check for Taxonomy-based filters.
  95. if (is_object($elem)) {
  96. $slice = array_slice($elem->option, 0, 1, TRUE);
  97. list($option, $elem) = each($slice);
  98. }
  99. // Check for optgroups. Put subelements in the $element_set array and add
  100. // a group heading. Otherwise, just add the element to the set.
  101. $element_set = array();
  102. $is_optgroup = FALSE;
  103. if (is_array($elem)) {
  104. $output .= '<div class="bef-group">';
  105. $output .= '<div class="bef-group-heading">' . $option . '</div>';
  106. $output .= '<div class="bef-group-items">';
  107. $element_set = $elem;
  108. $is_optgroup = TRUE;
  109. }
  110. else {
  111. $element_set[$option] = $elem;
  112. }
  113. foreach ($element_set as $key => $value) {
  114. $output .= bef_checkbox($element, $key, $value, array_search($key, $selected_options) !== FALSE);
  115. }
  116. if ($is_optgroup) {
  117. // Close group and item <div>s.
  118. $output .= '</div></div>';
  119. }
  120. }
  121. $output .= '</div>';
  122. // Fake theme_checkboxes() which we can't call because it calls
  123. // theme_form_element() for each option.
  124. $attributes['class'] = array('form-checkboxes', 'bef-select-as-checkboxes');
  125. if (!empty($element['#bef_select_all_none'])) {
  126. $attributes['class'][] = 'bef-select-all-none';
  127. }
  128. if (!empty($element['#bef_select_all_none_nested'])) {
  129. $attributes['class'][] = 'bef-select-all-none-nested';
  130. }
  131. if (!empty($element['#attributes']['class'])) {
  132. $attributes['class'] = array_merge($element['#attributes']['class'], $attributes['class']);
  133. }
  134. return '<div' . drupal_attributes($attributes) . ">$description$output</div>";
  135. }
  136. /**
  137. * Themes a select element as a series of hidden fields.
  138. *
  139. * @see http://api.drupal.org/api/function/theme_select/7
  140. *
  141. * @param array $vars
  142. * An array of arrays, the 'element' item holds the properties of the element.
  143. *
  144. * @return string
  145. * HTML representing the form element.
  146. */
  147. function theme_select_as_hidden($vars) {
  148. $element = $vars['element'];
  149. $output = '';
  150. $selected_options = empty($element['#value']) ? $element['#default_value'] : $element['#value'];
  151. $properties = array(
  152. 'title' => isset($element['#title']) ? $element['#title'] : '',
  153. 'description' => isset($element['#bef_description']) ? $element['#bef_description'] : '',
  154. 'required' => FALSE,
  155. );
  156. foreach ($element['#options'] as $option => $elem) {
  157. // Check for Taxonomy-based filters.
  158. if (is_object($elem)) {
  159. $slice = array_slice($elem->option, 0, 1, TRUE);
  160. list($option, $elem) = each($slice);
  161. }
  162. // Check for optgroups. Put subelements in the $element_set array and add a
  163. // group heading. Otherwise, just add the element to the set.
  164. $element_set = array();
  165. if (is_array($elem)) {
  166. $element_set = $elem;
  167. }
  168. else {
  169. $element_set[$option] = $elem;
  170. }
  171. foreach ($element_set as $key => $value) {
  172. // Only render fields for selected values -- no selected values renders
  173. // zero fields.
  174. if (array_search($key, $selected_options) !== FALSE) {
  175. // Custom ID for each hidden field based on the <select>'s original ID.
  176. $id = drupal_html_id($element['#id'] . '-' . $key);
  177. // Very similar to theme_hidden()
  178. // (http://api.drupal.org/api/function/theme_hidden/7).
  179. $hidden = '<input type="hidden" '
  180. // Brackets are key -- just like select.
  181. . 'name="' . filter_xss($element['#name']) . '[]" '
  182. . 'id="' . $id . '" '
  183. . 'value="' . check_plain($key) . '" '
  184. . drupal_attributes($element['#attributes']) . ' />';
  185. $output .= theme('form_element', array(
  186. 'element' => array_merge($properties, array(
  187. '#id' => $id,
  188. '#children' => $hidden,
  189. ))
  190. ));
  191. }
  192. }
  193. }
  194. return $output;
  195. }
  196. /**
  197. * Themes a select element as radio buttons enclosed in a collapsible fieldset.
  198. *
  199. * @param array $vars
  200. * An array of arrays, the 'element' item holds the properties of the element.
  201. *
  202. * @return string
  203. * HTML representing the form element.
  204. */
  205. function theme_select_as_radios_fieldset($vars) {
  206. // Merge incoming element with some default values. Prevents a lot of this.
  207. // $foo = isset($bar) ? $bar : $bar_default;
  208. $element = array_merge(
  209. array(
  210. '#bef_title' => '',
  211. '#bef_description' => '',
  212. '#bef_operator' => array(),
  213. ),
  214. $vars['element']
  215. );
  216. // The "all" option is the first in the list. If the selected radio button is
  217. // the all option, then leave the fieldset collapsed. Otherwise, render it
  218. // opened.
  219. $keys = array_keys($element['#options']);
  220. $all = array_shift($keys);
  221. $fieldset = array(
  222. '#title' => $element['#bef_title'],
  223. '#description' => $element['#bef_description'],
  224. '#attributes' => array(
  225. 'class' => array(
  226. 'bef-select-as-checkboxes-fieldset',
  227. 'collapsible',
  228. ),
  229. ),
  230. );
  231. if (empty($element['#value'])) {
  232. // Using the FAPI #collapsible and #collapsed attribute doesn't work here.
  233. // TODO: not sure why...
  234. $fieldset['#attributes']['class'][] = 'collapsed';
  235. }
  236. // We rendered the description as part of the fieldset element, don't render
  237. // it again along with the checkboxes.
  238. unset($element['#bef_description']);
  239. $children = '';
  240. if (!empty($element['#bef_operator'])) {
  241. // Put an exposed operator inside the fieldset.
  242. $children = drupal_render($element['#bef_operator']);
  243. }
  244. // Render the radio buttons.
  245. $children .= theme('select_as_radios', $element);
  246. $fieldset['#children'] = $children;
  247. return theme('fieldset', array('element' => $fieldset));
  248. }
  249. /**
  250. * Themes a select drop-down as a collection of radio buttons.
  251. *
  252. * @see http://api.drupal.org/api/function/theme_select/7
  253. *
  254. * @param array $vars
  255. * An array of arrays, the 'element' item holds the properties of the element.
  256. *
  257. * @return string
  258. * HTML representing the form element.
  259. */
  260. function theme_select_as_radios($vars) {
  261. $element = &$vars['element'];
  262. if (!empty($element['#bef_nested'])) {
  263. return theme('select_as_tree', $vars);
  264. }
  265. $output = '';
  266. foreach (element_children($element) as $key) {
  267. $element[$key]['#default_value'] = NULL;
  268. $element[$key]['#children'] = theme('radio', array('element' => $element[$key]));
  269. $output .= theme('form_element', array('element' => $element[$key]));
  270. }
  271. return $output;
  272. }
  273. /**
  274. * Themes a taxonomy-based exposed filter as a nested unordered list.
  275. *
  276. * Note: this routine depends on the '-' char prefixed on the term names by
  277. * Views to determine depth.
  278. *
  279. * @param array $vars
  280. * An array of arrays, the 'element' item holds the properties of the element.
  281. *
  282. * @return string
  283. * Nested, unordered list of filter options
  284. */
  285. function theme_select_as_tree($vars) {
  286. $element = $vars['element'];
  287. // The selected keys from #options.
  288. $selected_options = empty($element['#value']) ? $element['#default_value'] : $element['#value'];
  289. // Build a bunch of nested unordered lists to represent the hierarchy based
  290. // on the '-' prefix added by Views or optgroup structure.
  291. $output = '<ul class="bef-tree">';
  292. $curr_depth = -1;
  293. foreach ($element['#options'] as $option_value => $option_label) {
  294. // Check for Taxonomy-based filters.
  295. if (is_object($option_label)) {
  296. $slice = array_slice($option_label->option, 0, 1, TRUE);
  297. list($option_value, $option_label) = each($slice);
  298. }
  299. // Check for optgroups -- which is basically a two-level deep tree.
  300. if (is_array($option_label)) {
  301. // TODO:
  302. }
  303. else {
  304. // Build hierarchy based on prefixed '-' on the element label.
  305. if (t('- Any -') == $option_label) {
  306. $depth = -1;
  307. }
  308. else {
  309. preg_match('/^(-*).*$/', $option_label, $matches);
  310. $depth = strlen($matches[1]);
  311. $option_label = ltrim($option_label, '-');
  312. }
  313. // Build either checkboxes or radio buttons, depending on Views' settings.
  314. $html = '';
  315. if (!empty($element['#multiple'])) {
  316. $html = bef_checkbox(
  317. $element,
  318. $option_value,
  319. $option_label,
  320. (array_search($option_value, $selected_options) !== FALSE)
  321. );
  322. }
  323. else {
  324. $element[$option_value]['#title'] = $option_label;
  325. $element[$option_value]['#children'] = theme('radio', array('element' => $element[$option_value]));
  326. $html .= theme('form_element', array('element' => $element[$option_value]));
  327. }
  328. if ($depth > $curr_depth) {
  329. // We've moved down a level: create a new nested <ul>.
  330. // TODO: Is there is a way to jump more than one level deeper at a time?
  331. // I don't think so...
  332. $output .= "<ul class='bef-tree-child bef-tree-depth-$depth'><li>$html";
  333. $curr_depth = $depth;
  334. }
  335. elseif ($depth < $curr_depth) {
  336. // We've moved up a level: finish previous <ul> and <li> tags, once for
  337. // each level, since we can jump multiple levels up at a time.
  338. while ($depth < $curr_depth) {
  339. $output .= '</li></ul>';
  340. $curr_depth--;
  341. }
  342. $output .= "</li><li>$html";
  343. }
  344. else {
  345. if (-1 == $curr_depth) {
  346. // No </li> needed -- this is the first element.
  347. $output .= "<li>$html";
  348. $curr_depth = 0;
  349. }
  350. else {
  351. // Remain at same level as previous entry.
  352. $output .= "</li><li>$html";
  353. }
  354. }
  355. }
  356. } // foreach ($element['#options'] as $option_value => $option_label)
  357. if (!$curr_depth) {
  358. // Close last <li> tag.
  359. $output .= '</li>';
  360. }
  361. else {
  362. // Finish closing <ul> and <li> tags.
  363. while ($curr_depth) {
  364. $curr_depth--;
  365. $output .= '</li></ul></li>';
  366. }
  367. }
  368. // Close the opening <ul class="bef-tree"> tag.
  369. $output .= '</ul>';
  370. // Add exposed filter description.
  371. $description = '';
  372. if (!empty($element['#bef_description'])) {
  373. $description = '<div class="description">' . $element['#bef_description'] . '</div>';
  374. }
  375. // Add the select all/none option, if needed.
  376. if (!empty($element['#bef_select_all_none'])) {
  377. if (empty($element['#attributes']['class'])) {
  378. $element['#attributes']['class'] = array();
  379. }
  380. $element['#attributes']['class'][] = 'bef-select-all-none';
  381. }
  382. // Add the select all/none nested option, if needed.
  383. if (!empty($element['#bef_select_all_none_nested'])) {
  384. if (empty($element['#attributes']['class'])) {
  385. $element['#attributes']['class'] = array();
  386. }
  387. $element['#attributes']['class'][] = 'bef-select-all-none-nested';
  388. }
  389. // Name and multiple attributes are not valid for <div>'s.
  390. if (isset($element['#attributes']['name'])) {
  391. unset($element['#attributes']['name']);
  392. }
  393. if (isset($element['#attributes']['multiple'])) {
  394. unset($element['#attributes']['multiple']);
  395. }
  396. return '<div' . drupal_attributes($element['#attributes']) . ">$description$output</div>";
  397. }
  398. /**
  399. * Themes a select drop-down as a collection of links.
  400. *
  401. * @see http://api.drupal.org/api/function/theme_select/7
  402. *
  403. * @param array $vars
  404. * An array of arrays, the 'element' item holds the properties of the element.
  405. *
  406. * @return string
  407. * HTML representing the form element.
  408. */
  409. function theme_select_as_links($vars) {
  410. $element = $vars['element'];
  411. $output = '';
  412. $name = $element['#name'];
  413. // Collect selected values so we can properly style the links later.
  414. $selected_options = array();
  415. if (empty($element['#value'])) {
  416. if (!empty($element['#default_values'])) {
  417. $selected_options[] = $element['#default_values'];
  418. }
  419. }
  420. else {
  421. $selected_options[] = $element['#value'];
  422. }
  423. // Add to the selected options specified by Views whatever options are in the
  424. // URL query string, but only for this filter.
  425. $urllist = parse_url(request_uri());
  426. if (isset($urllist['query'])) {
  427. $query = array();
  428. parse_str(urldecode($urllist['query']), $query);
  429. foreach ($query as $key => $value) {
  430. if ($key != $name) {
  431. continue;
  432. }
  433. if (is_array($value)) {
  434. // This filter allows multiple selections, so put each one on the
  435. // selected_options array.
  436. foreach ($value as $option) {
  437. $selected_options[] = $option;
  438. }
  439. }
  440. else {
  441. $selected_options[] = $value;
  442. }
  443. }
  444. }
  445. // Clean incoming values to prevent XSS attacks.
  446. if (is_array($element['#value'])) {
  447. foreach ($element['#value'] as $index => $item) {
  448. unset($element['#value'][$index]);
  449. $element['#value'][filter_xss($index)] = filter_xss($item);
  450. }
  451. }
  452. elseif (is_string($element['#value'])) {
  453. $element['#value'] = filter_xss($element['#value']);
  454. }
  455. // Go through each filter option and build the appropriate link or plain text.
  456. foreach ($element['#options'] as $option => $elem) {
  457. if (!empty($element['#hidden_options'][$option])) {
  458. continue;
  459. }
  460. // Check for Taxonomy-based filters.
  461. if (is_object($elem)) {
  462. $slice = array_slice($elem->option, 0, 1, TRUE);
  463. list($option, $elem) = each($slice);
  464. }
  465. // Check for optgroups. Put subelements in the $element_set array and add
  466. // a group heading. Otherwise, just add the element to the set.
  467. $element_set = array();
  468. if (is_array($elem)) {
  469. $element_set = $elem;
  470. }
  471. else {
  472. $element_set[$option] = $elem;
  473. }
  474. $links = array();
  475. $multiple = !empty($element['#multiple']);
  476. // If we're in an exposed block, we'll get passed a path to use for the
  477. // Views results page.
  478. $path = '';
  479. if (!empty($element['#bef_path'])) {
  480. $path = $element['#bef_path'];
  481. }
  482. foreach ($element_set as $key => $value) {
  483. $element_output = '';
  484. // Custom ID for each link based on the <select>'s original ID.
  485. $id = drupal_html_id($element['#id'] . '-' . $key);
  486. $elem = array(
  487. '#id' => $id,
  488. '#markup' => '',
  489. '#type' => 'bef-link',
  490. '#name' => $id,
  491. );
  492. if (array_search($key, $selected_options) === FALSE) {
  493. $elem['#children'] = l($value, bef_replace_query_string_arg($name, $key, $multiple, FALSE, $path));
  494. //$output .= theme('form_element', array('element' => $elem));
  495. $element_output = theme('form_element', array('element' => $elem));
  496. if ($element['#name'] == 'sort_bef_combine' && !empty($element['#settings']['toggle_links'])) {
  497. $sort_pair = explode(' ', $key);
  498. if (count($sort_pair) == 2) {
  499. // Highlight the link if it is the selected sort_by (can be either
  500. // asc or desc, it doesn't matter).
  501. if (strpos($selected_options[0], $sort_pair[0]) === 0) {
  502. $element_output = str_replace('form-item', 'form-item selected', $element_output);
  503. }
  504. }
  505. }
  506. } else {
  507. $elem['#children'] = l($value, bef_replace_query_string_arg($name, $key, $multiple, TRUE, $path));
  508. _form_set_class($elem, array('bef-select-as-links-selected'));
  509. //$output .= str_replace('form-item', 'form-item selected', theme('form_element', array('element' => $elem)));
  510. $element_output = str_replace('form-item', 'form-item selected', theme('form_element', array('element' => $elem)));
  511. }
  512. $output .= $element_output;
  513. }
  514. }
  515. $properties = array(
  516. '#description' => isset($element['#bef_description']) ? $element['#bef_description'] : '',
  517. '#children' => $output,
  518. );
  519. $output = '<div class="bef-select-as-links">';
  520. $output .= theme('form_element', array('element' => $properties));
  521. if (!empty($element['#value'])) {
  522. if (is_array($element['#value'])) {
  523. foreach ($element['#value'] as $value) {
  524. $output .= '<input type="hidden" name="' . $name . '[]" value="' . $value . '" />';
  525. }
  526. }
  527. else {
  528. $output .= '<input type="hidden" name="' . $name . '" value="' . $element['#value'] . '" />';
  529. }
  530. }
  531. $output .= '</div>';
  532. return $output;
  533. }
  534. /**
  535. * Themes some exposed form elements in a collapsible fieldset.
  536. *
  537. * @param array $vars
  538. * An array of arrays, the 'element' item holds the properties of the element.
  539. *
  540. * @return string
  541. * HTML to render the form element.
  542. */
  543. function theme_secondary_exposed_elements($vars) {
  544. $element = $vars['element'];
  545. $output = '<div class="bef-secondary-options">';
  546. foreach (element_children($element) as $id) {
  547. $output .= drupal_render($element[$id]);
  548. }
  549. $output .= '</div>';
  550. return $output;
  551. }
  552. /*
  553. *
  554. * Helper functions
  555. *
  556. */
  557. /**
  558. * Build a BEF checkbox.
  559. *
  560. * @see http://api.drupal.org/api/function/theme_checkbox/7
  561. *
  562. * @param array $element
  563. * Original <select> element generated by Views.
  564. * @param string $value
  565. * Return value of this checkbox option.
  566. * @param string $label
  567. * Label of this checkbox option.
  568. * @param bool $selected
  569. * Checked or not.
  570. *
  571. * @return [type]
  572. * HTML to render a checkbox.
  573. */
  574. function bef_checkbox($element, $value, $label, $selected) {
  575. $value = check_plain($value);
  576. $label = filter_xss_admin($label);
  577. $id = drupal_html_id($element['#id'] . '-' . $value);
  578. // Custom ID for each checkbox based on the <select>'s original ID.
  579. $properties = array(
  580. '#required' => FALSE,
  581. '#id' => $id,
  582. '#type' => 'bef-checkbox',
  583. '#name' => $id,
  584. );
  585. // Prevent the select-all-none class from cascading to all checkboxes.
  586. if (!empty($element['#attributes']['class'])
  587. && FALSE !== ($key = array_search('bef-select-all-none', $element['#attributes']['class']))) {
  588. unset($element['#attributes']['class'][$key]);
  589. }
  590. // Unset the name attribute as we are setting it manually.
  591. unset($element['#attributes']['name']);
  592. // Unset the multiple attribute as it doesn't apply for checkboxes.
  593. unset ($element['#attributes']['multiple']);
  594. $checkbox = '<input type="checkbox" '
  595. // Brackets are key -- just like select.
  596. . 'name="' . $element['#name'] . '[]" '
  597. . 'id="' . $id . '" '
  598. . 'value="' . $value . '" '
  599. . ($selected ? 'checked="checked" ' : '')
  600. . drupal_attributes($element['#attributes']) . ' />';
  601. $properties['#children'] = "$checkbox <label class='option' for='$id'>$label</label>";
  602. $output = theme('form_element', array('element' => $properties));
  603. return $output;
  604. }
  605. /**
  606. * Replaces/adds a given query string argument to the current URL.
  607. *
  608. * @param string $key
  609. * Query string key (argument).
  610. * @param string $value
  611. * Query string value.
  612. * @param bool $multiple
  613. * (optional) TRUE if this key/value pair allows multiple values.
  614. * @param bool $remove
  615. * (optional) TRUE if this key/value should be a link to remove/unset the
  616. * filter.
  617. * @param string $path
  618. * (optional) Use this specify the View results page when the exposed form
  619. * is displayed as a block and may be a different URL from the results.
  620. * Defaults to the current path if unspecified.
  621. *
  622. * @return string
  623. * URL.
  624. */
  625. function bef_replace_query_string_arg($key, $value, $multiple = FALSE, $remove = FALSE, $path = '') {
  626. if (!$path) {
  627. $path = implode('/', arg());
  628. }
  629. // Prevents us from having to check for each index from parse_url that we may
  630. // use.
  631. $urllist = array('path' => '', 'fragment' => '', 'query' => '');
  632. $urllist = array_merge($urllist, parse_url(request_uri()));
  633. $fragment = urldecode($urllist['fragment']);
  634. $query = array();
  635. parse_str(urldecode($urllist['query']), $query);
  636. if (isset($query[$key]) && is_array($query[$key])) {
  637. // Multiple values allowed for this existing key.
  638. if ($remove && ($key_remove = array_search($value, $query[$key])) !== FALSE) {
  639. unset($query[$key][$key_remove]);
  640. }
  641. else {
  642. $query[$key][] = $value;
  643. }
  644. }
  645. else {
  646. // Create a new key.
  647. if ($multiple && !$remove) {
  648. $query[$key] = array($value);
  649. }
  650. elseif (!$remove) {
  651. $query[$key] = $value;
  652. }
  653. }
  654. return url($path, array(
  655. 'query' => $query,
  656. 'fragment' => $fragment,
  657. 'absolute' => TRUE,
  658. ));
  659. }