dataTables.fixedColumns.js 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423
  1. /*! FixedColumns 3.0.4
  2. * ©2010-2014 SpryMedia Ltd - datatables.net/license
  3. */
  4. /**
  5. * @summary FixedColumns
  6. * @description Freeze columns in place on a scrolling DataTable
  7. * @version 3.0.4
  8. * @file dataTables.fixedColumns.js
  9. * @author SpryMedia Ltd (www.sprymedia.co.uk)
  10. * @contact www.sprymedia.co.uk/contact
  11. * @copyright Copyright 2010-2014 SpryMedia Ltd.
  12. *
  13. * This source file is free software, available under the following license:
  14. * MIT license - http://datatables.net/license/mit
  15. *
  16. * This source file is distributed in the hope that it will be useful, but
  17. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18. * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
  19. *
  20. * For details please refer to: http://www.datatables.net
  21. */
  22. (function(window, document, undefined) {
  23. var factory = function( $, DataTable ) {
  24. "use strict";
  25. /**
  26. * When making use of DataTables' x-axis scrolling feature, you may wish to
  27. * fix the left most column in place. This plug-in for DataTables provides
  28. * exactly this option (note for non-scrolling tables, please use the
  29. * FixedHeader plug-in, which can fix headers, footers and columns). Key
  30. * features include:
  31. *
  32. * * Freezes the left or right most columns to the side of the table
  33. * * Option to freeze two or more columns
  34. * * Full integration with DataTables' scrolling options
  35. * * Speed - FixedColumns is fast in its operation
  36. *
  37. * @class
  38. * @constructor
  39. * @global
  40. * @param {object} dt DataTables instance. With DataTables 1.10 this can also
  41. * be a jQuery collection, a jQuery selector, DataTables API instance or
  42. * settings object.
  43. * @param {object} [init={}] Configuration object for FixedColumns. Options are
  44. * defined by {@link FixedColumns.defaults}
  45. *
  46. * @requires jQuery 1.7+
  47. * @requires DataTables 1.8.0+
  48. *
  49. * @example
  50. * var table = $('#example').dataTable( {
  51. * "scrollX": "100%"
  52. * } );
  53. * new $.fn.dataTable.fixedColumns( table );
  54. */
  55. var FixedColumns = function ( dt, init ) {
  56. var that = this;
  57. /* Sanity check - you just know it will happen */
  58. if ( ! ( this instanceof FixedColumns ) )
  59. {
  60. alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." );
  61. return;
  62. }
  63. if ( typeof init == 'undefined' )
  64. {
  65. init = {};
  66. }
  67. // Use the DataTables Hungarian notation mapping method, if it exists to
  68. // provide forwards compatibility for camel case variables
  69. var camelToHungarian = $.fn.dataTable.camelToHungarian;
  70. if ( camelToHungarian ) {
  71. camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );
  72. camelToHungarian( FixedColumns.defaults, init );
  73. }
  74. // v1.10 allows the settings object to be got form a number of sources
  75. var dtSettings = $.fn.dataTable.Api ?
  76. new $.fn.dataTable.Api( dt ).settings()[0] :
  77. dt.fnSettings();
  78. /**
  79. * Settings object which contains customisable information for FixedColumns instance
  80. * @namespace
  81. * @extends FixedColumns.defaults
  82. * @private
  83. */
  84. this.s = {
  85. /**
  86. * DataTables settings objects
  87. * @type object
  88. * @default Obtained from DataTables instance
  89. */
  90. "dt": dtSettings,
  91. /**
  92. * Number of columns in the DataTable - stored for quick access
  93. * @type int
  94. * @default Obtained from DataTables instance
  95. */
  96. "iTableColumns": dtSettings.aoColumns.length,
  97. /**
  98. * Original outer widths of the columns as rendered by DataTables - used to calculate
  99. * the FixedColumns grid bounding box
  100. * @type array.<int>
  101. * @default []
  102. */
  103. "aiOuterWidths": [],
  104. /**
  105. * Original inner widths of the columns as rendered by DataTables - used to apply widths
  106. * to the columns
  107. * @type array.<int>
  108. * @default []
  109. */
  110. "aiInnerWidths": []
  111. };
  112. /**
  113. * DOM elements used by the class instance
  114. * @namespace
  115. * @private
  116. *
  117. */
  118. this.dom = {
  119. /**
  120. * DataTables scrolling element
  121. * @type node
  122. * @default null
  123. */
  124. "scroller": null,
  125. /**
  126. * DataTables header table
  127. * @type node
  128. * @default null
  129. */
  130. "header": null,
  131. /**
  132. * DataTables body table
  133. * @type node
  134. * @default null
  135. */
  136. "body": null,
  137. /**
  138. * DataTables footer table
  139. * @type node
  140. * @default null
  141. */
  142. "footer": null,
  143. /**
  144. * Display grid elements
  145. * @namespace
  146. */
  147. "grid": {
  148. /**
  149. * Grid wrapper. This is the container element for the 3x3 grid
  150. * @type node
  151. * @default null
  152. */
  153. "wrapper": null,
  154. /**
  155. * DataTables scrolling element. This element is the DataTables
  156. * component in the display grid (making up the main table - i.e.
  157. * not the fixed columns).
  158. * @type node
  159. * @default null
  160. */
  161. "dt": null,
  162. /**
  163. * Left fixed column grid components
  164. * @namespace
  165. */
  166. "left": {
  167. "wrapper": null,
  168. "head": null,
  169. "body": null,
  170. "foot": null
  171. },
  172. /**
  173. * Right fixed column grid components
  174. * @namespace
  175. */
  176. "right": {
  177. "wrapper": null,
  178. "head": null,
  179. "body": null,
  180. "foot": null
  181. }
  182. },
  183. /**
  184. * Cloned table nodes
  185. * @namespace
  186. */
  187. "clone": {
  188. /**
  189. * Left column cloned table nodes
  190. * @namespace
  191. */
  192. "left": {
  193. /**
  194. * Cloned header table
  195. * @type node
  196. * @default null
  197. */
  198. "header": null,
  199. /**
  200. * Cloned body table
  201. * @type node
  202. * @default null
  203. */
  204. "body": null,
  205. /**
  206. * Cloned footer table
  207. * @type node
  208. * @default null
  209. */
  210. "footer": null
  211. },
  212. /**
  213. * Right column cloned table nodes
  214. * @namespace
  215. */
  216. "right": {
  217. /**
  218. * Cloned header table
  219. * @type node
  220. * @default null
  221. */
  222. "header": null,
  223. /**
  224. * Cloned body table
  225. * @type node
  226. * @default null
  227. */
  228. "body": null,
  229. /**
  230. * Cloned footer table
  231. * @type node
  232. * @default null
  233. */
  234. "footer": null
  235. }
  236. }
  237. };
  238. /* Attach the instance to the DataTables instance so it can be accessed easily */
  239. dtSettings._oFixedColumns = this;
  240. /* Let's do it */
  241. if ( ! dtSettings._bInitComplete )
  242. {
  243. dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {
  244. that._fnConstruct( init );
  245. }, 'FixedColumns' );
  246. }
  247. else
  248. {
  249. this._fnConstruct( init );
  250. }
  251. };
  252. FixedColumns.prototype = /** @lends FixedColumns.prototype */{
  253. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  254. * Public methods
  255. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  256. /**
  257. * Update the fixed columns - including headers and footers. Note that FixedColumns will
  258. * automatically update the display whenever the host DataTable redraws.
  259. * @returns {void}
  260. * @example
  261. * var table = $('#example').dataTable( {
  262. * "scrollX": "100%"
  263. * } );
  264. * var fc = new $.fn.dataTable.fixedColumns( table );
  265. *
  266. * // at some later point when the table has been manipulated....
  267. * fc.fnUpdate();
  268. */
  269. "fnUpdate": function ()
  270. {
  271. this._fnDraw( true );
  272. },
  273. /**
  274. * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.
  275. * This is useful if you update the width of the table container. Note that FixedColumns will
  276. * perform this function automatically when the window.resize event is fired.
  277. * @returns {void}
  278. * @example
  279. * var table = $('#example').dataTable( {
  280. * "scrollX": "100%"
  281. * } );
  282. * var fc = new $.fn.dataTable.fixedColumns( table );
  283. *
  284. * // Resize the table container and then have FixedColumns adjust its layout....
  285. * $('#content').width( 1200 );
  286. * fc.fnRedrawLayout();
  287. */
  288. "fnRedrawLayout": function ()
  289. {
  290. this._fnColCalc();
  291. this._fnGridLayout();
  292. this.fnUpdate();
  293. },
  294. /**
  295. * Mark a row such that it's height should be recalculated when using 'semiauto' row
  296. * height matching. This function will have no effect when 'none' or 'auto' row height
  297. * matching is used.
  298. * @param {Node} nTr TR element that should have it's height recalculated
  299. * @returns {void}
  300. * @example
  301. * var table = $('#example').dataTable( {
  302. * "scrollX": "100%"
  303. * } );
  304. * var fc = new $.fn.dataTable.fixedColumns( table );
  305. *
  306. * // manipulate the table - mark the row as needing an update then update the table
  307. * // this allows the redraw performed by DataTables fnUpdate to recalculate the row
  308. * // height
  309. * fc.fnRecalculateHeight();
  310. * table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
  311. */
  312. "fnRecalculateHeight": function ( nTr )
  313. {
  314. delete nTr._DTTC_iHeight;
  315. nTr.style.height = 'auto';
  316. },
  317. /**
  318. * Set the height of a given row - provides cross browser compatibility
  319. * @param {Node} nTarget TR element that should have it's height recalculated
  320. * @param {int} iHeight Height in pixels to set
  321. * @returns {void}
  322. * @example
  323. * var table = $('#example').dataTable( {
  324. * "scrollX": "100%"
  325. * } );
  326. * var fc = new $.fn.dataTable.fixedColumns( table );
  327. *
  328. * // You may want to do this after manipulating a row in the fixed column
  329. * fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
  330. */
  331. "fnSetRowHeight": function ( nTarget, iHeight )
  332. {
  333. nTarget.style.height = iHeight+"px";
  334. },
  335. /**
  336. * Get data index information about a row or cell in the table body.
  337. * This function is functionally identical to fnGetPosition in DataTables,
  338. * taking the same parameter (TH, TD or TR node) and returning exactly the
  339. * the same information (data index information). THe difference between
  340. * the two is that this method takes into account the fixed columns in the
  341. * table, so you can pass in nodes from the master table, or the cloned
  342. * tables and get the index position for the data in the main table.
  343. * @param {node} node TR, TH or TD element to get the information about
  344. * @returns {int} If nNode is given as a TR, then a single index is
  345. * returned, or if given as a cell, an array of [row index, column index
  346. * (visible), column index (all)] is given.
  347. */
  348. "fnGetPosition": function ( node )
  349. {
  350. var idx;
  351. var inst = this.s.dt.oInstance;
  352. if ( ! $(node).parents('.DTFC_Cloned').length )
  353. {
  354. // Not in a cloned table
  355. return inst.fnGetPosition( node );
  356. }
  357. else
  358. {
  359. // Its in the cloned table, so need to look up position
  360. if ( node.nodeName.toLowerCase() === 'tr' ) {
  361. idx = $(node).index();
  362. return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
  363. }
  364. else
  365. {
  366. var colIdx = $(node).index();
  367. idx = $(node.parentNode).index();
  368. var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
  369. return [
  370. row,
  371. colIdx,
  372. inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )
  373. ];
  374. }
  375. }
  376. },
  377. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  378. * Private methods (they are of course public in JS, but recommended as private)
  379. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  380. /**
  381. * Initialisation for FixedColumns
  382. * @param {Object} oInit User settings for initialisation
  383. * @returns {void}
  384. * @private
  385. */
  386. "_fnConstruct": function ( oInit )
  387. {
  388. var i, iLen, iWidth,
  389. that = this;
  390. /* Sanity checking */
  391. if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||
  392. this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )
  393. {
  394. alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+
  395. "Please upgrade your DataTables installation" );
  396. return;
  397. }
  398. if ( this.s.dt.oScroll.sX === "" )
  399. {
  400. this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+
  401. "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+
  402. "column fixing when scrolling is not enabled" );
  403. return;
  404. }
  405. /* Apply the settings from the user / defaults */
  406. this.s = $.extend( true, this.s, FixedColumns.defaults, oInit );
  407. /* Set up the DOM as we need it and cache nodes */
  408. var classes = this.s.dt.oClasses;
  409. this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];
  410. this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];
  411. /* Set up the DOM that we want for the fixed column layout grid */
  412. this._fnColCalc();
  413. this._fnGridSetup();
  414. /* Event handlers */
  415. var mouseController;
  416. // When the body is scrolled - scroll the left and right columns
  417. $(this.dom.scroller)
  418. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  419. mouseController = 'main';
  420. } )
  421. .on( 'scroll.DTFC', function () {
  422. if ( mouseController === 'main' ) {
  423. if ( that.s.iLeftColumns > 0 ) {
  424. that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;
  425. }
  426. if ( that.s.iRightColumns > 0 ) {
  427. that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;
  428. }
  429. }
  430. } );
  431. var wheelType = 'onwheel' in document.createElement('div') ?
  432. 'wheel.DTFC' :
  433. 'mousewheel.DTFC';
  434. if ( that.s.iLeftColumns > 0 ) {
  435. // When scrolling the left column, scroll the body and right column
  436. $(that.dom.grid.left.liner)
  437. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  438. mouseController = 'left';
  439. } )
  440. .on( 'scroll.DTFC', function () {
  441. if ( mouseController === 'left' ) {
  442. that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;
  443. if ( that.s.iRightColumns > 0 ) {
  444. that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;
  445. }
  446. }
  447. } )
  448. .on( wheelType, function(e) { // xxx update the destroy as well
  449. // Pass horizontal scrolling through
  450. var xDelta = e.type === 'wheel' ?
  451. -e.originalEvent.deltaX :
  452. e.originalEvent.wheelDeltaX;
  453. that.dom.scroller.scrollLeft -= xDelta;
  454. } );
  455. }
  456. if ( that.s.iRightColumns > 0 ) {
  457. // When scrolling the right column, scroll the body and the left column
  458. $(that.dom.grid.right.liner)
  459. .on( 'mouseover.DTFC touchstart.DTFC', function () {
  460. mouseController = 'right';
  461. } )
  462. .on( 'scroll.DTFC', function () {
  463. if ( mouseController === 'right' ) {
  464. that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;
  465. if ( that.s.iLeftColumns > 0 ) {
  466. that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;
  467. }
  468. }
  469. } )
  470. .on( wheelType, function(e) {
  471. // Pass horizontal scrolling through
  472. var xDelta = e.type === 'wheel' ?
  473. -e.originalEvent.deltaX :
  474. e.originalEvent.wheelDeltaX;
  475. that.dom.scroller.scrollLeft -= xDelta;
  476. } );
  477. }
  478. $(window).on( 'resize.DTFC', function () {
  479. that._fnGridLayout.call( that );
  480. } );
  481. var bFirstDraw = true;
  482. var jqTable = $(this.s.dt.nTable);
  483. jqTable
  484. .on( 'draw.dt.DTFC', function () {
  485. that._fnDraw.call( that, bFirstDraw );
  486. bFirstDraw = false;
  487. } )
  488. .on( 'column-sizing.dt.DTFC', function () {
  489. that._fnColCalc();
  490. that._fnGridLayout( that );
  491. } )
  492. .on( 'column-visibility.dt.DTFC', function () {
  493. that._fnColCalc();
  494. that._fnGridLayout( that );
  495. that._fnDraw( true );
  496. } )
  497. .on( 'destroy.dt.DTFC', function () {
  498. jqTable.off( 'column-sizing.dt.DTFC destroy.dt.DTFC draw.dt.DTFC' );
  499. $(that.dom.scroller).off( 'scroll.DTFC mouseover.DTFC' );
  500. $(window).off( 'resize.DTFC' );
  501. $(that.dom.grid.left.liner).off( 'scroll.DTFC mouseover.DTFC '+wheelType );
  502. $(that.dom.grid.left.wrapper).remove();
  503. $(that.dom.grid.right.liner).off( 'scroll.DTFC mouseover.DTFC '+wheelType );
  504. $(that.dom.grid.right.wrapper).remove();
  505. } );
  506. /* Get things right to start with - note that due to adjusting the columns, there must be
  507. * another redraw of the main table. It doesn't need to be a full redraw however.
  508. */
  509. this._fnGridLayout();
  510. this.s.dt.oInstance.fnDraw(false);
  511. },
  512. /**
  513. * Calculate the column widths for the grid layout
  514. * @returns {void}
  515. * @private
  516. */
  517. "_fnColCalc": function ()
  518. {
  519. var that = this;
  520. var iLeftWidth = 0;
  521. var iRightWidth = 0;
  522. this.s.aiInnerWidths = [];
  523. this.s.aiOuterWidths = [];
  524. $.each( this.s.dt.aoColumns, function (i, col) {
  525. var th = $(col.nTh);
  526. var border;
  527. if ( ! th.filter(':visible').length ) {
  528. that.s.aiInnerWidths.push( 0 );
  529. that.s.aiOuterWidths.push( 0 );
  530. }
  531. else
  532. {
  533. // Inner width is used to assign widths to cells
  534. // Outer width is used to calculate the container
  535. var iWidth = th.outerWidth();
  536. // When working with the left most-cell, need to add on the
  537. // table's border to the outerWidth, since we need to take
  538. // account of it, but it isn't in any cell
  539. if ( that.s.aiOuterWidths.length === 0 ) {
  540. border = $(that.s.dt.nTable).css('border-left-width');
  541. iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 );
  542. }
  543. // Likewise with the final column on the right
  544. if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {
  545. border = $(that.s.dt.nTable).css('border-right-width');
  546. iWidth += typeof border === 'string' ? 1 : parseInt( border, 10 );
  547. }
  548. that.s.aiOuterWidths.push( iWidth );
  549. that.s.aiInnerWidths.push( th.width() );
  550. if ( i < that.s.iLeftColumns )
  551. {
  552. iLeftWidth += iWidth;
  553. }
  554. if ( that.s.iTableColumns-that.s.iRightColumns <= i )
  555. {
  556. iRightWidth += iWidth;
  557. }
  558. }
  559. } );
  560. this.s.iLeftWidth = iLeftWidth;
  561. this.s.iRightWidth = iRightWidth;
  562. },
  563. /**
  564. * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid
  565. * for the left column, the DataTable (for which we just reuse the scrolling element DataTable
  566. * puts into the DOM) and the right column. In each of he two fixed column elements there is a
  567. * grouping wrapper element and then a head, body and footer wrapper. In each of these we then
  568. * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.
  569. * @returns {void}
  570. * @private
  571. */
  572. "_fnGridSetup": function ()
  573. {
  574. var that = this;
  575. var oOverflow = this._fnDTOverflow();
  576. var block;
  577. this.dom.body = this.s.dt.nTable;
  578. this.dom.header = this.s.dt.nTHead.parentNode;
  579. this.dom.header.parentNode.parentNode.style.position = "relative";
  580. var nSWrapper =
  581. $('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;">'+
  582. '<div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;">'+
  583. '<div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
  584. '<div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
  585. '<div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
  586. '</div>'+
  587. '<div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
  588. '</div>'+
  589. '<div class="DTFC_RightWrapper" style="position:absolute; top:0; left:0;">'+
  590. '<div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;">'+
  591. '<div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
  592. '</div>'+
  593. '<div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; overflow:hidden;">'+
  594. '<div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
  595. '</div>'+
  596. '<div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;">'+
  597. '<div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
  598. '</div>'+
  599. '</div>'+
  600. '</div>')[0];
  601. var nLeft = nSWrapper.childNodes[0];
  602. var nRight = nSWrapper.childNodes[1];
  603. this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );
  604. nSWrapper.appendChild( this.dom.grid.dt );
  605. this.dom.grid.wrapper = nSWrapper;
  606. if ( this.s.iLeftColumns > 0 )
  607. {
  608. this.dom.grid.left.wrapper = nLeft;
  609. this.dom.grid.left.head = nLeft.childNodes[0];
  610. this.dom.grid.left.body = nLeft.childNodes[1];
  611. this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];
  612. nSWrapper.appendChild( nLeft );
  613. }
  614. if ( this.s.iRightColumns > 0 )
  615. {
  616. this.dom.grid.right.wrapper = nRight;
  617. this.dom.grid.right.head = nRight.childNodes[0];
  618. this.dom.grid.right.body = nRight.childNodes[1];
  619. this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];
  620. block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];
  621. block.style.width = oOverflow.bar+"px";
  622. block.style.right = -oOverflow.bar+"px";
  623. this.dom.grid.right.headBlock = block;
  624. block = $('div.DTFC_RightFootBlocker', nSWrapper)[0];
  625. block.style.width = oOverflow.bar+"px";
  626. block.style.right = -oOverflow.bar+"px";
  627. this.dom.grid.right.footBlock = block;
  628. nSWrapper.appendChild( nRight );
  629. }
  630. if ( this.s.dt.nTFoot )
  631. {
  632. this.dom.footer = this.s.dt.nTFoot.parentNode;
  633. if ( this.s.iLeftColumns > 0 )
  634. {
  635. this.dom.grid.left.foot = nLeft.childNodes[2];
  636. }
  637. if ( this.s.iRightColumns > 0 )
  638. {
  639. this.dom.grid.right.foot = nRight.childNodes[2];
  640. }
  641. }
  642. },
  643. /**
  644. * Style and position the grid used for the FixedColumns layout
  645. * @returns {void}
  646. * @private
  647. */
  648. "_fnGridLayout": function ()
  649. {
  650. var oGrid = this.dom.grid;
  651. var iWidth = $(oGrid.wrapper).width();
  652. var iBodyHeight = $(this.s.dt.nTable.parentNode).outerHeight();
  653. var iFullHeight = $(this.s.dt.nTable.parentNode.parentNode).outerHeight();
  654. var oOverflow = this._fnDTOverflow();
  655. var
  656. iLeftWidth = this.s.iLeftWidth,
  657. iRightWidth = this.s.iRightWidth,
  658. iRight;
  659. var scrollbarAdjust = function ( node, width ) {
  660. if ( ! oOverflow.bar ) {
  661. // If there is no scrollbar (Macs) we need to hide the auto scrollbar
  662. node.style.width = (width+20)+"px";
  663. node.style.paddingRight = "20px";
  664. node.style.boxSizing = "border-box";
  665. }
  666. else {
  667. // Otherwise just overflow by the scrollbar
  668. node.style.width = (width+oOverflow.bar)+"px";
  669. }
  670. };
  671. // When x scrolling - don't paint the fixed columns over the x scrollbar
  672. if ( oOverflow.x )
  673. {
  674. iBodyHeight -= oOverflow.bar;
  675. }
  676. oGrid.wrapper.style.height = iFullHeight+"px";
  677. if ( this.s.iLeftColumns > 0 )
  678. {
  679. oGrid.left.wrapper.style.width = iLeftWidth+"px";
  680. oGrid.left.wrapper.style.height = "1px";
  681. oGrid.left.body.style.height = iBodyHeight+"px";
  682. if ( oGrid.left.foot ) {
  683. oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar
  684. }
  685. scrollbarAdjust( oGrid.left.liner, iLeftWidth );
  686. oGrid.left.liner.style.height = iBodyHeight+"px";
  687. }
  688. if ( this.s.iRightColumns > 0 )
  689. {
  690. iRight = iWidth - iRightWidth;
  691. if ( oOverflow.y )
  692. {
  693. iRight -= oOverflow.bar;
  694. }
  695. oGrid.right.wrapper.style.width = iRightWidth+"px";
  696. oGrid.right.wrapper.style.left = iRight+"px";
  697. oGrid.right.wrapper.style.height = "1px";
  698. oGrid.right.body.style.height = iBodyHeight+"px";
  699. if ( oGrid.right.foot ) {
  700. oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px";
  701. }
  702. scrollbarAdjust( oGrid.right.liner, iRightWidth );
  703. oGrid.right.liner.style.height = iBodyHeight+"px";
  704. oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';
  705. oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';
  706. }
  707. },
  708. /**
  709. * Get information about the DataTable's scrolling state - specifically if the table is scrolling
  710. * on either the x or y axis, and also the scrollbar width.
  711. * @returns {object} Information about the DataTables scrolling state with the properties:
  712. * 'x', 'y' and 'bar'
  713. * @private
  714. */
  715. "_fnDTOverflow": function ()
  716. {
  717. var nTable = this.s.dt.nTable;
  718. var nTableScrollBody = nTable.parentNode;
  719. var out = {
  720. "x": false,
  721. "y": false,
  722. "bar": this.s.dt.oScroll.iBarWidth
  723. };
  724. if ( nTable.offsetWidth > nTableScrollBody.clientWidth )
  725. {
  726. out.x = true;
  727. }
  728. if ( nTable.offsetHeight > nTableScrollBody.clientHeight )
  729. {
  730. out.y = true;
  731. }
  732. return out;
  733. },
  734. /**
  735. * Clone and position the fixed columns
  736. * @returns {void}
  737. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  738. * @private
  739. */
  740. "_fnDraw": function ( bAll )
  741. {
  742. this._fnGridLayout();
  743. this._fnCloneLeft( bAll );
  744. this._fnCloneRight( bAll );
  745. /* Draw callback function */
  746. if ( this.s.fnDrawCallback !== null )
  747. {
  748. this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );
  749. }
  750. /* Event triggering */
  751. $(this).trigger( 'draw.dtfc', {
  752. "leftClone": this.dom.clone.left,
  753. "rightClone": this.dom.clone.right
  754. } );
  755. },
  756. /**
  757. * Clone the right columns
  758. * @returns {void}
  759. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  760. * @private
  761. */
  762. "_fnCloneRight": function ( bAll )
  763. {
  764. if ( this.s.iRightColumns <= 0 ) {
  765. return;
  766. }
  767. var that = this,
  768. i, jq,
  769. aiColumns = [];
  770. for ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {
  771. if ( this.s.dt.aoColumns[i].bVisible ) {
  772. aiColumns.push( i );
  773. }
  774. }
  775. this._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );
  776. },
  777. /**
  778. * Clone the left columns
  779. * @returns {void}
  780. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  781. * @private
  782. */
  783. "_fnCloneLeft": function ( bAll )
  784. {
  785. if ( this.s.iLeftColumns <= 0 ) {
  786. return;
  787. }
  788. var that = this,
  789. i, jq,
  790. aiColumns = [];
  791. for ( i=0 ; i<this.s.iLeftColumns ; i++ ) {
  792. if ( this.s.dt.aoColumns[i].bVisible ) {
  793. aiColumns.push( i );
  794. }
  795. }
  796. this._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );
  797. },
  798. /**
  799. * Make a copy of the layout object for a header or footer element from DataTables. Note that
  800. * this method will clone the nodes in the layout object.
  801. * @returns {Array} Copy of the layout array
  802. * @param {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)
  803. * @param {Object} aiColumns Columns to copy
  804. * @private
  805. */
  806. "_fnCopyLayout": function ( aoOriginal, aiColumns )
  807. {
  808. var aReturn = [];
  809. var aClones = [];
  810. var aCloned = [];
  811. for ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )
  812. {
  813. var aRow = [];
  814. aRow.nTr = $(aoOriginal[i].nTr).clone(true, true)[0];
  815. for ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )
  816. {
  817. if ( $.inArray( j, aiColumns ) === -1 )
  818. {
  819. continue;
  820. }
  821. var iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );
  822. if ( iCloned === -1 )
  823. {
  824. var nClone = $(aoOriginal[i][j].cell).clone(true, true)[0];
  825. aClones.push( nClone );
  826. aCloned.push( aoOriginal[i][j].cell );
  827. aRow.push( {
  828. "cell": nClone,
  829. "unique": aoOriginal[i][j].unique
  830. } );
  831. }
  832. else
  833. {
  834. aRow.push( {
  835. "cell": aClones[ iCloned ],
  836. "unique": aoOriginal[i][j].unique
  837. } );
  838. }
  839. }
  840. aReturn.push( aRow );
  841. }
  842. return aReturn;
  843. },
  844. /**
  845. * Clone the DataTable nodes and place them in the DOM (sized correctly)
  846. * @returns {void}
  847. * @param {Object} oClone Object containing the header, footer and body cloned DOM elements
  848. * @param {Object} oGrid Grid object containing the display grid elements for the cloned
  849. * column (left or right)
  850. * @param {Array} aiColumns Column indexes which should be operated on from the DataTable
  851. * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
  852. * @private
  853. */
  854. "_fnClone": function ( oClone, oGrid, aiColumns, bAll )
  855. {
  856. var that = this,
  857. i, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,
  858. jqCloneThead, aoFixedHeader,
  859. dt = this.s.dt;
  860. /*
  861. * Header
  862. */
  863. if ( bAll )
  864. {
  865. if ( oClone.header !== null )
  866. {
  867. oClone.header.parentNode.removeChild( oClone.header );
  868. }
  869. oClone.header = $(this.dom.header).clone(true, true)[0];
  870. oClone.header.className += " DTFC_Cloned";
  871. oClone.header.style.width = "100%";
  872. oGrid.head.appendChild( oClone.header );
  873. /* Copy the DataTables layout cache for the header for our floating column */
  874. aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns );
  875. jqCloneThead = $('>thead', oClone.header);
  876. jqCloneThead.empty();
  877. /* Add the created cloned TR elements to the table */
  878. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  879. {
  880. jqCloneThead[0].appendChild( aoCloneLayout[i].nTr );
  881. }
  882. /* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan
  883. * calculations for us
  884. */
  885. dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
  886. }
  887. else
  888. {
  889. /* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows
  890. * etc, we make a copy of the header from the DataTable again, but don't insert the
  891. * cloned cells, just copy the classes across. To get the matching layout for the
  892. * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping
  893. */
  894. aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns );
  895. aoFixedHeader=[];
  896. dt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );
  897. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  898. {
  899. for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
  900. {
  901. aoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;
  902. // If jQuery UI theming is used we need to copy those elements as well
  903. $('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {
  904. this.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;
  905. } );
  906. }
  907. }
  908. }
  909. this._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );
  910. /*
  911. * Body
  912. */
  913. if ( this.s.sHeightMatch == 'auto' )
  914. {
  915. /* Remove any heights which have been applied already and let the browser figure it out */
  916. $('>tbody>tr', that.dom.body).css('height', 'auto');
  917. }
  918. if ( oClone.body !== null )
  919. {
  920. oClone.body.parentNode.removeChild( oClone.body );
  921. oClone.body = null;
  922. }
  923. oClone.body = $(this.dom.body).clone(true)[0];
  924. oClone.body.className += " DTFC_Cloned";
  925. oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px";
  926. oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */
  927. if ( oClone.body.getAttribute('id') !== null )
  928. {
  929. oClone.body.removeAttribute('id');
  930. }
  931. $('>thead>tr', oClone.body).empty();
  932. $('>tfoot', oClone.body).remove();
  933. var nBody = $('tbody', oClone.body)[0];
  934. $(nBody).empty();
  935. if ( dt.aiDisplay.length > 0 )
  936. {
  937. /* Copy the DataTables' header elements to force the column width in exactly the
  938. * same way that DataTables does it - have the header element, apply the width and
  939. * colapse it down
  940. */
  941. var nInnerThead = $('>thead>tr', oClone.body)[0];
  942. for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
  943. {
  944. iColumn = aiColumns[iIndex];
  945. nClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];
  946. nClone.innerHTML = "";
  947. var oStyle = nClone.style;
  948. oStyle.paddingTop = "0";
  949. oStyle.paddingBottom = "0";
  950. oStyle.borderTopWidth = "0";
  951. oStyle.borderBottomWidth = "0";
  952. oStyle.height = 0;
  953. oStyle.width = that.s.aiInnerWidths[iColumn]+"px";
  954. nInnerThead.appendChild( nClone );
  955. }
  956. /* Add in the tbody elements, cloning form the master table */
  957. $('>tbody>tr', that.dom.body).each( function (z) {
  958. var n = this.cloneNode(false);
  959. n.removeAttribute('id');
  960. var i = that.s.dt.oFeatures.bServerSide===false ?
  961. that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;
  962. var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');
  963. for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
  964. {
  965. iColumn = aiColumns[iIndex];
  966. if ( aTds.length > 0 )
  967. {
  968. nClone = $( aTds[iColumn] ).clone(true, true)[0];
  969. n.appendChild( nClone );
  970. }
  971. }
  972. nBody.appendChild( n );
  973. } );
  974. }
  975. else
  976. {
  977. $('>tbody>tr', that.dom.body).each( function (z) {
  978. nClone = this.cloneNode(true);
  979. nClone.className += ' DTFC_NoData';
  980. $('td', nClone).html('');
  981. nBody.appendChild( nClone );
  982. } );
  983. }
  984. oClone.body.style.width = "100%";
  985. oClone.body.style.margin = "0";
  986. oClone.body.style.padding = "0";
  987. // Interop with Scroller - need to use a height forcing element in the
  988. // scrolling area in the same way that Scroller does in the body scroll.
  989. if ( dt.oScroller !== undefined )
  990. {
  991. var scrollerForcer = dt.oScroller.dom.force;
  992. if ( ! oGrid.forcer ) {
  993. oGrid.forcer = scrollerForcer.cloneNode( true );
  994. oGrid.liner.appendChild( oGrid.forcer );
  995. }
  996. else {
  997. oGrid.forcer.style.height = scrollerForcer.style.height;
  998. }
  999. }
  1000. oGrid.liner.appendChild( oClone.body );
  1001. this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );
  1002. /*
  1003. * Footer
  1004. */
  1005. if ( dt.nTFoot !== null )
  1006. {
  1007. if ( bAll )
  1008. {
  1009. if ( oClone.footer !== null )
  1010. {
  1011. oClone.footer.parentNode.removeChild( oClone.footer );
  1012. }
  1013. oClone.footer = $(this.dom.footer).clone(true, true)[0];
  1014. oClone.footer.className += " DTFC_Cloned";
  1015. oClone.footer.style.width = "100%";
  1016. oGrid.foot.appendChild( oClone.footer );
  1017. /* Copy the footer just like we do for the header */
  1018. aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns );
  1019. var jqCloneTfoot = $('>tfoot', oClone.footer);
  1020. jqCloneTfoot.empty();
  1021. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  1022. {
  1023. jqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );
  1024. }
  1025. dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
  1026. }
  1027. else
  1028. {
  1029. aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns );
  1030. var aoCurrFooter=[];
  1031. dt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );
  1032. for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
  1033. {
  1034. for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
  1035. {
  1036. aoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;
  1037. }
  1038. }
  1039. }
  1040. this._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );
  1041. }
  1042. /* Equalise the column widths between the header footer and body - body get's priority */
  1043. var anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );
  1044. $(anUnique).each( function (i) {
  1045. iColumn = aiColumns[i];
  1046. this.style.width = that.s.aiInnerWidths[iColumn]+"px";
  1047. } );
  1048. if ( that.s.dt.nTFoot !== null )
  1049. {
  1050. anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );
  1051. $(anUnique).each( function (i) {
  1052. iColumn = aiColumns[i];
  1053. this.style.width = that.s.aiInnerWidths[iColumn]+"px";
  1054. } );
  1055. }
  1056. },
  1057. /**
  1058. * From a given table node (THEAD etc), get a list of TR direct child elements
  1059. * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)
  1060. * @returns {Array} List of TR elements found
  1061. * @private
  1062. */
  1063. "_fnGetTrNodes": function ( nIn )
  1064. {
  1065. var aOut = [];
  1066. for ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )
  1067. {
  1068. if ( nIn.childNodes[i].nodeName.toUpperCase() == "TR" )
  1069. {
  1070. aOut.push( nIn.childNodes[i] );
  1071. }
  1072. }
  1073. return aOut;
  1074. },
  1075. /**
  1076. * Equalise the heights of the rows in a given table node in a cross browser way
  1077. * @returns {void}
  1078. * @param {String} nodeName Node type - thead, tbody or tfoot
  1079. * @param {Node} original Original node to take the heights from
  1080. * @param {Node} clone Copy the heights to
  1081. * @private
  1082. */
  1083. "_fnEqualiseHeights": function ( nodeName, original, clone )
  1084. {
  1085. if ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )
  1086. {
  1087. return;
  1088. }
  1089. var that = this,
  1090. i, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,
  1091. rootOriginal = original.getElementsByTagName(nodeName)[0],
  1092. rootClone = clone.getElementsByTagName(nodeName)[0],
  1093. jqBoxHack = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),
  1094. iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(),
  1095. anOriginal = this._fnGetTrNodes( rootOriginal ),
  1096. anClone = this._fnGetTrNodes( rootClone ),
  1097. heights = [];
  1098. for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
  1099. {
  1100. iHeightOriginal = anOriginal[i].offsetHeight;
  1101. iHeightClone = anClone[i].offsetHeight;
  1102. iHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;
  1103. if ( this.s.sHeightMatch == 'semiauto' )
  1104. {
  1105. anOriginal[i]._DTTC_iHeight = iHeight;
  1106. }
  1107. heights.push( iHeight );
  1108. }
  1109. for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
  1110. {
  1111. anClone[i].style.height = heights[i]+"px";
  1112. anOriginal[i].style.height = heights[i]+"px";
  1113. }
  1114. }
  1115. };
  1116. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1117. * Statics
  1118. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1119. /**
  1120. * FixedColumns default settings for initialisation
  1121. * @name FixedColumns.defaults
  1122. * @namespace
  1123. * @static
  1124. */
  1125. FixedColumns.defaults = /** @lends FixedColumns.defaults */{
  1126. /**
  1127. * Number of left hand columns to fix in position
  1128. * @type int
  1129. * @default 1
  1130. * @static
  1131. * @example
  1132. * var = $('#example').dataTable( {
  1133. * "scrollX": "100%"
  1134. * } );
  1135. * new $.fn.dataTable.fixedColumns( table, {
  1136. * "leftColumns": 2
  1137. * } );
  1138. */
  1139. "iLeftColumns": 1,
  1140. /**
  1141. * Number of right hand columns to fix in position
  1142. * @type int
  1143. * @default 0
  1144. * @static
  1145. * @example
  1146. * var table = $('#example').dataTable( {
  1147. * "scrollX": "100%"
  1148. * } );
  1149. * new $.fn.dataTable.fixedColumns( table, {
  1150. * "rightColumns": 1
  1151. * } );
  1152. */
  1153. "iRightColumns": 0,
  1154. /**
  1155. * Draw callback function which is called when FixedColumns has redrawn the fixed assets
  1156. * @type function(object, object):void
  1157. * @default null
  1158. * @static
  1159. * @example
  1160. * var table = $('#example').dataTable( {
  1161. * "scrollX": "100%"
  1162. * } );
  1163. * new $.fn.dataTable.fixedColumns( table, {
  1164. * "drawCallback": function () {
  1165. * alert( "FixedColumns redraw" );
  1166. * }
  1167. * } );
  1168. */
  1169. "fnDrawCallback": null,
  1170. /**
  1171. * Height matching algorthim to use. This can be "none" which will result in no height
  1172. * matching being applied by FixedColumns (height matching could be forced by CSS in this
  1173. * case), "semiauto" whereby the height calculation will be performed once, and the result
  1174. * cached to be used again (fnRecalculateHeight can be used to force recalculation), or
  1175. * "auto" when height matching is performed on every draw (slowest but must accurate)
  1176. * @type string
  1177. * @default semiauto
  1178. * @static
  1179. * @example
  1180. * var table = $('#example').dataTable( {
  1181. * "scrollX": "100%"
  1182. * } );
  1183. * new $.fn.dataTable.fixedColumns( table, {
  1184. * "heightMatch": "auto"
  1185. * } );
  1186. */
  1187. "sHeightMatch": "semiauto"
  1188. };
  1189. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1190. * Constants
  1191. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1192. /**
  1193. * FixedColumns version
  1194. * @name FixedColumns.version
  1195. * @type String
  1196. * @default See code
  1197. * @static
  1198. */
  1199. FixedColumns.version = "3.0.4";
  1200. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1201. * Fired events (for documentation)
  1202. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1203. /**
  1204. * Event fired whenever FixedColumns redraws the fixed columns (i.e. clones the table elements from the main DataTable). This will occur whenever the DataTable that the FixedColumns instance is attached does its own draw.
  1205. * @name FixedColumns#draw.dtfc
  1206. * @event
  1207. * @param {event} e jQuery event object
  1208. * @param {object} o Event parameters from FixedColumns
  1209. * @param {object} o.leftClone Instance's object dom.clone.left for easy reference. This object contains references to the left fixed clumn column's nodes
  1210. * @param {object} o.rightClone Instance's object dom.clone.right for easy reference. This object contains references to the right fixed clumn column's nodes
  1211. */
  1212. // Make FixedColumns accessible from the DataTables instance
  1213. $.fn.dataTable.FixedColumns = FixedColumns;
  1214. $.fn.DataTable.FixedColumns = FixedColumns;
  1215. return FixedColumns;
  1216. }; // /factory
  1217. // Define as an AMD module if possible
  1218. if ( typeof define === 'function' && define.amd ) {
  1219. define( ['jquery', 'datatables'], factory );
  1220. }
  1221. else if ( typeof exports === 'object' ) {
  1222. // Node/CommonJS
  1223. factory( require('jquery'), require('datatables') );
  1224. }
  1225. else if ( jQuery && !jQuery.fn.dataTable.FixedColumns ) {
  1226. // Otherwise simply initialise as normal, stopping multiple evaluation
  1227. factory( jQuery, jQuery.fn.dataTable );
  1228. }
  1229. })(window, document);