diff --git a/misc/tabledrag.js b/misc/tabledrag.js
index fed674c..5d82942 100644
--- a/misc/tabledrag.js
+++ b/misc/tabledrag.js
@@ -104,10 +104,16 @@ Drupal.tableDrag = function (table, tableSettings) {
   // manipulate form elements directly, rather than using drag-and-drop..
   self.initColumns();
 
-  // Add mouse bindings to the document. The self variable is passed along
+  // Add event bindings to the document. The self variable is passed along
   // as event handlers do not have direct access to the tableDrag object.
-  $(document).bind('mousemove', function (event) { return self.dragRow(event, self); });
-  $(document).bind('mouseup', function (event) { return self.dropRow(event, self); });
+  if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
+    $(document).bind('touchmove', function (event) { return self.dragRow(event.originalEvent.touches[0], self); });
+    $(document).bind('touchend', function (event) { return self.dropRow(event.originalEvent.touches[0], self); });
+  }
+  else {
+    $(document).bind('mousemove', function (event) { return self.dragRow(event, self); });
+    $(document).bind('mouseup', function (event) { return self.dropRow(event, self); });
+  }
 };
 
 /**
@@ -273,64 +279,33 @@ Drupal.tableDrag.prototype.makeDraggable = function (item) {
     self.dragObject == null ? $(this).removeClass('tabledrag-handle-hover') : null;
   });
 
-  // Add the mousedown action for the handle.
-  handle.mousedown(function (event) {
-    // Create a new dragObject recording the event information.
-    self.dragObject = {};
-    self.dragObject.initMouseOffset = self.getMouseOffset(item, event);
-    self.dragObject.initMouseCoords = self.mouseCoords(event);
-    if (self.indentEnabled) {
-      self.dragObject.indentMousePos = self.dragObject.initMouseCoords;
-    }
-
-    // If there's a lingering row object from the keyboard, remove its focus.
-    if (self.rowObject) {
-      $('a.tabledrag-handle', self.rowObject.element).blur();
-    }
-
-    // Create a new rowObject for manipulation of this row.
-    self.rowObject = new self.row(item, 'mouse', self.indentEnabled, self.maxDepth, true);
-
-    // Save the position of the table.
-    self.table.topY = $(self.table).offset().top;
-    self.table.bottomY = self.table.topY + self.table.offsetHeight;
-
-    // Add classes to the handle and row.
-    $(this).addClass('tabledrag-handle-hover');
-    $(item).addClass('drag');
-
-    // Set the document to use the move cursor during drag.
-    $('body').addClass('drag');
-    if (self.oldRowElement) {
-      $(self.oldRowElement).removeClass('drag-previous');
-    }
-
-    // Hack for IE6 that flickers uncontrollably if select lists are moved.
-    if (navigator.userAgent.indexOf('MSIE 6.') != -1) {
-      $('select', this.table).css('display', 'none');
-    }
-
-    // Hack for Konqueror, prevent the blur handler from firing.
-    // Konqueror always gives links focus, even after returning false on mousedown.
-    self.safeBlur = false;
-
-    // Call optional placeholder function.
-    self.onDrag();
-    return false;
-  });
+  if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
+    handle.bind('touchstart', function (event) {
+      event.preventDefault();
+      event = event.originalEvent.touches[0];
+      self.dragStart(event, self, item);
+    });
+  }
+  else {
+    handle.mousedown(function (event) {
+      event.preventDefault();
+      self.dragStart(event, self, item);
+    });
+  }
 
   // Prevent the anchor tag from jumping us to the top of the page.
   handle.click(function () {
     return false;
   });
 
-  // Similar to the hover event, add a class when the handle is focused.
+  // Add a class and set blur cleanup when the handle is focused.
   handle.focus(function () {
     $(this).addClass('tabledrag-handle-hover');
     self.safeBlur = true;
   });
 
-  // Remove the handle class on blur and fire the same function as a mouseup.
+  // On blur, fire the same function as a touchend/mouseup. This is used to
+  // update values after a row has been moved through the keyboard support.
   handle.blur(function (event) {
     $(this).removeClass('tabledrag-handle-hover');
     if (self.rowObject && self.safeBlur) {
@@ -460,7 +435,62 @@ Drupal.tableDrag.prototype.makeDraggable = function (item) {
 };
 
 /**
- * Mousemove event handler, bound to document.
+ * Pointer event initiator, creates drag object and information.
+ *
+ * @param jQuery.Event event
+ *   The event object that triggered the drag.
+ * @param Drupal.tableDrag self
+ *   The drag handle.
+ * @param DOM item
+ *   The item that is being dragged.
+ */
+Drupal.tableDrag.prototype.dragStart = function (event, self, item) {
+  // Create a new dragObject recording the pointer information.
+  self.dragObject = {};
+  self.dragObject.initMouseOffset = self.getMouseOffset(item, event);
+  self.dragObject.initMouseCoords = self.mouseCoords(event);
+  if (self.indentEnabled) {
+    self.dragObject.indentMousePos = self.dragObject.initMouseCoords;
+  }
+
+  // If there's a lingering row object from the keyboard, remove its focus.
+  if (self.rowObject) {
+    $(self.rowObject.element).find('a.tabledrag-handle').blur();
+  }
+
+  // Create a new rowObject for manipulation of this row.
+  self.rowObject = new self.row(item, 'mouse', self.indentEnabled, self.maxDepth, true);
+
+  // Save the position of the table.
+  self.table.topY = $(self.table).offset().top;
+  self.table.bottomY = self.table.topY + self.table.offsetHeight;
+
+  // Add classes to the handle and row.
+  $(this).addClass('tabledrag-handle-hover');
+  $(item).addClass('drag');
+
+  // Set the document to use the move cursor during drag.
+  $('body').addClass('drag');
+  if (self.oldRowElement) {
+    $(self.oldRowElement).removeClass('drag-previous');
+  }
+
+  // Hack for IE6 that flickers uncontrollably if select lists are moved.
+  if (navigator.userAgent.indexOf('MSIE 6.') != -1) {
+    $('select', this.table).css('display', 'none');
+  }
+
+  // Hack for Konqueror, prevent the blur handler from firing.
+  // Konqueror always gives links focus, even after returning false on mousedown.
+  self.safeBlur = false;
+
+  // Call optional placeholder function.
+  self.onDrag();
+  return false;
+}
+
+/**
+ * Mouse movement handler, bound to document.
  */
 Drupal.tableDrag.prototype.dragRow = function (event, self) {
   if (self.dragObject) {
@@ -499,12 +529,12 @@ Drupal.tableDrag.prototype.dragRow = function (event, self) {
     // Similar to row swapping, handle indentations.
     if (self.indentEnabled) {
       var xDiff = self.currentMouseCoords.x - self.dragObject.indentMousePos.x;
-      // Set the number of indentations the mouse has been moved left or right.
+      // Set the number of indentations the pointer has been moved left or right.
       var indentDiff = Math.round(xDiff / self.indentAmount * self.rtl);
       // Indent the row with our estimated diff, which may be further
       // restricted according to the rows around this row.
       var indentChange = self.rowObject.indent(indentDiff);
-      // Update table and mouse indentations.
+      // Update table and pointer indentations.
       self.dragObject.indentMousePos.x += self.indentAmount * indentChange * self.rtl;
       self.indentCount = Math.max(self.indentCount, self.rowObject.indents);
     }
@@ -514,11 +544,10 @@ Drupal.tableDrag.prototype.dragRow = function (event, self) {
 };
 
 /**
- * Mouseup event handler, bound to document.
- * Blur event handler, bound to drag handle for keyboard support.
+ * Pointerup behaviour.
  */
 Drupal.tableDrag.prototype.dropRow = function (event, self) {
-  // Drop row functionality shared between mouseup and blur events.
+  // Drop row functionality.
   if (self.rowObject != null) {
     var droppedRow = self.rowObject.element;
     // The row is already in the right place so we just release it.
@@ -556,7 +585,7 @@ Drupal.tableDrag.prototype.dropRow = function (event, self) {
     self.rowObject = null;
   }
 
-  // Functionality specific only to mouseup event.
+  // Functionality specific only to pointerup events.
   if (self.dragObject != null) {
     $('.tabledrag-handle', droppedRow).removeClass('tabledrag-handle-hover');
 
@@ -572,7 +601,7 @@ Drupal.tableDrag.prototype.dropRow = function (event, self) {
 };
 
 /**
- * Get the mouse coordinates from the event (allowing for browser differences).
+ * Get the coordinates from the event (allowing for browser differences).
  */
 Drupal.tableDrag.prototype.mouseCoords = function (event) {
   if (event.pageX || event.pageY) {
@@ -585,8 +614,8 @@ Drupal.tableDrag.prototype.mouseCoords = function (event) {
 };
 
 /**
- * Given a target element and a mouse event, get the mouse offset from that
- * element. To do this we need the element's position and the mouse position.
+ * Given a target element and a pointer event, get the event offset from that
+ * element. To do this we need the element's position and the target position.
  */
 Drupal.tableDrag.prototype.getMouseOffset = function (target, event) {
   var docPos   = $(target).offset();
