1 /* 2 * File: ColReorder.js 3 * Version: 1.0.0 4 * CVS: $Id$ 5 * Description: Controls for column visiblity in DataTables 6 * Author: Allan Jardine (www.sprymedia.co.uk) 7 * Created: Wed Sep 15 18:23:29 BST 2010 8 * Modified: $Date$ by $Author$ 9 * Language: Javascript 10 * License: LGPL 11 * Project: DataTables 12 * Contact: www.sprymedia.co.uk/contact 13 * 14 * Copyright 2010 Allan Jardine, all rights reserved. 15 * 16 */ 17 18 19 (function($, window, document) { 20 21 22 /** 23 * Switch the key value pairing of an index array to be value key (i.e. the old value is now the 24 * key). For example consider [ 2, 0, 1 ] this would be returned as [ 1, 2, 0 ]. 25 * @method fnInvertKeyValues 26 * @param array aIn Array to switch around 27 * @returns array 28 */ 29 function fnInvertKeyValues( aIn ) 30 { 31 var aRet=[]; 32 for ( var i=0, iLen=aIn.length ; i<iLen ; i++ ) 33 { 34 aRet[ aIn[i] ] = i; 35 } 36 return aRet; 37 } 38 39 40 /** 41 * Modify an array by switching the position of two elements 42 * @method fnArraySwitch 43 * @param array aArray Array to consider, will be modified by reference (i.e. no return) 44 * @param int iFrom From point 45 * @param int iTo Insert point 46 * @returns void 47 */ 48 function fnArraySwitch( aArray, iFrom, iTo ) 49 { 50 var mStore = aArray.splice( iFrom, 1 )[0]; 51 aArray.splice( iTo, 0, mStore ); 52 } 53 54 55 /** 56 * Switch the positions of nodes in a parent node (note this is specifically designed for 57 * table rows) 58 * @method fnDomSwitch 59 * @param node nParent Parent node (i.e. the TR) 60 * @param string sTag Tag to consider 61 * @param int iFrom Element to move 62 * @param int Point to element the element to (before this point), can be null for append 63 * @returns void 64 */ 65 function fnDomSwitch( nParent, sTag, iFrom, iTo ) 66 { 67 var nTags = nParent.getElementsByTagName(sTag); 68 var nStore = nTags[ iFrom ]; 69 70 if ( iTo !== null ) 71 { 72 nParent.insertBefore( nStore, nTags[iTo] ); 73 } 74 else 75 { 76 nParent.appendChild( nStore ); 77 } 78 } 79 80 81 82 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 83 * DataTables plug-in API functions 84 * 85 * This are required by ColReorder in order to perform the tasks required, and also keep this 86 * code portable, to be used for other column reordering projects with DataTables, if needed. 87 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 88 89 90 /** 91 * Plug-in for DataTables which will reorder the internal column structure by taking the column 92 * from one position (iFrom) and insert it into a given point (iTo). 93 * @method $.fn.dataTableExt.oApi.fnColReorder 94 * @param object oSettings DataTables settings object - automatically added by DataTables! 95 * @param int iFrom Take the column to be repositioned from this point 96 * @param int iTo and insert it into this point 97 * @returns void 98 */ 99 $.fn.dataTableExt.oApi.fnColReorder = function ( oSettings, iFrom, iTo ) 100 { 101 var i, iLen, j, jLen, iCols=oSettings.aoColumns.length; 102 103 /* Sanity check in the input */ 104 if ( iFrom == iTo ) 105 { 106 /* Pointless reorder */ 107 return; 108 } 109 110 if ( iFrom < 0 || iFrom >= iCols ) 111 { 112 this.oApi._fnLog( oSettings, 1, "ColReorder 'from' index is out of bounds: "+iFrom ); 113 return; 114 } 115 116 if ( iTo < 0 || iTo >= iCols ) 117 { 118 this.oApi._fnLog( oSettings, 1, "ColReorder 'to' index is out of bounds: "+iTo ); 119 return; 120 } 121 122 /* 123 * Calculate the new column array index, so we have a mapping between the old and new 124 */ 125 var aiMapping = []; 126 for ( i=0, iLen=iCols ; i<iLen ; i++ ) 127 { 128 aiMapping[i] = i; 129 } 130 fnArraySwitch( aiMapping, iFrom, iTo ); 131 var aiInvertMapping = fnInvertKeyValues( aiMapping ); 132 133 134 /* 135 * Convert all internal indexing to the new column order indexes 136 */ 137 /* Sorting */ 138 for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ ) 139 { 140 oSettings.aaSorting[i][0] = aiInvertMapping[ oSettings.aaSorting[i][0] ]; 141 } 142 143 /* Fixed sorting */ 144 if ( oSettings.aaSortingFixed !== null ) 145 { 146 for ( i=0, iLen=oSettings.aaSortingFixed.length ; i<iLen ; i++ ) 147 { 148 oSettings.aaSortingFixed[i][0] = aiInvertMapping[ oSettings.aaSortingFixed[i][0] ]; 149 } 150 } 151 152 /* Data column sorting (the column which the sort for a given column should take place on) */ 153 for ( i=0, iLen=iCols ; i<iLen ; i++ ) 154 { 155 oSettings.aoColumns[i].iDataSort = aiInvertMapping[ oSettings.aoColumns[i].iDataSort ]; 156 } 157 158 159 /* 160 * Move the DOM elements 161 */ 162 if ( oSettings.aoColumns[iFrom].bVisible ) 163 { 164 /* Calculate the current visible index and the point to insert the node before. The insert 165 * before needs to take into account that there might not be an element to insert before, 166 * in which case it will be null, and an appendChild should be used 167 */ 168 var iVisibleIndex = this.oApi._fnColumnIndexToVisible( oSettings, iFrom ); 169 var iInsertBeforeIndex = null; 170 171 i = iTo < iFrom ? iTo : iTo + 1; 172 while ( iInsertBeforeIndex === null && i < iCols ) 173 { 174 iInsertBeforeIndex = this.oApi._fnColumnIndexToVisible( oSettings, i ); 175 i++; 176 } 177 178 /* Header */ 179 fnDomSwitch( oSettings.nTHead.getElementsByTagName('tr')[0], 'TH', 180 iVisibleIndex, iInsertBeforeIndex ); 181 182 /* Footer */ 183 if ( oSettings.nTFoot !== null ) 184 { 185 fnDomSwitch( oSettings.nTFoot.getElementsByTagName('tr')[0], 'TH', 186 iVisibleIndex, iInsertBeforeIndex ); 187 } 188 189 /* Body */ 190 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) 191 { 192 fnDomSwitch( oSettings.aoData[i].nTr, 'td', 193 iVisibleIndex, iInsertBeforeIndex ); 194 } 195 } 196 197 198 /* 199 * Move the internal array elements 200 */ 201 /* Columns */ 202 fnArraySwitch( oSettings.aoColumns, iFrom, iTo ); 203 204 /* Search columns */ 205 fnArraySwitch( oSettings.aoPreSearchCols, iFrom, iTo ); 206 207 /* Array array - internal data anodes cache */ 208 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) 209 { 210 fnArraySwitch( oSettings.aoData[i]._aData, iFrom, iTo ); 211 fnArraySwitch( oSettings.aoData[i]._anHidden, iFrom, iTo ); 212 } 213 214 215 /* 216 * Update DataTables' event handlers 217 */ 218 219 /* Sort listener */ 220 for ( i=0, iLen=iCols ; i<iLen ; i++ ) 221 { 222 $(oSettings.aoColumns[i].nTh).unbind('click'); 223 this.oApi._fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i ); 224 } 225 226 227 /* 228 * Any extra operations 229 */ 230 if ( typeof ColVis != 'undefined' ) 231 { 232 ColVis.fnRebuild( oSettings.oInstance ); 233 } 234 }; 235 236 237 238 239 /** 240 * ColReorder provides column visiblity control for DataTables 241 * @class ColReorder 242 * @constructor 243 * @param {object} DataTables object 244 * @param {object} ColReorder options 245 */ 246 ColReorder = function( oTable, oOpts ) 247 { 248 /* Santiy check that we are a new instance */ 249 if ( !this.CLASS || this.CLASS != "ColReorder" ) 250 { 251 alert( "Warning: ColReorder must be initialised with the keyword 'new'" ); 252 } 253 254 if ( typeof oOpts == 'undefined' ) 255 { 256 oOpts = {}; 257 } 258 259 260 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 261 * Public class variables 262 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 263 264 /** 265 * @namespace Settings object which contains customisable information for ColReorder instance 266 */ 267 this.s = { 268 /** 269 * DataTables settings object 270 * @property dt 271 * @type Object 272 * @default null 273 */ 274 dt: null, 275 276 /** 277 * Initialisation object used for this instance 278 * @property init 279 * @type object 280 * @default {} 281 */ 282 init: oOpts, 283 284 /** 285 * Number of columns to fix (not allow to be reordered) 286 * @property fixed 287 * @type int 288 * @default 0 289 */ 290 fixed: 0, 291 292 /** 293 * @namespace Information used for the mouse drag 294 */ 295 mouse: { 296 startX: -1, 297 startY: -1, 298 offsetX: -1, 299 offsetY: -1, 300 target: -1, 301 targetIndex: -1, 302 fromIndex: -1 303 }, 304 305 /** 306 * Information which is used for positioning the insert cusor and knowing where to do the 307 * insert. Array of objects with the properties: 308 * x: x-axis position 309 * to: insert point 310 * @property aoTargets 311 * @type array 312 * @default [] 313 */ 314 aoTargets: [] 315 }; 316 317 318 /** 319 * @namespace Common and useful DOM elements for the class instance 320 */ 321 this.dom = { 322 /** 323 * Dragging element (the one the mouse is moving) 324 * @property drag 325 * @type element 326 * @default null 327 */ 328 drag: null, 329 330 /** 331 * The insert cursor 332 * @property pointer 333 * @type element 334 * @default null 335 */ 336 pointer: null 337 }; 338 339 340 /* Constructor logic */ 341 this.s.dt = oTable.fnSettings(); 342 this._fnConstruct(); 343 344 /* Store the instance for later use */ 345 ColReorder.aoInstances.push( this ); 346 return this; 347 }; 348 349 350 351 ColReorder.prototype = { 352 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 353 * Public methods 354 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 355 356 fnReset: function () 357 { 358 var a = []; 359 for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ ) 360 { 361 a.push( this.s.dt.aoColumns[i]._ColReorder_iOrigCol ); 362 } 363 364 this._fnOrderColumns( a ); 365 }, 366 367 368 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 369 * Private methods (they are of course public in JS, but recommended as private) 370 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 371 372 /** 373 * Constructor logic 374 * @method _fnConstruct 375 * @returns void 376 * @private 377 */ 378 _fnConstruct: function () 379 { 380 var that = this; 381 var i, iLen; 382 383 /* Columns discounted from reordering - counting left to right */ 384 if ( typeof this.s.init.iFixedColumns != 'undefined' ) 385 { 386 this.s.fixed = this.s.init.iFixedColumns; 387 } 388 389 /* Add event handlers for the drag and drop, and also mark the original column order */ 390 for ( i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ ) 391 { 392 if ( i > this.s.fixed-1 ) 393 { 394 $(this.s.dt.aoColumns[i].nTh).bind( 'mousedown.ColReorder', function (e) { 395 that._fnMouseDown.call( that, e ); 396 return false; 397 } ); 398 } 399 400 /* Mark the original column order for later reference */ 401 this.s.dt.aoColumns[i]._ColReorder_iOrigCol = i; 402 } 403 404 /* State saving */ 405 this.s.dt.aoStateSave.push( { 406 fn: function (oS, sVal) { 407 return that._fnStateSave.call( that, sVal ); 408 }, 409 sName: "ColReorder_State" 410 } ); 411 412 /* An initial column order has been specified */ 413 var aiOrder = null; 414 if ( typeof this.s.init.aiOrder != 'undefined' ) 415 { 416 aiOrder = this.s.init.aiOrder.slice(); 417 } 418 419 /* State loading, overrides the column order given */ 420 if ( this.s.dt.oLoadedState && typeof this.s.dt.oLoadedState.ColReorder != 'undefined' && 421 this.s.dt.oLoadedState.ColReorder.length == this.s.dt.aoColumns.length ) 422 { 423 aiOrder = this.s.dt.oLoadedState.ColReorder; 424 } 425 426 /* If we have an order to apply - do so */ 427 if ( aiOrder ) 428 { 429 /* We might be called during or after the DataTables initialisation. If before, then we need 430 * to wait until the draw is done, if after, then do what we need to do right away 431 */ 432 if ( !that.s.dt._bInitComplete ) 433 { 434 var bDone = false; 435 this.s.dt.aoDrawCallback.push( { 436 fn: function () { 437 if ( !that.s.dt._bInitComplete && !bDone ) 438 { 439 bDone = true; 440 var resort = fnInvertKeyValues( aiOrder ); 441 that._fnOrderColumns.call( that, resort ); 442 } 443 }, 444 sName: "ColReorder_Pre" 445 } ); 446 } 447 else 448 { 449 var resort = fnInvertKeyValues( aiOrder ); 450 that._fnOrderColumns.call( that, resort ); 451 } 452 } 453 }, 454 455 456 /** 457 * Set the column order from an array 458 * @method _fnOrderColumns 459 * @param array a An array of integers which dictate the column order that should be applied 460 * @returns void 461 * @private 462 */ 463 _fnOrderColumns: function ( a ) 464 { 465 if ( a.length != this.s.dt.aoColumns.length ) 466 { 467 this.s.dt.oInstance.oApi._fnLog( oDTSettings, 1, "ColReorder - array reorder does not "+ 468 "match known number of columns. Skipping." ); 469 return; 470 } 471 472 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 473 { 474 var currIndex = $.inArray( i, a ); 475 if ( i != currIndex ) 476 { 477 /* Reorder our switching array */ 478 fnArraySwitch( a, currIndex, i ); 479 480 /* Do the column reorder in the table */ 481 this.s.dt.oInstance.fnColReorder( currIndex, i ); 482 } 483 } 484 485 /* When scrolling we need to recalculate the column sizes to allow for the shift */ 486 if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) 487 { 488 this.s.dt.oInstance.fnAdjustColumnSizing(); 489 } 490 491 /* Save the state */ 492 this.s.dt.oInstance.oApi._fnSaveState( this.s.dt ); 493 }, 494 495 496 /** 497 * This function effectively replaces the state saving function in DataTables (this is needed 498 * because otherwise DataTables would state save the columns in their reordered state, not the 499 * original which is needed on first draw). This is sensitive to any changes in the DataTables 500 * state saving method! 501 * @method _fnStateSave 502 * @param string sCurrentVal 503 * @returns string JSON encoded cookie string for DataTables 504 * @private 505 */ 506 _fnStateSave: function ( sCurrentVal ) 507 { 508 var i, iLen, sTmp; 509 var sValue = sCurrentVal.split('"aaSorting"')[0]; 510 var a = []; 511 var oSettings = this.s.dt; 512 513 /* Sorting */ 514 sValue += '"aaSorting":[ '; 515 for ( i=0 ; i<oSettings.aaSorting.length ; i++ ) 516 { 517 sValue += '['+oSettings.aoColumns[ oSettings.aaSorting[i][0] ]._ColReorder_iOrigCol+ 518 ',"'+oSettings.aaSorting[i][1]+'"],'; 519 } 520 sValue = sValue.substring(0, sValue.length-1); 521 sValue += "],"; 522 523 /* Column filter */ 524 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 525 { 526 a[ oSettings.aoColumns[i]._ColReorder_iOrigCol ] = { 527 sSearch: encodeURIComponent(oSettings.aoPreSearchCols[i].sSearch), 528 bRegex: !oSettings.aoPreSearchCols[i].bRegex 529 }; 530 } 531 532 sValue += '"aaSearchCols":[ '; 533 for ( i=0 ; i<a.length ; i++ ) 534 { 535 sValue += '["'+a[i].sSearch+'",'+a[i].bRegex+'],'; 536 } 537 sValue = sValue.substring(0, sValue.length-1); 538 sValue += "],"; 539 540 /* Visibility */ 541 a = []; 542 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 543 { 544 a[ oSettings.aoColumns[i]._ColReorder_iOrigCol ] = oSettings.aoColumns[i].bVisible; 545 } 546 547 sValue += '"abVisCols":[ '; 548 for ( i=0 ; i<a.length ; i++ ) 549 { 550 sValue += a[i]+","; 551 } 552 sValue = sValue.substring(0, sValue.length-1); 553 sValue += "],"; 554 555 /* Column reordering */ 556 a = []; 557 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) { 558 a.push( oSettings.aoColumns[i]._ColReorder_iOrigCol ); 559 } 560 sValue += '"ColReorder":['+a.join(',')+']'; 561 562 return sValue; 563 }, 564 565 566 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 567 * Mouse drop and drag 568 */ 569 570 /** 571 * Mouse down on a TH element in the table header 572 * @method _fnMouseDown 573 * @param event e Mouse event 574 * @returns void 575 * @private 576 */ 577 _fnMouseDown: function ( e ) 578 { 579 var 580 that = this, 581 aoColumns = this.s.dt.aoColumns; 582 583 /* Store information about the mouse position */ 584 var offset = $(e.target).offset(); 585 this.s.mouse.startX = e.pageX; 586 this.s.mouse.startY = e.pageY; 587 this.s.mouse.offsetX = e.pageX - offset.left; 588 this.s.mouse.offsetY = e.pageY - offset.top; 589 this.s.mouse.target = e.target; 590 this.s.mouse.targetIndex = $('th', e.target.parentNode).index( e.target ); 591 this.s.mouse.fromIndex = this.s.dt.oInstance.oApi._fnVisibleToColumnIndex( this.s.dt, 592 this.s.mouse.targetIndex ); 593 594 /* Calculate a cached array with the points of the column inserts, and the 'to' points */ 595 this.s.aoTargets.splice( 0, this.s.aoTargets.length ); 596 597 this.s.aoTargets.push( { 598 x: $(this.s.dt.nTable).offset().left, 599 to: 0 600 } ); 601 602 var iToPoint = 0; 603 for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ ) 604 { 605 /* For the column / header in question, we want it's position to remain the same if the 606 * position is just to it's immediate left or right, so we only incremement the counter for 607 * other columns 608 */ 609 if ( i != this.s.mouse.fromIndex ) 610 { 611 iToPoint++; 612 } 613 614 if ( aoColumns[i].bVisible ) 615 { 616 this.s.aoTargets.push( { 617 x: $(aoColumns[i].nTh).offset().left + $(aoColumns[i].nTh).outerWidth(), 618 to: iToPoint 619 } ); 620 } 621 } 622 623 /* Disallow columns for being reordered by drag and drop, counting left to right */ 624 if ( this.s.fixed !== 0 ) 625 { 626 this.s.aoTargets.splice( 0, this.s.fixed ); 627 } 628 629 /* Add event handlers to the document */ 630 $(document).bind( 'mousemove.ColReorder', function (e) { 631 that._fnMouseMove.call( that, e ); 632 } ); 633 634 $(document).bind( 'mouseup.ColReorder', function (e) { 635 that._fnMouseUp.call( that, e ); 636 } ); 637 }, 638 639 640 /** 641 * Deal with a mouse move event while dragging a node 642 * @method _fnMouseMove 643 * @param event e Mouse event 644 * @returns void 645 * @private 646 */ 647 _fnMouseMove: function ( e ) 648 { 649 var that = this; 650 651 if ( this.dom.drag === null ) 652 { 653 /* Only create the drag element if the mouse has moved a specific distance from the start 654 * point - this allows the user to make small mouse movements when sorting and not have a 655 * possibly confusing drag element showing up 656 */ 657 if ( Math.pow( 658 Math.pow(e.pageX - this.s.mouse.startX, 2) + 659 Math.pow(e.pageY - this.s.mouse.startY, 2), 0.5 ) < 5 ) 660 { 661 return; 662 } 663 this._fnCreateDragNode(); 664 } 665 666 /* Position the element - we respect where in the element the click occured */ 667 this.dom.drag.style.left = (e.pageX - this.s.mouse.offsetX) + "px"; 668 this.dom.drag.style.top = (e.pageY - this.s.mouse.offsetY) + "px"; 669 670 /* Based on the current mouse position, calculate where the insert should go */ 671 var bSet = false; 672 for ( var i=1, iLen=this.s.aoTargets.length ; i<iLen ; i++ ) 673 { 674 if ( e.pageX < this.s.aoTargets[i-1].x + ((this.s.aoTargets[i].x-this.s.aoTargets[i-1].x)/2) ) 675 { 676 this.dom.pointer.style.left = this.s.aoTargets[i-1].x +"px"; 677 this.s.mouse.toIndex = this.s.aoTargets[i-1].to; 678 bSet = true; 679 break; 680 } 681 } 682 683 /* The insert element wasn't positioned in the array (less than operator), so we put it at 684 * the end 685 */ 686 if ( !bSet ) 687 { 688 this.dom.pointer.style.left = this.s.aoTargets[this.s.aoTargets.length-1].x +"px"; 689 this.s.mouse.toIndex = this.s.aoTargets[this.s.aoTargets.length-1].to; 690 } 691 }, 692 693 694 /** 695 * Finish off the mouse drag and insert the column where needed 696 * @method _fnMouseUp 697 * @param event e Mouse event 698 * @returns void 699 * @private 700 */ 701 _fnMouseUp: function ( e ) 702 { 703 var that = this; 704 705 $(document).unbind( 'mousemove.ColReorder' ); 706 $(document).unbind( 'mouseup.ColReorder' ); 707 708 if ( this.dom.drag !== null ) 709 { 710 /* Remove the guide elements */ 711 document.body.removeChild( this.dom.drag ); 712 document.body.removeChild( this.dom.pointer ); 713 this.dom.drag = null; 714 this.dom.pointer = null; 715 716 /* Actually do the reorder */ 717 this.s.dt.oInstance.fnColReorder( this.s.mouse.fromIndex, this.s.mouse.toIndex ); 718 719 /* When scrolling we need to recalculate the column sizes to allow for the shift */ 720 if ( this.s.dt.oScroll.sX !== "" || this.s.dt.oScroll.sY !== "" ) 721 { 722 this.s.dt.oInstance.fnAdjustColumnSizing(); 723 } 724 725 /* Save the state */ 726 this.s.dt.oInstance.oApi._fnSaveState( this.s.dt ); 727 } 728 }, 729 730 731 /** 732 * Copy the TH element that is being drags so the user has the idea that they are actually 733 * moving it around the page. 734 * @method _fnCreateDragNode 735 * @returns void 736 * @private 737 */ 738 _fnCreateDragNode: function () 739 { 740 var that = this; 741 742 this.dom.drag = $(this.s.dt.nTHead.parentNode).clone(true)[0]; 743 this.dom.drag.className += " DTCR_clonedTable"; 744 while ( this.dom.drag.getElementsByTagName('tbody').length > 0 ) 745 { 746 this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tbody')[0] ); 747 } 748 while ( this.dom.drag.getElementsByTagName('tfoot').length > 0 ) 749 { 750 this.dom.drag.removeChild( this.dom.drag.getElementsByTagName('tfoot')[0] ); 751 } 752 753 $('thead tr:eq(0)', this.dom.drag).each( function () { 754 $('th:not(:eq('+that.s.mouse.targetIndex+'))', this).remove(); 755 } ); 756 $('tr', this.dom.drag).height( $(that.s.dt.nTHead).height() ); 757 758 $('thead tr:gt(0)', this.dom.drag).remove(); 759 760 $('thead th:eq(0)', this.dom.drag).each( function (i) { 761 this.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).width()+"px"; 762 } ); 763 764 this.dom.drag.style.position = "absolute"; 765 this.dom.drag.style.top = "0px"; 766 this.dom.drag.style.left = "0px"; 767 this.dom.drag.style.width = $('th:eq('+that.s.mouse.targetIndex+')', that.s.dt.nTHead).outerWidth()+"px"; 768 769 770 this.dom.pointer = document.createElement( 'div' ); 771 this.dom.pointer.className = "DTCR_pointer"; 772 this.dom.pointer.style.position = "absolute"; 773 774 if ( this.s.dt.oScroll.sX === "" && this.s.dt.oScroll.sY === "" ) 775 { 776 this.dom.pointer.style.top = $(this.s.dt.nTable).offset().top+"px"; 777 this.dom.pointer.style.height = $(this.s.dt.nTable).height()+"px"; 778 } 779 else 780 { 781 this.dom.pointer.style.top = $('div.dataTables_scroll', this.s.dt.nTableWrapper).offset().top+"px"; 782 this.dom.pointer.style.height = $('div.dataTables_scroll', this.s.dt.nTableWrapper).height()+"px"; 783 } 784 785 document.body.appendChild( this.dom.pointer ); 786 document.body.appendChild( this.dom.drag ); 787 } 788 }; 789 790 791 792 793 794 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 795 * Static parameters 796 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 797 798 /** 799 * Array of all ColReorder instances for later reference 800 * @property ColReorder.aoInstances 801 * @type array 802 * @default [] 803 * @static 804 */ 805 ColReorder.aoInstances = []; 806 807 808 809 810 811 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 812 * Static functions 813 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 814 815 /** 816 * Reset the column ordering for a DataTables instance 817 * @method ColReorder.fnReset 818 * @param object oTable DataTables instance to consider 819 * @returns void 820 * @static 821 */ 822 ColReorder.fnReset = function ( oTable ) 823 { 824 for ( var i=0, iLen=ColReorder.aoInstances.length ; i<iLen ; i++ ) 825 { 826 if ( ColReorder.aoInstances[i].s.dt.oInstance == oTable ) 827 { 828 ColReorder.aoInstances[i].fnReset(); 829 } 830 } 831 }; 832 833 834 835 836 837 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 838 * Constants 839 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 840 841 /** 842 * Name of this class 843 * @constant CLASS 844 * @type String 845 * @default ColReorder 846 */ 847 ColReorder.prototype.CLASS = "ColReorder"; 848 849 850 /** 851 * ColReorder version 852 * @constant VERSION 853 * @type String 854 * @default 1.0.0 855 */ 856 ColReorder.VERSION = "1.0.0"; 857 ColReorder.prototype.VERSION = ColReorder.VERSION; 858 859 860 861 862 863 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 864 * Initialisation 865 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 866 867 /* 868 * Register a new feature with DataTables 869 */ 870 if ( typeof $.fn.dataTable == "function" && 871 typeof $.fn.dataTableExt.fnVersionCheck == "function" && 872 $.fn.dataTableExt.fnVersionCheck('1.7.4') ) 873 { 874 $.fn.dataTableExt.aoFeatures.push( { 875 fnInit: function( oDTSettings ) { 876 var oTable = oDTSettings.oInstance; 877 if ( typeof oTable._oPluginColReorder == 'undefined' ) { 878 var opts = typeof oDTSettings.oInit.oColReorder != 'undefined' ? 879 oDTSettings.oInit.oColReorder : {}; 880 oTable._oPluginColReorder = new ColReorder( oDTSettings.oInstance, opts ); 881 } else { 882 oTable.oApi._fnLog( oDTSettings, 1, "ColReorder attempted to initialise twice. Ignoring second" ); 883 } 884 885 return null; /* No node to insert */ 886 }, 887 cFeature: "R", 888 sFeature: "ColReorder" 889 } ); 890 } 891 else 892 { 893 alert( "Warning: ColReorder requires DataTables 1.7.4 or greater - www.datatables.net/download"); 894 } 895 896 })(jQuery, window, document); 897