Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4755 amit.gupta 1
/**
2
 * @summary     DataTables
3
 * @description Paginate, search and sort HTML tables
4
 * @version     1.9.0
5
 * @file        jquery.dataTables.js
6
 * @author      Allan Jardine (www.sprymedia.co.uk)
7
 * @contact     www.sprymedia.co.uk/contact
8
 *
9
 * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
10
 *
11
 * This source file is free software, under either the GPL v2 license or a
12
 * BSD style license, available at:
13
 *   http://datatables.net/license_gpl2
14
 *   http://datatables.net/license_bsd
15
 * 
16
 * This source file is distributed in the hope that it will be useful, but 
17
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
18
 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
19
 * 
20
 * For details please refer to: http://www.datatables.net
21
 */
22
 
23
/*jslint evil: true, undef: true, browser: true */
24
/*globals $, jQuery,_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*/
25
 
26
(/** @lends <global> */function($, window, document, undefined) {
27
	/** 
28
	 * DataTables is a plug-in for the jQuery Javascript library. It is a 
29
	 * highly flexible tool, based upon the foundations of progressive 
30
	 * enhancement, which will add advanced interaction controls to any 
31
	 * HTML table. For a full list of features please refer to
32
	 * <a href="http://datatables.net">DataTables.net</a>.
33
	 *
34
	 * Note that the <i>DataTable</i> object is not a global variable but is
35
	 * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which 
36
	 * it may be  accessed.
37
	 *
38
	 *  @class
39
	 *  @param {object} [oInit={}] Configuration object for DataTables. Options
40
	 *    are defined by {@link DataTable.defaults}
41
	 *  @requires jQuery 1.3+
42
	 * 
43
	 *  @example
44
	 *    // Basic initialisation
45
	 *    $(document).ready( function {
46
	 *      $('#example').dataTable();
47
	 *    } );
48
	 *  
49
	 *  @example
50
	 *    // Initialisation with configuration options - in this case, disable
51
	 *    // pagination and sorting.
52
	 *    $(document).ready( function {
53
	 *      $('#example').dataTable( {
54
	 *        "bPaginate": false,
55
	 *        "bSort": false 
56
	 *      } );
57
	 *    } );
58
	 */
59
	var DataTable = function( oInit )
60
	{
61
 
62
 
63
		/**
64
		 * Add a column to the list used for the table with default values
65
		 *  @param {object} oSettings dataTables settings object
66
		 *  @param {node} nTh The th element for this column
67
		 *  @memberof DataTable#oApi
68
		 */
69
		function _fnAddColumn( oSettings, nTh )
70
		{
71
			var oDefaults = DataTable.defaults.columns;
72
			var iCol = oSettings.aoColumns.length;
73
			var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
74
				"sSortingClass": oSettings.oClasses.sSortable,
75
				"sSortingClassJUI": oSettings.oClasses.sSortJUI,
76
				"nTh": nTh ? nTh : document.createElement('th'),
77
				"sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
78
				"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
79
				"mDataProp": oDefaults.mDataProp ? oDefaults.oDefaults : iCol
80
			} );
81
			oSettings.aoColumns.push( oCol );
82
 
83
			/* Add a column specific filter */
84
			if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
85
			{
86
				oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
87
			}
88
			else
89
			{
90
				var oPre = oSettings.aoPreSearchCols[ iCol ];
91
 
92
				/* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
93
				if ( oPre.bRegex === undefined )
94
				{
95
					oPre.bRegex = true;
96
				}
97
 
98
				if ( oPre.bSmart === undefined )
99
				{
100
					oPre.bSmart = true;
101
				}
102
 
103
				if ( oPre.bCaseInsensitive === undefined )
104
				{
105
					oPre.bCaseInsensitive = true;
106
				}
107
			}
108
 
109
			/* Use the column options function to initialise classes etc */
110
			_fnColumnOptions( oSettings, iCol, null );
111
		}
112
 
113
 
114
		/**
115
		 * Apply options for a column
116
		 *  @param {object} oSettings dataTables settings object
117
		 *  @param {int} iCol column index to consider
118
		 *  @param {object} oOptions object with sType, bVisible and bSearchable
119
		 *  @memberof DataTable#oApi
120
		 */
121
		function _fnColumnOptions( oSettings, iCol, oOptions )
122
		{
123
			var oCol = oSettings.aoColumns[ iCol ];
124
 
125
			/* User specified column options */
126
			if ( oOptions !== undefined && oOptions !== null )
127
			{
128
				if ( oOptions.sType !== undefined )
129
				{
130
					oCol.sType = oOptions.sType;
131
					oCol._bAutoType = false;
132
				}
133
 
134
				$.extend( oCol, oOptions );
135
				_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
136
 
137
				/* iDataSort to be applied (backwards compatibility), but aDataSort will take
138
				 * priority if defined
139
				 */
140
				if ( oOptions.iDataSort !== undefined )
141
				{
142
					oCol.aDataSort = [ oOptions.iDataSort ];
143
				}
144
				_fnMap( oCol, oOptions, "aDataSort" );
145
			}
146
 
147
			/* Cache the data get and set functions for speed */
148
			oCol.fnGetData = _fnGetObjectDataFn( oCol.mDataProp );
149
			oCol.fnSetData = _fnSetObjectDataFn( oCol.mDataProp );
150
 
151
			/* Feature sorting overrides column specific when off */
152
			if ( !oSettings.oFeatures.bSort )
153
			{
154
				oCol.bSortable = false;
155
			}
156
 
157
			/* Check that the class assignment is correct for sorting */
158
			if ( !oCol.bSortable ||
159
				 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
160
			{
161
				oCol.sSortingClass = oSettings.oClasses.sSortableNone;
162
				oCol.sSortingClassJUI = "";
163
			}
164
			else if ( oCol.bSortable ||
165
			          ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
166
			{
167
			  oCol.sSortingClass = oSettings.oClasses.sSortable;
168
			  oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
169
			}
170
			else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
171
			{
172
				oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
173
				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
174
			}
175
			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
176
			{
177
				oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
178
				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
179
			}
180
		}
181
 
182
 
183
		/**
184
		 * Adjust the table column widths for new data. Note: you would probably want to 
185
		 * do a redraw after calling this function!
186
		 *  @param {object} oSettings dataTables settings object
187
		 *  @memberof DataTable#oApi
188
		 */
189
		function _fnAdjustColumnSizing ( oSettings )
190
		{
191
			/* Not interested in doing column width calculation if autowidth is disabled */
192
			if ( oSettings.oFeatures.bAutoWidth === false )
193
			{
194
				return false;
195
			}
196
 
197
			_fnCalculateColumnWidths( oSettings );
198
			for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
199
			{
200
				oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
201
			}
202
		}
203
 
204
 
205
		/**
206
		 * Covert the index of a visible column to the index in the data array (take account
207
		 * of hidden columns)
208
		 *  @param {object} oSettings dataTables settings object
209
		 *  @param {int} iMatch Visible column index to lookup
210
		 *  @returns {int} i the data index
211
		 *  @memberof DataTable#oApi
212
		 */
213
		function _fnVisibleToColumnIndex( oSettings, iMatch )
214
		{
215
			var iColumn = -1;
216
 
217
			for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
218
			{
219
				if ( oSettings.aoColumns[i].bVisible === true )
220
				{
221
					iColumn++;
222
				}
223
 
224
				if ( iColumn == iMatch )
225
				{
226
					return i;
227
				}
228
			}
229
 
230
			return null;
231
		}
232
 
233
 
234
		/**
235
		 * Covert the index of an index in the data array and convert it to the visible
236
		 *   column index (take account of hidden columns)
237
		 *  @param {int} iMatch Column index to lookup
238
		 *  @param {object} oSettings dataTables settings object
239
		 *  @returns {int} i the data index
240
		 *  @memberof DataTable#oApi
241
		 */
242
		function _fnColumnIndexToVisible( oSettings, iMatch )
243
		{
244
			var iVisible = -1;
245
			for ( var i=0 ; i<oSettings.aoColumns.length ; i++ )
246
			{
247
				if ( oSettings.aoColumns[i].bVisible === true )
248
				{
249
					iVisible++;
250
				}
251
 
252
				if ( i == iMatch )
253
				{
254
					return oSettings.aoColumns[i].bVisible === true ? iVisible : null;
255
				}
256
			}
257
 
258
			return null;
259
		}
260
 
261
 
262
		/**
263
		 * Get the number of visible columns
264
		 *  @returns {int} i the number of visible columns
265
		 *  @param {object} oS dataTables settings object
266
		 *  @memberof DataTable#oApi
267
		 */
268
		function _fnVisbleColumns( oS )
269
		{
270
			var iVis = 0;
271
			for ( var i=0 ; i<oS.aoColumns.length ; i++ )
272
			{
273
				if ( oS.aoColumns[i].bVisible === true )
274
				{
275
					iVis++;
276
				}
277
			}
278
			return iVis;
279
		}
280
 
281
 
282
		/**
283
		 * Get the sort type based on an input string
284
		 *  @param {string} sData data we wish to know the type of
285
		 *  @returns {string} type (defaults to 'string' if no type can be detected)
286
		 *  @memberof DataTable#oApi
287
		 */
288
		function _fnDetectType( sData )
289
		{
290
			var aTypes = DataTable.ext.aTypes;
291
			var iLen = aTypes.length;
292
 
293
			for ( var i=0 ; i<iLen ; i++ )
294
			{
295
				var sType = aTypes[i]( sData );
296
				if ( sType !== null )
297
				{
298
					return sType;
299
				}
300
			}
301
 
302
			return 'string';
303
		}
304
 
305
 
306
		/**
307
		 * Figure out how to reorder a display list
308
		 *  @param {object} oSettings dataTables settings object
309
		 *  @returns array {int} aiReturn index list for reordering
310
		 *  @memberof DataTable#oApi
311
		 */
312
		function _fnReOrderIndex ( oSettings, sColumns )
313
		{
314
			var aColumns = sColumns.split(',');
315
			var aiReturn = [];
316
 
317
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
318
			{
319
				for ( var j=0 ; j<iLen ; j++ )
320
				{
321
					if ( oSettings.aoColumns[i].sName == aColumns[j] )
322
					{
323
						aiReturn.push( j );
324
						break;
325
					}
326
				}
327
			}
328
 
329
			return aiReturn;
330
		}
331
 
332
 
333
		/**
334
		 * Get the column ordering that DataTables expects
335
		 *  @param {object} oSettings dataTables settings object
336
		 *  @returns {string} comma separated list of names
337
		 *  @memberof DataTable#oApi
338
		 */
339
		function _fnColumnOrdering ( oSettings )
340
		{
341
			var sNames = '';
342
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
343
			{
344
				sNames += oSettings.aoColumns[i].sName+',';
345
			}
346
			if ( sNames.length == iLen )
347
			{
348
				return "";
349
			}
350
			return sNames.slice(0, -1);
351
		}
352
 
353
 
354
		/**
355
		 * Take the column definitions and static columns arrays and calculate how
356
		 * they relate to column indexes. The callback function will then apply the
357
		 * definition found for a column to a suitable configuration object.
358
		 *  @param {object} oSettings dataTables settings object
359
		 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
360
		 *  @param {array} aoCols The aoColumns array that defines columns individually
361
		 *  @param {function} fn Callback function - takes two parameters, the calculated
362
		 *    column index and the definition for that column.
363
		 *  @memberof DataTable#oApi
364
		 */
365
		function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
366
		{
367
			var i, iLen, j, jLen, k, kLen;
368
 
369
			// Column definitions with aTargets
370
			if ( aoColDefs )
371
			{
372
				/* Loop over the definitions array - loop in reverse so first instance has priority */
373
				for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
374
				{
375
					/* Each definition can target multiple columns, as it is an array */
376
					var aTargets = aoColDefs[i].aTargets;
377
					if ( !$.isArray( aTargets ) )
378
					{
379
						_fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
380
					}
381
 
382
					for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
383
					{
384
						if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
385
						{
386
							/* Add columns that we don't yet know about */
387
							while( oSettings.aoColumns.length <= aTargets[j] )
388
							{
389
								_fnAddColumn( oSettings );
390
							}
391
 
392
							/* Integer, basic index */
393
							fn( aTargets[j], aoColDefs[i] );
394
						}
395
						else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
396
						{
397
							/* Negative integer, right to left column counting */
398
							fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
399
						}
400
						else if ( typeof aTargets[j] === 'string' )
401
						{
402
							/* Class name matching on TH element */
403
							for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
404
							{
405
								if ( aTargets[j] == "_all" ||
406
								     $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
407
								{
408
									fn( k, aoColDefs[i] );
409
								}
410
							}
411
						}
412
					}
413
				}
414
			}
415
 
416
			// Statically defined columns array
417
			if ( aoCols )
418
			{
419
				for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
420
				{
421
					fn( i, aoCols[i] );
422
				}
423
			}
424
		}
425
 
426
 
427
 
428
		/**
429
		 * Add a data array to the table, creating DOM node etc. This is the parallel to 
430
		 * _fnGatherData, but for adding rows from a Javascript source, rather than a
431
		 * DOM source.
432
		 *  @param {object} oSettings dataTables settings object
433
		 *  @param {array} aData data array to be added
434
		 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
435
		 *  @memberof DataTable#oApi
436
		 */
437
		function _fnAddData ( oSettings, aDataSupplied )
438
		{
439
			var oCol;
440
 
441
			/* Take an independent copy of the data source so we can bash it about as we wish */
442
			var aDataIn = ($.isArray(aDataSupplied)) ?
443
				aDataSupplied.slice() :
444
				$.extend( true, {}, aDataSupplied );
445
 
446
			/* Create the object for storing information about this new row */
447
			var iRow = oSettings.aoData.length;
448
			var oData = $.extend( true, {}, DataTable.models.oRow, {
449
				"_aData": aDataIn
450
			} );
451
			oSettings.aoData.push( oData );
452
 
453
			/* Create the cells */
454
			var nTd, sThisType;
455
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
456
			{
457
				oCol = oSettings.aoColumns[i];
458
 
459
				/* Use rendered data for filtering/sorting */
460
				if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mDataProp !== null )
461
				{
462
					_fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
463
				}
464
 
465
				/* See if we should auto-detect the column type */
466
				if ( oCol._bAutoType && oCol.sType != 'string' )
467
				{
468
					/* Attempt to auto detect the type - same as _fnGatherData() */
469
					var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
470
					if ( sVarType !== null && sVarType !== '' )
471
					{
472
						sThisType = _fnDetectType( sVarType );
473
						if ( oCol.sType === null )
474
						{
475
							oCol.sType = sThisType;
476
						}
477
						else if ( oCol.sType != sThisType && oCol.sType != "html" )
478
						{
479
							/* String is always the 'fallback' option */
480
							oCol.sType = 'string';
481
						}
482
					}
483
				}
484
			}
485
 
486
			/* Add to the display array */
487
			oSettings.aiDisplayMaster.push( iRow );
488
 
489
			/* Create the DOM imformation */
490
			if ( !oSettings.oFeatures.bDeferRender )
491
			{
492
				_fnCreateTr( oSettings, iRow );
493
			}
494
 
495
			return iRow;
496
		}
497
 
498
 
499
		/**
500
		 * Read in the data from the target table from the DOM
501
		 *  @param {object} oSettings dataTables settings object
502
		 *  @memberof DataTable#oApi
503
		 */
504
		function _fnGatherData( oSettings )
505
		{
506
			var iLoop, i, iLen, j, jLen, jInner,
507
			 	nTds, nTrs, nTd, aLocalData, iThisIndex,
508
				iRow, iRows, iColumn, iColumns, sNodeName,
509
				oCol, oData;
510
 
511
			/*
512
			 * Process by row first
513
			 * Add the data object for the whole table - storing the tr node. Note - no point in getting
514
			 * DOM based data if we are going to go and replace it with Ajax source data.
515
			 */
516
			if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
517
			{
518
				nTrs = oSettings.nTBody.childNodes;
519
				for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
520
				{
521
					if ( nTrs[i].nodeName.toUpperCase() == "TR" )
522
					{
523
						iThisIndex = oSettings.aoData.length;
524
						nTrs[i]._DT_RowIndex = iThisIndex;
525
						oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
526
							"nTr": nTrs[i]
527
						} ) );
528
 
529
						oSettings.aiDisplayMaster.push( iThisIndex );
530
						nTds = nTrs[i].childNodes;
531
						jInner = 0;
532
 
533
						for ( j=0, jLen=nTds.length ; j<jLen ; j++ )
534
						{
535
							sNodeName = nTds[j].nodeName.toUpperCase();
536
							if ( sNodeName == "TD" || sNodeName == "TH" )
537
							{
538
								_fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTds[j].innerHTML) );
539
								jInner++;
540
							}
541
						}
542
					}
543
				}
544
			}
545
 
546
			/* Gather in the TD elements of the Table - note that this is basically the same as
547
			 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
548
			 * setup!
549
			 */
550
			nTrs = _fnGetTrNodes( oSettings );
551
			nTds = [];
552
			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
553
			{
554
				for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
555
				{
556
					nTd = nTrs[i].childNodes[j];
557
					sNodeName = nTd.nodeName.toUpperCase();
558
					if ( sNodeName == "TD" || sNodeName == "TH" )
559
					{
560
						nTds.push( nTd );
561
					}
562
				}
563
			}
564
 
565
			/* Now process by column */
566
			for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
567
			{
568
				oCol = oSettings.aoColumns[iColumn];
569
 
570
				/* Get the title of the column - unless there is a user set one */
571
				if ( oCol.sTitle === null )
572
				{
573
					oCol.sTitle = oCol.nTh.innerHTML;
574
				}
575
 
576
				var
577
					bAutoType = oCol._bAutoType,
578
					bRender = typeof oCol.fnRender === 'function',
579
					bClass = oCol.sClass !== null,
580
					bVisible = oCol.bVisible,
581
					nCell, sThisType, sRendered, sValType;
582
 
583
				/* A single loop to rule them all (and be more efficient) */
584
				if ( bAutoType || bRender || bClass || !bVisible )
585
				{
586
					for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
587
					{
588
						oData = oSettings.aoData[iRow];
589
						nCell = nTds[ (iRow*iColumns) + iColumn ];
590
 
591
						/* Type detection */
592
						if ( bAutoType && oCol.sType != 'string' )
593
						{
594
							sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
595
							if ( sValType !== '' )
596
							{
597
								sThisType = _fnDetectType( sValType );
598
								if ( oCol.sType === null )
599
								{
600
									oCol.sType = sThisType;
601
								}
602
								else if ( oCol.sType != sThisType && 
603
								          oCol.sType != "html" )
604
								{
605
									/* String is always the 'fallback' option */
606
									oCol.sType = 'string';
607
								}
608
							}
609
						}
610
 
611
						if ( typeof oCol.mDataProp === 'function' )
612
						{
613
							nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
614
						}
615
 
616
						/* Rendering */
617
						if ( bRender )
618
						{
619
							sRendered = _fnRender( oSettings, iRow, iColumn );
620
							nCell.innerHTML = sRendered;
621
							if ( oCol.bUseRendered )
622
							{
623
								/* Use the rendered data for filtering/sorting */
624
								_fnSetCellData( oSettings, iRow, iColumn, sRendered );
625
							}
626
						}
627
 
628
						/* Classes */
629
						if ( bClass )
630
						{
631
							nCell.className += ' '+oCol.sClass;
632
						}
633
 
634
						/* Column visability */
635
						if ( !bVisible )
636
						{
637
							oData._anHidden[iColumn] = nCell;
638
							nCell.parentNode.removeChild( nCell );
639
						}
640
						else
641
						{
642
							oData._anHidden[iColumn] = null;
643
						}
644
 
645
						if ( oCol.fnCreatedCell )
646
						{
647
							oCol.fnCreatedCell.call( oSettings.oInstance,
648
								nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
649
							);
650
						}
651
					}
652
				}
653
			}
654
 
655
			/* Row created callbacks */
656
			if ( oSettings.aoRowCreatedCallback.length !== 0 )
657
			{
658
				for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
659
				{
660
					oData = oSettings.aoData[i];
661
					_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
662
				}
663
			}
664
		}
665
 
666
 
667
		/**
668
		 * Take a TR element and convert it to an index in aoData
669
		 *  @param {object} oSettings dataTables settings object
670
		 *  @param {node} n the TR element to find
671
		 *  @returns {int} index if the node is found, null if not
672
		 *  @memberof DataTable#oApi
673
		 */
674
		function _fnNodeToDataIndex( oSettings, n )
675
		{
676
			return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
677
		}
678
 
679
 
680
		/**
681
		 * Take a TD element and convert it into a column data index (not the visible index)
682
		 *  @param {object} oSettings dataTables settings object
683
		 *  @param {int} iRow The row number the TD/TH can be found in
684
		 *  @param {node} n The TD/TH element to find
685
		 *  @returns {int} index if the node is found, -1 if not
686
		 *  @memberof DataTable#oApi
687
		 */
688
		function _fnNodeToColumnIndex( oSettings, iRow, n )
689
		{
690
			var anCells = _fnGetTdNodes( oSettings, iRow );
691
 
692
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
693
			{
694
				if ( anCells[i] === n )
695
				{
696
					return i;
697
				}
698
			}
699
			return -1;
700
		}
701
 
702
 
703
		/**
704
		 * Get an array of data for a given row from the internal data cache
705
		 *  @param {object} oSettings dataTables settings object
706
		 *  @param {int} iRow aoData row id
707
		 *  @param {string} sSpecific data get type ('type' 'filter' 'sort')
708
		 *  @returns {array} Data array
709
		 *  @memberof DataTable#oApi
710
		 */
711
		function _fnGetRowData( oSettings, iRow, sSpecific )
712
		{
713
			var out = [];
714
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
715
			{
716
				out.push( _fnGetCellData( oSettings, iRow, i, sSpecific ) );
717
			}
718
			return out;
719
		}
720
 
721
 
722
		/**
723
		 * Get the data for a given cell from the internal cache, taking into account data mapping
724
		 *  @param {object} oSettings dataTables settings object
725
		 *  @param {int} iRow aoData row id
726
		 *  @param {int} iCol Column index
727
		 *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
728
		 *  @returns {*} Cell data
729
		 *  @memberof DataTable#oApi
730
		 */
731
		function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
732
		{
733
			var sData;
734
			var oCol = oSettings.aoColumns[iCol];
735
			var oData = oSettings.aoData[iRow]._aData;
736
 
737
			if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
738
			{
739
				if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
740
				{
741
					_fnLog( oSettings, 0, "Requested unknown parameter '"+oCol.mDataProp+
742
						"' from the data source for row "+iRow );
743
					oSettings.iDrawError = oSettings.iDraw;
744
				}
745
				return oCol.sDefaultContent;
746
			}
747
 
748
			/* When the data source is null, we can use default column data */
749
			if ( sData === null && oCol.sDefaultContent !== null )
750
			{
751
				sData = oCol.sDefaultContent;
752
			}
753
			else if ( typeof sData === 'function' )
754
			{
755
				/* If the data source is a function, then we run it and use the return */
756
				return sData();
757
			}
758
 
759
			if ( sSpecific == 'display' && sData === null )
760
			{
761
				return '';
762
			}
763
			return sData;
764
		}
765
 
766
 
767
		/**
768
		 * Set the value for a specific cell, into the internal data cache
769
		 *  @param {object} oSettings dataTables settings object
770
		 *  @param {int} iRow aoData row id
771
		 *  @param {int} iCol Column index
772
		 *  @param {*} val Value to set
773
		 *  @memberof DataTable#oApi
774
		 */
775
		function _fnSetCellData( oSettings, iRow, iCol, val )
776
		{
777
			var oCol = oSettings.aoColumns[iCol];
778
			var oData = oSettings.aoData[iRow]._aData;
779
 
780
			oCol.fnSetData( oData, val );
781
		}
782
 
783
 
784
		/**
785
		 * Return a function that can be used to get data from a source object, taking
786
		 * into account the ability to use nested objects as a source
787
		 *  @param {string|int|function} mSource The data source for the object
788
		 *  @returns {function} Data get function
789
		 *  @memberof DataTable#oApi
790
		 */
791
		function _fnGetObjectDataFn( mSource )
792
		{
793
			if ( mSource === null )
794
			{
795
				/* Give an empty string for rendering / sorting etc */
796
				return function (data, type) {
797
					return null;
798
				};
799
			}
800
			else if ( typeof mSource === 'function' )
801
			{
802
				return function (data, type) {
803
					return mSource( data, type );
804
				};
805
			}
806
			else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
807
			{
808
				/* If there is a . in the source string then the data source is in a 
809
				 * nested object so we loop over the data for each level to get the next
810
				 * level down. On each loop we test for undefined, and if found immediatly
811
				 * return. This allows entire objects to be missing and sDefaultContent to
812
				 * be used if defined, rather than throwing an error
813
				 */
814
				var a = mSource.split('.');
815
				return function (data, type) {
816
					for ( var i=0, iLen=a.length ; i<iLen ; i++ )
817
					{
818
						data = data[ a[i] ];
819
						if ( data === undefined )
820
						{
821
							return undefined;
822
						}
823
					}
824
					return data;
825
				};
826
			}
827
			else
828
			{
829
				/* Array or flat object mapping */
830
				return function (data, type) {
831
					return data[mSource];	
832
				};
833
			}
834
		}
835
 
836
 
837
		/**
838
		 * Return a function that can be used to set data from a source object, taking
839
		 * into account the ability to use nested objects as a source
840
		 *  @param {string|int|function} mSource The data source for the object
841
		 *  @returns {function} Data set function
842
		 *  @memberof DataTable#oApi
843
		 */
844
		function _fnSetObjectDataFn( mSource )
845
		{
846
			if ( mSource === null )
847
			{
848
				/* Nothing to do when the data source is null */
849
				return function (data, val) {};
850
			}
851
			else if ( typeof mSource === 'function' )
852
			{
853
				return function (data, val) {
854
					mSource( data, 'set', val );
855
				};
856
			}
857
			else if ( typeof mSource === 'string' && mSource.indexOf('.') != -1 )
858
			{
859
				/* Like the get, we need to get data from a nested object.  */
860
				var a = mSource.split('.');
861
				return function (data, val) {
862
					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
863
					{
864
						data = data[ a[i] ];
865
					}
866
					data[ a[a.length-1] ] = val;
867
				};
868
			}
869
			else
870
			{
871
				/* Array or flat object mapping */
872
				return function (data, val) {
873
					data[mSource] = val;	
874
				};
875
			}
876
		}
877
 
878
 
879
		/**
880
		 * Return an array with the full table data
881
		 *  @param {object} oSettings dataTables settings object
882
		 *  @returns array {array} aData Master data array
883
		 *  @memberof DataTable#oApi
884
		 */
885
		function _fnGetDataMaster ( oSettings )
886
		{
887
			var aData = [];
888
			var iLen = oSettings.aoData.length;
889
			for ( var i=0 ; i<iLen; i++ )
890
			{
891
				aData.push( oSettings.aoData[i]._aData );
892
			}
893
			return aData;
894
		}
895
 
896
 
897
		/**
898
		 * Nuke the table
899
		 *  @param {object} oSettings dataTables settings object
900
		 *  @memberof DataTable#oApi
901
		 */
902
		function _fnClearTable( oSettings )
903
		{
904
			oSettings.aoData.splice( 0, oSettings.aoData.length );
905
			oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
906
			oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
907
			_fnCalculateEnd( oSettings );
908
		}
909
 
910
 
911
		 /**
912
		 * Take an array of integers (index array) and remove a target integer (value - not 
913
		 * the key!)
914
		 *  @param {array} a Index array to target
915
		 *  @param {int} iTarget value to find
916
		 *  @memberof DataTable#oApi
917
		 */
918
		function _fnDeleteIndex( a, iTarget )
919
		{
920
			var iTargetIndex = -1;
921
 
922
			for ( var i=0, iLen=a.length ; i<iLen ; i++ )
923
			{
924
				if ( a[i] == iTarget )
925
				{
926
					iTargetIndex = i;
927
				}
928
				else if ( a[i] > iTarget )
929
				{
930
					a[i]--;
931
				}
932
			}
933
 
934
			if ( iTargetIndex != -1 )
935
			{
936
				a.splice( iTargetIndex, 1 );
937
			}
938
		}
939
 
940
 
941
		 /**
942
		 * Call the developer defined fnRender function for a given cell (row/column) with
943
		 * the required parameters and return the result.
944
		 *  @param {object} oSettings dataTables settings object
945
		 *  @param {int} iRow aoData index for the row
946
		 *  @param {int} iCol aoColumns index for the column
947
		 *  @returns {*} Return of the developer's fnRender function
948
		 *  @memberof DataTable#oApi
949
		 */
950
		function _fnRender( oSettings, iRow, iCol )
951
		{
952
			var oCol = oSettings.aoColumns[iCol];
953
 
954
			return oCol.fnRender( {
955
				"iDataRow":    iRow,
956
				"iDataColumn": iCol,
957
				"oSettings":   oSettings,
958
				"aData":       oSettings.aoData[iRow]._aData,
959
				"mDataProp":   oCol.mDataProp
960
			}, _fnGetCellData(oSettings, iRow, iCol, 'display') );
961
		}
962
 
963
 
964
		/**
965
		 * Create a new TR element (and it's TD children) for a row
966
		 *  @param {object} oSettings dataTables settings object
967
		 *  @param {int} iRow Row to consider
968
		 *  @memberof DataTable#oApi
969
		 */
970
		function _fnCreateTr ( oSettings, iRow )
971
		{
972
			var oData = oSettings.aoData[iRow];
973
			var nTd;
974
 
975
			if ( oData.nTr === null )
976
			{
977
				oData.nTr = document.createElement('tr');
978
 
979
				/* Use a private property on the node to allow reserve mapping from the node
980
				 * to the aoData array for fast look up
981
				 */
982
				oData.nTr._DT_RowIndex = iRow;
983
 
984
				/* Special parameters can be given by the data source to be used on the row */
985
				if ( oData._aData.DT_RowId )
986
				{
987
					oData.nTr.id = oData._aData.DT_RowId;
988
				}
989
 
990
				if ( oData._aData.DT_RowClass )
991
				{
992
					$(oData.nTr).addClass( oData._aData.DT_RowClass );
993
				}
994
 
995
				/* Process each column */
996
				for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
997
				{
998
					var oCol = oSettings.aoColumns[i];
999
					nTd = document.createElement('td');
1000
 
1001
					/* Render if needed - if bUseRendered is true then we already have the rendered
1002
					 * value in the data source - so can just use that
1003
					 */
1004
					nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mDataProp === null)) ?
1005
						_fnRender( oSettings, iRow, i ) :
1006
						_fnGetCellData( oSettings, iRow, i, 'display' );
1007
 
1008
					/* Add user defined class */
1009
					if ( oCol.sClass !== null )
1010
					{
1011
						nTd.className = oCol.sClass;
1012
					}
1013
 
1014
					if ( oCol.bVisible )
1015
					{
1016
						oData.nTr.appendChild( nTd );
1017
						oData._anHidden[i] = null;
1018
					}
1019
					else
1020
					{
1021
						oData._anHidden[i] = nTd;
1022
					}
1023
 
1024
					if ( oCol.fnCreatedCell )
1025
					{
1026
						oCol.fnCreatedCell.call( oSettings.oInstance,
1027
							nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
1028
						);
1029
					}
1030
				}
1031
 
1032
				_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
1033
			}
1034
		}
1035
 
1036
 
1037
		/**
1038
		 * Create the HTML header for the table
1039
		 *  @param {object} oSettings dataTables settings object
1040
		 *  @memberof DataTable#oApi
1041
		 */
1042
		function _fnBuildHead( oSettings )
1043
		{
1044
			var i, nTh, iLen, j, jLen;
1045
			var iThs = oSettings.nTHead.getElementsByTagName('th').length;
1046
			var iCorrector = 0;
1047
			var jqChildren;
1048
 
1049
			/* If there is a header in place - then use it - otherwise it's going to get nuked... */
1050
			if ( iThs !== 0 )
1051
			{
1052
				/* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
1053
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1054
				{
1055
					nTh = oSettings.aoColumns[i].nTh;
1056
					nTh.setAttribute('role', 'columnheader');
1057
					if ( oSettings.aoColumns[i].bSortable )
1058
					{
1059
						nTh.setAttribute('tabindex', oSettings.iTabIndex);
1060
						nTh.setAttribute('aria-controls', oSettings.sTableId);
1061
					}
1062
 
1063
					if ( oSettings.aoColumns[i].sClass !== null )
1064
					{
1065
						$(nTh).addClass( oSettings.aoColumns[i].sClass );
1066
					}
1067
 
1068
					/* Set the title of the column if it is user defined (not what was auto detected) */
1069
					if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
1070
					{
1071
						nTh.innerHTML = oSettings.aoColumns[i].sTitle;
1072
					}
1073
				}
1074
			}
1075
			else
1076
			{
1077
				/* We don't have a header in the DOM - so we are going to have to create one */
1078
				var nTr = document.createElement( "tr" );
1079
 
1080
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1081
				{
1082
					nTh = oSettings.aoColumns[i].nTh;
1083
					nTh.innerHTML = oSettings.aoColumns[i].sTitle;
1084
					nTh.setAttribute('tabindex', '0');
1085
 
1086
					if ( oSettings.aoColumns[i].sClass !== null )
1087
					{
1088
						$(nTh).addClass( oSettings.aoColumns[i].sClass );
1089
					}
1090
 
1091
					nTr.appendChild( nTh );
1092
				}
1093
				$(oSettings.nTHead).html( '' )[0].appendChild( nTr );
1094
				_fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
1095
			}
1096
 
1097
			/* ARIA role for the rows */	
1098
			$(oSettings.nTHead).children('tr').attr('role', 'row');
1099
 
1100
			/* Add the extra markup needed by jQuery UI's themes */
1101
			if ( oSettings.bJUI )
1102
			{
1103
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1104
				{
1105
					nTh = oSettings.aoColumns[i].nTh;
1106
 
1107
					var nDiv = document.createElement('div');
1108
					nDiv.className = oSettings.oClasses.sSortJUIWrapper;
1109
					$(nTh).contents().appendTo(nDiv);
1110
 
1111
					var nSpan = document.createElement('span');
1112
					nSpan.className = oSettings.oClasses.sSortIcon;
1113
					nDiv.appendChild( nSpan );
1114
					nTh.appendChild( nDiv );
1115
				}
1116
			}
1117
 
1118
			if ( oSettings.oFeatures.bSort )
1119
			{
1120
				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
1121
				{
1122
					if ( oSettings.aoColumns[i].bSortable !== false )
1123
					{
1124
						_fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
1125
					}
1126
					else
1127
					{
1128
						$(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
1129
					}
1130
				}
1131
			}
1132
 
1133
			/* Deal with the footer - add classes if required */
1134
			if ( oSettings.oClasses.sFooterTH !== "" )
1135
			{
1136
				$(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
1137
			}
1138
 
1139
			/* Cache the footer elements */
1140
			if ( oSettings.nTFoot !== null )
1141
			{
1142
				var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
1143
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1144
				{
1145
					if ( anCells[i] )
1146
					{
1147
						oSettings.aoColumns[i].nTf = anCells[i];
1148
						if ( oSettings.aoColumns[i].sClass )
1149
						{
1150
							$(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
1151
						}
1152
					}
1153
				}
1154
			}
1155
		}
1156
 
1157
 
1158
		/**
1159
		 * Draw the header (or footer) element based on the column visibility states. The
1160
		 * methodology here is to use the layout array from _fnDetectHeader, modified for
1161
		 * the instantaneous column visibility, to construct the new layout. The grid is
1162
		 * traversed over cell at a time in a rows x columns grid fashion, although each 
1163
		 * cell insert can cover multiple elements in the grid - which is tracks using the
1164
		 * aApplied array. Cell inserts in the grid will only occur where there isn't
1165
		 * already a cell in that position.
1166
		 *  @param {object} oSettings dataTables settings object
1167
		 *  @param array {objects} aoSource Layout array from _fnDetectHeader
1168
		 *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 
1169
		 *  @memberof DataTable#oApi
1170
		 */
1171
		function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1172
		{
1173
			var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1174
			var aoLocal = [];
1175
			var aApplied = [];
1176
			var iColumns = oSettings.aoColumns.length;
1177
			var iRowspan, iColspan;
1178
 
1179
			if (  bIncludeHidden === undefined )
1180
			{
1181
				bIncludeHidden = false;
1182
			}
1183
 
1184
			/* Make a copy of the master layout array, but without the visible columns in it */
1185
			for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1186
			{
1187
				aoLocal[i] = aoSource[i].slice();
1188
				aoLocal[i].nTr = aoSource[i].nTr;
1189
 
1190
				/* Remove any columns which are currently hidden */
1191
				for ( j=iColumns-1 ; j>=0 ; j-- )
1192
				{
1193
					if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1194
					{
1195
						aoLocal[i].splice( j, 1 );
1196
					}
1197
				}
1198
 
1199
				/* Prep the applied array - it needs an element for each row */
1200
				aApplied.push( [] );
1201
			}
1202
 
1203
			for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1204
			{
1205
				nLocalTr = aoLocal[i].nTr;
1206
 
1207
				/* All cells are going to be replaced, so empty out the row */
1208
				if ( nLocalTr )
1209
				{
1210
					while( (n = nLocalTr.firstChild) )
1211
					{
1212
						nLocalTr.removeChild( n );
1213
					}
1214
				}
1215
 
1216
				for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1217
				{
1218
					iRowspan = 1;
1219
					iColspan = 1;
1220
 
1221
					/* Check to see if there is already a cell (row/colspan) covering our target
1222
					 * insert point. If there is, then there is nothing to do.
1223
					 */
1224
					if ( aApplied[i][j] === undefined )
1225
					{
1226
						nLocalTr.appendChild( aoLocal[i][j].cell );
1227
						aApplied[i][j] = 1;
1228
 
1229
						/* Expand the cell to cover as many rows as needed */
1230
						while ( aoLocal[i+iRowspan] !== undefined &&
1231
						        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1232
						{
1233
							aApplied[i+iRowspan][j] = 1;
1234
							iRowspan++;
1235
						}
1236
 
1237
						/* Expand the cell to cover as many columns as needed */
1238
						while ( aoLocal[i][j+iColspan] !== undefined &&
1239
						        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1240
						{
1241
							/* Must update the applied array over the rows for the columns */
1242
							for ( k=0 ; k<iRowspan ; k++ )
1243
							{
1244
								aApplied[i+k][j+iColspan] = 1;
1245
							}
1246
							iColspan++;
1247
						}
1248
 
1249
						/* Do the actual expansion in the DOM */
1250
						aoLocal[i][j].cell.rowSpan = iRowspan;
1251
						aoLocal[i][j].cell.colSpan = iColspan;
1252
					}
1253
				}
1254
			}
1255
		}
1256
 
1257
 
1258
		/**
1259
		 * Insert the required TR nodes into the table for display
1260
		 *  @param {object} oSettings dataTables settings object
1261
		 *  @memberof DataTable#oApi
1262
		 */
1263
		function _fnDraw( oSettings )
1264
		{
1265
			var i, iLen, n;
1266
			var anRows = [];
1267
			var iRowCount = 0;
1268
			var iStripes = oSettings.asStripeClasses.length;
1269
			var iOpenRows = oSettings.aoOpenRows.length;
1270
 
1271
			/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1272
			var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1273
			if ( $.inArray( false, aPreDraw ) !== -1 )
1274
			{
1275
				return;
1276
			}
1277
 
1278
			oSettings.bDrawing = true;
1279
 
1280
			/* Check and see if we have an initial draw position from state saving */
1281
			if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 )
1282
			{
1283
				if ( oSettings.oFeatures.bServerSide )
1284
				{
1285
					oSettings._iDisplayStart = oSettings.iInitDisplayStart;
1286
				}
1287
				else
1288
				{
1289
					oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
1290
 
1291
				}
1292
				oSettings.iInitDisplayStart = -1;
1293
				_fnCalculateEnd( oSettings );
1294
			}
1295
 
1296
			/* Server-side processing draw intercept */
1297
			if ( oSettings.bDeferLoading )
1298
			{
1299
				oSettings.bDeferLoading = false;
1300
				oSettings.iDraw++;
1301
			}
1302
			else if ( !oSettings.oFeatures.bServerSide )
1303
			{
1304
				oSettings.iDraw++;
1305
			}
1306
			else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
1307
			{
1308
				return;
1309
			}
1310
 
1311
			if ( oSettings.aiDisplay.length !== 0 )
1312
			{
1313
				var iStart = oSettings._iDisplayStart;
1314
				var iEnd = oSettings._iDisplayEnd;
1315
 
1316
				if ( oSettings.oFeatures.bServerSide )
1317
				{
1318
					iStart = 0;
1319
					iEnd = oSettings.aoData.length;
1320
				}
1321
 
1322
				for ( var j=iStart ; j<iEnd ; j++ )
1323
				{
1324
					var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
1325
					if ( aoData.nTr === null )
1326
					{
1327
						_fnCreateTr( oSettings, oSettings.aiDisplay[j] );
1328
					}
1329
 
1330
					var nRow = aoData.nTr;
1331
 
1332
					/* Remove the old striping classes and then add the new one */
1333
					if ( iStripes !== 0 )
1334
					{
1335
						var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
1336
						if ( aoData._sRowStripe != sStripe )
1337
						{
1338
							$(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
1339
							aoData._sRowStripe = sStripe;
1340
						}
1341
					}
1342
 
1343
					/* Row callback functions - might want to manipule the row */
1344
					_fnCallbackFire( oSettings, 'aoRowCallback', null, 
1345
						[nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] );
1346
 
1347
					anRows.push( nRow );
1348
					iRowCount++;
1349
 
1350
					/* If there is an open row - and it is attached to this parent - attach it on redraw */
1351
					if ( iOpenRows !== 0 )
1352
					{
1353
						for ( var k=0 ; k<iOpenRows ; k++ )
1354
						{
1355
							if ( nRow == oSettings.aoOpenRows[k].nParent )
1356
							{
1357
								anRows.push( oSettings.aoOpenRows[k].nTr );
1358
								break;
1359
							}
1360
						}
1361
					}
1362
				}
1363
			}
1364
			else
1365
			{
1366
				/* Table is empty - create a row with an empty message in it */
1367
				anRows[ 0 ] = document.createElement( 'tr' );
1368
 
1369
				if ( oSettings.asStripeClasses[0] )
1370
				{
1371
					anRows[ 0 ].className = oSettings.asStripeClasses[0];
1372
				}
1373
 
1374
				var sZero = oSettings.oLanguage.sZeroRecords.replace(
1375
					'_MAX_', oSettings.fnFormatNumber(oSettings.fnRecordsTotal()) );
1376
				if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
1377
				{
1378
					sZero = oSettings.oLanguage.sLoadingRecords;
1379
				}
1380
				else if ( oSettings.oLanguage.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
1381
				{
1382
					sZero = oSettings.oLanguage.sEmptyTable;
1383
				}
1384
 
1385
				var nTd = document.createElement( 'td' );
1386
				nTd.setAttribute( 'valign', "top" );
1387
				nTd.colSpan = _fnVisbleColumns( oSettings );
1388
				nTd.className = oSettings.oClasses.sRowEmpty;
1389
				nTd.innerHTML = sZero;
1390
 
1391
				anRows[ iRowCount ].appendChild( nTd );
1392
			}
1393
 
1394
			/* Header and footer callbacks */
1395
			_fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 
1396
				_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
1397
 
1398
			_fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 
1399
				_fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
1400
 
1401
			/* 
1402
			 * Need to remove any old row from the display - note we can't just empty the tbody using
1403
			 * $().html('') since this will unbind the jQuery event handlers (even although the node 
1404
			 * still exists!) - equally we can't use innerHTML, since IE throws an exception.
1405
			 */
1406
			var
1407
				nAddFrag = document.createDocumentFragment(),
1408
				nRemoveFrag = document.createDocumentFragment(),
1409
				nBodyPar, nTrs;
1410
 
1411
			if ( oSettings.nTBody )
1412
			{
1413
				nBodyPar = oSettings.nTBody.parentNode;
1414
				nRemoveFrag.appendChild( oSettings.nTBody );
1415
 
1416
				/* When doing infinite scrolling, only remove child rows when sorting, filtering or start
1417
				 * up. When not infinite scroll, always do it.
1418
				 */
1419
				if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
1420
				 	oSettings.bSorted || oSettings.bFiltered )
1421
				{
1422
					while( (n = oSettings.nTBody.firstChild) )
1423
					{
1424
						oSettings.nTBody.removeChild( n );
1425
					}
1426
				}
1427
 
1428
				/* Put the draw table into the dom */
1429
				for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
1430
				{
1431
					nAddFrag.appendChild( anRows[i] );
1432
				}
1433
 
1434
				oSettings.nTBody.appendChild( nAddFrag );
1435
				if ( nBodyPar !== null )
1436
				{
1437
					nBodyPar.appendChild( oSettings.nTBody );
1438
				}
1439
			}
1440
 
1441
			/* Call all required callback functions for the end of a draw */
1442
			_fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
1443
 
1444
			/* Draw is complete, sorting and filtering must be as well */
1445
			oSettings.bSorted = false;
1446
			oSettings.bFiltered = false;
1447
			oSettings.bDrawing = false;
1448
 
1449
			if ( oSettings.oFeatures.bServerSide )
1450
			{
1451
				_fnProcessingDisplay( oSettings, false );
1452
				if ( !oSettings._bInitComplete )
1453
				{
1454
					_fnInitComplete( oSettings );
1455
				}
1456
			}
1457
		}
1458
 
1459
 
1460
		/**
1461
		 * Redraw the table - taking account of the various features which are enabled
1462
		 *  @param {object} oSettings dataTables settings object
1463
		 *  @memberof DataTable#oApi
1464
		 */
1465
		function _fnReDraw( oSettings )
1466
		{
1467
			if ( oSettings.oFeatures.bSort )
1468
			{
1469
				/* Sorting will refilter and draw for us */
1470
				_fnSort( oSettings, oSettings.oPreviousSearch );
1471
			}
1472
			else if ( oSettings.oFeatures.bFilter )
1473
			{
1474
				/* Filtering will redraw for us */
1475
				_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
1476
			}
1477
			else
1478
			{
1479
				_fnCalculateEnd( oSettings );
1480
				_fnDraw( oSettings );
1481
			}
1482
		}
1483
 
1484
 
1485
		/**
1486
		 * Add the options to the page HTML for the table
1487
		 *  @param {object} oSettings dataTables settings object
1488
		 *  @memberof DataTable#oApi
1489
		 */
1490
		function _fnAddOptionsHtml ( oSettings )
1491
		{
1492
			/*
1493
			 * Create a temporary, empty, div which we can later on replace with what we have generated
1494
			 * we do it this way to rendering the 'options' html offline - speed :-)
1495
			 */
1496
			var nHolding = $('<div></div>')[0];
1497
			oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
1498
 
1499
			/* 
1500
			 * All DataTables are wrapped in a div
1501
			 */
1502
			oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];
1503
			oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
1504
 
1505
			/* Track where we want to insert the option */
1506
			var nInsertNode = oSettings.nTableWrapper;
1507
 
1508
			/* Loop over the user set positioning and place the elements as needed */
1509
			var aDom = oSettings.sDom.split('');
1510
			var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
1511
			for ( var i=0 ; i<aDom.length ; i++ )
1512
			{
1513
				iPushFeature = 0;
1514
				cOption = aDom[i];
1515
 
1516
				if ( cOption == '<' )
1517
				{
1518
					/* New container div */
1519
					nNewNode = $('<div></div>')[0];
1520
 
1521
					/* Check to see if we should append an id and/or a class name to the container */
1522
					cNext = aDom[i+1];
1523
					if ( cNext == "'" || cNext == '"' )
1524
					{
1525
						sAttr = "";
1526
						j = 2;
1527
						while ( aDom[i+j] != cNext )
1528
						{
1529
							sAttr += aDom[i+j];
1530
							j++;
1531
						}
1532
 
1533
						/* Replace jQuery UI constants */
1534
						if ( sAttr == "H" )
1535
						{
1536
							sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix";
1537
						}
1538
						else if ( sAttr == "F" )
1539
						{
1540
							sAttr = "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix";
1541
						}
1542
 
1543
						/* The attribute can be in the format of "#id.class", "#id" or "class" This logic
1544
						 * breaks the string into parts and applies them as needed
1545
						 */
1546
						if ( sAttr.indexOf('.') != -1 )
1547
						{
1548
							var aSplit = sAttr.split('.');
1549
							nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
1550
							nNewNode.className = aSplit[1];
1551
						}
1552
						else if ( sAttr.charAt(0) == "#" )
1553
						{
1554
							nNewNode.id = sAttr.substr(1, sAttr.length-1);
1555
						}
1556
						else
1557
						{
1558
							nNewNode.className = sAttr;
1559
						}
1560
 
1561
						i += j; /* Move along the position array */
1562
					}
1563
 
1564
					nInsertNode.appendChild( nNewNode );
1565
					nInsertNode = nNewNode;
1566
				}
1567
				else if ( cOption == '>' )
1568
				{
1569
					/* End container div */
1570
					nInsertNode = nInsertNode.parentNode;
1571
				}
1572
				else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
1573
				{
1574
					/* Length */
1575
					nTmp = _fnFeatureHtmlLength( oSettings );
1576
					iPushFeature = 1;
1577
				}
1578
				else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
1579
				{
1580
					/* Filter */
1581
					nTmp = _fnFeatureHtmlFilter( oSettings );
1582
					iPushFeature = 1;
1583
				}
1584
				else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
1585
				{
1586
					/* pRocessing */
1587
					nTmp = _fnFeatureHtmlProcessing( oSettings );
1588
					iPushFeature = 1;
1589
				}
1590
				else if ( cOption == 't' )
1591
				{
1592
					/* Table */
1593
					nTmp = _fnFeatureHtmlTable( oSettings );
1594
					iPushFeature = 1;
1595
				}
1596
				else if ( cOption ==  'i' && oSettings.oFeatures.bInfo )
1597
				{
1598
					/* Info */
1599
					nTmp = _fnFeatureHtmlInfo( oSettings );
1600
					iPushFeature = 1;
1601
				}
1602
				else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
1603
				{
1604
					/* Pagination */
1605
					nTmp = _fnFeatureHtmlPaginate( oSettings );
1606
					iPushFeature = 1;
1607
				}
1608
				else if ( DataTable.ext.aoFeatures.length !== 0 )
1609
				{
1610
					/* Plug-in features */
1611
					var aoFeatures = DataTable.ext.aoFeatures;
1612
					for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
1613
					{
1614
						if ( cOption == aoFeatures[k].cFeature )
1615
						{
1616
							nTmp = aoFeatures[k].fnInit( oSettings );
1617
							if ( nTmp )
1618
							{
1619
								iPushFeature = 1;
1620
							}
1621
							break;
1622
						}
1623
					}
1624
				}
1625
 
1626
				/* Add to the 2D features array */
1627
				if ( iPushFeature == 1 && nTmp !== null )
1628
				{
1629
					if ( typeof oSettings.aanFeatures[cOption] !== 'object' )
1630
					{
1631
						oSettings.aanFeatures[cOption] = [];
1632
					}
1633
					oSettings.aanFeatures[cOption].push( nTmp );
1634
					nInsertNode.appendChild( nTmp );
1635
				}
1636
			}
1637
 
1638
			/* Built our DOM structure - replace the holding div with what we want */
1639
			nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
1640
		}
1641
 
1642
 
1643
		/**
1644
		 * Use the DOM source to create up an array of header cells. The idea here is to
1645
		 * create a layout grid (array) of rows x columns, which contains a reference
1646
		 * to the cell that that point in the grid (regardless of col/rowspan), such that
1647
		 * any column / row could be removed and the new grid constructed
1648
		 *  @param array {object} aLayout Array to store the calculated layout in
1649
		 *  @param {node} nThead The header/footer element for the table
1650
		 *  @memberof DataTable#oApi
1651
		 */
1652
		function _fnDetectHeader ( aLayout, nThead )
1653
		{
1654
			var nTrs = $(nThead).children('tr');
1655
			var nCell;
1656
			var i, j, k, l, iLen, jLen, iColShifted;
1657
			var fnShiftCol = function ( a, i, j ) {
1658
				while ( a[i][j] ) {
1659
					j++;
1660
				}
1661
				return j;
1662
			};
1663
 
1664
			aLayout.splice( 0, aLayout.length );
1665
 
1666
			/* We know how many rows there are in the layout - so prep it */
1667
			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
1668
			{
1669
				aLayout.push( [] );
1670
			}
1671
 
1672
			/* Calculate a layout array */
1673
			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
1674
			{
1675
				var iColumn = 0;
1676
 
1677
				/* For every cell in the row... */
1678
				for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
1679
				{
1680
					nCell = nTrs[i].childNodes[j];
1681
 
1682
					if ( nCell.nodeName.toUpperCase() == "TD" ||
1683
					     nCell.nodeName.toUpperCase() == "TH" )
1684
					{
1685
						/* Get the col and rowspan attributes from the DOM and sanitise them */
1686
						var iColspan = nCell.getAttribute('colspan') * 1;
1687
						var iRowspan = nCell.getAttribute('rowspan') * 1;
1688
						iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
1689
						iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
1690
 
1691
						/* There might be colspan cells already in this row, so shift our target 
1692
						 * accordingly
1693
						 */
1694
						iColShifted = fnShiftCol( aLayout, i, iColumn );
1695
 
1696
						/* If there is col / rowspan, copy the information into the layout grid */
1697
						for ( l=0 ; l<iColspan ; l++ )
1698
						{
1699
							for ( k=0 ; k<iRowspan ; k++ )
1700
							{
1701
								aLayout[i+k][iColShifted+l] = {
1702
									"cell": nCell,
1703
									"unique": iColspan == 1 ? true : false
1704
								};
1705
								aLayout[i+k].nTr = nTrs[i];
1706
							}
1707
						}
1708
					}
1709
				}
1710
			}
1711
		}
1712
 
1713
 
1714
		/**
1715
		 * Get an array of unique th elements, one for each column
1716
		 *  @param {object} oSettings dataTables settings object
1717
		 *  @param {node} nHeader automatically detect the layout from this node - optional
1718
		 *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
1719
		 *  @returns array {node} aReturn list of unique ths
1720
		 *  @memberof DataTable#oApi
1721
		 */
1722
		function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
1723
		{
1724
			var aReturn = [];
1725
			if ( !aLayout )
1726
			{
1727
				aLayout = oSettings.aoHeader;
1728
				if ( nHeader )
1729
				{
1730
					aLayout = [];
1731
					_fnDetectHeader( aLayout, nHeader );
1732
				}
1733
			}
1734
 
1735
			for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
1736
			{
1737
				for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
1738
				{
1739
					if ( aLayout[i][j].unique && 
1740
						 (!aReturn[j] || !oSettings.bSortCellsTop) )
1741
					{
1742
						aReturn[j] = aLayout[i][j].cell;
1743
					}
1744
				}
1745
			}
1746
 
1747
			return aReturn;
1748
		}
1749
 
1750
 
1751
 
1752
		/**
1753
		 * Update the table using an Ajax call
1754
		 *  @param {object} oSettings dataTables settings object
1755
		 *  @returns {boolean} Block the table drawing or not
1756
		 *  @memberof DataTable#oApi
1757
		 */
1758
		function _fnAjaxUpdate( oSettings )
1759
		{
1760
			if ( oSettings.bAjaxDataGet )
1761
			{
1762
				oSettings.iDraw++;
1763
				_fnProcessingDisplay( oSettings, true );
1764
				var iColumns = oSettings.aoColumns.length;
1765
				var aoData = _fnAjaxParameters( oSettings );
1766
				_fnServerParams( oSettings, aoData );
1767
 
1768
				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
1769
					function(json) {
1770
						_fnAjaxUpdateDraw( oSettings, json );
1771
					}, oSettings );
1772
				return false;
1773
			}
1774
			else
1775
			{
1776
				return true;
1777
			}
1778
		}
1779
 
1780
 
1781
		/**
1782
		 * Build up the parameters in an object needed for a server-side processing request
1783
		 *  @param {object} oSettings dataTables settings object
1784
		 *  @returns {bool} block the table drawing or not
1785
		 *  @memberof DataTable#oApi
1786
		 */
1787
		function _fnAjaxParameters( oSettings )
1788
		{
1789
			var iColumns = oSettings.aoColumns.length;
1790
			var aoData = [], mDataProp;
1791
			var i;
1792
 
1793
			aoData.push( { "name": "sEcho",          "value": oSettings.iDraw } );
1794
			aoData.push( { "name": "iColumns",       "value": iColumns } );
1795
			aoData.push( { "name": "sColumns",       "value": _fnColumnOrdering(oSettings) } );
1796
			aoData.push( { "name": "iDisplayStart",  "value": oSettings._iDisplayStart } );
1797
			aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
1798
				oSettings._iDisplayLength : -1 } );
1799
 
1800
			for ( i=0 ; i<iColumns ; i++ )
1801
			{
1802
			  mDataProp = oSettings.aoColumns[i].mDataProp;
1803
				aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );
1804
			}
1805
 
1806
			/* Filtering */
1807
			if ( oSettings.oFeatures.bFilter !== false )
1808
			{
1809
				aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
1810
				aoData.push( { "name": "bRegex",  "value": oSettings.oPreviousSearch.bRegex } );
1811
				for ( i=0 ; i<iColumns ; i++ )
1812
				{
1813
					aoData.push( { "name": "sSearch_"+i,     "value": oSettings.aoPreSearchCols[i].sSearch } );
1814
					aoData.push( { "name": "bRegex_"+i,      "value": oSettings.aoPreSearchCols[i].bRegex } );
1815
					aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
1816
				}
1817
			}
1818
 
1819
			/* Sorting */
1820
			if ( oSettings.oFeatures.bSort !== false )
1821
			{
1822
				var iFixed = oSettings.aaSortingFixed !== null ? oSettings.aaSortingFixed.length : 0;
1823
				var iUser = oSettings.aaSorting.length;
1824
				aoData.push( { "name": "iSortingCols",   "value": iFixed+iUser } );
1825
				for ( i=0 ; i<iFixed ; i++ )
1826
				{
1827
					aoData.push( { "name": "iSortCol_"+i,  "value": oSettings.aaSortingFixed[i][0] } );
1828
					aoData.push( { "name": "sSortDir_"+i,  "value": oSettings.aaSortingFixed[i][1] } );
1829
				}
1830
 
1831
				for ( i=0 ; i<iUser ; i++ )
1832
				{
1833
					aoData.push( { "name": "iSortCol_"+(i+iFixed),  "value": oSettings.aaSorting[i][0] } );
1834
					aoData.push( { "name": "sSortDir_"+(i+iFixed),  "value": oSettings.aaSorting[i][1] } );
1835
				}
1836
 
1837
				for ( i=0 ; i<iColumns ; i++ )
1838
				{
1839
					aoData.push( { "name": "bSortable_"+i,  "value": oSettings.aoColumns[i].bSortable } );
1840
				}
1841
			}
1842
 
1843
			return aoData;
1844
		}
1845
 
1846
 
1847
		/**
1848
		 * Add Ajax parameters from plugins
1849
		 *  @param {object} oSettings dataTables settings object
1850
		 *  @param array {objects} aoData name/value pairs to send to the server
1851
		 *  @memberof DataTable#oApi
1852
		 */
1853
		function _fnServerParams( oSettings, aoData )
1854
		{
1855
			_fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );
1856
		}
1857
 
1858
 
1859
		/**
1860
		 * Data the data from the server (nuking the old) and redraw the table
1861
		 *  @param {object} oSettings dataTables settings object
1862
		 *  @param {object} json json data return from the server.
1863
		 *  @param {string} json.sEcho Tracking flag for DataTables to match requests
1864
		 *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
1865
		 *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
1866
		 *  @param {array} json.aaData The data to display on this page
1867
		 *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
1868
		 *  @memberof DataTable#oApi
1869
		 */
1870
		function _fnAjaxUpdateDraw ( oSettings, json )
1871
		{
1872
			if ( json.sEcho !== undefined )
1873
			{
1874
				/* Protect against old returns over-writing a new one. Possible when you get
1875
				 * very fast interaction, and later queires are completed much faster
1876
				 */
1877
				if ( json.sEcho*1 < oSettings.iDraw )
1878
				{
1879
					return;
1880
				}
1881
				else
1882
				{
1883
					oSettings.iDraw = json.sEcho * 1;
1884
				}
1885
			}
1886
 
1887
			if ( !oSettings.oScroll.bInfinite ||
1888
				   (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
1889
			{
1890
				_fnClearTable( oSettings );
1891
			}
1892
			oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);
1893
			oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);
1894
 
1895
			/* Determine if reordering is required */
1896
			var sOrdering = _fnColumnOrdering(oSettings);
1897
			var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering );
1898
			var aiIndex;
1899
			if ( bReOrder )
1900
			{
1901
				aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
1902
			}
1903
 
1904
			var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );
1905
			for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
1906
			{
1907
				if ( bReOrder )
1908
				{
1909
					/* If we need to re-order, then create a new array with the correct order and add it */
1910
					var aDataSorted = [];
1911
					for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
1912
					{
1913
						aDataSorted.push( aData[i][ aiIndex[j] ] );
1914
					}
1915
					_fnAddData( oSettings, aDataSorted );
1916
				}
1917
				else
1918
				{
1919
					/* No re-order required, sever got it "right" - just straight add */
1920
					_fnAddData( oSettings, aData[i] );
1921
				}
1922
			}
1923
			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
1924
 
1925
			oSettings.bAjaxDataGet = false;
1926
			_fnDraw( oSettings );
1927
			oSettings.bAjaxDataGet = true;
1928
			_fnProcessingDisplay( oSettings, false );
1929
		}
1930
 
1931
 
1932
 
1933
		/**
1934
		 * Generate the node required for filtering text
1935
		 *  @returns {node} Filter control element
1936
		 *  @param {object} oSettings dataTables settings object
1937
		 *  @memberof DataTable#oApi
1938
		 */
1939
		function _fnFeatureHtmlFilter ( oSettings )
1940
		{
1941
			var oPreviousSearch = oSettings.oPreviousSearch;
1942
 
1943
			var sSearchStr = oSettings.oLanguage.sSearch;
1944
			sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
1945
			  sSearchStr.replace('_INPUT_', '<input type="text" />') :
1946
			  sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
1947
 
1948
			var nFilter = document.createElement( 'div' );
1949
			nFilter.className = oSettings.oClasses.sFilter;
1950
			nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
1951
			if ( !oSettings.aanFeatures.f )
1952
			{
1953
				nFilter.id = oSettings.sTableId+'_filter';
1954
			}
1955
 
1956
			var jqFilter = $("input", nFilter);
1957
			jqFilter.val( oPreviousSearch.sSearch.replace('"','&quot;') );
1958
			jqFilter.bind( 'keyup.DT', function(e) {
1959
				/* Update all other filter input elements for the new display */
1960
				var n = oSettings.aanFeatures.f;
1961
				for ( var i=0, iLen=n.length ; i<iLen ; i++ )
1962
				{
1963
					if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
1964
					{
1965
						$('input', n[i]).val( this.value );
1966
					}
1967
				}
1968
 
1969
				/* Now do the filter */
1970
				if ( this.value != oPreviousSearch.sSearch )
1971
				{
1972
					_fnFilterComplete( oSettings, { 
1973
						"sSearch": this.value, 
1974
						"bRegex": oPreviousSearch.bRegex,
1975
						"bSmart": oPreviousSearch.bSmart ,
1976
						"bCaseInsensitive": oPreviousSearch.bCaseInsensitive 
1977
					} );
1978
				}
1979
			} );
1980
 
1981
			jqFilter
1982
				.attr('aria-controls', oSettings.sTableId)
1983
				.bind( 'keypress.DT', function(e) {
1984
					/* Prevent form submission */
1985
					if ( e.keyCode == 13 )
1986
					{
1987
						return false;
1988
					}
1989
				}
1990
			);
1991
 
1992
			return nFilter;
1993
		}
1994
 
1995
 
1996
		/**
1997
		 * Filter the table using both the global filter and column based filtering
1998
		 *  @param {object} oSettings dataTables settings object
1999
		 *  @param {object} oSearch search information
2000
		 *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2001
		 *  @memberof DataTable#oApi
2002
		 */
2003
		function _fnFilterComplete ( oSettings, oInput, iForce )
2004
		{
2005
			var oPrevSearch = oSettings.oPreviousSearch;
2006
			var aoPrevSearch = oSettings.aoPreSearchCols;
2007
			var fnSaveFilter = function ( oFilter ) {
2008
				/* Save the filtering values */
2009
				oPrevSearch.sSearch = oFilter.sSearch;
2010
				oPrevSearch.bRegex = oFilter.bRegex;
2011
				oPrevSearch.bSmart = oFilter.bSmart;
2012
				oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2013
			};
2014
 
2015
			/* In server-side processing all filtering is done by the server, so no point hanging around here */
2016
			if ( !oSettings.oFeatures.bServerSide )
2017
			{
2018
				/* Global filter */
2019
				_fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );
2020
				fnSaveFilter( oInput );
2021
 
2022
				/* Now do the individual column filter */
2023
				for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
2024
				{
2025
					_fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex, 
2026
						aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2027
				}
2028
 
2029
				/* Custom filtering */
2030
				_fnFilterCustom( oSettings );
2031
			}
2032
			else
2033
			{
2034
				fnSaveFilter( oInput );
2035
			}
2036
 
2037
			/* Tell the draw function we have been filtering */
2038
			oSettings.bFiltered = true;
2039
			$(oSettings.oInstance).trigger('filter', oSettings);
2040
 
2041
			/* Redraw the table */
2042
			oSettings._iDisplayStart = 0;
2043
			_fnCalculateEnd( oSettings );
2044
			_fnDraw( oSettings );
2045
 
2046
			/* Rebuild search array 'offline' */
2047
			_fnBuildSearchArray( oSettings, 0 );
2048
		}
2049
 
2050
 
2051
		/**
2052
		 * Apply custom filtering functions
2053
		 *  @param {object} oSettings dataTables settings object
2054
		 *  @memberof DataTable#oApi
2055
		 */
2056
		function _fnFilterCustom( oSettings )
2057
		{
2058
			var afnFilters = DataTable.ext.afnFiltering;
2059
			for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
2060
			{
2061
				var iCorrector = 0;
2062
				for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
2063
				{
2064
					var iDisIndex = oSettings.aiDisplay[j-iCorrector];
2065
 
2066
					/* Check if we should use this row based on the filtering function */
2067
					if ( !afnFilters[i]( oSettings, _fnGetRowData( oSettings, iDisIndex, 'filter' ), iDisIndex ) )
2068
					{
2069
						oSettings.aiDisplay.splice( j-iCorrector, 1 );
2070
						iCorrector++;
2071
					}
2072
				}
2073
			}
2074
		}
2075
 
2076
 
2077
		/**
2078
		 * Filter the table on a per-column basis
2079
		 *  @param {object} oSettings dataTables settings object
2080
		 *  @param {string} sInput string to filter on
2081
		 *  @param {int} iColumn column to filter
2082
		 *  @param {bool} bRegex treat search string as a regular expression or not
2083
		 *  @param {bool} bSmart use smart filtering or not
2084
		 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
2085
		 *  @memberof DataTable#oApi
2086
		 */
2087
		function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )
2088
		{
2089
			if ( sInput === "" )
2090
			{
2091
				return;
2092
			}
2093
 
2094
			var iIndexCorrector = 0;
2095
			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
2096
 
2097
			for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
2098
			{
2099
				var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
2100
					oSettings.aoColumns[iColumn].sType );
2101
				if ( ! rpSearch.test( sData ) )
2102
				{
2103
					oSettings.aiDisplay.splice( i, 1 );
2104
					iIndexCorrector++;
2105
				}
2106
			}
2107
		}
2108
 
2109
 
2110
		/**
2111
		 * Filter the data table based on user input and draw the table
2112
		 *  @param {object} oSettings dataTables settings object
2113
		 *  @param {string} sInput string to filter on
2114
		 *  @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0)
2115
		 *  @param {bool} bRegex treat as a regular expression or not
2116
		 *  @param {bool} bSmart perform smart filtering or not
2117
		 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
2118
		 *  @memberof DataTable#oApi
2119
		 */
2120
		function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )
2121
		{
2122
			var i;
2123
			var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
2124
			var oPrevSearch = oSettings.oPreviousSearch;
2125
 
2126
			/* Check if we are forcing or not - optional parameter */
2127
			if ( !iForce )
2128
			{
2129
				iForce = 0;
2130
			}
2131
 
2132
			/* Need to take account of custom filtering functions - always filter */
2133
			if ( DataTable.ext.afnFiltering.length !== 0 )
2134
			{
2135
				iForce = 1;
2136
			}
2137
 
2138
			/*
2139
			 * If the input is blank - we want the full data set
2140
			 */
2141
			if ( sInput.length <= 0 )
2142
			{
2143
				oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
2144
				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2145
			}
2146
			else
2147
			{
2148
				/*
2149
				 * We are starting a new search or the new search string is smaller 
2150
				 * then the old one (i.e. delete). Search from the master array
2151
			 	 */
2152
				if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
2153
					   oPrevSearch.sSearch.length > sInput.length || iForce == 1 ||
2154
					   sInput.indexOf(oPrevSearch.sSearch) !== 0 )
2155
				{
2156
					/* Nuke the old display array - we are going to rebuild it */
2157
					oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
2158
 
2159
					/* Force a rebuild of the search array */
2160
					_fnBuildSearchArray( oSettings, 1 );
2161
 
2162
					/* Search through all records to populate the search array
2163
					 * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 
2164
					 * mapping
2165
					 */
2166
					for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
2167
					{
2168
						if ( rpSearch.test(oSettings.asDataSearch[i]) )
2169
						{
2170
							oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
2171
						}
2172
					}
2173
			  }
2174
			  else
2175
				{
2176
			  	/* Using old search array - refine it - do it this way for speed
2177
			  	 * Don't have to search the whole master array again
2178
					 */
2179
			  	var iIndexCorrector = 0;
2180
 
2181
			  	/* Search the current results */
2182
			  	for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
2183
					{
2184
			  		if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
2185
						{
2186
			  			oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
2187
			  			iIndexCorrector++;
2188
			  		}
2189
			  	}
2190
			  }
2191
			}
2192
		}
2193
 
2194
 
2195
		/**
2196
		 * Create an array which can be quickly search through
2197
		 *  @param {object} oSettings dataTables settings object
2198
		 *  @param {int} iMaster use the master data array - optional
2199
		 *  @memberof DataTable#oApi
2200
		 */
2201
		function _fnBuildSearchArray ( oSettings, iMaster )
2202
		{
2203
			if ( !oSettings.oFeatures.bServerSide )
2204
			{
2205
				/* Clear out the old data */
2206
				oSettings.asDataSearch.splice( 0, oSettings.asDataSearch.length );
2207
 
2208
				var aArray = (iMaster && iMaster===1) ?
2209
				 	oSettings.aiDisplayMaster : oSettings.aiDisplay;
2210
 
2211
				for ( var i=0, iLen=aArray.length ; i<iLen ; i++ )
2212
				{
2213
					oSettings.asDataSearch[i] = _fnBuildSearchRow( oSettings,
2214
						_fnGetRowData( oSettings, aArray[i], 'filter' ) );
2215
				}
2216
			}
2217
		}
2218
 
2219
 
2220
		/**
2221
		 * Create a searchable string from a single data row
2222
		 *  @param {object} oSettings dataTables settings object
2223
		 *  @param {array} aData Row data array to use for the data to search
2224
		 *  @memberof DataTable#oApi
2225
		 */
2226
		function _fnBuildSearchRow( oSettings, aData )
2227
		{
2228
			var sSearch = '';
2229
			if ( oSettings.__nTmpFilter === undefined )
2230
			{
2231
				oSettings.__nTmpFilter = document.createElement('div');
2232
			}
2233
			var nTmp = oSettings.__nTmpFilter;
2234
 
2235
			for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
2236
			{
2237
				if ( oSettings.aoColumns[j].bSearchable )
2238
				{
2239
					var sData = aData[j];
2240
					sSearch += _fnDataToSearch( sData, oSettings.aoColumns[j].sType )+'  ';
2241
				}
2242
			}
2243
 
2244
			/* If it looks like there is an HTML entity in the string, attempt to decode it */
2245
			if ( sSearch.indexOf('&') !== -1 )
2246
			{
2247
				nTmp.innerHTML = sSearch;
2248
				sSearch = nTmp.textContent ? nTmp.textContent : nTmp.innerText;
2249
 
2250
				/* IE and Opera appear to put an newline where there is a <br> tag - remove it */
2251
				sSearch = sSearch.replace(/\n/g," ").replace(/\r/g,"");
2252
			}
2253
 
2254
			return sSearch;
2255
		}
2256
 
2257
		/**
2258
		 * Build a regular expression object suitable for searching a table
2259
		 *  @param {string} sSearch string to search for
2260
		 *  @param {bool} bRegex treat as a regular expression or not
2261
		 *  @param {bool} bSmart perform smart filtering or not
2262
		 *  @param {bool} bCaseInsensitive Do case insenstive matching or not
2263
		 *  @returns {RegExp} constructed object
2264
		 *  @memberof DataTable#oApi
2265
		 */
2266
		function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )
2267
		{
2268
			var asSearch, sRegExpString;
2269
 
2270
			if ( bSmart )
2271
			{
2272
				/* Generate the regular expression to use. Something along the lines of:
2273
				 * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
2274
				 */
2275
				asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
2276
				sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
2277
				return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );
2278
			}
2279
			else
2280
			{
2281
				sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
2282
				return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );
2283
			}
2284
		}
2285
 
2286
 
2287
		/**
2288
		 * Convert raw data into something that the user can search on
2289
		 *  @param {string} sData data to be modified
2290
		 *  @param {string} sType data type
2291
		 *  @returns {string} search string
2292
		 *  @memberof DataTable#oApi
2293
		 */
2294
		function _fnDataToSearch ( sData, sType )
2295
		{
2296
			if ( typeof DataTable.ext.ofnSearch[sType] === "function" )
2297
			{
2298
				return DataTable.ext.ofnSearch[sType]( sData );
2299
			}
2300
			else if ( sType == "html" )
2301
			{
2302
				return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
2303
			}
2304
			else if ( typeof sData === "string" )
2305
			{
2306
				return sData.replace(/[\r\n]/g," ");
2307
			}
2308
			else if ( sData === null )
2309
			{
2310
				return '';
2311
			}
2312
			return sData;
2313
		}
2314
 
2315
 
2316
		/**
2317
		 * scape a string stuch that it can be used in a regular expression
2318
		 *  @param {string} sVal string to escape
2319
		 *  @returns {string} escaped string
2320
		 *  @memberof DataTable#oApi
2321
		 */
2322
		function _fnEscapeRegex ( sVal )
2323
		{
2324
			var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^' ];
2325
			var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
2326
			return sVal.replace(reReplace, '\\$1');
2327
		}
2328
 
2329
 
2330
 
2331
		/**
2332
		 * Generate the node required for the info display
2333
		 *  @param {object} oSettings dataTables settings object
2334
		 *  @returns {node} Information element
2335
		 *  @memberof DataTable#oApi
2336
		 */
2337
		function _fnFeatureHtmlInfo ( oSettings )
2338
		{
2339
			var nInfo = document.createElement( 'div' );
2340
			nInfo.className = oSettings.oClasses.sInfo;
2341
 
2342
			/* Actions that are to be taken once only for this feature */
2343
			if ( !oSettings.aanFeatures.i )
2344
			{
2345
				/* Add draw callback */
2346
				oSettings.aoDrawCallback.push( {
2347
					"fn": _fnUpdateInfo,
2348
					"sName": "information"
2349
				} );
2350
 
2351
				/* Add id */
2352
				nInfo.id = oSettings.sTableId+'_info';
2353
			}
2354
			oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );
2355
 
2356
			return nInfo;
2357
		}
2358
 
2359
 
2360
		/**
2361
		 * Update the information elements in the display
2362
		 *  @param {object} oSettings dataTables settings object
2363
		 *  @memberof DataTable#oApi
2364
		 */
2365
		function _fnUpdateInfo ( oSettings )
2366
		{
2367
			/* Show information about the table */
2368
			if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
2369
			{
2370
				return;
2371
			}
2372
 
2373
			var
2374
				iStart = oSettings._iDisplayStart+1, iEnd = oSettings.fnDisplayEnd(),
2375
				iMax = oSettings.fnRecordsTotal(), iTotal = oSettings.fnRecordsDisplay(),
2376
				sStart = oSettings.fnFormatNumber( iStart ), sEnd = oSettings.fnFormatNumber( iEnd ),
2377
				sMax = oSettings.fnFormatNumber( iMax ), sTotal = oSettings.fnFormatNumber( iTotal ),
2378
				sOut;
2379
 
2380
			/* When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
2381
			 * internally
2382
			 */
2383
			if ( oSettings.oScroll.bInfinite )
2384
			{
2385
				sStart = oSettings.fnFormatNumber( 1 );
2386
			}
2387
 
2388
			if ( oSettings.fnRecordsDisplay() === 0 && 
2389
				   oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
2390
			{
2391
				/* Empty record set */
2392
				sOut = oSettings.oLanguage.sInfoEmpty+ oSettings.oLanguage.sInfoPostFix;
2393
			}
2394
			else if ( oSettings.fnRecordsDisplay() === 0 )
2395
			{
2396
				/* Rmpty record set after filtering */
2397
				sOut = oSettings.oLanguage.sInfoEmpty +' '+ 
2398
					oSettings.oLanguage.sInfoFiltered.replace('_MAX_', sMax)+
2399
						oSettings.oLanguage.sInfoPostFix;
2400
			}
2401
			else if ( oSettings.fnRecordsDisplay() == oSettings.fnRecordsTotal() )
2402
			{
2403
				/* Normal record set */
2404
				sOut = oSettings.oLanguage.sInfo.
2405
						replace('_START_', sStart).
2406
						replace('_END_',   sEnd).
2407
						replace('_TOTAL_', sTotal)+ 
2408
					oSettings.oLanguage.sInfoPostFix;
2409
			}
2410
			else
2411
			{
2412
				/* Record set after filtering */
2413
				sOut = oSettings.oLanguage.sInfo.
2414
						replace('_START_', sStart).
2415
						replace('_END_',   sEnd).
2416
						replace('_TOTAL_', sTotal) +' '+ 
2417
					oSettings.oLanguage.sInfoFiltered.replace('_MAX_', 
2418
						oSettings.fnFormatNumber(oSettings.fnRecordsTotal()))+ 
2419
					oSettings.oLanguage.sInfoPostFix;
2420
			}
2421
 
2422
			if ( oSettings.oLanguage.fnInfoCallback !== null )
2423
			{
2424
				sOut = oSettings.oLanguage.fnInfoCallback.call( oSettings.oInstance, 
2425
					oSettings, iStart, iEnd, iMax, iTotal, sOut );
2426
			}
2427
 
2428
			var n = oSettings.aanFeatures.i;
2429
			for ( var i=0, iLen=n.length ; i<iLen ; i++ )
2430
			{
2431
				$(n[i]).html( sOut );
2432
			}
2433
		}
2434
 
2435
 
2436
 
2437
		/**
2438
		 * Draw the table for the first time, adding all required features
2439
		 *  @param {object} oSettings dataTables settings object
2440
		 *  @memberof DataTable#oApi
2441
		 */
2442
		function _fnInitialise ( oSettings )
2443
		{
2444
			var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
2445
 
2446
			/* Ensure that the table data is fully initialised */
2447
			if ( oSettings.bInitialised === false )
2448
			{
2449
				setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
2450
				return;
2451
			}
2452
 
2453
			/* Show the display HTML options */
2454
			_fnAddOptionsHtml( oSettings );
2455
 
2456
			/* Build and draw the header / footer for the table */
2457
			_fnBuildHead( oSettings );
2458
			_fnDrawHead( oSettings, oSettings.aoHeader );
2459
			if ( oSettings.nTFoot )
2460
			{
2461
				_fnDrawHead( oSettings, oSettings.aoFooter );
2462
			}
2463
 
2464
			/* Okay to show that something is going on now */
2465
			_fnProcessingDisplay( oSettings, true );
2466
 
2467
			/* Calculate sizes for columns */
2468
			if ( oSettings.oFeatures.bAutoWidth )
2469
			{
2470
				_fnCalculateColumnWidths( oSettings );
2471
			}
2472
 
2473
			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
2474
			{
2475
				if ( oSettings.aoColumns[i].sWidth !== null )
2476
				{
2477
					oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
2478
				}
2479
			}
2480
 
2481
			/* If there is default sorting required - let's do it. The sort function will do the
2482
			 * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
2483
			 * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
2484
			 */
2485
			if ( oSettings.oFeatures.bSort )
2486
			{
2487
				_fnSort( oSettings );
2488
			}
2489
			else if ( oSettings.oFeatures.bFilter )
2490
			{
2491
				_fnFilterComplete( oSettings, oSettings.oPreviousSearch );
2492
			}
2493
			else
2494
			{
2495
				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2496
				_fnCalculateEnd( oSettings );
2497
				_fnDraw( oSettings );
2498
			}
2499
 
2500
			/* if there is an ajax source load the data */
2501
			if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
2502
			{
2503
				var aoData = [];
2504
				_fnServerParams( oSettings, aoData );
2505
				oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
2506
					var aData = (oSettings.sAjaxDataProp !== "") ?
2507
					 	_fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json;
2508
 
2509
					/* Got the data - add it to the table */
2510
					for ( i=0 ; i<aData.length ; i++ )
2511
					{
2512
						_fnAddData( oSettings, aData[i] );
2513
					}
2514
 
2515
					/* Reset the init display for cookie saving. We've already done a filter, and
2516
					 * therefore cleared it before. So we need to make it appear 'fresh'
2517
					 */
2518
					oSettings.iInitDisplayStart = iAjaxStart;
2519
 
2520
					if ( oSettings.oFeatures.bSort )
2521
					{
2522
						_fnSort( oSettings );
2523
					}
2524
					else
2525
					{
2526
						oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
2527
						_fnCalculateEnd( oSettings );
2528
						_fnDraw( oSettings );
2529
					}
2530
 
2531
					_fnProcessingDisplay( oSettings, false );
2532
					_fnInitComplete( oSettings, json );
2533
				}, oSettings );
2534
				return;
2535
			}
2536
 
2537
			/* Server-side processing initialisation complete is done at the end of _fnDraw */
2538
			if ( !oSettings.oFeatures.bServerSide )
2539
			{
2540
				_fnProcessingDisplay( oSettings, false );
2541
				_fnInitComplete( oSettings );
2542
			}
2543
		}
2544
 
2545
 
2546
		/**
2547
		 * Draw the table for the first time, adding all required features
2548
		 *  @param {object} oSettings dataTables settings object
2549
		 *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
2550
		 *    with client-side processing (optional)
2551
		 *  @memberof DataTable#oApi
2552
		 */
2553
		function _fnInitComplete ( oSettings, json )
2554
		{
2555
			oSettings._bInitComplete = true;
2556
			_fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );
2557
		}
2558
 
2559
 
2560
		/**
2561
		 * Language compatibility - when certain options are given, and others aren't, we
2562
		 * need to duplicate the values over, in order to provide backwards compatibility
2563
		 * with older language files.
2564
		 *  @param {object} oSettings dataTables settings object
2565
		 *  @memberof DataTable#oApi
2566
		 */
2567
		function _fnLanguageCompat( oLanguage )
2568
		{
2569
			/* Backwards compatibility - if there is no sEmptyTable given, then use the same as
2570
			 * sZeroRecords - assuming that is given.
2571
			 */
2572
			if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords )
2573
			{
2574
				_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
2575
			}
2576
 
2577
			/* Likewise with loading records */
2578
			if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords )
2579
			{
2580
				_fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
2581
			}
2582
		}
2583
 
2584
 
2585
 
2586
		/**
2587
		 * Generate the node required for user display length changing
2588
		 *  @param {object} oSettings dataTables settings object
2589
		 *  @returns {node} Display length feature node
2590
		 *  @memberof DataTable#oApi
2591
		 */
2592
		function _fnFeatureHtmlLength ( oSettings )
2593
		{
2594
			if ( oSettings.oScroll.bInfinite )
2595
			{
2596
				return null;
2597
			}
2598
 
2599
			/* This can be overruled by not using the _MENU_ var/macro in the language variable */
2600
			var sName = 'name="'+oSettings.sTableId+'_length"';
2601
			var sStdMenu = '<select size="1" '+sName+'>';
2602
			var i, iLen;
2603
			var aLengthMenu = oSettings.aLengthMenu;
2604
 
2605
			if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && 
2606
					typeof aLengthMenu[1] === 'object' )
2607
			{
2608
				for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )
2609
				{
2610
					sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';
2611
				}
2612
			}
2613
			else
2614
			{
2615
				for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )
2616
				{
2617
					sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';
2618
				}
2619
			}
2620
			sStdMenu += '</select>';
2621
 
2622
			var nLength = document.createElement( 'div' );
2623
			if ( !oSettings.aanFeatures.l )
2624
			{
2625
				nLength.id = oSettings.sTableId+'_length';
2626
			}
2627
			nLength.className = oSettings.oClasses.sLength;
2628
			nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
2629
 
2630
			/*
2631
			 * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
2632
			 * and Stefan Skopnik for fixing the fix!
2633
			 */
2634
			$('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);
2635
 
2636
			$('select', nLength).bind( 'change.DT', function(e) {
2637
				var iVal = $(this).val();
2638
 
2639
				/* Update all other length options for the new display */
2640
				var n = oSettings.aanFeatures.l;
2641
				for ( i=0, iLen=n.length ; i<iLen ; i++ )
2642
				{
2643
					if ( n[i] != this.parentNode )
2644
					{
2645
						$('select', n[i]).val( iVal );
2646
					}
2647
				}
2648
 
2649
				/* Redraw the table */
2650
				oSettings._iDisplayLength = parseInt(iVal, 10);
2651
				_fnCalculateEnd( oSettings );
2652
 
2653
				/* If we have space to show extra rows (backing up from the end point - then do so */
2654
				if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
2655
				{
2656
					oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
2657
					if ( oSettings._iDisplayStart < 0 )
2658
					{
2659
						oSettings._iDisplayStart = 0;
2660
					}
2661
				}
2662
 
2663
				if ( oSettings._iDisplayLength == -1 )
2664
				{
2665
					oSettings._iDisplayStart = 0;
2666
				}
2667
 
2668
				_fnDraw( oSettings );
2669
			} );
2670
 
2671
 
2672
			$('select', nLength).attr('aria-controls', oSettings.sTableId);
2673
 
2674
			return nLength;
2675
		}
2676
 
2677
 
2678
		/**
2679
		 * Rcalculate the end point based on the start point
2680
		 *  @param {object} oSettings dataTables settings object
2681
		 *  @memberof DataTable#oApi
2682
		 */
2683
		function _fnCalculateEnd( oSettings )
2684
		{
2685
			if ( oSettings.oFeatures.bPaginate === false )
2686
			{
2687
				oSettings._iDisplayEnd = oSettings.aiDisplay.length;
2688
			}
2689
			else
2690
			{
2691
				/* Set the end point of the display - based on how many elements there are
2692
				 * still to display
2693
				 */
2694
				if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
2695
					   oSettings._iDisplayLength == -1 )
2696
				{
2697
					oSettings._iDisplayEnd = oSettings.aiDisplay.length;
2698
				}
2699
				else
2700
				{
2701
					oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
2702
				}
2703
			}
2704
		}
2705
 
2706
 
2707
 
2708
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2709
		 * Note that most of the paging logic is done in 
2710
		 * DataTable.ext.oPagination
2711
		 */
2712
 
2713
		/**
2714
		 * Generate the node required for default pagination
2715
		 *  @param {object} oSettings dataTables settings object
2716
		 *  @returns {node} Pagination feature node
2717
		 *  @memberof DataTable#oApi
2718
		 */
2719
		function _fnFeatureHtmlPaginate ( oSettings )
2720
		{
2721
			if ( oSettings.oScroll.bInfinite )
2722
			{
2723
				return null;
2724
			}
2725
 
2726
			var nPaginate = document.createElement( 'div' );
2727
			nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
2728
 
2729
			DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, 
2730
				function( oSettings ) {
2731
					_fnCalculateEnd( oSettings );
2732
					_fnDraw( oSettings );
2733
				}
2734
			);
2735
 
2736
			/* Add a draw callback for the pagination on first instance, to update the paging display */
2737
			if ( !oSettings.aanFeatures.p )
2738
			{
2739
				oSettings.aoDrawCallback.push( {
2740
					"fn": function( oSettings ) {
2741
						DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
2742
							_fnCalculateEnd( oSettings );
2743
							_fnDraw( oSettings );
2744
						} );
2745
					},
2746
					"sName": "pagination"
2747
				} );
2748
			}
2749
			return nPaginate;
2750
		}
2751
 
2752
 
2753
		/**
2754
		 * Alter the display settings to change the page
2755
		 *  @param {object} oSettings dataTables settings object
2756
		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
2757
		 *    or page number to jump to (integer)
2758
		 *  @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1
2759
		 *  @memberof DataTable#oApi
2760
		 */
2761
		function _fnPageChange ( oSettings, mAction )
2762
		{
2763
			var iOldStart = oSettings._iDisplayStart;
2764
 
2765
			if ( typeof mAction === "number" )
2766
			{
2767
				oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;
2768
				if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )
2769
				{
2770
					oSettings._iDisplayStart = 0;
2771
				}
2772
			}
2773
			else if ( mAction == "first" )
2774
			{
2775
				oSettings._iDisplayStart = 0;
2776
			}
2777
			else if ( mAction == "previous" )
2778
			{
2779
				oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
2780
					oSettings._iDisplayStart - oSettings._iDisplayLength :
2781
					0;
2782
 
2783
				/* Correct for underrun */
2784
				if ( oSettings._iDisplayStart < 0 )
2785
				{
2786
				  oSettings._iDisplayStart = 0;
2787
				}
2788
			}
2789
			else if ( mAction == "next" )
2790
			{
2791
				if ( oSettings._iDisplayLength >= 0 )
2792
				{
2793
					/* Make sure we are not over running the display array */
2794
					if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
2795
					{
2796
						oSettings._iDisplayStart += oSettings._iDisplayLength;
2797
					}
2798
				}
2799
				else
2800
				{
2801
					oSettings._iDisplayStart = 0;
2802
				}
2803
			}
2804
			else if ( mAction == "last" )
2805
			{
2806
				if ( oSettings._iDisplayLength >= 0 )
2807
				{
2808
					var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
2809
					oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
2810
				}
2811
				else
2812
				{
2813
					oSettings._iDisplayStart = 0;
2814
				}
2815
			}
2816
			else
2817
			{
2818
				_fnLog( oSettings, 0, "Unknown paging action: "+mAction );
2819
			}
2820
			$(oSettings.oInstance).trigger('page', oSettings);
2821
 
2822
			return iOldStart != oSettings._iDisplayStart;
2823
		}
2824
 
2825
 
2826
 
2827
		/**
2828
		 * Generate the node required for the processing node
2829
		 *  @param {object} oSettings dataTables settings object
2830
		 *  @returns {node} Processing element
2831
		 *  @memberof DataTable#oApi
2832
		 */
2833
		function _fnFeatureHtmlProcessing ( oSettings )
2834
		{
2835
			var nProcessing = document.createElement( 'div' );
2836
 
2837
			if ( !oSettings.aanFeatures.r )
2838
			{
2839
				nProcessing.id = oSettings.sTableId+'_processing';
2840
			}
2841
			nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
2842
			nProcessing.className = oSettings.oClasses.sProcessing;
2843
			oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
2844
 
2845
			return nProcessing;
2846
		}
2847
 
2848
 
2849
		/**
2850
		 * Display or hide the processing indicator
2851
		 *  @param {object} oSettings dataTables settings object
2852
		 *  @param {bool} bShow Show the processing indicator (true) or not (false)
2853
		 *  @memberof DataTable#oApi
2854
		 */
2855
		function _fnProcessingDisplay ( oSettings, bShow )
2856
		{
2857
			if ( oSettings.oFeatures.bProcessing )
2858
			{
2859
				var an = oSettings.aanFeatures.r;
2860
				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
2861
				{
2862
					an[i].style.visibility = bShow ? "visible" : "hidden";
2863
				}
2864
			}
2865
 
2866
			$(oSettings.oInstance).trigger('processing', [oSettings, bShow]);
2867
		}
2868
 
2869
 
2870
 
2871
		/**
2872
		 * Add any control elements for the table - specifically scrolling
2873
		 *  @param {object} oSettings dataTables settings object
2874
		 *  @returns {node} Node to add to the DOM
2875
		 *  @memberof DataTable#oApi
2876
		 */
2877
		function _fnFeatureHtmlTable ( oSettings )
2878
		{
2879
			/* Check if scrolling is enabled or not - if not then leave the DOM unaltered */
2880
			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
2881
			{
2882
				return oSettings.nTable;
2883
			}
2884
 
2885
			/*
2886
			 * The HTML structure that we want to generate in this function is:
2887
			 *  div - nScroller
2888
			 *    div - nScrollHead
2889
			 *      div - nScrollHeadInner
2890
			 *        table - nScrollHeadTable
2891
			 *          thead - nThead
2892
			 *    div - nScrollBody
2893
			 *      table - oSettings.nTable
2894
			 *        thead - nTheadSize
2895
			 *        tbody - nTbody
2896
			 *    div - nScrollFoot
2897
			 *      div - nScrollFootInner
2898
			 *        table - nScrollFootTable
2899
			 *          tfoot - nTfoot
2900
			 */
2901
			var
2902
			 	nScroller = document.createElement('div'),
2903
			 	nScrollHead = document.createElement('div'),
2904
			 	nScrollHeadInner = document.createElement('div'),
2905
			 	nScrollBody = document.createElement('div'),
2906
			 	nScrollFoot = document.createElement('div'),
2907
			 	nScrollFootInner = document.createElement('div'),
2908
			 	nScrollHeadTable = oSettings.nTable.cloneNode(false),
2909
			 	nScrollFootTable = oSettings.nTable.cloneNode(false),
2910
				nThead = oSettings.nTable.getElementsByTagName('thead')[0],
2911
			 	nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : 
2912
					oSettings.nTable.getElementsByTagName('tfoot')[0],
2913
				oClasses = oSettings.oClasses;
2914
 
2915
			nScrollHead.appendChild( nScrollHeadInner );
2916
			nScrollFoot.appendChild( nScrollFootInner );
2917
			nScrollBody.appendChild( oSettings.nTable );
2918
			nScroller.appendChild( nScrollHead );
2919
			nScroller.appendChild( nScrollBody );
2920
			nScrollHeadInner.appendChild( nScrollHeadTable );
2921
			nScrollHeadTable.appendChild( nThead );
2922
			if ( nTfoot !== null )
2923
			{
2924
				nScroller.appendChild( nScrollFoot );
2925
				nScrollFootInner.appendChild( nScrollFootTable );
2926
				nScrollFootTable.appendChild( nTfoot );
2927
			}
2928
 
2929
			nScroller.className = oClasses.sScrollWrapper;
2930
			nScrollHead.className = oClasses.sScrollHead;
2931
			nScrollHeadInner.className = oClasses.sScrollHeadInner;
2932
			nScrollBody.className = oClasses.sScrollBody;
2933
			nScrollFoot.className = oClasses.sScrollFoot;
2934
			nScrollFootInner.className = oClasses.sScrollFootInner;
2935
 
2936
			if ( oSettings.oScroll.bAutoCss )
2937
			{
2938
				nScrollHead.style.overflow = "hidden";
2939
				nScrollHead.style.position = "relative";
2940
				nScrollFoot.style.overflow = "hidden";
2941
				nScrollBody.style.overflow = "auto";
2942
			}
2943
 
2944
			nScrollHead.style.border = "0";
2945
			nScrollHead.style.width = "100%";
2946
			nScrollFoot.style.border = "0";
2947
			nScrollHeadInner.style.width = "150%"; /* will be overwritten */
2948
 
2949
			/* Modify attributes to respect the clones */
2950
			nScrollHeadTable.removeAttribute('id');
2951
			nScrollHeadTable.style.marginLeft = "0";
2952
			oSettings.nTable.style.marginLeft = "0";
2953
			if ( nTfoot !== null )
2954
			{
2955
				nScrollFootTable.removeAttribute('id');
2956
				nScrollFootTable.style.marginLeft = "0";
2957
			}
2958
 
2959
			/* Move any caption elements from the body to the header */
2960
			var nCaptions = $(oSettings.nTable).children('caption');
2961
			for ( var i=0, iLen=nCaptions.length ; i<iLen ; i++ )
2962
			{
2963
				nScrollHeadTable.appendChild( nCaptions[i] );
2964
			}
2965
 
2966
			/*
2967
			 * Sizing
2968
			 */
2969
			/* When xscrolling add the width and a scroller to move the header with the body */
2970
			if ( oSettings.oScroll.sX !== "" )
2971
			{
2972
				nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
2973
				nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
2974
 
2975
				if ( nTfoot !== null )
2976
				{
2977
					nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );	
2978
				}
2979
 
2980
				/* When the body is scrolled, then we also want to scroll the headers */
2981
				$(nScrollBody).scroll( function (e) {
2982
					nScrollHead.scrollLeft = this.scrollLeft;
2983
 
2984
					if ( nTfoot !== null )
2985
					{
2986
						nScrollFoot.scrollLeft = this.scrollLeft;
2987
					}
2988
				} );
2989
			}
2990
 
2991
			/* When yscrolling, add the height */
2992
			if ( oSettings.oScroll.sY !== "" )
2993
			{
2994
				nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
2995
			}
2996
 
2997
			/* Redraw - align columns across the tables */
2998
			oSettings.aoDrawCallback.push( {
2999
				"fn": _fnScrollDraw,
3000
				"sName": "scrolling"
3001
			} );
3002
 
3003
			/* Infinite scrolling event handlers */
3004
			if ( oSettings.oScroll.bInfinite )
3005
			{
3006
				$(nScrollBody).scroll( function() {
3007
					/* Use a blocker to stop scrolling from loading more data while other data is still loading */
3008
					if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 )
3009
					{
3010
						/* Check if we should load the next data set */
3011
						if ( $(this).scrollTop() + $(this).height() > 
3012
							$(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
3013
						{
3014
							/* Only do the redraw if we have to - we might be at the end of the data */
3015
							if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
3016
							{
3017
								_fnPageChange( oSettings, 'next' );
3018
								_fnCalculateEnd( oSettings );
3019
								_fnDraw( oSettings );
3020
							}
3021
						}
3022
					}
3023
				} );
3024
			}
3025
 
3026
			oSettings.nScrollHead = nScrollHead;
3027
			oSettings.nScrollFoot = nScrollFoot;
3028
 
3029
			return nScroller;
3030
		}
3031
 
3032
 
3033
		/**
3034
		 * Update the various tables for resizing. It's a bit of a pig this function, but
3035
		 * basically the idea to:
3036
		 *   1. Re-create the table inside the scrolling div
3037
		 *   2. Take live measurements from the DOM
3038
		 *   3. Apply the measurements
3039
		 *   4. Clean up
3040
		 *  @param {object} o dataTables settings object
3041
		 *  @returns {node} Node to add to the DOM
3042
		 *  @memberof DataTable#oApi
3043
		 */
3044
		function _fnScrollDraw ( o )
3045
		{
3046
			var
3047
				nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
3048
				nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
3049
				nScrollBody = o.nTable.parentNode,
3050
				i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
3051
				iWidth, aApplied=[], iSanityWidth,
3052
				nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
3053
				nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
3054
				ie67 = $.browser.msie && $.browser.version <= 7;
3055
 
3056
			/*
3057
			 * 1. Re-create the table inside the scrolling div
3058
			 */
3059
 
3060
			/* Remove the old minimised thead and tfoot elements in the inner table */
3061
			var nTheadSize = o.nTable.getElementsByTagName('thead');
3062
			if ( nTheadSize.length > 0 )
3063
			{
3064
				o.nTable.removeChild( nTheadSize[0] );
3065
			}
3066
 
3067
			var nTfootSize;
3068
			if ( o.nTFoot !== null )
3069
			{
3070
				/* Remove the old minimised footer element in the cloned header */
3071
				nTfootSize = o.nTable.getElementsByTagName('tfoot');
3072
				if ( nTfootSize.length > 0 )
3073
				{
3074
					o.nTable.removeChild( nTfootSize[0] );
3075
				}
3076
			}
3077
 
3078
			/* Clone the current header and footer elements and then place it into the inner table */
3079
			nTheadSize = o.nTHead.cloneNode(true);
3080
			o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
3081
 
3082
			if ( o.nTFoot !== null )
3083
			{
3084
				nTfootSize = o.nTFoot.cloneNode(true);
3085
				o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
3086
			}
3087
 
3088
			/*
3089
			 * 2. Take live measurements from the DOM - do not alter the DOM itself!
3090
			 */
3091
 
3092
			/* Remove old sizing and apply the calculated column widths
3093
			 * Get the unique column headers in the newly created (cloned) header. We want to apply the
3094
			 * calclated sizes to this header
3095
			 */
3096
			if ( o.oScroll.sX === "" )
3097
			{
3098
				nScrollBody.style.width = '100%';
3099
				nScrollHeadInner.parentNode.style.width = '100%';
3100
			}
3101
 
3102
			var nThs = _fnGetUniqueThs( o, nTheadSize );
3103
			for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
3104
			{
3105
				iVis = _fnVisibleToColumnIndex( o, i );
3106
				nThs[i].style.width = o.aoColumns[iVis].sWidth;
3107
			}
3108
 
3109
			if ( o.nTFoot !== null )
3110
			{
3111
				_fnApplyToChildren( function(n) {
3112
					n.style.width = "";
3113
				}, nTfootSize.getElementsByTagName('tr') );
3114
			}
3115
 
3116
			/* Size the table as a whole */
3117
			iSanityWidth = $(o.nTable).outerWidth();
3118
			if ( o.oScroll.sX === "" )
3119
			{
3120
				/* No x scrolling */
3121
				o.nTable.style.width = "100%";
3122
 
3123
				/* I know this is rubbish - but IE7 will make the width of the table when 100% include
3124
				 * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
3125
				 * into account.
3126
				 */
3127
				if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || 
3128
					$(nScrollBody).css('overflow-y') == "scroll")  )
3129
				{
3130
					o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth()-o.oScroll.iBarWidth );
3131
				}
3132
			}
3133
			else
3134
			{
3135
				if ( o.oScroll.sXInner !== "" )
3136
				{
3137
					/* x scroll inner has been given - use it */
3138
					o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
3139
				}
3140
				else if ( iSanityWidth == $(nScrollBody).width() &&
3141
				   $(nScrollBody).height() < $(o.nTable).height() )
3142
				{
3143
					/* There is y-scrolling - try to take account of the y scroll bar */
3144
					o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
3145
					if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
3146
					{
3147
						/* Not possible to take account of it */
3148
						o.nTable.style.width = _fnStringToCss( iSanityWidth );
3149
					}
3150
				}
3151
				else
3152
				{
3153
					/* All else fails */
3154
					o.nTable.style.width = _fnStringToCss( iSanityWidth );
3155
				}
3156
			}
3157
 
3158
			/* Recalculate the sanity width - now that we've applied the required width, before it was
3159
			 * a temporary variable. This is required because the column width calculation is done
3160
			 * before this table DOM is created.
3161
			 */
3162
			iSanityWidth = $(o.nTable).outerWidth();
3163
 
3164
			/* We want the hidden header to have zero height, so remove padding and borders. Then
3165
			 * set the width based on the real headers
3166
			 */
3167
			anHeadToSize = o.nTHead.getElementsByTagName('tr');
3168
			anHeadSizers = nTheadSize.getElementsByTagName('tr');
3169
 
3170
			_fnApplyToChildren( function(nSizer, nToSize) {
3171
				oStyle = nSizer.style;
3172
				oStyle.paddingTop = "0";
3173
				oStyle.paddingBottom = "0";
3174
				oStyle.borderTopWidth = "0";
3175
				oStyle.borderBottomWidth = "0";
3176
				oStyle.height = 0;
3177
 
3178
				iWidth = $(nSizer).width();
3179
				nToSize.style.width = _fnStringToCss( iWidth );
3180
				aApplied.push( iWidth );
3181
			}, anHeadSizers, anHeadToSize );
3182
			$(anHeadSizers).height(0);
3183
 
3184
			if ( o.nTFoot !== null )
3185
			{
3186
				/* Clone the current footer and then place it into the body table as a "hidden header" */
3187
				anFootSizers = nTfootSize.getElementsByTagName('tr');
3188
				anFootToSize = o.nTFoot.getElementsByTagName('tr');
3189
 
3190
				_fnApplyToChildren( function(nSizer, nToSize) {
3191
					oStyle = nSizer.style;
3192
					oStyle.paddingTop = "0";
3193
					oStyle.paddingBottom = "0";
3194
					oStyle.borderTopWidth = "0";
3195
					oStyle.borderBottomWidth = "0";
3196
					oStyle.height = 0;
3197
 
3198
					iWidth = $(nSizer).width();
3199
					nToSize.style.width = _fnStringToCss( iWidth );
3200
					aApplied.push( iWidth );
3201
				}, anFootSizers, anFootToSize );
3202
				$(anFootSizers).height(0);
3203
			}
3204
 
3205
			/*
3206
			 * 3. Apply the measurements
3207
			 */
3208
 
3209
			/* "Hide" the header and footer that we used for the sizing. We want to also fix their width
3210
			 * to what they currently are
3211
			 */
3212
			_fnApplyToChildren( function(nSizer) {
3213
				nSizer.innerHTML = "";
3214
				nSizer.style.width = _fnStringToCss( aApplied.shift() );
3215
			}, anHeadSizers );
3216
 
3217
			if ( o.nTFoot !== null )
3218
			{
3219
				_fnApplyToChildren( function(nSizer) {
3220
					nSizer.innerHTML = "";
3221
					nSizer.style.width = _fnStringToCss( aApplied.shift() );
3222
				}, anFootSizers );
3223
			}
3224
 
3225
			/* Sanity check that the table is of a sensible width. If not then we are going to get
3226
			 * misalignment - try to prevent this by not allowing the table to shrink below its min width
3227
			 */
3228
			if ( $(o.nTable).outerWidth() < iSanityWidth )
3229
			{
3230
				/* The min width depends upon if we have a vertical scrollbar visible or not */
3231
				var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || 
3232
					$(nScrollBody).css('overflow-y') == "scroll")) ?
3233
						iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
3234
 
3235
				/* IE6/7 are a law unto themselves... */
3236
				if ( ie67 && (nScrollBody.scrollHeight > 
3237
					nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll")  )
3238
				{
3239
					o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
3240
				}
3241
 
3242
				/* Apply the calculated minimum width to the table wrappers */
3243
				nScrollBody.style.width = _fnStringToCss( iCorrection );
3244
				nScrollHeadInner.parentNode.style.width = _fnStringToCss( iCorrection );
3245
 
3246
				if ( o.nTFoot !== null )
3247
				{
3248
					nScrollFootInner.parentNode.style.width = _fnStringToCss( iCorrection );
3249
				}
3250
 
3251
				/* And give the user a warning that we've stopped the table getting too small */
3252
				if ( o.oScroll.sX === "" )
3253
				{
3254
					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
3255
						" misalignment. The table has been drawn at its minimum possible width." );
3256
				}
3257
				else if ( o.oScroll.sXInner !== "" )
3258
				{
3259
					_fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
3260
						" misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
3261
						" calculation" );
3262
				}
3263
			}
3264
			else
3265
			{
3266
				nScrollBody.style.width = _fnStringToCss( '100%' );
3267
				nScrollHeadInner.parentNode.style.width = _fnStringToCss( '100%' );
3268
 
3269
				if ( o.nTFoot !== null )
3270
				{
3271
					nScrollFootInner.parentNode.style.width = _fnStringToCss( '100%' );
3272
				}
3273
			}
3274
 
3275
 
3276
			/*
3277
			 * 4. Clean up
3278
			 */
3279
			if ( o.oScroll.sY === "" )
3280
			{
3281
				/* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3282
				 * the scrollbar height from the visible display, rather than adding it on. We need to
3283
				 * set the height in order to sort this. Don't want to do it in any other browsers.
3284
				 */
3285
				if ( ie67 )
3286
				{
3287
					nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
3288
				}
3289
			}
3290
 
3291
			if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
3292
			{
3293
				nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
3294
 
3295
				var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
3296
				 	o.oScroll.iBarWidth : 0;
3297
				if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
3298
				{
3299
					nScrollBody.style.height = _fnStringToCss( $(o.nTable).height()+iExtra );
3300
				}
3301
			}
3302
 
3303
			/* Finally set the width's of the header and footer tables */
3304
			var iOuterWidth = $(o.nTable).outerWidth();
3305
			nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
3306
			nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
3307
 
3308
			if ( o.nTFoot !== null )
3309
			{
3310
				nScrollFootInner.style.width = _fnStringToCss( o.nTable.offsetWidth );
3311
				nScrollFootTable.style.width = _fnStringToCss( o.nTable.offsetWidth );
3312
			}
3313
 
3314
			/* If sorting or filtering has occurred, jump the scrolling back to the top */
3315
			if ( o.bSorted || o.bFiltered )
3316
			{
3317
				nScrollBody.scrollTop = 0;
3318
			}
3319
		}
3320
 
3321
 
3322
		/**
3323
		 * Apply a given function to the display child nodes of an element array (typically
3324
		 * TD children of TR rows
3325
		 *  @param {function} fn Method to apply to the objects
3326
		 *  @param array {nodes} an1 List of elements to look through for display children
3327
		 *  @param array {nodes} an2 Another list (identical structure to the first) - optional
3328
		 *  @memberof DataTable#oApi
3329
		 */
3330
		function _fnApplyToChildren( fn, an1, an2 )
3331
		{
3332
			for ( var i=0, iLen=an1.length ; i<iLen ; i++ )
3333
			{
3334
				for ( var j=0, jLen=an1[i].childNodes.length ; j<jLen ; j++ )
3335
				{
3336
					if ( an1[i].childNodes[j].nodeType == 1 )
3337
					{
3338
						if ( an2 )
3339
						{
3340
							fn( an1[i].childNodes[j], an2[i].childNodes[j] );
3341
						}
3342
						else
3343
						{
3344
							fn( an1[i].childNodes[j] );
3345
						}
3346
					}
3347
				}
3348
			}
3349
		}
3350
 
3351
 
3352
 
3353
		/**
3354
		 * Convert a CSS unit width to pixels (e.g. 2em)
3355
		 *  @param {string} sWidth width to be converted
3356
		 *  @param {node} nParent parent to get the with for (required for relative widths) - optional
3357
		 *  @returns {int} iWidth width in pixels
3358
		 *  @memberof DataTable#oApi
3359
		 */
3360
		function _fnConvertToWidth ( sWidth, nParent )
3361
		{
3362
			if ( !sWidth || sWidth === null || sWidth === '' )
3363
			{
3364
				return 0;
3365
			}
3366
 
3367
			if ( !nParent )
3368
			{
3369
				nParent = document.getElementsByTagName('body')[0];
3370
			}
3371
 
3372
			var iWidth;
3373
			var nTmp = document.createElement( "div" );
3374
			nTmp.style.width = _fnStringToCss( sWidth );
3375
 
3376
			nParent.appendChild( nTmp );
3377
			iWidth = nTmp.offsetWidth;
3378
			nParent.removeChild( nTmp );
3379
 
3380
			return ( iWidth );
3381
		}
3382
 
3383
 
3384
		/**
3385
		 * Calculate the width of columns for the table
3386
		 *  @param {object} oSettings dataTables settings object
3387
		 *  @memberof DataTable#oApi
3388
		 */
3389
		function _fnCalculateColumnWidths ( oSettings )
3390
		{
3391
			var iTableWidth = oSettings.nTable.offsetWidth;
3392
			var iUserInputs = 0;
3393
			var iTmpWidth;
3394
			var iVisibleColumns = 0;
3395
			var iColums = oSettings.aoColumns.length;
3396
			var i, iIndex, iCorrector, iWidth;
3397
			var oHeaders = $('th', oSettings.nTHead);
3398
			var widthAttr = oSettings.nTable.getAttribute('width');
3399
 
3400
			/* Convert any user input sizes into pixel sizes */
3401
			for ( i=0 ; i<iColums ; i++ )
3402
			{
3403
				if ( oSettings.aoColumns[i].bVisible )
3404
				{
3405
					iVisibleColumns++;
3406
 
3407
					if ( oSettings.aoColumns[i].sWidth !== null )
3408
					{
3409
						iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, 
3410
							oSettings.nTable.parentNode );
3411
						if ( iTmpWidth !== null )
3412
						{
3413
							oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
3414
						}
3415
 
3416
						iUserInputs++;
3417
					}
3418
				}
3419
			}
3420
 
3421
			/* If the number of columns in the DOM equals the number that we have to process in 
3422
			 * DataTables, then we can use the offsets that are created by the web-browser. No custom 
3423
			 * sizes can be set in order for this to happen, nor scrolling used
3424
			 */
3425
			if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
3426
				oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
3427
			{
3428
				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
3429
				{
3430
					iTmpWidth = $(oHeaders[i]).width();
3431
					if ( iTmpWidth !== null )
3432
					{
3433
						oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
3434
					}
3435
				}
3436
			}
3437
			else
3438
			{
3439
				/* Otherwise we are going to have to do some calculations to get the width of each column.
3440
				 * Construct a 1 row table with the widest node in the data, and any user defined widths,
3441
				 * then insert it into the DOM and allow the browser to do all the hard work of
3442
				 * calculating table widths.
3443
				 */
3444
				var
3445
					nCalcTmp = oSettings.nTable.cloneNode( false ),
3446
					nTheadClone = oSettings.nTHead.cloneNode(true),
3447
					nBody = document.createElement( 'tbody' ),
3448
					nTr = document.createElement( 'tr' ),
3449
					nDivSizing;
3450
 
3451
				nCalcTmp.removeAttribute( "id" );
3452
				nCalcTmp.appendChild( nTheadClone );
3453
				if ( oSettings.nTFoot !== null )
3454
				{
3455
					nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
3456
					_fnApplyToChildren( function(n) {
3457
						n.style.width = "";
3458
					}, nCalcTmp.getElementsByTagName('tr') );
3459
				}
3460
 
3461
				nCalcTmp.appendChild( nBody );
3462
				nBody.appendChild( nTr );
3463
 
3464
				/* Remove any sizing that was previously applied by the styles */
3465
				var jqColSizing = $('thead th', nCalcTmp);
3466
				if ( jqColSizing.length === 0 )
3467
				{
3468
					jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
3469
				}
3470
 
3471
				/* Apply custom sizing to the cloned header */
3472
				var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
3473
				iCorrector = 0;
3474
				for ( i=0 ; i<iColums ; i++ )
3475
				{
3476
					var oColumn = oSettings.aoColumns[i];
3477
					if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
3478
					{
3479
						nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
3480
					}
3481
					else if ( oColumn.bVisible )
3482
					{
3483
						nThs[i-iCorrector].style.width = "";
3484
					}
3485
					else
3486
					{
3487
						iCorrector++;
3488
					}
3489
				}
3490
 
3491
				/* Find the biggest td for each column and put it into the table */
3492
				for ( i=0 ; i<iColums ; i++ )
3493
				{
3494
					if ( oSettings.aoColumns[i].bVisible )
3495
					{
3496
						var nTd = _fnGetWidestNode( oSettings, i );
3497
						if ( nTd !== null )
3498
						{
3499
							nTd = nTd.cloneNode(true);
3500
							if ( oSettings.aoColumns[i].sContentPadding !== "" )
3501
							{
3502
								nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
3503
							}
3504
							nTr.appendChild( nTd );
3505
						}
3506
					}
3507
				}
3508
 
3509
				/* Build the table and 'display' it */
3510
				var nWrapper = oSettings.nTable.parentNode;
3511
				nWrapper.appendChild( nCalcTmp );
3512
 
3513
				/* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
3514
				 * when not scrolling leave the table width as it is. This results in slightly different,
3515
				 * but I think correct behaviour
3516
				 */
3517
				if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
3518
				{
3519
					nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
3520
				}
3521
				else if ( oSettings.oScroll.sX !== "" )
3522
				{
3523
					nCalcTmp.style.width = "";
3524
					if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
3525
					{
3526
						nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
3527
					}
3528
				}
3529
				else if ( oSettings.oScroll.sY !== "" )
3530
				{
3531
					nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
3532
				}
3533
				else if ( widthAttr )
3534
				{
3535
					nCalcTmp.style.width = _fnStringToCss( widthAttr );
3536
				}
3537
				nCalcTmp.style.visibility = "hidden";
3538
 
3539
				/* Scrolling considerations */
3540
				_fnScrollingWidthAdjust( oSettings, nCalcTmp );
3541
 
3542
				/* Read the width's calculated by the browser and store them for use by the caller. We
3543
				 * first of all try to use the elements in the body, but it is possible that there are
3544
				 * no elements there, under which circumstances we use the header elements
3545
				 */
3546
				var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
3547
				if ( oNodes.length === 0 )
3548
				{
3549
					oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
3550
				}
3551
 
3552
				/* Browsers need a bit of a hand when a width is assigned to any columns when 
3553
				 * x-scrolling as they tend to collapse the table to the min-width, even if
3554
				 * we sent the column widths. So we need to keep track of what the table width
3555
				 * should be by summing the user given values, and the automatic values
3556
				 */
3557
				if ( oSettings.oScroll.sX !== "" )
3558
				{
3559
					var iTotal = 0;
3560
					iCorrector = 0;
3561
					for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
3562
					{
3563
						if ( oSettings.aoColumns[i].bVisible )
3564
						{
3565
							if ( oSettings.aoColumns[i].sWidthOrig === null )
3566
							{
3567
								iTotal += $(oNodes[iCorrector]).outerWidth();
3568
							}
3569
							else
3570
							{
3571
								iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
3572
									($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
3573
							}
3574
							iCorrector++;
3575
						}
3576
					}
3577
 
3578
					nCalcTmp.style.width = _fnStringToCss( iTotal );
3579
					oSettings.nTable.style.width = _fnStringToCss( iTotal );
3580
				}
3581
 
3582
				iCorrector = 0;
3583
				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
3584
				{
3585
					if ( oSettings.aoColumns[i].bVisible )
3586
					{
3587
						iWidth = $(oNodes[iCorrector]).width();
3588
						if ( iWidth !== null && iWidth > 0 )
3589
						{
3590
							oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
3591
						}
3592
						iCorrector++;
3593
					}
3594
				}
3595
 
3596
				var cssWidth = $(nCalcTmp).css('width');
3597
				oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
3598
				    cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
3599
				nCalcTmp.parentNode.removeChild( nCalcTmp );
3600
			}
3601
 
3602
			if ( widthAttr )
3603
			{
3604
				oSettings.nTable.style.width = _fnStringToCss( widthAttr );
3605
			}
3606
		}
3607
 
3608
 
3609
		/**
3610
		 * Adjust a table's width to take account of scrolling
3611
		 *  @param {object} oSettings dataTables settings object
3612
		 *  @param {node} n table node
3613
		 *  @memberof DataTable#oApi
3614
		 */
3615
		function _fnScrollingWidthAdjust ( oSettings, n )
3616
		{
3617
			if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
3618
			{
3619
				/* When y-scrolling only, we want to remove the width of the scroll bar so the table
3620
				 * + scroll bar will fit into the area avaialble.
3621
				 */
3622
				var iOrigWidth = $(n).width();
3623
				n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
3624
			}
3625
			else if ( oSettings.oScroll.sX !== "" )
3626
			{
3627
				/* When x-scrolling both ways, fix the table at it's current size, without adjusting */
3628
				n.style.width = _fnStringToCss( $(n).outerWidth() );
3629
			}
3630
		}
3631
 
3632
 
3633
		/**
3634
		 * Get the widest node
3635
		 *  @param {object} oSettings dataTables settings object
3636
		 *  @param {int} iCol column of interest
3637
		 *  @returns {string} max strlens for each column
3638
		 *  @memberof DataTable#oApi
3639
		 */
3640
		function _fnGetWidestNode( oSettings, iCol )
3641
		{
3642
			var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
3643
			if ( iMaxIndex < 0 )
3644
			{
3645
				return null;
3646
			}
3647
 
3648
			if ( oSettings.aoData[iMaxIndex].nTr === null )
3649
			{
3650
				var n = document.createElement('td');
3651
				n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
3652
				return n;
3653
			}
3654
			return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
3655
		}
3656
 
3657
 
3658
		/**
3659
		 * Get the maximum strlen for each data column
3660
		 *  @param {object} oSettings dataTables settings object
3661
		 *  @param {int} iCol column of interest
3662
		 *  @returns {string} max strlens for each column
3663
		 *  @memberof DataTable#oApi
3664
		 */
3665
		function _fnGetMaxLenString( oSettings, iCol )
3666
		{
3667
			var iMax = -1;
3668
			var iMaxIndex = -1;
3669
 
3670
			for ( var i=0 ; i<oSettings.aoData.length ; i++ )
3671
			{
3672
				var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
3673
				s = s.replace( /<.*?>/g, "" );
3674
				if ( s.length > iMax )
3675
				{
3676
					iMax = s.length;
3677
					iMaxIndex = i;
3678
				}
3679
			}
3680
 
3681
			return iMaxIndex;
3682
		}
3683
 
3684
 
3685
		/**
3686
		 * Append a CSS unit (only if required) to a string
3687
		 *  @param {array} aArray1 first array
3688
		 *  @param {array} aArray2 second array
3689
		 *  @returns {int} 0 if match, 1 if length is different, 2 if no match
3690
		 *  @memberof DataTable#oApi
3691
		 */
3692
		function _fnStringToCss( s )
3693
		{
3694
			if ( s === null )
3695
			{
3696
				return "0px";
3697
			}
3698
 
3699
			if ( typeof s == 'number' )
3700
			{
3701
				if ( s < 0 )
3702
				{
3703
					return "0px";
3704
				}
3705
				return s+"px";
3706
			}
3707
 
3708
			/* Check if the last character is not 0-9 */
3709
			var c = s.charCodeAt( s.length-1 );
3710
			if (c < 0x30 || c > 0x39)
3711
			{
3712
				return s;
3713
			}
3714
			return s+"px";
3715
		}
3716
 
3717
 
3718
		/**
3719
		 * Get the width of a scroll bar in this browser being used
3720
		 *  @returns {int} width in pixels
3721
		 *  @memberof DataTable#oApi
3722
		 */
3723
		function _fnScrollBarWidth ()
3724
		{  
3725
			var inner = document.createElement('p');
3726
			var style = inner.style;
3727
			style.width = "100%";
3728
			style.height = "200px";
3729
			style.padding = "0px";
3730
 
3731
			var outer = document.createElement('div');
3732
			style = outer.style;
3733
			style.position = "absolute";
3734
			style.top = "0px";
3735
			style.left = "0px";
3736
			style.visibility = "hidden";
3737
			style.width = "200px";
3738
			style.height = "150px";
3739
			style.padding = "0px";
3740
			style.overflow = "hidden";
3741
			outer.appendChild(inner);
3742
 
3743
			document.body.appendChild(outer);
3744
			var w1 = inner.offsetWidth;
3745
			outer.style.overflow = 'scroll';
3746
			var w2 = inner.offsetWidth;
3747
			if ( w1 == w2 )
3748
			{
3749
				w2 = outer.clientWidth;
3750
			}
3751
 
3752
			document.body.removeChild(outer);
3753
			return (w1 - w2);  
3754
		}
3755
 
3756
 
3757
 
3758
		/**
3759
		 * Change the order of the table
3760
		 *  @param {object} oSettings dataTables settings object
3761
		 *  @param {bool} bApplyClasses optional - should we apply classes or not
3762
		 *  @memberof DataTable#oApi
3763
		 */
3764
		function _fnSort ( oSettings, bApplyClasses )
3765
		{
3766
			var
3767
				i, iLen, j, jLen, k, kLen,
3768
				sDataType, nTh,
3769
				aaSort = [],
3770
			 	aiOrig = [],
3771
				oSort = DataTable.ext.oSort,
3772
				aoData = oSettings.aoData,
3773
				aoColumns = oSettings.aoColumns,
3774
				oAria = oSettings.oLanguage.oAria;
3775
 
3776
			/* No sorting required if server-side or no sorting array */
3777
			if ( !oSettings.oFeatures.bServerSide && 
3778
				(oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
3779
			{
3780
				if ( oSettings.aaSortingFixed !== null )
3781
				{
3782
					aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
3783
				}
3784
				else
3785
				{
3786
					aaSort = oSettings.aaSorting.slice();
3787
				}
3788
 
3789
				/* If there is a sorting data type, and a fuction belonging to it, then we need to
3790
				 * get the data from the developer's function and apply it for this column
3791
				 */
3792
				for ( i=0 ; i<aaSort.length ; i++ )
3793
				{
3794
					var iColumn = aaSort[i][0];
3795
					var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
3796
					sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
3797
					if ( DataTable.ext.afnSortData[sDataType] )
3798
					{
3799
						var aData = DataTable.ext.afnSortData[sDataType]( oSettings, iColumn, iVisColumn );
3800
						for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
3801
						{
3802
							_fnSetCellData( oSettings, j, iColumn, aData[j] );
3803
						}
3804
					}
3805
				}
3806
 
3807
				/* Create a value - key array of the current row positions such that we can use their
3808
				 * current position during the sort, if values match, in order to perform stable sorting
3809
				 */
3810
				for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
3811
				{
3812
					aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
3813
				}
3814
 
3815
				/* Build an internal data array which is specific to the sort, so we can get and prep
3816
				 * the data to be sorted only once, rather than needing to do it every time the sorting
3817
				 * function runs. This make the sorting function a very simple comparison
3818
				 */
3819
				var iSortLen = aaSort.length;
3820
				var fnSortFormat, aDataSort;
3821
				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
3822
				{
3823
					for ( j=0 ; j<iSortLen ; j++ )
3824
					{
3825
						aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;
3826
 
3827
						for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
3828
						{
3829
							sDataType = aoColumns[ aDataSort[k] ].sType;
3830
							fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];
3831
 
3832
							aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ?
3833
								fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) :
3834
								_fnGetCellData( oSettings, i, aDataSort[k], 'sort' );
3835
						}
3836
					}
3837
				}
3838
 
3839
				/* Do the sort - here we want multi-column sorting based on a given data source (column)
3840
				 * and sorting function (from oSort) in a certain direction. It's reasonably complex to
3841
				 * follow on it's own, but this is what we want (example two column sorting):
3842
				 *  fnLocalSorting = function(a,b){
3843
				 *  	var iTest;
3844
				 *  	iTest = oSort['string-asc']('data11', 'data12');
3845
				 *  	if (iTest !== 0)
3846
				 *  		return iTest;
3847
				 *    iTest = oSort['numeric-desc']('data21', 'data22');
3848
				 *    if (iTest !== 0)
3849
				 *  		return iTest;
3850
				 *  	return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
3851
				 *  }
3852
				 * Basically we have a test for each sorting column, if the data in that column is equal,
3853
				 * test the next column. If all columns match, then we use a numeric sort on the row 
3854
				 * positions in the original data array to provide a stable sort.
3855
				 */
3856
				oSettings.aiDisplayMaster.sort( function ( a, b ) {
3857
					var k, l, lLen, iTest, aDataSort, sDataType;
3858
					for ( k=0 ; k<iSortLen ; k++ )
3859
					{
3860
						aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;
3861
 
3862
						for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )
3863
						{
3864
							sDataType = aoColumns[ aDataSort[l] ].sType;
3865
 
3866
							iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ](
3867
								aoData[a]._aSortData[ aDataSort[l] ],
3868
								aoData[b]._aSortData[ aDataSort[l] ]
3869
							);
3870
 
3871
							if ( iTest !== 0 )
3872
							{
3873
								return iTest;
3874
							}
3875
						}
3876
					}
3877
 
3878
					return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
3879
				} );
3880
			}
3881
 
3882
			/* Alter the sorting classes to take account of the changes */
3883
			if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
3884
			{
3885
				_fnSortingClasses( oSettings );
3886
			}
3887
 
3888
			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
3889
			{
3890
				nTh = aoColumns[i].nTh;
3891
				nTh.removeAttribute('aria-sort');
3892
				nTh.removeAttribute('aria-label');
3893
 
3894
				/* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
3895
				if ( aoColumns[i].bSortable )
3896
				{
3897
					if ( aaSort.length > 0 && aaSort[0][0] == i )
3898
					{
3899
						nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );
3900
 
3901
						var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ? 
3902
							aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
3903
						nTh.setAttribute('aria-label', aoColumns[i].sTitle+
3904
							(nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
3905
					}
3906
					else
3907
					{
3908
						nTh.setAttribute('aria-label', aoColumns[i].sTitle+
3909
							(aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
3910
					}
3911
				}
3912
				else
3913
				{
3914
					nTh.setAttribute('aria-label', aoColumns[i].sTitle);
3915
				}
3916
			}
3917
 
3918
			/* Tell the draw function that we have sorted the data */
3919
			oSettings.bSorted = true;
3920
			$(oSettings.oInstance).trigger('sort', oSettings);
3921
 
3922
			/* Copy the master data into the draw array and re-draw */
3923
			if ( oSettings.oFeatures.bFilter )
3924
			{
3925
				/* _fnFilter() will redraw the table for us */
3926
				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
3927
			}
3928
			else
3929
			{
3930
				oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
3931
				oSettings._iDisplayStart = 0; /* reset display back to page 0 */
3932
				_fnCalculateEnd( oSettings );
3933
				_fnDraw( oSettings );
3934
			}
3935
		}
3936
 
3937
 
3938
		/**
3939
		 * Attach a sort handler (click) to a node
3940
		 *  @param {object} oSettings dataTables settings object
3941
		 *  @param {node} nNode node to attach the handler to
3942
		 *  @param {int} iDataIndex column sorting index
3943
		 *  @param {function} [fnCallback] callback function
3944
		 *  @memberof DataTable#oApi
3945
		 */
3946
		function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
3947
		{
3948
			_fnBindAction( nNode, {}, function (e) {
3949
				/* If the column is not sortable - don't to anything */
3950
				if ( oSettings.aoColumns[iDataIndex].bSortable === false )
3951
				{
3952
					return;
3953
				}
3954
 
3955
				/*
3956
				 * This is a little bit odd I admit... I declare a temporary function inside the scope of
3957
				 * _fnBuildHead and the click handler in order that the code presented here can be used 
3958
				 * twice - once for when bProcessing is enabled, and another time for when it is 
3959
				 * disabled, as we need to perform slightly different actions.
3960
				 *   Basically the issue here is that the Javascript engine in modern browsers don't 
3961
				 * appear to allow the rendering engine to update the display while it is still excuting
3962
				 * it's thread (well - it does but only after long intervals). This means that the 
3963
				 * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
3964
				 * I force an execution break by using setTimeout - but this breaks the expected 
3965
				 * thread continuation for the end-developer's point of view (their code would execute
3966
				 * too early), so we on;y do it when we absolutely have to.
3967
				 */
3968
				var fnInnerSorting = function () {
3969
					var iColumn, iNextSort;
3970
 
3971
					/* If the shift key is pressed then we are multipe column sorting */
3972
					if ( e.shiftKey )
3973
					{
3974
						/* Are we already doing some kind of sort on this column? */
3975
						var bFound = false;
3976
						for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
3977
						{
3978
							if ( oSettings.aaSorting[i][0] == iDataIndex )
3979
							{
3980
								bFound = true;
3981
								iColumn = oSettings.aaSorting[i][0];
3982
								iNextSort = oSettings.aaSorting[i][2]+1;
3983
 
3984
								if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
3985
								{
3986
									/* Reached the end of the sorting options, remove from multi-col sort */
3987
									oSettings.aaSorting.splice( i, 1 );
3988
								}
3989
								else
3990
								{
3991
									/* Move onto next sorting direction */
3992
									oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
3993
									oSettings.aaSorting[i][2] = iNextSort;
3994
								}
3995
								break;
3996
							}
3997
						}
3998
 
3999
						/* No sort yet - add it in */
4000
						if ( bFound === false )
4001
						{
4002
							oSettings.aaSorting.push( [ iDataIndex, 
4003
								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
4004
						}
4005
					}
4006
					else
4007
					{
4008
						/* If no shift key then single column sort */
4009
						if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
4010
						{
4011
							iColumn = oSettings.aaSorting[0][0];
4012
							iNextSort = oSettings.aaSorting[0][2]+1;
4013
							if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
4014
							{
4015
								iNextSort = 0;
4016
							}
4017
							oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
4018
							oSettings.aaSorting[0][2] = iNextSort;
4019
						}
4020
						else
4021
						{
4022
							oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
4023
							oSettings.aaSorting.push( [ iDataIndex, 
4024
								oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
4025
						}
4026
					}
4027
 
4028
					/* Run the sort */
4029
					_fnSort( oSettings );
4030
				}; /* /fnInnerSorting */
4031
 
4032
				if ( !oSettings.oFeatures.bProcessing )
4033
				{
4034
					fnInnerSorting();
4035
				}
4036
				else
4037
				{
4038
					_fnProcessingDisplay( oSettings, true );
4039
					setTimeout( function() {
4040
						fnInnerSorting();
4041
						if ( !oSettings.oFeatures.bServerSide )
4042
						{
4043
							_fnProcessingDisplay( oSettings, false );
4044
						}
4045
					}, 0 );
4046
				}
4047
 
4048
				/* Call the user specified callback function - used for async user interaction */
4049
				if ( typeof fnCallback == 'function' )
4050
				{
4051
					fnCallback( oSettings );
4052
				}
4053
			} );
4054
		}
4055
 
4056
 
4057
		/**
4058
		 * Set the sorting classes on the header, Note: it is safe to call this function 
4059
		 * when bSort and bSortClasses are false
4060
		 *  @param {object} oSettings dataTables settings object
4061
		 *  @memberof DataTable#oApi
4062
		 */
4063
		function _fnSortingClasses( oSettings )
4064
		{
4065
			var i, iLen, j, jLen, iFound;
4066
			var aaSort, sClass;
4067
			var iColumns = oSettings.aoColumns.length;
4068
			var oClasses = oSettings.oClasses;
4069
 
4070
			for ( i=0 ; i<iColumns ; i++ )
4071
			{
4072
				if ( oSettings.aoColumns[i].bSortable )
4073
				{
4074
					$(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
4075
						" "+ oSettings.aoColumns[i].sSortingClass );
4076
				}
4077
			}
4078
 
4079
			if ( oSettings.aaSortingFixed !== null )
4080
			{
4081
				aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
4082
			}
4083
			else
4084
			{
4085
				aaSort = oSettings.aaSorting.slice();
4086
			}
4087
 
4088
			/* Apply the required classes to the header */
4089
			for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
4090
			{
4091
				if ( oSettings.aoColumns[i].bSortable )
4092
				{
4093
					sClass = oSettings.aoColumns[i].sSortingClass;
4094
					iFound = -1;
4095
					for ( j=0 ; j<aaSort.length ; j++ )
4096
					{
4097
						if ( aaSort[j][0] == i )
4098
						{
4099
							sClass = ( aaSort[j][1] == "asc" ) ?
4100
								oClasses.sSortAsc : oClasses.sSortDesc;
4101
							iFound = j;
4102
							break;
4103
						}
4104
					}
4105
					$(oSettings.aoColumns[i].nTh).addClass( sClass );
4106
 
4107
					if ( oSettings.bJUI )
4108
					{
4109
						/* jQuery UI uses extra markup */
4110
						var jqSpan = $("span."+oClasses.sSortIcon,  oSettings.aoColumns[i].nTh);
4111
						jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+ 
4112
							oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
4113
 
4114
						var sSpanClass;
4115
						if ( iFound == -1 )
4116
						{
4117
						 	sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
4118
						}
4119
						else if ( aaSort[iFound][1] == "asc" )
4120
						{
4121
							sSpanClass = oClasses.sSortJUIAsc;
4122
						}
4123
						else
4124
						{
4125
							sSpanClass = oClasses.sSortJUIDesc;
4126
						}
4127
 
4128
						jqSpan.addClass( sSpanClass );
4129
					}
4130
				}
4131
				else
4132
				{
4133
					/* No sorting on this column, so add the base class. This will have been assigned by
4134
					 * _fnAddColumn
4135
					 */
4136
					$(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
4137
				}
4138
			}
4139
 
4140
			/* 
4141
			 * Apply the required classes to the table body
4142
			 * Note that this is given as a feature switch since it can significantly slow down a sort
4143
			 * on large data sets (adding and removing of classes is always slow at the best of times..)
4144
			 * Further to this, note that this code is admitadly fairly ugly. It could be made a lot 
4145
			 * simpiler using jQuery selectors and add/removeClass, but that is significantly slower
4146
			 * (on the order of 5 times slower) - hence the direct DOM manipulation here.
4147
			 * Note that for defered drawing we do use jQuery - the reason being that taking the first
4148
			 * row found to see if the whole column needs processed can miss classes since the first
4149
			 * column might be new.
4150
			 */
4151
			sClass = oClasses.sSortColumn;
4152
 
4153
			if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
4154
			{
4155
				var nTds = _fnGetTdNodes( oSettings );
4156
 
4157
				/* Remove the old classes */
4158
				if ( oSettings.oFeatures.bDeferRender )
4159
				{
4160
					$(nTds).removeClass(sClass+'1 '+sClass+'2 '+sClass+'3');
4161
				}
4162
				else if ( nTds.length >= iColumns )
4163
				{
4164
					for ( i=0 ; i<iColumns ; i++ )
4165
					{
4166
						if ( nTds[i].className.indexOf(sClass+"1") != -1 )
4167
						{
4168
							for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4169
							{
4170
								nTds[(iColumns*j)+i].className = 
4171
									$.trim( nTds[(iColumns*j)+i].className.replace( sClass+"1", "" ) );
4172
							}
4173
						}
4174
						else if ( nTds[i].className.indexOf(sClass+"2") != -1 )
4175
						{
4176
							for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4177
							{
4178
								nTds[(iColumns*j)+i].className = 
4179
									$.trim( nTds[(iColumns*j)+i].className.replace( sClass+"2", "" ) );
4180
							}
4181
						}
4182
						else if ( nTds[i].className.indexOf(sClass+"3") != -1 )
4183
						{
4184
							for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4185
							{
4186
								nTds[(iColumns*j)+i].className = 
4187
									$.trim( nTds[(iColumns*j)+i].className.replace( " "+sClass+"3", "" ) );
4188
							}
4189
						}
4190
					}
4191
				}
4192
 
4193
				/* Add the new classes to the table */
4194
				var iClass = 1, iTargetCol;
4195
				for ( i=0 ; i<aaSort.length ; i++ )
4196
				{
4197
					iTargetCol = parseInt( aaSort[i][0], 10 );
4198
					for ( j=0, jLen=(nTds.length/iColumns) ; j<jLen ; j++ )
4199
					{
4200
						nTds[(iColumns*j)+iTargetCol].className += " "+sClass+iClass;
4201
					}
4202
 
4203
					if ( iClass < 3 )
4204
					{
4205
						iClass++;
4206
					}
4207
				}
4208
			}
4209
		}
4210
 
4211
 
4212
 
4213
		/**
4214
		 * Save the state of a table in a cookie such that the page can be reloaded
4215
		 *  @param {object} oSettings dataTables settings object
4216
		 *  @memberof DataTable#oApi
4217
		 */
4218
		function _fnSaveState ( oSettings )
4219
		{
4220
			if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
4221
			{
4222
				return;
4223
			}
4224
 
4225
			/* Store the interesting variables */
4226
			var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
4227
			var oState = {
4228
				"iCreate":      new Date().getTime(),
4229
				"iStart":       (bInfinite ? 0 : oSettings._iDisplayStart),
4230
				"iEnd":         (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
4231
				"iLength":      oSettings._iDisplayLength,
4232
				"aaSorting":    $.extend( true, [], oSettings.aaSorting ),
4233
				"oSearch":      $.extend( true, {}, oSettings.oPreviousSearch ),
4234
				"aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
4235
				"abVisCols":    []
4236
			};
4237
 
4238
			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
4239
			{
4240
				oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
4241
			}
4242
 
4243
			_fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
4244
 
4245
			oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
4246
		}
4247
 
4248
 
4249
		/**
4250
		 * Attempt to load a saved table state from a cookie
4251
		 *  @param {object} oSettings dataTables settings object
4252
		 *  @param {object} oInit DataTables init object so we can override settings
4253
		 *  @memberof DataTable#oApi
4254
		 */
4255
		function _fnLoadState ( oSettings, oInit )
4256
		{
4257
			if ( !oSettings.oFeatures.bStateSave )
4258
			{
4259
				return;
4260
			}
4261
 
4262
			var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
4263
			if ( !oData )
4264
			{
4265
				return;
4266
			}
4267
 
4268
			/* Allow custom and plug-in manipulation functions to alter the saved data set and
4269
			 * cancelling of loading by returning false
4270
			 */
4271
			var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
4272
			if ( $.inArray( false, abStateLoad ) !== -1 )
4273
			{
4274
				return;
4275
			}
4276
 
4277
			/* Store the saved state so it might be accessed at any time */
4278
			oSettings.oLoadedState = $.extend( true, {}, oData );
4279
 
4280
			/* Restore key features */
4281
			oSettings._iDisplayStart    = oData.iStart;
4282
			oSettings.iInitDisplayStart = oData.iStart;
4283
			oSettings._iDisplayEnd      = oData.iEnd;
4284
			oSettings._iDisplayLength   = oData.iLength;
4285
			oSettings.aaSorting         = oData.aaSorting.slice();
4286
			oSettings.saved_aaSorting   = oData.aaSorting.slice();
4287
 
4288
			/* Search filtering  */
4289
			$.extend( oSettings.oPreviousSearch, oData.oSearch );
4290
			$.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
4291
 
4292
			/* Column visibility state
4293
			 * Pass back visibiliy settings to the init handler, but to do not here override
4294
			 * the init object that the user might have passed in
4295
			 */
4296
			oInit.saved_aoColumns = [];
4297
			for ( var i=0 ; i<oData.abVisCols.length ; i++ )
4298
			{
4299
				oInit.saved_aoColumns[i] = {};
4300
				oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
4301
			}
4302
 
4303
			_fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
4304
		}
4305
 
4306
 
4307
		/**
4308
		 * Create a new cookie with a value to store the state of a table
4309
		 *  @param {string} sName name of the cookie to create
4310
		 *  @param {string} sValue the value the cookie should take
4311
		 *  @param {int} iSecs duration of the cookie
4312
		 *  @param {string} sBaseName sName is made up of the base + file name - this is the base
4313
		 *  @param {function} fnCallback User definable function to modify the cookie
4314
		 *  @memberof DataTable#oApi
4315
		 */
4316
		function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
4317
		{
4318
			var date = new Date();
4319
			date.setTime( date.getTime()+(iSecs*1000) );
4320
 
4321
			/* 
4322
			 * Shocking but true - it would appear IE has major issues with having the path not having
4323
			 * a trailing slash on it. We need the cookie to be available based on the path, so we
4324
			 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
4325
			 * patch to use at least some of the path
4326
			 */
4327
			var aParts = window.location.pathname.split('/');
4328
			var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
4329
			var sFullCookie, oData;
4330
 
4331
			if ( fnCallback !== null )
4332
			{
4333
				oData = (typeof $.parseJSON === 'function') ? 
4334
					$.parseJSON( sValue ) : eval( '('+sValue+')' );
4335
				sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
4336
					aParts.join('/')+"/" );
4337
			}
4338
			else
4339
			{
4340
				sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
4341
					"; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
4342
			}
4343
 
4344
			/* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
4345
			 * belonging to DataTables. This is FAR from bullet proof
4346
			 */
4347
			var sOldName="", iOldTime=9999999999999;
4348
			var iLength = _fnReadCookie( sNameFile )!==null ? document.cookie.length : 
4349
				sFullCookie.length + document.cookie.length;
4350
 
4351
			if ( iLength+10 > 4096 ) /* Magic 10 for padding */
4352
			{
4353
				var aCookies =document.cookie.split(';');
4354
				for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
4355
				{
4356
					if ( aCookies[i].indexOf( sBaseName ) != -1 )
4357
					{
4358
						/* It's a DataTables cookie, so eval it and check the time stamp */
4359
						var aSplitCookie = aCookies[i].split('=');
4360
						try { oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' ); }
4361
						catch( e ) { continue; }
4362
 
4363
						if ( oData.iCreate && oData.iCreate < iOldTime )
4364
						{
4365
							sOldName = aSplitCookie[0];
4366
							iOldTime = oData.iCreate;
4367
						}
4368
					}
4369
				}
4370
 
4371
				if ( sOldName !== "" )
4372
				{
4373
					document.cookie = sOldName+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
4374
						aParts.join('/') + "/";
4375
				}
4376
			}
4377
 
4378
			document.cookie = sFullCookie;
4379
		}
4380
 
4381
 
4382
		/**
4383
		 * Read an old cookie to get a cookie with an old table state
4384
		 *  @param {string} sName name of the cookie to read
4385
		 *  @returns {string} contents of the cookie - or null if no cookie with that name found
4386
		 *  @memberof DataTable#oApi
4387
		 */
4388
		function _fnReadCookie ( sName )
4389
		{
4390
			var
4391
				aParts = window.location.pathname.split('/'),
4392
				sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
4393
			 	sCookieContents = document.cookie.split(';');
4394
 
4395
			for( var i=0 ; i<sCookieContents.length ; i++ )
4396
			{
4397
				var c = sCookieContents[i];
4398
 
4399
				while (c.charAt(0)==' ')
4400
				{
4401
					c = c.substring(1,c.length);
4402
				}
4403
 
4404
				if (c.indexOf(sNameEQ) === 0)
4405
				{
4406
					return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
4407
				}
4408
			}
4409
			return null;
4410
		}
4411
 
4412
 
4413
 
4414
		/**
4415
		 * Return the settings object for a particular table
4416
		 *  @param {node} nTable table we are using as a dataTable
4417
		 *  @returns {object} Settings object - or null if not found
4418
		 *  @memberof DataTable#oApi
4419
		 */
4420
		function _fnSettingsFromNode ( nTable )
4421
		{
4422
			for ( var i=0 ; i<DataTable.settings.length ; i++ )
4423
			{
4424
				if ( DataTable.settings[i].nTable === nTable )
4425
				{
4426
					return DataTable.settings[i];
4427
				}
4428
			}
4429
 
4430
			return null;
4431
		}
4432
 
4433
 
4434
		/**
4435
		 * Return an array with the TR nodes for the table
4436
		 *  @param {object} oSettings dataTables settings object
4437
		 *  @returns {array} TR array
4438
		 *  @memberof DataTable#oApi
4439
		 */
4440
		function _fnGetTrNodes ( oSettings )
4441
		{
4442
			var aNodes = [];
4443
			var aoData = oSettings.aoData;
4444
			for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
4445
			{
4446
				if ( aoData[i].nTr !== null )
4447
				{
4448
					aNodes.push( aoData[i].nTr );
4449
				}
4450
			}
4451
			return aNodes;
4452
		}
4453
 
4454
 
4455
		/**
4456
		 * Return an flat array with all TD nodes for the table, or row
4457
		 *  @param {object} oSettings dataTables settings object
4458
		 *  @param {int} [iIndividualRow] aoData index to get the nodes for - optional 
4459
		 *    if not given then the return array will contain all nodes for the table
4460
		 *  @returns {array} TD array
4461
		 *  @memberof DataTable#oApi
4462
		 */
4463
		function _fnGetTdNodes ( oSettings, iIndividualRow )
4464
		{
4465
			var anReturn = [];
4466
			var iCorrector;
4467
			var anTds;
4468
			var iRow, iRows=oSettings.aoData.length,
4469
				iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
4470
 
4471
			/* Allow the collection to be limited to just one row */
4472
			if ( iIndividualRow !== undefined )
4473
			{
4474
				iStart = iIndividualRow;
4475
				iEnd = iIndividualRow+1;
4476
			}
4477
 
4478
			for ( iRow=iStart ; iRow<iEnd ; iRow++ )
4479
			{
4480
				oData = oSettings.aoData[iRow];
4481
				if ( oData.nTr !== null )
4482
				{
4483
					/* get the TD child nodes - taking into account text etc nodes */
4484
					anTds = [];
4485
					for ( iColumn=0, iColumns=oData.nTr.childNodes.length ; iColumn<iColumns ; iColumn++ )
4486
					{
4487
						sNodeName = oData.nTr.childNodes[iColumn].nodeName.toLowerCase();
4488
						if ( sNodeName == 'td' || sNodeName == 'th' )
4489
						{
4490
							anTds.push( oData.nTr.childNodes[iColumn] );
4491
						}
4492
					}
4493
 
4494
					iCorrector = 0;
4495
					for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
4496
					{
4497
						if ( oSettings.aoColumns[iColumn].bVisible )
4498
						{
4499
							anReturn.push( anTds[iColumn-iCorrector] );
4500
						}
4501
						else
4502
						{
4503
							anReturn.push( oData._anHidden[iColumn] );
4504
							iCorrector++;
4505
						}
4506
					}
4507
				}
4508
			}
4509
 
4510
			return anReturn;
4511
		}
4512
 
4513
 
4514
		/**
4515
		 * Log an error message
4516
		 *  @param {object} oSettings dataTables settings object
4517
		 *  @param {int} iLevel log error messages, or display them to the user
4518
		 *  @param {string} sMesg error message
4519
		 *  @memberof DataTable#oApi
4520
		 */
4521
		function _fnLog( oSettings, iLevel, sMesg )
4522
		{
4523
			var sAlert = (oSettings===null) ?
4524
				"DataTables warning: "+sMesg :
4525
				"DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
4526
 
4527
			if ( iLevel === 0 )
4528
			{
4529
				if ( DataTable.ext.sErrMode == 'alert' )
4530
				{
4531
					alert( sAlert );
4532
				}
4533
				else
4534
				{
4535
					throw sAlert;
4536
				}
4537
				return;
4538
			}
4539
			else if ( console !== undefined && console.log )
4540
			{
4541
				console.log( sAlert );
4542
			}
4543
		}
4544
 
4545
 
4546
		/**
4547
		 * See if a property is defined on one object, if so assign it to the other object
4548
		 *  @param {object} oRet target object
4549
		 *  @param {object} oSrc source object
4550
		 *  @param {string} sName property
4551
		 *  @param {string} [sMappedName] name to map too - optional, sName used if not given
4552
		 *  @memberof DataTable#oApi
4553
		 */
4554
		function _fnMap( oRet, oSrc, sName, sMappedName )
4555
		{
4556
			if ( sMappedName === undefined )
4557
			{
4558
				sMappedName = sName;
4559
			}
4560
			if ( oSrc[sName] !== undefined )
4561
			{
4562
				oRet[sMappedName] = oSrc[sName];
4563
			}
4564
		}
4565
 
4566
 
4567
		/**
4568
		 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
4569
		 * copy arrays. The reason we need to do this, is that we don't want to deep copy array
4570
		 * init values (such as aaSorting) since the dev wouldn't be able to override them, but
4571
		 * we do want to deep copy arrays.
4572
		 *  @param {object} oOut Object to extend
4573
		 *  @param {object} oExtender Object from which the properties will be applied to oOut
4574
		 *  @returns {object} oOut Reference, just for convenience - oOut === the return.
4575
		 *  @memberof DataTable#oApi
4576
		 *  @todo This doesn't take account of arrays inside the deep copied objects.
4577
		 */
4578
		function _fnExtend( oOut, oExtender )
4579
		{
4580
			for ( var prop in oOut )
4581
			{
4582
				if ( oOut.hasOwnProperty(prop) && oExtender[prop] !== undefined )
4583
				{
4584
					if ( typeof oInit[prop] === 'object' && $.isArray(oExtender[prop]) === false )
4585
					{
4586
						$.extend( true, oOut[prop], oExtender[prop] );
4587
					}
4588
					else
4589
					{
4590
						oOut[prop] = oExtender[prop];
4591
					}
4592
				}
4593
			}
4594
 
4595
			return oOut;
4596
		}
4597
 
4598
 
4599
		/**
4600
		 * Bind an event handers to allow a click or return key to activate the callback.
4601
		 * This is good for accessability since a return on the keyboard will have the
4602
		 * same effect as a click, if the element has focus.
4603
		 *  @param {element} n Element to bind the action to
4604
		 *  @param {object} oData Data object to pass to the triggered function
4605
		 *  @param {function) fn Callback function for when the event is triggered
4606
		 *  @memberof DataTable#oApi
4607
		 */
4608
		function _fnBindAction( n, oData, fn )
4609
		{
4610
			$(n)
4611
				.bind( 'click.DT', oData, function (e) {
4612
						fn(e);
4613
						n.blur(); // Remove focus outline for mouse users
4614
					} )
4615
				.bind( 'keypress.DT', oData, function (e){
4616
					if ( e.which === 13 ) {
4617
						fn(e);
4618
					} } )
4619
				.bind( 'selectstart.DT', function () {
4620
					/* Take the brutal approach to cancelling text selection */
4621
					return false;
4622
					} );
4623
		}
4624
 
4625
 
4626
		/**
4627
		 * Register a callback function. Easily allows a callback function to be added to
4628
		 * an array store of callback functions that can then all be called together.
4629
		 *  @param {object} oSettings dataTables settings object
4630
		 *  @param {string} sStore Name of the array storeage for the callbacks in oSettings
4631
		 *  @param {function} fn Function to be called back
4632
		 *  @param {string) sName Identifying name for the callback (i.e. a label)
4633
		 *  @memberof DataTable#oApi
4634
		 */
4635
		function _fnCallbackReg( oSettings, sStore, fn, sName )
4636
		{
4637
			if ( fn )
4638
			{
4639
				oSettings[sStore].push( {
4640
					"fn": fn,
4641
					"sName": sName
4642
				} );
4643
			}
4644
		}
4645
 
4646
 
4647
		/**
4648
		 * Fire callback functions and trigger events. Note that the loop over the callback
4649
		 * array store is done backwards! Further note that you do not want to fire off triggers
4650
		 * in time sensitive applications (for example cell creation) as its slow.
4651
		 *  @param {object} oSettings dataTables settings object
4652
		 *  @param {string} sStore Name of the array storeage for the callbacks in oSettings
4653
		 *  @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
4654
		 *    is fired
4655
		 *  @param {array) aArgs Array of arguments to pass to the callback function / trigger
4656
		 *  @memberof DataTable#oApi
4657
		 */
4658
		function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
4659
		{
4660
			var aoStore = oSettings[sStore];
4661
			var aRet =[];
4662
 
4663
			for ( var i=aoStore.length-1 ; i>=0 ; i-- )
4664
			{
4665
				aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
4666
			}
4667
 
4668
			if ( sTrigger !== null )
4669
			{
4670
				$(oSettings.oInstance).trigger(sTrigger, aArgs);
4671
			}
4672
 
4673
			return aRet;
4674
		}
4675
 
4676
 
4677
		/**
4678
		 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
4679
		 * library, then we use that as it is fast, safe and accurate. If the function isn't 
4680
		 * available then we need to built it ourselves - the insperation for this function comes
4681
		 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
4682
		 * not perfect and absolutely should not be used as a replacement to json2.js - but it does
4683
		 * do what we need, without requiring a dependency for DataTables.
4684
		 *  @param {object} o JSON object to be converted
4685
		 *  @returns {string} JSON string
4686
		 *  @memberof DataTable#oApi
4687
		 */
4688
		var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
4689
		{
4690
			/* Not an object or array */
4691
			var sType = typeof o;
4692
			if (sType !== "object" || o === null)
4693
			{
4694
				// simple data type
4695
				if (sType === "string")
4696
				{
4697
					o = '"'+o+'"';
4698
				}
4699
				return o+"";
4700
			}
4701
 
4702
			/* If object or array, need to recurse over it */
4703
			var
4704
				sProp, mValue,
4705
				json = [],
4706
				bArr = $.isArray(o);
4707
 
4708
			for (sProp in o)
4709
			{
4710
				mValue = o[sProp];
4711
				sType = typeof mValue;
4712
 
4713
				if (sType === "string")
4714
				{
4715
					mValue = '"'+mValue+'"';
4716
				}
4717
				else if (sType === "object" && mValue !== null)
4718
				{
4719
					mValue = _fnJsonString(mValue);
4720
				}
4721
 
4722
				json.push((bArr ? "" : '"'+sProp+'":') + mValue);
4723
			}
4724
 
4725
			return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
4726
		};
4727
 
4728
 
4729
 
4730
 
4731
		/**
4732
		 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
4733
		 * return the resulting jQuery object.
4734
		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
4735
		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
4736
		 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
4737
		 *    criterion ("applied") or all TR elements (i.e. no filter).
4738
		 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
4739
		 *    Can be either 'current', whereby the current sorting of the table is used, or
4740
		 *    'original' whereby the original order the data was read into the table is used.
4741
		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
4742
		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
4743
		 *    'current' and filter is 'applied', regardless of what they might be given as.
4744
		 *  @returns {object} jQuery object, filtered by the given selector.
4745
		 *  @dtopt API
4746
		 *
4747
		 *  @example
4748
		 *    $(document).ready(function() {
4749
		 *      var oTable = $('#example').dataTable();
4750
		 *
4751
		 *      // Highlight every second row
4752
		 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
4753
		 *    } );
4754
		 *
4755
		 *  @example
4756
		 *    $(document).ready(function() {
4757
		 *      var oTable = $('#example').dataTable();
4758
		 *
4759
		 *      // Filter to rows with 'Webkit' in them, add a background colour and then
4760
		 *      // remove the filter, thus highlighting the 'Webkit' rows only.
4761
		 *      oTable.fnFilter('Webkit');
4762
		 *      oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
4763
		 *      oTable.fnFilter('');
4764
		 *    } );
4765
		 */
4766
		this.$ = function ( sSelector, oOpts )
4767
		{
4768
			var i, iLen, a = [];
4769
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
4770
 
4771
			if ( !oOpts )
4772
			{
4773
				oOpts = {};
4774
			}
4775
 
4776
			oOpts = $.extend( {}, {
4777
				"filter": "none", // applied
4778
				"order": "current", // "original"
4779
				"page": "all" // current
4780
			}, oOpts );
4781
 
4782
			// Current page implies that order=current and fitler=applied, since it is fairly
4783
			// senseless otherwise
4784
			if ( oOpts.page == 'current' )
4785
			{
4786
				for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
4787
				{
4788
					a.push( oSettings.aoData[ oSettings.aiDisplay[i] ].nTr );
4789
				}
4790
			}
4791
			else if ( oOpts.order == "current" && oOpts.filter == "none" )
4792
			{
4793
				for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
4794
				{
4795
					a.push( oSettings.aoData[ oSettings.aiDisplayMaster[i] ].nTr );
4796
				}
4797
			}
4798
			else if ( oOpts.order == "current" && oOpts.filter == "applied" )
4799
			{
4800
				for ( i=0, iLen=oSettings.aiDisplay.length ; i<iLen ; i++ )
4801
				{
4802
					a.push( oSettings.aoData[ oSettings.aiDisplay[i] ].nTr );
4803
				}
4804
			}
4805
			else if ( oOpts.order == "original" && oOpts.filter == "none" )
4806
			{
4807
				for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
4808
				{
4809
					a.push( oSettings.aoData[ i ].nTr );
4810
				}
4811
			}
4812
			else if ( oOpts.order == "original" && oOpts.filter == "applied" )
4813
			{
4814
				for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
4815
				{
4816
					if ( $.inArray( i, oSettings.aiDisplay ) !== -1 )
4817
					{
4818
						a.push( oSettings.aoData[ i ].nTr );
4819
					}
4820
				}
4821
			}
4822
			else
4823
			{
4824
				_fnLog( oSettings, 1, "Unknown selection options" );
4825
			}
4826
 
4827
			/* We need to filter on the TR elements and also 'find' in their descendants
4828
			 * to make the selector act like it would in a full table - so we need
4829
			 * to build both results and then combine them together
4830
			 */
4831
			var jqA = $(a);
4832
			var jqTRs = jqA.filter( sSelector );
4833
			var jqDescendants = jqA.find( sSelector );
4834
 
4835
			return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
4836
		};
4837
 
4838
 
4839
		/**
4840
		 * Almost identical to $ in operation, but in this case returns the data for the matched
4841
		 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
4842
		 * rather than any decendents, so the data can be obtained for the row/cell. If matching
4843
		 * rows are found, the data returned is the original data array/object that was used to  
4844
		 * create the row (or a generated array if from a DOM source).
4845
		 *
4846
		 * This method is often useful incombination with $ where both functions are given the
4847
		 * same parameters and the array indexes will match identically.
4848
		 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
4849
		 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
4850
		 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
4851
		 *    criterion ("applied") or all elements (i.e. no filter).
4852
		 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
4853
		 *    Can be either 'current', whereby the current sorting of the table is used, or
4854
		 *    'original' whereby the original order the data was read into the table is used.
4855
		 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
4856
		 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
4857
		 *    'current' and filter is 'applied', regardless of what they might be given as.
4858
		 *  @returns {array} Data for the matched elements. If any elements, as a result of the
4859
		 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null 
4860
		 *    entry in the array.
4861
		 *  @dtopt API
4862
		 *
4863
		 *  @example
4864
		 *    $(document).ready(function() {
4865
		 *      var oTable = $('#example').dataTable();
4866
		 *
4867
		 *      // Get the data from the first row in the table
4868
		 *      var data = oTable._('tr:first');
4869
		 *
4870
		 *      // Do something useful with the data
4871
		 *      alert( "First cell is: "+data[0] );
4872
		 *    } );
4873
		 *
4874
		 *  @example
4875
		 *    $(document).ready(function() {
4876
		 *      var oTable = $('#example').dataTable();
4877
		 *
4878
		 *      // Filter to 'Webkit' and get all data for 
4879
		 *      oTable.fnFilter('Webkit');
4880
		 *      var data = oTable._('tr', {"filter": "applied"});
4881
		 *      
4882
		 *      // Do something with the data
4883
		 *      alert( data.length+" rows matched the filter" );
4884
		 *    } );
4885
		 */
4886
		this._ = function ( sSelector, oOpts )
4887
		{
4888
			var aOut = [];
4889
			var i, iLen, iIndex;
4890
			var aTrs = this.$( sSelector, oOpts );
4891
 
4892
			for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
4893
			{
4894
				aOut.push( this.fnGetData(aTrs[i]) );
4895
			}
4896
 
4897
			return aOut;
4898
		};
4899
 
4900
 
4901
		/**
4902
		 * Add a single new row or multiple rows of data to the table. Please note
4903
		 * that this is suitable for client-side processing only - if you are using 
4904
		 * server-side processing (i.e. "bServerSide": true), then to add data, you
4905
		 * must add it to the data source, i.e. the server-side, through an Ajax call.
4906
		 *  @param {array|object} mData The data to be added to the table. This can be:
4907
		 *    <ul>
4908
		 *      <li>1D array of data - add a single row with the data provided</li>
4909
		 *      <li>2D array of arrays - add multiple rows in a single call</li>
4910
		 *      <li>object - data object when using <i>mDataProp</i></li>
4911
		 *      <li>array of objects - multiple data objects when using <i>mDataProp</i></li>
4912
		 *    </ul>
4913
		 *  @param {bool} [bRedraw=true] redraw the table or not
4914
		 *  @returns {array} An array of integers, representing the list of indexes in 
4915
		 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 
4916
		 *    the table.
4917
		 *  @dtopt API
4918
		 *
4919
		 *  @example
4920
		 *    // Global var for counter
4921
		 *    var giCount = 2;
4922
		 *    
4923
		 *    $(document).ready(function() {
4924
		 *      $('#example').dataTable();
4925
		 *    } );
4926
		 *    
4927
		 *    function fnClickAddRow() {
4928
		 *      $('#example').dataTable().fnAddData( [
4929
		 *        giCount+".1",
4930
		 *        giCount+".2",
4931
		 *        giCount+".3",
4932
		 *        giCount+".4" ]
4933
		 *      );
4934
		 *        
4935
		 *      giCount++;
4936
		 *    }
4937
		 */
4938
		this.fnAddData = function( mData, bRedraw )
4939
		{
4940
			if ( mData.length === 0 )
4941
			{
4942
				return [];
4943
			}
4944
 
4945
			var aiReturn = [];
4946
			var iTest;
4947
 
4948
			/* Find settings from table node */
4949
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
4950
 
4951
			/* Check if we want to add multiple rows or not */
4952
			if ( typeof mData[0] === "object" && mData[0] !== null )
4953
			{
4954
				for ( var i=0 ; i<mData.length ; i++ )
4955
				{
4956
					iTest = _fnAddData( oSettings, mData[i] );
4957
					if ( iTest == -1 )
4958
					{
4959
						return aiReturn;
4960
					}
4961
					aiReturn.push( iTest );
4962
				}
4963
			}
4964
			else
4965
			{
4966
				iTest = _fnAddData( oSettings, mData );
4967
				if ( iTest == -1 )
4968
				{
4969
					return aiReturn;
4970
				}
4971
				aiReturn.push( iTest );
4972
			}
4973
 
4974
			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
4975
 
4976
			if ( bRedraw === undefined || bRedraw )
4977
			{
4978
				_fnReDraw( oSettings );
4979
			}
4980
			return aiReturn;
4981
		};
4982
 
4983
 
4984
		/**
4985
		 * This function will make DataTables recalculate the column sizes, based on the data 
4986
		 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 
4987
		 * through the sWidth parameter). This can be useful when the width of the table's 
4988
		 * parent element changes (for example a window resize).
4989
		 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
4990
		 *  @dtopt API
4991
		 *
4992
		 *  @example
4993
		 *    $(document).ready(function() {
4994
		 *      var oTable = $('#example').dataTable( {
4995
		 *        "sScrollY": "200px",
4996
		 *        "bPaginate": false
4997
		 *      } );
4998
		 *      
4999
		 *      $(window).bind('resize', function () {
5000
		 *        oTable.fnAdjustColumnSizing();
5001
		 *      } );
5002
		 *    } );
5003
		 */
5004
		this.fnAdjustColumnSizing = function ( bRedraw )
5005
		{
5006
			var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
5007
			_fnAdjustColumnSizing( oSettings );
5008
 
5009
			if ( bRedraw === undefined || bRedraw )
5010
			{
5011
				this.fnDraw( false );
5012
			}
5013
			else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
5014
			{
5015
				/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5016
				this.oApi._fnScrollDraw(oSettings);
5017
			}
5018
		};
5019
 
5020
 
5021
		/**
5022
		 * Quickly and simply clear a table
5023
		 *  @param {bool} [bRedraw=true] redraw the table or not
5024
		 *  @dtopt API
5025
		 *
5026
		 *  @example
5027
		 *    $(document).ready(function() {
5028
		 *      var oTable = $('#example').dataTable();
5029
		 *      
5030
		 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5031
		 *      oTable.fnClearTable();
5032
		 *    } );
5033
		 */
5034
		this.fnClearTable = function( bRedraw )
5035
		{
5036
			/* Find settings from table node */
5037
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5038
			_fnClearTable( oSettings );
5039
 
5040
			if ( bRedraw === undefined || bRedraw )
5041
			{
5042
				_fnDraw( oSettings );
5043
			}
5044
		};
5045
 
5046
 
5047
		/**
5048
		 * The exact opposite of 'opening' a row, this function will close any rows which 
5049
		 * are currently 'open'.
5050
		 *  @param {node} nTr the table row to 'close'
5051
		 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
5052
		 *  @dtopt API
5053
		 *
5054
		 *  @example
5055
		 *    $(document).ready(function() {
5056
		 *      var oTable;
5057
		 *      
5058
		 *      // 'open' an information row when a row is clicked on
5059
		 *      $('#example tbody tr').click( function () {
5060
		 *        if ( oTable.fnIsOpen(this) ) {
5061
		 *          oTable.fnClose( this );
5062
		 *        } else {
5063
		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5064
		 *        }
5065
		 *      } );
5066
		 *      
5067
		 *      oTable = $('#example').dataTable();
5068
		 *    } );
5069
		 */
5070
		this.fnClose = function( nTr )
5071
		{
5072
			/* Find settings from table node */
5073
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5074
 
5075
			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
5076
			{
5077
				if ( oSettings.aoOpenRows[i].nParent == nTr )
5078
				{
5079
					var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
5080
					if ( nTrParent )
5081
					{
5082
						/* Remove it if it is currently on display */
5083
						nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
5084
					}
5085
					oSettings.aoOpenRows.splice( i, 1 );
5086
					return 0;
5087
				}
5088
			}
5089
			return 1;
5090
		};
5091
 
5092
 
5093
		/**
5094
		 * Remove a row for the table
5095
		 *  @param {mixed} mTarget The index of the row from aoData to be deleted, or
5096
		 *    the TR element you want to delete
5097
		 *  @param {function|null} [fnCallBack] Callback function
5098
		 *  @param {bool} [bRedraw=true] Redraw the table or not
5099
		 *  @returns {array} The row that was deleted
5100
		 *  @dtopt API
5101
		 *
5102
		 *  @example
5103
		 *    $(document).ready(function() {
5104
		 *      var oTable = $('#example').dataTable();
5105
		 *      
5106
		 *      // Immediately remove the first row
5107
		 *      oTable.fnDeleteRow( 0 );
5108
		 *    } );
5109
		 */
5110
		this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
5111
		{
5112
			/* Find settings from table node */
5113
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5114
			var i, iLen, iAODataIndex;
5115
 
5116
			iAODataIndex = (typeof mTarget === 'object') ? 
5117
				_fnNodeToDataIndex(oSettings, mTarget) : mTarget;
5118
 
5119
			/* Return the data array from this row */
5120
			var oData = oSettings.aoData.splice( iAODataIndex, 1 );
5121
 
5122
			/* Update the _DT_RowIndex parameter */
5123
			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
5124
			{
5125
				if ( oSettings.aoData[i].nTr !== null )
5126
				{
5127
					oSettings.aoData[i].nTr._DT_RowIndex = i;
5128
				}
5129
			}
5130
 
5131
			/* Remove the target row from the search array */
5132
			var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
5133
			oSettings.asDataSearch.splice( iDisplayIndex, 1 );
5134
 
5135
			/* Delete from the display arrays */
5136
			_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
5137
			_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
5138
 
5139
			/* If there is a user callback function - call it */
5140
			if ( typeof fnCallBack === "function" )
5141
			{
5142
				fnCallBack.call( this, oSettings, oData );
5143
			}
5144
 
5145
			/* Check for an 'overflow' they case for dislaying the table */
5146
			if ( oSettings._iDisplayStart >= oSettings.aiDisplay.length )
5147
			{
5148
				oSettings._iDisplayStart -= oSettings._iDisplayLength;
5149
				if ( oSettings._iDisplayStart < 0 )
5150
				{
5151
					oSettings._iDisplayStart = 0;
5152
				}
5153
			}
5154
 
5155
			if ( bRedraw === undefined || bRedraw )
5156
			{
5157
				_fnCalculateEnd( oSettings );
5158
				_fnDraw( oSettings );
5159
			}
5160
 
5161
			return oData;
5162
		};
5163
 
5164
 
5165
		/**
5166
		 * Restore the table to it's original state in the DOM by removing all of DataTables 
5167
		 * enhancements, alterations to the DOM structure of the table and event listeners.
5168
		 *  @param {boolean} [bRemove=false] Completely remove the table from the DOM
5169
		 *  @dtopt API
5170
		 *
5171
		 *  @example
5172
		 *    $(document).ready(function() {
5173
		 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
5174
		 *      var oTable = $('#example').dataTable();
5175
		 *      oTable.fnDestroy();
5176
		 *    } );
5177
		 */
5178
		this.fnDestroy = function ( bRemove )
5179
		{
5180
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5181
			var nOrig = oSettings.nTableWrapper.parentNode;
5182
			var nBody = oSettings.nTBody;
5183
			var i, iLen;
5184
 
5185
			bRemove = (bRemove===undefined) ? false : true;
5186
 
5187
			/* Flag to note that the table is currently being destroyed - no action should be taken */
5188
			oSettings.bDestroying = true;
5189
 
5190
			/* Restore hidden columns */
5191
			for ( i=0, iLen=oSettings.aoDestroyCallback.length ; i<iLen ; i++ ) {
5192
				oSettings.aoDestroyCallback[i].fn();
5193
			}
5194
 
5195
			/* Restore hidden columns */
5196
			for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
5197
			{
5198
				if ( oSettings.aoColumns[i].bVisible === false )
5199
				{
5200
					this.fnSetColumnVis( i, true );
5201
				}
5202
			}
5203
 
5204
			/* Blitz all DT events */
5205
			$(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
5206
 
5207
			/* If there is an 'empty' indicator row, remove it */
5208
			$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
5209
 
5210
			/* When scrolling we had to break the table up - restore it */
5211
			if ( oSettings.nTable != oSettings.nTHead.parentNode )
5212
			{
5213
				$(oSettings.nTable).children('thead').remove();
5214
				oSettings.nTable.appendChild( oSettings.nTHead );
5215
			}
5216
 
5217
			if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
5218
			{
5219
				$(oSettings.nTable).children('tfoot').remove();
5220
				oSettings.nTable.appendChild( oSettings.nTFoot );
5221
			}
5222
 
5223
			/* Remove the DataTables generated nodes, events and classes */
5224
			oSettings.nTable.parentNode.removeChild( oSettings.nTable );
5225
			$(oSettings.nTableWrapper).remove();
5226
 
5227
			oSettings.aaSorting = [];
5228
			oSettings.aaSortingFixed = [];
5229
			_fnSortingClasses( oSettings );
5230
 
5231
			$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
5232
 
5233
			$('th, td', oSettings.nTHead).removeClass( [
5234
				oSettings.oClasses.sSortable,
5235
				oSettings.oClasses.sSortableAsc,
5236
				oSettings.oClasses.sSortableDesc,
5237
				oSettings.oClasses.sSortableNone ].join(' ')
5238
			);
5239
			if ( oSettings.bJUI )
5240
			{
5241
				$('th span.'+oSettings.oClasses.sSortIcon
5242
					+ ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
5243
 
5244
				$('th, td', oSettings.nTHead).each( function () {
5245
					var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
5246
					var kids = jqWrapper.contents();
5247
					$(this).append( kids );
5248
					jqWrapper.remove();
5249
				} );
5250
			}
5251
 
5252
			/* Add the TR elements back into the table in their original order */
5253
			if ( !bRemove && oSettings.nTableReinsertBefore )
5254
			{
5255
				nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
5256
			}
5257
			else if ( !bRemove )
5258
			{
5259
				nOrig.appendChild( oSettings.nTable );
5260
			}
5261
 
5262
			for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
5263
			{
5264
				if ( oSettings.aoData[i].nTr !== null )
5265
				{
5266
					nBody.appendChild( oSettings.aoData[i].nTr );
5267
				}
5268
			}
5269
 
5270
			/* Restore the width of the original table */
5271
			if ( oSettings.oFeatures.bAutoWidth === true )
5272
			{
5273
			  oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
5274
			}
5275
 
5276
			/* If the were originally odd/even type classes - then we add them back here. Note
5277
			 * this is not fool proof (for example if not all rows as odd/even classes - but 
5278
			 * it's a good effort without getting carried away
5279
			 */
5280
			$(nBody).children('tr:even').addClass( oSettings.asDestroyStripes[0] );
5281
			$(nBody).children('tr:odd').addClass( oSettings.asDestroyStripes[1] );
5282
 
5283
			/* Remove the settings object from the settings array */
5284
			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
5285
			{
5286
				if ( DataTable.settings[i] == oSettings )
5287
				{
5288
					DataTable.settings.splice( i, 1 );
5289
				}
5290
			}
5291
 
5292
			/* End it all */
5293
			oSettings = null;
5294
		};
5295
 
5296
 
5297
		/**
5298
		 * Redraw the table
5299
		 *  @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
5300
		 *  @dtopt API
5301
		 *
5302
		 *  @example
5303
		 *    $(document).ready(function() {
5304
		 *      var oTable = $('#example').dataTable();
5305
		 *      
5306
		 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5307
		 *      oTable.fnDraw();
5308
		 *    } );
5309
		 */
5310
		this.fnDraw = function( bComplete )
5311
		{
5312
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5313
			if ( bComplete )
5314
			{
5315
				_fnCalculateEnd( oSettings );
5316
				_fnDraw( oSettings );
5317
			}
5318
			else
5319
			{
5320
				_fnReDraw( oSettings );
5321
			}
5322
		};
5323
 
5324
 
5325
		/**
5326
		 * Filter the input based on data
5327
		 *  @param {string} sInput String to filter the table on
5328
		 *  @param {int|null} [iColumn] Column to limit filtering to
5329
		 *  @param {bool} [bRegex=false] Treat as regular expression or not
5330
		 *  @param {bool} [bSmart=true] Perform smart filtering or not
5331
		 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5332
		 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5333
		 *  @dtopt API
5334
		 *
5335
		 *  @example
5336
		 *    $(document).ready(function() {
5337
		 *      var oTable = $('#example').dataTable();
5338
		 *      
5339
		 *      // Sometime later - filter...
5340
		 *      oTable.fnFilter( 'test string' );
5341
		 *    } );
5342
		 */
5343
		this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5344
		{
5345
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5346
 
5347
			if ( !oSettings.oFeatures.bFilter )
5348
			{
5349
				return;
5350
			}
5351
 
5352
			if ( bRegex === undefined || bRegex === null )
5353
			{
5354
				bRegex = false;
5355
			}
5356
 
5357
			if ( bSmart === undefined || bSmart === null )
5358
			{
5359
				bSmart = true;
5360
			}
5361
 
5362
			if ( bShowGlobal === undefined || bShowGlobal === null )
5363
			{
5364
				bShowGlobal = true;
5365
			}
5366
 
5367
			if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
5368
			{
5369
				bCaseInsensitive = true;
5370
			}
5371
 
5372
			if ( iColumn === undefined || iColumn === null )
5373
			{
5374
				/* Global filter */
5375
				_fnFilterComplete( oSettings, {
5376
					"sSearch":sInput+"",
5377
					"bRegex": bRegex,
5378
					"bSmart": bSmart,
5379
					"bCaseInsensitive": bCaseInsensitive
5380
				}, 1 );
5381
 
5382
				if ( bShowGlobal && oSettings.aanFeatures.f )
5383
				{
5384
					var n = oSettings.aanFeatures.f;
5385
					for ( var i=0, iLen=n.length ; i<iLen ; i++ )
5386
					{
5387
						$('input', n[i]).val( sInput );
5388
					}
5389
				}
5390
			}
5391
			else
5392
			{
5393
				/* Single column filter */
5394
				$.extend( oSettings.aoPreSearchCols[ iColumn ], {
5395
					"sSearch": sInput+"",
5396
					"bRegex": bRegex,
5397
					"bSmart": bSmart,
5398
					"bCaseInsensitive": bCaseInsensitive
5399
				} );
5400
				_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
5401
			}
5402
		};
5403
 
5404
 
5405
		/**
5406
		 * Get the data for the whole table, an individual row or an individual cell based on the 
5407
		 * provided parameters.
5408
		 *  @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
5409
		 *    a TR node then the data source for the whole row will be returned. If given as a
5410
		 *    TD/TH cell node then iCol will be automatically calculated and the data for the
5411
		 *    cell returned. If given as an integer, then this is treated as the aoData internal
5412
		 *    data index for the row (see fnGetPosition) and the data for that row used.
5413
		 *  @param {int} [iCol] Optional column index that you want the data of.
5414
		 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
5415
		 *    returned. If mRow is defined, just data for that row, and is iCol is
5416
		 *    defined, only data for the designated cell is returned.
5417
		 *  @dtopt API
5418
		 *
5419
		 *  @example
5420
		 *    // Row data
5421
		 *    $(document).ready(function() {
5422
		 *      oTable = $('#example').dataTable();
5423
		 *
5424
		 *      oTable.$('tr').click( function () {
5425
		 *        var data = oTable.fnGetData( this );
5426
		 *        // ... do something with the array / object of data for the row
5427
		 *      } );
5428
		 *    } );
5429
		 *
5430
		 *  @example
5431
		 *    // Individual cell data
5432
		 *    $(document).ready(function() {
5433
		 *      oTable = $('#example').dataTable();
5434
		 *
5435
		 *      oTable.$('td').click( function () {
5436
		 *        var sData = oTable.fnGetData( this );
5437
		 *        alert( 'The cell clicked on had the value of '+sData );
5438
		 *      } );
5439
		 *    } );
5440
		 */
5441
		this.fnGetData = function( mRow, iCol )
5442
		{
5443
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5444
 
5445
			if ( mRow !== undefined )
5446
			{
5447
				var iRow = mRow;
5448
				if ( typeof mRow === 'object' )
5449
				{
5450
					var sNode = mRow.nodeName.toLowerCase();
5451
					if (sNode === "tr" )
5452
					{
5453
						iRow = _fnNodeToDataIndex(oSettings, mRow);
5454
					}
5455
					else if ( sNode === "td" )
5456
					{
5457
						iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
5458
						iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
5459
					}
5460
				}
5461
 
5462
				if ( iCol !== undefined )
5463
				{
5464
					return _fnGetCellData( oSettings, iRow, iCol, '' );
5465
				}
5466
				return (oSettings.aoData[iRow]!==undefined) ?
5467
					oSettings.aoData[iRow]._aData : null;
5468
			}
5469
			return _fnGetDataMaster( oSettings );
5470
		};
5471
 
5472
 
5473
		/**
5474
		 * Get an array of the TR nodes that are used in the table's body. Note that you will 
5475
		 * typically want to use the '$' API method in preference to this as it is more 
5476
		 * flexible.
5477
		 *  @param {int} [iRow] Optional row index for the TR element you want
5478
		 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
5479
		 *    in the table's body, or iRow is defined, just the TR element requested.
5480
		 *  @dtopt API
5481
		 *
5482
		 *  @example
5483
		 *    $(document).ready(function() {
5484
		 *      var oTable = $('#example').dataTable();
5485
		 *      
5486
		 *      // Get the nodes from the table
5487
		 *      var nNodes = oTable.fnGetNodes( );
5488
		 *    } );
5489
		 */
5490
		this.fnGetNodes = function( iRow )
5491
		{
5492
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5493
 
5494
			if ( iRow !== undefined ) {
5495
				return (oSettings.aoData[iRow]!==undefined) ?
5496
					oSettings.aoData[iRow].nTr : null;
5497
			}
5498
			return _fnGetTrNodes( oSettings );
5499
		};
5500
 
5501
 
5502
		/**
5503
		 * Get the array indexes of a particular cell from it's DOM element
5504
		 * and column index including hidden columns
5505
		 *  @param {node} nNode this can either be a TR, TD or TH in the table's body
5506
		 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
5507
		 *    if given as a cell, an array of [row index, column index (visible)] is given.
5508
		 *  @dtopt API
5509
		 *
5510
		 *  @example
5511
		 *    $(document).ready(function() {
5512
		 *      $('#example tbody td').click( function () {
5513
		 *        // Get the position of the current data from the node
5514
		 *        var aPos = oTable.fnGetPosition( this );
5515
		 *        
5516
		 *        // Get the data array for this row
5517
		 *        var aData = oTable.fnGetData( aPos[0] );
5518
		 *        
5519
		 *        // Update the data array and return the value
5520
		 *        aData[ aPos[1] ] = 'clicked';
5521
		 *        this.innerHTML = 'clicked';
5522
		 *      } );
5523
		 *      
5524
		 *      // Init DataTables
5525
		 *      oTable = $('#example').dataTable();
5526
		 *    } );
5527
		 */
5528
		this.fnGetPosition = function( nNode )
5529
		{
5530
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5531
			var sNodeName = nNode.nodeName.toUpperCase();
5532
 
5533
			if ( sNodeName == "TR" )
5534
			{
5535
				return _fnNodeToDataIndex(oSettings, nNode);
5536
			}
5537
			else if ( sNodeName == "TD" || sNodeName == "TH" )
5538
			{
5539
				var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
5540
				var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
5541
				return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
5542
			}
5543
			return null;
5544
		};
5545
 
5546
 
5547
		/**
5548
		 * Check to see if a row is 'open' or not.
5549
		 *  @param {node} nTr the table row to check
5550
		 *  @returns {boolean} true if the row is currently open, false otherwise
5551
		 *  @dtopt API
5552
		 *
5553
		 *  @example
5554
		 *    $(document).ready(function() {
5555
		 *      var oTable;
5556
		 *      
5557
		 *      // 'open' an information row when a row is clicked on
5558
		 *      $('#example tbody tr').click( function () {
5559
		 *        if ( oTable.fnIsOpen(this) ) {
5560
		 *          oTable.fnClose( this );
5561
		 *        } else {
5562
		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5563
		 *        }
5564
		 *      } );
5565
		 *      
5566
		 *      oTable = $('#example').dataTable();
5567
		 *    } );
5568
		 */
5569
		this.fnIsOpen = function( nTr )
5570
		{
5571
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5572
			var aoOpenRows = oSettings.aoOpenRows;
5573
 
5574
			for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
5575
			{
5576
				if ( oSettings.aoOpenRows[i].nParent == nTr )
5577
				{
5578
					return true;
5579
				}
5580
			}
5581
			return false;
5582
		};
5583
 
5584
 
5585
		/**
5586
		 * This function will place a new row directly after a row which is currently 
5587
		 * on display on the page, with the HTML contents that is passed into the 
5588
		 * function. This can be used, for example, to ask for confirmation that a 
5589
		 * particular record should be deleted.
5590
		 *  @param {node} nTr The table row to 'open'
5591
		 *  @param {string|node|jQuery} mHtml The HTML to put into the row
5592
		 *  @param {string} sClass Class to give the new TD cell
5593
		 *  @returns {node} The row opened. Note that if the table row passed in as the
5594
		 *    first parameter, is not found in the table, this method will silently
5595
		 *    return.
5596
		 *  @dtopt API
5597
		 *
5598
		 *  @example
5599
		 *    $(document).ready(function() {
5600
		 *      var oTable;
5601
		 *      
5602
		 *      // 'open' an information row when a row is clicked on
5603
		 *      $('#example tbody tr').click( function () {
5604
		 *        if ( oTable.fnIsOpen(this) ) {
5605
		 *          oTable.fnClose( this );
5606
		 *        } else {
5607
		 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
5608
		 *        }
5609
		 *      } );
5610
		 *      
5611
		 *      oTable = $('#example').dataTable();
5612
		 *    } );
5613
		 */
5614
		this.fnOpen = function( nTr, mHtml, sClass )
5615
		{
5616
			/* Find settings from table node */
5617
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5618
 
5619
			/* Check that the row given is in the table */
5620
			var nTableRows = _fnGetTrNodes( oSettings );
5621
			if ( $.inArray(nTr, nTableRows) === -1 )
5622
			{
5623
				return;
5624
			}
5625
 
5626
			/* the old open one if there is one */
5627
			this.fnClose( nTr );
5628
 
5629
			var nNewRow = document.createElement("tr");
5630
			var nNewCell = document.createElement("td");
5631
			nNewRow.appendChild( nNewCell );
5632
			nNewCell.className = sClass;
5633
			nNewCell.colSpan = _fnVisbleColumns( oSettings );
5634
 
5635
			if (typeof mHtml === "string")
5636
			{
5637
				nNewCell.innerHTML = mHtml;
5638
			}
5639
			else
5640
			{
5641
				$(nNewCell).html( mHtml );
5642
			}
5643
 
5644
			/* If the nTr isn't on the page at the moment - then we don't insert at the moment */
5645
			var nTrs = $('tr', oSettings.nTBody);
5646
			if ( $.inArray(nTr, nTrs) != -1  )
5647
			{
5648
				$(nNewRow).insertAfter(nTr);
5649
			}
5650
 
5651
			oSettings.aoOpenRows.push( {
5652
				"nTr": nNewRow,
5653
				"nParent": nTr
5654
			} );
5655
 
5656
			return nNewRow;
5657
		};
5658
 
5659
 
5660
		/**
5661
		 * Change the pagination - provides the internal logic for pagination in a simple API 
5662
		 * function. With this function you can have a DataTables table go to the next, 
5663
		 * previous, first or last pages.
5664
		 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5665
		 *    or page number to jump to (integer), note that page 0 is the first page.
5666
		 *  @param {bool} [bRedraw=true] Redraw the table or not
5667
		 *  @dtopt API
5668
		 *
5669
		 *  @example
5670
		 *    $(document).ready(function() {
5671
		 *      var oTable = $('#example').dataTable();
5672
		 *      oTable.fnPageChange( 'next' );
5673
		 *    } );
5674
		 */
5675
		this.fnPageChange = function ( mAction, bRedraw )
5676
		{
5677
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5678
			_fnPageChange( oSettings, mAction );
5679
			_fnCalculateEnd( oSettings );
5680
 
5681
			if ( bRedraw === undefined || bRedraw )
5682
			{
5683
				_fnDraw( oSettings );
5684
			}
5685
		};
5686
 
5687
 
5688
		/**
5689
		 * Show a particular column
5690
		 *  @param {int} iCol The column whose display should be changed
5691
		 *  @param {bool} bShow Show (true) or hide (false) the column
5692
		 *  @param {bool} [bRedraw=true] Redraw the table or not
5693
		 *  @dtopt API
5694
		 *
5695
		 *  @example
5696
		 *    $(document).ready(function() {
5697
		 *      var oTable = $('#example').dataTable();
5698
		 *      
5699
		 *      // Hide the second column after initialisation
5700
		 *      oTable.fnSetColumnVis( 1, false );
5701
		 *    } );
5702
		 */
5703
		this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5704
		{
5705
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5706
			var i, iLen;
5707
			var aoColumns = oSettings.aoColumns;
5708
			var aoData = oSettings.aoData;
5709
			var nTd, nCell, anTrs, jqChildren, bAppend, iBefore;
5710
 
5711
			/* No point in doing anything if we are requesting what is already true */
5712
			if ( aoColumns[iCol].bVisible == bShow )
5713
			{
5714
				return;
5715
			}
5716
 
5717
			/* Show the column */
5718
			if ( bShow )
5719
			{
5720
				var iInsert = 0;
5721
				for ( i=0 ; i<iCol ; i++ )
5722
				{
5723
					if ( aoColumns[i].bVisible )
5724
					{
5725
						iInsert++;
5726
					}
5727
				}
5728
 
5729
				/* Need to decide if we should use appendChild or insertBefore */
5730
				bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
5731
 
5732
				/* Which coloumn should we be inserting before? */
5733
				if ( !bAppend )
5734
				{
5735
					for ( i=iCol ; i<aoColumns.length ; i++ )
5736
					{
5737
						if ( aoColumns[i].bVisible )
5738
						{
5739
							iBefore = i;
5740
							break;
5741
						}
5742
					}
5743
				}
5744
 
5745
				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
5746
				{
5747
					if ( aoData[i].nTr !== null )
5748
					{
5749
						if ( bAppend )
5750
						{
5751
							aoData[i].nTr.appendChild( 
5752
								aoData[i]._anHidden[iCol]
5753
							);
5754
						}
5755
						else
5756
						{
5757
							aoData[i].nTr.insertBefore(
5758
								aoData[i]._anHidden[iCol], 
5759
								_fnGetTdNodes( oSettings, i )[iBefore] );
5760
						}
5761
					}
5762
				}
5763
			}
5764
			else
5765
			{
5766
				/* Remove a column from display */
5767
				for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
5768
				{
5769
					if ( aoData[i].nTr !== null )
5770
					{
5771
						nTd = _fnGetTdNodes( oSettings, i )[iCol];
5772
						aoData[i]._anHidden[iCol] = nTd;
5773
						nTd.parentNode.removeChild( nTd );
5774
					}
5775
				}
5776
			}
5777
 
5778
			/* Clear to set the visible flag */
5779
			aoColumns[iCol].bVisible = bShow;
5780
 
5781
			/* Redraw the header and footer based on the new column visibility */
5782
			_fnDrawHead( oSettings, oSettings.aoHeader );
5783
			if ( oSettings.nTFoot )
5784
			{
5785
				_fnDrawHead( oSettings, oSettings.aoFooter );
5786
			}
5787
 
5788
			/* If there are any 'open' rows, then we need to alter the colspan for this col change */
5789
			for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
5790
			{
5791
				oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
5792
			}
5793
 
5794
			/* Do a redraw incase anything depending on the table columns needs it 
5795
			 * (built-in: scrolling) 
5796
			 */
5797
			if ( bRedraw === undefined || bRedraw )
5798
			{
5799
				_fnAdjustColumnSizing( oSettings );
5800
				_fnDraw( oSettings );
5801
			}
5802
 
5803
			_fnSaveState( oSettings );
5804
		};
5805
 
5806
 
5807
		/**
5808
		 * Get the settings for a particular table for external manipulation
5809
		 *  @returns {object} DataTables settings object. See 
5810
		 *    {@link DataTable.models.oSettings}
5811
		 *  @dtopt API
5812
		 *
5813
		 *  @example
5814
		 *    $(document).ready(function() {
5815
		 *      var oTable = $('#example').dataTable();
5816
		 *      var oSettings = oTable.fnSettings();
5817
		 *      
5818
		 *      // Show an example parameter from the settings
5819
		 *      alert( oSettings._iDisplayStart );
5820
		 *    } );
5821
		 */
5822
		this.fnSettings = function()
5823
		{
5824
			return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5825
		};
5826
 
5827
 
5828
		/**
5829
		 * Sort the table by a particular row
5830
		 *  @param {int} iCol the data index to sort on. Note that this will not match the 
5831
		 *    'display index' if you have hidden data entries
5832
		 *  @dtopt API
5833
		 *
5834
		 *  @example
5835
		 *    $(document).ready(function() {
5836
		 *      var oTable = $('#example').dataTable();
5837
		 *      
5838
		 *      // Sort immediately with columns 0 and 1
5839
		 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5840
		 *    } );
5841
		 */
5842
		this.fnSort = function( aaSort )
5843
		{
5844
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5845
			oSettings.aaSorting = aaSort;
5846
			_fnSort( oSettings );
5847
		};
5848
 
5849
 
5850
		/**
5851
		 * Attach a sort listener to an element for a given column
5852
		 *  @param {node} nNode the element to attach the sort listener to
5853
		 *  @param {int} iColumn the column that a click on this node will sort on
5854
		 *  @param {function} [fnCallback] callback function when sort is run
5855
		 *  @dtopt API
5856
		 *
5857
		 *  @example
5858
		 *    $(document).ready(function() {
5859
		 *      var oTable = $('#example').dataTable();
5860
		 *      
5861
		 *      // Sort on column 1, when 'sorter' is clicked on
5862
		 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
5863
		 *    } );
5864
		 */
5865
		this.fnSortListener = function( nNode, iColumn, fnCallback )
5866
		{
5867
			_fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
5868
			 	fnCallback );
5869
		};
5870
 
5871
 
5872
		/**
5873
		 * Update a table cell or row - this method will accept either a single value to
5874
		 * update the cell with, an array of values with one element for each column or
5875
		 * an object in the same format as the original data source. The function is
5876
		 * self-referencing in order to make the multi column updates easier.
5877
		 *  @param {object|array|string} mData Data to update the cell/row with
5878
		 *  @param {node|int} mRow TR element you want to update or the aoData index
5879
		 *  @param {int} [iColumn] The column to update (not used of mData is an array or object)
5880
		 *  @param {bool} [bRedraw=true] Redraw the table or not
5881
		 *  @param {bool} [bAction=true] Perform predraw actions or not
5882
		 *  @returns {int} 0 on success, 1 on error
5883
		 *  @dtopt API
5884
		 *
5885
		 *  @example
5886
		 *    $(document).ready(function() {
5887
		 *      var oTable = $('#example').dataTable();
5888
		 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
5889
		 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
5890
		 *    } );
5891
		 */
5892
		this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
5893
		{
5894
			var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
5895
			var iVisibleColumn, i, iLen, sDisplay;
5896
			var iRow = (typeof mRow === 'object') ? 
5897
				_fnNodeToDataIndex(oSettings, mRow) : mRow;
5898
 
5899
			if ( oSettings.__fnUpdateDeep === undefined && $.isArray(mData) && typeof mData === 'object' )
5900
			{
5901
				/* Array update - update the whole row */
5902
				oSettings.aoData[iRow]._aData = mData.slice();
5903
 
5904
				/* Flag to the function that we are recursing */
5905
				oSettings.__fnUpdateDeep = true;
5906
				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
5907
				{
5908
					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
5909
				}
5910
				oSettings.__fnUpdateDeep = undefined;
5911
			}
5912
			else if ( oSettings.__fnUpdateDeep === undefined && mData !== null && typeof mData === 'object' )
5913
			{
5914
				/* Object update - update the whole row - assume the developer gets the object right */
5915
				oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
5916
 
5917
				oSettings.__fnUpdateDeep = true;
5918
				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
5919
				{
5920
					this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
5921
				}
5922
				oSettings.__fnUpdateDeep = undefined;
5923
			}
5924
			else
5925
			{
5926
				/* Individual cell update */
5927
				_fnSetCellData( oSettings, iRow, iColumn, mData );
5928
				sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
5929
 
5930
				var oCol = oSettings.aoColumns[iColumn];
5931
				if ( oCol.fnRender !== null )
5932
				{
5933
					sDisplay = _fnRender( oSettings, iRow, iColumn );
5934
					if ( oCol.bUseRendered )
5935
					{
5936
						_fnSetCellData( oSettings, iRow, iColumn, sDisplay );
5937
					}
5938
				}
5939
 
5940
				if ( oSettings.aoData[iRow].nTr !== null )
5941
				{
5942
					/* Do the actual HTML update */
5943
					_fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
5944
				}
5945
			}
5946
 
5947
			/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
5948
			 * will rebuild the search array - however, the redraw might be disabled by the user)
5949
			 */
5950
			var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
5951
			oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( oSettings, 
5952
				_fnGetRowData( oSettings, iRow, 'filter' ) );
5953
 
5954
			/* Perform pre-draw actions */
5955
			if ( bAction === undefined || bAction )
5956
			{
5957
				_fnAdjustColumnSizing( oSettings );
5958
			}
5959
 
5960
			/* Redraw the table */
5961
			if ( bRedraw === undefined || bRedraw )
5962
			{
5963
				_fnReDraw( oSettings );
5964
			}
5965
			return 0;
5966
		};
5967
 
5968
 
5969
		/**
5970
		 * Provide a common method for plug-ins to check the version of DataTables being used, in order
5971
		 * to ensure compatibility.
5972
		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
5973
		 *    formats "X" and "X.Y" are also acceptable.
5974
		 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
5975
		 *    version, or false if this version of DataTales is not suitable
5976
		 *  @method
5977
		 *  @dtopt API
5978
		 *
5979
		 *  @example
5980
		 *    $(document).ready(function() {
5981
		 *      var oTable = $('#example').dataTable();
5982
		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
5983
		 *    } );
5984
		 */
5985
		this.fnVersionCheck = DataTable.ext.fnVersionCheck;
5986
 
5987
 
5988
		/*
5989
		 * This is really a good bit rubbish this method of exposing the internal methods
5990
		 * publically... - To be fixed in 2.0 using methods on the prototype
5991
		 */
5992
 
5993
 
5994
		/**
5995
		 * Create a wrapper function for exporting an internal functions to an external API.
5996
		 *  @param {string} sFunc API function name
5997
		 *  @returns {function} wrapped function
5998
		 *  @memberof DataTable#oApi
5999
		 */
6000
		function _fnExternApiFunc (sFunc)
6001
		{
6002
			return function() {
6003
				var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat( 
6004
					Array.prototype.slice.call(arguments) );
6005
				return DataTable.ext.oApi[sFunc].apply( this, aArgs );
6006
			};
6007
		}
6008
 
6009
 
6010
		/**
6011
		 * Reference to internal functions for use by plug-in developers. Note that these
6012
		 * methods are references to internal functions and are considered to be private.
6013
		 * If you use these methods, be aware that they are liable to change between versions
6014
		 * (check the upgrade notes).
6015
		 *  @namespace
6016
		 */
6017
		this.oApi = {
6018
			"_fnExternApiFunc": _fnExternApiFunc,
6019
			"_fnInitialise": _fnInitialise,
6020
			"_fnInitComplete": _fnInitComplete,
6021
			"_fnLanguageCompat": _fnLanguageCompat,
6022
			"_fnAddColumn": _fnAddColumn,
6023
			"_fnColumnOptions": _fnColumnOptions,
6024
			"_fnAddData": _fnAddData,
6025
			"_fnCreateTr": _fnCreateTr,
6026
			"_fnGatherData": _fnGatherData,
6027
			"_fnBuildHead": _fnBuildHead,
6028
			"_fnDrawHead": _fnDrawHead,
6029
			"_fnDraw": _fnDraw,
6030
			"_fnReDraw": _fnReDraw,
6031
			"_fnAjaxUpdate": _fnAjaxUpdate,
6032
			"_fnAjaxParameters": _fnAjaxParameters,
6033
			"_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
6034
			"_fnServerParams": _fnServerParams,
6035
			"_fnAddOptionsHtml": _fnAddOptionsHtml,
6036
			"_fnFeatureHtmlTable": _fnFeatureHtmlTable,
6037
			"_fnScrollDraw": _fnScrollDraw,
6038
			"_fnAdjustColumnSizing": _fnAdjustColumnSizing,
6039
			"_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
6040
			"_fnFilterComplete": _fnFilterComplete,
6041
			"_fnFilterCustom": _fnFilterCustom,
6042
			"_fnFilterColumn": _fnFilterColumn,
6043
			"_fnFilter": _fnFilter,
6044
			"_fnBuildSearchArray": _fnBuildSearchArray,
6045
			"_fnBuildSearchRow": _fnBuildSearchRow,
6046
			"_fnFilterCreateSearch": _fnFilterCreateSearch,
6047
			"_fnDataToSearch": _fnDataToSearch,
6048
			"_fnSort": _fnSort,
6049
			"_fnSortAttachListener": _fnSortAttachListener,
6050
			"_fnSortingClasses": _fnSortingClasses,
6051
			"_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
6052
			"_fnPageChange": _fnPageChange,
6053
			"_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
6054
			"_fnUpdateInfo": _fnUpdateInfo,
6055
			"_fnFeatureHtmlLength": _fnFeatureHtmlLength,
6056
			"_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
6057
			"_fnProcessingDisplay": _fnProcessingDisplay,
6058
			"_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
6059
			"_fnColumnIndexToVisible": _fnColumnIndexToVisible,
6060
			"_fnNodeToDataIndex": _fnNodeToDataIndex,
6061
			"_fnVisbleColumns": _fnVisbleColumns,
6062
			"_fnCalculateEnd": _fnCalculateEnd,
6063
			"_fnConvertToWidth": _fnConvertToWidth,
6064
			"_fnCalculateColumnWidths": _fnCalculateColumnWidths,
6065
			"_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
6066
			"_fnGetWidestNode": _fnGetWidestNode,
6067
			"_fnGetMaxLenString": _fnGetMaxLenString,
6068
			"_fnStringToCss": _fnStringToCss,
6069
			"_fnDetectType": _fnDetectType,
6070
			"_fnSettingsFromNode": _fnSettingsFromNode,
6071
			"_fnGetDataMaster": _fnGetDataMaster,
6072
			"_fnGetTrNodes": _fnGetTrNodes,
6073
			"_fnGetTdNodes": _fnGetTdNodes,
6074
			"_fnEscapeRegex": _fnEscapeRegex,
6075
			"_fnDeleteIndex": _fnDeleteIndex,
6076
			"_fnReOrderIndex": _fnReOrderIndex,
6077
			"_fnColumnOrdering": _fnColumnOrdering,
6078
			"_fnLog": _fnLog,
6079
			"_fnClearTable": _fnClearTable,
6080
			"_fnSaveState": _fnSaveState,
6081
			"_fnLoadState": _fnLoadState,
6082
			"_fnCreateCookie": _fnCreateCookie,
6083
			"_fnReadCookie": _fnReadCookie,
6084
			"_fnDetectHeader": _fnDetectHeader,
6085
			"_fnGetUniqueThs": _fnGetUniqueThs,
6086
			"_fnScrollBarWidth": _fnScrollBarWidth,
6087
			"_fnApplyToChildren": _fnApplyToChildren,
6088
			"_fnMap": _fnMap,
6089
			"_fnGetRowData": _fnGetRowData,
6090
			"_fnGetCellData": _fnGetCellData,
6091
			"_fnSetCellData": _fnSetCellData,
6092
			"_fnGetObjectDataFn": _fnGetObjectDataFn,
6093
			"_fnSetObjectDataFn": _fnSetObjectDataFn,
6094
			"_fnApplyColumnDefs": _fnApplyColumnDefs,
6095
			"_fnBindAction": _fnBindAction,
6096
			"_fnExtend": _fnExtend,
6097
			"_fnCallbackReg": _fnCallbackReg,
6098
			"_fnCallbackFire": _fnCallbackFire,
6099
			"_fnJsonString": _fnJsonString,
6100
			"_fnRender": _fnRender,
6101
			"_fnNodeToColumnIndex": _fnNodeToColumnIndex
6102
		};
6103
 
6104
		$.extend( DataTable.ext.oApi, this.oApi );
6105
 
6106
		for ( var sFunc in DataTable.ext.oApi )
6107
		{
6108
			if ( sFunc )
6109
			{
6110
				this[sFunc] = _fnExternApiFunc(sFunc);
6111
			}
6112
		}
6113
 
6114
 
6115
		var _that = this;
6116
		return this.each(function() {
6117
 
6118
			var i=0, iLen, j, jLen, k, kLen;
6119
			var sId = this.getAttribute( 'id' );
6120
			var bInitHandedOff = false;
6121
			var bUsePassedData = false;
6122
 
6123
 
6124
			/* Sanity check */
6125
			if ( this.nodeName.toLowerCase() != 'table' )
6126
			{
6127
				_fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
6128
					"table: "+this.nodeName );
6129
				return;
6130
			}
6131
 
6132
			/* Check to see if we are re-initialising a table */
6133
			for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
6134
			{
6135
				/* Base check on table node */
6136
				if ( DataTable.settings[i].nTable == this )
6137
				{
6138
					if ( oInit === undefined || oInit.bRetrieve )
6139
					{
6140
						return DataTable.settings[i].oInstance;
6141
					}
6142
					else if ( oInit.bDestroy )
6143
					{
6144
						DataTable.settings[i].oInstance.fnDestroy();
6145
						break;
6146
					}
6147
					else
6148
					{
6149
						_fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
6150
							"To retrieve the DataTables object for this table, pass no arguments or see "+
6151
							"the docs for bRetrieve and bDestroy" );
6152
						return;
6153
					}
6154
				}
6155
 
6156
				/* If the element we are initialising has the same ID as a table which was previously
6157
				 * initialised, but the table nodes don't match (from before) then we destroy the old
6158
				 * instance by simply deleting it. This is under the assumption that the table has been
6159
				 * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6160
				 */
6161
				if ( DataTable.settings[i].sTableId == this.id )
6162
				{
6163
					DataTable.settings.splice( i, 1 );
6164
					break;
6165
				}
6166
			}
6167
 
6168
			/* Ensure the table has an ID - required for accessibility */
6169
			if ( sId === null )
6170
			{
6171
				sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
6172
				this.id = sId;
6173
			}
6174
 
6175
			/* Create the settings object for this table and set some of the default parameters */
6176
			var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6177
				"nTable":        this,
6178
				"oApi":          _that.oApi,
6179
				"oInit":         oInit,
6180
				"sDestroyWidth": $(this).width(),
6181
				"sInstance":     sId,
6182
				"sTableId":      sId
6183
			} );
6184
			DataTable.settings.push( oSettings );
6185
 
6186
			// Need to add the instance after the instance after the settings object has been added
6187
			// to the settings array, so we can self reference the table instance if more than one
6188
			oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6189
 
6190
			/* Setting up the initialisation object */
6191
			if ( !oInit )
6192
			{
6193
				oInit = {};
6194
			}
6195
 
6196
			// Backwards compatibility, before we apply all the defaults
6197
			if ( oInit.oLanguage )
6198
			{
6199
				_fnLanguageCompat( oInit.oLanguage );
6200
			}
6201
 
6202
			oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
6203
 
6204
			// Map the initialisation options onto the settings object
6205
			_fnMap( oSettings.oFeatures, oInit, "bPaginate" );
6206
			_fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
6207
			_fnMap( oSettings.oFeatures, oInit, "bFilter" );
6208
			_fnMap( oSettings.oFeatures, oInit, "bSort" );
6209
			_fnMap( oSettings.oFeatures, oInit, "bInfo" );
6210
			_fnMap( oSettings.oFeatures, oInit, "bProcessing" );
6211
			_fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
6212
			_fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
6213
			_fnMap( oSettings.oFeatures, oInit, "bServerSide" );
6214
			_fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
6215
			_fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
6216
			_fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
6217
			_fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
6218
			_fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
6219
			_fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
6220
			_fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
6221
			_fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
6222
			_fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
6223
			_fnMap( oSettings, oInit, "asStripeClasses" );
6224
			_fnMap( oSettings, oInit, "fnServerData" );
6225
			_fnMap( oSettings, oInit, "fnFormatNumber" );
6226
			_fnMap( oSettings, oInit, "sServerMethod" );
6227
			_fnMap( oSettings, oInit, "aaSorting" );
6228
			_fnMap( oSettings, oInit, "aaSortingFixed" );
6229
			_fnMap( oSettings, oInit, "aLengthMenu" );
6230
			_fnMap( oSettings, oInit, "sPaginationType" );
6231
			_fnMap( oSettings, oInit, "sAjaxSource" );
6232
			_fnMap( oSettings, oInit, "sAjaxDataProp" );
6233
			_fnMap( oSettings, oInit, "iCookieDuration" );
6234
			_fnMap( oSettings, oInit, "sCookiePrefix" );
6235
			_fnMap( oSettings, oInit, "sDom" );
6236
			_fnMap( oSettings, oInit, "bSortCellsTop" );
6237
			_fnMap( oSettings, oInit, "iTabIndex" );
6238
			_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
6239
			_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
6240
			_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
6241
			_fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
6242
			_fnMap( oSettings, oInit, "fnCookieCallback" );
6243
			_fnMap( oSettings, oInit, "fnStateLoad" );
6244
			_fnMap( oSettings, oInit, "fnStateSave" );
6245
			_fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6246
 
6247
			/* Callback functions which are array driven */
6248
			_fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
6249
			_fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
6250
			_fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
6251
			_fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
6252
			_fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
6253
			_fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
6254
			_fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
6255
			_fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
6256
			_fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
6257
			_fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
6258
			_fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
6259
 
6260
			if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
6261
				   oSettings.oFeatures.bSortClasses )
6262
			{
6263
				/* Enable sort classes for server-side processing. Safe to do it here, since server-side
6264
				 * processing must be enabled by the developer
6265
				 */
6266
				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
6267
			}
6268
			else if ( oSettings.oFeatures.bDeferRender )
6269
			{
6270
				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
6271
			}
6272
 
6273
			if ( oInit.bJQueryUI )
6274
			{
6275
				/* Use the JUI classes object for display. You could clone the oStdClasses object if 
6276
				 * you want to have multiple tables with multiple independent classes 
6277
				 */
6278
				$.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
6279
 
6280
				if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
6281
				{
6282
					/* Set the DOM to use a layout suitable for jQuery UI's theming */
6283
					oSettings.sDom = '<"H"lfr>t<"F"ip>';
6284
				}
6285
			}
6286
			else
6287
			{
6288
				$.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
6289
			}
6290
			$(this).addClass( oSettings.oClasses.sTable );
6291
 
6292
			/* Calculate the scroll bar width and cache it for use later on */
6293
			if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6294
			{
6295
				oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6296
			}
6297
 
6298
			if ( oSettings.iInitDisplayStart === undefined )
6299
			{
6300
				/* Display start point, taking into account the save saving */
6301
				oSettings.iInitDisplayStart = oInit.iDisplayStart;
6302
				oSettings._iDisplayStart = oInit.iDisplayStart;
6303
			}
6304
 
6305
			/* Must be done after everything which can be overridden by a cookie! */
6306
			if ( oInit.bStateSave )
6307
			{
6308
				oSettings.oFeatures.bStateSave = true;
6309
				_fnLoadState( oSettings, oInit );
6310
				_fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6311
			}
6312
 
6313
			if ( oInit.iDeferLoading !== null )
6314
			{
6315
				oSettings.bDeferLoading = true;
6316
				oSettings._iRecordsTotal = oInit.iDeferLoading;
6317
				oSettings._iRecordsDisplay = oInit.iDeferLoading;
6318
			}
6319
 
6320
			if ( oInit.aaData !== null )
6321
			{
6322
				bUsePassedData = true;
6323
			}
6324
 
6325
			/* Language definitions */
6326
			if ( oInit.oLanguage.sUrl !== "" )
6327
			{
6328
				/* Get the language definitions from a file - because this Ajax call makes the language
6329
				 * get async to the remainder of this function we use bInitHandedOff to indicate that 
6330
				 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6331
				 */
6332
				oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
6333
				$.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
6334
					_fnLanguageCompat( json );
6335
					$.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
6336
					_fnInitialise( oSettings );
6337
				} );
6338
				bInitHandedOff = true;
6339
			}
6340
			else
6341
			{
6342
				$.extend( true, oSettings.oLanguage, oInit.oLanguage );
6343
			}
6344
 
6345
 
6346
			/*
6347
			 * Stripes
6348
			 */
6349
 
6350
			/* Remove row stripe classes if they are already on the table row */
6351
			var bStripeRemove = false;
6352
			var anRows = $(this).children('tbody').children('tr');
6353
			for ( i=0, iLen=oSettings.asStripeClasses.length ; i<iLen ; i++ )
6354
			{
6355
				if ( anRows.filter(":lt(2)").hasClass( oSettings.asStripeClasses[i]) )
6356
				{
6357
					bStripeRemove = true;
6358
					break;
6359
				}
6360
			}
6361
 
6362
			if ( bStripeRemove )
6363
			{
6364
				/* Store the classes which we are about to remove so they can be readded on destroy */
6365
				oSettings.asDestroyStripes = [ '', '' ];
6366
				if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripeOdd) )
6367
				{
6368
					oSettings.asDestroyStripes[0] += oSettings.oClasses.sStripeOdd+" ";
6369
				}
6370
				if ( $(anRows[0]).hasClass(oSettings.oClasses.sStripeEven) )
6371
				{
6372
					oSettings.asDestroyStripes[0] += oSettings.oClasses.sStripeEven;
6373
				}
6374
				if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripeOdd) )
6375
				{
6376
					oSettings.asDestroyStripes[1] += oSettings.oClasses.sStripeOdd+" ";
6377
				}
6378
				if ( $(anRows[1]).hasClass(oSettings.oClasses.sStripeEven) )
6379
				{
6380
					oSettings.asDestroyStripes[1] += oSettings.oClasses.sStripeEven;
6381
				}
6382
 
6383
				anRows.removeClass( oSettings.asStripeClasses.join(' ') );
6384
			}
6385
 
6386
 
6387
			/*
6388
			 * Columns
6389
			 * See if we should load columns automatically or use defined ones
6390
			 */
6391
			var anThs = [];
6392
			var aoColumnsInit;
6393
			var nThead = this.getElementsByTagName('thead');
6394
			if ( nThead.length !== 0 )
6395
			{
6396
				_fnDetectHeader( oSettings.aoHeader, nThead[0] );
6397
				anThs = _fnGetUniqueThs( oSettings );
6398
			}
6399
 
6400
			/* If not given a column array, generate one with nulls */
6401
			if ( oInit.aoColumns === null )
6402
			{
6403
				aoColumnsInit = [];
6404
				for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6405
				{
6406
					aoColumnsInit.push( null );
6407
				}
6408
			}
6409
			else
6410
			{
6411
				aoColumnsInit = oInit.aoColumns;
6412
			}
6413
 
6414
			/* Add the columns */
6415
			for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6416
			{
6417
				/* Short cut - use the loop to check if we have column visibility state to restore */
6418
				if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
6419
				{
6420
					if ( aoColumnsInit[i] === null )
6421
					{
6422
						aoColumnsInit[i] = {};
6423
					}
6424
					aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
6425
				}
6426
 
6427
				_fnAddColumn( oSettings, anThs ? anThs[i] : null );
6428
			}
6429
 
6430
			/* Apply the column definitions */
6431
			_fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6432
				_fnColumnOptions( oSettings, iCol, oDef );
6433
			} );
6434
 
6435
 
6436
			/*
6437
			 * Sorting
6438
			 * Check the aaSorting array
6439
			 */
6440
			for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
6441
			{
6442
				if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
6443
				{
6444
					oSettings.aaSorting[i][0] = 0;
6445
				}
6446
				var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
6447
 
6448
				/* Add a default sorting index */
6449
				if ( oSettings.aaSorting[i][2] === undefined )
6450
				{
6451
					oSettings.aaSorting[i][2] = 0;
6452
				}
6453
 
6454
				/* If aaSorting is not defined, then we use the first indicator in asSorting */
6455
				if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
6456
				{
6457
					oSettings.aaSorting[i][1] = oColumn.asSorting[0];
6458
				}
6459
 
6460
				/* Set the current sorting index based on aoColumns.asSorting */
6461
				for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
6462
				{
6463
					if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
6464
					{
6465
						oSettings.aaSorting[i][2] = j;
6466
						break;
6467
					}
6468
				}
6469
			}
6470
 
6471
			/* Do a first pass on the sorting classes (allows any size changes to be taken into
6472
			 * account, and also will apply sorting disabled classes if disabled
6473
			 */
6474
			_fnSortingClasses( oSettings );
6475
 
6476
 
6477
			/*
6478
			 * Final init
6479
			 * Cache the header, body and footer as required, creating them if needed
6480
			 */
6481
			var thead = $(this).children('thead');
6482
			if ( thead.length === 0 )
6483
			{
6484
				thead = [ document.createElement( 'thead' ) ];
6485
				this.appendChild( thead[0] );
6486
			}
6487
			oSettings.nTHead = thead[0];
6488
 
6489
			var tbody = $(this).children('tbody');
6490
			if ( tbody.length === 0 )
6491
			{
6492
				tbody = [ document.createElement( 'tbody' ) ];
6493
				this.appendChild( tbody[0] );
6494
			}
6495
			oSettings.nTBody = tbody[0];
6496
			oSettings.nTBody.setAttribute( "role", "alert" );
6497
			oSettings.nTBody.setAttribute( "aria-live", "polite" );
6498
			oSettings.nTBody.setAttribute( "aria-relevant", "all" );
6499
 
6500
			var tfoot = $(this).children('tfoot');
6501
			if ( tfoot.length > 0 )
6502
			{
6503
				oSettings.nTFoot = tfoot[0];
6504
				_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6505
			}
6506
 
6507
			/* Check if there is data passing into the constructor */
6508
			if ( bUsePassedData )
6509
			{
6510
				for ( i=0 ; i<oInit.aaData.length ; i++ )
6511
				{
6512
					_fnAddData( oSettings, oInit.aaData[ i ] );
6513
				}
6514
			}
6515
			else
6516
			{
6517
				/* Grab the data from the page */
6518
				_fnGatherData( oSettings );
6519
			}
6520
 
6521
			/* Copy the data index array */
6522
			oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6523
 
6524
			/* Initialisation complete - table can be drawn */
6525
			oSettings.bInitialised = true;
6526
 
6527
			/* Check if we need to initialise the table (it might not have been handed off to the
6528
			 * language processor)
6529
			 */
6530
			if ( bInitHandedOff === false )
6531
			{
6532
				_fnInitialise( oSettings );
6533
			}
6534
		} );
6535
	};
6536
 
6537
	/**
6538
	 * Version string for plug-ins to check compatibility. Allowed format is
6539
	 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
6540
	 * e are optional
6541
	 *  @member
6542
	 *  @type string
6543
	 *  @default Version number
6544
	 */
6545
	DataTable.version = "1.9.0";
6546
 
6547
	/**
6548
	 * Private data store, containing all of the settings objects that are created for the
6549
	 * tables on a given page.
6550
	 * 
6551
	 * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i> 
6552
	 * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
6553
	 *  @member
6554
	 *  @type array
6555
	 *  @default []
6556
	 *  @private
6557
	 */
6558
	DataTable.settings = [];
6559
 
6560
	/**
6561
	 * Object models container, for the various models that DataTables has available
6562
	 * to it. These models define the objects that are used to hold the active state 
6563
	 * and configuration of the table.
6564
	 *  @namespace
6565
	 */
6566
	DataTable.models = {};
6567
 
6568
 
6569
	/**
6570
	 * DataTables extension options and plug-ins. This namespace acts as a collection "area"
6571
	 * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
6572
	 * of the build in methods use this method to provide their own capabilities (sorting methods
6573
	 * for example).
6574
	 * 
6575
	 * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
6576
	 * and modified by plug-ins.
6577
	 *  @namespace
6578
	 */
6579
	DataTable.models.ext = {
6580
		/**
6581
		 * Plug-in filtering functions - this method of filtering is complimentary to the default
6582
		 * type based filtering, and a lot more comprehensive as it allows you complete control
6583
		 * over the filtering logic. Each element in this array is a function (parameters
6584
		 * described below) that is called for every row in the table, and your logic decides if
6585
		 * it should be included in the filtered data set or not.
6586
		 *   <ul>
6587
		 *     <li>
6588
		 *       Function input parameters:
6589
		 *       <ul>
6590
		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6591
		 *         <li>{array|object} Data for the row to be processed (same as the original format
6592
		 *           that was passed in as the data source, or an array from a DOM data source</li>
6593
		 *         <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
6594
		 *           be useful to retrieve the TR element if you need DOM interaction.</li>
6595
		 *       </ul>
6596
		 *     </li>
6597
		 *     <li>
6598
		 *       Function return:
6599
		 *       <ul>
6600
		 *         <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
6601
		 *       </ul>
6602
		 *     </il>
6603
		 *   </ul>
6604
		 *  @type array
6605
		 *  @default []
6606
		 *
6607
		 *  @example
6608
		 *    // The following example shows custom filtering being applied to the fourth column (i.e.
6609
		 *    // the aData[3] index) based on two input values from the end-user, matching the data in 
6610
		 *    // a certain range.
6611
		 *    $.fn.dataTableExt.afnFiltering.push(
6612
		 *      function( oSettings, aData, iDataIndex ) {
6613
		 *        var iMin = document.getElementById('min').value * 1;
6614
		 *        var iMax = document.getElementById('max').value * 1;
6615
		 *        var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
6616
		 *        if ( iMin == "" && iMax == "" ) {
6617
		 *          return true;
6618
		 *        }
6619
		 *        else if ( iMin == "" && iVersion < iMax ) {
6620
		 *          return true;
6621
		 *        }
6622
		 *        else if ( iMin < iVersion && "" == iMax ) {
6623
		 *          return true;
6624
		 *        }
6625
		 *        else if ( iMin < iVersion && iVersion < iMax ) {
6626
		 *          return true;
6627
		 *        }
6628
		 *        return false;
6629
		 *      }
6630
		 *    );
6631
		 */
6632
		"afnFiltering": [],
6633
 
6634
 
6635
		/**
6636
		 * Plug-in sorting functions - this method of sorting is complimentary to the default type
6637
		 * based sorting that DataTables does automatically, allowing much greater control over the
6638
		 * the data that is being used to sort a column. This is useful if you want to do sorting
6639
		 * based on live data (for example the contents of an 'input' element) rather than just the
6640
		 * static string that DataTables knows of. The way these plug-ins work is that you create
6641
		 * an array of the values you wish to be sorted for the column in question and then return
6642
		 * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
6643
		 * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort 
6644
		 * data.
6645
		 *   <ul>
6646
	     *     <li>
6647
	     *       Function input parameters:
6648
	     *       <ul>
6649
		 *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6650
	     *         <li>{int} Target column index</li>
6651
	     *       </ul>
6652
	     *     </li>
6653
		 *     <li>
6654
		 *       Function return:
6655
		 *       <ul>
6656
		 *         <li>{array} Data for the column to be sorted upon</li>
6657
		 *       </ul>
6658
		 *     </il>
6659
		 *   </ul>
6660
		 *  
6661
		 * Note that as of v1.9, it is typically preferable to use <i>mDataProp</i> to prepare data for
6662
		 * the different uses that DataTables can put the data to. Specifically <i>mDataProp</i> when
6663
		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
6664
		 * prepare the data as required for the different types. As such, this method is deprecated.
6665
		 *  @type array
6666
		 *  @default []
6667
		 *  @deprecated
6668
		 *
6669
		 *  @example
6670
		 *    // Updating the cached sorting information with user entered values in HTML input elements
6671
		 *    jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
6672
		 *    {
6673
		 *      var aData = [];
6674
		 *      $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
6675
		 *        aData.push( this.value );
6676
		 *      } );
6677
		 *      return aData;
6678
		 *    }
6679
		 */
6680
		"afnSortData": [],
6681
 
6682
 
6683
		/**
6684
		 * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
6685
		 * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
6686
		 * option. As such, each feature plug-in must describe a function that is used to initialise
6687
		 * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
6688
		 * of the feature (sFeature). Thus the objects attached to this method must provide:
6689
		 *   <ul>
6690
		 *     <li>{function} fnInit Initialisation of the plug-in
6691
		 *       <ul>
6692
	     *         <li>
6693
	     *           Function input parameters:
6694
	     *           <ul>
6695
		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6696
	     *           </ul>
6697
	     *         </li>
6698
		 *         <li>
6699
		 *           Function return:
6700
		 *           <ul>
6701
		 *             <li>{node|null} The element which contains your feature. Note that the return
6702
		 *                may also be void if your plug-in does not require to inject any DOM elements 
6703
		 *                into DataTables control (sDom) - for example this might be useful when 
6704
		 *                developing a plug-in which allows table control via keyboard entry.</li>
6705
		 *           </ul>
6706
		 *         </il>
6707
		 *       </ul>
6708
		 *     </li>
6709
		 *     <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
6710
		 *     <li>{string} sFeature Feature name</li>
6711
		 *   </ul>
6712
		 *  @type array
6713
		 *  @default []
6714
		 * 
6715
		 *  @example
6716
		 *    // How TableTools initialises itself.
6717
		 *    $.fn.dataTableExt.aoFeatures.push( {
6718
		 *      "fnInit": function( oSettings ) {
6719
		 *        return new TableTools( { "oDTSettings": oSettings } );
6720
		 *      },
6721
		 *      "cFeature": "T",
6722
		 *      "sFeature": "TableTools"
6723
		 *    } );
6724
		 */
6725
		"aoFeatures": [],
6726
 
6727
 
6728
		/**
6729
		 * Type detection plug-in functions - DataTables utilises types to define how sorting and
6730
		 * filtering behave, and types can be either  be defined by the developer (sType for the
6731
		 * column) or they can be automatically detected by the methods in this array. The functions
6732
		 * defined in the array are quite simple, taking a single parameter (the data to analyse) 
6733
		 * and returning the type if it is a known type, or null otherwise.
6734
		 *   <ul>
6735
	     *     <li>
6736
	     *       Function input parameters:
6737
	     *       <ul>
6738
		 *         <li>{*} Data from the column cell to be analysed</li>
6739
	     *       </ul>
6740
	     *     </li>
6741
		 *     <li>
6742
		 *       Function return:
6743
		 *       <ul>
6744
		 *         <li>{string|null} Data type detected, or null if unknown (and thus pass it
6745
		 *           on to the other type detection functions.</li>
6746
		 *       </ul>
6747
		 *     </il>
6748
		 *   </ul>
6749
		 *  @type array
6750
		 *  @default []
6751
		 *  
6752
		 *  @example
6753
		 *    // Currency type detection plug-in:
6754
		 *    jQuery.fn.dataTableExt.aTypes.push(
6755
		 *      function ( sData ) {
6756
		 *        var sValidChars = "0123456789.-";
6757
		 *        var Char;
6758
		 *        
6759
		 *        // Check the numeric part
6760
		 *        for ( i=1 ; i<sData.length ; i++ ) {
6761
		 *          Char = sData.charAt(i); 
6762
		 *          if (sValidChars.indexOf(Char) == -1) {
6763
		 *            return null;
6764
		 *          }
6765
		 *        }
6766
		 *        
6767
		 *        // Check prefixed by currency
6768
		 *        if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {
6769
		 *          return 'currency';
6770
		 *        }
6771
		 *        return null;
6772
		 *      }
6773
		 *    );
6774
		 */
6775
		"aTypes": [],
6776
 
6777
 
6778
		/**
6779
		 * Provide a common method for plug-ins to check the version of DataTables being used, 
6780
		 * in order to ensure compatibility.
6781
		 *  @type function
6782
		 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note 
6783
		 *    that the formats "X" and "X.Y" are also acceptable.
6784
		 *  @returns {boolean} true if this version of DataTables is greater or equal to the 
6785
		 *    required version, or false if this version of DataTales is not suitable
6786
		 *
6787
		 *  @example
6788
		 *    $(document).ready(function() {
6789
		 *      var oTable = $('#example').dataTable();
6790
		 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
6791
		 *    } );
6792
		 */
6793
		"fnVersionCheck": function( sVersion )
6794
		{
6795
			/* This is cheap, but very effective */
6796
			var fnZPad = function (Zpad, count)
6797
			{
6798
				while(Zpad.length < count) {
6799
					Zpad += '0';
6800
				}
6801
				return Zpad;
6802
			};
6803
			var aThis = DataTable.ext.sVersion.split('.');
6804
			var aThat = sVersion.split('.');
6805
			var sThis = '', sThat = '';
6806
 
6807
			for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
6808
			{
6809
				sThis += fnZPad( aThis[i], 3 );
6810
				sThat += fnZPad( aThat[i], 3 );
6811
			}
6812
 
6813
			return parseInt(sThis, 10) >= parseInt(sThat, 10);
6814
		},
6815
 
6816
 
6817
		/**
6818
		 * Index for what 'this' index API functions should use
6819
		 *  @type int
6820
		 *  @default 0
6821
		 */
6822
		"iApiIndex": 0,
6823
 
6824
 
6825
		/**
6826
		 * Pre-processing of filtering data plug-ins - When you assign the sType for a column
6827
		 * (or have it automatically detected for you by DataTables or a type detection plug-in), 
6828
		 * you will typically be using this for custom sorting, but it can also be used to provide 
6829
		 * custom filtering by allowing you to pre-processing the data and returning the data in
6830
		 * the format that should be filtered upon. This is done by adding functions this object 
6831
		 * with a parameter name which matches the sType for that target column. This is the
6832
		 * corollary of <i>afnSortData</i> for filtering data.
6833
		 *   <ul>
6834
	     *     <li>
6835
	     *       Function input parameters:
6836
	     *       <ul>
6837
		 *         <li>{*} Data from the column cell to be prepared for filtering</li>
6838
	     *       </ul>
6839
	     *     </li>
6840
		 *     <li>
6841
		 *       Function return:
6842
		 *       <ul>
6843
		 *         <li>{string|null} Formatted string that will be used for the filtering.</li>
6844
		 *       </ul>
6845
		 *     </il>
6846
		 *   </ul>
6847
		 * 
6848
		 * Note that as of v1.9, it is typically preferable to use <i>mDataProp</i> to prepare data for
6849
		 * the different uses that DataTables can put the data to. Specifically <i>mDataProp</i> when
6850
		 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
6851
		 * prepare the data as required for the different types. As such, this method is deprecated.
6852
		 *  @type object
6853
		 *  @default {}
6854
		 *  @deprecated
6855
		 *
6856
		 *  @example
6857
		 *    $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
6858
		 *      return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
6859
		 *    }
6860
		 */
6861
		"ofnSearch": {},
6862
 
6863
 
6864
		/**
6865
		 * Container for all private functions in DataTables so they can be exposed externally
6866
		 *  @type object
6867
		 *  @default {}
6868
		 */
6869
		"oApi": {},
6870
 
6871
 
6872
		/**
6873
		 * Storage for the various classes that DataTables uses
6874
		 *  @type object
6875
		 *  @default {}
6876
		 */
6877
		"oStdClasses": {},
6878
 
6879
 
6880
		/**
6881
		 * Storage for the various classes that DataTables uses - jQuery UI suitable
6882
		 *  @type object
6883
		 *  @default {}
6884
		 */
6885
		"oJUIClasses": {},
6886
 
6887
 
6888
		/**
6889
		 * Pagination plug-in methods - The style and controls of the pagination can significantly 
6890
		 * impact on how the end user interacts with the data in your table, and DataTables allows 
6891
		 * the addition of pagination controls by extending this object, which can then be enabled
6892
		 * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
6893
		 * is added is an object (the property name of which is what <i>sPaginationType</i> refers
6894
		 * to) that has two properties, both methods that are used by DataTables to update the
6895
		 * control's state.
6896
		 *   <ul>
6897
		 *     <li>
6898
		 *       fnInit -  Initialisation of the paging controls. Called only during initialisation 
6899
		 *         of the table. It is expected that this function will add the required DOM elements 
6900
		 *         to the page for the paging controls to work. The element pointer 
6901
		 *         'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging 
6902
		 *         controls (note that this is a 2D array to allow for multiple instances of each 
6903
		 *         DataTables DOM element). It is suggested that you add the controls to this element 
6904
		 *         as children
6905
		 *       <ul>
6906
	     *         <li>
6907
	     *           Function input parameters:
6908
	     *           <ul>
6909
		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6910
		 *             <li>{node} Container into which the pagination controls must be inserted</li>
6911
		 *             <li>{function} Draw callback function - whenever the controls cause a page
6912
		 *               change, this method must be called to redraw the table.</li>
6913
	     *           </ul>
6914
	     *         </li>
6915
		 *         <li>
6916
		 *           Function return:
6917
		 *           <ul>
6918
		 *             <li>No return required</li>
6919
		 *           </ul>
6920
		 *         </il>
6921
		 *       </ul>
6922
		 *     </il>
6923
		 *     <li>
6924
		 *       fnInit -  This function is called whenever the paging status of the table changes and is
6925
		 *         typically used to update classes and/or text of the paging controls to reflex the new 
6926
		 *         status.
6927
		 *       <ul>
6928
	     *         <li>
6929
	     *           Function input parameters:
6930
	     *           <ul>
6931
		 *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
6932
		 *             <li>{function} Draw callback function - in case you need to redraw the table again
6933
		 *               or attach new event listeners</li>
6934
	     *           </ul>
6935
	     *         </li>
6936
		 *         <li>
6937
		 *           Function return:
6938
		 *           <ul>
6939
		 *             <li>No return required</li>
6940
		 *           </ul>
6941
		 *         </il>
6942
		 *       </ul>
6943
		 *     </il>
6944
		 *   </ul>
6945
		 *  @type object
6946
		 *  @default {}
6947
		 *
6948
		 *  @example
6949
		 *    $.fn.dataTableExt.oPagination.four_button = {
6950
		 *      "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
6951
		 *        nFirst = document.createElement( 'span' );
6952
		 *        nPrevious = document.createElement( 'span' );
6953
		 *        nNext = document.createElement( 'span' );
6954
		 *        nLast = document.createElement( 'span' );
6955
		 *        
6956
		 *        nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
6957
		 *        nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
6958
		 *        nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
6959
		 *        nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
6960
		 *        
6961
		 *        nFirst.className = "paginate_button first";
6962
		 *        nPrevious.className = "paginate_button previous";
6963
		 *        nNext.className="paginate_button next";
6964
		 *        nLast.className = "paginate_button last";
6965
		 *        
6966
		 *        nPaging.appendChild( nFirst );
6967
		 *        nPaging.appendChild( nPrevious );
6968
		 *        nPaging.appendChild( nNext );
6969
		 *        nPaging.appendChild( nLast );
6970
		 *        
6971
		 *        $(nFirst).click( function () {
6972
		 *          oSettings.oApi._fnPageChange( oSettings, "first" );
6973
		 *          fnCallbackDraw( oSettings );
6974
		 *        } );
6975
		 *        
6976
		 *        $(nPrevious).click( function() {
6977
		 *          oSettings.oApi._fnPageChange( oSettings, "previous" );
6978
		 *          fnCallbackDraw( oSettings );
6979
		 *        } );
6980
		 *        
6981
		 *        $(nNext).click( function() {
6982
		 *          oSettings.oApi._fnPageChange( oSettings, "next" );
6983
		 *          fnCallbackDraw( oSettings );
6984
		 *        } );
6985
		 *        
6986
		 *        $(nLast).click( function() {
6987
		 *          oSettings.oApi._fnPageChange( oSettings, "last" );
6988
		 *          fnCallbackDraw( oSettings );
6989
		 *        } );
6990
		 *        
6991
		 *        $(nFirst).bind( 'selectstart', function () { return false; } );
6992
		 *        $(nPrevious).bind( 'selectstart', function () { return false; } );
6993
		 *        $(nNext).bind( 'selectstart', function () { return false; } );
6994
		 *        $(nLast).bind( 'selectstart', function () { return false; } );
6995
		 *      },
6996
		 *      
6997
		 *      "fnUpdate": function ( oSettings, fnCallbackDraw ) {
6998
		 *        if ( !oSettings.aanFeatures.p ) {
6999
		 *          return;
7000
		 *        }
7001
		 *        
7002
		 *        // Loop over each instance of the pager
7003
		 *        var an = oSettings.aanFeatures.p;
7004
		 *        for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
7005
		 *          var buttons = an[i].getElementsByTagName('span');
7006
		 *          if ( oSettings._iDisplayStart === 0 ) {
7007
		 *            buttons[0].className = "paginate_disabled_previous";
7008
		 *            buttons[1].className = "paginate_disabled_previous";
7009
		 *          }
7010
		 *          else {
7011
		 *            buttons[0].className = "paginate_enabled_previous";
7012
		 *            buttons[1].className = "paginate_enabled_previous";
7013
		 *          }
7014
		 *          
7015
		 *          if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
7016
		 *            buttons[2].className = "paginate_disabled_next";
7017
		 *            buttons[3].className = "paginate_disabled_next";
7018
		 *          }
7019
		 *          else {
7020
		 *            buttons[2].className = "paginate_enabled_next";
7021
		 *            buttons[3].className = "paginate_enabled_next";
7022
		 *          }
7023
		 *        }
7024
		 *      }
7025
		 *    };
7026
		 */
7027
		"oPagination": {},
7028
 
7029
 
7030
		/**
7031
		 * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
7032
		 * data column (you can add your own type detection functions, or override automatic 
7033
		 * detection using sType). With this specific type given to the column, DataTables will 
7034
		 * apply the required sort from the functions in the object. Each sort type must provide
7035
		 * two mandatory methods, one each for ascending and descending sorting, and can optionally
7036
		 * provide a pre-formatting method that will help speed up sorting by allowing DataTables
7037
		 * to pre-format the sort data only once (rather than every time the actual sort functions
7038
		 * are run). The two sorting functions are typical Javascript sort methods:
7039
		 *   <ul>
7040
	     *     <li>
7041
	     *       Function input parameters:
7042
	     *       <ul>
7043
		 *         <li>{*} Data to compare to the second parameter</li>
7044
		 *         <li>{*} Data to compare to the first parameter</li>
7045
	     *       </ul>
7046
	     *     </li>
7047
		 *     <li>
7048
		 *       Function return:
7049
		 *       <ul>
7050
		 *         <li>{int} Sorting match: <0 if first parameter should be sorted lower than
7051
		 *           the second parameter, ===0 if the two parameters are equal and >0 if
7052
		 *           the first parameter should be sorted height than the second parameter.</li>
7053
		 *       </ul>
7054
		 *     </il>
7055
		 *   </ul>
7056
		 *  @type object
7057
		 *  @default {}
7058
		 *
7059
		 *  @example
7060
		 *    // Case-sensitive string sorting, with no pre-formatting method
7061
		 *    $.extend( $.fn.dataTableExt.oSort, {
7062
		 *      "string-case-asc": function(x,y) {
7063
		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
7064
		 *      },
7065
		 *      "string-case-desc": function(x,y) {
7066
		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
7067
		 *      }
7068
		 *    } );
7069
		 *
7070
		 *  @example
7071
		 *    // Case-insensitive string sorting, with pre-formatting
7072
		 *    $.extend( $.fn.dataTableExt.oSort, {
7073
		 *      "string-pre": function(x) {
7074
		 *        return x.toLowerCase();
7075
		 *      },
7076
		 *      "string-asc": function(x,y) {
7077
		 *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
7078
		 *      },
7079
		 *      "string-desc": function(x,y) {
7080
		 *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
7081
		 *      }
7082
		 *    } );
7083
		 */
7084
		"oSort": {},
7085
 
7086
 
7087
		/**
7088
		 * Version string for plug-ins to check compatibility. Allowed format is
7089
		 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
7090
		 * e are optional
7091
		 *  @type string
7092
		 *  @default Version number
7093
		 */
7094
		"sVersion": DataTable.version,
7095
 
7096
 
7097
		/**
7098
		 * How should DataTables report an error. Can take the value 'alert' or 'throw'
7099
		 *  @type string
7100
		 *  @default alert
7101
		 */
7102
		"sErrMode": "alert",
7103
 
7104
 
7105
		/**
7106
		 * Store information for DataTables to access globally about other instances
7107
		 *  @namespace
7108
		 *  @private
7109
		 */
7110
		"_oExternConfig": {
7111
			/* int:iNextUnique - next unique number for an instance */
7112
			"iNextUnique": 0
7113
		}
7114
	};
7115
 
7116
 
7117
 
7118
 
7119
	/**
7120
	 * Template object for the way in which DataTables holds information about
7121
	 * search information for the global filter and individual column filters.
7122
	 *  @namespace
7123
	 */
7124
	DataTable.models.oSearch = {
7125
		/**
7126
		 * Flag to indicate if the filtering should be case insensitive or not
7127
		 *  @type boolean
7128
		 *  @default true
7129
		 */
7130
		"bCaseInsensitive": true,
7131
 
7132
		/**
7133
		 * Applied search term
7134
		 *  @type string
7135
		 *  @default <i>Empty string</i>
7136
		 */
7137
		"sSearch": "",
7138
 
7139
		/**
7140
		 * Flag to indicate if the search term should be interpreted as a
7141
		 * regular expression (true) or not (false) and therefore and special
7142
		 * regex characters escaped.
7143
		 *  @type boolean
7144
		 *  @default false
7145
		 */
7146
		"bRegex": false,
7147
 
7148
		/**
7149
		 * Flag to indicate if DataTables is to use its smart filtering or not.
7150
		 *  @type boolean
7151
		 *  @default true
7152
		 */
7153
		"bSmart": true
7154
	};
7155
 
7156
 
7157
 
7158
 
7159
	/**
7160
	 * Template object for the way in which DataTables holds information about
7161
	 * each individual row. This is the object format used for the settings 
7162
	 * aoData array.
7163
	 *  @namespace
7164
	 */
7165
	DataTable.models.oRow = {
7166
		/**
7167
		 * TR element for the row
7168
		 *  @type node
7169
		 *  @default null
7170
		 */
7171
		"nTr": null,
7172
 
7173
		/**
7174
		 * Data object from the original data source for the row. This is either
7175
		 * an array if using the traditional form of DataTables, or an object if
7176
		 * using mDataProp options. The exact type will depend on the passed in
7177
		 * data from the data source, or will be an array if using DOM a data 
7178
		 * source.
7179
		 *  @type array|object
7180
		 *  @default []
7181
		 */
7182
		"_aData": [],
7183
 
7184
		/**
7185
		 * Sorting data cache - this array is ostensibly the same length as the
7186
		 * number of columns (although each index is generated only as it is 
7187
		 * needed), and holds the data that is used for sorting each column in the
7188
		 * row. We do this cache generation at the start of the sort in order that
7189
		 * the formatting of the sort data need be done only once for each cell
7190
		 * per sort. This array should not be read from or written to by anything
7191
		 * other than the master sorting methods.
7192
		 *  @type array
7193
		 *  @default []
7194
		 *  @private
7195
		 */
7196
		"_aSortData": [],
7197
 
7198
		/**
7199
		 * Array of TD elements that are cached for hidden rows, so they can be
7200
		 * reinserted into the table if a column is made visible again (or to act
7201
		 * as a store if a column is made hidden). Only hidden columns have a 
7202
		 * reference in the array. For non-hidden columns the value is either
7203
		 * undefined or null.
7204
		 *  @type array nodes
7205
		 *  @default []
7206
		 *  @private
7207
		 */
7208
		"_anHidden": [],
7209
 
7210
		/**
7211
		 * Cache of the class name that DataTables has applied to the row, so we
7212
		 * can quickly look at this variable rather than needing to do a DOM check
7213
		 * on className for the nTr property.
7214
		 *  @type string
7215
		 *  @default <i>Empty string</i>
7216
		 *  @private
7217
		 */
7218
		"_sRowStripe": ""
7219
	};
7220
 
7221
 
7222
 
7223
	/**
7224
	 * Template object for the column information object in DataTables. This object
7225
	 * is held in the settings aoColumns array and contains all the information that
7226
	 * DataTables needs about each individual column.
7227
	 * 
7228
	 * Note that this object is related to {@link DataTable.defaults.columns} 
7229
	 * but this one is the internal data store for DataTables's cache of columns.
7230
	 * It should NOT be manipulated outside of DataTables. Any configuration should
7231
	 * be done through the initialisation options.
7232
	 *  @namespace
7233
	 */
7234
	DataTable.models.oColumn = {
7235
		/**
7236
		 * A list of the columns that sorting should occur on when this column
7237
		 * is sorted. That this property is an array allows multi-column sorting
7238
		 * to be defined for a column (for example first name / last name columns
7239
		 * would benefit from this). The values are integers pointing to the
7240
		 * columns to be sorted on (typically it will be a single integer pointing
7241
		 * at itself, but that doesn't need to be the case).
7242
		 *  @type array
7243
		 */
7244
		"aDataSort": null,
7245
 
7246
		/**
7247
		 * Define the sorting directions that are applied to the column, in sequence
7248
		 * as the column is repeatedly sorted upon - i.e. the first value is used
7249
		 * as the sorting direction when the column if first sorted (clicked on).
7250
		 * Sort it again (click again) and it will move on to the next index.
7251
		 * Repeat until loop.
7252
		 *  @type array
7253
		 */
7254
		"asSorting": null,
7255
 
7256
		/**
7257
		 * Flag to indicate if the column is searchable, and thus should be included
7258
		 * in the filtering or not.
7259
		 *  @type boolean
7260
		 */
7261
		"bSearchable": null,
7262
 
7263
		/**
7264
		 * Flag to indicate if the column is sortable or not.
7265
		 *  @type boolean
7266
		 */
7267
		"bSortable": null,
7268
 
7269
		/**
7270
		 * When using fnRender, you have two options for what to do with the data,
7271
		 * and this property serves as the switch. Firstly, you can have the sorting
7272
		 * and filtering use the rendered value (true - default), or you can have
7273
		 * the sorting and filtering us the original value (false).
7274
		 * 
7275
		 * *NOTE* It is it is advisable now to use mDataProp as a function and make 
7276
		 * use of the 'type' that it gives, allowing (potentially) different data to
7277
		 * be used for sorting, filtering, display and type detection.
7278
		 *  @type boolean
7279
		 *  @deprecated
7280
		 */
7281
		"bUseRendered": null,
7282
 
7283
		/**
7284
		 * Flag to indicate if the column is currently visible in the table or not
7285
		 *  @type boolean
7286
		 */
7287
		"bVisible": null,
7288
 
7289
		/**
7290
		 * Flag to indicate to the type detection method if the automatic type
7291
		 * detection should be used, or if a column type (sType) has been specified
7292
		 *  @type boolean
7293
		 *  @default true
7294
		 *  @private
7295
		 */
7296
		"_bAutoType": true,
7297
 
7298
		/**
7299
		 * Developer definable function that is called whenever a cell is created (Ajax source,
7300
		 * etc) or processed for input (DOM source). This can be used as a compliment to fnRender
7301
		 * allowing you to modify the DOM element (add background colour for example) when the
7302
		 * element is available (since it is not when fnRender is called).
7303
		 *  @type function
7304
		 *  @param {element} nTd The TD node that has been created
7305
		 *  @param {*} sData The Data for the cell
7306
		 *  @param {array|object} oData The data for the whole row
7307
		 *  @param {int} iRow The row index for the aoData data store
7308
		 *  @default null
7309
		 */
7310
		"fnCreatedCell": null,
7311
 
7312
		/**
7313
		 * Function to get data from a cell in a column. You should <b>never</b>
7314
		 * access data directly through _aData internally in DataTables - always use
7315
		 * the method attached to this property. It allows mDataProp to function as
7316
		 * required. This function is automatically assigned by the column 
7317
		 * initialisation method
7318
		 *  @type function
7319
		 *  @param {array|object} oData The data array/object for the array 
7320
		 *    (i.e. aoData[]._aData)
7321
		 *  @param {string} sSpecific The specific data type you want to get - 
7322
		 *    'display', 'type' 'filter' 'sort'
7323
		 *  @returns {*} The data for the cell from the given row's data
7324
		 *  @default null
7325
		 */
7326
		"fnGetData": null,
7327
 
7328
		/**
7329
		 * Custom display function that will be called for the display of each cell 
7330
		 * in this column.
7331
		 *  @type function
7332
		 *  @param {object} o Object with the following parameters:
7333
		 *  @param {int}    o.iDataRow The row in aoData
7334
		 *  @param {int}    o.iDataColumn The column in question
7335
		 *  @param {array   o.aData The data for the row in question
7336
		 *  @param {object} o.oSettings The settings object for this DataTables instance
7337
		 *  @returns {string} The string you which to use in the display
7338
		 *  @default null
7339
		 */
7340
		"fnRender": null,
7341
 
7342
		/**
7343
		 * Function to set data for a cell in the column. You should <b>never</b> 
7344
		 * set the data directly to _aData internally in DataTables - always use
7345
		 * this method. It allows mDataProp to function as required. This function
7346
		 * is automatically assigned by the column initialisation method
7347
		 *  @type function
7348
		 *  @param {array|object} oData The data array/object for the array 
7349
		 *    (i.e. aoData[]._aData)
7350
		 *  @param {*} sValue Value to set
7351
		 *  @default null
7352
		 */
7353
		"fnSetData": null,
7354
 
7355
		/**
7356
		 * Property to read the value for the cells in the column from the data 
7357
		 * source array / object. If null, then the default content is used, if a
7358
		 * function is given then the return from the function is used.
7359
		 *  @type function|int|string|null
7360
		 *  @default null
7361
		 */
7362
		"mDataProp": null,
7363
 
7364
		/**
7365
		 * Unique header TH/TD element for this column - this is what the sorting
7366
		 * listener is attached to (if sorting is enabled.)
7367
		 *  @type node
7368
		 *  @default null
7369
		 */
7370
		"nTh": null,
7371
 
7372
		/**
7373
		 * Unique footer TH/TD element for this column (if there is one). Not used 
7374
		 * in DataTables as such, but can be used for plug-ins to reference the 
7375
		 * footer for each column.
7376
		 *  @type node
7377
		 *  @default null
7378
		 */
7379
		"nTf": null,
7380
 
7381
		/**
7382
		 * The class to apply to all TD elements in the table's TBODY for the column
7383
		 *  @type string
7384
		 *  @default null
7385
		 */
7386
		"sClass": null,
7387
 
7388
		/**
7389
		 * When DataTables calculates the column widths to assign to each column,
7390
		 * it finds the longest string in each column and then constructs a
7391
		 * temporary table and reads the widths from that. The problem with this
7392
		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
7393
		 * string - thus the calculation can go wrong (doing it properly and putting
7394
		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
7395
		 * a "work around" we provide this option. It will append its value to the
7396
		 * text that is found to be the longest string for the column - i.e. padding.
7397
		 *  @type string
7398
		 */
7399
		"sContentPadding": null,
7400
 
7401
		/**
7402
		 * Allows a default value to be given for a column's data, and will be used
7403
		 * whenever a null data source is encountered (this can be because mDataProp
7404
		 * is set to null, or because the data source itself is null).
7405
		 *  @type string
7406
		 *  @default null
7407
		 */
7408
		"sDefaultContent": null,
7409
 
7410
		/**
7411
		 * Name for the column, allowing reference to the column by name as well as
7412
		 * by index (needs a lookup to work by name).
7413
		 *  @type string
7414
		 */
7415
		"sName": null,
7416
 
7417
		/**
7418
		 * Custom sorting data type - defines which of the available plug-ins in
7419
		 * afnSortData the custom sorting will use - if any is defined.
7420
		 *  @type string
7421
		 *  @default std
7422
		 */
7423
		"sSortDataType": 'std',
7424
 
7425
		/**
7426
		 * Class to be applied to the header element when sorting on this column
7427
		 *  @type string
7428
		 *  @default null
7429
		 */
7430
		"sSortingClass": null,
7431
 
7432
		/**
7433
		 * Class to be applied to the header element when sorting on this column -
7434
		 * when jQuery UI theming is used.
7435
		 *  @type string
7436
		 *  @default null
7437
		 */
7438
		"sSortingClassJUI": null,
7439
 
7440
		/**
7441
		 * Title of the column - what is seen in the TH element (nTh).
7442
		 *  @type string
7443
		 */
7444
		"sTitle": null,
7445
 
7446
		/**
7447
		 * Column sorting and filtering type
7448
		 *  @type string
7449
		 *  @default null
7450
		 */
7451
		"sType": null,
7452
 
7453
		/**
7454
		 * Width of the column
7455
		 *  @type string
7456
		 *  @default null
7457
		 */
7458
		"sWidth": null,
7459
 
7460
		/**
7461
		 * Width of the column when it was first "encountered"
7462
		 *  @type string
7463
		 *  @default null
7464
		 */
7465
		"sWidthOrig": null
7466
	};
7467
 
7468
 
7469
 
7470
	/**
7471
	 * Initialisation options that can be given to DataTables at initialisation 
7472
	 * time.
7473
	 *  @namespace
7474
	 */
7475
	DataTable.defaults = {
7476
		/**
7477
		 * An array of data to use for the table, passed in at initialisation which 
7478
		 * will be used in preference to any data which is already in the DOM. This is
7479
		 * particularly useful for constructing tables purely in Javascript, for
7480
		 * example with a custom Ajax call.
7481
		 *  @type array
7482
		 *  @default null
7483
		 *  @dtopt Option
7484
		 * 
7485
		 *  @example
7486
		 *    // Using a 2D array data source
7487
		 *    $(document).ready( function () {
7488
		 *      $('#example').dataTable( {
7489
		 *        "aaData": [
7490
		 *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
7491
		 *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
7492
		 *        ],
7493
		 *        "aoColumns": [
7494
		 *          { "sTitle": "Engine" },
7495
		 *          { "sTitle": "Browser" },
7496
		 *          { "sTitle": "Platform" },
7497
		 *          { "sTitle": "Version" },
7498
		 *          { "sTitle": "Grade" }
7499
		 *        ]
7500
		 *      } );
7501
		 *    } );
7502
		 *    
7503
		 *  @example
7504
		 *    // Using an array of objects as a data source (mDataProp)
7505
		 *    $(document).ready( function () {
7506
		 *      $('#example').dataTable( {
7507
		 *        "aaData": [
7508
		 *          {
7509
		 *            "engine":   "Trident",
7510
		 *            "browser":  "Internet Explorer 4.0",
7511
		 *            "platform": "Win 95+",
7512
		 *            "version":  4,
7513
		 *            "grade":    "X"
7514
		 *          },
7515
		 *          {
7516
		 *            "engine":   "Trident",
7517
		 *            "browser":  "Internet Explorer 5.0",
7518
		 *            "platform": "Win 95+",
7519
		 *            "version":  5,
7520
		 *            "grade":    "C"
7521
		 *          }
7522
		 *        ],
7523
		 *        "aoColumns": [
7524
		 *          { "sTitle": "Engine",   "mDataProp": "engine" },
7525
		 *          { "sTitle": "Browser",  "mDataProp": "browser" },
7526
		 *          { "sTitle": "Platform", "mDataProp": "platform" },
7527
		 *          { "sTitle": "Version",  "mDataProp": "version" },
7528
		 *          { "sTitle": "Grade",    "mDataProp": "grade" }
7529
		 *        ]
7530
		 *      } );
7531
		 *    } );
7532
		 */
7533
		"aaData": null,
7534
 
7535
 
7536
		/**
7537
		 * If sorting is enabled, then DataTables will perform a first pass sort on 
7538
		 * initialisation. You can define which column(s) the sort is performed upon, 
7539
		 * and the sorting direction, with this variable. The aaSorting array should 
7540
		 * contain an array for each column to be sorted initially containing the 
7541
		 * column's index and a direction string ('asc' or 'desc').
7542
		 *  @type array
7543
		 *  @default [[0,'asc']]
7544
		 *  @dtopt Option
7545
		 * 
7546
		 *  @example
7547
		 *    // Sort by 3rd column first, and then 4th column
7548
		 *    $(document).ready( function() {
7549
		 *      $('#example').dataTable( {
7550
		 *        "aaSorting": [[2,'asc'], [3,'desc']]
7551
		 *      } );
7552
		 *    } );
7553
		 *    
7554
		 *    // No initial sorting
7555
		 *    $(document).ready( function() {
7556
		 *      $('#example').dataTable( {
7557
		 *        "aaSorting": []
7558
		 *      } );
7559
		 *    } );
7560
		 */
7561
		"aaSorting": [[0,'asc']],
7562
 
7563
 
7564
		/**
7565
		 * This parameter is basically identical to the aaSorting parameter, but 
7566
		 * cannot be overridden by user interaction with the table. What this means 
7567
		 * is that you could have a column (visible or hidden) which the sorting will 
7568
		 * always be forced on first - any sorting after that (from the user) will 
7569
		 * then be performed as required. This can be useful for grouping rows 
7570
		 * together.
7571
		 *  @type array
7572
		 *  @default null
7573
		 *  @dtopt Option
7574
		 * 
7575
		 *  @example
7576
		 *    $(document).ready( function() {
7577
		 *      $('#example').dataTable( {
7578
		 *        "aaSortingFixed": [[0,'asc']]
7579
		 *      } );
7580
		 *    } )
7581
		 */
7582
		"aaSortingFixed": null,
7583
 
7584
 
7585
		/**
7586
		 * This parameter allows you to readily specify the entries in the length drop
7587
		 * down menu that DataTables shows when pagination is enabled. It can be 
7588
		 * either a 1D array of options which will be used for both the displayed 
7589
		 * option and the value, or a 2D array which will use the array in the first 
7590
		 * position as the value, and the array in the second position as the 
7591
		 * displayed options (useful for language strings such as 'All').
7592
		 *  @type array
7593
		 *  @default [ 10, 25, 50, 100 ]
7594
		 *  @dtopt Option
7595
		 * 
7596
		 *  @example
7597
		 *    $(document).ready(function() {
7598
		 *      $('#example').dataTable( {
7599
		 *        "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
7600
		 *      } );
7601
		 *    } );
7602
		 *  
7603
		 *  @example
7604
		 *    // Setting the default display length as well as length menu
7605
		 *    // This is likely to be wanted if you remove the '10' option which
7606
		 *    // is the iDisplayLength default.
7607
		 *    $(document).ready(function() {
7608
		 *      $('#example').dataTable( {
7609
		 *        "iDisplayLength": 25,
7610
		 *        "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
7611
		 *      } );
7612
		 *    } );
7613
		 */
7614
		"aLengthMenu": [ 10, 25, 50, 100 ],
7615
 
7616
 
7617
		/**
7618
		 * The aoColumns option in the initialisation parameter allows you to define
7619
		 * details about the way individual columns behave. For a full list of
7620
		 * column options that can be set, please see 
7621
		 * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
7622
		 * define your columns, you must have an entry in the array for every single
7623
		 * column that you have in your table (these can be null if you don't which
7624
		 * to specify any options).
7625
		 *  @member
7626
		 */
7627
		"aoColumns": null,
7628
 
7629
		/**
7630
		 * Very similar to aoColumns, aoColumnDefs allows you to target a specific 
7631
		 * column, multiple columns, or all columns, using the aTargets property of 
7632
		 * each object in the array. This allows great flexibility when creating 
7633
		 * tables, as the aoColumnDefs arrays can be of any length, targeting the 
7634
		 * columns you specifically want. aoColumnDefs may use any of the column 
7635
		 * options available: {@link DataTable.defaults.columns}, but it _must_
7636
		 * have aTargets defined in each object in the array. Values in the aTargets
7637
		 * array may be:
7638
		 *   <ul>
7639
		 *     <li>a string - class name will be matched on the TH for the column</li>
7640
		 *     <li>0 or a positive integer - column index counting from the left</li>
7641
		 *     <li>a negative integer - column index counting from the right</li>
7642
		 *     <li>the string "_all" - all columns (i.e. assign a default)</li>
7643
		 *   </ul>
7644
		 *  @member
7645
		 */
7646
		"aoColumnDefs": null,
7647
 
7648
 
7649
		/**
7650
		 * Basically the same as oSearch, this parameter defines the individual column
7651
		 * filtering state at initialisation time. The array must be of the same size 
7652
		 * as the number of columns, and each element be an object with the parameters
7653
		 * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
7654
		 * accepted and the default will be used.
7655
		 *  @type array
7656
		 *  @default []
7657
		 *  @dtopt Option
7658
		 * 
7659
		 *  @example
7660
		 *    $(document).ready( function() {
7661
		 *      $('#example').dataTable( {
7662
		 *        "aoSearchCols": [
7663
		 *          null,
7664
		 *          { "sSearch": "My filter" },
7665
		 *          null,
7666
		 *          { "sSearch": "^[0-9]", "bEscapeRegex": false }
7667
		 *        ]
7668
		 *      } );
7669
		 *    } )
7670
		 */
7671
		"aoSearchCols": [],
7672
 
7673
 
7674
		/**
7675
		 * An array of CSS classes that should be applied to displayed rows. This 
7676
		 * array may be of any length, and DataTables will apply each class 
7677
		 * sequentially, looping when required.
7678
		 *  @type array
7679
		 *  @default [ 'odd', 'even' ]
7680
		 *  @dtopt Option
7681
		 * 
7682
		 *  @example
7683
		 *    $(document).ready( function() {
7684
		 *      $('#example').dataTable( {
7685
		 *        "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
7686
		 *      } );
7687
		 *    } )
7688
		 */
7689
		"asStripeClasses": [ 'odd', 'even' ],
7690
 
7691
 
7692
		/**
7693
		 * Enable or disable automatic column width calculation. This can be disabled
7694
		 * as an optimisation (it takes some time to calculate the widths) if the
7695
		 * tables widths are passed in using aoColumns.
7696
		 *  @type boolean
7697
		 *  @default true
7698
		 *  @dtopt Features
7699
		 * 
7700
		 *  @example
7701
		 *    $(document).ready( function () {
7702
		 *      $('#example').dataTable( {
7703
		 *        "bAutoWidth": false
7704
		 *      } );
7705
		 *    } );
7706
		 */
7707
		"bAutoWidth": true,
7708
 
7709
 
7710
		/**
7711
		 * Deferred rendering can provide DataTables with a huge speed boost when you
7712
		 * are using an Ajax or JS data source for the table. This option, when set to
7713
		 * true, will cause DataTables to defer the creation of the table elements for
7714
		 * each row until they are needed for a draw - saving a significant amount of
7715
		 * time.
7716
		 *  @type boolean
7717
		 *  @default false
7718
		 *  @dtopt Features
7719
		 * 
7720
		 *  @example
7721
		 *    $(document).ready(function() {
7722
		 *      var oTable = $('#example').dataTable( {
7723
		 *        "sAjaxSource": "sources/arrays.txt",
7724
		 *        "bDeferRender": true
7725
		 *      } );
7726
		 *    } );
7727
		 */
7728
		"bDeferRender": false,
7729
 
7730
 
7731
		/**
7732
		 * Replace a DataTable which matches the given selector and replace it with 
7733
		 * one which has the properties of the new initialisation object passed. If no
7734
		 * table matches the selector, then the new DataTable will be constructed as
7735
		 * per normal.
7736
		 *  @type boolean
7737
		 *  @default false
7738
		 *  @dtopt Options
7739
		 * 
7740
		 *  @example
7741
		 *    $(document).ready(function() {
7742
		 *      $('#example').dataTable( {
7743
		 *        "sScrollY": "200px",
7744
		 *        "bPaginate": false
7745
		 *      } );
7746
		 *      
7747
		 *      // Some time later....
7748
		 *      $('#example').dataTable( {
7749
		 *        "bFilter": false,
7750
		 *        "bDestroy": true
7751
		 *      } );
7752
		 *    } );
7753
		 */
7754
		"bDestroy": false,
7755
 
7756
 
7757
		/**
7758
		 * Enable or disable filtering of data. Filtering in DataTables is "smart" in
7759
		 * that it allows the end user to input multiple words (space separated) and
7760
		 * will match a row containing those words, even if not in the order that was
7761
		 * specified (this allow matching across multiple columns). Note that if you
7762
		 * wish to use filtering in DataTables this must remain 'true' - to remove the
7763
		 * default filtering input box and retain filtering abilities, please use
7764
		 * @ref{sDom}.
7765
		 *  @type boolean
7766
		 *  @default true
7767
		 *  @dtopt Features
7768
		 * 
7769
		 *  @example
7770
		 *    $(document).ready( function () {
7771
		 *      $('#example').dataTable( {
7772
		 *        "bFilter": false
7773
		 *      } );
7774
		 *    } );
7775
		 */
7776
		"bFilter": true,
7777
 
7778
 
7779
		/**
7780
		 * Enable or disable the table information display. This shows information 
7781
		 * about the data that is currently visible on the page, including information
7782
		 * about filtered data if that action is being performed.
7783
		 *  @type boolean
7784
		 *  @default true
7785
		 *  @dtopt Features
7786
		 * 
7787
		 *  @example
7788
		 *    $(document).ready( function () {
7789
		 *      $('#example').dataTable( {
7790
		 *        "bInfo": false
7791
		 *      } );
7792
		 *    } );
7793
		 */
7794
		"bInfo": true,
7795
 
7796
 
7797
		/**
7798
		 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
7799
		 * slightly different and additional mark-up from what DataTables has
7800
		 * traditionally used).
7801
		 *  @type boolean
7802
		 *  @default false
7803
		 *  @dtopt Features
7804
		 * 
7805
		 *  @example
7806
		 *    $(document).ready( function() {
7807
		 *      $('#example').dataTable( {
7808
		 *        "bJQueryUI": true
7809
		 *      } );
7810
		 *    } );
7811
		 */
7812
		"bJQueryUI": false,
7813
 
7814
 
7815
		/**
7816
		 * Allows the end user to select the size of a formatted page from a select
7817
		 * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
7818
		 *  @type boolean
7819
		 *  @default true
7820
		 *  @dtopt Features
7821
		 * 
7822
		 *  @example
7823
		 *    $(document).ready( function () {
7824
		 *      $('#example').dataTable( {
7825
		 *        "bLengthChange": false
7826
		 *      } );
7827
		 *    } );
7828
		 */
7829
		"bLengthChange": true,
7830
 
7831
 
7832
		/**
7833
		 * Enable or disable pagination.
7834
		 *  @type boolean
7835
		 *  @default true
7836
		 *  @dtopt Features
7837
		 * 
7838
		 *  @example
7839
		 *    $(document).ready( function () {
7840
		 *      $('#example').dataTable( {
7841
		 *        "bPaginate": false
7842
		 *      } );
7843
		 *    } );
7844
		 */
7845
		"bPaginate": true,
7846
 
7847
 
7848
		/**
7849
		 * Enable or disable the display of a 'processing' indicator when the table is
7850
		 * being processed (e.g. a sort). This is particularly useful for tables with
7851
		 * large amounts of data where it can take a noticeable amount of time to sort
7852
		 * the entries.
7853
		 *  @type boolean
7854
		 *  @default false
7855
		 *  @dtopt Features
7856
		 * 
7857
		 *  @example
7858
		 *    $(document).ready( function () {
7859
		 *      $('#example').dataTable( {
7860
		 *        "bProcessing": true
7861
		 *      } );
7862
		 *    } );
7863
		 */
7864
		"bProcessing": false,
7865
 
7866
 
7867
		/**
7868
		 * Retrieve the DataTables object for the given selector. Note that if the
7869
		 * table has already been initialised, this parameter will cause DataTables
7870
		 * to simply return the object that has already been set up - it will not take
7871
		 * account of any changes you might have made to the initialisation object
7872
		 * passed to DataTables (setting this parameter to true is an acknowledgement
7873
		 * that you understand this). bDestroy can be used to reinitialise a table if
7874
		 * you need.
7875
		 *  @type boolean
7876
		 *  @default false
7877
		 *  @dtopt Options
7878
		 * 
7879
		 *  @example
7880
		 *    $(document).ready(function() {
7881
		 *      initTable();
7882
		 *      tableActions();
7883
		 *    } );
7884
		 *    
7885
		 *    function initTable ()
7886
		 *    {
7887
		 *      return $('#example').dataTable( {
7888
		 *        "sScrollY": "200px",
7889
		 *        "bPaginate": false,
7890
		 *        "bRetrieve": true
7891
		 *      } );
7892
		 *    }
7893
		 *    
7894
		 *    function tableActions ()
7895
		 *    {
7896
		 *      var oTable = initTable();
7897
		 *      // perform API operations with oTable 
7898
		 *    }
7899
		 */
7900
		"bRetrieve": false,
7901
 
7902
 
7903
		/**
7904
		 * Indicate if DataTables should be allowed to set the padding / margin
7905
		 * etc for the scrolling header elements or not. Typically you will want
7906
		 * this.
7907
		 *  @type boolean
7908
		 *  @default true
7909
		 *  @dtopt Options
7910
		 * 
7911
		 *  @example
7912
		 *    $(document).ready(function() {
7913
		 *      $('#example').dataTable( {
7914
		 *        "bScrollAutoCss": false,
7915
		 *        "sScrollY": "200px"
7916
		 *      } );
7917
		 *    } );
7918
		 */
7919
		"bScrollAutoCss": true,
7920
 
7921
 
7922
		/**
7923
		 * When vertical (y) scrolling is enabled, DataTables will force the height of
7924
		 * the table's viewport to the given height at all times (useful for layout).
7925
		 * However, this can look odd when filtering data down to a small data set,
7926
		 * and the footer is left "floating" further down. This parameter (when
7927
		 * enabled) will cause DataTables to collapse the table's viewport down when
7928
		 * the result set will fit within the given Y height.
7929
		 *  @type boolean
7930
		 *  @default false
7931
		 *  @dtopt Options
7932
		 * 
7933
		 *  @example
7934
		 *    $(document).ready(function() {
7935
		 *      $('#example').dataTable( {
7936
		 *        "sScrollY": "200",
7937
		 *        "bScrollCollapse": true
7938
		 *      } );
7939
		 *    } );
7940
		 */
7941
		"bScrollCollapse": false,
7942
 
7943
 
7944
		/**
7945
		 * Enable infinite scrolling for DataTables (to be used in combination with
7946
		 * sScrollY). Infinite scrolling means that DataTables will continually load
7947
		 * data as a user scrolls through a table, which is very useful for large
7948
		 * dataset. This cannot be used with pagination, which is automatically
7949
		 * disabled. Note - the Scroller extra for DataTables is recommended in
7950
		 * in preference to this option.
7951
		 *  @type boolean
7952
		 *  @default false
7953
		 *  @dtopt Features
7954
		 * 
7955
		 *  @example
7956
		 *    $(document).ready(function() {
7957
		 *      $('#example').dataTable( {
7958
		 *        "bScrollInfinite": true,
7959
		 *        "bScrollCollapse": true,
7960
		 *        "sScrollY": "200px"
7961
		 *      } );
7962
		 *    } );
7963
		 */
7964
		"bScrollInfinite": false,
7965
 
7966
 
7967
		/**
7968
		 * Configure DataTables to use server-side processing. Note that the
7969
		 * sAjaxSource parameter must also be given in order to give DataTables a
7970
		 * source to obtain the required data for each draw.
7971
		 *  @type boolean
7972
		 *  @default false
7973
		 *  @dtopt Features
7974
		 *  @dtopt Server-side
7975
		 * 
7976
		 *  @example
7977
		 *    $(document).ready( function () {
7978
		 *      $('#example').dataTable( {
7979
		 *        "bServerSide": true,
7980
		 *        "sAjaxSource": "xhr.php"
7981
		 *      } );
7982
		 *    } );
7983
		 */
7984
		"bServerSide": false,
7985
 
7986
 
7987
		/**
7988
		 * Enable or disable sorting of columns. Sorting of individual columns can be
7989
		 * disabled by the "bSortable" option for each column.
7990
		 *  @type boolean
7991
		 *  @default true
7992
		 *  @dtopt Features
7993
		 * 
7994
		 *  @example
7995
		 *    $(document).ready( function () {
7996
		 *      $('#example').dataTable( {
7997
		 *        "bSort": false
7998
		 *      } );
7999
		 *    } );
8000
		 */
8001
		"bSort": true,
8002
 
8003
 
8004
		/**
8005
		 * Allows control over whether DataTables should use the top (true) unique
8006
		 * cell that is found for a single column, or the bottom (false - default).
8007
		 * This is useful when using complex headers.
8008
		 *  @type boolean
8009
		 *  @default false
8010
		 *  @dtopt Options
8011
		 * 
8012
		 *  @example
8013
		 *    $(document).ready(function() {
8014
		 *      $('#example').dataTable( {
8015
		 *        "bSortCellsTop": true
8016
		 *      } );
8017
		 *    } );
8018
		 */
8019
		"bSortCellsTop": false,
8020
 
8021
 
8022
		/**
8023
		 * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
8024
		 * 'sorting_3' to the columns which are currently being sorted on. This is
8025
		 * presented as a feature switch as it can increase processing time (while
8026
		 * classes are removed and added) so for large data sets you might want to
8027
		 * turn this off.
8028
		 *  @type boolean
8029
		 *  @default true
8030
		 *  @dtopt Features
8031
		 * 
8032
		 *  @example
8033
		 *    $(document).ready( function () {
8034
		 *      $('#example').dataTable( {
8035
		 *        "bSortClasses": false
8036
		 *      } );
8037
		 *    } );
8038
		 */
8039
		"bSortClasses": true,
8040
 
8041
 
8042
		/**
8043
		 * Enable or disable state saving. When enabled a cookie will be used to save
8044
		 * table display information such as pagination information, display length,
8045
		 * filtering and sorting. As such when the end user reloads the page the
8046
		 * display display will match what thy had previously set up.
8047
		 *  @type boolean
8048
		 *  @default false
8049
		 *  @dtopt Features
8050
		 * 
8051
		 *  @example
8052
		 *    $(document).ready( function () {
8053
		 *      $('#example').dataTable( {
8054
		 *        "bStateSave": true
8055
		 *      } );
8056
		 *    } );
8057
		 */
8058
		"bStateSave": false,
8059
 
8060
 
8061
		/**
8062
		 * Customise the cookie and / or the parameters being stored when using
8063
		 * DataTables with state saving enabled. This function is called whenever
8064
		 * the cookie is modified, and it expects a fully formed cookie string to be
8065
		 * returned. Note that the data object passed in is a Javascript object which
8066
		 * must be converted to a string (JSON.stringify for example).
8067
		 *  @type function
8068
		 *  @param {string} sName Name of the cookie defined by DataTables
8069
		 *  @param {object} oData Data to be stored in the cookie
8070
		 *  @param {string} sExpires Cookie expires string
8071
		 *  @param {string} sPath Path of the cookie to set
8072
		 *  @returns {string} Cookie formatted string (which should be encoded by
8073
		 *    using encodeURIComponent())
8074
		 *  @dtopt Callbacks
8075
		 * 
8076
		 *  @example
8077
		 *    $(document).ready( function () {
8078
		 *      $('#example').dataTable( {
8079
		 *        "fnCookieCallback": function (sName, oData, sExpires, sPath) {
8080
		 *          // Customise oData or sName or whatever else here
8081
		 *          return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
8082
		 *        }
8083
		 *      } );
8084
		 *    } );
8085
		 */
8086
		"fnCookieCallback": null,
8087
 
8088
 
8089
		/**
8090
		 * This function is called when a TR element is created (and all TD child
8091
		 * elements have been inserted), or registered if using a DOM source, allowing
8092
		 * manipulation of the TR element (adding classes etc).
8093
		 *  @type function
8094
		 *  @param {node} nRow "TR" element for the current row
8095
		 *  @param {array} aData Raw data array for this row
8096
		 *  @param {int} iDataIndex The index of this row in aoData
8097
		 *  @dtopt Callbacks
8098
		 * 
8099
		 *  @example
8100
		 *    $(document).ready(function() {
8101
		 *      $('#example').dataTable( {
8102
		 *        "fnCreatedRow": function( nRow, aData, iDataIndex ) {
8103
		 *          // Bold the grade for all 'A' grade browsers
8104
		 *          if ( aData[4] == "A" )
8105
		 *          {
8106
		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
8107
		 *          }
8108
		 *        }
8109
		 *      } );
8110
		 *    } );
8111
		 */
8112
		"fnCreatedRow": null,
8113
 
8114
 
8115
		/**
8116
		 * This function is called on every 'draw' event, and allows you to
8117
		 * dynamically modify any aspect you want about the created DOM.
8118
		 *  @type function
8119
		 *  @param {object} oSettings DataTables settings object
8120
		 *  @dtopt Callbacks
8121
		 * 
8122
		 *  @example
8123
		 *    $(document).ready( function() {
8124
		 *      $('#example').dataTable( {
8125
		 *        "fnDrawCallback": function() {
8126
		 *          alert( 'DataTables has redrawn the table' );
8127
		 *        }
8128
		 *      } );
8129
		 *    } );
8130
		 */
8131
		"fnDrawCallback": null,
8132
 
8133
 
8134
		/**
8135
		 * Identical to fnHeaderCallback() but for the table footer this function
8136
		 * allows you to modify the table footer on every 'draw' even.
8137
		 *  @type function
8138
		 *  @param {node} nFoot "TR" element for the footer
8139
		 *  @param {array} aData Full table data (as derived from the original HTML)
8140
		 *  @param {int} iStart Index for the current display starting point in the 
8141
		 *    display array
8142
		 *  @param {int} iEnd Index for the current display ending point in the 
8143
		 *    display array
8144
		 *  @param {array int} aiDisplay Index array to translate the visual position
8145
		 *    to the full data array
8146
		 *  @dtopt Callbacks
8147
		 * 
8148
		 *  @example
8149
		 *    $(document).ready( function() {
8150
		 *      $('#example').dataTable( {
8151
		 *        "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
8152
		 *          nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
8153
		 *        }
8154
		 *      } );
8155
		 *    } )
8156
		 */
8157
		"fnFooterCallback": null,
8158
 
8159
 
8160
		/**
8161
		 * When rendering large numbers in the information element for the table
8162
		 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
8163
		 * to have a comma separator for the 'thousands' units (e.g. 1 million is
8164
		 * rendered as "1,000,000") to help readability for the end user. This
8165
		 * function will override the default method DataTables uses.
8166
		 *  @type function
8167
		 *  @member
8168
		 *  @param {int} iIn number to be formatted
8169
		 *  @returns {string} formatted string for DataTables to show the number
8170
		 *  @dtopt Callbacks
8171
		 * 
8172
		 *  @example
8173
		 *    $(document).ready(function() {
8174
		 *      $('#example').dataTable( {
8175
		 *        "fnFormatNumber": function ( iIn ) {
8176
		 *          if ( iIn &lt; 1000 ) {
8177
		 *            return iIn;
8178
		 *          } else {
8179
		 *            var 
8180
		 *              s=(iIn+""), 
8181
		 *              a=s.split(""), out="", 
8182
		 *              iLen=s.length;
8183
		 *            
8184
		 *            for ( var i=0 ; i&lt;iLen ; i++ ) {
8185
		 *              if ( i%3 === 0 &amp;&amp; i !== 0 ) {
8186
		 *                out = "'"+out;
8187
		 *              }
8188
		 *              out = a[iLen-i-1]+out;
8189
		 *            }
8190
		 *          }
8191
		 *          return out;
8192
		 *        };
8193
		 *      } );
8194
		 *    } );
8195
		 */
8196
		"fnFormatNumber": function ( iIn ) {
8197
			if ( iIn < 1000 )
8198
			{
8199
				// A small optimisation for what is likely to be the majority of use cases
8200
				return iIn;
8201
			}
8202
 
8203
			var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
8204
 
8205
			for ( var i=0 ; i<iLen ; i++ )
8206
			{
8207
				if ( i%3 === 0 && i !== 0 )
8208
				{
8209
					out = this.oLanguage.sInfoThousands+out;
8210
				}
8211
				out = a[iLen-i-1]+out;
8212
			}
8213
			return out;
8214
		},
8215
 
8216
 
8217
		/**
8218
		 * This function is called on every 'draw' event, and allows you to
8219
		 * dynamically modify the header row. This can be used to calculate and
8220
		 * display useful information about the table.
8221
		 *  @type function
8222
		 *  @param {node} nHead "TR" element for the header
8223
		 *  @param {array} aData Full table data (as derived from the original HTML)
8224
		 *  @param {int} iStart Index for the current display starting point in the
8225
		 *    display array
8226
		 *  @param {int} iEnd Index for the current display ending point in the
8227
		 *    display array
8228
		 *  @param {array int} aiDisplay Index array to translate the visual position
8229
		 *    to the full data array
8230
		 *  @dtopt Callbacks
8231
		 * 
8232
		 *  @example
8233
		 *    $(document).ready( function() {
8234
		 *      $('#example').dataTable( {
8235
		 *        "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
8236
		 *          nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
8237
		 *        }
8238
		 *      } );
8239
		 *    } )
8240
		 */
8241
		"fnHeaderCallback": null,
8242
 
8243
 
8244
		/**
8245
		 * The information element can be used to convey information about the current
8246
		 * state of the table. Although the internationalisation options presented by
8247
		 * DataTables are quite capable of dealing with most customisations, there may
8248
		 * be times where you wish to customise the string further. This callback
8249
		 * allows you to do exactly that.
8250
		 *  @type function
8251
		 *  @param {object} oSettings DataTables settings object
8252
		 *  @param {int} iStart Starting position in data for the draw
8253
		 *  @param {int} iEnd End position in data for the draw
8254
		 *  @param {int} iMax Total number of rows in the table (regardless of
8255
		 *    filtering)
8256
		 *  @param {int} iTotal Total number of rows in the data set, after filtering
8257
		 *  @param {string} sPre The string that DataTables has formatted using it's
8258
		 *    own rules
8259
		 *  @returns {string} The string to be displayed in the information element.
8260
		 *  @dtopt Callbacks
8261
		 * 
8262
		 *  @example
8263
		 *    $('#example').dataTable( {
8264
		 *      "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
8265
		 *        return iStart +" to "+ iEnd;
8266
		 *      }
8267
		 *    } );
8268
		 */
8269
		"fnInfoCallback": null,
8270
 
8271
 
8272
		/**
8273
		 * Called when the table has been initialised. Normally DataTables will
8274
		 * initialise sequentially and there will be no need for this function,
8275
		 * however, this does not hold true when using external language information
8276
		 * since that is obtained using an async XHR call.
8277
		 *  @type function
8278
		 *  @param {object} oSettings DataTables settings object
8279
		 *  @param {object} json The JSON object request from the server - only
8280
		 *    present if client-side Ajax sourced data is used
8281
		 *  @dtopt Callbacks
8282
		 * 
8283
		 *  @example
8284
		 *    $(document).ready( function() {
8285
		 *      $('#example').dataTable( {
8286
		 *        "fnInitComplete": function(oSettings, json) {
8287
		 *          alert( 'DataTables has finished its initialisation.' );
8288
		 *        }
8289
		 *      } );
8290
		 *    } )
8291
		 */
8292
		"fnInitComplete": null,
8293
 
8294
 
8295
		/**
8296
		 * Called at the very start of each table draw and can be used to cancel the
8297
		 * draw by returning false, any other return (including undefined) results in
8298
		 * the full draw occurring).
8299
		 *  @type function
8300
		 *  @param {object} oSettings DataTables settings object
8301
		 *  @returns {boolean} False will cancel the draw, anything else (including no
8302
		 *    return) will allow it to complete.
8303
		 *  @dtopt Callbacks
8304
		 * 
8305
		 *  @example
8306
		 *    $(document).ready( function() {
8307
		 *      $('#example').dataTable( {
8308
		 *        "fnPreDrawCallback": function( oSettings ) {
8309
		 *          if ( $('#test').val() == 1 ) {
8310
		 *            return false;
8311
		 *          }
8312
		 *        }
8313
		 *      } );
8314
		 *    } );
8315
		 */
8316
		"fnPreDrawCallback": null,
8317
 
8318
 
8319
		/**
8320
		 * This function allows you to 'post process' each row after it have been
8321
		 * generated for each table draw, but before it is rendered on screen. This
8322
		 * function might be used for setting the row class name etc.
8323
		 *  @type function
8324
		 *  @param {node} nRow "TR" element for the current row
8325
		 *  @param {array} aData Raw data array for this row
8326
		 *  @param {int} iDisplayIndex The display index for the current table draw
8327
		 *  @param {int} iDisplayIndexFull The index of the data in the full list of
8328
		 *    rows (after filtering)
8329
		 *  @dtopt Callbacks
8330
		 * 
8331
		 *  @example
8332
		 *    $(document).ready(function() {
8333
		 *      $('#example').dataTable( {
8334
		 *        "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
8335
		 *          // Bold the grade for all 'A' grade browsers
8336
		 *          if ( aData[4] == "A" )
8337
		 *          {
8338
		 *            $('td:eq(4)', nRow).html( '<b>A</b>' );
8339
		 *          }
8340
		 *        }
8341
		 *      } );
8342
		 *    } );
8343
		 */
8344
		"fnRowCallback": null,
8345
 
8346
 
8347
		/**
8348
		 * This parameter allows you to override the default function which obtains
8349
		 * the data from the server ($.getJSON) so something more suitable for your
8350
		 * application. For example you could use POST data, or pull information from
8351
		 * a Gears or AIR database.
8352
		 *  @type function
8353
		 *  @member
8354
		 *  @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
8355
		 *  @param {array} aoData A key/value pair object containing the data to send
8356
		 *    to the server
8357
		 *  @param {function} fnCallback to be called on completion of the data get
8358
		 *    process that will draw the data on the page.
8359
		 *  @param {object} oSettings DataTables settings object
8360
		 *  @dtopt Callbacks
8361
		 *  @dtopt Server-side
8362
		 * 
8363
		 *  @example
8364
		 *    // POST data to server
8365
		 *    $(document).ready(function() {
8366
		 *      $('#example').dataTable( {
8367
		 *        "bProcessing": true,
8368
		 *        "bServerSide": true,
8369
		 *        "sAjaxSource": "xhr.php",
8370
		 *        "fnServerData": function ( sSource, aoData, fnCallback ) {
8371
		 *          $.ajax( {
8372
		 *            "dataType": 'json', 
8373
		 *            "type": "POST", 
8374
		 *            "url": sSource, 
8375
		 *            "data": aoData, 
8376
		 *            "success": fnCallback
8377
		 *          } );
8378
		 *        }
8379
		 *      } );
8380
		 *    } );
8381
		 */
8382
		"fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
8383
			oSettings.jqXHR = $.ajax( {
8384
				"url":  sUrl,
8385
				"data": aoData,
8386
				"success": function (json) {
8387
					$(oSettings.oInstance).trigger('xhr', oSettings);
8388
					fnCallback( json );
8389
				},
8390
				"dataType": "json",
8391
				"cache": false,
8392
				"type": oSettings.sServerMethod,
8393
				"error": function (xhr, error, thrown) {
8394
					if ( error == "parsererror" ) {
8395
						alert( "DataTables warning: JSON data from server could not be parsed. "+
8396
							"This is caused by a JSON formatting error." );
8397
					}
8398
				}
8399
			} );
8400
		},
8401
 
8402
 
8403
		/**
8404
		 * It is often useful to send extra data to the server when making an Ajax
8405
		 * request - for example custom filtering information, and this callback
8406
		 * function makes it trivial to send extra information to the server. The
8407
		 * passed in parameter is the data set that has been constructed by
8408
		 * DataTables, and you can add to this or modify it as you require.
8409
		 *  @type function
8410
		 *  @param {array} aoData Data array (array of objects which are name/value
8411
		 *    pairs) that has been constructed by DataTables and will be sent to the
8412
		 *    server. In the case of Ajax sourced data with server-side processing
8413
		 *    this will be an empty array, for server-side processing there will be a
8414
		 *    significant number of parameters!
8415
		 *  @returns {undefined} Ensure that you modify the aoData array passed in,
8416
		 *    as this is passed by reference.
8417
		 *  @dtopt Callbacks
8418
		 *  @dtopt Server-side
8419
		 * 
8420
		 *  @example
8421
		 *    $(document).ready(function() {
8422
		 *      $('#example').dataTable( {
8423
		 *        "bProcessing": true,
8424
		 *        "bServerSide": true,
8425
		 *        "sAjaxSource": "scripts/server_processing.php",
8426
		 *        "fnServerParams": function ( aoData ) {
8427
		 *          aoData.push( { "name": "more_data", "value": "my_value" } );
8428
		 *        }
8429
		 *      } );
8430
		 *    } );
8431
		 */
8432
		"fnServerParams": null,
8433
 
8434
 
8435
		/**
8436
		 * Load the table state. With this function you can define from where, and how, the
8437
		 * state of a table is loaded. By default DataTables will load from its state saving
8438
		 * cookie, but you might wish to use local storage (HTML5) or a server-side database.
8439
		 *  @type function
8440
		 *  @member
8441
		 *  @param {object} oSettings DataTables settings object
8442
		 *  @return {object} The DataTables state object to be loaded
8443
		 *  @dtopt Callbacks
8444
		 * 
8445
		 *  @example
8446
		 *    $(document).ready(function() {
8447
		 *      $('#example').dataTable( {
8448
		 *        "bStateSave": true,
8449
		 *        "fnStateSave": function (oSettings, oData) {
8450
		 *          var o;
8451
		 *          
8452
		 *          // Send an Ajax request to the server to get the data. Note that
8453
		 *          // this is a synchronous request.
8454
		 *          $.ajax( {
8455
		 *            "url": "/state_load",
8456
		 *            "async": false,
8457
		 *            "dataType": "json",
8458
		 *            "success": function (json) {
8459
		 *              o = json;
8460
		 *            }
8461
		 *          } );
8462
		 *          
8463
		 *          return o;
8464
		 *        }
8465
		 *      } );
8466
		 *    } );
8467
		 */
8468
		"fnStateLoad": function ( oSettings ) {
8469
			var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
8470
			var oData;
8471
 
8472
			try {
8473
				oData = (typeof $.parseJSON === 'function') ? 
8474
					$.parseJSON(sData) : eval( '('+sData+')' );
8475
			} catch (e) {
8476
				oData = null;
8477
			}
8478
 
8479
			return oData;
8480
		},
8481
 
8482
 
8483
		/**
8484
		 * Callback which allows modification of the saved state prior to loading that state.
8485
		 * This callback is called when the table is loading state from the stored data, but
8486
		 * prior to the settings object being modified by the saved state. Note that for 
8487
		 * plug-in authors, you should use the 'stateLoadParams' event to load parameters for 
8488
		 * a plug-in.
8489
		 *  @type function
8490
		 *  @param {object} oSettings DataTables settings object
8491
		 *  @param {object} oData The state object that is to be loaded
8492
		 *  @dtopt Callbacks
8493
		 * 
8494
		 *  @example
8495
		 *    // Remove a saved filter, so filtering is never loaded
8496
		 *    $(document).ready(function() {
8497
		 *      $('#example').dataTable( {
8498
		 *        "bStateSave": true,
8499
		 *        "fnStateLoadParams": function (oSettings, oData) {
8500
		 *          oData.oFilter.sSearch = "";
8501
		 *      } );
8502
		 *    } );
8503
		 * 
8504
		 *  @example
8505
		 *    // Disallow state loading by returning false
8506
		 *    $(document).ready(function() {
8507
		 *      $('#example').dataTable( {
8508
		 *        "bStateSave": true,
8509
		 *        "fnStateLoadParams": function (oSettings, oData) {
8510
		 *          return false;
8511
		 *      } );
8512
		 *    } );
8513
		 */
8514
		"fnStateLoadParams": null,
8515
 
8516
 
8517
		/**
8518
		 * Callback that is called when the state has been loaded from the state saving method
8519
		 * and the DataTables settings object has been modified as a result of the loaded state.
8520
		 *  @type function
8521
		 *  @param {object} oSettings DataTables settings object
8522
		 *  @param {object} oData The state object that was loaded
8523
		 *  @dtopt Callbacks
8524
		 * 
8525
		 *  @example
8526
		 *    // Show an alert with the filtering value that was saved
8527
		 *    $(document).ready(function() {
8528
		 *      $('#example').dataTable( {
8529
		 *        "bStateSave": true,
8530
		 *        "fnStateLoaded": function (oSettings, oData) {
8531
		 *          alert( 'Saved filter was: '+oData.oFilter.sSearch );
8532
		 *      } );
8533
		 *    } );
8534
		 */
8535
		"fnStateLoaded": null,
8536
 
8537
 
8538
		/**
8539
		 * Save the table state. This function allows you to define where and how the state
8540
		 * information for the table is stored - by default it will use a cookie, but you
8541
		 * might want to use local storage (HTML5) or a server-side database.
8542
		 *  @type function
8543
		 *  @member
8544
		 *  @param {object} oSettings DataTables settings object
8545
		 *  @param {object} oData The state object to be saved
8546
		 *  @dtopt Callbacks
8547
		 * 
8548
		 *  @example
8549
		 *    $(document).ready(function() {
8550
		 *      $('#example').dataTable( {
8551
		 *        "bStateSave": true,
8552
		 *        "fnStateSave": function (oSettings, oData) {
8553
		 *          // Send an Ajax request to the server with the state object
8554
		 *          $.ajax( {
8555
		 *            "url": "/state_save",
8556
		 *            "data": oData,
8557
		 *            "dataType": "json",
8558
		 *            "method": "POST"
8559
		 *            "success": function () {}
8560
		 *          } );
8561
		 *        }
8562
		 *      } );
8563
		 *    } );
8564
		 */
8565
		"fnStateSave": function ( oSettings, oData ) {
8566
			this.oApi._fnCreateCookie( 
8567
				oSettings.sCookiePrefix+oSettings.sInstance, 
8568
				this.oApi._fnJsonString(oData), 
8569
				oSettings.iCookieDuration, 
8570
				oSettings.sCookiePrefix, 
8571
				oSettings.fnCookieCallback
8572
			);
8573
		},
8574
 
8575
 
8576
		/**
8577
		 * Callback which allows modification of the state to be saved. Called when the table 
8578
		 * has changed state a new state save is required. This method allows modification of
8579
		 * the state saving object prior to actually doing the save, including addition or 
8580
		 * other state properties or modification. Note that for plug-in authors, you should 
8581
		 * use the 'stateSaveParams' event to save parameters for a plug-in.
8582
		 *  @type function
8583
		 *  @param {object} oSettings DataTables settings object
8584
		 *  @param {object} oData The state object to be saved
8585
		 *  @dtopt Callbacks
8586
		 * 
8587
		 *  @example
8588
		 *    // Remove a saved filter, so filtering is never saved
8589
		 *    $(document).ready(function() {
8590
		 *      $('#example').dataTable( {
8591
		 *        "bStateSave": true,
8592
		 *        "fnStateLoadParams": function (oSettings, oData) {
8593
		 *          oData.oFilter.sSearch = "";
8594
		 *      } );
8595
		 *    } );
8596
		 */
8597
		"fnStateSaveParams": null,
8598
 
8599
 
8600
		/**
8601
		 * Duration of the cookie which is used for storing session information. This
8602
		 * value is given in seconds.
8603
		 *  @type int
8604
		 *  @default 7200 <i>(2 hours)</i>
8605
		 *  @dtopt Options
8606
		 * 
8607
		 *  @example
8608
		 *    $(document).ready( function() {
8609
		 *      $('#example').dataTable( {
8610
		 *        "iCookieDuration": 60*60*24 // 1 day
8611
		 *      } );
8612
		 *    } )
8613
		 */
8614
		"iCookieDuration": 7200,
8615
 
8616
 
8617
		/**
8618
		 * When enabled DataTables will not make a request to the server for the first
8619
		 * page draw - rather it will use the data already on the page (no sorting etc
8620
		 * will be applied to it), thus saving on an XHR at load time. iDeferLoading
8621
		 * is used to indicate that deferred loading is required, but it is also used
8622
		 * to tell DataTables how many records there are in the full table (allowing
8623
		 * the information element and pagination to be displayed correctly).
8624
		 *  @type int
8625
		 *  @default null
8626
		 *  @dtopt Options
8627
		 * 
8628
		 *  @example
8629
		 *    $(document).ready(function() {
8630
		 *      $('#example').dataTable( {
8631
		 *        "bServerSide": true,
8632
		 *        "sAjaxSource": "scripts/server_processing.php",
8633
		 *        "iDeferLoading": 57
8634
		 *      } );
8635
		 *    } );
8636
		 */
8637
		"iDeferLoading": null,
8638
 
8639
 
8640
		/**
8641
		 * Number of rows to display on a single page when using pagination. If
8642
		 * feature enabled (bLengthChange) then the end user will be able to override
8643
		 * this to a custom setting using a pop-up menu.
8644
		 *  @type int
8645
		 *  @default 10
8646
		 *  @dtopt Options
8647
		 * 
8648
		 *  @example
8649
		 *    $(document).ready( function() {
8650
		 *      $('#example').dataTable( {
8651
		 *        "iDisplayLength": 50
8652
		 *      } );
8653
		 *    } )
8654
		 */
8655
		"iDisplayLength": 10,
8656
 
8657
 
8658
		/**
8659
		 * Define the starting point for data display when using DataTables with
8660
		 * pagination. Note that this parameter is the number of records, rather than
8661
		 * the page number, so if you have 10 records per page and want to start on
8662
		 * the third page, it should be "20".
8663
		 *  @type int
8664
		 *  @default 0
8665
		 *  @dtopt Options
8666
		 * 
8667
		 *  @example
8668
		 *    $(document).ready( function() {
8669
		 *      $('#example').dataTable( {
8670
		 *        "iDisplayStart": 20
8671
		 *      } );
8672
		 *    } )
8673
		 */
8674
		"iDisplayStart": 0,
8675
 
8676
 
8677
		/**
8678
		 * The scroll gap is the amount of scrolling that is left to go before
8679
		 * DataTables will load the next 'page' of data automatically. You typically
8680
		 * want a gap which is big enough that the scrolling will be smooth for the
8681
		 * user, while not so large that it will load more data than need.
8682
		 *  @type int
8683
		 *  @default 100
8684
		 *  @dtopt Options
8685
		 * 
8686
		 *  @example
8687
		 *    $(document).ready(function() {
8688
		 *      $('#example').dataTable( {
8689
		 *        "bScrollInfinite": true,
8690
		 *        "bScrollCollapse": true,
8691
		 *        "sScrollY": "200px",
8692
		 *        "iScrollLoadGap": 50
8693
		 *      } );
8694
		 *    } );
8695
		 */
8696
		"iScrollLoadGap": 100,
8697
 
8698
 
8699
		/**
8700
		 * By default DataTables allows keyboard navigation of the table (sorting, paging,
8701
		 * and filtering) by adding a tabindex attribute to the required elements. This
8702
		 * allows you to tab through the controls and press the enter key to activate them.
8703
		 * The tabindex is default 0, meaning that the tab follows the flow of the document.
8704
		 * You can overrule this using this parameter if you wish. Use a value of -1 to
8705
		 * disable built-in keyboard navigation.
8706
		 *  @type int
8707
		 *  @default 0
8708
		 *  @dtopt Options
8709
		 * 
8710
		 *  @example
8711
		 *    $(document).ready(function() {
8712
		 *      $('#example').dataTable( {
8713
		 *        "iTabIndex": 1
8714
		 *      } );
8715
		 *    } );
8716
		 */
8717
		"iTabIndex": 0,
8718
 
8719
 
8720
		/**
8721
		 * All strings that DataTables uses in the user interface that it creates
8722
		 * are defined in this object, allowing you to modified them individually or
8723
		 * completely replace them all as required.
8724
		 *  @namespace
8725
		 */
8726
		"oLanguage": {
8727
			/**
8728
			 * Strings that are used for WAI-ARIA labels and controls only (these are not
8729
			 * actually visible on the page, but will be read by screenreaders, and thus
8730
			 * must be internationalised as well).
8731
			 *  @namespace
8732
			 */
8733
			"oAria": {
8734
				/**
8735
				 * ARIA label that is added to the table headers when the column may be
8736
				 * sorted ascending by activing the column (click or return when focused).
8737
				 * Note that the column header is prefixed to this string.
8738
				 *  @type string
8739
				 *  @default : activate to sort column ascending
8740
				 *  @dtopt Language
8741
				 * 
8742
				 *  @example
8743
				 *    $(document).ready(function() {
8744
				 *      $('#example').dataTable( {
8745
				 *        "oLanguage": {
8746
				 *          "oAria": {
8747
				 *            "sSortAscending": " - click/return to sort ascending"
8748
				 *          }
8749
				 *        }
8750
				 *      } );
8751
				 *    } );
8752
				 */
8753
				"sSortAscending": ": activate to sort column ascending",
8754
 
8755
				/**
8756
				 * ARIA label that is added to the table headers when the column may be
8757
				 * sorted descending by activing the column (click or return when focused).
8758
				 * Note that the column header is prefixed to this string.
8759
				 *  @type string
8760
				 *  @default : activate to sort column ascending
8761
				 *  @dtopt Language
8762
				 * 
8763
				 *  @example
8764
				 *    $(document).ready(function() {
8765
				 *      $('#example').dataTable( {
8766
				 *        "oLanguage": {
8767
				 *          "oAria": {
8768
				 *            "sSortDescending": " - click/return to sort descending"
8769
				 *          }
8770
				 *        }
8771
				 *      } );
8772
				 *    } );
8773
				 */
8774
				"sSortDescending": ": activate to sort column descending"
8775
			},
8776
 
8777
			/**
8778
			 * Pagination string used by DataTables for the two built-in pagination
8779
			 * control types ("two_button" and "full_numbers")
8780
			 *  @namespace
8781
			 */
8782
			"oPaginate": {
8783
				/**
8784
				 * Text to use when using the 'full_numbers' type of pagination for the
8785
				 * button to take the user to the first page.
8786
				 *  @type string
8787
				 *  @default First
8788
				 *  @dtopt Language
8789
				 * 
8790
				 *  @example
8791
				 *    $(document).ready(function() {
8792
				 *      $('#example').dataTable( {
8793
				 *        "oLanguage": {
8794
				 *          "oPaginate": {
8795
				 *            "sFirst": "First page"
8796
				 *          }
8797
				 *        }
8798
				 *      } );
8799
				 *    } );
8800
				 */
8801
				"sFirst": "First",
8802
 
8803
 
8804
				/**
8805
				 * Text to use when using the 'full_numbers' type of pagination for the
8806
				 * button to take the user to the last page.
8807
				 *  @type string
8808
				 *  @default Last
8809
				 *  @dtopt Language
8810
				 * 
8811
				 *  @example
8812
				 *    $(document).ready(function() {
8813
				 *      $('#example').dataTable( {
8814
				 *        "oLanguage": {
8815
				 *          "oPaginate": {
8816
				 *            "sLast": "Last page"
8817
				 *          }
8818
				 *        }
8819
				 *      } );
8820
				 *    } );
8821
				 */
8822
				"sLast": "Last",
8823
 
8824
 
8825
				/**
8826
				 * Text to use when using the 'full_numbers' type of pagination for the
8827
				 * button to take the user to the next page.
8828
				 *  @type string
8829
				 *  @default Next
8830
				 *  @dtopt Language
8831
				 * 
8832
				 *  @example
8833
				 *    $(document).ready(function() {
8834
				 *      $('#example').dataTable( {
8835
				 *        "oLanguage": {
8836
				 *          "oPaginate": {
8837
				 *            "sNext": "Next page"
8838
				 *          }
8839
				 *        }
8840
				 *      } );
8841
				 *    } );
8842
				 */
8843
				"sNext": "Next",
8844
 
8845
 
8846
				/**
8847
				 * Text to use when using the 'full_numbers' type of pagination for the
8848
				 * button to take the user to the previous page.
8849
				 *  @type string
8850
				 *  @default Previous
8851
				 *  @dtopt Language
8852
				 * 
8853
				 *  @example
8854
				 *    $(document).ready(function() {
8855
				 *      $('#example').dataTable( {
8856
				 *        "oLanguage": {
8857
				 *          "oPaginate": {
8858
				 *            "sPrevious": "Previous page"
8859
				 *          }
8860
				 *        }
8861
				 *      } );
8862
				 *    } );
8863
				 */
8864
				"sPrevious": "Previous"
8865
			},
8866
 
8867
			/**
8868
			 * This string is shown in preference to sZeroRecords when the table is
8869
			 * empty of data (regardless of filtering). Note that this is an optional
8870
			 * parameter - if it is not given, the value of sZeroRecords will be used
8871
			 * instead (either the default or given value).
8872
			 *  @type string
8873
			 *  @default No data available in table
8874
			 *  @dtopt Language
8875
			 * 
8876
			 *  @example
8877
			 *    $(document).ready(function() {
8878
			 *      $('#example').dataTable( {
8879
			 *        "oLanguage": {
8880
			 *          "sEmptyTable": "No data available in table"
8881
			 *        }
8882
			 *      } );
8883
			 *    } );
8884
			 */
8885
			"sEmptyTable": "No data available in table",
8886
 
8887
 
8888
			/**
8889
			 * This string gives information to the end user about the information that 
8890
			 * is current on display on the page. The _START_, _END_ and _TOTAL_ 
8891
			 * variables are all dynamically replaced as the table display updates, and 
8892
			 * can be freely moved or removed as the language requirements change.
8893
			 *  @type string
8894
			 *  @default Showing _START_ to _END_ of _TOTAL_ entries
8895
			 *  @dtopt Language
8896
			 * 
8897
			 *  @example
8898
			 *    $(document).ready(function() {
8899
			 *      $('#example').dataTable( {
8900
			 *        "oLanguage": {
8901
			 *          "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
8902
			 *        }
8903
			 *      } );
8904
			 *    } );
8905
			 */
8906
			"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
8907
 
8908
 
8909
			/**
8910
			 * Display information string for when the table is empty. Typically the 
8911
			 * format of this string should match sInfo.
8912
			 *  @type string
8913
			 *  @default Showing 0 to 0 of 0 entries
8914
			 *  @dtopt Language
8915
			 * 
8916
			 *  @example
8917
			 *    $(document).ready(function() {
8918
			 *      $('#example').dataTable( {
8919
			 *        "oLanguage": {
8920
			 *          "sInfoEmpty": "No entries to show"
8921
			 *        }
8922
			 *      } );
8923
			 *    } );
8924
			 */
8925
			"sInfoEmpty": "Showing 0 to 0 of 0 entries",
8926
 
8927
 
8928
			/**
8929
			 * When a user filters the information in a table, this string is appended 
8930
			 * to the information (sInfo) to give an idea of how strong the filtering 
8931
			 * is. The variable _MAX_ is dynamically updated.
8932
			 *  @type string
8933
			 *  @default (filtered from _MAX_ total entries)
8934
			 *  @dtopt Language
8935
			 * 
8936
			 *  @example
8937
			 *    $(document).ready(function() {
8938
			 *      $('#example').dataTable( {
8939
			 *        "oLanguage": {
8940
			 *          "sInfoFiltered": " - filtering from _MAX_ records"
8941
			 *        }
8942
			 *      } );
8943
			 *    } );
8944
			 */
8945
			"sInfoFiltered": "(filtered from _MAX_ total entries)",
8946
 
8947
 
8948
			/**
8949
			 * If can be useful to append extra information to the info string at times,
8950
			 * and this variable does exactly that. This information will be appended to
8951
			 * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
8952
			 * being used) at all times.
8953
			 *  @type string
8954
			 *  @default <i>Empty string</i>
8955
			 *  @dtopt Language
8956
			 * 
8957
			 *  @example
8958
			 *    $(document).ready(function() {
8959
			 *      $('#example').dataTable( {
8960
			 *        "oLanguage": {
8961
			 *          "sInfoPostFix": "All records shown are derived from real information."
8962
			 *        }
8963
			 *      } );
8964
			 *    } );
8965
			 */
8966
			"sInfoPostFix": "",
8967
 
8968
 
8969
			/**
8970
			 * DataTables has a build in number formatter (fnFormatNumber) which is used
8971
			 * to format large numbers that are used in the table information. By
8972
			 * default a comma is used, but this can be trivially changed to any
8973
			 * character you wish with this parameter.
8974
			 *  @type string
8975
			 *  @default ,
8976
			 *  @dtopt Language
8977
			 * 
8978
			 *  @example
8979
			 *    $(document).ready(function() {
8980
			 *      $('#example').dataTable( {
8981
			 *        "oLanguage": {
8982
			 *          "sInfoThousands": "'"
8983
			 *        }
8984
			 *      } );
8985
			 *    } );
8986
			 */
8987
			"sInfoThousands": ",",
8988
 
8989
 
8990
			/**
8991
			 * Detail the action that will be taken when the drop down menu for the
8992
			 * pagination length option is changed. The '_MENU_' variable is replaced
8993
			 * with a default select list of 10, 25, 50 and 100, and can be replaced
8994
			 * with a custom select box if required.
8995
			 *  @type string
8996
			 *  @default Show _MENU_ entries
8997
			 *  @dtopt Language
8998
			 * 
8999
			 *  @example
9000
			 *    // Language change only
9001
			 *    $(document).ready(function() {
9002
			 *      $('#example').dataTable( {
9003
			 *        "oLanguage": {
9004
			 *          "sLengthMenu": "Display _MENU_ records"
9005
			 *        }
9006
			 *      } );
9007
			 *    } );
9008
			 *    
9009
			 *  @example
9010
			 *    // Language and options change
9011
			 *    $(document).ready(function() {
9012
			 *      $('#example').dataTable( {
9013
			 *        "oLanguage": {
9014
			 *          "sLengthMenu": 'Display <select>'+
9015
			 *            '<option value="10">10</option>'+
9016
			 *            '<option value="20">20</option>'+
9017
			 *            '<option value="30">30</option>'+
9018
			 *            '<option value="40">40</option>'+
9019
			 *            '<option value="50">50</option>'+
9020
			 *            '<option value="-1">All</option>'+
9021
			 *            '</select> records'
9022
			 *        }
9023
			 *      } );
9024
			 *    } );
9025
			 */
9026
			"sLengthMenu": "Show _MENU_ entries",
9027
 
9028
 
9029
			/**
9030
			 * When using Ajax sourced data and during the first draw when DataTables is
9031
			 * gathering the data, this message is shown in an empty row in the table to
9032
			 * indicate to the end user the the data is being loaded. Note that this
9033
			 * parameter is not used when loading data by server-side processing, just
9034
			 * Ajax sourced data with client-side processing.
9035
			 *  @type string
9036
			 *  @default Loading...
9037
			 *  @dtopt Language
9038
			 * 
9039
			 *  @example
9040
			 *    $(document).ready( function() {
9041
			 *      $('#example').dataTable( {
9042
			 *        "oLanguage": {
9043
			 *          "sLoadingRecords": "Please wait - loading..."
9044
			 *        }
9045
			 *      } );
9046
			 *    } );
9047
			 */
9048
			"sLoadingRecords": "Loading...",
9049
 
9050
 
9051
			/**
9052
			 * Text which is displayed when the table is processing a user action
9053
			 * (usually a sort command or similar).
9054
			 *  @type string
9055
			 *  @default Processing...
9056
			 *  @dtopt Language
9057
			 * 
9058
			 *  @example
9059
			 *    $(document).ready(function() {
9060
			 *      $('#example').dataTable( {
9061
			 *        "oLanguage": {
9062
			 *          "sProcessing": "DataTables is currently busy"
9063
			 *        }
9064
			 *      } );
9065
			 *    } );
9066
			 */
9067
			"sProcessing": "Processing...",
9068
 
9069
 
9070
			/**
9071
			 * Details the actions that will be taken when the user types into the
9072
			 * filtering input text box. The variable "_INPUT_", if used in the string,
9073
			 * is replaced with the HTML text box for the filtering input allowing
9074
			 * control over where it appears in the string. If "_INPUT_" is not given
9075
			 * then the input box is appended to the string automatically.
9076
			 *  @type string
9077
			 *  @default Search:
9078
			 *  @dtopt Language
9079
			 * 
9080
			 *  @example
9081
			 *    // Input text box will be appended at the end automatically
9082
			 *    $(document).ready(function() {
9083
			 *      $('#example').dataTable( {
9084
			 *        "oLanguage": {
9085
			 *          "sSearch": "Filter records:"
9086
			 *        }
9087
			 *      } );
9088
			 *    } );
9089
			 *    
9090
			 *  @example
9091
			 *    // Specify where the filter should appear
9092
			 *    $(document).ready(function() {
9093
			 *      $('#example').dataTable( {
9094
			 *        "oLanguage": {
9095
			 *          "sSearch": "Apply filter _INPUT_ to table"
9096
			 *        }
9097
			 *      } );
9098
			 *    } );
9099
			 */
9100
			"sSearch": "Search:",
9101
 
9102
 
9103
			/**
9104
			 * All of the language information can be stored in a file on the
9105
			 * server-side, which DataTables will look up if this parameter is passed.
9106
			 * It must store the URL of the language file, which is in a JSON format,
9107
			 * and the object has the same properties as the oLanguage object in the
9108
			 * initialiser object (i.e. the above parameters). Please refer to one of
9109
			 * the example language files to see how this works in action.
9110
			 *  @type string
9111
			 *  @default <i>Empty string - i.e. disabled</i>
9112
			 *  @dtopt Language
9113
			 * 
9114
			 *  @example
9115
			 *    $(document).ready(function() {
9116
			 *      $('#example').dataTable( {
9117
			 *        "oLanguage": {
9118
			 *          "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
9119
			 *        }
9120
			 *      } );
9121
			 *    } );
9122
			 */
9123
			"sUrl": "",
9124
 
9125
 
9126
			/**
9127
			 * Text shown inside the table records when the is no information to be
9128
			 * displayed after filtering. sEmptyTable is shown when there is simply no
9129
			 * information in the table at all (regardless of filtering).
9130
			 *  @type string
9131
			 *  @default No matching records found
9132
			 *  @dtopt Language
9133
			 * 
9134
			 *  @example
9135
			 *    $(document).ready(function() {
9136
			 *      $('#example').dataTable( {
9137
			 *        "oLanguage": {
9138
			 *          "sZeroRecords": "No records to display"
9139
			 *        }
9140
			 *      } );
9141
			 *    } );
9142
			 */
9143
			"sZeroRecords": "No matching records found"
9144
		},
9145
 
9146
 
9147
		/**
9148
		 * This parameter allows you to have define the global filtering state at
9149
		 * initialisation time. As an object the "sSearch" parameter must be
9150
		 * defined, but all other parameters are optional. When "bRegex" is true,
9151
		 * the search string will be treated as a regular expression, when false
9152
		 * (default) it will be treated as a straight string. When "bSmart"
9153
		 * DataTables will use it's smart filtering methods (to word match at
9154
		 * any point in the data), when false this will not be done.
9155
		 *  @namespace
9156
		 *  @extends DataTable.models.oSearch
9157
		 *  @dtopt Options
9158
		 * 
9159
		 *  @example
9160
		 *    $(document).ready( function() {
9161
		 *      $('#example').dataTable( {
9162
		 *        "oSearch": {"sSearch": "Initial search"}
9163
		 *      } );
9164
		 *    } )
9165
		 */
9166
		"oSearch": $.extend( {}, DataTable.models.oSearch ),
9167
 
9168
 
9169
		/**
9170
		 * By default DataTables will look for the property 'aaData' when obtaining
9171
		 * data from an Ajax source or for server-side processing - this parameter
9172
		 * allows that property to be changed. You can use Javascript dotted object
9173
		 * notation to get a data source for multiple levels of nesting.
9174
		 *  @type string
9175
		 *  @default aaData
9176
		 *  @dtopt Options
9177
		 *  @dtopt Server-side
9178
		 * 
9179
		 *  @example
9180
		 *    // Get data from { "data": [...] }
9181
		 *    $(document).ready(function() {
9182
		 *      var oTable = $('#example').dataTable( {
9183
		 *        "sAjaxSource": "sources/data.txt",
9184
		 *        "sAjaxDataProp": "data"
9185
		 *      } );
9186
		 *    } );
9187
		 *    
9188
		 *  @example
9189
		 *    // Get data from { "data": { "inner": [...] } }
9190
		 *    $(document).ready(function() {
9191
		 *      var oTable = $('#example').dataTable( {
9192
		 *        "sAjaxSource": "sources/data.txt",
9193
		 *        "sAjaxDataProp": "data.inner"
9194
		 *      } );
9195
		 *    } );
9196
		 */
9197
		"sAjaxDataProp": "aaData",
9198
 
9199
 
9200
		/**
9201
		 * You can instruct DataTables to load data from an external source using this
9202
		 * parameter (use aData if you want to pass data in you already have). Simply
9203
		 * provide a url a JSON object can be obtained from. This object must include
9204
		 * the parameter 'aaData' which is the data source for the table.
9205
		 *  @type string
9206
		 *  @default null
9207
		 *  @dtopt Options
9208
		 *  @dtopt Server-side
9209
		 * 
9210
		 *  @example
9211
		 *    $(document).ready( function() {
9212
		 *      $('#example').dataTable( {
9213
		 *        "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
9214
		 *      } );
9215
		 *    } )
9216
		 */
9217
		"sAjaxSource": null,
9218
 
9219
 
9220
		/**
9221
		 * This parameter can be used to override the default prefix that DataTables
9222
		 * assigns to a cookie when state saving is enabled.
9223
		 *  @type string
9224
		 *  @default SpryMedia_DataTables_
9225
		 *  @dtopt Options
9226
		 * 
9227
		 *  @example
9228
		 *    $(document).ready(function() {
9229
		 *      $('#example').dataTable( {
9230
		 *        "sCookiePrefix": "my_datatable_",
9231
		 *      } );
9232
		 *    } );
9233
		 */
9234
		"sCookiePrefix": "SpryMedia_DataTables_",
9235
 
9236
 
9237
		/**
9238
		 * This initialisation variable allows you to specify exactly where in the
9239
		 * DOM you want DataTables to inject the various controls it adds to the page
9240
		 * (for example you might want the pagination controls at the top of the
9241
		 * table). DIV elements (with or without a custom class) can also be added to
9242
		 * aid styling. The follow syntax is used:
9243
		 *   <ul>
9244
		 *     <li>The following options are allowed:	
9245
		 *       <ul>
9246
		 *         <li>'l' - Length changing</li
9247
		 *         <li>'f' - Filtering input</li>
9248
		 *         <li>'t' - The table!</li>
9249
		 *         <li>'i' - Information</li>
9250
		 *         <li>'p' - Pagination</li>
9251
		 *         <li>'r' - pRocessing</li>
9252
		 *       </ul>
9253
		 *     </li>
9254
		 *     <li>The following constants are allowed:
9255
		 *       <ul>
9256
		 *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
9257
		 *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
9258
		 *       </ul>
9259
		 *     </li>
9260
		 *     <li>The following syntax is expected:
9261
		 *       <ul>
9262
		 *         <li>'&lt;' and '&gt;' - div elements</li>
9263
		 *         <li>'&lt;"class" and '&gt;' - div with a class</li>
9264
		 *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
9265
		 *       </ul>
9266
		 *     </li>
9267
		 *     <li>Examples:
9268
		 *       <ul>
9269
		 *         <li>'&lt;"wrapper"flipt&gt;'</li>
9270
		 *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
9271
		 *       </ul>
9272
		 *     </li>
9273
		 *   </ul>
9274
		 *  @type string
9275
		 *  @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b> 
9276
		 *    <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
9277
		 *  @dtopt Options
9278
		 * 
9279
		 *  @example
9280
		 *    $(document).ready(function() {
9281
		 *      $('#example').dataTable( {
9282
		 *        "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&lgt;'
9283
		 *      } );
9284
		 *    } );
9285
		 */
9286
		"sDom": "lfrtip",
9287
 
9288
 
9289
		/**
9290
		 * DataTables features two different built-in pagination interaction methods
9291
		 * ('two_button' or 'full_numbers') which present different page controls to
9292
		 * the end user. Further methods can be added using the API (see below).
9293
		 *  @type string
9294
		 *  @default two_button
9295
		 *  @dtopt Options
9296
		 * 
9297
		 *  @example
9298
		 *    $(document).ready( function() {
9299
		 *      $('#example').dataTable( {
9300
		 *        "sPaginationType": "full_numbers"
9301
		 *      } );
9302
		 *    } )
9303
		 */
9304
		"sPaginationType": "two_button",
9305
 
9306
 
9307
		/**
9308
		 * Enable horizontal scrolling. When a table is too wide to fit into a certain
9309
		 * layout, or you have a large number of columns in the table, you can enable
9310
		 * x-scrolling to show the table in a viewport, which can be scrolled. This
9311
		 * property can by any CSS unit, or a number (in which case it will be treated
9312
		 * as a pixel measurement).
9313
		 *  @type string
9314
		 *  @default <i>blank string - i.e. disabled</i>
9315
		 *  @dtopt Features
9316
		 * 
9317
		 *  @example
9318
		 *    $(document).ready(function() {
9319
		 *      $('#example').dataTable( {
9320
		 *        "sScrollX": "100%",
9321
		 *        "bScrollCollapse": true
9322
		 *      } );
9323
		 *    } );
9324
		 */
9325
		"sScrollX": "",
9326
 
9327
 
9328
		/**
9329
		 * This property can be used to force a DataTable to use more width than it
9330
		 * might otherwise do when x-scrolling is enabled. For example if you have a
9331
		 * table which requires to be well spaced, this parameter is useful for
9332
		 * "over-sizing" the table, and thus forcing scrolling. This property can by
9333
		 * any CSS unit, or a number (in which case it will be treated as a pixel
9334
		 * measurement).
9335
		 *  @type string
9336
		 *  @default <i>blank string - i.e. disabled</i>
9337
		 *  @dtopt Options
9338
		 * 
9339
		 *  @example
9340
		 *    $(document).ready(function() {
9341
		 *      $('#example').dataTable( {
9342
		 *        "sScrollX": "100%",
9343
		 *        "sScrollXInner": "110%"
9344
		 *      } );
9345
		 *    } );
9346
		 */
9347
		"sScrollXInner": "",
9348
 
9349
 
9350
		/**
9351
		 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
9352
		 * to the given height, an enable scrolling for any data which overflows the
9353
		 * current viewport. This can be used as an alternative to paging to display
9354
		 * a lot of data in a small area (although paging and scrolling can both be
9355
		 * enabled at the same time). This property can by any CSS unit, or a number
9356
		 * (in which case it will be treated as a pixel measurement).
9357
		 *  @type string
9358
		 *  @default <i>blank string - i.e. disabled</i>
9359
		 *  @dtopt Features
9360
		 * 
9361
		 *  @example
9362
		 *    $(document).ready(function() {
9363
		 *      $('#example').dataTable( {
9364
		 *        "sScrollY": "200px",
9365
		 *        "bPaginate": false
9366
		 *      } );
9367
		 *    } );
9368
		 */
9369
		"sScrollY": "",
9370
 
9371
 
9372
		/**
9373
		 * Set the HTTP method that is used to make the Ajax call for server-side
9374
		 * processing or Ajax sourced data.
9375
		 *  @type string
9376
		 *  @default GET
9377
		 *  @dtopt Options
9378
		 *  @dtopt Server-side
9379
		 * 
9380
		 *  @example
9381
		 *    $(document).ready(function() {
9382
		 *      $('#example').dataTable( {
9383
		 *        "bServerSide": true,
9384
		 *        "sAjaxSource": "scripts/post.php",
9385
		 *        "sServerMethod": "POST"
9386
		 *      } );
9387
		 *    } );
9388
		 */
9389
		"sServerMethod": "GET"
9390
	};
9391
 
9392
 
9393
 
9394
	/**
9395
	 * Column options that can be given to DataTables at initialisation time.
9396
	 *  @namespace
9397
	 */
9398
	DataTable.defaults.columns = {
9399
		/**
9400
		 * Allows a column's sorting to take multiple columns into account when 
9401
		 * doing a sort. For example first name / last name columns make sense to 
9402
		 * do a multi-column sort over the two columns.
9403
		 *  @type array
9404
		 *  @default null <i>Takes the value of the column index automatically</i>
9405
		 *  @dtopt Columns
9406
		 * 
9407
		 *  @example
9408
		 *    // Using aoColumnDefs
9409
		 *    $(document).ready(function() {
9410
		 *      $('#example').dataTable( {
9411
		 *        "aoColumnDefs": [
9412
		 *          { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
9413
		 *          { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
9414
		 *          { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
9415
		 *        ]
9416
		 *      } );
9417
		 *    } );
9418
		 *    
9419
		 *  @example
9420
		 *    // Using aoColumns
9421
		 *    $(document).ready(function() {
9422
		 *      $('#example').dataTable( {
9423
		 *        "aoColumns": [
9424
		 *          { "aDataSort": [ 0, 1 ] },
9425
		 *          { "aDataSort": [ 1, 0 ] },
9426
		 *          { "aDataSort": [ 2, 3, 4 ] },
9427
		 *          null,
9428
		 *          null
9429
		 *        ]
9430
		 *      } );
9431
		 *    } );
9432
		 */
9433
		"aDataSort": null,
9434
 
9435
 
9436
		/**
9437
		 * You can control the default sorting direction, and even alter the behaviour
9438
		 * of the sort handler (i.e. only allow ascending sorting etc) using this
9439
		 * parameter.
9440
		 *  @type array
9441
		 *  @default [ 'asc', 'desc' ]
9442
		 *  @dtopt Columns
9443
		 * 
9444
		 *  @example
9445
		 *    // Using aoColumnDefs
9446
		 *    $(document).ready(function() {
9447
		 *      $('#example').dataTable( {
9448
		 *        "aoColumnDefs": [
9449
		 *          { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
9450
		 *          { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
9451
		 *          { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
9452
		 *        ]
9453
		 *      } );
9454
		 *    } );
9455
		 *    
9456
		 *  @example
9457
		 *    // Using aoColumns
9458
		 *    $(document).ready(function() {
9459
		 *      $('#example').dataTable( {
9460
		 *        "aoColumns": [
9461
		 *          null,
9462
		 *          { "asSorting": [ "asc" ] },
9463
		 *          { "asSorting": [ "desc", "asc", "asc" ] },
9464
		 *          { "asSorting": [ "desc" ] },
9465
		 *          null
9466
		 *        ]
9467
		 *      } );
9468
		 *    } );
9469
		 */
9470
		"asSorting": [ 'asc', 'desc' ],
9471
 
9472
 
9473
		/**
9474
		 * Enable or disable filtering on the data in this column.
9475
		 *  @type boolean
9476
		 *  @default true
9477
		 *  @dtopt Columns
9478
		 * 
9479
		 *  @example
9480
		 *    // Using aoColumnDefs
9481
		 *    $(document).ready(function() {
9482
		 *      $('#example').dataTable( {
9483
		 *        "aoColumnDefs": [ 
9484
		 *          { "bSearchable": false, "aTargets": [ 0 ] }
9485
		 *        ] } );
9486
		 *    } );
9487
		 *    
9488
		 *  @example
9489
		 *    // Using aoColumns
9490
		 *    $(document).ready(function() {
9491
		 *      $('#example').dataTable( {
9492
		 *        "aoColumns": [ 
9493
		 *          { "bSearchable": false },
9494
		 *          null,
9495
		 *          null,
9496
		 *          null,
9497
		 *          null
9498
		 *        ] } );
9499
		 *    } );
9500
		 */
9501
		"bSearchable": true,
9502
 
9503
 
9504
		/**
9505
		 * Enable or disable sorting on this column.
9506
		 *  @type boolean
9507
		 *  @default true
9508
		 *  @dtopt Columns
9509
		 * 
9510
		 *  @example
9511
		 *    // Using aoColumnDefs
9512
		 *    $(document).ready(function() {
9513
		 *      $('#example').dataTable( {
9514
		 *        "aoColumnDefs": [ 
9515
		 *          { "bSortable": false, "aTargets": [ 0 ] }
9516
		 *        ] } );
9517
		 *    } );
9518
		 *    
9519
		 *  @example
9520
		 *    // Using aoColumns
9521
		 *    $(document).ready(function() {
9522
		 *      $('#example').dataTable( {
9523
		 *        "aoColumns": [ 
9524
		 *          { "bSortable": false },
9525
		 *          null,
9526
		 *          null,
9527
		 *          null,
9528
		 *          null
9529
		 *        ] } );
9530
		 *    } );
9531
		 */
9532
		"bSortable": true,
9533
 
9534
 
9535
		/**
9536
		 * When using fnRender() for a column, you may wish to use the original data
9537
		 * (before rendering) for sorting and filtering (the default is to used the
9538
		 * rendered data that the user can see). This may be useful for dates etc.
9539
		 * 
9540
		 * *NOTE* It is it is advisable now to use mDataProp as a function and make 
9541
		 * use of the 'type' that it gives, allowing (potentially) different data to
9542
		 * be used for sorting, filtering, display and type detection.
9543
		 *  @type boolean
9544
		 *  @default true
9545
		 *  @dtopt Columns
9546
		 * 
9547
		 *  @example
9548
		 *    // Using aoColumnDefs
9549
		 *    $(document).ready(function() {
9550
		 *      $('#example').dataTable( {
9551
		 *        "aoColumnDefs": [ 
9552
		 *          {
9553
		 *            "fnRender": function ( oObj ) {
9554
		 *              return oObj.aData[0] +' '+ oObj.aData[3];
9555
		 *            },
9556
		 *            "bUseRendered": false,
9557
		 *            "aTargets": [ 0 ]
9558
		 *          }
9559
		 *        ]
9560
		 *      } );
9561
		 *    } );
9562
		 *    
9563
		 *  @example
9564
		 *    // Using aoColumns
9565
		 *    $(document).ready(function() {
9566
		 *      $('#example').dataTable( {
9567
		 *        "aoColumns": [ 
9568
		 *          {
9569
		 *            "fnRender": function ( oObj ) {
9570
		 *              return oObj.aData[0] +' '+ oObj.aData[3];
9571
		 *            },
9572
		 *            "bUseRendered": false
9573
		 *          },
9574
		 *          null,
9575
		 *          null,
9576
		 *          null,
9577
		 *          null
9578
		 *        ]
9579
		 *      } );
9580
		 *    } );
9581
		 */
9582
		"bUseRendered": true,
9583
 
9584
 
9585
		/**
9586
		 * Enable or disable the display of this column.
9587
		 *  @type boolean
9588
		 *  @default true
9589
		 *  @dtopt Columns
9590
		 * 
9591
		 *  @example
9592
		 *    // Using aoColumnDefs
9593
		 *    $(document).ready(function() {
9594
		 *      $('#example').dataTable( {
9595
		 *        "aoColumnDefs": [ 
9596
		 *          { "bVisible": false, "aTargets": [ 0 ] }
9597
		 *        ] } );
9598
		 *    } );
9599
		 *    
9600
		 *  @example
9601
		 *    // Using aoColumns
9602
		 *    $(document).ready(function() {
9603
		 *      $('#example').dataTable( {
9604
		 *        "aoColumns": [ 
9605
		 *          { "bVisible": false },
9606
		 *          null,
9607
		 *          null,
9608
		 *          null,
9609
		 *          null
9610
		 *        ] } );
9611
		 *    } );
9612
		 */
9613
		"bVisible": true,
9614
 
9615
 
9616
		/**
9617
		 * Developer definable function that is called whenever a cell is created (Ajax source,
9618
		 * etc) or processed for input (DOM source). This can be used as a compliment to fnRender
9619
		 * allowing you to modify the DOM element (add background colour for example) when the
9620
		 * element is available (since it is not when fnRender is called).
9621
		 *  @type function
9622
		 *  @param {element} nTd The TD node that has been created
9623
		 *  @param {*} sData The Data for the cell
9624
		 *  @param {array|object} oData The data for the whole row
9625
		 *  @param {int} iRow The row index for the aoData data store
9626
		 *  @param {int} iCol The column index for aoColumns
9627
		 *  @dtopt Columns
9628
		 * 
9629
		 *  @example
9630
		 *    $(document).ready(function() {
9631
		 *      $('#example').dataTable( {
9632
		 *        "aoColumnDefs": [ {
9633
		 *          "aTargets": [3],
9634
		 *          "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
9635
		 *            if ( sData == "1.7" ) {
9636
		 *              $(nTd).css('color', 'blue')
9637
		 *            }
9638
		 *          }
9639
		 *        } ]
9640
		 *      });
9641
		 *    } );
9642
		 */
9643
		"fnCreatedCell": null,
9644
 
9645
 
9646
		/**
9647
		 * Custom display function that will be called for the display of each cell in
9648
		 * this column.
9649
		 *  @type function
9650
		 *  @param {object} o Object with the following parameters:
9651
		 *  @param {int}    o.iDataRow The row in aoData
9652
		 *  @param {int}    o.iDataColumn The column in question
9653
		 *  @param {array}  o.aData The data for the row in question
9654
		 *  @param {object} o.oSettings The settings object for this DataTables instance
9655
		 *  @param {object} o.mDataProp The data property used for this column
9656
		 *  @param {*}      val The current cell value
9657
		 *  @returns {string} The string you which to use in the display
9658
		 *  @dtopt Columns
9659
		 * 
9660
		 *  @example
9661
		 *    // Using aoColumnDefs
9662
		 *    $(document).ready(function() {
9663
		 *      $('#example').dataTable( {
9664
		 *        "aoColumnDefs": [ 
9665
		 *          {
9666
		 *            "fnRender": function ( o, val ) {
9667
		 *              return o.aData[0] +' '+ o.aData[3];
9668
		 *            },
9669
		 *            "aTargets": [ 0 ]
9670
		 *          }
9671
		 *        ]
9672
		 *      } );
9673
		 *    } );
9674
		 *    
9675
		 *  @example
9676
		 *    // Using aoColumns
9677
		 *    $(document).ready(function() {
9678
		 *      $('#example').dataTable( {
9679
		 *        "aoColumns": [ 
9680
		 *          { "fnRender": function ( o, val ) {
9681
		 *            return o.aData[0] +' '+ o.aData[3];
9682
		 *          } },
9683
		 *          null,
9684
		 *          null,
9685
		 *          null,
9686
		 *          null
9687
		 *        ]
9688
		 *      } );
9689
		 *    } );
9690
		 */
9691
		"fnRender": null,
9692
 
9693
 
9694
		/**
9695
		 * The column index (starting from 0!) that you wish a sort to be performed
9696
		 * upon when this column is selected for sorting. This can be used for sorting
9697
		 * on hidden columns for example.
9698
		 *  @type int
9699
		 *  @default -1 <i>Use automatically calculated column index</i>
9700
		 *  @dtopt Columns
9701
		 * 
9702
		 *  @example
9703
		 *    // Using aoColumnDefs
9704
		 *    $(document).ready(function() {
9705
		 *      $('#example').dataTable( {
9706
		 *        "aoColumnDefs": [ 
9707
		 *          { "iDataSort": 1, "aTargets": [ 0 ] }
9708
		 *        ]
9709
		 *      } );
9710
		 *    } );
9711
		 *    
9712
		 *  @example
9713
		 *    // Using aoColumns
9714
		 *    $(document).ready(function() {
9715
		 *      $('#example').dataTable( {
9716
		 *        "aoColumns": [ 
9717
		 *          { "iDataSort": 1 },
9718
		 *          null,
9719
		 *          null,
9720
		 *          null,
9721
		 *          null
9722
		 *        ]
9723
		 *      } );
9724
		 *    } );
9725
		 */
9726
		"iDataSort": -1,
9727
 
9728
 
9729
		/**
9730
		 * This property can be used to read data from any JSON data source property,
9731
		 * including deeply nested objects / properties. mDataProp can be given in a
9732
		 * number of different ways which effect its behaviour:
9733
		 *   <ul>
9734
		 *     <li>integer - treated as an array index for the data source. This is the
9735
		 *       default that DataTables uses (incrementally increased for each column).</li>
9736
		 *     <li>string - read an object property from the data source. Note that you can
9737
		 *       use Javascript dotted notation to read deep properties/arrays from the
9738
		 *       data source.</li>
9739
		 *     <li>null -  the sDafaultContent option will use used for the cell (empty
9740
		 *       string by default. This can be useful on generated columns such as
9741
		 *       edit / delete action columns.</li>
9742
		 *     <li>function - the function given will be executed whenever DataTables 
9743
		 *       needs to set or get the data for a cell in the column. The function 
9744
		 *       takes three parameters:
9745
		 *       <ul>
9746
		 *         <li>{array|object} The data source for the row</li>
9747
		 *         <li>{string} The type call data requested - this will be 'set' when
9748
		 *           setting data or 'filter', 'display', 'type' or 'sort' when gathering
9749
		 *           data.</li>
9750
		 *         <li>{*} Data to set when the second parameter is 'set'.</li>
9751
		 *       </ul>
9752
		 *       The return value from the function is not required when 'set' is the type
9753
		 *       of call, but otherwise the return is what will be used for the data
9754
		 *       requested.</li>
9755
		 *    </ul>
9756
		 *  @type string|int|function|null
9757
		 *  @default null <i>Use automatically calculated column index</i>
9758
		 *  @dtopt Columns
9759
		 * 
9760
		 *  @example
9761
		 *    // Read table data from objects
9762
		 *    $(document).ready(function() {
9763
		 *      var oTable = $('#example').dataTable( {
9764
		 *        "sAjaxSource": "sources/deep.txt",
9765
		 *        "aoColumns": [
9766
		 *          { "mDataProp": "engine" },
9767
		 *          { "mDataProp": "browser" },
9768
		 *          { "mDataProp": "platform.inner" },
9769
		 *          { "mDataProp": "platform.details.0" },
9770
		 *          { "mDataProp": "platform.details.1" }
9771
		 *        ]
9772
		 *      } );
9773
		 *    } );
9774
		 * 
9775
		 *  @example
9776
		 *    // Using mDataProp as a function to provide different information for
9777
		 *    // sorting, filtering and display. In this case, currency (price)
9778
		 *    $(document).ready(function() {
9779
		 *      var oTable = $('#example').dataTable( {
9780
		 *        "aoColumnDefs": [
9781
		 *        {
9782
		 *          "aTargets": [ 0 ],
9783
		 *          "mDataProp": function ( source, type, val ) {
9784
		 *            if (type === 'set') {
9785
		 *              source.price = val;
9786
		 *              // Store the computed dislay and filter values for efficiency
9787
		 *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
9788
		 *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
9789
		 *              return;
9790
		 *            }
9791
		 *            else if (type === 'display') {
9792
		 *              return source.price_display;
9793
		 *            }
9794
		 *            else if (type === 'filter') {
9795
		 *              return source.price_filter;
9796
		 *            }
9797
		 *            // 'sort' and 'type' both just use the integer
9798
		 *            return source.price;
9799
		 *          }
9800
		 *        ]
9801
		 *      } );
9802
		 *    } );
9803
		 */
9804
		"mDataProp": null,
9805
 
9806
 
9807
		/**
9808
		 * Class to give to each cell in this column.
9809
		 *  @type string
9810
		 *  @default <i>Empty string</i>
9811
		 *  @dtopt Columns
9812
		 * 
9813
		 *  @example
9814
		 *    // Using aoColumnDefs
9815
		 *    $(document).ready(function() {
9816
		 *      $('#example').dataTable( {
9817
		 *        "aoColumnDefs": [ 
9818
		 *          { "sClass": "my_class", "aTargets": [ 0 ] }
9819
		 *        ]
9820
		 *      } );
9821
		 *    } );
9822
		 *    
9823
		 *  @example
9824
		 *    // Using aoColumns
9825
		 *    $(document).ready(function() {
9826
		 *      $('#example').dataTable( {
9827
		 *        "aoColumns": [ 
9828
		 *          { "sClass": "my_class" },
9829
		 *          null,
9830
		 *          null,
9831
		 *          null,
9832
		 *          null
9833
		 *        ]
9834
		 *      } );
9835
		 *    } );
9836
		 */
9837
		"sClass": "",
9838
 
9839
		/**
9840
		 * When DataTables calculates the column widths to assign to each column,
9841
		 * it finds the longest string in each column and then constructs a
9842
		 * temporary table and reads the widths from that. The problem with this
9843
		 * is that "mmm" is much wider then "iiii", but the latter is a longer 
9844
		 * string - thus the calculation can go wrong (doing it properly and putting
9845
		 * it into an DOM object and measuring that is horribly(!) slow). Thus as
9846
		 * a "work around" we provide this option. It will append its value to the
9847
		 * text that is found to be the longest string for the column - i.e. padding.
9848
		 * Generally you shouldn't need this, and it is not documented on the 
9849
		 * general DataTables.net documentation
9850
		 *  @type string
9851
		 *  @default <i>Empty string<i>
9852
		 *  @dtopt Columns
9853
		 *    
9854
		 *  @example
9855
		 *    // Using aoColumns
9856
		 *    $(document).ready(function() {
9857
		 *      $('#example').dataTable( {
9858
		 *        "aoColumns": [ 
9859
		 *          null,
9860
		 *          null,
9861
		 *          null,
9862
		 *          {
9863
		 *            "sContentPadding": "mmm"
9864
		 *          }
9865
		 *        ]
9866
		 *      } );
9867
		 *    } );
9868
		 */
9869
		"sContentPadding": "",
9870
 
9871
 
9872
		/**
9873
		 * Allows a default value to be given for a column's data, and will be used
9874
		 * whenever a null data source is encountered (this can be because mDataProp
9875
		 * is set to null, or because the data source itself is null).
9876
		 *  @type string
9877
		 *  @default null
9878
		 *  @dtopt Columns
9879
		 * 
9880
		 *  @example
9881
		 *    // Using aoColumnDefs
9882
		 *    $(document).ready(function() {
9883
		 *      $('#example').dataTable( {
9884
		 *        "aoColumnDefs": [ 
9885
		 *          {
9886
		 *            "mDataProp": null,
9887
		 *            "sDefaultContent": "Edit",
9888
		 *            "aTargets": [ -1 ]
9889
		 *          }
9890
		 *        ]
9891
		 *      } );
9892
		 *    } );
9893
		 *    
9894
		 *  @example
9895
		 *    // Using aoColumns
9896
		 *    $(document).ready(function() {
9897
		 *      $('#example').dataTable( {
9898
		 *        "aoColumns": [ 
9899
		 *          null,
9900
		 *          null,
9901
		 *          null,
9902
		 *          {
9903
		 *            "mDataProp": null,
9904
		 *            "sDefaultContent": "Edit"
9905
		 *          }
9906
		 *        ]
9907
		 *      } );
9908
		 *    } );
9909
		 */
9910
		"sDefaultContent": null,
9911
 
9912
 
9913
		/**
9914
		 * This parameter is only used in DataTables' server-side processing. It can
9915
		 * be exceptionally useful to know what columns are being displayed on the
9916
		 * client side, and to map these to database fields. When defined, the names
9917
		 * also allow DataTables to reorder information from the server if it comes
9918
		 * back in an unexpected order (i.e. if you switch your columns around on the
9919
		 * client-side, your server-side code does not also need updating).
9920
		 *  @type string
9921
		 *  @default <i>Empty string</i>
9922
		 *  @dtopt Columns
9923
		 * 
9924
		 *  @example
9925
		 *    // Using aoColumnDefs
9926
		 *    $(document).ready(function() {
9927
		 *      $('#example').dataTable( {
9928
		 *        "aoColumnDefs": [ 
9929
		 *          { "sName": "engine", "aTargets": [ 0 ] },
9930
		 *          { "sName": "browser", "aTargets": [ 1 ] },
9931
		 *          { "sName": "platform", "aTargets": [ 2 ] },
9932
		 *          { "sName": "version", "aTargets": [ 3 ] },
9933
		 *          { "sName": "grade", "aTargets": [ 4 ] }
9934
		 *        ]
9935
		 *      } );
9936
		 *    } );
9937
		 *    
9938
		 *  @example
9939
		 *    // Using aoColumns
9940
		 *    $(document).ready(function() {
9941
		 *      $('#example').dataTable( {
9942
		 *        "aoColumns": [ 
9943
		 *          { "sName": "engine" },
9944
		 *          { "sName": "browser" },
9945
		 *          { "sName": "platform" },
9946
		 *          { "sName": "version" },
9947
		 *          { "sName": "grade" }
9948
		 *        ]
9949
		 *      } );
9950
		 *    } );
9951
		 */
9952
		"sName": "",
9953
 
9954
 
9955
		/**
9956
		 * Defines a data source type for the sorting which can be used to read
9957
		 * realtime information from the table (updating the internally cached
9958
		 * version) prior to sorting. This allows sorting to occur on user editable
9959
		 * elements such as form inputs.
9960
		 *  @type string
9961
		 *  @default std
9962
		 *  @dtopt Columns
9963
		 * 
9964
		 *  @example
9965
		 *    // Using aoColumnDefs
9966
		 *    $(document).ready(function() {
9967
		 *      $('#example').dataTable( {
9968
		 *        "aoColumnDefs": [
9969
		 *          { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
9970
		 *          { "sType": "numeric", "aTargets": [ 3 ] },
9971
		 *          { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
9972
		 *          { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
9973
		 *        ]
9974
		 *      } );
9975
		 *    } );
9976
		 *    
9977
		 *  @example
9978
		 *    // Using aoColumns
9979
		 *    $(document).ready(function() {
9980
		 *      $('#example').dataTable( {
9981
		 *        "aoColumns": [
9982
		 *          null,
9983
		 *          null,
9984
		 *          { "sSortDataType": "dom-text" },
9985
		 *          { "sSortDataType": "dom-text", "sType": "numeric" },
9986
		 *          { "sSortDataType": "dom-select" },
9987
		 *          { "sSortDataType": "dom-checkbox" }
9988
		 *        ]
9989
		 *      } );
9990
		 *    } );
9991
		 */
9992
		"sSortDataType": "std",
9993
 
9994
 
9995
		/**
9996
		 * The title of this column.
9997
		 *  @type string
9998
		 *  @default null <i>Derived from the 'TH' value for this column in the 
9999
		 *    original HTML table.</i>
10000
		 *  @dtopt Columns
10001
		 * 
10002
		 *  @example
10003
		 *    // Using aoColumnDefs
10004
		 *    $(document).ready(function() {
10005
		 *      $('#example').dataTable( {
10006
		 *        "aoColumnDefs": [ 
10007
		 *          { "sTitle": "My column title", "aTargets": [ 0 ] }
10008
		 *        ]
10009
		 *      } );
10010
		 *    } );
10011
		 *    
10012
		 *  @example
10013
		 *    // Using aoColumns
10014
		 *    $(document).ready(function() {
10015
		 *      $('#example').dataTable( {
10016
		 *        "aoColumns": [ 
10017
		 *          { "sTitle": "My column title" },
10018
		 *          null,
10019
		 *          null,
10020
		 *          null,
10021
		 *          null
10022
		 *        ]
10023
		 *      } );
10024
		 *    } );
10025
		 */
10026
		"sTitle": null,
10027
 
10028
 
10029
		/**
10030
		 * The type allows you to specify how the data for this column will be sorted.
10031
		 * Four types (string, numeric, date and html (which will strip HTML tags
10032
		 * before sorting)) are currently available. Note that only date formats
10033
		 * understood by Javascript's Date() object will be accepted as type date. For
10034
		 * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
10035
		 * 'date' or 'html' (by default). Further types can be adding through
10036
		 * plug-ins.
10037
		 *  @type string
10038
		 *  @default null <i>Auto-detected from raw data</i>
10039
		 *  @dtopt Columns
10040
		 * 
10041
		 *  @example
10042
		 *    // Using aoColumnDefs
10043
		 *    $(document).ready(function() {
10044
		 *      $('#example').dataTable( {
10045
		 *        "aoColumnDefs": [ 
10046
		 *          { "sType": "html", "aTargets": [ 0 ] }
10047
		 *        ]
10048
		 *      } );
10049
		 *    } );
10050
		 *    
10051
		 *  @example
10052
		 *    // Using aoColumns
10053
		 *    $(document).ready(function() {
10054
		 *      $('#example').dataTable( {
10055
		 *        "aoColumns": [ 
10056
		 *          { "sType": "html" },
10057
		 *          null,
10058
		 *          null,
10059
		 *          null,
10060
		 *          null
10061
		 *        ]
10062
		 *      } );
10063
		 *    } );
10064
		 */
10065
		"sType": null,
10066
 
10067
 
10068
		/**
10069
		 * Defining the width of the column, this parameter may take any CSS value
10070
		 * (3em, 20px etc). DataTables applys 'smart' widths to columns which have not
10071
		 * been given a specific width through this interface ensuring that the table
10072
		 * remains readable.
10073
		 *  @type string
10074
		 *  @default null <i>Automatic</i>
10075
		 *  @dtopt Columns
10076
		 * 
10077
		 *  @example
10078
		 *    // Using aoColumnDefs
10079
		 *    $(document).ready(function() {
10080
		 *      $('#example').dataTable( {
10081
		 *        "aoColumnDefs": [ 
10082
		 *          { "sWidth": "20%", "aTargets": [ 0 ] }
10083
		 *        ]
10084
		 *      } );
10085
		 *    } );
10086
		 *    
10087
		 *  @example
10088
		 *    // Using aoColumns
10089
		 *    $(document).ready(function() {
10090
		 *      $('#example').dataTable( {
10091
		 *        "aoColumns": [ 
10092
		 *          { "sWidth": "20%" },
10093
		 *          null,
10094
		 *          null,
10095
		 *          null,
10096
		 *          null
10097
		 *        ]
10098
		 *      } );
10099
		 *    } );
10100
		 */
10101
		"sWidth": null
10102
	};
10103
 
10104
 
10105
 
10106
	/**
10107
	 * DataTables settings object - this holds all the information needed for a
10108
	 * given table, including configuration, data and current application of the
10109
	 * table options. DataTables does not have a single instance for each DataTable
10110
	 * with the settings attached to that instance, but rather instances of the
10111
	 * DataTable "class" are created on-the-fly as needed (typically by a 
10112
	 * $().dataTable() call) and the settings object is then applied to that
10113
	 * instance.
10114
	 * 
10115
	 * Note that this object is related to {@link DataTable.defaults} but this 
10116
	 * one is the internal data store for DataTables's cache of columns. It should
10117
	 * NOT be manipulated outside of DataTables. Any configuration should be done
10118
	 * through the initialisation options.
10119
	 *  @namespace
10120
	 *  @todo Really should attach the settings object to individual instances so we
10121
	 *    don't need to create new instances on each $().dataTable() call (if the
10122
	 *    table already exists). It would also save passing oSettings around and
10123
	 *    into every single function. However, this is a very significant 
10124
	 *    architecture change for DataTables and will almost certainly break
10125
	 *    backwards compatibility with older installations. This is something that
10126
	 *    will be done in 2.0.
10127
	 */
10128
	DataTable.models.oSettings = {
10129
		/**
10130
		 * Primary features of DataTables and their enablement state.
10131
		 *  @namespace
10132
		 */
10133
		"oFeatures": {
10134
 
10135
			/**
10136
			 * Flag to say if DataTables should automatically try to calculate the
10137
			 * optimum table and columns widths (true) or not (false).
10138
			 * Note that this parameter will be set by the initialisation routine. To
10139
			 * set a default use {@link DataTable.defaults}.
10140
			 *  @type boolean
10141
			 */
10142
			"bAutoWidth": null,
10143
 
10144
			/**
10145
			 * Delay the creation of TR and TD elements until they are actually
10146
			 * needed by a driven page draw. This can give a significant speed
10147
			 * increase for Ajax source and Javascript source data, but makes no
10148
			 * difference at all fro DOM and server-side processing tables.
10149
			 * Note that this parameter will be set by the initialisation routine. To
10150
			 * set a default use {@link DataTable.defaults}.
10151
			 *  @type boolean
10152
			 */
10153
			"bDeferRender": null,
10154
 
10155
			/**
10156
			 * Enable filtering on the table or not. Note that if this is disabled
10157
			 * then there is no filtering at all on the table, including fnFilter.
10158
			 * To just remove the filtering input use sDom and remove the 'f' option.
10159
			 * Note that this parameter will be set by the initialisation routine. To
10160
			 * set a default use {@link DataTable.defaults}.
10161
			 *  @type boolean
10162
			 */
10163
			"bFilter": null,
10164
 
10165
			/**
10166
			 * Table information element (the 'Showing x of y records' div) enable
10167
			 * flag.
10168
			 * Note that this parameter will be set by the initialisation routine. To
10169
			 * set a default use {@link DataTable.defaults}.
10170
			 *  @type boolean
10171
			 */
10172
			"bInfo": null,
10173
 
10174
			/**
10175
			 * Present a user control allowing the end user to change the page size
10176
			 * when pagination is enabled.
10177
			 * Note that this parameter will be set by the initialisation routine. To
10178
			 * set a default use {@link DataTable.defaults}.
10179
			 *  @type boolean
10180
			 */
10181
			"bLengthChange": null,
10182
 
10183
			/**
10184
			 * Pagination enabled or not. Note that if this is disabled then length
10185
			 * changing must also be disabled.
10186
			 * Note that this parameter will be set by the initialisation routine. To
10187
			 * set a default use {@link DataTable.defaults}.
10188
			 *  @type boolean
10189
			 */
10190
			"bPaginate": null,
10191
 
10192
			/**
10193
			 * Processing indicator enable flag whenever DataTables is enacting a
10194
			 * user request - typically an Ajax request for server-side processing.
10195
			 * Note that this parameter will be set by the initialisation routine. To
10196
			 * set a default use {@link DataTable.defaults}.
10197
			 *  @type boolean
10198
			 */
10199
			"bProcessing": null,
10200
 
10201
			/**
10202
			 * Server-side processing enabled flag - when enabled DataTables will
10203
			 * get all data from the server for every draw - there is no filtering,
10204
			 * sorting or paging done on the client-side.
10205
			 * Note that this parameter will be set by the initialisation routine. To
10206
			 * set a default use {@link DataTable.defaults}.
10207
			 *  @type boolean
10208
			 */
10209
			"bServerSide": null,
10210
 
10211
			/**
10212
			 * Sorting enablement flag.
10213
			 * Note that this parameter will be set by the initialisation routine. To
10214
			 * set a default use {@link DataTable.defaults}.
10215
			 *  @type boolean
10216
			 */
10217
			"bSort": null,
10218
 
10219
			/**
10220
			 * Apply a class to the columns which are being sorted to provide a
10221
			 * visual highlight or not. This can slow things down when enabled since
10222
			 * there is a lot of DOM interaction.
10223
			 * Note that this parameter will be set by the initialisation routine. To
10224
			 * set a default use {@link DataTable.defaults}.
10225
			 *  @type boolean
10226
			 */
10227
			"bSortClasses": null,
10228
 
10229
			/**
10230
			 * State saving enablement flag.
10231
			 * Note that this parameter will be set by the initialisation routine. To
10232
			 * set a default use {@link DataTable.defaults}.
10233
			 *  @type boolean
10234
			 */
10235
			"bStateSave": null
10236
		},
10237
 
10238
 
10239
		/**
10240
		 * Scrolling settings for a table.
10241
		 *  @namespace
10242
		 */
10243
		"oScroll": {
10244
			/**
10245
			 * Indicate if DataTables should be allowed to set the padding / margin
10246
			 * etc for the scrolling header elements or not. Typically you will want
10247
			 * this.
10248
			 * Note that this parameter will be set by the initialisation routine. To
10249
			 * set a default use {@link DataTable.defaults}.
10250
			 *  @type boolean
10251
			 */
10252
			"bAutoCss": null,
10253
 
10254
			/**
10255
			 * When the table is shorter in height than sScrollY, collapse the
10256
			 * table container down to the height of the table (when true).
10257
			 * Note that this parameter will be set by the initialisation routine. To
10258
			 * set a default use {@link DataTable.defaults}.
10259
			 *  @type boolean
10260
			 */
10261
			"bCollapse": null,
10262
 
10263
			/**
10264
			 * Infinite scrolling enablement flag. Now deprecated in favour of
10265
			 * using the Scroller plug-in.
10266
			 * Note that this parameter will be set by the initialisation routine. To
10267
			 * set a default use {@link DataTable.defaults}.
10268
			 *  @type boolean
10269
			 */
10270
			"bInfinite": null,
10271
 
10272
			/**
10273
			 * Width of the scrollbar for the web-browser's platform. Calculated
10274
			 * during table initialisation.
10275
			 *  @type int
10276
			 *  @default 0
10277
			 */
10278
			"iBarWidth": 0,
10279
 
10280
			/**
10281
			 * Space (in pixels) between the bottom of the scrolling container and 
10282
			 * the bottom of the scrolling viewport before the next page is loaded
10283
			 * when using infinite scrolling.
10284
			 * Note that this parameter will be set by the initialisation routine. To
10285
			 * set a default use {@link DataTable.defaults}.
10286
			 *  @type int
10287
			 */
10288
			"iLoadGap": null,
10289
 
10290
			/**
10291
			 * Viewport width for horizontal scrolling. Horizontal scrolling is 
10292
			 * disabled if an empty string.
10293
			 * Note that this parameter will be set by the initialisation routine. To
10294
			 * set a default use {@link DataTable.defaults}.
10295
			 *  @type string
10296
			 */
10297
			"sX": null,
10298
 
10299
			/**
10300
			 * Width to expand the table to when using x-scrolling. Typically you
10301
			 * should not need to use this.
10302
			 * Note that this parameter will be set by the initialisation routine. To
10303
			 * set a default use {@link DataTable.defaults}.
10304
			 *  @type string
10305
			 *  @deprecated
10306
			 */
10307
			"sXInner": null,
10308
 
10309
			/**
10310
			 * Viewport height for vertical scrolling. Vertical scrolling is disabled
10311
			 * if an empty string.
10312
			 * Note that this parameter will be set by the initialisation routine. To
10313
			 * set a default use {@link DataTable.defaults}.
10314
			 *  @type string
10315
			 */
10316
			"sY": null
10317
		},
10318
 
10319
		/**
10320
		 * Language information for the table.
10321
		 *  @namespace
10322
		 *  @extends DataTable.defaults.oLanguage
10323
		 */
10324
		"oLanguage": {
10325
			/**
10326
			 * Information callback function. See 
10327
			 * {@link DataTable.defaults.fnInfoCallback}
10328
			 *  @type function
10329
			 *  @default 
10330
			 */
10331
			"fnInfoCallback": null
10332
		},
10333
 
10334
		/**
10335
		 * Array referencing the nodes which are used for the features. The 
10336
		 * parameters of this object match what is allowed by sDom - i.e.
10337
		 *   <ul>
10338
		 *     <li>'l' - Length changing</li>
10339
		 *     <li>'f' - Filtering input</li>
10340
		 *     <li>'t' - The table!</li>
10341
		 *     <li>'i' - Information</li>
10342
		 *     <li>'p' - Pagination</li>
10343
		 *     <li>'r' - pRocessing</li>
10344
		 *   </ul>
10345
		 *  @type array
10346
		 *  @default []
10347
		 */
10348
		"aanFeatures": [],
10349
 
10350
		/**
10351
		 * Store data information - see {@link DataTable.models.oRow} for detailed
10352
		 * information.
10353
		 *  @type array
10354
		 *  @default []
10355
		 */
10356
		"aoData": [],
10357
 
10358
		/**
10359
		 * Array of indexes which are in the current display (after filtering etc)
10360
		 *  @type array
10361
		 *  @default []
10362
		 */
10363
		"aiDisplay": [],
10364
 
10365
		/**
10366
		 * Array of indexes for display - no filtering
10367
		 *  @type array
10368
		 *  @default []
10369
		 */
10370
		"aiDisplayMaster": [],
10371
 
10372
		/**
10373
		 * Store information about each column that is in use
10374
		 *  @type array
10375
		 *  @default []
10376
		 */
10377
		"aoColumns": [],
10378
 
10379
		/**
10380
		 * Store information about the table's header
10381
		 *  @type array
10382
		 *  @default []
10383
		 */
10384
		"aoHeader": [],
10385
 
10386
		/**
10387
		 * Store information about the table's footer
10388
		 *  @type array
10389
		 *  @default []
10390
		 */
10391
		"aoFooter": [],
10392
 
10393
		/**
10394
		 * Search data array for regular expression searching
10395
		 *  @type array
10396
		 *  @default []
10397
		 */
10398
		"asDataSearch": [],
10399
 
10400
		/**
10401
		 * Store the applied global search information in case we want to force a 
10402
		 * research or compare the old search to a new one.
10403
		 * Note that this parameter will be set by the initialisation routine. To
10404
		 * set a default use {@link DataTable.defaults}.
10405
		 *  @namespace
10406
		 *  @extends DataTable.models.oSearch
10407
		 */
10408
		"oPreviousSearch": {},
10409
 
10410
		/**
10411
		 * Store the applied search for each column - see 
10412
		 * {@link DataTable.models.oSearch} for the format that is used for the
10413
		 * filtering information for each column.
10414
		 *  @type array
10415
		 *  @default []
10416
		 */
10417
		"aoPreSearchCols": [],
10418
 
10419
		/**
10420
		 * Sorting that is applied to the table. Note that the inner arrays are
10421
		 * used in the following manner:
10422
		 * <ul>
10423
		 *   <li>Index 0 - column number</li>
10424
		 *   <li>Index 1 - current sorting direction</li>
10425
		 *   <li>Index 2 - index of asSorting for this column</li>
10426
		 * </ul>
10427
		 * Note that this parameter will be set by the initialisation routine. To
10428
		 * set a default use {@link DataTable.defaults}.
10429
		 *  @type array
10430
		 *  @todo These inner arrays should really be objects
10431
		 */
10432
		"aaSorting": null,
10433
 
10434
		/**
10435
		 * Sorting that is always applied to the table (i.e. prefixed in front of
10436
		 * aaSorting).
10437
		 * Note that this parameter will be set by the initialisation routine. To
10438
		 * set a default use {@link DataTable.defaults}.
10439
		 *  @type array|null
10440
		 *  @default null
10441
		 */
10442
		"aaSortingFixed": null,
10443
 
10444
		/**
10445
		 * Classes to use for the striping of a table.
10446
		 * Note that this parameter will be set by the initialisation routine. To
10447
		 * set a default use {@link DataTable.defaults}.
10448
		 *  @type array
10449
		 *  @default []
10450
		 */
10451
		"asStripeClasses": null,
10452
 
10453
		/**
10454
		 * If restoring a table - we should restore its striping classes as well
10455
		 *  @type array
10456
		 *  @default []
10457
		 */
10458
		"asDestroyStripes": [],
10459
 
10460
		/**
10461
		 * If restoring a table - we should restore its width 
10462
		 *  @type int
10463
		 *  @default 0
10464
		 */
10465
		"sDestroyWidth": 0,
10466
 
10467
		/**
10468
		 * Callback functions array for every time a row is inserted (i.e. on a draw).
10469
		 *  @type array
10470
		 *  @default []
10471
		 */
10472
		"aoRowCallback": [],
10473
 
10474
		/**
10475
		 * Callback functions for the header on each draw.
10476
		 *  @type array
10477
		 *  @default []
10478
		 */
10479
		"aoHeaderCallback": [],
10480
 
10481
		/**
10482
		 * Callback function for the footer on each draw.
10483
		 *  @type array
10484
		 *  @default []
10485
		 */
10486
		"aoFooterCallback": [],
10487
 
10488
		/**
10489
		 * Array of callback functions for draw callback functions
10490
		 *  @type array
10491
		 *  @default []
10492
		 */
10493
		"aoDrawCallback": [],
10494
 
10495
		/**
10496
		 * Array of callback functions for row created function
10497
		 *  @type array
10498
		 *  @default []
10499
		 */
10500
		"aoRowCreatedCallback": [],
10501
 
10502
		/**
10503
		 * Callback functions for just before the table is redrawn. A return of 
10504
		 * false will be used to cancel the draw.
10505
		 *  @type array
10506
		 *  @default []
10507
		 */
10508
		"aoPreDrawCallback": [],
10509
 
10510
		/**
10511
		 * Callback functions for when the table has been initialised.
10512
		 *  @type array
10513
		 *  @default []
10514
		 */
10515
		"aoInitComplete": [],
10516
 
10517
 
10518
		/**
10519
		 * Callbacks for modifying the settings to be stored for state saving, prior to
10520
		 * saving state.
10521
		 *  @type array
10522
		 *  @default []
10523
		 */
10524
		"aoStateSaveParams": [],
10525
 
10526
		/**
10527
		 * Callbacks for modifying the settings that have been stored for state saving
10528
		 * prior to using the stored values to restore the state.
10529
		 *  @type array
10530
		 *  @default []
10531
		 */
10532
		"aoStateLoadParams": [],
10533
 
10534
		/**
10535
		 * Callbacks for operating on the settings object once the saved state has been
10536
		 * loaded
10537
		 *  @type array
10538
		 *  @default []
10539
		 */
10540
		"aoStateLoaded": [],
10541
 
10542
		/**
10543
		 * Cache the table ID for quick access
10544
		 *  @type string
10545
		 *  @default <i>Empty string</i>
10546
		 */
10547
		"sTableId": "",
10548
 
10549
		/**
10550
		 * The TABLE node for the main table
10551
		 *  @type node
10552
		 *  @default null
10553
		 */
10554
		"nTable": null,
10555
 
10556
		/**
10557
		 * Permanent ref to the thead element
10558
		 *  @type node
10559
		 *  @default null
10560
		 */
10561
		"nTHead": null,
10562
 
10563
		/**
10564
		 * Permanent ref to the tfoot element - if it exists
10565
		 *  @type node
10566
		 *  @default null
10567
		 */
10568
		"nTFoot": null,
10569
 
10570
		/**
10571
		 * Permanent ref to the tbody element
10572
		 *  @type node
10573
		 *  @default null
10574
		 */
10575
		"nTBody": null,
10576
 
10577
		/**
10578
		 * Cache the wrapper node (contains all DataTables controlled elements)
10579
		 *  @type node
10580
		 *  @default null
10581
		 */
10582
		"nTableWrapper": null,
10583
 
10584
		/**
10585
		 * Indicate if when using server-side processing the loading of data 
10586
		 * should be deferred until the second draw.
10587
		 * Note that this parameter will be set by the initialisation routine. To
10588
		 * set a default use {@link DataTable.defaults}.
10589
		 *  @type boolean
10590
		 *  @default false
10591
		 */
10592
		"bDeferLoading": false,
10593
 
10594
		/**
10595
		 * Indicate if all required information has been read in
10596
		 *  @type boolean
10597
		 *  @default false
10598
		 */
10599
		"bInitialised": false,
10600
 
10601
		/**
10602
		 * Information about open rows. Each object in the array has the parameters
10603
		 * 'nTr' and 'nParent'
10604
		 *  @type array
10605
		 *  @default []
10606
		 */
10607
		"aoOpenRows": [],
10608
 
10609
		/**
10610
		 * Dictate the positioning of DataTables' control elements - see
10611
		 * {@link DataTable.model.oInit.sDom}.
10612
		 * Note that this parameter will be set by the initialisation routine. To
10613
		 * set a default use {@link DataTable.defaults}.
10614
		 *  @type string
10615
		 *  @default null
10616
		 */
10617
		"sDom": null,
10618
 
10619
		/**
10620
		 * Which type of pagination should be used.
10621
		 * Note that this parameter will be set by the initialisation routine. To
10622
		 * set a default use {@link DataTable.defaults}.
10623
		 *  @type string 
10624
		 *  @default two_button
10625
		 */
10626
		"sPaginationType": "two_button",
10627
 
10628
		/**
10629
		 * The cookie duration (for bStateSave) in seconds.
10630
		 * Note that this parameter will be set by the initialisation routine. To
10631
		 * set a default use {@link DataTable.defaults}.
10632
		 *  @type int
10633
		 *  @default 0
10634
		 */
10635
		"iCookieDuration": 0,
10636
 
10637
		/**
10638
		 * The cookie name prefix.
10639
		 * Note that this parameter will be set by the initialisation routine. To
10640
		 * set a default use {@link DataTable.defaults}.
10641
		 *  @type string
10642
		 *  @default <i>Empty string</i>
10643
		 */
10644
		"sCookiePrefix": "",
10645
 
10646
		/**
10647
		 * Callback function for cookie creation.
10648
		 * Note that this parameter will be set by the initialisation routine. To
10649
		 * set a default use {@link DataTable.defaults}.
10650
		 *  @type function
10651
		 *  @default null
10652
		 */
10653
		"fnCookieCallback": null,
10654
 
10655
		/**
10656
		 * Array of callback functions for state saving. Each array element is an 
10657
		 * object with the following parameters:
10658
		 *   <ul>
10659
		 *     <li>function:fn - function to call. Takes two parameters, oSettings
10660
		 *       and the JSON string to save that has been thus far created. Returns
10661
		 *       a JSON string to be inserted into a json object 
10662
		 *       (i.e. '"param": [ 0, 1, 2]')</li>
10663
		 *     <li>string:sName - name of callback</li>
10664
		 *   </ul>
10665
		 *  @type array
10666
		 *  @default []
10667
		 */
10668
		"aoStateSave": [],
10669
 
10670
		/**
10671
		 * Array of callback functions for state loading. Each array element is an 
10672
		 * object with the following parameters:
10673
		 *   <ul>
10674
		 *     <li>function:fn - function to call. Takes two parameters, oSettings 
10675
		 *       and the object stored. May return false to cancel state loading</li>
10676
		 *     <li>string:sName - name of callback</li>
10677
		 *   </ul>
10678
		 *  @type array
10679
		 *  @default []
10680
		 */
10681
		"aoStateLoad": [],
10682
 
10683
		/**
10684
		 * State that was loaded from the cookie. Useful for back reference
10685
		 *  @type object
10686
		 *  @default null
10687
		 */
10688
		"oLoadedState": null,
10689
 
10690
		/**
10691
		 * Source url for AJAX data for the table.
10692
		 * Note that this parameter will be set by the initialisation routine. To
10693
		 * set a default use {@link DataTable.defaults}.
10694
		 *  @type string
10695
		 *  @default null
10696
		 */
10697
		"sAjaxSource": null,
10698
 
10699
		/**
10700
		 * Property from a given object from which to read the table data from. This
10701
		 * can be an empty string (when not server-side processing), in which case 
10702
		 * it is  assumed an an array is given directly.
10703
		 * Note that this parameter will be set by the initialisation routine. To
10704
		 * set a default use {@link DataTable.defaults}.
10705
		 *  @type string
10706
		 */
10707
		"sAjaxDataProp": null,
10708
 
10709
		/**
10710
		 * Note if draw should be blocked while getting data
10711
		 *  @type boolean
10712
		 *  @default true
10713
		 */
10714
		"bAjaxDataGet": true,
10715
 
10716
		/**
10717
		 * The last jQuery XHR object that was used for server-side data gathering. 
10718
		 * This can be used for working with the XHR information in one of the 
10719
		 * callbacks
10720
		 *  @type object
10721
		 *  @default null
10722
		 */
10723
		"jqXHR": null,
10724
 
10725
		/**
10726
		 * Function to get the server-side data.
10727
		 * Note that this parameter will be set by the initialisation routine. To
10728
		 * set a default use {@link DataTable.defaults}.
10729
		 *  @type function
10730
		 */
10731
		"fnServerData": null,
10732
 
10733
		/**
10734
		 * Functions which are called prior to sending an Ajax request so extra 
10735
		 * parameters can easily be sent to the server
10736
		 *  @type array
10737
		 *  @default []
10738
		 */
10739
		"aoServerParams": [],
10740
 
10741
		/**
10742
		 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 
10743
		 * required).
10744
		 * Note that this parameter will be set by the initialisation routine. To
10745
		 * set a default use {@link DataTable.defaults}.
10746
		 *  @type string
10747
		 */
10748
		"sServerMethod": null,
10749
 
10750
		/**
10751
		 * Format numbers for display.
10752
		 * Note that this parameter will be set by the initialisation routine. To
10753
		 * set a default use {@link DataTable.defaults}.
10754
		 *  @type function
10755
		 */
10756
		"fnFormatNumber": null,
10757
 
10758
		/**
10759
		 * List of options that can be used for the user selectable length menu.
10760
		 * Note that this parameter will be set by the initialisation routine. To
10761
		 * set a default use {@link DataTable.defaults}.
10762
		 *  @type array
10763
		 *  @default []
10764
		 */
10765
		"aLengthMenu": null,
10766
 
10767
		/**
10768
		 * Counter for the draws that the table does. Also used as a tracker for
10769
		 * server-side processing
10770
		 *  @type int
10771
		 *  @default 0
10772
		 */
10773
		"iDraw": 0,
10774
 
10775
		/**
10776
		 * Indicate if a redraw is being done - useful for Ajax
10777
		 *  @type boolean
10778
		 *  @default false
10779
		 */
10780
		"bDrawing": false,
10781
 
10782
		/**
10783
		 * Draw index (iDraw) of the last error when parsing the returned data
10784
		 *  @type int
10785
		 *  @default -1
10786
		 */
10787
		"iDrawError": -1,
10788
 
10789
		/**
10790
		 * Paging display length
10791
		 *  @type int
10792
		 *  @default 10
10793
		 */
10794
		"_iDisplayLength": 10,
10795
 
10796
		/**
10797
		 * Paging start point - aiDisplay index
10798
		 *  @type int
10799
		 *  @default 0
10800
		 */
10801
		"_iDisplayStart": 0,
10802
 
10803
		/**
10804
		 * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
10805
		 * this property to get the end point
10806
		 *  @type int
10807
		 *  @default 10
10808
		 *  @private
10809
		 */
10810
		"_iDisplayEnd": 10,
10811
 
10812
		/**
10813
		 * Server-side processing - number of records in the result set
10814
		 * (i.e. before filtering), Use fnRecordsTotal rather than
10815
		 * this property to get the value of the number of records, regardless of
10816
		 * the server-side processing setting.
10817
		 *  @type int
10818
		 *  @default 0
10819
		 *  @private
10820
		 */
10821
		"_iRecordsTotal": 0,
10822
 
10823
		/**
10824
		 * Server-side processing - number of records in the current display set
10825
		 * (i.e. after filtering). Use fnRecordsDisplay rather than
10826
		 * this property to get the value of the number of records, regardless of
10827
		 * the server-side processing setting.
10828
		 *  @type boolean
10829
		 *  @default 0
10830
		 *  @private
10831
		 */
10832
		"_iRecordsDisplay": 0,
10833
 
10834
		/**
10835
		 * Flag to indicate if jQuery UI marking and classes should be used.
10836
		 * Note that this parameter will be set by the initialisation routine. To
10837
		 * set a default use {@link DataTable.defaults}.
10838
		 *  @type boolean
10839
		 */
10840
		"bJUI": null,
10841
 
10842
		/**
10843
		 * The classes to use for the table
10844
		 *  @type object
10845
		 *  @default {}
10846
		 */
10847
		"oClasses": {},
10848
 
10849
		/**
10850
		 * Flag attached to the settings object so you can check in the draw 
10851
		 * callback if filtering has been done in the draw. Deprecated in favour of
10852
		 * events.
10853
		 *  @type boolean
10854
		 *  @default false
10855
		 *  @deprecated
10856
		 */
10857
		"bFiltered": false,
10858
 
10859
		/**
10860
		 * Flag attached to the settings object so you can check in the draw 
10861
		 * callback if sorting has been done in the draw. Deprecated in favour of
10862
		 * events.
10863
		 *  @type boolean
10864
		 *  @default false
10865
		 *  @deprecated
10866
		 */
10867
		"bSorted": false,
10868
 
10869
		/**
10870
		 * Indicate that if multiple rows are in the header and there is more than 
10871
		 * one unique cell per column, if the top one (true) or bottom one (false) 
10872
		 * should be used for sorting / title by DataTables.
10873
		 * Note that this parameter will be set by the initialisation routine. To
10874
		 * set a default use {@link DataTable.defaults}.
10875
		 *  @type boolean
10876
		 */
10877
		"bSortCellsTop": null,
10878
 
10879
		/**
10880
		 * Initialisation object that is used for the table
10881
		 *  @type object
10882
		 *  @default null
10883
		 */
10884
		"oInit": null,
10885
 
10886
		/**
10887
		 * Destroy callback functions - for plug-ins to attach themselves to the
10888
		 * destroy so they can clean up markup and events.
10889
		 *  @type array
10890
		 *  @default []
10891
		 */
10892
		"aoDestroyCallback": [],
10893
 
10894
 
10895
		/**
10896
		 * Get the number of records in the current record set, before filtering
10897
		 *  @type function
10898
		 */
10899
		"fnRecordsTotal": function ()
10900
		{
10901
			if ( this.oFeatures.bServerSide ) {
10902
				return parseInt(this._iRecordsTotal, 10);
10903
			} else {
10904
				return this.aiDisplayMaster.length;
10905
			}
10906
		},
10907
 
10908
		/**
10909
		 * Get the number of records in the current record set, after filtering
10910
		 *  @type function
10911
		 */
10912
		"fnRecordsDisplay": function ()
10913
		{
10914
			if ( this.oFeatures.bServerSide ) {
10915
				return parseInt(this._iRecordsDisplay, 10);
10916
			} else {
10917
				return this.aiDisplay.length;
10918
			}
10919
		},
10920
 
10921
		/**
10922
		 * Set the display end point - aiDisplay index
10923
		 *  @type function
10924
		 *  @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
10925
		 */
10926
		"fnDisplayEnd": function ()
10927
		{
10928
			if ( this.oFeatures.bServerSide ) {
10929
				if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
10930
					return this._iDisplayStart+this.aiDisplay.length;
10931
				} else {
10932
					return Math.min( this._iDisplayStart+this._iDisplayLength, 
10933
						this._iRecordsDisplay );
10934
				}
10935
			} else {
10936
				return this._iDisplayEnd;
10937
			}
10938
		},
10939
 
10940
		/**
10941
		 * The DataTables object for this table
10942
		 *  @type object
10943
		 *  @default null
10944
		 */
10945
		"oInstance": null,
10946
 
10947
		/**
10948
		 * Unique identifier for each instance of the DataTables object. If there
10949
		 * is an ID on the table node, then it takes that value, otherwise an
10950
		 * incrementing internal counter is used.
10951
		 *  @type string
10952
		 *  @default null
10953
		 */
10954
		"sInstance": null,
10955
 
10956
		/**
10957
		 * tabindex attribute value that is added to DataTables control elements, allowing
10958
		 * keyboard navigation of the table and its controls.
10959
		 */
10960
		"iTabIndex": 0
10961
	};
10962
 
10963
	/**
10964
	 * Extension object for DataTables that is used to provide all extension options.
10965
	 * 
10966
	 * Note that the <i>DataTable.ext</i> object is available through
10967
	 * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
10968
	 * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
10969
	 *  @namespace
10970
	 *  @extends DataTable.models.ext
10971
	 */
10972
	DataTable.ext = $.extend( true, {}, DataTable.models.ext );
10973
 
10974
	$.extend( DataTable.ext.oStdClasses, {
10975
		"sTable": "dataTable",
10976
 
10977
		/* Two buttons buttons */
10978
		"sPagePrevEnabled": "paginate_enabled_previous",
10979
		"sPagePrevDisabled": "paginate_disabled_previous",
10980
		"sPageNextEnabled": "paginate_enabled_next",
10981
		"sPageNextDisabled": "paginate_disabled_next",
10982
		"sPageJUINext": "",
10983
		"sPageJUIPrev": "",
10984
 
10985
		/* Full numbers paging buttons */
10986
		"sPageButton": "paginate_button",
10987
		"sPageButtonActive": "paginate_active",
10988
		"sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
10989
		"sPageFirst": "first",
10990
		"sPagePrevious": "previous",
10991
		"sPageNext": "next",
10992
		"sPageLast": "last",
10993
 
10994
		/* Striping classes */
10995
		"sStripeOdd": "odd",
10996
		"sStripeEven": "even",
10997
 
10998
		/* Empty row */
10999
		"sRowEmpty": "dataTables_empty",
11000
 
11001
		/* Features */
11002
		"sWrapper": "dataTables_wrapper",
11003
		"sFilter": "dataTables_filter",
11004
		"sInfo": "dataTables_info",
11005
		"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
11006
		"sLength": "dataTables_length",
11007
		"sProcessing": "dataTables_processing",
11008
 
11009
		/* Sorting */
11010
		"sSortAsc": "sorting_asc",
11011
		"sSortDesc": "sorting_desc",
11012
		"sSortable": "sorting", /* Sortable in both directions */
11013
		"sSortableAsc": "sorting_asc_disabled",
11014
		"sSortableDesc": "sorting_desc_disabled",
11015
		"sSortableNone": "sorting_disabled",
11016
		"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
11017
		"sSortJUIAsc": "",
11018
		"sSortJUIDesc": "",
11019
		"sSortJUI": "",
11020
		"sSortJUIAscAllowed": "",
11021
		"sSortJUIDescAllowed": "",
11022
		"sSortJUIWrapper": "",
11023
		"sSortIcon": "",
11024
 
11025
		/* Scrolling */
11026
		"sScrollWrapper": "dataTables_scroll",
11027
		"sScrollHead": "dataTables_scrollHead",
11028
		"sScrollHeadInner": "dataTables_scrollHeadInner",
11029
		"sScrollBody": "dataTables_scrollBody",
11030
		"sScrollFoot": "dataTables_scrollFoot",
11031
		"sScrollFootInner": "dataTables_scrollFootInner",
11032
 
11033
		/* Misc */
11034
		"sFooterTH": ""
11035
	} );
11036
 
11037
 
11038
	$.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
11039
		/* Two buttons buttons */
11040
		"sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
11041
		"sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
11042
		"sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
11043
		"sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
11044
		"sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
11045
		"sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
11046
 
11047
		/* Full numbers paging buttons */
11048
		"sPageButton": "fg-button ui-button ui-state-default",
11049
		"sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
11050
		"sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
11051
		"sPageFirst": "first ui-corner-tl ui-corner-bl",
11052
		"sPageLast": "last ui-corner-tr ui-corner-br",
11053
 
11054
		/* Features */
11055
		"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
11056
			"ui-buttonset-multi paging_", /* Note that the type is postfixed */
11057
 
11058
		/* Sorting */
11059
		"sSortAsc": "ui-state-default",
11060
		"sSortDesc": "ui-state-default",
11061
		"sSortable": "ui-state-default",
11062
		"sSortableAsc": "ui-state-default",
11063
		"sSortableDesc": "ui-state-default",
11064
		"sSortableNone": "ui-state-default",
11065
		"sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
11066
		"sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
11067
		"sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
11068
		"sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
11069
		"sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
11070
		"sSortJUIWrapper": "DataTables_sort_wrapper",
11071
		"sSortIcon": "DataTables_sort_icon",
11072
 
11073
		/* Scrolling */
11074
		"sScrollHead": "dataTables_scrollHead ui-state-default",
11075
		"sScrollFoot": "dataTables_scrollFoot ui-state-default",
11076
 
11077
		/* Misc */
11078
		"sFooterTH": "ui-state-default"
11079
	} );
11080
 
11081
 
11082
	/*
11083
	 * Variable: oPagination
11084
	 * Purpose:  
11085
	 * Scope:    jQuery.fn.dataTableExt
11086
	 */
11087
	$.extend( DataTable.ext.oPagination, {
11088
		/*
11089
		 * Variable: two_button
11090
		 * Purpose:  Standard two button (forward/back) pagination
11091
		 * Scope:    jQuery.fn.dataTableExt.oPagination
11092
		 */
11093
		"two_button": {
11094
			/*
11095
			 * Function: oPagination.two_button.fnInit
11096
			 * Purpose:  Initialise dom elements required for pagination with forward/back buttons only
11097
			 * Returns:  -
11098
			 * Inputs:   object:oSettings - dataTables settings object
11099
			 *           node:nPaging - the DIV which contains this pagination control
11100
			 *           function:fnCallbackDraw - draw function which must be called on update
11101
			 */
11102
			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
11103
			{
11104
				var oLang = oSettings.oLanguage.oPaginate;
11105
				var oClasses = oSettings.oClasses;
11106
				var fnClickHandler = function ( e ) {
11107
					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
11108
					{
11109
						fnCallbackDraw( oSettings );
11110
					}
11111
				};
11112
 
11113
				var sAppend = (!oSettings.bJUI) ?
11114
					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
11115
					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
11116
					:
11117
					'<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
11118
					'<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
11119
				$(nPaging).append( sAppend );
11120
 
11121
				var els = $('a', nPaging);
11122
				var nPrevious = els[0],
11123
					nNext = els[1];
11124
 
11125
				oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
11126
				oSettings.oApi._fnBindAction( nNext,     {action: "next"},     fnClickHandler );
11127
 
11128
				/* ID the first elements only */
11129
				if ( !oSettings.aanFeatures.p )
11130
				{
11131
					nPaging.id = oSettings.sTableId+'_paginate';
11132
					nPrevious.id = oSettings.sTableId+'_previous';
11133
					nNext.id = oSettings.sTableId+'_next';
11134
 
11135
					nPrevious.setAttribute('aria-controls', oSettings.sTableId);
11136
					nNext.setAttribute('aria-controls', oSettings.sTableId);
11137
				}
11138
			},
11139
 
11140
			/*
11141
			 * Function: oPagination.two_button.fnUpdate
11142
			 * Purpose:  Update the two button pagination at the end of the draw
11143
			 * Returns:  -
11144
			 * Inputs:   object:oSettings - dataTables settings object
11145
			 *           function:fnCallbackDraw - draw function to call on page change
11146
			 */
11147
			"fnUpdate": function ( oSettings, fnCallbackDraw )
11148
			{
11149
				if ( !oSettings.aanFeatures.p )
11150
				{
11151
					return;
11152
				}
11153
 
11154
				var oClasses = oSettings.oClasses;
11155
				var an = oSettings.aanFeatures.p;
11156
 
11157
				/* Loop over each instance of the pager */
11158
				for ( var i=0, iLen=an.length ; i<iLen ; i++ )
11159
				{
11160
					if ( an[i].childNodes.length !== 0 )
11161
					{
11162
						an[i].childNodes[0].className = ( oSettings._iDisplayStart === 0 ) ? 
11163
							oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
11164
 
11165
						an[i].childNodes[1].className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ? 
11166
							oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
11167
					}
11168
				}
11169
			}
11170
		},
11171
 
11172
 
11173
		/*
11174
		 * Variable: iFullNumbersShowPages
11175
		 * Purpose:  Change the number of pages which can be seen
11176
		 * Scope:    jQuery.fn.dataTableExt.oPagination
11177
		 */
11178
		"iFullNumbersShowPages": 5,
11179
 
11180
		/*
11181
		 * Variable: full_numbers
11182
		 * Purpose:  Full numbers pagination
11183
		 * Scope:    jQuery.fn.dataTableExt.oPagination
11184
		 */
11185
		"full_numbers": {
11186
			/*
11187
			 * Function: oPagination.full_numbers.fnInit
11188
			 * Purpose:  Initialise dom elements required for pagination with a list of the pages
11189
			 * Returns:  -
11190
			 * Inputs:   object:oSettings - dataTables settings object
11191
			 *           node:nPaging - the DIV which contains this pagination control
11192
			 *           function:fnCallbackDraw - draw function which must be called on update
11193
			 */
11194
			"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
11195
			{
11196
				var oLang = oSettings.oLanguage.oPaginate;
11197
				var oClasses = oSettings.oClasses;
11198
				var fnClickHandler = function ( e ) {
11199
					if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
11200
					{
11201
						fnCallbackDraw( oSettings );
11202
					}
11203
				};
11204
 
11205
				$(nPaging).append(
11206
					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
11207
					'<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
11208
					'<span></span>'+
11209
					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
11210
					'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
11211
				);
11212
				var els = $('a', nPaging);
11213
				var nFirst = els[0],
11214
					nPrev = els[1],
11215
					nNext = els[2],
11216
					nLast = els[3];
11217
 
11218
				oSettings.oApi._fnBindAction( nFirst, {action: "first"},    fnClickHandler );
11219
				oSettings.oApi._fnBindAction( nPrev,  {action: "previous"}, fnClickHandler );
11220
				oSettings.oApi._fnBindAction( nNext,  {action: "next"},     fnClickHandler );
11221
				oSettings.oApi._fnBindAction( nLast,  {action: "last"},     fnClickHandler );
11222
 
11223
				/* ID the first elements only */
11224
				if ( !oSettings.aanFeatures.p )
11225
				{
11226
					nPaging.id = oSettings.sTableId+'_paginate';
11227
					nFirst.id =oSettings.sTableId+'_first';
11228
					nPrev.id =oSettings.sTableId+'_previous';
11229
					nNext.id =oSettings.sTableId+'_next';
11230
					nLast.id =oSettings.sTableId+'_last';
11231
				}
11232
			},
11233
 
11234
			/*
11235
			 * Function: oPagination.full_numbers.fnUpdate
11236
			 * Purpose:  Update the list of page buttons shows
11237
			 * Returns:  -
11238
			 * Inputs:   object:oSettings - dataTables settings object
11239
			 *           function:fnCallbackDraw - draw function to call on page change
11240
			 */
11241
			"fnUpdate": function ( oSettings, fnCallbackDraw )
11242
			{
11243
				if ( !oSettings.aanFeatures.p )
11244
				{
11245
					return;
11246
				}
11247
 
11248
				var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
11249
				var iPageCountHalf = Math.floor(iPageCount / 2);
11250
				var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
11251
				var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
11252
				var sList = "";
11253
				var iStartButton, iEndButton, i, iLen;
11254
				var oClasses = oSettings.oClasses;
11255
				var anButtons, anStatic, nPaginateList;
11256
				var an = oSettings.aanFeatures.p;
11257
				var fnBind = function (j) {
11258
					oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
11259
						/* Use the information in the element to jump to the required page */
11260
						oSettings.oApi._fnPageChange( oSettings, e.data.page );
11261
						fnCallbackDraw( oSettings );
11262
						e.preventDefault();
11263
					} );
11264
				};
11265
 
11266
				/* Pages calculation */
11267
				if (iPages < iPageCount)
11268
				{
11269
					iStartButton = 1;
11270
					iEndButton = iPages;
11271
				}
11272
				else if (iCurrentPage <= iPageCountHalf)
11273
				{
11274
					iStartButton = 1;
11275
					iEndButton = iPageCount;
11276
				}
11277
				else if (iCurrentPage >= (iPages - iPageCountHalf))
11278
				{
11279
					iStartButton = iPages - iPageCount + 1;
11280
					iEndButton = iPages;
11281
				}
11282
				else
11283
				{
11284
					iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
11285
					iEndButton = iStartButton + iPageCount - 1;
11286
				}
11287
 
11288
				/* Build the dynamic list */
11289
				for ( i=iStartButton ; i<=iEndButton ; i++ )
11290
				{
11291
					sList += (iCurrentPage !== i) ?
11292
						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
11293
						'<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
11294
				}
11295
 
11296
				/* Loop over each instance of the pager */
11297
				for ( i=0, iLen=an.length ; i<iLen ; i++ )
11298
				{
11299
					if ( an[i].childNodes.length === 0 )
11300
					{
11301
						continue;
11302
					}
11303
 
11304
					/* Build up the dynamic list forst - html and listeners */
11305
					$('span:eq(0)', an[i])
11306
						.html( sList )
11307
						.children('a').each( fnBind );
11308
 
11309
					/* Update the premanent botton's classes */
11310
					anButtons = an[i].getElementsByTagName('a');
11311
					anStatic = [
11312
						anButtons[0], anButtons[1], 
11313
						anButtons[anButtons.length-2], anButtons[anButtons.length-1]
11314
					];
11315
 
11316
					$(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
11317
					$([anStatic[0], anStatic[1]]).addClass( 
11318
						(iCurrentPage==1) ?
11319
							oClasses.sPageButtonStaticDisabled :
11320
							oClasses.sPageButton
11321
					);
11322
					$([anStatic[2], anStatic[3]]).addClass(
11323
						(iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
11324
							oClasses.sPageButtonStaticDisabled :
11325
							oClasses.sPageButton
11326
					);
11327
				}
11328
			}
11329
		}
11330
	} );
11331
 
11332
	$.extend( DataTable.ext.oSort, {
11333
		/*
11334
		 * text sorting
11335
		 */
11336
		"string-pre": function ( a )
11337
		{
11338
			if ( typeof a != 'string' ) { a = ''; }
11339
			return a.toLowerCase();
11340
		},
11341
 
11342
		"string-asc": function ( x, y )
11343
		{
11344
			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
11345
		},
11346
 
11347
		"string-desc": function ( x, y )
11348
		{
11349
			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
11350
		},
11351
 
11352
 
11353
		/*
11354
		 * html sorting (ignore html tags)
11355
		 */
11356
		"html-pre": function ( a )
11357
		{
11358
			return a.replace( /<.*?>/g, "" ).toLowerCase();
11359
		},
11360
 
11361
		"html-asc": function ( x, y )
11362
		{
11363
			return ((x < y) ? -1 : ((x > y) ? 1 : 0));
11364
		},
11365
 
11366
		"html-desc": function ( x, y )
11367
		{
11368
			return ((x < y) ? 1 : ((x > y) ? -1 : 0));
11369
		},
11370
 
11371
 
11372
		/*
11373
		 * date sorting
11374
		 */
11375
		"date-pre": function ( a )
11376
		{
11377
			var x = Date.parse( a );
11378
 
11379
			if ( isNaN(x) || x==="" )
11380
			{
11381
				x = Date.parse( "01/01/1970 00:00:00" );
11382
			}
11383
			return x;
11384
		},
11385
 
11386
		"date-asc": function ( x, y )
11387
		{
11388
			return x - y;
11389
		},
11390
 
11391
		"date-desc": function ( x, y )
11392
		{
11393
			return y - x;
11394
		},
11395
 
11396
 
11397
		/*
11398
		 * numerical sorting
11399
		 */
11400
		"numeric-pre": function ( a )
11401
		{
11402
			return (a=="-" || a==="") ? 0 : a*1;
11403
		},
11404
 
11405
		"numeric-asc": function ( x, y )
11406
		{
11407
			return x - y;
11408
		},
11409
 
11410
		"numeric-desc": function ( x, y )
11411
		{
11412
			return y - x;
11413
		}
11414
	} );
11415
 
11416
 
11417
	$.extend( DataTable.ext.aTypes, [
11418
		/*
11419
		 * Function: -
11420
		 * Purpose:  Check to see if a string is numeric
11421
		 * Returns:  string:'numeric' or null
11422
		 * Inputs:   mixed:sText - string to check
11423
		 */
11424
		function ( sData )
11425
		{
11426
			/* Allow zero length strings as a number */
11427
			if ( typeof sData === 'number' )
11428
			{
11429
				return 'numeric';
11430
			}
11431
			else if ( typeof sData !== 'string' )
11432
			{
11433
				return null;
11434
			}
11435
 
11436
			var sValidFirstChars = "0123456789-";
11437
			var sValidChars = "0123456789.";
11438
			var Char;
11439
			var bDecimal = false;
11440
 
11441
			/* Check for a valid first char (no period and allow negatives) */
11442
			Char = sData.charAt(0); 
11443
			if (sValidFirstChars.indexOf(Char) == -1) 
11444
			{
11445
				return null;
11446
			}
11447
 
11448
			/* Check all the other characters are valid */
11449
			for ( var i=1 ; i<sData.length ; i++ ) 
11450
			{
11451
				Char = sData.charAt(i); 
11452
				if (sValidChars.indexOf(Char) == -1) 
11453
				{
11454
					return null;
11455
				}
11456
 
11457
				/* Only allowed one decimal place... */
11458
				if ( Char == "." )
11459
				{
11460
					if ( bDecimal )
11461
					{
11462
						return null;
11463
					}
11464
					bDecimal = true;
11465
				}
11466
			}
11467
 
11468
			return 'numeric';
11469
		},
11470
 
11471
		/*
11472
		 * Function: -
11473
		 * Purpose:  Check to see if a string is actually a formatted date
11474
		 * Returns:  string:'date' or null
11475
		 * Inputs:   string:sText - string to check
11476
		 */
11477
		function ( sData )
11478
		{
11479
			var iParse = Date.parse(sData);
11480
			if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
11481
			{
11482
				return 'date';
11483
			}
11484
			return null;
11485
		},
11486
 
11487
		/*
11488
		 * Function: -
11489
		 * Purpose:  Check to see if a string should be treated as an HTML string
11490
		 * Returns:  string:'html' or null
11491
		 * Inputs:   string:sText - string to check
11492
		 */
11493
		function ( sData )
11494
		{
11495
			if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
11496
			{
11497
				return 'html';
11498
			}
11499
			return null;
11500
		}
11501
	] );
11502
 
11503
 
11504
	// jQuery aliases
11505
	$.fn.DataTable = DataTable;
11506
	$.fn.dataTable = DataTable;
11507
	$.fn.dataTableSettings = DataTable.settings;
11508
	$.fn.dataTableExt = DataTable.ext;
11509
 
11510
 
11511
	// Information about events fired by DataTables - for documentation.
11512
	/**
11513
	 * Draw event, fired whenever the table is redrawn on the page, at the same point as
11514
	 * fnDrawCallback. This may be useful for binding events or performing calculations when
11515
	 * the table is altered at all.
11516
	 *  @name DataTable#draw
11517
	 *  @event
11518
	 *  @param {event} e jQuery event object
11519
	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11520
	 */
11521
 
11522
	/**
11523
	 * Filter event, fired when the filtering applied to the table (using the build in global
11524
	 * global filter, or column filters) is altered.
11525
	 *  @name DataTable#filter
11526
	 *  @event
11527
	 *  @param {event} e jQuery event object
11528
	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11529
	 */
11530
 
11531
	/**
11532
	 * Page change event, fired when the paging of the table is altered.
11533
	 *  @name DataTable#page
11534
	 *  @event
11535
	 *  @param {event} e jQuery event object
11536
	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11537
	 */
11538
 
11539
	/**
11540
	 * Sort event, fired when the sorting applied to the table is altered.
11541
	 *  @name DataTable#sort
11542
	 *  @event
11543
	 *  @param {event} e jQuery event object
11544
	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11545
	 */
11546
 
11547
	/**
11548
	 * DataTables initialisation complete event, fired when the table is fully drawn,
11549
	 * including Ajax data loaded, if Ajax data is required.
11550
	 *  @name DataTable#init
11551
	 *  @event
11552
	 *  @param {event} e jQuery event object
11553
	 *  @param {object} oSettings DataTables settings object
11554
	 *  @param {object} json The JSON object request from the server - only
11555
	 *    present if client-side Ajax sourced data is used</li></ol>
11556
	 */
11557
 
11558
	/**
11559
	 * State save event, fired when the table has changed state a new state save is required.
11560
	 * This method allows modification of the state saving object prior to actually doing the
11561
	 * save, including addition or other state properties (for plug-ins) or modification
11562
	 * of a DataTables core property.
11563
	 *  @name DataTable#stateSaveParams
11564
	 *  @event
11565
	 *  @param {event} e jQuery event object
11566
	 *  @param {object} oSettings DataTables settings object
11567
	 *  @param {object} json The state information to be saved
11568
	 */
11569
 
11570
	/**
11571
	 * State load event, fired when the table is loading state from the stored data, but
11572
	 * prior to the settings object being modified by the saved state - allowing modification
11573
	 * of the saved state is required or loading of state for a plug-in.
11574
	 *  @name DataTable#stateLoadParams
11575
	 *  @event
11576
	 *  @param {event} e jQuery event object
11577
	 *  @param {object} oSettings DataTables settings object
11578
	 *  @param {object} json The saved state information
11579
	 */
11580
 
11581
	/**
11582
	 * State loaded event, fired when state has been loaded from stored data and the settings
11583
	 * object has been modified by the loaded data.
11584
	 *  @name DataTable#stateLoaded
11585
	 *  @event
11586
	 *  @param {event} e jQuery event object
11587
	 *  @param {object} oSettings DataTables settings object
11588
	 *  @param {object} json The saved state information
11589
	 */
11590
 
11591
	/**
11592
	 * Processing event, fired when DataTables is doing some kind of processing (be it,
11593
	 * sort, filter or anything else). Can be used to indicate to the end user that
11594
	 * there is something happening, or that something has finished.
11595
	 *  @name DataTable#processing
11596
	 *  @event
11597
	 *  @param {event} e jQuery event object
11598
	 *  @param {object} oSettings DataTables settings object
11599
	 *  @param {boolean} bShow Flag for if DataTables is doing processing or not
11600
	 */
11601
 
11602
	/**
11603
	 * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to 
11604
	 * made to the server for new data (note that this trigger is called in fnServerData,
11605
	 * if you override fnServerData and which to use this event, you need to trigger it in
11606
	 * you success function).
11607
	 *  @name DataTable#xhr
11608
	 *  @event
11609
	 *  @param {event} e jQuery event object
11610
	 *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
11611
	 */
11612
}(jQuery, window, document, undefined));