1 /*
  2  * File:        ColVis.js
  3  * Version:     1.0.5
  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 				this.dom.buttons[i].style.width = "auto";
690 				aiSizes.push( $(this.dom.buttons[i]).outerWidth() );
691 			}
692 			iMax = Math.max.apply(window, aiSizes);
693 			for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
694 			{
695 				this.dom.buttons[i].style.width = iMax+"px";
696 			}
697 			this.dom.collection.style.width = iMax+"px";
698 		}
699 		
700 		/* Visual corrections to try and keep the collection visible */
701 		nHidden.style.left = this.s.sAlign=="left" ?
702 			iDivX+"px" : (iDivX-$(nHidden).outerWidth()+$(this.dom.button).outerWidth())+"px";
703 		
704 		var iDivWidth = $(nHidden).outerWidth();
705 		var iDivHeight = $(nHidden).outerHeight();
706 		
707 		if ( iDivX + iDivWidth > iDocWidth )
708 		{
709 			nHidden.style.left = (iDocWidth-iDivWidth)+"px";
710 		}
711 		
712 		
713 		/* This results in a very small delay for the end user but it allows the animation to be
714 		 * much smoother. If you don't want the animation, then the setTimeout can be removed
715 		 */
716 		setTimeout( function () {
717 			$(nHidden).animate({opacity: 1}, that.s.iOverlayFade);
718 			$(nBackground).animate({opacity: 0.1}, that.s.iOverlayFade, 'linear', function () {
719 				/* In IE6 if you set the checked attribute of a hidden checkbox, then this is not visually
720 				 * reflected. As such, we need to do it here, once it is visible. Unbelievable.
721 				 */
722 				if ( jQuery.browser.msie && jQuery.browser.version == "6.0" )
723 				{
724 					that._fnDrawCallback();
725 				}
726 			});
727 		}, 10 );
728 		
729 		this.s.hidden = false;
730 	},
731 	
732 	
733 	/**
734 	 * Hide the show / hide list and the background
735 	 *  @method  _fnCollectionHide
736 	 *  @returns void
737 	 *  @private 
738 	 */
739 	_fnCollectionHide: function (  )
740 	{
741 		var that = this;
742 		
743 		if ( !this.s.hidden && this.dom.collection !== null )
744 		{
745 			this.s.hidden = true;
746 			
747 			$(this.dom.collection).animate({opacity: 0}, that.s.iOverlayFade, function (e) {
748 				this.style.display = "none";
749 			} );
750 			
751 			$(this.dom.background).animate({opacity: 0}, that.s.iOverlayFade, function (e) {
752 				document.body.removeChild( that.dom.background );
753 				document.body.removeChild( that.dom.catcher );
754 			} );
755 		}
756 	}
757 };
758 
759 
760 
761 
762 
763 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
764  * Static object methods
765  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
766 
767 /**
768  * Rebuild the collection for a given table, or all tables if no parameter given
769  *  @method  ColVis.fnRebuild
770  *  @static
771  *  @param   object oTable DataTable instance to consider - optional
772  *  @returns void
773  */
774 ColVis.fnRebuild = function ( oTable )
775 {
776 	var nTable = null;
777 	if ( typeof oTable != 'undefined' )
778 	{
779 		nTable = oTable.fnSettings().nTable;
780 	}
781 	
782 	for ( var i=0, iLen=ColVis.aInstances.length ; i<iLen ; i++ )
783 	{
784 		if ( typeof oTable == 'undefined' || nTable == ColVis.aInstances[i].s.dt.nTable )
785 		{
786 			ColVis.aInstances[i].fnRebuild();
787 		}
788 	}
789 };
790 
791 
792 
793 
794 
795 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
796  * Static object propterties
797  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
798 
799 /**
800  * Collection of all ColVis instances
801  *  @property ColVis.aInstances
802  *  @static
803  *  @type     Array
804  *  @default  []
805  */
806 ColVis.aInstances = [];
807 
808 
809 
810 
811 
812 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
813  * Constants
814  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
815 
816 /**
817  * Name of this class
818  *  @constant CLASS
819  *  @type     String
820  *  @default  ColVis
821  */
822 ColVis.prototype.CLASS = "ColVis";
823 
824 
825 /**
826  * ColVis version
827  *  @constant  VERSION
828  *  @type      String
829  *  @default   1.0.4.dev
830  */
831 ColVis.VERSION = "1.0.5";
832 ColVis.prototype.VERSION = ColVis.VERSION;
833 
834 
835 
836 
837 
838 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
839  * Initialisation
840  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
841 
842 /*
843  * Register a new feature with DataTables
844  */
845 if ( typeof $.fn.dataTable == "function" &&
846      typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
847      $.fn.dataTableExt.fnVersionCheck('1.7.0') )
848 {
849 	$.fn.dataTableExt.aoFeatures.push( {
850 		fnInit: function( oDTSettings ) {
851 			var init = (typeof oDTSettings.oInit.oColVis == 'undefined') ?
852 				{} : oDTSettings.oInit.oColVis;
853 			var oColvis = new ColVis( oDTSettings, init );
854 			return oColvis.dom.wrapper;
855 		},
856 		cFeature: "C",
857 		sFeature: "ColVis"
858 	} );
859 }
860 else
861 {
862 	alert( "Warning: ColVis requires DataTables 1.7 or greater - www.datatables.net/download");
863 }
864 
865 })(jQuery);
866