You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
557 lines
24 KiB
557 lines
24 KiB
/*! FixedColumns 4.0.0 |
|
* 2019-2021 SpryMedia Ltd - datatables.net/license |
|
*/ |
|
(function () { |
|
'use strict'; |
|
|
|
var $; |
|
var dataTable; |
|
function setJQuery(jq) { |
|
$ = jq; |
|
dataTable = $.fn.dataTable; |
|
} |
|
var FixedColumns = /** @class */ (function () { |
|
function FixedColumns(settings, opts) { |
|
var _this = this; |
|
// Check that the required version of DataTables is included |
|
if (!dataTable || !dataTable.versionCheck || !dataTable.versionCheck('1.10.0')) { |
|
throw new Error('StateRestore requires DataTables 1.10 or newer'); |
|
} |
|
var table = new dataTable.Api(settings); |
|
this.classes = $.extend(true, {}, FixedColumns.classes); |
|
// Get options from user |
|
this.c = $.extend(true, {}, FixedColumns.defaults, opts); |
|
// Backwards compatibility for deprecated leftColumns |
|
if (opts.left === undefined && this.c.leftColumns !== undefined) { |
|
this.c.left = this.c.leftColumns; |
|
} |
|
// Backwards compatibility for deprecated rightColumns |
|
if (opts.right === undefined && this.c.rightColumns !== undefined) { |
|
this.c.right = this.c.rightColumns; |
|
} |
|
this.s = { |
|
barWidth: 0, |
|
dt: table, |
|
rtl: $(table.table().node()).css('direction') === 'rtl' |
|
}; |
|
// Set the bar width if vertical scrolling is enabled |
|
if (this.s.dt.settings()[0].oInit.scrollY === true) { |
|
this.s.barWidth = this.s.dt.settings()[0].oBrowser.barWidth; |
|
} |
|
// Common CSS for all blockers |
|
var blockerCSS = { |
|
'background-color': 'white', |
|
'bottom': '0px', |
|
'display': 'block', |
|
'position': 'absolute', |
|
'width': this.s.barWidth + 1 + 'px' |
|
}; |
|
this.dom = { |
|
leftBottomBlocker: $('<div>') |
|
.css(blockerCSS) |
|
.css('left', 0) |
|
.addClass(this.classes.leftBottomBlocker), |
|
leftTopBlocker: $('<div>') |
|
.css(blockerCSS) |
|
.css({ |
|
left: 0, |
|
top: 0 |
|
}) |
|
.addClass(this.classes.leftTopBlocker), |
|
rightBottomBlocker: $('<div>') |
|
.css(blockerCSS) |
|
.css('right', 0) |
|
.addClass(this.classes.rightBottomBlocker), |
|
rightTopBlocker: $('<div>') |
|
.css(blockerCSS) |
|
.css({ |
|
right: 0, |
|
top: 0 |
|
}) |
|
.addClass(this.classes.rightTopBlocker) |
|
}; |
|
if (this.s.dt.settings()[0]._bInitComplete) { |
|
// Fixed Columns Initialisation |
|
this._addStyles(); |
|
this._setKeyTableListener(); |
|
} |
|
else { |
|
table.one('preInit.dt', function () { |
|
// Fixed Columns Initialisation |
|
_this._addStyles(); |
|
_this._setKeyTableListener(); |
|
}); |
|
} |
|
// Make class available through dt object |
|
table.settings()[0]._fixedColumns = this; |
|
return this; |
|
} |
|
/** |
|
* Getter/Setter for the fixedColumns.left property |
|
* |
|
* @param newVal Optional. If present this will be the new value for the number of left fixed columns |
|
* @returns The number of left fixed columns |
|
*/ |
|
FixedColumns.prototype.left = function (newVal) { |
|
// If the value is to change |
|
if (newVal !== undefined) { |
|
// Set the new values and redraw the columns |
|
this.c.left = newVal; |
|
this._addStyles(); |
|
} |
|
return this.c.left; |
|
}; |
|
/** |
|
* Getter/Setter for the fixedColumns.left property |
|
* |
|
* @param newVal Optional. If present this will be the new value for the number of right fixed columns |
|
* @returns The number of right fixed columns |
|
*/ |
|
FixedColumns.prototype.right = function (newVal) { |
|
// If the value is to change |
|
if (newVal !== undefined) { |
|
// Set the new values and redraw the columns |
|
this.c.right = newVal; |
|
this._addStyles(); |
|
} |
|
return this.c.right; |
|
}; |
|
/** |
|
* Iterates over the columns, fixing the appropriate ones to the left and right |
|
*/ |
|
FixedColumns.prototype._addStyles = function () { |
|
var parentDiv = null; |
|
// Get the header and it's height |
|
var header = this.s.dt.column(0).header(); |
|
var headerHeight = null; |
|
if (header !== null) { |
|
header = $(header); |
|
headerHeight = header.outerHeight() + 1; |
|
parentDiv = $(header.closest('div.dataTables_scroll')).css('position', 'relative'); |
|
} |
|
// Get the footer and it's height |
|
var footer = this.s.dt.column(0).footer(); |
|
var footerHeight = null; |
|
if (footer !== null) { |
|
footer = $(footer); |
|
footerHeight = footer.outerHeight(); |
|
// Only attempt to retrieve the parentDiv if it has not been retrieved already |
|
if (parentDiv === null) { |
|
parentDiv = $(footer.closest('div.dataTables_scroll')).css('position', 'relative'); |
|
} |
|
} |
|
// Get the number of columns in the table - this is used often so better to only make 1 api call |
|
var numCols = this.s.dt.columns().data().toArray().length; |
|
// Tracker for the number of pixels should be left to the left of the table |
|
var distLeft = 0; |
|
// Get all of the row elements in the table |
|
var rows = $(this.s.dt.table().node()).children('tbody').children('tr'); |
|
var invisibles = 0; |
|
// Iterate over all of the columns |
|
for (var i = 0; i < numCols; i++) { |
|
var column = this.s.dt.column(i); |
|
if (!column.visible()) { |
|
invisibles++; |
|
continue; |
|
} |
|
// Get the columns header and footer element |
|
var colHeader = $(column.header()); |
|
var colFooter = $(column.footer()); |
|
// If i is less than the value of left then this column should be fixed left |
|
if (i < this.c.left) { |
|
$(this.s.dt.table().node()).addClass(this.classes.tableFixedLeft); |
|
parentDiv.addClass(this.classes.tableFixedLeft); |
|
// Add the width of the previous node - only if we are on atleast the second column |
|
if (i !== 0) { |
|
var prevCol = this.s.dt.column(i - 1); |
|
if (prevCol.visible()) { |
|
distLeft += $(prevCol.nodes()[0]).outerWidth(); |
|
} |
|
} |
|
// Iterate over all of the rows, fixing the cell to the left |
|
for (var _i = 0, rows_1 = rows; _i < rows_1.length; _i++) { |
|
var row = rows_1[_i]; |
|
$($(row).children()[i - invisibles]) |
|
.css(this._getCellCSS(false, distLeft, 'left')) |
|
.addClass(this.classes.fixedLeft); |
|
} |
|
// Add the css for the header and the footer |
|
colHeader |
|
.css(this._getCellCSS(true, distLeft, 'left')) |
|
.addClass(this.classes.fixedLeft); |
|
colFooter |
|
.css(this._getCellCSS(true, distLeft, 'left')) |
|
.addClass(this.classes.fixedLeft); |
|
} |
|
else { |
|
// Iteriate through all of the rows, making sure they aren't currently trying to fix left |
|
for (var _a = 0, rows_2 = rows; _a < rows_2.length; _a++) { |
|
var row = rows_2[_a]; |
|
var cell = $($(row).children()[i - invisibles]); |
|
// If the cell is trying to fix to the left, remove the class and the css |
|
if (cell.hasClass(this.classes.fixedLeft)) { |
|
cell |
|
.css(this._clearCellCSS('left')) |
|
.removeClass(this.classes.fixedLeft); |
|
} |
|
} |
|
// Make sure the header for this column isn't fixed left |
|
if (colHeader.hasClass(this.classes.fixedLeft)) { |
|
colHeader |
|
.css(this._clearCellCSS('left')) |
|
.removeClass(this.classes.fixedLeft); |
|
} |
|
// Make sure the footer for this column isn't fixed left |
|
if (colFooter.hasClass(this.classes.fixedLeft)) { |
|
colFooter |
|
.css(this._clearCellCSS('left')) |
|
.removeClass(this.classes.fixedLeft); |
|
} |
|
} |
|
} |
|
// If there is a header with the index class and reading rtl then add left top blocker |
|
if (header !== null && !header.hasClass('index')) { |
|
if (this.s.rtl) { |
|
this.dom.leftTopBlocker.outerHeight(headerHeight); |
|
parentDiv.append(this.dom.leftTopBlocker); |
|
} |
|
else { |
|
this.dom.rightTopBlocker.outerHeight(headerHeight); |
|
parentDiv.append(this.dom.rightTopBlocker); |
|
} |
|
} |
|
// If there is a footer with the index class and reading rtl then add left bottom blocker |
|
if (footer !== null && !footer.hasClass('index')) { |
|
if (this.s.rtl) { |
|
this.dom.leftBottomBlocker.outerHeight(footerHeight); |
|
parentDiv.append(this.dom.leftBottomBlocker); |
|
} |
|
else { |
|
this.dom.rightBottomBlocker.outerHeight(footerHeight); |
|
parentDiv.append(this.dom.rightBottomBlocker); |
|
} |
|
} |
|
var distRight = 0; |
|
invisibles = 0; |
|
for (var i = numCols - 1; i >= 0; i--) { |
|
var column = this.s.dt.column(i); |
|
// Get the columns header and footer element |
|
var colHeader = $(column.header()); |
|
var colFooter = $(column.footer()); |
|
if (!column.visible()) { |
|
invisibles++; |
|
continue; |
|
} |
|
if (i >= numCols - this.c.right) { |
|
$(this.s.dt.table().node()).addClass(this.classes.tableFixedRight); |
|
parentDiv.addClass(this.classes.tableFixedLeft); |
|
// Add the widht of the previous node, only if we are on atleast the second column |
|
if (i !== numCols - 1) { |
|
var prevCol = this.s.dt.column(i + 1); |
|
if (prevCol.visible()) { |
|
distRight += $(prevCol.nodes()[0]).outerWidth(); |
|
} |
|
} |
|
// Iterate over all of the rows, fixing the cell to the right |
|
for (var _b = 0, rows_3 = rows; _b < rows_3.length; _b++) { |
|
var row = rows_3[_b]; |
|
$($(row).children()[i + invisibles]) |
|
.css(this._getCellCSS(false, distRight, 'right')) |
|
.addClass(this.classes.fixedRight); |
|
} |
|
// Add the css for the header and the footer |
|
colHeader |
|
.css(this._getCellCSS(true, distRight, 'right')) |
|
.addClass(this.classes.fixedRight); |
|
colFooter |
|
.css(this._getCellCSS(true, distRight, 'right')) |
|
.addClass(this.classes.fixedRight); |
|
} |
|
else { |
|
// Iteriate through all of the rows, making sure they aren't currently trying to fix right |
|
for (var _c = 0, rows_4 = rows; _c < rows_4.length; _c++) { |
|
var row = rows_4[_c]; |
|
var cell = $($(row).children()[i + invisibles]); |
|
// If the cell is trying to fix to the right, remove the class and the css |
|
if (cell.hasClass(this.classes.fixedRight)) { |
|
cell |
|
.css(this._clearCellCSS('right')) |
|
.removeClass(this.classes.fixedRight); |
|
} |
|
} |
|
// Make sure the header for this column isn't fixed right |
|
if (colHeader.hasClass(this.classes.fixedRight)) { |
|
colHeader |
|
.css(this._clearCellCSS('right')) |
|
.removeClass(this.classes.fixedRight); |
|
} |
|
// Make sure the footer for this column isn't fixed right |
|
if (colFooter.hasClass(this.classes.fixedRight)) { |
|
colFooter |
|
.css(this._clearCellCSS('right')) |
|
.removeClass(this.classes.fixedRight); |
|
} |
|
} |
|
} |
|
// If there is a header with the index class and reading rtl then add right top blocker |
|
if (header) { |
|
if (!this.s.rtl) { |
|
this.dom.rightTopBlocker.outerHeight(headerHeight); |
|
parentDiv.append(this.dom.rightTopBlocker); |
|
} |
|
else { |
|
this.dom.leftTopBlocker.outerHeight(headerHeight); |
|
parentDiv.append(this.dom.leftTopBlocker); |
|
} |
|
} |
|
// If there is a footer with the index class and reading rtl then add right bottom blocker |
|
if (footer) { |
|
if (!this.s.rtl) { |
|
this.dom.rightBottomBlocker.outerHeight(footerHeight); |
|
parentDiv.append(this.dom.rightBottomBlocker); |
|
} |
|
else { |
|
this.dom.leftBottomBlocker.outerHeight(footerHeight); |
|
parentDiv.append(this.dom.leftBottomBlocker); |
|
} |
|
} |
|
}; |
|
/** |
|
* Gets the correct CSS for the cell, header or footer based on options provided |
|
* |
|
* @param header Whether this cell is a header or a footer |
|
* @param dist The distance that the cell should be moved away from the edge |
|
* @param lr Indicator of fixing to the left or the right |
|
* @returns An object containing the correct css |
|
*/ |
|
FixedColumns.prototype._getCellCSS = function (header, dist, lr) { |
|
if (lr === 'left') { |
|
return !this.s.rtl ? |
|
{ |
|
left: dist + 'px', |
|
position: 'sticky' |
|
} : |
|
{ |
|
position: 'sticky', |
|
right: dist + (header ? this.s.barWidth : 0) + 'px' |
|
}; |
|
} |
|
else { |
|
return !this.s.rtl ? |
|
{ |
|
position: 'sticky', |
|
right: dist + (header ? this.s.barWidth : 0) + 'px' |
|
} : |
|
{ |
|
left: dist + 'px', |
|
position: 'sticky' |
|
}; |
|
} |
|
}; |
|
/** |
|
* Gets the css that is required to clear the fixing to a side |
|
* |
|
* @param lr Indicator of fixing to the left or the right |
|
* @returns An object containing the correct css |
|
*/ |
|
FixedColumns.prototype._clearCellCSS = function (lr) { |
|
if (lr === 'left') { |
|
return !this.s.rtl ? |
|
{ |
|
left: '', |
|
position: '' |
|
} : |
|
{ |
|
position: '', |
|
right: '' |
|
}; |
|
} |
|
else { |
|
return !this.s.rtl ? |
|
{ |
|
position: '', |
|
right: '' |
|
} : |
|
{ |
|
left: '', |
|
position: '' |
|
}; |
|
} |
|
}; |
|
FixedColumns.prototype._setKeyTableListener = function () { |
|
var _this = this; |
|
this.s.dt.on('key-focus', function (e, dt, cell) { |
|
var cellPos = $(cell.node()).offset(); |
|
var scroll = $($(_this.s.dt.table().node()).closest('div.dataTables_scrollBody')); |
|
// If there are fixed columns to the left |
|
if (_this.c.left > 0) { |
|
// Get the rightmost left fixed column header, it's position and it's width |
|
var rightMost = $(_this.s.dt.column(_this.c.left - 1).header()); |
|
var rightMostPos = rightMost.offset(); |
|
var rightMostWidth = rightMost.outerWidth(); |
|
// If the current highlighted cell is left of the rightmost cell on the screen |
|
if (cellPos.left < rightMostPos.left + rightMostWidth) { |
|
// Scroll it into view |
|
var currScroll = scroll.scrollLeft(); |
|
scroll.scrollLeft(currScroll - (rightMostPos.left + rightMostWidth - cellPos.left)); |
|
} |
|
} |
|
// If there are fixed columns to the right |
|
if (_this.c.right > 0) { |
|
// Get the number of columns and the width of the cell as doing right side calc |
|
var numCols = _this.s.dt.columns().data().toArray().length; |
|
var cellWidth = $(cell.node()).outerWidth(); |
|
// Get the leftmost right fixed column header and it's position |
|
var leftMost = $(_this.s.dt.column(numCols - _this.c.right).header()); |
|
var leftMostPos = leftMost.offset(); |
|
// If the current highlighted cell is right of the leftmost cell on the screen |
|
if (cellPos.left + cellWidth > leftMostPos.left) { |
|
// Scroll it into view |
|
var currScroll = scroll.scrollLeft(); |
|
scroll.scrollLeft(currScroll - (leftMostPos.left - (cellPos.left + cellWidth))); |
|
} |
|
} |
|
}); |
|
// Whenever a draw occurs there is potential for the data to have changed and therefore also the column widths |
|
// Therefore it is necessary to recalculate the values for the fixed columns |
|
this.s.dt.on('draw', function () { |
|
_this._addStyles(); |
|
}); |
|
this.s.dt.on('column-reorder', function () { |
|
_this._addStyles(); |
|
}); |
|
this.s.dt.on('column-visibility', function () { |
|
_this._addStyles(); |
|
}); |
|
}; |
|
FixedColumns.version = '4.0.0'; |
|
FixedColumns.classes = { |
|
fixedLeft: 'dtfc-fixed-left', |
|
fixedRight: 'dtfc-fixed-right', |
|
leftBottomBlocker: 'dtfc-left-bottom-blocker', |
|
leftTopBlocker: 'dtfc-left-top-blocker', |
|
rightBottomBlocker: 'dtfc-right-bottom-blocker', |
|
rightTopBlocker: 'dtfc-right-top-blocker', |
|
tableFixedLeft: 'dtfc-has-left', |
|
tableFixedRight: 'dtfc-has-right' |
|
}; |
|
FixedColumns.defaults = { |
|
i18n: { |
|
button: 'FixedColumns' |
|
}, |
|
left: 1, |
|
right: 0 |
|
}; |
|
return FixedColumns; |
|
}()); |
|
|
|
/*! FixedColumns 4.0.0 |
|
* 2019-2021 SpryMedia Ltd - datatables.net/license |
|
*/ |
|
// DataTables extensions common UMD. Note that this allows for AMD, CommonJS |
|
// (with window and jQuery being allowed as parameters to the returned |
|
// function) or just default browser loading. |
|
(function (factory) { |
|
if (typeof define === 'function' && define.amd) { |
|
// AMD |
|
define(['jquery', 'datatables.net'], function ($) { |
|
return factory($, window, document); |
|
}); |
|
} |
|
else if (typeof exports === 'object') { |
|
// CommonJS |
|
module.exports = function (root, $) { |
|
if (!root) { |
|
root = window; |
|
} |
|
if (!$ || !$.fn.dataTable) { |
|
// eslint-disable-next-line @typescript-eslint/no-var-requires |
|
$ = require('datatables.net')(root, $).$; |
|
} |
|
return factory($, root, root.document); |
|
}; |
|
} |
|
else { |
|
// Browser - assume jQuery has already been loaded |
|
factory(window.jQuery, window, document); |
|
} |
|
}(function ($, window, document) { |
|
setJQuery($); |
|
var dataTable = $.fn.dataTable; |
|
$.fn.dataTable.FixedColumns = FixedColumns; |
|
$.fn.DataTable.FixedColumns = FixedColumns; |
|
var apiRegister = $.fn.dataTable.Api.register; |
|
apiRegister('fixedColumns()', function () { |
|
return this; |
|
}); |
|
apiRegister('fixedColumns().left()', function (newVal) { |
|
var ctx = this.context[0]; |
|
if (newVal !== undefined) { |
|
ctx._fixedColumns.left(newVal); |
|
return this; |
|
} |
|
else { |
|
return ctx._fixedColumns.left(); |
|
} |
|
}); |
|
apiRegister('fixedColumns().right()', function (newVal) { |
|
var ctx = this.context[0]; |
|
if (newVal !== undefined) { |
|
ctx._fixedColumns.right(newVal); |
|
return this; |
|
} |
|
else { |
|
return ctx._fixedColumns.right(); |
|
} |
|
}); |
|
$.fn.dataTable.ext.buttons.fixedColumns = { |
|
action: function (e, dt, node, config) { |
|
if ($(node).attr('active')) { |
|
$(node).removeAttr('active').removeClass('active'); |
|
dt.fixedColumns().left(0); |
|
dt.fixedColumns().right(0); |
|
} |
|
else { |
|
$(node).attr('active', true).addClass('active'); |
|
dt.fixedColumns().left(config.config.left); |
|
dt.fixedColumns().right(config.config.right); |
|
} |
|
}, |
|
config: { |
|
left: 1, |
|
right: 0 |
|
}, |
|
init: function (dt, node, config) { |
|
if (dt.settings()[0]._fixedColumns === undefined) { |
|
_init(dt.settings(), config); |
|
} |
|
$(node).attr('active', true).addClass('active'); |
|
dt.button(node).text(config.text || dt.i18n('buttons.fixedColumns', dt.settings()[0]._fixedColumns.c.i18n.button)); |
|
}, |
|
text: null |
|
}; |
|
function _init(settings, options) { |
|
if (options === void 0) { options = null; } |
|
var api = new dataTable.Api(settings); |
|
var opts = options |
|
? options |
|
: api.init().fixedColumns || dataTable.defaults.fixedColumns; |
|
var fixedColumns = new FixedColumns(api, opts); |
|
return fixedColumns; |
|
} |
|
// Attach a listener to the document which listens for DataTables initialisation |
|
// events so we can automatically initialise |
|
$(document).on('init.dt.dtfc', function (e, settings) { |
|
if (e.namespace !== 'dt') { |
|
return; |
|
} |
|
if (settings.oInit.fixedColumns || |
|
dataTable.defaults.fixedColumns) { |
|
if (!settings._fixedColumns) { |
|
_init(settings, null); |
|
} |
|
} |
|
}); |
|
})); |
|
|
|
}());
|
|
|