1 | /*! FixedColumns 3.3.0
|
---|
2 | * ©2010-2018 SpryMedia Ltd - datatables.net/license
|
---|
3 | */
|
---|
4 |
|
---|
5 | /**
|
---|
6 | * @summary FixedColumns
|
---|
7 | * @description Freeze columns in place on a scrolling DataTable
|
---|
8 | * @version 3.3.0
|
---|
9 | * @file dataTables.fixedColumns.js
|
---|
10 | * @author SpryMedia Ltd (www.sprymedia.co.uk)
|
---|
11 | * @contact www.sprymedia.co.uk/contact
|
---|
12 | * @copyright Copyright 2010-2018 SpryMedia Ltd.
|
---|
13 | *
|
---|
14 | * This source file is free software, available under the following license:
|
---|
15 | * MIT license - http://datatables.net/license/mit
|
---|
16 | *
|
---|
17 | * This source file is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
---|
19 | * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
---|
20 | *
|
---|
21 | * For details please refer to: http://www.datatables.net
|
---|
22 | */
|
---|
23 | (function( factory ){
|
---|
24 | if ( typeof define === 'function' && define.amd ) {
|
---|
25 | // AMD
|
---|
26 | define( ['jquery', 'datatables.net'], function ( $ ) {
|
---|
27 | return factory( $, window, document );
|
---|
28 | } );
|
---|
29 | }
|
---|
30 | else if ( typeof exports === 'object' ) {
|
---|
31 | // CommonJS
|
---|
32 | module.exports = function (root, $) {
|
---|
33 | if ( ! root ) {
|
---|
34 | root = window;
|
---|
35 | }
|
---|
36 |
|
---|
37 | if ( ! $ || ! $.fn.dataTable ) {
|
---|
38 | $ = require('datatables.net')(root, $).$;
|
---|
39 | }
|
---|
40 |
|
---|
41 | return factory( $, root, root.document );
|
---|
42 | };
|
---|
43 | }
|
---|
44 | else {
|
---|
45 | // Browser
|
---|
46 | factory( jQuery, window, document );
|
---|
47 | }
|
---|
48 | }(function( $, window, document, undefined ) {
|
---|
49 | 'use strict';
|
---|
50 | var DataTable = $.fn.dataTable;
|
---|
51 | var _firefoxScroll;
|
---|
52 |
|
---|
53 | /**
|
---|
54 | * When making use of DataTables' x-axis scrolling feature, you may wish to
|
---|
55 | * fix the left most column in place. This plug-in for DataTables provides
|
---|
56 | * exactly this option (note for non-scrolling tables, please use the
|
---|
57 | * FixedHeader plug-in, which can fix headers and footers). Key
|
---|
58 | * features include:
|
---|
59 | *
|
---|
60 | * * Freezes the left or right most columns to the side of the table
|
---|
61 | * * Option to freeze two or more columns
|
---|
62 | * * Full integration with DataTables' scrolling options
|
---|
63 | * * Speed - FixedColumns is fast in its operation
|
---|
64 | *
|
---|
65 | * @class
|
---|
66 | * @constructor
|
---|
67 | * @global
|
---|
68 | * @param {object} dt DataTables instance. With DataTables 1.10 this can also
|
---|
69 | * be a jQuery collection, a jQuery selector, DataTables API instance or
|
---|
70 | * settings object.
|
---|
71 | * @param {object} [init={}] Configuration object for FixedColumns. Options are
|
---|
72 | * defined by {@link FixedColumns.defaults}
|
---|
73 | *
|
---|
74 | * @requires jQuery 1.7+
|
---|
75 | * @requires DataTables 1.8.0+
|
---|
76 | *
|
---|
77 | * @example
|
---|
78 | * var table = $('#example').dataTable( {
|
---|
79 | * "scrollX": "100%"
|
---|
80 | * } );
|
---|
81 | * new $.fn.dataTable.fixedColumns( table );
|
---|
82 | */
|
---|
83 | var FixedColumns = function ( dt, init ) {
|
---|
84 | var that = this;
|
---|
85 |
|
---|
86 | /* Sanity check - you just know it will happen */
|
---|
87 | if ( ! ( this instanceof FixedColumns ) ) {
|
---|
88 | alert( "FixedColumns warning: FixedColumns must be initialised with the 'new' keyword." );
|
---|
89 | return;
|
---|
90 | }
|
---|
91 |
|
---|
92 | if ( init === undefined || init === true ) {
|
---|
93 | init = {};
|
---|
94 | }
|
---|
95 |
|
---|
96 | // Use the DataTables Hungarian notation mapping method, if it exists to
|
---|
97 | // provide forwards compatibility for camel case variables
|
---|
98 | var camelToHungarian = $.fn.dataTable.camelToHungarian;
|
---|
99 | if ( camelToHungarian ) {
|
---|
100 | camelToHungarian( FixedColumns.defaults, FixedColumns.defaults, true );
|
---|
101 | camelToHungarian( FixedColumns.defaults, init );
|
---|
102 | }
|
---|
103 |
|
---|
104 | // v1.10 allows the settings object to be got form a number of sources
|
---|
105 | var dtSettings = new $.fn.dataTable.Api( dt ).settings()[0];
|
---|
106 |
|
---|
107 | /**
|
---|
108 | * Settings object which contains customisable information for FixedColumns instance
|
---|
109 | * @namespace
|
---|
110 | * @extends FixedColumns.defaults
|
---|
111 | * @private
|
---|
112 | */
|
---|
113 | this.s = {
|
---|
114 | /**
|
---|
115 | * DataTables settings objects
|
---|
116 | * @type object
|
---|
117 | * @default Obtained from DataTables instance
|
---|
118 | */
|
---|
119 | "dt": dtSettings,
|
---|
120 |
|
---|
121 | /**
|
---|
122 | * Number of columns in the DataTable - stored for quick access
|
---|
123 | * @type int
|
---|
124 | * @default Obtained from DataTables instance
|
---|
125 | */
|
---|
126 | "iTableColumns": dtSettings.aoColumns.length,
|
---|
127 |
|
---|
128 | /**
|
---|
129 | * Original outer widths of the columns as rendered by DataTables - used to calculate
|
---|
130 | * the FixedColumns grid bounding box
|
---|
131 | * @type array.<int>
|
---|
132 | * @default []
|
---|
133 | */
|
---|
134 | "aiOuterWidths": [],
|
---|
135 |
|
---|
136 | /**
|
---|
137 | * Original inner widths of the columns as rendered by DataTables - used to apply widths
|
---|
138 | * to the columns
|
---|
139 | * @type array.<int>
|
---|
140 | * @default []
|
---|
141 | */
|
---|
142 | "aiInnerWidths": [],
|
---|
143 |
|
---|
144 |
|
---|
145 | /**
|
---|
146 | * Is the document layout right-to-left
|
---|
147 | * @type boolean
|
---|
148 | */
|
---|
149 | rtl: $(dtSettings.nTable).css('direction') === 'rtl'
|
---|
150 | };
|
---|
151 |
|
---|
152 |
|
---|
153 | /**
|
---|
154 | * DOM elements used by the class instance
|
---|
155 | * @namespace
|
---|
156 | * @private
|
---|
157 | *
|
---|
158 | */
|
---|
159 | this.dom = {
|
---|
160 | /**
|
---|
161 | * DataTables scrolling element
|
---|
162 | * @type node
|
---|
163 | * @default null
|
---|
164 | */
|
---|
165 | "scroller": null,
|
---|
166 |
|
---|
167 | /**
|
---|
168 | * DataTables header table
|
---|
169 | * @type node
|
---|
170 | * @default null
|
---|
171 | */
|
---|
172 | "header": null,
|
---|
173 |
|
---|
174 | /**
|
---|
175 | * DataTables body table
|
---|
176 | * @type node
|
---|
177 | * @default null
|
---|
178 | */
|
---|
179 | "body": null,
|
---|
180 |
|
---|
181 | /**
|
---|
182 | * DataTables footer table
|
---|
183 | * @type node
|
---|
184 | * @default null
|
---|
185 | */
|
---|
186 | "footer": null,
|
---|
187 |
|
---|
188 | /**
|
---|
189 | * Display grid elements
|
---|
190 | * @namespace
|
---|
191 | */
|
---|
192 | "grid": {
|
---|
193 | /**
|
---|
194 | * Grid wrapper. This is the container element for the 3x3 grid
|
---|
195 | * @type node
|
---|
196 | * @default null
|
---|
197 | */
|
---|
198 | "wrapper": null,
|
---|
199 |
|
---|
200 | /**
|
---|
201 | * DataTables scrolling element. This element is the DataTables
|
---|
202 | * component in the display grid (making up the main table - i.e.
|
---|
203 | * not the fixed columns).
|
---|
204 | * @type node
|
---|
205 | * @default null
|
---|
206 | */
|
---|
207 | "dt": null,
|
---|
208 |
|
---|
209 | /**
|
---|
210 | * Left fixed column grid components
|
---|
211 | * @namespace
|
---|
212 | */
|
---|
213 | "left": {
|
---|
214 | "wrapper": null,
|
---|
215 | "head": null,
|
---|
216 | "body": null,
|
---|
217 | "foot": null
|
---|
218 | },
|
---|
219 |
|
---|
220 | /**
|
---|
221 | * Right fixed column grid components
|
---|
222 | * @namespace
|
---|
223 | */
|
---|
224 | "right": {
|
---|
225 | "wrapper": null,
|
---|
226 | "head": null,
|
---|
227 | "body": null,
|
---|
228 | "foot": null
|
---|
229 | }
|
---|
230 | },
|
---|
231 |
|
---|
232 | /**
|
---|
233 | * Cloned table nodes
|
---|
234 | * @namespace
|
---|
235 | */
|
---|
236 | "clone": {
|
---|
237 | /**
|
---|
238 | * Left column cloned table nodes
|
---|
239 | * @namespace
|
---|
240 | */
|
---|
241 | "left": {
|
---|
242 | /**
|
---|
243 | * Cloned header table
|
---|
244 | * @type node
|
---|
245 | * @default null
|
---|
246 | */
|
---|
247 | "header": null,
|
---|
248 |
|
---|
249 | /**
|
---|
250 | * Cloned body table
|
---|
251 | * @type node
|
---|
252 | * @default null
|
---|
253 | */
|
---|
254 | "body": null,
|
---|
255 |
|
---|
256 | /**
|
---|
257 | * Cloned footer table
|
---|
258 | * @type node
|
---|
259 | * @default null
|
---|
260 | */
|
---|
261 | "footer": null
|
---|
262 | },
|
---|
263 |
|
---|
264 | /**
|
---|
265 | * Right column cloned table nodes
|
---|
266 | * @namespace
|
---|
267 | */
|
---|
268 | "right": {
|
---|
269 | /**
|
---|
270 | * Cloned header table
|
---|
271 | * @type node
|
---|
272 | * @default null
|
---|
273 | */
|
---|
274 | "header": null,
|
---|
275 |
|
---|
276 | /**
|
---|
277 | * Cloned body table
|
---|
278 | * @type node
|
---|
279 | * @default null
|
---|
280 | */
|
---|
281 | "body": null,
|
---|
282 |
|
---|
283 | /**
|
---|
284 | * Cloned footer table
|
---|
285 | * @type node
|
---|
286 | * @default null
|
---|
287 | */
|
---|
288 | "footer": null
|
---|
289 | }
|
---|
290 | }
|
---|
291 | };
|
---|
292 |
|
---|
293 | if ( dtSettings._oFixedColumns ) {
|
---|
294 | throw 'FixedColumns already initialised on this table';
|
---|
295 | }
|
---|
296 |
|
---|
297 | /* Attach the instance to the DataTables instance so it can be accessed easily */
|
---|
298 | dtSettings._oFixedColumns = this;
|
---|
299 |
|
---|
300 | /* Let's do it */
|
---|
301 | if ( ! dtSettings._bInitComplete )
|
---|
302 | {
|
---|
303 | dtSettings.oApi._fnCallbackReg( dtSettings, 'aoInitComplete', function () {
|
---|
304 | that._fnConstruct( init );
|
---|
305 | }, 'FixedColumns' );
|
---|
306 | }
|
---|
307 | else
|
---|
308 | {
|
---|
309 | this._fnConstruct( init );
|
---|
310 | }
|
---|
311 | };
|
---|
312 |
|
---|
313 |
|
---|
314 |
|
---|
315 | $.extend( FixedColumns.prototype , {
|
---|
316 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
317 | * Public methods
|
---|
318 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
---|
319 |
|
---|
320 | /**
|
---|
321 | * Update the fixed columns - including headers and footers. Note that FixedColumns will
|
---|
322 | * automatically update the display whenever the host DataTable redraws.
|
---|
323 | * @returns {void}
|
---|
324 | * @example
|
---|
325 | * var table = $('#example').dataTable( {
|
---|
326 | * "scrollX": "100%"
|
---|
327 | * } );
|
---|
328 | * var fc = new $.fn.dataTable.fixedColumns( table );
|
---|
329 | *
|
---|
330 | * // at some later point when the table has been manipulated....
|
---|
331 | * fc.fnUpdate();
|
---|
332 | */
|
---|
333 | "fnUpdate": function ()
|
---|
334 | {
|
---|
335 | this._fnDraw( true );
|
---|
336 | },
|
---|
337 |
|
---|
338 |
|
---|
339 | /**
|
---|
340 | * Recalculate the resizes of the 3x3 grid that FixedColumns uses for display of the table.
|
---|
341 | * This is useful if you update the width of the table container. Note that FixedColumns will
|
---|
342 | * perform this function automatically when the window.resize event is fired.
|
---|
343 | * @returns {void}
|
---|
344 | * @example
|
---|
345 | * var table = $('#example').dataTable( {
|
---|
346 | * "scrollX": "100%"
|
---|
347 | * } );
|
---|
348 | * var fc = new $.fn.dataTable.fixedColumns( table );
|
---|
349 | *
|
---|
350 | * // Resize the table container and then have FixedColumns adjust its layout....
|
---|
351 | * $('#content').width( 1200 );
|
---|
352 | * fc.fnRedrawLayout();
|
---|
353 | */
|
---|
354 | "fnRedrawLayout": function ()
|
---|
355 | {
|
---|
356 | this._fnColCalc();
|
---|
357 | this._fnGridLayout();
|
---|
358 | this.fnUpdate();
|
---|
359 | },
|
---|
360 |
|
---|
361 |
|
---|
362 | /**
|
---|
363 | * Mark a row such that it's height should be recalculated when using 'semiauto' row
|
---|
364 | * height matching. This function will have no effect when 'none' or 'auto' row height
|
---|
365 | * matching is used.
|
---|
366 | * @param {Node} nTr TR element that should have it's height recalculated
|
---|
367 | * @returns {void}
|
---|
368 | * @example
|
---|
369 | * var table = $('#example').dataTable( {
|
---|
370 | * "scrollX": "100%"
|
---|
371 | * } );
|
---|
372 | * var fc = new $.fn.dataTable.fixedColumns( table );
|
---|
373 | *
|
---|
374 | * // manipulate the table - mark the row as needing an update then update the table
|
---|
375 | * // this allows the redraw performed by DataTables fnUpdate to recalculate the row
|
---|
376 | * // height
|
---|
377 | * fc.fnRecalculateHeight();
|
---|
378 | * table.fnUpdate( $('#example tbody tr:eq(0)')[0], ["insert date", 1, 2, 3 ... ]);
|
---|
379 | */
|
---|
380 | "fnRecalculateHeight": function ( nTr )
|
---|
381 | {
|
---|
382 | delete nTr._DTTC_iHeight;
|
---|
383 | nTr.style.height = 'auto';
|
---|
384 | },
|
---|
385 |
|
---|
386 |
|
---|
387 | /**
|
---|
388 | * Set the height of a given row - provides cross browser compatibility
|
---|
389 | * @param {Node} nTarget TR element that should have it's height recalculated
|
---|
390 | * @param {int} iHeight Height in pixels to set
|
---|
391 | * @returns {void}
|
---|
392 | * @example
|
---|
393 | * var table = $('#example').dataTable( {
|
---|
394 | * "scrollX": "100%"
|
---|
395 | * } );
|
---|
396 | * var fc = new $.fn.dataTable.fixedColumns( table );
|
---|
397 | *
|
---|
398 | * // You may want to do this after manipulating a row in the fixed column
|
---|
399 | * fc.fnSetRowHeight( $('#example tbody tr:eq(0)')[0], 50 );
|
---|
400 | */
|
---|
401 | "fnSetRowHeight": function ( nTarget, iHeight )
|
---|
402 | {
|
---|
403 | nTarget.style.height = iHeight+"px";
|
---|
404 | },
|
---|
405 |
|
---|
406 |
|
---|
407 | /**
|
---|
408 | * Get data index information about a row or cell in the table body.
|
---|
409 | * This function is functionally identical to fnGetPosition in DataTables,
|
---|
410 | * taking the same parameter (TH, TD or TR node) and returning exactly the
|
---|
411 | * the same information (data index information). THe difference between
|
---|
412 | * the two is that this method takes into account the fixed columns in the
|
---|
413 | * table, so you can pass in nodes from the master table, or the cloned
|
---|
414 | * tables and get the index position for the data in the main table.
|
---|
415 | * @param {node} node TR, TH or TD element to get the information about
|
---|
416 | * @returns {int} If nNode is given as a TR, then a single index is
|
---|
417 | * returned, or if given as a cell, an array of [row index, column index
|
---|
418 | * (visible), column index (all)] is given.
|
---|
419 | */
|
---|
420 | "fnGetPosition": function ( node )
|
---|
421 | {
|
---|
422 | var idx;
|
---|
423 | var inst = this.s.dt.oInstance;
|
---|
424 |
|
---|
425 | if ( ! $(node).parents('.DTFC_Cloned').length )
|
---|
426 | {
|
---|
427 | // Not in a cloned table
|
---|
428 | return inst.fnGetPosition( node );
|
---|
429 | }
|
---|
430 | else
|
---|
431 | {
|
---|
432 | // Its in the cloned table, so need to look up position
|
---|
433 | if ( node.nodeName.toLowerCase() === 'tr' ) {
|
---|
434 | idx = $(node).index();
|
---|
435 | return inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
|
---|
436 | }
|
---|
437 | else
|
---|
438 | {
|
---|
439 | var colIdx = $(node).index();
|
---|
440 | idx = $(node.parentNode).index();
|
---|
441 | var row = inst.fnGetPosition( $('tr', this.s.dt.nTBody)[ idx ] );
|
---|
442 |
|
---|
443 | return [
|
---|
444 | row,
|
---|
445 | colIdx,
|
---|
446 | inst.oApi._fnVisibleToColumnIndex( this.s.dt, colIdx )
|
---|
447 | ];
|
---|
448 | }
|
---|
449 | }
|
---|
450 | },
|
---|
451 |
|
---|
452 | fnToFixedNode: function ( rowIdx, colIdx )
|
---|
453 | {
|
---|
454 | var found;
|
---|
455 |
|
---|
456 | if ( colIdx < this.s.iLeftColumns ) {
|
---|
457 | found = $(this.dom.clone.left.body).find('[data-dt-row='+rowIdx+'][data-dt-column='+colIdx+']');
|
---|
458 | }
|
---|
459 | else if ( colIdx >= this.s.iRightColumns ) {
|
---|
460 | found = $(this.dom.clone.right.body).find('[data-dt-row='+rowIdx+'][data-dt-column='+colIdx+']');
|
---|
461 | }
|
---|
462 |
|
---|
463 | if ( found && found.length ) {
|
---|
464 | return found[0];
|
---|
465 | }
|
---|
466 |
|
---|
467 | // Fallback - non-fixed node
|
---|
468 | var table = new $.fn.dataTable.Api(this.s.dt);
|
---|
469 | return table.cell(rowIdx, colIdx).node();
|
---|
470 | },
|
---|
471 |
|
---|
472 |
|
---|
473 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
474 | * Private methods (they are of course public in JS, but recommended as private)
|
---|
475 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
---|
476 |
|
---|
477 | /**
|
---|
478 | * Initialisation for FixedColumns
|
---|
479 | * @param {Object} oInit User settings for initialisation
|
---|
480 | * @returns {void}
|
---|
481 | * @private
|
---|
482 | */
|
---|
483 | "_fnConstruct": function ( oInit )
|
---|
484 | {
|
---|
485 | var i, iLen, iWidth,
|
---|
486 | that = this;
|
---|
487 |
|
---|
488 | /* Sanity checking */
|
---|
489 | if ( typeof this.s.dt.oInstance.fnVersionCheck != 'function' ||
|
---|
490 | this.s.dt.oInstance.fnVersionCheck( '1.8.0' ) !== true )
|
---|
491 | {
|
---|
492 | alert( "FixedColumns "+FixedColumns.VERSION+" required DataTables 1.8.0 or later. "+
|
---|
493 | "Please upgrade your DataTables installation" );
|
---|
494 | return;
|
---|
495 | }
|
---|
496 |
|
---|
497 | if ( this.s.dt.oScroll.sX === "" )
|
---|
498 | {
|
---|
499 | this.s.dt.oInstance.oApi._fnLog( this.s.dt, 1, "FixedColumns is not needed (no "+
|
---|
500 | "x-scrolling in DataTables enabled), so no action will be taken. Use 'FixedHeader' for "+
|
---|
501 | "column fixing when scrolling is not enabled" );
|
---|
502 | return;
|
---|
503 | }
|
---|
504 |
|
---|
505 | /* Apply the settings from the user / defaults */
|
---|
506 | this.s = $.extend( true, this.s, FixedColumns.defaults, oInit );
|
---|
507 |
|
---|
508 | /* Set up the DOM as we need it and cache nodes */
|
---|
509 | var classes = this.s.dt.oClasses;
|
---|
510 | this.dom.grid.dt = $(this.s.dt.nTable).parents('div.'+classes.sScrollWrapper)[0];
|
---|
511 | this.dom.scroller = $('div.'+classes.sScrollBody, this.dom.grid.dt )[0];
|
---|
512 |
|
---|
513 | /* Set up the DOM that we want for the fixed column layout grid */
|
---|
514 | this._fnColCalc();
|
---|
515 | this._fnGridSetup();
|
---|
516 |
|
---|
517 | /* Event handlers */
|
---|
518 | var mouseController;
|
---|
519 | var mouseDown = false;
|
---|
520 |
|
---|
521 | // When the mouse is down (drag scroll) the mouse controller cannot
|
---|
522 | // change, as the browser keeps the original element as the scrolling one
|
---|
523 | $(this.s.dt.nTableWrapper).on( 'mousedown.DTFC', function (e) {
|
---|
524 | if ( e.button === 0 ) {
|
---|
525 | mouseDown = true;
|
---|
526 |
|
---|
527 | $(document).one( 'mouseup', function () {
|
---|
528 | mouseDown = false;
|
---|
529 | } );
|
---|
530 | }
|
---|
531 | } );
|
---|
532 |
|
---|
533 | // When the body is scrolled - scroll the left and right columns
|
---|
534 | $(this.dom.scroller)
|
---|
535 | .on( 'mouseover.DTFC touchstart.DTFC', function () {
|
---|
536 | if ( ! mouseDown ) {
|
---|
537 | mouseController = 'main';
|
---|
538 | }
|
---|
539 | } )
|
---|
540 | .on( 'scroll.DTFC', function (e) {
|
---|
541 | if ( ! mouseController && e.originalEvent ) {
|
---|
542 | mouseController = 'main';
|
---|
543 | }
|
---|
544 |
|
---|
545 | if ( mouseController === 'main' ) {
|
---|
546 | if ( that.s.iLeftColumns > 0 ) {
|
---|
547 | that.dom.grid.left.liner.scrollTop = that.dom.scroller.scrollTop;
|
---|
548 | }
|
---|
549 | if ( that.s.iRightColumns > 0 ) {
|
---|
550 | that.dom.grid.right.liner.scrollTop = that.dom.scroller.scrollTop;
|
---|
551 | }
|
---|
552 | }
|
---|
553 | } );
|
---|
554 |
|
---|
555 | var wheelType = 'onwheel' in document.createElement('div') ?
|
---|
556 | 'wheel.DTFC' :
|
---|
557 | 'mousewheel.DTFC';
|
---|
558 |
|
---|
559 | if ( that.s.iLeftColumns > 0 ) {
|
---|
560 | // When scrolling the left column, scroll the body and right column
|
---|
561 | $(that.dom.grid.left.liner)
|
---|
562 | .on( 'mouseover.DTFC touchstart.DTFC', function () {
|
---|
563 | if ( ! mouseDown ) {
|
---|
564 | mouseController = 'left';
|
---|
565 | }
|
---|
566 | } )
|
---|
567 | .on( 'scroll.DTFC', function ( e ) {
|
---|
568 | if ( ! mouseController && e.originalEvent ) {
|
---|
569 | mouseController = 'left';
|
---|
570 | }
|
---|
571 |
|
---|
572 | if ( mouseController === 'left' ) {
|
---|
573 | that.dom.scroller.scrollTop = that.dom.grid.left.liner.scrollTop;
|
---|
574 | if ( that.s.iRightColumns > 0 ) {
|
---|
575 | that.dom.grid.right.liner.scrollTop = that.dom.grid.left.liner.scrollTop;
|
---|
576 | }
|
---|
577 | }
|
---|
578 | } )
|
---|
579 | .on( wheelType, function(e) {
|
---|
580 | // Pass horizontal scrolling through
|
---|
581 | var xDelta = e.type === 'wheel' ?
|
---|
582 | -e.originalEvent.deltaX :
|
---|
583 | e.originalEvent.wheelDeltaX;
|
---|
584 | that.dom.scroller.scrollLeft -= xDelta;
|
---|
585 | } );
|
---|
586 | }
|
---|
587 |
|
---|
588 | if ( that.s.iRightColumns > 0 ) {
|
---|
589 | // When scrolling the right column, scroll the body and the left column
|
---|
590 | $(that.dom.grid.right.liner)
|
---|
591 | .on( 'mouseover.DTFC touchstart.DTFC', function () {
|
---|
592 | if ( ! mouseDown ) {
|
---|
593 | mouseController = 'right';
|
---|
594 | }
|
---|
595 | } )
|
---|
596 | .on( 'scroll.DTFC', function ( e ) {
|
---|
597 | if ( ! mouseController && e.originalEvent ) {
|
---|
598 | mouseController = 'right';
|
---|
599 | }
|
---|
600 |
|
---|
601 | if ( mouseController === 'right' ) {
|
---|
602 | that.dom.scroller.scrollTop = that.dom.grid.right.liner.scrollTop;
|
---|
603 | if ( that.s.iLeftColumns > 0 ) {
|
---|
604 | that.dom.grid.left.liner.scrollTop = that.dom.grid.right.liner.scrollTop;
|
---|
605 | }
|
---|
606 | }
|
---|
607 | } )
|
---|
608 | .on( wheelType, function(e) {
|
---|
609 | // Pass horizontal scrolling through
|
---|
610 | var xDelta = e.type === 'wheel' ?
|
---|
611 | -e.originalEvent.deltaX :
|
---|
612 | e.originalEvent.wheelDeltaX;
|
---|
613 | that.dom.scroller.scrollLeft -= xDelta;
|
---|
614 | } );
|
---|
615 | }
|
---|
616 |
|
---|
617 | $(window).on( 'resize.DTFC', function () {
|
---|
618 | that._fnGridLayout.call( that );
|
---|
619 | } );
|
---|
620 |
|
---|
621 | var bFirstDraw = true;
|
---|
622 | var jqTable = $(this.s.dt.nTable);
|
---|
623 |
|
---|
624 | jqTable
|
---|
625 | .on( 'draw.dt.DTFC', function () {
|
---|
626 | that._fnColCalc();
|
---|
627 | that._fnDraw.call( that, bFirstDraw );
|
---|
628 | bFirstDraw = false;
|
---|
629 | } )
|
---|
630 | .on( 'column-sizing.dt.DTFC', function () {
|
---|
631 | that._fnColCalc();
|
---|
632 | that._fnGridLayout( that );
|
---|
633 | } )
|
---|
634 | .on( 'column-visibility.dt.DTFC', function ( e, settings, column, vis, recalc ) {
|
---|
635 | if ( recalc === undefined || recalc ) {
|
---|
636 | that._fnColCalc();
|
---|
637 | that._fnGridLayout( that );
|
---|
638 | that._fnDraw( true );
|
---|
639 | }
|
---|
640 | } )
|
---|
641 | .on( 'select.dt.DTFC deselect.dt.DTFC', function ( e, dt, type, indexes ) {
|
---|
642 | if ( e.namespace === 'dt' ) {
|
---|
643 | that._fnDraw( false );
|
---|
644 | }
|
---|
645 | } )
|
---|
646 | .on( 'destroy.dt.DTFC', function () {
|
---|
647 | jqTable.off( '.DTFC' );
|
---|
648 |
|
---|
649 | $(that.dom.scroller).off( '.DTFC' );
|
---|
650 | $(window).off( '.DTFC' );
|
---|
651 | $(that.s.dt.nTableWrapper).off( '.DTFC' );
|
---|
652 |
|
---|
653 | $(that.dom.grid.left.liner).off( '.DTFC '+wheelType );
|
---|
654 | $(that.dom.grid.left.wrapper).remove();
|
---|
655 |
|
---|
656 | $(that.dom.grid.right.liner).off( '.DTFC '+wheelType );
|
---|
657 | $(that.dom.grid.right.wrapper).remove();
|
---|
658 | } );
|
---|
659 |
|
---|
660 | /* Get things right to start with - note that due to adjusting the columns, there must be
|
---|
661 | * another redraw of the main table. It doesn't need to be a full redraw however.
|
---|
662 | */
|
---|
663 | this._fnGridLayout();
|
---|
664 | this.s.dt.oInstance.fnDraw(false);
|
---|
665 | },
|
---|
666 |
|
---|
667 |
|
---|
668 | /**
|
---|
669 | * Calculate the column widths for the grid layout
|
---|
670 | * @returns {void}
|
---|
671 | * @private
|
---|
672 | */
|
---|
673 | "_fnColCalc": function ()
|
---|
674 | {
|
---|
675 | var that = this;
|
---|
676 | var iLeftWidth = 0;
|
---|
677 | var iRightWidth = 0;
|
---|
678 |
|
---|
679 | this.s.aiInnerWidths = [];
|
---|
680 | this.s.aiOuterWidths = [];
|
---|
681 |
|
---|
682 | $.each( this.s.dt.aoColumns, function (i, col) {
|
---|
683 | var th = $(col.nTh);
|
---|
684 | var border;
|
---|
685 |
|
---|
686 | if ( ! th.filter(':visible').length ) {
|
---|
687 | that.s.aiInnerWidths.push( 0 );
|
---|
688 | that.s.aiOuterWidths.push( 0 );
|
---|
689 | }
|
---|
690 | else
|
---|
691 | {
|
---|
692 | // Inner width is used to assign widths to cells
|
---|
693 | // Outer width is used to calculate the container
|
---|
694 | var iWidth = th.outerWidth();
|
---|
695 |
|
---|
696 | // When working with the left most-cell, need to add on the
|
---|
697 | // table's border to the outerWidth, since we need to take
|
---|
698 | // account of it, but it isn't in any cell
|
---|
699 | if ( that.s.aiOuterWidths.length === 0 ) {
|
---|
700 | border = $(that.s.dt.nTable).css('border-left-width');
|
---|
701 | iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
|
---|
702 | 1 :
|
---|
703 | parseInt( border, 10 );
|
---|
704 | }
|
---|
705 |
|
---|
706 | // Likewise with the final column on the right
|
---|
707 | if ( that.s.aiOuterWidths.length === that.s.dt.aoColumns.length-1 ) {
|
---|
708 | border = $(that.s.dt.nTable).css('border-right-width');
|
---|
709 | iWidth += typeof border === 'string' && border.indexOf('px') === -1 ?
|
---|
710 | 1 :
|
---|
711 | parseInt( border, 10 );
|
---|
712 | }
|
---|
713 |
|
---|
714 | that.s.aiOuterWidths.push( iWidth );
|
---|
715 | that.s.aiInnerWidths.push( th.width() );
|
---|
716 |
|
---|
717 | if ( i < that.s.iLeftColumns )
|
---|
718 | {
|
---|
719 | iLeftWidth += iWidth;
|
---|
720 | }
|
---|
721 |
|
---|
722 | if ( that.s.iTableColumns-that.s.iRightColumns <= i )
|
---|
723 | {
|
---|
724 | iRightWidth += iWidth;
|
---|
725 | }
|
---|
726 | }
|
---|
727 | } );
|
---|
728 |
|
---|
729 | this.s.iLeftWidth = iLeftWidth;
|
---|
730 | this.s.iRightWidth = iRightWidth;
|
---|
731 | },
|
---|
732 |
|
---|
733 |
|
---|
734 | /**
|
---|
735 | * Set up the DOM for the fixed column. The way the layout works is to create a 1x3 grid
|
---|
736 | * for the left column, the DataTable (for which we just reuse the scrolling element DataTable
|
---|
737 | * puts into the DOM) and the right column. In each of he two fixed column elements there is a
|
---|
738 | * grouping wrapper element and then a head, body and footer wrapper. In each of these we then
|
---|
739 | * place the cloned header, body or footer tables. This effectively gives as 3x3 grid structure.
|
---|
740 | * @returns {void}
|
---|
741 | * @private
|
---|
742 | */
|
---|
743 | "_fnGridSetup": function ()
|
---|
744 | {
|
---|
745 | var that = this;
|
---|
746 | var oOverflow = this._fnDTOverflow();
|
---|
747 | var block;
|
---|
748 |
|
---|
749 | this.dom.body = this.s.dt.nTable;
|
---|
750 | this.dom.header = this.s.dt.nTHead.parentNode;
|
---|
751 | this.dom.header.parentNode.parentNode.style.position = "relative";
|
---|
752 |
|
---|
753 | var nSWrapper =
|
---|
754 | $('<div class="DTFC_ScrollWrapper" style="position:relative; clear:both;">'+
|
---|
755 | '<div class="DTFC_LeftWrapper" style="position:absolute; top:0; left:0;" aria-hidden="true">'+
|
---|
756 | '<div class="DTFC_LeftHeadWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
|
---|
757 | '<div class="DTFC_LeftBodyWrapper" style="position:relative; top:0; left:0; height:0; overflow:hidden;">'+
|
---|
758 | '<div class="DTFC_LeftBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
|
---|
759 | '</div>'+
|
---|
760 | '<div class="DTFC_LeftFootWrapper" style="position:relative; top:0; left:0; overflow:hidden;"></div>'+
|
---|
761 | '</div>'+
|
---|
762 | '<div class="DTFC_RightWrapper" style="position:absolute; top:0; right:0;" aria-hidden="true">'+
|
---|
763 | '<div class="DTFC_RightHeadWrapper" style="position:relative; top:0; left:0;">'+
|
---|
764 | '<div class="DTFC_RightHeadBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
|
---|
765 | '</div>'+
|
---|
766 | '<div class="DTFC_RightBodyWrapper" style="position:relative; top:0; left:0; height:0; overflow:hidden;">'+
|
---|
767 | '<div class="DTFC_RightBodyLiner" style="position:relative; top:0; left:0; overflow-y:scroll;"></div>'+
|
---|
768 | '</div>'+
|
---|
769 | '<div class="DTFC_RightFootWrapper" style="position:relative; top:0; left:0;">'+
|
---|
770 | '<div class="DTFC_RightFootBlocker DTFC_Blocker" style="position:absolute; top:0; bottom:0;"></div>'+
|
---|
771 | '</div>'+
|
---|
772 | '</div>'+
|
---|
773 | '</div>')[0];
|
---|
774 | var nLeft = nSWrapper.childNodes[0];
|
---|
775 | var nRight = nSWrapper.childNodes[1];
|
---|
776 |
|
---|
777 | this.dom.grid.dt.parentNode.insertBefore( nSWrapper, this.dom.grid.dt );
|
---|
778 | nSWrapper.appendChild( this.dom.grid.dt );
|
---|
779 |
|
---|
780 | this.dom.grid.wrapper = nSWrapper;
|
---|
781 |
|
---|
782 | if ( this.s.iLeftColumns > 0 )
|
---|
783 | {
|
---|
784 | this.dom.grid.left.wrapper = nLeft;
|
---|
785 | this.dom.grid.left.head = nLeft.childNodes[0];
|
---|
786 | this.dom.grid.left.body = nLeft.childNodes[1];
|
---|
787 | this.dom.grid.left.liner = $('div.DTFC_LeftBodyLiner', nSWrapper)[0];
|
---|
788 |
|
---|
789 | nSWrapper.appendChild( nLeft );
|
---|
790 | }
|
---|
791 |
|
---|
792 | if ( this.s.iRightColumns > 0 )
|
---|
793 | {
|
---|
794 | this.dom.grid.right.wrapper = nRight;
|
---|
795 | this.dom.grid.right.head = nRight.childNodes[0];
|
---|
796 | this.dom.grid.right.body = nRight.childNodes[1];
|
---|
797 | this.dom.grid.right.liner = $('div.DTFC_RightBodyLiner', nSWrapper)[0];
|
---|
798 |
|
---|
799 | nRight.style.right = oOverflow.bar+"px";
|
---|
800 |
|
---|
801 | block = $('div.DTFC_RightHeadBlocker', nSWrapper)[0];
|
---|
802 | block.style.width = oOverflow.bar+"px";
|
---|
803 | block.style.right = -oOverflow.bar+"px";
|
---|
804 | this.dom.grid.right.headBlock = block;
|
---|
805 |
|
---|
806 | block = $('div.DTFC_RightFootBlocker', nSWrapper)[0];
|
---|
807 | block.style.width = oOverflow.bar+"px";
|
---|
808 | block.style.right = -oOverflow.bar+"px";
|
---|
809 | this.dom.grid.right.footBlock = block;
|
---|
810 |
|
---|
811 | nSWrapper.appendChild( nRight );
|
---|
812 | }
|
---|
813 |
|
---|
814 | if ( this.s.dt.nTFoot )
|
---|
815 | {
|
---|
816 | this.dom.footer = this.s.dt.nTFoot.parentNode;
|
---|
817 | if ( this.s.iLeftColumns > 0 )
|
---|
818 | {
|
---|
819 | this.dom.grid.left.foot = nLeft.childNodes[2];
|
---|
820 | }
|
---|
821 | if ( this.s.iRightColumns > 0 )
|
---|
822 | {
|
---|
823 | this.dom.grid.right.foot = nRight.childNodes[2];
|
---|
824 | }
|
---|
825 | }
|
---|
826 |
|
---|
827 | // RTL support - swap the position of the left and right columns (#48)
|
---|
828 | if ( this.s.rtl ) {
|
---|
829 | $('div.DTFC_RightHeadBlocker', nSWrapper).css( {
|
---|
830 | left: -oOverflow.bar+'px',
|
---|
831 | right: ''
|
---|
832 | } );
|
---|
833 | }
|
---|
834 | },
|
---|
835 |
|
---|
836 |
|
---|
837 | /**
|
---|
838 | * Style and position the grid used for the FixedColumns layout
|
---|
839 | * @returns {void}
|
---|
840 | * @private
|
---|
841 | */
|
---|
842 | "_fnGridLayout": function ()
|
---|
843 | {
|
---|
844 | var that = this;
|
---|
845 | var oGrid = this.dom.grid;
|
---|
846 | var iWidth = $(oGrid.wrapper).width();
|
---|
847 | var iBodyHeight = this.s.dt.nTable.parentNode.offsetHeight;
|
---|
848 | var iFullHeight = this.s.dt.nTable.parentNode.parentNode.offsetHeight;
|
---|
849 | var oOverflow = this._fnDTOverflow();
|
---|
850 | var iLeftWidth = this.s.iLeftWidth;
|
---|
851 | var iRightWidth = this.s.iRightWidth;
|
---|
852 | var rtl = $(this.dom.body).css('direction') === 'rtl';
|
---|
853 | var wrapper;
|
---|
854 | var scrollbarAdjust = function ( node, width ) {
|
---|
855 | if ( ! oOverflow.bar ) {
|
---|
856 | // If there is no scrollbar (Macs) we need to hide the auto scrollbar
|
---|
857 | node.style.width = (width+20)+"px";
|
---|
858 | node.style.paddingRight = "20px";
|
---|
859 | node.style.boxSizing = "border-box";
|
---|
860 | }
|
---|
861 | else if ( that._firefoxScrollError() ) {
|
---|
862 | // See the above function for why this is required
|
---|
863 | if ( $(node).height() > 34 ) {
|
---|
864 | node.style.width = (width+oOverflow.bar)+"px";
|
---|
865 | }
|
---|
866 | }
|
---|
867 | else {
|
---|
868 | // Otherwise just overflow by the scrollbar
|
---|
869 | node.style.width = (width+oOverflow.bar)+"px";
|
---|
870 | }
|
---|
871 | };
|
---|
872 |
|
---|
873 | // When x scrolling - don't paint the fixed columns over the x scrollbar
|
---|
874 | if ( oOverflow.x )
|
---|
875 | {
|
---|
876 | iBodyHeight -= oOverflow.bar;
|
---|
877 | }
|
---|
878 |
|
---|
879 | oGrid.wrapper.style.height = iFullHeight+"px";
|
---|
880 |
|
---|
881 | if ( this.s.iLeftColumns > 0 )
|
---|
882 | {
|
---|
883 | wrapper = oGrid.left.wrapper;
|
---|
884 | wrapper.style.width = iLeftWidth+'px';
|
---|
885 | wrapper.style.height = '1px';
|
---|
886 |
|
---|
887 | // Swap the position of the left and right columns for rtl (#48)
|
---|
888 | // This is always up against the edge, scrollbar on the far side
|
---|
889 | if ( rtl ) {
|
---|
890 | wrapper.style.left = '';
|
---|
891 | wrapper.style.right = 0;
|
---|
892 | }
|
---|
893 | else {
|
---|
894 | wrapper.style.left = 0;
|
---|
895 | wrapper.style.right = '';
|
---|
896 | }
|
---|
897 |
|
---|
898 | oGrid.left.body.style.height = iBodyHeight+"px";
|
---|
899 | if ( oGrid.left.foot ) {
|
---|
900 | oGrid.left.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px"; // shift footer for scrollbar
|
---|
901 | }
|
---|
902 |
|
---|
903 | scrollbarAdjust( oGrid.left.liner, iLeftWidth );
|
---|
904 | oGrid.left.liner.style.height = iBodyHeight+"px";
|
---|
905 | oGrid.left.liner.style.maxHeight = iBodyHeight+"px";
|
---|
906 | }
|
---|
907 |
|
---|
908 | if ( this.s.iRightColumns > 0 )
|
---|
909 | {
|
---|
910 | wrapper = oGrid.right.wrapper;
|
---|
911 | wrapper.style.width = iRightWidth+'px';
|
---|
912 | wrapper.style.height = '1px';
|
---|
913 |
|
---|
914 | // Need to take account of the vertical scrollbar
|
---|
915 | if ( this.s.rtl ) {
|
---|
916 | wrapper.style.left = oOverflow.y ? oOverflow.bar+'px' : 0;
|
---|
917 | wrapper.style.right = '';
|
---|
918 | }
|
---|
919 | else {
|
---|
920 | wrapper.style.left = '';
|
---|
921 | wrapper.style.right = oOverflow.y ? oOverflow.bar+'px' : 0;
|
---|
922 | }
|
---|
923 |
|
---|
924 | oGrid.right.body.style.height = iBodyHeight+"px";
|
---|
925 | if ( oGrid.right.foot ) {
|
---|
926 | oGrid.right.foot.style.top = (oOverflow.x ? oOverflow.bar : 0)+"px";
|
---|
927 | }
|
---|
928 |
|
---|
929 | scrollbarAdjust( oGrid.right.liner, iRightWidth );
|
---|
930 | oGrid.right.liner.style.height = iBodyHeight+"px";
|
---|
931 | oGrid.right.liner.style.maxHeight = iBodyHeight+"px";
|
---|
932 |
|
---|
933 | oGrid.right.headBlock.style.display = oOverflow.y ? 'block' : 'none';
|
---|
934 | oGrid.right.footBlock.style.display = oOverflow.y ? 'block' : 'none';
|
---|
935 | }
|
---|
936 | },
|
---|
937 |
|
---|
938 |
|
---|
939 | /**
|
---|
940 | * Get information about the DataTable's scrolling state - specifically if the table is scrolling
|
---|
941 | * on either the x or y axis, and also the scrollbar width.
|
---|
942 | * @returns {object} Information about the DataTables scrolling state with the properties:
|
---|
943 | * 'x', 'y' and 'bar'
|
---|
944 | * @private
|
---|
945 | */
|
---|
946 | "_fnDTOverflow": function ()
|
---|
947 | {
|
---|
948 | var nTable = this.s.dt.nTable;
|
---|
949 | var nTableScrollBody = nTable.parentNode;
|
---|
950 | var out = {
|
---|
951 | "x": false,
|
---|
952 | "y": false,
|
---|
953 | "bar": this.s.dt.oScroll.iBarWidth
|
---|
954 | };
|
---|
955 |
|
---|
956 | if ( nTable.offsetWidth > nTableScrollBody.clientWidth )
|
---|
957 | {
|
---|
958 | out.x = true;
|
---|
959 | }
|
---|
960 |
|
---|
961 | if ( nTable.offsetHeight > nTableScrollBody.clientHeight )
|
---|
962 | {
|
---|
963 | out.y = true;
|
---|
964 | }
|
---|
965 |
|
---|
966 | return out;
|
---|
967 | },
|
---|
968 |
|
---|
969 |
|
---|
970 | /**
|
---|
971 | * Clone and position the fixed columns
|
---|
972 | * @returns {void}
|
---|
973 | * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
|
---|
974 | * @private
|
---|
975 | */
|
---|
976 | "_fnDraw": function ( bAll )
|
---|
977 | {
|
---|
978 | this._fnGridLayout();
|
---|
979 | this._fnCloneLeft( bAll );
|
---|
980 | this._fnCloneRight( bAll );
|
---|
981 |
|
---|
982 | /* Draw callback function */
|
---|
983 | if ( this.s.fnDrawCallback !== null )
|
---|
984 | {
|
---|
985 | this.s.fnDrawCallback.call( this, this.dom.clone.left, this.dom.clone.right );
|
---|
986 | }
|
---|
987 |
|
---|
988 | /* Event triggering */
|
---|
989 | $(this).trigger( 'draw.dtfc', {
|
---|
990 | "leftClone": this.dom.clone.left,
|
---|
991 | "rightClone": this.dom.clone.right
|
---|
992 | } );
|
---|
993 | },
|
---|
994 |
|
---|
995 |
|
---|
996 | /**
|
---|
997 | * Clone the right columns
|
---|
998 | * @returns {void}
|
---|
999 | * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
|
---|
1000 | * @private
|
---|
1001 | */
|
---|
1002 | "_fnCloneRight": function ( bAll )
|
---|
1003 | {
|
---|
1004 | if ( this.s.iRightColumns <= 0 ) {
|
---|
1005 | return;
|
---|
1006 | }
|
---|
1007 |
|
---|
1008 | var that = this,
|
---|
1009 | i, jq,
|
---|
1010 | aiColumns = [];
|
---|
1011 |
|
---|
1012 | for ( i=this.s.iTableColumns-this.s.iRightColumns ; i<this.s.iTableColumns ; i++ ) {
|
---|
1013 | if ( this.s.dt.aoColumns[i].bVisible ) {
|
---|
1014 | aiColumns.push( i );
|
---|
1015 | }
|
---|
1016 | }
|
---|
1017 |
|
---|
1018 | this._fnClone( this.dom.clone.right, this.dom.grid.right, aiColumns, bAll );
|
---|
1019 | },
|
---|
1020 |
|
---|
1021 |
|
---|
1022 | /**
|
---|
1023 | * Clone the left columns
|
---|
1024 | * @returns {void}
|
---|
1025 | * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
|
---|
1026 | * @private
|
---|
1027 | */
|
---|
1028 | "_fnCloneLeft": function ( bAll )
|
---|
1029 | {
|
---|
1030 | if ( this.s.iLeftColumns <= 0 ) {
|
---|
1031 | return;
|
---|
1032 | }
|
---|
1033 |
|
---|
1034 | var that = this,
|
---|
1035 | i, jq,
|
---|
1036 | aiColumns = [];
|
---|
1037 |
|
---|
1038 | for ( i=0 ; i<this.s.iLeftColumns ; i++ ) {
|
---|
1039 | if ( this.s.dt.aoColumns[i].bVisible ) {
|
---|
1040 | aiColumns.push( i );
|
---|
1041 | }
|
---|
1042 | }
|
---|
1043 |
|
---|
1044 | this._fnClone( this.dom.clone.left, this.dom.grid.left, aiColumns, bAll );
|
---|
1045 | },
|
---|
1046 |
|
---|
1047 |
|
---|
1048 | /**
|
---|
1049 | * Make a copy of the layout object for a header or footer element from DataTables. Note that
|
---|
1050 | * this method will clone the nodes in the layout object.
|
---|
1051 | * @returns {Array} Copy of the layout array
|
---|
1052 | * @param {Object} aoOriginal Layout array from DataTables (aoHeader or aoFooter)
|
---|
1053 | * @param {Object} aiColumns Columns to copy
|
---|
1054 | * @param {boolean} events Copy cell events or not
|
---|
1055 | * @private
|
---|
1056 | */
|
---|
1057 | "_fnCopyLayout": function ( aoOriginal, aiColumns, events )
|
---|
1058 | {
|
---|
1059 | var aReturn = [];
|
---|
1060 | var aClones = [];
|
---|
1061 | var aCloned = [];
|
---|
1062 |
|
---|
1063 | for ( var i=0, iLen=aoOriginal.length ; i<iLen ; i++ )
|
---|
1064 | {
|
---|
1065 | var aRow = [];
|
---|
1066 | aRow.nTr = $(aoOriginal[i].nTr).clone(events, false)[0];
|
---|
1067 |
|
---|
1068 | for ( var j=0, jLen=this.s.iTableColumns ; j<jLen ; j++ )
|
---|
1069 | {
|
---|
1070 | if ( $.inArray( j, aiColumns ) === -1 )
|
---|
1071 | {
|
---|
1072 | continue;
|
---|
1073 | }
|
---|
1074 |
|
---|
1075 | var iCloned = $.inArray( aoOriginal[i][j].cell, aCloned );
|
---|
1076 | if ( iCloned === -1 )
|
---|
1077 | {
|
---|
1078 | var nClone = $(aoOriginal[i][j].cell).clone(events, false)[0];
|
---|
1079 | aClones.push( nClone );
|
---|
1080 | aCloned.push( aoOriginal[i][j].cell );
|
---|
1081 |
|
---|
1082 | aRow.push( {
|
---|
1083 | "cell": nClone,
|
---|
1084 | "unique": aoOriginal[i][j].unique
|
---|
1085 | } );
|
---|
1086 | }
|
---|
1087 | else
|
---|
1088 | {
|
---|
1089 | aRow.push( {
|
---|
1090 | "cell": aClones[ iCloned ],
|
---|
1091 | "unique": aoOriginal[i][j].unique
|
---|
1092 | } );
|
---|
1093 | }
|
---|
1094 | }
|
---|
1095 |
|
---|
1096 | aReturn.push( aRow );
|
---|
1097 | }
|
---|
1098 |
|
---|
1099 | return aReturn;
|
---|
1100 | },
|
---|
1101 |
|
---|
1102 |
|
---|
1103 | /**
|
---|
1104 | * Clone the DataTable nodes and place them in the DOM (sized correctly)
|
---|
1105 | * @returns {void}
|
---|
1106 | * @param {Object} oClone Object containing the header, footer and body cloned DOM elements
|
---|
1107 | * @param {Object} oGrid Grid object containing the display grid elements for the cloned
|
---|
1108 | * column (left or right)
|
---|
1109 | * @param {Array} aiColumns Column indexes which should be operated on from the DataTable
|
---|
1110 | * @param {Boolean} bAll Indicate if the header and footer should be updated as well (true)
|
---|
1111 | * @private
|
---|
1112 | */
|
---|
1113 | "_fnClone": function ( oClone, oGrid, aiColumns, bAll )
|
---|
1114 | {
|
---|
1115 | var that = this,
|
---|
1116 | i, iLen, j, jLen, jq, nTarget, iColumn, nClone, iIndex, aoCloneLayout,
|
---|
1117 | jqCloneThead, aoFixedHeader,
|
---|
1118 | dt = this.s.dt;
|
---|
1119 |
|
---|
1120 | /*
|
---|
1121 | * Header
|
---|
1122 | */
|
---|
1123 | if ( bAll )
|
---|
1124 | {
|
---|
1125 | $(oClone.header).remove();
|
---|
1126 |
|
---|
1127 | oClone.header = $(this.dom.header).clone(true, false)[0];
|
---|
1128 | oClone.header.className += " DTFC_Cloned";
|
---|
1129 | oClone.header.style.width = "100%";
|
---|
1130 | oGrid.head.appendChild( oClone.header );
|
---|
1131 |
|
---|
1132 | /* Copy the DataTables layout cache for the header for our floating column */
|
---|
1133 | aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, true );
|
---|
1134 | jqCloneThead = $('>thead', oClone.header);
|
---|
1135 | jqCloneThead.empty();
|
---|
1136 |
|
---|
1137 | /* Add the created cloned TR elements to the table */
|
---|
1138 | for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
|
---|
1139 | {
|
---|
1140 | jqCloneThead[0].appendChild( aoCloneLayout[i].nTr );
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | /* Use the handy _fnDrawHead function in DataTables to do the rowspan/colspan
|
---|
1144 | * calculations for us
|
---|
1145 | */
|
---|
1146 | dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
|
---|
1147 | }
|
---|
1148 | else
|
---|
1149 | {
|
---|
1150 | /* To ensure that we copy cell classes exactly, regardless of colspan, multiple rows
|
---|
1151 | * etc, we make a copy of the header from the DataTable again, but don't insert the
|
---|
1152 | * cloned cells, just copy the classes across. To get the matching layout for the
|
---|
1153 | * fixed component, we use the DataTables _fnDetectHeader method, allowing 1:1 mapping
|
---|
1154 | */
|
---|
1155 | aoCloneLayout = this._fnCopyLayout( dt.aoHeader, aiColumns, false );
|
---|
1156 | aoFixedHeader=[];
|
---|
1157 |
|
---|
1158 | dt.oApi._fnDetectHeader( aoFixedHeader, $('>thead', oClone.header)[0] );
|
---|
1159 |
|
---|
1160 | for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
|
---|
1161 | {
|
---|
1162 | for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
|
---|
1163 | {
|
---|
1164 | aoFixedHeader[i][j].cell.className = aoCloneLayout[i][j].cell.className;
|
---|
1165 |
|
---|
1166 | // If jQuery UI theming is used we need to copy those elements as well
|
---|
1167 | $('span.DataTables_sort_icon', aoFixedHeader[i][j].cell).each( function () {
|
---|
1168 | this.className = $('span.DataTables_sort_icon', aoCloneLayout[i][j].cell)[0].className;
|
---|
1169 | } );
|
---|
1170 | }
|
---|
1171 | }
|
---|
1172 | }
|
---|
1173 | this._fnEqualiseHeights( 'thead', this.dom.header, oClone.header );
|
---|
1174 |
|
---|
1175 | /*
|
---|
1176 | * Body
|
---|
1177 | */
|
---|
1178 | if ( this.s.sHeightMatch == 'auto' )
|
---|
1179 | {
|
---|
1180 | /* Remove any heights which have been applied already and let the browser figure it out */
|
---|
1181 | $('>tbody>tr', that.dom.body).css('height', 'auto');
|
---|
1182 | }
|
---|
1183 |
|
---|
1184 | if ( oClone.body !== null )
|
---|
1185 | {
|
---|
1186 | $(oClone.body).remove();
|
---|
1187 | oClone.body = null;
|
---|
1188 | }
|
---|
1189 |
|
---|
1190 | oClone.body = $(this.dom.body).clone(true)[0];
|
---|
1191 | oClone.body.className += " DTFC_Cloned";
|
---|
1192 | oClone.body.style.paddingBottom = dt.oScroll.iBarWidth+"px";
|
---|
1193 | oClone.body.style.marginBottom = (dt.oScroll.iBarWidth*2)+"px"; /* For IE */
|
---|
1194 | if ( oClone.body.getAttribute('id') !== null )
|
---|
1195 | {
|
---|
1196 | oClone.body.removeAttribute('id');
|
---|
1197 | }
|
---|
1198 |
|
---|
1199 | $('>thead>tr', oClone.body).empty();
|
---|
1200 | $('>tfoot', oClone.body).remove();
|
---|
1201 |
|
---|
1202 | var nBody = $('tbody', oClone.body)[0];
|
---|
1203 | $(nBody).empty();
|
---|
1204 | if ( dt.aiDisplay.length > 0 )
|
---|
1205 | {
|
---|
1206 | /* Copy the DataTables' header elements to force the column width in exactly the
|
---|
1207 | * same way that DataTables does it - have the header element, apply the width and
|
---|
1208 | * colapse it down
|
---|
1209 | */
|
---|
1210 | var nInnerThead = $('>thead>tr', oClone.body)[0];
|
---|
1211 | for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
|
---|
1212 | {
|
---|
1213 | iColumn = aiColumns[iIndex];
|
---|
1214 |
|
---|
1215 | nClone = $(dt.aoColumns[iColumn].nTh).clone(true)[0];
|
---|
1216 | nClone.innerHTML = "";
|
---|
1217 |
|
---|
1218 | var oStyle = nClone.style;
|
---|
1219 | oStyle.paddingTop = "0";
|
---|
1220 | oStyle.paddingBottom = "0";
|
---|
1221 | oStyle.borderTopWidth = "0";
|
---|
1222 | oStyle.borderBottomWidth = "0";
|
---|
1223 | oStyle.height = 0;
|
---|
1224 | oStyle.width = that.s.aiInnerWidths[iColumn]+"px";
|
---|
1225 |
|
---|
1226 | nInnerThead.appendChild( nClone );
|
---|
1227 | }
|
---|
1228 |
|
---|
1229 | /* Add in the tbody elements, cloning form the master table */
|
---|
1230 | $('>tbody>tr', that.dom.body).each( function (z) {
|
---|
1231 | var i = that.s.dt.oFeatures.bServerSide===false ?
|
---|
1232 | that.s.dt.aiDisplay[ that.s.dt._iDisplayStart+z ] : z;
|
---|
1233 | var aTds = that.s.dt.aoData[ i ].anCells || $(this).children('td, th');
|
---|
1234 |
|
---|
1235 | var n = this.cloneNode(false);
|
---|
1236 | n.removeAttribute('id');
|
---|
1237 | n.setAttribute( 'data-dt-row', i );
|
---|
1238 |
|
---|
1239 | for ( iIndex=0 ; iIndex<aiColumns.length ; iIndex++ )
|
---|
1240 | {
|
---|
1241 | iColumn = aiColumns[iIndex];
|
---|
1242 |
|
---|
1243 | if ( aTds.length > 0 )
|
---|
1244 | {
|
---|
1245 | nClone = $( aTds[iColumn] ).clone(true, true)[0];
|
---|
1246 | nClone.removeAttribute( 'id' );
|
---|
1247 | nClone.setAttribute( 'data-dt-row', i );
|
---|
1248 | nClone.setAttribute( 'data-dt-column', iColumn );
|
---|
1249 | n.appendChild( nClone );
|
---|
1250 | }
|
---|
1251 | }
|
---|
1252 | nBody.appendChild( n );
|
---|
1253 | } );
|
---|
1254 | }
|
---|
1255 | else
|
---|
1256 | {
|
---|
1257 | $('>tbody>tr', that.dom.body).each( function (z) {
|
---|
1258 | nClone = this.cloneNode(true);
|
---|
1259 | nClone.className += ' DTFC_NoData';
|
---|
1260 | $('td', nClone).html('');
|
---|
1261 | nBody.appendChild( nClone );
|
---|
1262 | } );
|
---|
1263 | }
|
---|
1264 |
|
---|
1265 | oClone.body.style.width = "100%";
|
---|
1266 | oClone.body.style.margin = "0";
|
---|
1267 | oClone.body.style.padding = "0";
|
---|
1268 |
|
---|
1269 | // Interop with Scroller - need to use a height forcing element in the
|
---|
1270 | // scrolling area in the same way that Scroller does in the body scroll.
|
---|
1271 | if ( dt.oScroller !== undefined )
|
---|
1272 | {
|
---|
1273 | var scrollerForcer = dt.oScroller.dom.force;
|
---|
1274 |
|
---|
1275 | if ( ! oGrid.forcer ) {
|
---|
1276 | oGrid.forcer = scrollerForcer.cloneNode( true );
|
---|
1277 | oGrid.liner.appendChild( oGrid.forcer );
|
---|
1278 | }
|
---|
1279 | else {
|
---|
1280 | oGrid.forcer.style.height = scrollerForcer.style.height;
|
---|
1281 | }
|
---|
1282 | }
|
---|
1283 |
|
---|
1284 | oGrid.liner.appendChild( oClone.body );
|
---|
1285 |
|
---|
1286 | this._fnEqualiseHeights( 'tbody', that.dom.body, oClone.body );
|
---|
1287 |
|
---|
1288 | /*
|
---|
1289 | * Footer
|
---|
1290 | */
|
---|
1291 | if ( dt.nTFoot !== null )
|
---|
1292 | {
|
---|
1293 | if ( bAll )
|
---|
1294 | {
|
---|
1295 | if ( oClone.footer !== null )
|
---|
1296 | {
|
---|
1297 | oClone.footer.parentNode.removeChild( oClone.footer );
|
---|
1298 | }
|
---|
1299 | oClone.footer = $(this.dom.footer).clone(true, true)[0];
|
---|
1300 | oClone.footer.className += " DTFC_Cloned";
|
---|
1301 | oClone.footer.style.width = "100%";
|
---|
1302 | oGrid.foot.appendChild( oClone.footer );
|
---|
1303 |
|
---|
1304 | /* Copy the footer just like we do for the header */
|
---|
1305 | aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, true );
|
---|
1306 | var jqCloneTfoot = $('>tfoot', oClone.footer);
|
---|
1307 | jqCloneTfoot.empty();
|
---|
1308 |
|
---|
1309 | for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
|
---|
1310 | {
|
---|
1311 | jqCloneTfoot[0].appendChild( aoCloneLayout[i].nTr );
|
---|
1312 | }
|
---|
1313 | dt.oApi._fnDrawHead( dt, aoCloneLayout, true );
|
---|
1314 | }
|
---|
1315 | else
|
---|
1316 | {
|
---|
1317 | aoCloneLayout = this._fnCopyLayout( dt.aoFooter, aiColumns, false );
|
---|
1318 | var aoCurrFooter=[];
|
---|
1319 |
|
---|
1320 | dt.oApi._fnDetectHeader( aoCurrFooter, $('>tfoot', oClone.footer)[0] );
|
---|
1321 |
|
---|
1322 | for ( i=0, iLen=aoCloneLayout.length ; i<iLen ; i++ )
|
---|
1323 | {
|
---|
1324 | for ( j=0, jLen=aoCloneLayout[i].length ; j<jLen ; j++ )
|
---|
1325 | {
|
---|
1326 | aoCurrFooter[i][j].cell.className = aoCloneLayout[i][j].cell.className;
|
---|
1327 | }
|
---|
1328 | }
|
---|
1329 | }
|
---|
1330 | this._fnEqualiseHeights( 'tfoot', this.dom.footer, oClone.footer );
|
---|
1331 | }
|
---|
1332 |
|
---|
1333 | /* Equalise the column widths between the header footer and body - body get's priority */
|
---|
1334 | var anUnique = dt.oApi._fnGetUniqueThs( dt, $('>thead', oClone.header)[0] );
|
---|
1335 | $(anUnique).each( function (i) {
|
---|
1336 | iColumn = aiColumns[i];
|
---|
1337 | this.style.width = that.s.aiInnerWidths[iColumn]+"px";
|
---|
1338 | } );
|
---|
1339 |
|
---|
1340 | if ( that.s.dt.nTFoot !== null )
|
---|
1341 | {
|
---|
1342 | anUnique = dt.oApi._fnGetUniqueThs( dt, $('>tfoot', oClone.footer)[0] );
|
---|
1343 | $(anUnique).each( function (i) {
|
---|
1344 | iColumn = aiColumns[i];
|
---|
1345 | this.style.width = that.s.aiInnerWidths[iColumn]+"px";
|
---|
1346 | } );
|
---|
1347 | }
|
---|
1348 | },
|
---|
1349 |
|
---|
1350 |
|
---|
1351 | /**
|
---|
1352 | * From a given table node (THEAD etc), get a list of TR direct child elements
|
---|
1353 | * @param {Node} nIn Table element to search for TR elements (THEAD, TBODY or TFOOT element)
|
---|
1354 | * @returns {Array} List of TR elements found
|
---|
1355 | * @private
|
---|
1356 | */
|
---|
1357 | "_fnGetTrNodes": function ( nIn )
|
---|
1358 | {
|
---|
1359 | var aOut = [];
|
---|
1360 | for ( var i=0, iLen=nIn.childNodes.length ; i<iLen ; i++ )
|
---|
1361 | {
|
---|
1362 | if ( nIn.childNodes[i].nodeName.toUpperCase() == "TR" )
|
---|
1363 | {
|
---|
1364 | aOut.push( nIn.childNodes[i] );
|
---|
1365 | }
|
---|
1366 | }
|
---|
1367 | return aOut;
|
---|
1368 | },
|
---|
1369 |
|
---|
1370 |
|
---|
1371 | /**
|
---|
1372 | * Equalise the heights of the rows in a given table node in a cross browser way
|
---|
1373 | * @returns {void}
|
---|
1374 | * @param {String} nodeName Node type - thead, tbody or tfoot
|
---|
1375 | * @param {Node} original Original node to take the heights from
|
---|
1376 | * @param {Node} clone Copy the heights to
|
---|
1377 | * @private
|
---|
1378 | */
|
---|
1379 | "_fnEqualiseHeights": function ( nodeName, original, clone )
|
---|
1380 | {
|
---|
1381 | if ( this.s.sHeightMatch == 'none' && nodeName !== 'thead' && nodeName !== 'tfoot' )
|
---|
1382 | {
|
---|
1383 | return;
|
---|
1384 | }
|
---|
1385 |
|
---|
1386 | var that = this,
|
---|
1387 | i, iLen, iHeight, iHeight2, iHeightOriginal, iHeightClone,
|
---|
1388 | rootOriginal = original.getElementsByTagName(nodeName)[0],
|
---|
1389 | rootClone = clone.getElementsByTagName(nodeName)[0],
|
---|
1390 | jqBoxHack = $('>'+nodeName+'>tr:eq(0)', original).children(':first'),
|
---|
1391 | iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(),
|
---|
1392 | anOriginal = this._fnGetTrNodes( rootOriginal ),
|
---|
1393 | anClone = this._fnGetTrNodes( rootClone ),
|
---|
1394 | heights = [];
|
---|
1395 |
|
---|
1396 | for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
|
---|
1397 | {
|
---|
1398 | iHeightOriginal = anOriginal[i].offsetHeight;
|
---|
1399 | iHeightClone = anClone[i].offsetHeight;
|
---|
1400 | iHeight = iHeightClone > iHeightOriginal ? iHeightClone : iHeightOriginal;
|
---|
1401 |
|
---|
1402 | if ( this.s.sHeightMatch == 'semiauto' )
|
---|
1403 | {
|
---|
1404 | anOriginal[i]._DTTC_iHeight = iHeight;
|
---|
1405 | }
|
---|
1406 |
|
---|
1407 | heights.push( iHeight );
|
---|
1408 | }
|
---|
1409 |
|
---|
1410 | for ( i=0, iLen=anClone.length ; i<iLen ; i++ )
|
---|
1411 | {
|
---|
1412 | anClone[i].style.height = heights[i]+"px";
|
---|
1413 | anOriginal[i].style.height = heights[i]+"px";
|
---|
1414 | }
|
---|
1415 | },
|
---|
1416 |
|
---|
1417 | /**
|
---|
1418 | * Determine if the UA suffers from Firefox's overflow:scroll scrollbars
|
---|
1419 | * not being shown bug.
|
---|
1420 | *
|
---|
1421 | * Firefox doesn't draw scrollbars, even if it is told to using
|
---|
1422 | * overflow:scroll, if the div is less than 34px height. See bugs 292284 and
|
---|
1423 | * 781885. Using UA detection here since this is particularly hard to detect
|
---|
1424 | * using objects - its a straight up rendering error in Firefox.
|
---|
1425 | *
|
---|
1426 | * @return {boolean} True if Firefox error is present, false otherwise
|
---|
1427 | */
|
---|
1428 | _firefoxScrollError: function () {
|
---|
1429 | if ( _firefoxScroll === undefined ) {
|
---|
1430 | var test = $('<div/>')
|
---|
1431 | .css( {
|
---|
1432 | position: 'absolute',
|
---|
1433 | top: 0,
|
---|
1434 | left: 0,
|
---|
1435 | height: 10,
|
---|
1436 | width: 50,
|
---|
1437 | overflow: 'scroll'
|
---|
1438 | } )
|
---|
1439 | .appendTo( 'body' );
|
---|
1440 |
|
---|
1441 | // Make sure this doesn't apply on Macs with 0 width scrollbars
|
---|
1442 | _firefoxScroll = (
|
---|
1443 | test[0].clientWidth === test[0].offsetWidth && this._fnDTOverflow().bar !== 0
|
---|
1444 | );
|
---|
1445 |
|
---|
1446 | test.remove();
|
---|
1447 | }
|
---|
1448 |
|
---|
1449 | return _firefoxScroll;
|
---|
1450 | }
|
---|
1451 | } );
|
---|
1452 |
|
---|
1453 |
|
---|
1454 |
|
---|
1455 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
1456 | * Statics
|
---|
1457 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
---|
1458 |
|
---|
1459 | /**
|
---|
1460 | * FixedColumns default settings for initialisation
|
---|
1461 | * @name FixedColumns.defaults
|
---|
1462 | * @namespace
|
---|
1463 | * @static
|
---|
1464 | */
|
---|
1465 | FixedColumns.defaults = /** @lends FixedColumns.defaults */{
|
---|
1466 | /**
|
---|
1467 | * Number of left hand columns to fix in position
|
---|
1468 | * @type int
|
---|
1469 | * @default 1
|
---|
1470 | * @static
|
---|
1471 | * @example
|
---|
1472 | * var = $('#example').dataTable( {
|
---|
1473 | * "scrollX": "100%"
|
---|
1474 | * } );
|
---|
1475 | * new $.fn.dataTable.fixedColumns( table, {
|
---|
1476 | * "leftColumns": 2
|
---|
1477 | * } );
|
---|
1478 | */
|
---|
1479 | "iLeftColumns": 1,
|
---|
1480 |
|
---|
1481 | /**
|
---|
1482 | * Number of right hand columns to fix in position
|
---|
1483 | * @type int
|
---|
1484 | * @default 0
|
---|
1485 | * @static
|
---|
1486 | * @example
|
---|
1487 | * var table = $('#example').dataTable( {
|
---|
1488 | * "scrollX": "100%"
|
---|
1489 | * } );
|
---|
1490 | * new $.fn.dataTable.fixedColumns( table, {
|
---|
1491 | * "rightColumns": 1
|
---|
1492 | * } );
|
---|
1493 | */
|
---|
1494 | "iRightColumns": 0,
|
---|
1495 |
|
---|
1496 | /**
|
---|
1497 | * Draw callback function which is called when FixedColumns has redrawn the fixed assets
|
---|
1498 | * @type function(object, object):void
|
---|
1499 | * @default null
|
---|
1500 | * @static
|
---|
1501 | * @example
|
---|
1502 | * var table = $('#example').dataTable( {
|
---|
1503 | * "scrollX": "100%"
|
---|
1504 | * } );
|
---|
1505 | * new $.fn.dataTable.fixedColumns( table, {
|
---|
1506 | * "drawCallback": function () {
|
---|
1507 | * alert( "FixedColumns redraw" );
|
---|
1508 | * }
|
---|
1509 | * } );
|
---|
1510 | */
|
---|
1511 | "fnDrawCallback": null,
|
---|
1512 |
|
---|
1513 | /**
|
---|
1514 | * Height matching algorthim to use. This can be "none" which will result in no height
|
---|
1515 | * matching being applied by FixedColumns (height matching could be forced by CSS in this
|
---|
1516 | * case), "semiauto" whereby the height calculation will be performed once, and the result
|
---|
1517 | * cached to be used again (fnRecalculateHeight can be used to force recalculation), or
|
---|
1518 | * "auto" when height matching is performed on every draw (slowest but must accurate)
|
---|
1519 | * @type string
|
---|
1520 | * @default semiauto
|
---|
1521 | * @static
|
---|
1522 | * @example
|
---|
1523 | * var table = $('#example').dataTable( {
|
---|
1524 | * "scrollX": "100%"
|
---|
1525 | * } );
|
---|
1526 | * new $.fn.dataTable.fixedColumns( table, {
|
---|
1527 | * "heightMatch": "auto"
|
---|
1528 | * } );
|
---|
1529 | */
|
---|
1530 | "sHeightMatch": "semiauto"
|
---|
1531 | };
|
---|
1532 |
|
---|
1533 |
|
---|
1534 |
|
---|
1535 |
|
---|
1536 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
1537 | * Constants
|
---|
1538 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
---|
1539 |
|
---|
1540 | /**
|
---|
1541 | * FixedColumns version
|
---|
1542 | * @name FixedColumns.version
|
---|
1543 | * @type String
|
---|
1544 | * @default See code
|
---|
1545 | * @static
|
---|
1546 | */
|
---|
1547 | FixedColumns.version = "3.3.0";
|
---|
1548 |
|
---|
1549 |
|
---|
1550 |
|
---|
1551 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
1552 | * DataTables API integration
|
---|
1553 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
---|
1554 |
|
---|
1555 | DataTable.Api.register( 'fixedColumns()', function () {
|
---|
1556 | return this;
|
---|
1557 | } );
|
---|
1558 |
|
---|
1559 | DataTable.Api.register( 'fixedColumns().update()', function () {
|
---|
1560 | return this.iterator( 'table', function ( ctx ) {
|
---|
1561 | if ( ctx._oFixedColumns ) {
|
---|
1562 | ctx._oFixedColumns.fnUpdate();
|
---|
1563 | }
|
---|
1564 | } );
|
---|
1565 | } );
|
---|
1566 |
|
---|
1567 | DataTable.Api.register( 'fixedColumns().relayout()', function () {
|
---|
1568 | return this.iterator( 'table', function ( ctx ) {
|
---|
1569 | if ( ctx._oFixedColumns ) {
|
---|
1570 | ctx._oFixedColumns.fnRedrawLayout();
|
---|
1571 | }
|
---|
1572 | } );
|
---|
1573 | } );
|
---|
1574 |
|
---|
1575 | DataTable.Api.register( 'rows().recalcHeight()', function () {
|
---|
1576 | return this.iterator( 'row', function ( ctx, idx ) {
|
---|
1577 | if ( ctx._oFixedColumns ) {
|
---|
1578 | ctx._oFixedColumns.fnRecalculateHeight( this.row(idx).node() );
|
---|
1579 | }
|
---|
1580 | } );
|
---|
1581 | } );
|
---|
1582 |
|
---|
1583 | DataTable.Api.register( 'fixedColumns().rowIndex()', function ( row ) {
|
---|
1584 | row = $(row);
|
---|
1585 |
|
---|
1586 | return row.parents('.DTFC_Cloned').length ?
|
---|
1587 | this.rows( { page: 'current' } ).indexes()[ row.index() ] :
|
---|
1588 | this.row( row ).index();
|
---|
1589 | } );
|
---|
1590 |
|
---|
1591 | DataTable.Api.register( 'fixedColumns().cellIndex()', function ( cell ) {
|
---|
1592 | cell = $(cell);
|
---|
1593 |
|
---|
1594 | if ( cell.parents('.DTFC_Cloned').length ) {
|
---|
1595 | var rowClonedIdx = cell.parent().index();
|
---|
1596 | var rowIdx = this.rows( { page: 'current' } ).indexes()[ rowClonedIdx ];
|
---|
1597 | var columnIdx;
|
---|
1598 |
|
---|
1599 | if ( cell.parents('.DTFC_LeftWrapper').length ) {
|
---|
1600 | columnIdx = cell.index();
|
---|
1601 | }
|
---|
1602 | else {
|
---|
1603 | var columns = this.columns().flatten().length;
|
---|
1604 | columnIdx = columns - this.context[0]._oFixedColumns.s.iRightColumns + cell.index();
|
---|
1605 | }
|
---|
1606 |
|
---|
1607 | return {
|
---|
1608 | row: rowIdx,
|
---|
1609 | column: this.column.index( 'toData', columnIdx ),
|
---|
1610 | columnVisible: columnIdx
|
---|
1611 | };
|
---|
1612 | }
|
---|
1613 | else {
|
---|
1614 | return this.cell( cell ).index();
|
---|
1615 | }
|
---|
1616 | } );
|
---|
1617 |
|
---|
1618 | DataTable.Api.registerPlural( 'cells().fixedNodes()', 'cell().fixedNode()', function () {
|
---|
1619 | return this.iterator( 'cell', function ( settings, row, column ) {
|
---|
1620 | return settings._oFixedColumns
|
---|
1621 | ? settings._oFixedColumns.fnToFixedNode( row, column )
|
---|
1622 | : this.node();
|
---|
1623 | }, 1 );
|
---|
1624 | } );
|
---|
1625 |
|
---|
1626 |
|
---|
1627 |
|
---|
1628 |
|
---|
1629 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
---|
1630 | * Initialisation
|
---|
1631 | * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
---|
1632 |
|
---|
1633 | // Attach a listener to the document which listens for DataTables initialisation
|
---|
1634 | // events so we can automatically initialise
|
---|
1635 | $(document).on( 'init.dt.fixedColumns', function (e, settings) {
|
---|
1636 | if ( e.namespace !== 'dt' ) {
|
---|
1637 | return;
|
---|
1638 | }
|
---|
1639 |
|
---|
1640 | var init = settings.oInit.fixedColumns;
|
---|
1641 | var defaults = DataTable.defaults.fixedColumns;
|
---|
1642 |
|
---|
1643 | if ( init || defaults ) {
|
---|
1644 | var opts = $.extend( {}, init, defaults );
|
---|
1645 |
|
---|
1646 | if ( init !== false ) {
|
---|
1647 | new FixedColumns( settings, opts );
|
---|
1648 | }
|
---|
1649 | }
|
---|
1650 | } );
|
---|
1651 |
|
---|
1652 |
|
---|
1653 |
|
---|
1654 | // Make FixedColumns accessible from the DataTables instance
|
---|
1655 | $.fn.dataTable.FixedColumns = FixedColumns;
|
---|
1656 | $.fn.DataTable.FixedColumns = FixedColumns;
|
---|
1657 |
|
---|
1658 | return FixedColumns;
|
---|
1659 | }));
|
---|