diff --git a/core/modules/views/js/exposed-form-ajax.js b/core/modules/views/js/exposed-form-ajax.js new file mode 100644 index 0000000..86857d6 --- /dev/null +++ b/core/modules/views/js/exposed-form-ajax.js @@ -0,0 +1,24 @@ +/** + * @file + * Handles Views' exposed form AJAX data submission. + */ +(function ($) { + + /* + * Gets Form build info from settings and adds it to ajax data. + * + * @see views_exposed_form_ajax_enable(). + */ + Drupal.behaviors.ViewsExposedFormAjax = { + attach: function(context, settings) { + for (var ajaxObject in Drupal.ajax.instances) { + for(var name in drupalSettings.ViewsExposedFormInfo) { + if (Drupal.ajax.instances[ajaxObject].options && Drupal.ajax.instances[ajaxObject].options.data._triggering_element_name == name) { + jQuery.extend(Drupal.ajax.instances[ajaxObject].options.data, drupalSettings.ViewsExposedFormInfo[name]); + } + } + } + } + }; + +})(jQuery); diff --git a/core/modules/views/views.libraries.yml b/core/modules/views/views.libraries.yml index 640492d..8208a44 100644 --- a/core/modules/views/views.libraries.yml +++ b/core/modules/views/views.libraries.yml @@ -16,3 +16,15 @@ views.ajax: - core/jquery.once - core/jquery.form - core/drupal.ajax + +views.exposed-form-ajax: + version: VERSION + js: + js/exposed-form-ajax.js: {} + dependencies: + - core/jquery + - core/drupal + - core/drupalSettings + - core/jquery.once + - core/jquery.form + - core/drupal.ajax diff --git a/core/modules/views/views.module b/core/modules/views/views.module index e1a4d8c..1cf2241 100644 --- a/core/modules/views/views.module +++ b/core/modules/views/views.module @@ -10,6 +10,7 @@ use Drupal\Core\Database\Query\AlterableInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Form\FormStateInterface; +use Drupal\Core\Render\Element; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; use Drupal\views\Plugin\Derivative\ViewsLocalTask; @@ -644,6 +645,77 @@ function views_form_views_exposed_form_alter(&$form, FormStateInterface $form_st $form['form_build_id']['#access'] = FALSE; $form['form_token']['#access'] = FALSE; $form['form_id']['#access'] = FALSE; + // AJAX behaviors need these data, so we add it back in #after_build. + $form['#after_build'][] = 'views_exposed_form_ajax_enable'; +} + +/** + * Checks whether the exposed form will use ajax and passes required + * form information removed in views_form_views_exposed_form_alter(). + */ +function views_exposed_form_ajax_enable(&$form, &$form_state) { + // In order for Ajax to work, we need the form build info. Here we + // check if #ajax has been added to any form elements, and if so, + // pass this info as settings via Javascript, which get attached to + // the submitted form on Ajax form submissions. + // #ajax property can be set not only for the first level of the form, + // so we look for it in the whole form. + $ajax_info = []; + $ajax_elements = views_exposed_form_ajax_lookup_recursive($form); + // Determine if form is being processed. + + $triggering_element = $form_state->getTriggeringElement(); + if (!empty($triggering_element['#parents'])) { + $triggering_element_name = end($triggering_element['#parents']); + } + // When we have multiple elements with #ajax set on exposed form + // we need to pass only triggering element name to Javascript. + // Otherwise #ajax will work only for the first element. + if (!empty($triggering_element_name) && !empty($ajax_elements)) { + // Check if element has #ajax property set. + if (in_array($triggering_element_name, $ajax_elements)) { + $ajax_elements = [$triggering_element_name => $triggering_element_name]; + } + else { + $ajax_elements = []; + } + } + if (!empty($ajax_elements)) { + $form_info = [ + 'form_id' => $form['#form_id'], + 'form_build_id' => $form['#build_id'], + ]; + // Anonymous users don't get a token. + if (!empty($form['#token'])) { + $form_info['form_token'] = drupal_get_token($form['#token']); + } + foreach ($ajax_elements as $element_name) { + $ajax_info[$element_name] = $form_info; + } + $form['#attached']['drupalSettings']['ViewsExposedFormInfo'] = $ajax_info; + $form['#attached']['library'][] = 'views/views.exposed-form-ajax'; + } + return $form; +} + +/** + * Recursively looks for the #ajax property for every form elemet. + * @param $elements + * The element array to look for #ajax property. + * + * @return + * Array of the elements names where #ajax was found. + */ +function views_exposed_form_ajax_lookup_recursive($elements) { + $ajax_elements = []; + foreach (Element::children($elements) as $key) { + if (!empty($elements[$key]['#name']) && !empty($elements[$key]['#ajax'])) { + $ajax_elements[$elements[$key]['#name']] = $elements[$key]['#name']; + } + // Recursive call to look for #ajax in element's childrens. + $ajax_elements += views_exposed_form_ajax_lookup_recursive($elements[$key]); + } + return $ajax_elements; } /**