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