From 3a396daad64574425298f0a72b0aa3e752957185 Mon Sep 17 00:00:00 2001
From: Mark Carver <mark.carver@me.com>
Date: Fri, 5 Apr 2013 16:32:28 -0500
Subject: [PATCH] Fixes [#1950694] - Use Bootstrap's progress bar

---
 css/style.css      |   9 +++++
 includes/theme.inc |  21 +++++++++++
 js/progress.js     | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 136 insertions(+)
 create mode 100644 js/progress.js

diff --git a/css/style.css b/css/style.css
index ac05a6a..f6a8df4 100644
--- a/css/style.css
+++ b/css/style.css
@@ -226,3 +226,12 @@ e.g. multipage*/
 .form-actions{
   clear: both;
 }
+
+/* Progress Bar Overrides */
+.progress-wrapper .progress {
+  margin-bottom: 10px;
+}
+.progress-wrapper .progress .bar {
+  border: 0 none;
+  margin: 0;
+}
\ No newline at end of file
diff --git a/includes/theme.inc b/includes/theme.inc
index 1e15888..b011475 100644
--- a/includes/theme.inc
+++ b/includes/theme.inc
@@ -297,6 +297,13 @@ function bootstrap_js_alter(&$js) {
   if (module_exists('bootstrap_ui')) {
     libraries_load('bootstrap', 'minified');
   }
+  
+  // Replace core progress bar JS with the Bootstrap equivilent.
+  if (isset($js['misc/progress.js']) && !empty($js['misc/progress.js'])) {
+    unset($js['misc/progress.js']);
+    $progress = drupal_get_path('theme', 'bootstrap') . '/js/progress.js';
+    $js[$progress] = drupal_js_defaults($progress);
+  }
 
   $js = array_diff_key($js, $excludes);
   if (theme_get_setting('cdn_bootstrap')) {
@@ -331,6 +338,20 @@ function _bootstrap_alter($files, $type) {
 }
 
 /**
+ * Returns HTML for Bootstrap's progress bar.
+ */
+function bootstrap_progress_bar($variables) {
+  $output .= '<div id="progress" class="progress-wrapper">';
+  $output .= '  <div class="progress progress-striped progress-info active">';
+  $output .= '    <div class="bar" style="width: ' . $variables['percent'] . '%"></div>';
+  $output .= '  </div>';
+  $output .= '  <div class="percentage pull-right">' . $variables['percent'] . '%</div>';
+  $output .= '  <div class="message">' . $variables['message'] . '</div>';
+  $output .= '</div>';
+  return $output;
+}
+
+/**
  * Returns HTML for Bootstrap's modal.
  */
 function bootstrap_bootstrap_modal($variables) {
diff --git a/js/progress.js b/js/progress.js
new file mode 100644
index 0000000..cf6893e
--- /dev/null
+++ b/js/progress.js
@@ -0,0 +1,106 @@
+(function ($) {
+
+/**
+ * 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".
+ *
+ * e.g. pb = new progressBar('myProgressBar');
+ *      some_element.appendChild(pb.element);
+ */
+Drupal.progressBar = function (id, updateCallback, method, errorCallback) {
+  var pb = this;
+  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 = $('<div class="progress-wrapper" aria-live="polite"></div>');
+  this.element.html('<div id ="' + id + '" class="progress progress-striped progress-info active"><div class="bar"></div></div>' +
+                    '<div class="percentage pull-right"></div>' +
+                    '<div class="message">&nbsp;</div>');
+};
+
+/**
+ * Set the percentage and status message for the progressbar.
+ */
+Drupal.progressBar.prototype.setProgress = function (percentage, message) {
+  if (percentage >= 0 && percentage <= 100) {
+    $('div.bar', this.element).css('width', percentage + '%');
+    $('div.percentage', this.element).html(percentage + '%');
+  }
+  $('div.message', this.element).html(message);
+  if (this.updateCallback) {
+    this.updateCallback(percentage, message, this);
+  }
+};
+
+/**
+ * Start monitoring progress via Ajax.
+ */
+Drupal.progressBar.prototype.startMonitoring = function (uri, delay) {
+  this.delay = delay;
+  this.uri = uri;
+  this.sendPing();
+};
+
+/**
+ * Stop monitoring progress via Ajax.
+ */
+Drupal.progressBar.prototype.stopMonitoring = function () {
+  clearTimeout(this.timer);
+  // This allows monitoring to be stopped from within the callback.
+  this.uri = null;
+};
+
+/**
+ * Request progress data from server.
+ */
+Drupal.progressBar.prototype.sendPing = function () {
+  if (this.timer) {
+    clearTimeout(this.timer);
+  }
+  if (this.uri) {
+    var 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.
+    $.ajax({
+      type: this.method,
+      url: this.uri,
+      data: '',
+      dataType: 'json',
+      success: function (progress) {
+        // Display errors.
+        if (progress.status == 0) {
+          pb.displayError(progress.data);
+          return;
+        }
+        // Update display.
+        pb.setProgress(progress.percentage, progress.message);
+        // Schedule next timer.
+        pb.timer = setTimeout(function () { pb.sendPing(); }, pb.delay);
+      },
+      error: function (xmlhttp) {
+        pb.displayError(Drupal.ajaxError(xmlhttp, pb.uri));
+      }
+    });
+  }
+};
+
+/**
+ * Display errors on the page.
+ */
+Drupal.progressBar.prototype.displayError = function (string) {
+  var error = $('<div class="alert alert-block alert-error"><a class="close" data-dismiss="alert" href="#">&times;</a><h4>Error message</h4></div>').append(string);
+  $(this.element).before(error).hide();
+
+  if (this.errorCallback) {
+    this.errorCallback(this);
+  }
+};
+
+})(jQuery);
-- 
1.7.11.5

