Project

General

Profile

Download (36.5 KB) Statistics
| Branch: | Tag: | Revision:
1
/**
2
 * Perform a jQuery selector action on the table's TR elements (from the tbody) and
3
 * return the resulting jQuery object.
4
 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5
 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
6
 *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
7
 *    criterion ("applied") or all TR elements (i.e. no filter).
8
 *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
9
 *    Can be either 'current', whereby the current sorting of the table is used, or
10
 *    'original' whereby the original order the data was read into the table is used.
11
 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
12
 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
13
 *    'current' and filter is 'applied', regardless of what they might be given as.
14
 *  @returns {object} jQuery object, filtered by the given selector.
15
 *  @dtopt API
16
 *
17
 *  @example
18
 *    $(document).ready(function() {
19
 *      var oTable = $('#example').dataTable();
20
 *
21
 *      // Highlight every second row
22
 *      oTable.$('tr:odd').css('backgroundColor', 'blue');
23
 *    } );
24
 *
25
 *  @example
26
 *    $(document).ready(function() {
27
 *      var oTable = $('#example').dataTable();
28
 *
29
 *      // Filter to rows with 'Webkit' in them, add a background colour and then
30
 *      // remove the filter, thus highlighting the 'Webkit' rows only.
31
 *      oTable.fnFilter('Webkit');
32
 *      oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
33
 *      oTable.fnFilter('');
34
 *    } );
35
 */
36
this.$ = function ( sSelector, oOpts )
37
{
38
	var i, iLen, a = [], tr;
39
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
40
	var aoData = oSettings.aoData;
41
	var aiDisplay = oSettings.aiDisplay;
42
	var aiDisplayMaster = oSettings.aiDisplayMaster;
43

    
44
	if ( !oOpts )
45
	{
46
		oOpts = {};
47
	}
48

    
49
	oOpts = $.extend( {}, {
50
		"filter": "none", // applied
51
		"order": "current", // "original"
52
		"page": "all" // current
53
	}, oOpts );
54

    
55
	// Current page implies that order=current and fitler=applied, since it is fairly
56
	// senseless otherwise
57
	if ( oOpts.page == 'current' )
58
	{
59
		for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
60
		{
61
			tr = aoData[ aiDisplay[i] ].nTr;
62
			if ( tr )
63
			{
64
				a.push( tr );
65
			}
66
		}
67
	}
68
	else if ( oOpts.order == "current" && oOpts.filter == "none" )
69
	{
70
		for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
71
		{
72
			tr = aoData[ aiDisplayMaster[i] ].nTr;
73
			if ( tr )
74
			{
75
				a.push( tr );
76
			}
77
		}
78
	}
79
	else if ( oOpts.order == "current" && oOpts.filter == "applied" )
80
	{
81
		for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
82
		{
83
			tr = aoData[ aiDisplay[i] ].nTr;
84
			if ( tr )
85
			{
86
				a.push( tr );
87
			}
88
		}
89
	}
90
	else if ( oOpts.order == "original" && oOpts.filter == "none" )
91
	{
92
		for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
93
		{
94
			tr = aoData[ i ].nTr ;
95
			if ( tr )
96
			{
97
				a.push( tr );
98
			}
99
		}
100
	}
101
	else if ( oOpts.order == "original" && oOpts.filter == "applied" )
102
	{
103
		for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
104
		{
105
			tr = aoData[ i ].nTr;
106
			if ( $.inArray( i, aiDisplay ) !== -1 && tr )
107
			{
108
				a.push( tr );
109
			}
110
		}
111
	}
112
	else
113
	{
114
		_fnLog( oSettings, 1, "Unknown selection options" );
115
	}
116

    
117
	/* We need to filter on the TR elements and also 'find' in their descendants
118
	 * to make the selector act like it would in a full table - so we need
119
	 * to build both results and then combine them together
120
	 */
121
	var jqA = $(a);
122
	var jqTRs = jqA.filter( sSelector );
123
	var jqDescendants = jqA.find( sSelector );
124

    
125
	return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
126
};
127

    
128

    
129
/**
130
 * Almost identical to $ in operation, but in this case returns the data for the matched
131
 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
132
 * rather than any descendants, so the data can be obtained for the row/cell. If matching
133
 * rows are found, the data returned is the original data array/object that was used to  
134
 * create the row (or a generated array if from a DOM source).
135
 *
136
 * This method is often useful in-combination with $ where both functions are given the
137
 * same parameters and the array indexes will match identically.
138
 *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
139
 *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
140
 *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
141
 *    criterion ("applied") or all elements (i.e. no filter).
142
 *  @param {string} [oOpts.order=current] Order of the data in the processed array.
143
 *    Can be either 'current', whereby the current sorting of the table is used, or
144
 *    'original' whereby the original order the data was read into the table is used.
145
 *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
146
 *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
147
 *    'current' and filter is 'applied', regardless of what they might be given as.
148
 *  @returns {array} Data for the matched elements. If any elements, as a result of the
149
 *    selector, were not TR, TD or TH elements in the DataTable, they will have a null 
150
 *    entry in the array.
151
 *  @dtopt API
152
 *
153
 *  @example
154
 *    $(document).ready(function() {
155
 *      var oTable = $('#example').dataTable();
156
 *
157
 *      // Get the data from the first row in the table
158
 *      var data = oTable._('tr:first');
159
 *
160
 *      // Do something useful with the data
161
 *      alert( "First cell is: "+data[0] );
162
 *    } );
163
 *
164
 *  @example
165
 *    $(document).ready(function() {
166
 *      var oTable = $('#example').dataTable();
167
 *
168
 *      // Filter to 'Webkit' and get all data for 
169
 *      oTable.fnFilter('Webkit');
170
 *      var data = oTable._('tr', {"filter": "applied"});
171
 *      
172
 *      // Do something with the data
173
 *      alert( data.length+" rows matched the filter" );
174
 *    } );
175
 */
176
this._ = function ( sSelector, oOpts )
177
{
178
	var aOut = [];
179
	var i, iLen, iIndex;
180
	var aTrs = this.$( sSelector, oOpts );
181

    
182
	for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
183
	{
184
		aOut.push( this.fnGetData(aTrs[i]) );
185
	}
186

    
187
	return aOut;
188
};
189

    
190

    
191
/**
192
 * Add a single new row or multiple rows of data to the table. Please note
193
 * that this is suitable for client-side processing only - if you are using 
194
 * server-side processing (i.e. "bServerSide": true), then to add data, you
195
 * must add it to the data source, i.e. the server-side, through an Ajax call.
196
 *  @param {array|object} mData The data to be added to the table. This can be:
197
 *    <ul>
198
 *      <li>1D array of data - add a single row with the data provided</li>
199
 *      <li>2D array of arrays - add multiple rows in a single call</li>
200
 *      <li>object - data object when using <i>mData</i></li>
201
 *      <li>array of objects - multiple data objects when using <i>mData</i></li>
202
 *    </ul>
203
 *  @param {bool} [bRedraw=true] redraw the table or not
204
 *  @returns {array} An array of integers, representing the list of indexes in 
205
 *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 
206
 *    the table.
207
 *  @dtopt API
208
 *
209
 *  @example
210
 *    // Global var for counter
211
 *    var giCount = 2;
212
 *    
213
 *    $(document).ready(function() {
214
 *      $('#example').dataTable();
215
 *    } );
216
 *    
217
 *    function fnClickAddRow() {
218
 *      $('#example').dataTable().fnAddData( [
219
 *        giCount+".1",
220
 *        giCount+".2",
221
 *        giCount+".3",
222
 *        giCount+".4" ]
223
 *      );
224
 *        
225
 *      giCount++;
226
 *    }
227
 */
228
this.fnAddData = function( mData, bRedraw )
229
{
230
	if ( mData.length === 0 )
231
	{
232
		return [];
233
	}
234
	
235
	var aiReturn = [];
236
	var iTest;
237
	
238
	/* Find settings from table node */
239
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
240
	
241
	/* Check if we want to add multiple rows or not */
242
	if ( typeof mData[0] === "object" && mData[0] !== null )
243
	{
244
		for ( var i=0 ; i<mData.length ; i++ )
245
		{
246
			iTest = _fnAddData( oSettings, mData[i] );
247
			if ( iTest == -1 )
248
			{
249
				return aiReturn;
250
			}
251
			aiReturn.push( iTest );
252
		}
253
	}
254
	else
255
	{
256
		iTest = _fnAddData( oSettings, mData );
257
		if ( iTest == -1 )
258
		{
259
			return aiReturn;
260
		}
261
		aiReturn.push( iTest );
262
	}
263
	
264
	oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
265
	
266
	if ( bRedraw === undefined || bRedraw )
267
	{
268
		_fnReDraw( oSettings );
269
	}
270
	return aiReturn;
271
};
272

    
273

    
274
/**
275
 * This function will make DataTables recalculate the column sizes, based on the data 
276
 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 
277
 * through the sWidth parameter). This can be useful when the width of the table's 
278
 * parent element changes (for example a window resize).
279
 *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
280
 *  @dtopt API
281
 *
282
 *  @example
283
 *    $(document).ready(function() {
284
 *      var oTable = $('#example').dataTable( {
285
 *        "sScrollY": "200px",
286
 *        "bPaginate": false
287
 *      } );
288
 *      
289
 *      $(window).bind('resize', function () {
290
 *        oTable.fnAdjustColumnSizing();
291
 *      } );
292
 *    } );
293
 */
294
this.fnAdjustColumnSizing = function ( bRedraw )
295
{
296
	var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
297
	_fnAdjustColumnSizing( oSettings );
298
	
299
	if ( bRedraw === undefined || bRedraw )
300
	{
301
		this.fnDraw( false );
302
	}
303
	else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
304
	{
305
		/* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
306
		this.oApi._fnScrollDraw(oSettings);
307
	}
308
};
309

    
310

    
311
/**
312
 * Quickly and simply clear a table
313
 *  @param {bool} [bRedraw=true] redraw the table or not
314
 *  @dtopt API
315
 *
316
 *  @example
317
 *    $(document).ready(function() {
318
 *      var oTable = $('#example').dataTable();
319
 *      
320
 *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
321
 *      oTable.fnClearTable();
322
 *    } );
323
 */
324
this.fnClearTable = function( bRedraw )
325
{
326
	/* Find settings from table node */
327
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
328
	_fnClearTable( oSettings );
329
	
330
	if ( bRedraw === undefined || bRedraw )
331
	{
332
		_fnDraw( oSettings );
333
	}
334
};
335

    
336

    
337
/**
338
 * The exact opposite of 'opening' a row, this function will close any rows which 
339
 * are currently 'open'.
340
 *  @param {node} nTr the table row to 'close'
341
 *  @returns {int} 0 on success, or 1 if failed (can't find the row)
342
 *  @dtopt API
343
 *
344
 *  @example
345
 *    $(document).ready(function() {
346
 *      var oTable;
347
 *      
348
 *      // 'open' an information row when a row is clicked on
349
 *      $('#example tbody tr').click( function () {
350
 *        if ( oTable.fnIsOpen(this) ) {
351
 *          oTable.fnClose( this );
352
 *        } else {
353
 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
354
 *        }
355
 *      } );
356
 *      
357
 *      oTable = $('#example').dataTable();
358
 *    } );
359
 */
360
this.fnClose = function( nTr )
361
{
362
	/* Find settings from table node */
363
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
364
	
365
	for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
366
	{
367
		if ( oSettings.aoOpenRows[i].nParent == nTr )
368
		{
369
			var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
370
			if ( nTrParent )
371
			{
372
				/* Remove it if it is currently on display */
373
				nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
374
			}
375
			oSettings.aoOpenRows.splice( i, 1 );
376
			return 0;
377
		}
378
	}
379
	return 1;
380
};
381

    
382

    
383
/**
384
 * Remove a row for the table
385
 *  @param {mixed} mTarget The index of the row from aoData to be deleted, or
386
 *    the TR element you want to delete
387
 *  @param {function|null} [fnCallBack] Callback function
388
 *  @param {bool} [bRedraw=true] Redraw the table or not
389
 *  @returns {array} The row that was deleted
390
 *  @dtopt API
391
 *
392
 *  @example
393
 *    $(document).ready(function() {
394
 *      var oTable = $('#example').dataTable();
395
 *      
396
 *      // Immediately remove the first row
397
 *      oTable.fnDeleteRow( 0 );
398
 *    } );
399
 */
400
this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
401
{
402
	/* Find settings from table node */
403
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
404
	var i, iLen, iAODataIndex;
405
	
406
	iAODataIndex = (typeof mTarget === 'object') ? 
407
		_fnNodeToDataIndex(oSettings, mTarget) : mTarget;
408
	
409
	/* Return the data array from this row */
410
	var oData = oSettings.aoData.splice( iAODataIndex, 1 );
411

    
412
	/* Update the _DT_RowIndex parameter */
413
	for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
414
	{
415
		if ( oSettings.aoData[i].nTr !== null )
416
		{
417
			oSettings.aoData[i].nTr._DT_RowIndex = i;
418
		}
419
	}
420
	
421
	/* Remove the target row from the search array */
422
	var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
423
	oSettings.asDataSearch.splice( iDisplayIndex, 1 );
424
	
425
	/* Delete from the display arrays */
426
	_fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
427
	_fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
428
	
429
	/* If there is a user callback function - call it */
430
	if ( typeof fnCallBack === "function" )
431
	{
432
		fnCallBack.call( this, oSettings, oData );
433
	}
434
	
435
	/* Check for an 'overflow' they case for displaying the table */
436
	if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
437
	{
438
		oSettings._iDisplayStart -= oSettings._iDisplayLength;
439
		if ( oSettings._iDisplayStart < 0 )
440
		{
441
			oSettings._iDisplayStart = 0;
442
		}
443
	}
444
	
445
	if ( bRedraw === undefined || bRedraw )
446
	{
447
		_fnCalculateEnd( oSettings );
448
		_fnDraw( oSettings );
449
	}
450
	
451
	return oData;
452
};
453

    
454

    
455
/**
456
 * Restore the table to it's original state in the DOM by removing all of DataTables 
457
 * enhancements, alterations to the DOM structure of the table and event listeners.
458
 *  @param {boolean} [bRemove=false] Completely remove the table from the DOM
459
 *  @dtopt API
460
 *
461
 *  @example
462
 *    $(document).ready(function() {
463
 *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
464
 *      var oTable = $('#example').dataTable();
465
 *      oTable.fnDestroy();
466
 *    } );
467
 */
468
this.fnDestroy = function ( bRemove )
469
{
470
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
471
	var nOrig = oSettings.nTableWrapper.parentNode;
472
	var nBody = oSettings.nTBody;
473
	var i, iLen;
474

    
475
	bRemove = (bRemove===undefined) ? false : bRemove;
476
	
477
	/* Flag to note that the table is currently being destroyed - no action should be taken */
478
	oSettings.bDestroying = true;
479
	
480
	/* Fire off the destroy callbacks for plug-ins etc */
481
	_fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
482

    
483
	/* If the table is not being removed, restore the hidden columns */
484
	if ( !bRemove )
485
	{
486
		for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
487
		{
488
			if ( oSettings.aoColumns[i].bVisible === false )
489
			{
490
				this.fnSetColumnVis( i, true );
491
			}
492
		}
493
	}
494
	
495
	/* Blitz all DT events */
496
	$(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
497
	
498
	/* If there is an 'empty' indicator row, remove it */
499
	$('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
500
	
501
	/* When scrolling we had to break the table up - restore it */
502
	if ( oSettings.nTable != oSettings.nTHead.parentNode )
503
	{
504
		$(oSettings.nTable).children('thead').remove();
505
		oSettings.nTable.appendChild( oSettings.nTHead );
506
	}
507
	
508
	if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
509
	{
510
		$(oSettings.nTable).children('tfoot').remove();
511
		oSettings.nTable.appendChild( oSettings.nTFoot );
512
	}
513
	
514
	/* Remove the DataTables generated nodes, events and classes */
515
	oSettings.nTable.parentNode.removeChild( oSettings.nTable );
516
	$(oSettings.nTableWrapper).remove();
517
	
518
	oSettings.aaSorting = [];
519
	oSettings.aaSortingFixed = [];
520
	_fnSortingClasses( oSettings );
521
	
522
	$(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
523
	
524
	$('th, td', oSettings.nTHead).removeClass( [
525
		oSettings.oClasses.sSortable,
526
		oSettings.oClasses.sSortableAsc,
527
		oSettings.oClasses.sSortableDesc,
528
		oSettings.oClasses.sSortableNone ].join(' ')
529
	);
530
	if ( oSettings.bJUI )
531
	{
532
		$('th span.'+oSettings.oClasses.sSortIcon
533
			+ ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
534

    
535
		$('th, td', oSettings.nTHead).each( function () {
536
			var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
537
			var kids = jqWrapper.contents();
538
			$(this).append( kids );
539
			jqWrapper.remove();
540
		} );
541
	}
542
	
543
	/* Add the TR elements back into the table in their original order */
544
	if ( !bRemove && oSettings.nTableReinsertBefore )
545
	{
546
		nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
547
	}
548
	else if ( !bRemove )
549
	{
550
		nOrig.appendChild( oSettings.nTable );
551
	}
552

    
553
	for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
554
	{
555
		if ( oSettings.aoData[i].nTr !== null )
556
		{
557
			nBody.appendChild( oSettings.aoData[i].nTr );
558
		}
559
	}
560
	
561
	/* Restore the width of the original table */
562
	if ( oSettings.oFeatures.bAutoWidth === true )
563
	{
564
	  oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
565
	}
566
	
567
	/* If the were originally stripe classes - then we add them back here. Note
568
	 * this is not fool proof (for example if not all rows had stripe classes - but
569
	 * it's a good effort without getting carried away
570
	 */
571
	iLen = oSettings.asDestroyStripes.length;
572
	if (iLen)
573
	{
574
		var anRows = $(nBody).children('tr');
575
		for ( i=0 ; i<iLen ; i++ )
576
		{
577
			anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
578
		}
579
	}
580
	
581
	/* Remove the settings object from the settings array */
582
	for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
583
	{
584
		if ( DataTable.settings[i] == oSettings )
585
		{
586
			DataTable.settings.splice( i, 1 );
587
		}
588
	}
589
	
590
	/* End it all */
591
	oSettings = null;
592
	oInit = null;
593
};
594

    
595

    
596
/**
597
 * Redraw the table
598
 *  @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
599
 *  @dtopt API
600
 *
601
 *  @example
602
 *    $(document).ready(function() {
603
 *      var oTable = $('#example').dataTable();
604
 *      
605
 *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
606
 *      oTable.fnDraw();
607
 *    } );
608
 */
609
this.fnDraw = function( bComplete )
610
{
611
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
612
	if ( bComplete === false )
613
	{
614
		_fnCalculateEnd( oSettings );
615
		_fnDraw( oSettings );
616
	}
617
	else
618
	{
619
		_fnReDraw( oSettings );
620
	}
621
};
622

    
623

    
624
/**
625
 * Filter the input based on data
626
 *  @param {string} sInput String to filter the table on
627
 *  @param {int|null} [iColumn] Column to limit filtering to
628
 *  @param {bool} [bRegex=false] Treat as regular expression or not
629
 *  @param {bool} [bSmart=true] Perform smart filtering or not
630
 *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
631
 *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
632
 *  @dtopt API
633
 *
634
 *  @example
635
 *    $(document).ready(function() {
636
 *      var oTable = $('#example').dataTable();
637
 *      
638
 *      // Sometime later - filter...
639
 *      oTable.fnFilter( 'test string' );
640
 *    } );
641
 */
642
this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
643
{
644
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
645
	
646
	if ( !oSettings.oFeatures.bFilter )
647
	{
648
		return;
649
	}
650
	
651
	if ( bRegex === undefined || bRegex === null )
652
	{
653
		bRegex = false;
654
	}
655
	
656
	if ( bSmart === undefined || bSmart === null )
657
	{
658
		bSmart = true;
659
	}
660
	
661
	if ( bShowGlobal === undefined || bShowGlobal === null )
662
	{
663
		bShowGlobal = true;
664
	}
665
	
666
	if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
667
	{
668
		bCaseInsensitive = true;
669
	}
670
	
671
	if ( iColumn === undefined || iColumn === null )
672
	{
673
		/* Global filter */
674
		_fnFilterComplete( oSettings, {
675
			"sSearch":sInput+"",
676
			"bRegex": bRegex,
677
			"bSmart": bSmart,
678
			"bCaseInsensitive": bCaseInsensitive
679
		}, 1 );
680
		
681
		if ( bShowGlobal && oSettings.aanFeatures.f )
682
		{
683
			var n = oSettings.aanFeatures.f;
684
			for ( var i=0, iLen=n.length ; i<iLen ; i++ )
685
			{
686
				// IE9 throws an 'unknown error' if document.activeElement is used
687
				// inside an iframe or frame...
688
				try {
689
					if ( n[i]._DT_Input != document.activeElement )
690
					{
691
						$(n[i]._DT_Input).val( sInput );
692
					}
693
				}
694
				catch ( e ) {
695
					$(n[i]._DT_Input).val( sInput );
696
				}
697
			}
698
		}
699
	}
700
	else
701
	{
702
		/* Single column filter */
703
		$.extend( oSettings.aoPreSearchCols[ iColumn ], {
704
			"sSearch": sInput+"",
705
			"bRegex": bRegex,
706
			"bSmart": bSmart,
707
			"bCaseInsensitive": bCaseInsensitive
708
		} );
709
		_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
710
	}
711
};
712

    
713

    
714
/**
715
 * Get the data for the whole table, an individual row or an individual cell based on the 
716
 * provided parameters.
717
 *  @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
718
 *    a TR node then the data source for the whole row will be returned. If given as a
719
 *    TD/TH cell node then iCol will be automatically calculated and the data for the
720
 *    cell returned. If given as an integer, then this is treated as the aoData internal
721
 *    data index for the row (see fnGetPosition) and the data for that row used.
722
 *  @param {int} [iCol] Optional column index that you want the data of.
723
 *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
724
 *    returned. If mRow is defined, just data for that row, and is iCol is
725
 *    defined, only data for the designated cell is returned.
726
 *  @dtopt API
727
 *
728
 *  @example
729
 *    // Row data
730
 *    $(document).ready(function() {
731
 *      oTable = $('#example').dataTable();
732
 *
733
 *      oTable.$('tr').click( function () {
734
 *        var data = oTable.fnGetData( this );
735
 *        // ... do something with the array / object of data for the row
736
 *      } );
737
 *    } );
738
 *
739
 *  @example
740
 *    // Individual cell data
741
 *    $(document).ready(function() {
742
 *      oTable = $('#example').dataTable();
743
 *
744
 *      oTable.$('td').click( function () {
745
 *        var sData = oTable.fnGetData( this );
746
 *        alert( 'The cell clicked on had the value of '+sData );
747
 *      } );
748
 *    } );
749
 */
750
this.fnGetData = function( mRow, iCol )
751
{
752
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
753
	
754
	if ( mRow !== undefined )
755
	{
756
		var iRow = mRow;
757
		if ( typeof mRow === 'object' )
758
		{
759
			var sNode = mRow.nodeName.toLowerCase();
760
			if (sNode === "tr" )
761
			{
762
				iRow = _fnNodeToDataIndex(oSettings, mRow);
763
			}
764
			else if ( sNode === "td" )
765
			{
766
				iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
767
				iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
768
			}
769
		}
770

    
771
		if ( iCol !== undefined )
772
		{
773
			return _fnGetCellData( oSettings, iRow, iCol, '' );
774
		}
775
		return (oSettings.aoData[iRow]!==undefined) ?
776
			oSettings.aoData[iRow]._aData : null;
777
	}
778
	return _fnGetDataMaster( oSettings );
779
};
780

    
781

    
782
/**
783
 * Get an array of the TR nodes that are used in the table's body. Note that you will 
784
 * typically want to use the '$' API method in preference to this as it is more 
785
 * flexible.
786
 *  @param {int} [iRow] Optional row index for the TR element you want
787
 *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
788
 *    in the table's body, or iRow is defined, just the TR element requested.
789
 *  @dtopt API
790
 *
791
 *  @example
792
 *    $(document).ready(function() {
793
 *      var oTable = $('#example').dataTable();
794
 *      
795
 *      // Get the nodes from the table
796
 *      var nNodes = oTable.fnGetNodes( );
797
 *    } );
798
 */
799
this.fnGetNodes = function( iRow )
800
{
801
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
802
	
803
	if ( iRow !== undefined ) {
804
		return (oSettings.aoData[iRow]!==undefined) ?
805
			oSettings.aoData[iRow].nTr : null;
806
	}
807
	return _fnGetTrNodes( oSettings );
808
};
809

    
810

    
811
/**
812
 * Get the array indexes of a particular cell from it's DOM element
813
 * and column index including hidden columns
814
 *  @param {node} nNode this can either be a TR, TD or TH in the table's body
815
 *  @returns {int} If nNode is given as a TR, then a single index is returned, or
816
 *    if given as a cell, an array of [row index, column index (visible), 
817
 *    column index (all)] is given.
818
 *  @dtopt API
819
 *
820
 *  @example
821
 *    $(document).ready(function() {
822
 *      $('#example tbody td').click( function () {
823
 *        // Get the position of the current data from the node
824
 *        var aPos = oTable.fnGetPosition( this );
825
 *        
826
 *        // Get the data array for this row
827
 *        var aData = oTable.fnGetData( aPos[0] );
828
 *        
829
 *        // Update the data array and return the value
830
 *        aData[ aPos[1] ] = 'clicked';
831
 *        this.innerHTML = 'clicked';
832
 *      } );
833
 *      
834
 *      // Init DataTables
835
 *      oTable = $('#example').dataTable();
836
 *    } );
837
 */
838
this.fnGetPosition = function( nNode )
839
{
840
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
841
	var sNodeName = nNode.nodeName.toUpperCase();
842
	
843
	if ( sNodeName == "TR" )
844
	{
845
		return _fnNodeToDataIndex(oSettings, nNode);
846
	}
847
	else if ( sNodeName == "TD" || sNodeName == "TH" )
848
	{
849
		var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
850
		var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
851
		return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
852
	}
853
	return null;
854
};
855

    
856

    
857
/**
858
 * Check to see if a row is 'open' or not.
859
 *  @param {node} nTr the table row to check
860
 *  @returns {boolean} true if the row is currently open, false otherwise
861
 *  @dtopt API
862
 *
863
 *  @example
864
 *    $(document).ready(function() {
865
 *      var oTable;
866
 *      
867
 *      // 'open' an information row when a row is clicked on
868
 *      $('#example tbody tr').click( function () {
869
 *        if ( oTable.fnIsOpen(this) ) {
870
 *          oTable.fnClose( this );
871
 *        } else {
872
 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
873
 *        }
874
 *      } );
875
 *      
876
 *      oTable = $('#example').dataTable();
877
 *    } );
878
 */
879
this.fnIsOpen = function( nTr )
880
{
881
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
882
	var aoOpenRows = oSettings.aoOpenRows;
883
	
884
	for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
885
	{
886
		if ( oSettings.aoOpenRows[i].nParent == nTr )
887
		{
888
			return true;
889
		}
890
	}
891
	return false;
892
};
893

    
894

    
895
/**
896
 * This function will place a new row directly after a row which is currently 
897
 * on display on the page, with the HTML contents that is passed into the 
898
 * function. This can be used, for example, to ask for confirmation that a 
899
 * particular record should be deleted.
900
 *  @param {node} nTr The table row to 'open'
901
 *  @param {string|node|jQuery} mHtml The HTML to put into the row
902
 *  @param {string} sClass Class to give the new TD cell
903
 *  @returns {node} The row opened. Note that if the table row passed in as the
904
 *    first parameter, is not found in the table, this method will silently
905
 *    return.
906
 *  @dtopt API
907
 *
908
 *  @example
909
 *    $(document).ready(function() {
910
 *      var oTable;
911
 *      
912
 *      // 'open' an information row when a row is clicked on
913
 *      $('#example tbody tr').click( function () {
914
 *        if ( oTable.fnIsOpen(this) ) {
915
 *          oTable.fnClose( this );
916
 *        } else {
917
 *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
918
 *        }
919
 *      } );
920
 *      
921
 *      oTable = $('#example').dataTable();
922
 *    } );
923
 */
924
this.fnOpen = function( nTr, mHtml, sClass )
925
{
926
	/* Find settings from table node */
927
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
928

    
929
	/* Check that the row given is in the table */
930
	var nTableRows = _fnGetTrNodes( oSettings );
931
	if ( $.inArray(nTr, nTableRows) === -1 )
932
	{
933
		return;
934
	}
935
	
936
	/* the old open one if there is one */
937
	this.fnClose( nTr );
938
	
939
	var nNewRow = document.createElement("tr");
940
	var nNewCell = document.createElement("td");
941
	nNewRow.appendChild( nNewCell );
942
	nNewCell.className = sClass;
943
	nNewCell.colSpan = _fnVisbleColumns( oSettings );
944

    
945
	if (typeof mHtml === "string")
946
	{
947
		nNewCell.innerHTML = mHtml;
948
	}
949
	else
950
	{
951
		$(nNewCell).html( mHtml );
952
	}
953

    
954
	/* If the nTr isn't on the page at the moment - then we don't insert at the moment */
955
	var nTrs = $('tr', oSettings.nTBody);
956
	if ( $.inArray(nTr, nTrs) != -1  )
957
	{
958
		$(nNewRow).insertAfter(nTr);
959
	}
960
	
961
	oSettings.aoOpenRows.push( {
962
		"nTr": nNewRow,
963
		"nParent": nTr
964
	} );
965
	
966
	return nNewRow;
967
};
968

    
969

    
970
/**
971
 * Change the pagination - provides the internal logic for pagination in a simple API 
972
 * function. With this function you can have a DataTables table go to the next, 
973
 * previous, first or last pages.
974
 *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
975
 *    or page number to jump to (integer), note that page 0 is the first page.
976
 *  @param {bool} [bRedraw=true] Redraw the table or not
977
 *  @dtopt API
978
 *
979
 *  @example
980
 *    $(document).ready(function() {
981
 *      var oTable = $('#example').dataTable();
982
 *      oTable.fnPageChange( 'next' );
983
 *    } );
984
 */
985
this.fnPageChange = function ( mAction, bRedraw )
986
{
987
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
988
	_fnPageChange( oSettings, mAction );
989
	_fnCalculateEnd( oSettings );
990
	
991
	if ( bRedraw === undefined || bRedraw )
992
	{
993
		_fnDraw( oSettings );
994
	}
995
};
996

    
997

    
998
/**
999
 * Show a particular column
1000
 *  @param {int} iCol The column whose display should be changed
1001
 *  @param {bool} bShow Show (true) or hide (false) the column
1002
 *  @param {bool} [bRedraw=true] Redraw the table or not
1003
 *  @dtopt API
1004
 *
1005
 *  @example
1006
 *    $(document).ready(function() {
1007
 *      var oTable = $('#example').dataTable();
1008
 *      
1009
 *      // Hide the second column after initialisation
1010
 *      oTable.fnSetColumnVis( 1, false );
1011
 *    } );
1012
 */
1013
this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
1014
{
1015
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
1016
	var i, iLen;
1017
	var aoColumns = oSettings.aoColumns;
1018
	var aoData = oSettings.aoData;
1019
	var nTd, bAppend, iBefore;
1020
	
1021
	/* No point in doing anything if we are requesting what is already true */
1022
	if ( aoColumns[iCol].bVisible == bShow )
1023
	{
1024
		return;
1025
	}
1026
	
1027
	/* Show the column */
1028
	if ( bShow )
1029
	{
1030
		var iInsert = 0;
1031
		for ( i=0 ; i<iCol ; i++ )
1032
		{
1033
			if ( aoColumns[i].bVisible )
1034
			{
1035
				iInsert++;
1036
			}
1037
		}
1038
		
1039
		/* Need to decide if we should use appendChild or insertBefore */
1040
		bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
1041

    
1042
		/* Which coloumn should we be inserting before? */
1043
		if ( !bAppend )
1044
		{
1045
			for ( i=iCol ; i<aoColumns.length ; i++ )
1046
			{
1047
				if ( aoColumns[i].bVisible )
1048
				{
1049
					iBefore = i;
1050
					break;
1051
				}
1052
			}
1053
		}
1054

    
1055
		for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
1056
		{
1057
			if ( aoData[i].nTr !== null )
1058
			{
1059
				if ( bAppend )
1060
				{
1061
					aoData[i].nTr.appendChild( 
1062
						aoData[i]._anHidden[iCol]
1063
					);
1064
				}
1065
				else
1066
				{
1067
					aoData[i].nTr.insertBefore(
1068
						aoData[i]._anHidden[iCol], 
1069
						_fnGetTdNodes( oSettings, i )[iBefore] );
1070
				}
1071
			}
1072
		}
1073
	}
1074
	else
1075
	{
1076
		/* Remove a column from display */
1077
		for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
1078
		{
1079
			if ( aoData[i].nTr !== null )
1080
			{
1081
				nTd = _fnGetTdNodes( oSettings, i )[iCol];
1082
				aoData[i]._anHidden[iCol] = nTd;
1083
				nTd.parentNode.removeChild( nTd );
1084
			}
1085
		}
1086
	}
1087

    
1088
	/* Clear to set the visible flag */
1089
	aoColumns[iCol].bVisible = bShow;
1090

    
1091
	/* Redraw the header and footer based on the new column visibility */
1092
	_fnDrawHead( oSettings, oSettings.aoHeader );
1093
	if ( oSettings.nTFoot )
1094
	{
1095
		_fnDrawHead( oSettings, oSettings.aoFooter );
1096
	}
1097
	
1098
	/* If there are any 'open' rows, then we need to alter the colspan for this col change */
1099
	for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
1100
	{
1101
		oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
1102
	}
1103
	
1104
	/* Do a redraw incase anything depending on the table columns needs it 
1105
	 * (built-in: scrolling) 
1106
	 */
1107
	if ( bRedraw === undefined || bRedraw )
1108
	{
1109
		_fnAdjustColumnSizing( oSettings );
1110
		_fnDraw( oSettings );
1111
	}
1112
	
1113
	_fnSaveState( oSettings );
1114
};
1115

    
1116

    
1117
/**
1118
 * Get the settings for a particular table for external manipulation
1119
 *  @returns {object} DataTables settings object. See 
1120
 *    {@link DataTable.models.oSettings}
1121
 *  @dtopt API
1122
 *
1123
 *  @example
1124
 *    $(document).ready(function() {
1125
 *      var oTable = $('#example').dataTable();
1126
 *      var oSettings = oTable.fnSettings();
1127
 *      
1128
 *      // Show an example parameter from the settings
1129
 *      alert( oSettings._iDisplayStart );
1130
 *    } );
1131
 */
1132
this.fnSettings = function()
1133
{
1134
	return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
1135
};
1136

    
1137

    
1138
/**
1139
 * Sort the table by a particular column
1140
 *  @param {int} iCol the data index to sort on. Note that this will not match the 
1141
 *    'display index' if you have hidden data entries
1142
 *  @dtopt API
1143
 *
1144
 *  @example
1145
 *    $(document).ready(function() {
1146
 *      var oTable = $('#example').dataTable();
1147
 *      
1148
 *      // Sort immediately with columns 0 and 1
1149
 *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
1150
 *    } );
1151
 */
1152
this.fnSort = function( aaSort )
1153
{
1154
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
1155
	oSettings.aaSorting = aaSort;
1156
	_fnSort( oSettings );
1157
};
1158

    
1159

    
1160
/**
1161
 * Attach a sort listener to an element for a given column
1162
 *  @param {node} nNode the element to attach the sort listener to
1163
 *  @param {int} iColumn the column that a click on this node will sort on
1164
 *  @param {function} [fnCallback] callback function when sort is run
1165
 *  @dtopt API
1166
 *
1167
 *  @example
1168
 *    $(document).ready(function() {
1169
 *      var oTable = $('#example').dataTable();
1170
 *      
1171
 *      // Sort on column 1, when 'sorter' is clicked on
1172
 *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
1173
 *    } );
1174
 */
1175
this.fnSortListener = function( nNode, iColumn, fnCallback )
1176
{
1177
	_fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
1178
	 	fnCallback );
1179
};
1180

    
1181

    
1182
/**
1183
 * Update a table cell or row - this method will accept either a single value to
1184
 * update the cell with, an array of values with one element for each column or
1185
 * an object in the same format as the original data source. The function is
1186
 * self-referencing in order to make the multi column updates easier.
1187
 *  @param {object|array|string} mData Data to update the cell/row with
1188
 *  @param {node|int} mRow TR element you want to update or the aoData index
1189
 *  @param {int} [iColumn] The column to update (not used of mData is an array or object)
1190
 *  @param {bool} [bRedraw=true] Redraw the table or not
1191
 *  @param {bool} [bAction=true] Perform pre-draw actions or not
1192
 *  @returns {int} 0 on success, 1 on error
1193
 *  @dtopt API
1194
 *
1195
 *  @example
1196
 *    $(document).ready(function() {
1197
 *      var oTable = $('#example').dataTable();
1198
 *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
1199
 *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
1200
 *    } );
1201
 */
1202
this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
1203
{
1204
	var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
1205
	var i, iLen, sDisplay;
1206
	var iRow = (typeof mRow === 'object') ? 
1207
		_fnNodeToDataIndex(oSettings, mRow) : mRow;
1208
	
1209
	if ( $.isArray(mData) && iColumn === undefined )
1210
	{
1211
		/* Array update - update the whole row */
1212
		oSettings.aoData[iRow]._aData = mData.slice();
1213
		
1214
		/* Flag to the function that we are recursing */
1215
		for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
1216
		{
1217
			this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
1218
		}
1219
	}
1220
	else if ( $.isPlainObject(mData) && iColumn === undefined )
1221
	{
1222
		/* Object update - update the whole row - assume the developer gets the object right */
1223
		oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
1224

    
1225
		for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
1226
		{
1227
			this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
1228
		}
1229
	}
1230
	else
1231
	{
1232
		/* Individual cell update */
1233
		_fnSetCellData( oSettings, iRow, iColumn, mData );
1234
		sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
1235
		
1236
		var oCol = oSettings.aoColumns[iColumn];
1237
		if ( oCol.fnRender !== null )
1238
		{
1239
			sDisplay = _fnRender( oSettings, iRow, iColumn );
1240
			if ( oCol.bUseRendered )
1241
			{
1242
				_fnSetCellData( oSettings, iRow, iColumn, sDisplay );
1243
			}
1244
		}
1245
		
1246
		if ( oSettings.aoData[iRow].nTr !== null )
1247
		{
1248
			/* Do the actual HTML update */
1249
			_fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
1250
		}
1251
	}
1252
	
1253
	/* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
1254
	 * will rebuild the search array - however, the redraw might be disabled by the user)
1255
	 */
1256
	var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
1257
	oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
1258
		oSettings, 
1259
		_fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
1260
	);
1261
	
1262
	/* Perform pre-draw actions */
1263
	if ( bAction === undefined || bAction )
1264
	{
1265
		_fnAdjustColumnSizing( oSettings );
1266
	}
1267
	
1268
	/* Redraw the table */
1269
	if ( bRedraw === undefined || bRedraw )
1270
	{
1271
		_fnReDraw( oSettings );
1272
	}
1273
	return 0;
1274
};
1275

    
1276

    
1277
/**
1278
 * Provide a common method for plug-ins to check the version of DataTables being used, in order
1279
 * to ensure compatibility.
1280
 *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
1281
 *    formats "X" and "X.Y" are also acceptable.
1282
 *  @returns {boolean} true if this version of DataTables is greater or equal to the required
1283
 *    version, or false if this version of DataTales is not suitable
1284
 *  @method
1285
 *  @dtopt API
1286
 *
1287
 *  @example
1288
 *    $(document).ready(function() {
1289
 *      var oTable = $('#example').dataTable();
1290
 *      alert( oTable.fnVersionCheck( '1.9.0' ) );
1291
 *    } );
1292
 */
1293
this.fnVersionCheck = DataTable.ext.fnVersionCheck;
1294

    
(2-2/3)