diff --git a/core/misc/tableheader.js b/core/misc/tableheader.js
index 364cad2..c5cb1ac 100644
--- a/core/misc/tableheader.js
+++ b/core/misc/tableheader.js
@@ -174,8 +174,9 @@ $.extend(TableHeader.prototype, {
    * Create the duplicate header.
    */
   createSticky: function () {
-    // Clone the table header so it inherits original jQuery properties.
-    var $stickyHeader = this.$originalHeader.clone(true);
+    // Deep clone the table header so it and its children inherit their original
+    // jQuery properties.
+    var $stickyHeader = this.$originalHeader.clone(true, true);
     // Hide the table to avoid a flash of the header clone upon page load.
     this.$stickyTable = $('<table class="sticky-header"/>')
       .css({
@@ -190,6 +191,9 @@ $.extend(TableHeader.prototype, {
 
     // Initialize all computations.
     this.recalculateSticky();
+
+    // Let other scripts know a sticky table header was created.
+    this.$stickyTable.trigger('stickyTableCreated');
   },
 
   /**
diff --git a/core/misc/tableselect.js b/core/misc/tableselect.js
index 36af864..edf369f 100644
--- a/core/misc/tableselect.js
+++ b/core/misc/tableselect.js
@@ -1,93 +1,191 @@
-(function ($) {
+(function ($, Drupal) {
 
 "use strict";
 
-Drupal.behaviors.tableSelect = {
-  attach: function (context, settings) {
-    // Select the inner-most table in case of nested tables.
-    $(context).find('th.select-all').closest('table').once('table-select', Drupal.tableSelect);
-  }
-};
+Drupal.behaviors.TableSelect = {
+  attach: function (context) {
+    var $selectAllHeaders = $(context).find('th.select-all');
+    tableSelectInitHandler($selectAllHeaders);
+  },
 
-Drupal.tableSelect = function () {
-  // Do not add a "Select all" checkbox if there are no rows with checkboxes in the table
-  if ($(this).find('td input:checkbox').length === 0) {
-    return;
+  detach: function (context) {
+    // @todo: Remove event handlers and 'select all' checkboxes.
   }
+};
 
-  // Keep track of the table, which checkbox is checked and alias the settings.
-  var table = this, checkboxes, lastChecked;
-  var $table = $(table);
-  var strings = { 'selectAll': Drupal.t('Select all rows in this table'), 'selectNone': Drupal.t('Deselect all rows in this table') };
-  var updateSelectAll = function (state) {
-    // Update table's select-all checkbox (and sticky header's if available).
-    $table.prev('table.sticky-header').andSelf().find('th.select-all input:checkbox').each(function() {
-      $(this).attr('title', state ? strings.selectNone : strings.selectAll);
-      this.checked = state;
-    });
-  };
-
-  // Find all <th> with class select-all, and insert the check all checkbox.
-  $table.find('th.select-all').prepend($('<input type="checkbox" class="form-checkbox" />').attr('title', strings.selectAll)).click(function (event) {
-    if ($(event.target).is('input:checkbox')) {
-      // Loop through all checkboxes and set their state to the select all checkbox' state.
-      checkboxes.each(function () {
-        this.checked = event.target.checked;
-        // Either add or remove the selected class based on the state of the check all checkbox.
-        $(this).closest('tr').toggleClass('selected', this.checked);
+function tableSelectInitHandler($selectAllHeaders) {
+  $selectAllHeaders.each(function() {
+    var $header = $(this);
+    var $table = $header.closest('table');
+    // Do nothing if there are no rows with checkboxes in the table.
+    if ($table.find('td input:checkbox').length !== 0) {
+      $table.once('table-select', function() {
+        TableSelect.tables.push(new TableSelect($table, $header));
       });
-      // Update the title and the state of the check all box.
-      updateSelectAll(event.target.checked);
     }
   });
+}
 
-  // For each of the checkboxes within the table that are not disabled.
-  checkboxes = $table.find('td input:checkbox:enabled').click(function (e) {
-    // Either add or remove the selected class based on the state of the check all checkbox.
-    $(this).closest('tr').toggleClass('selected', this.checked);
+/**
+ * Constructor for the TableSelect object.
+ *
+ * TableSelect will add a 'select all' checkbox to header of the current table.
+ *
+ * @param $table
+ *   jQuery object for the parent table to add a 'select all' checkbox to.
+ * @param $header
+ *   jQuery object for the header to add a 'select all' checkbox to.
+ *
+ * @constructor
+ */
+function TableSelect($table, $header) {
+  // Cached jQuery selectors.
+  this.$table = $table;
+  this.$header = $header;
+  this.$selectAll = null;
 
-    // If this is a shift click, we need to highlight everything in the range.
-    // Also make sure that we are actually checking checkboxes over a range and
-    // that a checkbox has been checked or unchecked before.
-    if (e.shiftKey && lastChecked && lastChecked !== e.target) {
-      // We use the checkbox's parent TR to do our range searching.
-      Drupal.tableSelectRange($(e.target).closest('tr')[0], $(lastChecked).closest('tr')[0], e.target.checked);
+  // DOM collections.
+  this.checkboxes = [];
+  this.rows = [];
+
+  // Keep track of checkbox properties.
+  this.checkboxSum = 0;
+  this.checkboxMaxSum = 0;
+  this.lastState = [];
+  this.lastIndex = null;
+
+  // Create 'select all' checkbox and behaviour.
+  this.createSelectAll();
+}
+
+/**
+ * Store the state of TableSelect.
+ */
+$.extend(TableSelect, {
+  /**
+   * This will store the state of all processed tables.
+   *
+   * @type {Array}
+   */
+  tables: []
+});
+
+/**
+ * Extend TableSelect prototype.
+ */
+$.extend(TableSelect.prototype, {
+  titleSelectAll: {
+    all:  Drupal.t('Select all rows in this table'),
+    none: Drupal.t('Deselect all rows in this table')
+  },
+
+  createSelectAll: function () {
+    // Store the checkboxes, initial state and their parent rows.
+    var $checkboxes = this.$table.find('td input:checkbox');
+    for (var i = 0, il = $checkboxes.length; i < il; i++) {
+      // Checkbox DOM node.
+      this.checkboxes[i] = $checkboxes[i];
+      // Checkbox initial state.
+      if (!$checkboxes[i].disabled) {
+        this.checkboxSum = $checkboxes[i].checked ? this.checkboxSum+1 : this.checkboxSum;
+        this.checkboxMaxSum++;
+      }
+      this.lastState[i] = $checkboxes[i].checked;
+      // Parent row.
+      var $row = $($checkboxes[i]).closest('tr');
+      this.rows.push($row[0]);
     }
+    // Create the 'select all' checkbox.
+    var $selectAll = $('<input type="checkbox" class="form-checkbox" />').attr('title', this.titleSelectAll.all);
+    $selectAll.on('click.TableSelect.checkboxAll', {TableSelect: this}, this.toggleSelectAll);
+    this.$selectAll = $selectAll.prependTo(this.$header);
+    // Listen for the creation of sticky tables. Do this on the direct parent of
+    // the table, to minimize the actual execution of the following function.
+    this.$table.parent().on('stickyTableCreated', {TableSelect: this}, this.adaptToSticky);
+    // Keep track of the checkboxes state.
+    this.$table.on('click.TableSelect.toggleCheckbox', 'td input:checkbox', {TableSelect: this}, this.toggleCheckbox);
+    // Let other scripts know a 'select all' checkbox was created.
+    this.$table.trigger('TableSelectCreated');
+  },
 
-    // If all checkboxes are checked, make sure the select-all one is checked too, otherwise keep unchecked.
-    updateSelectAll((checkboxes.length === checkboxes.filter(':checked').length));
+  adaptToSticky: function (e) {
+    var self = e.data.TableSelect;
+    var $stickyTable = self.$table.prev('table.sticky-header');
+    // If there is a sticky table header attached to the current table, add the
+    // sticky table 'select all' checkbox to the cached 'select all' selector.
+    if ($stickyTable.length === 1) {
+      var $stickyCheckbox = $stickyTable.find('th.select-all input:checkbox');
+      self.$selectAll = $([self.$selectAll[0], $stickyCheckbox[0]]);
+    }
+  },
 
-    // Keep track of the last checked checkbox.
-    lastChecked = e.target;
-  });
-};
+  toggleSelectAll: function (e) {
+    var self = e.data.TableSelect;
+    var state = $(e.target).prop('checked');
+    // Update the 'select all' checkbox.
+    self.updateSelectAll(state);
+    // Toggle all checkboxes.
+    self.toggleCheckboxes(0, self.checkboxes.length-1, state);
+  },
 
-Drupal.tableSelectRange = function (from, to, state) {
-  // We determine the looping mode based on the the order of from and to.
-  var mode = from.rowIndex > to.rowIndex ? 'previousSibling' : 'nextSibling';
+  updateSelectAll: function (state) {
+    // Set the title and 'checked' state explicitly in the event there are
+    // multiple checkboxes controlling the same table. Otherwise these 
+    // checkboxes would not be in sync.
+    var title = state ? this.titleSelectAll.none : this.titleSelectAll.all;
+    this.$selectAll.attr('title', title).prop('checked', state);
+  },
 
-  // Traverse through the sibling nodes.
-  for (var i = from[mode], $i; i; i = i[mode]) {
-    // Make sure that we're only dealing with elements.
-    if (i.nodeType !== 1) {
-      continue;
+  toggleCheckbox: function (e) {
+    var self = e.data.TableSelect;
+    var currentCheckbox = e.target;
+    var currentIndex = $(self.checkboxes).index(currentCheckbox);
+    // If this is a shift click, we need to highlight everything in the range.
+    // Also make sure that we are actually checking checkboxes over a range and
+    // that a checkbox has been checked or unchecked before.
+    var from, to;
+    if (e.shiftKey && self.lastIndex && self.lastIndex !== currentIndex) {
+      from = self.lastIndex < currentIndex ? self.lastIndex : currentIndex;
+      to =   currentIndex > self.lastIndex ? currentIndex : self.lastIndex;
     }
-    $i = $(i);
-    // Either add or remove the selected class based on the state of the target checkbox.
-    $i.toggleClass('selected', state);
-    $i.find('input:checkbox').attr('checked', state);
-
-    if (to.nodeType) {
-      // If we are at the end of the range, stop.
-      if (i === to) {
-        break;
-      }
+    else {
+      from = currentIndex;
+      to =   currentIndex;
     }
-    // A faster alternative to doing $(i).filter(to).length.
-    else if ($.filter(to, [i]).r.length) {
-      break;
+    // Update the checkboxes and parent rows.
+    self.toggleCheckboxes(from, to, currentCheckbox.checked);
+    // Update the most recent toggled checkbox.
+    self.lastIndex = currentIndex;
+
+    // If all checkboxes are checked, make sure the select-all one is checked
+    // too, otherwise keep unchecked.
+    var state = self.checkboxSum === self.checkboxMaxSum ? true : false;
+    self.updateSelectAll(state);
+  },
+
+  toggleCheckboxes: function (from, to, state) {
+    var checkboxes = this.checkboxes;
+    var rows = this.rows;
+    // Gather all the non-disabled checkboxes that need to be toggled.
+    var applyCheckboxes = [];
+    var applyRows = [];
+    for (var i = from, il = to; i <= il; i++) {
+      if (!checkboxes[i].disabled) {
+        applyCheckboxes.push(checkboxes[i]);
+        applyRows.push(rows[i]);
+        if (this.lastState[i] !== state) {
+          this.checkboxSum = state ? this.checkboxSum+1 : this.checkboxSum-1;
+        }
+        this.lastState[i] = state;
+      }
     }
+    // Toggle both the 'checked' property and the 'selected' class.
+    $(applyCheckboxes).prop('checked', state);
+    $(applyRows).toggleClass('selected', state);
   }
-};
+});
+
+// Expose constructor in the public space.
+Drupal.TableSelect = TableSelect;
 
-})(jQuery);
+}(jQuery, Drupal));
