1/*! FixedColumns 4.3.0 2 * © SpryMedia Ltd - datatables.net/license 3 */ 4 5(function( factory ){ 6 if ( typeof define === 'function' && define.amd ) { 7 // AMD 8 define( ['jquery', 'datatables.net'], function ( $ ) { 9 return factory( $, window, document ); 10 } ); 11 } 12 else if ( typeof exports === 'object' ) { 13 // CommonJS 14 var jq = require('jquery'); 15 var cjsRequires = function (root, $) { 16 if ( ! $.fn.dataTable ) { 17 require('datatables.net')(root, $); 18 } 19 }; 20 21 if (typeof window === 'undefined') { 22 module.exports = function (root, $) { 23 if ( ! root ) { 24 // CommonJS environments without a window global must pass a 25 // root. This will give an error otherwise 26 root = window; 27 } 28 29 if ( ! $ ) { 30 $ = jq( root ); 31 } 32 33 cjsRequires( root, $ ); 34 return factory( $, root, root.document ); 35 }; 36 } 37 else { 38 cjsRequires( window, jq ); 39 module.exports = factory( jq, window, window.document ); 40 } 41 } 42 else { 43 // Browser 44 factory( jQuery, window, document ); 45 } 46}(function( $, window, document, undefined ) { 47'use strict'; 48var DataTable = $.fn.dataTable; 49 50 51(function () { 52 'use strict'; 53 54 var $$1; 55 var dataTable; 56 function setJQuery(jq) { 57 $$1 = jq; 58 dataTable = $$1.fn.dataTable; 59 } 60 var FixedColumns = /** @class */ (function () { 61 function FixedColumns(settings, opts) { 62 var _this = this; 63 // Check that the required version of DataTables is included 64 if (!dataTable || !dataTable.versionCheck || !dataTable.versionCheck('1.10.0')) { 65 throw new Error('FixedColumns requires DataTables 1.10 or newer'); 66 } 67 var table = new dataTable.Api(settings); 68 this.classes = $$1.extend(true, {}, FixedColumns.classes); 69 // Get options from user 70 this.c = $$1.extend(true, {}, FixedColumns.defaults, opts); 71 // Backwards compatibility for deprecated leftColumns 72 if ((!opts || opts.left === undefined) && this.c.leftColumns !== undefined) { 73 this.c.left = this.c.leftColumns; 74 } 75 // Backwards compatibility for deprecated rightColumns 76 if ((!opts || opts.right === undefined) && this.c.rightColumns !== undefined) { 77 this.c.right = this.c.rightColumns; 78 } 79 this.s = { 80 barWidth: 0, 81 dt: table, 82 rtl: $$1('body').css('direction') === 'rtl' 83 }; 84 // Common CSS for all blockers 85 var blockerCSS = { 86 'bottom': '0px', 87 'display': 'block', 88 'position': 'absolute', 89 'width': this.s.barWidth + 1 + 'px' 90 }; 91 this.dom = { 92 leftBottomBlocker: $$1('<div>') 93 .css(blockerCSS) 94 .css('left', 0) 95 .addClass(this.classes.leftBottomBlocker), 96 leftTopBlocker: $$1('<div>') 97 .css(blockerCSS) 98 .css({ 99 left: 0, 100 top: 0 101 }) 102 .addClass(this.classes.leftTopBlocker), 103 rightBottomBlocker: $$1('<div>') 104 .css(blockerCSS) 105 .css('right', 0) 106 .addClass(this.classes.rightBottomBlocker), 107 rightTopBlocker: $$1('<div>') 108 .css(blockerCSS) 109 .css({ 110 right: 0, 111 top: 0 112 }) 113 .addClass(this.classes.rightTopBlocker) 114 }; 115 if (this.s.dt.settings()[0]._bInitComplete) { 116 // Fixed Columns Initialisation 117 this._addStyles(); 118 this._setKeyTableListener(); 119 } 120 else { 121 table.one('init.dt.dtfc', function () { 122 // Fixed Columns Initialisation 123 _this._addStyles(); 124 _this._setKeyTableListener(); 125 }); 126 } 127 table.on('column-sizing.dt.dtfc', function () { return _this._addStyles(); }); 128 // Make class available through dt object 129 table.settings()[0]._fixedColumns = this; 130 table.on('destroy', function () { return _this._destroy(); }); 131 return this; 132 } 133 FixedColumns.prototype.left = function (newVal) { 134 // If the value is to change 135 if (newVal !== undefined) { 136 if (newVal >= 0 && newVal <= this.s.dt.columns().count()) { 137 // Set the new values and redraw the columns 138 this.c.left = newVal; 139 this._addStyles(); 140 } 141 return this; 142 } 143 return this.c.left; 144 }; 145 FixedColumns.prototype.right = function (newVal) { 146 // If the value is to change 147 if (newVal !== undefined) { 148 if (newVal >= 0 && newVal <= this.s.dt.columns().count()) { 149 // Set the new values and redraw the columns 150 this.c.right = newVal; 151 this._addStyles(); 152 } 153 return this; 154 } 155 return this.c.right; 156 }; 157 /** 158 * Iterates over the columns, fixing the appropriate ones to the left and right 159 */ 160 FixedColumns.prototype._addStyles = function () { 161 // Set the bar width if vertical scrolling is enabled 162 if (this.s.dt.settings()[0].oScroll.sY) { 163 var scroll_1 = $$1(this.s.dt.table().node()).closest('div.dataTables_scrollBody')[0]; 164 var barWidth = this.s.dt.settings()[0].oBrowser.barWidth; 165 if (scroll_1.offsetWidth - scroll_1.clientWidth >= barWidth) { 166 this.s.barWidth = barWidth; 167 } 168 else { 169 this.s.barWidth = 0; 170 } 171 this.dom.rightTopBlocker.css('width', this.s.barWidth + 1); 172 this.dom.leftTopBlocker.css('width', this.s.barWidth + 1); 173 this.dom.rightBottomBlocker.css('width', this.s.barWidth + 1); 174 this.dom.leftBottomBlocker.css('width', this.s.barWidth + 1); 175 } 176 var parentDiv = null; 177 // Get the header and it's height 178 var header = this.s.dt.column(0).header(); 179 var headerHeight = null; 180 if (header !== null) { 181 header = $$1(header); 182 headerHeight = header.outerHeight() + 1; 183 parentDiv = $$1(header.closest('div.dataTables_scroll')).css('position', 'relative'); 184 } 185 // Get the footer and it's height 186 var footer = this.s.dt.column(0).footer(); 187 var footerHeight = null; 188 if (footer !== null) { 189 footer = $$1(footer); 190 footerHeight = footer.outerHeight(); 191 // Only attempt to retrieve the parentDiv if it has not been retrieved already 192 if (parentDiv === null) { 193 parentDiv = $$1(footer.closest('div.dataTables_scroll')).css('position', 'relative'); 194 } 195 } 196 // Get the number of columns in the table - this is used often so better to only make 1 api call 197 var numCols = this.s.dt.columns().data().toArray().length; 198 // Tracker for the number of pixels should be left to the left of the table 199 var distLeft = 0; 200 // Sometimes the headers have slightly different widths so need to track them individually 201 var headLeft = 0; 202 // Get all of the row elements in the table 203 var rows = $$1(this.s.dt.table().node()).children('tbody').children('tr'); 204 var invisibles = 0; 205 // When working from right to left we need to know how many are invisible before a point, 206 // without including those that are invisible after 207 var prevInvisible = new Map(); 208 // Iterate over all of the columns 209 for (var i = 0; i < numCols; i++) { 210 var column = this.s.dt.column(i); 211 // Set the map for the previous column 212 if (i > 0) { 213 prevInvisible.set(i - 1, invisibles); 214 } 215 if (!column.visible()) { 216 invisibles++; 217 continue; 218 } 219 // Get the columns header and footer element 220 var colHeader = $$1(column.header()); 221 var colFooter = $$1(column.footer()); 222 // If i is less than the value of left then this column should be fixed left 223 if (i - invisibles < this.c.left) { 224 $$1(this.s.dt.table().node()).addClass(this.classes.tableFixedLeft); 225 parentDiv.addClass(this.classes.tableFixedLeft); 226 // Add the width of the previous node - only if we are on atleast the second column 227 if (i - invisibles > 0) { 228 var prevIdx = i; 229 // Simply using the number of hidden columns doesn't work here, 230 // if the first is hidden then this would be thrown off 231 while (prevIdx + 1 < numCols) { 232 var prevCol = this.s.dt.column(prevIdx - 1, { page: 'current' }); 233 if (prevCol.visible()) { 234 distLeft += $$1(prevCol.nodes()[0]).outerWidth(); 235 headLeft += prevCol.header() ? 236 $$1(prevCol.header()).outerWidth() : 237 prevCol.footer() ? 238 $$1(prevCol.header()).outerWidth() : 239 0; 240 break; 241 } 242 prevIdx--; 243 } 244 } 245 // Iterate over all of the rows, fixing the cell to the left 246 for (var _i = 0, rows_1 = rows; _i < rows_1.length; _i++) { 247 var row = rows_1[_i]; 248 $$1($$1(row).children()[i - invisibles]) 249 .css(this._getCellCSS(false, distLeft, 'left')) 250 .addClass(this.classes.fixedLeft); 251 } 252 // Add the css for the header and the footer 253 colHeader 254 .css(this._getCellCSS(true, headLeft, 'left')) 255 .addClass(this.classes.fixedLeft); 256 colFooter 257 .css(this._getCellCSS(true, headLeft, 'left')) 258 .addClass(this.classes.fixedLeft); 259 } 260 else { 261 // Iteriate through all of the rows, making sure they aren't currently trying to fix left 262 for (var _a = 0, rows_2 = rows; _a < rows_2.length; _a++) { 263 var row = rows_2[_a]; 264 var cell = $$1($$1(row).children()[i - invisibles]); 265 // If the cell is trying to fix to the left, remove the class and the css 266 if (cell.hasClass(this.classes.fixedLeft)) { 267 cell 268 .css(this._clearCellCSS('left')) 269 .removeClass(this.classes.fixedLeft); 270 } 271 } 272 // Make sure the header for this column isn't fixed left 273 if (colHeader.hasClass(this.classes.fixedLeft)) { 274 colHeader 275 .css(this._clearCellCSS('left')) 276 .removeClass(this.classes.fixedLeft); 277 } 278 // Make sure the footer for this column isn't fixed left 279 if (colFooter.hasClass(this.classes.fixedLeft)) { 280 colFooter 281 .css(this._clearCellCSS('left')) 282 .removeClass(this.classes.fixedLeft); 283 } 284 } 285 } 286 var distRight = 0; 287 var headRight = 0; 288 // Counter for the number of invisible columns so far 289 var rightInvisibles = 0; 290 for (var i = numCols - 1; i >= 0; i--) { 291 var column = this.s.dt.column(i); 292 // If a column is invisible just skip it 293 if (!column.visible()) { 294 rightInvisibles++; 295 continue; 296 } 297 // Get the columns header and footer element 298 var colHeader = $$1(column.header()); 299 var colFooter = $$1(column.footer()); 300 // Get the number of visible columns that came before this one 301 var prev = prevInvisible.get(i); 302 if (prev === undefined) { 303 // If it wasn't set then it was the last column so just use the final value 304 prev = invisibles; 305 } 306 if (i + rightInvisibles >= numCols - this.c.right) { 307 $$1(this.s.dt.table().node()).addClass(this.classes.tableFixedRight); 308 parentDiv.addClass(this.classes.tableFixedRight); 309 // Add the widht of the previous node, only if we are on atleast the second column 310 if (i + 1 + rightInvisibles < numCols) { 311 var prevIdx = i; 312 // Simply using the number of hidden columns doesn't work here, 313 // if the first is hidden then this would be thrown off 314 while (prevIdx + 1 < numCols) { 315 var prevCol = this.s.dt.column(prevIdx + 1, { page: 'current' }); 316 if (prevCol.visible()) { 317 distRight += $$1(prevCol.nodes()[0]).outerWidth(); 318 headRight += prevCol.header() ? 319 $$1(prevCol.header()).outerWidth() : 320 prevCol.footer() ? 321 $$1(prevCol.header()).outerWidth() : 322 0; 323 break; 324 } 325 prevIdx++; 326 } 327 } 328 // Iterate over all of the rows, fixing the cell to the right 329 for (var _b = 0, rows_3 = rows; _b < rows_3.length; _b++) { 330 var row = rows_3[_b]; 331 $$1($$1(row).children()[i - prev]) 332 .css(this._getCellCSS(false, distRight, 'right')) 333 .addClass(this.classes.fixedRight); 334 } 335 // Add the css for the header and the footer 336 colHeader 337 .css(this._getCellCSS(true, headRight, 'right')) 338 .addClass(this.classes.fixedRight); 339 colFooter 340 .css(this._getCellCSS(true, headRight, 'right')) 341 .addClass(this.classes.fixedRight); 342 } 343 else { 344 // Iteriate through all of the rows, making sure they aren't currently trying to fix right 345 for (var _c = 0, rows_4 = rows; _c < rows_4.length; _c++) { 346 var row = rows_4[_c]; 347 var cell = $$1($$1(row).children()[i - prev]); 348 // If the cell is trying to fix to the right, remove the class and the css 349 if (cell.hasClass(this.classes.fixedRight)) { 350 cell 351 .css(this._clearCellCSS('right')) 352 .removeClass(this.classes.fixedRight); 353 } 354 } 355 // Make sure the header for this column isn't fixed right 356 if (colHeader.hasClass(this.classes.fixedRight)) { 357 colHeader 358 .css(this._clearCellCSS('right')) 359 .removeClass(this.classes.fixedRight); 360 } 361 // Make sure the footer for this column isn't fixed right 362 if (colFooter.hasClass(this.classes.fixedRight)) { 363 colFooter 364 .css(this._clearCellCSS('right')) 365 .removeClass(this.classes.fixedRight); 366 } 367 } 368 } 369 // If there is a header with the index class and reading rtl then add right top blocker 370 if (header) { 371 if (!this.s.rtl) { 372 this.dom.rightTopBlocker.outerHeight(headerHeight); 373 parentDiv.append(this.dom.rightTopBlocker); 374 } 375 else { 376 this.dom.leftTopBlocker.outerHeight(headerHeight); 377 parentDiv.append(this.dom.leftTopBlocker); 378 } 379 } 380 // If there is a footer with the index class and reading rtl then add right bottom blocker 381 if (footer) { 382 if (!this.s.rtl) { 383 this.dom.rightBottomBlocker.outerHeight(footerHeight); 384 parentDiv.append(this.dom.rightBottomBlocker); 385 } 386 else { 387 this.dom.leftBottomBlocker.outerHeight(footerHeight); 388 parentDiv.append(this.dom.leftBottomBlocker); 389 } 390 } 391 }; 392 /** 393 * Clean up 394 */ 395 FixedColumns.prototype._destroy = function () { 396 this.s.dt.off('.dtfc'); 397 this.dom.leftBottomBlocker.remove(); 398 this.dom.leftTopBlocker.remove(); 399 this.dom.rightBottomBlocker.remove(); 400 this.dom.rightTopBlocker.remove(); 401 }; 402 /** 403 * Gets the correct CSS for the cell, header or footer based on options provided 404 * 405 * @param header Whether this cell is a header or a footer 406 * @param dist The distance that the cell should be moved away from the edge 407 * @param lr Indicator of fixing to the left or the right 408 * @returns An object containing the correct css 409 */ 410 FixedColumns.prototype._getCellCSS = function (header, dist, lr) { 411 if (lr === 'left') { 412 return this.s.rtl 413 ? { 414 position: 'sticky', 415 right: dist + 'px' 416 } 417 : { 418 left: dist + 'px', 419 position: 'sticky' 420 }; 421 } 422 else { 423 return this.s.rtl 424 ? { 425 left: dist + (header ? this.s.barWidth : 0) + 'px', 426 position: 'sticky' 427 } 428 : { 429 position: 'sticky', 430 right: dist + (header ? this.s.barWidth : 0) + 'px' 431 }; 432 } 433 }; 434 /** 435 * Gets the css that is required to clear the fixing to a side 436 * 437 * @param lr Indicator of fixing to the left or the right 438 * @returns An object containing the correct css 439 */ 440 FixedColumns.prototype._clearCellCSS = function (lr) { 441 if (lr === 'left') { 442 return !this.s.rtl ? 443 { 444 left: '', 445 position: '' 446 } : 447 { 448 position: '', 449 right: '' 450 }; 451 } 452 else { 453 return !this.s.rtl ? 454 { 455 position: '', 456 right: '' 457 } : 458 { 459 left: '', 460 position: '' 461 }; 462 } 463 }; 464 FixedColumns.prototype._setKeyTableListener = function () { 465 var _this = this; 466 this.s.dt.on('key-focus.dt.dtfc', function (e, dt, cell) { 467 var cellPos = $$1(cell.node()).offset(); 468 var scroll = $$1($$1(_this.s.dt.table().node()).closest('div.dataTables_scrollBody')); 469 // If there are fixed columns to the left 470 if (_this.c.left > 0) { 471 // Get the rightmost left fixed column header, it's position and it's width 472 var rightMost = $$1(_this.s.dt.column(_this.c.left - 1).header()); 473 var rightMostPos = rightMost.offset(); 474 var rightMostWidth = rightMost.outerWidth(); 475 // If the current highlighted cell is left of the rightmost cell on the screen 476 if (cellPos.left < rightMostPos.left + rightMostWidth) { 477 // Scroll it into view 478 var currScroll = scroll.scrollLeft(); 479 scroll.scrollLeft(currScroll - (rightMostPos.left + rightMostWidth - cellPos.left)); 480 } 481 } 482 // If there are fixed columns to the right 483 if (_this.c.right > 0) { 484 // Get the number of columns and the width of the cell as doing right side calc 485 var numCols = _this.s.dt.columns().data().toArray().length; 486 var cellWidth = $$1(cell.node()).outerWidth(); 487 // Get the leftmost right fixed column header and it's position 488 var leftMost = $$1(_this.s.dt.column(numCols - _this.c.right).header()); 489 var leftMostPos = leftMost.offset(); 490 // If the current highlighted cell is right of the leftmost cell on the screen 491 if (cellPos.left + cellWidth > leftMostPos.left) { 492 // Scroll it into view 493 var currScroll = scroll.scrollLeft(); 494 scroll.scrollLeft(currScroll - (leftMostPos.left - (cellPos.left + cellWidth))); 495 } 496 } 497 }); 498 // Whenever a draw occurs there is potential for the data to have changed and therefore also the column widths 499 // Therefore it is necessary to recalculate the values for the fixed columns 500 this.s.dt.on('draw.dt.dtfc', function () { 501 _this._addStyles(); 502 }); 503 this.s.dt.on('column-reorder.dt.dtfc', function () { 504 _this._addStyles(); 505 }); 506 this.s.dt.on('column-visibility.dt.dtfc', function (e, settings, column, state, recalc) { 507 if (recalc && !settings.bDestroying) { 508 setTimeout(function () { 509 _this._addStyles(); 510 }, 50); 511 } 512 }); 513 }; 514 FixedColumns.version = '4.3.0'; 515 FixedColumns.classes = { 516 fixedLeft: 'dtfc-fixed-left', 517 fixedRight: 'dtfc-fixed-right', 518 leftBottomBlocker: 'dtfc-left-bottom-blocker', 519 leftTopBlocker: 'dtfc-left-top-blocker', 520 rightBottomBlocker: 'dtfc-right-bottom-blocker', 521 rightTopBlocker: 'dtfc-right-top-blocker', 522 tableFixedLeft: 'dtfc-has-left', 523 tableFixedRight: 'dtfc-has-right' 524 }; 525 FixedColumns.defaults = { 526 i18n: { 527 button: 'FixedColumns' 528 }, 529 left: 1, 530 right: 0 531 }; 532 return FixedColumns; 533 }()); 534 535 /*! FixedColumns 4.3.0 536 * © SpryMedia Ltd - datatables.net/license 537 */ 538 setJQuery($); 539 $.fn.dataTable.FixedColumns = FixedColumns; 540 $.fn.DataTable.FixedColumns = FixedColumns; 541 var apiRegister = DataTable.Api.register; 542 apiRegister('fixedColumns()', function () { 543 return this; 544 }); 545 apiRegister('fixedColumns().left()', function (newVal) { 546 var ctx = this.context[0]; 547 if (newVal !== undefined) { 548 ctx._fixedColumns.left(newVal); 549 return this; 550 } 551 else { 552 return ctx._fixedColumns.left(); 553 } 554 }); 555 apiRegister('fixedColumns().right()', function (newVal) { 556 var ctx = this.context[0]; 557 if (newVal !== undefined) { 558 ctx._fixedColumns.right(newVal); 559 return this; 560 } 561 else { 562 return ctx._fixedColumns.right(); 563 } 564 }); 565 DataTable.ext.buttons.fixedColumns = { 566 action: function (e, dt, node, config) { 567 if ($(node).attr('active')) { 568 $(node).removeAttr('active').removeClass('active'); 569 dt.fixedColumns().left(0); 570 dt.fixedColumns().right(0); 571 } 572 else { 573 $(node).attr('active', 'true').addClass('active'); 574 dt.fixedColumns().left(config.config.left); 575 dt.fixedColumns().right(config.config.right); 576 } 577 }, 578 config: { 579 left: 1, 580 right: 0 581 }, 582 init: function (dt, node, config) { 583 if (dt.settings()[0]._fixedColumns === undefined) { 584 _init(dt.settings(), config); 585 } 586 $(node).attr('active', 'true').addClass('active'); 587 dt.button(node).text(config.text || dt.i18n('buttons.fixedColumns', dt.settings()[0]._fixedColumns.c.i18n.button)); 588 }, 589 text: null 590 }; 591 function _init(settings, options) { 592 if (options === void 0) { options = null; } 593 var api = new DataTable.Api(settings); 594 var opts = options 595 ? options 596 : api.init().fixedColumns || DataTable.defaults.fixedColumns; 597 var fixedColumns = new FixedColumns(api, opts); 598 return fixedColumns; 599 } 600 // Attach a listener to the document which listens for DataTables initialisation 601 // events so we can automatically initialise 602 $(document).on('plugin-init.dt', function (e, settings) { 603 if (e.namespace !== 'dt') { 604 return; 605 } 606 if (settings.oInit.fixedColumns || 607 DataTable.defaults.fixedColumns) { 608 if (!settings._fixedColumns) { 609 _init(settings, null); 610 } 611 } 612 }); 613 614})(); 615 616 617return DataTable; 618})); 619