jquery-load-json
Version:
jQuery plugin that enables developers to load JSON data from the server and load JSON object into the DOM.
1,614 lines (1,438 loc) • 230 kB
JavaScript
/*
* File: jquery.dataTables.js
* Version: 1.8.2
* Description: Paginate, search and sort HTML tables
* Author: Allan Jardine (www.sprymedia.co.uk)
* Created: 28/3/2008
* Language: Javascript
* License: GPL v2 or BSD 3 point style
* Project: Mtaala
* Contact: allan.jardine@sprymedia.co.uk
*
* Copyright 2008-2011 Allan Jardine, all rights reserved.
*
* This source file is free software, under either the GPL v2 license or a
* BSD style license, as supplied with this software.
*
* This source file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
*
* For details please refer to: http://www.datatables.net
*/
/*
* When considering jsLint, we need to allow eval() as it it is used for reading cookies
*/
/*jslint evil: true, undef: true, browser: true */
/*globals $, jQuery,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageProcess,_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,_fnArrayCmp,_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*/
(function($, window, document) {
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - DataTables variables
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Variable: dataTableSettings
* Purpose: Store the settings for each dataTables instance
* Scope: jQuery.fn
*/
$.fn.dataTableSettings = [];
var _aoSettings = $.fn.dataTableSettings; /* Short reference for fast internal lookup */
/*
* Variable: dataTableExt
* Purpose: Container for customisable parts of DataTables
* Scope: jQuery.fn
*/
$.fn.dataTableExt = {};
var _oExt = $.fn.dataTableExt;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - DataTables extensible objects
*
* The _oExt object is used to provide an area where user defined plugins can be
* added to DataTables. The following properties of the object are used:
* oApi - Plug-in API functions
* aTypes - Auto-detection of types
* oSort - Sorting functions used by DataTables (based on the type)
* oPagination - Pagination functions for different input styles
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Variable: sVersion
* Purpose: Version string for plug-ins to check compatibility
* Scope: jQuery.fn.dataTableExt
* Notes: Allowed format is a.b.c.d.e where:
* a:int, b:int, c:int, d:string(dev|beta), e:int. d and e are optional
*/
_oExt.sVersion = "1.8.2";
/*
* Variable: sErrMode
* Purpose: How should DataTables report an error. Can take the value 'alert' or 'throw'
* Scope: jQuery.fn.dataTableExt
*/
_oExt.sErrMode = "alert";
/*
* Variable: iApiIndex
* Purpose: Index for what 'this' index API functions should use
* Scope: jQuery.fn.dataTableExt
*/
_oExt.iApiIndex = 0;
/*
* Variable: oApi
* Purpose: Container for plugin API functions
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oApi = { };
/*
* Variable: aFiltering
* Purpose: Container for plugin filtering functions
* Scope: jQuery.fn.dataTableExt
*/
_oExt.afnFiltering = [ ];
/*
* Variable: aoFeatures
* Purpose: Container for plugin function functions
* Scope: jQuery.fn.dataTableExt
* Notes: Array of objects with the following parameters:
* fnInit: Function for initialisation of Feature. Takes oSettings and returns node
* cFeature: Character that will be matched in sDom - case sensitive
* sFeature: Feature name - just for completeness :-)
*/
_oExt.aoFeatures = [ ];
/*
* Variable: ofnSearch
* Purpose: Container for custom filtering functions
* Scope: jQuery.fn.dataTableExt
* Notes: This is an object (the name should match the type) for custom filtering function,
* which can be used for live DOM checking or formatted text filtering
*/
_oExt.ofnSearch = { };
/*
* Variable: afnSortData
* Purpose: Container for custom sorting data source functions
* Scope: jQuery.fn.dataTableExt
* Notes: Array (associative) of functions which is run prior to a column of this
* 'SortDataType' being sorted upon.
* Function input parameters:
* object:oSettings- DataTables settings object
* int:iColumn - Target column number
* Return value: Array of data which exactly matched the full data set size for the column to
* be sorted upon
*/
_oExt.afnSortData = [ ];
/*
* Variable: oStdClasses
* Purpose: Storage for the various classes that DataTables uses
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oStdClasses = {
/* Two buttons buttons */
"sPagePrevEnabled": "paginate_enabled_previous",
"sPagePrevDisabled": "paginate_disabled_previous",
"sPageNextEnabled": "paginate_enabled_next",
"sPageNextDisabled": "paginate_disabled_next",
"sPageJUINext": "",
"sPageJUIPrev": "",
/* Full numbers paging buttons */
"sPageButton": "paginate_button",
"sPageButtonActive": "paginate_active",
"sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
"sPageFirst": "first",
"sPagePrevious": "previous",
"sPageNext": "next",
"sPageLast": "last",
/* Striping classes */
"sStripeOdd": "odd",
"sStripeEven": "even",
/* Empty row */
"sRowEmpty": "dataTables_empty",
/* Features */
"sWrapper": "dataTables_wrapper",
"sFilter": "dataTables_filter",
"sInfo": "dataTables_info",
"sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
"sLength": "dataTables_length",
"sProcessing": "dataTables_processing",
/* Sorting */
"sSortAsc": "sorting_asc",
"sSortDesc": "sorting_desc",
"sSortable": "sorting", /* Sortable in both directions */
"sSortableAsc": "sorting_asc_disabled",
"sSortableDesc": "sorting_desc_disabled",
"sSortableNone": "sorting_disabled",
"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
"sSortJUIAsc": "",
"sSortJUIDesc": "",
"sSortJUI": "",
"sSortJUIAscAllowed": "",
"sSortJUIDescAllowed": "",
"sSortJUIWrapper": "",
"sSortIcon": "",
/* Scrolling */
"sScrollWrapper": "dataTables_scroll",
"sScrollHead": "dataTables_scrollHead",
"sScrollHeadInner": "dataTables_scrollHeadInner",
"sScrollBody": "dataTables_scrollBody",
"sScrollFoot": "dataTables_scrollFoot",
"sScrollFootInner": "dataTables_scrollFootInner",
/* Misc */
"sFooterTH": ""
};
/*
* Variable: oJUIClasses
* Purpose: Storage for the various classes that DataTables uses - jQuery UI suitable
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oJUIClasses = {
/* Two buttons buttons */
"sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
"sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
"sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
"sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
"sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
"sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
/* Full numbers paging buttons */
"sPageButton": "fg-button ui-button ui-state-default",
"sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
"sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
"sPageFirst": "first ui-corner-tl ui-corner-bl",
"sPagePrevious": "previous",
"sPageNext": "next",
"sPageLast": "last ui-corner-tr ui-corner-br",
/* Striping classes */
"sStripeOdd": "odd",
"sStripeEven": "even",
/* Empty row */
"sRowEmpty": "dataTables_empty",
/* Features */
"sWrapper": "dataTables_wrapper",
"sFilter": "dataTables_filter",
"sInfo": "dataTables_info",
"sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
"ui-buttonset-multi paging_", /* Note that the type is postfixed */
"sLength": "dataTables_length",
"sProcessing": "dataTables_processing",
/* Sorting */
"sSortAsc": "ui-state-default",
"sSortDesc": "ui-state-default",
"sSortable": "ui-state-default",
"sSortableAsc": "ui-state-default",
"sSortableDesc": "ui-state-default",
"sSortableNone": "ui-state-default",
"sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
"sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
"sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
"sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
"sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
"sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
"sSortJUIWrapper": "DataTables_sort_wrapper",
"sSortIcon": "DataTables_sort_icon",
/* Scrolling */
"sScrollWrapper": "dataTables_scroll",
"sScrollHead": "dataTables_scrollHead ui-state-default",
"sScrollHeadInner": "dataTables_scrollHeadInner",
"sScrollBody": "dataTables_scrollBody",
"sScrollFoot": "dataTables_scrollFoot ui-state-default",
"sScrollFootInner": "dataTables_scrollFootInner",
/* Misc */
"sFooterTH": "ui-state-default"
};
/*
* Variable: oPagination
* Purpose: Container for the various type of pagination that dataTables supports
* Scope: jQuery.fn.dataTableExt
*/
_oExt.oPagination = {
/*
* Variable: two_button
* Purpose: Standard two button (forward/back) pagination
* Scope: jQuery.fn.dataTableExt.oPagination
*/
"two_button": {
/*
* Function: oPagination.two_button.fnInit
* Purpose: Initialise dom elements required for pagination with forward/back buttons only
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* node:nPaging - the DIV which contains this pagination control
* function:fnCallbackDraw - draw function which must be called on update
*/
"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
{
var nPrevious, nNext, nPreviousInner, nNextInner;
/* Store the next and previous elements in the oSettings object as they can be very
* usful for automation - particularly testing
*/
if ( !oSettings.bJUI )
{
nPrevious = document.createElement( 'div' );
nNext = document.createElement( 'div' );
}
else
{
nPrevious = document.createElement( 'a' );
nNext = document.createElement( 'a' );
nNextInner = document.createElement('span');
nNextInner.className = oSettings.oClasses.sPageJUINext;
nNext.appendChild( nNextInner );
nPreviousInner = document.createElement('span');
nPreviousInner.className = oSettings.oClasses.sPageJUIPrev;
nPrevious.appendChild( nPreviousInner );
}
nPrevious.className = oSettings.oClasses.sPagePrevDisabled;
nNext.className = oSettings.oClasses.sPageNextDisabled;
nPrevious.title = oSettings.oLanguage.oPaginate.sPrevious;
nNext.title = oSettings.oLanguage.oPaginate.sNext;
nPaging.appendChild( nPrevious );
nPaging.appendChild( nNext );
$(nPrevious).bind( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
{
/* Only draw when the page has actually changed */
fnCallbackDraw( oSettings );
}
} );
$(nNext).bind( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
{
fnCallbackDraw( oSettings );
}
} );
/* Take the brutal approach to cancelling text selection */
$(nPrevious).bind( 'selectstart.DT', function () { return false; } );
$(nNext).bind( 'selectstart.DT', function () { return false; } );
/* ID the first elements only */
if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
{
nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
}
},
/*
* Function: oPagination.two_button.fnUpdate
* Purpose: Update the two button pagination at the end of the draw
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* function:fnCallbackDraw - draw function to call on page change
*/
"fnUpdate": function ( oSettings, fnCallbackDraw )
{
if ( !oSettings.aanFeatures.p )
{
return;
}
/* Loop over each instance of the pager */
var an = oSettings.aanFeatures.p;
for ( var i=0, iLen=an.length ; i<iLen ; i++ )
{
if ( an[i].childNodes.length !== 0 )
{
an[i].childNodes[0].className =
( oSettings._iDisplayStart === 0 ) ?
oSettings.oClasses.sPagePrevDisabled : oSettings.oClasses.sPagePrevEnabled;
an[i].childNodes[1].className =
( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
oSettings.oClasses.sPageNextDisabled : oSettings.oClasses.sPageNextEnabled;
}
}
}
},
/*
* Variable: iFullNumbersShowPages
* Purpose: Change the number of pages which can be seen
* Scope: jQuery.fn.dataTableExt.oPagination
*/
"iFullNumbersShowPages": 5,
/*
* Variable: full_numbers
* Purpose: Full numbers pagination
* Scope: jQuery.fn.dataTableExt.oPagination
*/
"full_numbers": {
/*
* Function: oPagination.full_numbers.fnInit
* Purpose: Initialise dom elements required for pagination with a list of the pages
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* node:nPaging - the DIV which contains this pagination control
* function:fnCallbackDraw - draw function which must be called on update
*/
"fnInit": function ( oSettings, nPaging, fnCallbackDraw )
{
var nFirst = document.createElement( 'span' );
var nPrevious = document.createElement( 'span' );
var nList = document.createElement( 'span' );
var nNext = document.createElement( 'span' );
var nLast = document.createElement( 'span' );
nFirst.innerHTML = oSettings.oLanguage.oPaginate.sFirst;
nPrevious.innerHTML = oSettings.oLanguage.oPaginate.sPrevious;
nNext.innerHTML = oSettings.oLanguage.oPaginate.sNext;
nLast.innerHTML = oSettings.oLanguage.oPaginate.sLast;
var oClasses = oSettings.oClasses;
nFirst.className = oClasses.sPageButton+" "+oClasses.sPageFirst;
nPrevious.className = oClasses.sPageButton+" "+oClasses.sPagePrevious;
nNext.className= oClasses.sPageButton+" "+oClasses.sPageNext;
nLast.className = oClasses.sPageButton+" "+oClasses.sPageLast;
nPaging.appendChild( nFirst );
nPaging.appendChild( nPrevious );
nPaging.appendChild( nList );
nPaging.appendChild( nNext );
nPaging.appendChild( nLast );
$(nFirst).bind( 'click.DT', function () {
if ( oSettings.oApi._fnPageChange( oSettings, "first" ) )
{
fnCallbackDraw( oSettings );
}
} );
$(nPrevious).bind( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "previous" ) )
{
fnCallbackDraw( oSettings );
}
} );
$(nNext).bind( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "next" ) )
{
fnCallbackDraw( oSettings );
}
} );
$(nLast).bind( 'click.DT', function() {
if ( oSettings.oApi._fnPageChange( oSettings, "last" ) )
{
fnCallbackDraw( oSettings );
}
} );
/* Take the brutal approach to cancelling text selection */
$('span', nPaging)
.bind( 'mousedown.DT', function () { return false; } )
.bind( 'selectstart.DT', function () { return false; } );
/* ID the first elements only */
if ( oSettings.sTableId !== '' && typeof oSettings.aanFeatures.p == "undefined" )
{
nPaging.setAttribute( 'id', oSettings.sTableId+'_paginate' );
nFirst.setAttribute( 'id', oSettings.sTableId+'_first' );
nPrevious.setAttribute( 'id', oSettings.sTableId+'_previous' );
nNext.setAttribute( 'id', oSettings.sTableId+'_next' );
nLast.setAttribute( 'id', oSettings.sTableId+'_last' );
}
},
/*
* Function: oPagination.full_numbers.fnUpdate
* Purpose: Update the list of page buttons shows
* Returns: -
* Inputs: object:oSettings - dataTables settings object
* function:fnCallbackDraw - draw function to call on page change
*/
"fnUpdate": function ( oSettings, fnCallbackDraw )
{
if ( !oSettings.aanFeatures.p )
{
return;
}
var iPageCount = _oExt.oPagination.iFullNumbersShowPages;
var iPageCountHalf = Math.floor(iPageCount / 2);
var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
var sList = "";
var iStartButton, iEndButton, i, iLen;
var oClasses = oSettings.oClasses;
/* Pages calculation */
if (iPages < iPageCount)
{
iStartButton = 1;
iEndButton = iPages;
}
else
{
if (iCurrentPage <= iPageCountHalf)
{
iStartButton = 1;
iEndButton = iPageCount;
}
else
{
if (iCurrentPage >= (iPages - iPageCountHalf))
{
iStartButton = iPages - iPageCount + 1;
iEndButton = iPages;
}
else
{
iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
iEndButton = iStartButton + iPageCount - 1;
}
}
}
/* Build the dynamic list */
for ( i=iStartButton ; i<=iEndButton ; i++ )
{
if ( iCurrentPage != i )
{
sList += '<span class="'+oClasses.sPageButton+'">'+i+'</span>';
}
else
{
sList += '<span class="'+oClasses.sPageButtonActive+'">'+i+'</span>';
}
}
/* Loop over each instance of the pager */
var an = oSettings.aanFeatures.p;
var anButtons, anStatic, nPaginateList;
var fnClick = function(e) {
/* Use the information in the element to jump to the required page */
var iTarget = (this.innerHTML * 1) - 1;
oSettings._iDisplayStart = iTarget * oSettings._iDisplayLength;
fnCallbackDraw( oSettings );
e.preventDefault();
};
var fnFalse = function () { return false; };
for ( i=0, iLen=an.length ; i<iLen ; i++ )
{
if ( an[i].childNodes.length === 0 )
{
continue;
}
/* Build up the dynamic list forst - html and listeners */
var qjPaginateList = $('span:eq(2)', an[i]);
qjPaginateList.html( sList );
$('span', qjPaginateList).bind( 'click.DT', fnClick ).bind( 'mousedown.DT', fnFalse )
.bind( 'selectstart.DT', fnFalse );
/* Update the 'premanent botton's classes */
anButtons = an[i].getElementsByTagName('span');
anStatic = [
anButtons[0], anButtons[1],
anButtons[anButtons.length-2], anButtons[anButtons.length-1]
];
$(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
if ( iCurrentPage == 1 )
{
anStatic[0].className += " "+oClasses.sPageButtonStaticDisabled;
anStatic[1].className += " "+oClasses.sPageButtonStaticDisabled;
}
else
{
anStatic[0].className += " "+oClasses.sPageButton;
anStatic[1].className += " "+oClasses.sPageButton;
}
if ( iPages === 0 || iCurrentPage == iPages || oSettings._iDisplayLength == -1 )
{
anStatic[2].className += " "+oClasses.sPageButtonStaticDisabled;
anStatic[3].className += " "+oClasses.sPageButtonStaticDisabled;
}
else
{
anStatic[2].className += " "+oClasses.sPageButton;
anStatic[3].className += " "+oClasses.sPageButton;
}
}
}
}
};
/*
* Variable: oSort
* Purpose: Wrapper for the sorting functions that can be used in DataTables
* Scope: jQuery.fn.dataTableExt
* Notes: The functions provided in this object are basically standard javascript sort
* functions - they expect two inputs which they then compare and then return a priority
* result. For each sort method added, two functions need to be defined, an ascending sort and
* a descending sort.
*/
_oExt.oSort = {
/*
* text sorting
*/
"string-asc": function ( a, b )
{
if ( typeof a != 'string' ) { a = ''; }
if ( typeof b != 'string' ) { b = ''; }
var x = a.toLowerCase();
var y = b.toLowerCase();
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
},
"string-desc": function ( a, b )
{
if ( typeof a != 'string' ) { a = ''; }
if ( typeof b != 'string' ) { b = ''; }
var x = a.toLowerCase();
var y = b.toLowerCase();
return ((x < y) ? 1 : ((x > y) ? -1 : 0));
},
/*
* html sorting (ignore html tags)
*/
"html-asc": function ( a, b )
{
var x = a.replace( /<.*?>/g, "" ).toLowerCase();
var y = b.replace( /<.*?>/g, "" ).toLowerCase();
return ((x < y) ? -1 : ((x > y) ? 1 : 0));
},
"html-desc": function ( a, b )
{
var x = a.replace( /<.*?>/g, "" ).toLowerCase();
var y = b.replace( /<.*?>/g, "" ).toLowerCase();
return ((x < y) ? 1 : ((x > y) ? -1 : 0));
},
/*
* date sorting
*/
"date-asc": function ( a, b )
{
var x = Date.parse( a );
var y = Date.parse( b );
if ( isNaN(x) || x==="" )
{
x = Date.parse( "01/01/1970 00:00:00" );
}
if ( isNaN(y) || y==="" )
{
y = Date.parse( "01/01/1970 00:00:00" );
}
return x - y;
},
"date-desc": function ( a, b )
{
var x = Date.parse( a );
var y = Date.parse( b );
if ( isNaN(x) || x==="" )
{
x = Date.parse( "01/01/1970 00:00:00" );
}
if ( isNaN(y) || y==="" )
{
y = Date.parse( "01/01/1970 00:00:00" );
}
return y - x;
},
/*
* numerical sorting
*/
"numeric-asc": function ( a, b )
{
var x = (a=="-" || a==="") ? 0 : a*1;
var y = (b=="-" || b==="") ? 0 : b*1;
return x - y;
},
"numeric-desc": function ( a, b )
{
var x = (a=="-" || a==="") ? 0 : a*1;
var y = (b=="-" || b==="") ? 0 : b*1;
return y - x;
}
};
/*
* Variable: aTypes
* Purpose: Container for the various type of type detection that dataTables supports
* Scope: jQuery.fn.dataTableExt
* Notes: The functions in this array are expected to parse a string to see if it is a data
* type that it recognises. If so then the function should return the name of the type (a
* corresponding sort function should be defined!), if the type is not recognised then the
* function should return null such that the parser and move on to check the next type.
* Note that ordering is important in this array - the functions are processed linearly,
* starting at index 0.
* Note that the input for these functions is always a string! It cannot be any other data
* type
*/
_oExt.aTypes = [
/*
* Function: -
* Purpose: Check to see if a string is numeric
* Returns: string:'numeric' or null
* Inputs: mixed:sText - string to check
*/
function ( sData )
{
/* Allow zero length strings as a number */
if ( typeof sData == 'number' )
{
return 'numeric';
}
else if ( typeof sData != 'string' )
{
return null;
}
var sValidFirstChars = "0123456789-";
var sValidChars = "0123456789.";
var Char;
var bDecimal = false;
/* Check for a valid first char (no period and allow negatives) */
Char = sData.charAt(0);
if (sValidFirstChars.indexOf(Char) == -1)
{
return null;
}
/* Check all the other characters are valid */
for ( var i=1 ; i<sData.length ; i++ )
{
Char = sData.charAt(i);
if (sValidChars.indexOf(Char) == -1)
{
return null;
}
/* Only allowed one decimal place... */
if ( Char == "." )
{
if ( bDecimal )
{
return null;
}
bDecimal = true;
}
}
return 'numeric';
},
/*
* Function: -
* Purpose: Check to see if a string is actually a formatted date
* Returns: string:'date' or null
* Inputs: string:sText - string to check
*/
function ( sData )
{
var iParse = Date.parse(sData);
if ( (iParse !== null && !isNaN(iParse)) || (typeof sData == 'string' && sData.length === 0) )
{
return 'date';
}
return null;
},
/*
* Function: -
* Purpose: Check to see if a string should be treated as an HTML string
* Returns: string:'html' or null
* Inputs: string:sText - string to check
*/
function ( sData )
{
if ( typeof sData == 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
{
return 'html';
}
return null;
}
];
/*
* Function: fnVersionCheck
* Purpose: Check a version string against this version of DataTables. Useful for plug-ins
* Returns: bool:true -this version of DataTables is greater or equal to the required version
* false -this version of DataTales is not suitable
* Inputs: string:sVersion - the version to check against. May be in the following formats:
* "a", "a.b" or "a.b.c"
* Notes: This function will only check the first three parts of a version string. It is
* assumed that beta and dev versions will meet the requirements. This might change in future
*/
_oExt.fnVersionCheck = function( sVersion )
{
/* This is cheap, but very effective */
var fnZPad = function (Zpad, count)
{
while(Zpad.length < count) {
Zpad += '0';
}
return Zpad;
};
var aThis = _oExt.sVersion.split('.');
var aThat = sVersion.split('.');
var sThis = '', sThat = '';
for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
{
sThis += fnZPad( aThis[i], 3 );
sThat += fnZPad( aThat[i], 3 );
}
return parseInt(sThis, 10) >= parseInt(sThat, 10);
};
/*
* Variable: _oExternConfig
* Purpose: Store information for DataTables to access globally about other instances
* Scope: jQuery.fn.dataTableExt
*/
_oExt._oExternConfig = {
/* int:iNextUnique - next unique number for an instance */
"iNextUnique": 0
};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - DataTables prototype
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Function: dataTable
* Purpose: DataTables information
* Returns: -
* Inputs: object:oInit - initialisation options for the table
*/
$.fn.dataTable = function( oInit )
{
/*
* Function: classSettings
* Purpose: Settings container function for all 'class' properties which are required
* by dataTables
* Returns: -
* Inputs: -
*/
function classSettings ()
{
this.fnRecordsTotal = function ()
{
if ( this.oFeatures.bServerSide ) {
return parseInt(this._iRecordsTotal, 10);
} else {
return this.aiDisplayMaster.length;
}
};
this.fnRecordsDisplay = function ()
{
if ( this.oFeatures.bServerSide ) {
return parseInt(this._iRecordsDisplay, 10);
} else {
return this.aiDisplay.length;
}
};
this.fnDisplayEnd = function ()
{
if ( this.oFeatures.bServerSide ) {
if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
return this._iDisplayStart+this.aiDisplay.length;
} else {
return Math.min( this._iDisplayStart+this._iDisplayLength,
this._iRecordsDisplay );
}
} else {
return this._iDisplayEnd;
}
};
/*
* Variable: oInstance
* Purpose: The DataTables object for this table
* Scope: jQuery.dataTable.classSettings
*/
this.oInstance = null;
/*
* Variable: sInstance
* Purpose: Unique idendifier for each instance of the DataTables object
* Scope: jQuery.dataTable.classSettings
*/
this.sInstance = null;
/*
* Variable: oFeatures
* Purpose: Indicate the enablement of key dataTable features
* Scope: jQuery.dataTable.classSettings
*/
this.oFeatures = {
"bPaginate": true,
"bLengthChange": true,
"bFilter": true,
"bSort": true,
"bInfo": true,
"bAutoWidth": true,
"bProcessing": false,
"bSortClasses": true,
"bStateSave": false,
"bServerSide": false,
"bDeferRender": false
};
/*
* Variable: oScroll
* Purpose: Container for scrolling options
* Scope: jQuery.dataTable.classSettings
*/
this.oScroll = {
"sX": "",
"sXInner": "",
"sY": "",
"bCollapse": false,
"bInfinite": false,
"iLoadGap": 100,
"iBarWidth": 0,
"bAutoCss": true
};
/*
* Variable: aanFeatures
* Purpose: Array referencing the nodes which are used for the features
* Scope: jQuery.dataTable.classSettings
* Notes: The parameters of this object match what is allowed by sDom - i.e.
* 'l' - Length changing
* 'f' - Filtering input
* 't' - The table!
* 'i' - Information
* 'p' - Pagination
* 'r' - pRocessing
*/
this.aanFeatures = [];
/*
* Variable: oLanguage
* Purpose: Store the language strings used by dataTables
* Scope: jQuery.dataTable.classSettings
* Notes: The words in the format _VAR_ are variables which are dynamically replaced
* by javascript
*/
this.oLanguage = {
"sProcessing": "Processing...",
"sLengthMenu": "Show _MENU_ entries",
"sZeroRecords": "No matching records found",
"sEmptyTable": "No data available in table",
"sLoadingRecords": "Loading...",
"sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
"sInfoEmpty": "Showing 0 to 0 of 0 entries",
"sInfoFiltered": "(filtered from _MAX_ total entries)",
"sInfoPostFix": "",
"sInfoThousands": ",",
"sSearch": "Search:",
"sUrl": "",
"oPaginate": {
"sFirst": "First",
"sPrevious": "Previous",
"sNext": "Next",
"sLast": "Last"
},
"fnInfoCallback": null
};
/*
* Variable: aoData
* Purpose: Store data information
* Scope: jQuery.dataTable.classSettings
* Notes: This is an array of objects with the following parameters:
* int: _iId - internal id for tracking
* array: _aData - internal data - used for sorting / filtering etc
* node: nTr - display node
* array node: _anHidden - hidden TD nodes
* string: _sRowStripe
*/
this.aoData = [];
/*
* Variable: aiDisplay
* Purpose: Array of indexes which are in the current display (after filtering etc)
* Scope: jQuery.dataTable.classSettings
*/
this.aiDisplay = [];
/*
* Variable: aiDisplayMaster
* Purpose: Array of indexes for display - no filtering
* Scope: jQuery.dataTable.classSettings
*/
this.aiDisplayMaster = [];
/*
* Variable: aoColumns
* Purpose: Store information about each column that is in use
* Scope: jQuery.dataTable.classSettings
*/
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
* Purpose: Store the next unique id to be used for a new row
* Scope: jQuery.dataTable.classSettings
*/
this.iNextId = 0;
/*
* Variable: asDataSearch
* Purpose: Search data array for regular expression searching
* Scope: jQuery.dataTable.classSettings
*/
this.asDataSearch = [];
/*
* Variable: oPreviousSearch
* Purpose: Store the previous search incase we want to force a re-search
* or compare the old search to a new one
* Scope: jQuery.dataTable.classSettings
*/
this.oPreviousSearch = {
"sSearch": "",
"bRegex": false,
"bSmart": true
};
/*
* Variable: aoPreSearchCols
* Purpose: Store the previous search for each column
* Scope: jQuery.dataTable.classSettings
*/
this.aoPreSearchCols = [];
/*
* Variable: aaSorting
* Purpose: Sorting information
* Scope: jQuery.dataTable.classSettings
* Notes: Index 0 - column number
* Index 1 - current sorting direction
* Index 2 - index of asSorting for this column
*/
this.aaSorting = [ [0, 'asc', 0] ];
/*
* Variable: aaSortingFixed
* Purpose: Sorting information that is always applied
* Scope: jQuery.dataTable.classSettings
*/
this.aaSortingFixed = null;
/*
* Variable: asStripeClasses
* Purpose: Classes to use for the striping of a table
* Scope: jQuery.dataTable.classSettings
*/
this.asStripeClasses = [];
/*
* Variable: asDestroyStripes
* Purpose: If restoring a table - we should restore its striping classes as well
* Scope: jQuery.dataTable.classSettings
*/
this.asDestroyStripes = [];
/*
* Variable: sDestroyWidth
* Purpose: If restoring a table - we should restore its width
* Scope: jQuery.dataTable.classSettings
*/
this.sDestroyWidth = 0;
/*
* Variable: fnRowCallback
* Purpose: Call this function every time a row is inserted (draw)
* Scope: jQuery.dataTable.classSettings
*/
this.fnRowCallback = null;
/*
* Variable: fnHeaderCallback
* Purpose: Callback function for the header on each draw
* Scope: jQuery.dataTable.classSettings
*/
this.fnHeaderCallback = null;
/*
* Variable: fnFooterCallback
* Purpose: Callback function for the footer on each draw
* Scope: jQuery.dataTable.classSettings
*/
this.fnFooterCallback = null;
/*
* Variable: aoDrawCallback
* Purpose: Array of callback functions for draw callback functions
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call
* string:sName - name callback (feature). useful for arranging array
*/
this.aoDrawCallback = [];
/*
* Variable: fnPreDrawCallback
* Purpose: Callback function for just before the table is redrawn. A return of false
* will be used to cancel the draw.
* Scope: jQuery.dataTable.classSettings
*/
this.fnPreDrawCallback = null;
/*
* Variable: fnInitComplete
* Purpose: Callback function for when the table has been initialised
* Scope: jQuery.dataTable.classSettings
*/
this.fnInitComplete = null;
/*
* Variable: sTableId
* Purpose: Cache the table ID for quick access
* Scope: jQuery.dataTable.classSettings
*/
this.sTableId = "";
/*
* Variable: nTable
* Purpose: Cache the table node for quick access
* Scope: jQuery.dataTable.classSettings
*/
this.nTable = null;
/*
* Variable: nTHead
* Purpose: Permanent ref to the thead element
* Scope: jQuery.dataTable.classSettings
*/
this.nTHead = null;
/*
* Variable: nTFoot
* Purpose: Permanent ref to the tfoot element - if it exists
* Scope: jQuery.dataTable.classSettings
*/
this.nTFoot = null;
/*
* Variable: nTBody
* Purpose: Permanent ref to the tbody element
* Scope: jQuery.dataTable.classSettings
*/
this.nTBody = null;
/*
* Variable: nTableWrapper
* Purpose: Cache the wrapper node (contains all DataTables controlled elements)
* Scope: jQuery.dataTable.classSettings
*/
this.nTableWrapper = null;
/*
* Variable: bDeferLoading
* Purpose: Indicate if when using server-side processing the loading of data
* should be deferred until the second draw
* Scope: jQuery.dataTable.classSettings
*/
this.bDeferLoading = false;
/*
* Variable: bInitialised
* Purpose: Indicate if all required information has been read in
* Scope: jQuery.dataTable.classSettings
*/
this.bInitialised = false;
/*
* Variable: aoOpenRows
* Purpose: Information about open rows
* Scope: jQuery.dataTable.classSettings
* Notes: Has the parameters 'nTr' and 'nParent'
*/
this.aoOpenRows = [];
/*
* Variable: sDom
* Purpose: Dictate the positioning that the created elements will take
* Scope: jQuery.dataTable.classSettings
* Notes:
* The following options are allowed:
* 'l' - Length changing
* 'f' - Filtering input
* 't' - The table!
* 'i' - Information
* 'p' - Pagination
* 'r' - pRocessing
* The following constants are allowed:
* 'H' - jQueryUI theme "header" classes
* 'F' - jQueryUI theme "footer" classes
* The following syntax is expected:
* '<' and '>' - div elements
* '<"class" and '>' - div with a class
* Examples:
* '<"wrapper"flipt>', '<lf<t>ip>'
*/
this.sDom = 'lfrtip';
/*
* Variable: sPaginationType
* Purpose: Note which type of sorting should be used
* Scope: jQuery.dataTable.classSettings
*/
this.sPaginationType = "two_button";
/*
* Variable: iCookieDuration
* Purpose: The cookie duration (for bStateSave) in seconds - default 2 hours
* Scope: jQuery.dataTable.classSettings
*/
this.iCookieDuration = 60 * 60 * 2;
/*
* Variable: sCookiePrefix
* Purpose: The cookie name prefix
* Scope: jQuery.dataTable.classSettings
*/
this.sCookiePrefix = "SpryMedia_DataTables_";
/*
* Variable: fnCookieCallback
* Purpose: Callback function for cookie creation
* Scope: jQuery.dataTable.classSettings
*/
this.fnCookieCallback = null;
/*
* Variable: aoStateSave
* Purpose: Array of callback functions for state saving
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call. Takes two parameters, oSettings and the JSON string to
* save that has been thus far created. Returns a JSON string to be inserted into a
* json object (i.e. '"param": [ 0, 1, 2]')
* string:sName - name of callback
*/
this.aoStateSave = [];
/*
* Variable: aoStateLoad
* Purpose: Array of callback functions for state loading
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call. Takes two parameters, oSettings and the object stored.
* May return false to cancel state loading.
* string:sName - name of callback
*/
this.aoStateLoad = [];
/*
* Variable: oLoadedState
* Purpose: State that was loaded from the cookie. Useful for back reference
* Scope: jQuery.dataTable.classSettings
*/
this.oLoadedState = null;
/*
* Variable: sAjaxSource
* Purpose: Source url for AJAX data for the table
* Scope: jQuery.dataTable.classSettings
*/
this.sAjaxSource = null;
/*
* Variable: sAjaxDataProp
* Purpose: Property from a given object from which to read the table data from. This can
* be an empty string (when not server-side processing), in which case it is
* assumed an an array is given directly.
* Scope: jQuery.dataTable.classSettings
*/
this.sAjaxDataProp = 'aaData';
/*
* Variable: bAjaxDataGet
* Purpose: Note if draw should be blocked while getting data
* Scope: jQuery.dataTable.classSettings
*/
this.bAjaxDataGet = true;
/*
* Variable: jqXHR
* Purpose: The last jQuery XHR object that was used for server-side data gathering.
* This can be used for working with the XHR information in one of the callbacks
* Scope: jQuery.dataTable.classSettings
*/
this.jqXHR = null;
/*
* Variable: fnServerData
* Purpose: Function to get the server-side data - can be overruled by the developer
* Scope: jQuery.dataTable.classSettings
*/
this.fnServerData = function ( url, data, callback, settings ) {
settings.jqXHR = $.ajax( {
"url": url,
"data": data,
"success": function (json) {
$(settings.oInstance).trigger('xhr', settings);
callback( json );
},
"dataType": "json",
"cache": false,
"error": function (xhr, error, thrown) {
if ( error == "parsererror" ) {
alert( "DataTables warning: JSON data from server could not be parsed. "+
"This is caused by a JSON formatting error." );
}
}
} );
};
/*
* Variable: aoServerParams
* Purpose: Functions which are called prior to sending an Ajax request so extra parameters
* can easily be sent to the server
* Scope: jQuery.dataTable.classSettings
* Notes: Each array element is an object with the following parameters:
* function:fn - function to call
* string:sName - name callback - useful for knowing where it came from (plugin etc)
*/
this.aoServerParams = [];
/*
* Variable: fnFormatNumber
* Purpose: Format numbers for display
* Scope: jQuery.dataTable.classSettings
*/
this.fnFormatNumber = function ( iIn )
{
if ( iIn < 1000 )
{
/* A small optimisation for what is likely to be the vast majority of use cases */
return iIn;
}
else
{
var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
for ( var i=0 ; i<iLen ; i++ )
{
if ( i%3 === 0 && i !== 0 )
{
out = this.oLanguage.sInfoThousands+out;
}
out = a[iLen-i-1]+out;
}
}
return out;
};
/*
* Variable: aLengthMenu
* Purpose: List of options that can be used for the user selectable length menu
* Scope: jQuery.dataTable.classSettings
* Note: This varaible can take for form of a 1D array, in which case the value and the
* displayed value in the menu are the same, or a 2D array in which case the value comes
* from the first array, and the displayed value to the end user comes from the second
* array. 2D example: [ [ 10, 25, 50, 100, -1 ], [ 10, 25, 50, 100, 'All' ] ];
*/
this.aLengthMenu = [ 10, 25, 50, 100 ];
/*
* Variable: iDraw
* Purpose: Counter for the draws that the table does. Also used as a tracker for
* server-side processing
* Scope: jQuery.dataTable.classSettings
*/
this.iDraw = 0;
/*
* Variable: bDrawing
* Purpose: Indicate if a redraw is being done - useful for Ajax
* Scope: jQuery.dataTable.classSettings
*/
this.bDrawing = 0;
/*
* Variable: iDrawError
* Purpose: Last draw error
* Scope: jQuery.dataTable.classSettings
*/
this.iDrawError = -1;
/*
* Variable: _iDisplayLength, _iDisplayStart, _iDisplayEnd
* Purpose: Display length variables
* Scope: jQuery.dataTable.classSettings
* Notes: These variable must NOT be used externally to get the data length. Rather, use
* the fnRecordsTotal() (etc) functions.
*/
this._iDisplayLength = 10;
this._iDisplayStart = 0;
this._iDisplayEnd = 10;
/*
* Variable: _iRecordsTotal, _iRecordsDisplay
* Purpose: Display length variables used for server side processing
* Scope: jQuery.dataTable.classSettings
* Notes: These variable must NOT be used externally to get the data length. Rather, use
* the fnRecordsTotal() (etc) functions.
*/
this._iRecordsTotal = 0;
this._iRecordsDisplay = 0;
/*
* Variable: bJUI
* Purpose: Should we add the markup needed for jQuery UI theming?
* Scope: jQuery.dataTable.classSettings
*/
this.bJUI = false;
/*
* Variable: oClasses
* Purpose: Should we add the markup needed for jQuery UI theming?
* Scope: jQuery.dataTable.classSettings
*/
this.oClasses = _oExt.oStdClasses;
/*
* Variable: bFiltered and bSorted
* Purpose: Flags to allow callback functions to see what actions have been performed
* Scope: jQuery.dataTable.classSettings
*/
this.bFiltered = 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
* Purpose: Initialisation object that is used for the table
* Scope: jQuery.dataTable.classSettings
*/
this.oInit = null;
/*
* Variable: aoDestroyCallback
* Purpose: Destroy callback functions
* Scope: jQuery.dataTable.classSettings
*/
this.aoDestroyCallback = [];
}
/*
* Variable: oApi
* Purpose: Container for publicly exposed 'private' functions
* Scope: jQuery.dataTable
*/
this.oApi = {};
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Section - API functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Function: fnDraw
* Purpose: Redraw the table
* Returns: -
* Inputs: bool:bComplete - Refilter and resort (if enabled) the table before the draw.
* Optional: default - true
*/
this.fnDraw = function( bComplete )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
if ( typeof bComplete != 'undefined' && bComplete === false )
{
_fnCalculateEnd( oSettings );
_fnDraw( oSettings );
}
else
{
_fnReDraw( oSettings );
}
};
/*
* Function: fnFilter
* Purpose: Filter the input based on data
* Returns: -
* Inputs: string:sInput - string to filter the table on
* int:iColumn - optional - column to limit filtering to
* bool:bRegex - optional - treat as regular expression or not - default false
* bool:bSmart - optional - perform smart filtering or not - default true
* bool:bShowGlobal - optional - show the input global filter in it's input box(es)
* - default true
*/
this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal )
{
var oSettings = _fnSettingsFromNode( this[_oExt.iApiIndex] );
if ( !oSettings.oFeatures.bFilter )
{
return;
}
if ( typeof bRegex == 'undefined' )
{
bRegex = false;
}
if ( typeof bSmart == 'undefined' )
{
bSmart = true;
}
if ( typeof bShowGlobal == 'undefined' )
{
bShowGlobal = true;
}
if ( typeof iColumn == "undefined" || iColumn === null )
{
/* Global filter */
_fnFilterComplete( oSettings, {
"sSearch":sInput,
"bRegex": bRegex,
"bSmart": bSmart
}, 1 );
if ( bShowGlobal && typeof oSettings.aanFeatures.f != 'undefined' )
{
var n = oSettings.aanFeatures.f;
for ( var i=0, iLen=n.length ; i<iLen ; i++ )
{
$('input', n[i]).val( sInput );
}
}
}
else
{
/* Single column filter */
oSettings.aoPreSearchCols[ iColumn ].sSearch = sInput;
oSettings.aoPreSearchCols[ iColumn ].bRegex = bRegex;
oSettings.aoPreSearchCols[ iColumn ].bSmart = bSmart;
_fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
}
};
/*
* Function: fnSettings
* Purpose: Get the settings for a particular table for extern. manipulation
* Returns: -
* Inputs: -
*/
this.fnSettings = function( nNode )
{
return _fnSettingsFromNode( this[_oExt.iApiIndex] );
};
/*
* Function: fnVersionCheck
* Notes: The function is the same as the 'static' function provided in the ext variable
*/
this.fnVersionCheck = _oExt.fnVersionCheck;
/*
* Function: fnSort
* Purpose: Sort the table by a particular row
* Returns: -
* Inputs: int:iCol - the data index to sort on. Note that this will
* not match the 'display index' if you have hidden data entries
*/
this.fn