[7304c7f] | 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 | }));
|
---|