diff -ruN api6/misc/ahah.js fileshare/misc/ahah.js
--- api6/misc/ahah.js	2008-02-11 16:46:27.000000000 +0200
+++ fileshare/misc/ahah.js	2008-06-29 13:28:17.000000000 +0300
@@ -140,6 +140,13 @@
     }
     $(this.element).after(this.progress.element);
   }
+  else if (this.progress.type == 'wrapper') {
+    var Wrapper = new Drupal.Wrapper('ahah-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback),this.progress.wrapper);
+    if (this.progress.url) {
+      Wrapper.startMonitoring(this.progress.url, this.progress.interval || 1500);
+    }
+    this.progress.object = Wrapper;
+  }
 };
 
 /**
diff -ruN api6/misc/wrapper.js fileshare/misc/wrapper.js
--- api6/misc/wrapper.js	1970-01-01 03:00:00.000000000 +0300
+++ fileshare/misc/wrapper.js	2008-06-22 19:17:11.000000000 +0300
@@ -0,0 +1,79 @@
+// $Id$
+
+Drupal.Wrapper = function (id, updateCallback, method, errorCallback, wrapper) {
+  var pb = this;
+  this.id = id;
+  this.method = method || "GET";
+  this.updateCallback = updateCallback;
+  this.errorCallback = errorCallback;
+  this.wrapper = '#' + wrapper;
+};
+
+/**
+ * Start monitoring progress via Ajax.
+ */
+Drupal.Wrapper.prototype.startMonitoring = function (uri, delay) {
+  this.delay = delay;
+  this.uri = uri;
+  this.sendPing();
+};
+
+/**
+ * Stop monitoring progress via Ajax.
+ */
+Drupal.Wrapper.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.Wrapper.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
+        if (pb.updateCallback) {
+          pb.updateCallback(pb.wrapper,progress);
+        }
+        // Schedule next timer
+        pb.timer = setTimeout(function() { pb.sendPing(); }, pb.delay);
+      },
+      error: function (xmlhttp) {
+        pb.displayError(Drupal.ahahError(xmlhttp, pb.uri));
+      }
+    });
+  }
+};
+
+/**
+ * Display errors on the page.
+ */
+Drupal.Wrapper.prototype.displayError = function (string) {
+  var error = document.createElement('div');
+  error.className = 'error';
+  error.innerHTML = string;
+
+  $(this.wrapper).before(error).hide();
+
+  if (this.errorCallback) {
+    this.errorCallback(this);
+  }
+};
