Security update for Core, with self-updated composer
[yaffs-website] / web / core / misc / progress.es6.js
diff --git a/web/core/misc/progress.es6.js b/web/core/misc/progress.es6.js
new file mode 100644 (file)
index 0000000..bec63d5
--- /dev/null
@@ -0,0 +1,167 @@
+/**
+ * @file
+ * Progress bar.
+ */
+
+(function ($, Drupal) {
+  /**
+   * Theme function for the progress bar.
+   *
+   * @param {string} id
+   *   The id for the progress bar.
+   *
+   * @return {string}
+   *   The HTML for the progress bar.
+   */
+  Drupal.theme.progressBar = function (id) {
+    return `<div id="${id}" class="progress" aria-live="polite">` +
+      '<div class="progress__label">&nbsp;</div>' +
+      '<div class="progress__track"><div class="progress__bar"></div></div>' +
+      '<div class="progress__percentage"></div>' +
+      '<div class="progress__description">&nbsp;</div>' +
+      '</div>';
+  };
+
+  /**
+   * A progressbar object. Initialized with the given id. Must be inserted into
+   * the DOM afterwards through progressBar.element.
+   *
+   * Method is the function which will perform the HTTP request to get the
+   * progress bar state. Either "GET" or "POST".
+   *
+   * @example
+   * pb = new Drupal.ProgressBar('myProgressBar');
+   * some_element.appendChild(pb.element);
+   *
+   * @constructor
+   *
+   * @param {string} id
+   *   The id for the progressbar.
+   * @param {function} updateCallback
+   *   Callback to run on update.
+   * @param {string} method
+   *   HTTP method to use.
+   * @param {function} errorCallback
+   *   Callback to call on error.
+   */
+  Drupal.ProgressBar = function (id, updateCallback, method, errorCallback) {
+    this.id = id;
+    this.method = method || 'GET';
+    this.updateCallback = updateCallback;
+    this.errorCallback = errorCallback;
+
+    // The WAI-ARIA setting aria-live="polite" will announce changes after
+    // users
+    // have completed their current activity and not interrupt the screen
+    // reader.
+    this.element = $(Drupal.theme('progressBar', id));
+  };
+
+  $.extend(Drupal.ProgressBar.prototype, /** @lends Drupal.ProgressBar# */{
+
+    /**
+     * Set the percentage and status message for the progressbar.
+     *
+     * @param {number} percentage
+     *   The progress percentage.
+     * @param {string} message
+     *   The message to show the user.
+     * @param {string} label
+     *   The text for the progressbar label.
+     */
+    setProgress(percentage, message, label) {
+      if (percentage >= 0 && percentage <= 100) {
+        $(this.element).find('div.progress__bar').css('width', `${percentage}%`);
+        $(this.element).find('div.progress__percentage').html(`${percentage}%`);
+      }
+      $('div.progress__description', this.element).html(message);
+      $('div.progress__label', this.element).html(label);
+      if (this.updateCallback) {
+        this.updateCallback(percentage, message, this);
+      }
+    },
+
+    /**
+     * Start monitoring progress via Ajax.
+     *
+     * @param {string} uri
+     *   The URI to use for monitoring.
+     * @param {number} delay
+     *   The delay for calling the monitoring URI.
+     */
+    startMonitoring(uri, delay) {
+      this.delay = delay;
+      this.uri = uri;
+      this.sendPing();
+    },
+
+    /**
+     * Stop monitoring progress via Ajax.
+     */
+    stopMonitoring() {
+      clearTimeout(this.timer);
+      // This allows monitoring to be stopped from within the callback.
+      this.uri = null;
+    },
+
+    /**
+     * Request progress data from server.
+     */
+    sendPing() {
+      if (this.timer) {
+        clearTimeout(this.timer);
+      }
+      if (this.uri) {
+        const pb = this;
+        // When doing a post request, you need non-null data. Otherwise a
+        // HTTP 411 or HTTP 406 (with Apache mod_security) error may result.
+        let uri = this.uri;
+        if (uri.indexOf('?') === -1) {
+          uri += '?';
+        }
+        else {
+          uri += '&';
+        }
+        uri += '_format=json';
+        $.ajax({
+          type: this.method,
+          url: uri,
+          data: '',
+          dataType: 'json',
+          success(progress) {
+            // Display errors.
+            if (progress.status === 0) {
+              pb.displayError(progress.data);
+              return;
+            }
+            // Update display.
+            pb.setProgress(progress.percentage, progress.message, progress.label);
+            // Schedule next timer.
+            pb.timer = setTimeout(() => {
+              pb.sendPing();
+            }, pb.delay);
+          },
+          error(xmlhttp) {
+            const e = new Drupal.AjaxError(xmlhttp, pb.uri);
+            pb.displayError(`<pre>${e.message}</pre>`);
+          },
+        });
+      }
+    },
+
+    /**
+     * Display errors on the page.
+     *
+     * @param {string} string
+     *   The error message to show the user.
+     */
+    displayError(string) {
+      const error = $('<div class="messages messages--error"></div>').html(string);
+      $(this.element).before(error).hide();
+
+      if (this.errorCallback) {
+        this.errorCallback(this);
+      }
+    },
+  });
+}(jQuery, Drupal));