/* * File: jquery.dataTables.js * Version: 1.8.3.dev * 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) { var _oExt = {}; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 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.3.dev"; /* * 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 = [ ]; /* * 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= 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 }; /* * 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; var fnClickHandler = function ( e ) { if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) ) { fnCallbackDraw( oSettings ); } }; /* 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', { action: "previous" }, fnClickHandler ) .bind( 'selectstart.DT', function () { return false; } ); /* Take the brutal approach to cancelling text selection */ $(nNext) .bind( 'click.DT', { action: "next" }, fnClickHandler ) .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= (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 += ''+i+''; } else { sList += ''+i+''; } } /* 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 y) ? 1 : 0)); }, "string-desc": function ( x, y ) { return ((x < y) ? 1 : ((x > y) ? -1 : 0)); }, /* * html sorting (ignore html tags) */ "html-pre": function ( a ) { return a.replace( /<.*?>/g, "" ).toLowerCase(); }, "html-asc": function ( x, y ) { return ((x < y) ? -1 : ((x > y) ? 1 : 0)); }, "html-desc": function ( x, y ) { return ((x < y) ? 1 : ((x > y) ? -1 : 0)); }, /* * date sorting */ "date-pre": function ( a ) { var x = Date.parse( a ); if ( isNaN(x) || x==="" ) { x = Date.parse( "01/01/1970 00:00:00" ); } return x; }, "date-asc": function ( x, y ) { return x - y; }, "date-desc": function ( x, y ) { return y - x; }, /* * numerical sorting */ "numeric-asc": function ( a ) { return (a=="-" || a==="") ? 0 : a*1; }, "numeric-asc": function ( x, y ) { return x - y; }, "numeric-desc": function ( x, y ) { 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') != -1 ) { return 'html'; } return null; } ]; /** * DataTables is a plug-in for the jQuery Javascript library. It is a * highly flexible tool, based upon the foundations of progressive * enhancement, which will add advanced interaction controls to any * HTML table. For a full list of features please refer to * DataTables.net. * @class * @constructor * @param {object} [oInit={}] Configuration object for DataTables. Options * are defined by {@link FixedColumns.defaults} * @requires jQuery 1.3+ * * @example * // Basic initialisation * $(document).ready( function { * $('#example').dataTable(); * } ); * * @example * // Initialisation with configuration options - in this case, disable * // pagination and sorting. * $(document).ready( function { * $('#example').dataTable( { * "bPaginate": false, * "bSort": false * } ); * } ); */ var DataTable = function( oInit ) { /* * Function: _fnAddColumn * Purpose: Add a column to the list used for the table with default values * Returns: - * Inputs: object:oSettings - dataTables settings object * node:nTh - the th element for this column */ function _fnAddColumn( oSettings, nTh ) { var iCol = oSettings.aoColumns.length; var oCol = { "sType": null, "_bAutoType": true, "bVisible": true, "bSearchable": true, "bSortable": true, "asSorting": [ 'asc', 'desc' ], "sSortingClass": oSettings.oClasses.sSortable, "sSortingClassJUI": oSettings.oClasses.sSortJUI, "sTitle": nTh ? nTh.innerHTML : '', "sName": '', "sWidth": null, "sWidthOrig": null, "sClass": null, "fnRender": null, "bUseRendered": true, "aDataSort": [ iCol ], "mDataProp": iCol, "fnGetData": null, "fnSetData": null, "sSortDataType": 'std', "sDefaultContent": null, "sContentPadding": "", "nTh": nTh ? nTh : document.createElement('th'), "nTf": null }; oSettings.aoColumns.push( oCol ); /* Add a column specific filter */ if ( typeof oSettings.aoPreSearchCols[ iCol ] == 'undefined' || oSettings.aoPreSearchCols[ iCol ] === null ) { oSettings.aoPreSearchCols[ iCol ] = { "sSearch": "", "bRegex": false, "bSmart": true }; } else { /* Don't require that the user must specify bRegex and / or bSmart */ if ( typeof oSettings.aoPreSearchCols[ iCol ].bRegex == 'undefined' ) { oSettings.aoPreSearchCols[ iCol ].bRegex = true; } if ( typeof oSettings.aoPreSearchCols[ iCol ].bSmart == 'undefined' ) { oSettings.aoPreSearchCols[ iCol ].bSmart = true; } } /* Use the column options function to initialise classes etc */ _fnColumnOptions( oSettings, iCol, null ); } /* * Function: _fnColumnOptions * Purpose: Apply options for a column * Returns: - * Inputs: object:oSettings - dataTables settings object * int:iCol - column index to consider * object:oOptions - object with sType, bVisible and bSearchable */ function _fnColumnOptions( oSettings, iCol, oOptions ) { var oCol = oSettings.aoColumns[ iCol ]; /* User specified column options */ if ( typeof oOptions != 'undefined' && oOptions !== null ) { if ( typeof oOptions.sType != 'undefined' ) { oCol.sType = oOptions.sType; oCol._bAutoType = false; } _fnMap( oCol, oOptions, "bVisible" ); _fnMap( oCol, oOptions, "bSearchable" ); _fnMap( oCol, oOptions, "bSortable" ); _fnMap( oCol, oOptions, "sTitle" ); _fnMap( oCol, oOptions, "sName" ); _fnMap( oCol, oOptions, "sWidth" ); _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); _fnMap( oCol, oOptions, "sClass" ); _fnMap( oCol, oOptions, "fnRender" ); _fnMap( oCol, oOptions, "bUseRendered" ); _fnMap( oCol, oOptions, "mDataProp" ); _fnMap( oCol, oOptions, "asSorting" ); _fnMap( oCol, oOptions, "sSortDataType" ); _fnMap( oCol, oOptions, "sDefaultContent" ); _fnMap( oCol, oOptions, "sContentPadding" ); /* iDataSort to be applied (backwards compatibility), but aDataSort will take * priority if defined */ if ( typeof oOptions.iDataSort != 'undefined' ) { oCol.aDataSort = [ oOptions.iDataSort ]; } _fnMap( oCol, oOptions, "aDataSort" ); } /* Cache the data get and set functions for speed */ oCol.fnGetData = _fnGetObjectDataFn( oCol.mDataProp ); oCol.fnSetData = _fnSetObjectDataFn( oCol.mDataProp ); /* Feature sorting overrides column specific when off */ if ( !oSettings.oFeatures.bSort ) { oCol.bSortable = false; } /* Check that the class assignment is correct for sorting */ if ( !oCol.bSortable || ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) ) { oCol.sSortingClass = oSettings.oClasses.sSortableNone; oCol.sSortingClassJUI = ""; } else if ( oCol.bSortable || ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) ) { oCol.sSortingClass = oSettings.oClasses.sSortable; oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI; } else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 ) { oCol.sSortingClass = oSettings.oClasses.sSortableAsc; oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed; } else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 ) { oCol.sSortingClass = oSettings.oClasses.sSortableDesc; oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed; } } /* * Function: _fnAdjustColumnSizing * Purpose: Adjust the table column widths for new data * Returns: - * Inputs: object:oSettings - dataTables settings object * Notes: You would probably want to do a redraw after calling this function! */ function _fnAdjustColumnSizing ( oSettings ) { /* Not interested in doing column width calculation if autowidth is disabled */ if ( oSettings.oFeatures.bAutoWidth === false ) { return false; } _fnCalculateColumnWidths( oSettings ); for ( var i=0 , iLen=oSettings.aoColumns.length ; i