diff --git a/config/schema/views_ajax_get.schema.yml b/config/schema/views_ajax_get.schema.yml new file mode 100644 index 0000000..7beb26b --- /dev/null +++ b/config/schema/views_ajax_get.schema.yml @@ -0,0 +1,6 @@ +views.display_extender.views_ajax_get: + type: views_display_extender + mapping: + ajax_get: + type: Boolean + label: 'Use Ajax GET requests' diff --git a/views_ajax_get.js b/js/views_ajax_get.js similarity index 62% rename from views_ajax_get.js rename to js/views_ajax_get.js index 99c8a5d..ddcdd24 100644 --- a/views_ajax_get.js +++ b/js/views_ajax_get.js @@ -1,7 +1,7 @@ -(function ($) { +(function ($, drupalSettings) { // Store the original beforeSerialize, as we want to continue using // it after we've overridden it. - Drupal.ajax.prototype.originalBeforeSerialize = Drupal.ajax.prototype.beforeSerialize; + Drupal.Ajax.prototype.originalBeforeSerialize = Drupal.Ajax.prototype.beforeSerialize; /** * Override core's beforeSerialize. @@ -10,17 +10,17 @@ * We also avoid adding ajax_html_id and ajax_page_state. * (This happens in core's beforeSerialize). */ - Drupal.ajax.prototype.beforeSerialize = function (element, options) { + Drupal.Ajax.prototype.beforeSerialize = function (element, options) { // If this is for a view, switch to GET. if (options.url && options.url.indexOf('/views/ajax') !== -1 && - Drupal.settings.viewsAjaxGet && - $.inArray(options.data.view_name, Drupal.settings.viewsAjaxGet) !== -1) { + drupalSettings.viewsAjaxGet && + $.inArray(options.data.view_name, drupalSettings.viewsAjaxGet) !== -1) { - // @See Drupal.ajax.prototype.beforeSerialize + // @See Drupal.Ajax.prototype.beforeSerialize if (this.form) { - var settings = this.settings || Drupal.settings; + var settings = this.settings || drupalSettings; Drupal.detachBehaviors(this.form, settings, 'serialize'); } @@ -31,4 +31,4 @@ return this.originalBeforeSerialize(element, options); }; -})(jQuery); +})(jQuery, drupalSettings); diff --git a/src/CacheableAjaxResponse.php b/src/CacheableAjaxResponse.php new file mode 100644 index 0000000..8821206 --- /dev/null +++ b/src/CacheableAjaxResponse.php @@ -0,0 +1,13 @@ +view->id(); + $vars['display_id'] = $this->view->current_display; + + return serialize($vars); + } + + /** + * {@inheritdoc} + */ + public function unserialize($serialized) { + $unserialized = unserialize($serialized); + foreach ($unserialized as $key => $value) { + $this->{$key} = $value; + } + // Ensure that there is a request on the request stack. + $fake_request = FALSE; + if (!$request = \Drupal::request()) { + $fake_request = TRUE; + \Drupal::requestStack()->push(Request::create('/uri')); + } + $this->view = Views::getView($unserialized['view_id']); + $this->view->setDisplay($unserialized['display_id']); + if ($fake_request) { + \Drupal::requestStack()->pop(); + } + } + +} diff --git a/src/Controller/ViewsAjaxController.php b/src/Controller/ViewsAjaxController.php new file mode 100644 index 0000000..8231a36 --- /dev/null +++ b/src/Controller/ViewsAjaxController.php @@ -0,0 +1,31 @@ +request->add($request->query->all()); + $response = parent::ajaxView($request); + + if (_views_ajax_get_is_ajax_get_view($response->getView())) { + $cacheable_response = new CacheableViewsAjaxResponse(); + $cacheable_response->setView($response->getView()); + $cacheable_commands =& $cacheable_response->getCommands(); + $cacheable_commands = $response->getCommands(); + + // Don't allow attachments + // $cacheable_response->setAttachments($response->getAttachments()); + return $cacheable_response; + } + + return $response; + } + +} diff --git a/src/EventSubscriber/AjaxResponseSubscriber.php b/src/EventSubscriber/AjaxResponseSubscriber.php new file mode 100644 index 0000000..f77ea46 --- /dev/null +++ b/src/EventSubscriber/AjaxResponseSubscriber.php @@ -0,0 +1,42 @@ +getResponse(); + if (!$response instanceof ViewAjaxResponse) { + return; + } + + $request = $event->getRequest(); + if (RouteMatch::createFromRequest($request) + ->getRouteName() === 'views.ajax') { + /** @var \Drupal\views\ViewExecutable $view */ + $view = $response->getView(); + // If view is excluded from conversion, don't add cache headers. + if (_views_ajax_get_is_ajax_get_view($view)) { + $view->getRequest()->headers->set('Cache-Control', 'public, max-age=' . \Drupal::config('system_performance_settings')->get('cache.page.max_age')); + } + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[KernelEvents::RESPONSE][] = ['onResponse', 0]; + return $events; + } + +} diff --git a/src/EventSubscriber/RouteAlterSubscriber.php b/src/EventSubscriber/RouteAlterSubscriber.php new file mode 100644 index 0000000..ef783e8 --- /dev/null +++ b/src/EventSubscriber/RouteAlterSubscriber.php @@ -0,0 +1,26 @@ +getRouteCollection(); + if ($route = $collection->get('views.ajax')) { + $route->setDefault('_controller', '\Drupal\views_ajax_get\Controller\ViewsAjaxController::ajaxView'); + } + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events[RoutingEvents::ALTER][] = ['onRouteAlter']; + return $events; + } + +} diff --git a/src/Plugin/views/display_extender/ViewsAjax.php b/src/Plugin/views/display_extender/ViewsAjax.php new file mode 100644 index 0000000..6803fc5 --- /dev/null +++ b/src/Plugin/views/display_extender/ViewsAjax.php @@ -0,0 +1,63 @@ + FALSE]; + + return $options; + } + + /** + * {@inheritdoc} + */ + public function buildOptionsForm(&$form, FormStateInterface $form_state) { + parent::buildOptionsForm($form, $form_state); + + if ($form_state->get('section') === 'use_ajax') { + $form['ajax_get'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Use GET requests'), + '#default_value' => $this->options['ajax_get'], + ]; + } + } + + /** + * {@inheritdoc} + */ + public function submitOptionsForm(&$form, FormStateInterface $form_state) { + parent::submitOptionsForm($form, $form_state); + switch ($form_state->get('section')) { + case 'use_ajax': + $this->options['ajax_get'] = $form_state->getValue('ajax_get'); + break; + } + } + + /** + * {@inheritdoc} + */ + public function defaultableSections(&$sections, $section = NULL) { + $sections['ajax_get'] = ['ajax_get']; + } + +} diff --git a/src/ResponsePolicy.php b/src/ResponsePolicy.php new file mode 100644 index 0000000..fe71f22 --- /dev/null +++ b/src/ResponsePolicy.php @@ -0,0 +1,22 @@ +attributes->get(RouteObjectInterface::ROUTE_NAME) === 'views.ajax') { + return static::DENY; + } + } + +} diff --git a/views_ajax_get.admin.inc b/views_ajax_get.admin.inc deleted file mode 100644 index fd49c7d..0000000 --- a/views_ajax_get.admin.inc +++ /dev/null @@ -1,24 +0,0 @@ - 'checkboxes', - '#title' => t('Exempt the following views from using GET ajax.'), - '#description' => t('Use this if you are having issues with certain views using GET ajax. - (They will revert to using POST). - Note this will only apply to Views that have ajax enabled.'), - '#options' => drupal_map_assoc(array_keys($views)), - '#default_value' => variable_get('views_ajax_get_exemptions', array()), - ); - - return system_settings_form($form); -} diff --git a/views_ajax_get.info b/views_ajax_get.info deleted file mode 100644 index 0f39352..0000000 --- a/views_ajax_get.info +++ /dev/null @@ -1,5 +0,0 @@ -name = Views Ajax Get -description = Overrides Views Ajax to work with GET instead of POST -dependencies[] = views -package = Views -core = 7.x diff --git a/views_ajax_get.info.yml b/views_ajax_get.info.yml new file mode 100644 index 0000000..76618dd --- /dev/null +++ b/views_ajax_get.info.yml @@ -0,0 +1,7 @@ +name: Views Ajax Get +description: Overrides Views Ajax to work with GET instead of POST +dependencies: + - views +package: Views +core: 8.x +type: module diff --git a/views_ajax_get.install b/views_ajax_get.install deleted file mode 100644 index ee903c0..0000000 --- a/views_ajax_get.install +++ /dev/null @@ -1,13 +0,0 @@ - 'Views Ajax Get Settings', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('views_ajax_get_admin_form'), - 'access arguments' => array('administer views ajax get'), - 'file' => 'views_ajax_get.admin.inc', - ); - return $items; -} +use Drupal\views\ViewExecutable; /** * Implements hook_views_pre_render(). @@ -27,41 +13,24 @@ function views_ajax_get_menu() { * Include the necessary JavaScript file if an Ajax view is embedded * on the page. */ -function views_ajax_get_views_pre_render(&$view) { - $exempt_views = variable_get('views_ajax_get_exemptions', array()); - - if ($view->use_ajax - && empty($view->is_attachment) - && empty($view->live_preview) - && (!isset($exempt_views[$view->name]) || !$exempt_views[$view->name])) { - drupal_add_js(drupal_get_path('module', 'views_ajax_get') . '/views_ajax_get.js'); - $data = array('viewsAjaxGet' => array($view->name)); - drupal_add_js($data, 'setting'); +function views_ajax_get_views_pre_render(ViewExecutable $view) { + if (_views_ajax_get_is_ajax_get_view($view)) { + $view->element['#attached']['library'][] = 'views_ajax_get/ajax_get'; + $view->element['#attached']['drupalSettings']['viewsAjaxGet'][] = $view->id(); } } /** - * Implements hook_views_ajax_data_alter(). + * Determines whether the current view has ajax get enabled. * - * Adding the headers for cache control so that these requests can be cached. - */ -function views_ajax_get_views_ajax_data_alter(&$commands, $view) { - $exempt_views = variable_get('views_ajax_get_exemptions', array()); - // If view is excluded from conversion, don't add cache headers. - if (drupal_page_is_cacheable() && (!isset($exempt_views[$view->name]) || !$exempt_views[$view->name])) { - drupal_add_http_header('Cache-Control', 'public, max-age=' . variable_get('page_cache_maximum_age', 0)); - } -} - -/** - * Implements hook_permission(). + * @param \Drupal\views\ViewExecutable $view + * The view. + * + * @return bool */ -function views_ajax_get_permission() { - return array( - 'administer views ajax get' => array( - 'title' => t('Administer views ajax get'), - 'description' => t('Access the views get administration pages.'), - 'restrict access' => TRUE, - ), - ); +function _views_ajax_get_is_ajax_get_view(ViewExecutable $view) { + return $view->display_handler->usesAJAX() + && empty($view->is_attachment) + && empty($view->live_preview) + && !empty($view->display_handler->getExtenders()['views_ajax_get']) && $view->display_handler->getExtenders()['views_ajax_get']->options['ajax_get']; } diff --git a/views_ajax_get.services.yml b/views_ajax_get.services.yml new file mode 100644 index 0000000..452a3d4 --- /dev/null +++ b/views_ajax_get.services.yml @@ -0,0 +1,14 @@ +services: + views_ajax_get.ajax_response: + class: \Drupal\views_ajax_get\EventSubscriber\AjaxResponseSubscriber + tags: + - { name: event_subscriber } + views_ajax_get.route_alter: + class: \Drupal\views_ajax_get\EventSubscriber\RouteAlterSubscriber + tags: + - { name: event_subscriber } + views_ajax_get.disable_cache: + class: \Drupal\views_ajax_get\ResponsePolicy + tags: + - { name: page_cache_response_policy } + - { name: dynamic_page_cache_response_policy }