views_plugin_exposed_form.inc

Definition of views_plugin_exposed_form.

File

plugins/views_plugin_exposed_form.inc
View source
  1. <?php
  2. /**
  3. * @file
  4. * Definition of views_plugin_exposed_form.
  5. */
  6. /**
  7. * @defgroup views_exposed_form_plugins Views exposed form plugins
  8. * @{
  9. * Plugins that handle the validation/submission and rendering of exposed forms.
  10. *
  11. * If needed, it is possible to use them to add additional form elements.
  12. *
  13. * @see hook_views_plugins()
  14. */
  15. /**
  16. * The base plugin to handle exposed filter forms.
  17. */
  18. class views_plugin_exposed_form extends views_plugin {
  19. /**
  20. * Initialize the plugin.
  21. *
  22. * @param $view
  23. * The view object.
  24. * @param $display
  25. * The display handler.
  26. */
  27. function init(&$view, &$display, $options = array()) {
  28. $this->view = &$view;
  29. $this->display = &$display;
  30. $this->unpack_options($this->options, $options);
  31. }
  32. function option_definition() {
  33. $options = parent::option_definition();
  34. $options['submit_button'] = array('default' => 'Apply', 'translatable' => TRUE);
  35. $options['reset_button'] = array('default' => FALSE, 'bool' => TRUE);
  36. $options['reset_button_label'] = array('default' => 'Reset', 'translatable' => TRUE);
  37. $options['exposed_sorts_label'] = array('default' => 'Sort by', 'translatable' => TRUE);
  38. $options['expose_sort_order'] = array('default' => TRUE, 'bool' => TRUE);
  39. $options['sort_asc_label'] = array('default' => 'Asc', 'translatable' => TRUE);
  40. $options['sort_desc_label'] = array('default' => 'Desc', 'translatable' => TRUE);
  41. $options['autosubmit'] = array('default' => FALSE, 'bool' => TRUE);
  42. $options['autosubmit_hide'] = array('default' => TRUE, 'bool' => TRUE);
  43. return $options;
  44. }
  45. function options_form(&$form, &$form_state) {
  46. parent::options_form($form, $form_state);
  47. $form['submit_button'] = array(
  48. '#type' => 'textfield',
  49. '#title' => t('Submit button text'),
  50. '#description' => t('Text to display in the submit button of the exposed form.'),
  51. '#default_value' => $this->options['submit_button'],
  52. '#required' => TRUE,
  53. );
  54. $form['reset_button'] = array (
  55. '#type' => 'checkbox',
  56. '#title' => t('Include reset button'),
  57. '#description' => t('If checked the exposed form will provide a button to reset all the applied exposed filters'),
  58. '#default_value' => $this->options['reset_button'],
  59. );
  60. $form['reset_button_label'] = array(
  61. '#type' => 'textfield',
  62. '#title' => t('Reset button label'),
  63. '#description' => t('Text to display in the reset button of the exposed form.'),
  64. '#default_value' => $this->options['reset_button_label'],
  65. '#required' => TRUE,
  66. '#dependency' => array(
  67. 'edit-exposed-form-options-reset-button' => array(1)
  68. ),
  69. );
  70. $form['exposed_sorts_label'] = array(
  71. '#type' => 'textfield',
  72. '#title' => t('Exposed sorts label'),
  73. '#description' => t('Text to display as the label of the exposed sort select box.'),
  74. '#default_value' => $this->options['exposed_sorts_label'],
  75. '#required' => TRUE,
  76. );
  77. $form['expose_sort_order'] = array(
  78. '#type' => 'checkbox',
  79. '#title' => t('Expose sort order'),
  80. '#description' => t('Allow the user to choose the sort order. If sort order is not exposed, the sort criteria settings for each sort will determine its order.'),
  81. '#default_value' => $this->options['expose_sort_order'],
  82. );
  83. $form['sort_asc_label'] = array(
  84. '#type' => 'textfield',
  85. '#title' => t('Ascending'),
  86. '#description' => t('Text to use when exposed sort is ordered ascending.'),
  87. '#default_value' => $this->options['sort_asc_label'],
  88. '#required' => TRUE,
  89. '#dependency' => array('edit-exposed-form-options-expose-sort-order' => array(TRUE)),
  90. );
  91. $form['sort_desc_label'] = array(
  92. '#type' => 'textfield',
  93. '#title' => t('Descending'),
  94. '#description' => t('Text to use when exposed sort is ordered descending.'),
  95. '#default_value' => $this->options['sort_desc_label'],
  96. '#required' => TRUE,
  97. '#dependency' => array('edit-exposed-form-options-expose-sort-order' => array(TRUE)),
  98. );
  99. $form['autosubmit'] = array(
  100. '#type' => 'checkbox',
  101. '#title' => t('Autosubmit'),
  102. '#description' => t('Automatically submit the form once an element is changed.'),
  103. '#default_value' => $this->options['autosubmit'],
  104. );
  105. $form['autosubmit_hide'] = array(
  106. '#type' => 'checkbox',
  107. '#title' => t('Hide submit button'),
  108. '#description' => t('Hide submit button if javascript is enabled.'),
  109. '#default_value' => $this->options['autosubmit_hide'],
  110. '#dependency' => array(
  111. 'edit-exposed-form-options-autosubmit' => array(1),
  112. ),
  113. );
  114. }
  115. /**
  116. * Render the exposed filter form.
  117. *
  118. * This actually does more than that; because it's using FAPI, the form will
  119. * also assign data to the appropriate handlers for use in building the
  120. * query.
  121. */
  122. function render_exposed_form($block = FALSE) {
  123. // Deal with any exposed filters we may have, before building.
  124. $form_state = array(
  125. 'view' => &$this->view,
  126. 'display' => &$this->display,
  127. 'method' => 'get',
  128. 'rerender' => TRUE,
  129. 'no_redirect' => TRUE,
  130. 'always_process' => TRUE,
  131. );
  132. // Some types of displays (eg. attachments) may wish to use the exposed
  133. // filters of their parent displays instead of showing an additional
  134. // exposed filter form for the attachment as well as that for the parent.
  135. if (!$this->view->display_handler->displays_exposed() || (!$block && $this->view->display_handler->get_option('exposed_block'))) {
  136. unset($form_state['rerender']);
  137. }
  138. if (!empty($this->ajax)) {
  139. $form_state['ajax'] = TRUE;
  140. }
  141. $form_state['exposed_form_plugin'] = $this;
  142. $form = drupal_build_form('views_exposed_form', $form_state);
  143. $output = drupal_render($form);
  144. if (!$this->view->display_handler->displays_exposed() || (!$block && $this->view->display_handler->get_option('exposed_block'))) {
  145. return "";
  146. }
  147. else {
  148. return $output;
  149. }
  150. }
  151. function query() {
  152. $view = $this->view;
  153. $exposed_data = isset($view->exposed_data) ? $view->exposed_data : array();
  154. $sort_by = isset($exposed_data['sort_by']) ? $exposed_data['sort_by'] : NULL;
  155. if (!empty($sort_by) && $this->view->style_plugin->build_sort()) {
  156. // Make sure the original order of sorts is preserved
  157. // (e.g. a sticky sort is often first)
  158. if (isset($view->sort[$sort_by])) {
  159. $view->query->orderby = array();
  160. foreach ($view->sort as $key => $sort) {
  161. if (!$sort->is_exposed()) {
  162. $sort->query();
  163. }
  164. else if ($key == $sort_by) {
  165. if (isset($exposed_data['sort_order']) && in_array($exposed_data['sort_order'], array('ASC', 'DESC'))) {
  166. $sort->options['order'] = $exposed_data['sort_order'];
  167. }
  168. $sort->set_relationship();
  169. $sort->query();
  170. }
  171. }
  172. }
  173. }
  174. }
  175. function pre_render($values) { }
  176. function post_render(&$output) { }
  177. function pre_execute() { }
  178. function post_execute() { }
  179. function exposed_form_alter(&$form, &$form_state) {
  180. if (!empty($this->options['reset_button'])) {
  181. $form['reset'] = array(
  182. '#value' => $this->options['reset_button_label'],
  183. '#type' => 'submit',
  184. );
  185. }
  186. $form['submit']['#value'] = $this->options['submit_button'];
  187. // Check if there is exposed sorts for this view
  188. $exposed_sorts = array();
  189. foreach ($this->view->sort as $id => $handler) {
  190. if ($handler->can_expose() && $handler->is_exposed()) {
  191. $exposed_sorts[$id] = check_plain($handler->options['expose']['label']);
  192. }
  193. }
  194. if (count($exposed_sorts)) {
  195. $form['sort_by'] = array(
  196. '#type' => 'select',
  197. '#options' => $exposed_sorts,
  198. '#title' => $this->options['exposed_sorts_label'],
  199. );
  200. $sort_order = array(
  201. 'ASC' => $this->options['sort_asc_label'],
  202. 'DESC' => $this->options['sort_desc_label'],
  203. );
  204. if (isset($form_state['input']['sort_by']) && isset($this->view->sort[$form_state['input']['sort_by']])) {
  205. $default_sort_order = $this->view->sort[$form_state['input']['sort_by']]->options['order'];
  206. } else {
  207. $first_sort = reset($this->view->sort);
  208. $default_sort_order = $first_sort->options['order'];
  209. }
  210. if (!isset($form_state['input']['sort_by'])) {
  211. $keys = array_keys($exposed_sorts);
  212. $form_state['input']['sort_by'] = array_shift($keys);
  213. }
  214. if ($this->options['expose_sort_order']) {
  215. $form['sort_order'] = array(
  216. '#type' => 'select',
  217. '#options' => $sort_order,
  218. '#title' => t('Order'),
  219. '#default_value' => $default_sort_order,
  220. );
  221. }
  222. $form['submit']['#weight'] = 10;
  223. if (isset($form['reset'])) {
  224. $form['reset']['#weight'] = 10;
  225. }
  226. }
  227. $pager = $this->view->display_handler->get_plugin('pager');
  228. if ($pager) {
  229. $pager->exposed_form_alter($form, $form_state);
  230. $form_state['pager_plugin'] = $pager;
  231. }
  232. // Apply autosubmit values.
  233. if (!empty($this->options['autosubmit'])) {
  234. $form = array_merge_recursive($form, array('#attributes' => array('class' => array('ctools-auto-submit-full-form'))));
  235. $form['submit']['#attributes']['class'][] = 'ctools-use-ajax';
  236. $form['submit']['#attributes']['class'][] = 'ctools-auto-submit-click';
  237. $form['#attached']['js'][] = drupal_get_path('module', 'ctools') . '/js/auto-submit.js';
  238. if (!empty($this->options['autosubmit_hide'])) {
  239. $form['submit']['#attributes']['class'][] = 'js-hide';
  240. }
  241. }
  242. }
  243. function exposed_form_validate(&$form, &$form_state) {
  244. if (isset($form_state['pager_plugin'])) {
  245. $form_state['pager_plugin']->exposed_form_validate($form, $form_state);
  246. }
  247. }
  248. /**
  249. * This function is executed when exposed form is submited.
  250. *
  251. * @param $form
  252. * Nested array of form elements that comprise the form.
  253. * @param $form_state
  254. * A keyed array containing the current state of the form.
  255. * @param $exclude
  256. * Nested array of keys to exclude of insert into
  257. * $view->exposed_raw_input
  258. */
  259. function exposed_form_submit(&$form, &$form_state, &$exclude) {
  260. if (!empty($form_state['values']['op']) && $form_state['values']['op'] == $this->options['reset_button_label']) {
  261. $this->reset_form($form, $form_state);
  262. }
  263. if (isset($form_state['pager_plugin'])) {
  264. $form_state['pager_plugin']->exposed_form_submit($form, $form_state, $exclude);
  265. $exclude[] = 'pager_plugin';
  266. }
  267. }
  268. function reset_form(&$form, &$form_state) {
  269. // _SESSION is not defined for users who are not logged in.
  270. // If filters are not overridden, store the 'remember' settings on the
  271. // default display. If they are, store them on this display. This way,
  272. // multiple displays in the same view can share the same filters and
  273. // remember settings.
  274. $display_id = ($this->view->display_handler->is_defaulted('filters')) ? 'default' : $this->view->current_display;
  275. if (isset($_SESSION['views'][$this->view->name][$display_id])) {
  276. unset($_SESSION['views'][$this->view->name][$display_id]);
  277. }
  278. // Set the form to allow redirect.
  279. if (empty($this->view->live_preview)) {
  280. $form_state['no_redirect'] = FALSE;
  281. }
  282. else {
  283. $form_state['rebuild'] = TRUE;
  284. $this->view->exposed_data = array();
  285. }
  286. $form_state['redirect'] = current_path();
  287. $form_state['values'] = array();
  288. }
  289. }
  290. /**
  291. * @}
  292. */