summaryrefslogtreecommitdiff
path: root/misc/tableheader.js
blob: 4efe26a43e156d8a694bcf809284358abfae77cc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// $Id$
(function ($) {

Drupal.tableHeaderDoScroll = function () {
  if ($.isFunction(Drupal.tableHeaderOnScroll)) {
    Drupal.tableHeaderOnScroll();
  }
};

Drupal.behaviors.tableHeader = {
  attach: function (context, settings) {
    // This breaks in anything less than IE 7. Prevent it from running.
    if ($.browser.msie && parseInt($.browser.version, 10) < 7) {
      return;
    }

    $('table.sticky-enabled thead', context).once('tableheader', function () {
      // Clone the table header so it inherits original jQuery properties. Hide
      // the table to avoid a flash of the header clone upon page load.
      var headerClone = $(this).clone(true).hide().insertBefore(this.parentNode).wrap('<table class="sticky-header"></table>').parent().css({
        position: 'fixed',
        top: '0px'
      });

      headerClone = $(headerClone)[0];

      // Store parent table.
      var table = $(this).parent('table')[0];
      headerClone.table = table;
      // Finish initializing header positioning.
      tracker(headerClone);
      // We hid the header to avoid it showing up erroneously on page load;
      // we need to unhide it now so that it will show up when expected.
      $(headerClone).children('thead').show();

      $(table).addClass('sticky-table');
    });

    // Define the anchor holding var.
    var prevAnchor = '';

    // Track positioning and visibility.
    function tracker(e) {
      // Reset top position of sticky table headers to the current top offset.
      var topOffset = Drupal.settings.tableHeaderOffset ? eval(Drupal.settings.tableHeaderOffset + '()') : 0;
      $('.sticky-header').css('top', topOffset + 'px');
      // Save positioning data.
      var viewHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
      if (e.viewHeight != viewHeight) {
        e.viewHeight = viewHeight;
        e.vPosition = $(e.table).offset().top - 4 - topOffset;
        e.hPosition = $(e.table).offset().left;
        e.vLength = e.table.clientHeight - 100;
        // Resize header and its cell widths.
        var parentCell = $('th', e.table);
        $('th', e).each(function (index) {
          var cellWidth = parentCell.eq(index).css('width');
          // Exception for IE7.
          if (cellWidth == 'auto') {
            cellWidth = parentCell.get(index).clientWidth + 'px';
          }
          $(this).css('width', cellWidth);
        });
        $(e).css('width', $(e.table).css('width'));
      }

      // Track horizontal positioning relative to the viewport and set visibility.
      var hScroll = document.documentElement.scrollLeft || document.body.scrollLeft;
      var vOffset = (document.documentElement.scrollTop || document.body.scrollTop) - e.vPosition;
      var visState = (vOffset > 0 && vOffset < e.vLength) ? 'visible' : 'hidden';
      $(e).css({ left: -hScroll + e.hPosition + 'px', visibility: visState });

      // Check the previous anchor to see if we need to scroll to make room for the header.
      // Get the height of the header table and scroll up that amount.
      if (prevAnchor != location.hash) {
        if (location.hash != '') {
          var scrollLocation = $('td' + location.hash).offset().top - $(e).height();
          $('body, html').scrollTop(scrollLocation);
        }
        prevAnchor = location.hash;
      }
    }

    // Only attach to scrollbars once, even if Drupal.attachBehaviors is called
    //  multiple times.
    $('body').once(function () {
      $(window).scroll(Drupal.tableHeaderDoScroll);
      $(document.documentElement).scroll(Drupal.tableHeaderDoScroll);
    });

    // Track scrolling.
    Drupal.tableHeaderOnScroll = function () {
      $('table.sticky-header').each(function () {
        tracker(this);
      });
    };

    // Track resizing.
    var time = null;
    var resize = function () {
      // Ensure minimum time between adjustments.
      if (time) {
        return;
      }
      time = setTimeout(function () {
        $('table.sticky-header').each(function () {
          // Force cell width calculation.
          this.viewHeight = 0;
          tracker(this);
        });
        // Reset timer.
        time = null;
      }, 250);
    };
    $(window).resize(resize);
  }
};

})(jQuery);