Heine

  • home
  • drupal
  • drupal core commits
  • about
Home › Drupal Core Commits

Commit 94909 by goba

#194590 by scor, JirkaRybka, attiks, dvessel; with heavy testing by catch: fix a dozen issues with sticky table headers

--- misc/tableheader.js 2007/10/02 07:09:51     1.9
+++ misc/tableheader.js 2008/01/09 09:56:39     1.10
@@ -1,4 +1,4 @@
-// $Id: tableheader.js,v 1.9 2007/10/02 07:09:51 dries Exp $
+// $Id: tableheader.js,v 1.10 2008/01/09 09:56:39 goba Exp $
 
 Drupal.behaviors.tableHeader = function (context) {
   // This breaks in anything less than IE 7. Prevent it from running.
@@ -6,70 +6,73 @@
     return;
   }
 
-  // Keep track of all header cells.
-  var cells = [];
+  // Keep track of all cloned table headers.
+  var headers = [];
 
-  var z = 0;
   $('table thead:not(.tableHeader-processed)', context).each(function () {
-    // Find table height.
-    var table = $(this).parent('table')[0];
-    var height = $(table).addClass('sticky-table').height();
-    var i = 0;
+    // Clone table and remove unwanted elements so it inherits original properties.
+    var headerClone = $(this.parentNode).clone(true).insertBefore(this.parentNode).addClass('sticky-header').css({
+      position: 'fixed',
+      visibility: 'hidden',
+      top: '0px'
+    });
+    // Everything except thead must be removed. See theme_table().
+    $('tbody', headerClone).remove();
+    $('caption', headerClone).remove();
 
-    // Find all header cells.
-    $('th', this).each(function () {
+    var headerClone = $(headerClone)[0];
+    headers.push(headerClone);
 
-      // Ensure each cell has an element in it.
-      var html = $(this).html();
-      if (html == ' ') {
-        html = ' ';
-      }
-      if ($(this).children().size() == 0) {
-        html = '<span>'+ html +'</span>';
-      }
-
-      // Clone and wrap cell contents in sticky wrapper that overlaps the cell's padding.
-      $('<div class="sticky-header" style="position: fixed; visibility: hidden; top: 0px;">'+ html +'</div>').prependTo(this);
-      var div = $('div.sticky-header', this).css({
-        'marginLeft': '-'+ $(this).css('paddingLeft'),
-        'marginRight': '-'+ $(this).css('paddingRight'),
-        'paddingLeft': $(this).css('paddingLeft'),
-        'paddingTop': $(this).css('paddingTop'),
-        'paddingBottom': $(this).css('paddingBottom'),
-        'z-index': ++z
-      })[0];
-      cells.push(div);
-
-      // Adjust width to fit cell/table.
-      var ref = this;
-      if (!i++) {
-        // The first cell is as wide as the table to prevent gaps.
-        ref = table;
-        div.wide = true;
-      }
-      $(div).width(Math.max(0, $(ref).width() - parseInt($(div).css('paddingLeft'))));
-
-      // Get position and store.
-      div.cell = this;
-      div.table = table;
-      div.stickyMax = height;
-      div.stickyPosition = $(this).offset().top;
-    });
+    // Store parent table.
+    var table = $(this).parent('table')[0];
+    headerClone.table = table;
+    // Finish initialzing header positioning.
+    headerClone.resizeWidths = true;
+    tracker(headerClone);
+
+    $(table).addClass('sticky-table');
     $(this).addClass('tableHeader-processed');
   });
 
+  // Track positioning and visibility.
+  function tracker(e) {
+    // Save positioning data.
+    var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
+    if (e.viewHeight != viewHeight || e.resizeWidths) {
+      e.viewHeight = viewHeight;
+      e.vPosition = $(e.table).offset().top;
+      e.hPosition = $(e.table).offset().left;
+      e.vLength = $(e.table).height();
+    }
+
+    // Track horizontal positioning relative to the viewport and set visibility.
+    var hScroll = document.documentElement.scrollLeft || document.body.scrollLeft;
+    var vScroll = document.documentElement.scrollTop || document.body.scrollTop;
+    var vOffset = vScroll - e.vPosition - 4;
+    var visState = (vOffset > 0 && vOffset < e.vLength - 100) ? 'visible' : 'hidden';
+    $(e).css({left: -hScroll + e.hPosition +'px', visibility: visState});
+
+    // Resize cell widths.
+    if (e.resizeWidths) {
+      var cellCount = 0;
+      $('th', e).each(function() {
+        var cellWidth = parseInt($('th', e.table).eq(cellCount).css('width'));
+        // Exception for IE7.
+        if (!cellWidth) {
+          var cellWidth = $('th', e.table).eq(cellCount).width();
+        }
+        cellCount++;
+        $(this).css('width', cellWidth +'px');
+      });
+      $(e).css('width', $(e.table).width() +'px');
+      e.resizeWidths = false;
+    }
+  };
+
   // Track scrolling.
   var scroll = function() {
-    $(cells).each(function () {
-      // Fetch scrolling position.
-      var scroll = document.documentElement.scrollTop || document.body.scrollTop;
-      var offset = scroll - this.stickyPosition - 4;
-      if (offset > 0 && offset < this.stickyMax - 100) {
-        $(this).css('visibility', 'visible');
-      }
-      else {
-        $(this).css('visibility', 'hidden');
-      }
+    $(headers).each(function () {
+      tracker(this);
     });
   };
   $(window).scroll(scroll);
@@ -83,26 +86,10 @@
       return;
     }
     time = setTimeout(function () {
-
-      // Precalculate table heights
-      $('table.sticky-table').each(function () {
-        this.savedHeight = $(this).height();
+      $(headers).each(function () {
+        this.resizeWidths = true;
+        tracker(this);
       });
-
-      $('table.sticky-table div.sticky-header').each(function () {
-        // Get position.
-        this.stickyPosition = $(this.cell).offset().top;
-        this.stickyMax = this.table.savedHeight;
-
-        // Reflow the cell.
-        var ref = this.cell;
-        if (this.wide) {
-          // Resize the first cell to fit the table.
-          ref = this.table;
-        }
-        $(this).width(Math.max(0, $(ref).width() - parseInt($(this).css('paddingLeft'))));
-      });
-
       // Reset timer
       time = null;
     }, 250);

--- modules/system/system.css   2008/01/08 19:54:07     1.47
+++ modules/system/system.css   2008/01/09 09:56:39     1.48
@@ -1,4 +1,4 @@
-/* $Id: system.css,v 1.47 2008/01/08 19:54:07 goba Exp $ */
+/* $Id: system.css,v 1.48 2008/01/09 09:56:39 goba Exp $ */
 
 /*
 ** HTML elements
@@ -472,7 +472,8 @@
 /*
 ** Floating header for tableheader.js
 */
-thead div.sticky-header {
+table.sticky-header {
+  margin-top: 0;
   background: #fff;
 }
 

--- themes/garland/style.css    2007/12/29 16:02:52     1.36
+++ themes/garland/style.css    2008/01/09 09:56:39     1.37
@@ -1,4 +1,4 @@
-/* $Id: style.css,v 1.36 2007/12/29 16:02:52 dries Exp $ */
+/* $Id: style.css,v 1.37 2008/01/09 09:56:39 goba Exp $ */
 
 /**
  * Garland, for Drupal 5.0
@@ -201,10 +201,6 @@
   font-weight: bold;
 }
 
-thead div.sticky-header {
-  border-bottom: 2px solid #d3e7f4;
-}
-
 th a:link, th a:visited {
   color: #6f9dbd;
 }

No votes yet
  • Drupal Core
  • Download patch

Recent posts

  • Aan: prorail - Hekwerk langs tunnel onvoldoende - kinderen op spoordijk
  • Unserializing user-supplied data, a bad idea
  • Planet Drupal past and current
  • Help! - Cannot access a global variable.
  • Why is my module's update hook not listed on update.php's selection form?
more

Security reviews

  • Afraid custom code makes your site vulnerable?
  • You don't really trust that module you just downloaded from Drupal.org?

Sleep better after a security review.

Tags

Captcha CSRF Drupal embed Input Format modx OpenID Performance Planet Drupal rants Security Varnish
more tags
  • home
  • drupal
  • drupal core commits
  • about

Copyright © 2010 by Heine Deelstra. All rights reserved.