Issue #2407859 by vaplas, lauriii, vprocessor, drpal, jwilson3, sidharthap, aprogs, finnsky: Allow theming throbber element
parent
3663ab6bc0
commit
bae2ff8761
|
|
@ -811,6 +811,40 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An animated progress throbber and container element for AJAX operations.
|
||||||
|
*
|
||||||
|
* @param {string} [message]
|
||||||
|
* (optional) The message shown on the UI.
|
||||||
|
* @return {string}
|
||||||
|
* The HTML markup for the throbber.
|
||||||
|
*/
|
||||||
|
Drupal.theme.ajaxProgressThrobber = (message) => {
|
||||||
|
// Build markup without adding extra white space since it affects rendering.
|
||||||
|
const messageMarkup = typeof message === 'string' ? Drupal.theme('ajaxProgressMessage', message) : '';
|
||||||
|
const throbber = '<div class="throbber"> </div>';
|
||||||
|
|
||||||
|
return `<div class="ajax-progress ajax-progress-throbber">${throbber}${messageMarkup}</div>`;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An animated progress throbber and container element for AJAX operations.
|
||||||
|
*
|
||||||
|
* @return {string}
|
||||||
|
* The HTML markup for the throbber.
|
||||||
|
*/
|
||||||
|
Drupal.theme.ajaxProgressIndicatorFullscreen = () => '<div class="ajax-progress ajax-progress-fullscreen"> </div>';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats text accompanying the AJAX progress throbber.
|
||||||
|
*
|
||||||
|
* @param {string} message
|
||||||
|
* The message shown on the UI.
|
||||||
|
* @return {string}
|
||||||
|
* The HTML markup for the throbber.
|
||||||
|
*/
|
||||||
|
Drupal.theme.ajaxProgressMessage = message => `<div class="message">${message}</div>`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the progress bar progress indicator.
|
* Sets the progress bar progress indicator.
|
||||||
*/
|
*/
|
||||||
|
|
@ -831,10 +865,7 @@
|
||||||
* Sets the throbber progress indicator.
|
* Sets the throbber progress indicator.
|
||||||
*/
|
*/
|
||||||
Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
|
Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
|
||||||
this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>');
|
this.progress.element = $(Drupal.theme('ajaxProgressThrobber', this.progress.message));
|
||||||
if (this.progress.message) {
|
|
||||||
this.progress.element.find('.throbber').after(`<div class="message">${this.progress.message}</div>`);
|
|
||||||
}
|
|
||||||
$(this.element).after(this.progress.element);
|
$(this.element).after(this.progress.element);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -842,7 +873,7 @@
|
||||||
* Sets the fullscreen progress indicator.
|
* Sets the fullscreen progress indicator.
|
||||||
*/
|
*/
|
||||||
Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
|
Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
|
||||||
this.progress.element = $('<div class="ajax-progress ajax-progress-fullscreen"> </div>');
|
this.progress.element = $(Drupal.theme('ajaxProgressIndicatorFullscreen'));
|
||||||
$('body').after(this.progress.element);
|
$('body').after(this.progress.element);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -368,6 +368,21 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Drupal.theme.ajaxProgressThrobber = function (message) {
|
||||||
|
var messageMarkup = typeof message === 'string' ? Drupal.theme('ajaxProgressMessage', message) : '';
|
||||||
|
var throbber = '<div class="throbber"> </div>';
|
||||||
|
|
||||||
|
return '<div class="ajax-progress ajax-progress-throbber">' + throbber + messageMarkup + '</div>';
|
||||||
|
};
|
||||||
|
|
||||||
|
Drupal.theme.ajaxProgressIndicatorFullscreen = function () {
|
||||||
|
return '<div class="ajax-progress ajax-progress-fullscreen"> </div>';
|
||||||
|
};
|
||||||
|
|
||||||
|
Drupal.theme.ajaxProgressMessage = function (message) {
|
||||||
|
return '<div class="message">' + message + '</div>';
|
||||||
|
};
|
||||||
|
|
||||||
Drupal.Ajax.prototype.setProgressIndicatorBar = function () {
|
Drupal.Ajax.prototype.setProgressIndicatorBar = function () {
|
||||||
var progressBar = new Drupal.ProgressBar('ajax-progress-' + this.element.id, $.noop, this.progress.method, $.noop);
|
var progressBar = new Drupal.ProgressBar('ajax-progress-' + this.element.id, $.noop, this.progress.method, $.noop);
|
||||||
if (this.progress.message) {
|
if (this.progress.message) {
|
||||||
|
|
@ -382,15 +397,12 @@ function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr
|
||||||
};
|
};
|
||||||
|
|
||||||
Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
|
Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
|
||||||
this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>');
|
this.progress.element = $(Drupal.theme('ajaxProgressThrobber', this.progress.message));
|
||||||
if (this.progress.message) {
|
|
||||||
this.progress.element.find('.throbber').after('<div class="message">' + this.progress.message + '</div>');
|
|
||||||
}
|
|
||||||
$(this.element).after(this.progress.element);
|
$(this.element).after(this.progress.element);
|
||||||
};
|
};
|
||||||
|
|
||||||
Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
|
Drupal.Ajax.prototype.setProgressIndicatorFullscreen = function () {
|
||||||
this.progress.element = $('<div class="ajax-progress ajax-progress-fullscreen"> </div>');
|
this.progress.element = $(Drupal.theme('ajaxProgressIndicatorFullscreen'));
|
||||||
$('body').after(this.progress.element);
|
$('body').after(this.progress.element);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@
|
||||||
|
|
||||||
if (rowNames.length) {
|
if (rowNames.length) {
|
||||||
// Add a throbber next each of the ajaxElements.
|
// Add a throbber next each of the ajaxElements.
|
||||||
$(ajaxElements).after('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>');
|
$(ajaxElements).after(Drupal.theme.ajaxProgressThrobber());
|
||||||
|
|
||||||
// Fire the Ajax update.
|
// Fire the Ajax update.
|
||||||
$('input[name=refresh_rows]').val(rowNames.join(' '));
|
$('input[name=refresh_rows]').val(rowNames.join(' '));
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
if (rowNames.length) {
|
if (rowNames.length) {
|
||||||
$(ajaxElements).after('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>');
|
$(ajaxElements).after(Drupal.theme.ajaxProgressThrobber());
|
||||||
|
|
||||||
$('input[name=refresh_rows]').val(rowNames.join(' '));
|
$('input[name=refresh_rows]').val(rowNames.join(' '));
|
||||||
$('input[data-drupal-selector="edit-refresh"]').trigger('mousedown');
|
$('input[data-drupal-selector="edit-refresh"]').trigger('mousedown');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
name: Hold test
|
||||||
|
type: module
|
||||||
|
description: 'Support testing with request/response hold.'
|
||||||
|
package: Testing
|
||||||
|
version: VERSION
|
||||||
|
core: 8.x
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Install, update and uninstall functions for the hold_test module.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implements hook_install().
|
||||||
|
*/
|
||||||
|
function hold_test_install() {
|
||||||
|
hold_test_request(FALSE);
|
||||||
|
hold_test_response(FALSE);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* Contains functions for testing hold request/response.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request hold.
|
||||||
|
*
|
||||||
|
* @param bool $status
|
||||||
|
* TRUE - enable hold, FALSE - disable hold.
|
||||||
|
*/
|
||||||
|
function hold_test_request($status) {
|
||||||
|
file_put_contents(\Drupal::root() . '/sites/default/files/simpletest/hold_test_request.txt', $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response hold.
|
||||||
|
*
|
||||||
|
* @param bool $status
|
||||||
|
* TRUE - enable hold, FALSE - disable hold.
|
||||||
|
*/
|
||||||
|
function hold_test_response($status) {
|
||||||
|
file_put_contents(\Drupal::root() . '/sites/default/files/simpletest/hold_test_response.txt', $status);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
services:
|
||||||
|
hold_test.response:
|
||||||
|
class: Drupal\hold_test\EventSubscriber\HoldTestSubscriber
|
||||||
|
tags:
|
||||||
|
- { name: event_subscriber }
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\hold_test\EventSubscriber;
|
||||||
|
|
||||||
|
use Symfony\Component\HttpKernel\KernelEvents;
|
||||||
|
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response subscriber to test hold.
|
||||||
|
*/
|
||||||
|
class HoldTestSubscriber implements EventSubscriberInterface {
|
||||||
|
|
||||||
|
const HOLD_REQUEST = 'request';
|
||||||
|
const HOLD_RESPONSE = 'response';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request hold.
|
||||||
|
*/
|
||||||
|
public function onRequest() {
|
||||||
|
$this->hold(static::HOLD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response hold.
|
||||||
|
*/
|
||||||
|
public function onRespond() {
|
||||||
|
$this->hold(static::HOLD_RESPONSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hold process by type.
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* Type of hold.
|
||||||
|
*/
|
||||||
|
protected function hold($type) {
|
||||||
|
$path = \Drupal::root() . "/sites/default/files/simpletest/hold_test_$type.txt";
|
||||||
|
do {
|
||||||
|
$status = (bool) file_get_contents($path);
|
||||||
|
} while ($status && (NULL === usleep(100000)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static function getSubscribedEvents() {
|
||||||
|
$events[KernelEvents::REQUEST][] = ['onRequest'];
|
||||||
|
$events[KernelEvents::RESPONSE][] = ['onRespond'];
|
||||||
|
return $events;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\FunctionalJavascriptTests\Ajax;
|
||||||
|
|
||||||
|
use Drupal\FunctionalJavascriptTests\DrupalSelenium2Driver;
|
||||||
|
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the throbber.
|
||||||
|
*
|
||||||
|
* @group Ajax
|
||||||
|
*/
|
||||||
|
class ThrobberTest extends JavascriptTestBase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected $minkDefaultDriverClass = DrupalSelenium2Driver::class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public static $modules = [
|
||||||
|
'node',
|
||||||
|
'views',
|
||||||
|
'views_ui',
|
||||||
|
'views_ui_test_field',
|
||||||
|
'hold_test',
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$admin_user = $this->drupalCreateUser([
|
||||||
|
'administer views',
|
||||||
|
]);
|
||||||
|
$this->drupalLogin($admin_user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests theming throbber element.
|
||||||
|
*/
|
||||||
|
public function testThemingThrobberElement() {
|
||||||
|
$session = $this->getSession();
|
||||||
|
$web_assert = $this->assertSession();
|
||||||
|
$page = $session->getPage();
|
||||||
|
|
||||||
|
$custom_ajax_progress_indicator_fullscreen = <<<JS
|
||||||
|
Drupal.theme.ajaxProgressIndicatorFullscreen = function () {
|
||||||
|
return '<div class="custom-ajax-progress-fullscreen"></div>';
|
||||||
|
};
|
||||||
|
JS;
|
||||||
|
$custom_ajax_progress_throbber = <<<JS
|
||||||
|
Drupal.theme.ajaxProgressThrobber = function (message) {
|
||||||
|
return '<div class="custom-ajax-progress-throbber"></div>';
|
||||||
|
};
|
||||||
|
JS;
|
||||||
|
$custom_ajax_progress_message = <<<JS
|
||||||
|
Drupal.theme.ajaxProgressMessage = function (message) {
|
||||||
|
return '<div class="custom-ajax-progress-message">Hold door!</div>';
|
||||||
|
};
|
||||||
|
JS;
|
||||||
|
|
||||||
|
$this->drupalGet('admin/structure/views/view/content');
|
||||||
|
$this->waitForNoElement('.ajax-progress-fullscreen');
|
||||||
|
|
||||||
|
// Test theming fullscreen throbber.
|
||||||
|
$session->executeScript($custom_ajax_progress_indicator_fullscreen);
|
||||||
|
hold_test_response(TRUE);
|
||||||
|
$page->clickLink('Content: Published (grouped)');
|
||||||
|
$this->assertNotNull($web_assert->waitForElement('css', '.custom-ajax-progress-fullscreen'), 'Custom ajaxProgressIndicatorFullscreen.');
|
||||||
|
hold_test_response(FALSE);
|
||||||
|
$this->waitForNoElement('.custom-ajax-progress-fullscreen');
|
||||||
|
|
||||||
|
// Test theming throbber message.
|
||||||
|
$web_assert->waitForElementVisible('css', '[data-drupal-selector="edit-options-group-info-add-group"]');
|
||||||
|
$session->executeScript($custom_ajax_progress_message);
|
||||||
|
hold_test_response(TRUE);
|
||||||
|
$page->pressButton('Add another item');
|
||||||
|
$this->assertNotNull($web_assert->waitForElement('css', '.ajax-progress-throbber .custom-ajax-progress-message'), 'Custom ajaxProgressMessage.');
|
||||||
|
hold_test_response(FALSE);
|
||||||
|
$this->waitForNoElement('.ajax-progress-throbber');
|
||||||
|
|
||||||
|
// Test theming throbber.
|
||||||
|
$web_assert->waitForElementVisible('css', '[data-drupal-selector="edit-options-group-info-group-items-3-title"]');
|
||||||
|
$session->executeScript($custom_ajax_progress_throbber);
|
||||||
|
hold_test_response(TRUE);
|
||||||
|
$page->pressButton('Add another item');
|
||||||
|
$this->assertNotNull($web_assert->waitForElement('css', '.custom-ajax-progress-throbber'), 'Custom ajaxProgressThrobber.');
|
||||||
|
hold_test_response(FALSE);
|
||||||
|
$this->waitForNoElement('.custom-ajax-progress-throbber');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for an element to be removed from the page.
|
||||||
|
*
|
||||||
|
* @param string $selector
|
||||||
|
* CSS selector.
|
||||||
|
* @param int $timeout
|
||||||
|
* (optional) Timeout in milliseconds, defaults to 10000.
|
||||||
|
*
|
||||||
|
* @todo Remove in https://www.drupal.org/node/2892440.
|
||||||
|
*/
|
||||||
|
protected function waitForNoElement($selector, $timeout = 10000) {
|
||||||
|
$condition = "(typeof jQuery !== 'undefined' && jQuery('$selector').length === 0)";
|
||||||
|
$this->assertJsCondition($condition, $timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue