LaravelTest
1041 строка · 28.4 Кб
1/*! FixedHeader 3.2.1
2* ©2009-2021 SpryMedia Ltd - datatables.net/license
3*/
4
5/**
6* @summary FixedHeader
7* @description Fix a table's header or footer, so it is always visible while
8* scrolling
9* @version 3.2.1
10* @file dataTables.fixedHeader.js
11* @author SpryMedia Ltd (www.sprymedia.co.uk)
12* @contact www.sprymedia.co.uk/contact
13* @copyright Copyright 2009-2021 SpryMedia Ltd.
14*
15* This source file is free software, available under the following license:
16* MIT license - http://datatables.net/license/mit
17*
18* This source file is distributed in the hope that it will be useful, but
19* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
21*
22* For details please refer to: http://www.datatables.net
23*/
24
25(function( factory ){26if ( typeof define === 'function' && define.amd ) {27// AMD28define( ['jquery', 'datatables.net'], function ( $ ) {29return factory( $, window, document );30} );31}32else if ( typeof exports === 'object' ) {33// CommonJS34module.exports = function (root, $) {35if ( ! root ) {36root = window;37}38
39if ( ! $ || ! $.fn.dataTable ) {40$ = require('datatables.net')(root, $).$;41}42
43return factory( $, root, root.document );44};45}46else {47// Browser48factory( jQuery, window, document );49}50}(function( $, window, document, undefined ) {51'use strict';52var DataTable = $.fn.dataTable;53
54
55var _instCounter = 0;56
57var FixedHeader = function ( dt, config ) {58// Sanity check - you just know it will happen59if ( ! (this instanceof FixedHeader) ) {60throw "FixedHeader must be initialised with the 'new' keyword.";61}62
63// Allow a boolean true for defaults64if ( config === true ) {65config = {};66}67
68dt = new DataTable.Api( dt );69
70this.c = $.extend( true, {}, FixedHeader.defaults, config );71
72this.s = {73dt: dt,74position: {75theadTop: 0,76tbodyTop: 0,77tfootTop: 0,78tfootBottom: 0,79width: 0,80left: 0,81tfootHeight: 0,82theadHeight: 0,83windowHeight: $(window).height(),84visible: true85},86headerMode: null,87footerMode: null,88autoWidth: dt.settings()[0].oFeatures.bAutoWidth,89namespace: '.dtfc'+(_instCounter++),90scrollLeft: {91header: -1,92footer: -193},94enable: true95};96
97this.dom = {98floatingHeader: null,99thead: $(dt.table().header()),100tbody: $(dt.table().body()),101tfoot: $(dt.table().footer()),102header: {103host: null,104floating: null,105floatingParent: $('<div class="dtfh-floatingparent">'),106placeholder: null107},108footer: {109host: null,110floating: null,111floatingParent: $('<div class="dtfh-floatingparent">'),112placeholder: null113}114};115
116this.dom.header.host = this.dom.thead.parent();117this.dom.footer.host = this.dom.tfoot.parent();118
119var dtSettings = dt.settings()[0];120if ( dtSettings._fixedHeader ) {121throw "FixedHeader already initialised on table "+dtSettings.nTable.id;122}123
124dtSettings._fixedHeader = this;125
126this._constructor();127};128
129
130/*
131* Variable: FixedHeader
132* Purpose: Prototype for FixedHeader
133* Scope: global
134*/
135$.extend( FixedHeader.prototype, {136/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *137* API methods
138*/
139
140/**141* Kill off FH and any events
142*/
143destroy: function () {144this.s.dt.off( '.dtfc' );145$(window).off( this.s.namespace );146
147if ( this.c.header ) {148this._modeChange( 'in-place', 'header', true );149}150
151if ( this.c.footer && this.dom.tfoot.length ) {152this._modeChange( 'in-place', 'footer', true );153}154},155
156/**157* Enable / disable the fixed elements
158*
159* @param {boolean} enable `true` to enable, `false` to disable
160*/
161enable: function ( enable, update )162{163this.s.enable = enable;164
165if ( update || update === undefined ) {166this._positions();167this._scroll( true );168}169},170
171/**172* Get enabled status
173*/
174enabled: function ()175{176return this.s.enable;177},178
179/**180* Set header offset
181*
182* @param {int} new value for headerOffset
183*/
184headerOffset: function ( offset )185{186if ( offset !== undefined ) {187this.c.headerOffset = offset;188this.update();189}190
191return this.c.headerOffset;192},193
194/**195* Set footer offset
196*
197* @param {int} new value for footerOffset
198*/
199footerOffset: function ( offset )200{201if ( offset !== undefined ) {202this.c.footerOffset = offset;203this.update();204}205
206return this.c.footerOffset;207},208
209
210/**211* Recalculate the position of the fixed elements and force them into place
212*/
213update: function (force)214{215var table = this.s.dt.table().node();216
217if ( $(table).is(':visible') ) {218this.enable( true, false );219}220else {221this.enable( false, false );222}223
224// Don't update if header is not in the document atm (due to225// async events)226if ($(table).children('thead').length === 0) {227return;228}229
230this._positions();231this._scroll( force !== undefined ? force : true );232},233
234
235/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *236* Constructor
237*/
238
239/**240* FixedHeader constructor - adding the required event listeners and
241* simple initialisation
242*
243* @private
244*/
245_constructor: function ()246{247var that = this;248var dt = this.s.dt;249
250$(window)251.on( 'scroll'+this.s.namespace, function () {252that._scroll();253} )254.on( 'resize'+this.s.namespace, DataTable.util.throttle( function () {255that.s.position.windowHeight = $(window).height();256that.update();257}, 50 ) );258
259var autoHeader = $('.fh-fixedHeader');260if ( ! this.c.headerOffset && autoHeader.length ) {261this.c.headerOffset = autoHeader.outerHeight();262}263
264var autoFooter = $('.fh-fixedFooter');265if ( ! this.c.footerOffset && autoFooter.length ) {266this.c.footerOffset = autoFooter.outerHeight();267}268
269dt
270.on( 'column-reorder.dt.dtfc column-visibility.dt.dtfc column-sizing.dt.dtfc responsive-display.dt.dtfc', function (e, ctx) {271that.update();272} )273.on( 'draw.dt.dtfc', function (e, ctx) {274// For updates from our own table, don't reclone, but for all others, do275that.update(ctx === dt.settings()[0] ? false : true);276} );277
278dt.on( 'destroy.dtfc', function () {279that.destroy();280} );281
282this._positions();283this._scroll();284},285
286
287/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *288* Private methods
289*/
290
291/**292* Clone a fixed item to act as a place holder for the original element
293* which is moved into a clone of the table element, and moved around the
294* document to give the fixed effect.
295*
296* @param {string} item 'header' or 'footer'
297* @param {boolean} force Force the clone to happen, or allow automatic
298* decision (reuse existing if available)
299* @private
300*/
301_clone: function ( item, force )302{303var dt = this.s.dt;304var itemDom = this.dom[ item ];305var itemElement = item === 'header' ?306this.dom.thead :307this.dom.tfoot;308
309// If footer and scrolling is enabled then we don't clone310// Instead the table's height is decreased accordingly - see `_scroll()`311if (item === 'footer' && this._scrollEnabled()) {312return;313}314
315if ( ! force && itemDom.floating ) {316// existing floating element - reuse it317itemDom.floating.removeClass( 'fixedHeader-floating fixedHeader-locked' );318}319else {320if ( itemDom.floating ) {321if(itemDom.placeholder !== null) {322itemDom.placeholder.remove();323}324this._unsize( item );325itemDom.floating.children().detach();326itemDom.floating.remove();327}328
329var tableNode = $(dt.table().node());330var scrollBody = $(tableNode.parent());331var scrollEnabled = this._scrollEnabled();332
333itemDom.floating = $( dt.table().node().cloneNode( false ) )334.attr( 'aria-hidden', 'true' )335.css({336'table-layout': 'fixed',337top: 0,338left: 0339})340.removeAttr( 'id' )341.append( itemElement );342
343itemDom.floatingParent344.css({345width: scrollBody.width(),346overflow: 'hidden',347height: 'fit-content',348position: 'fixed',349left: scrollEnabled ? tableNode.offset().left + scrollBody.scrollLeft() : 0350})351.css(352item === 'header' ?353{354top: this.c.headerOffset,355bottom: ''356} :357{358top: '',359bottom: this.c.footerOffset360}361)362.addClass(item === 'footer' ? 'dtfh-floatingparentfoot' : 'dtfh-floatingparenthead')363.append(itemDom.floating)364.appendTo( 'body' );365
366this._stickyPosition(itemDom.floating, '-');367
368var scrollLeftUpdate = () => {369var scrollLeft = scrollBody.scrollLeft()370this.s.scrollLeft = {footer: scrollLeft, header: scrollLeft};371itemDom.floatingParent.scrollLeft(this.s.scrollLeft.header);372}373
374scrollLeftUpdate();375scrollBody.scroll(scrollLeftUpdate)376
377// Insert a fake thead/tfoot into the DataTable to stop it jumping around378itemDom.placeholder = itemElement.clone( false );379itemDom.placeholder380.find( '*[id]' )381.removeAttr( 'id' );382
383itemDom.host.prepend( itemDom.placeholder );384
385// Clone widths386this._matchWidths( itemDom.placeholder, itemDom.floating );387}388},389
390/**391* This method sets the sticky position of the header elements to match fixed columns
392* @param {JQuery<HTMLElement>} el
393* @param {string} sign
394*/
395_stickyPosition(el, sign) {396if (this._scrollEnabled()) {397var that = this398var rtl = $(that.s.dt.table().node()).css('direction') === 'rtl';399
400el.find('th').each(function() {401// Find out if fixed header has previously set this column402if ($(this).css('position') === 'sticky') {403var right = $(this).css('right');404var left = $(this).css('left');405if (right !== 'auto' && !rtl) {406// New position either adds or dismisses the barWidth407var potential = +right.replace(/px/g, '') + (sign === '-' ? -1 : 1) * that.s.dt.settings()[0].oBrowser.barWidth;408$(this).css('right', potential > 0 ? potential : 0);409}410else if(left !== 'auto' && rtl) {411var potential = +left.replace(/px/g, '') + (sign === '-' ? -1 : 1) * that.s.dt.settings()[0].oBrowser.barWidth;412$(this).css('left', potential > 0 ? potential : 0);413}414}415});416}417},418
419/**420* Copy widths from the cells in one element to another. This is required
421* for the footer as the footer in the main table takes its sizes from the
422* header columns. That isn't present in the footer so to have it still
423* align correctly, the sizes need to be copied over. It is also required
424* for the header when auto width is not enabled
425*
426* @param {jQuery} from Copy widths from
427* @param {jQuery} to Copy widths to
428* @private
429*/
430_matchWidths: function ( from, to ) {431var get = function ( name ) {432return $(name, from)433.map( function () {434return $(this).css('width').replace(/[^\d\.]/g, '') * 1;435} ).toArray();436};437
438var set = function ( name, toWidths ) {439$(name, to).each( function ( i ) {440$(this).css( {441width: toWidths[i],442minWidth: toWidths[i]443} );444} );445};446
447var thWidths = get( 'th' );448var tdWidths = get( 'td' );449
450set( 'th', thWidths );451set( 'td', tdWidths );452},453
454/**455* Remove assigned widths from the cells in an element. This is required
456* when inserting the footer back into the main table so the size is defined
457* by the header columns and also when auto width is disabled in the
458* DataTable.
459*
460* @param {string} item The `header` or `footer`
461* @private
462*/
463_unsize: function ( item ) {464var el = this.dom[ item ].floating;465
466if ( el && (item === 'footer' || (item === 'header' && ! this.s.autoWidth)) ) {467$('th, td', el).css( {468width: '',469minWidth: ''470} );471}472else if ( el && item === 'header' ) {473$('th, td', el).css( 'min-width', '' );474}475},476
477/**478* Reposition the floating elements to take account of horizontal page
479* scroll
480*
481* @param {string} item The `header` or `footer`
482* @param {int} scrollLeft Document scrollLeft
483* @private
484*/
485_horizontal: function ( item, scrollLeft )486{487var itemDom = this.dom[ item ];488var position = this.s.position;489var lastScrollLeft = this.s.scrollLeft;490
491if ( itemDom.floating && lastScrollLeft[ item ] !== scrollLeft ) {492// If scrolling is enabled we need to match the floating header to the body493if (this._scrollEnabled()) {494var newScrollLeft = $($(this.s.dt.table().node()).parent()).scrollLeft()495itemDom.floating.scrollLeft(newScrollLeft);496itemDom.floatingParent.scrollLeft(newScrollLeft);497}498
499lastScrollLeft[ item ] = scrollLeft;500}501},502
503/**504* Change from one display mode to another. Each fixed item can be in one
505* of:
506*
507* * `in-place` - In the main DataTable
508* * `in` - Floating over the DataTable
509* * `below` - (Header only) Fixed to the bottom of the table body
510* * `above` - (Footer only) Fixed to the top of the table body
511*
512* @param {string} mode Mode that the item should be shown in
513* @param {string} item 'header' or 'footer'
514* @param {boolean} forceChange Force a redraw of the mode, even if already
515* in that mode.
516* @private
517*/
518_modeChange: function ( mode, item, forceChange )519{520var dt = this.s.dt;521var itemDom = this.dom[ item ];522var position = this.s.position;523
524// Just determine if scroll is enabled once525var scrollEnabled = this._scrollEnabled();526
527// If footer and scrolling is enabled then we don't clone528// Instead the table's height is decreased accordingly - see `_scroll()`529if (item === 'footer' && scrollEnabled) {530return;531}532
533// It isn't trivial to add a !important css attribute...534var importantWidth = function (w) {535itemDom.floating.attr('style', function(i,s) {536return (s || '') + 'width: '+w+'px !important;';537});538
539// If not scrolling also have to update the floatingParent540if (!scrollEnabled) {541itemDom.floatingParent.attr('style', function(i,s) {542return (s || '') + 'width: '+w+'px !important;';543});544}545};546
547// Record focus. Browser's will cause input elements to loose focus if548// they are inserted else where in the doc549var tablePart = this.dom[ item==='footer' ? 'tfoot' : 'thead' ];550var focus = $.contains( tablePart[0], document.activeElement ) ?551document.activeElement :552null;553var scrollBody = $($(this.s.dt.table().node()).parent());554
555if ( mode === 'in-place' ) {556// Insert the header back into the table's real header557if ( itemDom.placeholder ) {558itemDom.placeholder.remove();559itemDom.placeholder = null;560}561
562this._unsize( item );563
564if ( item === 'header' ) {565itemDom.host.prepend( tablePart );566}567else {568itemDom.host.append( tablePart );569}570
571if ( itemDom.floating ) {572itemDom.floating.remove();573itemDom.floating = null;574this._stickyPosition(itemDom.host, '+');575}576
577if ( itemDom.floatingParent ) {578itemDom.floatingParent.remove();579}580
581$($(itemDom.host.parent()).parent()).scrollLeft(scrollBody.scrollLeft())582}583else if ( mode === 'in' ) {584// Remove the header from the read header and insert into a fixed585// positioned floating table clone586this._clone( item, forceChange );587
588// Get useful position values589var scrollOffset = scrollBody.offset();590var windowTop = $(document).scrollTop();591var windowHeight = $(window).height();592var windowBottom = windowTop + windowHeight;593var bodyTop = scrollEnabled ? scrollOffset.top : position.tbodyTop;594var bodyBottom = scrollEnabled ? scrollOffset.top + scrollBody.outerHeight() : position.tfootTop595
596// Calculate the amount that the footer or header needs to be shuffled597var shuffle = item === 'footer' ?598// footer and top of body isn't on screen599bodyTop > windowBottom ?600// Yes - push the footer below601position.tfootHeight :602// No - bottom set to the gap between the top of the body and the bottom of the window603bodyTop + position.tfootHeight - windowBottom :604// Otherwise must be a header so get the difference from the bottom of the605// desired floating header and the bottom of the table body606windowTop + this.c.headerOffset + position.theadHeight - bodyBottom607
608// Set the top or bottom based off of the offset and the shuffle value609var prop = item === 'header' ? 'top' : 'bottom';610var val = this.c[item+'Offset'] - (shuffle > 0 ? shuffle : 0);611
612itemDom.floating.addClass( 'fixedHeader-floating' );613itemDom.floatingParent614.css(prop, val)615.css( {616'left': position.left,617'height': item === 'header' ? position.theadHeight : position.tfootHeight,618'z-index': 2619})620.append(itemDom.floating);621
622importantWidth(position.width);623
624if ( item === 'footer' ) {625itemDom.floating.css( 'top', '' );626}627}628else if ( mode === 'below' ) { // only used for the header629// Fix the position of the floating header at base of the table body630this._clone( item, forceChange );631
632itemDom.floating.addClass( 'fixedHeader-locked' );633itemDom.floatingParent.css({634position: 'absolute',635top: position.tfootTop - position.theadHeight,636left: position.left+'px'637});638
639importantWidth(position.width);640}641else if ( mode === 'above' ) { // only used for the footer642// Fix the position of the floating footer at top of the table body643this._clone( item, forceChange );644
645itemDom.floating.addClass( 'fixedHeader-locked' );646itemDom.floatingParent.css({647position: 'absolute',648top: position.tbodyTop,649left: position.left+'px'650});651
652importantWidth(position.width);653}654
655// Restore focus if it was lost656if ( focus && focus !== document.activeElement ) {657setTimeout( function () {658focus.focus();659}, 10 );660}661
662this.s.scrollLeft.header = -1;663this.s.scrollLeft.footer = -1;664this.s[item+'Mode'] = mode;665},666
667/**668* Cache the positional information that is required for the mode
669* calculations that FixedHeader performs.
670*
671* @private
672*/
673_positions: function ()674{675var dt = this.s.dt;676var table = dt.table();677var position = this.s.position;678var dom = this.dom;679var tableNode = $(table.node());680var scrollEnabled = this._scrollEnabled();681
682// Need to use the header and footer that are in the main table,683// regardless of if they are clones, since they hold the positions we684// want to measure from685var thead = $(dt.table().header());686var tfoot = $(dt.table().footer());687var tbody = dom.tbody;688var scrollBody = tableNode.parent();689
690position.visible = tableNode.is(':visible');691position.width = tableNode.outerWidth();692position.left = tableNode.offset().left;693position.theadTop = thead.offset().top;694position.tbodyTop = scrollEnabled ? scrollBody.offset().top : tbody.offset().top;695position.tbodyHeight = scrollEnabled ? scrollBody.outerHeight() : tbody.outerHeight();696position.theadHeight = thead.outerHeight();697position.theadBottom = position.theadTop + position.theadHeight;698
699if ( tfoot.length ) {700position.tfootTop = position.tbodyTop + position.tbodyHeight; //tfoot.offset().top;701position.tfootBottom = position.tfootTop + tfoot.outerHeight();702position.tfootHeight = tfoot.outerHeight();703}704else {705position.tfootTop = position.tbodyTop + tbody.outerHeight();706position.tfootBottom = position.tfootTop;707position.tfootHeight = position.tfootTop;708}709},710
711
712/**713* Mode calculation - determine what mode the fixed items should be placed
714* into.
715*
716* @param {boolean} forceChange Force a redraw of the mode, even if already
717* in that mode.
718* @private
719*/
720_scroll: function ( forceChange )721{722// ScrollBody details723var scrollEnabled = this._scrollEnabled();724var scrollBody = $(this.s.dt.table().node()).parent();725var scrollOffset = scrollBody.offset();726var scrollHeight = scrollBody.outerHeight();727
728// Window details729var windowLeft = $(document).scrollLeft();730var windowTop = $(document).scrollTop();731var windowHeight = $(window).height();732var windowBottom = windowHeight + windowTop733
734
735var position = this.s.position;736var headerMode, footerMode;737
738// Body Details739var bodyTop = (scrollEnabled ? scrollOffset.top : position.tbodyTop);740var bodyLeft = (scrollEnabled ? scrollOffset.left : position.left);741var bodyBottom = (scrollEnabled ? scrollOffset.top + scrollHeight : position.tfootTop);742var bodyWidth = (scrollEnabled ? scrollBody.outerWidth() : position.tbodyWidth);743
744var windowBottom = windowTop + windowHeight;745
746if ( this.c.header ) {747if ( ! this.s.enable ) {748headerMode = 'in-place';749}750// The header is in it's normal place if the body top is lower than751// the scroll of the window plus the headerOffset and the height of the header752else if ( ! position.visible || windowTop + this.c.headerOffset + position.theadHeight <= bodyTop) {753headerMode = 'in-place';754}755// The header should be floated if756else if (757// The scrolling plus the header offset plus the height of the header is lower than the top of the body758windowTop + this.c.headerOffset + position.theadHeight > bodyTop &&759// And the scrolling at the top plus the header offset is above the bottom of the body760windowTop + this.c.headerOffset < bodyBottom761) {762headerMode = 'in';763var scrollBody = $($(this.s.dt.table().node()).parent());764
765// Further to the above, If the scrolling plus the header offset plus the header height is lower766// than the bottom of the table a shuffle is required so have to force the calculation767if(windowTop + this.c.headerOffset + position.theadHeight > bodyBottom || this.dom.header.floatingParent === undefined){768forceChange = true;769}770else {771this.dom.header.floatingParent772.css({773'top': this.c.headerOffset,774'position': 'fixed'775})776.append(this.dom.header.floating);777}778}779// Anything else and the view is below the table780else {781headerMode = 'below';782}783
784if ( forceChange || headerMode !== this.s.headerMode ) {785this._modeChange( headerMode, 'header', forceChange );786}787
788this._horizontal( 'header', windowLeft );789}790
791var header = {792offset: {top: 0, left: 0},793height: 0794}795var footer = {796offset: {top: 0, left: 0},797height: 0798}799
800if ( this.c.footer && this.dom.tfoot.length ) {801if ( ! this.s.enable ) {802footerMode = 'in-place';803}804else if ( ! position.visible || position.tfootBottom + this.c.footerOffset <= windowBottom ) {805footerMode = 'in-place';806}807else if (808bodyBottom + position.tfootHeight + this.c.footerOffset > windowBottom &&809bodyTop + this.c.footerOffset < windowBottom810) {811footerMode = 'in';812forceChange = true;813}814else {815footerMode = 'above';816}817
818if ( forceChange || footerMode !== this.s.footerMode ) {819this._modeChange( footerMode, 'footer', forceChange );820}821
822this._horizontal( 'footer', windowLeft );823
824var getOffsetHeight = (el) => {825return {826offset: el.offset(),827height: el.outerHeight()828}829}830
831header = this.dom.header.floating ? getOffsetHeight(this.dom.header.floating) : getOffsetHeight(this.dom.thead);832footer = this.dom.footer.floating ? getOffsetHeight(this.dom.footer.floating) : getOffsetHeight(this.dom.tfoot);833
834// If scrolling is enabled and the footer is off the screen835if (scrollEnabled && footer.offset.top > windowTop){// && footer.offset.top >= windowBottom) {836// Calculate the gap between the top of the scrollBody and the top of the window837var overlap = windowTop - scrollOffset.top;838// The new height is the bottom of the window839var newHeight = windowBottom +840// If the gap between the top of the scrollbody and the window is more than841// the height of the header then the top of the table is still visible so add that gap842// Doing this has effectively calculated the height from the top of the table to the bottom of the current page843(overlap > -header.height ? overlap : 0) -844// Take from that845(846// The top of the header plus847header.offset.top +848// The header height if the standard header is present849(overlap < -header.height ? header.height : 0) +850// And the height of the footer851footer.height852)853
854// Don't want a negative height855if (newHeight < 0) {856newHeight = 0;857}858
859// At the end of the above calculation the space between the header (top of the page if floating)860// and the point just above the footer should be the new value for the height of the table.861scrollBody.outerHeight(newHeight);862
863// Need some rounding here as sometimes very small decimal places are encountered864// If the actual height is bigger or equal to the height we just applied then the footer is "Floating"865if(Math.round(scrollBody.outerHeight()) >= Math.round(newHeight)) {866$(this.dom.tfoot.parent()).addClass("fixedHeader-floating");867}868// Otherwise max-width has kicked in so it is not floating869else {870$(this.dom.tfoot.parent()).removeClass("fixedHeader-floating");871}872}873}874
875if(this.dom.header.floating){876this.dom.header.floatingParent.css('left', bodyLeft-windowLeft);877}878if(this.dom.footer.floating){879this.dom.footer.floatingParent.css('left', bodyLeft-windowLeft);880}881
882// If fixed columns is being used on this table then the blockers need to be copied across883// Cloning these is cleaner than creating as our own as it will keep consistency with fixedColumns automatically884// ASSUMING that the class remains the same885if (this.s.dt.settings()[0]._fixedColumns !== undefined) {886var adjustBlocker = (side, end, el) => {887if (el === undefined) {888let blocker = $('div.dtfc-'+side+'-'+end+'-blocker');889el = blocker.length === 0 ?890null :891blocker.clone().appendTo('body').css('z-index', 1);892}893if(el !== null) {894el.css({895top: end === 'top' ? header.offset.top : footer.offset.top,896left: side === 'right' ? bodyLeft + bodyWidth - el.width() : bodyLeft897});898}899
900return el;901}902
903// Adjust all blockers904this.dom.header.rightBlocker = adjustBlocker('right', 'top', this.dom.header.rightBlocker);905this.dom.header.leftBlocker = adjustBlocker('left', 'top', this.dom.header.leftBlocker);906this.dom.footer.rightBlocker = adjustBlocker('right', 'bottom', this.dom.footer.rightBlocker);907this.dom.footer.leftBlocker = adjustBlocker('left', 'bottom', this.dom.footer.leftBlocker);908}909},910
911/**912* Function to check if scrolling is enabled on the table or not
913* @returns Boolean value indicating if scrolling on the table is enabled or not
914*/
915_scrollEnabled: function() {916var oScroll = this.s.dt.settings()[0].oScroll;917if(oScroll.sY !== "" || oScroll.sX !== "") {918return true;919}920return false921}922} );923
924
925/**
926* Version
927* @type {String}
928* @static
929*/
930FixedHeader.version = "3.2.1";931
932/**
933* Defaults
934* @type {Object}
935* @static
936*/
937FixedHeader.defaults = {938header: true,939footer: false,940headerOffset: 0,941footerOffset: 0942};943
944
945/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
946* DataTables interfaces
947*/
948
949// Attach for constructor access
950$.fn.dataTable.FixedHeader = FixedHeader;951$.fn.DataTable.FixedHeader = FixedHeader;952
953
954// DataTables creation - check if the FixedHeader option has been defined on the
955// table and if so, initialise
956$(document).on( 'init.dt.dtfh', function (e, settings, json) {957if ( e.namespace !== 'dt' ) {958return;959}960
961var init = settings.oInit.fixedHeader;962var defaults = DataTable.defaults.fixedHeader;963
964if ( (init || defaults) && ! settings._fixedHeader ) {965var opts = $.extend( {}, defaults, init );966
967if ( init !== false ) {968new FixedHeader( settings, opts );969}970}971} );972
973// DataTables API methods
974DataTable.Api.register( 'fixedHeader()', function () {} );975
976DataTable.Api.register( 'fixedHeader.adjust()', function () {977return this.iterator( 'table', function ( ctx ) {978var fh = ctx._fixedHeader;979
980if ( fh ) {981fh.update();982}983} );984} );985
986DataTable.Api.register( 'fixedHeader.enable()', function ( flag ) {987return this.iterator( 'table', function ( ctx ) {988var fh = ctx._fixedHeader;989
990flag = ( flag !== undefined ? flag : true );991if ( fh && flag !== fh.enabled() ) {992fh.enable( flag );993}994} );995} );996
997DataTable.Api.register( 'fixedHeader.enabled()', function () {998if ( this.context.length ) {999var fh = this.context[0]._fixedHeader;1000
1001if ( fh ) {1002return fh.enabled();1003}1004}1005
1006return false;1007} );1008
1009DataTable.Api.register( 'fixedHeader.disable()', function ( ) {1010return this.iterator( 'table', function ( ctx ) {1011var fh = ctx._fixedHeader;1012
1013if ( fh && fh.enabled() ) {1014fh.enable( false );1015}1016} );1017} );1018
1019$.each( ['header', 'footer'], function ( i, el ) {1020DataTable.Api.register( 'fixedHeader.'+el+'Offset()', function ( offset ) {1021var ctx = this.context;1022
1023if ( offset === undefined ) {1024return ctx.length && ctx[0]._fixedHeader ?1025ctx[0]._fixedHeader[el +'Offset']() :1026undefined;1027}1028
1029return this.iterator( 'table', function ( ctx ) {1030var fh = ctx._fixedHeader;1031
1032if ( fh ) {1033fh[ el +'Offset' ]( offset );1034}1035} );1036} );1037} );1038
1039
1040return FixedHeader;1041}));1042