PageSourceSearch

https://langleywa.org/_assets_/js/jquery.dataTables2.js

js langleywa.org collected 2026-10-02 06:04:54 UTC 413,880 bytes, 24,198 lines download raw bytes

1/**
2
3 * @summary     DataTables
4
5 * @description Paginate, search and sort HTML tables
6
7 * @version     1.9.4
8
9 * @file        jquery.dataTables.js
10
11 * @author      Allan Jardine (www.sprymedia.co.uk)
12
13 * @contact     www.sprymedia.co.uk/contact
14
15 *
16
17 * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
18
19 *
20
21 * This source file is free software, under either the GPL v2 license or a
22
23 * BSD style license, available at:
24
25 *   http://datatables.net/license_gpl2
26
27 *   http://datatables.net/license_bsd
28
29 * 
30
31 * This source file is distributed in the hope that it will be useful, but 
32
33 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
34
35 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
36
37 * 
38
39 * For details please refer to: http://www.datatables.net
40
41 */
42
43
44
45/*jslint evil: true, undef: true, browser: true */
46
47/*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns*/
48
49
50
51(/** @lends <global> */function( window, document, undefined ) {
52
53
54
55(function( factory ) {
56
57	"use strict";
58
59
60
61	// Define as an AMD module if possible
62
63	if ( typeof define === 'function' && define.amd )
64
65	{
66
67		define( ['jquery'], factory );
68
69	}
70
71	/* Define using browser globals otherwise
72
73	 * Prevent multiple instantiations if the script is loaded twice
74
75	 */
76
77	else if ( jQuery && !jQuery.fn.dataTable )
78
79	{
80
81		factory( jQuery );
82
83	}
84
85}
86
87(/** @lends <global> */function( $ ) {
88
89	"use strict";
90
91	/** 
92
93	 * DataTables is a plug-in for the jQuery Javascript library. It is a 
94
95	 * highly flexible tool, based upon the foundations of progressive 
96
97	 * enhancement, which will add advanced interaction controls to any 
98
99	 * HTML table. For a full list of features please refer to
100
101	 * <a href="http://datatables.net">DataTables.net</a>.
102
103	 *
104
105	 * Note that the <i>DataTable</i> object is not a global variable but is
106
107	 * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which 
108
109	 * it may be  accessed.
110
111	 *
112
113	 *  @class
114
115	 *  @param {object} [oInit={}] Configuration object for DataTables. Options
116
117	 *    are defined by {@link DataTable.defaults}
118
119	 *  @requires jQuery 1.3+
120
121	 * 
122
123	 *  @example
124
125	 *    // Basic initialisation
126
127	 *    $(document).ready( function {
128
129	 *      $('#example').dataTable();
130
131	 *    } );
132
133	 *  
134
135	 *  @example
136
137	 *    // Initialisation with configuration options - in this case, disable
138
139	 *    // pagination and sorting.
140
141	 *    $(document).ready( function {
142
143	 *      $('#example').dataTable( {
144
145	 *        "bPaginate": false,
146
147	 *        "bSort": false 
148
149	 *      } );
150
151	 *    } );
152
153	 */
154
155	var DataTable = function( oInit )
156
157	{
158
159		
160
161		
162
163		/**
164
165		 * Add a column to the list used for the table with default values
166
167		 *  @param {object} oSettings dataTables settings object
168
169		 *  @param {node} nTh The th element for this column
170
171		 *  @memberof DataTable#oApi
172
173		 */
174
175		function _fnAddColumn( oSettings, nTh )
176
177		{
178
179			var oDefaults = DataTable.defaults.columns;
180
181			var iCol = oSettings.aoColumns.length;
182
183			var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
184
185				"sSortingClass": oSettings.oClasses.sSortable,
186
187				"sSortingClassJUI": oSettings.oClasses.sSortJUI,
188
189				"nTh": nTh ? nTh : document.createElement('th'),
190
191				"sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
192
193				"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
194
195				"mData": oDefaults.mData ? oDefaults.oDefaults : iCol
196
197			} );
198
199			oSettings.aoColumns.push( oCol );
200
201			
202
203			/* Add a column specific filter */
204
205			if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
206
207			{
208
209				oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
210
211			}
212
213			else
214
215			{
216
217				var oPre = oSettings.aoPreSearchCols[ iCol ];
218
219				
220
221				/* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
222
223				if ( oPre.bRegex === undefined )
224
225				{
226
227					oPre.bRegex = true;
228
229				}
230
231				
232
233				if ( oPre.bSmart === undefined )
234
235				{
236
237					oPre.bSmart = true;
238
239				}
240
241				
242
243				if ( oPre.bCaseInsensitive === undefined )
244
245				{
246
247					oPre.bCaseInsensitive = true;
248
249				}
250
251			}
252
253			
254
255			/* Use the column options function to initialise classes etc */
256
257			_fnColumnOptions( oSettings, iCol, null );
258
259		}
260
261		
262
263		
264
265		/**
266
267		 * Apply options for a column
268
269		 *  @param {object} oSettings dataTables settings object
270
271		 *  @param {int} iCol column index to consider
272
273		 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
274
275		 *  @memberof DataTable#oApi
276
277		 */
278
279		function _fnColumnOptions( oSettings, iCol, oOptions )
280
281		{
282
283			var oCol = oSettings.aoColumns[ iCol ];
284
285			
286
287			/* User specified column options */
288
289			if ( oOptions !== undefined && oOptions !== null )
290
291			{
292
293				/* Backwards compatibility for mDataProp */
294
295				if ( oOptions.mDataProp && !oOptions.mData )
296
297				{
298
299					oOptions.mData = oOptions.mDataProp;
300
301				}
302
303		
304
305				if ( oOptions.sType !== undefined )
306
307				{
308
309					oCol.sType = oOptions.sType;
310
311					oCol._bAutoType = false;
312
313				}
314
315				
316
317				$.extend( oCol, oOptions );
318
319				_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
320
321		
322
323				/* iDataSort to be applied (backwards compatibility), but aDataSort will take
324
325				 * priority if defined
326
327				 */
328
329				if ( oOptions.iDataSort !== undefined )
330
331				{
332
333					oCol.aDataSort = [ oOptions.iDataSort ];
334
335				}
336
337				_fnMap( oCol, oOptions, "aDataSort" );
338
339			}
340
341		
342
343			/* Cache the data get and set functions for speed */
344
345			var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
346
347			var mData = _fnGetObjectDataFn( oCol.mData );
348
349		
350
351			oCol.fnGetData = function (oData, sSpecific) {
352
353				var innerData = mData( oData, sSpecific );
354
355		
356
357				if ( oCol.mRender && (sSpecific && sSpecific !== '') )
358
359				{
360
361					return mRender( innerData, sSpecific, oData );
362
363				}
364
365				return innerData;
366
367			};
368
369			oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
370
371			
372
373			/* Feature sorting overrides column specific when off */
374
375			if ( !oSettings.oFeatures.bSort )
376
377			{
378
379				oCol.bSortable = false;
380
381			}
382
383			
384
385			/* Check that the class assignment is correct for sorting */
386
387			if ( !oCol.bSortable ||
388
389				 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
390
391			{
392
393				oCol.sSortingClass = oSettings.oClasses.sSortableNone;
394
395				oCol.sSortingClassJUI = "";
396
397			}
398
399			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )
400
401			{
402
403				oCol.sSortingClass = oSettings.oClasses.sSortable;
404
405				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
406
407			}
408
409			else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
410
411			{
412
413				oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
414
415				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
416
417			}
418
419			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
420
421			{
422
423				oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
424
425				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
426
427			}
428
429		}
430
431		
432
433		
434
435		/**
436
437		 * Adjust the table column widths for new data. Note: you would probably want to 
438
439		 * do a redraw after calling this function!
440
441		 *  @param {object} oSettings dataTables settings object
442
443		 *  @memberof DataTable#oApi
444
445		 */
446
447		function _fnAdjustColumnSizing ( oSettings )
448
449		{
450
451			/* Not interested in doing column width calculation if auto-width is disabled */
452
453			if ( oSettings.oFeatures.bAutoWidth === false )
454
455			{
456
457				return false;
458
459			}
460
461			
462
463			_fnCalculateColumnWidths( oSettings );
464
465			for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
466
467			{
468
469				oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
470
471			}
472
473		}
474
475		
476
477		
478
479		/**
480
481		 * Covert the index of a visible column to the index in the data array (take account
482
483		 * of hidden columns)
484
485		 *  @param {object} oSettings dataTables settings object
486
487		 *  @param {int} iMatch Visible column index to lookup
488
489		 *  @returns {int} i the data index
490
491		 *  @memberof DataTable#oApi
492
493		 */
494
495		function _fnVisibleToColumnIndex( oSettings, iMatch )
496
497		{
498
499			var aiVis = _fnGetColumns( oSettings, 'bVisible' );
500
501		
502
503			return typeof aiVis[iMatch] === 'number' ?
504
505				aiVis[iMatch] :
506
507				null;
508
509		}
510
511		
512
513		
514
515		/**
516
517		 * Covert the index of an index in the data array and convert it to the visible
518
519		 *   column index (take account of hidden columns)
520
521		 *  @param {int} iMatch Column index to lookup
522
523		 *  @param {object} oSettings dataTables settings object
524
525		 *  @returns {int} i the data index
526
527		 *  @memberof DataTable#oApi
528
529		 */
530
531		function _fnColumnIndexToVisible( oSettings, iMatch )
532
533		{
534
535			var aiVis = _fnGetColumns( oSettings, 'bVisible' );
536
537			var iPos = $.inArray( iMatch, aiVis );
538
539		
540
541			return iPos !== -1 ? iPos : null;
542
543		}
544
545		
546
547		
548
549		/**
550
551		 * Get the number of visible columns
552
553		 *  @param {object} oSettings dataTables settings object
554
555		 *  @returns {int} i the number of visible columns
556
557		 *  @memberof DataTable#oApi
558
559		 */
560
561		function _fnVisbleColumns( oSettings )
562
563		{
564
565			return _fnGetColumns( oSettings, 'bVisible' ).length;
566
567		}
568
569		
570
571		
572
573		/**
574
575		 * Get an array of column indexes that match a given property
576
577		 *  @param {object} oSettings dataTables settings object
578
579		 *  @param {string} sParam Parameter in aoColumns to look for - typically 
580
581		 *    bVisible or bSearchable
582
583		 *  @returns {array} Array of indexes with matched properties
584
585		 *  @memberof DataTable#oApi
586
587		 */
588
589		function _fnGetColumns( oSettings, sParam )
590
591		{
592
593			var a = [];
594
595		
596
597			$.map( oSettings.aoColumns, function(val, i) {
598
599				if ( val[sParam] ) {
600
601					a.push( i );
602
603				}
604
605			} );
606
607		
608
609			return a;
610
611		}
612
613		
614
615		
616
617		/**
618
619		 * Get the sort type based on an input string
620
621		 *  @param {string} sData data we wish to know the type of
622
623		 *  @returns {string} type (defaults to 'string' if no type can be detected)
624
625		 *  @memberof DataTable#oApi
626
627		 */
628
629		function _fnDetectType( sData )
630
631		{
632
633			var aTypes = DataTable.ext.aTypes;
634
635			var iLen = aTypes.length;
636
637			
638
639			for ( var i=0 ; i<iLen ; i++ )
640
641			{
642
643				var sType = aTypes[i]( sData );
644
645				if ( sType !== null )
646
647				{
648
649					return sType;
650
651				}
652
653			}
654
655			
656
657			return 'string';
658
659		}
660
661		
662
663		
664
665		/**
666
667		 * Figure out how to reorder a display list
668
669		 *  @param {object} oSettings dataTables settings object
670
671		 *  @returns array {int} aiReturn index list for reordering
672
673		 *  @memberof DataTable#oApi
674
675		 */
676
677		function _fnReOrderIndex ( oSettings, sColumns )
678
679		{
680
681			var aColumns = sColumns.split(',');
682
683			var aiReturn = [];
684
685			
686
687			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
688
689			{
690
691				for ( var j=0 ; j<iLen ; j++ )
692
693				{
694
695					if ( oSettings.aoColumns[i].sName == aColumns[j] )
696
697					{
698
699						aiReturn.push( j );
700
701						break;
702
703					}
704
705				}
706
707			}
708
709			
710
711			return aiReturn;
712
713		}
714
715		
716
717		
718
719		/**
720
721		 * Get the column ordering that DataTables expects
722
723		 *  @param {object} oSettings dataTables settings object
724
725		 *  @returns {string} comma separated list of names
726
727		 *  @memberof DataTable#oApi
728
729		 */
730
731		function _fnColumnOrdering ( oSettings )
732
733		{
734
735			var sNames = '';
736
737			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
738
739			{
740
741				sNames += oSettings.aoColumns[i].sName+',';
742
743			}
744
745			if ( sNames.length == iLen )
746
747			{
748
749				return "";
750
751			}
752
753			return sNames.slice(0, -1);
754
755		}
756
757		
758
759		
760
761		/**
762
763		 * Take the column definitions and static columns arrays and calculate how
764
765		 * they relate to column indexes. The callback function will then apply the
766
767		 * definition found for a column to a suitable configuration object.
768
769		 *  @param {object} oSettings dataTables settings object
770
771		 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
772
773		 *  @param {array} aoCols The aoColumns array that defines columns individually
774
775		 *  @param {function} fn Callback function - takes two parameters, the calculated
776
777		 *    column index and the definition for that column.
778
779		 *  @memberof DataTable#oApi
780
781		 */
782
783		function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
784
785		{
786
787			var i, iLen, j, jLen, k, kLen;
788
789		
790
791			// Column definitions with aTargets
792
793			if ( aoColDefs )
794
795			{
796
797				/* Loop over the definitions array - loop in reverse so first instance has priority */
798
799				for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
800
801				{
802
803					/* Each definition can target multiple columns, as it is an array */
804
805					var aTargets = aoColDefs[i].aTargets;
806
807					if ( !$.isArray( aTargets ) )
808
809					{
810
811						_fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
812
813					}
814
815		
816
817					for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
818
819					{
820
821						if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
822
823						{
824
825							/* Add columns that we don't yet know about */
826
827							while( oSettings.aoColumns.length <= aTargets[j] )
828
829							{
830
831								_fnAddColumn( oSettings );
832
833							}
834
835		
836
837							/* Integer, basic index */
838
839							fn( aTargets[j], aoColDefs[i] );
840
841						}
842
843						else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
844
845						{
846
847							/* Negative integer, right to left column counting */
848
849							fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
850
851						}
852
853						else if ( typeof aTargets[j] === 'string' )
854
855						{
856
857							/* Class name matching on TH element */
858
859							for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
860
861							{
862
863								if ( aTargets[j] == "_all" ||
864
865								     $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
866
867								{
868
869									fn( k, aoColDefs[i] );
870
871								}
872
873							}
874
875						}
876
877					}
878
879				}
880
881			}
882
883		
884
885			// Statically defined columns array
886
887			if ( aoCols )
888
889			{
890
891				for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
892
893				{
894
895					fn( i, aoCols[i] );
896
897				}
898
899			}
900
901		}
902
903		
904
905		/**
906
907		 * Add a data array to the table, creating DOM node etc. This is the parallel to 
908
909		 * _fnGatherData, but for adding rows from a Javascript source, rather than a
910
911		 * DOM source.
912
913		 *  @param {object} oSettings dataTables settings object
914
915		 *  @param {array} aData data array to be added
916
917		 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
918
919		 *  @memberof DataTable#oApi
920
921		 */
922
923		function _fnAddData ( oSettings, aDataSupplied )
924
925		{
926
927			var oCol;
928
929			
930
931			/* Take an independent copy of the data source so we can bash it about as we wish */
932
933			var aDataIn = ($.isArray(aDataSupplied)) ?
934
935				aDataSupplied.slice() :
936
937				$.extend( true, {}, aDataSupplied );
938
939			
940
941			/* Create the object for storing information about this new row */
942
943			var iRow = oSettings.aoData.length;
944
945			var oData = $.extend( true, {}, DataTable.models.oRow );
946
947			oData._aData = aDataIn;
948
949			oSettings.aoData.push( oData );
950
951		
952
953			/* Create the cells */
954
955			var nTd, sThisType;
956
957			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
958
959			{
960
961				oCol = oSettings.aoColumns[i];
962
963		
964
965				/* Use rendered data for filtering / sorting */
966
967				if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
968
969				{
970
971					_fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
972
973				}
974
975				else
976
977				{
978
979					_fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
980
981				}
982
983				
984
985				/* See if we should auto-detect the column type */
986
987				if ( oCol._bAutoType && oCol.sType != 'string' )
988
989				{
990
991					/* Attempt to auto detect the type - same as _fnGatherData() */
992
993					var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
994
995					if ( sVarType !== null && sVarType !== '' )
996
997					{
998
999						sThisType = _fnDetectType( sVarType );
1000
1001						if ( oCol.sType === null )
1002
1003						{
1004
1005							oCol.sType = sThisType;
1006
1007						}
1008
1009						else if ( oCol.sType != sThisType && oCol.sType != "html" )
1010
1011						{
1012
1013							/* String is always the 'fallback' option */
1014
1015							oCol.sType = 'string';
1016
1017						}
1018
1019					}
1020
1021				}
1022
1023			}
1024
1025			
1026
1027			/* Add to the display array */
1028
1029			oSettings.aiDisplayMaster.push( iRow );
1030
1031		
1032
1033			/* Create the DOM information */
1034
1035			if ( !oSettings.oFeatures.bDeferRender )
1036
1037			{
1038
1039				_fnCreateTr( oSettings, iRow );
1040
1041			}
1042
1043		
1044
1045			return iRow;
1046
1047		}
1048
1049		
1050
1051		
1052
1053		/**
1054
1055		 * Read in the data from the target table from the DOM
1056
1057		 *  @param {object} oSettings dataTables settings object
1058
1059		 *  @memberof DataTable#oApi
1060
1061		 */
1062
1063		function _fnGatherData( oSettings )
1064
1065		{
1066
1067			var iLoop, i, iLen, j, jLen, jInner,
1068
1069			 	nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
1070
1071				iRow, iRows, iColumn, iColumns, sNodeName,
1072
1073				oCol, oData;
1074
1075			
1076
1077			/*
1078
1079			 * Process by row first
1080
1081			 * Add the data object for the whole table - storing the tr node. Note - no point in getting
1082
1083			 * DOM based data if we are going to go and replace it with Ajax source data.
1084
1085			 */
1086
1087			if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
1088
1089			{
1090
1091				nTr = oSettings.nTBody.firstChild;
1092
1093				while ( nTr )
1094
1095				{
1096
1097					if ( nTr.nodeName.toUpperCase() == "TR" )
1098
1099					{
1100
1101						iThisIndex = oSettings.aoData.length;
1102
1103						nTr._DT_RowIndex = iThisIndex;
1104
1105						oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
1106
1107							"nTr": nTr
1108
1109						} ) );
1110
1111		
1112
1113						oSettings.aiDisplayMaster.push( iThisIndex );
1114
1115						nTd = nTr.firstChild;
1116
1117						jInner = 0;
1118
1119						while ( nTd )
1120
1121						{
1122
1123							sNodeName = nTd.nodeName.toUpperCase();
1124
1125							if ( sNodeName == "TD" || sNodeName == "TH" )
1126
1127							{
1128
1129								_fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
1130
1131								jInner++;
1132
1133							}
1134
1135							nTd = nTd.nextSibling;
1136
1137						}
1138
1139					}
1140
1141					nTr = nTr.nextSibling;
1142
1143				}
1144
1145			}
1146
1147			
1148
1149			/* Gather in the TD elements of the Table - note that this is basically the same as
1150
1151			 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
1152
1153			 * setup!
1154
1155			 */
1156
1157			nTrs = _fnGetTrNodes( oSettings );
1158
1159			nTds = [];
1160
1161			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
1162
1163			{
1164
1165				nTd = nTrs[i].firstChild;
1166
1167				while ( nTd )
1168
1169				{
1170
1171					sNodeName = nTd.nodeName.toUpperCase();
1172
1173					if ( sNodeName == "TD" || sNodeName == "TH" )
1174
1175					{
1176
1177						nTds.push( nTd );
1178
1179					}
1180
1181					nTd = nTd.nextSibling;
1182
1183				}
1184
1185			}
1186
1187			
1188
1189			/* Now process by column */
1190
1191			for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
1192
1193			{
1194
1195				oCol = oSettings.aoColumns[iColumn];
1196
1197		
1198
1199				/* Get the title of the column - unless there is a user set one */
1200
1201				if ( oCol.sTitle === null )
1202
1203				{
1204
1205					oCol.sTitle = oCol.nTh.innerHTML;
1206
1207				}
1208
1209				
1210
1211				var
1212
1213					bAutoType = oCol._bAutoType,
1214
1215					bRender = typeof oCol.fnRender === 'function',
1216
1217					bClass = oCol.sClass !== null,
1218
1219					bVisible = oCol.bVisible,
1220
1221					nCell, sThisType, sRendered, sValType;
1222
1223				
1224
1225				/* A single loop to rule them all (and be more efficient) */
1226
1227				if ( bAutoType || bRender || bClass || !bVisible )
1228
1229				{
1230
1231					for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
1232
1233					{
1234
1235						oData = oSettings.aoData[iRow];
1236
1237						nCell = nTds[ (iRow*iColumns) + iColumn ];
1238
1239						
1240
1241						/* Type detection */
1242
1243						if ( bAutoType && oCol.sType != 'string' )
1244
1245						{
1246
1247							sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
1248
1249							if ( sValType !== '' )
1250
1251							{
1252
1253								sThisType = _fnDetectType( sValType );
1254
1255								if ( oCol.sType === null )
1256
1257								{
1258
1259									oCol.sType = sThisType;
1260
1261								}
1262
1263								else if ( oCol.sType != sThisType && 
1264
1265								          oCol.sType != "html" )
1266
1267								{
1268
1269									/* String is always the 'fallback' option */
1270
1271									oCol.sType = 'string';
1272
1273								}
1274
1275							}
1276
1277						}
1278
1279		
1280
1281						if ( oCol.mRender )
1282
1283						{
1284
1285							// mRender has been defined, so we need to get the value and set it
1286
1287							nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
1288
1289						}
1290
1291						else if ( oCol.mData !== iColumn )
1292
1293						{
1294
1295							// If mData is not the same as the column number, then we need to
1296
1297							// get the dev set value. If it is the column, no point in wasting
1298
1299							// time setting the value that is already there!
1300
1301							nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
1302
1303						}
1304
1305						
1306
1307						/* Rendering */
1308
1309						if ( bRender )
1310
1311						{
1312
1313							sRendered = _fnRender( oSettings, iRow, iColumn );
1314
1315							nCell.innerHTML = sRendered;
1316
1317							if ( oCol.bUseRendered )
1318
1319							{
1320
1321								/* Use the rendered data for filtering / sorting */
1322
1323								_fnSetCellData( oSettings, iRow, iColumn, sRendered );
1324
1325							}
1326
1327						}
1328
1329						
1330
1331						/* Classes */
1332
1333						if ( bClass )
1334
1335						{
1336
1337							nCell.className += ' '+oCol.sClass;
1338
1339						}
1340
1341						
1342
1343						/* Column visibility */
1344
1345						if ( !bVisible )
1346
1347						{
1348
1349							oData._anHidden[iColumn] = nCell;
1350
1351							nCell.parentNode.removeChild( nCell );
1352
1353						}
1354
1355						else
1356
1357						{
1358
1359							oData._anHidden[iColumn] = null;
1360
1361						}
1362
1363		
1364
1365						if ( oCol.fnCreatedCell )
1366
1367						{
1368
1369							oCol.fnCreatedCell.call( oSettings.oInstance,
1370
1371								nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
1372
1373							);
1374
1375						}
1376
1377					}
1378
1379				}
1380
1381			}
1382
1383		
1384
1385			/* Row created callbacks */
1386
1387			if ( oSettings.aoRowCreatedCallback.length !== 0 )
1388
1389			{
1390
1391				for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
1392
1393				{
1394
1395					oData = oSettings.aoData[i];
1396
1397					_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
1398
1399				}
1400
1401			}
1402
1403		}
1404
1405		
1406
1407		
1408
1409		/**
1410
1411		 * Take a TR element and convert it to an index in aoData
1412
1413		 *  @param {object} oSettings dataTables settings object
1414
1415		 *  @param {node} n the TR element to find
1416
1417		 *  @returns {int} index if the node is found, null if not
1418
1419		 *  @memberof DataTable#oApi
1420
1421		 */
1422
1423		function _fnNodeToDataIndex( oSettings, n )
1424
1425		{
1426
1427			return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1428
1429		}
1430
1431		
1432
1433		
1434
1435		/**
1436
1437		 * Take a TD element and convert it into a column data index (not the visible index)
1438
1439		 *  @param {object} oSettings dataTables settings object
1440
1441		 *  @param {int} iRow The row number the TD/TH can be found in
1442
1443		 *  @param {node} n The TD/TH element to find
1444
1445		 *  @returns {int} index if the node is found, -1 if not
1446
1447		 *  @memberof DataTable#oApi
1448
1449		 */
1450
1451		function _fnNodeToColumnIndex( oSettings, iRow, n )
1452
1453		{
1454
1455			var anCells = _fnGetTdNodes( oSettings, iRow );
1456
1457		
1458
1459			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1460
1461			{
1462
1463				if ( anCells[i] === n )
1464
1465				{
1466
1467					return i;
1468
1469				}
1470
1471			}
1472
1473			return -1;
1474
1475		}
1476
1477		
1478
1479		
1480
1481		/**
1482
1483		 * Get an array of data for a given row from the internal data cache
1484
1485		 *  @param {object} oSettings dataTables settings object
1486
1487		 *  @param {int} iRow aoData row id
1488
1489		 *  @param {string} sSpecific data get type ('type' 'filter' 'sort')
1490
1491		 *  @param {array} aiColumns Array of column indexes to get data from
1492
1493		 *  @returns {array} Data array
1494
1495		 *  @memberof DataTable#oApi
1496
1497		 */
1498
1499		function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
1500
1501		{
1502
1503			var out = [];
1504
1505			for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
1506
1507			{
1508
1509				out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
1510
1511			}
1512
1513			return out;
1514
1515		}
1516
1517		
1518
1519		
1520
1521		/**
1522
1523		 * Get the data for a given cell from the internal cache, taking into account data mapping
1524
1525		 *  @param {object} oSettings dataTables settings object
1526
1527		 *  @param {int} iRow aoData row id
1528
1529		 *  @param {int} iCol Column index
1530
1531		 *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
1532
1533		 *  @returns {*} Cell data
1534
1535		 *  @memberof DataTable#oApi
1536
1537		 */
1538
1539		function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
1540
1541		{
1542
1543			var sData;
1544
1545			var oCol = oSettings.aoColumns[iCol];
1546
1547			var oData = oSettings.aoData[iRow]._aData;
1548
1549		
1550
1551			if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
1552
1553			{
1554
1555				if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
1556
1557				{
1558
1559					_fnLog( oSettings, 0, "Requested unknown parameter "+
1560
1561						(typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
1562
1563						" from the data source for row "+iRow );
1564
1565					oSettings.iDrawError = oSettings.iDraw;
1566
1567				}
1568
1569				return oCol.sDefaultContent;
1570
1571			}
1572
1573		
1574
1575			/* When the data source is null, we can use default column data */
1576
1577			if ( sData === null && oCol.sDefaultContent !== null )
1578
1579			{
1580
1581				sData = oCol.sDefaultContent;
1582
1583			}
1584
1585			else if ( typeof sData === 'function' )
1586
1587			{
1588
1589				/* If the data source is a function, then we run it and use the return */
1590
1591				return sData();
1592
1593			}
1594
1595		
1596
1597			if ( sSpecific == 'display' && sData === null )
1598
1599			{
1600
1601				return '';
1602
1603			}
1604
1605			return sData;
1606
1607		}
1608
1609		
1610
1611		
1612
1613		/**
1614
1615		 * Set the value for a specific cell, into the internal data cache
1616
1617		 *  @param {object} oSettings dataTables settings object
1618
1619		 *  @param {int} iRow aoData row id
1620
1621		 *  @param {int} iCol Column index
1622
1623		 *  @param {*} val Value to set
1624
1625		 *  @memberof DataTable#oApi
1626
1627		 */
1628
1629		function _fnSetCellData( oSettings, iRow, iCol, val )
1630
1631		{
1632
1633			var oCol = oSettings.aoColumns[iCol];
1634
1635			var oData = oSettings.aoData[iRow]._aData;
1636
1637		
1638
1639			oCol.fnSetData( oData, val );
1640
1641		}
1642
1643		
1644
1645		
1646
1647		// Private variable that is used to match array syntax in the data property object
1648
1649		var __reArray = /\[.*?\]$/;
1650
1651		
1652
1653		/**
1654
1655		 * Return a function that can be used to get data from a source object, taking
1656
1657		 * into account the ability to use nested objects as a source
1658
1659		 *  @param {string|int|function} mSource The data source for the object
1660
1661		 *  @returns {function} Data get function
1662
1663		 *  @memberof DataTable#oApi
1664
1665		 */
1666
1667		function _fnGetObjectDataFn( mSource )
1668
1669		{
1670
1671			if ( mSource === null )
1672
1673			{
1674
1675				/* Give an empty string for rendering / sorting etc */
1676
1677				return function (data, type) {
1678
1679					return null;
1680
1681				};
1682
1683			}
1684
1685			else if ( typeof mSource === 'function' )
1686
1687			{
1688
1689				return function (data, type, extra) {
1690
1691					return mSource( data, type, extra );
1692
1693				};
1694
1695			}
1696
1697			else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
1698
1699			{
1700
1701				/* If there is a . in the source string then the data source is in a 
1702
1703				 * nested object so we loop over the data for each level to get the next
1704
1705				 * level down. On each loop we test for undefined, and if found immediately
1706
1707				 * return. This allows entire objects to be missing and sDefaultContent to
1708
1709				 * be used if defined, rather than throwing an error
1710
1711				 */
1712
1713				var fetchData = function (data, type, src) {
1714
1715					var a = src.split('.');
1716
1717					var arrayNotation, out, innerSrc;
1718
1719		
1720
1721					if ( src !== "" )
1722
1723					{
1724
1725						for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1726
1727						{
1728
1729							// Check if we are dealing with an array notation request
1730
1731							arrayNotation = a[i].match(__reArray);
1732
1733		
1734
1735							if ( arrayNotation ) {
1736
1737								a[i] = a[i].replace(__reArray, '');
1738
1739		
1740
1741								// Condition allows simply [] to be passed in
1742
1743								if ( a[i] !== "" ) {
1744
1745									data = data[ a[i] ];
1746
1747								}
1748
1749								out = [];
1750
1751								
1752
1753								// Get the remainder of the nested object to get
1754
1755								a.splice( 0, i+1 );
1756
1757								innerSrc = a.join('.');
1758
1759		
1760
1761								// Traverse each entry in the array getting the properties requested
1762
1763								for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1764
1765									out.push( fetchData( data[j], type, innerSrc ) );
1766
1767								}
1768
1769		
1770
1771								// If a string is given in between the array notation indicators, that
1772
1773								// is used to join the strings together, otherwise an array is returned
1774
1775								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1776
1777								data = (join==="") ? out : out.join(join);
1778
1779		
1780
1781								// The inner call to fetchData has already traversed through the remainder
1782
1783								// of the source requested, so we exit from the loop
1784
1785								break;
1786
1787							}
1788
1789		
1790
1791							if ( data === null || data[ a[i] ] === undefined )
1792
1793							{
1794
1795								return undefined;
1796
1797							}
1798
1799							data = data[ a[i] ];
1800
1801						}
1802
1803					}
1804
1805		
1806
1807					return data;
1808
1809				};
1810
1811		
1812
1813				return function (data, type) {
1814
1815					return fetchData( data, type, mSource );
1816
1817				};
1818
1819			}
1820
1821			else
1822
1823			{
1824
1825				/* Array or flat object mapping */
1826
1827				return function (data, type) {
1828
1829					return data[mSource];	
1830
1831				};
1832
1833			}
1834
1835		}
1836
1837		
1838
1839		
1840
1841		/**
1842
1843		 * Return a function that can be used to set data from a source object, taking
1844
1845		 * into account the ability to use nested objects as a source
1846
1847		 *  @param {string|int|function} mSource The data source for the object
1848
1849		 *  @returns {function} Data set function
1850
1851		 *  @memberof DataTable#oApi
1852
1853		 */
1854
1855		function _fnSetObjectDataFn( mSource )
1856
1857		{
1858
1859			if ( mSource === null )
1860
1861			{
1862
1863				/* Nothing to do when the data source is null */
1864
1865				return function (data, val) {};
1866
1867			}
1868
1869			else if ( typeof mSource === 'function' )
1870
1871			{
1872
1873				return function (data, val) {
1874
1875					mSource( data, 'set', val );
1876
1877				};
1878
1879			}
1880
1881			else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
1882
1883			{
1884
1885				/* Like the get, we need to get data from a nested object */
1886
1887				var setData = function (data, val, src) {
1888
1889					var a = src.split('.'), b;
1890
1891					var arrayNotation, o, innerSrc;
1892
1893		
1894
1895					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1896
1897					{
1898
1899						// Check if we are dealing with an array notation request
1900
1901						arrayNotation = a[i].match(__reArray);
1902
1903		
1904
1905						if ( arrayNotation )
1906
1907						{
1908
1909							a[i] = a[i].replace(__reArray, '');
1910
1911							data[ a[i] ] = [];
1912
1913							
1914
1915							// Get the remainder of the nested object to set so we can recurse
1916
1917							b = a.slice();
1918
1919							b.splice( 0, i+1 );
1920
1921							innerSrc = b.join('.');
1922
1923		
1924
1925							// Traverse each entry in the array setting the properties requested
1926
1927							for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1928
1929							{
1930
1931								o = {};
1932
1933								setData( o, val[j], innerSrc );
1934
1935								data[ a[i] ].push( o );
1936
1937							}
1938
1939		
1940
1941							// The inner call to setData has already traversed through the remainder
1942
1943							// of the source and has set the data, thus we can exit here
1944
1945							return;
1946
1947						}
1948
1949		
1950
1951						// If the nested object doesn't currently exist - since we are
1952
1953						// trying to set the value - create it
1954
1955						if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1956
1957						{
1958
1959							data[ a[i] ] = {};
1960
1961						}
1962
1963						data = data[ a[i] ];
1964
1965					}
1966
1967		
1968
1969					// If array notation is used, we just want to strip it and use the property name
1970
1971					// and assign the value. If it isn't used, then we get the result we want anyway
1972
1973					data[ a[a.length-1].replace(__reArray, '') ] = val;
1974
1975				};
1976
1977		
1978
1979				return function (data, val) {
1980
1981					return setData( data, val, mSource );
1982
1983				};
1984
1985			}
1986
1987			else
1988
1989			{
1990
1991				/* Array or flat object mapping */
1992
1993				return function (data, val) {
1994
1995					data[mSource] = val;	
1996
1997				};
1998
1999			}
2000
2001		}
2002
2003		
2004
2005		
2006
2007		/**
2008
2009		 * Return an array with the full table data
2010
2011		 *  @param {object} oSettings dataTables settings object
2012
2013		 *  @returns array {array} aData Master data array
2014
2015		 *  @memberof DataTable#oApi
2016
2017		 */
2018
2019		function _fnGetDataMaster ( oSettings )
2020
2021		{
2022
2023			var aData = [];
2024
2025			var iLen = oSettings.aoData.length;
2026
2027			for ( var i=0 ; i<iLen; i++ )
2028
2029			{
2030
2031				aData.push( oSettings.aoData[i]._aData );
2032
2033			}
2034
2035			return aData;
2036
2037		}
2038
2039		
2040
2041		
2042
2043		/**
2044
2045		 * Nuke the table
2046
2047		 *  @param {object} oSettings dataTables settings object
2048
2049		 *  @memberof DataTable#oApi
2050
2051		 */
2052
2053		function _fnClearTable( oSettings )
2054
2055		{
2056
2057			oSettings.aoData.splice( 0, oSettings.aoData.length );
2058
2059			oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
2060
2061			oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
2062
2063			_fnCalculateEnd( oSettings );
2064
2065		}
2066
2067		
2068
2069		
2070
2071		 /**
2072
2073		 * Take an array of integers (index array) and remove a target integer (value - not 
2074
2075		 * the key!)
2076
2077		 *  @param {array} a Index array to target
2078
2079		 *  @param {int} iTarget value to find
2080
2081		 *  @memberof DataTable#oApi
2082
2083		 */
2084
2085		function _fnDeleteIndex( a, iTarget )
2086
2087		{
2088
2089			var iTargetIndex = -1;
2090
2091			
2092
2093			for ( var i=0, iLen=a.length ; i<iLen ; i++ )
2094
2095			{
2096
2097				if ( a[i] == iTarget )
2098
2099				{
2100
2101					iTargetIndex = i;
2102
2103				}
2104
2105				else if ( a[i] > iTarget )
2106
2107				{
2108
2109					a[i]--;
2110
2111				}
2112
2113			}
2114
2115			
2116
2117			if ( iTargetIndex != -1 )
2118
2119			{
2120
2121				a.splice( iTargetIndex, 1 );
2122
2123			}
2124
2125		}
2126
2127		
2128
2129		
2130
2131		 /**
2132
2133		 * Call the developer defined fnRender function for a given cell (row/column) with
2134
2135		 * the required parameters and return the result.
2136
2137		 *  @param {object} oSettings dataTables settings object
2138
2139		 *  @param {int} iRow aoData index for the row
2140
2141		 *  @param {int} iCol aoColumns index for the column
2142
2143		 *  @returns {*} Return of the developer's fnRender function
2144
2145		 *  @memberof DataTable#oApi
2146
2147		 */
2148
2149		function _fnRender( oSettings, iRow, iCol )
2150
2151		{
2152
2153			var oCol = oSettings.aoColumns[iCol];
2154
2155		
2156
2157			return oCol.fnRender( {
2158
2159				"iDataRow":    iRow,
2160
2161				"iDataColumn": iCol,
2162
2163				"oSettings":   oSettings,
2164
2165				"aData":       oSettings.aoData[iRow]._aData,
2166
2167				"mDataProp":   oCol.mData
2168
2169			}, _fnGetCellData(oSettings, iRow, iCol, 'display') );
2170
2171		}
2172
2173		/**
2174
2175		 * Create a new TR element (and it's TD children) for a row
2176
2177		 *  @param {object} oSettings dataTables settings object
2178
2179		 *  @param {int} iRow Row to consider
2180
2181		 *  @memberof DataTable#oApi
2182
2183		 */
2184
2185		function _fnCreateTr ( oSettings, iRow )
2186
2187		{
2188
2189			var oData = oSettings.aoData[iRow];
2190
2191			var nTd;
2192
2193		
2194
2195			if ( oData.nTr === null )
2196
2197			{
2198
2199				oData.nTr = document.createElement('tr');
2200
2201		
2202
2203				/* Use a private property on the node to allow reserve mapping from the node
2204
2205				 * to the aoData array for fast look up
2206
2207				 */
2208
2209				oData.nTr._DT_RowIndex = iRow;
2210
2211		
2212
2213				/* Special parameters can be given by the data source to be used on the row */
2214
2215				if ( oData._aData.DT_RowId )
2216
2217				{
2218
2219					oData.nTr.id = oData._aData.DT_RowId;
2220
2221				}
2222
2223		
2224
2225				if ( oData._aData.DT_RowClass )
2226
2227				{
2228
2229					oData.nTr.className = oData._aData.DT_RowClass;
2230
2231				}
2232
2233		
2234
2235				/* Process each column */
2236
2237				for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2238
2239				{
2240
2241					var oCol = oSettings.aoColumns[i];
2242
2243					nTd = document.createElement( oCol.sCellType );
2244
2245		
2246
2247					/* Render if needed - if bUseRendered is true then we already have the rendered
2248
2249					 * value in the data source - so can just use that
2250
2251					 */
2252
2253					nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ?
2254
2255						_fnRender( oSettings, iRow, i ) :
2256
2257						_fnGetCellData( oSettings, iRow, i, 'display' );
2258
2259				
2260
2261					/* Add user defined class */
2262
2263					if ( oCol.sClass !== null )
2264
2265					{
2266
2267						nTd.className = oCol.sClass;
2268
2269					}
2270
2271					
2272
2273					if ( oCol.bVisible )
2274
2275					{
2276
2277						oData.nTr.appendChild( nTd );
2278
2279						oData._anHidden[i] = null;
2280
2281					}
2282
2283					else
2284
2285					{
2286
2287						oData._anHidden[i] = nTd;
2288
2289					}
2290
2291		
2292
2293					if ( oCol.fnCreatedCell )
2294
2295					{
2296
2297						oCol.fnCreatedCell.call( oSettings.oInstance,
2298
2299							nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
2300
2301						);
2302
2303					}
2304
2305				}
2306
2307		
2308
2309				_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
2310
2311			}
2312
2313		}
2314
2315		
2316
2317		
2318
2319		/**
2320
2321		 * Create the HTML header for the table
2322
2323		 *  @param {object} oSettings dataTables settings object
2324
2325		 *  @memberof DataTable#oApi
2326
2327		 */
2328
2329		function _fnBuildHead( oSettings )
2330
2331		{
2332
2333			var i, nTh, iLen, j, jLen;
2334
2335			var iThs = $('th, td', oSettings.nTHead).length;
2336
2337			var iCorrector = 0;
2338
2339			var jqChildren;
2340
2341			
2342
2343			/* If there is a header in place - then use it - otherwise it's going to get nuked... */
2344
2345			if ( iThs !== 0 )
2346
2347			{
2348
2349				/* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
2350
2351				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2352
2353				{
2354
2355					nTh = oSettings.aoColumns[i].nTh;
2356
2357					nTh.setAttribute('role', 'columnheader');
2358
2359					if ( oSettings.aoColumns[i].bSortable )
2360
2361					{
2362
2363						nTh.setAttribute('tabindex', oSettings.iTabIndex);
2364
2365						nTh.setAttribute('aria-controls', oSettings.sTableId);
2366
2367					}
2368
2369		
2370
2371					if ( oSettings.aoColumns[i].sClass !== null )
2372
2373					{
2374
2375						$(nTh).addClass( oSettings.aoColumns[i].sClass );
2376
2377					}
2378
2379					
2380
2381					/* Set the title of the column if it is user defined (not what was auto detected) */
2382
2383					if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
2384
2385					{
2386
2387						nTh.innerHTML = oSettings.aoColumns[i].sTitle;
2388
2389					}
2390
2391				}
2392
2393			}
2394
2395			else
2396
2397			{
2398
2399				/* We don't have a header in the DOM - so we are going to have to create one */
2400
2401				var nTr = document.createElement( "tr" );
2402
2403				
2404
2405				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2406
2407				{
2408
2409					nTh = oSettings.aoColumns[i].nTh;
2410
2411					nTh.innerHTML = oSettings.aoColumns[i].sTitle;
2412
2413					nTh.setAttribute('tabindex', '0');
2414
2415					
2416
2417					if ( oSettings.aoColumns[i].sClass !== null )
2418
2419					{
2420
2421						$(nTh).addClass( oSettings.aoColumns[i].sClass );
2422
2423					}
2424
2425					
2426
2427					nTr.appendChild( nTh );
2428
2429				}
2430
2431				$(oSettings.nTHead).html( '' )[0].appendChild( nTr );
2432
2433				_fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
2434
2435			}
2436
2437			
2438
2439			/* ARIA role for the rows */	
2440
2441			$(oSettings.nTHead).children('tr').attr('role', 'row');
2442
2443			
2444
2445			/* Add the extra markup needed by jQuery UI's themes */
2446
2447			if ( oSettings.bJUI )
2448
2449			{
2450
2451				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2452
2453				{
2454
2455					nTh = oSettings.aoColumns[i].nTh;
2456
2457					
2458
2459					var nDiv = document.createElement('div');
2460
2461					nDiv.className = oSettings.oClasses.sSortJUIWrapper;
2462
2463					$(nTh).contents().appendTo(nDiv);
2464
2465					
2466
2467					var nSpan = document.createElement('span');
2468
2469					nSpan.className = oSettings.oClasses.sSortIcon;
2470
2471					nDiv.appendChild( nSpan );
2472
2473					nTh.appendChild( nDiv );
2474
2475				}
2476
2477			}
2478
2479			
2480
2481			if ( oSettings.oFeatures.bSort )
2482
2483			{
2484
2485				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
2486
2487				{
2488
2489					if ( oSettings.aoColumns[i].bSortable !== false )
2490
2491					{
2492
2493						_fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
2494
2495					}
2496
2497					else
2498
2499					{
2500
2501						$(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
2502
2503					}
2504
2505				}
2506
2507			}
2508
2509			
2510
2511			/* Deal with the footer - add classes if required */
2512
2513			if ( oSettings.oClasses.sFooterTH !== "" )
2514
2515			{
2516
2517				$(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
2518
2519			}
2520
2521			
2522
2523			/* Cache the footer elements */
2524
2525			if ( oSettings.nTFoot !== null )
2526
2527			{
2528
2529				var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
2530
2531				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2532
2533				{
2534
2535					if ( anCells[i] )
2536
2537					{
2538
2539						oSettings.aoColumns[i].nTf = anCells[i];
2540
2541						if ( oSettings.aoColumns[i].sClass )
2542
2543						{
2544
2545							$(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
2546
2547						}
2548
2549					}
2550
2551				}
2552
2553			}
2554
2555		}
2556
2557		
2558
2559		
2560
2561		/**
2562
2563		 * Draw the header (or footer) element based on the column visibility states. The
2564
2565		 * methodology here is to use the layout array from _fnDetectHeader, modified for
2566
2567		 * the instantaneous column visibility, to construct the new layout. The grid is
2568
2569		 * traversed over cell at a time in a rows x columns grid fashion, although each 
2570
2571		 * cell insert can cover multiple elements in the grid - which is tracks using the
2572
2573		 * aApplied array. Cell inserts in the grid will only occur where there isn't
2574
2575		 * already a cell in that position.
2576
2577		 *  @param {object} oSettings dataTables settings object
2578
2579		 *  @param array {objects} aoSource Layout array from _fnDetectHeader
2580
2581		 *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 
2582
2583		 *  @memberof DataTable#oApi
2584
2585		 */
2586
2587		function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
2588
2589		{
2590
2591			var i, iLen, j, jLen, k, kLen, n, nLocalTr;
2592
2593			var aoLocal = [];
2594
2595			var aApplied = [];
2596
2597			var iColumns = oSettings.aoColumns.length;
2598
2599			var iRowspan, iColspan;
2600
2601		
2602
2603			if (  bIncludeHidden === undefined )
2604
2605			{
2606
2607				bIncludeHidden = false;
2608
2609			}
2610
2611		
2612
2613			/* Make a copy of the master layout array, but without the visible columns in it */
2614
2615			for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
2616
2617			{
2618
2619				aoLocal[i] = aoSource[i].slice();
2620
2621				aoLocal[i].nTr = aoSource[i].nTr;
2622
2623		
2624
2625				/* Remove any columns which are currently hidden */
2626
2627				for ( j=iColumns-1 ; j>=0 ; j-- )
2628
2629				{
2630
2631					if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
2632
2633					{
2634
2635						aoLocal[i].splice( j, 1 );
2636
2637					}
2638
2639				}
2640
2641		
2642
2643				/* Prep the applied array - it needs an element for each row */
2644
2645				aApplied.push( [] );
2646
2647			}
2648
2649		
2650
2651			for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
2652
2653			{
2654
2655				nLocalTr = aoLocal[i].nTr;
2656
2657				
2658
2659				/* All cells are going to be replaced, so empty out the row */
2660
2661				if ( nLocalTr )
2662
2663				{
2664
2665					while( (n = nLocalTr.firstChild) )
2666
2667					{
2668
2669						nLocalTr.removeChild( n );
2670
2671					}
2672
2673				}
2674
2675		
2676
2677				for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
2678
2679				{
2680
2681					iRowspan = 1;
2682
2683					iColspan = 1;
2684
2685		
2686
2687					/* Check to see if there is already a cell (row/colspan) covering our target
2688
2689					 * insert point. If there is, then there is nothing to do.
2690
2691					 */
2692
2693					if ( aApplied[i][j] === undefined )
2694
2695					{
2696
2697						nLocalTr.appendChild( aoLocal[i][j].cell );
2698
2699						aApplied[i][j] = 1;
2700
2701		
2702
2703						/* Expand the cell to cover as many rows as needed */
2704
2705						while ( aoLocal[i+iRowspan] !== undefined &&
2706
2707						        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
2708
2709						{
2710
2711							aApplied[i+iRowspan][j] = 1;
2712
2713							iRowspan++;
2714
2715						}
2716
2717		
2718
2719						/* Expand the cell to cover as many columns as needed */
2720
2721						while ( aoLocal[i][j+iColspan] !== undefined &&
2722
2723						        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
2724
2725						{
2726
2727							/* Must update the applied array over the rows for the columns */
2728
2729							for ( k=0 ; k<iRowspan ; k++ )
2730
2731							{
2732
2733								aApplied[i+k][j+iColspan] = 1;
2734
2735							}
2736
2737							iColspan++;
2738
2739						}
2740
2741		
2742
2743						/* Do the actual expansion in the DOM */
2744
2745						aoLocal[i][j].cell.rowSpan = iRowspan;
2746
2747						aoLocal[i][j].cell.colSpan = iColspan;
2748
2749					}
2750
2751				}
2752
2753			}
2754
2755		}
2756
2757		
2758
2759		
2760
2761		/**
2762
2763		 * Insert the required TR nodes into the table for display
2764
2765		 *  @param {object} oSettings dataTables settings object
2766
2767		 *  @memberof DataTable#oApi
2768
2769		 */
2770
2771		function _fnDraw( oSettings )
2772
2773		{
2774
2775			/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
2776
2777			var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
2778
2779			if ( $.inArray( false, aPreDraw ) !== -1 )
2780
2781			{
2782
2783				_fnProcessingDisplay( oSettings, false );
2784
2785				return;
2786
2787			}
2788
2789			
2790
2791			var i, iLen, n;
2792
2793			var anRows = [];
2794
2795			var iRowCount = 0;
2796
2797			var iStripes = oSettings.asStripeClasses.length;
2798
2799			var iOpenRows = oSettings.aoOpenRows.length;
2800
2801			
2802
2803			oSettings.bDrawing = true;
2804
2805			
2806
2807			/* Check and see if we have an initial draw position from state saving */
2808
2809			if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 )
2810
2811			{
2812
2813				if ( oSettings.oFeatures.bServerSide )
2814
2815				{
2816
2817					oSettings._iDisplayStart = oSettings.iInitDisplayStart;
2818
2819				}
2820
2821				else
2822
2823				{
2824
2825					oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
2826
2827						0 : oSettings.iInitDisplayStart;
2828
2829				}
2830
2831				oSettings.iInitDisplayStart = -1;
2832
2833				_fnCalculateEnd( oSettings );
2834
2835			}
2836
2837			
2838
2839			/* Server-side processing draw intercept */
2840
2841			if ( oSettings.bDeferLoading )
2842
2843			{
2844
2845				oSettings.bDeferLoading = false;
2846
2847				oSettings.iDraw++;
2848
2849			}
2850
2851			else if ( !oSettings.oFeatures.bServerSide )
2852
2853			{
2854
2855				oSettings.iDraw++;
2856
2857			}
2858
2859			else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
2860
2861			{
2862
2863				return;
2864
2865			}
2866
2867			
2868
2869			if ( oSettings.aiDisplay.length !== 0 )
2870
2871			{
2872
2873				var iStart = oSettings._iDisplayStart;
2874
2875				var iEnd = oSettings._iDisplayEnd;
2876
2877				
2878
2879				if ( oSettings.oFeatures.bServerSide )
2880
2881				{
2882
2883					iStart = 0;
2884
2885					iEnd = oSettings.aoData.length;
2886
2887				}
2888
2889				
2890
2891				for ( var j=iStart ; j<iEnd ; j++ )
2892
2893				{
2894
2895					var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
2896
2897					if ( aoData.nTr === null )
2898
2899					{
2900
2901						_fnCreateTr( oSettings, oSettings.aiDisplay[j] );
2902
2903					}
2904
2905		
2906
2907					var nRow = aoData.nTr;
2908
2909					
2910
2911					/* Remove the old striping classes and then add the new one */
2912
2913					if ( iStripes !== 0 )
2914
2915					{
2916
2917						var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
2918
2919						if ( aoData._sRowStripe != sStripe )
2920
2921						{
2922
2923							$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2924
2925							aoData._sRowStripe = sStripe;
2926
2927						}
2928
2929					}
2930
2931					
2932
2933					/* Row callback functions - might want to manipulate the row */
2934
2935					_fnCallbackFire( oSettings, 'aoRowCallback', null, 
2936
2937						[nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] );
2938
2939					
2940
2941					anRows.push( nRow );
2942
2943					iRowCount++;
2944
2945					
2946
2947					/* If there is an open row - and it is attached to this parent - attach it on redraw */
2948
2949					if ( iOpenRows !== 0 )
2950
2951					{
2952
2953						for ( var k=0 ; k<iOpenRows ; k++ )
2954
2955						{
2956
2957							if ( nRow == oSettings.aoOpenRows[k].nParent )
2958
2959							{
2960
2961								anRows.push( oSettings.aoOpenRows[k].nTr );
2962
2963								break;
2964
2965							}
2966
2967						}
2968
2969					}
2970
2971				}
2972
2973			}
2974
2975			else
2976
2977			{
2978
2979				/* Table is empty - create a row with an empty message in it */
2980
2981				anRows[ 0 ] = document.createElement( 'tr' );
2982
2983				
2984
2985				if ( oSettings.asStripeClasses[0] )
2986
2987				{
2988
2989					anRows[ 0 ].className = oSettings.asStripeClasses[0];
2990
2991				}
2992
2993		
2994
2995				var oLang = oSettings.oLanguage;
2996
2997				var sZero = oLang.sZeroRecords;
2998
2999				if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
3000
3001				{
3002
3003					sZero = oLang.sLoadingRecords;
3004
3005				}
3006
3007				else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
3008
3009				{
3010
3011					sZero = oLang.sEmptyTable;
3012
3013				}
3014
3015		
3016
3017				var nTd = document.createElement( 'td' );
3018
3019				nTd.setAttribute( 'valign', "top" );
3020
3021				nTd.colSpan = _fnVisbleColumns( oSettings );
3022
3023				nTd.className = oSettings.oClasses.sRowEmpty;
3024
3025				nTd.innerHTML = _fnInfoMacros( oSettings, sZero );
3026
3027				
3028
3029				anRows[ iRowCount ].appendChild( nTd );
3030
3031			}
3032
3033			
3034
3035			/* Header and footer callbacks */
3036
3037			_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 
3038
3039				_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
3040
3041			
3042
3043			_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 
3044
3045				_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
3046
3047			
3048
3049			/* 
3050
3051			 * Need to remove any old row from the display - note we can't just empty the tbody using
3052
3053			 * $().html('') since this will unbind the jQuery event handlers (even although the node 
3054
3055			 * still exists!) - equally we can't use innerHTML, since IE throws an exception.
3056
3057			 */
3058
3059			var
3060
3061				nAddFrag = document.createDocumentFragment(),
3062
3063				nRemoveFrag = document.createDocumentFragment(),
3064
3065				nBodyPar, nTrs;
3066
3067			
3068
3069			if ( oSettings.nTBody )
3070
3071			{
3072
3073				nBodyPar = oSettings.nTBody.parentNode;
3074
3075				nRemoveFrag.appendChild( oSettings.nTBody );
3076
3077				
3078
3079				/* When doing infinite scrolling, only remove child rows when sorting, filtering or start
3080
3081				 * up. When not infinite scroll, always do it.
3082
3083				 */
3084
3085				if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
3086
3087				 	oSettings.bSorted || oSettings.bFiltered )
3088
3089				{
3090
3091					while( (n = oSettings.nTBody.firstChild) )
3092
3093					{
3094
3095						oSettings.nTBody.removeChild( n );
3096
3097					}
3098
3099				}
3100
3101				
3102
3103				/* Put the draw table into the dom */
3104
3105				for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
3106
3107				{
3108
3109					nAddFrag.appendChild( anRows[i] );
3110
3111				}
3112
3113				
3114
3115				oSettings.nTBody.appendChild( nAddFrag );
3116
3117				if ( nBodyPar !== null )
3118
3119				{
3120
3121					nBodyPar.appendChild( oSettings.nTBody );
3122
3123				}
3124
3125			}
3126
3127			
3128
3129			/* Call all required callback functions for the end of a draw */
3130
3131			_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
3132
3133			
3134
3135			/* Draw is complete, sorting and filtering must be as well */
3136
3137			oSettings.bSorted = false;
3138
3139			oSettings.bFiltered = false;
3140
3141			oSettings.bDrawing = false;
3142
3143			
3144
3145			if ( oSettings.oFeatures.bServerSide )
3146
3147			{
3148
3149				_fnProcessingDisplay( oSettings, false );
3150
3151				if ( !oSettings._bInitComplete )
3152
3153				{
3154
3155					_fnInitComplete( oSettings );
3156
3157				}
3158
3159			}
3160
3161		}
3162
3163		
3164
3165		
3166
3167		/**
3168
3169		 * Redraw the table - taking account of the various features which are enabled
3170
3171		 *  @param {object} oSettings dataTables settings object
3172
3173		 *  @memberof DataTable#oApi
3174
3175		 */
3176
3177		function _fnReDraw( oSettings )
3178
3179		{
3180
3181			if ( oSettings.oFeatures.bSort )
3182
3183			{
3184
3185				/* Sorting will refilter and draw for us */
3186
3187				_fnSort( oSettings, oSettings.oPreviousSearch );
3188
3189			}
3190
3191			else if ( oSettings.oFeatures.bFilter )
3192
3193			{
3194
3195				/* Filtering will redraw for us */
3196
3197				_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
3198
3199			}
3200
3201			else
3202
3203			{
3204
3205				_fnCalculateEnd( oSettings );
3206
3207				_fnDraw( oSettings );
3208
3209			}
3210
3211		}
3212
3213		
3214
3215		
3216
3217		/**
3218
3219		 * Add the options to the page HTML for the table
3220
3221		 *  @param {object} oSettings dataTables settings object
3222
3223		 *  @memberof DataTable#oApi
3224
3225		 */
3226
3227		function _fnAddOptionsHtml ( oSettings )
3228
3229		{
3230
3231			/*
3232
3233			 * Create a temporary, empty, div which we can later on replace with what we have generated
3234
3235			 * we do it this way to rendering the 'options' html offline - speed :-)
3236
3237			 */
3238
3239			var nHolding = $('<div></div>')[0];
3240
3241			oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
3242
3243			
3244
3245			/* 
3246
3247			 * All DataTables are wrapped in a div
3248
3249			 */
3250
3251			oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];
3252
3253			oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
3254
3255		
3256
3257			/* Track where we want to insert the option */
3258
3259			var nInsertNode = oSettings.nTableWrapper;
3260
3261			
3262
3263			/* Loop over the user set positioning and place the elements as needed */
3264
3265			var aDom = oSettings.sDom.split('');
3266
3267			var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
3268
3269			for ( var i=0 ; i<aDom.length ; i++ )
3270
3271			{
3272
3273				iPushFeature = 0;
3274
3275				cOption = aDom[i];
3276
3277				
3278
3279				if ( cOption == '<' )
3280
3281				{
3282
3283					/* New container div */
3284
3285					nNewNode = $('<div></div>')[0];
3286
3287					
3288
3289					/* Check to see if we should append an id and/or a class name to the container */
3290
3291					cNext = aDom[i+1];
3292
3293					if ( cNext == "'" || cNext == '"' )
3294
3295					{
3296
3297						sAttr = "";
3298
3299						j = 2;
3300
3301						while ( aDom[i+j] != cNext )
3302
3303						{
3304
3305							sAttr += aDom[i+j];
3306
3307							j++;
3308
3309						}
3310
3311						
3312
3313						/* Replace jQuery UI constants */
3314
3315						if ( sAttr == "H" )
3316
3317						{
3318
3319							sAttr = oSettings.oClasses.sJUIHeader;
3320
3321						}
3322
3323						else if ( sAttr == "F" )
3324
3325						{
3326
3327							sAttr = oSettings.oClasses.sJUIFooter;
3328
3329						}
3330
3331						
3332
3333						/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
3334
3335						 * breaks the string into parts and applies them as needed
3336
3337						 */
3338
3339						if ( sAttr.indexOf('.') != -1 )
3340
3341						{
3342
3343							var aSplit = sAttr.split('.');
3344
3345							nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
3346
3347							nNewNode.className = aSplit[1];
3348
3349						}
3350
3351						else if ( sAttr.charAt(0) == "#" )
3352
3353						{
3354
3355							nNewNode.id = sAttr.substr(1, sAttr.length-1);
3356
3357						}
3358
3359						else
3360
3361						{
3362
3363							nNewNode.className = sAttr;
3364
3365						}
3366
3367						
3368
3369						i += j; /* Move along the position array */
3370
3371					}
3372
3373					
3374
3375					nInsertNode.appendChild( nNewNode );
3376
3377					nInsertNode = nNewNode;
3378
3379				}
3380
3381				else if ( cOption == '>' )
3382
3383				{
3384
3385					/* End container div */
3386
3387					nInsertNode = nInsertNode.parentNode;
3388
3389				}
3390
3391				else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
3392
3393				{
3394
3395					/* Length */
3396
3397					nTmp = _fnFeatureHtmlLength( oSettings );
3398
3399					iPushFeature = 1;
3400
3401				}
3402
3403				else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
3404
3405				{
3406
3407					/* Filter */
3408
3409					nTmp = _fnFeatureHtmlFilter( oSettings );
3410
3411					iPushFeature = 1;
3412
3413				}
3414
3415				else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
3416
3417				{
3418
3419					/* pRocessing */
3420
3421					nTmp = _fnFeatureHtmlProcessing( oSettings );
3422
3423					iPushFeature = 1;
3424
3425				}
3426
3427				else if ( cOption == 't' )
3428
3429				{
3430
3431					/* Table */
3432
3433					nTmp = _fnFeatureHtmlTable( oSettings );
3434
3435					iPushFeature = 1;
3436
3437				}
3438
3439				else if ( cOption ==  'i' && oSettings.oFeatures.bInfo )
3440
3441				{
3442
3443					/* Info */
3444
3445					nTmp = _fnFeatureHtmlInfo( oSettings );
3446
3447					iPushFeature = 1;
3448
3449				}
3450
3451				else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
3452
3453				{
3454
3455					/* Pagination */
3456
3457					nTmp = _fnFeatureHtmlPaginate( oSettings );
3458
3459					iPushFeature = 1;
3460
3461				}
3462
3463				else if ( DataTable.ext.aoFeatures.length !== 0 )
3464
3465				{
3466
3467					/* Plug-in features */
3468
3469					var aoFeatures = DataTable.ext.aoFeatures;
3470
3471					for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
3472
3473					{
3474
3475						if ( cOption == aoFeatures[k].cFeature )
3476
3477						{
3478
3479							nTmp = aoFeatures[k].fnInit( oSettings );
3480
3481							if ( nTmp )
3482
3483							{
3484
3485								iPushFeature = 1;
3486
3487							}
3488
3489							break;
3490
3491						}
3492
3493					}
3494
3495				}
3496
3497				
3498
3499				/* Add to the 2D features array */
3500
3501				if ( iPushFeature == 1 && nTmp !== null )
3502
3503				{
3504
3505					if ( typeof oSettings.aanFeatures[cOption] !== 'object' )
3506
3507					{
3508
3509						oSettings.aanFeatures[cOption] = [];
3510
3511					}
3512
3513					oSettings.aanFeatures[cOption].push( nTmp );
3514
3515					nInsertNode.appendChild( nTmp );
3516
3517				}
3518
3519			}
3520
3521			
3522
3523			/* Built our DOM structure - replace the holding div with what we want */
3524
3525			nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
3526
3527		}
3528
3529		
3530
3531		
3532
3533		/**
3534
3535		 * Use the DOM source to create up an array of header cells. The idea here is to
3536
3537		 * create a layout grid (array) of rows x columns, which contains a reference
3538
3539		 * to the cell that that point in the grid (regardless of col/rowspan), such that
3540
3541		 * any column / row could be removed and the new grid constructed
3542
3543		 *  @param array {object} aLayout Array to store the calculated layout in
3544
3545		 *  @param {node} nThead The header/footer element for the table
3546
3547		 *  @memberof DataTable#oApi
3548
3549		 */
3550
3551		function _fnDetectHeader ( aLayout, nThead )
3552
3553		{
3554
3555			var nTrs = $(nThead).children('tr');
3556
3557			var nTr, nCell;
3558
3559			var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
3560
3561			var bUnique;
3562
3563			var fnShiftCol = function ( a, i, j ) {
3564
3565				var k = a[i];
3566
3567		                while ( k[j] ) {
3568
3569					j++;
3570
3571				}
3572
3573				return j;
3574
3575			};
3576
3577		
3578
3579			aLayout.splice( 0, aLayout.length );
3580
3581			
3582
3583			/* We know how many rows there are in the layout - so prep it */
3584
3585			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3586
3587			{
3588
3589				aLayout.push( [] );
3590
3591			}
3592
3593			
3594
3595			/* Calculate a layout array */
3596
3597			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
3598
3599			{
3600
3601				nTr = nTrs[i];
3602
3603				iColumn = 0;
3604
3605				
3606
3607				/* For every cell in the row... */
3608
3609				nCell = nTr.firstChild;
3610
3611				while ( nCell ) {
3612
3613					if ( nCell.nodeName.toUpperCase() == "TD" ||
3614
3615					     nCell.nodeName.toUpperCase() == "TH" )
3616
3617					{
3618
3619						/* Get the col and rowspan attributes from the DOM and sanitise them */
3620
3621						iColspan = nCell.getAttribute('colspan') * 1;
3622
3623						iRowspan = nCell.getAttribute('rowspan') * 1;
3624
3625						iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
3626
3627						iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
3628
3629		
3630
3631						/* There might be colspan cells already in this row, so shift our target 
3632
3633						 * accordingly
3634
3635						 */
3636
3637						iColShifted = fnShiftCol( aLayout, i, iColumn );
3638
3639						
3640
3641						/* Cache calculation for unique columns */
3642
3643						bUnique = iColspan === 1 ? true : false;
3644
3645						
3646
3647						/* If there is col / rowspan, copy the information into the layout grid */
3648
3649						for ( l=0 ; l<iColspan ; l++ )
3650
3651						{
3652
3653							for ( k=0 ; k<iRowspan ; k++ )
3654
3655							{
3656
3657								aLayout[i+k][iColShifted+l] = {
3658
3659									"cell": nCell,
3660
3661									"unique": bUnique
3662
3663								};
3664
3665								aLayout[i+k].nTr = nTr;
3666
3667							}
3668
3669						}
3670
3671					}
3672
3673					nCell = nCell.nextSibling;
3674
3675				}
3676
3677			}
3678
3679		}
3680
3681		
3682
3683		
3684
3685		/**
3686
3687		 * Get an array of unique th elements, one for each column
3688
3689		 *  @param {object} oSettings dataTables settings object
3690
3691		 *  @param {node} nHeader automatically detect the layout from this node - optional
3692
3693		 *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
3694
3695		 *  @returns array {node} aReturn list of unique th's
3696
3697		 *  @memberof DataTable#oApi
3698
3699		 */
3700
3701		function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
3702
3703		{
3704
3705			var aReturn = [];
3706
3707			if ( !aLayout )
3708
3709			{
3710
3711				aLayout = oSettings.aoHeader;
3712
3713				if ( nHeader )
3714
3715				{
3716
3717					aLayout = [];
3718
3719					_fnDetectHeader( aLayout, nHeader );
3720
3721				}
3722
3723			}
3724
3725		
3726
3727			for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
3728
3729			{
3730
3731				for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
3732
3733				{
3734
3735					if ( aLayout[i][j].unique && 
3736
3737						 (!aReturn[j] || !oSettings.bSortCellsTop) )
3738
3739					{
3740
3741						aReturn[j] = aLayout[i][j].cell;
3742
3743					}
3744
3745				}
3746
3747			}
3748
3749			
3750
3751			return aReturn;
3752
3753		}
3754
3755		
3756
3757		
3758
3759		
3760
3761		/**
3762
3763		 * Update the table using an Ajax call
3764
3765		 *  @param {object} oSettings dataTables settings object
3766
3767		 *  @returns {boolean} Block the table drawing or not
3768
3769		 *  @memberof DataTable#oApi
3770
3771		 */
3772
3773		function _fnAjaxUpdate( oSettings )
3774
3775		{
3776
3777			if ( oSettings.bAjaxDataGet )
3778
3779			{
3780
3781				oSettings.iDraw++;
3782
3783				_fnProcessingDisplay( oSettings, true );
3784
3785				var iColumns = oSettings.aoColumns.length;
3786
3787				var aoData = _fnAjaxParameters( oSettings );
3788
3789				_fnServerParams( oSettings, aoData );
3790
3791				
3792
3793				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, ao
3793Data,
3794
3795					function(json) {
3796
3797						_fnAjaxUpdateDraw( oSettings, json );
3798
3799					}, oSettings );
3800
3801				return false;
3802
3803			}
3804
3805			else
3806
3807			{
3808
3809				return true;
3810
3811			}
3812
3813		}
3814
3815		
3816
3817		
3818
3819		/**
3820
3821		 * Build up the parameters in an object needed for a server-side processing request
3822
3823		 *  @param {object} oSettings dataTables settings object
3824
3825		 *  @returns {bool} block the table drawing or not
3826
3827		 *  @memberof DataTable#oApi
3828
3829		 */
3830
3831		function _fnAjaxParameters( oSettings )
3832
3833		{
3834
3835			var iColumns = oSettings.aoColumns.length;
3836
3837			var aoData = [], mDataProp, aaSort, aDataSort;
3838
3839			var i, j;
3840
3841			
3842
3843			aoData.push( { "name": "sEcho",          "value": oSettings.iDraw } );
3844
3845			aoData.push( { "name": "iColumns",       "value": iColumns } );
3846
3847			aoData.push( { "name": "sColumns",       "value": _fnColumnOrdering(oSettings) } );
3848
3849			aoData.push( { "name": "iDisplayStart",  "value": oSettings._iDisplayStart } );
3850
3851			aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
3852
3853				oSettings._iDisplayLength : -1 } );
3854
3855				
3856
3857			for ( i=0 ; i<iColumns ; i++ )
3858
3859			{
3860
3861			  mDataProp = oSettings.aoColumns[i].mData;
3862
3863				aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );
3864
3865			}
3866
3867			
3868
3869			/* Filtering */
3870
3871			if ( oSettings.oFeatures.bFilter !== false )
3872
3873			{
3874
3875				aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
3876
3877				aoData.push( { "name": "bRegex",  "value": oSettings.oPreviousSearch.bRegex } );
3878
3879				for ( i=0 ; i<iColumns ; i++ )
3880
3881				{
3882
3883					aoData.push( { "name": "sSearch_"+i,     "value": oSettings.aoPreSearchCols[i].sSearch } );
3884
3885					aoData.push( { "name": "bRegex_"+i,      "value": oSettings.aoPreSearchCols[i].bRegex } );
3886
3887					aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
3888
3889				}
3890
3891			}
3892
3893			
3894
3895			/* Sorting */
3896
3897			if ( oSettings.oFeatures.bSort !== false )
3898
3899			{
3900
3901				var iCounter = 0;
3902
3903		
3904
3905				aaSort = ( oSettings.aaSortingFixed !== null ) ?
3906
3907					oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
3908
3909					oSettings.aaSorting.slice();
3910
3911				
3912
3913				for ( i=0 ; i<aaSort.length ; i++ )
3914
3915				{
3916
3917					aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort;
3918
3919					
3920
3921					for ( j=0 ; j<aDataSort.length ; j++ )
3922
3923					{
3924
3925						aoData.push( { "name": "iSortCol_"+iCounter,  "value": aDataSort[j] } );
3926
3927						aoData.push( { "name": "sSortDir_"+iCounter,  "value": aaSort[i][1] } );
3928
3929						iCounter++;
3930
3931					}
3932
3933				}
3934
3935				aoData.push( { "name": "iSortingCols",   "value": iCounter } );
3936
3937				
3938
3939				for ( i=0 ; i<iColumns ; i++ )
3940
3941				{
3942
3943					aoData.push( { "name": "bSortable_"+i,  "value": oSettings.aoColumns[i].bSortable } );
3944
3945				}
3946
3947			}
3948
3949			
3950
3951			return aoData;
3952
3953		}
3954
3955		
3956
3957		
3958
3959		/**
3960
3961		 * Add Ajax parameters from plug-ins
3962
3963		 *  @param {object} oSettings dataTables settings object
3964
3965		 *  @param array {objects} aoData name/value pairs to send to the server
3966
3967		 *  @memberof DataTable#oApi
3968
3969		 */
3970
3971		function _fnServerParams( oSettings, aoData )
3972
3973		{
3974
3975			_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );
3976
3977		}
3978
3979		
3980
3981		
3982
3983		/**
3984
3985		 * Data the data from the server (nuking the old) and redraw the table
3986
3987		 *  @param {object} oSettings dataTables settings object
3988
3989		 *  @param {object} json json data return from the server.
3990
3991		 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
3992
3993		 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
3994
3995		 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
3996
3997		 *  @param {array} json.aaData The data to display on this page
3998
3999		 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
4000
4001		 *  @memberof DataTable#oApi
4002
4003		 */
4004
4005		function _fnAjaxUpdateDraw ( oSettings, json )
4006
4007		{
4008
4009			if ( json.sEcho !== undefined )
4010
4011			{
4012
4013				/* Protect against old returns over-writing a new one. Possible when you get
4014
4015				 * very fast interaction, and later queries are completed much faster
4016
4017				 */
4018
4019				if ( json.sEcho*1 < oSettings.iDraw )
4020
4021				{
4022
4023					return;
4024
4025				}
4026
4027				else
4028
4029				{
4030
4031					oSettings.iDraw = json.sEcho * 1;
4032
4033				}
4034
4035			}
4036
4037			
4038
4039			if ( !oSettings.oScroll.bInfinite ||
4040
4041				   (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
4042
4043			{
4044
4045				_fnClearTable( oSettings );
4046
4047			}
4048
4049			oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);
4050
4051			oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);
4052
4053			
4054
4055			/* Determine if reordering is required */
4056
4057			var sOrdering = _fnColumnOrdering(oSettings);
4058
4059			var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering );
4060
4061			var aiIndex;
4062
4063			if ( bReOrder )
4064
4065			{
4066
4067				aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
4068
4069			}
4070
4071			
4072
4073			var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );
4074
4075			for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
4076
4077			{
4078
4079				if ( bReOrder )
4080
4081				{
4082
4083					/* If we need to re-order, then create a new array with the correct order and add it */
4084
4085					var aDataSorted = [];
4086
4087					for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
4088
4089					{
4090
4091						aDataSorted.push( aData[i][ aiIndex[j] ] );
4092
4093					}
4094
4095					_fnAddData( oSettings, aDataSorted );
4096
4097				}
4098
4099				else
4100
4101				{
4102
4103					/* No re-order required, sever got it "right" - just straight add */
4104
4105					_fnAddData( oSettings, aData[i] );
4106
4107				}
4108
4109			}
4110
4111			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
4112
4113			
4114
4115			oSettings.bAjaxDataGet = false;
4116
4117			_fnDraw( oSettings );
4118
4119			oSettings.bAjaxDataGet = true;
4120
4121			_fnProcessingDisplay( oSettings, false );
4122
4123		}
4124
4125		
4126
4127		
4128
4129		
4130
4131		/**
4132
4133		 * Generate the node required for filtering text
4134
4135		 *  @returns {node} Filter control element
4136
4137		 *  @param {object} oSettings dataTables settings object
4138
4139		 *  @memberof DataTable#oApi
4140
4141		 */
4142
4143		function _fnFeatureHtmlFilter ( oSettings )
4144
4145		{
4146
4147			var oPreviousSearch = oSettings.oPreviousSearch;
4148
4149			
4150
4151			var sSearchStr = oSettings.oLanguage.sSearch;
4152
4153			sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
4154
4155			  sSearchStr.replace('_INPUT_', '<input type="text" />') :
4156
4157			  sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
4158
4159			
4160
4161			var nFilter = document.createElement( 'div' );
4162
4163			nFilter.className = oSettings.oClasses.sFilter;
4164
4165			nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
4166
4167			if ( !oSettings.aanFeatures.f )
4168
4169			{
4170
4171				nFilter.id = oSettings.sTableId+'_filter';
4172
4173			}
4174
4175			
4176
4177			var jqFilter = $('input[type="text"]', nFilter);
4178
4179		
4180
4181			// Store a reference to the input element, so other input elements could be
4182
4183			// added to the filter wrapper if needed (submit button for example)
4184
4185			nFilter._DT_Input = jqFilter[0];
4186
4187		
4188
4189			jqFilter.val( oPreviousSearch.sSearch.replace('"','&quot;') );
4190
4191			jqFilter.bind( 'keyup.DT', function(e) {
4192
4193				/* Update all other filter input elements for the new display */
4194
4195				var n = oSettings.aanFeatures.f;
4196
4197				var val = this.value==="" ? "" : this.value; // mental IE8 fix :-(
4198
4199		
4200
4201				for ( var i=0, iLen=n.length ; i<iLen ; i++ )
4202
4203				{
4204
4205					if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
4206
4207					{
4208
4209						$(n[i]._DT_Input).val( val );
4210
4211					}
4212
4213				}
4214
4215				
4216
4217				/* Now do the filter */
4218
4219				if ( val != oPreviousSearch.sSearch )
4220
4221				{
4222
4223					_fnFilterComplete( oSettings, { 
4224
4225						"sSearch": val, 
4226
4227						"bRegex": oPreviousSearch.bRegex,
4228
4229						"bSmart": oPreviousSearch.bSmart ,
4230
4231						"bCaseInsensitive": oPreviousSearch.bCaseInsensitive 
4232
4233					} );
4234
4235				}
4236
4237			} );
4238
4239		
4240
4241			jqFilter
4242
4243				.attr('aria-controls', oSettings.sTableId)
4244
4245				.bind( 'keypress.DT', function(e) {
4246
4247					/* Prevent form submission */
4248
4249					if ( e.keyCode == 13 )
4250
4251					{
4252
4253						return false;
4254
4255					}
4256
4257				}
4258
4259			);
4260
4261			
4262
4263			return nFilter;
4264
4265		}
4266
4267		
4268
4269		
4270
4271		/**
4272
4273		 * Filter the table using both the global filter and column based filtering
4274
4275		 *  @param {object} oSettings dataTables settings object
4276
4277		 *  @param {object} oSearch search information
4278
4279		 *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
4280
4281		 *  @memberof DataTable#oApi
4282
4283		 */
4284
4285		function _fnFilterComplete ( oSettings, oInput, iForce )
4286
4287		{
4288
4289			var oPrevSearch = oSettings.oPreviousSearch;
4290
4291			var aoPrevSearch = oSettings.aoPreSearchCols;
4292
4293			var fnSaveFilter = function ( oFilter ) {
4294
4295				/* Save the filtering values */
4296
4297				oPrevSearch.sSearch = oFilter.sSearch;
4298
4299				oPrevSearch.bRegex = oFilter.bRegex;
4300
4301				oPrevSearch.bSmart = oFilter.bSmart;
4302
4303				oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
4304
4305			};
4306
4307		
4308
4309			/* In server-side processing all filtering is done by the server, so no point hanging around here */
4310
4311			if ( !oSettings.oFeatures.bServerSide )
4312
4313			{
4314
4315				/* Global filter */
4316
4317				_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );
4318
4319				fnSaveFilter( oInput );
4320
4321		
4322
4323				/* Now do the individual column filter */
4324
4325				for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
4326
4327				{
4328
4329					_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex, 
4330
4331						aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
4332
4333				}
4334
4335				
4336
4337				/* Custom filtering */
4338
4339				_fnFilterCustom( oSettings );
4340
4341			}
4342
4343			else
4344
4345			{
4346
4347				fnSaveFilter( oInput );
4348
4349			}
4350
4351			
4352
4353			/* Tell the draw function we have been filtering */
4354
4355			oSettings.bFiltered = true;
4356
4357			$(oSettings.oInstance).trigger('filter', oSettings);
4358
4359			
4360langleywa
4361			/* Redraw the table */
4362
4363			oSettings._iDisplayStart = 0;
4364
4365			_fnCalculateEnd( oSettings );
4366
4367			_fnDraw( oSettings );
4368
4369			
4370
4371			/* Rebuild search array 'offline' */
4372
4373			_fnBuildSearchArray( oSettings, 0 );
4374
4375		}
4376
4377		
4378
4379		
4380
4381		/**
4382
4383		 * Apply custom filtering functions
4384
4385		 *  @param {object} oSettings dataTables settings object
4386
4387		 *  @memberof DataTable#oApi
4388
4389		 */
4390
4391		function _fnFilterCustom( oSettings )
4392
4393		{
4394
4395			var afnFilters = DataTable.ext.afnFiltering;
4396
4397			var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
4398
4399		
4400
4401			for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
4402
4403			{
4404
4405				var iCorrector = 0;
4406
4407				for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
4408
4409				{
4410
4411					var iDisIndex = oSettings.aiDisplay[j-iCorrector];
4412
4413					var bTest = afnFilters[i](
4414
4415						oSettings,
4416
4417						_fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),
4418
4419						iDisIndex
4420
4421					);
4422
4423					
4424
4425					/* Check if we should use this row based on the filtering function */
4426
4427					if ( !bTest )
4428
4429					{
4430
4431						oSettings.aiDisplay.splice( j-iCorrector, 1 );
4432
4433						iCorrector++;
4434
4435					}
4436
4437				}
4438
4439			}
4440
4441		}
4442
4443		
4444
4445		
4446
4447		/**
4448
4449		 * Filter the table on a per-column basis
4450
4451		 *  @param {object} oSettings dataTables settings object
4452
4453		 *  @param {string} sInput string to filter on
4454
4455		 *  @param {int} iColumn column to filter
4456
4457		 *  @param {bool} bRegex treat search string as a regular expression or not
4458
4459		 *  @param {bool} bSmart use smart filtering or not
4460
4461		 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
4462
4463		 *  @memberof DataTable#oApi
4464
4465		 */
4466
4467		function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )
4468
4469		{
4470
4471			if ( sInput === "" )
4472
4473			{
4474
4475				return;
4476
4477			}
4478
4479			
4480
4481			var iIndexCorrector = 0;
4482
4483			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
4484
4485			
4486
4487			for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
4488
4489			{
4490
4491				var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
4492
4493					oSettings.aoColumns[iColumn].sType );
4494
4495				if ( ! rpSearch.test( sData ) )
4496
4497				{
4498
4499					oSettings.aiDisplay.splice( i, 1 );
4500
4501					iIndexCorrector++;
4502
4503				}
4504
4505			}
4506
4507		}
4508
4509		
4510
4511		
4512
4513		/**
4514
4515		 * Filter the data table based on user input and draw the table
4516
4517		 *  @param {object} oSettings dataTables settings object
4518
4519		 *  @param {string} sInput string to filter on
4520
4521		 *  @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0)
4522
4523		 *  @param {bool} bRegex treat as a regular expression or not
4524
4525		 *  @param {bool} bSmart perform smart filtering or not
4526
4527		 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
4528
4529		 *  @memberof DataTable#oApi
4530
4531		 */
4532
4533		function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )
4534
4535		{
4536
4537			var i;
4538
4539			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
4540
4541			var oPrevSearch = oSettings.oPreviousSearch;
4542
4543			
4544
4545			/* Check if we are forcing or not - optional parameter */
4546
4547			if ( !iForce )
4548
4549			{
4550
4551				iForce = 0;
4552
4553			}
4554
4555			
4556
4557			/* Need to take account of custom filtering functions - always filter */
4558
4559			if ( DataTable.ext.afnFiltering.length !== 0 )
4560
4561			{
4562
4563				iForce = 1;
4564
4565			}
4566
4567			
4568
4569			/*
4570
4571			 * If the input is blank - we want the full data set
4572
4573			 */
4574
4575			if ( sInput.length <= 0 )
4576
4577			{
4578
4579				oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
4580
4581				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
4582
4583			}
4584
4585			else
4586
4587			{
4588
4589				/*
4590
4591				 * We are starting a new search or the new search string is smaller 
4592
4593				 * then the old one (i.e. delete). Search from the master array
4594
4595			 	 */
4596
4597				if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
4598
4599					   oPrevSearch.sSearch.length > sInput.length || iForce == 1 ||
4600
4601					   sInput.indexOf(oPrevSearch.sSearch) !== 0 )
4602
4603				{
4604
4605					/* Nuke the old display array - we are going to rebuild it */
4606
4607					oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
4608
4609					
4610
4611					/* Force a rebuild of the search array */
4612
4613					_fnBuildSearchArray( oSettings, 1 );
4614
4615					
4616
4617					/* Search through all records to populate the search array
4618
4619					 * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 
4620
4621					 * mapping
4622
4623					 */
4624
4625					for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
4626
4627					{
4628
4629						if ( rpSearch.test(oSettings.asDataSearch[i]) )
4630
4631						{
4632
4633							oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
4634
4635						}
4636
4637					}
4638
4639			  }
4640
4641			  else
4642
4643				{
4644
4645			  	/* Using old search array - refine it - do it this way for speed
4646
4647			  	 * Don't have to search the whole master array again
4648
4649					 */
4650
4651			  	var iIndexCorrector = 0;
4652
4653			  	
4654
4655			  	/* Search the current results */
4656
4657			  	for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
4658
4659					{
4660
4661			  		if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
4662
4663						{
4664
4665			  			oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
4666
4667			  			iIndexCorrector++;
4668
4669			  		}
4670
4671			  	}
4672
4673			  }
4674
4675			}
4676
4677		}
4678
4679		
4680
4681		
4682
4683		/**
4684
4685		 * Create an array which can be quickly search through
4686
4687		 *  @param {object} oSettings dataTables settings object
4688
4689		 *  @param {int} iMaster use the master data array - optional
4690
4691		 *  @memberof DataTable#oApi
4692
4693		 */
4694
4695		function _fnBuildSearchArray ( oSettings, iMaster )
4696
4697		{
4698
4699			if ( !oSettings.oFeatures.bServerSide )
4700
4701			{
4702
4703				/* Clear out the old data */
4704
4705				oSettings.asDataSearch = [];
4706
4707		
4708
4709				var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
4710
4711				var aiIndex = (iMaster===1) ?
4712
4713				 	oSettings.aiDisplayMaster :
4714
4715				 	oSettings.aiDisplay;
4716
4717				
4718
4719				for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ )
4720
4721				{
4722
4723					oSettings.asDataSearch[i] = _fnBuildSearchRow(
4724
4725						oSettings,
4726
4727						_fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns )
4728
4729					);
4730
4731				}
4732
4733			}
4734
4735		}
4736
4737		
4738
4739		
4740
4741		/**
4742
4743		 * Create a searchable string from a single data row
4744
4745		 *  @param {object} oSettings dataTables settings object
4746
4747		 *  @param {array} aData Row data array to use for the data to search
4748
4749		 *  @memberof DataTable#oApi
4750
4751		 */
4752
4753		function _fnBuildSearchRow( oSettings, aData )
4754
4755		{
4756
4757			var sSearch = aData.join('  ');
4758
4759			
4760
4761			/* If it looks like there is an HTML entity in the string, attempt to decode it */
4762
4763			if ( sSearch.indexOf('&') !== -1 )
4764
4765			{
4766
4767				sSearch = $('<div>').html(sSearch).text();
4768
4769			}
4770
4771			
4772
4773			// Strip newline characters
4774
4775			return sSearch.replace( /[\n\r]/g, " " );
4776
4777		}
4778
4779		
4780
4781		/**
4782
4783		 * Build a regular expression object suitable for searching a table
4784
4785		 *  @param {string} sSearch string to search for
4786
4787		 *  @param {bool} bRegex treat as a regular expression or not
4788
4789		 *  @param {bool} bSmart perform smart filtering or not
4790
4791		 *  @param {bool} bCaseInsensitive Do case insensitive matching or not
4792
4793		 *  @returns {RegExp} constructed object
4794
4795		 *  @memberof DataTable#oApi
4796
4797		 */
4798
4799		function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )
4800
4801		{
4802
4803			var asSearch, sRegExpString;
4804
4805			
4806
4807			if ( bSmart )
4808
4809			{
4810
4811				/* Generate the regular expression to use. Something along the lines of:
4812
4813				 * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
4814
4815				 */
4816
4817				asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
4818
4819				sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
4820
4821				return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );
4822
4823			}
4824
4825			else
4826
4827			{
4828
4829				sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
4830
4831				return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );
4832
4833			}
4834
4835		}
4836
4837		
4838
4839		
4840
4841		/**
4842
4843		 * Convert raw data into something that the user can search on
4844
4845		 *  @param {string} sData data to be modified
4846
4847		 *  @param {string} sType data type
4848
4849		 *  @returns {string} search string
4850
4851		 *  @memberof DataTable#oApi
4852
4853		 */
4854
4855		function _fnDataToSearch ( sData, sType )
4856
4857		{
4858
4859			if ( typeof DataTable.ext.ofnSearch[sType] === "function" )
4860
4861			{
4862
4863				return DataTable.ext.ofnSearch[sType]( sData );
4864
4865			}
4866
4867			else if ( sData === null )
4868langleywa
4869			{
4870
4871				return '';
4872
4873			}
4874
4875			else if ( sType == "html" )
4876
4877			{
4878
4879				return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
4880
4881			}
4882
4883			else if ( typeof sData === "string" )
4884
4885			{
4886
4887				return sData.replace(/[\r\n]/g," ");
4888
4889			}
4890
4891			return sData;
4892
4893		}
4894
4895		
4896
4897		
4898
4899		/**
4900
4901		 * scape a string such that it can be used in a regular expression
4902
4903		 *  @param {string} sVal string to escape
4904
4905		 *  @returns {string} escaped string
4906
4907		 *  @memberof DataTable#oApi
4908
4909		 */
4910
4911		function _fnEscapeRegex ( sVal )
4912
4913		{
4914
4915			var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];
4916
4917			var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
4918
4919			return sVal.replace(reReplace, '\\$1');
4920
4921		}
4922
4923		
4924
4925		
4926
4927		/**
4928
4929		 * Generate the node required for the info display
4930
4931		 *  @param {object} oSettings dataTables settings object
4932
4933		 *  @returns {node} Information element
4934
4935		 *  @memberof DataTable#oApi
4936
4937		 */
4938
4939		function _fnFeatureHtmlInfo ( oSettings )
4940
4941		{
4942
4943			var nInfo = document.createElement( 'div' );
4944
4945			nInfo.className = oSettings.oClasses.sInfo;
4946
4947			
4948
4949			/* Actions that are to be taken once only for this feature */
4950
4951			if ( !oSettings.aanFeatures.i )
4952
4953			{
4954
4955				/* Add draw callback */
4956
4957				oSettings.aoDrawCallback.push( {
4958
4959					"fn": _fnUpdateInfo,
4960
4961					"sName": "information"
4962
4963				} );
4964
4965				
4966
4967				/* Add id */
4968
4969				nInfo.id = oSettings.sTableId+'_info';
4970
4971			}
4972
4973			oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );
4974
4975			
4976
4977			return nInfo;
4978
4979		}
4980
4981		
4982
4983		
4984
4985		/**
4986
4987		 * Update the information elements in the display
4988
4989		 *  @param {object} oSettings dataTables settings object
4990
4991		 *  @memberof DataTable#oApi
4992
4993		 */
4994
4995		function _fnUpdateInfo ( oSettings )
4996
4997		{
4998
4999			/* Show information about the table */
5000
5001			if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
5002
5003			{
5004
5005				return;
5006
5007			}
5008
5009			
5010
5011			var
5012
5013				oLang = oSettings.oLanguage,
5014
5015				iStart = oSettings._iDisplayStart+1,
5016
5017				iEnd = oSettings.fnDisplayEnd(),
5018
5019				iMax = oSettings.fnRecordsTotal(),
5020
5021				iTotal = oSettings.fnRecordsDisplay(),
5022
5023				sOut;
5024
5025			
5026
5027			if ( iTotal === 0 )
5028
5029			{
5030
5031				/* Empty record set */
5032
5033				sOut = oLang.sInfoEmpty;
5034
5035			}
5036
5037			else {
5038
5039				/* Normal record set */
5040
5041				sOut = oLang.sInfo;
5042
5043			}
5044
5045		
5046
5047			if ( iTotal != iMax )
5048
5049			{
5050
5051				/* Record set after filtering */
5052
5053				sOut += ' ' + oLang.sInfoFiltered;
5054
5055			}
5056
5057		
5058
5059			// Convert the macros
5060
5061			sOut += oLang.sInfoPostFix;
5062
5063			sOut = _fnInfoMacros( oSettings, sOut );
5064
5065			
5066
5067			if ( oLang.fnInfoCallback !== null )
5068
5069			{
5070
5071				sOut = oLang.fnInfoCallback.call( oSettings.oInstance, 
5072
5073					oSettings, iStart, iEnd, iMax, iTotal, sOut );
5074
5075			}
5076
5077			
5078
5079			var n = oSettings.aanFeatures.i;
5080
5081			for ( var i=0, iLen=n.length ; i<iLen ; i++ )
5082
5083			{
5084
5085				$(n[i]).html( sOut );
5086
5087			}
5088
5089		}
5090
5091		
5092
5093		
5094
5095		function _fnInfoMacros ( oSettings, str )
5096
5097		{
5098
5099			var
5100
5101				iStart = oSettings._iDisplayStart+1,
5102
5103				sStart = oSettings.fnFormatNumber( iStart ),
5104
5105				iEnd = oSettings.fnDisplayEnd(),
5106
5107				sEnd = oSettings.fnFormatNumber( iEnd ),
5108
5109				iTotal = oSettings.fnRecordsDisplay(),
5110
5111				sTotal = oSettings.fnFormatNumber( iTotal ),
5112
5113				iMax = oSettings.fnRecordsTotal(),
5114
5115				sMax = oSettings.fnFormatNumber( iMax );
5116
5117		
5118
5119			// When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
5120
5121			// internally
5122
5123			if ( oSettings.oScroll.bInfinite )
5124
5125			{
5126
5127				sStart = oSettings.fnFormatNumber( 1 );
5128
5129			}
5130
5131		
5132
5133			return str.
5134
5135				replace(/_START_/g, sStart).
5136
5137				replace(/_END_/g,   sEnd).
5138
5139				replace(/_TOTAL_/g, sTotal).
5140
5141				replace(/_MAX_/g,   sMax);
5142
5143		}
5144
5145		
5146
5147		
5148
5149		
5150
5151		/**
5152
5153		 * Draw the table for the first time, adding all required features
5154
5155		 *  @param {object} oSettings dataTables settings object
5156
5157		 *  @memberof DataTable#oApi
5158
5159		 */
5160
5161		function _fnInitialise ( oSettings )
5162
5163		{
5164
5165			var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
5166
5167			
5168
5169			/* Ensure that the table data is fully initialised */
5170
5171			if ( oSettings.bInitialised === false )
5172
5173			{
5174
5175				setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
5176
5177				return;
5178
5179			}
5180
5181			
5182
5183			/* Show the display HTML options */
5184
5185			_fnAddOptionsHtml( oSettings );
5186
5187			
5188
5189			/* Build and draw the header / footer for the table */
5190
5191			_fnBuildHead( oSettings );
5192
5193			_fnDrawHead( oSettings, oSettings.aoHeader );
5194
5195			if ( oSettings.nTFoot )
5196
5197			{
5198
5199				_fnDrawHead( oSettings, oSettings.aoFooter );
5200
5201			}
5202
5203		
5204
5205			/* Okay to show that something is going on now */
5206
5207			_fnProcessingDisplay( oSettings, true );
5208
5209			
5210
5211			/* Calculate sizes for columns */
5212
5213			if ( oSettings.oFeatures.bAutoWidth )
5214
5215			{
5216
5217				_fnCalculateColumnWidths( oSettings );
5218
5219			}
5220
5221			
5222
5223			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
5224
5225			{
5226
5227				if ( oSettings.aoColumns[i].sWidth !== null )
5228
5229				{
5230
5231					oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
5232
5233				}
5234
5235			}
5236
5237			
5238
5239			/* If there is default sorting required - let's do it. The sort function will do the
5240
5241			 * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
5242
5243			 * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
5244
5245			 */
5246
5247			if ( oSettings.oFeatures.bSort )
5248
5249			{
5250
5251				_fnSort( oSettings );
5252
5253			}
5254
5255			else if ( oSettings.oFeatures.bFilter )
5256
5257			{
5258
5259				_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
5260
5261			}
5262
5263			else
5264
5265			{
5266
5267				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
5268
5269				_fnCalculateEnd( oSettings );
5270
5271				_fnDraw( oSettings );
5272
5273			}
5274
5275			
5276
5277			/* if there is an ajax source load the data */
5278
5279			if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
5280
5281			{
5282
5283				var aoData = [];
5284
5285				_fnServerParams( oSettings, aoData );
5286
5287				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
5288
5289					var aData = (oSettings.sAjaxDataProp !== "") ?
5290
5291					 	_fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json;
5292
5293		
5294
5295					/* Got the data - add it to the table */
5296
5297					for ( i=0 ; i<aData.length ; i++ )
5298
5299					{
5300
5301						_fnAddData( oSettings, aData[i] );
5302
5303					}
5304
5305					
5306
5307					/* Reset the init display for cookie saving. We've already done a filter, and
5308
5309					 * therefore cleared it before. So we need to make it appear 'fresh'
5310
5311					 */
5312
5313					oSettings.iInitDisplayStart = iAjaxStart;
5314
5315					
5316
5317					if ( oSettings.oFeatures.bSort )
5318
5319					{
5320
5321						_fnSort( oSettings );
5322
5323					}
5324
5325					else
5326
5327					{
5328
5329						oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
5330
5331						_fnCalculateEnd( oSettings );
5332
5333						_fnDraw( oSettings );
5334
5335					}
5336
5337					
5338
5339					_fnProcessingDisplay( oSettings, false );
5340
5341					_fnInitComplete( oSettings, json );
5342
5343				}, oSettings );
5344
5345				return;
5346
5347			}
5348
5349			
5350
5351			/* Server-side processing initialisation complete is done at the end of _fnDraw */
5352
5353			if ( !oSettings.oFeatures.bServerSide )
5354
5355			{
5356
5357				_fnProcessingDisplay( oSettings, false );
5358
5359				_fnInitComplete( oSettings );
5360
5361			}
5362
5363		}
5364
5365		
5366
5367		
5368
5369		/**
5370
5371		 * Draw the table for the first time, adding all required features
5372
5373		 *  @param {object} oSettings dataTables settings object
5374
5375		 *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
5376
5377		 *    with client-side processing (optional)
5378
5379		 *  @memberof DataTable#oApi
5380
5381		 */
5382
5383		function _fnInitComplete ( oSettings, json )
5384
5385		{
5386
5387			oSettings._bInitComplete = true;
5388
5389			_fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );
5390
5391		}
5392
5393		
5394
5395		
5396
5397		/**
5398
5399		 * Language compatibility - when certain options are given, and others aren't, we
5400
5401		 * need to duplicate the values over, in order to provide backwards compatibility
5402
5403		 * with older language files.
5404
5405		 *  @param {object} oSettings dataTables settings object
5406
5407		 *  @memberof DataTable#oApi
5408
5409		 */
5410
5411		function _fnLanguageCompat( oLanguage )
5412
5413		{
5414
5415			var oDefaults = DataTable.defaults.oLanguage;
5416
5417		
5418
5419			/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
5420
5421			 * sZeroRecords - assuming that is given.
5422
5423			 */
5424
5425			if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&
5426
5427				oDefaults.sEmptyTable === "No data available in table" )
5428
5429			{
5430
5431				_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
5432
5433			}
5434
5435		
5436
5437			/* Likewise with loading records */
5438
5439			if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&
5440
5441				oDefaults.sLoadingRecords === "Loading..." )
5442
5443			{
5444
5445				_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
5446
5447			}
5448
5449		}
5450
5451		
5452
5453		
5454
5455		
5456
5457		/**
5458
5459		 * Generate the node required for user display length changing
5460
5461		 *  @param {object} oSettings dataTables settings object
5462
5463		 *  @returns {node} Display length feature node
5464
5465		 *  @memberof DataTable#oApi
5466
5467		 */
5468
5469		function _fnFeatureHtmlLength ( oSettings )
5470
5471		{
5472
5473			if ( oSettings.oScroll.bInfinite )
5474
5475			{
5476
5477				return null;
5478
5479			}
5480
5481			
5482
5483			/* This can be overruled by not using the _MENU_ var/macro in the language variable */
5484
5485			var sName = 'name="'+oSettings.sTableId+'_length"';
5486
5487			var sStdMenu = '<select id="e1" size="1" '+sName+'>';
5488
5489			var i, iLen;
5490
5491			var aLengthMenu = oSettings.aLengthMenu;
5492
5493			
5494
5495			if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && 
5496
5497					typeof aLengthMenu[1] === 'object' )
5498
5499			{
5500
5501				for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )
5502
5503				{
5504
5505					sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';
5506
5507				}
5508
5509			}
5510
5511			else
5512
5513			{
5514
5515				for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )
5516
5517				{
5518
5519					sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';
5520
5521				}
5522
5523			}
5524
5525			sStdMenu += '</select>';
5526
5527			
5528
5529			var nLength = document.createElement( 'div' );
5530
5531			if ( !oSettings.aanFeatures.l )
5532
5533			{
5534
5535				nLength.id = oSettings.sTableId+'_length';
5536
5537			}
5538
5539			nLength.className = oSettings.oClasses.sLength;
5540
5541			nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
5542
5543			
5544
5545			/*
5546
5547			 * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
5548
5549			 * and Stefan Skopnik for fixing the fix!
5550
5551			 */
5552
5553			$('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);
5554
5555			
5556
5557			$('select', nLength).bind( 'change.DT', function(e) {
5558
5559				var iVal = $(this).val();
5560
5561				
5562
5563				/* Update all other length options for the new display */
5564
5565				var n = oSettings.aanFeatures.l;
5566
5567				for ( i=0, iLen=n.length ; i<iLen ; i++ )
5568
5569				{
5570
5571					if ( n[i] != this.parentNode )
5572
5573					{
5574
5575						$('select', n[i]).val( iVal );
5576
5577					}
5578
5579				}
5580
5581				
5582
5583				/* Redraw the table */
5584
5585				oSettings._iDisplayLength = parseInt(iVal, 10);
5586
5587				_fnCalculateEnd( oSettings );
5588
5589				
5590
5591				/* If we have space to show extra rows (backing up from the end point - then do so */
5592
5593				if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
5594
5595				{
5596
5597					oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
5598
5599					if ( oSettings._iDisplayStart < 0 )
5600
5601					{
5602
5603						oSettings._iDisplayStart = 0;
5604
5605					}
5606
5607				}
5608
5609				
5610
5611				if ( oSettings._iDisplayLength == -1 )
5612
5613				{
5614
5615					oSettings._iDisplayStart = 0;
5616
5617				}
5618
5619				
5620
5621				_fnDraw( oSettings );
5622
5623			} );
5624
5625		
5626
5627		
5628
5629			$('select', nLength).attr('aria-controls', oSettings.sTableId);
5630
5631			
5632
5633			return nLength;
5634
5635		}
5636
5637		
5638
5639		
5640
5641		/**
5642
5643		 * Recalculate the end point based on the start point
5644
5645		 *  @param {object} oSettings dataTables settings object
5646
5647		 *  @memberof DataTable#oApi
5648
5649		 */
5650
5651		function _fnCalculateEnd( oSettings )
5652
5653		{
5654
5655			if ( oSettings.oFeatures.bPaginate === false )
5656
5657			{
5658
5659				oSettings._iDisplayEnd = oSettings.aiDisplay.length;
5660
5661			}
5662
5663			else
5664
5665			{
5666
5667				/* Set the end point of the display - based on how many elements there are
5668
5669				 * still to display
5670
5671				 */
5672
5673				if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
5674
5675					   oSettings._iDisplayLength == -1 )
5676
5677				{
5678
5679					oSettings._iDisplayEnd = oSettings.aiDisplay.length;
5680
5681				}
5682
5683				else
5684
5685				{
5686
5687					oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
5688
5689				}
5690
5691			}
5692
5693		}
5694
5695		
5696
5697		
5698
5699		
5700
5701		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
5702
5703		 * Note that most of the paging logic is done in 
5704
5705		 * DataTable.ext.oPagination
5706
5707		 */
5708
5709		
5710
5711		/**
5712
5713		 * Generate the node required for default pagination
5714
5715		 *  @param {object} oSettings dataTables settings object
5716
5717		 *  @returns {node} Pagination feature node
5718
5719		 *  @memberof DataTable#oApi
5720
5721		 */
5722
5723		function _fnFeatureHtmlPaginate ( oSettings )
5724
5725		{
5726
5727			if ( oSettings.oScroll.bInfinite )
5728
5729			{
5730
5731				return null;
5732
5733			}
5734
5735			
5736
5737			var nPaginate = document.createElement( 'div' );
5738
5739			nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
5740
5741			
5742
5743			DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, 
5744
5745				function( oSettings ) {
5746
5747					_fnCalculateEnd( oSettings );
5748
5749					_fnDraw( oSettings );
5750
5751				}
5752
5753			);
5754
5755			
5756
5757			/* Add a draw callback for the pagination on first instance, to update the paging display */
5758
5759			if ( !oSettings.aanFeatures.p )
5760
5761			{
5762
5763				oSettings.aoDrawCallback.push( {
5764
5765					"fn": function( oSettings ) {
5766
5767						DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
5768
5769							_fnCalculateEnd( oSettings );
5770
5771							_fnDraw( oSettings );
5772
5773						} );
5774
5775					},
5776
5777					"sName": "pagination"
5778
5779				} );
5780
5781			}
5782
5783			return nPaginate;
5784
5785		}
5786
5787		
5788
5789		
5790
5791		/**
5792
5793		 * Alter the display settings to change the page
5794
5795		 *  @param {object} oSettings dataTables settings object
5796
5797		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5798
5799		 *    or page number to jump to (integer)
5800
5801		 *  @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1
5802
5803		 *  @memberof DataTable#oApi
5804
5805		 */
5806
5807		function _fnPageChange ( oSettings, mAction )
5808
5809		{
5810
5811			var iOldStart = oSettings._iDisplayStart;
5812
5813			
5814
5815			if ( typeof mAction === "number" )
5816
5817			{
5818
5819				oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;
5820
5821				if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )
5822
5823				{
5824
5825					oSettings._iDisplayStart = 0;
5826
5827				}
5828
5829			}
5830
5831			else if ( mAction == "first" )
5832
5833			{
5834
5835				oSettings._iDisplayStart = 0;
5836
5837			}
5838
5839			else if ( mAction == "previous" )
5840
5841			{
5842
5843				oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
5844
5845					oSettings._iDisplayStart - oSettings._iDisplayLength :
5846
5847					0;
5848
5849				
5850
5851				/* Correct for under-run */
5852
5853				if ( oSettings._iDisplayStart < 0 )
5854
5855				{
5856
5857				  oSettings._iDisplayStart = 0;
5858
5859				}
5860
5861			}
5862
5863			else if ( mAction == "next" )
5864
5865			{
5866
5867				if ( oSettings._iDisplayLength >= 0 )
5868
5869				{
5870
5871					/* Make sure we are not over running the display array */
5872
5873					if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
5874
5875					{
5876
5877						oSettings._iDisplayStart += oSettings._iDisplayLength;
5878
5879					}
5880
5881				}
5882
5883				else
5884
5885				{
5886
5887					oSettings._iDisplayStart = 0;
5888
5889				}
5890
5891			}
5892
5893			else if ( mAction == "last" )
5894
5895			{
5896
5897				if ( oSettings._iDisplayLength >= 0 )
5898
5899				{
5900
5901					var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
5902
5903					oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
5904
5905				}
5906
5907				else
5908
5909				{
5910
5911					oSettings._iDisplayStart = 0;
5912
5913				}
5914
5915			}
5916
5917			else
5918
5919			{
5920
5921				_fnLog( oSettings, 0, "Unknown paging action: "+mAction );
5922
5923			}
5924
5925			$(oSettings.oInstance).trigger('page', oSettings);
5926
5927			
5928
5929			return iOldStart != oSettings._iDisplayStart;
5930
5931		}
5932
5933		
5934
5935		
5936
5937		
5938
5939		/**
5940
5941		 * Generate the node required for the processing node
5942
5943		 *  @param {object} oSettings dataTables settings object
5944
5945		 *  @returns {node} Processing element
5946
5947		 *  @memberof DataTable#oApi
5948
5949		 */
5950
5951		function _fnFeatureHtmlProcessing ( oSettings )
5952
5953		{
5954
5955			var nProcessing = document.createElement( 'div' );
5956
5957			
5958
5959			if ( !oSettings.aanFeatures.r )
5960
5961			{
5962
5963				nProcessing.id = oSettings.sTableId+'_processing';
5964
5965			}
5966
5967			nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
5968
5969			nProcessing.className = oSettings.oClasses.sProcessing;
5970
5971			oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
5972
5973			
5974
5975			return nProcessing;
5976
5977		}
5978
5979		
5980
5981		
5982
5983		/**
5984
5985		 * Display or hide the processing indicator
5986
5987		 *  @param {object} oSettings dataTables settings object
5988
5989		 *  @param {bool} bShow Show the processing indicator (true) or not (false)
5990
5991		 *  @memberof DataTable#oApi
5992
5993		 */
5994
5995		function _fnProcessingDisplay ( oSettings, bShow )
5996
5997		{
5998
5999			if ( oSettings.oFeatures.bProcessing )
6000
6001			{
6002
6003				var an = oSettings.aanFeatures.r;
6004
6005				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
6006
6007				{
6008
6009					an[i].style.visibility = bShow ? "visible" : "hidden";
6010
6011				}
6012
6013			}
6014
6015		
6016
6017			$(oSettings.oInstance).trigger('processing', [oSettings, bShow]);
6018
6019		}
6020
6021		
6022
6023		/**
6024
6025		 * Add any control elements for the table - specifically scrolling
6026
6027		 *  @param {object} oSettings dataTables settings object
6028
6029		 *  @returns {node} Node to add to the DOM
6030
6031		 *  @memberof DataTable#oApi
6032
6033		 */
6034
6035		function _fnFeatureHtmlTable ( oSettings )
6036
6037		{
6038
6039			/* Check if scrolling is enabled or not - if not then leave the DOM unaltered */
6040
6041			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
6042
6043			{
6044
6045				return oSettings.nTable;
6046
6047			}
6048
6049			
6050
6051			/*
6052
6053			 * The HTML structure that we want to generate in this function is:
6054
6055			 *  div - nScroller
6056
6057			 *    div - nScrollHead
6058
6059			 *      div - nScrollHeadInner
6060
6061			 *        table - nScrollHeadTable
6062
6063			 *          thead - nThead
6064
6065			 *    div - nScrollBody
6066
6067			 *      table - oSettings.nTable
6068
6069			 *        thead - nTheadSize
6070
6071			 *        tbody - nTbody
6072
6073			 *    div - nScrollFoot
6074
6075			 *      div - nScrollFootInner
6076
6077			 *        table - nScrollFootTable
6078
6079			 *          tfoot - nTfoot
6080
6081			 */
6082
6083			var
6084
6085			 	nScroller = document.createElement('div'),
6086
6087			 	nScrollHead = document.createElement('div'),
6088
6089			 	nScrollHeadInner = document.createElement('div'),
6090
6091			 	nScrollBody = document.createElement('div'),
6092
6093			 	nScrollFoot = document.createElement('div'),
6094
6095			 	nScrollFootInner = document.createElement('div'),
6096
6097			 	nScrollHeadTable = oSettings.nTable.cloneNode(false),
6098
6099			 	nScrollFootTable = oSettings.nTable.cloneNode(false),
6100
6101				nThead = oSettings.nTable.getElementsByTagName('thead')[0],
6102
6103			 	nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : 
6104
6105					oSettings.nTable.getElementsByTagName('tfoot')[0],
6106
6107				oClasses = oSettings.oClasses;
6108
6109			
6110
6111			nScrollHead.appendChild( nScrollHeadInner );
6112
6113			nScrollFoot.appendChild( nScrollFootInner );
6114
6115			nScrollBody.appendChild( oSettings.nTable );
6116
6117			nScroller.appendChild( nScrollHead );
6118
6119			nScroller.appendChild( nScrollBody );
6120
6121			nScrollHeadInner.appendChild( nScrollHeadTable );
6122
6123			nScrollHeadTable.appendChild( nThead );
6124
6125			if ( nTfoot !== null )
6126
6127			{
6128
6129				nScroller.appendChild( nScrollFoot );
6130
6131				nScrollFootInner.appendChild( nScrollFootTable );
6132
6133				nScrollFootTable.appendChild( nTfoot );
6134
6135			}
6136
6137			
6138
6139			nScroller.className = oClasses.sScrollWrapper;
6140
6141			nScrollHead.className = oClasses.sScrollHead;
6142
6143			nScrollHeadInner.className = oClasses.sScrollHeadInner;
6144
6145			nScrollBody.className = oClasses.sScrollBody;
6146
6147			nScrollFoot.className = oClasses.sScrollFoot;
6148
6149			nScrollFootInner.className = oClasses.sScrollFootInner;
6150
6151			
6152
6153			if ( oSettings.oScroll.bAutoCss )
6154
6155			{
6156
6157				nScrollHead.style.overflow = "hidden";
6158
6159				nScrollHead.style.position = "relative";
6160
6161				nScrollFoot.style.overflow = "hidden";
6162
6163				nScrollBody.style.overflow = "auto";
6164
6165			}
6166
6167			
6168
6169			nScrollHead.style.border = "0";
6170
6171			nScrollHead.style.width = "100%";
6172
6173			nScrollFoot.style.border = "0";
6174
6175			nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ?
6176
6177				oSettings.oScroll.sXInner : "100%"; /* will be overwritten */
6178
6179			
6180
6181			/* Modify attributes to respect the clones */
6182
6183			nScrollHeadTable.removeAttribute('id');
6184
6185			nScrollHeadTable.style.marginLeft = "0";
6186
6187			oSettings.nTable.style.marginLeft = "0";
6188
6189			if ( nTfoot !== null )
6190
6191			{
6192
6193				nScrollFootTable.removeAttribute('id');
6194
6195				nScrollFootTable.style.marginLeft = "0";
6196
6197			}
6198
6199			
6200
6201			/* Move caption elements from the body to the header, footer or leave where it is
6202
6203			 * depending on the configuration. Note that the DTD says there can be only one caption */
6204
6205			var nCaption = $(oSettings.nTable).children('caption');
6206
6207			if ( nCaption.length > 0 )
6208
6209			{
6210
6211				nCaption = nCaption[0];
6212
6213				if ( nCaption._captionSide === "top" )
6214
6215				{
6216
6217					nScrollHeadTable.appendChild( nCaption );
6218
6219				}
6220
6221				else if ( nCaption._captionSide === "bottom" && nTfoot )
6222
6223				{
6224
6225					nScrollFootTable.appendChild( nCaption );
6226
6227				}
6228
6229			}
6230
6231			
6232
6233			/*
6234
6235			 * Sizing
6236
6237			 */
6238
6239			/* When x-scrolling add the width and a scroller to move the header with the body */
6240
6241			if ( oSettings.oScroll.sX !== "" )
6242
6243			{
6244
6245				nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
6246
6247				nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
6248
6249				
6250
6251				if ( nTfoot !== null )
6252
6253				{
6254
6255					nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );	
6256
6257				}
6258
6259				
6260
6261				/* When the body is scrolled, then we also want to scroll the headers */
6262
6263				$(nScrollBody).scroll( function (e) {
6264
6265					nScrollHead.scrollLeft = this.scrollLeft;
6266
6267					
6268
6269					if ( nTfoot !== null )
6270
6271					{
6272
6273						nScrollFoot.scrollLeft = this.scrollLeft;
6274
6275					}
6276
6277				} );
6278
6279			}
6280
6281			
6282
6283			/* When yscrolling, add the height */
6284
6285			if ( oSettings.oScroll.sY !== "" )
6286
6287			{
6288
6289				nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
6290
6291			}
6292
6293			
6294
6295			/* Redraw - align columns across the tables */
6296
6297			oSettings.aoDrawCallback.push( {
6298
6299				"fn": _fnScrollDraw,
6300
6301				"sName": "scrolling"
6302
6303			} );
6304
6305			
6306
6307			/* Infinite scrolling event handlers */
6308
6309			if ( oSettings.oScroll.bInfinite )
6310
6311			{
6312
6313				$(nScrollBody).scroll( function() {
6314
6315					/* Use a blocker to stop scrolling from loading more data while other data is still loading */
6316
6317					if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 )
6318
6319					{
6320
6321						/* Check if we should load the next data set */
6322
6323						if ( $(this).scrollTop() + $(this).height() > 
6324
6325							$(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
6326
6327						{
6328
6329							/* Only do the redraw if we have to - we might be at the end of the data */
6330
6331							if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
6332
6333							{
6334
6335								_fnPageChange( oSettings, 'next' );
6336
6337								_fnCalculateEnd( oSettings );
6338
6339								_fnDraw( oSettings );
6340
6341							}
6342
6343						}
6344
6345					}
6346
6347				} );
6348
6349			}
6350
6351			
6352
6353			oSettings.nScrollHead = nScrollHead;
6354
6355			oSettings.nScrollFoot = nScrollFoot;
6356
6357			
6358
6359			return nScroller;
6360
6361		}
6362
6363		
6364
6365		
6366
6367		/**
6368
6369		 * Update the various tables for resizing. It's a bit of a pig this function, but
6370
6371		 * basically the idea to:
6372
6373		 *   1. Re-create the table inside the scrolling div
6374
6375		 *   2. Take live measurements from the DOM
6376
6377		 *   3. Apply the measurements
6378
6379		 *   4. Clean up
6380
6381		 *  @param {object} o dataTables settings object
6382
6383		 *  @returns {node} Node to add to the DOM
6384
6385		 *  @memberof DataTable#oApi
6386
6387		 */
6388
6389		function _fnScrollDraw ( o )
6390
6391		{
6392
6393			var
6394
6395				nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
6396
6397				nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
6398
6399				nScrollBody = o.nTable.parentNode,
6400
6401				i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
6402
6403				nTheadSize, nTfootSize,
6404
6405				iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth,
6406
6407				nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
6408
6409				nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
6410
6411				ie67 = o.oBrowser.bScrollOversize,
6412
6413				zeroOut = function(nSizer) {
6414
6415					oStyle = nSizer.style;
6416
6417					oStyle.paddingTop = "0";
6418
6419					oStyle.paddingBottom = "0";
6420
6421					oStyle.borderTopWidth = "0";
6422
6423					oStyle.borderBottomWidth = "0";
6424
6425					oStyle.height = 0;
6426
6427				};
6428
6429			
6430
6431			/*
6432
6433			 * 1. Re-create the table inside the scrolling div
6434
6435			 */
6436
6437			
6438
6439			/* Remove the old minimised thead and tfoot elements in the inner table */
6440
6441			$(o.nTable).children('thead, tfoot').remove();
6442
6443		
6444
6445			/* Clone the current header and footer elements and then place it into the inner table */
6446
6447			nTheadSize = $(o.nTHead).clone()[0];
6448
6449			o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
6450
6451			anHeadToSize = o.nTHead.getElementsByTagName('tr');
6452
6453			anHeadSizers = nTheadSize.getElementsByTagName('tr');
6454
6455			
6456
6457			if ( o.nTFoot !== null )
6458
6459			{
6460
6461				nTfootSize = $(o.nTFoot).clone()[0];
6462
6463				o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
6464
6465				anFootToSize = o.nTFoot.getElementsByTagName('tr');
6466
6467				anFootSizers = nTfootSize.getElementsByTagName('tr');
6468
6469			}
6470
6471			
6472
6473			/*
6474
6475			 * 2. Take live measurements from the DOM - do not alter the DOM itself!
6476
6477			 */
6478
6479			
6480
6481			/* Remove old sizing and apply the calculated column widths
6482
6483			 * Get the unique column headers in the newly created (cloned) header. We want to apply the
6484
6485			 * calculated sizes to this header
6486
6487			 */
6488
6489			if ( o.oScroll.sX === "" )
6490
6491			{
6492
6493				nScrollBody.style.width = '100%';
6494
6495				nScrollHeadInner.parentNode.style.width = '100%';
6496
6497			}
6498
6499			
6500
6501			var nThs = _fnGetUniqueThs( o, nTheadSize );
6502
6503			for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
6504
6505			{
6506
6507				iVis = _fnVisibleToColumnIndex( o, i );
6508
6509				nThs[i].style.width = o.aoColumns[iVis].sWidth;
6510
6511			}
6512
6513			
6514
6515			if ( o.nTFoot !== null )
6516
6517			{
6518
6519				_fnApplyToChildren( function(n) {
6520
6521					n.style.width = "";
6522
6523				}, anFootSizers );
6524
6525			}
6526
6527		
6528
6529			// If scroll collapse is enabled, when we put the headers back into the body for sizing, we
6530
6531			// will end up forcing the scrollbar to appear, making our measurements wrong for when we
6532
6533			// then hide it (end of this function), so add the header height to the body scroller.
6534
6535			if ( o.oScroll.bCollapse && o.oScroll.sY !== "" )
6536
6537			{
6538
6539				nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";
6540
6541			}
6542
6543			
6544
6545			/* Size the table as a whole */
6546
6547			iSanityWidth = $(o.nTable).outerWidth();
6548
6549			if ( o.oScroll.sX === "" )
6550
6551			{
6552
6553				/* No x scrolling */
6554
6555				o.nTable.style.width = "100%";
6556
6557				
6558
6559				/* I know this is rubbish - but IE7 will make the width of the table when 100% include
6560
6561				 * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
6562
6563				 * into account.
6564
6565				 */
6566
6567				if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || 
6568
6569					$(nScrollBody).css('overflow-y') == "scroll")  )
6570
6571				{
6572
6573					o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
6574
6575				}
6576
6577			}
6578
6579			else
6580
6581			{
6582
6583				if ( o.oScroll.sXInner !== "" )
6584
6585				{
6586
6587					/* x scroll inner has been given - use it */
6588
6589					o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
6590
6591				}
6592
6593				else if ( iSanityWidth == $(nScrollBody).width() &&
6594
6595				   $(nScrollBody).height() < $(o.nTable).height() )
6596
6597				{
6598
6599					/* There is y-scrolling - try to take account of the y scroll bar */
6600
6601					o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
6602
6603					if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
6604
6605					{
6606
6607						/* Not possible to take account of it */
6608
6609						o.nTable.style.width = _fnStringToCss( iSanityWidth );
6610
6611					}
6612
6613				}
6614
6615				else
6616
6617				{
6618
6619					/* All else fails */
6620
6621					o.nTable.style.width = _fnStringToCss( iSanityWidth );
6622
6623				}
6624
6625			}
6626
6627			
6628
6629			/* Recalculate the sanity width - now that we've applied the required width, before it was
6630
6631			 * a temporary variable. This is required because the column width calculation is done
6632
6633			 * before this table DOM is created.
6634
6635			 */
6636
6637			iSanityWidth = $(o.nTable).outerWidth();
6638
6639			
6640
6641			/* We want the hidden header to have zero height, so remove padding and borders. Then
6642
6643			 * set the width based on the real headers
6644
6645			 */
6646
6647			
6648
6649			// Apply all styles in one pass. Invalidates layout only once because we don't read any 
6650
6651			// DOM properties.
6652
6653			_fnApplyToChildren( zeroOut, anHeadSizers );
6654
6655			 
6656
6657			// Read all widths in next pass. Forces layout only once because we do not change 
6658
6659			// any DOM properties.
6660
6661			_fnApplyToChildren( function(nSizer) {
6662
6663				aApplied.push( _fnStringToCss( $(nSizer).width() ) );
6664
6665			}, anHeadSizers );
6666
6667			 
6668
6669			// Apply all widths in final pass. Invalidates layout only once because we do not
6670
6671			// read any DOM properties.
6672
6673			_fnApplyToChildren( function(nToSize, i) {
6674
6675				nToSize.style.width = aApplied[i];
6676
6677			}, anHeadToSize );
6678
6679		
6680
6681			$(anHeadSizers).height(0);
6682
6683			
6684
6685			/* Same again with the footer if we have one */
6686
6687			if ( o.nTFoot !== null )
6688
6689			{
6690
6691				_fnApplyToChildren( zeroOut, anFootSizers );
6692
6693				 
6694
6695				_fnApplyToChildren( function(nSizer) {
6696
6697					aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) );
6698
6699				}, anFootSizers );
6700
6701				 
6702
6703				_fnApplyToChildren( function(nToSize, i) {
6704
6705					nToSize.style.width = aAppliedFooter[i];
6706
6707				}, anFootToSize );
6708
6709		
6710
6711				$(anFootSizers).height(0);
6712
6713			}
6714
6715			
6716
6717			/*
6718
6719			 * 3. Apply the measurements
6720
6721			 */
6722
6723			
6724
6725			/* "Hide" the header and footer that we used for the sizing. We want to also fix their width
6726
6727			 * to what they currently are
6728
6729			 */
6730
6731			_fnApplyToChildren( function(nSizer, i) {
6732
6733				nSizer.innerHTML = "";
6734
6735				nSizer.style.width = aApplied[i];
6736
6737			}, anHeadSizers );
6738
6739			
6740
6741			if ( o.nTFoot !== null )
6742
6743			{
6744
6745				_fnApplyToChildren( function(nSizer, i) {
6746
6747					nSizer.innerHTML = "";
6748
6749					nSizer.style.width = aAppliedFooter[i];
6750
6751				}, anFootSizers );
6752
6753			}
6754
6755			
6756
6757			/* Sanity check that the table is of a sensible width. If not then we are going to get
6758
6759			 * misalignment - try to prevent this by not allowing the table to shrink below its min width
6760
6761			 */
6762
6763			if ( $(o.nTable).outerWidth() < iSanityWidth )
6764
6765			{
6766
6767				/* The min width depends upon if we have a vertical scrollbar visible or not */
6768
6769				var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || 
6770
6771					$(nScrollBody).css('overflow-y') == "scroll")) ?
6772
6773						iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
6774
6775				
6776
6777				/* IE6/7 are a law unto themselves... */
6778
6779				if ( ie67 && (nScrollBody.scrollHeight > 
6780
6781					nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll")  )
6782
6783				{
6784
6785					o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
6786
6787				}
6788
6789				
6790
6791				/* Apply the calculated minimum width to the table wrappers */
6792
6793				nScrollBody.style.width = _fnStringToCss( iCorrection );
6794
6795				o.nScrollHead.style.width = _fnStringToCss( iCorrection );
6796
6797				
6798
6799				if ( o.nTFoot !== null )
6800
6801				{
6802
6803					o.nScrollFoot.style.width = _fnStringToCss( iCorrection );
6804
6805				}
6806
6807				
6808
6809				/* And give the user a warning that we've stopped the table getting too small */
6810
6811				if ( o.oScroll.sX === "" )
6812
6813				{
6814
6815					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
6816
6817						" misalignment. The table has been drawn at its minimum possible width." );
6818
6819				}
6820
6821				else if ( o.oScroll.sXInner !== "" )
6822
6823				{
6824
6825					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
6826
6827						" misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
6828
6829						" calculation" );
6830
6831				}
6832
6833			}
6834
6835			else
6836
6837			{
6838
6839				nScrollBody.style.width = _fnStringToCss( '100%' );
6840
6841				o.nScrollHead.style.width = _fnStringToCss( '100%' );
6842
6843				
6844
6845				if ( o.nTFoot !== null )
6846
6847				{
6848
6849					o.nScrollFoot.style.width = _fnStringToCss( '100%' );
6850
6851				}
6852
6853			}
6854
6855			
6856
6857			
6858
6859			/*
6860
6861			 * 4. Clean up
6862
6863			 */
6864
6865			if ( o.oScroll.sY === "" )
6866
6867			{
6868
6869				/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
6870
6871				 * the scrollbar height from the visible display, rather than adding it on. We need to
6872
6873				 * set the height in order to sort this. Don't want to do it in any other browsers.
6874
6875				 */
6876
6877				if ( ie67 )
6878
6879				{
6880
6881					nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
6882
6883				}
6884
6885			}
6886
6887			
6888
6889			if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
6890
6891			{
6892
6893				nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
6894
6895				
6896
6897				var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
6898
6899				 	o.oScroll.iBarWidth : 0;
6900
6901				if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
6902
6903				{
6904
6905					nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
6906
6907				}
6908
6909			}
6910
6911			
6912
6913			/* Finally set the width's of the header and footer tables */
6914
6915			var iOuterWidth = $(o.nTable).outerWidth();
6916
6917			nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
6918
6919			nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
6920
6921		
6922
6923			// Figure out if there are scrollbar present - if so then we need a the header and footer to
6924
6925			// provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
6926
6927			var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll";
6928
6929			nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
6930
6931			
6932
6933			if ( o.nTFoot !== null )
6934
6935			{
6936
6937				nScrollFootTable.style.width = _fnStringToCss( iOuterWidth );
6938
6939				nScrollFootInner.style.width = _fnStringToCss( iOuterWidth );
6940
6941				nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
6942
6943			}
6944
6945		
6946
6947			/* Adjust the position of the header in case we loose the y-scrollbar */
6948
6949			$(nScrollBody).scroll();
6950
6951			
6952
6953			/* If sorting or filtering has occurred, jump the scrolling back to the top */
6954
6955			if ( o.bSorted || o.bFiltered )
6956
6957			{
6958
6959				nScrollBody.scrollTop = 0;
6960
6961			}
6962
6963		}
6964
6965		
6966
6967		
6968
6969		/**
6970
6971		 * Apply a given function to the display child nodes of an element array (typically
6972
6973		 * TD children of TR rows
6974
6975		 *  @param {function} fn Method to apply to the objects
6976
6977		 *  @param array {nodes} an1 List of elements to look through for display children
6978
6979		 *  @param array {nodes} an2 Another list (identical structure to the first) - optional
6980
6981		 *  @memberof DataTable#oApi
6982
6983		 */
6984
6985		function _fnApplyToChildren( fn, an1, an2 )
6986
6987		{
6988
6989			var index=0, i=0, iLen=an1.length;
6990
6991			var nNode1, nNode2;
6992
6993		
6994
6995			while ( i < iLen )
6996
6997			{
6998
6999				nNode1 = an1[i].firstChild;
7000
7001				nNode2 = an2 ? an2[i].firstChild : null;
7002
7003				while ( nNode1 )
7004
7005				{
7006
7007					if ( nNode1.nodeType === 1 )
7008
7009					{
7010
7011						if ( an2 )
7012
7013						{
7014
7015							fn( nNode1, nNode2, index );
7016
7017						}
7018
7019						else
7020
7021						{
7022
7023							fn( nNode1, index );
7024
7025						}
7026
7027						index++;
7028
7029					}
7030
7031					nNode1 = nNode1.nextSibling;
7032
7033					nNode2 = an2 ? nNode2.nextSibling : null;
7034
7035				}
7036
7037				i++;
7038
7039			}
7040
7041		}
7042
7043		
7044
7045		/**
7046
7047		 * Convert a CSS unit width to pixels (e.g. 2em)
7048
7049		 *  @param {string} sWidth width to be converted
7050
7051		 *  @param {node} nParent parent to get the with for (required for relative widths) - optional
7052
7053		 *  @returns {int} iWidth width in pixels
7054
7055		 *  @memberof DataTable#oApi
7056
7057		 */
7058
7059		function _fnConvertToWidth ( sWidth, nParent )
7060
7061		{
7062
7063			if ( !sWidth || sWidth === null || sWidth === '' )
7064
7065			{
7066
7067				return 0;
7068
7069			}
7070
7071			
7072
7073			if ( !nParent )
7074
7075			{
7076
7077				nParent = document.body;
7078
7079			}
7080
7081			
7082
7083			var iWidth;
7084
7085			var nTmp = document.createElement( "div" );
7086
7087			nTmp.style.width = _fnStringToCss( sWidth );
7088
7089			
7090
7091			nParent.appendChild( nTmp );
7092
7093			iWidth = nTmp.offsetWidth;
7094
7095			nParent.removeChild( nTmp );
7096
7097			
7098
7099			return ( iWidth );
7100
7101		}
7102
7103		
7104
7105		
7106
7107		/**
7108
7109		 * Calculate the width of columns for the table
7110
7111		 *  @param {object} oSettings dataTables settings object
7112
7113		 *  @memberof DataTable#oApi
7114
7115		 */
7116
7117		function _fnCalculateColumnWidths ( oSettings )
7118
7119		{
7120
7121			var iTableWidth = oSettings.nTable.offsetWidth;
7122
7123			var iUserInputs = 0;
7124
7125			var iTmpWidth;
7126
7127			var iVisibleColumns = 0;
7128
7129			var iColums = oSettings.aoColumns.length;
7130
7131			var i, iIndex, iCorrector, iWidth;
7132
7133			var oHeaders = $('th', oSettings.nTHead);
7134
7135			var widthAttr = oSettings.nTable.getAttribute('width');
7136
7137			var nWrapper = oSettings.nTable.parentNode;
7138
7139			
7140
7141			/* Convert any user input sizes into pixel sizes */
7142
7143			for ( i=0 ; i<iColums ; i++ )
7144
7145			{
7146
7147				if ( oSettings.aoColumns[i].bVisible )
7148
7149				{
7150
7151					iVisibleColumns++;
7152
7153					
7154
7155					if ( oSettings.aoColumns[i].sWidth !== null )
7156
7157					{
7158
7159						iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, 
7160
7161							nWrapper );
7162
7163						if ( iTmpWidth !== null )
7164
7165						{
7166
7167							oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
7168
7169						}
7170
7171							
7172
7173						iUserInputs++;
7174
7175					}
7176
7177				}
7178
7179			}
7180
7181			
7182
7183			/* If the number of columns in the DOM equals the number that we have to process in 
7184
7185			 * DataTables, then we can use the offsets that are created by the web-browser. No custom 
7186
7187			 * sizes can be set in order for this to happen, nor scrolling used
7188
7189			 */
7190
7191			if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
7192
7193				oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
7194
7195			{
7196
7197				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
7198
7199				{
7200
7201					iTmpWidth = $(oHeaders[i]).width();
7202
7203					if ( iTmpWidth !== null )
7204
7205					{
7206
7207						oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
7208
7209					}
7210
7211				}
7212
7213			}
7214
7215			else
7216
7217			{
7218
7219				/* Otherwise we are going to have to do some calculations to get the width of each column.
7220
7221				 * Construct a 1 row table with the widest node in the data, and any user defined widths,
7222
7223				 * then insert it into the DOM and allow the browser to do all the hard 
7223work of
7224
7225				 * calculating table widths.
7226
7227				 */
7228
7229				var
7230
7231					nCalcTmp = oSettings.nTable.cloneNode( false ),
7232
7233					nTheadClone = oSettings.nTHead.cloneNode(true),
7234
7235					nBody = document.createElement( 'tbody' ),
7236
7237					nTr = document.createElement( 'tr' ),
7238
7239					nDivSizing;
7240
7241				
7242
7243				nCalcTmp.removeAttribute( "id" );
7244
7245				nCalcTmp.appendChild( nTheadClone );
7246
7247				if ( oSettings.nTFoot !== null )
7248
7249				{
7250
7251					nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
7252
7253					_fnApplyToChildren( function(n) {
7254
7255						n.style.width = "";
7256
7257					}, nCalcTmp.getElementsByTagName('tr') );
7258
7259				}
7260
7261				
7262
7263				nCalcTmp.appendChild( nBody );
7264
7265				nBody.appendChild( nTr );
7266
7267				
7268
7269				/* Remove any sizing that was previously applied by the styles */
7270
7271				var jqColSizing = $('thead th', nCalcTmp);
7272
7273				if ( jqColSizing.length === 0 )
7274
7275				{
7276
7277					jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
7278
7279				}
7280
7281		
7282
7283				/* Apply custom sizing to the cloned header */
7284
7285				var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
7286
7287				iCorrector = 0;
7288
7289				for ( i=0 ; i<iColums ; i++ )
7290
7291				{
7292
7293					var oColumn = oSettings.aoColumns[i];
7294
7295					if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
7296
7297					{
7298
7299						nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
7300
7301					}
7302
7303					else if ( oColumn.bVisible )
7304
7305					{
7306
7307						nThs[i-iCorrector].style.width = "";
7308
7309					}
7310
7311					else
7312
7313					{
7314
7315						iCorrector++;
7316
7317					}
7318
7319				}
7320
7321		
7322
7323				/* Find the biggest td for each column and put it into the table */
7324
7325				for ( i=0 ; i<iColums ; i++ )
7326
7327				{
7328
7329					if ( oSettings.aoColumns[i].bVisible )
7330
7331					{
7332
7333						var nTd = _fnGetWidestNode( oSettings, i );
7334
7335						if ( nTd !== null )
7336
7337						{
7338
7339							nTd = nTd.cloneNode(true);
7340
7341							if ( oSettings.aoColumns[i].sContentPadding !== "" )
7342
7343							{
7344
7345								nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
7346
7347							}
7348
7349							nTr.appendChild( nTd );
7350
7351						}
7352
7353					}
7354
7355				}
7356
7357				
7358
7359				/* Build the table and 'display' it */
7360
7361				nWrapper.appendChild( nCalcTmp );
7362
7363				
7364
7365				/* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
7366
7367				 * when not scrolling leave the table width as it is. This results in slightly different,
7368
7369				 * but I think correct behaviour
7370
7371				 */
7372
7373				if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
7374
7375				{
7376
7377					nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
7378
7379				}
7380
7381				else if ( oSettings.oScroll.sX !== "" )
7382
7383				{
7384
7385					nCalcTmp.style.width = "";
7386
7387					if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
7388
7389					{
7390
7391						nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
7392
7393					}
7394
7395				}
7396
7397				else if ( oSettings.oScroll.sY !== "" )
7398
7399				{
7400
7401					nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
7402
7403				}
7404
7405				else if ( widthAttr )
7406
7407				{
7408
7409					nCalcTmp.style.width = _fnStringToCss( widthAttr );
7410
7411				}
7412
7413				nCalcTmp.style.visibility = "hidden";
7414
7415				
7416
7417				/* Scrolling considerations */
7418
7419				_fnScrollingWidthAdjust( oSettings, nCalcTmp );
7420
7421				
7422
7423				/* Read the width's calculated by the browser and store them for use by the caller. We
7424
7425				 * first of all try to use the elements in the body, but it is possible that there are
7426
7427				 * no elements there, under which circumstances we use the header elements
7428
7429				 */
7430
7431				var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
7432
7433				if ( oNodes.length === 0 )
7434
7435				{
7436
7437					oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
7438
7439				}
7440
7441		
7442
7443				/* Browsers need a bit of a hand when a width is assigned to any columns when 
7444
7445				 * x-scrolling as they tend to collapse the table to the min-width, even if
7446
7447				 * we sent the column widths. So we need to keep track of what the table width
7448
7449				 * should be by summing the user given values, and the automatic values
7450
7451				 */
7452
7453				if ( oSettings.oScroll.sX !== "" )
7454
7455				{
7456
7457					var iTotal = 0;
7458
7459					iCorrector = 0;
7460
7461					for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
7462
7463					{
7464
7465						if ( oSettings.aoColumns[i].bVisible )
7466
7467						{
7468
7469							if ( oSettings.aoColumns[i].sWidthOrig === null )
7470
7471							{
7472
7473								iTotal += $(oNodes[iCorrector]).outerWidth();
7474
7475							}
7476
7477							else
7478
7479							{
7480
7481								iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
7482
7483									($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
7484
7485							}
7486
7487							iCorrector++;
7488
7489						}
7490
7491					}
7492
7493					
7494
7495					nCalcTmp.style.width = _fnStringToCss( iTotal );
7496
7497					oSettings.nTable.style.width = _fnStringToCss( iTotal );
7498
7499				}
7500
7501		
7502
7503				iCorrector = 0;
7504
7505				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
7506
7507				{
7508
7509					if ( oSettings.aoColumns[i].bVisible )
7510
7511					{
7512
7513						iWidth = $(oNodes[iCorrector]).width();
7514
7515						if ( iWidth !== null && iWidth > 0 )
7516
7517						{
7518
7519							oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
7520
7521						}
7522
7523						iCorrector++;
7524
7525					}
7526
7527				}
7528
7529		
7530
7531				var cssWidth = $(nCalcTmp).css('width');
7532
7533				oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
7534
7535				    cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
7536
7537				nCalcTmp.parentNode.removeChild( nCalcTmp );
7538
7539			}
7540
7541		
7542
7543			if ( widthAttr )
7544
7545			{
7546
7547				oSettings.nTable.style.width = _fnStringToCss( widthAttr );
7548
7549			}
7550
7551		}
7552
7553		
7554
7555		
7556
7557		/**
7558
7559		 * Adjust a table's width to take account of scrolling
7560
7561		 *  @param {object} oSettings dataTables settings object
7562
7563		 *  @param {node} n table node
7564
7565		 *  @memberof DataTable#oApi
7566
7567		 */
7568
7569		function _fnScrollingWidthAdjust ( oSettings, n )
7570
7571		{
7572
7573			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
7574
7575			{
7576
7577				/* When y-scrolling only, we want to remove the width of the scroll bar so the table
7578
7579				 * + scroll bar will fit into the area avaialble.
7580
7581				 */
7582
7583				var iOrigWidth = $(n).width();
7584
7585				n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
7586
7587			}
7588
7589			else if ( oSettings.oScroll.sX !== "" )
7590
7591			{
7592
7593				/* When x-scrolling both ways, fix the table at it's current size, without adjusting */
7594
7595				n.style.width = _fnStringToCss( $(n).outerWidth() );
7596
7597			}
7598
7599		}
7600
7601		
7602
7603		
7604
7605		/**
7606
7607		 * Get the widest node
7608
7609		 *  @param {object} oSettings dataTables settings object
7610
7611		 *  @param {int} iCol column of interest
7612
7613		 *  @returns {node} widest table node
7614
7615		 *  @memberof DataTable#oApi
7616
7617		 */
7618
7619		function _fnGetWidestNode( oSettings, iCol )
7620
7621		{
7622
7623			var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
7624
7625			if ( iMaxIndex < 0 )
7626
7627			{
7628
7629				return null;
7630
7631			}
7632
7633		
7634
7635			if ( oSettings.aoData[iMaxIndex].nTr === null )
7636
7637			{
7638
7639				var n = document.createElement('td');
7640
7641				n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
7642
7643				return n;
7644
7645			}
7646
7647			return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
7648
7649		}
7650
7651		
7652
7653		
7654
7655		/**
7656
7657		 * Get the maximum strlen for each data column
7658
7659		 *  @param {object} oSettings dataTables settings object
7660
7661		 *  @param {int} iCol column of interest
7662
7663		 *  @returns {string} max string length for each column
7664
7665		 *  @memberof DataTable#oApi
7666
7667		 */
7668
7669		function _fnGetMaxLenString( oSettings, iCol )
7670
7671		{
7672
7673			var iMax = -1;
7674
7675			var iMaxIndex = -1;
7676
7677			
7678
7679			for ( var i=0 ; i<oSettings.aoData.length ; i++ )
7680
7681			{
7682
7683				var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
7684
7685				s = s.replace( /<.*?>/g, "" );
7686
7687				if ( s.length > iMax )
7688
7689				{
7690
7691					iMax = s.length;
7692
7693					iMaxIndex = i;
7694
7695				}
7696
7697			}
7698
7699			
7700
7701			return iMaxIndex;
7702
7703		}
7704
7705		
7706
7707		
7708
7709		/**
7710
7711		 * Append a CSS unit (only if required) to a string
7712
7713		 *  @param {array} aArray1 first array
7714
7715		 *  @param {array} aArray2 second array
7716
7717		 *  @returns {int} 0 if match, 1 if length is different, 2 if no match
7718
7719		 *  @memberof DataTable#oApi
7720
7721		 */
7722
7723		function _fnStringToCss( s )
7724
7725		{
7726
7727			if ( s === null )
7728
7729			{
7730
7731				return "0px";
7732
7733			}
7734
7735			
7736
7737			if ( typeof s == 'number' )
7738
7739			{
7740
7741				if ( s < 0 )
7742
7743				{
7744
7745					return "0px";
7746
7747				}
7748
7749				return s+"px";
7750
7751			}
7752
7753			
7754
7755			/* Check if the last character is not 0-9 */
7756
7757			var c = s.charCodeAt( s.length-1 );
7758
7759			if (c < 0x30 || c > 0x39)
7760
7761			{
7762
7763				return s;
7764
7765			}
7766
7767			return s+"px";
7768
7769		}
7770
7771		
7772
7773		
7774
7775		/**
7776
7777		 * Get the width of a scroll bar in this browser being used
7778
7779		 *  @returns {int} width in pixels
7780
7781		 *  @memberof DataTable#oApi
7782
7783		 */
7784
7785		function _fnScrollBarWidth ()
7786
7787		{  
7788
7789			var inner = document.createElement('p');
7790
7791			var style = inner.style;
7792
7793			style.width = "100%";
7794
7795			style.height = "200px";
7796
7797			style.padding = "0px";
7798
7799			
7800
7801			var outer = document.createElement('div');
7802
7803			style = outer.style;
7804
7805			style.position = "absolute";
7806
7807			style.top = "0px";
7808
7809			style.left = "0px";
7810
7811			style.visibility = "hidden";
7812
7813			style.width = "200px";
7814
7815			style.height = "150px";
7816
7817			style.padding = "0px";
7818
7819			style.overflow = "hidden";
7820
7821			outer.appendChild(inner);
7822
7823			
7824
7825			document.body.appendChild(outer);
7826
7827			var w1 = inner.offsetWidth;
7828
7829			outer.style.overflow = 'scroll';
7830
7831			var w2 = inner.offsetWidth;
7832
7833			if ( w1 == w2 )
7834
7835			{
7836
7837				w2 = outer.clientWidth;
7838
7839			}
7840
7841			
7842
7843			document.body.removeChild(outer);
7844
7845			return (w1 - w2);  
7846
7847		}
7848
7849		
7850
7851		/**
7852
7853		 * Change the order of the table
7854
7855		 *  @param {object} oSettings dataTables settings object
7856
7857		 *  @param {bool} bApplyClasses optional - should we apply classes or not
7858
7859		 *  @memberof DataTable#oApi
7860
7861		 */
7862
7863		function _fnSort ( oSettings, bApplyClasses )
7864
7865		{
7866
7867			var
7868
7869				i, iLen, j, jLen, k, kLen,
7870
7871				sDataType, nTh,
7872
7873				aaSort = [],
7874
7875			 	aiOrig = [],
7876
7877				oSort = DataTable.ext.oSort,
7878
7879				aoData = oSettings.aoData,
7880
7881				aoColumns = oSettings.aoColumns,
7882
7883				oAria = oSettings.oLanguage.oAria;
7884
7885			
7886
7887			/* No sorting required if server-side or no sorting array */
7888
7889			if ( !oSettings.oFeatures.bServerSide && 
7890
7891				(oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
7892
7893			{
7894
7895				aaSort = ( oSettings.aaSortingFixed !== null ) ?
7896
7897					oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
7898
7899					oSettings.aaSorting.slice();
7900
7901				
7902
7903				/* If there is a sorting data type, and a function belonging to it, then we need to
7904
7905				 * get the data from the developer's function and apply it for this column
7906
7907				 */
7908
7909				for ( i=0 ; i<aaSort.length ; i++ )
7910
7911				{
7912
7913					var iColumn = aaSort[i][0];
7914
7915					var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
7916
7917					sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
7918
7919					if ( DataTable.ext.afnSortData[sDataType] )
7920
7921					{
7922
7923						var aData = DataTable.ext.afnSortData[sDataType].call( 
7924
7925							oSettings.oInstance, oSettings, iColumn, iVisColumn
7926
7927						);
7928
7929						if ( aData.length === aoData.length )
7930
7931						{
7932
7933							for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
7934
7935							{
7936
7937								_fnSetCellData( oSettings, j, iColumn, aData[j] );
7938
7939							}
7940
7941						}
7942
7943						else
7944
7945						{
7946
7947							_fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" );
7948
7949						}
7950
7951					}
7952
7953				}
7954
7955				
7956
7957				/* Create a value - key array of the current row positions such that we can use their
7958
7959				 * current position during the sort, if values match, in order to perform stable sorting
7960
7961				 */
7962
7963				for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
7964
7965				{
7966
7967					aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
7968
7969				}
7970
7971		
7972
7973				/* Build an internal data array which is specific to the sort, so we can get and prep
7974
7975				 * the data to be sorted only once, rather than needing to do it every time the sorting
7976
7977				 * function runs. This make the sorting function a very simple comparison
7978
7979				 */
7980
7981				var iSortLen = aaSort.length;
7982
7983				var fnSortFormat, aDataSort;
7984
7985				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
7986
7987				{
7988
7989					for ( j=0 ; j<iSortLen ; j++ )
7990
7991					{
7992
7993						aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;
7994
7995		
7996
7997						for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
7998
7999						{
8000
8001							sDataType = aoColumns[ aDataSort[k] ].sType;
8002
8003							fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];
8004
8005							
8006
8007							aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ?
8008
8009								fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) :
8010
8011								_fnGetCellData( oSettings, i, aDataSort[k], 'sort' );
8012
8013						}
8014
8015					}
8016
8017				}
8018
8019				
8020
8021				/* Do the sort - here we want multi-column sorting based on a given data source (column)
8022
8023				 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
8024
8025				 * follow on it's own, but this is what we want (example two column sorting):
8026
8027				 *  fnLocalSorting = function(a,b){
8028
8029				 *  	var iTest;
8030
8031				 *  	iTest = oSort['string-asc']('data11', 'data12');
8032
8033				 *  	if (iTest !== 0)
8034
8035				 *  		return iTest;
8036
8037				 *    iTest = oSort['numeric-desc']('data21', 'data22');
8038
8039				 *    if (iTest !== 0)
8040
8041				 *  		return iTest;
8042
8043				 *  	return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
8044
8045				 *  }
8046
8047				 * Basically we have a test for each sorting column, if the data in that column is equal,
8048
8049				 * test the next column. If all columns match, then we use a numeric sort on the row 
8050
8051				 * positions in the original data array to provide a stable sort.
8052
8053				 */
8054
8055				oSettings.aiDisplayMaster.sort( function ( a, b ) {
8056
8057					var k, l, lLen, iTest, aDataSort, sDataType;
8058
8059					for ( k=0 ; k<iSortLen ; k++ )
8060
8061					{
8062
8063						aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;
8064
8065		
8066
8067						for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )
8068
8069						{
8070
8071							sDataType = aoColumns[ aDataSort[l] ].sType;
8072
8073							
8074
8075							iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ](
8076
8077								aoData[a]._aSortData[ aDataSort[l] ],
8078
8079								aoData[b]._aSortData[ aDataSort[l] ]
8080
8081							);
8082
8083						
8084
8085							if ( iTest !== 0 )
8086
8087							{
8088
8089								return iTest;
8090
8091							}
8092
8093						}
8094
8095					}
8096
8097					
8098
8099					return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
8100
8101				} );
8102
8103			}
8104
8105			
8106
8107			/* Alter the sorting classes to take account of the changes */
8108
8109			if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
8110
8111			{
8112
8113				_fnSortingClasses( oSettings );
8114
8115			}
8116
8117		
8118
8119			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
8120
8121			{
8122
8123				var sTitle = aoColumns[i].sTitle.replace( /<.*?>/g, "" );
8124
8125				nTh = aoColumns[i].nTh;
8126
8127				nTh.removeAttribute('aria-sort');
8128
8129				nTh.removeAttribute('aria-label');
8130
8131				
8132
8133				/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
8134
8135				if ( aoColumns[i].bSortable )
8136
8137				{
8138
8139					if ( aaSort.length > 0 && aaSort[0][0] == i )
8140
8141					{
8142
8143						nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );
8144
8145						
8146
8147						var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ? 
8148
8149							aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
8150
8151						nTh.setAttribute('aria-label', sTitle+
8152
8153							(nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
8154
8155					}
8156
8157					else
8158
8159					{
8160
8161						nTh.setAttribute('aria-label', sTitle+
8162
8163							(aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
8164
8165					}
8166
8167				}
8168
8169				else
8170
8171				{
8172
8173					nTh.setAttribute('aria-label', sTitle);
8174
8175				}
8176
8177			}
8178
8179			
8180
8181			/* Tell the draw function that we have sorted the data */
8182
8183			oSettings.bSorted = true;
8184
8185			$(oSettings.oInstance).trigger('sort', oSettings);
8186
8187			
8188
8189			/* Copy the master data into the draw array and re-draw */
8190
8191			if ( oSettings.oFeatures.bFilter )
8192
8193			{
8194
8195				/* _fnFilter() will redraw the table for us */
8196
8197				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
8198
8199			}
8200
8201			else
8202
8203			{
8204
8205				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
8206
8207				oSettings._iDisplayStart = 0; /* reset display back to page 0 */
8208
8209				_fnCalculateEnd( oSettings );
8210
8211				_fnDraw( oSettings );
8212
8213			}
8214
8215		}
8216
8217		
8218
8219		
8220
8221		/**
8222
8223		 * Attach a sort handler (click) to a node
8224
8225		 *  @param {object} oSettings dataTables settings object
8226
8227		 *  @param {node} nNode node to attach the handler to
8228
8229		 *  @param {int} iDataIndex column sorting index
8230
8231		 *  @param {function}
8231 [fnCallback] callback function
8232
8233		 *  @memberof DataTable#oApi
8234
8235		 */
8236
8237		function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
8238
8239		{
8240
8241			_fnBindAction( nNode, {}, function (e) {
8242
8243				/* If the column is not sortable - don't to anything */
8244
8245				if ( oSettings.aoColumns[iDataIndex].bSortable === false )
8246
8247				{
8248
8249					return;
8250
8251				}
8252
8253				
8254
8255				/*
8256
8257				 * This is a little bit odd I admit... I declare a temporary function inside the scope of
8258
8259				 * _fnBuildHead and the click handler in order that the code presented here can be used 
8260
8261				 * twice - once for when bProcessing is enabled, and another time for when it is 
8262
8263				 * disabled, as we need to perform slightly different actions.
8264
8265				 *   Basically the issue here is that the Javascript engine in modern browsers don't 
8266
8267				 * appear to allow the rendering engine to update the display while it is still executing
8268
8269				 * it's thread (well - it does but only after long intervals). This means that the 
8270
8271				 * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
8272
8273				 * I force an execution break by using setTimeout - but this breaks the expected 
8274
8275				 * thread continuation for the end-developer's point of view (their code would execute
8276
8277				 * too early), so we only do it when we absolutely have to.
8278
8279				 */
8280
8281				var fnInnerSorting = function () {
8282
8283					var iColumn, iNextSort;
8284
8285					
8286
8287					/* If the shift key is pressed then we are multiple column sorting */
8288
8289					if ( e.shiftKey )
8290
8291					{
8292
8293						/* Are we already doing some kind of sort on this column? */
8294
8295						var bFound = false;
8296
8297						for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
8298
8299						{
8300
8301							if ( oSettings.aaSorting[i][0] == iDataIndex )
8302
8303							{
8304
8305								bFound = true;
8306
8307								iColumn = oSettings.aaSorting[i][0];
8308
8309								iNextSort = oSettings.aaSorting[i][2]+1;
8310
8311								
8312
8313								if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
8314
8315								{
8316
8317									/* Reached the end of the sorting options, remove from multi-col sort */
8318
8319									oSettings.aaSorting.splice( i, 1 );
8320
8321								}
8322
8323								else
8324
8325								{
8326
8327									/* Move onto next sorting direction */
8328
8329									oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
8330
8331									oSettings.aaSorting[i][2] = iNextSort;
8332
8333								}
8334
8335								break;
8336
8337							}
8338
8339						}
8340
8341						
8342
8343						/* No sort yet - add it in */
8344
8345						if ( bFound === false )
8346
8347						{
8348
8349							oSettings.aaSorting.push( [ iDataIndex, 
8350
8351								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
8352
8353						}
8354
8355					}
8356
8357					else
8358
8359					{
8360
8361						/* If no shift key then single column sort */
8362
8363						if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
8364
8365						{
8366
8367							iColumn = oSettings.aaSorting[0][0];
8368
8369							iNextSort = oSettings.aaSorting[0][2]+1;
8370
8371							if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
8372
8373							{
8374
8375								iNextSort = 0;
8376
8377							}
8378
8379							oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
8380
8381							oSettings.aaSorting[0][2] = iNextSort;
8382
8383						}
8384
8385						else
8386
8387						{
8388
8389							oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
8390
8391							oSettings.aaSorting.push( [ iDataIndex, 
8392
8393								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
8394
8395						}
8396
8397					}
8398
8399					
8400
8401					/* Run the sort */
8402
8403					_fnSort( oSettings );
8404
8405				}; /* /fnInnerSorting */
8406
8407				
8408
8409				if ( !oSettings.oFeatures.bProcessing )
8410
8411				{
8412
8413					fnInnerSorting();
8414
8415				}
8416
8417				else
8418
8419				{
8420
8421					_fnProcessingDisplay( oSettings, true );
8422
8423					setTimeout( function() {
8424
8425						fnInnerSorting();
8426
8427						if ( !oSettings.oFeatures.bServerSide )
8428
8429						{
8430
8431							_fnProcessingDisplay( oSettings, false );
8432
8433						}
8434
8435					}, 0 );
8436
8437				}
8438
8439				
8440
8441				/* Call the user specified callback function - used for async user interaction */
8442
8443				if ( typeof fnCallback == 'function' )
8444
8445				{
8446
8447					fnCallback( oSettings );
8448
8449				}
8450
8451			} );
8452
8453		}
8454
8455		
8456
8457		
8458
8459		/**
8460
8461		 * Set the sorting classes on the header, Note: it is safe to call this function 
8462
8463		 * when bSort and bSortClasses are false
8464
8465		 *  @param {object} oSettings dataTables settings object
8466
8467		 *  @memberof DataTable#oApi
8468
8469		 */
8470
8471		function _fnSortingClasses( oSettings )
8472
8473		{
8474
8475			var i, iLen, j, jLen, iFound;
8476
8477			var aaSort, sClass;
8478
8479			var iColumns = oSettings.aoColumns.length;
8480
8481			var oClasses = oSettings.oClasses;
8482
8483			
8484
8485			for ( i=0 ; i<iColumns ; i++ )
8486
8487			{
8488
8489				if ( oSettings.aoColumns[i].bSortable )
8490
8491				{
8492
8493					$(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
8494
8495						" "+ oSettings.aoColumns[i].sSortingClass );
8496
8497				}
8498
8499			}
8500
8501			
8502
8503			if ( oSettings.aaSortingFixed !== null )
8504
8505			{
8506
8507				aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
8508
8509			}
8510
8511			else
8512
8513			{
8514
8515				aaSort = oSettings.aaSorting.slice();
8516
8517			}
8518
8519			
8520
8521			/* Apply the required classes to the header */
8522
8523			for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
8524
8525			{
8526
8527				if ( oSettings.aoColumns[i].bSortable )
8528
8529				{
8530
8531					sClass = oSettings.aoColumns[i].sSortingClass;
8532
8533					iFound = -1;
8534
8535					for ( j=0 ; j<aaSort.length ; j++ )
8536
8537					{
8538
8539						if ( aaSort[j][0] == i )
8540
8541						{
8542
8543							sClass = ( aaSort[j][1] == "asc" ) ?
8544
8545								oClasses.sSortAsc : oClasses.sSortDesc;
8546
8547							iFound = j;
8548
8549							break;
8550
8551						}
8552
8553					}
8554
8555					$(oSettings.aoColumns[i].nTh).addClass( sClass );
8556
8557					
8558
8559					if ( oSettings.bJUI )
8560
8561					{
8562
8563						/* jQuery UI uses extra markup */
8564
8565						var jqSpan = $("span."+oClasses.sSortIcon,  oSettings.aoColumns[i].nTh);
8566
8567						jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+ 
8568
8569							oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
8570
8571						
8572
8573						var sSpanClass;
8574
8575						if ( iFound == -1 )
8576
8577						{
8578
8579						 	sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
8580
8581						}
8582
8583						else if ( aaSort[iFound][1] == "asc" )
8584
8585						{
8586
8587							sSpanClass = oClasses.sSortJUIAsc;
8588
8589						}
8590
8591						else
8592
8593						{
8594
8595							sSpanClass = oClasses.sSortJUIDesc;
8596
8597						}
8598
8599						
8600
8601						jqSpan.addClass( sSpanClass );
8602
8603					}
8604
8605				}
8606
8607				else
8608
8609				{
8610
8611					/* No sorting on this column, so add the base class. This will have been assigned by
8612
8613					 * _fnAddColumn
8614
8615					 */
8616
8617					$(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
8618
8619				}
8620
8621			}
8622
8623			
8624
8625			/* 
8626
8627			 * Apply the required classes to the table body
8628
8629			 * Note that this is given as a feature switch since it can significantly slow down a sort
8630
8631			 * on large data sets (adding and removing of classes is always slow at the best of times..)
8632
8633			 * Further to this, note that this code is admittedly fairly ugly. It could be made a lot 
8634
8635			 * simpler using jQuery selectors and add/removeClass, but that is significantly slower
8636
8637			 * (on the order of 5 times slower) - hence the direct DOM manipulation here.
8638
8639			 * Note that for deferred drawing we do use jQuery - the reason being that taking the first
8640
8641			 * row found to see if the whole column needs processed can miss classes since the first
8642
8643			 * column might be new.
8644
8645			 */
8646
8647			sClass = oClasses.sSortColumn;
8648
8649			
8650
8651			if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
8652
8653			{
8654
8655				var nTds = _fnGetTdNodes( oSettings );
8656
8657				
8658
8659				/* Determine what the sorting class for each column should be */
8660
8661				var iClass, iTargetCol;
8662
8663				var asClasses = [];
8664
8665				for (i = 0; i < iColumns; i++)
8666
8667				{
8668
8669					asClasses.push("");
8670
8671				}
8672
8673				for (i = 0, iClass = 1; i < aaSort.length; i++)
8674
8675				{
8676
8677					iTargetCol = parseInt( aaSort[i][0], 10 );
8678
8679					asClasses[iTargetCol] = sClass + iClass;
8680
8681					
8682
8683					if ( iClass < 3 )
8684
8685					{
8686
8687						iClass++;
8688
8689					}
8690
8691				}
8692
8693				
8694
8695				/* Make changes to the classes for each cell as needed */
8696
8697				var reClass = new RegExp(sClass + "[123]");
8698
8699				var sTmpClass, sCurrentClass, sNewClass;
8700
8701				for ( i=0, iLen=nTds.length; i<iLen; i++ )
8702
8703				{
8704
8705					/* Determine which column we're looking at */
8706
8707					iTargetCol = i % iColumns;
8708
8709					
8710
8711					/* What is the full list of classes now */
8712
8713					sCurrentClass = nTds[i].className;
8714
8715					/* What sorting class should be applied? */
8716
8717					sNewClass = asClasses[iTargetCol];
8718
8719					/* What would the new full list be if we did a replacement? */
8720
8721					sTmpClass = sCurrentClass.replace(reClass, sNewClass);
8722
8723					
8724
8725					if ( sTmpClass != sCurrentClass )
8726
8727					{
8728
8729						/* We changed something */
8730
8731						nTds[i].className = $.trim( sTmpClass );
8732
8733					}
8734
8735					else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 )
8736
8737					{
8738
8739						/* We need to add a class */
8740
8741						nTds[i].className = sCurrentClass + " " + sNewClass;
8742
8743					}
8744
8745				}
8746
8747			}
8748
8749		}
8750
8751		
8752
8753		
8754
8755		
8756
8757		/**
8758
8759		 * Save the state of a table in a cookie such that the page can be reloaded
8760
8761		 *  @param {object} oSettings dataTables settings object
8762
8763		 *  @memberof DataTable#oApi
8764
8765		 */
8766
8767		function _fnSaveState ( oSettings )
8768
8769		{
8770
8771			if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
8772
8773			{
8774
8775				return;
8776
8777			}
8778
8779		
8780
8781			/* Store the interesting variables */
8782
8783			var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
8784
8785			var oState = {
8786
8787				"iCreate":      new Date().getTime(),
8788
8789				"iStart":       (bInfinite ? 0 : oSettings._iDisplayStart),
8790
8791				"iEnd":         (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
8792
8793				"iLength":      oSettings._iDisplayLength,
8794
8795				"aaSorting":    $.extend( true, [], oSettings.aaSorting ),
8796
8797				"oSearch":      $.extend( true, {}, oSettings.oPreviousSearch ),
8798
8799				"aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
8800
8801				"abVisCols":    []
8802
8803			};
8804
8805		
8806
8807			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
8808
8809			{
8810
8811				oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
8812
8813			}
8814
8815		
8816
8817			_fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
8818
8819			
8820
8821			oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
8822
8823		}
8824
8825		
8826
8827		
8828
8829		/**
8830
8831		 * Attempt to load a saved table state from a cookie
8832
8833		 *  @param {object} oSettings dataTables settings object
8834
8835		 *  @param {object} oInit DataTables init object so we can override settings
8836
8837		 *  @memberof DataTable#oApi
8838
8839		 */
8840
8841		function _fnLoadState ( oSettings, oInit )
8842
8843		{
8844
8845			if ( !oSettings.oFeatures.bStateSave )
8846
8847			{
8848
8849				return;
8850
8851			}
8852
8853		
8854
8855			var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
8856
8857			if ( !oData )
8858
8859			{
8860
8861				return;
8862
8863			}
8864
8865			
8866
8867			/* Allow custom and plug-in manipulation functions to alter the saved data set and
8868
8869			 * cancelling of loading by returning false
8870
8871			 */
8872
8873			var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
8874
8875			if ( $.inArray( false, abStateLoad ) !== -1 )
8876
8877			{
8878
8879				return;
8880
8881			}
8882
8883			
8884
8885			/* Store the saved state so it might be accessed at any time */
8886
8887			oSettings.oLoadedState = $.extend( true, {}, oData );
8888
8889			
8890
8891			/* Restore key features */
8892
8893			oSettings._iDisplayStart    = oData.iStart;
8894
8895			oSettings.iInitDisplayStart = oData.iStart;
8896
8897			oSettings._iDisplayEnd      = oData.iEnd;
8898
8899			oSettings._iDisplayLength   = oData.iLength;
8900
8901			oSettings.aaSorting         = oData.aaSorting.slice();
8902
8903			oSettings.saved_aaSorting   = oData.aaSorting.slice();
8904
8905			
8906
8907			/* Search filtering  */
8908
8909			$.extend( oSettings.oPreviousSearch, oData.oSearch );
8910
8911			$.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
8912
8913			
8914
8915			/* Column visibility state
8916
8917			 * Pass back visibility settings to the init handler, but to do not here override
8918
8919			 * the init object that the user might have passed in
8920
8921			 */
8922
8923			oInit.saved_aoColumns = [];
8924
8925			for ( var i=0 ; i<oData.abVisCols.length ; i++ )
8926
8927			{
8928
8929				oInit.saved_aoColumns[i] = {};
8930
8931				oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
8932
8933			}
8934
8935		
8936
8937			_fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
8938
8939		}
8940
8941		
8942
8943		
8944
8945		/**
8946
8947		 * Create a new cookie with a value to store the state of a table
8948
8949		 *  @param {string} sName name of the cookie to create
8950
8951		 *  @param {string} sValue the value the cookie should take
8952
8953		 *  @param {int} iSecs duration of the cookie
8954
8955		 *  @param {string} sBaseName sName is made up of the base + file name - this is the base
8956
8957		 *  @param {function} fnCallback User definable function to modify the cookie
8958
8959		 *  @memberof DataTable#oApi
8960
8961		 */
8962
8963		function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
8964
8965		{
8966
8967			var date = new Date();
8968
8969			date.setTime( date.getTime()+(iSecs*1000) );
8970
8971			
8972
8973			/* 
8974
8975			 * Shocking but true - it would appear IE has major issues with having the path not having
8976
8977			 * a trailing slash on it. We need the cookie to be available based on the path, so we
8978
8979			 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
8980
8981			 * patch to use at least some of the path
8982
8983			 */
8984
8985			var aParts = window.location.pathname.split('/');
8986
8987			var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
8988
8989			var sFullCookie, oData;
8990
8991			
8992
8993			if ( fnCallback !== null )
8994
8995			{
8996
8997				oData = (typeof $.parseJSON === 'function') ? 
8998
8999					$.parseJSON( sValue ) : eval( '('+sValue+')' );
9000
9001				sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
9002
9003					aParts.join('/')+"/" );
9004
9005			}
9006
9007			else
9008
9009			{
9010
9011				sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
9012
9013					"; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
9014
9015			}
9016
9017			
9018
9019			/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
9020
9021			 * belonging to DataTables.
9022
9023			 */
9024
9025			var
9026
9027				aCookies =document.cookie.split(';'),
9028
9029				iNewCookieLen = sFullCookie.split(';')[0].length,
9030
9031				aOldCookies = [];
9032
9033			
9034
9035			if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
9036
9037			{
9038
9039				for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
9040
9041				{
9042
9043					if ( aCookies[i].indexOf( sBaseName ) != -1 )
9044
9045					{
9046
9047						/* It's a DataTables cookie, so eval it and check the time stamp */
9048
9049						var aSplitCookie = aCookies[i].split('=');
9050
9051						try {
9052
9053							oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );
9054
9055		
9056
9057							if ( oData && oData.iCreate )
9058
9059							{
9060
9061								aOldCookies.push( {
9062
9063									"name": aSplitCookie[0],
9064
9065									"time": oData.iCreate
9066
9067								} );
9068
9069							}
9070
9071						}
9072
9073						catch( e ) {}
9074
9075					}
9076
9077				}
9078
9079		
9080
9081				// Make sure we delete the oldest ones first
9082
9083				aOldCookies.sort( function (a, b) {
9084
9085					return b.time - a.time;
9086
9087				} );
9088
9089		
9090
9091				// Eliminate as many old DataTables cookies as we need to
9092
9093				while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
9094
9095					if ( aOldCookies.length === 0 ) {
9096
9097						// Deleted all DT cookies and still not enough space. Can't state save
9098
9099						return;
9100
9101					}
9102
9103					
9104
9105					var old = aOldCookies.pop();
9106
9107					document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
9108
9109						aParts.join('/') + "/";
9110
9111				}
9112
9113			}
9114
9115			
9116
9117			document.cookie = sFullCookie;
9118
9119		}
9120
9121		
9122
9123		
9124
9125		/**
9126
9127		 * Read an old cookie to get a cookie with an old table state
9128
9129		 *  @param {string} sName name of the cookie to read
9130
9131		 *  @returns {string} contents of the cookie - or null if no cookie with that name found
9132
9133		 *  @memberof DataTable#oApi
9134
9135		 */
9136
9137		function _fnReadCookie ( sName )
9138
9139		{
9140
9141			var
9142
9143				aParts = window.location.pathname.split('/'),
9144
9145				sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
9146
9147			 	sCookieContents = document.cookie.split(';');
9148
9149			
9150
9151			for( var i=0 ; i<sCookieContents.length ; i++ )
9152
9153			{
9154
9155				var c = sCookieContents[i];
9156
9157				
9158
9159				while (c.charAt(0)==' ')
9160
9161				{
9162
9163					c = c.substring(1,c.length);
9164
9165				}
9166
9167				
9168
9169				if (c.indexOf(sNameEQ) === 0)
9170
9171				{
9172
9173					return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
9174
9175				}
9176
9177			}
9178
9179			return null;
9180
9181		}
9182
9183		
9184
9185		
9186
9187		/**
9188
9189		 * Return the settings object for a particular table
9190
9191		 *  @param {node} nTable table we are using as a dataTable
9192
9193		 *  @returns {object} Settings object - or null if not found
9194
9195		 *  @memberof DataTable#oApi
9196
9197		 */
9198
9199		function _fnSettingsFromNode ( nTable )
9200
9201		{
9202
9203			for ( var i=0 ; i<DataTable.settings.length ; i++ )
9204
9205			{
9206
9207				if ( DataTable.settings[i].nTable === nTable )
9208
9209				{
9210
9211					return DataTable.settings[i];
9212
9213				}
9214
9215			}
9216
9217			
9218
9219			return null;
9220
9221		}
9222
9223		
9224
9225		
9226
9227		/**
9228
9229		 * Return an array with the TR nodes for the table
9230
9231		 *  @param {object} oSettings dataTables settings object
9232
9233		 *  @returns {array} TR array
9234
9235		 *  @memberof DataTable#oApi
9236
9237		 */
9238
9239		function _fnGetTrNodes ( oSettings )
9240
9241		{
9242
9243			var aNodes = [];
9244
9245			var aoData = oSettings.aoData;
9246
9247			for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
9248
9249			{
9250
9251				if ( aoData[i].nTr !== null )
9252
9253				{
9254
9255					aNodes.push( aoData[i].nTr );
9256
9257				}
9258
9259			}
9260
9261			return aNodes;
9262
9263		}
9264
9265		
9266
9267		
9268
9269		/**
9270
9271		 * Return an flat array with all TD nodes for the table, or row
9272
9273		 *  @param {object} oSettings dataTables settings object
9274
9275		 *  @param {int} [iIndividualRow] aoData index to get the nodes for - optional 
9276
9277		 *    if not given then the return array will contain all nodes for the table
9278
9279		 *  @returns {array} TD array
9280
9281		 *  @memberof DataTable#oApi
9282
9283		 */
9284
9285		function _fnGetTdNodes ( oSettings, iIndividualRow )
9286
9287		{
9288
9289			var anReturn = [];
9290
9291			var iCorrector;
9292
9293			var anTds, nTd;
9294
9295			var iRow, iRows=oSettings.aoData.length,
9296
9297				iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
9298
9299			
9300
9301			/* Allow the collection to be limited to just one row */
9302
9303			if ( iIndividualRow !== undefined )
9304
9305			{
9306
9307				iStart = iIndividualRow;
9308
9309				iEnd = iIndividualRow+1;
9310
9311			}
9312
9313		
9314
9315			for ( iRow=iStart ; iRow<iEnd ; iRow++ )
9316
9317			{
9318
9319				oData = oSettings.aoData[iRow];
9320
9321				if ( oData.nTr !== null )
9322
9323				{
9324
9325					/* get the TD child nodes - taking into account text etc nodes */
9326
9327					anTds = [];
9328
9329					nTd = oData.nTr.firstChild;
9330
9331					while ( nTd )
9332
9333					{
9334
9335						sNodeName = nTd.nodeName.toLowerCase();
9336
9337						if ( sNodeName == 'td' || sNodeName == 'th' )
9338
9339						{
9340
9341							anTds.push( nTd );
9342
9343						}
9344
9345						nTd = nTd.nextSibling;
9346
9347					}
9348
9349		
9350
9351					iCorrector = 0;
9352
9353					for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
9354
9355					{
9356
9357						if ( oSettings.aoColumns[iColumn].bVisible )
9358
9359						{
9360
9361							anReturn.push( anTds[iColumn-iCorrector] );
9362
9363						}
9364
9365						else
9366
9367						{
9368
9369							anReturn.push( oData._anHidden[iColumn] );
9370
9371							iCorrector++;
9372
9373						}
9374
9375					}
9376
9377				}
9378
9379			}
9380
9381		
9382
9383			return anReturn;
9384
9385		}
9386
9387		
9388
9389		
9390
9391		/**
9392
9393		 * Log an error message
9394
9395		 *  @param {object} oSettings dataTables settings object
9396
9397		 *  @param {int} iLevel log error messages, or display them to the user
9398
9399		 *  @param {string} sMesg error message
9400
9401		 *  @memberof DataTable#oApi
9402
9403		 */
9404
9405		function _fnLog( oSettings, iLevel, sMesg )
9406
9407		{
9408
9409			var sAlert = (oSettings===null) ?
9410
9411				"DataTables warning: "+sMesg :
9412
9413				"DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
9414
9415			
9416
9417			if ( iLevel === 0 )
9418
9419			{
9420
9421				if ( DataTable.ext.sErrMode == 'alert' )
9422
9423				{
9424
9425					alert( sAlert );
9426
9427				}
9428
9429				else
9430
9431				{
9432
9433					throw new Error(sAlert);
9434
9435				}
9436
9437				return;
9438
9439			}
9440
9441			else if ( window.console && console.log )
9442
9443			{
9444
9445				console.log( sAlert );
9446
9447			}
9448
9449		}
9450
9451		
9452
9453		
9454
9455		/**
9456
9457		 * See if a property is defined on one object, if so assign it to the other object
9458
9459		 *  @param {object} oRet target object
9460
9461		 *  @param {object} oSrc source object
9462
9463		 *  @param {string} sName property
9464
9465		 *  @param {string} [sMappedName] name to map too - optional, sName used if not given
9466
9467		 *  @memberof DataTable#oApi
9468
9469		 */
9470
9471		function _fnMap( oRet, oSrc, sName, sMappedName )
9472
9473		{
9474
9475			if ( sMappedName === undefined )
9476
9477			{
9478
9479				sMappedName = sName;
9480
9481			}
9482
9483			if ( oSrc[sName] !== undefined )
9484
9485			{
9486
9487				oRet[sMappedName] = oSrc[sName];
9488
9489			}
9490
9491		}
9492
9493		
9494
9495		
9496
9497		/**
9498
9499		 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
9500
9501		 * copy arrays. The reason we need to do this, is that we don't want to deep copy array
9502
9503		 * init values (such as aaSorting) since the dev wouldn't be able to override them, but
9504
9505		 * we do want to deep copy arrays.
9506
9507		 *  @param {object} oOut Object to extend
9508
9509		 *  @param {object} oExtender Object from which the properties will be applied to oOut
9510
9511		 *  @returns {object} oOut Reference, just for convenience - oOut === the return.
9512
9513		 *  @memberof DataTable#oApi
9514
9515		 *  @todo This doesn't take account of arrays inside the deep copied objects.
9516
9517		 */
9518
9519		function _fnExtend( oOut, oExtender )
9520
9521		{
9522
9523			var val;
9524
9525			
9526
9527			for ( var prop in oExtender )
9528
9529			{
9530
9531				if ( oExtender.hasOwnProperty(prop) )
9532
9533				{
9534
9535					val = oExtender[prop];
9536
9537		
9538
9539					if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
9540
9541					{
9542
9543						$.extend( true, oOut[prop], val );
9544
9545					}
9546
9547					else
9548
9549					{
9550
9551						oOut[prop] = val;
9552
9553					}
9554
9555				}
9556
9557			}
9558
9559		
9560
9561			return oOut;
9562
9563		}
9564
9565		
9566
9567		
9568
9569		/**
9570
9571		 * Bind an event handers to allow a click or return key to activate the callback.
9572
9573		 * This is good for accessibility since a return on the keyboard will have the
9574
9575		 * same effect as a click, if the element has focus.
9576
9577		 *  @param {element} n Element to bind the action to
9578
9579		 *  @param {object} oData Data object to pass to the triggered function
9580
9581		 *  @param {function} fn Callback function for when the event is triggered
9582
9583		 *  @memberof DataTable#oApi
9584
9585		 */
9586
9587		function _fnBindAction( n, oData, fn )
9588
9589		{
9590
9591			$(n)
9592
9593				.bind( 'click.DT', oData, function (e) {
9594
9595						n.blur(); // Remove focus outline for mouse users
9596
9597						fn(e);
9598
9599					} )
9600
9601				.bind( 'keypress.DT', oData, function (e){
9602
9603					if ( e.which === 13 ) {
9604
9605						fn(e);
9606
9607					} } )
9608
9609				.bind( 'selectstart.DT', function () {
9610
9611					/* Take the brutal approach to cancelling text selection */
9612
9613					return false;
9614
9615					} );
9616
9617		}
9618
9619		
9620
9621		
9622
9623		/**
9624
9625		 * Register a callback function. Easily allows a callback function to be added to
9626
9627		 * an array store of callback functions that can then all be called together.
9628
9629		 *  @param {object} oSettings dataTables settings object
9630
9631		 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
9632
9633		 *  @param {function} fn Function to be called back
9634
9635		 *  @param {string} sName Identifying name for the callback (i.e. a label)
9636
9637		 *  @memberof DataTable#oApi
9638
9639		 */
9640
9641		function _fnCallbackReg( oSettings, sStore, fn, sName )
9642
9643		{
9644
9645			if ( fn )
9646
9647			{
9648
9649				oSettings[sStore].push( {
9650
9651					"fn": fn,
9652
9653					"sName": sName
9654
9655				} );
9656
9657			}
9658
9659		}
9660
9661		
9662
9663		
9664
9665		/**
9666
9667		 * Fire callback functions and trigger Businesses. Note that the loop over the callback
9668
9669		 * array store is done backwards! Further note that you do not want to fire off triggers
9670
9671		 * in time sensitive applications (for example cell creation) as its slow.
9672
9673		 *  @param {object} oSettings dataTables settings object
9674
9675		 *  @param {string} sStore Name of the array storage for the callbacks in oSettings
9676
9677		 *  @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
9678
9679		 *    is fired
9680
9681		 *  @param {array} aArgs Array of arguments to pass to the callback function / trigger
9682
9683		 *  @memberof DataTable#oApi
9684
9685		 */
9686
9687		function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
9688
9689		{
9690
9691			var aoStore = oSettings[sStore];
9692
9693			var aRet =[];
9694
9695		
9696
9697			for ( var i=aoStore.length-1 ; i>=0 ; i-- )
9698
9699			{
9700
9701				aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
9702
9703			}
9704
9705		
9706
9707			if ( sTrigger !== null )
9708
9709			{
9710
9711				$(oSettings.oInstance).trigger(sTrigger, aArgs);
9712
9713			}
9714
9715		
9716
9717			return aRet;
9718
9719		}
9720
9721		
9722
9723		
9724
9725		/**
9726
9727		 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
9728
9729		 * library, then we use that as it is fast, safe and accurate. If the function isn't 
9730
9731		 * available then we need to built it ourselves - the inspiration for this function comes
9732
9733		 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
9734
9735		 * not perfect and absolutely should not be used as a replacement to json2.js - but it does
9736
9737		 * do what we need, without requiring a dependency for DataTables.
9738
9739		 *  @param {object} o JSON object to be converted
9740
9741		 *  @returns {string} JSON string
9742
9743		 *  @memberof DataTable#oApi
9744
9745		 */
9746
9747		var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
9748
9749		{
9750
9751			/* Not an object or array */
9752
9753			var sType = typeof o;
9754
9755			if (sType !== "object" || o === null)
9756
9757			{
9758
9759				// simple data type
9760
9761				if (sType === "string")
9762
9763				{
9764
9765					o = '"'+o+'"';
9766
9767				}
9768
9769				return o+"";
9770
9771			}
9772
9773		
9774
9775			/* If object or array, need to recurse over it */
9776
9777			var
9778
9779				sProp, mValue,
9780
9781				json = [],
9782
9783				bArr = $.isArray(o);
9784
9785			
9786
9787			for (sProp in o)
9788
9789			{
9790
9791				mValue = o[sProp];
9792
9793				sType = typeof mValue;
9794
9795		
9796
9797				if (sType === "string")
9798
9799				{
9800
9801					mValue = '"'+mValue+'"';
9802
9803				}
9804
9805				else if (sType === "object" && mValue !== null)
9806
9807				{
9808
9809					mValue = _fnJsonString(mValue);
9810
9811				}
9812
9813		
9814
9815				json.push((bArr ? "" : '"'+sProp+'":') + mValue);
9816
9817			}
9818
9819		
9820
9821			return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
9822
9823		};
9824
9825		
9826
9827		
9828
9829		/**
9830
9831		 * From some browsers (specifically IE6/7) we need special handling to work around browser
9832
9833		 * bugs - this function is used to detect when these workarounds are needed.
9834
9835		 *  @param {object} oSettings dataTables settings object
9836
9837		 *  @memberof DataTable#oApi
9838
9839		 */
9840
9841		function _fnBrowserDetect( oSettings )
9842
9843		{
9844
9845			/* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
9846
9847			 * width of the scrollbar, while other browsers ensure the inner element is contained
9848
9849			 * without forcing scrolling
9850
9851			 */
9852
9853			var n = $(
9854
9855				'<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
9856
9857					'<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
9858
9859						'<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
9860
9861					'</div>'+
9862
9863				'</div>')[0];
9864
9865		
9866
9867			document.body.appendChild( n );
9868
9869			oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
9870
9871			document.body.removeChild( n );
9872
9873		}
9874
9875		
9876
9877
9878
9879		/**
9880
9881		 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
9882
9883		 * return the resulting jQuery object.
9884
9885		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
9886
9887		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
9888
9889		 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
9890
9891		 *    criterion ("applied") or all TR elements (i.e. no filter).
9892
9893		 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
9894
9895		 *    Can be either 'current', whereby the current sorting of the table is used, or
9896
9897		 *    'original' whereby the original order the data was read into the table is used.
9898
9899		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
9900
9901		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
9902
9903		 *    'current' and filter is 'applied', regardless of what they might be given as.
9904
9905		 *  @returns {object} jQuery object, filtered by the given selector.
9906
9907		 *  @dtopt API
9908
9909		 *
9910
9911		 *  @example
9912
9913		 *    $(document).ready(function() {
9914
9915		 *      var oTable = $('#example').dataTable();
9916
9917		 *
9918
9919		 *      // Highlight every second row
9920
9921		 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
9922
9923		 *    } );
9924
9925		 *
9926
9927		 *  @example
9928
9929		 *    $(document).ready(function() {
9930
9931		 *      var oTable = $('#example').dataTable();
9932
9933		 *
9934
9935		 *      // Filter to rows with 'Webkit' in them, add a background colour and then
9936
9937		 *      // remove the filter, thus highlighting the 'Webkit' rows only.
9938
9939		 *      oTable.fnFilter('Webkit');
9940
9941		 *      oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
9942
9943		 *      oTable.fnFilter('');
9944
9945		 *    } );
9946
9947		 */
9948
9949		this.$ = function ( sSelector, oOpts )
9950
9951		{
9952
9953			var i, iLen, a = [], tr;
9954
9955			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
9956
9957			var aoData = oSettings.aoData;
9958
9959			var aiDisplay = oSettings.aiDisplay;
9960
9961			var aiDisplayMaster = oSettings.aiDisplayMaster;
9962
9963		
9964
9965			if ( !oOpts )
9966
9967			{
9968
9969				oOpts = {};
9970
9971			}
9972
9973		
9974
9975			oOpts = $.extend( {}, {
9976
9977				"filter": "none", // applied
9978
9979				"order": "current", // "original"
9980
9981				"page": "all" // current
9982
9983			}, oOpts );
9984
9985		
9986
9987			// Current page implies that order=current and fitler=applied, since it is fairly
9988
9989			// senseless otherwise
9990
9991			if ( oOpts.page == 'current' )
9992
9993			{
9994
9995				for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
9996
9997				{
9998
9999					tr = aoData[ aiDisplay[i] ].nTr;
10000
10001					if ( tr )
10002
10003					{
10004
10005						a.push( tr );
10006
10007					}
10008
10009				}
10010
10011			}
10012
10013			else if ( oOpts.order == "current" && oOpts.filter == "none" )
10014
10015			{
10016
10017				for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
10018
10019				{
10020
10021					tr = aoData[ aiDisplayMaster[i] ].nTr;
10022
10023					if ( tr )
10024
10025					{
10026
10027						a.push( tr );
10028
10029					}
10030
10031				}
10032
10033			}
10034
10035			else if ( oOpts.order == "current" && oOpts.filter == "applied" )
10036
10037			{
10038
10039				for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
10040
10041				{
10042
10043					tr = aoData[ aiDisplay[i] ].nTr;
10044
10045					if ( tr )
10046
10047					{
10048
10049						a.push( tr );
10050
10051					}
10052
10053				}
10054
10055			}
10056
10057			else if ( oOpts.order == "original" && oOpts.filter == "none" )
10058
10059			{
10060
10061				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
10062
10063				{
10064
10065					tr = aoData[ i ].nTr ;
10066
10067					if ( tr )
10068
10069					{
10070
10071						a.push( tr );
10072
10073					}
10074
10075				}
10076
10077			}
10078
10079			else if ( oOpts.order == "original" && oOpts.filter == "applied" )
10080
10081			{
10082
10083				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
10084
10085				{
10086
10087					tr = aoData[ i ].nTr;
10088
10089					if ( $.inArray( i, aiDisplay ) !== -1 && tr )
10090
10091					{
10092
10093						a.push( tr );
10094
10095					}
10096
10097				}
10098
10099			}
10100
10101			else
10102
10103			{
10104
10105				_fnLog( oSettings, 1, "Unknown selection options" );
10106
10107			}
10108
10109		
10110
10111			/* We need to filter on the TR elements and also 'find' in their descendants
10112
10113			 * to make the selector act like it would in a full table - so we need
10114
10115			 * to build both results and then combine them together
10116
10117			 */
10118
10119			var jqA = $(a);
10120
10121			var jqTRs = jqA.filter( sSelector );
10122
10123			var jqDescendants = jqA.find( sSelector );
10124
10125		
10126
10127			return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
10128
10129		};
10130
10131		
10132
10133		
10134
10135		/**
10136
10137		 * Almost identical to $ in operation, but in this case returns the data for the matched
10138
10139		 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
10140
10141		 * rather than any descendants, so the data can be obtained for the row/cell. If matching
10142
10143		 * rows are found, the data returned is the original data array/object that was used to  
10144
10145		 * create the row (or a generated array if from a DOM source).
10146
10147		 *
10148
10149		 * This method is often useful in-combination with $ where both functions are given the
10150
10151		 * same parameters and the array indexes will match identically.
10152
10153		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
10154
10155		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
10156
10157		 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
10158
10159		 *    criterion ("applied") or all elements (i.e. no filter).
10160
10161		 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
10162
10163		 *    Can be either 'current', whereby the current sorting of the table is used, or
10164
10165		 *    'original' whereby the original order the data was read into the table is used.
10166
10167		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
10168
10169		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
10170
10171		 *    'current' and filter is 'applied', regardless of what they might be given as.
10172
10173		 *  @returns {array} Data for the matched elements. If any elements, as a result of the
10174
10175		 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null 
10176
10177		 *    entry in the array.
10178
10179		 *  @dtopt API
10180
10181		 *
10182
10183		 *  @example
10184
10185		 *    $(document).ready(function() {
10186
10187		 *      var oTable = $('#example').dataTable();
10188
10189		 *
10190
10191		 *      // Get the data from the first row in the table
10192
10193		 *      var data = oTable._('tr:first');
10194
10195		 *
10196
10197		 *      // Do something useful with the data
10198
10199		 *      alert( "First cell is: "+data[0] );
10200
10201		 *    } );
10202
10203		 *
10204
10205		 *  @example
10206
10207		 *    $(document).ready(function() {
10208
10209		 *      var oTable = $('#example').dataTable();
10210
10211		 *
10212
10213		 *      // Filter to 'Webkit' and get all data for 
10214
10215		 *      oTable.fnFilter('Webkit');
10216
10217		 *      var data = oTable._('tr', {"filter": "applied"});
10218
10219		 *      
10220
10221		 *      // Do something with the data
10222
10223		 *      alert( data.length+" rows matched the filter" );
10224
10225		 *    } );
10226
10227		 */
10228
10229		this._ = function ( sSelector, oOpts )
10230
10231		{
10232
10233			var aOut = [];
10234
10235			var i, iLen, iIndex;
10236
10237			var aTrs = this.$( sSelector, oOpts );
10238
10239		
10240
10241			for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
10242
10243			{
10244
10245				aOut.push( this.fnGetData(aTrs[i]) );
10246
10247			}
10248
10249		
10250
10251			return aOut;
10252
10253		};
10254
10255		
10256
10257		
10258
10259		/**
10260
10261		 * Add a single new row or multiple rows of data to the table. Please note
10262
10263		 * that this is suitable for client-side processing only - if you are using 
10264
10265		 * server-side processing (i.e. "bServerSide": true), then to add data, you
10266
10267		 * must add it to the data source, i.e. the server-side, through an Ajax call.
10268
10269		 *  @param {array|object} mData The data to be added to the table. This can be:
10270
10271		 *    <ul>
10272
10273		 *      <li>1D array of data - add a single row with the data provided</li>
10274
10275		 *      <li>2D array of arrays - add multiple rows in a single call</li>
10276
10277		 *      <li>object - data object when using <i>mData</i></li>
10278
10279		 *      <li>array of objects - multiple data objects when using <i>mData</i></li>
10280
10281		 *    </ul>
10282
10283		 *  @param {bool} [bRedraw=true] redraw the table or not
10284
10285		 *  @returns {array} An array of integers, representing the list of indexes in 
10286
10287		 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 
10288
10289		 *    the table.
10290
10291		 *  @dtopt API
10292
10293		 *
10294
10295		 *  @example
10296
10297		 *    // Global var for counter
10298
10299		 *    var giCount = 2;
10300
10301		 *    
10302
10303		 *    $(document).ready(function() {
10304
10305		 *      $('#example').dataTable();
10306
10307		 *    } );
10308
10309		 *    
10310
10311		 *    function fnClickAddRow() {
10312
10313		 *      $('#example').dataTable().fnAddData( [
10314
10315		 *        giCount+".1",
10316
10317		 *        giCount+".2",
10318
10319		 *        giCount+".3",
10320
10321		 *        giCount+".4" ]
10322
10323		 *      );
10324
10325		 *        
10326
10327		 *      giCount++;
10328
10329		 *    }
10330
10331		 */
10332
10333		this.fnAddData = function( mData, bRedraw )
10334
10335		{
10336
10337			if ( mData.length === 0 )
10338
10339			{
10340
10341				return [];
10342
10343			}
10344
10345			
10346
10347			var aiReturn = [];
10348
10349			var iTest;
10350
10351			
10352
10353			/* Find settings from table node */
10354
10355			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
10356
10357			
10358
10359			/* Check if we want to add multiple rows or not */
10360
10361			if ( typeof mData[0] === "object" && mData[0] !== null )
10362
10363			{
10364
10365				for ( var i=0 ; i<mData.length ; i++ )
10366
10367				{
10368
10369					iTest = _fnAddData( oSettings, mData[i] );
10370
10371					if ( iTest == -1 )
10372
10373					{
10374
10375						return aiReturn;
10376
10377					}
10378
10379					aiReturn.push( iTest );
10380
10381				}
10382
10383			}
10384
10385			else
10386
10387			{
10388
10389				iTest = _fnAddData( oSettings, mData );
10390
10391				if ( iTest == -1 )
10392
10393				{
10394
10395					return aiReturn;
10396
10397				}
10398
10399				aiReturn.push( iTest );
10400
10401			}
10402
10403			
10404
10405			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
10406
10407			
10408
10409			if ( bRedraw === undefined || bRedraw )
10410
10411			{
10412
10413				_fnReDraw( oSettings );
10414
10415			}
10416
10417			return aiReturn;
10418
10419		};
10420
10421		
10422
10423		
10424
10425		/**
10426
10427		 * This function will make DataTables recalculate the column sizes, based on the data 
10428
10429		 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 
10430
10431		 * through the sWidth parameter). This can be useful when the width of the table's 
10432
10433		 * parent element changes (for example a window resize).
10434
10435		 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
10436
10437		 *  @dtopt API
10438
10439		 *
10440
10441		 *  @example
10442
10443		 *    $(document).ready(function() {
10444
10445		 *      var oTable = $('#example').dataTable( {
10446
10447		 *        "sScrollY": "200px",
10448
10449		 *        "bPaginate": false
10450
10451		 *      } );
10452
10453		 *      
10454
10455		 *      $(window).bind('resize', function () {
10456
10457		 *        oTable.fnAdjustColumnSizing();
10458
10459		 *      } );
10460
10461		 *    } );
10462
10463		 */
10464
10465		this.fnAdjustColumnSizing = function ( bRedraw )
10466
10467		{
10468
10469			var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
10470
10471			_fnAdjustColumnSizing( oSettings );
10472
10473			
10474
10475			if ( bRedraw === undefined || bRedraw )
10476
10477			{
10478
10479				this.fnDraw( false );
10480
10481			}
10482
10483			else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
10484
10485			{
10486
10487				/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
10488
10489				this.oApi._fnScrollDraw(oSettings);
10490
10491			}
10492
10493		};
10494
10495		
10496
10497		
10498
10499		/**
10500
10501		 * Quickly and simply clear a table
10502
10503		 *  @param {bool} [bRedraw=true] redraw the table or not
10504
10505		 *  @dtopt API
10506
10507		 *
10508
10509		 *  @example
10510
10511		 *    $(document).ready(function() {
10512
10513		 *      var oTable = $('#example').dataTable();
10514
10515		 *      
10516
10517		 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
10518
10519		 *      oTable.fnClearTable();
10520
10521		 *    } );
10522
10523		 */
10524
10525		this.fnClearTable = function( bRedraw )
10526
10527		{
10528
10529			/* Find settings from table node */
10530
10531			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
10532
10533			_fnClearTable( oSettings );
10534
10535			
10536
10537			if ( bRedraw === undefined || bRedraw )
10538
10539			{
10540
10541				_fnDraw( oSettings );
10542
10543			}
10544
10545		};
10546
10547		
10548
10549		
10550
10551		/**
10552
10553		 * The exact opposite of 'opening' a row, this function will close any rows which 
10554
10555		 * are currently 'open'.
10556
10557		 *  @param {node} nTr the table row to 'close'
10558
10559		 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
10560
10561		 *  @dtopt API
10562
10563		 *
10564
10565		 *  @example
10566
10567		 *    $(document).ready(function() {
10568
10569		 *      var oTable;
10570
10571		 *      
10572
10573		 *      // 'open' an information row when a row is clicked on
10574
10575		 *      $('#example tbody tr').click( function () {
10576
10577		 *        if ( oTable.fnIsOpen(this) ) {
10578
10579		 *          oTable.fnClose( this );
10580
10581		 *        } else {
10582
10583		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
10584
10585		 *        }
10586
10587		 *      } );
10588
10589		 *      
10590
10591		 *      oTable = $('#example').dataTable();
10592
10593		 *    } );
10594
10595		 */
10596
10597		this.fnClose = function( nTr )
10598
10599		{
10600
10601			/* Find settings from table node */
10602
10603			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
10604
10605			
10606
10607			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
10608
10609			{
10610
10611				if ( oSettings.aoOpenRows[i].nParent == nTr )
10612
10613				{
10614
10615					var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
10616
10617					if ( nTrParent )
10618
10619					{
10620
10621						/* Remove it if it is currently on display */
10622
10623						nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
10624
10625					}
10626
10627					oSettings.aoOpenRows.splice( i, 1 );
10628
10629					return 0;
10630
10631				}
10632
10633			}
10634
10635			return 1;
10636
10637		};
10638
10639		
10640
10641		
10642
10643		/**
10644
10645		 * Remove a row for the table
10646
10647		 *  @param {mixed} mTarget The index of the row from aoData to be deleted, or
10648
10649		 *    the TR element you want to delete
10650
10651		 *  @param {function|null} [fnCallBack] Callback function
10652
10653		 *  @param {bool} [bRedraw=true] Redraw the table or not
10654
10655		 *  @returns {array} The row that was deleted
10656
10657		 *  @dtopt API
10658
10659		 *
10660
10661		 *  @example
10662
10663		 *    $(document).ready(function() {
10664
10665		 *      var oTable = $('#example').dataTable();
10666
10667		 *      
10668
10669		 *      // Immediately remove the first row
10670
10671		 *      oTable.fnDeleteRow( 0 );
10672
10673		 *    } );
10674
10675		 */
10676
10677		this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
10678
10679		{
10680
10681			/* Find settings from table node */
10682
10683			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
10684
10685			var i, iLen, iAODataIndex;
10686
10687			
10688
10689			iAODataIndex = (typeof mTarget === 'object') ? 
10690
10691				_fnNodeToDataIndex(oSettings, mTarget) : mTarget;
10692
10693			
10694
10695			/* Return the data array from this row */
10696
10697			var oData = oSettings.aoData.splice( iAODataIndex, 1 );
10698
10699		
10700
10701			/* Update the _DT_RowIndex parameter */
10702
10703			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
10704
10705			{
10706
10707				if ( oSettings.aoData[i].nTr !== null )
10708
10709				{
10710
10711					oSettings.aoData[i].nTr._DT_RowIndex = i;
10712
10713				}
10714
10715			}
10716
10717			
10718
10719			/* Remove the target row from the search array */
10720
10721			var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
10722
10723			oSettings.asDataSearch.splice( iDisplayIndex, 1 );
10724
10725			
10726
10727			/* Delete from the display arrays */
10728
10729			_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
10730
10731			_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
10732
10733			
10734
10735			/* If there is a user callback function - call it */
10736
10737			if ( typeof fnCallBack === "function" )
10738
10739			{
10740
10741				fnCallBack.call( this, oSettings, oData );
10742
10743			}
10744
10745			
10746
10747			/* Check for an 'overflow' they case for displaying the table */
10748
10749			if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
10750
10751			{
10752
10753				oSettings._iDisplayStart -= oSettings._iDisplayLength;
10754
10755				if ( oSettings._iDisplayStart < 0 )
10756
10757				{
10758
10759					oSettings._iDisplayStart = 0;
10760
10761				}
10762
10763			}
10764
10765			
10766
10767			if ( bRedraw === undefined || bRedraw )
10768
10769			{
10770
10771				_fnCalculateEnd( oSettings );
10772
10773				_fnDraw( oSettings );
10774
10775			}
10776
10777			
10778
10779			return oData;
10780
10781		};
10782
10783		
10784
10785		
10786
10787		/**
10788
10789		 * Restore the table to it's original state in the DOM by removing all of DataTables 
10790
10791		 * enhancements, alterations to the DOM structure of the table and event listeners.
10792
10793		 *  @param {boolean} [bRemove=false] Completely remove the table from the DOM
10794
10795		 *  @dtopt API
10796
10797		 *
10798
10799		 *  @example
10800
10801		 *    $(document).ready(function() {
10802
10803		 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
10804
10805		 *      var oTable = $('#example').dataTable();
10806
10807		 *      oTable.fnDestroy();
10808
10809		 *    } );
10810
10811		 */
10812
10813		this.fnDestroy = function ( bRemove )
10814
10815		{
10816
10817			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
10818
10819			var nOrig = oSettings.nTableWrapper.parentNode;
10820
10821			var nBody = oSettings.nTBody;
10822
10823			var i, iLen;
10824
10825		
10826
10827			bRemove = (bRemove===undefined) ? false : bRemove;
10828
10829			
10830
10831			/* Flag to note that the table is currently being destroyed - no action should be taken */
10832
10833			oSettings.bDestroying = true;
10834
10835			
10836
10837			/* Fire off the destroy callbacks for plug-ins etc */
10838
10839			_fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
10840
10841		
10842
10843			/* If the table is not being removed, restore the hidden columns */
10844
10845			if ( !bRemove )
10846
10847			{
10848
10849				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
10850
10851				{
10852
10853					if ( oSettings.aoColumns[i].bVisible === false )
10854
10855					{
10856
10857						this.fnSetColumnVis( i, true );
10858
10859					}
10860
10861				}
10862
10863			}
10864
10865			
10866
10867			/* Blitz all DT Businesses */
10868
10869			$(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
10870
10871			
10872
10873			/* If there is an 'empty' indicator row, remove it */
10874
10875			$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
10876
10877			
10878
10879			/* When scrolling we had to break the table up - restore it */
10880
10881			if ( oSettings.nTable != oSettings.nTHead.parentNode )
10882
10883			{
10884
10885				$(oSettings.nTable).children('thead').remove();
10886
10887				oSettings.nTable.appendChild( oSettings.nTHead );
10888
10889			}
10890
10891			
10892
10893			if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
10894
10895			{
10896
10897				$(oSettings.nTable).children('tfoot').remove();
10898
10899				oSettings.nTable.appendChild( oSettings.nTFoot );
10900
10901			}
10902
10903			
10904
10905			/* Remove the DataTables generated nodes, Businesses and classes */
10906
10907			oSettings.nTable.parentNode.removeChild( oSettings.nTable );
10908
10909			$(oSettings.nTableWrapper).remove();
10910
10911			
10912
10913			oSettings.aaSorting = [];
10914
10915			oSettings.aaSortingFixed = [];
10916
10917			_fnSortingClasses( oSettings );
10918
10919			
10920
10921			$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
10922
10923			
10924
10925			$('th, td', oSettings.nTHead).removeClass( [
10926
10927				oSettings.oClasses.sSortable,
10928
10929				oSettings.oClasses.sSortableAsc,
10930
10931				oSettings.oClasses.sSortableDesc,
10932
10933				oSettings.oClasses.sSortableNone ].join(' ')
10934
10935			);
10936
10937			if ( oSettings.bJUI )
10938
10939			{
10940
10941				$('th span.'+oSettings.oClasses.sSortIcon
10942
10943					+ ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
10944
10945		
10946
10947				$('th, td', oSettings.nTHead).each( function () {
10948
10949					var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
10950
10951					var kids = jqWrapper.contents();
10952
10953					$(this).append( kids );
10954
10955					jqWrapper.remove();
10956
10957				} );
10958
10959			}
10960
10961			
10962
10963			/* Add the TR elements back into the table in their original order */
10964
10965			if ( !bRemove && oSettings.nTableReinsertBefore )
10966
10967			{
10968
10969				nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
10970
10971			}
10972
10973			else if ( !bRemove )
10974
10975			{
10976
10977				nOrig.appendChild( oSettings.nTable );
10978
10979			}
10980
10981		
10982
10983			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
10984
10985			{
10986
10987				if ( oSettings.aoData[i].nTr !== null )
10988
10989				{
10990
10991					nBody.appendChild( oSettings.aoData[i].nTr );
10992
10993				}
10994
10995			}
10996
10997			
10998
10999			/* Restore the width of the original table */
11000
11001			if ( oSettings.oFeatures.bAutoWidth === true )
11002
11003			{
11004
11005			  oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
11006
11007			}
11008
11009			
11010
11011			/* If the were originally stripe classes - then we add them back here. Note
11012
11013			 * this is not fool proof (for example if not all rows had stripe classes - but
11014
11015			 * it's a good effort without getting carried away
11016
11017			 */
11018
11019			iLen = oSettings.asDestroyStripes.length;
11020
11021			if (iLen)
11022
11023			{
11024
11025				var anRows = $(nBody).children('tr');
11026
11027				for ( i=0 ; i<iLen ; i++ )
11028
11029				{
11030
11031					anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
11032
11033				}
11034
11035			}
11036
11037			
11038
11039			/* Remove the settings object from the settings array */
11040
11041			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
11042
11043			{
11044
11045				if ( DataTable.settings[i] == oSettings )
11046
11047				{
11048
11049					DataTable.settings.splice( i, 1 );
11050
11051				}
11052
11053			}
11054
11055			
11056
11057			/* End it all */
11058
11059			oSettings = null;
11060
11061			oInit = null;
11062
11063		};
11064
11065		
11066
11067		
11068
11069		/**
11070
11071		 * Redraw the table
11072
11073		 *  @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
11074
11075		 *  @dtopt API
11076
11077		 *
11078
11079		 *  @example
11080
11081		 *    $(document).ready(function() {
11082
11083		 *      var oTable = $('#example').dataTable();
11084
11085		 *      
11086
11087		 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
11088
11089		 *      oTable.fnDraw();
11090
11091		 *    } );
11092
11093		 */
11094
11095		this.fnDraw = function( bComplete )
11096
11097		{
11098
11099			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11100
11101			if ( bComplete === false )
11102
11103			{
11104
11105				_fnCalculateEnd( oSettings );
11106
11107				_fnDraw( oSettings );
11108
11109			}
11110
11111			else
11112
11113			{
11114
11115				_fnReDraw( oSettings );
11116
11117			}
11118
11119		};
11120
11121		
11122
11123		
11124
11125		/**
11126
11127		 * Filter the input based on data
11128
11129		 *  @param {string} sInput String to filter the table on
11130
11131		 *  @param {int|null} [iColumn] Column to limit filtering to
11132
11133		 *  @param {bool} [bRegex=false] Treat as regular expression or not
11134
11135		 *  @param {bool} [bSmart=true] Perform smart filtering or not
11136
11137		 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
11138
11139		 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
11140
11141		 *  @dtopt API
11142
11143		 *
11144
11145		 *  @example
11146
11147		 *    $(document).ready(function() {
11148
11149		 *      var oTable = $('#example').dataTable();
11150
11151		 *      
11152
11153		 *      // Sometime later - filter...
11154
11155		 *      oTable.fnFilter( 'test string' );
11156
11157		 *    } );
11158
11159		 */
11160
11161		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
11162
11163		{
11164
11165			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11166
11167			
11168
11169			if ( !oSettings.oFeatures.bFilter )
11170
11171			{
11172
11173				return;
11174
11175			}
11176
11177			
11178
11179			if ( bRegex === undefined || bRegex === null )
11180
11181			{
11182
11183				bRegex = false;
11184
11185			}
11186
11187			
11188
11189			if ( bSmart === undefined || bSmart === null )
11190
11191			{
11192
11193				bSmart = true;
11194
11195			}
11196
11197			
11198
11199			if ( bShowGlobal === undefined || bShowGlobal === null )
11200
11201			{
11202
11203				bShowGlobal = true;
11204
11205			}
11206
11207			
11208
11209			if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
11210
11211			{
11212
11213				bCaseInsensitive = true;
11214
11215			}
11216
11217			
11218
11219			if ( iColumn === undefined || iColumn === null )
11220
11221			{
11222
11223				/* Global filter */
11224
11225				_fnFilterComplete( oSettings, {
11226
11227					"sSearch":sInput+"",
11228
11229					"bRegex": bRegex,
11230
11231					"bSmart": bSmart,
11232
11233					"bCaseInsensitive": bCaseInsensitive
11234
11235				}, 1 );
11236
11237				
11238
11239				if ( bShowGlobal && oSettings.aanFeatures.f )
11240
11241				{
11242
11243					var n = oSettings.aanFeatures.f;
11244
11245					for ( var i=0, iLen=n.length ; i<iLen ; i++ )
11246
11247					{
11248
11249						// IE9 throws an 'unknown error' if document.activeElement is used
11250
11251						// inside an iframe or frame...
11252
11253						try {
11254
11255							if ( n[i]._DT_Input != document.activeElement )
11256
11257							{
11258
11259								$(n[i]._DT_Input).val( sInput );
11260
11261							}
11262
11263						}
11264
11265						catch ( e ) {
11266
11267							$(n[i]._DT_Input).val( sInput );
11268
11269						}
11270
11271					}
11272
11273				}
11274
11275			}
11276
11277			else
11278
11279			{
11280
11281				/* Single column filter */
11282
11283				$.extend( oSettings.aoPreSearchCols[ iColumn ], {
11284
11285					"sSearch": sInput+"",
11286
11287					"bRegex": bRegex,
11288
11289					"bSmart": bSmart,
11290
11291					"bCaseInsensitive": bCaseInsensitive
11292
11293				} );
11294
11295				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
11296
11297			}
11298
11299		};
11300
11301		
11302
11303		
11304
11305		/**
11306
11307		 * Get the data for the whole table, an individual row or an individual cell based on the 
11308
11309		 * provided parameters.
11310
11311		 *  @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
11312
11313		 *    a TR node then the data source for the whole row will be returned. If given as a
11314
11315		 *    TD/TH cell node then iCol will be automatically calculated and the data for the
11316
11317		 *    cell returned. If given as an integer, then this is treated as the aoData internal
11318
11319		 *    data index for the row (see fnGetPosition) and the data for that row used.
11320
11321		 *  @param {int} [iCol] Optional column index that you want the data of.
11322
11323		 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
11324
11325		 *    returned. If mRow is defined, just data for that row, and is iCol is
11326
11327		 *    defined, only data for the designated cell is returned.
11328
11329		 *  @dtopt API
11330
11331		 *
11332
11333		 *  @example
11334
11335		 *    // Row data
11336
11337		 *    $(document).ready(function() {
11338
11339		 *      oTable = $('#example').dataTable();
11340
11341		 *
11342
11343		 *      oTable.$('tr').click( function () {
11344
11345		 *        var data = oTable.fnGetData( this );
11346
11347		 *        // ... do something with the array / object of data for the row
11348
11349		 *      } );
11350
11351		 *    } );
11352
11353		 *
11354
11355		 *  @example
11356
11357		 *    // Individual cell data
11358
11359		 *    $(document).ready(function() {
11360
11361		 *      oTable = $('#example').dataTable();
11362
11363		 *
11364
11365		 *      oTable.$('td').click( function () {
11366
11367		 *        var sData = oTable.fnGetData( this );
11368
11369		 *        alert( 'The cell clicked on had the value of '+sData );
11370
11371		 *      } );
11372
11373		 *    } );
11374
11375		 */
11376
11377		this.fnGetData = function( mRow, iCol )
11378
11379		{
11380
11381			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11382
11383			
11384
11385			if ( mRow !== undefined )
11386
11387			{
11388
11389				var iRow = mRow;
11390
11391				if ( typeof mRow === 'object' )
11392
11393				{
11394
11395					var sNode = mRow.nodeName.toLowerCase();
11396
11397					if (sNode === "tr" )
11398
11399					{
11400
11401						iRow = _fnNodeToDataIndex(oSettings, mRow);
11402
11403					}
11404
11405					else if ( sNode === "td" )
11406
11407					{
11408
11409						iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
11410
11411						iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
11412
11413					}
11414
11415				}
11416
11417		
11418
11419				if ( iCol !== undefined )
11420
11421				{
11422
11423					return _fnGetCellData( oSettings, iRow, iCol, '' );
11424
11425				}
11426
11427				return (oSettings.aoData[iRow]!==undefined) ?
11428
11429					oSettings.aoData[iRow]._aData : null;
11430
11431			}
11432
11433			return _fnGetDataMaster( oSettings );
11434
11435		};
11436
11437		
11438
11439		
11440
11441		/**
11442
11443		 * Get an array of the TR nodes that are used in the table's body. Note that you will 
11444
11445		 * typically want to use the '$' API method in preference to this as it is more 
11446
11447		 * flexible.
11448
11449		 *  @param {int} [iRow] Optional row index for the TR element you want
11450
11451		 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
11452
11453		 *    in the table's body, or iRow is defined, just the TR element requested.
11454
11455		 *  @dtopt API
11456
11457		 *
11458
11459		 *  @example
11460
11461		 *    $(document).ready(function() {
11462
11463		 *      var oTable = $('#example').dataTable();
11464
11465		 *      
11466
11467		 *      // Get the nodes from the table
11468
11469		 *      var nNodes = oTable.fnGetNodes( );
11470
11471		 *    } );
11472
11473		 */
11474
11475		this.fnGetNodes = function( iRow )
11476
11477		{
11478
11479			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11480
11481			
11482
11483			if ( iRow !== undefined ) {
11484
11485				return (oSettings.aoData[iRow]!==undefined) ?
11486
11487					oSettings.aoData[iRow].nTr : null;
11488
11489			}
11490
11491			return _fnGetTrNodes( oSettings );
11492
11493		};
11494
11495		
11496
11497		
11498
11499		/**
11500
11501		 * Get the array indexes of a particular cell from it's DOM element
11502
11503		 * and column index including hidden columns
11504
11505		 *  @param {node} nNode this can either be a TR, TD or TH in the table's body
11506
11507		 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
11508
11509		 *    if given as a cell, an array of [row index, column index (visible), 
11510
11511		 *    column index (all)] is given.
11512
11513		 *  @dtopt API
11514
11515		 *
11516
11517		 *  @example
11518
11519		 *    $(document).ready(function() {
11520
11521		 *      $('#example tbody td').click( function () {
11522
11523		 *        // Get the position of the current data from the node
11524
11525		 *        var aPos = oTable.fnGetPosition( this );
11526
11527		 *        
11528
11529		 *        // Get the data array for this row
11530
11531		 *        var aData = oTable.fnGetData( aPos[0] );
11532
11533		 *        
11534
11535		 *        // Update the data array and return the value
11536
11537		 *        aData[ aPos[1] ] = 'clicked';
11538
11539		 *        this.innerHTML = 'clicked';
11540
11541		 *      } );
11542
11543		 *      
11544
11545		 *      // Init DataTables
11546
11547		 *      oTable = $('#example').dataTable();
11548
11549		 *    } );
11550
11551		 */
11552
11553		this.fnGetPosition = function( nNode )
11554
11555		{
11556
11557			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11558
11559			var sNodeName = nNode.nodeName.toUpperCase();
11560
11561			
11562
11563			if ( sNodeName == "TR" )
11564
11565			{
11566
11567				return _fnNodeToDataIndex(oSettings, nNode);
11568
11569			}
11570
11571			else if ( sNodeName == "TD" || sNodeName == "TH" )
11572
11573			{
11574
11575				var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
11576
11577				var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
11578
11579				return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
11580
11581			}
11582
11583			return null;
11584
11585		};
11586
11587		
11588
11589		
11590
11591		/**
11592
11593		 * Check to see if a row is 'open' or not.
11594
11595		 *  @param {node} nTr the table row to check
11596
11597		 *  @returns {boolean} true if the row is currently open, false otherwise
11598
11599		 *  @dtopt API
11600
11601		 *
11602
11603		 *  @example
11604
11605		 *    $(document).ready(function() {
11606
11607		 *      var oTable;
11608
11609		 *      
11610
11611		 *      // 'open' an information row when a row is clicked on
11612
11613		 *      $('#example tbody tr').click( function () {
11614
11615		 *        if ( oTable.fnIsOpen(this) ) {
11616
11617		 *          oTable.fnClose( this );
11618
11619		 *        } else {
11620
11621		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
11622
11623		 *        }
11624
11625		 *      } );
11626
11627		 *      
11628
11629		 *      oTable = $('#example').dataTable();
11630
11631		 *    } );
11632
11633		 */
11634
11635		this.fnIsOpen = function( nTr )
11636
11637		{
11638
11639			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11640
11641			var aoOpenRows = oSettings.aoOpenRows;
11642
11643			
11644
11645			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
11646
11647			{
11648
11649				if ( oSettings.aoOpenRows[i].nParent == nTr )
11650
11651				{
11652
11653					return true;
11654
11655				}
11656
11657			}
11658
11659			return false;
11660
11661		};
11662
11663		
11664
11665		
11666
11667		/**
11668
11669		 * This function will place a new row directly after a row which is currently 
11670
11671		 * on display on the page, with the HTML contents that is passed into the 
11672
11673		 * function. This can be used, for example, to ask for confirmation that a 
11674
11675		 * particular record should be deleted.
11676
11677		 *  @param {node} nTr The table row to 'open'
11678
11679		 *  @param {string|node|jQuery} mHtml The HTML to put into the row
11680
11681		 *  @param {string} sClass Class to give the new TD cell
11682
11683		 *  @returns {node} The row opened. Note that if the table row passed in as the
11684
11685		 *    first parameter, is not found in the table, this method will silently
11686
11687		 *    return.
11688
11689		 *  @dtopt API
11690
11691		 *
11692
11693		 *  @example
11694
11695		 *    $(document).ready(function() {
11696
11697		 *      var oTable;
11698
11699		 *      
11700
11701		 *      // 'open' an information row when a row is clicked on
11702
11703		 *      $('#example tbody tr').click( function () {
11704
11705		 *        if ( oTable.fnIsOpen(this) ) {
11706
11707		 *          oTable.fnClose( this );
11708
11709		 *        } else {
11710
11711		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
11712
11713		 *        }
11714
11715		 *      } );
11716
11717		 *      
11718
11719		 *      oTable = $('#example').dataTable();
11720
11721		 *    } );
11722
11723		 */
11724
11725		this.fnOpen = function( nTr, mHtml, sClass )
11726
11727		{
11728
11729			/* Find settings from table node */
11730
11731			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11732
11733		
11734
11735			/* Check that the row given is in the table */
11736
11737			var nTableRows = _fnGetTrNodes( oSettings );
11738
11739			if ( $.inArray(nTr, nTableRows) === -1 )
11740
11741			{
11742
11743				return;
11744
11745			}
11746
11747			
11748
11749			/* the old open one if there is one */
11750
11751			this.fnClose( nTr );
11752
11753			
11754
11755			var nNewRow = document.createElement("tr");
11756
11757			var nNewCell = document.createElement("td");
11758
11759			nNewRow.appendChild( nNewCell );
11760
11761			nNewCell.className = sClass;
11762
11763			nNewCell.colSpan = _fnVisbleColumns( oSettings );
11764
11765		
11766
11767			if (typeof mHtml === "string")
11768
11769			{
11770
11771				nNewCell.innerHTML = mHtml;
11772
11773			}
11774
11775			else
11776
11777			{
11778
11779				$(nNewCell).html( mHtml );
11780
11781			}
11782
11783		
11784
11785			/* If the nTr isn't on the page at the moment - then we don't insert at the moment */
11786
11787			var nTrs = $('tr', oSettings.nTBody);
11788
11789			if ( $.inArray(nTr, nTrs) != -1  )
11790
11791			{
11792
11793				$(nNewRow).insertAfter(nTr);
11794
11795			}
11796
11797			
11798
11799			oSettings.aoOpenRows.push( {
11800
11801				"nTr": nNewRow,
11802
11803				"nParent": nTr
11804
11805			} );
11806
11807			
11808
11809			return nNewRow;
11810
11811		};
11812
11813		
11814
11815		
11816
11817		/**
11818
11819		 * Change the pagination - provides the internal logic for pagination in a simple API 
11820
11821		 * function. With this function you can have a DataTables table go to the next, 
11822
11823		 * previous, first or last pages.
11824
11825		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
11826
11827		 *    or page number to jump to (integer), note that page 0 is the first page.
11828
11829		 *  @param {bool} [bRedraw=true] Redraw the table or not
11830
11831		 *  @dtopt API
11832
11833		 *
11834
11835		 *  @example
11836
11837		 *    $(document).ready(function() {
11838
11839		 *      var oTable = $('#example').dataTable();
11840
11841		 *      oTable.fnPageChange( 'next' );
11842
11843		 *    } );
11844
11845		 */
11846
11847		this.fnPageChange = function ( mAction, bRedraw )
11848
11849		{
11850
11851			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11852
11853			_fnPageChange( oSettings, mAction );
11854
11855			_fnCalculateEnd( oSettings );
11856
11857			
11858
11859			if ( bRedraw === undefined || bRedraw )
11860
11861			{
11862
11863				_fnDraw( oSettings );
11864
11865			}
11866
11867		};
11868
11869		
11870
11871		
11872
11873		/**
11874
11875		 * Show a particular column
11876
11877		 *  @param {int} iCol The column whose display should be changed
11878
11879		 *  @param {bool} bShow Show (true) or hide (false) the column
11880
11881		 *  @param {bool} [bRedraw=true] Redraw the table or not
11882
11883		 *  @dtopt API
11884
11885		 *
11886
11887		 *  @example
11888
11889		 *    $(document).ready(function() {
11890
11891		 *      var oTable = $('#example').dataTable();
11892
11893		 *      
11894
11895		 *      // Hide the second column after initialisation
11896
11897		 *      oTable.fnSetColumnVis( 1, false );
11898
11899		 *    } );
11900
11901		 */
11902
11903		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
11904
11905		{
11906
11907			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
11908
11909			var i, iLen;
11910
11911			var aoColumns = oSettings.aoColumns;
11912
11913			var aoData = oSettings.aoData;
11914
11915			var nTd, bAppend, iBefore;
11916
11917			
11918
11919			/* No point in doing anything if we are requesting what is already true */
11920
11921			if ( aoColumns[iCol].bVisible == bShow )
11922
11923			{
11924
11925				return;
11926
11927			}
11928
11929			
11930
11931			/* Show the column */
11932
11933			if ( bShow )
11934
11935			{
11936
11937				var iInsert = 0;
11938
11939				for ( i=0 ; i<iCol ; i++ )
11940
11941				{
11942
11943					if ( aoColumns[i].bVisible )
11944
11945					{
11946
11947						iInsert++;
11948
11949					}
11950
11951				}
11952
11953				
11954
11955				/* Need to decide if we should use appendChild or insertBefore */
11956
11957				bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
11958
11959		
11960
11961				/* Which coloumn should we be inserting before? */
11962
11963				if ( !bAppend )
11964
11965				{
11966
11967					for ( i=iCol ; i<aoColumns.length ; i++ )
11968
11969					{
11970
11971						if ( aoCol
11971umns[i].bVisible )
11972
11973						{
11974
11975							iBefore = i;
11976
11977							break;
11978
11979						}
11980
11981					}
11982
11983				}
11984
11985		
11986
11987				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
11988
11989				{
11990
11991					if ( aoData[i].nTr !== null )
11992
11993					{
11994
11995						if ( bAppend )
11996
11997						{
11998
11999							aoData[i].nTr.appendChild( 
12000
12001								aoData[i]._anHidden[iCol]
12002
12003							);
12004
12005						}
12006
12007						else
12008
12009						{
12010
12011							aoData[i].nTr.insertBefore(
12012
12013								aoData[i]._anHidden[iCol], 
12014
12015								_fnGetTdNodes( oSettings, i )[iBefore] );
12016
12017						}
12018
12019					}
12020
12021				}
12022
12023			}
12024
12025			else
12026
12027			{
12028
12029				/* Remove a column from display */
12030
12031				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
12032
12033				{
12034
12035					if ( aoData[i].nTr !== null )
12036
12037					{
12038
12039						nTd = _fnGetTdNodes( oSettings, i )[iCol];
12040
12041						aoData[i]._anHidden[iCol] = nTd;
12042
12043						nTd.parentNode.removeChild( nTd );
12044
12045					}
12046
12047				}
12048
12049			}
12050
12051		
12052
12053			/* Clear to set the visible flag */
12054
12055			aoColumns[iCol].bVisible = bShow;
12056
12057		
12058
12059			/* Redraw the header and footer based on the new column visibility */
12060
12061			_fnDrawHead( oSettings, oSettings.aoHeader );
12062
12063			if ( oSettings.nTFoot )
12064
12065			{
12066
12067				_fnDrawHead( oSettings, oSettings.aoFooter );
12068
12069			}
12070
12071			
12072
12073			/* If there are any 'open' rows, then we need to alter the colspan for this col change */
12074
12075			for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
12076
12077			{
12078
12079				oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
12080
12081			}
12082
12083			
12084
12085			/* Do a redraw incase anything depending on the table columns needs it 
12086
12087			 * (built-in: scrolling) 
12088
12089			 */
12090
12091			if ( bRedraw === undefined || bRedraw )
12092
12093			{
12094
12095				_fnAdjustColumnSizing( oSettings );
12096
12097				_fnDraw( oSettings );
12098
12099			}
12100
12101			
12102
12103			_fnSaveState( oSettings );
12104
12105		};
12106
12107		
12108
12109		
12110
12111		/**
12112
12113		 * Get the settings for a particular table for external manipulation
12114
12115		 *  @returns {object} DataTables settings object. See 
12116
12117		 *    {@link DataTable.models.oSettings}
12118
12119		 *  @dtopt API
12120
12121		 *
12122
12123		 *  @example
12124
12125		 *    $(document).ready(function() {
12126
12127		 *      var oTable = $('#example').dataTable();
12128
12129		 *      var oSettings = oTable.fnSettings();
12130
12131		 *      
12132
12133		 *      // Show an example parameter from the settings
12134
12135		 *      alert( oSettings._iDisplayStart );
12136
12137		 *    } );
12138
12139		 */
12140
12141		this.fnSettings = function()
12142
12143		{
12144
12145			return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
12146
12147		};
12148
12149		
12150
12151		
12152
12153		/**
12154
12155		 * Sort the table by a particular column
12156
12157		 *  @param {int} iCol the data index to sort on. Note that this will not match the 
12158
12159		 *    'display index' if you have hidden data Businesses
12160
12161		 *  @dtopt API
12162
12163		 *
12164
12165		 *  @example
12166
12167		 *    $(document).ready(function() {
12168
12169		 *      var oTable = $('#example').dataTable();
12170
12171		 *      
12172
12173		 *      // Sort immediately with columns 0 and 1
12174
12175		 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
12176
12177		 *    } );
12178
12179		 */
12180
12181		this.fnSort = function( aaSort )
12182
12183		{
12184
12185			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
12186
12187			oSettings.aaSorting = aaSort;
12188
12189			_fnSort( oSettings );
12190
12191		};
12192
12193		
12194
12195		
12196
12197		/**
12198
12199		 * Attach a sort listener to an element for a given column
12200
12201		 *  @param {node} nNode the element to attach the sort listener to
12202
12203		 *  @param {int} iColumn the column that a click on this node will sort on
12204
12205		 *  @param {function} [fnCallback] callback function when sort is run
12206
12207		 *  @dtopt API
12208
12209		 *
12210
12211		 *  @example
12212
12213		 *    $(document).ready(function() {
12214
12215		 *      var oTable = $('#example').dataTable();
12216
12217		 *      
12218
12219		 *      // Sort on column 1, when 'sorter' is clicked on
12220
12221		 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
12222
12223		 *    } );
12224
12225		 */
12226
12227		this.fnSortListener = function( nNode, iColumn, fnCallback )
12228
12229		{
12230
12231			_fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
12232
12233			 	fnCallback );
12234
12235		};
12236
12237		
12238
12239		
12240
12241		/**
12242
12243		 * Update a table cell or row - this method will accept either a single value to
12244
12245		 * update the cell with, an array of values with one element for each column or
12246
12247		 * an object in the same format as the original data source. The function is
12248
12249		 * self-referencing in order to make the multi column updates easier.
12250
12251		 *  @param {object|array|string} mData Data to update the cell/row with
12252
12253		 *  @param {node|int} mRow TR element you want to update or the aoData index
12254
12255		 *  @param {int} [iColumn] The column to update (not used of mData is an array or object)
12256
12257		 *  @param {bool} [bRedraw=true] Redraw the table or not
12258
12259		 *  @param {bool} [bAction=true] Perform pre-draw actions or not
12260
12261		 *  @returns {int} 0 on success, 1 on error
12262
12263		 *  @dtopt API
12264
12265		 *
12266
12267		 *  @example
12268
12269		 *    $(document).ready(function() {
12270
12271		 *      var oTable = $('#example').dataTable();
12272
12273		 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
12274
12275		 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
12276
12277		 *    } );
12278
12279		 */
12280
12281		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
12282
12283		{
12284
12285			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
12286
12287			var i, iLen, sDisplay;
12288
12289			var iRow = (typeof mRow === 'object') ? 
12290
12291				_fnNodeToDataIndex(oSettings, mRow) : mRow;
12292
12293			
12294
12295			if ( $.isArray(mData) && iColumn === undefined )
12296
12297			{
12298
12299				/* Array update - update the whole row */
12300
12301				oSettings.aoData[iRow]._aData = mData.slice();
12302
12303				
12304
12305				/* Flag to the function that we are recursing */
12306
12307				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
12308
12309				{
12310
12311					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
12312
12313				}
12314
12315			}
12316
12317			else if ( $.isPlainObject(mData) && iColumn === undefined )
12318
12319			{
12320
12321				/* Object update - update the whole row - assume the developer gets the object right */
12322
12323				oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
12324
12325		
12326
12327				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
12328
12329				{
12330
12331					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
12332
12333				}
12334
12335			}
12336
12337			else
12338
12339			{
12340
12341				/* Individual cell update */
12342
12343				_fnSetCellData( oSettings, iRow, iColumn, mData );
12344
12345				sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
12346
12347				
12348
12349				var oCol = oSettings.aoColumns[iColumn];
12350
12351				if ( oCol.fnRender !== null )
12352
12353				{
12354
12355					sDisplay = _fnRender( oSettings, iRow, iColumn );
12356
12357					if ( oCol.bUseRendered )
12358
12359					{
12360
12361						_fnSetCellData( oSettings, iRow, iColumn, sDisplay );
12362
12363					}
12364
12365				}
12366
12367				
12368
12369				if ( oSettings.aoData[iRow].nTr !== null )
12370
12371				{
12372
12373					/* Do the actual HTML update */
12374
12375					_fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
12376
12377				}
12378
12379			}
12380
12381			
12382
12383			/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
12384
12385			 * will rebuild the search array - however, the redraw might be disabled by the user)
12386
12387			 */
12388
12389			var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
12390
12391			oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
12392
12393				oSettings, 
12394
12395				_fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
12396
12397			);
12398
12399			
12400
12401			/* Perform pre-draw actions */
12402
12403			if ( bAction === undefined || bAction )
12404
12405			{
12406
12407				_fnAdjustColumnSizing( oSettings );
12408
12409			}
12410
12411			
12412
12413			/* Redraw the table */
12414
12415			if ( bRedraw === undefined || bRedraw )
12416
12417			{
12418
12419				_fnReDraw( oSettings );
12420
12421			}
12422
12423			return 0;
12424
12425		};
12426
12427		
12428
12429		
12430
12431		/**
12432
12433		 * Provide a common method for plug-ins to check the version of DataTables being used, in order
12434
12435		 * to ensure compatibility.
12436
12437		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
12438
12439		 *    formats "X" and "X.Y" are also acceptable.
12440
12441		 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
12442
12443		 *    version, or false if this version of DataTales is not suitable
12444
12445		 *  @method
12446
12447		 *  @dtopt API
12448
12449		 *
12450
12451		 *  @example
12452
12453		 *    $(document).ready(function() {
12454
12455		 *      var oTable = $('#example').dataTable();
12456
12457		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
12458
12459		 *    } );
12460
12461		 */
12462
12463		this.fnVersionCheck = DataTable.ext.fnVersionCheck;
12464
12465		
12466
12467		
12468
12469		/*
12470
12471		 * This is really a good bit rubbish this method of exposing the internal methods
12472
12473		 * publicly... - To be fixed in 2.0 using methods on the prototype
12474
12475		 */
12476
12477		
12478
12479		
12480
12481		/**
12482
12483		 * Create a wrapper function for exporting an internal functions to an external API.
12484
12485		 *  @param {string} sFunc API function name
12486
12487		 *  @returns {function} wrapped function
12488
12489		 *  @memberof DataTable#oApi
12490
12491		 */
12492
12493		function _fnExternApiFunc (sFunc)
12494
12495		{
12496
12497			return function() {
12498
12499				var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat( 
12500
12501					Array.prototype.slice.call(arguments) );
12502
12503				return DataTable.ext.oApi[sFunc].apply( this, aArgs );
12504
12505			};
12506
12507		}
12508
12509		
12510
12511		
12512
12513		/**
12514
12515		 * Reference to internal functions for use by plug-in developers. Note that these
12516
12517		 * methods are references to internal functions and are considered to be private.
12518
12519		 * If you use these methods, be aware that they are liable to change between versions
12520
12521		 * (check the upgrade notes).
12522
12523		 *  @namespace
12524
12525		 */
12526
12527		this.oApi = {
12528
12529			"_fnExternApiFunc": _fnExternApiFunc,
12530
12531			"_fnInitialise": _fnInitialise,
12532
12533			"_fnInitComplete": _fnInitComplete,
12534
12535			"_fnLanguageCompat": _fnLanguageCompat,
12536
12537			"_fnAddColumn": _fnAddColumn,
12538
12539			"_fnColumnOptions": _fnColumnOptions,
12540
12541			"_fnAddData": _fnAddData,
12542
12543			"_fnCreateTr": _fnCreateTr,
12544
12545			"_fnGatherData": _fnGatherData,
12546
12547			"_fnBuildHead": _fnBuildHead,
12548
12549			"_fnDrawHead": _fnDrawHead,
12550
12551			"_fnDraw": _fnDraw,
12552
12553			"_fnReDraw": _fnReDraw,
12554
12555			"_fnAjaxUpdate": _fnAjaxUpdate,
12556
12557			"_fnAjaxParameters": _fnAjaxParameters,
12558
12559			"_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
12560
12561			"_fnServerParams": _fnServerParams,
12562
12563			"_fnAddOptionsHtml": _fnAddOptionsHtml,
12564
12565			"_fnFeatureHtmlTable": _fnFeatureHtmlTable,
12566
12567			"_fnScrollDraw": _fnScrollDraw,
12568
12569			"_fnAdjustColumnSizing": _fnAdjustColumnSizing,
12570
12571			"_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
12572
12573			"_fnFilterComplete": _fnFilterComplete,
12574
12575			"_fnFilterCustom": _fnFilterCustom,
12576
12577			"_fnFilterColumn": _fnFilterColumn,
12578
12579			"_fnFilter": _fnFilter,
12580
12581			"_fnBuildSearchArray": _fnBuildSearchArray,
12582
12583			"_fnBuildSearchRow": _fnBuildSearchRow,
12584
12585			"_fnFilterCreateSearch": _fnFilterCreateSearch,
12586
12587			"_fnDataToSearch": _fnDataToSearch,
12588
12589			"_fnSort": _fnSort,
12590
12591			"_fnSortAttachListener": _fnSortAttachListener,
12592
12593			"_fnSortingClasses": _fnSortingClasses,
12594
12595			"_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
12596
12597			"_fnPageChange": _fnPageChange,
12598
12599			"_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
12600
12601			"_fnUpdateInfo": _fnUpdateInfo,
12602
12603			"_fnFeatureHtmlLength": _fnFeatureHtmlLength,
12604
12605			"_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
12606
12607			"_fnProcessingDisplay": _fnProcessingDisplay,
12608
12609			"_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
12610
12611			"_fnColumnIndexToVisible": _fnColumnIndexToVisible,
12612
12613			"_fnNodeToDataIndex": _fnNodeToDataIndex,
12614
12615			"_fnVisbleColumns": _fnVisbleColumns,
12616
12617			"_fnCalculateEnd": _fnCalculateEnd,
12618
12619			"_fnConvertToWidth": _fnConvertToWidth,
12620
12621			"_fnCalculateColumnWidths": _fnCalculateColumnWidths,
12622
12623			"_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
12624
12625			"_fnGetWidestNode": _fnGetWidestNode,
12626
12627			"_fnGetMaxLenString": _fnGetMaxLenString,
12628
12629			"_fnStringToCss": _fnStringToCss,
12630
12631			"_fnDetectType": _fnDetectType,
12632
12633			"_fnSettingsFromNode": _fnSettingsFromNode,
12634
12635			"_fnGetDataMaster": _fnGetDataMaster,
12636
12637			"_fnGetTrNodes": _fnGetTrNodes,
12638
12639			"_fnGetTdNodes": _fnGetTdNodes,
12640
12641			"_fnEscapeRegex": _fnEscapeRegex,
12642
12643			"_fnDeleteIndex": _fnDeleteIndex,
12644
12645			"_fnReOrderIndex": _fnReOrderIndex,
12646
12647			"_fnColumnOrdering": _fnColumnOrdering,
12648
12649			"_fnLog": _fnLog,
12650
12651			"_fnClearTable": _fnClearTable,
12652
12653			"_fnSaveState": _fnSaveState,
12654
12655			"_fnLoadState": _fnLoadState,
12656
12657			"_fnCreateCookie": _fnCreateCookie,
12658
12659			"_fnReadCookie": _fnReadCookie,
12660
12661			"_fnDetectHeader": _fnDetectHeader,
12662
12663			"_fnGetUniqueThs": _fnGetUniqueThs,
12664
12665			"_fnScrollBarWidth": _fnScrollBarWidth,
12666
12667			"_fnApplyToChildren": _fnApplyToChildren,
12668
12669			"_fnMap": _fnMap,
12670
12671			"_fnGetRowData": _fnGetRowData,
12672
12673			"_fnGetCellData": _fnGetCellData,
12674
12675			"_fnSetCellData": _fnSetCellData,
12676
12677			"_fnGetObjectDataFn": _fnGetObjectDataFn,
12678
12679			"_fnSetObjectDataFn": _fnSetObjectDataFn,
12680
12681			"_fnApplyColumnDefs": _fnApplyColumnDefs,
12682
12683			"_fnBindAction": _fnBindAction,
12684
12685			"_fnExtend": _fnExtend,
12686
12687			"_fnCallbackReg": _fnCallbackReg,
12688
12689			"_fnCallbackFire": _fnCallbackFire,
12690
12691			"_fnJsonString": _fnJsonString,
12692
12693			"_fnRender": _fnRender,
12694
12695			"_fnNodeToColumnIndex": _fnNodeToColumnIndex,
12696
12697			"_fnInfoMacros": _fnInfoMacros,
12698
12699			"_fnBrowserDetect": _fnBrowserDetect,
12700
12701			"_fnGetColumns": _fnGetColumns
12702
12703		};
12704
12705		
12706
12707		$.extend( DataTable.ext.oApi, this.oApi );
12708
12709		
12710
12711		for ( var sFunc in DataTable.ext.oApi )
12712
12713		{
12714
12715			if ( sFunc )
12716
12717			{
12718
12719				this[sFunc] = _fnExternApiFunc(sFunc);
12720
12721			}
12722
12723		}
12724
12725		
12726
12727		
12728
12729		var _that = this;
12730
12731		this.each(function() {
12732
12733			var i=0, iLen, j, jLen, k, kLen;
12734
12735			var sId = this.getAttribute( 'id' );
12736
12737			var bInitHandedOff = false;
12738
12739			var bUsePassedData = false;
12740
12741			
12742
12743			
12744
12745			/* Sanity check */
12746
12747			if ( this.nodeName.toLowerCase() != 'table' )
12748
12749			{
12750
12751				_fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
12752
12753					"table: "+this.nodeName );
12754
12755				return;
12756
12757			}
12758
12759			
12760
12761			/* Check to see if we are re-initialising a table */
12762
12763			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
12764
12765			{
12766
12767				/* Base check on table node */
12768
12769				if ( DataTable.settings[i].nTable == this )
12770
12771				{
12772
12773					if ( oInit === undefined || oInit.bRetrieve )
12774
12775					{
12776
12777						return DataTable.settings[i].oInstance;
12778
12779					}
12780
12781					else if ( oInit.bDestroy )
12782
12783					{
12784
12785						DataTable.settings[i].oInstance.fnDestroy();
12786
12787						break;
12788
12789					}
12790
12791					else
12792
12793					{
12794
12795						_fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
12796
12797							"To retrieve the DataTables object for this table, pass no arguments or see "+
12798
12799							"the docs for bRetrieve and bDestroy" );
12800
12801						return;
12802
12803					}
12804
12805				}
12806
12807				
12808
12809				/* If the element we are initialising has the same ID as a table which was previously
12810
12811				 * initialised, but the table nodes don't match (from before) then we destroy the old
12812
12813				 * instance by simply deleting it. This is under the assumption that the table has been
12814
12815				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
12816
12817				 */
12818
12819				if ( DataTable.settings[i].sTableId == this.id )
12820
12821				{
12822
12823					DataTable.settings.splice( i, 1 );
12824
12825					break;
12826
12827				}
12828
12829			}
12830
12831			
12832
12833			/* Ensure the table has an ID - required for accessibility */
12834
12835			if ( sId === null || sId === "" )
12836
12837			{
12838
12839				sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
12840
12841				this.id = sId;
12842
12843			}
12844
12845			
12846
12847			/* Create the settings object for this table and set some of the default parameters */
12848
12849			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
12850
12851				"nTable":        this,
12852
12853				"oApi":          _that.oApi,
12854
12855				"oInit":         oInit,
12856
12857				"sDestroyWidth": $(this).width(),
12858
12859				"sInstance":     sId,
12860
12861				"sTableId":      sId
12862
12863			} );
12864
12865			DataTable.settings.push( oSettings );
12866
12867			
12868
12869			// Need to add the instance after the instance after the settings object has been added
12870
12871			// to the settings array, so we can self reference the table instance if more than one
12872
12873			oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
12874
12875			
12876
12877			/* Setting up the initialisation object */
12878
12879			if ( !oInit )
12880
12881			{
12882
12883				oInit = {};
12884
12885			}
12886
12887			
12888
12889			// Backwards compatibility, before we apply all the defaults
12890
12891			if ( oInit.oLanguage )
12892
12893			{
12894
12895				_fnLanguageCompat( oInit.oLanguage );
12896
12897			}
12898
12899			
12900
12901			oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
12902
12903			
12904
12905			// Map the initialisation options onto the settings object
12906
12907			_fnMap( oSettings.oFeatures, oInit, "bPaginate" );
12908
12909			_fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
12910
12911			_fnMap( oSettings.oFeatures, oInit, "bFilter" );
12912
12913			_fnMap( oSettings.oFeatures, oInit, "bSort" );
12914
12915			_fnMap( oSettings.oFeatures, oInit, "bInfo" );
12916
12917			_fnMap( oSettings.oFeatures, oInit, "bProcessing" );
12918
12919			_fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
12920
12921			_fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
12922
12923			_fnMap( oSettings.oFeatures, oInit, "bServerSide" );
12924
12925			_fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
12926
12927			_fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
12928
12929			_fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
12930
12931			_fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
12932
12933			_fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
12934
12935			_fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
12936
12937			_fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
12938
12939			_fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
12940
12941			_fnMap( oSettings, oInit, "asStripeClasses" );
12942
12943			_fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
12944
12945			_fnMap( oSettings, oInit, "fnServerData" );
12946
12947			_fnMap( oSettings, oInit, "fnFormatNumber" );
12948
12949			_fnMap( oSettings, oInit, "sServerMethod" );
12950
12951			_fnMap( oSettings, oInit, "aaSorting" );
12952
12953			_fnMap( oSettings, oInit, "aaSortingFixed" );
12954
12955			_fnMap( oSettings, oInit, "aLengthMenu" );
12956
12957			_fnMap( oSettings, oInit, "sPaginationType" );
12958
12959			_fnMap( oSettings, oInit, "sAjaxSource" );
12960
12961			_fnMap( oSettings, oInit, "sAjaxDataProp" );
12962
12963			_fnMap( oSettings, oInit, "iCookieDuration" );
12964
12965			_fnMap( oSettings, oInit, "sCookiePrefix" );
12966
12967			_fnMap( oSettings, oInit, "sDom" );
12968
12969			_fnMap( oSettings, oInit, "bSortCellsTop" );
12970
12971			_fnMap( oSettings, oInit, "iTabIndex" );
12972
12973			_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
12974
12975			_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
12976
12977			_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
12978
12979			_fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
12980
12981			_fnMap( oSettings, oInit, "fnCookieCallback" );
12982
12983			_fnMap( oSettings, oInit, "fnStateLoad" );
12984
12985			_fnMap( oSettings, oInit, "fnStateSave" );
12986
12987			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
12988
12989			
12990
12991			/* Callback functions which are array driven */
12992
12993			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
12994
12995			_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
12996
12997			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
12998
12999			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
13000
13001			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
13002
13003			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
13004
13005			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
13006
13007			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
13008
13009			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
13010
13011			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
13012
13013			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
13014
13015			
13016
13017			if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
13018
13019				   oSettings.oFeatures.bSortClasses )
13020
13021			{
13022
13023				/* Enable sort classes for server-side processing. Safe to do it here, since server-side
13024
13025				 * processing must be enabled by the developer
13026
13027				 */
13028
13029				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
13030
13031			}
13032
13033			else if ( oSettings.oFeatures.bDeferRender )
13034
13035			{
13036
13037				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
13038
13039			}
13040
13041			
13042
13043			if ( oInit.bJQueryUI )
13044
13045			{
13046
13047				/* Use the JUI classes object for display. You could clone the oStdClasses object if 
13048
13049				 * you want to have multiple tables with multiple independent classes 
13050
13051				 */
13052
13053				$.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
13054
13055				
13056
13057				if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
13058
13059				{
13060
13061					/* Set the DOM to use a layout suitable for jQuery UI's theming */
13062
13063					oSettings.sDom = '<"H"lfr>t<"F"ip>';
13064
13065				}
13066
13067			}
13068
13069			else
13070
13071			{
13072
13073				$.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
13074
13075			}
13076
13077			$(this).addClass( oSettings.oClasses.sTable );
13078
13079			
13080
13081			/* Calculate the scroll bar width and cache it for use later on */
13082
13083			if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
13084
13085			{
13086
13087				oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
13088
13089			}
13090
13091			
13092
13093			if ( oSettings.iInitDisplayStart === undefined )
13094
13095			{
13096
13097				/* Display start point, taking into account the save saving */
13098
13099				oSettings.iInitDisplayStart = oInit.iDisplayStart;
13100
13101				oSettings._iDisplayStart = oInit.iDisplayStart;
13102
13103			}
13104
13105			
13106
13107			/* Must be done after everything which can be overridden by a cookie! */
13108
13109			if ( oInit.bStateSave )
13110
13111			{
13112
13113				oSettings.oFeatures.bStateSave = true;
13114
13115				_fnLoadState( oSettings, oInit );
13116
13117				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
13118
13119			}
13120
13121			
13122
13123			if ( oInit.iDeferLoading !== null )
13124
13125			{
13126
13127				oSettings.bDeferLoading = true;
13128
13129				var tmp = $.isArray( oInit.iDeferLoading );
13130
13131				oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
13132
13133				oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
13134
13135			}
13136
13137			
13138
13139			if ( oInit.aaData !== null )
13140
13141			{
13142
13143				bUsePassedData = true;
13144
13145			}
13146
13147			
13148
13149			/* Language definitions */
13150
13151			if ( oInit.oLanguage.sUrl !== "" )
13152
13153			{
13154
13155				/* Get the language definitions from a file - because this Ajax call makes the language
13156
13157				 * get async to the remainder of this function we use bInitHandedOff to indicate that 
13158
13159				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
13160
13161				 */
13162
13163				oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
13164
13165				$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
13166
13167					_fnLanguageCompat( json );
13168
13169					$.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
13170
13171					_fnInitialise( oSettings );
13172
13173				} );
13174
13175				bInitHandedOff = true;
13176
13177			}
13178
13179			else
13180
13181			{
13182
13183				$.extend( true, oSettings.oLanguage, oInit.oLanguage );
13184
13185			}
13186
13187			
13188
13189			
13190
13191			/*
13192
13193			 * Stripes
13194
13195			 */
13196
13197			if ( oInit.asStripeClasses === null )
13198
13199			{
13200
13201				oSettings.asStripeClasses =[
13202
13203					oSettings.oClasses.sStripeOdd,
13204
13205					oSettings.oClasses.sStripeEven
13206
13207				];
13208
13209			}
13210
13211			
13212
13213			/* Remove row stripe classes if they are already on the table row */
13214
13215			iLen=oSettings.asStripeClasses.length;
13216
13217			oSettings.asDestroyStripes = [];
13218
13219			if (iLen)
13220
13221			{
13222
13223				var bStripeRemove = false;
13224
13225				var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')');
13226
13227				for ( i=0 ; i<iLen ; i++ )
13228
13229				{
13230
13231					if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )
13232
13233					{
13234
13235						bStripeRemove = true;
13236
13237						
13238
13239						/* Store the classes which we are about to remove so they can be re-added on destroy */
13240
13241						oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] );
13242
13243					}
13244
13245				}
13246
13247				
13248
13249				if ( bStripeRemove )
13250
13251				{
13252
13253					anRows.removeClass( oSettings.asStripeClasses.join(' ') );
13254
13255				}
13256
13257			}
13258
13259			
13260
13261			/*
13262
13263			 * Columns
13264
13265			 * See if we should load columns automatically or use defined ones
13266
13267			 */
13268
13269			var anThs = [];
13270
13271			var aoColumnsInit;
13272
13273			var nThead = this.getElementsByTagName('thead');
13274
13275			if ( nThead.length !== 0 )
13276
13277			{
13278
13279				_fnDetectHeader( oSettings.aoHeader, nThead[0] );
13280
13281				anThs = _fnGetUniqueThs( oSettings );
13282
13283			}
13284
13285			
13286
13287			/* If not given a column array, generate one with nulls */
13288
13289			if ( oInit.aoColumns === null )
13290
13291			{
13292
13293				aoColumnsInit = [];
13294
13295				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
13296
13297				{
13298
13299					aoColumnsInit.push( null );
13300
13301				}
13302
13303			}
13304
13305			else
13306
13307			{
13308
13309				aoColumnsInit = oInit.aoColumns;
13310
13311			}
13312
13313			
13314
13315			/* Add the columns */
13316
13317			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
13318
13319			{
13320
13321				/* Short cut - use the loop to check if we have column visibility state to restore */
13322
13323				if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
13324
13325				{
13326
13327					if ( aoColumnsInit[i] === null )
13328
13329					{
13330
13331						aoColumnsInit[i] = {};
13332
13333					}
13334
13335					aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
13336
13337				}
13338
13339				
13340
13341				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
13342
13343			}
13344
13345			
13346
13347			/* Apply the column definitions */
13348
13349			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
13350
13351				_fnColumnOptions( oSettings, iCol, oDef );
13352
13353			} );
13354
13355			
13356
13357			
13358
13359			/*
13360
13361			 * Sorting
13362
13363			 * Check the aaSorting array
13364
13365			 */
13366
13367			for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
13368
13369			{
13370
13371				if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
13372
13373				{
13374
13375					oSettings.aaSorting[i][0] = 0;
13376
13377				}
13378
13379				var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
13380
13381				
13382
13383				/* Add a default sorting index */
13384
13385				if ( oSettings.aaSorting[i][2] === undefined )
13386
13387				{
13388
13389					oSettings.aaSorting[i][2] = 0;
13390
13391				}
13392
13393				
13394
13395				/* If aaSorting is not defined, then we use the first indicator in asSorting */
13396
13397				if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
13398
13399				{
13400
13401					oSettings.aaSorting[i][1] = oColumn.asSorting[0];
13402
13403				}
13404
13405				
13406
13407				/* Set the current sorting index based on aoColumns.asSorting */
13408
13409				for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
13410
13411				{
13412
13413					if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
13414
13415					{
13416
13417						oSettings.aaSorting[i][2] = j;
13418
13419						break;
13420
13421					}
13422
13423				}
13424
13425			}
13426
13427				
13428
13429			/* Do a first pass on the sorting classes (allows any size changes to be taken into
13430
13431			 * account, and also will apply sorting disabled classes if disabled
13432
13433			 */
13434
13435			_fnSortingClasses( oSettings );
13436
13437			
13438
13439			
13440
13441			/*
13442
13443			 * Final init
13444
13445			 * Cache the header, body and footer as required, creating them if needed
13446
13447			 */
13448
13449			
13450
13451			/* Browser support detection */
13452
13453			_fnBrowserDetect( oSettings );
13454
13455			
13456
13457			// Work around for Webkit bug 83867 - store the caption-side before removing from doc
13458
13459			var captions = $(this).children('caption').each( function () {
13460
13461				this._captionSide = $(this).css('caption-side');
13462
13463			} );
13464
13465			
13466
13467			var thead = $(this).children('thead');
13468
13469			if ( thead.length === 0 )
13470
13471			{
13472
13473				thead = [ document.createElement( 'thead' ) ];
13474
13475				this.appendChild( thead[0] );
13476
13477			}
13478
13479			oSettings.nTHead = thead[0];
13480
13481			
13482
13483			var tbody = $(this).children('tbody');
13484
13485			if ( tbody.length === 0 )
13486
13487			{
13488
13489				tbody = [ document.createElement( 'tbody' ) ];
13490
13491				this.appendChild( tbody[0] );
13492
13493			}
13494
13495			oSettings.nTBody = tbody[0];
13496
13497			oSettings.nTBody.setAttribute( "role", "alert" );
13498
13499			oSettings.nTBody.setAttribute( "aria-live", "polite" );
13500
13501			oSettings.nTBody.setAttribute( "aria-relevant", "all" );
13502
13503			
13504
13505			var tfoot = $(this).children('tfoot');
13506
13507			if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
13508
13509			{
13510
13511				// If we are a scrolling table, and no footer has been given, then we need to create
13512
13513				// a tfoot element for the caption element to be appended to
13514
13515				tfoot = [ document.createElement( 'tfoot' ) ];
13516
13517				this.appendChild( tfoot[0] );
13518
13519			}
13520
13521			
13522
13523			if ( tfoot.length > 0 )
13524
13525			{
13526
13527				oSettings.nTFoot = tfoot[0];
13528
13529				_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
13530
13531			}
13532
13533			
13534
13535			/* Check if there is data passing into the constructor */
13536
13537			if ( bUsePassedData )
13538
13539			{
13540
13541				for ( i=0 ; i<oInit.aaData.length ; i++ )
13542
13543				{
13544
13545					_fnAddData( oSettings, oInit.aaData[ i ] );
13546
13547				}
13548
13549			}
13550
13551			else
13552
13553			{
13554
13555				/* Grab the data from the page */
13556
13557				_fnGatherData( oSettings );
13558
13559			}
13560
13561			
13562
13563			/* Copy the data index array */
13564
13565			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
13566
13567			
13568
13569			/* Initialisation complete - table can be drawn */
13570
13571			oSettings.bInitialised = true;
13572
13573			
13574
13575			/* Check if we need to initialise the table (it might not have been handed off to the
13576
13577			 * language processor)
13578
13579			 */
13580
13581			if ( bInitHandedOff === false )
13582
13583			{
13584
13585				_fnInitialise( oSettings );
13586
13587			}
13588
13589		} );
13590
13591		_that = null;
13592
13593		return this;
13594
13595	};
13596
13597
13598
13599	
13600
13601	
13602
13603	/**
13604
13605	 * Provide a common method for plug-ins to check the version of DataTables being used, in order
13606
13607	 * to ensure compatibility.
13608
13609	 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
13610
13611	 *    formats "X" and "X.Y" are also acceptable.
13612
13613	 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
13614
13615	 *    version, or false if this version of DataTales is not suitable
13616
13617	 *  @static
13618
13619	 *  @dtopt API-Static
13620
13621	 *
13622
13623	 *  @example
13624
13625	 *    alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
13626
13627	 */
13628
13629	DataTable.fnVersionCheck = function( sVersion )
13630
13631	{
13632
13633		/* This is cheap, but effective */
13634
13635		var fnZPad = function (Zpad, count)
13636
13637		{
13638
13639			while(Zpad.length < count) {
13640
13641				Zpad += '0';
13642
13643			}
13644
13645			return Zpad;
13646
13647		};
13648
13649		var aThis = DataTable.ext.sVersion.split('.');
13650
13651		var aThat = sVersion.split('.');
13652
13653		var sThis = '', sThat = '';
13654
13655		
13656
13657		for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
13658
13659		{
13660
13661			sThis += fnZPad( aThis[i], 3 );
13662
13663			sThat += fnZPad( aThat[i], 3 );
13664
13665		}
13666
13667		
13668
13669		return parseInt(sThis, 10) >= parseInt(sThat, 10);
13670
13671	};
13672
13673	
13674
13675	
13676
13677	/**
13678
13679	 * Check if a TABLE node is a DataTable table already or not.
13680
13681	 *  @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
13682
13683	 *    node types can be passed in, but will always return false).
13684
13685	 *  @returns {boolean} true the table given is a DataTable, or false otherwise
13686
13687	 *  @static
13688
13689	 *  @dtopt API-Static
13690
13691	 *
13692
13693	 *  @example
13694
13695	 *    var ex = document.getElementById('example');
13696
13697	 *    if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
13698
13699	 *      $(ex).dataTable();
13700
13701	 *    }
13702
13703	 */
13704
13705	DataTable.fnIsDataTable = function ( nTable )
13706
13707	{
13708
13709		var o = DataTable.settings;
13710
13711	
13712
13713		for ( var i=0 ; i<o.length ; i++ )
13714
13715		{
13716
13717			if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )
13718
13719			{
13720
13721				return true;
13722
13723			}
13724
13725		}
13726
13727	
13728
13729		return false;
13730
13731	};
13732
13733	
13734
13735	
13736
13737	/**
13738
13739	 * Get all DataTable tables that have been initialised - optionally you can select to
13740
13741	 * get only currently visible tables.
13742
13743	 *  @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or 
13744
13745	 *    visible tables only.
13746
13747	 *  @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables
13748
13749	 *  @static
13750
13751	 *  @dtopt API-Static
13752
13753	 *
13754
13755	 *  @example
13756
13757	 *    var table = $.fn.dataTable.fnTables(true);
13758
13759	 *    if ( table.length > 0 ) {
13760
13761	 *      $(table).dataTable().fnAdjustColumnSizing();
13762
13763	 *    }
13764
13765	 */
13766
13767	DataTable.fnTables = function ( bVisible )
13768
13769	{
13770
13771		var out = [];
13772
13773	
13774
13775		jQuery.each( DataTable.settings, function (i, o) {
13776
13777			if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
13778
13779			{
13780
13781				out.push( o.nTable );
13782
13783			}
13784
13785		} );
13786
13787	
13788
13789		return out;
13790
13791	};
13792
13793	
13794
13795
13796
13797	/**
13798
13799	 * Version string for plug-ins to check compatibility. Allowed format is
13800
13801	 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
13802
13803	 * e are optional
13804
13805	 *  @member
13806
13807	 *  @type string
13808
13809	 *  @default Version number
13810
13811	 */
13812
13813	DataTable.version = "1.9.4";
13814
13815
13816
13817	/**
13818
13819	 * Private data store, containing all of the settings objects that are created for the
13820
13821	 * tables on a given page.
13822
13823	 * 
13824
13825	 * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i> 
13826
13827	 * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
13828
13829	 *  @member
13830
13831	 *  @type array
13832
13833	 *  @default []
13834
13835	 *  @private
13836
13837	 */
13838
13839	DataTable.settings = [];
13840
13841
13842
13843	/**
13844
13845	 * Object models container, for the various models that DataTables has available
13846
13847	 * to it. These models define the objects that are used to hold the active state 
13848
13849	 * and configuration of the table.
13850
13851	 *  @namespace
13852
13853	 */
13854
13855	DataTable.models = {};
13856
13857	
13858
13859	
13860
13861	/**
13862
13863	 * DataTables extension options and plug-ins. This namespace acts as a collection "area"
13864
13865	 * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
13866
13867	 * of the build in methods use this method to provide their own capabilities (sorting methods
13868
13869	 * for example).
13870
13871	 * 
13872
13873	 * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
13874
13875	 * and modified by plug-ins.
13876
13877	 *  @namespace
13878
13879	 */
13880
13881	DataTable.models.ext = {
13882
13883		/**
13884
13885		 * Plug-in filtering functions - this method of filtering is complimentary to the default
13886
13887		 * type based filtering, and a lot more comprehensive as it allows you complete control
13888
13889		 * over the filtering logic. Each element in this array is a function (parameters
13890
13891		 * described below) that is called for every row in the table, and your logic decides if
13892
13893		 * it should be included in the filtered data set or not.
13894
13895		 *   <ul>
13896
13897		 *     <li>
13898
13899		 *       Function input parameters:
13900
13901		 *       <ul>
13902
13903		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
13904
13905		 *         <li>{array|object} Data for the row to be processed (same as the original format
13906
13907		 *           that was passed in as the data source, or an array from a DOM data source</li>
13908
13909		 *         <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
13910
13911		 *           be useful to retrieve the TR element if you need DOM interaction.</li>
13912
13913		 *       </ul>
13914
13915		 *     </li>
13916
13917		 *     <li>
13918
13919		 *       Function return:
13920
13921		 *       <ul>
13922
13923		 *         <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
13924
13925		 *       </ul>
13926
13927		 *     </il>
13928
13929		 *   </ul>
13930
13931		 *  @type array
13932
13933		 *  @default []
13934
13935		 *
13936
13937		 *  @example
13938
13939		 *    // The following example shows custom filtering being applied to the fourth column (i.e.
13940
13941		 *    // the aData[3] index) based on two input values from the end-user, matching the data in 
13942
13943		 *    // a certain range.
13944
13945		 *    $.fn.dataTableExt.afnFiltering.push(
13946
13947		 *      function( oSettings, aData, iDataIndex ) {
13948
13949		 *        var iMin = document.getElementById('min').value * 1;
13950
13951		 *        var iMax = document.getElementById('max').value * 1;
13952
13953		 *        var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
13954
13955		 *        if ( iMin == "" && iMax == "" ) {
13956
13957		 *          return true;
13958
13959		 *        }
13960
13961		 *        else if ( iMin == "" && iVersion < iMax ) {
13962
13963		 *          return true;
13964
13965		 *        }
13966
13967		 *        else if ( iMin < iVersion && "" == iMax ) {
13968
13969		 *          return true;
13970
13971		 *        }
13972
13973		 *        else if ( iMin < iVersion && iVersion < iMax ) {
13974
13975		 *          return true;
13976
13977		 *        }
13978
13979		 *        return false;
13980
13981		 *      }
13982
13983		 *    );
13984
13985		 */
13986
13987		"afnFiltering": [],
13988
13989	
13990
13991	
13992
13993		/**
13994
13995		 * Plug-in sorting functions - this method of sorting is complimentary to the default type
13996
13997		 * based sorting that DataTables does automatically, allowing much greater control over the
13998
13999		 * the data that is being used to sort a column. This is useful if you want to do sorting
14000
14001		 * based on live data (for example the contents of an 'input' element) rather than just the
14002
14003		 * static string that DataTables knows of. The way these plug-ins work is that you create
14004
14005		 * an array of the values you wish to be sorted for the column in question and then return
14006
14007		 * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
14008
14009		 * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort 
14010
14011		 * data.
14012
14013		 *   <ul>
14014
14015	     *     <li>
14016
14017	     *       Function input parameters:
14018
14019	     *       <ul>
14020
14021		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
14022
14023	     *         <li>{int} Target column index</li>
14024
14025	     *       </ul>
14026
14027	     *     </li>
14028
14029		 *     <li>
14030
14031		 *       Function return:
14032
14033		 *       <ul>
14034
14035		 *         <li>{array} Data for the column to be sorted upon</li>
14036
14037		 *       </ul>
14038
14039		 *     </il>
14040
14041		 *   </ul>
14042
14043		 *  
14044
14045		 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
14046
14047		 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
14048
14049		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
14050
14051		 * prepare the data as required for the different types. As such, this method is deprecated.
14052
14053		 *  @type array
14054
14055		 *  @default []
14056
14057		 *  @deprecated
14058
14059		 *
14060
14061		 *  @example
14062
14063		 *    // Updating the cached sorting information with user entered values in HTML input elements
14064
14065		 *    jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
14066
14067		 *    {
14068
14069		 *      var aData = [];
14070
14071		 *      $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
14072
14073		 *        aData.push( this.value );
14074
14075		 *      } );
14076
14077		 *      return aData;
14078
14079		 *    }
14080
14081		 */
14082
14083		"afnSortData": [],
14084
14085	
14086
14087	
14088
14089		/**
14090
14091		 * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
14092
14093		 * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
14094
14095		 * option. As such, each feature plug-in must describe a function that is used to initialise
14096
14097		 * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
14098
14099		 * of the feature (sFeature). Thus the objects attached to this method must provide:
14100
14101		 *   <ul>
14102
14103		 *     <li>{function} fnInit Initialisation of the plug-in
14104
14105		 *       <ul>
14106
14107	     *         <li>
14108
14109	     *           Function input parameters:
14110
14111	     *           <ul>
14112
14113		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
14114
14115	     *           </ul>
14116
14117	     *         </li>
14118
14119		 *         <li>
14120
14121		 *           Function return:
14122
14123		 *           <ul>
14124
14125		 *             <li>{node|null} The element which contains your feature. Note that the return
14126
14127		 *                may al
14127so be void if your plug-in does not require to inject any DOM elements 
14128
14129		 *                into DataTables control (sDom) - for example this might be useful when 
14130
14131		 *                developing a plug-in which allows table control via keyboard entry.</li>
14132
14133		 *           </ul>
14134
14135		 *         </il>
14136
14137		 *       </ul>
14138
14139		 *     </li>
14140
14141		 *     <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
14142
14143		 *     <li>{string} sFeature Feature name</li>
14144
14145		 *   </ul>
14146
14147		 *  @type array
14148
14149		 *  @default []
14150
14151		 * 
14152
14153		 *  @example
14154
14155		 *    // How TableTools initialises itself.
14156
14157		 *    $.fn.dataTableExt.aoFeatures.push( {
14158
14159		 *      "fnInit": function( oSettings ) {
14160
14161		 *        return new TableTools( { "oDTSettings": oSettings } );
14162
14163		 *      },
14164
14165		 *      "cFeature": "T",
14166
14167		 *      "sFeature": "TableTools"
14168
14169		 *    } );
14170
14171		 */
14172
14173		"aoFeatures": [],
14174
14175	
14176
14177	
14178
14179		/**
14180
14181		 * Type detection plug-in functions - DataTables utilises types to define how sorting and
14182
14183		 * filtering behave, and types can be either  be defined by the developer (sType for the
14184
14185		 * column) or they can be automatically detected by the methods in this array. The functions
14186
14187		 * defined in the array are quite simple, taking a single parameter (the data to analyse) 
14188
14189		 * and returning the type if it is a known type, or null otherwise.
14190
14191		 *   <ul>
14192
14193	     *     <li>
14194
14195	     *       Function input parameters:
14196
14197	     *       <ul>
14198
14199		 *         <li>{*} Data from the column cell to be analysed</li>
14200
14201	     *       </ul>
14202
14203	     *     </li>
14204
14205		 *     <li>
14206
14207		 *       Function return:
14208
14209		 *       <ul>
14210
14211		 *         <li>{string|null} Data type detected, or null if unknown (and thus pass it
14212
14213		 *           on to the other type detection functions.</li>
14214
14215		 *       </ul>
14216
14217		 *     </il>
14218
14219		 *   </ul>
14220
14221		 *  @type array
14222
14223		 *  @default []
14224
14225		 *  
14226
14227		 *  @example
14228
14229		 *    // Currency type detection plug-in:
14230
14231		 *    jQuery.fn.dataTableExt.aTypes.push(
14232
14233		 *      function ( sData ) {
14234
14235		 *        var sValidChars = "0123456789.-";
14236
14237		 *        var Char;
14238
14239		 *        
14240
14241		 *        // Check the numeric part
14242
14243		 *        for ( i=1 ; i<sData.length ; i++ ) {
14244
14245		 *          Char = sData.charAt(i); 
14246
14247		 *          if (sValidChars.indexOf(Char) == -1) {
14248
14249		 *            return null;
14250
14251		 *          }
14252
14253		 *        }
14254
14255		 *        
14256
14257		 *        // Check prefixed by currency
14258
14259		 *        if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {
14260
14261		 *          return 'currency';
14262
14263		 *        }
14264
14265		 *        return null;
14266
14267		 *      }
14268
14269		 *    );
14270
14271		 */
14272
14273		"aTypes": [],
14274
14275	
14276
14277	
14278
14279		/**
14280
14281		 * Provide a common method for plug-ins to check the version of DataTables being used, 
14282
14283		 * in order to ensure compatibility.
14284
14285		 *  @type function
14286
14287		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note 
14288
14289		 *    that the formats "X" and "X.Y" are also acceptable.
14290
14291		 *  @returns {boolean} true if this version of DataTables is greater or equal to the 
14292
14293		 *    required version, or false if this version of DataTales is not suitable
14294
14295		 *
14296
14297		 *  @example
14298
14299		 *    $(document).ready(function() {
14300
14301		 *      var oTable = $('#example').dataTable();
14302
14303		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
14304
14305		 *    } );
14306
14307		 */
14308
14309		"fnVersionCheck": DataTable.fnVersionCheck,
14310
14311	
14312
14313	
14314
14315		/**
14316
14317		 * Index for what 'this' index API functions should use
14318
14319		 *  @type int
14320
14321		 *  @default 0
14322
14323		 */
14324
14325		"iApiIndex": 0,
14326
14327	
14328
14329	
14330
14331		/**
14332
14333		 * Pre-processing of filtering data plug-ins - When you assign the sType for a column
14334
14335		 * (or have it automatically detected for you by DataTables or a type detection plug-in), 
14336
14337		 * you will typically be using this for custom sorting, but it can also be used to provide 
14338
14339		 * custom filtering by allowing you to pre-processing the data and returning the data in
14340
14341		 * the format that should be filtered upon. This is done by adding functions this object 
14342
14343		 * with a parameter name which matches the sType for that target column. This is the
14344
14345		 * corollary of <i>afnSortData</i> for filtering data.
14346
14347		 *   <ul>
14348
14349	     *     <li>
14350
14351	     *       Function input parameters:
14352
14353	     *       <ul>
14354
14355		 *         <li>{*} Data from the column cell to be prepared for filtering</li>
14356
14357	     *       </ul>
14358
14359	     *     </li>
14360
14361		 *     <li>
14362
14363		 *       Function return:
14364
14365		 *       <ul>
14366
14367		 *         <li>{string|null} Formatted string that will be used for the filtering.</li>
14368
14369		 *       </ul>
14370
14371		 *     </il>
14372
14373		 *   </ul>
14374
14375		 * 
14376
14377		 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
14378
14379		 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
14380
14381		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
14382
14383		 * prepare the data as required for the different types. As such, this method is deprecated.
14384
14385		 *  @type object
14386
14387		 *  @default {}
14388
14389		 *  @deprecated
14390
14391		 *
14392
14393		 *  @example
14394
14395		 *    $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
14396
14397		 *      return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
14398
14399		 *    }
14400
14401		 */
14402
14403		"ofnSearch": {},
14404
14405	
14406
14407	
14408
14409		/**
14410
14411		 * Container for all private functions in DataTables so they can be exposed externally
14412
14413		 *  @type object
14414
14415		 *  @default {}
14416
14417		 */
14418
14419		"oApi": {},
14420
14421	
14422
14423	
14424
14425		/**
14426
14427		 * Storage for the various classes that DataTables uses
14428
14429		 *  @type object
14430
14431		 *  @default {}
14432
14433		 */
14434
14435		"oStdClasses": {},
14436
14437		
14438
14439	
14440
14441		/**
14442
14443		 * Storage for the various classes that DataTables uses - jQuery UI suitable
14444
14445		 *  @type object
14446
14447		 *  @default {}
14448
14449		 */
14450
14451		"oJUIClasses": {},
14452
14453	
14454
14455	
14456
14457		/**
14458
14459		 * Pagination plug-in methods - The style and controls of the pagination can significantly 
14460
14461		 * impact on how the end user interacts with the data in your table, and DataTables allows 
14462
14463		 * the addition of pagination controls by extending this object, which can then be enabled
14464
14465		 * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
14466
14467		 * is added is an object (the property name of which is what <i>sPaginationType</i> refers
14468
14469		 * to) that has two properties, both methods that are used by DataTables to update the
14470
14471		 * control's state.
14472
14473		 *   <ul>
14474
14475		 *     <li>
14476
14477		 *       fnInit -  Initialisation of the paging controls. Called only during initialisation 
14478
14479		 *         of the table. It is expected that this function will add the required DOM elements 
14480
14481		 *         to the page for the paging controls to work. The element pointer 
14482
14483		 *         'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging 
14484
14485		 *         controls (note that this is a 2D array to allow for multiple instances of each 
14486
14487		 *         DataTables DOM element). It is suggested that you add the controls to this element 
14488
14489		 *         as children
14490
14491		 *       <ul>
14492
14493	     *         <li>
14494
14495	     *           Function input parameters:
14496
14497	     *           <ul>
14498
14499		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
14500
14501		 *             <li>{node} Container into which the pagination controls must be inserted</li>
14502
14503		 *             <li>{function} Draw callback function - whenever the controls cause a page
14504
14505		 *               change, this method must be called to redraw the table.</li>
14506
14507	     *           </ul>
14508
14509	     *         </li>
14510
14511		 *         <li>
14512
14513		 *           Function return:
14514
14515		 *           <ul>
14516
14517		 *             <li>No return required</li>
14518
14519		 *           </ul>
14520
14521		 *         </il>
14522
14523		 *       </ul>
14524
14525		 *     </il>
14526
14527		 *     <li>
14528
14529		 *       fnInit -  This function is called whenever the paging status of the table changes and is
14530
14531		 *         typically used to update classes and/or text of the paging controls to reflex the new 
14532
14533		 *         status.
14534
14535		 *       <ul>
14536
14537	     *         <li>
14538
14539	     *           Function input parameters:
14540
14541	     *           <ul>
14542
14543		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
14544
14545		 *             <li>{function} Draw callback function - in case you need to redraw the table again
14546
14547		 *               or attach new event listeners</li>
14548
14549	     *           </ul>
14550
14551	     *         </li>
14552
14553		 *         <li>
14554
14555		 *           Function return:
14556
14557		 *           <ul>
14558
14559		 *             <li>No return required</li>
14560
14561		 *           </ul>
14562
14563		 *         </il>
14564
14565		 *       </ul>
14566
14567		 *     </il>
14568
14569		 *   </ul>
14570
14571		 *  @type object
14572
14573		 *  @default {}
14574
14575		 *
14576
14577		 *  @example
14578
14579		 *    $.fn.dataTableExt.oPagination.four_button = {
14580
14581		 *      "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
14582
14583		 *        nFirst = document.createElement( 'span' );
14584
14585		 *        nPrevious = document.createElement( 'span' );
14586
14587		 *        nNext = document.createElement( 'span' );
14588
14589		 *        nLast = document.createElement( 'span' );
14590
14591		 *        
14592
14593		 *        nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
14594
14595		 *        nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
14596
14597		 *        nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
14598
14599		 *        nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
14600
14601		 *        
14602
14603		 *        nFirst.className = "paginate_button first";
14604
14605		 *        nPrevious.className = "paginate_button previous";
14606
14607		 *        nNext.className="paginate_button next";
14608
14609		 *        nLast.className = "paginate_button last";
14610
14611		 *        
14612
14613		 *        nPaging.appendChild( nFirst );
14614
14615		 *        nPaging.appendChild( nPrevious );
14616
14617		 *        nPaging.appendChild( nNext );
14618
14619		 *        nPaging.appendChild( nLast );
14620
14621		 *        
14622
14623		 *        $(nFirst).click( function () {
14624
14625		 *          oSettings.oApi._fnPageChange( oSettings, "first" );
14626
14627		 *          fnCallbackDraw( oSettings );
14628
14629		 *        } );
14630
14631		 *        
14632
14633		 *        $(nPrevious).click( function() {
14634
14635		 *          oSettings.oApi._fnPageChange( oSettings, "previous" );
14636
14637		 *          fnCallbackDraw( oSettings );
14638
14639		 *        } );
14640
14641		 *        
14642
14643		 *        $(nNext).click( function() {
14644
14645		 *          oSettings.oApi._fnPageChange( oSettings, "next" );
14646
14647		 *          fnCallbackDraw( oSettings );
14648
14649		 *        } );
14650
14651		 *        
14652
14653		 *        $(nLast).click( function() {
14654
14655		 *          oSettings.oApi._fnPageChange( oSettings, "last" );
14656
14657		 *          fnCallbackDraw( oSettings );
14658
14659		 *        } );
14660
14661		 *        
14662
14663		 *        $(nFirst).bind( 'selectstart', function () { return false; } );
14664
14665		 *        $(nPrevious).bind( 'selectstart', function () { return false; } );
14666
14667		 *        $(nNext).bind( 'selectstart', function () { return false; } );
14668
14669		 *        $(nLast).bind( 'selectstart', function () { return false; } );
14670
14671		 *      },
14672
14673		 *      
14674
14675		 *      "fnUpdate": function ( oSettings, fnCallbackDraw ) {
14676
14677		 *        if ( !oSettings.aanFeatures.p ) {
14678
14679		 *          return;
14680
14681		 *        }
14682
14683		 *        
14684
14685		 *        // Loop over each instance of the pager
14686
14687		 *        var an = oSettings.aanFeatures.p;
14688
14689		 *        for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
14690
14691		 *          var buttons = an[i].getElementsByTagName('span');
14692
14693		 *          if ( oSettings._iDisplayStart === 0 ) {
14694
14695		 *            buttons[0].className = "paginate_disabled_previous";
14696
14697		 *            buttons[1].className = "paginate_disabled_previous";
14698
14699		 *          }
14700
14701		 *          else {
14702
14703		 *            buttons[0].className = "paginate_enabled_previous";
14704
14705		 *            buttons[1].className = "paginate_enabled_previous";
14706
14707		 *          }
14708
14709		 *          
14710
14711		 *          if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
14712
14713		 *            buttons[2].className = "paginate_disabled_next";
14714
14715		 *            buttons[3].className = "paginate_disabled_next";
14716
14717		 *          }
14718
14719		 *          else {
14720
14721		 *            buttons[2].className = "paginate_enabled_next";
14722
14723		 *            buttons[3].className = "paginate_enabled_next";
14724
14725		 *          }
14726
14727		 *        }
14728
14729		 *      }
14730
14731		 *    };
14732
14733		 */
14734
14735		"oPagination": {},
14736
14737	
14738
14739	
14740
14741		/**
14742
14743		 * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
14744
14745		 * data column (you can add your own type detection functions, or override automatic 
14746
14747		 * detection using sType). With this specific type given to the column, DataTables will 
14748
14749		 * apply the required sort from the functions in the object. Each sort type must provide
14750
14751		 * two mandatory methods, one each for ascending and descending sorting, and can optionally
14752
14753		 * provide a pre-formatting method that will help speed up sorting by allowing DataTables
14754
14755		 * to pre-format the sort data only once (rather than every time the actual sort functions
14756
14757		 * are run). The two sorting functions are typical Javascript sort methods:
14758
14759		 *   <ul>
14760
14761	     *     <li>
14762
14763	     *       Function input parameters:
14764
14765	     *       <ul>
14766
14767		 *         <li>{*} Data to compare to the second parameter</li>
14768
14769		 *         <li>{*} Data to compare to the first parameter</li>
14770
14771	     *       </ul>
14772
14773	     *     </li>
14774
14775		 *     <li>
14776
14777		 *       Function return:
14778
14779		 *       <ul>
14780
14781		 *         <li>{int} Sorting match: <0 if first parameter should be sorted lower than
14782
14783		 *           the second parameter, ===0 if the two parameters are equal and >0 if
14784
14785		 *           the first parameter should be sorted height than the second parameter.</li>
14786
14787		 *       </ul>
14788
14789		 *     </il>
14790
14791		 *   </ul>
14792
14793		 *  @type object
14794
14795		 *  @default {}
14796
14797		 *
14798
14799		 *  @example
14800
14801		 *    // Case-sensitive string sorting, with no pre-formatting method
14802
14803		 *    $.extend( $.fn.dataTableExt.oSort, {
14804
14805		 *      "string-case-asc": function(x,y) {
14806
14807		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14808
14809		 *      },
14810
14811		 *      "string-case-desc": function(x,y) {
14812
14813		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14814
14815		 *      }
14816
14817		 *    } );
14818
14819		 *
14820
14821		 *  @example
14822
14823		 *    // Case-insensitive string sorting, with pre-formatting
14824
14825		 *    $.extend( $.fn.dataTableExt.oSort, {
14826
14827		 *      "string-pre": function(x) {
14828
14829		 *        return x.toLowerCase();
14830
14831		 *      },
14832
14833		 *      "string-asc": function(x,y) {
14834
14835		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14836
14837		 *      },
14838
14839		 *      "string-desc": function(x,y) {
14840
14841		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14842
14843		 *      }
14844
14845		 *    } );
14846
14847		 */
14848
14849		"oSort": {},
14850
14851	
14852
14853	
14854
14855		/**
14856
14857		 * Version string for plug-ins to check compatibility. Allowed format is
14858
14859		 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
14860
14861		 * e are optional
14862
14863		 *  @type string
14864
14865		 *  @default Version number
14866
14867		 */
14868
14869		"sVersion": DataTable.version,
14870
14871	
14872
14873	
14874
14875		/**
14876
14877		 * How should DataTables report an error. Can take the value 'alert' or 'throw'
14878
14879		 *  @type string
14880
14881		 *  @default alert
14882
14883		 */
14884
14885		"sErrMode": "alert",
14886
14887	
14888
14889	
14890
14891		/**
14892
14893		 * Store information for DataTables to access globally about other instances
14894
14895		 *  @namespace
14896
14897		 *  @private
14898
14899		 */
14900
14901		"_oExternConfig": {
14902
14903			/* int:iNextUnique - next unique number for an instance */
14904
14905			"iNextUnique": 0
14906
14907		}
14908
14909	};
14910
14911	
14912
14913	
14914
14915	
14916
14917	
14918
14919	/**
14920
14921	 * Template object for the way in which DataTables holds information about
14922
14923	 * search information for the global filter and individual column filters.
14924
14925	 *  @namespace
14926
14927	 */
14928
14929	DataTable.models.oSearch = {
14930
14931		/**
14932
14933		 * Flag to indicate if the filtering should be case insensitive or not
14934
14935		 *  @type boolean
14936
14937		 *  @default true
14938
14939		 */
14940
14941		"bCaseInsensitive": true,
14942
14943	
14944
14945		/**
14946
14947		 * Applied search term
14948
14949		 *  @type string
14950
14951		 *  @default <i>Empty string</i>
14952
14953		 */
14954
14955		"sSearch": "",
14956
14957	
14958
14959		/**
14960
14961		 * Flag to indicate if the search term should be interpreted as a
14962
14963		 * regular expression (true) or not (false) and therefore and special
14964
14965		 * regex characters escaped.
14966
14967		 *  @type boolean
14968
14969		 *  @default false
14970
14971		 */
14972
14973		"bRegex": false,
14974
14975	
14976
14977		/**
14978
14979		 * Flag to indicate if DataTables is to use its smart filtering or not.
14980
14981		 *  @type boolean
14982
14983		 *  @default true
14984
14985		 */
14986
14987		"bSmart": true
14988
14989	};
14990
14991	
14992
14993	
14994
14995	
14996
14997	
14998
14999	/**
15000
15001	 * Template object for the way in which DataTables holds information about
15002
15003	 * each individual row. This is the object format used for the settings 
15004
15005	 * aoData array.
15006
15007	 *  @namespace
15008
15009	 */
15010
15011	DataTable.models.oRow = {
15012
15013		/**
15014
15015		 * TR element for the row
15016
15017		 *  @type node
15018
15019		 *  @default null
15020
15021		 */
15022
15023		"nTr": null,
15024
15025	
15026
15027		/**
15028
15029		 * Data object from the original data source for the row. This is either
15030
15031		 * an array if using the traditional form of DataTables, or an object if
15032
15033		 * using mData options. The exact type will depend on the passed in
15034
15035		 * data from the data source, or will be an array if using DOM a data 
15036
15037		 * source.
15038
15039		 *  @type array|object
15040
15041		 *  @default []
15042
15043		 */
15044
15045		"_aData": [],
15046
15047	
15048
15049		/**
15050
15051		 * Sorting data cache - this array is ostensibly the same length as the
15052
15053		 * number of columns (although each index is generated only as it is 
15054
15055		 * needed), and holds the data that is used for sorting each column in the
15056
15057		 * row. We do this cache generation at the start of the sort in order that
15058
15059		 * the formatting of the sort data need be done only once for each cell
15060
15061		 * per sort. This array should not be read from or written to by anything
15062
15063		 * other than the master sorting methods.
15064
15065		 *  @type array
15066
15067		 *  @default []
15068
15069		 *  @private
15070
15071		 */
15072
15073		"_aSortData": [],
15074
15075	
15076
15077		/**
15078
15079		 * Array of TD elements that are cached for hidden rows, so they can be
15080
15081		 * reinserted into the table if a column is made visible again (or to act
15082
15083		 * as a store if a column is made hidden). Only hidden columns have a 
15084
15085		 * reference in the array. For non-hidden columns the value is either
15086
15087		 * undefined or null.
15088
15089		 *  @type array nodes
15090
15091		 *  @default []
15092
15093		 *  @private
15094
15095		 */
15096
15097		"_anHidden": [],
15098
15099	
15100
15101		/**
15102
15103		 * Cache of the class name that DataTables has applied to the row, so we
15104
15105		 * can quickly look at this variable rather than needing to do a DOM check
15106
15107		 * on className for the nTr property.
15108
15109		 *  @type string
15110
15111		 *  @default <i>Empty string</i>
15112
15113		 *  @private
15114
15115		 */
15116
15117		"_sRowStripe": ""
15118
15119	};
15120
15121	
15122
15123	
15124
15125	
15126
15127	/**
15128
15129	 * Template object for the column information object in DataTables. This object
15130
15131	 * is held in the settings aoColumns array and contains all the information that
15132
15133	 * DataTables needs about each individual column.
15134
15135	 * 
15136
15137	 * Note that this object is related to {@link DataTable.defaults.columns} 
15138
15139	 * but this one is the internal data store for DataTables's cache of columns.
15140
15141	 * It should NOT be manipulated outside of DataTables. Any configuration should
15142
15143	 * be done through the initialisation options.
15144
15145	 *  @namespace
15146
15147	 */
15148
15149	DataTable.models.oColumn = {
15150
15151		/**
15152
15153		 * A list of the columns that sorting should occur on when this column
15154
15155		 * is sorted. That this property is an array allows multi-column sorting
15156
15157		 * to be defined for a column (for example first name / last name columns
15158
15159		 * would benefit from this). The values are integers pointing to the
15160
15161		 * columns to be sorted on (typically it will be a single integer pointing
15162
15163		 * at itself, but that doesn't need to be the case).
15164
15165		 *  @type array
15166
15167		 */
15168
15169		"aDataSort": null,
15170
15171	
15172
15173		/**
15174
15175		 * Define the sorting directions that are applied to the column, in sequence
15176
15177		 * as the column is repeatedly sorted upon - i.e. the first value is used
15178
15179		 * as the sorting direction when the column if first sorted (clicked on).
15180
15181		 * Sort it again (click again) and it will move on to the next index.
15182
15183		 * Repeat until loop.
15184
15185		 *  @type array
15186
15187		 */
15188
15189		"asSorting": null,
15190
15191		
15192
15193		/**
15194
15195		 * Flag to indicate if the column is searchable, and thus should be included
15196
15197		 * in the filtering or not.
15198
15199		 *  @type boolean
15200
15201		 */
15202
15203		"bSearchable": null,
15204
15205		
15206
15207		/**
15208
15209		 * Flag to indicate if the column is sortable or not.
15210
15211		 *  @type boolean
15212
15213		 */
15214
15215		"bSortable": null,
15216
15217		
15218
15219		/**
15220
15221		 * <code>Deprecated</code> When using fnRender, you have two options for what 
15222
15223		 * to do with the data, and this property serves as the switch. Firstly, you 
15224
15225		 * can have the sorting and filtering use the rendered value (true - default), 
15226
15227		 * or you can have the sorting and filtering us the original value (false).
15228
15229		 *
15230
15231		 * Please note that this option has now been deprecated and will be removed
15232
15233		 * in the next version of DataTables. Please use mRender / mData rather than
15234
15235		 * fnRender.
15236
15237		 *  @type boolean
15238
15239		 *  @deprecated
15240
15241		 */
15242
15243		"bUseRendered": null,
15244
15245		
15246
15247		/**
15248
15249		 * Flag to indicate if the column is currently visible in the table or not
15250
15251		 *  @type boolean
15252
15253		 */
15254
15255		"bVisible": null,
15256
15257		
15258
15259		/**
15260
15261		 * Flag to indicate to the type detection method if the automatic type
15262
15263		 * detection should be used, or if a column type (sType) has been specified
15264
15265		 *  @type boolean
15266
15267		 *  @default true
15268
15269		 *  @private
15270
15271		 */
15272
15273		"_bAutoType": true,
15274
15275		
15276
15277		/**
15278
15279		 * Developer definable function that is called whenever a cell is created (Ajax source,
15280
15281		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
15282
15283		 * allowing you to modify the DOM element (add background colour for example) when the
15284
15285		 * element is available.
15286
15287		 *  @type function
15288
15289		 *  @param {element} nTd The TD node that has been created
15290
15291		 *  @param {*} sData The Data for the cell
15292
15293		 *  @param {array|object} oData The data for the whole row
15294
15295		 *  @param {int} iRow The row index for the aoData data store
15296
15297		 *  @default null
15298
15299		 */
15300
15301		"fnCreatedCell": null,
15302
15303		
15304
15305		/**
15306
15307		 * Function to get data from a cell in a column. You should <b>never</b>
15308
15309		 * access data directly through _aData internally in DataTables - always use
15310
15311		 * the method attached to this property. It allows mData to function as
15312
15313		 * required. This function is automatically assigned by the column 
15314
15315		 * initialisation method
15316
15317		 *  @type function
15318
15319		 *  @param {array|object} oData The data array/object for the array 
15320
15321		 *    (i.e. aoData[]._aData)
15322
15323		 *  @param {string} sSpecific The specific data type you want to get - 
15324
15325		 *    'display', 'type' 'filter' 'sort'
15326
15327		 *  @returns {*} The data for the cell from the given row's data
15328
15329		 *  @default null
15330
15331		 */
15332
15333		"fnGetData": null,
15334
15335		
15336
15337		/**
15338
15339		 * <code>Deprecated</code> Custom display function that will be called for the 
15340
15341		 * display of each cell in this column.
15342
15343		 *
15344
15345		 * Please note that this option has now been deprecated and will be removed
15346
15347		 * in the next version of DataTables. Please use mRender / mData rather than
15348
15349		 * fnRender.
15350
15351		 *  @type function
15352
15353		 *  @param {object} o Object with the following parameters:
15354
15355		 *  @param {int}    o.iDataRow The row in aoData
15356
15357		 *  @param {int}    o.iDataColumn The column in question
15358
15359		 *  @param {array}  o.aData The data for the row in question
15360
15361		 *  @param {object} o.oSettings The settings object for this DataTables instance
15362
15363		 *  @returns {string} The string you which to use in the display
15364
15365		 *  @default null
15366
15367		 *  @deprecated
15368
15369		 */
15370
15371		"fnRender": null,
15372
15373		
15374
15375		/**
15376
15377		 * Function to set data for a cell in the column. You should <b>never</b> 
15378
15379		 * set the data directly to _aData internally in DataTables - always use
15380
15381		 * this method. It allows mData to function as required. This function
15382
15383		 * is automatically assigned by the column initialisation method
15384
15385		 *  @type function
15386
15387		 *  @param {array|object} oData The data array/object for the array 
15388
15389		 *    (i.e. aoData[]._aData)
15390
15391		 *  @param {*} sValue Value to set
15392
15393		 *  @default null
15394
15395		 */
15396
15397		"fnSetData": null,
15398
15399		
15400
15401		/**
15402
15403		 * Property to read the value for the cells in the column from the data 
15404
15405		 * source array / object. If null, then the default content is used, if a
15406
15407		 * function is given then the return from the function is used.
15408
15409		 *  @type function|int|string|null
15410
15411		 *  @default null
15412
15413		 */
15414
15415		"mData": null,
15416
15417		
15418
15419		/**
15420
15421		 * Partner property to mData which is used (only when defined) to get
15422
15423		 * the data - i.e. it is basically the same as mData, but without the
15424
15425		 * 'set' option, and also the data fed to it is the result from mData.
15426
15427		 * This is the rendering method to match the data method of mData.
15428
15429		 *  @type function|int|string|null
15430
15431		 *  @default null
15432
15433		 */
15434
15435		"mRender": null,
15436
15437		
15438
15439		/**
15440
15441		 * Unique header TH/TD element for this column - this is what the sorting
15442
15443		 * listener is attached to (if sorting is enabled.)
15444
15445		 *  @type node
15446
15447		 *  @default null
15448
15449		 */
15450
15451		"nTh": null,
15452
15453		
15454
15455		/**
15456
15457		 * Unique footer TH/TD element for this column (if there is one). Not used 
15458
15459		 * in DataTables as such, but can be used for plug-ins to reference the 
15460
15461		 * footer for each column.
15462
15463		 *  @type node
15464
15465		 *  @default null
15466
15467		 */
15468
15469		"nTf": null,
15470
15471		
15472
15473		/**
15474
15475		 * The class to apply to all TD elements in the table's TBODY for the column
15476
15477		 *  @type string
15478
15479		 *  @default null
15480
15481		 */
15482
15483		"sClass": null,
15484
15485		
15486
15487		/**
15488
15489		 * When DataTables calculates the column widths to assign to each column,
15490
15491		 * it finds the longest string in each column and then constructs a
15492
15493		 * temporary table and reads the widths from that. The problem with this
15494
15495		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
15496
15497		 * string - thus the calculation can go wrong (doing it properly and putting
15498
15499		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
15500
15501		 * a "work around" we provide this option. It will append its value to the
15502
15503		 * text that is found to be the longest string for the column - i.e. padding.
15504
15505		 *  @type string
15506
15507		 */
15508
15509		"sContentPadding": null,
15510
15511		
15512
15513		/**
15514
15515		 * Allows a default value to be given for a column's data, and will be used
15516
15517		 * whenever a null data source is encountered (this can be because mData
15518
15519		 * is set to null, or because the data source itself is null).
15520
15521		 *  @type string
15522
15523		 *  @default null
15524
15525		 */
15526
15527		"sDefaultContent": null,
15528
15529		
15530
15531		/**
15532
15533		 * Name for the column, allowing reference to the column by name as well as
15534
15535		 * by index (needs a lookup to work by name).
15536
15537		 *  @type string
15538
15539		 */
15540
15541		"sName": null,
15542
15543		
15544
15545		/**
15546
15547		 * Custom sorting data type - defines which of the available plug-ins in
15548
15549		 * afnSortData the custom sorting will use - if any is defined.
15550
15551		 *  @type string
15552
15553		 *  @default std
15554
15555		 */
15556
15557		"sSortDataType": 'std',
15558
15559		
15560
15561		/**
15562
15563		 * Class to be applied to the header element when sorting on this column
15564
15565		 *  @type string
15566
15567		 *  @default null
15568
15569		 */
15570
15571		"sSortingClass": null,
15572
15573		
15574
15575		/**
15576
15577		 * Class to be applied to the header element when sorting on this column -
15578
15579		 * when jQuery UI theming is used.
15580
15581		 *  @type string
15582
15583		 *  @default null
15584
15585		 */
15586
15587		"sSortingClassJUI": null,
15588
15589		
15590
15591		/**
15592
15593		 * Title of the column - what is seen in the TH element (nTh).
15594
15595		 *  @type string
15596
15597		 */
15598
15599		"sTitle": null,
15600
15601		
15602
15603		/**
15604
15605		 * Column sorting and filtering type
15606
15607		 *  @type string
15608
15609		 *  @default null
15610
15611		 */
15612
15613		"sType": null,
15614
15615		
15616
15617		/**
15618
15619		 * Width of the column
15620
15621		 *  @type string
15622
15623		 *  @default null
15624
15625		 */
15626
15627		"sWidth": null,
15628
15629		
15630
15631		/**
15632
15633		 * Width of the column when it was first "encountered"
15634
15635		 *  @type string
15636
15637		 *  @default null
15638
15639		 */
15640
15641		"sWidthOrig": null
15642
15643	};
15644
15645	
15646
15647	
15648
15649	
15650
15651	/**
15652
15653	 * Initialisation options that can be given to DataTables at initialisation 
15654
15655	 * time.
15656
15657	 *  @namespace
15658
15659	 */
15660
15661	DataTable.defaults = {
15662
15663		/**
15664
15665		 * An array of data to use for the table, passed in at initialisation which 
15666
15667		 * will be used in preference to any data which is already in the DOM. This is
15668
15669		 * particularly useful for constructing tables purely in Javascript, for
15670
15671		 * example with a custom Ajax call.
15672
15673		 *  @type array
15674
15675		 *  @default null
15676
15677		 *  @dtopt Option
15678
15679		 * 
15680
15681		 *  @example
15682
15683		 *    // Using a 2D array data source
15684
15685		 *    $(document).ready( function () {
15686
15687		 *      $('#example').dataTable( {
15688
15689		 *        "aaData": [
15690
15691		 *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
15692
15693		 *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
15694
15695		 *        ],
15696
15697		 *        "aoColumns": [
15698
15699		 *          { "sTitle": "Engine" },
15700
15701		 *          { "sTitle": "Browser" },
15702
15703		 *          { "sTitle": "Platform" },
15704
15705		 *          { "sTitle": "Version" },
15706
15707		 *          { "sTitle": "Grade" }
15708
15709		 *        ]
15710
15711		 *      } );
15712
15713		 *    } );
15714
15715		 *    
15716
15717		 *  @example
15718
15719		 *    // Using an array of objects as a data source (mData)
15720
15721		 *    $(document).ready( function () {
15722
15723		 *      $('#example').dataTable( {
15724
15725		 *        "aaData": [
15726
15727		 *          {
15728
15729		 *            "engine":   "Trident",
15730
15731		 *            "browser":  "Internet Explorer 4.0",
15732
15733		 *            "platform": "Win 95+",
15734
15735		 *            "version":  4,
15736
15737		 *            "grade":    "X"
15738
15739		 *          },
15740
15741		 *          {
15742
15743		 *            "engine":   "Trident",
15744
15745		 *            "browser":  "Internet Explorer 5.0",
15746
15747		 *            "platform": "Win 95+",
15748
15749		 *            "version":  5,
15750
15751		 *            "grade":    "C"
15752
15753		 *          }
15754
15755		 *        ],
15756
15757		 *        "aoColumns": [
15758
15759		 *          { "sTitle": "Engine",   "mData": "engine" },
15760
15761		 *          { "sTitle": "Browser",  "mData": "browser" },
15762
15763		 *          { "sTitle": "Platform", "mData": "platform" },
15764
15765		 *          { "sTitle": "Version",  "mData": "version" },
15766
15767		 *          { "sTitle": "Grade",    "mData": "grade" }
15768
15769		 *        ]
15770
15771		 *      } );
15772
15773		 *    } );
15774
15775		 */
15776
15777		"aaData": null,
15778
15779	
15780
15781	
15782
15783		/**
15784
15785		 * If sorting is enabled, then DataTables will perform a first pass sort on 
15786
15787		 * initialisation. You can define which column(s) the sort is performed upon, 
15788
15789		 * and the sorting direction, with this variable. The aaSorting array should 
15790
15791		 * contain an array for each column to be sorted initially containing the 
15792
15793		 * column's index and a direction string ('asc' or 'desc').
15794
15795		 *  @type array
15796
15797		 *  @default [[0,'asc']]
15798
15799		 *  @dtopt Option
15800
15801		 * 
15802
15803		 *  @example
15804
15805		 *    // Sort by 3rd column first, and then 4th column
15806
15807		 *    $(document).ready( function() {
15808
15809		 *      $('#example').dataTable( {
15810
15811		 *        "aaSorting": [[2,'asc'], [3,'desc']]
15812
15813		 *      } );
15814
15815		 *    } );
15816
15817		 *    
15818
15819		 *    // No initial sorting
15820
15821		 *    $(document).ready( function() {
15822
15823		 *      $('#example').dataTable( {
15824
15825		 *        "aaSorting": []
15826
15827		 *      } );
15828
15829		 *    } );
15830
15831		 */
15832
15833		"aaSorting": [[0,'asc']],
15834
15835	
15836
15837	
15838
15839		/**
15840
15841		 * This parameter is basically identical to the aaSorting parameter, but 
15842
15843		 * cannot be overridden by user interaction with the table. What this means 
15844
15845		 * is that you could have a column (visible or hidden) which the sorting will 
15846
15847		 * always be forced on first - any sorting after that (from the user) will 
15848
15849		 * then be performed as required. This can be useful for grouping rows 
15850
15851		 * together.
15852
15853		 *  @type array
15854
15855		 *  @default null
15856
15857		 *  @dtopt Option
15858
15859		 * 
15860
15861		 *  @example
15862
15863		 *    $(document).ready( function() {
15864
15865		 *      $('#example').dataTable( {
15866
15867		 *        "aaSortingFixed": [[0,'asc']]
15868
15869		 *      } );
15870
15871		 *    } )
15872
15873		 */
15874
15875		"aaSortingFixed": null,
15876
15877	
15878
15879	
15880
15881		/**
15882
15883		 * This parameter allows you to readily specify the Businesses in the length drop
15884
15885		 * down menu that DataTables shows when pagination is enabled. It can be 
15886
15887		 * either a 1D array of options which will be used for both the displayed 
15888
15889		 * option and the value, or a 2D array which will use the array in the first 
15890
15891		 * position as the value, and the array in the second position as the 
15892
15893		 * displayed options (useful for language strings such as 'All').
15894
15895		 *  @type array
15896
15897		 *  @default [ 10, 25, 50, 100 ]
15898
15899		 *  @dtopt Option
15900
15901		 * 
15902
15903		 *  @example
15904
15905		 *    $(document).ready( function() {
15906
15907		 *      $('#example').dataTable( {
15908
15909		 *        "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
15910
15911		 *      } );
15912
15913		 *    } );
15914
15915		 *  
15916
15917		 *  @example
15918
15919		 *    // Setting the default display length as well as length menu
15920
15921		 *    // This is likely to be wanted if you remove the '10' option which
15922
15923		 *    // is the iDisplayLength default.
15924
15925		 *    $(document).ready( function() {
15926
15927		 *      $('#example').dataTable( {
15928
15929		 *        "iDisplayLength": 25,
15930
15931		 *        "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
15932
15933		 *      } );
15934
15935		 *    } );
15936
15937		 */
15938
15939		"aLengthMenu": [ 10, 25, 50, 100 ],
15940
15941	
15942
15943	
15944
15945		/**
15946
15947		 * The aoColumns option in the initialisation parameter allows you to define
15948
15949		 * details about the way individual columns behave. For a full list of
15950
15951		 * column options that can be set, please see 
15952
15953		 * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
15954
15955		 * define your columns, you must have an entry in the array for every single
15956
15957		 * column that you have in your table (these can be null if you don't which
15958
15959		 * to specify any options).
15960
15961		 *  @member
15962
15963		 */
15964
15965		"aoColumns": null,
15966
15967	
15968
15969		/**
15970
15971		 * Very similar to aoColumns, aoColumnDefs allows you to target a specific 
15972
15973		 * column, multiple columns, or all columns, using the aTargets property of 
15974
15975		 * each object in the array. This allows great flexibility when creating 
15976
15977		 * tables, as the aoColumnDefs arrays can be of any length, targeting the 
15978
15979		 * columns you specifically want. aoColumnDefs may use any of the column 
15980
15981		 * options available: {@link DataTable.defaults.columns}, but it _must_
15982
15983		 * have aTargets defined in each object in the array. Values in the aTargets
15984
15985		 * array may be:
15986
15987		 *   <ul>
15988
15989		 *     <li>a string - class name will be matched on the TH for the column</li>
15990
15991		 *     <li>0 or a positive integer - column index counting from the left</li>
15992
15993		 *     <li>a negative integer - column index counting from the right</li>
15994
15995		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
15996
15997		 *   </ul>
15998
15999		 *  @member
16000
16001		 */
16002
16003		"aoColumnDefs": null,
16004
16005	
16006
16007	
16008
16009		/**
16010
16011		 * Basically the same as oSearch, this parameter defines the individual column
16012
16013		 * filtering state at initialisation time. The array must be of the same size 
16014
16015		 * as the number of columns, and each element be an object with the parameters
16016
16017		 * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
16018
16019		 * accepted and the default will be used.
16020
16021		 *  @type array
16022
16023		 *  @default []
16024
16025		 *  @dtopt Option
16026
16027		 * 
16028
16029		 *  @example
16030
16031		 *    $(document).ready( function() {
16032
16033		 *      $('#example').dataTable( {
16034
16035		 *        "aoSearchCols": [
16036
16037		 *          null,
16038
16039		 *          { "sSearch": "My filter" },
16040
16041		 *          null,
16042
16043		 *          { "sSearch": "^[0-9]", "bEscapeRegex": false }
16044
16045		 *        ]
16046
16047		 *      } );
16048
16049		 *    } )
16050
16051		 */
16052
16053		"aoSearchCols": [],
16054
16055	
16056
16057	
16058
16059		/**
16060
16061		 * An array of CSS classes that should be applied to displayed rows. This 
16062
16063		 * array may be of any length, and DataTables will apply each class 
16064
16065		 * sequentially, looping when required.
16066
16067		 *  @type array
16068
16069		 *  @default null <i>Will take the values determined by the oClasses.sStripe*
16070
16071		 *    options</i>
16072
16073		 *  @dtopt Option
16074
16075		 * 
16076
16077		 *  @example
16078
16079		 *    $(document).ready( function() {
16080
16081		 *      $('#example').dataTable( {
16082
16083		 *        "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
16084
16085		 *      } );
16086
16087		 *    } )
16088
16089		 */
16090
16091		"asStripeClasses": null,
16092
16093	
16094
16095	
16096
16097		/**
16098
16099		 * Enable or disable automatic column width calculation. This can be disabled
16100
16101		 * as an optimisation (it takes some time to calculate the widths) if the
16102
16103		 * tables widths are passed in using aoColumns.
16104
16105		 *  @type boolean
16106
16107		 *  @default true
16108
16109		 *  @dtopt Features
16110
16111		 * 
16112
16113		 *  @example
16114
16115		 *    $(document).ready( function () {
16116
16117		 *      $('#example').dataTable( {
16118
16119		 *        "bAutoWidth": false
16120
16121		 *      } );
16122
16123		 *    } );
16124
16125		 */
16126
16127		"bAutoWidth": true,
16128
16129	
16130
16131	
16132
16133		/**
16134
16135		 * Deferred rendering can provide DataTables with a huge speed boost when you
16136
16137		 * are using an Ajax or JS data source for the table. This option, when set to
16138
16139		 * true, will cause DataTables to defer the creation of the table elements for
16140
16141		 * each row until they are needed for a draw - saving a significant amount of
16142
16143		 * time.
16144
16145		 *  @type boolean
16146
16147		 *  @default false
16148
16149		 *  @dtopt Features
16150
16151		 * 
16152
16153		 *  @example
16154
16155		 *    $(document).ready( function() {
16156
16157		 *      var oTable = $('#example').dataTable( {
16158
16159		 *        "sAjaxSource": "sources/arrays.txt",
16160
16161		 *        "bDeferRender": true
16162
16163		 *      } );
16164
16165		 *    } );
16166
16167		 */
16168
16169		"bDeferRender": false,
16170
16171	
16172
16173	
16174
16175		/**
16176
16177		 * Replace a DataTable which matches the given selector and replace it with 
16178
16179		 * one which has the properties of the new initialisation object passed. If no
16180
16181		 * table matches the selector, then the new DataTable will be constructed as
16182
16183		 * per normal.
16184
16185		 *  @type boolean
16186
16187		 *  @default false
16188
16189		 *  @dtopt Options
16190
16191		 * 
16192
16193		 *  @example
16194
16195		 *    $(document).ready( function() {
16196
16197		 *      $('#example').dataTable( {
16198
16199		 *        "sScrollY": "200px",
16200
16201		 *        "bPaginate": false
16202
16203		 *      } );
16204
16205		 *      
16206
16207		 *      // Some time later....
16208
16209		 *      $('#example').dataTable( {
16210
16211		 *        "bFilter": false,
16212
16213		 *        "bDestroy": true
16214
16215		 *      } );
16216
16217		 *    } );
16218
16219		 */
16220
16221		"bDestroy": false,
16222
16223	
16224
16225	
16226
16227		/**
16228
16229		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
16230
16231		 * that it allows the end user to input multiple words (space separated) and
16232
16233		 * will match a row containing those words, even if not in the order that was
16234
16235		 * specified (this allow matching across multiple columns). Note that if you
16236
16237		 * wish to use filtering in DataTables this must remain 'true' - to remove the
16238
16239		 * default filtering input box and retain filtering abilities, please use
16240
16241		 * {@link DataTable.defaults.sDom}.
16242
16243		 *  @type boolean
16244
16245		 *  @default true
16246
16247		 *  @dtopt Features
16248
16249		 * 
16250
16251		 *  @example
16252
16253		 *    $(document).ready( function () {
16254
16255		 *      $('#example').dataTable( {
16256
16257		 *        "bFilter": false
16258
16259		 *      } );
16260
16261		 *    } );
16262
16263		 */
16264
16265		"bFilter": true,
16266
16267	
16268
16269	
16270
16271		/**
16272
16273		 * Enable or disable the table information display. This shows information 
16274
16275		 * about the data that is currently visible on the page, including information
16276
16277		 * about filtered data if that action is being performed.
16278
16279		 *  @type boolean
16280
16281		 *  @default true
16282
16283		 *  @dtopt Features
16284
16285		 * 
16286
16287		 *  @example
16288
16289		 *    $(document).ready( function () {
16290
16291		 *      $('#example').dataTable( {
16292
16293		 *        "bInfo": false
16294
16295		 *      } );
16296
16297		 *    } );
16298
16299		 */
16300
16301		"bInfo": true,
16302
16303	
16304
16305	
16306
16307		/**
16308
16309		 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
16310
16311		 * slightly different and additional mark-up from what DataTables has
16312
16313		 * traditionally used).
16314
16315		 *  @type boolean
16316
16317		 *  @default false
16318
16319		 *  @dtopt Features
16320
16321		 * 
16322
16323		 *  @example
16324
16325		 *    $(document).ready( function() {
16326
16327		 *      $('#example').dataTable( {
16328
16329		 *        "bJQueryUI": true
16330
16331		 *      } );
16332
16333		 *    } );
16334
16335		 */
16336
16337		"bJQueryUI": false,
16338
16339	
16340
16341	
16342
16343		/**
16344
16345		 * Allows the end user to select the size of a formatted page from a select
16346
16347		 * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
16348
16349		 *  @type boolean
16350
16351		 *  @default true
16352
16353		 *  @dtopt Features
16354
16355		 * 
16356
16357		 *  @example
16358
16359		 *    $(document).ready( function () {
16360
16361		 *      $('#example').dataTable( {
16362
16363		 *        "bLengthChange": false
16364
16365		 *      } );
16366
16367		 *    } );
16368
16369		 */
16370
16371		"bLengthChange": true,
16372
16373	
16374
16375	
16376
16377		/**
16378
16379		 * Enable or disable pagination.
16380
16381		 *  @type boolean
16382
16383		 *  @default true
16384
16385		 *  @dtopt Features
16386
16387		 * 
16388
16389		 *  @example
16390
16391		 *    $(document).ready( function () {
16392
16393		 *      $('#example').dataTable( {
16394
16395		 *        "bPaginate": false
16396
16397		 *      } );
16398
16399		 *    } );
16400
16401		 */
16402
16403		"bPaginate": true,
16404
16405	
16406
16407	
16408
16409		/**
16410
16411		 * Enable or disable the display of a 'processing' indicator when the table is
16412
16413		 * being processed (e.g. a sort). This is particularly useful for tables with
16414
16415		 * large amounts of data where it can take a noticeable amount of time to sort
16416
16417		 * the Businesses.
16418
16419		 *  @type boolean
16420
16421		 *  @default false
16422
16423		 *  @dtopt Features
16424
16425		 * 
16426
16427		 *  @example
16428
16429		 *    $(document).ready( function () {
16430
16431		 *      $('#example').dataTable( {
16432
16433		 *        "bProcessing": true
16434
16435		 *      } );
16436
16437		 *    } );
16438
16439		 */
16440
16441		"bProcessing": false,
16442
16443	
16444
16445	
16446
16447		/**
16448
16449		 * Retrieve the DataTables object for the given selector. Note that if the
16450
16451		 * table has already been initialised, this parameter will cause DataTables
16452
16453		 * to simply return the object that has already been set up - it will not take
16454
16455		 * account of any changes you might have made to the initialisation object
16456
16457		 * passed to DataTables (setting this parameter to true is an acknowledgement
16458
16459		 * that you understand this). bDestroy can be used to reinitialise a table if
16460
16461		 * you need.
16462
16463		 *  @type boolean
16464
16465		 *  @default false
16466
16467		 *  @dtopt Options
16468
16469		 * 
16470
16471		 *  @example
16472
16473		 *    $(document).ready( function() {
16474
16475		 *      initTable();
16476
16477		 *      tableActions();
16478
16479		 *    } );
16480
16481		 *    
16482
16483		 *    function initTable ()
16484
16485		 *    {
16486
16487		 *      return $('#example').dataTable( {
16488
16489		 *        "sScrollY": "200px",
16490
16491		 *        "bPaginate": false,
16492
16493		 *        "bRetrieve": true
16494
16495		 *      } );
16496
16497		 *    }
16498
16499		 *    
16500
16501		 *    function tableActions ()
16502
16503		 *    {
16504
16505		 *      var oTable = initTable();
16506
16507		 *      // perform API operations with oTable 
16508
16509		 *    }
16510
16511		 */
16512
16513		"bRetrieve": false,
16514
16515	
16516
16517	
16518
16519		/**
16520
16521		 * Indicate if DataTables should be allowed to set the padding / margin
16522
16523		 * etc for the scrolling header elements or not. Typically you will want
16524
16525		 * this.
16526
16527		 *  @type boolean
16528
16529		 *  @default true
16530
16531		 *  @dtopt Options
16532
16533		 * 
16534
16535		 *  @example
16536
16537		 *    $(document).ready( function() {
16538
16539		 *      $('#example').dataTable( {
16540
16541		 *        "bScrollAutoCss": false,
16542
16543		 *        "sScrollY": "200px"
16544
16545		 *      } );
16546
16547		 *    } );
16548
16549		 */
16550
16551		"bScrollAutoCss": true,
16552
16553	
16554
16555	
16556
16557		/**
16558
16559		 * When vertical (y) scrolling is enabled, DataTables will force the height of
16560
16561		 * the table's viewport to the given height at all times (useful for layout).
16562
16563		 * However, this can look odd when filtering data down to a small data set,
16564
16565		 * and the footer is left "floating" further down. This parameter (when
16566
16567		 * enabled) will cause DataTables to collapse the table's viewport down when
16568
16569		 * the result set will fit within the given Y height.
16570
16571		 *  @type boolean
16572
16573		 *  @default false
16574
16575		 *  @dtopt Options
16576
16577		 * 
16578
16579		 *  @example
16580
16581		 *    $(document).ready( function() {
16582
16583		 *      $('#example').dataTable( {
16584
16585		 *        "sScrollY": "200",
16586
16587		 *        "bScrollCollapse": true
16588
16589		 *      } );
16590
16591		 *    } );
16592
16593		 */
16594
16595		"bScrollCollapse": false,
16596
16597	
16598
16599	
16600
16601		/**
16602
16603		 * Enable infinite scrolling for DataTables (to be used in combination with
16604
16605		 * sScrollY). Infinite scrolling means that DataTables will continually load
16606
16607		 * data as a user scrolls through a table, which is very useful for large
16608
16609		 * dataset. This cannot be used with pagination, which is automatically
16610
16611		 * disabled. Note - the Scroller extra for DataTables is recommended in
16612
16613		 * in preference to this option.
16614
16615		 *  @type boolean
16616
16617		 *  @default false
16618
16619		 *  @dtopt Features
16620
16621		 * 
16622
16623		 *  @example
16624
16625		 *    $(document).ready( function() {
16626
16627		 *      $('#example').dataTable( {
16628
16629		 *        "bScrollInfinite": true,
16630
16631		 *        "bScrollCollapse": true,
16632
16633		 *        "sScrollY": "200px"
16634
16635		 *      } );
16636
16637		 *    } );
16638
16639		 */
16640
16641		"bScrollInfinite": false,
16642
16643	
16644
16645	
16646
16647		/**
16648
16649		 * Configure DataTables to use server-side processing. Note that the
16650
16651		 * sAjaxSource parameter must also be given in order to give DataTables a
16652
16653		 * source to obtain the required data for each draw.
16654
16655		 *  @type boolean
16656
16657		 *  @default false
16658
16659		 *  @dtopt Features
16660
16661		 *  @dtopt Server-side
16662
16663		 * 
16664
16665		 *  @example
16666
16667		 *    $(document).ready( function () {
16668
16669		 *      $('#example').dataTable( {
16670
16671		 *        "bServerSide": true,
16672
16673		 *        "sAjaxSource": "xhr.php"
16674
16675		 *      } );
16676
16677		 *    } );
16678
16679		 */
16680
16681		"bServerSide": false,
16682
16683	
16684
16685	
16686
16687		/**
16688
16689		 * Enable or disable sorting of columns. Sorting of individual columns can be
16690
16691		 * disabled by the "bSortable" option for each column.
16692
16693		 *  @type boolean
16694
16695		 *  @default true
16696
16697		 *  @dtopt Features
16698
16699		 * 
16700
16701		 *  @example
16702
16703		 *    $(document).ready( function () {
16704
16705		 *      $('#example').dataTable( {
16706
16707		 *        "bSort": false
16708
16709		 *      } );
16710
16711		 *    } );
16712
16713		 */
16714
16715		"bSort": true,
16716
16717	
16718
16719	
16720
16721		/**
16722
16723		 * Allows control over whether DataTables should use the top (true) unique
16724
16725		 * cell that is found for a single column, or the bottom (false - default).
16726
16727		 * This is useful when using complex headers.
16728
16729		 *  @type boolean
16730
16731		 *  @default false
16732
16733		 *  @dtopt Options
16734
16735		 * 
16736
16737		 *  @example
16738
16739		 *    $(document).ready( function() {
16740
16741		 *      $('#example').dataTable( {
16742
16743		 *        "bSortCellsTop": true
16744
16745		 *      } );
16746
16747		 *    } );
16748
16749		 */
16750
16751		"bSortCellsTop": false,
16752
16753	
16754
16755	
16756
16757		/**
16758
16759		 * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
16760
16761		 * 'sorting_3' to the columns which are currently being sorted on. This is
16762
16763		 * presented as a feature switch as it can increase processing time (while
16764
16765		 * classes are removed and added) so for large data sets you might want to
16766
16767		 * turn this off.
16768
16769		 *  @type boolean
16770
16771		 *  @default true
16772
16773		 *  @dtopt Features
16774
16775		 * 
16776
16777		 *  @example
16778
16779		 *    $(document).ready( function () {
16780
16781		 *      $('#example').dataTable( {
16782
16783		 *        "bSortClasses": false
16784
16785		 *      } );
16786
16787		 *    } );
16788
16789		 */
16790
16791		"bSortClasses": true,
16792
16793	
16794
16795	
16796
16797		/**
16798
16799		 * Enable or disable state saving. When enabled a cookie will be used to save
16800
16801		 * table display information such as pagination information, display length,
16802
16803		 * filtering and sorting. As such when the end user reloads the page the
16804
16805		 * display display will match what thy had previously set up.
16806
16807		 *  @type boolean
16808
16809		 *  @default false
16810
16811		 *  @dtopt Features
16812
16813		 * 
16814
16815		 *  @example
16816
16817		 *    $(document).ready( function () {
16818
16819		 *      $('#example').dataTable( {
16820
16821		 *        "bStateSave": true
16822
16823		 *      } );
16824
16825		 *    } );
16826
16827		 */
16828
16829		"bStateSave": false,
16830
16831	
16832
16833	
16834
16835		/**
16836
16837		 * Customise the cookie and / or the parameters being stored when using
16838
16839		 * DataTables with state saving enabled. This function is called whenever
16840
16841		 * the cookie is modified, and it expects a fully formed cookie string to be
16842
16843		 * returned. Note that the data object passed in is a Javascript object which
16844
16845		 * must be converted to a string (JSON.stringify for example).
16846
16847		 *  @type function
16848
16849		 *  @param {string} sName Name of the cookie defined by DataTables
16850
16851		 *  @param {object} oData Data to be stored in the cookie
16852
16853		 *  @param {string} sExpires Cookie expires string
16854
16855		 *  @param {string} sPath Path of the cookie to set
16856
16857		 *  @returns {string} Cookie formatted string (which should be encoded by
16858
16859		 *    using encodeURIComponent())
16860
16861		 *  @dtopt Callbacks
16862
16863		 * 
16864
16865		 *  @example
16866
16867		 *    $(document).ready( function () {
16868
16869		 *      $('#example').dataTable( {
16870
16871		 *        "fnCookieCallback": function (sName, oData, sExpires, sPath) {
16872
16873		 *          // Customise oData or sName or whatever else here
16874
16875		 *          return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
16876
16877		 *        }
16878
16879		 *      } );
16880
16881		 *    } );
16882
16883		 */
16884
16885		"fnCookieCallback": null,
16886
16887	
16888
16889	
16890
16891		/**
16892
16893		 * This function is called when a TR element is created (and all TD child
16894
16895		 * elements have been inserted), or registered if using a DOM source, allowing
16896
16897		 * manipulation of the TR element (adding classes etc).
16898
16899		 *  @type function
16900
16901		 *  @param {node} nRow "TR" element for the current row
16902
16903		 *  @param {array} aData Raw data array for this row
16904
16905		 *  @param {int} iDataIndex The index of this row in aoData
16906
16907		 *  @dtopt Callbacks
16908
16909		 * 
16910
16911		 *  @example
16912
16913		 *    $(document).ready( function() {
16914
16915		 *      $('#example').dataTable( {
16916
16917		 *        "fnCreatedRow": function( nRow, aData, iDataIndex ) {
16918
16919		 *          // Bold the grade for all 'A' grade browsers
16920
16921		 *          if ( aData[4] == "A" )
16922
16923		 *          {
16924
16925		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
16926
16927		 *          }
16928
16929		 *        }
16930
16931		 *      } );
16932
16933		 *    } );
16934
16935		 */
16936
16937		"fnCreatedRow": null,
16938
16939	
16940
16941	
16942
16943		/**
16944
16945		 * This function is called on every 'draw' event, and allows you to
16946
16947		 * dynamically modify any aspect you want about the created DOM.
16948
16949		 *  @type function
16950
16951		 *  @param {object} oSettings DataTables settings object
16952
16953		 *  @dtopt Callbacks
16954
16955		 * 
16956
16957		 *  @example
16958
16959		 *    $(document).ready( function() {
16960
16961		 *      $('#example').dataTable( {
16962
16963		 *        "fnDrawCallback": function( oSettings ) {
16964
16965		 *          alert( 'DataTables has redrawn the table' );
16966
16967		 *        }
16968
16969		 *      } );
16970
16971		 *    } );
16972
16973		 */
16974
16975		"fnDrawCallback": null,
16976
16977	
16978
16979	
16980
16981		/**
16982
16983		 * Identical to fnHeaderCallback() but for the table footer this function
16984
16985		 * allows you to modify the table footer on every 'draw' even.
16986
16987		 *  @type function
16988
16989		 *  @param {node} nFoot "TR" element for the footer
16990
16991		 *  @param {array} aData Full table data (as derived from the original HTML)
16992
16993		 *  @param {int} iStart Index for the current display starting point in the 
16994
16995		 *    display array
16996
16997		 *  @param {int} iEnd Index for the current display ending point in the 
16998
16999		 *    display array
17000
17001		 *  @param {array int} aiDisplay Index array to translate the visual position
17002
17003		 *    to the full data array
17004
17005		 *  @dtopt Callbacks
17006
17007		 * 
17008
17009		 *  @example
17010
17011		 *    $(document).ready( function() {
17012
17013		 *      $('#example').dataTable( {
17014
17015		 *        "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
17016
17017		 *          nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
17018
17019		 *        }
17020
17021		 *      } );
17022
17023		 *    } )
17024
17025		 */
17026
17027		"fnFooterCallback": null,
17028
17029	
17030
17031	
17032
17033		/**
17034
17035		 * When rendering large numbers in the information element for the table
17036
17037		 * (i.e. "Showing 1 to 10 of 57 Businesses") DataTables will render large numbers
17038
17039		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
17040
17041		 * rendered as "1,000,000") to help readability for the end user. This
17042
17043		 * function will override the default method DataTables uses.
17044
17045		 *  @type function
17046
17047		 *  @member
17048
17049		 *  @param {int} iIn number to be formatted
17050
17051		 *  @returns {string} formatted string for DataTables to show the number
17052
17053		 *  @dtopt Callbacks
17054
17055		 * 
17056
17057		 *  @example
17058
17059		 *    $(document).ready( function() {
17060
17061		 *      $('#example').dataTable( {
17062
17063		 *        "fnFormatNumber": function ( iIn ) {
17064
17065		 *          if ( iIn &lt; 1000 ) {
17066
17067		 *            return iIn;
17068
17069		 *          } else {
17070
17071		 *            var 
17072
17073		 *              s=(iIn+""), 
17074
17075		 *              a=s.split(""), out="", 
17076
17077		 *              iLen=s.length;
17078
17079		 *            
17080
17081		 *            for ( var i=0 ; i&lt;iLen ; i++ ) {
17082
17083		 *              if ( i%3 === 0 &amp;&amp; i !== 0 ) {
17084
17085		 *                out = "'"+out;
17086
17087		 *              }
17088
17089		 *              out = a[iLen-i-1]+out;
17090
17091		 *            }
17092
17093		 *          }
17094
17095		 *          return out;
17096
17097		 *        };
17098
17099		 *      } );
17100
17101		 *    } );
17102
17103		 */
17104
17105		"fnFormatNumber": function ( iIn ) {
17106
17107			if ( iIn < 1000 )
17108
17109			{
17110
17111				// A small optimisation for what is likely to be the majority of use cases
17112
17113				return iIn;
17114
17115			}
17116
17117	
17118
17119			var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
17120
17121			
17122
17123			for ( var i=0 ; i<iLen ; i++ )
17124
17125			{
17126
17127				if ( i%3 === 0 && i !== 0 )
17128
17129				{
17130
17131					out = this.oLanguage.sInfoThousands+out;
17132
17133				}
17134
17135				out = a[iLen-i-1]+out;
17136
17137			}
17138
17139			return out;
17140
17141		},
17142
17143	
17144
17145	
17146
17147		/**
17148
17149		 * This function is called on every 'draw' event, and allows you to
17150
17151		 * dynamically modify the header row. This can be used to calculate and
17152
17153		 * display useful information about the table.
17154
17155		 *  @type function
17156
17157		 *  @param {node} nHead "TR" element for the header
17158
17159		 *  @param {array} aData Full table data (as derived from the original HTML)
17160
17161		 *  @param {int} iStart Index for the current display starting point in the
17162
17163		 *    display array
17164
17165		 *  @param {int} iEnd Index for the current display ending point in the
17166
17167		 *    display array
17168
17169		 *  @param {array int} aiDisplay Index array to translate the visual position
17170
17171		 *    to the full data array
17172
17173		 *  @dtopt Callbacks
17174
17175		 * 
17176
17177		 *  @example
17178
17179		 *    $(document).ready( function() {
17180
17181		 *      $('#example').dataTable( {
17182
17183		 *        "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
17184
17185		 *          nHead.getElementsByTagName('th')[0].innerHTML = "Dis
17185playing "+(iEnd-iStart)+" records";
17186
17187		 *        }
17188
17189		 *      } );
17190
17191		 *    } )
17192
17193		 */
17194
17195		"fnHeaderCallback": null,
17196
17197	
17198
17199	
17200
17201		/**
17202
17203		 * The information element can be used to convey information about the current
17204
17205		 * state of the table. Although the internationalisation options presented by
17206
17207		 * DataTables are quite capable of dealing with most customisations, there may
17208
17209		 * be times where you wish to customise the string further. This callback
17210
17211		 * allows you to do exactly that.
17212
17213		 *  @type function
17214
17215		 *  @param {object} oSettings DataTables settings object
17216
17217		 *  @param {int} iStart Starting position in data for the draw
17218
17219		 *  @param {int} iEnd End position in data for the draw
17220
17221		 *  @param {int} iMax Total number of rows in the table (regardless of
17222
17223		 *    filtering)
17224
17225		 *  @param {int} iTotal Total number of rows in the data set, after filtering
17226
17227		 *  @param {string} sPre The string that DataTables has formatted using it's
17228
17229		 *    own rules
17230
17231		 *  @returns {string} The string to be displayed in the information element.
17232
17233		 *  @dtopt Callbacks
17234
17235		 * 
17236
17237		 *  @example
17238
17239		 *    $('#example').dataTable( {
17240
17241		 *      "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
17242
17243		 *        return iStart +" to "+ iEnd;
17244
17245		 *      }
17246
17247		 *    } );
17248
17249		 */
17250
17251		"fnInfoCallback": null,
17252
17253	
17254
17255	
17256
17257		/**
17258
17259		 * Called when the table has been initialised. Normally DataTables will
17260
17261		 * initialise sequentially and there will be no need for this function,
17262
17263		 * however, this does not hold true when using external language information
17264
17265		 * since that is obtained using an async XHR call.
17266
17267		 *  @type function
17268
17269		 *  @param {object} oSettings DataTables settings object
17270
17271		 *  @param {object} json The JSON object request from the server - only
17272
17273		 *    present if client-side Ajax sourced data is used
17274
17275		 *  @dtopt Callbacks
17276
17277		 * 
17278
17279		 *  @example
17280
17281		 *    $(document).ready( function() {
17282
17283		 *      $('#example').dataTable( {
17284
17285		 *        "fnInitComplete": function(oSettings, json) {
17286
17287		 *          alert( 'DataTables has finished its initialisation.' );
17288
17289		 *        }
17290
17291		 *      } );
17292
17293		 *    } )
17294
17295		 */
17296
17297		"fnInitComplete": null,
17298
17299	
17300
17301	
17302
17303		/**
17304
17305		 * Called at the very start of each table draw and can be used to cancel the
17306
17307		 * draw by returning false, any other return (including undefined) results in
17308
17309		 * the full draw occurring).
17310
17311		 *  @type function
17312
17313		 *  @param {object} oSettings DataTables settings object
17314
17315		 *  @returns {boolean} False will cancel the draw, anything else (including no
17316
17317		 *    return) will allow it to complete.
17318
17319		 *  @dtopt Callbacks
17320
17321		 * 
17322
17323		 *  @example
17324
17325		 *    $(document).ready( function() {
17326
17327		 *      $('#example').dataTable( {
17328
17329		 *        "fnPreDrawCallback": function( oSettings ) {
17330
17331		 *          if ( $('#test').val() == 1 ) {
17332
17333		 *            return false;
17334
17335		 *          }
17336
17337		 *        }
17338
17339		 *      } );
17340
17341		 *    } );
17342
17343		 */
17344
17345		"fnPreDrawCallback": null,
17346
17347	
17348
17349	
17350
17351		/**
17352
17353		 * This function allows you to 'post process' each row after it have been
17354
17355		 * generated for each table draw, but before it is rendered on screen. This
17356
17357		 * function might be used for setting the row class name etc.
17358
17359		 *  @type function
17360
17361		 *  @param {node} nRow "TR" element for the current row
17362
17363		 *  @param {array} aData Raw data array for this row
17364
17365		 *  @param {int} iDisplayIndex The display index for the current table draw
17366
17367		 *  @param {int} iDisplayIndexFull The index of the data in the full list of
17368
17369		 *    rows (after filtering)
17370
17371		 *  @dtopt Callbacks
17372
17373		 * 
17374
17375		 *  @example
17376
17377		 *    $(document).ready( function() {
17378
17379		 *      $('#example').dataTable( {
17380
17381		 *        "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
17382
17383		 *          // Bold the grade for all 'A' grade browsers
17384
17385		 *          if ( aData[4] == "A" )
17386
17387		 *          {
17388
17389		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
17390
17391		 *          }
17392
17393		 *        }
17394
17395		 *      } );
17396
17397		 *    } );
17398
17399		 */
17400
17401		"fnRowCallback": null,
17402
17403	
17404
17405	
17406
17407		/**
17408
17409		 * This parameter allows you to override the default function which obtains
17410
17411		 * the data from the server ($.getJSON) so something more suitable for your
17412
17413		 * application. For example you could use POST data, or pull information from
17414
17415		 * a Gears or AIR database.
17416
17417		 *  @type function
17418
17419		 *  @member
17420
17421		 *  @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
17422
17423		 *  @param {array}
17423 aoData A key/value pair object containing the data to send
17424
17425		 *    to the server
17426
17427		 *  @param {function} fnCallback to be called on completion of the data get
17428
17429		 *    process that will draw the data on the page.
17430
17431		 *  @param {object} oSettings DataTables settings object
17432
17433		 *  @dtopt Callbacks
17434
17435		 *  @dtopt Server-side
17436
17437		 * 
17438
17439		 *  @example
17440
17441		 *    // POST data to server
17442
17443		 *    $(document).ready( function() {
17444
17445		 *      $('#example').dataTable( {
17446
17447		 *        "bProcessing": true,
17448
17449		 *        "bServerSide": true,
17450
17451		 *        "sAjaxSource": "xhr.php",
17452
17453		 *        "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
17454
17455		 *          oSettings.jqXHR = $.ajax( {
17456
17457		 *            "dataType": 'json', 
17458
17459		 *            "type": "POST", 
17460
17461		 *            "url": sSource, 
17462
17463		 *            "data": aoData, 
17464
17465		 *            "success": fnCallback
17466
17467		 *          } );
17468
17469		 *        }
17470
17471		 *      } );
17472
17473		 *    } );
17474
17475		 */
17476
17477		"fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
17478
17479			oSettings.jqXHR = $.ajax( {
17480
17481				"url":  sUrl,
17482
17483				"data": aoData,
17484
17485				"success": function (json) {
17486
17487					if ( json.sError ) {
17488
17489						oSettings.oApi._fnLog( oSettings, 0, json.sError );
17490
17491					}
17492
17493					
17494
17495					$(oSettings.oInstance).trigger('xhr', [oSettings, json]);
17496
17497					fnCallback( json );
17498
17499				},
17500
17501				"dataType": "json",
17502
17503				"cache": false,
17504
17505				"type": oSettings.sServerMethod,
17506
17507				"error": function (xhr, error, thrown) {
17508
17509					if ( error == "parsererror" ) {
17510
17511						oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
17512
17513							"server could not be parsed. This is caused by a JSON formatting error." );
17514
17515					}
17516
17517				}
17518
17519			} );
17520
17521		},
17522
17523	
17524
17525	
17526
17527		/**
17528
17529		 * It is often useful to send extra data to the server when making an Ajax
17530
17531		 * request - for example custom filtering information, and this callback
17532
17533		 * function makes it trivial to send extra information to the server. The
17534
17535		 * passed in parameter is the data set that has been constructed by
17536
17537		 * DataTables, and you can add to this or modify it as you require.
17538
17539		 *  @type function
17540
17541		 *  @param {array} aoData Data array (array of objects which are name/value
17542
17543		 *    pairs) that has been constructed by DataTables and will be sent to the
17544
17545		 *    server. In the case of Ajax sourced data with server-side processing
17546
17547		 *    this will be an empty array, for server-side processing there will be a
17548
17549		 *    significant number of parameters!
17550
17551		 *  @returns {undefined} Ensure that you modify the aoData array passed in,
17552
17553		 *    as this is passed by reference.
17554
17555		 *  @dtopt Callbacks
17556
17557		 *  @dtopt Server-side
17558
17559		 * 
17560
17561		 *  @example
17562
17563		 *    $(document).ready( function() {
17564
17565		 *      $('#example').dataTable( {
17566
17567		 *        "bProcessing": true,
17568
17569		 *        "bServerSide": true,
17570
17571		 *        "sAjaxSource": "scripts/server_processing.php",
17572
17573		 *        "fnServerParams": function ( aoData ) {
17574
17575		 *          aoData.push( { "name": "more_data", "value": "my_value" } );
17576
17577		 *        }
17578
17579		 *      } );
17580
17581		 *    } );
17582
17583		 */
17584
17585		"fnServerParams": null,
17586
17587	
17588
17589	
17590
17591		/**
17592
17593		 * Load the table state. With this function you can define from where, and how, the
17594
17595		 * state of a table is loaded. By default DataTables will load from its state saving
17596
17597		 * cookie, but you might wish to use local storage (HTML5) or a server-side database.
17598
17599		 *  @type function
17600
17601		 *  @member
17602
17603		 *  @param {object} oSettings DataTables settings object
17604
17605		 *  @return {object} The DataTables state object to be loaded
17606
17607		 *  @dtopt Callbacks
17608
17609		 * 
17610
17611		 *  @example
17612
17613		 *    $(document).ready( function() {
17614
17615		 *      $('#example').dataTable( {
17616
17617		 *        "bStateSave": true,
17618
17619		 *        "fnStateLoad": function (oSettings) {
17620
17621		 *          var o;
17622
17623		 *          
17624
17625		 *          // Send an Ajax request to the server to get the data. Note that
17626
17627		 *          // this is a synchronous request.
17628
17629		 *          $.ajax( {
17630
17631		 *            "url": "/state_load",
17632
17633		 *            "async": false,
17634
17635		 *            "dataType": "json",
17636
17637		 *            "success": function (json) {
17638
17639		 *              o = json;
17640
17641		 *            }
17642
17643		 *          } );
17644
17645		 *          
17646
17647		 *          return o;
17648
17649		 *        }
17650
17651		 *      } );
17652
17653		 *    } );
17654
17655		 */
17656
17657		"fnStateLoad": function ( oSettings ) {
17658
17659			var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
17660
17661			var oData;
17662
17663	
17664
17665			try {
17666
17667				oData = (typeof $.parseJSON === 'function') ? 
17668
17669					$.parseJSON(sData) : eval( '('+sData+')' );
17670
17671			} catch (e) {
17672
17673				oData = null;
17674
17675			}
17676
17677	
17678
17679			return oData;
17680
17681		},
17682
17683	
17684
17685	
17686
17687		/**
17688
17689		 * Callback which allows modification of the saved state prior to loading that state.
17690
17691		 * This callback is called when the table is loading state from the stored data, but
17692
17693		 * prior to the settings object being modified by the saved state. Note that for 
17694
17695		 * plug-in authors, you should use the 'stateLoadParams' event to load parameters for 
17696
17697		 * a plug-in.
17698
17699		 *  @type function
17700
17701		 *  @param {object} oSettings DataTables settings object
17702
17703		 *  @param {object} oData The state object that is to be loaded
17704
17705		 *  @dtopt Callbacks
17706
17707		 * 
17708
17709		 *  @example
17710
17711		 *    // Remove a saved filter, so filtering is never loaded
17712
17713		 *    $(document).ready( function() {
17714
17715		 *      $('#example').dataTable( {
17716
17717		 *        "bStateSave": true,
17718
17719		 *        "fnStateLoadParams": function (oSettings, oData) {
17720
17721		 *          oData.oSearch.sSearch = "";
17722
17723		 *        }
17724
17725		 *      } );
17726
17727		 *    } );
17728
17729		 * 
17730
17731		 *  @example
17732
17733		 *    // Disallow state loading by returning false
17734
17735		 *    $(document).ready( function() {
17736
17737		 *      $('#example').dataTable( {
17738
17739		 *        "bStateSave": true,
17740
17741		 *        "fnStateLoadParams": function (oSettings, oData) {
17742
17743		 *          return false;
17744
17745		 *        }
17746
17747		 *      } );
17748
17749		 *    } );
17750
17751		 */
17752
17753		"fnStateLoadParams": null,
17754
17755	
17756
17757	
17758
17759		/**
17760
17761		 * Callback that is called when the state has been loaded from the state saving method
17762
17763		 * and the DataTables settings object has been modified as a result of the loaded state.
17764
17765		 *  @type function
17766
17767		 *  @param {object} oSettings DataTables settings object
17768
17769		 *  @param {object} oData The state object that was loaded
17770
17771		 *  @dtopt Callbacks
17772
17773		 * 
17774
17775		 *  @example
17776
17777		 *    // Show an alert with the filtering value that was saved
17778
17779		 *    $(document).ready( function() {
17780
17781		 *      $('#example').dataTable( {
17782
17783		 *        "bStateSave": true,
17784
17785		 *        "fnStateLoaded": function (oSettings, oData) {
17786
17787		 *          alert( 'Saved filter was: '+oData.oSearch.sSearch );
17788
17789		 *        }
17790
17791		 *      } );
17792
17793		 *    } );
17794
17795		 */
17796
17797		"fnStateLoaded": null,
17798
17799	
17800
17801	
17802
17803		/**
17804
17805		 * Save the table state. This function allows you to define where and how the state
17806
17807		 * information for the table is stored - by default it will use a cookie, but you
17808
17809		 * might want to use local storage (HTML5) or a server-side database.
17810
17811		 *  @type function
17812
17813		 *  @member
17814
17815		 *  @param {object} oSettings DataTables settings object
17816
17817		 *  @param {object} oData The state object to be saved
17818
17819		 *  @dtopt Callbacks
17820
17821		 * 
17822
17823		 *  @example
17824
17825		 *    $(document).ready( function() {
17826
17827		 *      $('#example').dataTable( {
17828
17829		 *        "bStateSave": true,
17830
17831		 *        "fnStateSave": function (oSettings, oData) {
17832
17833		 *          // Send an Ajax request to the server with the state object
17834
17835		 *          $.ajax( {
17836
17837		 *            "url": "/state_save",
17838
17839		 *            "data": oData,
17840
17841		 *            "dataType": "json",
17842
17843		 *            "method": "POST"
17844
17845		 *            "success": function () {}
17846
17847		 *          } );
17848
17849		 *        }
17850
17851		 *      } );
17852
17853		 *    } );
17854
17855		 */
17856
17857		"fnStateSave": function ( oSettings, oData ) {
17858
17859			this.oApi._fnCreateCookie( 
17860
17861				oSettings.sCookiePrefix+oSettings.sInstance, 
17862
17863				this.oApi._fnJsonString(oData), 
17864
17865				oSettings.iCookieDuration, 
17866
17867				oSettings.sCookiePrefix, 
17868
17869				oSettings.fnCookieCallback
17870
17871			);
17872
17873		},
17874
17875	
17876
17877	
17878
17879		/**
17880
17881		 * Callback which allows modification of the state to be saved. Called when the table 
17882
17883		 * has changed state a new state save is required. This method allows modification of
17884
17885		 * the state saving object prior to actually doing the save, including addition or 
17886
17887		 * other state properties or modification. Note that for plug-in authors, you should 
17888
17889		 * use the 'stateSaveParams' event to save parameters for a plug-in.
17890
17891		 *  @type function
17892
17893		 *  @param {object} oSettings DataTables settings object
17894
17895		 *  @param {object} oData The state object to be saved
17896
17897		 *  @dtopt Callbacks
17898
17899		 * 
17900
17901		 *  @example
17902
17903		 *    // Remove a saved filter, so filtering is never saved
17904
17905		 *    $(document).ready( function() {
17906
17907		 *      $('#example').dataTable( {
17908
17909		 *        "bStateSave": true,
17910
17911		 *        "fnStateSaveParams": function (oSettings, oData) {
17912
17913		 *          oData.oSearch.sSearch = "";
17914
17915		 *        }
17916
17917		 *      } );
17918
17919		 *    } );
17920
17921		 */
17922
17923		"fnStateSaveParams": null,
17924
17925	
17926
17927	
17928
17929		/**
17930
17931		 * Duration of the cookie which is used for storing session information. This
17932
17933		 * value is given in seconds.
17934
17935		 *  @type int
17936
17937		 *  @default 7200 <i>(2 hours)</i>
17938
17939		 *  @dtopt Options
17940
17941		 * 
17942
17943		 *  @example
17944
17945		 *    $(document).ready( function() {
17946
17947		 *      $('#example').dataTable( {
17948
17949		 *        "iCookieDuration": 60*60*24; // 1 day
17950
17951		 *      } );
17952
17953		 *    } )
17954
17955		 */
17956
17957		"iCookieDuration": 7200,
17958
17959	
17960
17961	
17962
17963		/**
17964
17965		 * When enabled DataTables will not make a request to the server for the first
17966
17967		 * page draw - rather it will use the data already on the page (no sorting etc
17968
17969		 * will be applied to it), thus saving on an XHR at load time. iDeferLoading
17970
17971		 * is used to indicate that deferred loading is required, but it is also used
17972
17973		 * to tell DataTables how many records there are in the full table (allowing
17974
17975		 * the information element and pagination to be displayed correctly). In the case
17976
17977		 * where a filtering is applied to the table on initial load, this can be
17978
17979		 * indicated by giving the parameter as an array, where the first element is
17980
17981		 * the number of records available after filtering and the second element is the
17982
17983		 * number of records without filtering (allowing the table information element
17984
17985		 * to be shown correctly).
17986
17987		 *  @type int | array
17988
17989		 *  @default null
17990
17991		 *  @dtopt Options
17992
17993		 * 
17994
17995		 *  @example
17996
17997		 *    // 57 records available in the table, no filtering applied
17998
17999		 *    $(document).ready( function() {
18000
18001		 *      $('#example').dataTable( {
18002
18003		 *        "bServerSide": true,
18004
18005		 *        "sAjaxSource": "scripts/server_processing.php",
18006
18007		 *        "iDeferLoading": 57
18008
18009		 *      } );
18010
18011		 *    } );
18012
18013		 * 
18014
18015		 *  @example
18016
18017		 *    // 57 records after filtering, 100 without filtering (an initial filter applied)
18018
18019		 *    $(document).ready( function() {
18020
18021		 *      $('#example').dataTable( {
18022
18023		 *        "bServerSide": true,
18024
18025		 *        "sAjaxSource": "scripts/server_processing.php",
18026
18027		 *        "iDeferLoading": [ 57, 100 ],
18028
18029		 *        "oSearch": {
18030
18031		 *          "sSearch": "my_filter"
18032
18033		 *        }
18034
18035		 *      } );
18036
18037		 *    } );
18038
18039		 */
18040
18041		"iDeferLoading": null,
18042
18043	
18044
18045	
18046
18047		/**
18048
18049		 * Number of rows to display on a single page when using pagination. If
18050
18051		 * feature enabled (bLengthChange) then the end user will be able to override
18052
18053		 * this to a custom setting using a pop-up menu.
18054
18055		 *  @type int
18056
18057		 *  @default 10
18058
18059		 *  @dtopt Options
18060
18061		 * 
18062
18063		 *  @example
18064
18065		 *    $(document).ready( function() {
18066
18067		 *      $('#example').dataTable( {
18068
18069		 *        "iDisplayLength": 50
18070
18071		 *      } );
18072
18073		 *    } )
18074
18075		 */
18076
18077		"iDisplayLength": 10,
18078
18079	
18080
18081	
18082
18083		/**
18084
18085		 * Define the starting point for data display when using DataTables with
18086
18087		 * pagination. Note that this parameter is the number of records, rather than
18088
18089		 * the page number, so if you have 10 records per page and want to start on
18090
18091		 * the third page, it should be "20".
18092
18093		 *  @type int
18094
18095		 *  @default 0
18096
18097		 *  @dtopt Options
18098
18099		 * 
18100
18101		 *  @example
18102
18103		 *    $(document).ready( function() {
18104
18105		 *      $('#example').dataTable( {
18106
18107		 *        "iDisplayStart": 20
18108
18109		 *      } );
18110
18111		 *    } )
18112
18113		 */
18114
18115		"iDisplayStart": 0,
18116
18117	
18118
18119	
18120
18121		/**
18122
18123		 * The scroll gap is the amount of scrolling that is left to go before
18124
18125		 * DataTables will load the next 'page' of data automatically. You typically
18126
18127		 * want a gap which is big enough that the scrolling will be smooth for the
18128
18129		 * user, while not so large that it will load more data than need.
18130
18131		 *  @type int
18132
18133		 *  @default 100
18134
18135		 *  @dtopt Options
18136
18137		 * 
18138
18139		 *  @example
18140
18141		 *    $(document).ready( function() {
18142
18143		 *      $('#example').dataTable( {
18144
18145		 *        "bScrollInfinite": true,
18146
18147		 *        "bScrollCollapse": true,
18148
18149		 *        "sScrollY": "200px",
18150
18151		 *        "iScrollLoadGap": 50
18152
18153		 *      } );
18154
18155		 *    } );
18156
18157		 */
18158
18159		"iScrollLoadGap": 100,
18160
18161	
18162
18163	
18164
18165		/**
18166
18167		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
18168
18169		 * and filtering) by adding a tabindex attribute to the required elements. This
18170
18171		 * allows you to tab through the controls and press the enter key to activate them.
18172
18173		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
18174
18175		 * You can overrule this using this parameter if you wish. Use a value of -1 to
18176
18177		 * disable built-in keyboard navigation.
18178
18179		 *  @type int
18180
18181		 *  @default 0
18182
18183		 *  @dtopt Options
18184
18185		 * 
18186
18187		 *  @example
18188
18189		 *    $(document).ready( function() {
18190
18191		 *      $('#example').dataTable( {
18192
18193		 *        "iTabIndex": 1
18194
18195		 *      } );
18196
18197		 *    } );
18198
18199		 */
18200
18201		"iTabIndex": 0,
18202
18203	
18204
18205	
18206
18207		/**
18208
18209		 * All strings that DataTables uses in the user interface that it creates
18210
18211		 * are defined in this object, allowing you to modified them individually or
18212
18213		 * completely replace them all as required.
18214
18215		 *  @namespace
18216
18217		 */
18218
18219		"oLanguage": {
18220
18221			/**
18222
18223			 * Strings that are used for WAI-ARIA labels and controls only (these are not
18224
18225			 * actually visible on the page, but will be read by screenreaders, and thus
18226
18227			 * must be internationalised as well).
18228
18229			 *  @namespace
18230
18231			 */
18232
18233			"oAria": {
18234
18235				/**
18236
18237				 * ARIA label that is added to the table headers when the column may be
18238
18239				 * sorted ascending by activing the column (click or return when focused).
18240
18241				 * Note that the column header is prefixed to this string.
18242
18243				 *  @type string
18244
18245				 *  @default : activate to sort column ascending
18246
18247				 *  @dtopt Language
18248
18249				 * 
18250
18251				 *  @example
18252
18253				 *    $(document).ready( function() {
18254
18255				 *      $('#example').dataTable( {
18256
18257				 *        "oLanguage": {
18258
18259				 *          "oAria": {
18260
18261				 *            "sSortAscending": " - click/return to sort ascending"
18262
18263				 *          }
18264
18265				 *        }
18266
18267				 *      } );
18268
18269				 *    } );
18270
18271				 */
18272
18273				"sSortAscending": ": activate to sort column ascending",
18274
18275	
18276
18277				/**
18278
18279				 * ARIA label that is added to the table headers when the column may be
18280
18281				 * sorted descending by activing the column (click or return when focused).
18282
18283				 * Note that the column header is prefixed to this string.
18284
18285				 *  @type string
18286
18287				 *  @default : activate to sort column ascending
18288
18289				 *  @dtopt Language
18290
18291				 * 
18292
18293				 *  @example
18294
18295				 *    $(document).ready( function() {
18296
18297				 *      $('#example').dataTable( {
18298
18299				 *        "oLanguage": {
18300
18301				 *          "oAria": {
18302
18303				 *            "sSortDescending": " - click/return to sort descending"
18304
18305				 *          }
18306
18307				 *        }
18308
18309				 *      } );
18310
18311				 *    } );
18312
18313				 */
18314
18315				"sSortDescending": ": activate to sort column descending"
18316
18317			},
18318
18319	
18320
18321			/**
18322
18323			 * Pagination string used by DataTables for the two built-in pagination
18324
18325			 * control types ("two_button" and "full_numbers")
18326
18327			 *  @namespace
18328
18329			 */
18330
18331			"oPaginate": {
18332
18333				/**
18334
18335				 * Text to use when using the 'full_numbers' type of pagination for the
18336
18337				 * button to take the user to the first page.
18338
18339				 *  @type string
18340
18341				 *  @default First
18342
18343				 *  @dtopt Language
18344
18345				 * 
18346
18347				 *  @example
18348
18349				 *    $(document).ready( function() {
18350
18351				 *      $('#example').dataTable( {
18352
18353				 *        "oLanguage": {
18354
18355				 *          "oPaginate": {
18356
18357				 *            "sFirst": "First page"
18358
18359				 *          }
18360
18361				 *        }
18362
18363				 *      } );
18364
18365				 *    } );
18366
18367				 */
18368
18369				"sFirst": "First",
18370
18371			
18372
18373			
18374
18375				/**
18376
18377				 * Text to use when using the 'full_numbers' type of pagination for the
18378
18379				 * button to take the user to the last page.
18380
18381				 *  @type string
18382
18383				 *  @default Last
18384
18385				 *  @dtopt Language
18386
18387				 * 
18388
18389				 *  @example
18390
18391				 *    $(document).ready( function() {
18392
18393				 *      $('#example').dataTable( {
18394
18395				 *        "oLanguage": {
18396
18397				 *          "oPaginate": {
18398
18399				 *            "sLast": "Last page"
18400
18401				 *          }
18402
18403				 *        }
18404
18405				 *      } );
18406
18407				 *    } );
18408
18409				 */
18410
18411				"sLast": "Last",
18412
18413			
18414
18415			
18416
18417				/**
18418
18419				 * Text to use for the 'next' pagination button (to take the user to the 
18420
18421				 * next page).
18422
18423				 *  @type string
18424
18425				 *  @default Next
18426
18427				 *  @dtopt Language
18428
18429				 * 
18430
18431				 *  @example
18432
18433				 *    $(document).ready( function() {
18434
18435				 *      $('#example').dataTable( {
18436
18437				 *        "oLanguage": {
18438
18439				 *          "oPaginate": {
18440
18441				 *            "sNext": "Next page"
18442
18443				 *          }
18444
18445				 *        }
18446
18447				 *      } );
18448
18449				 *    } );
18450
18451				 */
18452
18453				"sNext": "Next",
18454
18455			
18456
18457			
18458
18459				/**
18460
18461				 * Text to use for the 'previous' pagination button (to take the user to  
18462
18463				 * the previous page).
18464
18465				 *  @type string
18466
18467				 *  @default Previous
18468
18469				 *  @dtopt Language
18470
18471				 * 
18472
18473				 *  @example
18474
18475				 *    $(document).ready( function() {
18476
18477				 *      $('#example').dataTable( {
18478
18479				 *        "oLanguage": {
18480
18481				 *          "oPaginate": {
18482
18483				 *            "sPrevious": "Previous page"
18484
18485				 *          }
18486
18487				 *        }
18488
18489				 *      } );
18490
18491				 *    } );
18492
18493				 */
18494
18495				"sPrevious": "Previous"
18496
18497			},
18498
18499		
18500
18501			/**
18502
18503			 * This string is shown in preference to sZeroRecords when the table is
18504
18505			 * empty of data (regardless of filtering). Note that this is an optional
18506
18507			 * parameter - if it is not given, the value of sZeroRecords will be used
18508
18509			 * instead (either the default or given value).
18510
18511			 *  @type string
18512
18513			 *  @default No data available in table
18514
18515			 *  @dtopt Language
18516
18517			 * 
18518
18519			 *  @example
18520
18521			 *    $(document).ready( function() {
18522
18523			 *      $('#example').dataTable( {
18524
18525			 *        "oLanguage": {
18526
18527			 *          "sEmptyTable": "No data available in table"
18528
18529			 *        }
18530
18531			 *      } );
18532
18533			 *    } );
18534
18535			 */
18536
18537			"sEmptyTable": "No data available in table",
18538
18539		
18540
18541		
18542
18543			/**
18544
18545			 * This string gives information to the end user about the information that 
18546
18547			 * is current on display on the page. The _START_, _END_ and _TOTAL_ 
18548
18549			 * variables are all dynamically replaced as the table display updates, and 
18550
18551			 * can be freely moved or removed as the language requirements change.
18552
18553			 *  @type string
18554
18555			 *  @default Showing _START_ to _END_ of _TOTAL_ Businesses
18556
18557			 *  @dtopt Language
18558
18559			 * 
18560
18561			 *  @example
18562
18563			 *    $(document).ready( function() {
18564
18565			 *      $('#example').dataTable( {
18566
18567			 *        "oLanguage": {
18568
18569			 *          "sInfo": "Got a total of _TOTAL_ Businesses to show (_START_ to _END_)"
18570
18571			 *        }
18572
18573			 *      } );
18574
18575			 *    } );
18576
18577			 */
18578
18579			"sInfo": "Showing _START_ to _END_ of _TOTAL_",
18580
18581		
18582
18583		
18584
18585			/**
18586
18587			 * Display information string for when the table is empty. Typically the 
18588
18589			 * format of this string should match sInfo.
18590
18591			 *  @type string
18592
18593			 *  @default Showing 0 to 0 of 0 Businesses
18594
18595			 *  @dtopt Language
18596
18597			 * 
18598
18599			 *  @example
18600
18601			 *    $(document).ready( function() {
18602
18603			 *      $('#example').dataTable( {
18604
18605			 *        "oLanguage": {
18606
18607			 *          "sInfoEmpty": "No Businesses to show"
18608
18609			 *        }
18610
18611			 *      } );
18612
18613			 *    } );
18614
18615			 */
18616
18617			"sInfoEmpty": "Showing 0 to 0 of 0",
18618
18619		
18620
18621		
18622
18623			/**
18624
18625			 * When a user filters the information in a table, this string is appended 
18626
18627			 * to the information (sInfo) to give an idea of how strong the filtering 
18628
18629			 * is. The variable _MAX_ is dynamically updated.
18630
18631			 *  @type string
18632
18633			 *  @default (filtered from _MAX_ total Businesses)
18634
18635			 *  @dtopt Language
18636
18637			 * 
18638
18639			 *  @example
18640
18641			 *    $(document).ready( function() {
18642
18643			 *      $('#example').dataTable( {
18644
18645			 *        "oLanguage": {
18646
18647			 *          "sInfoFiltered": " - filtering from _MAX_ records"
18648
18649			 *        }
18650
18651			 *      } );
18652
18653			 *    } );
18654
18655			 */
18656
18657			"sInfoFiltered": "(filtered from _MAX_ total)",
18658
18659		
18660
18661		
18662
18663			/**
18664
18665			 * If can be useful to append extra information to the info string at times,
18666
18667			 * and this variable does exactly that. This information will be appended to
18668
18669			 * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
18670
18671			 * being used) at all times.
18672
18673			 *  @type string
18674
18675			 *  @default <i>Empty string</i>
18676
18677			 *  @dtopt Language
18678
18679			 * 
18680
18681			 *  @example
18682
18683			 *    $(document).ready( function() {
18684
18685			 *      $('#example').dataTable( {
18686
18687			 *        "oLanguage": {
18688
18689			 *          "sInfoPostFix": "All records shown are derived from real information."
18690
18691			 *        }
18692
18693			 *      } );
18694
18695			 *    } );
18696
18697			 */
18698
18699			"sInfoPostFix": "",
18700
18701		
18702
18703		
18704
18705			/**
18706
18707			 * DataTables has a build in number formatter (fnFormatNumber) which is used
18708
18709			 * to format large numbers that are used in the table information. By
18710
18711			 * default a comma is used, but this can be trivially changed to any
18712
18713			 * character you wish with this parameter.
18714
18715			 *  @type string
18716
18717			 *  @default ,
18718
18719			 *  @dtopt Language
18720
18721			 * 
18722
18723			 *  @example
18724
18725			 *    $(document).ready( function() {
18726
18727			 *      $('#example').dataTable( {
18728
18729			 *        "oLanguage": {
18730
18731			 *          "sInfoThousands": "'"
18732
18733			 *        }
18734
18735			 *      } );
18736
18737			 *    } );
18738
18739			 */
18740
18741			"sInfoThousands": ",",
18742
18743		
18744
18745		
18746
18747			/**
18748
18749			 * Detail the action that will be taken when the drop down menu for the
18750
18751			 * pagination length option is changed. The '_MENU_' variable is replaced
18752
18753			 * with a default select list of 10, 25, 50 and 100, and can be replaced
18754
18755			 * with a custom select box if required.
18756
18757			 *  @type string
18758
18759			 *  @default Show _MENU_ Businesses
18760
18761			 *  @dtopt Language
18762
18763			 * 
18764
18765			 *  @example
18766
18767			 *    // Language change only
18768
18769			 *    $(document).ready( function() {
18770
18771			 *      $('#example').dataTable( {
18772
18773			 *        "oLanguage": {
18774
18775			 *          "sLengthMenu": "Display _MENU_ records"
18776
18777			 *        }
18778
18779			 *      } );
18780
18781			 *    } );
18782
18783			 *    
18784
18785			 *  @example
18786
18787			 *    // Language and options change
18788
18789			 *    $(document).ready( function() {
18790
18791			 *      $('#example').dataTable( {
18792
18793			 *        "oLanguage": {
18794
18795			 *          "sLengthMenu": 'Display <select>'+
18796
18797			 *            '<option value="10">10</option>'+
18798
18799			 *            '<option value="20">20</option>'+
18800
18801			 *            '<option value="30">30</option>'+
18802
18803			 *            '<option value="40">40</option>'+
18804
18805			 *            '<option value="50">50</option>'+
18806
18807			 *            '<option value="-1">All</option>'+
18808
18809			 *            '</select> records'
18810
18811			 *        }
18812
18813			 *      } );
18814
18815			 *    } );
18816
18817			 */
18818
18819			"sLengthMenu": "Show _MENU_",
18820
18821		
18822
18823		
18824
18825			/**
18826
18827			 * When using Ajax sourced data and during the first draw when DataTables is
18828
18829			 * gathering the data, this message is shown in an empty row in the table to
18830
18831			 * indicate to the end user the the data is being loaded. Note that this
18832
18833			 * parameter is not used when loading data by server-side processing, just
18834
18835			 * Ajax sourced data with client-side processing.
18836
18837			 *  @type string
18838
18839			 *  @default Loading...
18840
18841			 *  @dtopt Language
18842
18843			 * 
18844
18845			 *  @example
18846
18847			 *    $(document).ready( function() {
18848
18849			 *      $('#example').dataTable( {
18850
18851			 *        "oLanguage": {
18852
18853			 *          "sLoadingRecords": "Please wait - loading..."
18854
18855			 *        }
18856
18857			 *      } );
18858
18859			 *    } );
18860
18861			 */
18862
18863			"sLoadingRecords": "Loading...",
18864
18865		
18866
18867		
18868
18869			/**
18870
18871			 * Text which is displayed when the table is processing a user action
18872
18873			 * (usually a sort command or similar).
18874
18875			 *  @type string
18876
18877			 *  @default Processing...
18878
18879			 *  @dtopt Language
18880
18881			 * 
18882
18883			 *  @example
18884
18885			 *    $(document).ready( function() {
18886
18887			 *      $('#example').dataTable( {
18888
18889			 *        "oLanguage": {
18890
18891			 *          "sProcessing": "DataTables is currently busy"
18892
18893			 *        }
18894
18895			 *      } );
18896
18897			 *    } );
18898
18899			 */
18900
18901			"sProcessing": "Processing...",
18902
18903		
18904
18905		
18906
18907			/**
18908
18909			 * Details the actions that will be taken when the user types into the
18910
18911			 * filtering input text box. The variable "_INPUT_", if used in the string,
18912
18913			 * is replaced with the HTML text box for the filtering input allowing
18914
18915			 * control over where it appears in the string. If "_INPUT_" is not given
18916
18917			 * then the input box is appended to the string automatically.
18918
18919			 *  @type string
18920
18921			 *  @default Search:
18922
18923			 *  @dtopt Language
18924
18925			 * 
18926
18927			 *  @example
18928
18929			 *    // Input text box will be appended at the end automatically
18930
18931			 *    $(document).ready( function() {
18932
18933			 *      $('#example').dataTable( {
18934
18935			 *        "oLanguage": {
18936
18937			 *          "sSearch": "Filter records:"
18938
18939			 *        }
18940
18941			 *      } );
18942
18943			 *    } );
18944
18945			 *    
18946
18947			 *  @example
18948
18949			 *    // Specify where the filter should appear
18950
18951			 *    $(document).ready( function() {
18952
18953			 *      $('#example').dataTable( {
18954
18955			 *        "oLanguage": {
18956
18957			 *          "sSearch": "Apply filter _INPUT_ to table"
18958
18959			 *        }
18960
18961			 *      } );
18962
18963			 *    } );
18964
18965			 */
18966
18967			"sSearch": "Search:",
18968
18969		
18970
18971		
18972
18973			/**
18974
18975			 * All of the language information can be stored in a file on the
18976
18977			 * server-side, which DataTables will look up if this parameter is passed.
18978
18979			 * It must store the URL of the language file, which is in a JSON format,
18980
18981			 * and the object has the same properties as the oLanguage object in the
18982
18983			 * initialiser object (i.e. the above parameters). Please refer to one of
18984
18985			 * the example language files to see how this works in action.
18986
18987			 *  @type string
18988
18989			 *  @default <i>Empty string - i.e. disabled</i>
18990
18991			 *  @dtopt Language
18992
18993			 * 
18994
18995			 *  @example
18996
18997			 *    $(document).ready( function() {
18998
18999			 *      $('#example').dataTable( {
19000
19001			 *        "oLanguage": {
19002
19003			 *          "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
19004
19005			 *        }
19006
19007			 *      } );
19008
19009			 *    } );
19010
19011			 */
19012
19013			"sUrl": "",
19014
19015		
19016
19017		
19018
19019			/**
19020
19021			 * Text shown inside the table records when the is no information to be
19022
19023			 * displayed after filtering. sEmptyTable is shown when there is simply no
19024
19025			 * information in the table at all (regardless of filtering).
19026
19027			 *  @type string
19028
19029			 *  @default No matching records found
19030
19031			 *  @dtopt Language
19032
19033			 * 
19034
19035			 *  @example
19036
19037			 *    $(document).ready( function() {
19038
19039			 *      $('#example').dataTable( {
19040
19041			 *        "oLanguage": {
19042
19043			 *          "sZeroRecords": "No records to display"
19044
19045			 *        }
19046
19047			 *      } );
19048
19049			 *    } );
19050
19051			 */
19052
19053			"sZeroRecords": "Sorry no found. Try a different search. "
19054
19055		},
19056
19057	
19058
19059	
19060
19061		/**
19062
19063		 * This parameter allows you to have define the global filtering state at
19064
19065		 * initialisation time. As an object the "sSearch" parameter must be
19066
19067		 * defined, but all other parameters are optional. When "bRegex" is true,
19068
19069		 * the search string will be treated as a regular expression, when false
19070
19071		 * (default) it will be treated as a straight string. When "bSmart"
19072
19073		 * DataTables will use it's smart filtering methods (to word match at
19074
19075		 * any point in the data), when false this will not be done.
19076
19077		 *  @namespace
19078
19079		 *  @extends DataTable.models.oSearch
19080
19081		 *  @dtopt Options
19082
19083		 * 
19084
19085		 *  @example
19086
19087		 *    $(document).ready( function() {
19088
19089		 *      $('#example').dataTable( {
19090
19091		 *        "oSearch": {"sSearch": "Initial search"}
19092
19093		 *      } );
19094
19095		 *    } )
19096
19097		 */
19098
19099		"oSearch": $.extend( {}, DataTable.models.oSearch ),
19100
19101	
19102
19103	
19104
19105		/**
19106
19107		 * By default DataTables will look for the property 'aaData' when obtaining
19108
19109		 * data from an Ajax source or for server-side processing - this parameter
19110
19111		 * allows that property to be changed. You can use Javascript dotted object
19112
19113		 * notation to get a data source for multiple levels of nesting.
19114
19115		 *  @type string
19116
19117		 *  @default aaData
19118
19119		 *  @dtopt Options
19120
19121		 *  @dtopt Server-side
19122
19123		 * 
19124
19125		 *  @example
19126
19127		 *    // Get data from { "data": [...] }
19128
19129		 *    $(document).ready( function() {
19130
19131		 *      var oTable = $('#example').dataTable( {
19132
19133		 *        "sAjaxSource": "sources/data.txt",
19134
19135		 *        "sAjaxDataProp": "data"
19136
19137		 *      } );
19138
19139		 *    } );
19140
19141		 *    
19142
19143		 *  @example
19144
19145		 *    // Get data from { "data": { "inner": [...] } }
19146
19147		 *    $(document).ready( function() {
19148
19149		 *      var oTable = $('#example').dataTable( {
19150
19151		 *        "sAjaxSource": "sources/data.txt",
19152
19153		 *        "sAjaxDataProp": "data.inner"
19154
19155		 *      } );
19156
19157		 *    } );
19158
19159		 */
19160
19161		"sAjaxDataProp": "aaData",
19162
19163	
19164
19165	
19166
19167		/**
19168
19169		 * You can instruct DataTables to load data from an external source using this
19170
19171		 * parameter (use aData if you want to pass data in you already have). Simply
19172
19173		 * provide a url a JSON object can be obtained from. This object must include
19174
19175		 * the parameter 'aaData' which is the data source for the table.
19176
19177		 *  @type string
19178
19179		 *  @default null
19180
19181		 *  @dtopt Options
19182
19183		 *  @dtopt Server-side
19184
19185		 * 
19186
19187		 *  @example
19188
19189		 *    $(document).ready( function() {
19190
19191		 *      $('#example').dataTable( {
19192
19193		 *        "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
19194
19195		 *      } );
19196
19197		 *    } )
19198
19199		 */
19200
19201		"sAjaxSource": null,
19202
19203	
19204
19205	
19206
19207		/**
19208
19209		 * This parameter can be used to override the default prefix that DataTables
19210
19211		 * assigns to a cookie when state saving is enabled.
19212
19213		 *  @type string
19214
19215		 *  @default SpryMedia_DataTables_
19216
19217		 *  @dtopt Options
19218
19219		 * 
19220
19221		 *  @example
19222
19223		 *    $(document).ready( function() {
19224
19225		 *      $('#example').dataTable( {
19226
19227		 *        "sCookiePrefix": "my_datatable_",
19228
19229		 *      } );
19230
19231		 *    } );
19232
19233		 */
19234
19235		"sCookiePrefix": "SpryMedia_DataTables_",
19236
19237	
19238
19239	
19240
19241		/**
19242
19243		 * This initialisation variable allows you to specify exactly where in the
19244
19245		 * DOM you want DataTables to inject the various controls it adds to the page
19246
19247		 * (for example you might want the pagination controls at the top of the
19248
19249		 * table). DIV elements (with or without a custom class) can also be added to
19250
19251		 * aid styling. The follow syntax is used:
19252
19253		 *   <ul>
19254
19255		 *     <li>The following options are allowed:	
19256
19257		 *       <ul>
19258
19259		 *         <li>'l' - Length changing</li
19260
19261		 *         <li>'f' - Filtering input</li>
19262
19263		 *         <li>'t' - The table!</li>
19264
19265		 *         <li>'i' - Information</li>
19266
19267		 *         <li>'p' - Pagination</li>
19268
19269		 *         <li>'r' - pRocessing</li>
19270
19271		 *       </ul>
19272
19273		 *     </li>
19274
19275		 *     <li>The following constants are allowed:
19276
19277		 *       <ul>
19278
19279		 *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
19280
19281		 *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
19282
19283		 *       </ul>
19284
19285		 *     </li>
19286
19287		 *     <li>The following syntax is expected:
19288
19289		 *       <ul>
19290
19291		 *         <li>'&lt;' and '&gt;' - div elements</li>
19292
19293		 *         <li>'&lt;"class" and '&gt;' - div with a class</li>
19294
19295		 *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
19296
19297		 *       </ul>
19298
19299		 *     </li>
19300
19301		 *     <li>Examples:
19302
19303		 *       <ul>
19304
19305		 *         <li>'&lt;"wrapper"flipt&gt;'</li>
19306
19307		 *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
19308
19309		 *       </ul>
19310
19311		 *     </li>
19312
19313		 *   </ul>
19314
19315		 *  @type string
19316
19317		 *  @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b> 
19318
19319		 *    <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
19320
19321		 *  @dtopt Options
19322
19323		 * 
19324
19325		 *  @example
19326
19327		 *    $(document).ready( function() {
19328
19329		 *      $('#example').dataTable( {
19330
19331		 *        "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
19332
19333		 *      } );
19334
19335		 *    } );
19336
19337		 */
19338
19339		"sDom": "lfrtip",
19340
19341	
19342
19343	
19344
19345		/**
19346
19347		 * DataTables features two different built-in pagination interaction methods
19348
19349		 * ('two_button' or 'full_numbers') which present different page controls to
19350
19351		 * the end user. Further methods can be added using the API (see below).
19352
19353		 *  @type string
19354
19355		 *  @default two_button
19356
19357		 *  @dtopt Options
19358
19359		 * 
19360
19361		 *  @example
19362
19363		 *    $(document).ready( function() {
19364
19365		 *      $('#example').dataTable( {
19366
19367		 *        "sPaginationType": "full_numbers"
19368
19369		 *      } );
19370
19371		 *    } )
19372
19373		 */
19374
19375		"sPaginationType": "two_button",
19376
19377	
19378
19379	
19380
19381		/**
19382
19383		 * Enable horizontal scrolling. When a table is too wide to fit into a certain
19384
19385		 * layout, or you have a large number of columns in the table, you can enable
19386
19387		 * x-scrolling to show the table in a viewport, which can be scrolled. This
19388
19389		 * property can be any CSS unit, or a number (in which case it will be treated
19390
19391		 * as a pixel measurement).
19392
19393		 *  @type string
19394
19395		 *  @default <i>blank string - i.e. disabled</i>
19396
19397		 *  @dtopt Features
19398
19399		 * 
19400
19401		 *  @example
19402
19403		 *    $(document).ready( function() {
19404
19405		 *      $('#example').dataTable( {
19406
19407		 *        "sScrollX": "100%",
19408
19409		 *        "bScrollCollapse": true
19410
19411		 *      } );
19412
19413		 *    } );
19414
19415		 */
19416
19417		"sScrollX": "",
19418
19419	
19420
19421	
19422
19423		/**
19424
19425		 * This property can be used to force a DataTable to use more width than it
19426
19427		 * might otherwise do when x-scrolling is enabled. For example if you have a
19428
19429		 * table which requires to be well spaced, this parameter is useful for
19430
19431		 * "over-sizing" the table, and thus forcing scrolling. This property can by
19432
19433		 * any CSS unit, or a number (in which case it will be treated as a pixel
19434
19435		 * measurement).
19436
19437		 *  @type string
19438
19439		 *  @default <i>blank string - i.e. disabled</i>
19440
19441		 *  @dtopt Options
19442
19443		 * 
19444
19445		 *  @example
19446
19447		 *    $(document).ready( function() {
19448
19449		 *      $('#example').dataTable( {
19450
19451		 *        "sScrollX": "100%",
19452
19453		 *        "sScrollXInner": "110%"
19454
19455		 *      } );
19456
19457		 *    } );
19458
19459		 */
19460
19461		"sScrollXInner": "",
19462
19463	
19464
19465	
19466
19467		/**
19468
19469		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
19470
19471		 * to the given height, and enable scrolling for any data which overflows the
19472
19473		 * current viewport. This can be used as an alternative to paging to display
19474
19475		 * a lot of data in a small area (although paging and scrolling can both be
19476
19477		 * enabled at the same time). This property can be any CSS unit, or a number
19478
19479		 * (in which case it will be treated as a pixel measurement).
19480
19481		 *  @type string
19482
19483		 *  @default <i>blank string - i.e. disabled</i>
19484
19485		 *  @dtopt Features
19486
19487		 * 
19488
19489		 *  @example
19490
19491		 *    $(document).ready( function() {
19492
19493		 *      $('#example').dataTable( {
19494
19495		 *        "sScrollY": "200px",
19496
19497		 *        "bPaginate": false
19498
19499		 *      } );
19500
19501		 *    } );
19502
19503		 */
19504
19505		"sScrollY": "",
19506
19507	
19508
19509	
19510
19511		/**
19512
19513		 * Set the HTTP method that is used to make the Ajax call for server-side
19514
19515		 * processing or Ajax sourced data.
19516
19517		 *  @type string
19518
19519		 *  @default GET
19520
19521		 *  @dtopt Options
19522
19523		 *  @dtopt Server-side
19524
19525		 * 
19526
19527		 *  @example
19528
19529		 *    $(document).ready( function() {
19530
19531		 *      $('#example').dataTable( {
19532
19533		 *        "bServerSide": true,
19534
19535		 *        "sAjaxSource": "scripts/post.php",
19536
19537		 *        "sServerMethod": "POST"
19538
19539		 *      } );
19540
19541		 *    } );
19542
19543		 */
19544
19545		"sServerMethod": "GET"
19546
19547	};
19548
19549	
19550
19551	
19552
19553	
19554
19555	/**
19556
19557	 * Column options that can be given to DataTables at initialisation time.
19558
19559	 *  @namespace
19560
19561	 */
19562
19563	DataTable.defaults.columns = {
19564
19565		/**
19566
19567		 * Allows a column's sorting to take multiple columns into account when 
19568
19569		 * doing a sort. For example first name / last name columns make sense to 
19570
19571		 * do a multi-column sort over the two columns.
19572
19573		 *  @type array
19574
19575		 *  @default null <i>Takes the value of the column index automatically</i>
19576
19577		 *  @dtopt Columns
19578
19579		 * 
19580
19581		 *  @example
19582
19583		 *    // Using aoColumnDefs
19584
19585		 *    $(document).ready( function() {
19586
19587		 *      $('#example').dataTable( {
19588
19589		 *        "aoColumnDefs": [
19590
19591		 *          { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
19592
19593		 *          { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
19594
19595		 *          { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
19596
19597		 *        ]
19598
19599		 *      } );
19600
19601		 *    } );
19602
19603		 *    
19604
19605		 *  @example
19606
19607		 *    // Using aoColumns
19608
19609		 *    $(document).ready( function() {
19610
19611		 *      $('#example').dataTable( {
19612
19613		 *        "aoColumns": [
19614
19615		 *          { "aDataSort": [ 0, 1 ] },
19616
19617		 *          { "aDataSort": [ 1, 0 ] },
19618
19619		 *          { "aDataSort": [ 2, 3, 4 ] },
19620
19621		 *          null,
19622
19623		 *          null
19624
19625		 *        ]
19626
19627		 *      } );
19628
19629		 *    } );
19630
19631		 */
19632
19633		"aDataSort": null,
19634
19635	
19636
19637	
19638
19639		/**
19640
19641		 * You can control the default sorting direction, and even alter the behaviour
19642
19643		 * of the sort handler (i.e. only allow ascending sorting etc) using this
19644
19645		 * parameter.
19646
19647		 *  @type array
19648
19649		 *  @default [ 'asc', 'desc' ]
19650
19651		 *  @dtopt Columns
19652
19653		 * 
19654
19655		 *  @example
19656
19657		 *    // Using aoColumnDefs
19658
19659		 *    $(document).ready( function() {
19660
19661		 *      $('#example').dataTable( {
19662
19663		 *        "aoColumnDefs": [
19664
19665		 *          { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
19666
19667		 *          { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
19668
19669		 *          { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
19670
19671		 *        ]
19672
19673		 *      } );
19674
19675		 *    } );
19676
19677		 *    
19678
19679		 *  @example
19680
19681		 *    // Using aoColumns
19682
19683		 *    $(document).ready( function() {
19684
19685		 *      $('#example').dataTable( {
19686
19687		 *        "aoColumns": [
19688
19689		 *          null,
19690
19691		 *          { "asSorting": [ "asc" ] },
19692
19693		 *          { "asSorting": [ "desc", "asc", "asc" ] },
19694
19695		 *          { "asSorting": [ "desc" ] },
19696
19697		 *          null
19698
19699		 *        ]
19700
19701		 *      } );
19702
19703		 *    } );
19704
19705		 */
19706
19707		"asSorting": [ 'asc', 'desc' ],
19708
19709	
19710
19711	
19712
19713		/**
19714
19715		 * Enable or disable filtering on the data in this column.
19716
19717		 *  @type boolean
19718
19719		 *  @default true
19720
19721		 *  @dtopt Columns
19722
19723		 * 
19724
19725		 *  @example
19726
19727		 *    // Using aoColumnDefs
19728
19729		 *    $(document).ready( function() {
19730
19731		 *      $('#example').dataTable( {
19732
19733		 *        "aoColumnDefs": [ 
19734
19735		 *          { "bSearchable": false, "aTargets": [ 0 ] }
19736
19737		 *        ] } );
19738
19739		 *    } );
19740
19741		 *    
19742
19743		 *  @example
19744
19745		 *    // Using aoColumns
19746
19747		 *    $(document).ready( function() {
19748
19749		 *      $('#example').dataTable( {
19750
19751		 *        "aoColumns": [ 
19752
19753		 *          { "bSearchable": false },
19754
19755		 *          null,
19756
19757		 *          null,
19758
19759		 *          null,
19760
19761		 *          null
19762
19763		 *        ] } );
19764
19765		 *    } );
19766
19767		 */
19768
19769		"bSearchable": true,
19770
19771	
19772
19773	
19774
19775		/**
19776
19777		 * Enable or disable sorting on this column.
19778
19779		 *  @type boolean
19780
19781		 *  @default true
19782
19783		 *  @dtopt Columns
19784
19785		 * 
19786
19787		 *  @example
19788
19789		 *    // Using aoColumnDefs
19790
19791		 *    $(document).ready( function() {
19792
19793		 *      $('#example').dataTable( {
19794
19795		 *        "aoColumnDefs": [ 
19796
19797		 *          { "bSortable": false, "aTargets": [ 0 ] }
19798
19799		 *        ] } );
19800
19801		 *    } );
19802
19803		 *    
19804
19805		 *  @example
19806
19807		 *    // Using aoColumns
19808
19809		 *    $(document).ready( function() {
19810
19811		 *      $('#example').dataTable( {
19812
19813		 *        "aoColumns": [ 
19814
19815		 *          { "bSortable": false },
19816
19817		 *          null,
19818
19819		 *          null,
19820
19821		 *          null,
19822
19823		 *          null
19824
19825		 *        ] } );
19826
19827		 *    } );
19828
19829		 */
19830
19831		"bSortable": true,
19832
19833	
19834
19835	
19836
19837		/**
19838
19839		 * <code>Deprecated</code> When using fnRender() for a column, you may wish 
19840
19841		 * to use the original data (before rendering) for sorting and filtering 
19842
19843		 * (the default is to used the rendered data that the user can see). This 
19844
19845		 * may be useful for dates etc.
19846
19847		 * 
19848
19849		 * Please note that this option has now been deprecated and will be removed
19850
19851		 * in the next version of DataTables. Please use mRender / mData rather than
19852
19853		 * fnRender.
19854
19855		 *  @type boolean
19856
19857		 *  @default true
19858
19859		 *  @dtopt Columns
19860
19861		 *  @deprecated
19862
19863		 */
19864
19865		"bUseRendered": true,
19866
19867	
19868
19869	
19870
19871		/**
19872
19873		 * Enable or disable the display of this column.
19874
19875		 *  @type boolean
19876
19877		 *  @default true
19878
19879		 *  @dtopt Columns
19880
19881		 * 
19882
19883		 *  @example
19884
19885		 *    // Using aoColumnDefs
19886
19887		 *    $(document).ready( function() {
19888
19889		 *      $('#example').dataTable( {
19890
19891		 *        "aoColumnDefs": [ 
19892
19893		 *          { "bVisible": false, "aTargets": [ 0 ] }
19894
19895		 *        ] } );
19896
19897		 *    } );
19898
19899		 *    
19900
19901		 *  @example
19902
19903		 *    // Using aoColumns
19904
19905		 *    $(document).ready( function() {
19906
19907		 *      $('#example').dataTable( {
19908
19909		 *        "aoColumns": [ 
19910
19911		 *          { "bVisible": false },
19912
19913		 *          null,
19914
19915		 *          null,
19916
19917		 *          null,
19918
19919		 *          null
19920
19921		 *        ] } );
19922
19923		 *    } );
19924
19925		 */
19926
19927		"bVisible": true,
19928
19929		
19930
19931		
19932
19933		/**
19934
19935		 * Developer definable function that is called whenever a cell is created (Ajax source,
19936
19937		 * etc) or processed for input (DOM source). This can be used as a compliment to mRender
19938
19939		 * allowing you to modify the DOM element (add background colour for example) when the
19940
19941		 * element is available.
19942
19943		 *  @type function
19944
19945		 *  @param {element} nTd The TD node that has been created
19946
19947		 *  @param {*} sData The Data for the cell
19948
19949		 *  @param {array|object} oData The data for the whole row
19950
19951		 *  @param {int} iRow The row index for the aoData data store
19952
19953		 *  @param {int} iCol The column index for aoColumns
19954
19955		 *  @dtopt Columns
19956
19957		 * 
19958
19959		 *  @example
19960
19961		 *    $(document).ready( function() {
19962
19963		 *      $('#example').dataTable( {
19964
19965		 *        "aoColumnDefs": [ {
19966
19967		 *          "aTargets": [3],
19968
19969		 *          "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
19970
19971		 *            if ( sData == "1.7" ) {
19972
19973		 *              $(nTd).css('color', 'blue')
19974
19975		 *            }
19976
19977		 *          }
19978
19979		 *        } ]
19980
19981		 *      });
19982
19983		 *    } );
19984
19985		 */
19986
19987		"fnCreatedCell": null,
19988
19989	
19990
19991	
19992
19993		/**
19994
19995		 * <code>Deprecated</code> Custom display function that will be called for the 
19996
19997		 * display of each cell in this column.
19998
19999		 *
20000
20001		 * Please note that this option has now been deprecated and will be removed
20002
20003		 * in the next version of DataTables. Please use mRender / mData rather than
20004
20005		 * fnRender.
20006
20007		 *  @type function
20008
20009		 *  @param {object} o Object with the following parameters:
20010
20011		 *  @param {int}    o.iDataRow The row in aoData
20012
20013		 *  @param {int}    o.iDataColumn The column in question
20014
20015		 *  @param {array}  o.aData The data for the row in question
20016
20017		 *  @param {object} o.oSettings The settings object for this DataTables instance
20018
20019		 *  @param {object} o.mDataProp The data property used for this column
20020
20021		 *  @param {*}      val The current cell value
20022
20023		 *  @returns {string} The string you which to use in the display
20024
20025		 *  @dtopt Columns
20026
20027		 *  @deprecated
20028
20029		 */
20030
20031		"fnRender": null,
20032
20033	
20034
20035	
20036
20037		/**
20038
20039		 * The column index (starting from 0!) that you wish a sort to be performed
20040
20041		 * upon when this column is selected for sorting. This can be used for sorting
20042
20043		 * on hidden columns for example.
20044
20045		 *  @type int
20046
20047		 *  @default -1 <i>Use automatically calculated column index</i>
20048
20049		 *  @dtopt Columns
20050
20051		 * 
20052
20053		 *  @example
20054
20055		 *    // Using aoColumnDefs
20056
20057		 *    $(document).ready( function() {
20058
20059		 *      $('#example').dataTable( {
20060
20061		 *        "aoColumnDefs": [ 
20062
20063		 *          { "iDataSort": 1, "aTargets": [ 0 ] }
20064
20065		 *        ]
20066
20067		 *      } );
20068
20069		 *    } );
20070
20071		 *    
20072
20073		 *  @example
20074
20075		 *    // Using aoColumns
20076
20077		 *    $(document).ready( function() {
20078
20079		 *      $('#example').dataTable( {
20080
20081		 *        "aoColumns": [ 
20082
20083		 *          { "iDataSort": 1 },
20084
20085		 *          null,
20086
20087		 *          null,
20088
20089		 *          null,
20090
20091		 *          null
20092
20093		 *        ]
20094
20095		 *      } );
20096
20097		 *    } );
20098
20099		 */
20100
20101		"iDataSort": -1,
20102
20103	
20104
20105	
20106
20107		/**
20108
20109		 * This parameter has been replaced by mData in DataTables to ensure naming
20110
20111		 * consistency. mDataProp can still be used, as there is backwards compatibility
20112
20113		 * in DataTables for this option, but it is strongly recommended that you use
20114
20115		 * mData in preference to mDataProp.
20116
20117		 *  @name DataTable.defaults.columns.mDataProp
20118
20119		 */
20120
20121	
20122
20123	
20124
20125		/**
20126
20127		 * This property can be used to read data from any JSON data source property,
20128
20129		 * including deeply nested objects / properties. mData can be given in a
20130
20131		 * number of different ways which effect its behaviour:
20132
20133		 *   <ul>
20134
20135		 *     <li>integer - treated as an array index for the data source. This is the
20136
20137		 *       default that DataTables uses (incrementally increased for each column).</li>
20138
20139		 *     <li>string - read an object property from the data source. Note that you can
20140
20141		 *       use Javascript dotted notation to read deep properties / arrays from the
20142
20143		 *       data source.</li>
20144
20145		 *     <li>null - the sDefaultContent option will be used for the cell (null
20146
20147		 *       by default, so you will need to specify the default content you want -
20148
20149		 *       typically an empty string). This can be useful on generated columns such 
20150
20151		 *       as edit / delete action columns.</li>
20152
20153		 *     <li>function - the function given will be executed whenever DataTables 
20154
20155		 *       needs to set or get the data for a cell in the column. The function 
20156
20157		 *       takes three parameters:
20158
20159		 *       <ul>
20160
20161		 *         <li>{array|object} The data source for the row</li>
20162
20163		 *         <li>{string} The type call data requested - this will be 'set' when
20164
20165		 *           setting data or 'filter', 'display', 'type', 'sort' or undefined when 
20166
20167		 *           gathering data. Note that when <i>undefined</i> is given for the type
20168
20169		 *           DataTables expects to get the raw data for the object back</li>
20170
20171		 *         <li>{*} Data to set when the second parameter is 'set'.</li>
20172
20173		 *       </ul>
20174
20175		 *       The return value from the function is not required when 'set' is the type
20176
20177		 *       of call, but otherwise the return is what will be used for the data
20178
20179		 *       requested.</li>
20180
20181		 *    </ul>
20182
20183		 *
20184
20185		 * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change
20186
20187		 * reflects the flexibility of this property and is consistent with the naming of
20188
20189		 * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as
20190
20191		 * it automatically maps the old name to the new if required.
20192
20193		 *  @type string|int|function|null
20194
20195		 *  @default null <i>Use automatically calculated column index</i>
20196
20197		 *  @dtopt Columns
20198
20199		 * 
20200
20201		 *  @example
20202
20203		 *    // Read table data from objects
20204
20205		 *    $(document).ready( function() {
20206
20207		 *      var oTable = $('#example').dataTable( {
20208
20209		 *        "sAjaxSource": "sources/deep.txt",
20210
20211		 *        "aoColumns": [
20212
20213		 *          { "mData": "engine" },
20214
20215		 *          { "mData": "browser" },
20216
20217		 *          { "mData": "platform.inner" },
20218
20219		 *          { "mData": "platform.details.0" },
20220
20221		 *          { "mData": "platform.details.1" }
20222
20223		 *        ]
20224
20225		 *      } );
20226
20227		 *    } );
20228
20229		 * 
20230
20231		 *  @example
20232
20233		 *    // Using mData as a function to provide different information for
20234
20235		 *    // sorting, filtering and display. In this case, currency (price)
20236
20237		 *    $(document).ready( function() {
20238
20239		 *      var oTable = $('#example').dataTable( {
20240
20241		 *        "aoColumnDefs": [ {
20242
20243		 *          "aTargets": [ 0 ],
20244
20245		 *          "mData": function ( source, type, val ) {
20246
20247		 *            if (type === 'set') {
20248
20249		 *              source.price = val;
20250
20251		 *              // Store the computed dislay and filter values for efficiency
20252
20253		 *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
20254
20255		 *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
20256
20257		 *              return;
20258
20259		 *            }
20260
20261		 *            else if (type === 'display') {
20262
20263		 *              return source.price_display;
20264
20265		 *            }
20266
20267		 *            else if (type === 'filter') {
20268
20269		 *              return source.price_filter;
20270
20271		 *            }
20272
20273		 *            // 'sort', 'type' and undefined all just use the integer
20274
20275		 *            return source.price;
20276
20277		 *          }
20278
20279		 *        } ]
20280
20281		 *      } );
20282
20283		 *    } );
20284
20285		 */
20286
20287		"mData": null,
20288
20289	
20290
20291	
20292
20293		/**
20294
20295		 * This property is the rendering partner to mData and it is suggested that
20296
20297		 * when you want to manipulate data for display (including filtering, sorting etc)
20298
20299		 * but not altering the underlying data for the table, use this property. mData
20300
20301		 * can actually do everything this property can and more, but this parameter is
20302
20303		 * easier to use since there is no 'set' option. Like mData is can be given
20304
20305		 * in a number of different ways to effect its behaviour, with the addition of 
20306
20307		 * supporting array syntax for easy outputting of arrays (including arrays of
20308
20309		 * objects):
20310
20311		 *   <ul>
20312
20313		 *     <li>integer - treated as an array index for the data source. This is the
20314
20315		 *       default that DataTables uses (incrementally increased for each column).</li>
20316
20317		 *     <li>string - read an object property from the data source. Note that you can
20318
20319		 *       use Javascript dotted notation to read deep properties / arrays from the
20320
20321		 *       data source and also array brackets to indicate that the data reader should
20322
20323		 *       loop over the data source array. When characters are given between the array
20324
20325		 *       brackets, these characters are used to join the data source array together.
20326
20327		 *       For example: "accounts[, ].name" would result in a comma separated list with
20328
20329		 *       the 'name' value from the 'accounts' array of objects.</li>
20330
20331		 *     <li>function - the function given will be executed whenever DataTables 
20332
20333		 *       needs to set or get the data for a cell in the column. The function 
20334
20335		 *       takes three parameters:
20336
20337		 *       <ul>
20338
20339		 *         <li>{array|object} The data source for the row (based on mData)</li>
20340
20341		 *         <li>{string} The type call data requested - this will be 'filter', 'display', 
20342
20343		 *           'type' or 'sort'.</li>
20344
20345		 *         <li>{array|object} The full data source for the row (not based on mData)</li>
20346
20347		 *       </ul>
20348
20349		 *       The return value from the function is what will be used for the data
20350
20351		 *       requested.</li>
20352
20353		 *    </ul>
20354
20355		 *  @type string|int|function|null
20356
20357		 *  @default null <i>Use mData</i>
20358
20359		 *  @dtopt Columns
20360
20361		 * 
20362
20363		 *  @example
20364
20365		 *    // Create a comma separated list from an array of objects
20366
20367		 *    $(document).ready( function() {
20368
20369		 *      var oTable = $('#example').dataTable( {
20370
20371		 *        "sAjaxSource": "sources/deep.txt",
20372
20373		 *        "aoColumns": [
20374
20375		 *          { "mData": "engine" },
20376
20377		 *          { "mData": "browser" },
20378
20379		 *          {
20380
20381		 *            "mData": "platform",
20382
20383		 *            "mRender": "[, ].name"
20384
20385		 *          }
20386
20387		 *        ]
20388
20389		 *      } );
20390
20391		 *    } );
20392
20393		 * 
20394
20395		 *  @example
20396
20397		 *    // Use as a function to create a link from the data source
20398
20399		 *    $(document).ready( function() {
20400
20401		 *      var oTable = $('#example').dataTable( {
20402
20403		 *        "aoColumnDefs": [
20404
20405		 *        {
20406
20407		 *          "aTargets": [ 0 ],
20408
20409		 *          "mData": "download_link",
20410
20411		 *          "mRender": function ( data, type, full ) {
20412
20413		 *            return '<a href="'+data+'">Download</a>';
20414
20415		 *          }
20416
20417		 *        ]
20418
20419		 *      } );
20420
20421		 *    } );
20422
20423		 */
20424
20425		"mRender": null,
20426
20427	
20428
20429	
20430
20431		/**
20432
20433		 * Change the cell type created for the column - either TD cells or TH cells. This
20434
20435		 * can be useful as TH cells have semantic meaning in the table body, allowing them
20436
20437		 * to act as a header for a row (you may wish to add scope='row' to the TH elements).
20438
20439		 *  @type string
20440
20441		 *  @default td
20442
20443		 *  @dtopt Columns
20444
20445		 * 
20446
20447		 *  @example
20448
20449		 *    // Make the first column use TH cells
20450
20451		 *    $(document).ready( function() {
20452
20453		 *      var oTable = $('#example').dataTable( {
20454
20455		 *        "aoColumnDefs": [ {
20456
20457		 *          "aTargets": [ 0 ],
20458
20459		 *          "sCellType": "th"
20460
20461		 *        } ]
20462
20463		 *      } );
20464
20465		 *    } );
20466
20467		 */
20468
20469		"sCellType": "td",
20470
20471	
20472
20473	
20474
20475		/**
20476
20477		 * Class to give to each cell in this column.
20478
20479		 *  @type string
20480
20481		 *  @default <i>Empty string</i>
20482
20483		 *  @dtopt Columns
20484
20485		 * 
20486
20487		 *  @example
20488
20489		 *    // Using aoColumnDefs
20490
20491		 *    $(document).ready( function() {
20492
20493		 *      $('#example').dataTable( {
20494
20495		 *        "aoColumnDefs": [ 
20496
20497		 *          { "sClass": "my_class", "aTargets": [ 0 ] }
20498
20499		 *        ]
20500
20501		 *      } );
20502
20503		 *    } );
20504
20505		 *    
20506
20507		 *  @example
20508
20509		 *    // Using aoColumns
20510
20511		 *    $(document).ready( function() {
20512
20513		 *      $('#example').dataTable( {
20514
20515		 *        "aoColumns": [ 
20516
20517		 *          { "sClass": "my_class" },
20518
20519		 *          null,
20520
20521		 *          null,
20522
20523		 *          null,
20524
20525		 *          null
20526
20527		 *        ]
20528
20529		 *      } );
20530
20531		 *    } );
20532
20533		 */
20534
20535		"sClass": "",
20536
20537		
20538
20539		/**
20540
20541		 * When DataTables calculates the column widths to assign to each column,
20542
20543		 * it finds the longest string in each column and then constructs a
20544
20545		 * temporary table and reads the widths from that. The problem with this
20546
20547		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
20548
20549		 * string - thus the calculation can go wrong (doing it properly and putting
20550
20551		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
20552
20553		 * a "work around" we provide this option. It will append its value to the
20554
20555		 * text that is found to be the longest string for the column - i.e. padding.
20556
20557		 * Generally you shouldn't need this, and it is not documented on the 
20558
20559		 * general DataTables.net documentation
20560
20561		 *  @type string
20562
20563		 *  @default <i>Empty string<i>
20564
20565		 *  @dtopt Columns
20566
20567		 *    
20568
20569		 *  @example
20570
20571		 *    // Using aoColumns
20572
20573		 *    $(document).ready( function() {
20574
20575		 *      $('#example').dataTable( {
20576
20577		 *        "aoColumns": [ 
20578
20579		 *          null,
20580
20581		 *          null,
20582
20583		 *          null,
20584
20585		 *          {
20586
20587		 *            "sContentPadding": "mmm"
20588
20589		 *          }
20590
20591		 *        ]
20592
20593		 *      } );
20594
20595		 *    } );
20596
20597		 */
20598
20599		"sContentPadding": "",
20600
20601	
20602
20603	
20604
20605		/**
20606
20607		 * Allows a default value to be given for a column's data, and will be used
20608
20609		 * whenever a null data source is encountered (this can be because mData
20610
20611		 * is set to null, or because the data source itself is null).
20612
20613		 *  @type string
20614
20615		 *  @default null
20616
20617		 *  @dtopt Columns
20618
20619		 * 
20620
20621		 *  @example
20622
20623		 *    // Using aoColumnDefs
20624
20625		 *    $(document).ready( function() {
20626
20627		 *      $('#example').dataTable( {
20628
20629		 *        "aoColumnDefs": [ 
20630
20631		 *          {
20632
20633		 *            "mData": null,
20634
20635		 *            "sDefaultContent": "Edit",
20636
20637		 *            "aTargets": [ -1 ]
20638
20639		 *          }
20640
20641		 *        ]
20642
20643		 *      } );
20644
20645		 *    } );
20646
20647		 *    
20648
20649		 *  @example
20650
20651		 *    // Using aoColumns
20652
20653		 *    $(document).ready( function() {
20654
20655		 *      $('#example').dataTable( {
20656
20657		 *        "aoColumns": [ 
20658
20659		 *          null,
20660
20661		 *          null,
20662
20663		 *          null,
20664
20665		 *          {
20666
20667		 *            "mData": null,
20668
20669		 *            "sDefaultContent": "Edit"
20670
20671		 *          }
20672
20673		 *        ]
20674
20675		 *      } );
20676
20677		 *    } );
20678
20679		 */
20680
20681		"sDefaultContent": null,
20682
20683	
20684
20685	
20686
20687		/**
20688
20689		 * This parameter is only used in DataTables' server-side processing. It can
20690
20691		 * be exceptionally useful to know what columns are being displayed on the
20692
20693		 * client side, and to map these to database fields. When defined, the names
20694
20695		 * also allow DataTables to reorder information from the server if it comes
20696
20697		 * back in an unexpected order (i.e. if you switch your columns around on the
20698
20699		 * client-side, your server-side code does not also need updating).
20700
20701		 *  @type string
20702
20703		 *  @default <i>Empty string</i>
20704
20705		 *  @dtopt Columns
20706
20707		 * 
20708
20709		 *  @example
20710
20711		 *    // Using aoColumnDefs
20712
20713		 *    $(document).ready( function() {
20714
20715		 *      $('#example').dataTable( {
20716
20717		 *        "aoColumnDefs": [ 
20718
20719		 *          { "sName": "engine", "aTargets": [ 0 ] },
20720
20721		 *          { "sName": "browser", "aTargets": [ 1 ] },
20722
20723		 *          { "sName": "platform", "aTargets": [ 2 ] },
20724
20725		 *          { "sName": "version", "aTargets": [ 3 ] },
20726
20727		 *          { "sName": "grade", "aTargets": [ 4 ] }
20728
20729		 *        ]
20730
20731		 *      } );
20732
20733		 *    } );
20734
20735		 *    
20736
20737		 *  @example
20738
20739		 *    // Using aoColumns
20740
20741		 *    $(document).ready( function() {
20742
20743		 *      $('#example').dataTable( {
20744
20745		 *        "aoColumns": [ 
20746
20747		 *          { "sName": "engine" },
20748
20749		 *          { "sName": "browser" },
20750
20751		 *          { "sName": "platform" },
20752
20753		 *          { "sName": "version" },
20754
20755		 *          { "sName": "grade" }
20756
20757		 *        ]
20758
20759		 *      } );
20760
20761		 *    } );
20762
20763		 */
20764
20765		"sName": "",
20766
20767	
20768
20769	
20770
20771		/**
20772
20773		 * Defines a data source type for the sorting which can be used to read
20774
20775		 * real-time information from the table (updating the internally cached
20776
20777		 * version) prior to sorting. This allows sorting to occur on user editable
20778
20779		 * elements such as form inputs.
20780
20781		 *  @type string
20782
20783		 *  @default std
20784
20785		 *  @dtopt Columns
20786
20787		 * 
20788
20789		 *  @example
20790
20791		 *    // Using aoColumnDefs
20792
20793		 *    $(document).ready( function() {
20794
20795		 *      $('#example').dataTable( {
20796
20797		 *        "aoColumnDefs": [
20798
20799		 *          { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
20800
20801		 *          { "sType": "numeric", "aTargets": [ 3 ] },
20802
20803		 *          { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
20804
20805		 *          { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
20806
20807		 *        ]
20808
20809		 *      } );
20810
20811		 *    } );
20812
20813		 *    
20814
20815		 *  @example
20816
20817		 *    // Using aoColumns
20818
20819		 *    $(document).ready( function() {
20820
20821		 *      $('#example').dataTable( {
20822
20823		 *        "aoColumns": [
20824
20825		 *          null,
20826
20827		 *          null,
20828
20829		 *          { "sSortDataType": "dom-text" },
20830
20831		 *          { "sSortDataType": "dom-text", "sType": "numeric" },
20832
20833		 *          { "sSortDataType": "dom-select" },
20834
20835		 *          { "sSortDataType": "dom-checkbox" }
20836
20837		 *        ]
20838
20839		 *      } );
20840
20841		 *    } );
20842
20843		 */
20844
20845		"sSortDataType": "std",
20846
20847	
20848
20849	
20850
20851		/**
20852
20853		 * The title of this column.
20854
20855		 *  @type string
20856
20857		 *  @default null <i>Derived from the 'TH' value for this column in the 
20858
20859		 *    original HTML table.</i>
20860
20861		 *  @dtopt Columns
20862
20863		 * 
20864
20865		 *  @example
20866
20867		 *    // Using aoColumnDefs
20868
20869		 *    $(document).ready( function() {
20870
20871		 *      $('#example').dataTable( {
20872
20873		 *        "aoColumnDefs": [ 
20874
20875		 *          { "sTitle": "My column title", "aTargets": [ 0 ] }
20876
20877		 *        ]
20878
20879		 *      } );
20880
20881		 *    } );
20882
20883		 *    
20884
20885		 *  @example
20886
20887		 *    // Using aoColumns
20888
20889		 *    $(document).ready( function() {
20890
20891		 *      $('#example').dataTable( {
20892
20893		 *        "aoColumns": [ 
20894
20895		 *          { "sTitle": "My column title" },
20896
20897		 *          null,
20898
20899		 *          null,
20900
20901		 *          null,
20902
20903		 *          null
20904
20905		 *        ]
20906
20907		 *      } );
20908
20909		 *    } );
20910
20911		 */
20912
20913		"sTitle": null,
20914
20915	
20916
20917	
20918
20919		/**
20920
20921		 * The type allows you to specify how the data for this column will be sorted.
20922
20923		 * Four types (string, numeric, date and html (which will strip HTML tags
20924
20925		 * before sorting)) are currently available. Note that only date formats
20926
20927	
20927	 * understood by Javascript's Date() object will be accepted as type date. For
20928
20929		 * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
20930
20931		 * 'date' or 'html' (by default). Further types can be adding through
20932
20933		 * plug-ins.
20934
20935		 *  @type string
20936
20937		 *  @default null <i>Auto-detected from raw data</i>
20938
20939		 *  @dtopt Columns
20940
20941		 * 
20942
20943		 *  @example
20944
20945		 *    // Using aoColumnDefs
20946
20947		 *    $(document).ready( function() {
20948
20949		 *      $('#example').dataTable( {
20950
20951		 *        "aoColumnDefs": [ 
20952
20953		 *          { "sType": "html", "aTargets": [ 0 ] }
20954
20955		 *        ]
20956
20957		 *      } );
20958
20959		 *    } );
20960
20961		 *    
20962
20963		 *  @example
20964
20965		 *    // Using aoColumns
20966
20967		 *    $(document).ready( function() {
20968
20969		 *      $('#example').dataTable( {
20970
20971		 *        "aoColumns": [ 
20972
20973		 *          { "sType": "html" },
20974
20975		 *          null,
20976
20977		 *          null,
20978
20979		 *          null,
20980
20981		 *          null
20982
20983		 *        ]
20984
20985		 *      } );
20986
20987		 *    } );
20988
20989		 */
20990
20991		"sType": null,
20992
20993	
20994
20995	
20996
20997		/**
20998
20999		 * Defining the width of the column, this parameter may take any CSS value
21000
21001		 * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not
21002
21003		 * been given a specific width through this interface ensuring that the table
21004
21005		 * remains readable.
21006
21007		 *  @type string
21008
21009		 *  @default null <i>Automatic</i>
21010
21011		 *  @dtopt Columns
21012
21013		 * 
21014
21015		 *  @example
21016
21017		 *    // Using aoColumnDefs
21018
21019		 *    $(document).ready( function() {
21020
21021		 *      $('#example').dataTable( {
21022
21023		 *        "aoColumnDefs": [ 
21024
21025		 *          { "sWidth": "20%", "aTargets": [ 0 ] }
21026
21027		 *        ]
21028
21029		 *      } );
21030
21031		 *    } );
21032
21033		 *    
21034
21035		 *  @example
21036
21037		 *    // Using aoColumns
21038
21039		 *    $(document).ready( function() {
21040
21041		 *      $('#example').dataTable( {
21042
21043		 *        "aoColumns": [ 
21044
21045		 *          { "sWidth": "20%" },
21046
21047		 *          null,
21048
21049		 *          null,
21050
21051		 *          null,
21052
21053		 *          null
21054
21055		 *        ]
21056
21057		 *      } );
21058
21059		 *    } );
21060
21061		 */
21062
21063		"sWidth": null
21064
21065	};
21066
21067	
21068
21069	
21070
21071	
21072
21073	/**
21074
21075	 * DataTables settings object - this holds all the information needed for a
21076
21077	 * given table, including configuration, data and current application of the
21078
21079	 * table options. DataTables does not have a single instance for each DataTable
21080
21081	 * with the settings attached to that instance, but rather instances of the
21082
21083	 * DataTable "class" are created on-the-fly as needed (typically by a 
21084
21085	 * $().dataTable() call) and the settings object is then applied to that
21086
21087	 * instance.
21088
21089	 * 
21090
21091	 * Note that this object is related to {@link DataTable.defaults} but this 
21092
21093	 * one is the internal data store for DataTables's cache of columns. It should
21094
21095	 * NOT be manipulated outside of DataTables. Any configuration should be done
21096
21097	 * through the initialisation options.
21098
21099	 *  @namespace
21100
21101	 *  @todo Really should attach the settings object to individual instances so we
21102
21103	 *    don't need to create new instances on each $().dataTable() call (if the
21104
21105	 *    table already exists). It would also save passing oSettings around and
21106
21107	 *    into every single function. However, this is a very significant 
21108
21109	 *    architecture change for DataTables and will almost certainly break
21110
21111	 *    backwards compatibility with older installations. This is something that
21112
21113	 *    will be done in 2.0.
21114
21115	 */
21116
21117	DataTable.models.oSettings = {
21118
21119		/**
21120
21121		 * Primary features of DataTables and their enablement state.
21122
21123		 *  @namespace
21124
21125		 */
21126
21127		"oFeatures": {
21128
21129			
21130
21131			/**
21132
21133			 * Flag to say if DataTables should automatically try to calculate the
21134
21135			 * optimum table and columns widths (true) or not (false).
21136
21137			 * Note that this parameter will be set by the initialisation routine. To
21138
21139			 * set a default use {@link DataTable.defaults}.
21140
21141			 *  @type boolean
21142
21143			 */
21144
21145			"bAutoWidth": null,
21146
21147	
21148
21149			/**
21150
21151			 * Delay the creation of TR and TD elements until they are actually
21152
21153			 * needed by a driven page draw. This can give a significant speed
21154
21155			 * increase for Ajax source and Javascript source data, but makes no
21156
21157			 * difference at all fro DOM and server-side processing tables.
21158
21159			 * Note that this parameter will be set by the initialisation routine. To
21160
21161			 * set a default use {@link DataTable.defaults}.
21162
21163			 *  @type boolean
21164
21165			 */
21166
21167			"bDeferRender": null,
21168
21169			
21170
21171			/**
21172
21173			 * Enable filtering on the table or not. Note that if this is disabled
21174
21175			 * then there is no filtering at all on the table, including fnFilter.
21176
21177			 * To just remove the filtering input use sDom and remove the 'f' option.
21178
21179			 * Note that this parameter will be set by the initialisation routine. To
21180
21181			 * set a default use {@link DataTable.defaults}.
21182
21183			 *  @type boolean
21184
21185			 */
21186
21187			"bFilter": null,
21188
21189			
21190
21191			/**
21192
21193			 * Table information element (the 'Showing x of y records' div) enable
21194
21195			 * flag.
21196
21197			 * Note that this parameter will be set by the initialisation routine. To
21198
21199			 * set a default use {@link DataTable.defaults}.
21200
21201			 *  @type boolean
21202
21203			 */
21204
21205			"bInfo": null,
21206
21207			
21208
21209			/**
21210
21211			 * Present a user control allowing the end user to change the page size
21212
21213			 * when pagination is enabled.
21214
21215			 * Note that this parameter will be set by the initialisation routine. To
21216
21217			 * set a default use {@link DataTable.defaults}.
21218
21219			 *  @type boolean
21220
21221			 */
21222
21223			"bLengthChange": null,
21224
21225	
21226
21227			/**
21228
21229			 * Pagination enabled or not. Note that if this is disabled then length
21230
21231			 * changing must also be disabled.
21232
21233			 * Note that this parameter will be set by the initialisation routine. To
21234
21235			 * set a default use {@link DataTable.defaults}.
21236
21237			 *  @type boolean
21238
21239			 */
21240
21241			"bPaginate": null,
21242
21243			
21244
21245			/**
21246
21247			 * Processing indicator enable flag whenever DataTables is enacting a
21248
21249			 * user request - typically an Ajax request for server-side processing.
21250
21251			 * Note that this parameter will be set by the initialisation routine. To
21252
21253			 * set a default use {@link DataTable.defaults}.
21254
21255			 *  @type boolean
21256
21257			 */
21258
21259			"bProcessing": null,
21260
21261			
21262
21263			/**
21264
21265			 * Server-side processing enabled flag - when enabled DataTables will
21266
21267			 * get all data from the server for every draw - there is no filtering,
21268
21269			 * sorting or paging done on the client-side.
21270
21271			 * Note that this parameter will be set by the initialisation routine. To
21272
21273			 * set a default use {@link DataTable.defaults}.
21274
21275			 *  @type boolean
21276
21277			 */
21278
21279			"bServerSide": null,
21280
21281			
21282
21283			/**
21284
21285			 * Sorting enablement flag.
21286
21287			 * Note that this parameter will be set by the initialisation routine. To
21288
21289			 * set a default use {@link DataTable.defaults}.
21290
21291			 *  @type boolean
21292
21293			 */
21294
21295			"bSort": null,
21296
21297			
21298
21299			/**
21300
21301			 * Apply a class to the columns which are being sorted to provide a
21302
21303			 * visual highlight or not. This can slow things down when enabled since
21304
21305			 * there is a lot of DOM interaction.
21306
21307			 * Note that this parameter will be set by the initialisation routine. To
21308
21309			 * set a default use {@link DataTable.defaults}.
21310
21311			 *  @type boolean
21312
21313			 */
21314
21315			"bSortClasses": null,
21316
21317			
21318
21319			/**
21320
21321			 * State saving enablement flag.
21322
21323			 * Note that this parameter will be set by the initialisation routine. To
21324
21325			 * set a default use {@link DataTable.defaults}.
21326
21327			 *  @type boolean
21328
21329			 */
21330
21331			"bStateSave": null
21332
21333		},
21334
21335		
21336
21337	
21338
21339		/**
21340
21341		 * Scrolling settings for a table.
21342
21343		 *  @namespace
21344
21345		 */
21346
21347		"oScroll": {
21348
21349			/**
21350
21351			 * Indicate if DataTables should be allowed to set the padding / margin
21352
21353			 * etc for the scrolling header elements or not. Typically you will want
21354
21355			 * this.
21356
21357			 * Note that this parameter will be set by the initialisation routine. To
21358
21359			 * set a default use {@link DataTable.defaults}.
21360
21361			 *  @type boolean
21362
21363			 */
21364
21365			"bAutoCss": null,
21366
21367			
21368
21369			/**
21370
21371			 * When the table is shorter in height than sScrollY, collapse the
21372
21373			 * table container down to the height of the table (when true).
21374
21375			 * Note that this parameter will be set by the initialisation routine. To
21376
21377			 * set a default use {@link DataTable.defaults}.
21378
21379			 *  @type boolean
21380
21381			 */
21382
21383			"bCollapse": null,
21384
21385			
21386
21387			/**
21388
21389			 * Infinite scrolling enablement flag. Now deprecated in favour of
21390
21391			 * using the Scroller plug-in.
21392
21393			 * Note that this parameter will be set by the initialisation routine. To
21394
21395			 * set a default use {@link DataTable.defaults}.
21396
21397			 *  @type boolean
21398
21399			 */
21400
21401			"bInfinite": null,
21402
21403			
21404
21405			/**
21406
21407			 * Width of the scrollbar for the web-browser's platform. Calculated
21408
21409			 * during table initialisation.
21410
21411			 *  @type int
21412
21413			 *  @default 0
21414
21415			 */
21416
21417			"iBarWidth": 0,
21418
21419			
21420
21421			/**
21422
21423			 * Space (in pixels) between the bottom of the scrolling container and 
21424
21425			 * the bottom of the scrolling viewport before the next page is loaded
21426
21427			 * when using infinite scrolling.
21428
21429			 * Note that this parameter will be set by the initialisation routine. To
21430
21431			 * set a default use {@link DataTable.defaults}.
21432
21433			 *  @type int
21434
21435			 */
21436
21437			"iLoadGap": null,
21438
21439			
21440
21441			/**
21442
21443			 * Viewport width for horizontal scrolling. Horizontal scrolling is 
21444
21445			 * disabled if an empty string.
21446
21447			 * Note that this parameter will be set by the initialisation routine. To
21448
21449			 * set a default use {@link DataTable.defaults}.
21450
21451			 *  @type string
21452
21453			 */
21454
21455			"sX": null,
21456
21457			
21458
21459			/**
21460
21461			 * Width to expand the table to when using x-scrolling. Typically you
21462
21463			 * should not need to use this.
21464
21465			 * Note that this parameter will be set by the initialisation routine. To
21466
21467			 * set a default use {@link DataTable.defaults}.
21468
21469			 *  @type string
21470
21471			 *  @deprecated
21472
21473			 */
21474
21475			"sXInner": null,
21476
21477			
21478
21479			/**
21480
21481			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
21482
21483			 * if an empty string.
21484
21485			 * Note that this parameter will be set by the initialisation routine. To
21486
21487			 * set a default use {@link DataTable.defaults}.
21488
21489			 *  @type string
21490
21491			 */
21492
21493			"sY": null
21494
21495		},
21496
21497		
21498
21499		/**
21500
21501		 * Language information for the table.
21502
21503		 *  @namespace
21504
21505		 *  @extends DataTable.defaults.oLanguage
21506
21507		 */
21508
21509		"oLanguage": {
21510
21511			/**
21512
21513			 * Information callback function. See 
21514
21515			 * {@link DataTable.defaults.fnInfoCallback}
21516
21517			 *  @type function
21518
21519			 *  @default null
21520
21521			 */
21522
21523			"fnInfoCallback": null
21524
21525		},
21526
21527		
21528
21529		/**
21530
21531		 * Browser support parameters
21532
21533		 *  @namespace
21534
21535		 */
21536
21537		"oBrowser": {
21538
21539			/**
21540
21541			 * Indicate if the browser incorrectly calculates width:100% inside a
21542
21543			 * scrolling element (IE6/7)
21544
21545			 *  @type boolean
21546
21547			 *  @default false
21548
21549			 */
21550
21551			"bScrollOversize": false
21552
21553		},
21554
21555		
21556
21557		/**
21558
21559		 * Array referencing the nodes which are used for the features. The 
21560
21561		 * parameters of this object match what is allowed by sDom - i.e.
21562
21563		 *   <ul>
21564
21565		 *     <li>'l' - Length changing</li>
21566
21567		 *     <li>'f' - Filtering input</li>
21568
21569		 *     <li>'t' - The table!</li>
21570
21571		 *     <li>'i' - Information</li>
21572
21573		 *     <li>'p' - Pagination</li>
21574
21575		 *     <li>'r' - pRocessing</li>
21576
21577		 *   </ul>
21578
21579		 *  @type array
21580
21581		 *  @default []
21582
21583		 */
21584
21585		"aanFeatures": [],
21586
21587		
21588
21589		/**
21590
21591		 * Store data information - see {@link DataTable.models.oRow} for detailed
21592
21593		 * information.
21594
21595		 *  @type array
21596
21597		 *  @default []
21598
21599		 */
21600
21601		"aoData": [],
21602
21603		
21604
21605		/**
21606
21607		 * Array of indexes which are in the current display (after filtering etc)
21608
21609		 *  @type array
21610
21611		 *  @default []
21612
21613		 */
21614
21615		"aiDisplay": [],
21616
21617		
21618
21619		/**
21620
21621		 * Array of indexes for display - no filtering
21622
21623		 *  @type array
21624
21625		 *  @default []
21626
21627		 */
21628
21629		"aiDisplayMaster": [],
21630
21631		
21632
21633		/**
21634
21635		 * Store information about each column that is in use
21636
21637		 *  @type array
21638
21639		 *  @default []
21640
21641		 */
21642
21643		"aoColumns": [],
21644
21645		
21646
21647		/**
21648
21649		 * Store information about the table's header
21650
21651		 *  @type array
21652
21653		 *  @default []
21654
21655		 */
21656
21657		"aoHeader": [],
21658
21659		
21660
21661		/**
21662
21663		 * Store information about the table's footer
21664
21665		 *  @type array
21666
21667		 *  @default []
21668
21669		 */
21670
21671		"aoFooter": [],
21672
21673		
21674
21675		/**
21676
21677		 * Search data array for regular expression searching
21678
21679		 *  @type array
21680
21681		 *  @default []
21682
21683		 */
21684
21685		"asDataSearch": [],
21686
21687		
21688
21689		/**
21690
21691		 * Store the applied global search information in case we want to force a 
21692
21693		 * research or compare the old search to a new one.
21694
21695		 * Note that this parameter will be set by the initialisation routine. To
21696
21697		 * set a default use {@link DataTable.defaults}.
21698
21699		 *  @namespace
21700
21701		 *  @extends DataTable.models.oSearch
21702
21703		 */
21704
21705		"oPreviousSearch": {},
21706
21707		
21708
21709		/**
21710
21711		 * Store the applied search for each column - see 
21712
21713		 * {@link DataTable.models.oSearch} for the format that is used for the
21714
21715		 * filtering information for each column.
21716
21717		 *  @type array
21718
21719		 *  @default []
21720
21721		 */
21722
21723		"aoPreSearchCols": [],
21724
21725		
21726
21727		/**
21728
21729		 * Sorting that is applied to the table. Note that the inner arrays are
21730
21731		 * used in the following manner:
21732
21733		 * <ul>
21734
21735		 *   <li>Index 0 - column number</li>
21736
21737		 *   <li>Index 1 - current sorting direction</li>
21738
21739		 *   <li>Index 2 - index of asSorting for this column</li>
21740
21741		 * </ul>
21742
21743		 * Note that this parameter will be set by the initialisation routine. To
21744
21745		 * set a default use {@link DataTable.defaults}.
21746
21747		 *  @type array
21748
21749		 *  @todo These inner arrays should really be objects
21750
21751		 */
21752
21753		"aaSorting": null,
21754
21755		
21756
21757		/**
21758
21759		 * Sorting that is always applied to the table (i.e. prefixed in front of
21760
21761		 * aaSorting).
21762
21763		 * Note that this parameter will be set by the initialisation routine. To
21764
21765		 * set a default use {@link DataTable.defaults}.
21766
21767		 *  @type array|null
21768
21769		 *  @default null
21770
21771		 */
21772
21773		"aaSortingFixed": null,
21774
21775		
21776
21777		/**
21778
21779		 * Classes to use for the striping of a table.
21780
21781		 * Note that this parameter will be set by the initialisation routine. To
21782
21783		 * set a default use {@link DataTable.defaults}.
21784
21785		 *  @type array
21786
21787		 *  @default []
21788
21789		 */
21790
21791		"asStripeClasses": null,
21792
21793		
21794
21795		/**
21796
21797		 * If restoring a table - we should restore its striping classes as well
21798
21799		 *  @type array
21800
21801		 *  @default []
21802
21803		 */
21804
21805		"asDestroyStripes": [],
21806
21807		
21808
21809		/**
21810
21811		 * If restoring a table - we should restore its width 
21812
21813		 *  @type int
21814
21815		 *  @default 0
21816
21817		 */
21818
21819		"sDestroyWidth": 0,
21820
21821		
21822
21823		/**
21824
21825		 * Callback functions array for every time a row is inserted (i.e. on a draw).
21826
21827		 *  @type array
21828
21829		 *  @default []
21830
21831		 */
21832
21833		"aoRowCallback": [],
21834
21835		
21836
21837		/**
21838
21839		 * Callback functions for the header on each draw.
21840
21841		 *  @type array
21842
21843		 *  @default []
21844
21845		 */
21846
21847		"aoHeaderCallback": [],
21848
21849		
21850
21851		/**
21852
21853		 * Callback function for the footer on each draw.
21854
21855		 *  @type array
21856
21857		 *  @default []
21858
21859		 */
21860
21861		"aoFooterCallback": [],
21862
21863		
21864
21865		/**
21866
21867		 * Array of callback functions for draw callback functions
21868
21869		 *  @type array
21870
21871		 *  @default []
21872
21873		 */
21874
21875		"aoDrawCallback": [],
21876
21877		
21878
21879		/**
21880
21881		 * Array of callback functions for row created function
21882
21883		 *  @type array
21884
21885		 *  @default []
21886
21887		 */
21888
21889		"aoRowCreatedCallback": [],
21890
21891		
21892
21893		/**
21894
21895		 * Callback functions for just before the table is redrawn. A return of 
21896
21897		 * false will be used to cancel the draw.
21898
21899		 *  @type array
21900
21901		 *  @default []
21902
21903		 */
21904
21905		"aoPreDrawCallback": [],
21906
21907		
21908
21909		/**
21910
21911		 * Callback functions for when the table has been initialised.
21912
21913		 *  @type array
21914
21915		 *  @default []
21916
21917		 */
21918
21919		"aoInitComplete": [],
21920
21921	
21922
21923		
21924
21925		/**
21926
21927		 * Callbacks for modifying the settings to be stored for state saving, prior to
21928
21929		 * saving state.
21930
21931		 *  @type array
21932
21933		 *  @default []
21934
21935		 */
21936
21937		"aoStateSaveParams": [],
21938
21939		
21940
21941		/**
21942
21943		 * Callbacks for modifying the settings that have been stored for state saving
21944
21945		 * prior to using the stored values to restore the state.
21946
21947		 *  @type array
21948
21949		 *  @default []
21950
21951		 */
21952
21953		"aoStateLoadParams": [],
21954
21955		
21956
21957		/**
21958
21959		 * Callbacks for operating on the settings object once the saved state has been
21960
21961		 * loaded
21962
21963		 *  @type array
21964
21965		 *  @default []
21966
21967		 */
21968
21969		"aoStateLoaded": [],
21970
21971		
21972
21973		/**
21974
21975		 * Cache the table ID for quick access
21976
21977		 *  @type string
21978
21979		 *  @default <i>Empty string</i>
21980
21981		 */
21982
21983		"sTableId": "",
21984
21985		
21986
21987		/**
21988
21989		 * The TABLE node for the main table
21990
21991		 *  @type node
21992
21993		 *  @default null
21994
21995		 */
21996
21997		"nTable": null,
21998
21999		
22000
22001		/**
22002
22003		 * Permanent ref to the thead element
22004
22005		 *  @type node
22006
22007		 *  @default null
22008
22009		 */
22010
22011		"nTHead": null,
22012
22013		
22014
22015		/**
22016
22017		 * Permanent ref to the tfoot element - if it exists
22018
22019		 *  @type node
22020
22021		 *  @default null
22022
22023		 */
22024
22025		"nTFoot": null,
22026
22027		
22028
22029		/**
22030
22031		 * Permanent ref to the tbody element
22032
22033		 *  @type node
22034
22035		 *  @default null
22036
22037		 */
22038
22039		"nTBody": null,
22040
22041		
22042
22043		/**
22044
22045		 * Cache the wrapper node (contains all DataTables controlled elements)
22046
22047		 *  @type node
22048
22049		 *  @default null
22050
22051		 */
22052
22053		"nTableWrapper": null,
22054
22055		
22056
22057		/**
22058
22059		 * Indicate if when using server-side processing the loading of data 
22060
22061		 * should be deferred until the second draw.
22062
22063		 * Note that this parameter will be set by the initialisation routine. To
22064
22065		 * set a default use {@link DataTable.defaults}.
22066
22067		 *  @type boolean
22068
22069		 *  @default false
22070
22071		 */
22072
22073		"bDeferLoading": false,
22074
22075		
22076
22077		/**
22078
22079		 * Indicate if all required information has been read in
22080
22081		 *  @type boolean
22082
22083		 *  @default false
22084
22085		 */
22086
22087		"bInitialised": false,
22088
22089		
22090
22091		/**
22092
22093		 * Information about open rows. Each object in the array has the parameters
22094
22095		 * 'nTr' and 'nParent'
22096
22097		 *  @type array
22098
22099		 *  @default []
22100
22101		 */
22102
22103		"aoOpenRows": [],
22104
22105		
22106
22107		/**
22108
22109		 * Dictate the positioning of DataTables' control elements - see
22110
22111		 * {@link DataTable.model.oInit.sDom}.
22112
22113		 * Note that this parameter will be set by the initialisation routine. To
22114
22115		 * set a default use {@link DataTable.defaults}.
22116
22117		 *  @type string
22118
22119		 *  @default null
22120
22121		 */
22122
22123		"sDom": null,
22124
22125		
22126
22127		/**
22128
22129		 * Which type of pagination should be used.
22130
22131		 * Note that this parameter will be set by the initialisation routine. To
22132
22133		 * set a default use {@link DataTable.defaults}.
22134
22135		 *  @type string 
22136
22137		 *  @default two_button
22138
22139		 */
22140
22141		"sPaginationType": "two_button",
22142
22143		
22144
22145		/**
22146
22147		 * The cookie duration (for bStateSave) in seconds.
22148
22149		 * Note that this parameter will be set by the initialisation routine. To
22150
22151		 * set a default use {@link DataTable.defaults}.
22152
22153		 *  @type int
22154
22155		 *  @default 0
22156
22157		 */
22158
22159		"iCookieDuration": 0,
22160
22161		
22162
22163		/**
22164
22165		 * The cookie name prefix.
22166
22167		 * Note that this parameter will be set by the initialisation routine. To
22168
22169		 * set a default use {@link DataTable.defaults}.
22170
22171		 *  @type string
22172
22173		 *  @default <i>Empty string</i>
22174
22175		 */
22176
22177		"sCookiePrefix": "",
22178
22179		
22180
22181		/**
22182
22183		 * Callback function for cookie creation.
22184
22185		 * Note that this parameter will be set by the initialisation routine. To
22186
22187		 * set a default use {@link DataTable.defaults}.
22188
22189		 *  @type function
22190
22191		 *  @default null
22192
22193		 */
22194
22195		"fnCookieCallback": null,
22196
22197		
22198
22199		/**
22200
22201		 * Array of callback functions for state saving. Each array element is an 
22202
22203		 * object with the following parameters:
22204
22205		 *   <ul>
22206
22207		 *     <li>function:fn - function to call. Takes two parameters, oSettings
22208
22209		 *       and the JSON string to save that has been thus far created. Returns
22210
22211		 *       a JSON string to be inserted into a json object 
22212
22213		 *       (i.e. '"param": [ 0, 1, 2]')</li>
22214
22215		 *     <li>string:sName - name of callback</li>
22216
22217		 *   </ul>
22218
22219		 *  @type array
22220
22221		 *  @default []
22222
22223		 */
22224
22225		"aoStateSave": [],
22226
22227		
22228
22229		/**
22230
22231		 * Array of callback functions for state loading. Each array element is an 
22232
22233		 * object with the following parameters:
22234
22235		 *   <ul>
22236
22237		 *     <li>function:fn - function to call. Takes two parameters, oSettings 
22238
22239		 *       and the object stored. May return false to cancel state loading</li>
22240
22241		 *     <li>string:sName - name of callback</li>
22242
22243		 *   </ul>
22244
22245		 *  @type array
22246
22247		 *  @default []
22248
22249		 */
22250
22251		"aoStateLoad": [],
22252
22253		
22254
22255		/**
22256
22257		 * State that was loaded from the cookie. Useful for back reference
22258
22259		 *  @type object
22260
22261		 *  @default null
22262
22263		 */
22264
22265		"oLoadedState": null,
22266
22267		
22268
22269		/**
22270
22271		 * Source url for AJAX data for the table.
22272
22273		 * Note that this parameter will be set by the initialisation routine. To
22274
22275		 * set a default use {@link DataTable.defaults}.
22276
22277		 *  @type string
22278
22279		 *  @default null
22280
22281		 */
22282
22283		"sAjaxSource": null,
22284
22285		
22286
22287		/**
22288
22289		 * Property from a given object from which to read the table data from. This
22290
22291		 * can be an empty string (when not server-side processing), in which case 
22292
22293		 * it is  assumed an an array is given directly.
22294
22295		 * Note that this parameter will be set by the initialisation routine. To
22296
22297		 * set a default use {@link DataTable.defaults}.
22298
22299		 *  @type string
22300
22301		 */
22302
22303		"sAjaxDataProp": null,
22304
22305		
22306
22307		/**
22308
22309		 * Note if draw should be blocked while getting data
22310
22311		 *  @type boolean
22312
22313		 *  @default true
22314
22315		 */
22316
22317		"bAjaxDataGet": true,
22318
22319		
22320
22321		/**
22322
22323		 * The last jQuery XHR object that was used for server-side data gathering. 
22324
22325		 * This can be used for working with the XHR information in one of the 
22326
22327		 * callbacks
22328
22329		 *  @type object
22330
22331		 *  @default null
22332
22333		 */
22334
22335		"jqXHR": null,
22336
22337		
22338
22339		/**
22340
22341		 * Function to get the server-side data.
22342
22343		 * Note that this parameter will be set by the initialisation routine. To
22344
22345		 * set a default use {@link DataTable.defaults}.
22346
22347		 *  @type function
22348
22349		 */
22350
22351		"fnServerData": null,
22352
22353		
22354
22355		/**
22356
22357		 * Functions which are called prior to sending an Ajax request so extra 
22358
22359		 * parameters can easily be sent to the server
22360
22361		 *  @type array
22362
22363		 *  @default []
22364
22365		 */
22366
22367		"aoServerParams": [],
22368
22369		
22370
22371		/**
22372
22373		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 
22374
22375		 * required).
22376
22377		 * Note that this parameter will be set by the initialisation routine. To
22378
22379		 * set a default use {@link DataTable.defaults}.
22380
22381		 *  @type string
22382
22383		 */
22384
22385		"sServerMethod": null,
22386
22387		
22388
22389		/**
22390
22391		 * Format numbers for display.
22392
22393		 * Note that this parameter will be set by the initialisation routine. To
22394
22395		 * set a default use {@link DataTable.defaults}.
22396
22397		 *  @type function
22398
22399		 */
22400
22401		"fnFormatNumber": null,
22402
22403		
22404
22405		/**
22406
22407		 * List of options that can be used for the user selectable length menu.
22408
22409		 * Note that this parameter will be set by the initialisation routine. To
22410
22411		 * set a default use {@link DataTable.defaults}.
22412
22413		 *  @type array
22414
22415		 *  @default []
22416
22417		 */
22418
22419		"aLengthMenu": null,
22420
22421		
22422
22423		/**
22424
22425		 * Counter for the draws that the table does. Also used as a tracker for
22426
22427		 * server-side processing
22428
22429		 *  @type int
22430
22431		 *  @default 0
22432
22433		 */
22434
22435		"iDraw": 0,
22436
22437		
22438
22439		/**
22440
22441		 * Indicate if a redraw is being done - useful for Ajax
22442
22443		 *  @type boolean
22444
22445		 *  @default false
22446
22447		 */
22448
22449		"bDrawing": false,
22450
22451		
22452
22453		/**
22454
22455		 * Draw index (iDraw) of the last error when parsing the returned data
22456
22457		 *  @type int
22458
22459		 *  @default -1
22460
22461		 */
22462
22463		"iDrawError": -1,
22464
22465		
22466
22467		/**
22468
22469		 * Paging display length
22470
22471		 *  @type int
22472
22473		 *  @default 10
22474
22475		 */
22476
22477		"_iDisplayLength": 10,
22478
22479	
22480
22481		/**
22482
22483		 * Paging start point - aiDisplay index
22484
22485		 *  @type int
22486
22487		 *  @default 0
22488
22489		 */
22490
22491		"_iDisplayStart": 0,
22492
22493	
22494
22495		/**
22496
22497		 * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
22498
22499		 * this property to get the end point
22500
22501		 *  @type int
22502
22503		 *  @default 10
22504
22505		 *  @private
22506
22507		 */
22508
22509		"_iDisplayEnd": 10,
22510
22511		
22512
22513		/**
22514
22515		 * Server-side processing - number of records in the result set
22516
22517		 * (i.e. before filtering), Use fnRecordsTotal rather than
22518
22519		 * this property to get the value of the number of records, regardless of
22520
22521		 * the server-side processing setting.
22522
22523		 *  @type int
22524
22525		 *  @default 0
22526
22527		 *  @private
22528
22529		 */
22530
22531		"_iRecordsTotal": 0,
22532
22533	
22534
22535		/**
22536
22537		 * Server-side processing - number of records in the current display set
22538
22539		 * (i.e. after filtering). Use fnRecordsDisplay rather than
22540
22541		 * this property to get the value of the number of records, regardless of
22542
22543		 * the server-side processing setting.
22544
22545		 *  @type boolean
22546
22547		 *  @default 0
22548
22549		 *  @private
22550
22551		 */
22552
22553		"_iRecordsDisplay": 0,
22554
22555		
22556
22557		/**
22558
22559		 * Flag to indicate if jQuery UI marking and classes should be used.
22560
22561		 * Note that this parameter will be set by the initialisation routine. To
22562
22563		 * set a default use {@link DataTable.defaults}.
22564
22565		 *  @type boolean
22566
22567		 */
22568
22569		"bJUI": null,
22570
22571		
22572
22573		/**
22574
22575		 * The classes to use for the table
22576
22577		 *  @type object
22578
22579		 *  @default {}
22580
22581		 */
22582
22583		"oClasses": {},
22584
22585		
22586
22587		/**
22588
22589		 * Flag attached to the settings object so you can check in the draw 
22590
22591		 * callback if filtering has been done in the draw. Deprecated in favour of
22592
22593		 * Businesses.
22594
22595		 *  @type boolean
22596
22597		 *  @default false
22598
22599		 *  @deprecated
22600
22601		 */
22602
22603		"bFiltered": false,
22604
22605		
22606
22607		/**
22608
22609		 * Flag attached to the settings object so you can check in the draw 
22610
22611		 * callback if sorting has been done in the draw. Deprecated in favour of
22612
22613		 * Businesses.
22614
22615		 *  @type boolean
22616
22617		 *  @default false
22618
22619		 *  @deprecated
22620
22621		 */
22622
22623		"bSorted": false,
22624
22625		
22626
22627		/**
22628
22629		 * Indicate that if multiple rows are in the header and there is more than 
22630
22631		 * one unique cell per column, if the top one (true) or bottom one (false) 
22632
22633		 * should be used for sorting / title by DataTables.
22634
22635		 * Note that this parameter will be set by the initialisation routine. To
22636
22637		 * set a default use {@link DataTable.defaults}.
22638
22639		 *  @type boolean
22640
22641		 */
22642
22643		"bSortCellsTop": null,
22644
22645		
22646
22647		/**
22648
22649		 * Initialisation object that is used for the table
22650
22651		 *  @type object
22652
22653		 *  @default null
22654
22655		 */
22656
22657		"oInit": null,
22658
22659		
22660
22661		/**
22662
22663		 * Destroy callback functions - for plug-ins to attach themselves to the
22664
22665		 * destroy so they can clean up markup and Businesses.
22666
22667		 *  @type array
22668
22669		 *  @default []
22670
22671		 */
22672
22673		"aoDestroyCallback": [],
22674
22675	
22676
22677		
22678
22679		/**
22680
22681		 * Get the number of records in the current record set, before filtering
22682
22683		 *  @type function
22684
22685		 */
22686
22687		"fnRecordsTotal": function ()
22688
22689		{
22690
22691			if ( this.oFeatures.bServerSide ) {
22692
22693				return parseInt(this._iRecordsTotal, 10);
22694
22695			} else {
22696
22697				return this.aiDisplayMaster.length;
22698
22699			}
22700
22701		},
22702
22703		
22704
22705		/**
22706
22707		 * Get the number of records in the current record set, after filtering
22708
22709		 *  @type function
22710
22711		 */
22712
22713		"fnRecordsDisplay": function ()
22714
22715		{
22716
22717			if ( this.oFeatures.bServerSide ) {
22718
22719				return parseInt(this._iRecordsDisplay, 10);
22720
22721			} else {
22722
22723				return this.aiDisplay.length;
22724
22725			}
22726
22727		},
22728
22729		
22730
22731		/**
22732
22733		 * Set the display end point - aiDisplay index
22734
22735		 *  @type function
22736
22737		 *  @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
22738
22739		 */
22740
22741		"fnDisplayEnd": function ()
22742
22743		{
22744
22745			if ( this.oFeatures.bServerSide ) {
22746
22747				if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
22748
22749					return this._iDisplayStart+this.aiDisplay.length;
22750
22751				} else {
22752
22753					return Math.min( this._iDisplayStart+this._iDisplayLength, 
22754
22755						this._iRecordsDisplay );
22756
22757				}
22758
22759			} else {
22760
22761				return this._iDisplayEnd;
22762
22763			}
22764
22765		},
22766
22767		
22768
22769		/**
22770
22771		 * The DataTables object for this table
22772
22773		 *  @type object
22774
22775		 *  @default null
22776
22777		 */
22778
22779		"oInstance": null,
22780
22781		
22782
22783		/**
22784
22785		 * Unique identifier for each instance of the DataTables object. If there
22786
22787		 * is an ID on the table node, then it takes that value, otherwise an
22788
22789		 * incrementing internal counter is used.
22790
22791		 *  @type string
22792
22793		 *  @default null
22794
22795		 */
22796
22797		"sInstance": null,
22798
22799	
22800
22801		/**
22802
22803		 * tabindex attribute value that is added to DataTables control elements, allowing
22804
22805		 * keyboard navigation of the table and its controls.
22806
22807		 */
22808
22809		"iTabIndex": 0,
22810
22811	
22812
22813		/**
22814
22815		 * DIV container for the footer scrolling table if scrolling
22816
22817		 */
22818
22819		"nScrollHead": null,
22820
22821	
22822
22823		/**
22824
22825		 * DIV container for the footer scrolling table if scrolling
22826
22827		 */
22828
22829		"nScrollFoot": null
22830
22831	};
22832
22833
22834
22835	/**
22836
22837	 * Extension object for DataTables that is used to provide all extension options.
22838
22839	 * 
22840
22841	 * Note that the <i>DataTable.ext</i> object is available through
22842
22843	 * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
22844
22845	 * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
22846
22847	 *  @namespace
22848
22849	 *  @extends DataTable.models.ext
22850
22851	 */
22852
22853	DataTable.ext = $.extend( true, {}, DataTable.models.ext );
22854
22855	
22856
22857	$.extend( DataTable.ext.oStdClasses, {
22858
22859		"sTable": "dataTable",
22860
22861	
22862
22863		/* Two buttons buttons */
22864
22865		"sPagePrevEnabled": "paginate_enabled_previous",
22866
22867		"sPagePrevDisabled": "paginate_disabled_previous",
22868
22869		"sPageNextEnabled": "paginate_enabled_next",
22870
22871		"sPageNextDisabled": "paginate_disabled_next",
22872
22873		"sPageJUINext": "",
22874
22875		"sPageJUIPrev": "",
22876
22877		
22878
22879		/* Full numbers paging buttons */
22880
22881		"sPageButton": "paginate_button",
22882
22883		"sPageButtonActive": "paginate_active",
22884
22885		"sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
22886
22887		"sPageFirst": "first",
22888
22889		"sPagePrevious": "previous",
22890
22891		"sPageNext": "next",
22892
22893		"sPageLast": "last",
22894
22895		
22896
22897		/* Striping classes */
22898
22899		"sStripeOdd": "odd",
22900
22901		"sStripeEven": "even",
22902
22903		
22904
22905		/* Empty row */
22906
22907		"sRowEmpty": "dataTables_empty",
22908
22909		
22910
22911		/* Features */
22912
22913		"sWrapper": "dataTables_wrapper",
22914
22915		"sFilter": "dataTables_filter",
22916
22917		"sInfo": "dataTables_info",
22918
22919		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
22920
22921		"sLength": "dataTables_length",
22922
22923		"sProcessing": "dataTables_processing",
22924
22925		
22926
22927		/* Sorting */
22928
22929		"sSortAsc": "sorting_asc",
22930
22931		"sSortDesc": "sorting_desc",
22932
22933		"sSortable": "sorting", /* Sortable in both directions */
22934
22935		"sSortableAsc": "sorting_asc_disabled",
22936
22937		"sSortableDesc": "sorting_desc_disabled",
22938
22939		"sSortableNone": "sorting_disabled",
22940
22941		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
22942
22943		"sSortJUIAsc": "",
22944
22945		"sSortJUIDesc": "",
22946
22947		"sSortJUI": "",
22948
22949		"sSortJUIAscAllowed": "",
22950
22951		"sSortJUIDescAllowed": "",
22952
22953		"sSortJUIWrapper": "",
22954
22955		"sSortIcon": "",
22956
22957		
22958
22959		/* Scrolling */
22960
22961		"sScrollWrapper": "dataTables_scroll",
22962
22963		"sScrollHead": "dataTables_scrollHead",
22964
22965		"sScrollHeadInner": "dataTables_scrollHeadInner",
22966
22967		"sScrollBody": "dataTables_scrollBody",
22968
22969		"sScrollFoot": "dataTables_scrollFoot",
22970
22971		"sScrollFootInner": "dataTables_scrollFootInner",
22972
22973		
22974
22975		/* Misc */
22976
22977		"sFooterTH": "",
22978
22979		"sJUIHeader": "",
22980
22981		"sJUIFooter": ""
22982
22983	} );
22984
22985	
22986
22987	
22988
22989	$.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
22990
22991		/* Two buttons buttons */
22992
22993		"sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
22994
22995		"sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
22996
22997		"sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
22998
22999		"sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
23000
23001		"sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
23002
23003		"sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
23004
23005		
23006
23007		/* Full numbers paging buttons */
23008
23009		"sPageButton": "fg-button ui-button ui-state-default",
23010
23011		"sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
23012
23013		"sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
23014
23015		"sPageFirst": "first ui-corner-tl ui-corner-bl",
23016
23017		"sPageLast": "last ui-corner-tr ui-corner-br",
23018
23019		
23020
23021		/* Features */
23022
23023		"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
23024
23025			"ui-buttonset-multi paging_", /* Note that the type is postfixed */
23026
23027		
23028
23029		/* Sorting */
23030
23031		"sSortAsc": "ui-state-default",
23032
23033		"sSortDesc": "ui-state-default",
23034
23035		"sSortable": "ui-state-default",
23036
23037		"sSortableAsc": "ui-state-default",
23038
23039		"sSortableDesc": "ui-state-default",
23040
23041		"sSortableNone": "ui-state-default",
23042
23043		"sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
23044
23045		"sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
23046
23047		"sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
23048
23049		"sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
23050
23051		"sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
23052
23053		"sSortJUIWrapper": "DataTables_sort_wrapper",
23054
23055		"sSortIcon": "DataTables_sort_icon",
23056
23057		
23058
23059		/* Scrolling */
23060
23061		"sScrollHead": "dataTables_scrollHead ui-state-default",
23062
23063		"sScrollFoot": "dataTables_scrollFoot ui-state-default",
23064
23065		
23066
23067		/* Misc */
23068
23069		"sFooterTH": "ui-state-default",
23070
23071		"sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",
23072
23073		"sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"
23074
23075	} );
23076
23077	
23078
23079	/*
23080
23081	 * Variable: oPagination
23082
23083	 * Purpose:  
23084
23085	 * Scope:    jQuery.fn.dataTableExt
23086
23087	 */
23088
23089	$.extend( DataTable.ext.oPagination, {
23090
23091		/*
23092
23093		 * Variable: two_button
23094
23095		 * Purpose:  Standard two button (forward/back) pagination
23096
23097		 * Scope:    jQuery.fn.dataTableExt.oPagination
23098
23099		 */
23100
23101		"two_button": {
23102
23103			/*
23104
23105			 * Function: oPagination.two_button.fnInit
23106
23107			 * Purpose:  Initialise dom elements required for pagination with forward/back buttons only
23108
23109			 * Returns:  -
23110
23111			 * Inputs:   object:oSettings - dataTables settings object
23112
23113			 *           node:nPaging - the DIV which contains this pagination control
23114
23115			 *           function:fnCallbackDraw - draw function which must be called on update
23116
23117			 */
23118
23119			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
23120
23121			{
23122
23123				var oLang = oSettings.oLanguage.oPaginate;
23124
23125				var oClasses = oSettings.oClasses;
23126
23127				var fnClickHandler = function ( e ) {
23128
23129					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
23130
23131					{
23132
23133						fnCallbackDraw( oSettings );
23134
23135					}
23136
23137				};
23138
23139	
23140
23141				var sAppend = (!oSettings.bJUI) ?
23142
23143					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
23144
23145					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
23146
23147					:
23148
23149					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
23150
23151					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
23152
23153				$(nPaging).append( sAppend );
23154
23155				
23156
23157				var els = $('a', nPaging);
23158
23159				var nPrevious = els[0],
23160
23161					nNext = els[1];
23162
23163				
23164
23165				oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
23166
23167				oSettings.oApi._fnBindAction( nNext,     {action: "next"},     fnClickHandler );
23168
23169				
23170
23171				/* ID the first elements only */
23172
23173				if ( !oSettings.aanFeatures.p )
23174
23175				{
23176
23177					nPaging.id = oSettings.sTableId+'_paginate';
23178
23179					nPrevious.id = oSettings.sTableId+'_previous';
23180
23181					nNext.id = oSettings.sTableId+'_next';
23182
23183	
23184
23185					nPrevious.setAttribute('aria-controls', oSettings.sTableId);
23186
23187					nNext.setAttribute('aria-controls', oSettings.sTableId);
23188
23189				}
23190
23191			},
23192
23193			
23194
23195			/*
23196
23197			 * Function: oPagination.two_button.fnUpdate
23198
23199			 * Purpose:  Update the two button pagination at the end of the draw
23200
23201			 * Returns:  -
23202
23203			 * Inputs:   object:oSettings - dataTables settings object
23204
23205			 *           function:fnCallbackDraw - draw function to call on page change
23206
23207			 */
23208
23209			"fnUpdate": function ( oSettings, fnCallbackDraw )
23210
23211			{
23212
23213				if ( !oSettings.aanFeatures.p )
23214
23215				{
23216
23217					return;
23218
23219				}
23220
23221				
23222
23223				var oClasses = oSettings.oClasses;
23224
23225				var an = oSettings.aanFeatures.p;
23226
23227				var nNode;
23228
23229	
23230
23231				/* Loop over each instance of the pager */
23232
23233				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
23234
23235				{
23236
23237					nNode = an[i].firstChild;
23238
23239					if ( nNode )
23240
23241					{
23242
23243						/* Previous page */
23244
23245						nNode.className = ( oSettings._iDisplayStart === 0 ) ?
23246
23247						    oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
23248
23249						    
23250
23251						/* Next page */
23252
23253						nNode = nNode.nextSibling;
23254
23255						nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
23256
23257						    oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
23258
23259					}
23260
23261				}
23262
23263			}
23264
23265		},
23266
23267		
23268
23269		
23270
23271		/*
23272
23273		 * Variable: iFullNumbersShowPages
23274
23275		 * Purpose:  Change the number of pages which can be seen
23276
23277		 * Scope:    jQuery.fn.dataTableExt.oPagination
23278
23279		 */
23280
23281		"iFullNumbersShowPages": 5,
23282
23283		
23284
23285		/*
23286
23287		 * Variable: full_numbers
23288
23289		 * Purpose:  Full numbers pagination
23290
23291		 * Scope:    jQuery.fn.dataTableExt.oPagination
23292
23293		 */
23294
23295		"full_numbers": {
23296
23297			/*
23298
23299			 * Function: oPagination.full_numbers.fnInit
23300
23301			 * Purpose:  Initialise dom elements required for pagination with a list of the pages
23302
23303			 * Returns:  -
23304
23305			 * Inputs:   object:oSettings - dataTables settings object
23306
23307			 *           node:nPaging - the DIV which contains this pagination control
23308
23309			 *           function:fnCallbackDraw - draw function which must be called on update
23310
23311			 */
23312
23313			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
23314
23315			{
23316
23317				var oLang = oSettings.oLanguage.oPaginate;
23318
23319				var oClasses = oSettings.oClasses;
23320
23321				var fnClickHandler = function ( e ) {
23322
23323					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
23324
23325					{
23326
23327						fnCallbackDraw( oSettings );
23328
23329					}
23330
23331				};
23332
23333	
23334
23335				$(nPaging).append(
23336
23337					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
23338
23339					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
23340
23341					'<span></span>'+
23342
23343					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
23344
23345					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
23346
23347				);
23348
23349				var els = $('a', nPaging);
23350
23351				var nFirst = els[0],
23352
23353					nPrev = els[1],
23354
23355					nNext = els[2],
23356
23357					nLast = els[3];
23358
23359				
23360
23361				oSettings.oApi._fnBindAction( nFirst, {action: "first"},    fnClickHandler );
23362
23363				oSettings.oApi._fnBindAction( nPrev,  {action: "previous"}, fnClickHandler );
23364
23365				oSettings.oApi._fnBindAction( nNext,  {action: "next"},     fnClickHandler );
23366
23367				oSettings.oApi._fnBindAction( nLast,  {action: "last"},     fnClickHandler );
23368
23369				
23370
23371				/* ID the first elements only */
23372
23373				if ( !oSettings.aanFeatures.p )
23374
23375				{
23376
23377					nPaging.id = oSettings.sTableId+'_paginate';
23378
23379					nFirst.id =oSettings.sTableId+'_first';
23380
23381					nPrev.id =oSettings.sTableId+'_previous';
23382
23383					nNext.id =oSettings.sTableId+'_next';
23384
23385					nLast.id =oSettings.sTableId+'_last';
23386
23387				}
23388
23389			},
23390
23391			
23392
23393			/*
23394
23395			 * Function: oPagination.full_numbers.fnUpdate
23396
23397			 * Purpose:  Update the list of page buttons shows
23398
23399			 * Returns:  -
23400
23401			 * Inputs:   object:oSettings - dataTables settings object
23402
23403			 *           function:fnCallbackDraw - draw function to call on page change
23404
23405			 */
23406
23407			"fnUpdate": function ( oSettings, fnCallbackDraw )
23408
23409			{
23410
23411				if ( !oSettings.aanFeatures.p )
23412
23413				{
23414
23415					return;
23416
23417				}
23418
23419				
23420
23421				var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
23422
23423				var iPageCountHalf = Math.floor(iPageCount / 2);
23424
23425				var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
23426
23427				var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
23428
23429				var sList = "";
23430
23431				var iStartButton, iEndButton, i, iLen;
23432
23433				var oClasses = oSettings.oClasses;
23434
23435				var anButtons, anStatic, nPaginateList, nNode;
23436
23437				var an = oSettings.aanFeatures.p;
23438
23439				var fnBind = function (j) {
23440
23441					oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
23442
23443						/* Use the information in the element to jump to the required page */
23444
23445						oSettings.oApi._fnPageChange( oSettings, e.data.page );
23446
23447						fnCallbackDraw( oSettings );
23448
23449						e.preventDefault();
23450
23451					} );
23452
23453				};
23454
23455				
23456
23457				/* Pages calculation */
23458
23459				if ( oSettings._iDisplayLength === -1 )
23460
23461				{
23462
23463					iStartButton = 1;
23464
23465					iEndButton = 1;
23466
23467					iCurrentPage = 1;
23468
23469				}
23470
23471				else if (iPages < iPageCount)
23472
23473				{
23474
23475					iStartButton = 1;
23476
23477					iEndButton = iPages;
23478
23479				}
23480
23481				else if (iCurrentPage <= iPageCountHalf)
23482
23483				{
23484
23485					iStartButton = 1;
23486
23487					iEndButton = iPageCount;
23488
23489				}
23490
23491				else if (iCurrentPage >= (iPages - iPageCountHalf))
23492
23493				{
23494
23495					iStartButton = iPages - iPageCount + 1;
23496
23497					iEndButton = iPages;
23498
23499				}
23500
23501				else
23502
23503				{
23504
23505					iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
23506
23507					iEndButton = iStartButton + iPageCount - 1;
23508
23509				}
23510
23511	
23512
23513				
23514
23515				/* Build the dynamic list */
23516
23517				for ( i=iStartButton ; i<=iEndButton ; i++ )
23518
23519				{
23520
23521					sList += (iCurrentPage !== i) ?
23522
23523						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
23524
23525						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
23526
23527				}
23528
23529				
23530
23531				/* Loop over each instance of the pager */
23532
23533				for ( i=0, iLen=an.length ; i<iLen ; i++ )
23534
23535				{
23536
23537					nNode = an[i];
23538
23539					if ( !nNode.hasChildNodes() )
23540
23541					{
23542
23543						continue;
23544
23545					}
23546
23547					
23548
23549					/* Build up the dynamic list first - html and listeners */
23550
23551					$('span:eq(0)', nNode)
23552
23553						.html( sList )
23554
23555						.children('a').each( fnBind );
23556
23557					
23558
23559					/* Update the permanent button's classes */
23560
23561					anButtons = nNode.getElementsByTagName('a');
23562
23563					anStatic = [
23564
23565						anButtons[0], anButtons[1], 
23566
23567						anButtons[anButtons.length-2], anButtons[anButtons.length-1]
23568
23569					];
23570
23571	
23572
23573					$(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
23574
23575					$([anStatic[0], anStatic[1]]).addClass( 
23576
23577						(iCurrentPage==1) ?
23578
23579							oClasses.sPageButtonStaticDisabled :
23580
23581							oClasses.sPageButton
23582
23583					);
23584
23585					$([anStatic[2], anStatic[3]]).addClass(
23586
23587						(iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
23588
23589							oClasses.sPageButtonStaticDisabled :
23590
23591							oClasses.sPageButton
23592
23593					);
23594
23595				}
23596
23597			}
23598
23599		}
23600
23601	} );
23602
23603	
23604
23605	$.extend( DataTable.ext.oSort, {
23606
23607		/*
23608
23609		 * text sorting
23610
23611		 */
23612
23613		"string-pre": function ( a )
23614
23615		{
23616
23617			if ( typeof a != 'string' ) {
23618
23619				a = (a !== null && a.toString) ? a.toString() : '';
23620
23621			}
23622
23623			return a.toLowerCase();
23624
23625		},
23626
23627	
23628
23629		"string-asc": function ( x, y )
23630
23631		{
23632
23633			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
23634
23635		},
23636
23637		
23638
23639		"string-desc": function ( x, y )
23640
23641		{
23642
23643			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
23644
23645		},
23646
23647		
23648
23649		
23650
23651		/*
23652
23653		 * html sorting (ignore html tags)
23654
23655		 */
23656
23657		"html-pre": function ( a )
23658
23659		{
23660
23661			return a.replace( /<.*?>/g, "" ).toLowerCase();
23662
23663		},
23664
23665		
23666
23667		"html-asc": function ( x, y )
23668
23669		{
23670
23671			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
23672
23673		},
23674
23675		
23676
23677		"html-desc": function ( x, y )
23678
23679		{
23680
23681			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
23682
23683		},
23684
23685		
23686
23687		
23688
23689		/*
23690
23691		 * date sorting
23692
23693		 */
23694
23695		"date-pre": function ( a )
23696
23697		{
23698
23699			var x = Date.parse( a );
23700
23701			
23702
23703			if ( isNaN(x) || x==="" )
23704
23705			{
23706
23707				x = Date.parse( "01/01/1970 00:00:00" );
23708
23709			}
23710
23711			return x;
23712
23713		},
23714
23715	
23716
23717		"date-asc": function ( x, y )
23718
23719		{
23720
23721			return x - y;
23722
23723		},
23724
23725		
23726
23727		"date-desc": function ( x, y )
23728
23729		{
23730
23731			return y - x;
23732
23733		},
23734
23735		
23736
23737		
23738
23739		/*
23740
23741		 * numerical sorting
23742
23743		 */
23744
23745		"numeric-pre": function ( a )
23746
23747		{
23748
23749			return (a=="-" || a==="") ? 0 : a*1;
23750
23751		},
23752
23753	
23754
23755		"numeric-asc": function ( x, y )
23756
23757		{
23758
23759			return x - y;
23760
23761		},
23762
23763		
23764
23765		"numeric-desc": function ( x, y )
23766
23767		{
23768
23769			return y - x;
23770
23771		}
23772
23773	} );
23774
23775	
23776
23777	
23778
23779	$.extend( DataTable.ext.aTypes, [
23780
23781		/*
23782
23783		 * Function: -
23784
23785		 * Purpose:  Check to see if a string is numeric
23786
23787		 * Returns:  string:'numeric' or null
23788
23789		 * Inputs:   mixed:sText - string to check
23790
23791		 */
23792
23793		function ( sData )
23794
23795		{
23796
23797			/* Allow zero length strings as a number */
23798
23799			if ( typeof sData === 'number' )
23800
23801			{
23802
23803				return 'numeric';
23804
23805			}
23806
23807			else if ( typeof sData !== 'string' )
23808
23809			{
23810
23811				return null;
23812
23813			}
23814
23815			
23816
23817			var sValidFirstChars = "0123456789-";
23818
23819			var sValidChars = "0123456789.";
23820
23821			var Char;
23822
23823			var bDecimal = false;
23824
23825			
23826
23827			/* Check for a valid first char (no period and allow negatives) */
23828
23829			Char = sData.charAt(0); 
23830
23831			if (sValidFirstChars.indexOf(Char) == -1) 
23832
23833			{
23834
23835				return null;
23836
23837			}
23838
23839			
23840
23841			/* Check all the other characters are valid */
23842
23843			for ( var i=1 ; i<sData.length ; i++ ) 
23844
23845			{
23846
23847				Char = sData.charAt(i); 
23848
23849				if (sValidChars.indexOf(Char) == -1) 
23850
23851				{
23852
23853					return null;
23854
23855				}
23856
23857				
23858
23859				/* Only allowed one decimal place... */
23860
23861				if ( Char == "." )
23862
23863				{
23864
23865					if ( bDecimal )
23866
23867					{
23868
23869						return null;
23870
23871					}
23872
23873					bDecimal = true;
23874
23875				}
23876
23877			}
23878
23879			
23880
23881			return 'numeric';
23882
23883		},
23884
23885		
23886
23887		/*
23888
23889		 * Function: -
23890
23891		 * Purpose:  Check to see if a string is actually a formatted date
23892
23893		 * Returns:  string:'date' or null
23894
23895		 * Inputs:   string:sText - string to check
23896
23897		 */
23898
23899		function ( sData )
23900
23901		{
23902
23903			var iParse = Date.parse(sData);
23904
23905			if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
23906
23907			{
23908
23909				return 'date';
23910
23911			}
23912
23913			return null;
23914
23915		},
23916
23917		
23918
23919		/*
23920
23921		 * Function: -
23922
23923		 * Purpose:  Check to see if a string should be treated as an HTML string
23924
23925		 * Returns:  string:'html' or null
23926
23927		 * Inputs:   string:sText - string to check
23928
23929		 */
23930
23931		function ( sData )
23932
23933		{
23934
23935			if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
23936
23937			{
23938
23939				return 'html';
23940
23941			}
23942
23943			return null;
23944
23945		}
23946
23947	] );
23948
23949	
23950
23951
23952
23953	// jQuery aliases
23954
23955	$.fn.DataTable = DataTable;
23956
23957	$.fn.dataTable = DataTable;
23958
23959	$.fn.dataTableSettings = DataTable.settings;
23960
23961	$.fn.dataTableExt = DataTable.ext;
23962
23963
23964
23965
23966
23967	// Information about Businesses fired by DataTables - for documentation.
23968
23969	/**
23970
23971	 * Draw event, fired whenever the table is redrawn on the page, at the same point as
23972
23973	 * fnDrawCallback. This may be useful for binding Businesses or performing calculations when
23974
23975	 * the table is altered at all.
23976
23977	 *  @name DataTable#draw
23978
23979	 *  @event
23980
23981	 *  @param {event} e jQuery event object
23982
23983	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
23984
23985	 */
23986
23987
23988
23989	/**
23990
23991	 * Filter event, fired when the filtering applied to the table (using the build in global
23992
23993	 * global filter, or column filters) is altered.
23994
23995	 *  @name DataTable#filter
23996
23997	 *  @event
23998
23999	 *  @param {event} e jQuery event object
24000
24001	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24002
24003	 */
24004
24005
24006
24007	/**
24008
24009	 * Page change event, fired when the paging of the table is altered.
24010
24011	 *  @name DataTable#page
24012
24013	 *  @event
24014
24015	 *  @param {event} e jQuery event object
24016
24017	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24018
24019	 */
24020
24021
24022
24023	/**
24024
24025	 * Sort event, fired when the sorting applied to the table is altered.
24026
24027	 *  @name DataTable#sort
24028
24029	 *  @event
24030
24031	 *  @param {event} e jQuery event object
24032
24033	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24034
24035	 */
24036
24037
24038
24039	/**
24040
24041	 * DataTables initialisation complete event, fired when the table is fully drawn,
24042
24043	 * including Ajax data loaded, if Ajax data is required.
24044
24045	 *  @name DataTable#init
24046
24047	 *  @event
24048
24049	 *  @param {event} e jQuery event object
24050
24051	 *  @param {object} oSettings DataTables settings object
24052
24053	 *  @param {object} json The JSON object request from the server - only
24054
24055	 *    present if client-side Ajax sourced data is used</li></ol>
24056
24057	 */
24058
24059
24060
24061	/**
24062
24063	 * State save event, fired when the table has changed state a new state save is required.
24064
24065	 * This method allows modification of the state saving object prior to actually doing the
24066
24067	 * save, including addition or other state properties (for plug-ins) or modification
24068
24069	 * of a DataTables core property.
24070
24071	 *  @name DataTable#stateSaveParams
24072
24073	 *  @event
24074
24075	 *  @param {event} e jQuery event object
24076
24077	 *  @param {object} oSettings DataTables settings object
24078
24079	 *  @param {object} json The state information to be saved
24080
24081	 */
24082
24083
24084
24085	/**
24086
24087	 * State load event, fired when the table is loading state from the stored data, but
24088
24089	 * prior to the settings object being modified by the saved state - allowing modification
24090
24091	 * of the saved state is required or loading of state for a plug-in.
24092
24093	 *  @name DataTable#stateLoadParams
24094
24095	 *  @event
24096
24097	 *  @param {event} e jQuery event object
24098
24099	 *  @param {object} oSettings DataTables settings object
24100
24101	 *  @param {object} json The saved state information
24102
24103	 */
24104
24105
24106
24107	/**
24108
24109	 * State loaded event, fired when state has been loaded from stored data and the settings
24110
24111	 * object has been modified by the loaded data.
24112
24113	 *  @name DataTable#stateLoaded
24114
24115	 *  @event
24116
24117	 *  @param {event} e jQuery event object
24118
24119	 *  @param {object} oSettings DataTables settings object
24120
24121	 *  @param {object} json The saved state information
24122
24123	 */
24124
24125
24126
24127	/**
24128
24129	 * Processing event, fired when DataTables is doing some kind of processing (be it,
24130
24131	 * sort, filter or anything else). Can be used to indicate to the end user that
24132
24133	 * there is something happening, or that something has finished.
24134
24135	 *  @name DataTable#processing
24136
24137	 *  @event
24138
24139	 *  @param {event} e jQuery event object
24140
24141	 *  @param {object} oSettings DataTables settings object
24142
24143	 *  @param {boolean} bShow Flag for if DataTables is doing processing or not
24144
24145	 */
24146
24147
24148
24149	/**
24150
24151	 * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to 
24152
24153	 * made to the server for new data (note that this trigger is called 
24153in fnServerData,
24154
24155	 * if you override fnServerData and which to use this event, you need to trigger it in
24156
24157	 * you success function).
24158
24159	 *  @name DataTable#xhr
24160
24161	 *  @event
24162
24163	 *  @param {event} e jQuery event object
24164
24165	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24166
24167	 *  @param {object} json JSON returned from the server
24168
24169	 */
24170
24171
24172
24173	/**
24174
24175	 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing
24176
24177	 * the bDestroy:true parameter in the initialisation object. This can be used to remove
24178
24179	 * bound Businesses, added DOM nodes, etc.
24180
24181	 *  @name DataTable#destroy
24182
24183	 *  @event
24184
24185	 *  @param {event} e jQuery event object
24186
24187	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
24188
24189	 */
24190
24191}));
24192
24193
24194
24195}(window, document));
24196
24197
24198

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.