PageSourceSearch

https://thorhildminorhockey.com/cloud/global/js/jquery.fixedheadertable.js

js thorhildminorhockey.com collected 2026-10-02 00:57:18 UTC 21,918 bytes, 706 lines download raw bytes

1/*!
2 * jquery.fixedHeaderTable. The jQuery fixedHeaderTable plugin
3 *
4 * Copyright (c) 2013 Mark Malek
5 * http://fixedheadertable.com
6 *
7 * Licensed under MIT
8 * http://www.opensource.org/licenses/mit-license.php
9 *
10 * http://docs.jquery.com/Plugins/Authoring
11 * jQuery authoring guidelines
12 *
13 * Launch  : October 2009
14 * Version : 1.3
15 * Released: May 9th, 2011
16 *
17 *
18 * all CSS sizing (width,height) is done in pixels (px)
19 */
20
21(function ($) {
22
23  $.fn.fixedHeaderTable = function (method) {
24
25    // plugin's default options
26    var defaults = {
27      width:          '100%',
28      height:         '100%',
29      themeClass:     'fht-default',
30      borderCollapse:  true,
31      fixedColumns:    0, // fixed first columns
32      fixedColumn:     false, // For backward-compatibility
33      sortable:        false,
34      autoShow:        true, // hide table after its created
35      footer:          false, // show footer
36      cloneHeadToFoot: false, // clone head and use as footer
37      autoResize:      false, // resize table if its parent wrapper changes size
38      create:          null // callback after plugin completes
39    };
40
41    var settings = {};
42
43    // public methods
44    var methods = {
45      init: function (options) {
46        settings = $.extend({}, defaults, options);
47
48        // iterate through all the DOM elements we are attaching the plugin to
49        return this.each(function () {
50          var $self = $(this); // reference the jQuery version of the current DOM element
51
52          if (helpers._isTable($self)) {
53            methods.setup.apply(this, Array.prototype.slice.call(arguments, 1));
54            $.isFunction(settings.create) && settings.create.call(this);
55          } else {
56            $.error('Invalid table mark-up');
57          }
58        });
59      },
60
61      /*
62       * Setup table structure for fixed headers and optional footer
63       */
64      setup: function () {
65        var $self       = $(this),
66            self        = this,
67            $thead      = $self.find('thead'),
68            $tfoot      = $self.find('tfoot'),
69            tfootHeight = 0,
70            $wrapper,
71            $divHead,
72            $divBody,
73            $fixedBody,
74            widthMinusScrollbar;
75
76        settings.originalTable = $(this).clone();
77        settings.includePadding = helpers._isPaddingIncludedWithWidth();
78        settings.scrollbarOffset = helpers._getScrollbarWidth();
79        settings.themeClassName = settings.themeClass;
80
81        if (settings.width.search && settings.width.search('%') > -1) {
82            widthMinusScrollbar = $self.parent().width() - settings.scrollbarOffset;
83        } else {
84            widthMinusScrollbar = settings.width - settings.scrollbarOffset;
85        }
86
87        $self.css({
88          width: widthMinusScrollbar
89        });
90
91
92        if (!$self.closest('.fht-table-wrapper').length) {
93          $self.addClass('fht-table');
94          $self.wrap('<div class="fht-table-wrapper"></div>');
95        }
96
97        $wrapper = $self.closest('.fht-table-wrapper');
98
99        if(settings.fixedColumn == true && settings.fixedColumns <= 0) {
100          settings.fixedColumns = 1;
101        }
102
103        if (settings.fixedColumns > 0 && $wrapper.find('.fht-fixed-column').length == 0) {
104          $self.wrap('<div class="fht-fixed-body"></div>');
105
106          $('<div class="fht-fixed-column"></div>').prependTo($wrapper);
107
108          $fixedBody    = $wrapper.find('.fht-fixed-body');
109        }
110
111        $wrapper.css({
112          width: settings.width,
113          height: settings.height
114        })
115          .addClass(settings.themeClassName);
116
117        if (!$self.hasClass('fht-table-init')) {
118          $self.wrap('<div class="fht-tbody"></div>');
119        }
120
121        $divBody = $self.closest('.fht-tbody');
122
123        var tableProps = helpers._getTableProps($self);
124
125        helpers._setupClone($divBody, tableProps.tbody);
126
127        if (!$self.hasClass('fht-table-init')) {
128          if (settings.fixedColumns > 0) {
129            $divHead = $('<div class="fht-thead"><table class="fht-table"></table></div>').prependTo($fixedBody);
130          } else {
131            $divHead = $('<div class="fht-thead"><table class="fht-table"></table></div>').prependTo($wrapper);
132          }
133
134          $divHead.find('table.fht-table')
135            .addClass(settings.originalTable.attr('class'))
136            .attr('style', settings.originalTable.attr('style'));
137
138          $thead.clone().appendTo($divHead.find('table'));
139        } else {
140          $divHead = $wrapper.find('div.fht-thead');
141        }
142
143        helpers._setupClone($divHead, tableProps.thead);
144
145        $self.css({
146          'margin-top': -$divHead.outerHeight(true)
147        });
148
149        /*
150         * Check for footer
151         * Setup footer if present
152         */
153        if (settings.footer == true) {
154          helpers._setupTableFooter($self, self, tableProps);
155
156          if (!$tfoot.length) {
157            $tfoot = $wrapper.find('div.fht-tfoot table');
158          }
159
160          tfootHeight = $tfoot.outerHeight(true);
161        }
162
163        var tbodyHeight = $wrapper.height() - $thead.outerHeight(true) - tfootHeight - tableProps.border;
164
165        $divBody.css({
166          'height': tbodyHeight
167        });
168
169        $self.addClass('fht-table-init');
170
171        if (typeof(settings.altClass) !== 'undefined') {
172          methods.altRows.apply(self);
173        }
174
175        if (settings.fixedColumns > 0) {
176          helpers._setupFixedColumn($self, self, tableProps);
177        }
178
179        if (!settings.autoShow) {
180          $wrapper.hide();
181        }
182
183        helpers._bindScroll($divBody, tableProps);
184
185        return self;
186      },
187
188      /*
189       * Resize the table
190       * Incomplete - not implemented yet
191       */
192      resize: function() {
193        var self  = this;
194        return self;
195      },
196
197      /*
198       * Add CSS class to alternating rows
199       */
200      altRows: function(arg1) {
201        var $self = $(this),
202        altClass  = (typeof(arg1) !== 'undefined') ? arg1 : settings.altClass;
203
204        $self.closest('.fht-table-wrapper')
205          .find('tbody tr:odd:not(:hidden)')
206          .addClass(altClass);
207      },
208
209      /*
210       * Show a hidden fixedHeaderTable table
211       */
212      show: function(arg1, arg2, arg3) {
213        var $self   = $(this),
214            self      = this,
215            $wrapper  = $self.closest('.fht-table-wrapper');
216
217        // User provided show duration without a specific effect
218        if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'number') {
219          $wrapper.show(arg1, function() {
220            $.isFunction(arg2) && arg2.call(this);
221          });
222
223          return self;
224
225        } else if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'string' &&
226          typeof(arg2) !== 'undefined' && typeof(arg2) === 'number') {
227          // User provided show duration with an effect
228
229          $wrapper.show(arg1, arg2, function() {
230            $.isFunction(arg3) && arg3.call(this);
231          });
232
233          return self;
234
235        }
236
237        $self.closest('.fht-table-wrapper')
238          .show();
239        $.isFunction(arg1) && arg1.call(this);
240
241        return self;
242      },
243
244      /*
245       * Hide a fixedHeaderTable table
246       */
247      hide: function(arg1, arg2, arg3) {
248        var $self     = $(this),
249            self    = this,
250            $wrapper  = $self.closest('.fht-table-wrapper');
251
252        // User provided show duration without a specific effect
253        if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'number') {
254          $wrapper.hide(arg1, function() {
255            $.isFunction(arg3) && arg3.call(this);
256          });
257
258          return self;
259        } else if (typeof(arg1) !== 'undefined' && typeof(arg1) === 'string' &&
260          typeof(arg2) !== 'undefined' && typeof(arg2) === 'number') {
261
262          $wrapper.hide(arg1, arg2, function() {
263            $.isFunction(arg3) && arg3.call(this);
264          });
265
266          return self;
267        }
268
269        $self.closest('.fht-table-wrapper')
270          .hide();
271
272        $.isFunction(arg3) && arg3.call(this);
273
274
275
276        return self;
277      },
278
279      /*
280       * Destory fixedHeaderTable and return table to original state
281       */
282      destroy: function() {
283        var $self    = $(this),
284            self     = this,
285            $wrapper = $self.closest('.fht-table-wrapper');
286
287        $self.insertBefore($wrapper)
288          .removeAttr('style')
289          .append($wrapper.find('tfoot'))
290          .removeClass('fht-table fht-table-init')
291          .find('.fht-cell')
292          .remove();
293
294        $wrapper.remove();
295
296        return self;
297      }
298
299    };
300
301    // private methods
302    var helpers = {
303
304      /*
305       * return boolean
306       * True if a thead and tbody exist.
307       */
308      _isTable: function($obj) {
309        var $self = $obj,
310            hasTable = $self.is('table'),
311            hasThead = $self.find('thead').length > 0,
312            hasTbody = $self.find('tbody').length > 0;
313
314        if (hasTable && hasThead && hasTbody) {
315          return true;
316        }
317
318        return false;
319
320      },
321
322      /*
323       * return void
324       * bind scroll event
325       */
326      _bindScroll: function($obj) {
327        var $self = $obj,
328            $wrapper = $self.closest('.fht-table-wrapper'),
329            $thead = $self.siblings('.fht-thead'),
330            $tfoot = $self.siblings('.fht-tfoot');
331
332        $self.bind('scroll', function() {
333          if (settings.fixedColumns > 0) {
334            var $fixedColumns = $wrapper.find('.fht-fixed-column');
335
336            $fixedColumns.find('.fht-tbody table')
337              .css({
338                  'margin-top': -$self.scrollTop()
339              });
340          }
341
342          $thead.find('table')
343            .css({
344              'margin-left': -this.scrollLeft
345            });
346
347          if (settings.footer || settings.cloneHeadToFoot) {
348            $tfoot.find('table')
349              .css({
350                'margin-left': -this.scrollLeft
351              });
352          }
353        });
354      },
355
356      /*
357       * return void
358       */
359      _fixHeightWithCss: function ($obj, tableProps) {
360        if (settings.includePadding) {
361          $obj.css({
362            'height': $obj.height() + tableProps.border
363          });
364        } else {
365          $obj.css({
366            'height': $obj.parent().height() + tableProps.border
367          });
368        }
369      },
370
371      /*
372       * return void
373       */
374      _fixWidthWithCss: function($obj, tableProps, width) {
375        if (settings.includePadding) {
376          $obj.each(function() {
377            $(this).css({
378              'width': width == undefined ? $(this).width() + tableProps.border : width + tableProps.border
379            });
380          });
381        } else {
382          $obj.each(function() {
383            $(this).css({
384              'width': width == undefined ? $(this).parent().width() + tableProps.border : width + tableProps.border
385            });
386          });
387        }
388
389      },
390
391      /*
392       * return void
393       */
394      _setupFixedColumn: function ($obj, obj, tableProps) {
395        var $self             = $obj,
396            $wrapper          = $self.closest('.fht-table-wrapper'),
397            $fixedBody        = $wrapper.find('.fht-fixed-body'),
398            $fixedColumn      = $wrapper.find('.fht-fixed-column'),
399            $thead            = $('<div class="fht-thead"><table class="fht-table"><thead><tr></tr></thead></table></div>'),
400            $tbody            = $('<div class="fht-tbody"><table class="fht-table"><tbody></tbody></table></div>'),
401            $tfoot            = $('<div class="fht-tfoot"><table class="fht-table"><tfoot><tr></tr></tfoot></table></div>'),
402            fixedBodyWidth    = $wrapper.width(),
403            fixedBodyHeight   = $fixedBody.find('.fht-tbody').height() - settings.scrollbarOffset,
404            $firstThChildren,
405            $firstTdChildren,
406            fixedColumnWidth,
407            $newRow,
408            firstTdChildrenSelector;
409
410        $thead.find('table.fht-table').addClass(settings.originalTable.attr('class'));
411        $tbody.find('table.fht-table').addClass(settings.originalTable.attr('class'));
412        $tfoot.find('table.fht-table').addClass(settings.originalTable.attr('class'));
413
414        $firstThChildren = $fixedBody.find('.fht-thead thead tr > *:lt(' + settings.fixedColumns + ')');
415        fixedColumnWidth = settings.fixedColumns * tableProps.border;
416        $firstThChildren.each(function() {
417          fixedColumnWidth += $(this).outerWidth(true);
418        });
419
420        // Fix cell heights
421        helpers._fixHeightWithCss($firstThChildren, tableProps);
422        helpers._fixWidthWithCss($firstThChildren, tableProps);
423
424        var tdWidths = [];
425        $firstThChildren.each(function() {
426          tdWidths.push($(this).width());
427        });
428
429        firstTdChildrenSelector = 'tbody tr > *:not(:nth-child(n+' + (settings.fixedColumns + 1) + '))';
430        $firstTdChildren = $fixedBody.find(firstTdChildrenSelector)
431          .each(function(index) {
432            helpers._fixHeightWithCss($(this), tableProps);
433            helpers._fixWidthWithCss($(this), tableProps, tdWidths[index % settings.fixedColumns] );
434          });
435
436        // clone header
437        $thead.appendTo($fixedColumn)
438          .find('tr')
439          .append($firstThChildren.clone());
440
441        $tbody.appendTo($fixedColumn)
442          .css({
443            'margin-top': -1,
444            'height': fixedBodyHeight + tableProps.border
445          });
446
447        $firstTdChildren.each(function(index) {
448          if (index % settings.fixedColumns == 0) {
449            $newRow = $('<tr></tr>').appendTo($tbody.find('tbody'));
450
451            if (settings.altClass && $(this).parent().hasClass(settings.altClass)) {
452              $newRow.addClass(settings.altClass);
453            }
454          }
455
456          $(this).clone()
457            .appendTo($newRow);
458        });
459
460        // set width of fixed column wrapper
461        $fixedColumn.css({
462          'height': 0,
463          'width': fixedColumnWidth
464        });
465
466
467        // bind mousewheel events
468        var maxTop = $fixedColumn.find('.fht-tbody .fht-table').height() - $fixedColumn.find('.fht-tbody').height();
469        $fixedColumn.find('.fht-tbody .fht-table').bind('mousewheel', function(event, delta, deltaX, deltaY) {
470          if (deltaY == 0) {
471            return;
472          }
473          var top = parseInt($(this).css('marginTop'), 10) + (deltaY > 0 ? 120 : -120);
474          if (top > 0) {
475            top = 0;
476          }
477          if (top < -maxTop) {
478            top = -maxTop;
479          }
480          $(this).css('marginTop', top);
481          $fixedBody.find('.fht-tbody').scrollTop(-top).scroll();
482          return false;
483        });
484
485
486        // set width of body table wrapper
487        $fixedBody.css({
488          'width': fixedBodyWidth
489        });
490
491        // setup clone footer with fixed column
492        if (settings.footer == true || settings.cloneHeadToFoot == true) {
493          var $firstTdFootChild = $fixedBody.find('.fht-tfoot tr > *:lt(' + settings.fixedColumns + ')'),
494              footwidth;
495
496          helpers._fixHeightWithCss($firstTdFootChild, tableProps);
497          $tfoot.appendTo($fixedColumn)
498            .find('tr')
499            .append($firstTdFootChild.clone());
500          // Set (view width) of $tfoot div to width of table (this accounts for footers with a colspan)
501          footwidth = $tfoot.find('table').innerWidth();
502          $tfoot.css({
503            'top': settings.scrollbarOffset,
504            'width': footwidth
505          });
506        }
507      },
508
509      /*
510       * return void
511       */
512      _setupTableFooter: function ($obj, obj, tableProps) {
513        var $self     = $obj,
514            $wrapper  = $self.closest('.fht-table-wrapper'),
515            $tfoot    = $self.find('tfoot'),
516            $divFoot  = $wrapper.find('div.fht-tfoot');
517
518        if (!$divFoot.length) {
519          if (settings.fixedColumns > 0) {
520            $divFoot = $('<div class="fht-tfoot"><table class="fht-table"></table></div>').appendTo($wrapper.find('.fht-fixed-body'));
521          } else {
522            $divFoot = $('<div class="fht-tfoot"><table class="fht-table"></table></div>').appendTo($wrapper);
523          }
524        }
525        $divFoot.find('table.fht-table').addClass(settings.originalTable.attr('class'));
526
527        switch (true) {
528          case !$tfoot.length && settings.cloneHeadToFoot == true && settings.footer == true:
529
530            var $divHead = $wrapper.find('div.fht-thead');
531
532            $divFoot.empty();
533            $divHead.find('table')
534              .clone()
535              .appendTo($divFoot);
536
537            break;
538          case $tfoot.length && settings.cloneHeadToFoot == false && settings.footer == true:
539
540            $divFoot.find('table')
541              .append($tfoot)
542              .css({
543                'margin-top': -tableProps.border
544              });
545
546            helpers._setupClone($divFoot, tableProps.tfoot);
547
548            break;
549        }
550
551      },
552
553      /*
554       * return object
555       * Widths of each thead cell and tbody cell for the first rows.
556       * Used in fixing widths for the fixed header and optional footer.
557       */
558      _getTableProps: function($obj) {
559        var tableProp = {
560              thead: {},
561              tbody: {},
562              tfoot: {},
563              border: 0
564            },
565            borderCollapse = 1;
566
567        if (settings.borderCollapse == true) {
568          borderCollapse = 2;
569        }
570
571        tableProp.border = ($obj.find('th:first-child').outerWidth() - $obj.find('th:first-child').innerWidth()) / borderCollapse;
572
573        $obj.find('thead tr:first-child > *').each(function(index) {
574          tableProp.thead[index] = $(this).width() + tableProp.border;
575        });
576
577        $obj.find('tfoot tr:first-child > *').each(function(index) {
578          tableProp.tfoot[index] = $(this).width() + tableProp.border;
579        });
580
581        $obj.find('tbody tr:first-child > *').each(function(index) {
582          tableProp.tbody[index] = $(this).width() + tableProp.border;
583        });
584
585        return tableProp;
586      },
587
588      /*
589       * return void
590       * Fix widths of each cell in the first row of obj.
591       */
592      _setupClone: function($obj, cellArray) {
593        var $self    = $obj,
594            selector = ($self.find('thead').length) ?
595              'thead tr:first-child > *' :
596              ($self.find('tfoot').length) ?
597              'tfoot tr:first-child > *' :
598              'tbody tr:first-child > *',
599            $cell;
600
601        $self.find(selector).each(function(index) {
602          $cell = ($(this).find('div.fht-cell').length) ? $(this).find('div.fht-cell') : $('<div class="fht-cell"></div>').appendTo($(this));
603
604          $cell.css({
605            'width': parseInt(cellArray[index], 10)
606          });
607
608          /*
609           * Fixed Header and Footer should extend the full width
610           * to align with the scrollbar of the body
611           */
612          if (!$(this).closest('.fht-tbody').length && $(this).is(':last-child') && !$(this).closest('.fht-fixed-column').length) {
613            var padding = Math.max((($(this).innerWidth() - $(this).width()) / 2), settings.scrollbarOffset);
614            $(this).css({
615              'padding-right': parseInt($(this).css('padding-right')) + padding + 'px'
616            });
617          }
618        });
619      },
620
621      /*
622       * return boolean
623       * Determine how the browser calculates fixed widths with padding for tables
624       * true if width = padding + width
625       * false if width = width
626       */
627      _isPaddingIncludedWithWidth: function() {
628        var $obj = $('<table class="fht-table"><tr><td style="padding: 10px; font-size: 10px;">test</td></tr></table>'),
629            defaultHeight,
630            newHeight;
631
632        $obj.addClass(settings.originalTable.attr('class'));
633        $obj.appendTo('body');
634
635        defaultHeight = $obj.find('td').height();
636
637        $obj.find('td')
638          .css('height', $obj.find('tr').height());
639
640        newHeight = $obj.find('td').height();
641        $obj.remove();
642
643        if (defaultHeight != newHeight) {
644          return true;
645        } else {
646          return false;
647        }
648
649      },
650
651      /*
652       * return int
653       * get the width of the browsers scroll bar
654       */
655      _getScrollbarWidth: function() {
656        var scrollbarWidth = 0;
657
658        if (!scrollbarWidth) {
659          if (/msie/.test(navigator.userAgent.toLowerCase())) {
660            var $textarea1 = $('<textarea cols="10" rows="2"></textarea>')
661                  .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body'),
662                $textarea2 = $('<textarea cols="10" rows="2" style="overflow: hidden;"></textarea>')
663                  .css({ position: 'absolute', top: -1000, left: -1000 }).appendTo('body');
664
665            scrollbarWidth = $textarea1.width() - $textarea2.width() + 2; // + 2 for border offset
666            $textarea1.add($textarea2).remove();
667          } else {
668            var $div = $('<div />')
669                  .css({ width: 100, height: 100, overflow: 'auto', position: 'absolute', top: -1000, left: -1000 })
670                  .prependTo('body').append('<div />').find('div')
671                  .css({ width: '100%', height: 200 });
672
673            scrollbarWidth = 100 - $div.width();
674            $div.parent().remove();
675          }
676        }
677
678        return scrollbarWidth;
679      }
680
681    };
682
683
684    // if a method as the given argument exists
685    if (methods[method]) {
686
687      // call the respective method
688      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
689
690      // if an object is given as method OR nothing is given as argument
691    } else if (typeof method === 'object' || !method) {
692
693      // call the initialization method
694      return methods.init.apply(this, arguments);
695
696      // otherwise
697    } else {
698
699      // trigger an error
700      $.error('Method "' +  method + '" does not exist in fixedHeaderTable plugin!');
701
702    }
703
704  };
705
706})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.