25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dataTables.fixedColumns.js 24KB

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