Mercurial > repos > saskia-hiltemann > ireport_dev
comparison DataTables-1.9.4/extras/FixedHeader/js/FixedHeader.js @ 2:3c160414da2e default tip
initial upload
| author | shiltemann |
|---|---|
| date | Thu, 26 Feb 2015 14:05:23 +0100 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 2:3c160414da2e |
|---|---|
| 1 /* | |
| 2 * File: FixedHeader.js | |
| 3 * Version: 2.0.6 | |
| 4 * Description: "Fix" a header at the top of the table, so it scrolls with the table | |
| 5 * Author: Allan Jardine (www.sprymedia.co.uk) | |
| 6 * Created: Wed 16 Sep 2009 19:46:30 BST | |
| 7 * Language: Javascript | |
| 8 * License: GPL v2 or BSD 3 point style | |
| 9 * Project: Just a little bit of fun - enjoy :-) | |
| 10 * Contact: www.sprymedia.co.uk/contact | |
| 11 * | |
| 12 * Copyright 2009-2012 Allan Jardine, all rights reserved. | |
| 13 * | |
| 14 * This source file is free software, under either the GPL v2 license or a | |
| 15 * BSD style license, available at: | |
| 16 * http://datatables.net/license_gpl2 | |
| 17 * http://datatables.net/license_bsd | |
| 18 */ | |
| 19 | |
| 20 /* | |
| 21 * Function: FixedHeader | |
| 22 * Purpose: Provide 'fixed' header, footer and columns on an HTML table | |
| 23 * Returns: object:FixedHeader - must be called with 'new' | |
| 24 * Inputs: mixed:mTable - target table | |
| 25 * 1. DataTable object - when using FixedHeader with DataTables, or | |
| 26 * 2. HTML table node - when using FixedHeader without DataTables | |
| 27 * object:oInit - initialisation settings, with the following properties (each optional) | |
| 28 * bool:top - fix the header (default true) | |
| 29 * bool:bottom - fix the footer (default false) | |
| 30 * bool:left - fix the left most column (default false) | |
| 31 * bool:right - fix the right most column (default false) | |
| 32 * int:zTop - fixed header zIndex | |
| 33 * int:zBottom - fixed footer zIndex | |
| 34 * int:zLeft - fixed left zIndex | |
| 35 * int:zRight - fixed right zIndex | |
| 36 */ | |
| 37 var FixedHeader = function ( mTable, oInit ) { | |
| 38 /* Sanity check - you just know it will happen */ | |
| 39 if ( typeof this.fnInit != 'function' ) | |
| 40 { | |
| 41 alert( "FixedHeader warning: FixedHeader must be initialised with the 'new' keyword." ); | |
| 42 return; | |
| 43 } | |
| 44 | |
| 45 var that = this; | |
| 46 var oSettings = { | |
| 47 "aoCache": [], | |
| 48 "oSides": { | |
| 49 "top": true, | |
| 50 "bottom": false, | |
| 51 "left": false, | |
| 52 "right": false | |
| 53 }, | |
| 54 "oZIndexes": { | |
| 55 "top": 104, | |
| 56 "bottom": 103, | |
| 57 "left": 102, | |
| 58 "right": 101 | |
| 59 }, | |
| 60 "oMes": { | |
| 61 "iTableWidth": 0, | |
| 62 "iTableHeight": 0, | |
| 63 "iTableLeft": 0, | |
| 64 "iTableRight": 0, /* note this is left+width, not actually "right" */ | |
| 65 "iTableTop": 0, | |
| 66 "iTableBottom": 0 /* note this is top+height, not actually "bottom" */ | |
| 67 }, | |
| 68 "oOffset": { | |
| 69 "top": 0 | |
| 70 }, | |
| 71 "nTable": null, | |
| 72 "bUseAbsPos": false, | |
| 73 "bFooter": false | |
| 74 }; | |
| 75 | |
| 76 /* | |
| 77 * Function: fnGetSettings | |
| 78 * Purpose: Get the settings for this object | |
| 79 * Returns: object: - settings object | |
| 80 * Inputs: - | |
| 81 */ | |
| 82 this.fnGetSettings = function () { | |
| 83 return oSettings; | |
| 84 }; | |
| 85 | |
| 86 /* | |
| 87 * Function: fnUpdate | |
| 88 * Purpose: Update the positioning and copies of the fixed elements | |
| 89 * Returns: - | |
| 90 * Inputs: - | |
| 91 */ | |
| 92 this.fnUpdate = function () { | |
| 93 this._fnUpdateClones(); | |
| 94 this._fnUpdatePositions(); | |
| 95 }; | |
| 96 | |
| 97 /* | |
| 98 * Function: fnPosition | |
| 99 * Purpose: Update the positioning of the fixed elements | |
| 100 * Returns: - | |
| 101 * Inputs: - | |
| 102 */ | |
| 103 this.fnPosition = function () { | |
| 104 this._fnUpdatePositions(); | |
| 105 }; | |
| 106 | |
| 107 /* Let's do it */ | |
| 108 this.fnInit( mTable, oInit ); | |
| 109 | |
| 110 /* Store the instance on the DataTables object for easy access */ | |
| 111 if ( typeof mTable.fnSettings == 'function' ) | |
| 112 { | |
| 113 mTable._oPluginFixedHeader = this; | |
| 114 } | |
| 115 }; | |
| 116 | |
| 117 | |
| 118 /* | |
| 119 * Variable: FixedHeader | |
| 120 * Purpose: Prototype for FixedHeader | |
| 121 * Scope: global | |
| 122 */ | |
| 123 FixedHeader.prototype = { | |
| 124 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 125 * Initialisation | |
| 126 */ | |
| 127 | |
| 128 /* | |
| 129 * Function: fnInit | |
| 130 * Purpose: The "constructor" | |
| 131 * Returns: - | |
| 132 * Inputs: {as FixedHeader function} | |
| 133 */ | |
| 134 fnInit: function ( oTable, oInit ) | |
| 135 { | |
| 136 var s = this.fnGetSettings(); | |
| 137 var that = this; | |
| 138 | |
| 139 /* Record the user definable settings */ | |
| 140 this.fnInitSettings( s, oInit ); | |
| 141 | |
| 142 /* DataTables specific stuff */ | |
| 143 if ( typeof oTable.fnSettings == 'function' ) | |
| 144 { | |
| 145 if ( typeof oTable.fnVersionCheck == 'functon' && | |
| 146 oTable.fnVersionCheck( '1.6.0' ) !== true ) | |
| 147 { | |
| 148 alert( "FixedHeader 2 required DataTables 1.6.0 or later. "+ | |
| 149 "Please upgrade your DataTables installation" ); | |
| 150 return; | |
| 151 } | |
| 152 | |
| 153 var oDtSettings = oTable.fnSettings(); | |
| 154 | |
| 155 if ( oDtSettings.oScroll.sX != "" || oDtSettings.oScroll.sY != "" ) | |
| 156 { | |
| 157 alert( "FixedHeader 2 is not supported with DataTables' scrolling mode at this time" ); | |
| 158 return; | |
| 159 } | |
| 160 | |
| 161 s.nTable = oDtSettings.nTable; | |
| 162 oDtSettings.aoDrawCallback.push( { | |
| 163 "fn": function () { | |
| 164 FixedHeader.fnMeasure(); | |
| 165 that._fnUpdateClones.call(that); | |
| 166 that._fnUpdatePositions.call(that); | |
| 167 }, | |
| 168 "sName": "FixedHeader" | |
| 169 } ); | |
| 170 } | |
| 171 else | |
| 172 { | |
| 173 s.nTable = oTable; | |
| 174 } | |
| 175 | |
| 176 s.bFooter = ($('>tfoot', s.nTable).length > 0) ? true : false; | |
| 177 | |
| 178 /* "Detect" browsers that don't support absolute positioing - or have bugs */ | |
| 179 s.bUseAbsPos = (jQuery.browser.msie && (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0")); | |
| 180 | |
| 181 /* Add the 'sides' that are fixed */ | |
| 182 if ( s.oSides.top ) | |
| 183 { | |
| 184 s.aoCache.push( that._fnCloneTable( "fixedHeader", "FixedHeader_Header", that._fnCloneThead ) ); | |
| 185 } | |
| 186 if ( s.oSides.bottom ) | |
| 187 { | |
| 188 s.aoCache.push( that._fnCloneTable( "fixedFooter", "FixedHeader_Footer", that._fnCloneTfoot ) ); | |
| 189 } | |
| 190 if ( s.oSides.left ) | |
| 191 { | |
| 192 s.aoCache.push( that._fnCloneTable( "fixedLeft", "FixedHeader_Left", that._fnCloneTLeft ) ); | |
| 193 } | |
| 194 if ( s.oSides.right ) | |
| 195 { | |
| 196 s.aoCache.push( that._fnCloneTable( "fixedRight", "FixedHeader_Right", that._fnCloneTRight ) ); | |
| 197 } | |
| 198 | |
| 199 /* Event listeners for window movement */ | |
| 200 FixedHeader.afnScroll.push( function () { | |
| 201 that._fnUpdatePositions.call(that); | |
| 202 } ); | |
| 203 | |
| 204 jQuery(window).resize( function () { | |
| 205 FixedHeader.fnMeasure(); | |
| 206 that._fnUpdateClones.call(that); | |
| 207 that._fnUpdatePositions.call(that); | |
| 208 } ); | |
| 209 | |
| 210 /* Get things right to start with */ | |
| 211 FixedHeader.fnMeasure(); | |
| 212 that._fnUpdateClones(); | |
| 213 that._fnUpdatePositions(); | |
| 214 }, | |
| 215 | |
| 216 | |
| 217 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 218 * Support functions | |
| 219 */ | |
| 220 | |
| 221 /* | |
| 222 * Function: fnInitSettings | |
| 223 * Purpose: Take the user's settings and copy them to our local store | |
| 224 * Returns: - | |
| 225 * Inputs: object:s - the local settings object | |
| 226 * object:oInit - the user's settings object | |
| 227 */ | |
| 228 fnInitSettings: function ( s, oInit ) | |
| 229 { | |
| 230 if ( typeof oInit != 'undefined' ) | |
| 231 { | |
| 232 if ( typeof oInit.top != 'undefined' ) { | |
| 233 s.oSides.top = oInit.top; | |
| 234 } | |
| 235 if ( typeof oInit.bottom != 'undefined' ) { | |
| 236 s.oSides.bottom = oInit.bottom; | |
| 237 } | |
| 238 if ( typeof oInit.left != 'undefined' ) { | |
| 239 s.oSides.left = oInit.left; | |
| 240 } | |
| 241 if ( typeof oInit.right != 'undefined' ) { | |
| 242 s.oSides.right = oInit.right; | |
| 243 } | |
| 244 | |
| 245 if ( typeof oInit.zTop != 'undefined' ) { | |
| 246 s.oZIndexes.top = oInit.zTop; | |
| 247 } | |
| 248 if ( typeof oInit.zBottom != 'undefined' ) { | |
| 249 s.oZIndexes.bottom = oInit.zBottom; | |
| 250 } | |
| 251 if ( typeof oInit.zLeft != 'undefined' ) { | |
| 252 s.oZIndexes.left = oInit.zLeft; | |
| 253 } | |
| 254 if ( typeof oInit.zRight != 'undefined' ) { | |
| 255 s.oZIndexes.right = oInit.zRight; | |
| 256 } | |
| 257 | |
| 258 if ( typeof oInit.offsetTop != 'undefined' ) { | |
| 259 s.oOffset.top = oInit.offsetTop; | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 /* Detect browsers which have poor position:fixed support so we can use absolute positions. | |
| 264 * This is much slower since the position must be updated for each scroll, but widens | |
| 265 * compatibility | |
| 266 */ | |
| 267 s.bUseAbsPos = (jQuery.browser.msie && | |
| 268 (jQuery.browser.version=="6.0"||jQuery.browser.version=="7.0")); | |
| 269 }, | |
| 270 | |
| 271 /* | |
| 272 * Function: _fnCloneTable | |
| 273 * Purpose: Clone the table node and do basic initialisation | |
| 274 * Returns: - | |
| 275 * Inputs: - | |
| 276 */ | |
| 277 _fnCloneTable: function ( sType, sClass, fnClone ) | |
| 278 { | |
| 279 var s = this.fnGetSettings(); | |
| 280 var nCTable; | |
| 281 | |
| 282 /* We know that the table _MUST_ has a DIV wrapped around it, because this is simply how | |
| 283 * DataTables works. Therefore, we can set this to be relatively position (if it is not | |
| 284 * alreadu absolute, and use this as the base point for the cloned header | |
| 285 */ | |
| 286 if ( jQuery(s.nTable.parentNode).css('position') != "absolute" ) | |
| 287 { | |
| 288 s.nTable.parentNode.style.position = "relative"; | |
| 289 } | |
| 290 | |
| 291 /* Just a shallow clone will do - we only want the table node */ | |
| 292 nCTable = s.nTable.cloneNode( false ); | |
| 293 nCTable.removeAttribute( 'id' ); | |
| 294 | |
| 295 var nDiv = document.createElement( 'div' ); | |
| 296 nDiv.style.position = "absolute"; | |
| 297 nDiv.style.top = "0px"; | |
| 298 nDiv.style.left = "0px"; | |
| 299 nDiv.className += " FixedHeader_Cloned "+sType+" "+sClass; | |
| 300 | |
| 301 /* Set the zIndexes */ | |
| 302 if ( sType == "fixedHeader" ) | |
| 303 { | |
| 304 nDiv.style.zIndex = s.oZIndexes.top; | |
| 305 } | |
| 306 if ( sType == "fixedFooter" ) | |
| 307 { | |
| 308 nDiv.style.zIndex = s.oZIndexes.bottom; | |
| 309 } | |
| 310 if ( sType == "fixedLeft" ) | |
| 311 { | |
| 312 nDiv.style.zIndex = s.oZIndexes.left; | |
| 313 } | |
| 314 else if ( sType == "fixedRight" ) | |
| 315 { | |
| 316 nDiv.style.zIndex = s.oZIndexes.right; | |
| 317 } | |
| 318 | |
| 319 /* remove margins since we are going to poistion it absolutely */ | |
| 320 nCTable.style.margin = "0"; | |
| 321 | |
| 322 /* Insert the newly cloned table into the DOM, on top of the "real" header */ | |
| 323 nDiv.appendChild( nCTable ); | |
| 324 document.body.appendChild( nDiv ); | |
| 325 | |
| 326 return { | |
| 327 "nNode": nCTable, | |
| 328 "nWrapper": nDiv, | |
| 329 "sType": sType, | |
| 330 "sPosition": "", | |
| 331 "sTop": "", | |
| 332 "sLeft": "", | |
| 333 "fnClone": fnClone | |
| 334 }; | |
| 335 }, | |
| 336 | |
| 337 /* | |
| 338 * Function: _fnUpdatePositions | |
| 339 * Purpose: Get the current positioning of the table in the DOM | |
| 340 * Returns: - | |
| 341 * Inputs: - | |
| 342 */ | |
| 343 _fnMeasure: function () | |
| 344 { | |
| 345 var | |
| 346 s = this.fnGetSettings(), | |
| 347 m = s.oMes, | |
| 348 jqTable = jQuery(s.nTable), | |
| 349 oOffset = jqTable.offset(), | |
| 350 iParentScrollTop = this._fnSumScroll( s.nTable.parentNode, 'scrollTop' ), | |
| 351 iParentScrollLeft = this._fnSumScroll( s.nTable.parentNode, 'scrollLeft' ); | |
| 352 | |
| 353 m.iTableWidth = jqTable.outerWidth(); | |
| 354 m.iTableHeight = jqTable.outerHeight(); | |
| 355 m.iTableLeft = oOffset.left + s.nTable.parentNode.scrollLeft; | |
| 356 m.iTableTop = oOffset.top + iParentScrollTop; | |
| 357 m.iTableRight = m.iTableLeft + m.iTableWidth; | |
| 358 m.iTableRight = FixedHeader.oDoc.iWidth - m.iTableLeft - m.iTableWidth; | |
| 359 m.iTableBottom = FixedHeader.oDoc.iHeight - m.iTableTop - m.iTableHeight; | |
| 360 }, | |
| 361 | |
| 362 /* | |
| 363 * Function: _fnSumScroll | |
| 364 * Purpose: Sum node parameters all the way to the top | |
| 365 * Returns: int: sum | |
| 366 * Inputs: node:n - node to consider | |
| 367 * string:side - scrollTop or scrollLeft | |
| 368 */ | |
| 369 _fnSumScroll: function ( n, side ) | |
| 370 { | |
| 371 var i = n[side]; | |
| 372 while ( n = n.parentNode ) | |
| 373 { | |
| 374 if ( n.nodeName == 'HTML' || n.nodeName == 'BODY' ) | |
| 375 { | |
| 376 break; | |
| 377 } | |
| 378 i = n[side]; | |
| 379 } | |
| 380 return i; | |
| 381 }, | |
| 382 | |
| 383 /* | |
| 384 * Function: _fnUpdatePositions | |
| 385 * Purpose: Loop over the fixed elements for this table and update their positions | |
| 386 * Returns: - | |
| 387 * Inputs: - | |
| 388 */ | |
| 389 _fnUpdatePositions: function () | |
| 390 { | |
| 391 var s = this.fnGetSettings(); | |
| 392 this._fnMeasure(); | |
| 393 | |
| 394 for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ ) | |
| 395 { | |
| 396 if ( s.aoCache[i].sType == "fixedHeader" ) | |
| 397 { | |
| 398 this._fnScrollFixedHeader( s.aoCache[i] ); | |
| 399 } | |
| 400 else if ( s.aoCache[i].sType == "fixedFooter" ) | |
| 401 { | |
| 402 this._fnScrollFixedFooter( s.aoCache[i] ); | |
| 403 } | |
| 404 else if ( s.aoCache[i].sType == "fixedLeft" ) | |
| 405 { | |
| 406 this._fnScrollHorizontalLeft( s.aoCache[i] ); | |
| 407 } | |
| 408 else | |
| 409 { | |
| 410 this._fnScrollHorizontalRight( s.aoCache[i] ); | |
| 411 } | |
| 412 } | |
| 413 }, | |
| 414 | |
| 415 /* | |
| 416 * Function: _fnUpdateClones | |
| 417 * Purpose: Loop over the fixed elements for this table and call their cloning functions | |
| 418 * Returns: - | |
| 419 * Inputs: - | |
| 420 */ | |
| 421 _fnUpdateClones: function () | |
| 422 { | |
| 423 var s = this.fnGetSettings(); | |
| 424 for ( var i=0, iLen=s.aoCache.length ; i<iLen ; i++ ) | |
| 425 { | |
| 426 s.aoCache[i].fnClone.call( this, s.aoCache[i] ); | |
| 427 } | |
| 428 }, | |
| 429 | |
| 430 | |
| 431 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 432 * Scrolling functions | |
| 433 */ | |
| 434 | |
| 435 /* | |
| 436 * Function: _fnScrollHorizontalLeft | |
| 437 * Purpose: Update the positioning of the scrolling elements | |
| 438 * Returns: - | |
| 439 * Inputs: object:oCache - the cahced values for this fixed element | |
| 440 */ | |
| 441 _fnScrollHorizontalRight: function ( oCache ) | |
| 442 { | |
| 443 var | |
| 444 s = this.fnGetSettings(), | |
| 445 oMes = s.oMes, | |
| 446 oWin = FixedHeader.oWin, | |
| 447 oDoc = FixedHeader.oDoc, | |
| 448 nTable = oCache.nWrapper, | |
| 449 iFixedWidth = jQuery(nTable).outerWidth(); | |
| 450 | |
| 451 if ( oWin.iScrollRight < oMes.iTableRight ) | |
| 452 { | |
| 453 /* Fully right aligned */ | |
| 454 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 455 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); | |
| 456 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iFixedWidth)+"px", 'left', nTable.style ); | |
| 457 } | |
| 458 else if ( oMes.iTableLeft < oDoc.iWidth-oWin.iScrollRight-iFixedWidth ) | |
| 459 { | |
| 460 /* Middle */ | |
| 461 if ( s.bUseAbsPos ) | |
| 462 { | |
| 463 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 464 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); | |
| 465 this._fnUpdateCache( oCache, 'sLeft', (oDoc.iWidth-oWin.iScrollRight-iFixedWidth)+"px", 'left', nTable.style ); | |
| 466 } | |
| 467 else | |
| 468 { | |
| 469 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); | |
| 470 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style ); | |
| 471 this._fnUpdateCache( oCache, 'sLeft', (oWin.iWidth-iFixedWidth)+"px", 'left', nTable.style ); | |
| 472 } | |
| 473 } | |
| 474 else | |
| 475 { | |
| 476 /* Fully left aligned */ | |
| 477 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 478 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); | |
| 479 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 480 } | |
| 481 }, | |
| 482 | |
| 483 /* | |
| 484 * Function: _fnScrollHorizontalLeft | |
| 485 * Purpose: Update the positioning of the scrolling elements | |
| 486 * Returns: - | |
| 487 * Inputs: object:oCache - the cahced values for this fixed element | |
| 488 */ | |
| 489 _fnScrollHorizontalLeft: function ( oCache ) | |
| 490 { | |
| 491 var | |
| 492 s = this.fnGetSettings(), | |
| 493 oMes = s.oMes, | |
| 494 oWin = FixedHeader.oWin, | |
| 495 oDoc = FixedHeader.oDoc, | |
| 496 nTable = oCache.nWrapper, | |
| 497 iCellWidth = jQuery(nTable).outerWidth(); | |
| 498 | |
| 499 if ( oWin.iScrollLeft < oMes.iTableLeft ) | |
| 500 { | |
| 501 /* Fully left align */ | |
| 502 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 503 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); | |
| 504 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 505 } | |
| 506 else if ( oWin.iScrollLeft < oMes.iTableLeft+oMes.iTableWidth-iCellWidth ) | |
| 507 { | |
| 508 /* Middle */ | |
| 509 if ( s.bUseAbsPos ) | |
| 510 { | |
| 511 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 512 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); | |
| 513 this._fnUpdateCache( oCache, 'sLeft', oWin.iScrollLeft+"px", 'left', nTable.style ); | |
| 514 } | |
| 515 else | |
| 516 { | |
| 517 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); | |
| 518 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop-oWin.iScrollTop)+"px", 'top', nTable.style ); | |
| 519 this._fnUpdateCache( oCache, 'sLeft', "0px", 'left', nTable.style ); | |
| 520 } | |
| 521 } | |
| 522 else | |
| 523 { | |
| 524 /* Fully right align */ | |
| 525 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 526 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); | |
| 527 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft+oMes.iTableWidth-iCellWidth)+"px", 'left', nTable.style ); | |
| 528 } | |
| 529 }, | |
| 530 | |
| 531 /* | |
| 532 * Function: _fnScrollFixedFooter | |
| 533 * Purpose: Update the positioning of the scrolling elements | |
| 534 * Returns: - | |
| 535 * Inputs: object:oCache - the cahced values for this fixed element | |
| 536 */ | |
| 537 _fnScrollFixedFooter: function ( oCache ) | |
| 538 { | |
| 539 var | |
| 540 s = this.fnGetSettings(), | |
| 541 oMes = s.oMes, | |
| 542 oWin = FixedHeader.oWin, | |
| 543 oDoc = FixedHeader.oDoc, | |
| 544 nTable = oCache.nWrapper, | |
| 545 iTheadHeight = jQuery("thead", s.nTable).outerHeight(), | |
| 546 iCellHeight = jQuery(nTable).outerHeight(); | |
| 547 | |
| 548 if ( oWin.iScrollBottom < oMes.iTableBottom ) | |
| 549 { | |
| 550 /* Below */ | |
| 551 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 552 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+oMes.iTableHeight-iCellHeight)+"px", 'top', nTable.style ); | |
| 553 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 554 } | |
| 555 else if ( oWin.iScrollBottom < oMes.iTableBottom+oMes.iTableHeight-iCellHeight-iTheadHeight ) | |
| 556 { | |
| 557 /* Middle */ | |
| 558 if ( s.bUseAbsPos ) | |
| 559 { | |
| 560 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); | |
| 561 this._fnUpdateCache( oCache, 'sTop', (oDoc.iHeight-oWin.iScrollBottom-iCellHeight)+"px", 'top', nTable.style ); | |
| 562 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 563 } | |
| 564 else | |
| 565 { | |
| 566 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); | |
| 567 this._fnUpdateCache( oCache, 'sTop', (oWin.iHeight-iCellHeight)+"px", 'top', nTable.style ); | |
| 568 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style ); | |
| 569 } | |
| 570 } | |
| 571 else | |
| 572 { | |
| 573 /* Above */ | |
| 574 this._fnUpdateCache( oCache, 'sPosition', 'absolute', 'position', nTable.style ); | |
| 575 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iCellHeight)+"px", 'top', nTable.style ); | |
| 576 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 577 } | |
| 578 }, | |
| 579 | |
| 580 /* | |
| 581 * Function: _fnScrollFixedHeader | |
| 582 * Purpose: Update the positioning of the scrolling elements | |
| 583 * Returns: - | |
| 584 * Inputs: object:oCache - the cahced values for this fixed element | |
| 585 */ | |
| 586 _fnScrollFixedHeader: function ( oCache ) | |
| 587 { | |
| 588 var | |
| 589 s = this.fnGetSettings(), | |
| 590 oMes = s.oMes, | |
| 591 oWin = FixedHeader.oWin, | |
| 592 oDoc = FixedHeader.oDoc, | |
| 593 nTable = oCache.nWrapper, | |
| 594 iTbodyHeight = 0, | |
| 595 anTbodies = s.nTable.getElementsByTagName('tbody'); | |
| 596 | |
| 597 for (var i = 0; i < anTbodies.length; ++i) { | |
| 598 iTbodyHeight += anTbodies[i].offsetHeight; | |
| 599 } | |
| 600 | |
| 601 if ( oMes.iTableTop > oWin.iScrollTop + s.oOffset.top ) | |
| 602 { | |
| 603 /* Above the table */ | |
| 604 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); | |
| 605 this._fnUpdateCache( oCache, 'sTop', oMes.iTableTop+"px", 'top', nTable.style ); | |
| 606 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 607 } | |
| 608 else if ( oWin.iScrollTop + s.oOffset.top > oMes.iTableTop+iTbodyHeight ) | |
| 609 { | |
| 610 /* At the bottom of the table */ | |
| 611 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); | |
| 612 this._fnUpdateCache( oCache, 'sTop', (oMes.iTableTop+iTbodyHeight)+"px", 'top', nTable.style ); | |
| 613 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 614 } | |
| 615 else | |
| 616 { | |
| 617 /* In the middle of the table */ | |
| 618 if ( s.bUseAbsPos ) | |
| 619 { | |
| 620 this._fnUpdateCache( oCache, 'sPosition', "absolute", 'position', nTable.style ); | |
| 621 this._fnUpdateCache( oCache, 'sTop', oWin.iScrollTop+"px", 'top', nTable.style ); | |
| 622 this._fnUpdateCache( oCache, 'sLeft', oMes.iTableLeft+"px", 'left', nTable.style ); | |
| 623 } | |
| 624 else | |
| 625 { | |
| 626 this._fnUpdateCache( oCache, 'sPosition', 'fixed', 'position', nTable.style ); | |
| 627 this._fnUpdateCache( oCache, 'sTop', s.oOffset.top+"px", 'top', nTable.style ); | |
| 628 this._fnUpdateCache( oCache, 'sLeft', (oMes.iTableLeft-oWin.iScrollLeft)+"px", 'left', nTable.style ); | |
| 629 } | |
| 630 } | |
| 631 }, | |
| 632 | |
| 633 /* | |
| 634 * Function: _fnUpdateCache | |
| 635 * Purpose: Check the cache and update cache and value if needed | |
| 636 * Returns: - | |
| 637 * Inputs: object:oCache - local cache object | |
| 638 * string:sCache - cache property | |
| 639 * string:sSet - value to set | |
| 640 * string:sProperty - object property to set | |
| 641 * object:oObj - object to update | |
| 642 */ | |
| 643 _fnUpdateCache: function ( oCache, sCache, sSet, sProperty, oObj ) | |
| 644 { | |
| 645 if ( oCache[sCache] != sSet ) | |
| 646 { | |
| 647 oObj[sProperty] = sSet; | |
| 648 oCache[sCache] = sSet; | |
| 649 } | |
| 650 }, | |
| 651 | |
| 652 | |
| 653 | |
| 654 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 655 * Cloning functions | |
| 656 */ | |
| 657 | |
| 658 /* | |
| 659 * Function: _fnCloneThead | |
| 660 * Purpose: Clone the thead element | |
| 661 * Returns: - | |
| 662 * Inputs: object:oCache - the cahced values for this fixed element | |
| 663 */ | |
| 664 _fnCloneThead: function ( oCache ) | |
| 665 { | |
| 666 var s = this.fnGetSettings(); | |
| 667 var nTable = oCache.nNode; | |
| 668 | |
| 669 /* Set the wrapper width to match that of the cloned table */ | |
| 670 oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px"; | |
| 671 | |
| 672 /* Remove any children the cloned table has */ | |
| 673 while ( nTable.childNodes.length > 0 ) | |
| 674 { | |
| 675 jQuery('thead th', nTable).unbind( 'click' ); | |
| 676 nTable.removeChild( nTable.childNodes[0] ); | |
| 677 } | |
| 678 | |
| 679 /* Clone the DataTables header */ | |
| 680 var nThead = jQuery('thead', s.nTable).clone(true)[0]; | |
| 681 nTable.appendChild( nThead ); | |
| 682 | |
| 683 /* Copy the widths across - apparently a clone isn't good enough for this */ | |
| 684 jQuery("thead>tr th", s.nTable).each( function (i) { | |
| 685 jQuery("thead>tr th:eq("+i+")", nTable).width( jQuery(this).width() ); | |
| 686 } ); | |
| 687 | |
| 688 jQuery("thead>tr td", s.nTable).each( function (i) { | |
| 689 jQuery("thead>tr td:eq("+i+")", nTable).width( jQuery(this).width() ); | |
| 690 } ); | |
| 691 }, | |
| 692 | |
| 693 /* | |
| 694 * Function: _fnCloneTfoot | |
| 695 * Purpose: Clone the tfoot element | |
| 696 * Returns: - | |
| 697 * Inputs: object:oCache - the cahced values for this fixed element | |
| 698 */ | |
| 699 _fnCloneTfoot: function ( oCache ) | |
| 700 { | |
| 701 var s = this.fnGetSettings(); | |
| 702 var nTable = oCache.nNode; | |
| 703 | |
| 704 /* Set the wrapper width to match that of the cloned table */ | |
| 705 oCache.nWrapper.style.width = jQuery(s.nTable).outerWidth()+"px"; | |
| 706 | |
| 707 /* Remove any children the cloned table has */ | |
| 708 while ( nTable.childNodes.length > 0 ) | |
| 709 { | |
| 710 nTable.removeChild( nTable.childNodes[0] ); | |
| 711 } | |
| 712 | |
| 713 /* Clone the DataTables footer */ | |
| 714 var nTfoot = jQuery('tfoot', s.nTable).clone(true)[0]; | |
| 715 nTable.appendChild( nTfoot ); | |
| 716 | |
| 717 /* Copy the widths across - apparently a clone isn't good enough for this */ | |
| 718 jQuery("tfoot:eq(0)>tr th", s.nTable).each( function (i) { | |
| 719 jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable).width( jQuery(this).width() ); | |
| 720 } ); | |
| 721 | |
| 722 jQuery("tfoot:eq(0)>tr td", s.nTable).each( function (i) { | |
| 723 jQuery("tfoot:eq(0)>tr th:eq("+i+")", nTable)[0].style.width( jQuery(this).width() ); | |
| 724 } ); | |
| 725 }, | |
| 726 | |
| 727 /* | |
| 728 * Function: _fnCloneTLeft | |
| 729 * Purpose: Clone the left column | |
| 730 * Returns: - | |
| 731 * Inputs: object:oCache - the cached values for this fixed element | |
| 732 */ | |
| 733 _fnCloneTLeft: function ( oCache ) | |
| 734 { | |
| 735 var s = this.fnGetSettings(); | |
| 736 var nTable = oCache.nNode; | |
| 737 var nBody = $('tbody', s.nTable)[0]; | |
| 738 var iCols = $('tbody tr:eq(0) td', s.nTable).length; | |
| 739 var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")); | |
| 740 | |
| 741 /* Remove any children the cloned table has */ | |
| 742 while ( nTable.childNodes.length > 0 ) | |
| 743 { | |
| 744 nTable.removeChild( nTable.childNodes[0] ); | |
| 745 } | |
| 746 | |
| 747 /* Is this the most efficient way to do this - it looks horrible... */ | |
| 748 nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] ); | |
| 749 nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] ); | |
| 750 if ( s.bFooter ) | |
| 751 { | |
| 752 nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] ); | |
| 753 } | |
| 754 | |
| 755 /* Remove unneeded cells */ | |
| 756 $('thead tr', nTable).each( function (k) { | |
| 757 $('th:gt(0)', this).remove(); | |
| 758 } ); | |
| 759 | |
| 760 $('tfoot tr', nTable).each( function (k) { | |
| 761 $('th:gt(0)', this).remove(); | |
| 762 } ); | |
| 763 | |
| 764 $('tbody tr', nTable).each( function (k) { | |
| 765 $('td:gt(0)', this).remove(); | |
| 766 } ); | |
| 767 | |
| 768 this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); | |
| 769 | |
| 770 var iWidth = jQuery('thead tr th:eq(0)', s.nTable).outerWidth(); | |
| 771 nTable.style.width = iWidth+"px"; | |
| 772 oCache.nWrapper.style.width = iWidth+"px"; | |
| 773 }, | |
| 774 | |
| 775 /* | |
| 776 * Function: _fnCloneTRight | |
| 777 * Purpose: Clone the right most colun | |
| 778 * Returns: - | |
| 779 * Inputs: object:oCache - the cahced values for this fixed element | |
| 780 */ | |
| 781 _fnCloneTRight: function ( oCache ) | |
| 782 { | |
| 783 var s = this.fnGetSettings(); | |
| 784 var nBody = $('tbody', s.nTable)[0]; | |
| 785 var nTable = oCache.nNode; | |
| 786 var iCols = jQuery('tbody tr:eq(0) td', s.nTable).length; | |
| 787 var bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")); | |
| 788 | |
| 789 /* Remove any children the cloned table has */ | |
| 790 while ( nTable.childNodes.length > 0 ) | |
| 791 { | |
| 792 nTable.removeChild( nTable.childNodes[0] ); | |
| 793 } | |
| 794 | |
| 795 /* Is this the most efficient way to do this - it looks horrible... */ | |
| 796 nTable.appendChild( jQuery("thead", s.nTable).clone(true)[0] ); | |
| 797 nTable.appendChild( jQuery("tbody", s.nTable).clone(true)[0] ); | |
| 798 if ( s.bFooter ) | |
| 799 { | |
| 800 nTable.appendChild( jQuery("tfoot", s.nTable).clone(true)[0] ); | |
| 801 } | |
| 802 jQuery('thead tr th:not(:nth-child('+iCols+'n))', nTable).remove(); | |
| 803 jQuery('tfoot tr th:not(:nth-child('+iCols+'n))', nTable).remove(); | |
| 804 | |
| 805 /* Remove unneeded cells */ | |
| 806 $('tbody tr', nTable).each( function (k) { | |
| 807 $('td:lt('+(iCols-1)+')', this).remove(); | |
| 808 } ); | |
| 809 | |
| 810 this.fnEqualiseHeights( 'tbody', nBody.parentNode, nTable ); | |
| 811 | |
| 812 var iWidth = jQuery('thead tr th:eq('+(iCols-1)+')', s.nTable).outerWidth(); | |
| 813 nTable.style.width = iWidth+"px"; | |
| 814 oCache.nWrapper.style.width = iWidth+"px"; | |
| 815 }, | |
| 816 | |
| 817 | |
| 818 /** | |
| 819 * Equalise the heights of the rows in a given table node in a cross browser way. Note that this | |
| 820 * is more or less lifted as is from FixedColumns | |
| 821 * @method fnEqualiseHeights | |
| 822 * @returns void | |
| 823 * @param {string} parent Node type - thead, tbody or tfoot | |
| 824 * @param {element} original Original node to take the heights from | |
| 825 * @param {element} clone Copy the heights to | |
| 826 * @private | |
| 827 */ | |
| 828 "fnEqualiseHeights": function ( parent, original, clone ) | |
| 829 { | |
| 830 var that = this, | |
| 831 jqBoxHack = $(parent+' tr:eq(0)', original).children(':eq(0)'), | |
| 832 iBoxHack = jqBoxHack.outerHeight() - jqBoxHack.height(), | |
| 833 bRubbishOldIE = ($.browser.msie && ($.browser.version == "6.0" || $.browser.version == "7.0")); | |
| 834 | |
| 835 /* Remove cells which are not needed and copy the height from the original table */ | |
| 836 $(parent+' tr', clone).each( function (k) { | |
| 837 /* Can we use some kind of object detection here?! This is very nasty - damn browsers */ | |
| 838 if ( $.browser.mozilla || $.browser.opera ) | |
| 839 { | |
| 840 $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() ); | |
| 841 } | |
| 842 else | |
| 843 { | |
| 844 $(this).children().height( $(parent+' tr:eq('+k+')', original).outerHeight() - iBoxHack ); | |
| 845 } | |
| 846 | |
| 847 if ( !bRubbishOldIE ) | |
| 848 { | |
| 849 $(parent+' tr:eq('+k+')', original).height( $(parent+' tr:eq('+k+')', original).outerHeight() ); | |
| 850 } | |
| 851 } ); | |
| 852 } | |
| 853 }; | |
| 854 | |
| 855 | |
| 856 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 857 * Static properties and methods | |
| 858 * We use these for speed! This information is common to all instances of FixedHeader, so no | |
| 859 * point if having them calculated and stored for each different instance. | |
| 860 */ | |
| 861 | |
| 862 /* | |
| 863 * Variable: oWin | |
| 864 * Purpose: Store information about the window positioning | |
| 865 * Scope: FixedHeader | |
| 866 */ | |
| 867 FixedHeader.oWin = { | |
| 868 "iScrollTop": 0, | |
| 869 "iScrollRight": 0, | |
| 870 "iScrollBottom": 0, | |
| 871 "iScrollLeft": 0, | |
| 872 "iHeight": 0, | |
| 873 "iWidth": 0 | |
| 874 }; | |
| 875 | |
| 876 /* | |
| 877 * Variable: oDoc | |
| 878 * Purpose: Store information about the document size | |
| 879 * Scope: FixedHeader | |
| 880 */ | |
| 881 FixedHeader.oDoc = { | |
| 882 "iHeight": 0, | |
| 883 "iWidth": 0 | |
| 884 }; | |
| 885 | |
| 886 /* | |
| 887 * Variable: afnScroll | |
| 888 * Purpose: Array of functions that are to be used for the scrolling components | |
| 889 * Scope: FixedHeader | |
| 890 */ | |
| 891 FixedHeader.afnScroll = []; | |
| 892 | |
| 893 /* | |
| 894 * Function: fnMeasure | |
| 895 * Purpose: Update the measurements for the window and document | |
| 896 * Returns: - | |
| 897 * Inputs: - | |
| 898 */ | |
| 899 FixedHeader.fnMeasure = function () | |
| 900 { | |
| 901 var | |
| 902 jqWin = jQuery(window), | |
| 903 jqDoc = jQuery(document), | |
| 904 oWin = FixedHeader.oWin, | |
| 905 oDoc = FixedHeader.oDoc; | |
| 906 | |
| 907 oDoc.iHeight = jqDoc.height(); | |
| 908 oDoc.iWidth = jqDoc.width(); | |
| 909 | |
| 910 oWin.iHeight = jqWin.height(); | |
| 911 oWin.iWidth = jqWin.width(); | |
| 912 oWin.iScrollTop = jqWin.scrollTop(); | |
| 913 oWin.iScrollLeft = jqWin.scrollLeft(); | |
| 914 oWin.iScrollRight = oDoc.iWidth - oWin.iScrollLeft - oWin.iWidth; | |
| 915 oWin.iScrollBottom = oDoc.iHeight - oWin.iScrollTop - oWin.iHeight; | |
| 916 }; | |
| 917 | |
| 918 | |
| 919 FixedHeader.VERSION = "2.0.6"; | |
| 920 FixedHeader.prototype.VERSION = FixedHeader.VERSION; | |
| 921 | |
| 922 | |
| 923 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 924 * Global processing | |
| 925 */ | |
| 926 | |
| 927 /* | |
| 928 * Just one 'scroll' event handler in FixedHeader, which calls the required components. This is | |
| 929 * done as an optimisation, to reduce calculation and proagation time | |
| 930 */ | |
| 931 jQuery(window).scroll( function () { | |
| 932 FixedHeader.fnMeasure(); | |
| 933 for ( var i=0, iLen=FixedHeader.afnScroll.length ; i<iLen ; i++ ) | |
| 934 { | |
| 935 FixedHeader.afnScroll[i](); | |
| 936 } | |
| 937 } ); |
