diff --git a/misc/tabledrag.js b/misc/tabledrag.js
index fed674c..2358eec 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); });
+  }
 };
 
 /**
@@ -266,73 +272,33 @@ Drupal.tableDrag.prototype.makeDraggable = function (item) {
     $('td:first', item).prepend(handle);
   }
 
-  // Add hover action for the handle.
-  handle.hover(function () {
-    self.dragObject == null ? $(this).addClass('tabledrag-handle-hover') : null;
-  }, function () {
-    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.
+  // Set blur cleanup when a 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) {
       self.dropRow(event, self);
     }
@@ -460,14 +426,55 @@ 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 trigger the drag.
+ * @param Drupal.tableDrag self
+ *   The drag handle.
+ * @param DOM item
+ *   The item that that is being dragged.
+ */
+Drupal.tableDrag.prototype.dragStart = function (event, self, item) {
+  // Create a new dragObject recording the pointer information.
+  self.dragObject = {};
+  self.dragObject.initOffset = self.getPointerOffset(item, event);
+  self.dragObject.initPointerCoords = self.pointerCoords(event);
+  if (self.indentEnabled) {
+    self.dragObject.indentPointerPos = self.dragObject.initPointerCoords;
+  }
+
+  // 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, 'pointer', 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.
+  $(item).addClass('drag');
+
+  // Set the document to use the move cursor during drag.
+  $('body').addClass('drag');
+  if (self.oldRowElement) {
+    $(self.oldRowElement).removeClass('drag-previous');
+  }
+}
+
+/**
+ * Pointer movement handler, bound to document.
  */
 Drupal.tableDrag.prototype.dragRow = function (event, self) {
   if (self.dragObject) {
-    self.currentMouseCoords = self.mouseCoords(event);
 
-    var y = self.currentMouseCoords.y - self.dragObject.initMouseOffset.y;
-    var x = self.currentMouseCoords.x - self.dragObject.initMouseOffset.x;
+    self.currentPointerCoords = self.pointerCoords(event);
+    var y = self.currentPointerCoords.y - self.dragObject.initOffset.y;
+    var x = self.currentPointerCoords.x - self.dragObject.initOffset.x;
 
     // Check for row swapping and vertical scrolling.
     if (y != self.oldY) {
@@ -475,7 +482,7 @@ Drupal.tableDrag.prototype.dragRow = function (event, self) {
       self.oldY = y; // Update the old value.
 
       // Check if the window should be scrolled (and how fast).
-      var scrollAmount = self.checkScroll(self.currentMouseCoords.y);
+      var scrollAmount = self.checkScroll(self.currentPointerCoords.y);
       // Stop any current scrolling.
       clearInterval(self.scrollInterval);
       // Continue scrolling if the mouse has moved in the scroll direction.
@@ -498,14 +505,14 @@ 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.
+      var xDiff = self.currentPointerCoords.x - self.dragObject.indentPointerPos.x;
+      // 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.
-      self.dragObject.indentMousePos.x += self.indentAmount * indentChange * self.rtl;
+      // Update table and pointer indentations.
+      self.dragObject.indentPointerPos.x += self.indentAmount * indentChange * self.rtl;
       self.indentCount = Math.max(self.indentCount, self.rowObject.indents);
     }
 
@@ -514,11 +521,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,9 +562,8 @@ 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');
 
     self.dragObject = null;
     $('body').removeClass('drag');
@@ -572,9 +577,9 @@ 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) {
+Drupal.tableDrag.prototype.pointerCoords = function (event) {
   if (event.pageX || event.pageY) {
     return { x: event.pageX, y: event.pageY };
   }
@@ -585,13 +590,13 @@ 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();
-  var mousePos = this.mouseCoords(event);
-  return { x: mousePos.x - docPos.left, y: mousePos.y - docPos.top };
+Drupal.tableDrag.prototype.getPointerOffset = function (target, event) {
+  var docPos = $(target).offset();
+  var pointerPos = this.pointerCoords(event);
+  return { x: pointerPos.x - docPos.left, y: pointerPos.y - docPos.top };
 };
 
 /**
@@ -837,7 +842,7 @@ Drupal.tableDrag.prototype.setScroll = function (scrollAmount) {
 
   this.scrollInterval = setInterval(function () {
     // Update the scroll values stored in the object.
-    self.checkScroll(self.currentMouseCoords.y);
+    self.checkScroll(self.currentPointerCoords.y);
     var aboveTable = self.scrollY > self.table.topY;
     var belowTable = self.scrollY + self.windowHeight < self.table.bottomY;
     if (scrollAmount > 0 && belowTable || scrollAmount < 0 && aboveTable) {
