summaryrefslogtreecommitdiff
path: root/misc/progress.js
blob: b519f066b5736a7657161585d6cbe102a2de5df0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// $Id$

/**
 * 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 HTTPGet or HTTPPost.
 *
 * e.g. pb = new progressBar('myProgressBar');
 *      some_element.appendChild(pb.element);
 */
function progressBar(id, updateCallback, method, errorCallback) {
  var pb = this;
  this.id = id;
  this.method = method ? method : HTTPGet;
  this.updateCallback = updateCallback;
  this.errorCallback = errorCallback;

  this.element = document.createElement('div');
  this.element.id = id;
  this.element.className = 'progress';
  this.element.innerHTML = '<div class="percentage"></div>'+
                           '<div class="message">&nbsp;</div>'+
                           '<div class="bar"><div class="filled"></div></div>';
}

/**
 * Set the percentage and status message for the progressbar.
 */
progressBar.prototype.setProgress = function (percentage, message) {
  var divs = this.element.getElementsByTagName('div');
  var div;
  for (var i = 0; div = divs[i]; ++i) {
    if (percentage >= 0) {
      if (hasClass(divs[i], 'filled')) {
        divs[i].style.width = percentage + '%';
      }
      if (hasClass(divs[i], 'percentage')) {
        divs[i].innerHTML = percentage + '%';
      }
    }
    if (hasClass(divs[i], 'message')) {
      divs[i].innerHTML = message;
    }
  }
  if (this.updateCallback) {
    this.updateCallback(percentage, message, this);
  }
}

/**
 * Start monitoring progress via Ajax.
 */
progressBar.prototype.startMonitoring = function (uri, delay) {
  this.delay = delay;
  this.uri = uri;
  this.sendPing();
}

/**
 * Stop monitoring progress via Ajax.
 */
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.
 */
progressBar.prototype.sendPing = function () {
  if (this.timer) {
    clearTimeout(this.timer);
  }
  if (this.uri) {
    this.method(this.uri, this.receivePing, this, '');
  }
}

/**
 * HTTP callback function. Passes data back to the progressbar and sets a new
 * timer for the next ping.
 */
progressBar.prototype.receivePing = function (string, xmlhttp, pb) {
  if (xmlhttp.status != 200) {
    return pb.displayError('An HTTP error '+ xmlhttp.status +' occured.\n'+ pb.uri);
  }
  // Parse response
  var progress = parseJson(string);
  // 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);
}

/**
 * Display errors on the page.
 */
progressBar.prototype.displayError = function (string) {
  var error = document.createElement('div');
  error.className = 'error';
  error.innerHTML = string;

  this.element.style.display = 'none';
  this.element.parentNode.insertBefore(error, this.element);

  if (this.errorCallback) {
    this.errorCallback(this);
  }
}