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.
 | 
			
		||||
   */
 | 
			
		||||
| 
						 | 
				
			
			@ -831,10 +865,7 @@
 | 
			
		|||
   * Sets the throbber progress indicator.
 | 
			
		||||
   */
 | 
			
		||||
  Drupal.Ajax.prototype.setProgressIndicatorThrobber = function () {
 | 
			
		||||
    this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>');
 | 
			
		||||
    if (this.progress.message) {
 | 
			
		||||
      this.progress.element.find('.throbber').after(`<div class="message">${this.progress.message}</div>`);
 | 
			
		||||
    }
 | 
			
		||||
    this.progress.element = $(Drupal.theme('ajaxProgressThrobber', this.progress.message));
 | 
			
		||||
    $(this.element).after(this.progress.element);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -842,7 +873,7 @@
 | 
			
		|||
   * Sets the fullscreen progress indicator.
 | 
			
		||||
   */
 | 
			
		||||
  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);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 () {
 | 
			
		||||
    var progressBar = new Drupal.ProgressBar('ajax-progress-' + this.element.id, $.noop, this.progress.method, $.noop);
 | 
			
		||||
    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 () {
 | 
			
		||||
    this.progress.element = $('<div class="ajax-progress ajax-progress-throbber"><div class="throbber"> </div></div>');
 | 
			
		||||
    if (this.progress.message) {
 | 
			
		||||
      this.progress.element.find('.throbber').after('<div class="message">' + this.progress.message + '</div>');
 | 
			
		||||
    }
 | 
			
		||||
    this.progress.element = $(Drupal.theme('ajaxProgressThrobber', this.progress.message));
 | 
			
		||||
    $(this.element).after(this.progress.element);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  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);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -219,7 +219,7 @@
 | 
			
		|||
 | 
			
		||||
      if (rowNames.length) {
 | 
			
		||||
        // 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.
 | 
			
		||||
        $('input[name=refresh_rows]').val(rowNames.join(' '));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -126,7 +126,7 @@
 | 
			
		|||
      });
 | 
			
		||||
 | 
			
		||||
      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[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