refreshless-8.x-1.x-dev/components/progress-bar-delay/progress-bar-delay.js

components/progress-bar-delay/progress-bar-delay.js
/**
 * @file
 * RefreshLess progress bar delay.
 *
 * @see https://www.drupal.org/project/refreshless/issues/3488464
 *   Issue for adapting this out of Turbo.
 *
 * @see https://github.com/hotwired/turbo/blob/ea54ae5ad4b6b28cb62ccd62951352641ed08293/src/core/drive/progress_bar.js
 *   Originally adapted from the Turbo progress bar.
 */
(function(Drupal, $) {

  'use strict';

  // @todo Remove when SDC additive aggregation is fixed.
  //
  // @see https://www.drupal.org/project/refreshless/issues/3543409
  if (Drupal?.RefreshLess?.classes?.ProgressBarDelay) {
    return;
  }

  /**
   * CSS custom property base name.
   *
   * @type {String}
   */
  const customPropertyBase = '--refreshless-progress-bar';

  /**
   * Name of the CSS custom property containing the progress bar delay.
   *
   * The value will be a time in ms.
   *
   * @type {String}
   */
  const delayCustomProperty = `${customPropertyBase}-delay`;

  /**
   * The <html> element.
   *
   * @type {HTMLHtmlElement}
   */
  const html = document.documentElement;

  /**
   * Represents a progress bar delay wrapper.
   */
  class ProgressBarDelay {

    /**
     * Time in milliseconds before the progress bar is shown.
     *
     * @type {Number}
     */
    #delay = 0;

    /**
     * The visit timeout ID, if any.
     *
     * @type {Number|null}
     */
    #visitTimeout = null;

    /**
     * The form submit timeout ID, if any.
     *
     * @type {Number|null}
     */
    #formTimeout = null;

    /**
     * The progress bar instance that we're wrapping.
     *
     * @type {ProgressBar}
     */
    #progressBar;

    constructor(delay, progressBar) {

      this.#delay = delay;

      this.#progressBar = progressBar;

    }

    /**
     * Destroy this instance.
     */
    destroy() {

      // These will cancel any existing timeouts if they're running, and will
      // call this.uninstall() for us.
      this.hideVisit();
      this.hideForm();

      this.#progressBar.destroy();

    }

    /**
     * Install the progress bar in the document and set various properties.
     */
    install() {

      html.style.setProperty(
        delayCustomProperty, `${this.#delay}ms`,
      );

    }

    /**
     * Uninstall the progress bar from the document and remove properties.
     */
    uninstall() {

      html.style.removeProperty(delayCustomProperty);

    }

    /**
     * Start the timeout to show the progress bar.
     *
     * @param {Number|null} timeoutId
     *   An existing timeout ID, if any.
     *
     * @return {Number}
     *   A new timeout ID.
     */
    showAfterDelay(timeoutId) {

      if (timeoutId !== null) {
        window.clearTimeout(timeoutId);
      }

      this.install();

      return window.setTimeout(async () => {

        await this.#progressBar.setValue(0);

        this.#progressBar.show();

      }, this.#delay);

    }

    /**
     * Hide the progress bar and cancel an existing timeout, if any.
     *
     * @param {Number|null} timeoutId
     *
     * @return {null}
     */
    hideAndCancelDelay(timeoutId) {

      if (timeoutId === null) {
        return timeoutId;
      }

      window.clearTimeout(timeoutId);

      timeoutId = null;

      this.#progressBar.finish().then(() => this.uninstall());

      return timeoutId;

    }

    /**
     * Show the progress bar after a delay for non-form submission visits.
     */
    showVisitAfterDelay() {

      this.#visitTimeout = this.showAfterDelay(this.#visitTimeout);

    }

    /**
     * Hide the progress bar for non-form submission visits.
     */
    hideVisit() {

      this.#visitTimeout = this.hideAndCancelDelay(this.#visitTimeout);

    }

    /**
     * Show the progress bar after a delay for form submissions.
     */
    showFormAfterDelay() {

      // Unlike the visit progress bar, we prefer to not replace an existing
      // form submission progress bar.
      //
      // @todo Is this necessary? Don't browsers by default treat both types the
      //   same when showing progress?
      if (this.#formTimeout !== null) {
        return;
      }

      this.#formTimeout = this.showAfterDelay(this.#formTimeout);

    }

    /**
     * Hide the progress bar for form submissions.
     */
    hideForm() {

      this.#formTimeout = this.hideAndCancelDelay(this.#formTimeout);

    }

    /**
     * Get the progress bar instance we're wrapping.
     *
     * @return {ProgressBar}
     */
    get progressBar() {
      return this.#progressBar;
    }

  }

  // Merge Drupal.RefreshLess.classes into the existing Drupal global.
  $.extend(true, Drupal, {RefreshLess: {classes: {
    ProgressBarDelay: ProgressBarDelay,
  }}});

})(Drupal, jQuery);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc