      1 /*
      2  * File:        ColVis.js
      3  * Version:     1.0.6
      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:     GPL v2 or BSD 3 point style
     11  * Project:     Just a little bit of fun :-)
     12  * Contact:     www.sprymedia.co.uk/contact
     13  *
     14  * Copyright 2010-2011 Allan Jardine, all rights reserved.
     15  *
     16  * This source file is free software, under either the GPL v2 license or a
     17  * BSD style license, available at:
     18  *   http://datatables.net/license_gpl2
     19  *   http://datatables.net/license_bsd
     20  */
     21
     22 (function($) {
     23
     24 /**
     25  * ColVis provides column visiblity control for DataTables
     26  * @class ColVis
     27  * @constructor
     28  * @param {object} DataTables settings object
     29  */
     30 ColVis = function( oDTSettings, oInit )
     31 {
     32 	/* Santiy check that we are a new instance */
     33 	if ( !this.CLASS || this.CLASS != "ColVis" )
     34 	{
     35 		alert( "Warning: ColVis must be initialised with the keyword 'new'" );
     36 	}
     37
     38 	if ( typeof oInit == 'undefined' )
     39 	{
     40 		oInit = {};
     41 	}
     42
     43
     44 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
     45 	 * Public class variables
     46 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
     47
     48 	/**
     49 	 * @namespace Settings object which contains customisable information for ColVis instance
     50 	 */
     51 	this.s = {
     52 		/**
     53 		 * DataTables settings object
     54 		 *  @property dt
     55 		 *  @type     Object
     56 		 *  @default  null
     57 		 */
     58 		dt: null,
     59
     60 		/**
     61 		 * Customisation object
     62 		 *  @property oInit
     63 		 *  @type     Object
     64 		 *  @default  passed in
     65 		 */
     66 		oInit: oInit,
     67
     68 		/**
     69 		 * Callback function to tell the user when the state has changed
     70 		 *  @property fnStateChange
     71 		 *  @type     function
     72 		 *  @default  null
     73 		 */
     74 		fnStateChange: null,
     75
     76 		/**
     77 		 * Mode of activation. Can be 'click' or 'mouseover'
     78 		 *  @property activate
     79 		 *  @type     String
     80 		 *  @default  click
     81 		 */
     82 		activate: "click",
     83
     84 		/**
     85 		 * Position of the collection menu when shown - align "left" or "right"
     86 		 *  @property sAlign
     87 		 *  @type     String
     88 		 *  @default  right
     89 		 */
     90 		sAlign: "left",
     91
     92 		/**
     93 		 * Text used for the button
     94 		 *  @property buttonText
     95 		 *  @type     String
     96 		 *  @default  Show / hide columns
     97 		 */
     98 		buttonText: "Show / hide columns",
     99
    100 		/**
    101 		 * Flag to say if the collection is hidden
    102 		 *  @property hidden
    103 		 *  @type     boolean
    104 		 *  @default  true
    105 		 */
    106 		hidden: true,
    107
    108 		/**
    109 		 * List of columns (integers) which should be excluded from the list
    110 		 *  @property aiExclude
    111 		 *  @type     Array
    112 		 *  @default  []
    113 		 */
    114 		aiExclude: [],
    115
    116 		/**
    117 		 * Store the original viisbility settings so they could be restored
    118 		 *  @property abOriginal
    119 		 *  @type     Array
    120 		 *  @default  []
    121 		 */
    122 		abOriginal: [],
    123
    124 		/**
    125 		 * Show restore button
    126 		 *  @property bRestore
    127 		 *  @type     Array
    128 		 *  @default  []
    129 		 */
    130 		bRestore: false,
    131
    132 		/**
    133 		 * Restore button text
    134 		 *  @property sRestore
    135 		 *  @type     String
    136 		 *  @default  Restore original
    137 		 */
    138 		sRestore: "Restore original",
    139
    140 		/**
    141 		 * Overlay animation duration in mS
    142 		 *  @property iOverlayFade
    143 		 *  @type     Integer
    144 		 *  @default  500
    145 		 */
    146 		iOverlayFade: 500,
    147
    148 		/**
    149 		 * Label callback for column names. Takes three parameters: 1. the column index, 2. the column
    150 		 * title detected by DataTables and 3. the TH node for the column
    151 		 *  @property fnLabel
    152 		 *  @type     Function
    153 		 *  @default  null
    154 		 */
    155 		fnLabel: null,
    156
    157 		/**
    158 		 * Indicate if ColVis should automatically calculate the size of buttons or not. The default
    159 		 * is for it to do so. Set to "css" to disable the automatic sizing
    160 		 *  @property sSize
    161 		 *  @type     String
    162 		 *  @default  auto
    163 		 */
    164 		sSize: "auto"
    165 	};
    166
    167
    168 	/**
    169 	 * @namespace Common and useful DOM elements for the class instance
    170 	 */
    171 	this.dom = {
    172 		/**
    173 		 * Wrapper for the button - given back to DataTables as the node to insert
    174 		 *  @property wrapper
    175 		 *  @type     Node
    176 		 *  @default  null
    177 		 */
    178 		wrapper: null,
    179
    180 		/**
    181 		 * Activation button
    182 		 *  @property button
    183 		 *  @type     Node
    184 		 *  @default  null
    185 		 */
    186 		button: null,
    187
    188 		/**
    189 		 * Collection list node
    190 		 *  @property collection
    191 		 *  @type     Node
    192 		 *  @default  null
    193 		 */
    194 		collection: null,
    195
    196 		/**
    197 		 * Background node used for shading the display and event capturing
    198 		 *  @property background
    199 		 *  @type     Node
    200 		 *  @default  null
    201 		 */
    202 		background: null,
    203
    204 		/**
    205 		 * Element to position over the activation button to catch mouse events when using mouseover
    206 		 *  @property catcher
    207 		 *  @type     Node
    208 		 *  @default  null
    209 		 */
    210 		catcher: null,
    211
    212 		/**
    213 		 * List of button elements
    214 		 *  @property buttons
    215 		 *  @type     Array
    216 		 *  @default  []
    217 		 */
    218 		buttons: [],
    219
    220 		/**
    221 		 * Restore button
    222 		 *  @property restore
    223 		 *  @type     Node
    224 		 *  @default  null
    225 		 */
    226 		restore: null
    227 	};
    228
    229 	/* Store global reference */
    230 	ColVis.aInstances.push( this );
    231
    232 	/* Constructor logic */
    233 	this.s.dt = oDTSettings;
    234 	this._fnConstruct();
    235 	return this;
    236 };
    237
    238
    239
    240 ColVis.prototype = {
    241 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    242 	 * Public methods
    243 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    244
    245 	/**
    246 	 * Rebuild the list of buttons for this instance (i.e. if there is a column header update)
    247 	 *  @method  fnRebuild
    248 	 *  @returns void
    249 	 */
    250 	fnRebuild: function ()
    251 	{
    252 		/* Remove the old buttons */
    253 		for ( var i=this.dom.buttons.length-1 ; i>=0 ; i-- )
    254 		{
    255 			if ( this.dom.buttons[i] !== null )
    256 			{
    257 				this.dom.collection.removeChild( this.dom.buttons[i] );
    258 			}
    259 		}
    260 		this.dom.buttons.splice( 0, this.dom.buttons.length );
    261
    262 		if ( this.dom.restore )
    263 		{
    264 			this.dom.restore.parentNode( this.dom.restore );
    265 		}
    266
    267 		/* Re-add them (this is not the optimal way of doing this, it is fast and effective) */
    268 		this._fnAddButtons();
    269
    270 		/* Update the checkboxes */
    271 		this._fnDrawCallback();
    272 	},
    273
    274
    275
    276 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    277 	 * Private methods (they are of course public in JS, but recommended as private)
    278 	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    279
    280 	/**
    281 	 * Constructor logic
    282 	 *  @method  _fnConstruct
    283 	 *  @returns void
    284 	 *  @private
    285 	 */
    286 	_fnConstruct: function ()
    287 	{
    288 		this._fnApplyCustomisation();
    289
    290 		var that = this;
    291 		this.dom.wrapper = document.createElement('div');
    292 		this.dom.wrapper.className = "ColVis TableTools";
    293
    294 		this.dom.button = this._fnDomBaseButton( this.s.buttonText );
    295 		this.dom.button.className += " ColVis_MasterButton";
    296 		this.dom.wrapper.appendChild( this.dom.button );
    297
    298 		this.dom.catcher = this._fnDomCatcher();
    299 		this.dom.collection = this._fnDomCollection();
    300 		this.dom.background = this._fnDomBackground();
    301
    302 		this._fnAddButtons();
    303
    304 		/* Store the original visbility information */
    305 		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
    306 		{
    307 			this.s.abOriginal.push( this.s.dt.aoColumns[i].bVisible );
    308 		}
    309
    310 		/* Update on each draw */
    311 		this.s.dt.aoDrawCallback.push( {
    312 			fn: function () {
    313 				that._fnDrawCallback.call( that );
    314 			},
    315 			sName: "ColVis"
    316 		} );
    317 	},
    318
    319
    320 	/**
    321 	 * Apply any customisation to the settings from the DataTables initialisation
    322 	 *  @method  _fnApplyCustomisation
    323 	 *  @returns void
    324 	 *  @private
    325 	 */
    326 	_fnApplyCustomisation: function ()
    327 	{
    328 		var oConfig = this.s.oInit;
    329
    330 		if ( typeof oConfig.activate != 'undefined' )
    331 		{
    332 			this.s.activate = oConfig.activate;
    333 		}
    334
    335 		if ( typeof oConfig.buttonText != 'undefined' )
    336 		{
    337 			this.s.buttonText = oConfig.buttonText;
    338 		}
    339
    340 		if ( typeof oConfig.aiExclude != 'undefined' )
    341 		{
    342 			this.s.aiExclude = oConfig.aiExclude;
    343 		}
    344
    345 		if ( typeof oConfig.bRestore != 'undefined' )
    346 		{
    347 			this.s.bRestore = oConfig.bRestore;
    348 		}
    349
    350 		if ( typeof oConfig.sRestore != 'undefined' )
    351 		{
    352 			this.s.sRestore = oConfig.sRestore;
    353 		}
    354
    355 		if ( typeof oConfig.sAlign != 'undefined' )
    356 		{
    357 			this.s.sAlign = oConfig.sAlign;
    358 		}
    359
    360 		if ( typeof oConfig.fnStateChange != 'undefined' )
    361 		{
    362 			this.s.fnStateChange = oConfig.fnStateChange;
    363 		}
    364
    365 		if ( typeof oConfig.iOverlayFade != 'undefined' )
    366 		{
    367 			this.s.iOverlayFade = oConfig.iOverlayFade;
    368 		}
    369
    370 		if ( typeof oConfig.fnLabel != 'undefined' )
    371 		{
    372 			this.s.fnLabel = oConfig.fnLabel;
    373 		}
    374 	},
    375
    376
    377 	/**
    378 	 * On each table draw, check the visiblity checkboxes as needed. This allows any process to
    379 	 * update the table's column visiblity and ColVis will still be accurate.
    380 	 *  @method  _fnDrawCallback
    381 	 *  @returns void
    382 	 *  @private
    383 	 */
    384 	_fnDrawCallback: function ()
    385 	{
    386 		var aoColumns = this.s.dt.aoColumns;
    387
    388 		for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
    389 		{
    390 			if ( this.dom.buttons[i] !== null )
    391 			{
    392 				if ( aoColumns[i].bVisible )
    393 				{
    394 					$('input', this.dom.buttons[i]).attr('checked','checked');
    395 				}
    396 				else
    397 				{
    398 					$('input', this.dom.buttons[i]).removeAttr('checked');
    399 				}
    400 			}
    401 		}
    402 	},
    403
    404
    405 	/**
    406 	 * Loop through the columns in the table and as a new button for each one.
    407 	 *  @method  _fnAddButtons
    408 	 *  @returns void
    409 	 *  @private
    410 	 */
    411 	_fnAddButtons: function ()
    412 	{
    413 		var
    414 			nButton,
    415 			sExclude = ","+this.s.aiExclude.join(',')+",";
    416
    417 		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
    418 		{
    419 			if ( sExclude.indexOf( ","+i+"," ) == -1 )
    420 			{
    421 				nButton = this._fnDomColumnButton( i );
    422 				this.dom.buttons.push( nButton );
    423 				this.dom.collection.appendChild( nButton );
    424 			}
    425 			else
    426 			{
    427 				this.dom.buttons.push( null );
    428 			}
    429 		}
    430
    431 		if ( this.s.bRestore )
    432 		{
    433 			nButton = this._fnDomRestoreButton();
    434 			nButton.className += " ColVis_Restore";
    435 			this.dom.buttons.push( nButton );
    436 			this.dom.collection.appendChild( nButton );
    437 		}
    438 	},
    439
    440
    441 	/**
    442 	 * Create a button which allows a "restore" action
    443 	 *  @method  _fnDomRestoreButton
    444 	 *  @returns {Node} Created button
    445 	 *  @private
    446 	 */
    447 	_fnDomRestoreButton: function ()
    448 	{
    449 		var
    450 			that = this,
    451 		  nButton = document.createElement('button'),
    452 		  nSpan = document.createElement('span');
    453
    454 		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
    455 			"ColVis_Button TableTools_Button ui-button ui-state-default";
    456 		nButton.appendChild( nSpan );
    457 		$(nSpan).html( '<span class="ColVis_title">'+this.s.sRestore+'</span>' );
    458
    459 		$(nButton).click( function (e) {
    460 			for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ )
    461 			{
    462 				that.s.dt.oInstance.fnSetColumnVis( i, that.s.abOriginal[i], false );
    463 			}
    464 			that.s.dt.oInstance.fnDraw( false );
    465 		} );
    466
    467 		return nButton;
    468 	},
    469
    470
    471 	/**
    472 	 * Create the DOM for a show / hide button
    473 	 *  @method  _fnDomColumnButton
    474 	 *  @param {int} i Column in question
    475 	 *  @returns {Node} Created button
    476 	 *  @private
    477 	 */
    478 	_fnDomColumnButton: function ( i )
    479 	{
    480 		var
    481 			that = this,
    482 			oColumn = this.s.dt.aoColumns[i],
    483 		  nButton = document.createElement('button'),
    484 		  nSpan = document.createElement('span');
    485
    486 		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
    487 			"ColVis_Button TableTools_Button ui-button ui-state-default";
    488 		nButton.appendChild( nSpan );
    489 		var sTitle = this.s.fnLabel===null ? oColumn.sTitle : this.s.fnLabel( i, oColumn.sTitle, oColumn.nTh );
    490 		$(nSpan).html(
    491 			'<span class="ColVis_radio"><input type="checkbox"></span>'+
    492 			'<span class="ColVis_title">'+sTitle+'</span>' );
    493
    494 		$(nButton).click( function (e) {
    495 			var showHide = !$('input', this).is(":checked");
    496 			if ( e.target.nodeName.toLowerCase() == "input" )
    497 			{
    498 				showHide = $('input', this).is(":checked");
    499 			}
    500
    501 			/* Need to consider the case where the initialiser created more than one table - change the
    502 			 * API index that DataTables is using
    503 			 */
    504 			var oldIndex = $.fn.dataTableExt.iApiIndex;
    505 			$.fn.dataTableExt.iApiIndex = that._fnDataTablesApiIndex.call(that);
    506 			that.s.dt.oInstance.fnSetColumnVis( i, showHide );
    507 			$.fn.dataTableExt.iApiIndex = oldIndex; /* Restore */
    508
    509 			if ( that.s.fnStateChange !== null )
    510 			{
    511 				that.s.fnStateChange.call( that, i, showHide );
    512 			}
    513 		} );
    514
    515 		return nButton;
    516 	},
    517
    518
    519 	/**
    520 	 * Get the position in the DataTables instance array of the table for this instance of ColVis
    521 	 *  @method  _fnDataTablesApiIndex
    522 	 *  @returns {int} Index
    523 	 *  @private
    524 	 */
    525 	_fnDataTablesApiIndex: function ()
    526 	{
    527 		for ( var i=0, iLen=this.s.dt.oInstance.length ; i<iLen ; i++ )
    528 		{
    529 			if ( this.s.dt.oInstance[i] == this.s.dt.nTable )
    530 			{
    531 				return i;
    532 			}
    533 		}
    534 		return 0;
    535 	},
    536
    537
    538 	/**
    539 	 * Create the DOM needed for the button and apply some base properties. All buttons start here
    540 	 *  @method  _fnDomBaseButton
    541 	 *  @param   {String} text Button text
    542 	 *  @returns {Node} DIV element for the button
    543 	 *  @private
    544 	 */
    545 	_fnDomBaseButton: function ( text )
    546 	{
    547 		var
    548 			that = this,
    549 		  nButton = document.createElement('button'),
    550 		  nSpan = document.createElement('span'),
    551 			sEvent = this.s.activate=="mouseover" ? "mouseover" : "click";
    552
    553 		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
    554 			"ColVis_Button TableTools_Button ui-button ui-state-default";
    555 		nButton.appendChild( nSpan );
    556 		nSpan.innerHTML = text;
    557
    558 		$(nButton).bind( sEvent, function (e) {
    559 			that._fnCollectionShow();
    560 			e.preventDefault();
    561 		} );
    562
    563 		return nButton;
    564 	},
    565
    566
    567 	/**
    568 	 * Create the element used to contain list the columns (it is shown and hidden as needed)
    569 	 *  @method  _fnDomCollection
    570 	 *  @returns {Node} div container for the collection
    571 	 *  @private
    572 	 */
    573 	_fnDomCollection: function ()
    574 	{
    575 		var that = this;
    576 		var nHidden = document.createElement('div');
    577 		nHidden.style.display = "none";
    578 		nHidden.className = !this.s.dt.bJUI ? "ColVis_collection TableTools_collection" :
    579 			"ColVis_collection TableTools_collection ui-buttonset ui-buttonset-multi";
    580 		nHidden.style.position = "absolute";
    581 		$(nHidden).css('opacity', 0);
    582
    583 		return nHidden;
    584 	},
    585
    586
    587 	/**
    588 	 * An element to be placed on top of the activate button to catch events
    589 	 *  @method  _fnDomCatcher
    590 	 *  @returns {Node} div container for the collection
    591 	 *  @private
    592 	 */
    593 	_fnDomCatcher: function ()
    594 	{
    595 		var
    596 			that = this,
    597 			nCatcher = document.createElement('div');
    598 		nCatcher.className = "ColVis_catcher TableTools_catcher";
    599
    600 		$(nCatcher).click( function () {
    601 			that._fnCollectionHide.call( that, null, null );
    602 		} );
    603
    604 		return nCatcher;
    605 	},
    606
    607
    608 	/**
    609 	 * Create the element used to shade the background, and capture hide events (it is shown and
    610 	 * hidden as needed)
    611 	 *  @method  _fnDomBackground
    612 	 *  @returns {Node} div container for the background
    613 	 *  @private
    614 	 */
    615 	_fnDomBackground: function ()
    616 	{
    617 		var that = this;
    618
    619 		var nBackground = document.createElement('div');
    620 		nBackground.style.position = "absolute";
    621 		nBackground.style.left = "0px";
    622 		nBackground.style.top = "0px";
    623 		nBackground.className = "ColVis_collectionBackground TableTools_collectionBackground";
    624 		$(nBackground).css('opacity', 0);
    625
    626 		$(nBackground).click( function () {
    627 			that._fnCollectionHide.call( that, null, null );
    628 		} );
    629
    630 		/* When considering a mouse over action for the activation, we also consider a mouse out
    631 		 * which is the same as a mouse over the background - without all the messing around of
    632 		 * bubbling events. Use the catcher element to avoid messing around with bubbling
    633 		 */
    634 		if ( this.s.activate == "mouseover" )
    635 		{
    636 			$(nBackground).mouseover( function () {
    637 				that.s.overcollection = false;
    638 				that._fnCollectionHide.call( that, null, null );
    639 			} );
    640 		}
    641
    642 		return nBackground;
    643 	},
    644
    645
    646 	/**
    647 	 * Show the show / hide list and the background
    648 	 *  @method  _fnCollectionShow
    649 	 *  @returns void
    650 	 *  @private
    651 	 */
    652 	_fnCollectionShow: function ()
    653 	{
    654 		var that = this, i, iLen;
    655 		var oPos = $(this.dom.button).offset();
    656 		var nHidden = this.dom.collection;
    657 		var nBackground = this.dom.background;
    658 		var iDivX = parseInt(oPos.left, 10);
    659 		var iDivY = parseInt(oPos.top + $(this.dom.button).outerHeight(), 10);
    660
    661 		nHidden.style.top = iDivY+"px";
    662 		nHidden.style.left = iDivX+"px";
    663 		nHidden.style.display = "block";
    664 		$(nHidden).css('opacity',0);
    665
    666 		var iWinHeight = $(window).height(), iDocHeight = $(document).height(),
    667 		 	iWinWidth = $(window).width(), iDocWidth = $(document).width();
    668
    669 		nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px";
    670 		nBackground.style.width = ((iWinWidth<iDocWidth)? iWinWidth : iDocWidth) +"px";
    671
    672 		var oStyle = this.dom.catcher.style;
    673 		oStyle.height = $(this.dom.button).outerHeight()+"px";
    674 		oStyle.width = $(this.dom.button).outerWidth()+"px";
    675 		oStyle.top = oPos.top+"px";
    676 		oStyle.left = iDivX+"px";
    677
    678 		document.body.appendChild( nBackground );
    679 		document.body.appendChild( nHidden );
    680 		document.body.appendChild( this.dom.catcher );
    681
    682 		/* Resize the buttons */
    683 		if ( this.s.sSize == "auto" )
    684 		{
    685 			var aiSizes = [];
    686 			this.dom.collection.style.width = "auto";
    687 			for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
    688 			{
    689 				if ( this.dom.buttons[i] !== null )
    690 				{
    691 					this.dom.buttons[i].style.width = "auto";
    692 					aiSizes.push( $(this.dom.buttons[i]).outerWidth() );
    693 				}
    694 			}
    695 			iMax = Math.max.apply(window, aiSizes);
    696 			for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
    697 			{
    698 				if ( this.dom.buttons[i] !== null )
    699 				{
    700 					this.dom.buttons[i].style.width = iMax+"px";
    701 				}
    702 			}
    703 			this.dom.collection.style.width = iMax+"px";
    704 		}
    705
    706 		/* Visual corrections to try and keep the collection visible */
    707 		nHidden.style.left = this.s.sAlign=="left" ?
    708 			iDivX+"px" : (iDivX-$(nHidden).outerWidth()+$(this.dom.button).outerWidth())+"px";
    709
    710 		var iDivWidth = $(nHidden).outerWidth();
    711 		var iDivHeight = $(nHidden).outerHeight();
    712
    713 		if ( iDivX + iDivWidth > iDocWidth )
    714 		{
    715 			nHidden.style.left = (iDocWidth-iDivWidth)+"px";
    716 		}
    717
    718
    719 		/* This results in a very small delay for the end user but it allows the animation to be
    720 		 * much smoother. If you don't want the animation, then the setTimeout can be removed
    721 		 */
    722 		setTimeout( function () {
    723 			$(nHidden).animate({opacity: 1}, that.s.iOverlayFade);
    724 			$(nBackground).animate({opacity: 0.1}, that.s.iOverlayFade, 'linear', function () {
    725 				/* In IE6 if you set the checked attribute of a hidden checkbox, then this is not visually
    726 				 * reflected. As such, we need to do it here, once it is visible. Unbelievable.
    727 				 */
    728 				if ( jQuery.browser.msie && jQuery.browser.version == "6.0" )
    729 				{
    730 					that._fnDrawCallback();
    731 				}
    732 			});
    733 		}, 10 );
    734
    735 		this.s.hidden = false;
    736 	},
    737
    738
    739 	/**
    740 	 * Hide the show / hide list and the background
    741 	 *  @method  _fnCollectionHide
    742 	 *  @returns void
    743 	 *  @private
    744 	 */
    745 	_fnCollectionHide: function (  )
    746 	{
    747 		var that = this;
    748
    749 		if ( !this.s.hidden && this.dom.collection !== null )
    750 		{
    751 			this.s.hidden = true;
    752
    753 			$(this.dom.collection).animate({opacity: 0}, that.s.iOverlayFade, function (e) {
    754 				this.style.display = "none";
    755 			} );
    756
    757 			$(this.dom.background).animate({opacity: 0}, that.s.iOverlayFade, function (e) {
    758 				document.body.removeChild( that.dom.background );
    759 				document.body.removeChild( that.dom.catcher );
    760 			} );
    761 		}
    762 	}
    763 };
    764
    765
    766
    767
    768
    769 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    770  * Static object methods
    771  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    772
    773 /**
    774  * Rebuild the collection for a given table, or all tables if no parameter given
    775  *  @method  ColVis.fnRebuild
    776  *  @static
    777  *  @param   object oTable DataTable instance to consider - optional
    778  *  @returns void
    779  */
    780 ColVis.fnRebuild = function ( oTable )
    781 {
    782 	var nTable = null;
    783 	if ( typeof oTable != 'undefined' )
    784 	{
    785 		nTable = oTable.fnSettings().nTable;
    786 	}
    787
    788 	for ( var i=0, iLen=ColVis.aInstances.length ; i<iLen ; i++ )
    789 	{
    790 		if ( typeof oTable == 'undefined' || nTable == ColVis.aInstances[i].s.dt.nTable )
    791 		{
    792 			ColVis.aInstances[i].fnRebuild();
    793 		}
    794 	}
    795 };
    796
    797
    798
    799
    800
    801 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    802  * Static object propterties
    803  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    804
    805 /**
    806  * Collection of all ColVis instances
    807  *  @property ColVis.aInstances
    808  *  @static
    809  *  @type     Array
    810  *  @default  []
    811  */
    812 ColVis.aInstances = [];
    813
    814
    815
    816
    817
    818 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    819  * Constants
    820  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    821
    822 /**
    823  * Name of this class
    824  *  @constant CLASS
    825  *  @type     String
    826  *  @default  ColVis
    827  */
    828 ColVis.prototype.CLASS = "ColVis";
    829
    830
    831 /**
    832  * ColVis version
    833  *  @constant  VERSION
    834  *  @type      String
    835  *  @default   See code
    836  */
    837 ColVis.VERSION = "1.0.6";
    838 ColVis.prototype.VERSION = ColVis.VERSION;
    839
    840
    841
    842
    843
    844 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
    845  * Initialisation
    846  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    847
    848 /*
    849  * Register a new feature with DataTables
    850  */
    851 if ( typeof $.fn.dataTable == "function" &&
    852      typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
    853      $.fn.dataTableExt.fnVersionCheck('1.7.0') )
    854 {
    855 	$.fn.dataTableExt.aoFeatures.push( {
    856 		fnInit: function( oDTSettings ) {
    857 			var init = (typeof oDTSettings.oInit.oColVis == 'undefined') ?
    858 				{} : oDTSettings.oInit.oColVis;
    859 			var oColvis = new ColVis( oDTSettings, init );
    860 			return oColvis.dom.wrapper;
    861 		},
    862 		cFeature: "C",
    863 		sFeature: "ColVis"
    864 	} );
    865 }
    866 else
    867 {
    868 	alert( "Warning: ColVis requires DataTables 1.7 or greater - www.datatables.net/download");
    869 }
    870
    871 })(jQuery);
    872