Revision 8a217fa2

b/snf-astakos-app/astakos/im/static/im/css/modules.css
198 198
a.button:hover								 	{ background-color: #F89A1C; border:0 none; color:#fff;}*/
199 199

  
200 200
/*pagination*/
201
.pagination .next-prev                          { float:right; }
202
.pagination .next-prev a						{ margin-left:15px; }
203
.pagination .nums                               { text-align:left;}
204
.pagination .nums span                          { color:#000;}
205
.pagination .next-prev a.disabled				{ text-decoration: none; color:#ccc; cursor:default; }
206
                    
201
.dataTables_info 								{ float:left;}
202
.dataTables_paginate                            { float:right; }
203
.dataTables_paginate a:after 					{ content: ' >';}
204
.dataTables_paginate a:first-child:after 		{ content: '';}
205
.dataTables_paginate a:first-child:before 		{ content: '< ';}
206
.dataTables_paginate .paginate_enabled_next,
207
.dataTables_paginate .paginate_disabled_next	{ margin-left:15px; }
208

  
209
.dataTables_paginate .paginate_enabled_previous:hover,
210
.dataTables_paginate .paginate_enabled_next:hover { cursor: pointer; }
211
.dataTables_paginate .paginate_disabled_previous:hover,
212
.dataTables_paginate .paginate_disabled_previous,
213
.dataTables_paginate .paginate_disabled_next,
214
.dataTables_paginate .paginate_disabled_next:hover { color: gray; text-decoration: none}
215
.dataTables_length 						 		{ display: none;}
216
.dataTables_filter 								{ position: absolute; right: 70px;}
217
.dataTables_filter input 						{ border: 1px solid #9e9e9e; height: 21px; line-height: 21px; padding: 3px 10px;}
218
.dataTables_paginate .nums                      { text-align:left;}
219
.dataTables_paginate .nums span                          { color:#000;}
220
.dataTables_paginate .next-prev a.disabled				{ text-decoration: none; color:#ccc; cursor:default; }
207 221
.two-cols .lt .clients-wrapper p				{ padding:0; }
208 222

  
209 223

  
......
241 255
table.alt-style tr td a							{ margin:0; }
242 256
table.alt-style tr td:first-child a				{ margin:0; }
243 257
table.alt-style tr th a							{ padding-right:20px; }
258
table.alt-style tr th:focus 					{ outline: 0 none;}
244 259
table.alt-style tr th.asc a						{ background:url(../images/arrow_th_bg.png) no-repeat right -48px; }
245 260
table.alt-style tr th.desc a					{ background:url(../images/arrow_th_bg.png) no-repeat right 6px; }
246
table.alt-style tr th.headerSortDown span		{ padding-right:20px;background:url(../images/arrow_th_bg.png) no-repeat right -46px; }
247
table.alt-style tr th.headerSortUp span			{ padding-right:20px;background:url(../images/arrow_th_bg.png) no-repeat right 6px;}
261
table.alt-style tr th.sorting_asc span			{ padding-right:20px;background:url(../images/arrow_th_bg.png) no-repeat right -46px; }
262
table.alt-style tr th.sorting_desc span			{ padding-right:20px;background:url(../images/arrow_th_bg.png) no-repeat right 6px;}
248 263
table.my-projects tr th:hover 					{ cursor: pointer; text-decoration: underline;}
249 264
.content a.submit								{ margin:0; display:inline-block; margin:10px 0 ;  height:auto; min-width:100px; text-align:center;}
250 265
table.alt-style tr:nth-child(2n) td				{ background:#F2F2F2 } 
b/snf-astakos-app/astakos/im/static/im/js/common.js
444 444
    $('.renew-token a.do').show();
445 445
  })
446 446

  
447
// control pagination for projects intro page
448
$('.projects').siblings("#projects-list")
449
    .tablesorter({
450
      widthFixed: true,
451
      sortList: [[0,0]],
452
    })
453
    .tablesorterPager({
454
      container: $("#pager"),
455
      size:10,
456
      positionFixed:false,
457
    });
447
  // control pagination for projects intro page
448
  $('.search-projects').parents('.projects').find('table#projects-list').dataTable({
449
    "iDisplayLength": 20,
450
  });
458 451

  
459
// control pagination for find project page
460
$('.projects').find("#projects-list")
461
    .tablesorter({
462
      widthFixed: true,
463
      sortList: [[0,0]],
464
    })
465
    .tablesorterPager({
466
      container: $("#pager"),
467
      size:20,
468
      positionFixed:false,
469
    });
452
  $('.search-projects').parents('.projects').find('#projects-list_filter').hide();
453
  // control pagination for projects intro page
454
  $('.projects-intro').parents('.projects').siblings('table#projects-list').dataTable({
455
    "iDisplayLength": 10,
456
  });
470 457

  
471 458
});
472 459

  
b/snf-astakos-app/astakos/im/static/im/js/jquery.dataTables.js
1
/**
2
 * @summary     DataTables
3
 * @description Paginate, search and sort HTML tables
4
 * @version     1.9.4
5
 * @file        jquery.dataTables.js
6
 * @author      Allan Jardine (www.sprymedia.co.uk)
7
 * @contact     www.sprymedia.co.uk/contact
8
 *
9
 * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
10
 *
11
 * This source file is free software, under either the GPL v2 license or a
12
 * BSD style license, available at:
13
 *   http://datatables.net/license_gpl2
14
 *   http://datatables.net/license_bsd
15
 * 
16
 * This source file is distributed in the hope that it will be useful, but 
17
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
18
 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
19
 * 
20
 * For details please refer to: http://www.datatables.net
21
 */
22

  
23
/*jslint evil: true, undef: true, browser: true */
24
/*globals $, jQuery,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*/
25

  
26
(/** @lends <global> */function( window, document, undefined ) {
27

  
28
(function( factory ) {
29
	"use strict";
30

  
31
	// Define as an AMD module if possible
32
	if ( typeof define === 'function' && define.amd )
33
	{
34
		define( ['jquery'], factory );
35
	}
36
	/* Define using browser globals otherwise
37
	 * Prevent multiple instantiations if the script is loaded twice
38
	 */
39
	else if ( jQuery && !jQuery.fn.dataTable )
40
	{
41
		factory( jQuery );
42
	}
43
}
44
(/** @lends <global> */function( $ ) {
45
	"use strict";
46
	/** 
47
	 * DataTables is a plug-in for the jQuery Javascript library. It is a 
48
	 * highly flexible tool, based upon the foundations of progressive 
49
	 * enhancement, which will add advanced interaction controls to any 
50
	 * HTML table. For a full list of features please refer to
51
	 * <a href="http://datatables.net">DataTables.net</a>.
52
	 *
53
	 * Note that the <i>DataTable</i> object is not a global variable but is
54
	 * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which 
55
	 * it may be  accessed.
56
	 *
57
	 *  @class
58
	 *  @param {object} [oInit={}] Configuration object for DataTables. Options
59
	 *    are defined by {@link DataTable.defaults}
60
	 *  @requires jQuery 1.3+
61
	 * 
62
	 *  @example
63
	 *    // Basic initialisation
64
	 *    $(document).ready( function {
65
	 *      $('#example').dataTable();
66
	 *    } );
67
	 *  
68
	 *  @example
69
	 *    // Initialisation with configuration options - in this case, disable
70
	 *    // pagination and sorting.
71
	 *    $(document).ready( function {
72
	 *      $('#example').dataTable( {
73
	 *        "bPaginate": false,
74
	 *        "bSort": false 
75
	 *      } );
76
	 *    } );
77
	 */
78
	var DataTable = function( oInit )
79
	{
80
		
81
		
82
		/**
83
		 * Add a column to the list used for the table with default values
84
		 *  @param {object} oSettings dataTables settings object
85
		 *  @param {node} nTh The th element for this column
86
		 *  @memberof DataTable#oApi
87
		 */
88
		function _fnAddColumn( oSettings, nTh )
89
		{
90
			var oDefaults = DataTable.defaults.columns;
91
			var iCol = oSettings.aoColumns.length;
92
			var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
93
				"sSortingClass": oSettings.oClasses.sSortable,
94
				"sSortingClassJUI": oSettings.oClasses.sSortJUI,
95
				"nTh": nTh ? nTh : document.createElement('th'),
96
				"sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
97
				"aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
98
				"mData": oDefaults.mData ? oDefaults.oDefaults : iCol
99
			} );
100
			oSettings.aoColumns.push( oCol );
101
			
102
			/* Add a column specific filter */
103
			if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
104
			{
105
				oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
106
			}
107
			else
108
			{
109
				var oPre = oSettings.aoPreSearchCols[ iCol ];
110
				
111
				/* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
112
				if ( oPre.bRegex === undefined )
113
				{
114
					oPre.bRegex = true;
115
				}
116
				
117
				if ( oPre.bSmart === undefined )
118
				{
119
					oPre.bSmart = true;
120
				}
121
				
122
				if ( oPre.bCaseInsensitive === undefined )
123
				{
124
					oPre.bCaseInsensitive = true;
125
				}
126
			}
127
			
128
			/* Use the column options function to initialise classes etc */
129
			_fnColumnOptions( oSettings, iCol, null );
130
		}
131
		
132
		
133
		/**
134
		 * Apply options for a column
135
		 *  @param {object} oSettings dataTables settings object
136
		 *  @param {int} iCol column index to consider
137
		 *  @param {object} oOptions object with sType, bVisible and bSearchable etc
138
		 *  @memberof DataTable#oApi
139
		 */
140
		function _fnColumnOptions( oSettings, iCol, oOptions )
141
		{
142
			var oCol = oSettings.aoColumns[ iCol ];
143
			
144
			/* User specified column options */
145
			if ( oOptions !== undefined && oOptions !== null )
146
			{
147
				/* Backwards compatibility for mDataProp */
148
				if ( oOptions.mDataProp && !oOptions.mData )
149
				{
150
					oOptions.mData = oOptions.mDataProp;
151
				}
152
		
153
				if ( oOptions.sType !== undefined )
154
				{
155
					oCol.sType = oOptions.sType;
156
					oCol._bAutoType = false;
157
				}
158
				
159
				$.extend( oCol, oOptions );
160
				_fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
161
		
162
				/* iDataSort to be applied (backwards compatibility), but aDataSort will take
163
				 * priority if defined
164
				 */
165
				if ( oOptions.iDataSort !== undefined )
166
				{
167
					oCol.aDataSort = [ oOptions.iDataSort ];
168
				}
169
				_fnMap( oCol, oOptions, "aDataSort" );
170
			}
171
		
172
			/* Cache the data get and set functions for speed */
173
			var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
174
			var mData = _fnGetObjectDataFn( oCol.mData );
175
		
176
			oCol.fnGetData = function (oData, sSpecific) {
177
				var innerData = mData( oData, sSpecific );
178
		
179
				if ( oCol.mRender && (sSpecific && sSpecific !== '') )
180
				{
181
					return mRender( innerData, sSpecific, oData );
182
				}
183
				return innerData;
184
			};
185
			oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
186
			
187
			/* Feature sorting overrides column specific when off */
188
			if ( !oSettings.oFeatures.bSort )
189
			{
190
				oCol.bSortable = false;
191
			}
192
			
193
			/* Check that the class assignment is correct for sorting */
194
			if ( !oCol.bSortable ||
195
				 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
196
			{
197
				oCol.sSortingClass = oSettings.oClasses.sSortableNone;
198
				oCol.sSortingClassJUI = "";
199
			}
200
			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )
201
			{
202
				oCol.sSortingClass = oSettings.oClasses.sSortable;
203
				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
204
			}
205
			else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
206
			{
207
				oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
208
				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
209
			}
210
			else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
211
			{
212
				oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
213
				oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
214
			}
215
		}
216
		
217
		
218
		/**
219
		 * Adjust the table column widths for new data. Note: you would probably want to 
220
		 * do a redraw after calling this function!
221
		 *  @param {object} oSettings dataTables settings object
222
		 *  @memberof DataTable#oApi
223
		 */
224
		function _fnAdjustColumnSizing ( oSettings )
225
		{
226
			/* Not interested in doing column width calculation if auto-width is disabled */
227
			if ( oSettings.oFeatures.bAutoWidth === false )
228
			{
229
				return false;
230
			}
231
			
232
			_fnCalculateColumnWidths( oSettings );
233
			for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
234
			{
235
				oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
236
			}
237
		}
238
		
239
		
240
		/**
241
		 * Covert the index of a visible column to the index in the data array (take account
242
		 * of hidden columns)
243
		 *  @param {object} oSettings dataTables settings object
244
		 *  @param {int} iMatch Visible column index to lookup
245
		 *  @returns {int} i the data index
246
		 *  @memberof DataTable#oApi
247
		 */
248
		function _fnVisibleToColumnIndex( oSettings, iMatch )
249
		{
250
			var aiVis = _fnGetColumns( oSettings, 'bVisible' );
251
		
252
			return typeof aiVis[iMatch] === 'number' ?
253
				aiVis[iMatch] :
254
				null;
255
		}
256
		
257
		
258
		/**
259
		 * Covert the index of an index in the data array and convert it to the visible
260
		 *   column index (take account of hidden columns)
261
		 *  @param {int} iMatch Column index to lookup
262
		 *  @param {object} oSettings dataTables settings object
263
		 *  @returns {int} i the data index
264
		 *  @memberof DataTable#oApi
265
		 */
266
		function _fnColumnIndexToVisible( oSettings, iMatch )
267
		{
268
			var aiVis = _fnGetColumns( oSettings, 'bVisible' );
269
			var iPos = $.inArray( iMatch, aiVis );
270
		
271
			return iPos !== -1 ? iPos : null;
272
		}
273
		
274
		
275
		/**
276
		 * Get the number of visible columns
277
		 *  @param {object} oSettings dataTables settings object
278
		 *  @returns {int} i the number of visible columns
279
		 *  @memberof DataTable#oApi
280
		 */
281
		function _fnVisbleColumns( oSettings )
282
		{
283
			return _fnGetColumns( oSettings, 'bVisible' ).length;
284
		}
285
		
286
		
287
		/**
288
		 * Get an array of column indexes that match a given property
289
		 *  @param {object} oSettings dataTables settings object
290
		 *  @param {string} sParam Parameter in aoColumns to look for - typically 
291
		 *    bVisible or bSearchable
292
		 *  @returns {array} Array of indexes with matched properties
293
		 *  @memberof DataTable#oApi
294
		 */
295
		function _fnGetColumns( oSettings, sParam )
296
		{
297
			var a = [];
298
		
299
			$.map( oSettings.aoColumns, function(val, i) {
300
				if ( val[sParam] ) {
301
					a.push( i );
302
				}
303
			} );
304
		
305
			return a;
306
		}
307
		
308
		
309
		/**
310
		 * Get the sort type based on an input string
311
		 *  @param {string} sData data we wish to know the type of
312
		 *  @returns {string} type (defaults to 'string' if no type can be detected)
313
		 *  @memberof DataTable#oApi
314
		 */
315
		function _fnDetectType( sData )
316
		{
317
			var aTypes = DataTable.ext.aTypes;
318
			var iLen = aTypes.length;
319
			
320
			for ( var i=0 ; i<iLen ; i++ )
321
			{
322
				var sType = aTypes[i]( sData );
323
				if ( sType !== null )
324
				{
325
					return sType;
326
				}
327
			}
328
			
329
			return 'string';
330
		}
331
		
332
		
333
		/**
334
		 * Figure out how to reorder a display list
335
		 *  @param {object} oSettings dataTables settings object
336
		 *  @returns array {int} aiReturn index list for reordering
337
		 *  @memberof DataTable#oApi
338
		 */
339
		function _fnReOrderIndex ( oSettings, sColumns )
340
		{
341
			var aColumns = sColumns.split(',');
342
			var aiReturn = [];
343
			
344
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
345
			{
346
				for ( var j=0 ; j<iLen ; j++ )
347
				{
348
					if ( oSettings.aoColumns[i].sName == aColumns[j] )
349
					{
350
						aiReturn.push( j );
351
						break;
352
					}
353
				}
354
			}
355
			
356
			return aiReturn;
357
		}
358
		
359
		
360
		/**
361
		 * Get the column ordering that DataTables expects
362
		 *  @param {object} oSettings dataTables settings object
363
		 *  @returns {string} comma separated list of names
364
		 *  @memberof DataTable#oApi
365
		 */
366
		function _fnColumnOrdering ( oSettings )
367
		{
368
			var sNames = '';
369
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
370
			{
371
				sNames += oSettings.aoColumns[i].sName+',';
372
			}
373
			if ( sNames.length == iLen )
374
			{
375
				return "";
376
			}
377
			return sNames.slice(0, -1);
378
		}
379
		
380
		
381
		/**
382
		 * Take the column definitions and static columns arrays and calculate how
383
		 * they relate to column indexes. The callback function will then apply the
384
		 * definition found for a column to a suitable configuration object.
385
		 *  @param {object} oSettings dataTables settings object
386
		 *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
387
		 *  @param {array} aoCols The aoColumns array that defines columns individually
388
		 *  @param {function} fn Callback function - takes two parameters, the calculated
389
		 *    column index and the definition for that column.
390
		 *  @memberof DataTable#oApi
391
		 */
392
		function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
393
		{
394
			var i, iLen, j, jLen, k, kLen;
395
		
396
			// Column definitions with aTargets
397
			if ( aoColDefs )
398
			{
399
				/* Loop over the definitions array - loop in reverse so first instance has priority */
400
				for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
401
				{
402
					/* Each definition can target multiple columns, as it is an array */
403
					var aTargets = aoColDefs[i].aTargets;
404
					if ( !$.isArray( aTargets ) )
405
					{
406
						_fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
407
					}
408
		
409
					for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
410
					{
411
						if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
412
						{
413
							/* Add columns that we don't yet know about */
414
							while( oSettings.aoColumns.length <= aTargets[j] )
415
							{
416
								_fnAddColumn( oSettings );
417
							}
418
		
419
							/* Integer, basic index */
420
							fn( aTargets[j], aoColDefs[i] );
421
						}
422
						else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
423
						{
424
							/* Negative integer, right to left column counting */
425
							fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
426
						}
427
						else if ( typeof aTargets[j] === 'string' )
428
						{
429
							/* Class name matching on TH element */
430
							for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
431
							{
432
								if ( aTargets[j] == "_all" ||
433
								     $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
434
								{
435
									fn( k, aoColDefs[i] );
436
								}
437
							}
438
						}
439
					}
440
				}
441
			}
442
		
443
			// Statically defined columns array
444
			if ( aoCols )
445
			{
446
				for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
447
				{
448
					fn( i, aoCols[i] );
449
				}
450
			}
451
		}
452
		
453
		/**
454
		 * Add a data array to the table, creating DOM node etc. This is the parallel to 
455
		 * _fnGatherData, but for adding rows from a Javascript source, rather than a
456
		 * DOM source.
457
		 *  @param {object} oSettings dataTables settings object
458
		 *  @param {array} aData data array to be added
459
		 *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
460
		 *  @memberof DataTable#oApi
461
		 */
462
		function _fnAddData ( oSettings, aDataSupplied )
463
		{
464
			var oCol;
465
			
466
			/* Take an independent copy of the data source so we can bash it about as we wish */
467
			var aDataIn = ($.isArray(aDataSupplied)) ?
468
				aDataSupplied.slice() :
469
				$.extend( true, {}, aDataSupplied );
470
			
471
			/* Create the object for storing information about this new row */
472
			var iRow = oSettings.aoData.length;
473
			var oData = $.extend( true, {}, DataTable.models.oRow );
474
			oData._aData = aDataIn;
475
			oSettings.aoData.push( oData );
476
		
477
			/* Create the cells */
478
			var nTd, sThisType;
479
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
480
			{
481
				oCol = oSettings.aoColumns[i];
482
		
483
				/* Use rendered data for filtering / sorting */
484
				if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
485
				{
486
					_fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
487
				}
488
				else
489
				{
490
					_fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
491
				}
492
				
493
				/* See if we should auto-detect the column type */
494
				if ( oCol._bAutoType && oCol.sType != 'string' )
495
				{
496
					/* Attempt to auto detect the type - same as _fnGatherData() */
497
					var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
498
					if ( sVarType !== null && sVarType !== '' )
499
					{
500
						sThisType = _fnDetectType( sVarType );
501
						if ( oCol.sType === null )
502
						{
503
							oCol.sType = sThisType;
504
						}
505
						else if ( oCol.sType != sThisType && oCol.sType != "html" )
506
						{
507
							/* String is always the 'fallback' option */
508
							oCol.sType = 'string';
509
						}
510
					}
511
				}
512
			}
513
			
514
			/* Add to the display array */
515
			oSettings.aiDisplayMaster.push( iRow );
516
		
517
			/* Create the DOM information */
518
			if ( !oSettings.oFeatures.bDeferRender )
519
			{
520
				_fnCreateTr( oSettings, iRow );
521
			}
522
		
523
			return iRow;
524
		}
525
		
526
		
527
		/**
528
		 * Read in the data from the target table from the DOM
529
		 *  @param {object} oSettings dataTables settings object
530
		 *  @memberof DataTable#oApi
531
		 */
532
		function _fnGatherData( oSettings )
533
		{
534
			var iLoop, i, iLen, j, jLen, jInner,
535
			 	nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
536
				iRow, iRows, iColumn, iColumns, sNodeName,
537
				oCol, oData;
538
			
539
			/*
540
			 * Process by row first
541
			 * Add the data object for the whole table - storing the tr node. Note - no point in getting
542
			 * DOM based data if we are going to go and replace it with Ajax source data.
543
			 */
544
			if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
545
			{
546
				nTr = oSettings.nTBody.firstChild;
547
				while ( nTr )
548
				{
549
					if ( nTr.nodeName.toUpperCase() == "TR" )
550
					{
551
						iThisIndex = oSettings.aoData.length;
552
						nTr._DT_RowIndex = iThisIndex;
553
						oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
554
							"nTr": nTr
555
						} ) );
556
		
557
						oSettings.aiDisplayMaster.push( iThisIndex );
558
						nTd = nTr.firstChild;
559
						jInner = 0;
560
						while ( nTd )
561
						{
562
							sNodeName = nTd.nodeName.toUpperCase();
563
							if ( sNodeName == "TD" || sNodeName == "TH" )
564
							{
565
								_fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
566
								jInner++;
567
							}
568
							nTd = nTd.nextSibling;
569
						}
570
					}
571
					nTr = nTr.nextSibling;
572
				}
573
			}
574
			
575
			/* Gather in the TD elements of the Table - note that this is basically the same as
576
			 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
577
			 * setup!
578
			 */
579
			nTrs = _fnGetTrNodes( oSettings );
580
			nTds = [];
581
			for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
582
			{
583
				nTd = nTrs[i].firstChild;
584
				while ( nTd )
585
				{
586
					sNodeName = nTd.nodeName.toUpperCase();
587
					if ( sNodeName == "TD" || sNodeName == "TH" )
588
					{
589
						nTds.push( nTd );
590
					}
591
					nTd = nTd.nextSibling;
592
				}
593
			}
594
			
595
			/* Now process by column */
596
			for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
597
			{
598
				oCol = oSettings.aoColumns[iColumn];
599
		
600
				/* Get the title of the column - unless there is a user set one */
601
				if ( oCol.sTitle === null )
602
				{
603
					oCol.sTitle = oCol.nTh.innerHTML;
604
				}
605
				
606
				var
607
					bAutoType = oCol._bAutoType,
608
					bRender = typeof oCol.fnRender === 'function',
609
					bClass = oCol.sClass !== null,
610
					bVisible = oCol.bVisible,
611
					nCell, sThisType, sRendered, sValType;
612
				
613
				/* A single loop to rule them all (and be more efficient) */
614
				if ( bAutoType || bRender || bClass || !bVisible )
615
				{
616
					for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
617
					{
618
						oData = oSettings.aoData[iRow];
619
						nCell = nTds[ (iRow*iColumns) + iColumn ];
620
						
621
						/* Type detection */
622
						if ( bAutoType && oCol.sType != 'string' )
623
						{
624
							sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
625
							if ( sValType !== '' )
626
							{
627
								sThisType = _fnDetectType( sValType );
628
								if ( oCol.sType === null )
629
								{
630
									oCol.sType = sThisType;
631
								}
632
								else if ( oCol.sType != sThisType && 
633
								          oCol.sType != "html" )
634
								{
635
									/* String is always the 'fallback' option */
636
									oCol.sType = 'string';
637
								}
638
							}
639
						}
640
		
641
						if ( oCol.mRender )
642
						{
643
							// mRender has been defined, so we need to get the value and set it
644
							nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
645
						}
646
						else if ( oCol.mData !== iColumn )
647
						{
648
							// If mData is not the same as the column number, then we need to
649
							// get the dev set value. If it is the column, no point in wasting
650
							// time setting the value that is already there!
651
							nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
652
						}
653
						
654
						/* Rendering */
655
						if ( bRender )
656
						{
657
							sRendered = _fnRender( oSettings, iRow, iColumn );
658
							nCell.innerHTML = sRendered;
659
							if ( oCol.bUseRendered )
660
							{
661
								/* Use the rendered data for filtering / sorting */
662
								_fnSetCellData( oSettings, iRow, iColumn, sRendered );
663
							}
664
						}
665
						
666
						/* Classes */
667
						if ( bClass )
668
						{
669
							nCell.className += ' '+oCol.sClass;
670
						}
671
						
672
						/* Column visibility */
673
						if ( !bVisible )
674
						{
675
							oData._anHidden[iColumn] = nCell;
676
							nCell.parentNode.removeChild( nCell );
677
						}
678
						else
679
						{
680
							oData._anHidden[iColumn] = null;
681
						}
682
		
683
						if ( oCol.fnCreatedCell )
684
						{
685
							oCol.fnCreatedCell.call( oSettings.oInstance,
686
								nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
687
							);
688
						}
689
					}
690
				}
691
			}
692
		
693
			/* Row created callbacks */
694
			if ( oSettings.aoRowCreatedCallback.length !== 0 )
695
			{
696
				for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
697
				{
698
					oData = oSettings.aoData[i];
699
					_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
700
				}
701
			}
702
		}
703
		
704
		
705
		/**
706
		 * Take a TR element and convert it to an index in aoData
707
		 *  @param {object} oSettings dataTables settings object
708
		 *  @param {node} n the TR element to find
709
		 *  @returns {int} index if the node is found, null if not
710
		 *  @memberof DataTable#oApi
711
		 */
712
		function _fnNodeToDataIndex( oSettings, n )
713
		{
714
			return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
715
		}
716
		
717
		
718
		/**
719
		 * Take a TD element and convert it into a column data index (not the visible index)
720
		 *  @param {object} oSettings dataTables settings object
721
		 *  @param {int} iRow The row number the TD/TH can be found in
722
		 *  @param {node} n The TD/TH element to find
723
		 *  @returns {int} index if the node is found, -1 if not
724
		 *  @memberof DataTable#oApi
725
		 */
726
		function _fnNodeToColumnIndex( oSettings, iRow, n )
727
		{
728
			var anCells = _fnGetTdNodes( oSettings, iRow );
729
		
730
			for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
731
			{
732
				if ( anCells[i] === n )
733
				{
734
					return i;
735
				}
736
			}
737
			return -1;
738
		}
739
		
740
		
741
		/**
742
		 * Get an array of data for a given row from the internal data cache
743
		 *  @param {object} oSettings dataTables settings object
744
		 *  @param {int} iRow aoData row id
745
		 *  @param {string} sSpecific data get type ('type' 'filter' 'sort')
746
		 *  @param {array} aiColumns Array of column indexes to get data from
747
		 *  @returns {array} Data array
748
		 *  @memberof DataTable#oApi
749
		 */
750
		function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
751
		{
752
			var out = [];
753
			for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
754
			{
755
				out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
756
			}
757
			return out;
758
		}
759
		
760
		
761
		/**
762
		 * Get the data for a given cell from the internal cache, taking into account data mapping
763
		 *  @param {object} oSettings dataTables settings object
764
		 *  @param {int} iRow aoData row id
765
		 *  @param {int} iCol Column index
766
		 *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
767
		 *  @returns {*} Cell data
768
		 *  @memberof DataTable#oApi
769
		 */
770
		function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
771
		{
772
			var sData;
773
			var oCol = oSettings.aoColumns[iCol];
774
			var oData = oSettings.aoData[iRow]._aData;
775
		
776
			if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
777
			{
778
				if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
779
				{
780
					_fnLog( oSettings, 0, "Requested unknown parameter "+
781
						(typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
782
						" from the data source for row "+iRow );
783
					oSettings.iDrawError = oSettings.iDraw;
784
				}
785
				return oCol.sDefaultContent;
786
			}
787
		
788
			/* When the data source is null, we can use default column data */
789
			if ( sData === null && oCol.sDefaultContent !== null )
790
			{
791
				sData = oCol.sDefaultContent;
792
			}
793
			else if ( typeof sData === 'function' )
794
			{
795
				/* If the data source is a function, then we run it and use the return */
796
				return sData();
797
			}
798
		
799
			if ( sSpecific == 'display' && sData === null )
800
			{
801
				return '';
802
			}
803
			return sData;
804
		}
805
		
806
		
807
		/**
808
		 * Set the value for a specific cell, into the internal data cache
809
		 *  @param {object} oSettings dataTables settings object
810
		 *  @param {int} iRow aoData row id
811
		 *  @param {int} iCol Column index
812
		 *  @param {*} val Value to set
813
		 *  @memberof DataTable#oApi
814
		 */
815
		function _fnSetCellData( oSettings, iRow, iCol, val )
816
		{
817
			var oCol = oSettings.aoColumns[iCol];
818
			var oData = oSettings.aoData[iRow]._aData;
819
		
820
			oCol.fnSetData( oData, val );
821
		}
822
		
823
		
824
		// Private variable that is used to match array syntax in the data property object
825
		var __reArray = /\[.*?\]$/;
826
		
827
		/**
828
		 * Return a function that can be used to get data from a source object, taking
829
		 * into account the ability to use nested objects as a source
830
		 *  @param {string|int|function} mSource The data source for the object
831
		 *  @returns {function} Data get function
832
		 *  @memberof DataTable#oApi
833
		 */
834
		function _fnGetObjectDataFn( mSource )
835
		{
836
			if ( mSource === null )
837
			{
838
				/* Give an empty string for rendering / sorting etc */
839
				return function (data, type) {
840
					return null;
841
				};
842
			}
843
			else if ( typeof mSource === 'function' )
844
			{
845
				return function (data, type, extra) {
846
					return mSource( data, type, extra );
847
				};
848
			}
849
			else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
850
			{
851
				/* If there is a . in the source string then the data source is in a 
852
				 * nested object so we loop over the data for each level to get the next
853
				 * level down. On each loop we test for undefined, and if found immediately
854
				 * return. This allows entire objects to be missing and sDefaultContent to
855
				 * be used if defined, rather than throwing an error
856
				 */
857
				var fetchData = function (data, type, src) {
858
					var a = src.split('.');
859
					var arrayNotation, out, innerSrc;
860
		
861
					if ( src !== "" )
862
					{
863
						for ( var i=0, iLen=a.length ; i<iLen ; i++ )
864
						{
865
							// Check if we are dealing with an array notation request
866
							arrayNotation = a[i].match(__reArray);
867
		
868
							if ( arrayNotation ) {
869
								a[i] = a[i].replace(__reArray, '');
870
		
871
								// Condition allows simply [] to be passed in
872
								if ( a[i] !== "" ) {
873
									data = data[ a[i] ];
874
								}
875
								out = [];
876
								
877
								// Get the remainder of the nested object to get
878
								a.splice( 0, i+1 );
879
								innerSrc = a.join('.');
880
		
881
								// Traverse each entry in the array getting the properties requested
882
								for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
883
									out.push( fetchData( data[j], type, innerSrc ) );
884
								}
885
		
886
								// If a string is given in between the array notation indicators, that
887
								// is used to join the strings together, otherwise an array is returned
888
								var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
889
								data = (join==="") ? out : out.join(join);
890
		
891
								// The inner call to fetchData has already traversed through the remainder
892
								// of the source requested, so we exit from the loop
893
								break;
894
							}
895
		
896
							if ( data === null || data[ a[i] ] === undefined )
897
							{
898
								return undefined;
899
							}
900
							data = data[ a[i] ];
901
						}
902
					}
903
		
904
					return data;
905
				};
906
		
907
				return function (data, type) {
908
					return fetchData( data, type, mSource );
909
				};
910
			}
911
			else
912
			{
913
				/* Array or flat object mapping */
914
				return function (data, type) {
915
					return data[mSource];	
916
				};
917
			}
918
		}
919
		
920
		
921
		/**
922
		 * Return a function that can be used to set data from a source object, taking
923
		 * into account the ability to use nested objects as a source
924
		 *  @param {string|int|function} mSource The data source for the object
925
		 *  @returns {function} Data set function
926
		 *  @memberof DataTable#oApi
927
		 */
928
		function _fnSetObjectDataFn( mSource )
929
		{
930
			if ( mSource === null )
931
			{
932
				/* Nothing to do when the data source is null */
933
				return function (data, val) {};
934
			}
935
			else if ( typeof mSource === 'function' )
936
			{
937
				return function (data, val) {
938
					mSource( data, 'set', val );
939
				};
940
			}
941
			else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
942
			{
943
				/* Like the get, we need to get data from a nested object */
944
				var setData = function (data, val, src) {
945
					var a = src.split('.'), b;
946
					var arrayNotation, o, innerSrc;
947
		
948
					for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
949
					{
950
						// Check if we are dealing with an array notation request
951
						arrayNotation = a[i].match(__reArray);
952
		
953
						if ( arrayNotation )
954
						{
955
							a[i] = a[i].replace(__reArray, '');
956
							data[ a[i] ] = [];
957
							
958
							// Get the remainder of the nested object to set so we can recurse
959
							b = a.slice();
960
							b.splice( 0, i+1 );
961
							innerSrc = b.join('.');
962
		
963
							// Traverse each entry in the array setting the properties requested
964
							for ( var j=0, jLen=val.length ; j<jLen ; j++ )
965
							{
966
								o = {};
967
								setData( o, val[j], innerSrc );
968
								data[ a[i] ].push( o );
969
							}
970
		
971
							// The inner call to setData has already traversed through the remainder
972
							// of the source and has set the data, thus we can exit here
973
							return;
974
						}
975
		
976
						// If the nested object doesn't currently exist - since we are
977
						// trying to set the value - create it
978
						if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
979
						{
980
							data[ a[i] ] = {};
981
						}
982
						data = data[ a[i] ];
983
					}
984
		
985
					// If array notation is used, we just want to strip it and use the property name
986
					// and assign the value. If it isn't used, then we get the result we want anyway
987
					data[ a[a.length-1].replace(__reArray, '') ] = val;
988
				};
989
		
990
				return function (data, val) {
991
					return setData( data, val, mSource );
992
				};
993
			}
994
			else
995
			{
996
				/* Array or flat object mapping */
997
				return function (data, val) {
998
					data[mSource] = val;	
999
				};
1000
			}
1001
		}
1002
		
1003
		
1004
		/**
1005
		 * Return an array with the full table data
1006
		 *  @param {object} oSettings dataTables settings object
1007
		 *  @returns array {array} aData Master data array
1008
		 *  @memberof DataTable#oApi
1009
		 */
1010
		function _fnGetDataMaster ( oSettings )
1011
		{
1012
			var aData = [];
1013
			var iLen = oSettings.aoData.length;
1014
			for ( var i=0 ; i<iLen; i++ )
1015
			{
1016
				aData.push( oSettings.aoData[i]._aData );
1017
			}
1018
			return aData;
1019
		}
1020
		
1021
		
1022
		/**
1023
		 * Nuke the table
1024
		 *  @param {object} oSettings dataTables settings object
1025
		 *  @memberof DataTable#oApi
1026
		 */
1027
		function _fnClearTable( oSettings )
1028
		{
1029
			oSettings.aoData.splice( 0, oSettings.aoData.length );
1030
			oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
1031
			oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
1032
			_fnCalculateEnd( oSettings );
1033
		}
1034
		
1035
		
1036
		 /**
1037
		 * Take an array of integers (index array) and remove a target integer (value - not 
1038
		 * the key!)
1039
		 *  @param {array} a Index array to target
1040
		 *  @param {int} iTarget value to find
1041
		 *  @memberof DataTable#oApi
1042
		 */
1043
		function _fnDeleteIndex( a, iTarget )
1044
		{
1045
			var iTargetIndex = -1;
1046
			
1047
			for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1048
			{
1049
				if ( a[i] == iTarget )
1050
				{
1051
					iTargetIndex = i;
1052
				}
1053
				else if ( a[i] > iTarget )
1054
				{
1055
					a[i]--;
1056
				}
1057
			}
1058
			
1059
			if ( iTargetIndex != -1 )
1060
			{
1061
				a.splice( iTargetIndex, 1 );
1062
			}
1063
		}
1064
		
1065
		
1066
		 /**
1067
		 * Call the developer defined fnRender function for a given cell (row/column) with
1068
		 * the required parameters and return the result.
1069
		 *  @param {object} oSettings dataTables settings object
1070
		 *  @param {int} iRow aoData index for the row
1071
		 *  @param {int} iCol aoColumns index for the column
1072
		 *  @returns {*} Return of the developer's fnRender function
1073
		 *  @memberof DataTable#oApi
1074
		 */
1075
		function _fnRender( oSettings, iRow, iCol )
1076
		{
1077
			var oCol = oSettings.aoColumns[iCol];
1078
		
1079
			return oCol.fnRender( {
1080
				"iDataRow":    iRow,
1081
				"iDataColumn": iCol,
1082
				"oSettings":   oSettings,
1083
				"aData":       oSettings.aoData[iRow]._aData,
1084
				"mDataProp":   oCol.mData
1085
			}, _fnGetCellData(oSettings, iRow, iCol, 'display') );
1086
		}
1087
		/**
1088
		 * Create a new TR element (and it's TD children) for a row
1089
		 *  @param {object} oSettings dataTables settings object
1090
		 *  @param {int} iRow Row to consider
1091
		 *  @memberof DataTable#oApi
1092
		 */
1093
		function _fnCreateTr ( oSettings, iRow )
1094
		{
1095
			var oData = oSettings.aoData[iRow];
1096
			var nTd;
1097
		
1098
			if ( oData.nTr === null )
1099
			{
1100
				oData.nTr = document.createElement('tr');
1101
		
1102
				/* Use a private property on the node to allow reserve mapping from the node
1103
				 * to the aoData array for fast look up
1104
				 */
1105
				oData.nTr._DT_RowIndex = iRow;
1106
		
1107
				/* Special parameters can be given by the data source to be used on the row */
1108
				if ( oData._aData.DT_RowId )
1109
				{
1110
					oData.nTr.id = oData._aData.DT_RowId;
1111
				}
1112
		
1113
				if ( oData._aData.DT_RowClass )
1114
				{
1115
					oData.nTr.className = oData._aData.DT_RowClass;
1116
				}
1117
		
1118
				/* Process each column */
1119
				for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1120
				{
1121
					var oCol = oSettings.aoColumns[i];
1122
					nTd = document.createElement( oCol.sCellType );
1123
		
1124
					/* Render if needed - if bUseRendered is true then we already have the rendered
1125
					 * value in the data source - so can just use that
1126
					 */
1127
					nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ?
1128
						_fnRender( oSettings, iRow, i ) :
1129
						_fnGetCellData( oSettings, iRow, i, 'display' );
1130
				
1131
					/* Add user defined class */
1132
					if ( oCol.sClass !== null )
1133
					{
1134
						nTd.className = oCol.sClass;
1135
					}
1136
					
1137
					if ( oCol.bVisible )
1138
					{
1139
						oData.nTr.appendChild( nTd );
1140
						oData._anHidden[i] = null;
1141
					}
1142
					else
1143
					{
1144
						oData._anHidden[i] = nTd;
1145
					}
1146
		
1147
					if ( oCol.fnCreatedCell )
1148
					{
1149
						oCol.fnCreatedCell.call( oSettings.oInstance,
1150
							nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
1151
						);
1152
					}
1153
				}
1154
		
1155
				_fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
1156
			}
1157
		}
1158
		
1159
		
1160
		/**
1161
		 * Create the HTML header for the table
1162
		 *  @param {object} oSettings dataTables settings object
1163
		 *  @memberof DataTable#oApi
1164
		 */
1165
		function _fnBuildHead( oSettings )
1166
		{
1167
			var i, nTh, iLen, j, jLen;
1168
			var iThs = $('th, td', oSettings.nTHead).length;
1169
			var iCorrector = 0;
1170
			var jqChildren;
1171
			
1172
			/* If there is a header in place - then use it - otherwise it's going to get nuked... */
1173
			if ( iThs !== 0 )
1174
			{
1175
				/* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
1176
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1177
				{
1178
					nTh = oSettings.aoColumns[i].nTh;
1179
					nTh.setAttribute('role', 'columnheader');
1180
					if ( oSettings.aoColumns[i].bSortable )
1181
					{
1182
						nTh.setAttribute('tabindex', oSettings.iTabIndex);
1183
						nTh.setAttribute('aria-controls', oSettings.sTableId);
1184
					}
1185
		
1186
					if ( oSettings.aoColumns[i].sClass !== null )
1187
					{
1188
						$(nTh).addClass( oSettings.aoColumns[i].sClass );
1189
					}
1190
					
1191
					/* Set the title of the column if it is user defined (not what was auto detected) */
1192
					if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
1193
					{
1194
						nTh.innerHTML = oSettings.aoColumns[i].sTitle;
1195
					}
1196
				}
1197
			}
1198
			else
1199
			{
1200
				/* We don't have a header in the DOM - so we are going to have to create one */
1201
				var nTr = document.createElement( "tr" );
1202
				
1203
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1204
				{
1205
					nTh = oSettings.aoColumns[i].nTh;
1206
					nTh.innerHTML = oSettings.aoColumns[i].sTitle;
1207
					nTh.setAttribute('tabindex', '0');
1208
					
1209
					if ( oSettings.aoColumns[i].sClass !== null )
1210
					{
1211
						$(nTh).addClass( oSettings.aoColumns[i].sClass );
1212
					}
1213
					
1214
					nTr.appendChild( nTh );
1215
				}
1216
				$(oSettings.nTHead).html( '' )[0].appendChild( nTr );
1217
				_fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
1218
			}
1219
			
1220
			/* ARIA role for the rows */	
1221
			$(oSettings.nTHead).children('tr').attr('role', 'row');
1222
			
1223
			/* Add the extra markup needed by jQuery UI's themes */
1224
			if ( oSettings.bJUI )
1225
			{
1226
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1227
				{
1228
					nTh = oSettings.aoColumns[i].nTh;
1229
					
1230
					var nDiv = document.createElement('div');
1231
					nDiv.className = oSettings.oClasses.sSortJUIWrapper;
1232
					$(nTh).contents().appendTo(nDiv);
1233
					
1234
					var nSpan = document.createElement('span');
1235
					nSpan.className = oSettings.oClasses.sSortIcon;
1236
					nDiv.appendChild( nSpan );
1237
					nTh.appendChild( nDiv );
1238
				}
1239
			}
1240
			
1241
			if ( oSettings.oFeatures.bSort )
1242
			{
1243
				for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
1244
				{
1245
					if ( oSettings.aoColumns[i].bSortable !== false )
1246
					{
1247
						_fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
1248
					}
1249
					else
1250
					{
1251
						$(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
1252
					}
1253
				}
1254
			}
1255
			
1256
			/* Deal with the footer - add classes if required */
1257
			if ( oSettings.oClasses.sFooterTH !== "" )
1258
			{
1259
				$(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
1260
			}
1261
			
1262
			/* Cache the footer elements */
1263
			if ( oSettings.nTFoot !== null )
1264
			{
1265
				var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
1266
				for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1267
				{
1268
					if ( anCells[i] )
1269
					{
1270
						oSettings.aoColumns[i].nTf = anCells[i];
1271
						if ( oSettings.aoColumns[i].sClass )
1272
						{
1273
							$(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
1274
						}
1275
					}
1276
				}
1277
			}
1278
		}
1279
		
1280
		
1281
		/**
1282
		 * Draw the header (or footer) element based on the column visibility states. The
1283
		 * methodology here is to use the layout array from _fnDetectHeader, modified for
1284
		 * the instantaneous column visibility, to construct the new layout. The grid is
1285
		 * traversed over cell at a time in a rows x columns grid fashion, although each 
1286
		 * cell insert can cover multiple elements in the grid - which is tracks using the
1287
		 * aApplied array. Cell inserts in the grid will only occur where there isn't
1288
		 * already a cell in that position.
1289
		 *  @param {object} oSettings dataTables settings object
1290
		 *  @param array {objects} aoSource Layout array from _fnDetectHeader
1291
		 *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 
1292
		 *  @memberof DataTable#oApi
1293
		 */
1294
		function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1295
		{
1296
			var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1297
			var aoLocal = [];
1298
			var aApplied = [];
1299
			var iColumns = oSettings.aoColumns.length;
1300
			var iRowspan, iColspan;
1301
		
1302
			if (  bIncludeHidden === undefined )
1303
			{
1304
				bIncludeHidden = false;
1305
			}
1306
		
1307
			/* Make a copy of the master layout array, but without the visible columns in it */
1308
			for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1309
			{
1310
				aoLocal[i] = aoSource[i].slice();
1311
				aoLocal[i].nTr = aoSource[i].nTr;
1312
		
1313
				/* Remove any columns which are currently hidden */
1314
				for ( j=iColumns-1 ; j>=0 ; j-- )
1315
				{
1316
					if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1317
					{
1318
						aoLocal[i].splice( j, 1 );
1319
					}
1320
				}
1321
		
1322
				/* Prep the applied array - it needs an element for each row */
1323
				aApplied.push( [] );
1324
			}
1325
		
1326
			for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1327
			{
1328
				nLocalTr = aoLocal[i].nTr;
1329
				
1330
				/* All cells are going to be replaced, so empty out the row */
1331
				if ( nLocalTr )
1332
				{
1333
					while( (n = nLocalTr.firstChild) )
1334
					{
1335
						nLocalTr.removeChild( n );
1336
					}
1337
				}
1338
		
1339
				for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1340
				{
1341
					iRowspan = 1;
1342
					iColspan = 1;
1343
		
1344
					/* Check to see if there is already a cell (row/colspan) covering our target
1345
					 * insert point. If there is, then there is nothing to do.
1346
					 */
1347
					if ( aApplied[i][j] === undefined )
1348
					{
1349
						nLocalTr.appendChild( aoLocal[i][j].cell );
1350
						aApplied[i][j] = 1;
1351
		
1352
						/* Expand the cell to cover as many rows as needed */
1353
						while ( aoLocal[i+iRowspan] !== undefined &&
1354
						        aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1355
						{
1356
							aApplied[i+iRowspan][j] = 1;
1357
							iRowspan++;
1358
						}
1359
		
1360
						/* Expand the cell to cover as many columns as needed */
1361
						while ( aoLocal[i][j+iColspan] !== undefined &&
1362
						        aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1363
						{
1364
							/* Must update the applied array over the rows for the columns */
1365
							for ( k=0 ; k<iRowspan ; k++ )
1366
							{
1367
								aApplied[i+k][j+iColspan] = 1;
1368
							}
1369
							iColspan++;
1370
						}
1371
		
1372
						/* Do the actual expansion in the DOM */
1373
						aoLocal[i][j].cell.rowSpan = iRowspan;
1374
						aoLocal[i][j].cell.colSpan = iColspan;
1375
					}
1376
				}
1377
			}
1378
		}
1379
		
1380
		
1381
		/**
1382
		 * Insert the required TR nodes into the table for display
1383
		 *  @param {object} oSettings dataTables settings object
1384
		 *  @memberof DataTable#oApi
1385
		 */
1386
		function _fnDraw( oSettings )
1387
		{
1388
			/* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1389
			var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1390
			if ( $.inArray( false, aPreDraw ) !== -1 )
1391
			{
1392
				_fnProcessingDisplay( oSettings, false );
1393
				return;
1394
			}
1395
			
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff