1
0
mirror of https://github.com/DataTables/DataTables.git synced 2024-12-10 22:24:10 +01:00

New: Column visibilty will now work great with rowspan / colspan in the header and footer! The way this is done is by creating a stored grid of the header/footer information - a grid of rows x columns - which contains information about the cell that should be at each point - regardless of rowspan / colspan. From that information it is then possible to draw the header / footer, minus any column (or row, although that is not used here) as needed. The initialisation and column visibility functions have been updated to account for this. This allows ColVis and the other plug-ins to 'just work' with complex headers.

New: Initialisation parameter: bSortCellsTop. This parameter allows control over whether DataTables should use the top (true) unique cell that is found for a single column, or the bottom (false - default). This is useful when using complex headers.
Removed: From the column definiations array (aoColumns) there is now no longer any need for anThExtra, anTfExtra or nTf. These have now been removed and will cause compatibilty issues for any plug-ins which use them.
Fix: Tidy up spaces where there should be tabs
This commit is contained in:
Allan Jardine 2011-04-10 19:15:09 +01:00
parent a0967b7b14
commit e290f76496

View File

@ -26,7 +26,7 @@
* building the dynamic multi-column sort functions. * building the dynamic multi-column sort functions.
*/ */
/*jslint evil: true, undef: true, browser: true */ /*jslint evil: true, undef: true, browser: true */
/*globals $, jQuery,_fnExternApiFunc,_fnInitalise,_fnInitComplete,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnGatherData,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxUpdateDraw,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAjustColumnSizing,_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,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap*/ /*globals $, jQuery,_fnExternApiFunc,_fnInitalise,_fnInitComplete,_fnLanguageProcess,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnGatherData,_fnBuildHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxUpdateDraw,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAjustColumnSizing,_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,_fnArrayCmp,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap*/
(function($, window, document) { (function($, window, document) {
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
@ -1008,6 +1008,20 @@
*/ */
this.aoColumns = []; this.aoColumns = [];
/*
* Variable: aoHeader
* Purpose: Store information about the table's header
* Scope: jQuery.dataTable.classSettings
*/
this.aoHeader = [];
/*
* Variable: aoFooter
* Purpose: Store information about the table's footer
* Scope: jQuery.dataTable.classSettings
*/
this.aoFooter = [];
/* /*
* Variable: iNextId * Variable: iNextId
* Purpose: Store the next unique id to be used for a new row * Purpose: Store the next unique id to be used for a new row
@ -1388,7 +1402,7 @@
this.bJUI = false; this.bJUI = false;
/* /*
* Variable: bJUI * Variable: oClasses
* Purpose: Should we add the markup needed for jQuery UI theming? * Purpose: Should we add the markup needed for jQuery UI theming?
* Scope: jQuery.dataTable.classSettings * Scope: jQuery.dataTable.classSettings
*/ */
@ -1402,6 +1416,15 @@
this.bFiltered = false; this.bFiltered = false;
this.bSorted = false; this.bSorted = false;
/*
* Variable: bSortCellsTop
* Purpose: Indicate that if multiple rows are in the header and there is more than one
* unique cell per column, if the top one (true) or bottom one (false) should
* be used for sorting / title by DataTables
* Scope: jQuery.dataTable.classSettings
*/
this.bSortCellsTop = false;
/* /*
* Variable: oInit * Variable: oInit
* Purpose: Initialisation object that is used for the table * Purpose: Initialisation object that is used for the table
@ -1972,16 +1995,6 @@
return; return;
} }
var nTrHead = $('>tr', oSettings.nTHead)[0];
var nTrFoot = $('>tr', oSettings.nTFoot)[0];
var anTheadTh = [];
var anTfootTh = [];
for ( i=0 ; i<iColumns ; i++ )
{
anTheadTh.push( oSettings.aoColumns[i].nTh );
anTfootTh.push( oSettings.aoColumns[i].nTf );
}
/* Show the column */ /* Show the column */
if ( bShow ) if ( bShow )
{ {
@ -1997,23 +2010,6 @@
/* Need to decide if we should use appendChild or insertBefore */ /* Need to decide if we should use appendChild or insertBefore */
if ( iInsert >= _fnVisbleColumns( oSettings ) ) if ( iInsert >= _fnVisbleColumns( oSettings ) )
{ {
nTrHead.appendChild( anTheadTh[iCol] );
anTrs = $('>tr', oSettings.nTHead);
for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
{
anTrs[i].appendChild( oSettings.aoColumns[iCol].anThExtra[i-1] );
}
if ( nTrFoot )
{
nTrFoot.appendChild( anTfootTh[iCol] );
anTrs = $('>tr', oSettings.nTFoot);
for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
{
anTrs[i].appendChild( oSettings.aoColumns[iCol].anTfExtra[i-1] );
}
}
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
{ {
nTd = oSettings.aoData[i]._anHidden[iCol]; nTd = oSettings.aoData[i]._anHidden[iCol];
@ -2033,25 +2029,6 @@
} }
} }
nTrHead.insertBefore( anTheadTh[iCol], nTrHead.getElementsByTagName('th')[iBefore] );
anTrs = $('>tr', oSettings.nTHead);
for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
{
jqChildren = $(anTrs[i]).children();
anTrs[i].insertBefore( oSettings.aoColumns[iCol].anThExtra[i-1], jqChildren[iBefore] );
}
if ( nTrFoot )
{
nTrFoot.insertBefore( anTfootTh[iCol], nTrFoot.getElementsByTagName('th')[iBefore] );
anTrs = $('>tr', oSettings.nTFoot);
for ( i=1, iLen=anTrs.length ; i<iLen ; i++ )
{
jqChildren = $(anTrs[i]).children();
anTrs[i].insertBefore( oSettings.aoColumns[iCol].anTfExtra[i-1], jqChildren[iBefore] );
}
}
anTds = _fnGetTdNodes( oSettings ); anTds = _fnGetTdNodes( oSettings );
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
{ {
@ -2060,29 +2037,10 @@
oSettings.aoData[i].nTr)[0] ); oSettings.aoData[i].nTr)[0] );
} }
} }
oSettings.aoColumns[iCol].bVisible = true;
} }
else else
{ {
/* Remove a column from display */ /* Remove a column from display */
nTrHead.removeChild( anTheadTh[iCol] );
for ( i=0, iLen=oSettings.aoColumns[iCol].anThExtra.length ; i<iLen ; i++ )
{
nCell = oSettings.aoColumns[iCol].anThExtra[i];
nCell.parentNode.removeChild( nCell );
}
if ( nTrFoot )
{
nTrFoot.removeChild( anTfootTh[iCol] );
for ( i=0, iLen=oSettings.aoColumns[iCol].anTfExtra.length ; i<iLen ; i++ )
{
nCell = oSettings.aoColumns[iCol].anTfExtra[i];
nCell.parentNode.removeChild( nCell );
}
}
anTds = _fnGetTdNodes( oSettings ); anTds = _fnGetTdNodes( oSettings );
for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
{ {
@ -2090,8 +2048,16 @@
oSettings.aoData[i]._anHidden[iCol] = nTd; oSettings.aoData[i]._anHidden[iCol] = nTd;
nTd.parentNode.removeChild( nTd ); nTd.parentNode.removeChild( nTd );
} }
}
oSettings.aoColumns[iCol].bVisible = false; /* Clear to set the visible flag */
oSettings.aoColumns[iCol].bVisible = bShow;
/* Redraw the header and footer based on the new column visibility */
_fnDrawHead( oSettings, oSettings.aoHeader, oSettings.nTHead );
if ( oSettings.nTFoot )
{
_fnDrawHead( oSettings, oSettings.aoFooter, oSettings.nTFoot );
} }
/* If there are any 'open' rows, then we need to alter the colspan for this col change */ /* If there are any 'open' rows, then we need to alter the colspan for this col change */
@ -2325,8 +2291,13 @@
/* Show the display HTML options */ /* Show the display HTML options */
_fnAddOptionsHtml( oSettings ); _fnAddOptionsHtml( oSettings );
/* Draw the headers for the table */ /* Build and draw the header / footer for the table */
_fnDrawHead( oSettings ); _fnBuildHead( oSettings );
_fnDrawHead( oSettings, oSettings.aoHeader, oSettings.nTHead );
if ( oSettings.nTFoot )
{
_fnDrawHead( oSettings, oSettings.aoFooter, oSettings.nTFoot );
}
/* Okay to show that something is going on now */ /* Okay to show that something is going on now */
_fnProcessingDisplay( oSettings, true ); _fnProcessingDisplay( oSettings, true );
@ -2492,10 +2463,7 @@
"bUseRendered": true, "bUseRendered": true,
"iDataSort": oSettings.aoColumns.length-1, "iDataSort": oSettings.aoColumns.length-1,
"sSortDataType": 'std', "sSortDataType": 'std',
"nTh": nTh ? nTh : document.createElement('th'), "nTh": nTh ? nTh : document.createElement('th')
"nTf": null,
"anThExtra": [],
"anTfExtra": []
}; };
var iCol = oSettings.aoColumns.length-1; var iCol = oSettings.aoColumns.length-1;
@ -2860,19 +2828,13 @@
} }
} }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Drawing functions
*/
/* /*
* Function: _fnDrawHead * Function: _fnBuildHead
* Purpose: Create the HTML header for the table * Purpose: Create the HTML header for the table
* Returns: - * Returns: -
* Inputs: object:oSettings - dataTables settings object * Inputs: object:oSettings - dataTables settings object
*/ */
function _fnDrawHead( oSettings ) function _fnBuildHead( oSettings )
{ {
var i, nTh, iLen, j, jLen; var i, nTh, iLen, j, jLen;
var anTr = oSettings.nTHead.getElementsByTagName('tr'); var anTr = oSettings.nTHead.getElementsByTagName('tr');
@ -2893,31 +2855,12 @@
$(nTh).addClass( oSettings.aoColumns[i].sClass ); $(nTh).addClass( oSettings.aoColumns[i].sClass );
} }
/* Cache and remove (if needed) any extra elements for this column in the header */
for ( j=1, jLen=anTr.length ; j<jLen ; j++ )
{
jqChildren = $(anTr[j]).children();
oSettings.aoColumns[i].anThExtra.push( jqChildren[i-iCorrector] );
if ( !oSettings.aoColumns[i].bVisible )
{
anTr[j].removeChild( jqChildren[i-iCorrector] );
}
}
if ( oSettings.aoColumns[i].bVisible )
{
/* Set the title of the column if it is user defined (not what was auto detected) */ /* Set the title of the column if it is user defined (not what was auto detected) */
if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML ) if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
{ {
nTh.innerHTML = oSettings.aoColumns[i].sTitle; nTh.innerHTML = oSettings.aoColumns[i].sTitle;
} }
} }
else
{
nTh.parentNode.removeChild( nTh );
iCorrector++;
}
}
} }
else else
{ {
@ -2934,12 +2877,10 @@
$(nTh).addClass( oSettings.aoColumns[i].sClass ); $(nTh).addClass( oSettings.aoColumns[i].sClass );
} }
if ( oSettings.aoColumns[i].bVisible )
{
nTr.appendChild( nTh ); nTr.appendChild( nTh );
} }
}
$(oSettings.nTHead).html( '' )[0].appendChild( nTr ); $(oSettings.nTHead).html( '' )[0].appendChild( nTr );
_fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
} }
/* Add the extra markup needed by jQuery UI's themes */ /* Add the extra markup needed by jQuery UI's themes */
@ -2982,41 +2923,100 @@
} }
} }
/* Cache the footer elements */ /* Deal with the footer - add classes if required */
if ( oSettings.nTFoot !== null )
{
iCorrector = 0;
anTr = oSettings.nTFoot.getElementsByTagName('tr');
var nTfs = anTr[0].getElementsByTagName('th');
for ( i=0, iLen=nTfs.length ; i<iLen ; i++ )
{
if ( typeof oSettings.aoColumns[i] != 'undefined' )
{
oSettings.aoColumns[i].nTf = nTfs[i-iCorrector];
if ( oSettings.oClasses.sFooterTH !== "" ) if ( oSettings.oClasses.sFooterTH !== "" )
{ {
oSettings.aoColumns[i].nTf.className += " "+oSettings.oClasses.sFooterTH; $('>tr>th', oSettings.nTFoot).addClass( oSettings.oClasses.sFooterTH );
}
/* Deal with any extra elements for this column from the footer */
for ( j=1, jLen=anTr.length ; j<jLen ; j++ )
{
jqChildren = $(anTr[j]).children();
oSettings.aoColumns[i].anTfExtra.push( jqChildren[i-iCorrector] );
if ( !oSettings.aoColumns[i].bVisible )
{
anTr[j].removeChild( jqChildren[i-iCorrector] );
} }
} }
if ( !oSettings.aoColumns[i].bVisible )
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - Drawing functions
*/
/*
* Function: _fnDrawHead
* Purpose: Draw the header (or footer) element based on the column visibility states. The
* methodology here is to use the layout array from _fnDetectHeader, modified for
* the instantaneous column visibility, to construct the new layout. The grid is
* traversed over cell at a time in a rows x columns grid fashion, although each
* cell insert can cover multiple elements in the grid - which is tracks using the
* aApplied array. Cell inserts in the grid will only occur where there isn't
* already a cell in that position.
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* array objects:aoSource - Layout array from _fnDetectHeader
* node:nTarget - The header or footer element to layout
*/
function _fnDrawHead( oSettings, aoSource, nTarget )
{ {
nTfs[i-iCorrector].parentNode.removeChild( nTfs[i-iCorrector] ); var i, iLen;
iCorrector++; var aoLocal = [];
var aApplied = [];
var iColumns = oSettings.aoColumns.length;
var iRowspan, iColspan;
/* Make a copy of the master layout array, but without the visible columns in it */
for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
{
aoLocal[i] = aoSource[i].slice();
aoLocal[i].nTr = aoSource[i].nTr;
/* Remove any columns which are currently hidden */
for ( j=iColumns-1 ; j>=0 ; j-- )
{
if ( !oSettings.aoColumns[j].bVisible )
{
aoLocal[i].splice( j, 1 );
} }
} }
/* Prep the applied array - it needs an element for each row */
aApplied.push( [] );
}
for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
{
/* All cells are going to be replaced, so empty out the row */
$(aoLocal[i].nTr).empty();
for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
{
iRowspan = 1;
iColspan = 1;
/* Check to see if there is already a cell (row/colspan) covering our target
* insert point. If there is, then there is nothing to do.
*/
if ( typeof aApplied[i][j] == 'undefined' )
{
aoLocal[i].nTr.appendChild( aoLocal[i][j].cell );
aApplied[i][j] = 1;
/* Expand the cell to cover as many rows as needed */
while ( typeof aoLocal[i+iRowspan] != 'undefined' &&
aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
{
aApplied[i+iRowspan][j] = 1;
iRowspan++;
}
/* Expand the cell to cover as many columns as needed */
while ( typeof aoLocal[i][j+iColspan] != 'undefined' &&
aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
{
/* Must update the applied array over the rows for the columns */
for ( var k=0 ; k<iRowspan ; k++ )
{
aApplied[i+k][j+iColspan] = 1;
}
iColspan++;
}
/* Do the actual expansion in the DOM */
aoLocal[i][j].cell.setAttribute('rowspan', iRowspan);
aoLocal[i][j].cell.setAttribute('colspan', iColspan);
}
} }
} }
} }
@ -4501,7 +4501,7 @@
/* /*
* This is a little bit odd I admit... I declare a temporary function inside the scope of * This is a little bit odd I admit... I declare a temporary function inside the scope of
* _fnDrawHead and the click handler in order that the code presented here can be used * _fnBuildHead and the click handler in order that the code presented here can be used
* twice - once for when bProcessing is enabled, and another time for when it is * twice - once for when bProcessing is enabled, and another time for when it is
* disabled, as we need to perform slightly different actions. * disabled, as we need to perform slightly different actions.
* Basically the issue here is that the Javascript engine in modern browsers don't * Basically the issue here is that the Javascript engine in modern browsers don't
@ -6130,92 +6130,95 @@
} }
/* /*
* Function: _fnGetUniqueThs * Function: _fnDetectHeader
* Purpose: Get an array of unique th elements, one for each column * Purpose: Use the DOM source to create up an array of header cells. The idea here is to
* Returns: array node:aReturn - list of unique ths * create a layout grid (array) of rows x columns, which contains a reference
* Inputs: node:nThead - The thead element for the table * to the cell that that point in the grid (regardless of col/rowspan), such that
* any column / row could be removed and the new grid constructed
* Returns: void
* Outputs: array object:aLayout - Array to store the calculated layout in
* Inputs: node:nThead - The header/footer element for the table
*/ */
function _fnGetUniqueThs ( nThead ) function _fnDetectHeader ( aLayout, nThead )
{ {
var nTrs = nThead.getElementsByTagName('tr'); var nTrs = nThead.getElementsByTagName('tr');
var nCell;
/* Nice simple case */ var i, j, k, l, iLen, jLen, iColShifted;
if ( nTrs.length == 1 )
{
return nTrs[0].getElementsByTagName('th');
}
/* Otherwise we need to figure out the layout array to get the nodes */
var aLayout = [], aReturn = [];
var ROWSPAN = 2, COLSPAN = 3, TDELEM = 4;
var i, j, k, iLen, jLen, iColumnShifted;
var fnShiftCol = function ( a, i, j ) { var fnShiftCol = function ( a, i, j ) {
while ( typeof a[i][j] != 'undefined' ) { while ( typeof a[i][j] != 'undefined' ) {
j++; j++;
} }
return j; return j;
}; };
var fnAddRow = function ( i ) {
if ( typeof aLayout[i] == 'undefined' ) { aLayout.splice( 0, aLayout.length );
aLayout[i] = [];
/* We know how many rows there are in the layout - so prep it */
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
{
aLayout.push( [] );
} }
};
/* Calculate a layout array */ /* Calculate a layout array */
for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
{ {
fnAddRow( i );
var iColumn = 0; var iColumn = 0;
var nTds = [];
/* For every cell in the row... */
for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ ) for ( j=0, jLen=nTrs[i].childNodes.length ; j<jLen ; j++ )
{ {
if ( nTrs[i].childNodes[j].nodeName.toUpperCase() == "TD" || nCell = nTrs[i].childNodes[j];
nTrs[i].childNodes[j].nodeName.toUpperCase() == "TH" )
{
nTds.push( nTrs[i].childNodes[j] );
}
}
for ( j=0, jLen=nTds.length ; j<jLen ; j++ ) if ( nCell.nodeName.toUpperCase() == "TD" ||
nCell.nodeName.toUpperCase() == "TH" )
{ {
var iColspan = nTds[j].getAttribute('colspan') * 1; /* Get the col and rowspan attributes from the DOM and sanitise them */
var iRowspan = nTds[j].getAttribute('rowspan') * 1; var iColspan = nCell.getAttribute('colspan') * 1;
var iRowspan = nCell.getAttribute('rowspan') * 1;
iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
if ( !iColspan || iColspan===0 || iColspan===1 ) /* There might be colspan cells already in this row, so shift our target
* accordingly
*/
iColShifted = fnShiftCol( aLayout, i, iColumn );
/* If there is col / rowspan, copy the information into the layout grid */
for ( l=0 ; l<iColspan ; l++ )
{ {
iColumnShifted = fnShiftCol( aLayout, i, iColumn ); for ( k=0 ; k<iRowspan ; k++ )
aLayout[i][iColumnShifted] = (nTds[j].nodeName.toUpperCase()=="TD") ? TDELEM : nTds[j];
if ( iRowspan || iRowspan===0 || iRowspan===1 )
{ {
for ( k=1 ; k<iRowspan ; k++ ) aLayout[i+k][iColShifted+l] = {
{ "cell": nCell,
fnAddRow( i+k ); "unique": iColspan == 1 ? true : false
aLayout[i+k][iColumnShifted] = ROWSPAN; };
aLayout[i+k].nTr = nTrs[i];
} }
} }
iColumn++;
} }
else
{
iColumnShifted = fnShiftCol( aLayout, i, iColumn );
for ( k=0 ; k<iColspan ; k++ )
{
aLayout[i][iColumnShifted+k] = COLSPAN;
}
iColumn += iColspan;
} }
} }
} }
/* Convert the layout array into a node array */ /*
* Function: _fnGetUniqueThs
* Purpose: Get an array of unique th elements, one for each column
* Returns: array node:aReturn - list of unique ths
* Inputs: object:oSettings - dataTables settings object
*/
function _fnGetUniqueThs ( oSettings )
{
var aReturn = [];
var aLayout = oSettings.aoHeader;
for ( i=0, iLen=aLayout.length ; i<iLen ; i++ ) for ( i=0, iLen=aLayout.length ; i<iLen ; i++ )
{ {
for ( j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) for ( j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
{ {
if ( typeof aLayout[i][j] == 'object' && typeof aReturn[j] == 'undefined' ) if ( aLayout[i][j].unique &&
(typeof aReturn[j] == 'undefined' || !oSettings.bSortCellsTop) )
{ {
aReturn[j] = aLayout[i][j]; aReturn[j] = aLayout[i][j].cell;
} }
} }
} }
@ -6328,7 +6331,7 @@
this.oApi._fnColumnOptions = _fnColumnOptions; this.oApi._fnColumnOptions = _fnColumnOptions;
this.oApi._fnAddData = _fnAddData; this.oApi._fnAddData = _fnAddData;
this.oApi._fnGatherData = _fnGatherData; this.oApi._fnGatherData = _fnGatherData;
this.oApi._fnDrawHead = _fnDrawHead; this.oApi._fnBuildHead = _fnBuildHead;
this.oApi._fnDraw = _fnDraw; this.oApi._fnDraw = _fnDraw;
this.oApi._fnReDraw = _fnReDraw; this.oApi._fnReDraw = _fnReDraw;
this.oApi._fnAjaxUpdate = _fnAjaxUpdate; this.oApi._fnAjaxUpdate = _fnAjaxUpdate;
@ -6518,6 +6521,7 @@
_fnMap( oSettings, oInit, "iCookieDuration" ); _fnMap( oSettings, oInit, "iCookieDuration" );
_fnMap( oSettings, oInit, "sCookiePrefix" ); _fnMap( oSettings, oInit, "sCookiePrefix" );
_fnMap( oSettings, oInit, "sDom" ); _fnMap( oSettings, oInit, "sDom" );
_fnMap( oSettings, oInit, "bSortCellsTop" );
_fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" ); _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
_fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" ); _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
_fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" ); _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
@ -6697,9 +6701,14 @@
* Columns * Columns
* See if we should load columns automatically or use defined ones * See if we should load columns automatically or use defined ones
*/ */
var nThead = this.getElementsByTagName('thead'); var anThs = [];
var anThs = nThead.length===0 ? [] : _fnGetUniqueThs( nThead[0] );
var aoColumnsInit; var aoColumnsInit;
var nThead = this.getElementsByTagName('thead');
if ( nThead.length !== 0 )
{
_fnDetectHeader( oSettings.aoHeader, nThead[0] );
anThs = _fnGetUniqueThs( oSettings );
}
/* If not given a column array, generate one with nulls */ /* If not given a column array, generate one with nulls */
if ( typeof oInit.aoColumns == 'undefined' ) if ( typeof oInit.aoColumns == 'undefined' )
@ -6848,6 +6857,7 @@
if ( this.getElementsByTagName('tfoot').length > 0 ) if ( this.getElementsByTagName('tfoot').length > 0 )
{ {
oSettings.nTFoot = this.getElementsByTagName('tfoot')[0]; oSettings.nTFoot = this.getElementsByTagName('tfoot')[0];
_fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
} }
/* Check if there is data passing into the constructor */ /* Check if there is data passing into the constructor */