Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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