Commit 8b8eaa3e authored by catch's avatar catch

Issue #1843224 by dawehner, tim.plunkett: Convert Views Ajax commands to new Ajax API.

parent 8787384e
......@@ -6,6 +6,12 @@
*/
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\views\Ajax\HighlightCommand;
use Drupal\views\Ajax\SetFormCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\views\Ajax\ScrollTopCommand;
use Drupal\views\Ajax\ViewAjaxResponse;
use Drupal\Core\Ajax\AjaxResponse;
/**
* @defgroup views_ajax Views AJAX library
......@@ -29,7 +35,7 @@ function views_ajax() {
$pager_element = $request->request->get('pager_element');
$pager_element = isset($pager_element) ? intval($pager_element) : NULL;
$commands = array();
$response = new ViewAjaxResponse();
// Remove all of this stuff from the query of the request so it doesn't end
// up in pagers and tablesort URLs.
......@@ -68,160 +74,18 @@ function views_ajax() {
// Override the display's pager_element with the one actually used.
if (isset($pager_element)) {
$commands[] = views_ajax_command_scroll_top('.view-dom-id-' . $dom_id);
$response->addCommand(new ScrollTopCommand(".view-dom-id-$dom_id"));
$view->displayHandlers->get($display_id)->setOption('pager_element', $pager_element);
}
// Reuse the same DOM id so it matches that in Drupal.settings.
$view->dom_id = $dom_id;
$commands[] = ajax_command_replace('.view-dom-id-' . $dom_id, $view->preview($display_id, $args));
$response->addCommand(new ReplaceCommand(".view-dom-id-$dom_id", $view->preview($display_id, $args)));
}
drupal_alter('views_ajax_data', $commands, $view);
return array('#type' => 'ajax', '#commands' => $commands);
return $response;
}
}
/**
* Creates a Drupal AJAX 'viewsSetForm' command.
*
* @param $output
* The form to display in the modal.
* @param $title
* The title.
* @param $url
* An optional URL.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_set_form($output, $title, $url = NULL) {
$command = array(
'command' => 'viewsSetForm',
'output' => $output,
'title' => $title,
);
if (isset($url)) {
$command['url'] = $url;
}
return $command;
}
/**
* Creates a Drupal AJAX 'viewsDismissForm' command.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_dismiss_form() {
$command = array(
'command' => 'viewsDismissForm',
);
return $command;
}
/**
* Creates a Drupal AJAX 'viewsHilite' command.
*
* @param $selector
* The selector to highlight
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_hilite($selector) {
return array(
'command' => 'viewsHilite',
'selector' => $selector,
);
}
/**
* Creates a Drupal AJAX 'addTab' command.
*
* @param $id
* The DOM ID.
* @param $title
* The title.
* @param $body
* The body.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_add_tab($id, $title, $body) {
$command = array(
'command' => 'viewsAddTab',
'id' => $id,
'title' => $title,
'body' => $body,
);
return $command;
}
/**
* Scroll to top of the current view.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_scroll_top($selector) {
$command = array(
'command' => 'viewsScrollTop',
'selector' => $selector,
);
return $command;
}
/**
* Shows Save and Cancel buttons.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_show_buttons() {
$command = array(
'command' => 'viewsShowButtons',
);
return $command;
}
/**
* Trigger the Views live preview.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_trigger_preview() {
$command = array(
'command' => 'viewsTriggerPreview',
);
return $command;
}
/**
* Replace the page title.
*
* @return
* An array suitable for use with the ajax_render() function.
*/
function views_ajax_command_replace_title($title) {
$command = array(
'command' => 'viewsReplaceTitle',
'title' => $title,
'siteName' => config('system.site')->get('name'),
);
return $command;
}
/**
* Return an AJAX error.
*/
function views_ajax_error($message) {
$commands = array();
$commands[] = views_ajax_command_set_form($message, t('Error'));
return $commands;
}
/**
* Wrapper around drupal_build_form to handle some AJAX stuff automatically.
* This makes some assumptions about the client.
......@@ -249,7 +113,7 @@ function views_ajax_form_wrapper($form_id, &$form_state) {
if (!empty($form_state['ajax']) && (empty($form_state['executed']) || !empty($form_state['rerender']))) {
// If the form didn't execute and we're using ajax, build up a
// Ajax command list to execute.
$commands = array();
$response = new AjaxResponse();
$display = '';
if ($messages = theme('status_messages')) {
......@@ -261,13 +125,13 @@ function views_ajax_form_wrapper($form_id, &$form_state) {
$url = empty($form_state['url']) ? url(current_path(), array('absolute' => TRUE)) : $form_state['url'];
$commands[] = views_ajax_command_set_form($display, $title, $url);
$response->addCommand(new SetFormCommand($display, $title, $url));
if (!empty($form_state['#section'])) {
$commands[] = views_ajax_command_hilite('.' . drupal_clean_css_identifier($form_state['#section']));
$response->addCommand(new HighlightCommand('.' . drupal_clean_css_identifier($form_state['#section'])));
}
return $commands;
return $response;
}
// These forms have the title built in, so set the title here:
......
<?php
/**
* @file
* Contains \Drupal\views\Ajax\DismissFormCommand.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* Provides an AJAX command for closing the views form modal.
*
* This command is implemented in Drupal.ajax.prototype.commands.viewsDismissForm.
*/
class DismissFormCommand implements CommandInterface {
/**
* Implements \Drupal\Core\Ajax\CommandInterface::render().
*/
public function render() {
return array(
'command' => 'viewsDismissForm',
);
}
}
<?php
/**
* @file
* Contains \Drupal\views\Ajax\HighlightCommand.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* Provides an AJAX command for highlighting a certain new piece of html.
*
* This command is implemented in Drupal.ajax.prototype.commands.viewsHighlight.
*/
class HighlightCommand implements CommandInterface {
/**
* A CSS selector string.
*
* @var string
*/
protected $selector;
/**
* Constructs a \Drupal\views\Ajax\HighlightCommand object.
*
* @param string $selector
* A CSS selector.
*/
public function __construct($selector) {
$this->selector = $selector;
}
/**
* Implements \Drupal\Core\Ajax\CommandInterface::render().
*/
public function render() {
return array(
'command' => 'viewsHighlight',
'selector' => $this->selector,
);
}
}
<?php
/**
* @file
* Contains \Drupal\views\Ajax\ReplaceTitleCommand.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* Provides an AJAX command for replacing the page title.
*
* This command is implemented in Drupal.ajax.prototype.commands.viewsReplaceTitle.
*/
class ReplaceTitleCommand implements CommandInterface {
/**
* The page title to replace.
*
* @var string
*/
protected $title;
/**
* Constructs a \Drupal\views\Ajax\ReplaceTitleCommand object.
*
* @param string $title
* The title of the page.
*/
public function __construct($title) {
$this->title = $title;
}
/**
* Implements \Drupal\Core\Ajax\CommandInterface::render().
*/
public function render() {
return array(
'command' => 'viewsReplaceTitle',
'selector' => $this->title,
);
}
}
<?php
/**
* @file
* Contains \Drupal\views\Ajax\ScrollTopCommand.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* Provides an AJAX command for scolling to the top of an element.
*
* This command is implemented in Drupal.ajax.prototype.commands.viewsScrollTop.
*/
class ScrollTopCommand implements CommandInterface {
/**
* A CSS selector string.
*
* @var string
*/
protected $selector;
/**
* Constructs a \Drupal\views\Ajax\ScrollTopCommand object.
*
* @param string $selector
* A CSS selector.
*/
public function __construct($selector) {
$this->selector = $selector;
}
/**
* Implements \Drupal\Core\Ajax\CommandInterface::render().
*/
public function render() {
return array(
'command' => 'viewsScrollTop',
'selector' => $this->selector,
);
}
}
<?php
/**
* @file
* Contains \Drupal\views\Ajax\SetFormCommand.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* Provides an AJAX command for setting a form in the views edit modal.
*
* This command is implemented in Drupal.ajax.prototype.commands.viewsSetForm.
*/
class SetFormCommand implements CommandInterface {
/**
* The rendered output of the form.
*
* @var string
*/
protected $output;
/**
* The title of the form.
*
* @var string
*/
protected $title;
/**
* The URL of the form.
*
* @var string
*/
protected $url;
/**
* Constructs a \Drupal\views\Ajax\ReplaceTitleCommand object.
*
* @param string $output
* The form to display in the modal.
* @param string $title
* The title of the form.
* @param string $url
* (optional) An optional URL of the form.
*/
public function __construct($output, $title, $url = NULL) {
$this->output = $output;
$this->title = $title;
$this->url = $url;
}
/**
* Implements \Drupal\Core\Ajax\CommandInterface::render().
*/
public function render() {
$command = array(
'command' => 'viewsSetForm',
'output' => $this->output,
'title' => $this->title,
);
if (isset($this->url)) {
$command['url'] = $this->url;
}
return $command;
}
}
<?php
/**
* @file
* Contains \Drupal\views\Ajax\ShowButtonsCommand.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* Provides an AJAX command for showing the save and cancel buttons.
*
* This command is implemented in Drupal.ajax.prototype.commands.viewsShowButtons.
*/
class ShowButtonsCommand implements CommandInterface {
/**
* Implements \Drupal\Core\Ajax\CommandInterface::render().
*/
public function render() {
return array(
'command' => 'viewsShowButtons',
);
}
}
<?php
/**
* @file
* Contains \Drupal\views\Ajax\TriggerPreviewCommand.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\CommandInterface;
/**
* Provides an AJAX command for triggering the views live preview.
*
* This command is implemented in Drupal.ajax.prototype.commands.viewsTriggerPreview.
*/
class TriggerPreviewCommand implements CommandInterface {
/**
* Implements \Drupal\Core\Ajax\CommandInterface::render().
*/
public function render() {
return array(
'command' => 'viewsTriggerPreview',
);
}
}
<?php
/**
* @file
* Contains \Drupal\views\Ajax\ViewAjaxResponse.
*/
namespace Drupal\views\Ajax;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\views\ViewExecutable;
/**
* Custom JSON response object for an ajax view response.
*
* We use a special response object to be able to fire a proper alter hook.
*/
class ViewAjaxResponse extends AjaxResponse {
/**
* The view executed on this ajax request.
*
* @var \Drupal\views\ViewExecutable
*/
protected $view;
/**
* Sets the executed view of this response.
*
* @param \Drupal\views\ViewExecutable $view
* The View executed on this ajax request.
*/
public function setView(ViewExecutable $view) {
$this->view = $view;
}
/**
* Gets the executed view of this response.
*
* @return \Drupal\views\ViewExecutable $view
* The View executed on this ajax request.
*/
public function getView() {
return $this->view;
}
}
......@@ -594,25 +594,7 @@ function hook_views_ui_display_top_links_alter(array &$links, ViewExecutable $vi
}
}
/**
* Alter the commands used on a Views AJAX request.
*
* @param array $commands
* An array of ajax commands.
* @param \Drupal\views\ViewExecutable $view
* The view which is requested.
*
* @see views_ajax()
*/
function hook_views_ajax_data_alter(array &$commands, ViewExecutable $view) {
// Replace Views' method for scrolling to the top of the element with your
// custom scrolling method.
foreach ($commands as &$command) {
if ($command['method'] == 'viewsScrollTop') {
$command['method'] .= 'myScrollTop';
}
}
}
// @todo Describe how to alter a view ajax response with event listeners.
/**
* Allow modules to respond to the invalidation of the Views cache.
......
......@@ -7,6 +7,11 @@
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Database\Database;
use Drupal\views\Ajax\ReplaceTitleCommand;
use Drupal\views\Ajax\TriggerPreviewCommand;
use Drupal\views\Ajax\ShowButtonsCommand;
use Drupal\views\Ajax\DismissFormCommand;
use Drupal\Core\Ajax\AjaxResponse;
use Symfony\Component\HttpFoundation\JsonResponse;
use Drupal\views_ui\ViewUI;
use Drupal\views_ui\ViewFormControllerBase;
......@@ -603,7 +608,7 @@ function views_ui_ajax_form($js, $key, ViewUI $view, $display_id = '') {
// reset the drupal_add_js() static before rendering the second time.
$drupal_add_js_original = drupal_add_js();
$drupal_add_js = &drupal_static('drupal_add_js');
$output = views_ajax_form_wrapper($form_state['form_id'], $form_state);
$response = views_ajax_form_wrapper($form_state['form_id'], $form_state);
if ($form_state['submitted'] && empty($form_state['rerender'])) {
// Sometimes we need to re-generate the form for multi-step type operations.
$object = NULL;
......@@ -618,19 +623,19 @@ function views_ui_ajax_form($js, $key, ViewUI $view, $display_id = '') {
if (!$js) {
return drupal_goto(views_ui_build_form_url($form_state));
}
$output = views_ajax_form_wrapper($form_state['form_id'], $form_state);
$response = views_ajax_form_wrapper($form_state['form_id'], $form_state);
}
elseif (!$js) {
// if nothing on the stack, non-js forms just go back to the main view editor.
return drupal_goto("admin/structure/views/view/{$view->id()}/edit");
}
else {
$output = array();
$output[] = views_ajax_command_dismiss_form();
$output[] = views_ajax_command_show_buttons();
$output[] = views_ajax_command_trigger_preview();
$response = new AjaxResponse();
$response->addCommand(new DismissFormCommand());
$response->addCommand(new ShowButtonsCommand());
$response->addCommand(new TriggerPreviewCommand());
if (!empty($form_state['#page_title'])) {
$output[] = views_ajax_command_replace_title($form_state['#page_title']);
$response->addCommand(new ReplaceTitleCommand($form_state['#page_title']));
}
}
// If this form was for view-wide changes, there's no need to regenerate
......@@ -638,11 +643,11 @@ function views_ui_ajax_form($js, $key, ViewUI $view, $display_id = '') {
if ($display_id !== '') {
drupal_container()->get('plugin.manager.entity')
->getFormController('view', 'edit')
->rebuildCurrentTab($view, $output, $display_id);
->rebuildCurrentTab($view, $response, $display_id);
}
}
return $js ? array('#type' => 'ajax', '#commands' => $output) : $output;
return $response;
}
/**
......
......@@ -42,25 +42,11 @@
$(Drupal.settings.views.ajax.popup).dialog('close');
};
Drupal.ajax.prototype.commands.viewsHilite = function (ajax, response, status) {
Drupal.ajax.prototype.commands.viewsHighlight = function (ajax, response, status) {
$('.hilited').removeClass('hilited');
$(response.selector).addClass('hilited');
};
Drupal.ajax.prototype.commands.viewsAddTab = function (ajax, response, status) {
var id = '#views-tab-' + response.id;
$('#views-tabset').viewsAddTab(id, response.title, 0);
$(id).html(response.body).addClass('views-tab');
// Update the preview widget to preview the new tab.
var display_id = id.replace('#views-tab-', '');
$("#preview-display-id").append('<option selected="selected" value="' + display_id + '">' + response.title + '</option>');
Drupal.attachBehaviors(id);
var instance = $.viewsUi.tabs.instances[$('#views-tabset').get(0).UI_TABS_UUID];
$('#views-tabset').viewsClickTab(instance.$tabs.length);
};
Drupal.ajax.prototype.commands.viewsShowButtons = function (ajax, response, status) {
$('div.views-edit-view div.form-actions').removeClass('js-hide');
$('div.views-edit-view div.view-changed.messages').removeClass('js-hide');
......
......@@ -7,6 +7,9 @@
namespace Drupal\views_ui;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Component\Utility\NestedArray;
use Drupal\views\ViewExecutable;
......@@ -607,8 +610,15 @@ public function submitDisplayDelete($form, &$form_state) {
/**
* Regenerate the current tab for AJAX updates.
*
* @param \Drupal\views_ui\ViewUI $view
* The view to regenerate its tab.
* @param \Drupal\Core\Ajax\AjaxResponse $response
* The response object to add new commands to.
* @param string $display_id
* The display ID of the tab to regenerate.
*/
public function rebuildCurrentTab(ViewUI $view, &$output, $display_id) {
public function rebuildCurrentTab(ViewUI $view, AjaxResponse $response, $display_id) {
$view->displayID = $display_id;
if (!$view->get('executable')->setDisplay('default')) {
return;
......@@ -617,12 +627,12 @@ public function rebuildCurrentTab(ViewUI $view, &$output, $display_id) {
// Regenerate the main display area.
$build = $this->getDisplayTab($view);
static::addMicroweights($build);
$output[] = ajax_command_html('#views-tab-' . $display_id, drupal_render($build));