1/** 2 3 * @summary DataTables 4 5 * @description Paginate, search and sort HTML tables 6 7 * @version 1.9.4 8 9 * @file jquery.dataTables.js 10 11 * @author Allan Jardine (www.sprymedia.co.uk) 12 13 * @contact www.sprymedia.co.uk/contact 14 15 * 16 17 * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved. 18 19 * 20 21 * This source file is free software, under either the GPL v2 license or a 22 23 * BSD style license, available at: 24 25 * http://datatables.net/license_gpl2 26 27 * http://datatables.net/license_bsd 28 29 * 30 31 * This source file is distributed in the hope that it will be useful, but 32 33 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 34 35 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 36 37 * 38 39 * For details please refer to: http://www.datatables.net 40 41 */ 42 43 44 45/*jslint evil: true, undef: true, browser: true */ 46 47/*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*/ 48 49 50 51(/** @lends <global> */function( window, document, undefined ) { 52 53 54 55(function( factory ) { 56 57 "use strict"; 58 59 60 61 // Define as an AMD module if possible 62 63 if ( typeof define === 'function' && define.amd ) 64 65 { 66 67 define( ['jquery'], factory ); 68 69 } 70 71 /* Define using browser globals otherwise 72 73 * Prevent multiple instantiations if the script is loaded twice 74 75 */ 76 77 else if ( jQuery && !jQuery.fn.dataTable ) 78 79 { 80 81 factory( jQuery ); 82 83 } 84 85} 86 87(/** @lends <global> */function( $ ) { 88 89 "use strict"; 90 91 /** 92 93 * DataTables is a plug-in for the jQuery Javascript library. It is a 94 95 * highly flexible tool, based upon the foundations of progressive 96 97 * enhancement, which will add advanced interaction controls to any 98 99 * HTML table. For a full list of features please refer to 100 101 * <a href="http://datatables.net">DataTables.net</a>. 102 103 * 104 105 * Note that the <i>DataTable</i> object is not a global variable but is 106 107 * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which 108 109 * it may be accessed. 110 111 * 112 113 * @class 114 115 * @param {object} [oInit={}] Configuration object for DataTables. Options 116 117 * are defined by {@link DataTable.defaults} 118 119 * @requires jQuery 1.3+ 120 121 * 122 123 * @example 124 125 * // Basic initialisation 126 127 * $(document).ready( function { 128 129 * $('#example').dataTable(); 130 131 * } ); 132 133 * 134 135 * @example 136 137 * // Initialisation with configuration options - in this case, disable 138 139 * // pagination and sorting. 140 141 * $(document).ready( function { 142 143 * $('#example').dataTable( { 144 145 * "bPaginate": false, 146 147 * "bSort": false 148 149 * } ); 150 151 * } ); 152 153 */ 154 155 var DataTable = function( oInit ) 156 157 { 158 159 160 161 162 163 /** 164 165 * Add a column to the list used for the table with default values 166 167 * @param {object} oSettings dataTables settings object 168 169 * @param {node} nTh The th element for this column 170 171 * @memberof DataTable#oApi 172 173 */ 174 175 function _fnAddColumn( oSettings, nTh ) 176 177 { 178 179 var oDefaults = DataTable.defaults.columns; 180 181 var iCol = oSettings.aoColumns.length; 182 183 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 184 185 "sSortingClass": oSettings.oClasses.sSortable, 186 187 "sSortingClassJUI": oSettings.oClasses.sSortJUI, 188 189 "nTh": nTh ? nTh : document.createElement('th'), 190 191 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 192 193 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 194 195 "mData": oDefaults.mData ? oDefaults.oDefaults : iCol 196 197 } ); 198 199 oSettings.aoColumns.push( oCol ); 200 201 202 203 /* Add a column specific filter */ 204 205 if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null ) 206 207 { 208 209 oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch ); 210 211 } 212 213 else 214 215 { 216 217 var oPre = oSettings.aoPreSearchCols[ iCol ]; 218 219 220 221 /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */ 222 223 if ( oPre.bRegex === undefined ) 224 225 { 226 227 oPre.bRegex = true; 228 229 } 230 231 232 233 if ( oPre.bSmart === undefined ) 234 235 { 236 237 oPre.bSmart = true; 238 239 } 240 241 242 243 if ( oPre.bCaseInsensitive === undefined ) 244 245 { 246 247 oPre.bCaseInsensitive = true; 248 249 } 250 251 } 252 253 254 255 /* Use the column options function to initialise classes etc */ 256 257 _fnColumnOptions( oSettings, iCol, null ); 258 259 } 260 261 262 263 264 265 /** 266 267 * Apply options for a column 268 269 * @param {object} oSettings dataTables settings object 270 271 * @param {int} iCol column index to consider 272 273 * @param {object} oOptions object with sType, bVisible and bSearchable etc 274 275 * @memberof DataTable#oApi 276 277 */ 278 279 function _fnColumnOptions( oSettings, iCol, oOptions ) 280 281 { 282 283 var oCol = oSettings.aoColumns[ iCol ]; 284 285 286 287 /* User specified column options */ 288 289 if ( oOptions !== undefined && oOptions !== null ) 290 291 { 292 293 /* Backwards compatibility for mDataProp */ 294 295 if ( oOptions.mDataProp && !oOptions.mData ) 296 297 { 298 299 oOptions.mData = oOptions.mDataProp; 300 301 } 302 303 304 305 if ( oOptions.sType !== undefined ) 306 307 { 308 309 oCol.sType = oOptions.sType; 310 311 oCol._bAutoType = false; 312 313 } 314 315 316 317 $.extend( oCol, oOptions ); 318 319 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 320 321 322 323 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 324 325 * priority if defined 326 327 */ 328 329 if ( oOptions.iDataSort !== undefined ) 330 331 { 332 333 oCol.aDataSort = [ oOptions.iDataSort ]; 334 335 } 336 337 _fnMap( oCol, oOptions, "aDataSort" ); 338 339 } 340 341 342 343 /* Cache the data get and set functions for speed */ 344 345 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 346 347 var mData = _fnGetObjectDataFn( oCol.mData ); 348 349 350 351 oCol.fnGetData = function (oData, sSpecific) { 352 353 var innerData = mData( oData, sSpecific ); 354 355 356 357 if ( oCol.mRender && (sSpecific && sSpecific !== '') ) 358 359 { 360
361 return mRender( innerData, sSpecific, oData ); 362 363 } 364 365 return innerData; 366 367 }; 368 369 oCol.fnSetData = _fnSetObjectDataFn( oCol.mData ); 370 371 372 373 /* Feature sorting overrides column specific when off */ 374 375 if ( !oSettings.oFeatures.bSort ) 376 377 { 378 379 oCol.bSortable = false; 380 381 } 382 383 384 385 /* Check that the class assignment is correct for sorting */ 386 387 if ( !oCol.bSortable || 388 389 ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) ) 390 391 { 392 393 oCol.sSortingClass = oSettings.oClasses.sSortableNone; 394 395 oCol.sSortingClassJUI = ""; 396 397 } 398 399 else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 ) 400 401 { 402 403 oCol.sSortingClass = oSettings.oClasses.sSortable; 404 405 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI; 406 407 } 408 409 else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 ) 410 411 { 412 413 oCol.sSortingClass = oSettings.oClasses.sSortableAsc; 414 415 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed; 416 417 } 418 419 else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 ) 420 421 { 422 423 oCol.sSortingClass = oSettings.oClasses.sSortableDesc; 424 425 oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed; 426 427 } 428 429 } 430 431 432 433 434 435 /** 436 437 * Adjust the table column widths for new data. Note: you would probably want to 438 439 * do a redraw after calling this function! 440 441 * @param {object} oSettings dataTables settings object 442 443 * @memberof DataTable#oApi 444 445 */ 446 447 function _fnAdjustColumnSizing ( oSettings ) 448 449 { 450 451 /* Not interested in doing column width calculation if auto-width is disabled */ 452 453 if ( oSettings.oFeatures.bAutoWidth === false ) 454 455 { 456 457 return false; 458 459 } 460 461 462 463 _fnCalculateColumnWidths( oSettings ); 464 465 for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 466 467 { 468 469 oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth; 470 471 } 472 473 } 474 475 476 477 478 479 /** 480 481 * Covert the index of a visible column to the index in the data array (take account 482 483 * of hidden columns) 484 485 * @param {object} oSettings dataTables settings object 486 487 * @param {int} iMatch Visible column index to lookup 488 489 * @returns {int} i the data index 490 491 * @memberof DataTable#oApi 492 493 */ 494 495 function _fnVisibleToColumnIndex( oSettings, iMatch ) 496 497 { 498 499 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 500 501 502 503 return typeof aiVis[iMatch] === 'number' ? 504 505 aiVis[iMatch] : 506 507 null; 508 509 } 510 511 512 513 514 515 /** 516 517 * Covert the index of an index in the data array and convert it to the visible 518 519 * column index (take account of hidden columns) 520 521 * @param {int} iMatch Column index to lookup 522 523 * @param {object} oSettings dataTables settings object 524 525 * @returns {int} i the data index 526 527 * @memberof DataTable#oApi 528 529 */ 530 531 function _fnColumnIndexToVisible( oSettings, iMatch ) 532 533 { 534 535 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 536 537 var iPos = $.inArray( iMatch, aiVis ); 538 539 540 541 return iPos !== -1 ? iPos : null; 542 543 } 544 545 546 547 548 549 /** 550 551 * Get the number of visible columns 552 553 * @param {object} oSettings dataTables settings object 554 555 * @returns {int} i the number of visible columns 556 557 * @memberof DataTable#oApi 558 559 */ 560 561 function _fnVisbleColumns( oSettings ) 562 563 { 564 565 return _fnGetColumns( oSettings, 'bVisible' ).length; 566 567 } 568 569 570 571 572 573 /** 574 575 * Get an array of column indexes that match a given property 576 577 * @param {object} oSettings dataTables settings object 578 579 * @param {string} sParam Parameter in aoColumns to look for - typically 580 581 * bVisible or bSearchable 582 583 * @returns {array} Array of indexes with matched properties 584 585 * @memberof DataTable#oApi 586 587 */ 588 589 function _fnGetColumns( oSettings, sParam ) 590 591 { 592 593 var a = []; 594 595 596 597 $.map( oSettings.aoColumns, function(val, i) { 598 599 if ( val[sParam] ) { 600 601 a.push( i ); 602 603 } 604 605 } ); 606 607 608 609 return a; 610 611 } 612 613 614 615 616 617 /** 618 619 * Get the sort type based on an input string 620 621 * @param {string} sData data we wish to know the type of 622 623 * @returns {string} type (defaults to 'string' if no type can be detected) 624 625 * @memberof DataTable#oApi 626 627 */ 628 629 function _fnDetectType( sData ) 630 631 { 632 633 var aTypes = DataTable.ext.aTypes; 634 635 var iLen = aTypes.length; 636 637 638 639 for ( var i=0 ; i<iLen ; i++ ) 640 641 { 642 643 var sType = aTypes[i]( sData ); 644 645 if ( sType !== null ) 646 647 { 648 649 return sType; 650 651 } 652 653 } 654 655 656 657 return 'string'; 658 659 } 660 661 662 663 664 665 /** 666 667 * Figure out how to reorder a display list 668 669 * @param {object} oSettings dataTables settings object 670 671 * @returns array {int} aiReturn index list for reordering 672 673 * @memberof DataTable#oApi 674 675 */ 676 677 function _fnReOrderIndex ( oSettings, sColumns ) 678 679 { 680 681 var aColumns = sColumns.split(','); 682 683 var aiReturn = []; 684 685 686
687 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 688 689 { 690 691 for ( var j=0 ; j<iLen ; j++ ) 692 693 { 694 695 if ( oSettings.aoColumns[i].sName == aColumns[j] ) 696 697 { 698 699 aiReturn.push( j ); 700 701 break; 702 703 } 704 705 } 706 707 } 708 709 710 711 return aiReturn; 712 713 } 714 715 716 717 718 719 /** 720 721 * Get the column ordering that DataTables expects 722 723 * @param {object} oSettings dataTables settings object 724 725 * @returns {string} comma separated list of names 726 727 * @memberof DataTable#oApi 728 729 */ 730 731 function _fnColumnOrdering ( oSettings ) 732 733 { 734 735 var sNames = ''; 736 737 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 738 739 { 740 741 sNames += oSettings.aoColumns[i].sName+','; 742 743 } 744 745 if ( sNames.length == iLen ) 746 747 { 748 749 return ""; 750 751 } 752 753 return sNames.slice(0, -1); 754 755 } 756 757 758 759 760 761 /** 762 763 * Take the column definitions and static columns arrays and calculate how 764 765 * they relate to column indexes. The callback function will then apply the 766 767 * definition found for a column to a suitable configuration object. 768 769 * @param {object} oSettings dataTables settings object 770 771 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 772 773 * @param {array} aoCols The aoColumns array that defines columns individually 774 775 * @param {function} fn Callback function - takes two parameters, the calculated 776 777 * column index and the definition for that column. 778 779 * @memberof DataTable#oApi 780 781 */ 782 783 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 784 785 { 786 787 var i, iLen, j, jLen, k, kLen; 788 789 790 791 // Column definitions with aTargets 792 793 if ( aoColDefs ) 794 795 { 796 797 /* Loop over the definitions array - loop in reverse so first instance has priority */ 798 799 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 800 801 { 802 803 /* Each definition can target multiple columns, as it is an array */ 804 805 var aTargets = aoColDefs[i].aTargets; 806 807 if ( !$.isArray( aTargets ) ) 808 809 { 810 811 _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) ); 812 813 } 814 815 816 817 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 818 819 { 820 821 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 822 823 { 824 825 /* Add columns that we don't yet know about */ 826 827 while( oSettings.aoColumns.length <= aTargets[j] ) 828 829 { 830 831 _fnAddColumn( oSettings ); 832 833 } 834 835 836 837 /* Integer, basic index */ 838 839 fn( aTargets[j], aoColDefs[i] ); 840 841 } 842 843 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 844 845 { 846 847 /* Negative integer, right to left column counting */ 848 849 fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] ); 850 851 } 852 853 else if ( typeof aTargets[j] === 'string' ) 854 855 { 856 857 /* Class name matching on TH element */ 858 859 for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ ) 860 861 { 862 863 if ( aTargets[j] == "_all" || 864 865 $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) ) 866 867 { 868 869 fn( k, aoColDefs[i] ); 870 871 } 872 873 } 874 875 } 876 877 } 878 879 } 880 881 } 882 883 884 885 // Statically defined columns array 886 887 if ( aoCols ) 888 889 { 890 891 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 892 893 { 894 895 fn( i, aoCols[i] ); 896 897 } 898 899 } 900 901 } 902 903 904 905 /** 906 907 * Add a data array to the table, creating DOM node etc. This is the parallel to 908 909 * _fnGatherData, but for adding rows from a Javascript source, rather than a 910 911 * DOM source. 912 913 * @param {object} oSettings dataTables settings object 914 915 * @param {array} aData data array to be added 916 917 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 918 919 * @memberof DataTable#oApi 920 921 */ 922 923 function _fnAddData ( oSettings, aDataSupplied ) 924 925 { 926 927 var oCol; 928 929 930 931 /* Take an independent copy of the data source so we can bash it about as we wish */ 932 933 var aDataIn = ($.isArray(aDataSupplied)) ? 934 935 aDataSupplied.slice() : 936 937 $.extend( true, {}, aDataSupplied ); 938 939 940 941 /* Create the object for storing information about this new row */ 942 943 var iRow = oSettings.aoData.length; 944 945 var oData = $.extend( true, {}, DataTable.models.oRow ); 946 947 oData._aData = aDataIn; 948 949 oSettings.aoData.push( oData ); 950 951 952 953 /* Create the cells */ 954 955 var nTd, sThisType; 956
957 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 958 959 { 960 961 oCol = oSettings.aoColumns[i]; 962 963 964 965 /* Use rendered data for filtering / sorting */ 966 967 if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null ) 968 969 { 970 971 _fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) ); 972 973 } 974 975 else 976 977 { 978 979 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) ); 980 981 } 982 983 984 985 /* See if we should auto-detect the column type */ 986 987 if ( oCol._bAutoType && oCol.sType != 'string' ) 988 989 { 990 991 /* Attempt to auto detect the type - same as _fnGatherData() */ 992 993 var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' ); 994 995 if ( sVarType !== null && sVarType !== '' ) 996 997 { 998 999 sThisType = _fnDetectType( sVarType ); 1000 1001 if ( oCol.sType === null ) 1002 1003 { 1004 1005 oCol.sType = sThisType; 1006 1007 } 1008 1009 else if ( oCol.sType != sThisType && oCol.sType != "html" ) 1010 1011 { 1012 1013 /* String is always the 'fallback' option */ 1014 1015 oCol.sType = 'string'; 1016 1017 } 1018 1019 } 1020 1021 } 1022 1023 } 1024 1025 1026 1027 /* Add to the display array */ 1028 1029 oSettings.aiDisplayMaster.push( iRow ); 1030 1031 1032 1033 /* Create the DOM information */ 1034 1035 if ( !oSettings.oFeatures.bDeferRender ) 1036 1037 { 1038 1039 _fnCreateTr( oSettings, iRow ); 1040 1041 } 1042 1043 1044 1045 return iRow; 1046 1047 } 1048 1049 1050 1051 1052 1053 /** 1054 1055 * Read in the data from the target table from the DOM 1056 1057 * @param {object} oSettings dataTables settings object 1058 1059 * @memberof DataTable#oApi 1060 1061 */ 1062 1063 function _fnGatherData( oSettings ) 1064 1065 { 1066 1067 var iLoop, i, iLen, j, jLen, jInner, 1068 1069 nTds, nTrs, nTd, nTr, aLocalData, iThisIndex, 1070 1071 iRow, iRows, iColumn, iColumns, sNodeName, 1072 1073 oCol, oData; 1074 1075 1076 1077 /* 1078 1079 * Process by row first 1080 1081 * Add the data object for the whole table - storing the tr node. Note - no point in getting 1082 1083 * DOM based data if we are going to go and replace it with Ajax source data. 1084 1085 */ 1086 1087 if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null ) 1088 1089 { 1090 1091 nTr = oSettings.nTBody.firstChild; 1092 1093 while ( nTr ) 1094 1095 { 1096 1097 if ( nTr.nodeName.toUpperCase() == "TR" ) 1098 1099 { 1100 1101 iThisIndex = oSettings.aoData.length; 1102 1103 nTr._DT_RowIndex = iThisIndex; 1104 1105 oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, { 1106 1107 "nTr": nTr 1108 1109 } ) ); 1110 1111 1112 1113 oSettings.aiDisplayMaster.push( iThisIndex ); 1114 1115 nTd = nTr.firstChild; 1116 1117 jInner = 0; 1118 1119 while ( nTd ) 1120 1121 { 1122 1123 sNodeName = nTd.nodeName.toUpperCase(); 1124 1125 if ( sNodeName == "TD" || sNodeName == "TH" ) 1126 1127 { 1128 1129 _fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) ); 1130 1131 jInner++; 1132 1133 } 1134 1135 nTd = nTd.nextSibling; 1136 1137 } 1138 1139 } 1140 1141 nTr = nTr.nextSibling; 1142 1143 } 1144 1145 } 1146 1147 1148 1149 /* Gather in the TD elements of the Table - note that this is basically the same as 1150 1151 * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet 1152 1153 * setup! 1154 1155 */ 1156 1157 nTrs = _fnGetTrNodes( oSettings ); 1158 1159 nTds = []; 1160 1161 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 1162 1163 { 1164 1165 nTd = nTrs[i].firstChild; 1166 1167 while ( nTd ) 1168 1169 { 1170 1171 sNodeName = nTd.nodeName.toUpperCase(); 1172 1173 if ( sNodeName == "TD" || sNodeName == "TH" ) 1174 1175 { 1176 1177 nTds.push( nTd ); 1178 1179 } 1180 1181 nTd = nTd.nextSibling; 1182 1183 } 1184 1185 } 1186 1187 1188 1189 /* Now process by column */ 1190 1191 for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ ) 1192 1193 { 1194 1195 oCol = oSettings.aoColumns[iColumn]; 1196 1197 1198 1199 /* Get the title of the column - unless there is a user set one */ 1200 1201 if ( oCol.sTitle === null ) 1202 1203 { 1204 1205 oCol.sTitle = oCol.nTh.innerHTML; 1206 1207 } 1208 1209 1210 1211 var 1212 1213 bAutoType = oCol._bAutoType, 1214 1215 bRender = typeof oCol.fnRender === 'function', 1216 1217 bClass = oCol.sClass !== null, 1218 1219 bVisible = oCol.bVisible, 1220 1221 nCell, sThisType, sRendered, sValType; 1222 1223 1224 1225 /* A single loop to rule them all (and be more efficient) */ 1226 1227 if ( bAutoType || bRender || bClass || !bVisible ) 1228 1229 { 1230 1231 for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ ) 1232 1233 { 1234 1235 oData = oSettings.aoData[iRow]; 1236 1237 nCell = nTds[ (iRow*iColumns) + iColumn ]; 1238 1239 1240 1241 /* Type detection */ 1242 1243 if ( bAutoType && oCol.sType != 'string' ) 1244 1245 { 1246 1247 sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' ); 1248 1249 if ( sValType !== '' ) 1250 1251 { 1252 1253 sThisType = _fnDetectType( sValType ); 1254 1255 if ( oCol.sType === null ) 1256 1257 { 1258 1259 oCol.sType = sThisType; 1260 1261 } 1262 1263 else if ( oCol.sType != sThisType && 1264 1265 oCol.sType != "html" ) 1266 1267 { 1268 1269 /* String is always the 'fallback' option */ 1270 1271 oCol.sType = 'string'; 1272 1273 } 1274 1275 } 1276 1277 } 1278 1279 1280 1281 if ( oCol.mRender ) 1282 1283 { 1284 1285 // mRender has been defined, so we need to get the value and set it 1286 1287 nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' ); 1288 1289 } 1290 1291 else if ( oCol.mData !== iColumn ) 1292 1293 { 1294 1295 // If mData is not the same as the column number, then we need to 1296 1297 // get the dev set value. If it is the column, no point in wasting 1298 1299 // time setting the value that is already there! 1300 1301 nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' ); 1302 1303 } 1304 1305 1306 1307 /* Rendering */ 1308 1309 if ( bRender ) 1310 1311 { 1312 1313 sRendered = _fnRender( oSettings, iRow, iColumn ); 1314 1315 nCell.innerHTML = sRendered; 1316 1317 if ( oCol.bUseRendered ) 1318 1319 { 1320 1321 /* Use the rendered data for filtering / sorting */ 1322 1323 _fnSetCellData( oSettings, iRow, iColumn, sRendered ); 1324 1325 } 1326 1327 } 1328 1329 1330 1331 /* Classes */ 1332 1333 if ( bClass ) 1334 1335 { 1336 1337 nCell.className += ' '+oCol.sClass; 1338 1339 } 1340 1341 1342 1343 /* Column visibility */ 1344 1345 if ( !bVisible ) 1346 1347 { 1348 1349 oData._anHidden[iColumn] = nCell; 1350 1351 nCell.parentNode.removeChild( nCell ); 1352 1353 } 1354 1355 else 1356 1357 { 1358 1359 oData._anHidden[iColumn] = null; 1360 1361 } 1362 1363 1364 1365 if ( oCol.fnCreatedCell ) 1366 1367 { 1368 1369 oCol.fnCreatedCell.call( oSettings.oInstance, 1370 1371 nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn 1372 1373 ); 1374 1375 } 1376 1377 } 1378 1379 } 1380 1381 } 1382 1383 1384 1385 /* Row created callbacks */ 1386 1387 if ( oSettings.aoRowCreatedCallback.length !== 0 ) 1388 1389 { 1390
1391 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) 1392 1393 { 1394 1395 oData = oSettings.aoData[i]; 1396 1397 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] ); 1398 1399 } 1400 1401 } 1402 1403 } 1404 1405 1406 1407 1408 1409 /** 1410 1411 * Take a TR element and convert it to an index in aoData 1412 1413 * @param {object} oSettings dataTables settings object 1414 1415 * @param {node} n the TR element to find 1416 1417 * @returns {int} index if the node is found, null if not 1418 1419 * @memberof DataTable#oApi 1420 1421 */ 1422 1423 function _fnNodeToDataIndex( oSettings, n ) 1424 1425 { 1426 1427 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 1428 1429 } 1430 1431 1432 1433 1434 1435 /** 1436 1437 * Take a TD element and convert it into a column data index (not the visible index) 1438 1439 * @param {object} oSettings dataTables settings object 1440 1441 * @param {int} iRow The row number the TD/TH can be found in 1442 1443 * @param {node} n The TD/TH element to find 1444 1445 * @returns {int} index if the node is found, -1 if not 1446 1447 * @memberof DataTable#oApi 1448 1449 */ 1450 1451 function _fnNodeToColumnIndex( oSettings, iRow, n ) 1452 1453 { 1454 1455 var anCells = _fnGetTdNodes( oSettings, iRow ); 1456 1457 1458 1459 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 1460 1461 { 1462 1463 if ( anCells[i] === n ) 1464 1465 { 1466 1467 return i; 1468 1469 } 1470 1471 } 1472 1473 return -1; 1474 1475 } 1476 1477 1478 1479 1480 1481 /** 1482 1483 * Get an array of data for a given row from the internal data cache 1484 1485 * @param {object} oSettings dataTables settings object 1486 1487 * @param {int} iRow aoData row id 1488 1489 * @param {string} sSpecific data get type ('type' 'filter' 'sort') 1490 1491 * @param {array} aiColumns Array of column indexes to get data from 1492 1493 * @returns {array} Data array 1494 1495 * @memberof DataTable#oApi 1496 1497 */ 1498 1499 function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns ) 1500 1501 { 1502 1503 var out = []; 1504 1505 for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ ) 1506 1507 { 1508 1509 out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) ); 1510 1511 } 1512 1513 return out; 1514 1515 } 1516 1517 1518 1519 1520 1521 /** 1522 1523 * Get the data for a given cell from the internal cache, taking into account data mapping 1524 1525 * @param {object} oSettings dataTables settings object 1526 1527 * @param {int} iRow aoData row id 1528 1529 * @param {int} iCol Column index 1530 1531 * @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort') 1532 1533 * @returns {*} Cell data 1534 1535 * @memberof DataTable#oApi 1536 1537 */ 1538 1539 function _fnGetCellData( oSettings, iRow, iCol, sSpecific ) 1540 1541 { 1542 1543 var sData; 1544 1545 var oCol = oSettings.aoColumns[iCol]; 1546 1547 var oData = oSettings.aoData[iRow]._aData; 1548 1549 1550 1551 if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined ) 1552 1553 { 1554 1555 if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null ) 1556 1557 { 1558 1559 _fnLog( oSettings, 0, "Requested unknown parameter "+ 1560 1561 (typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+ 1562 1563 " from the data source for row "+iRow ); 1564 1565 oSettings.iDrawError = oSettings.iDraw; 1566 1567 } 1568 1569 return oCol.sDefaultContent; 1570 1571 } 1572 1573 1574 1575 /* When the data source is null, we can use default column data */ 1576 1577 if ( sData === null && oCol.sDefaultContent !== null ) 1578 1579 { 1580 1581 sData = oCol.sDefaultContent; 1582 1583 } 1584 1585 else if ( typeof sData === 'function' ) 1586 1587 { 1588 1589 /* If the data source is a function, then we run it and use the return */ 1590 1591 return sData(); 1592 1593 } 1594 1595 1596 1597 if ( sSpecific == 'display' && sData === null ) 1598 1599 { 1600 1601 return ''; 1602 1603 } 1604 1605 return sData; 1606 1607 } 1608 1609 1610 1611 1612 1613 /** 1614 1615 * Set the value for a specific cell, into the internal data cache 1616 1617 * @param {object} oSettings dataTables settings object 1618 1619 * @param {int} iRow aoData row id 1620 1621 * @param {int} iCol Column index 1622 1623 * @param {*} val Value to set 1624 1625 * @memberof DataTable#oApi 1626 1627 */ 1628 1629 function _fnSetCellData( oSettings, iRow, iCol, val ) 1630 1631 { 1632 1633 var oCol = oSettings.aoColumns[iCol]; 1634 1635 var oData = oSettings.aoData[iRow]._aData; 1636 1637 1638 1639 oCol.fnSetData( oData, val ); 1640 1641 } 1642 1643 1644 1645 1646 1647 // Private variable that is used to match array syntax in the data property object 1648 1649 var __reArray = /\[.*?\]$/; 1650 1651 1652 1653 /** 1654 1655 * Return a function that can be used to get data from a source object, taking 1656 1657 * into account the ability to use nested objects as a source 1658 1659 * @param {string|int|function} mSource The data source for the object 1660 1661 * @returns {function} Data get function 1662 1663 * @memberof DataTable#oApi 1664 1665 */ 1666 1667 function _fnGetObjectDataFn( mSource ) 1668 1669 { 1670 1671 if ( mSource === null ) 1672 1673 { 1674 1675 /* Give an empty string for rendering / sorting etc */ 1676 1677 return function (data, type) { 1678 1679 return null; 1680 1681 }; 1682 1683 } 1684 1685 else if ( typeof mSource === 'function' ) 1686 1687 { 1688 1689 return function (data, type, extra) { 1690 1691 return mSource( data, type, extra ); 1692 1693 }; 1694 1695 } 1696 1697 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) ) 1698 1699 { 1700 1701 /* If there is a . in the source string then the data source is in a 1702 1703 * nested object so we loop over the data for each level to get the next 1704 1705 * level down. On each loop we test for undefined, and if found immediately 1706 1707 * return. This allows entire objects to be missing and sDefaultContent to 1708 1709 * be used if defined, rather than throwing an error 1710 1711 */ 1712
1713 var fetchData = function (data, type, src) { 1714 1715 var a = src.split('.'); 1716 1717 var arrayNotation, out, innerSrc; 1718 1719 1720 1721 if ( src !== "" ) 1722 1723 { 1724 1725 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 1726 1727 { 1728 1729 // Check if we are dealing with an array notation request 1730 1731 arrayNotation = a[i].match(__reArray); 1732 1733 1734 1735 if ( arrayNotation ) { 1736 1737 a[i] = a[i].replace(__reArray, ''); 1738 1739 1740 1741 // Condition allows simply [] to be passed in 1742 1743 if ( a[i] !== "" ) { 1744 1745 data = data[ a[i] ]; 1746 1747 } 1748 1749 out = []; 1750 1751 1752 1753 // Get the remainder of the nested object to get 1754 1755 a.splice( 0, i+1 ); 1756 1757 innerSrc = a.join('.'); 1758 1759 1760 1761 // Traverse each entry in the array getting the properties requested 1762 1763 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 1764 1765 out.push( fetchData( data[j], type, innerSrc ) ); 1766 1767 } 1768 1769 1770 1771 // If a string is given in between the array notation indicators, that 1772 1773 // is used to join the strings together, otherwise an array is returned 1774 1775 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 1776 1777 data = (join==="") ? out : out.join(join); 1778 1779 1780 1781 // The inner call to fetchData has already traversed through the remainder 1782 1783 // of the source requested, so we exit from the loop 1784 1785 break; 1786 1787 } 1788 1789 1790 1791 if ( data === null || data[ a[i] ] === undefined ) 1792 1793 { 1794 1795 return undefined; 1796 1797 } 1798 1799 data = data[ a[i] ]; 1800 1801 } 1802 1803 } 1804 1805 1806 1807 return data; 1808 1809 }; 1810 1811 1812 1813 return function (data, type) { 1814 1815 return fetchData( data, type, mSource ); 1816 1817 }; 1818 1819 } 1820 1821 else 1822 1823 { 1824 1825 /* Array or flat object mapping */ 1826 1827 return function (data, type) { 1828 1829 return data[mSource]; 1830 1831 }; 1832 1833 } 1834 1835 } 1836 1837 1838 1839 1840 1841 /** 1842 1843 * Return a function that can be used to set data from a source object, taking 1844 1845 * into account the ability to use nested objects as a source 1846 1847 * @param {string|int|function} mSource The data source for the object 1848 1849 * @returns {function} Data set function 1850 1851 * @memberof DataTable#oApi 1852 1853 */ 1854 1855 function _fnSetObjectDataFn( mSource ) 1856 1857 { 1858 1859 if ( mSource === null ) 1860 1861 { 1862 1863 /* Nothing to do when the data source is null */ 1864 1865 return function (data, val) {}; 1866 1867 } 1868 1869 else if ( typeof mSource === 'function' ) 1870 1871 { 1872 1873 return function (data, val) { 1874 1875 mSource( data, 'set', val ); 1876 1877 }; 1878 1879 } 1880 1881 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) ) 1882 1883 { 1884 1885 /* Like the get, we need to get data from a nested object */ 1886 1887 var setData = function (data, val, src) { 1888 1889 var a = src.split('.'), b; 1890 1891 var arrayNotation, o, innerSrc; 1892 1893 1894 1895 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) 1896 1897 { 1898 1899 // Check if we are dealing with an array notation request 1900 1901 arrayNotation = a[i].match(__reArray); 1902 1903 1904 1905 if ( arrayNotation ) 1906 1907 { 1908 1909 a[i] = a[i].replace(__reArray, ''); 1910 1911 data[ a[i] ] = []; 1912 1913 1914 1915 // Get the remainder of the nested object to set so we can recurse 1916 1917 b = a.slice(); 1918 1919 b.splice( 0, i+1 ); 1920 1921 innerSrc = b.join('.'); 1922 1923 1924 1925 // Traverse each entry in the array setting the properties requested 1926 1927 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) 1928 1929 { 1930 1931 o = {}; 1932 1933 setData( o, val[j], innerSrc ); 1934 1935 data[ a[i] ].push( o ); 1936 1937 } 1938 1939 1940 1941 // The inner call to setData has already traversed through the remainder 1942 1943 // of the source and has set the data, thus we can exit here 1944 1945 return; 1946 1947 } 1948 1949 1950 1951 // If the nested object doesn't currently exist - since we are 1952 1953 // trying to set the value - create it 1954 1955 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) 1956 1957 { 1958 1959 data[ a[i] ] = {}; 1960 1961 } 1962 1963 data = data[ a[i] ]; 1964 1965 } 1966 1967 1968 1969 // If array notation is used, we just want to strip it and use the property name 1970 1971 // and assign the value. If it isn't used, then we get the result we want anyway 1972 1973 data[ a[a.length-1].replace(__reArray, '') ] = val; 1974 1975 }; 1976 1977 1978 1979 return function (data, val) { 1980 1981 return setData( data, val, mSource ); 1982 1983 }; 1984 1985 } 1986 1987 else 1988 1989 { 1990 1991 /* Array or flat object mapping */ 1992 1993 return function (data, val) { 1994 1995 data[mSource] = val; 1996 1997 }; 1998 1999 } 2000 2001 } 2002 2003 2004 2005 2006 2007 /** 2008 2009 * Return an array with the full table data 2010 2011 * @param {object} oSettings dataTables settings object 2012 2013 * @returns array {array} aData Master data array 2014 2015 * @memberof DataTable#oApi 2016 2017 */ 2018 2019 function _fnGetDataMaster ( oSettings ) 2020 2021 { 2022 2023 var aData = []; 2024 2025 var iLen = oSettings.aoData.length; 2026 2027 for ( var i=0 ; i<iLen; i++ ) 2028 2029 { 2030 2031 aData.push( oSettings.aoData[i]._aData ); 2032 2033 } 2034 2035 return aData; 2036 2037 } 2038 2039 2040 2041 2042 2043 /** 2044 2045 * Nuke the table 2046 2047 * @param {object} oSettings dataTables settings object 2048 2049 * @memberof DataTable#oApi 2050 2051 */ 2052 2053 function _fnClearTable( oSettings ) 2054 2055 { 2056 2057 oSettings.aoData.splice( 0, oSettings.aoData.length ); 2058 2059 oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length ); 2060 2061 oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length ); 2062 2063 _fnCalculateEnd( oSettings ); 2064 2065 } 2066 2067 2068 2069 2070 2071 /** 2072 2073 * Take an array of integers (index array) and remove a target integer (value - not 2074 2075 * the key!) 2076 2077 * @param {array} a Index array to target 2078 2079 * @param {int} iTarget value to find 2080 2081 * @memberof DataTable#oApi 2082 2083 */ 2084 2085 function _fnDeleteIndex( a, iTarget ) 2086 2087 { 2088 2089 var iTargetIndex = -1; 2090 2091 2092 2093 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 2094 2095 { 2096 2097 if ( a[i] == iTarget ) 2098 2099 { 2100 2101 iTargetIndex = i; 2102 2103 } 2104 2105 else if ( a[i] > iTarget ) 2106 2107 { 2108 2109 a[i]--; 2110 2111 } 2112 2113 } 2114 2115 2116 2117 if ( iTargetIndex != -1 ) 2118 2119 { 2120 2121 a.splice( iTargetIndex, 1 ); 2122 2123 } 2124 2125 } 2126 2127 2128 2129 2130 2131 /** 2132
2133 * Call the developer defined fnRender function for a given cell (row/column) with 2134 2135 * the required parameters and return the result. 2136 2137 * @param {object} oSettings dataTables settings object 2138 2139 * @param {int} iRow aoData index for the row 2140 2141 * @param {int} iCol aoColumns index for the column 2142 2143 * @returns {*} Return of the developer's fnRender function 2144 2145 * @memberof DataTable#oApi 2146 2147 */ 2148 2149 function _fnRender( oSettings, iRow, iCol ) 2150 2151 { 2152 2153 var oCol = oSettings.aoColumns[iCol]; 2154 2155 2156 2157 return oCol.fnRender( { 2158 2159 "iDataRow": iRow, 2160 2161 "iDataColumn": iCol, 2162 2163 "oSettings": oSettings, 2164 2165 "aData": oSettings.aoData[iRow]._aData, 2166 2167 "mDataProp": oCol.mData 2168 2169 }, _fnGetCellData(oSettings, iRow, iCol, 'display') ); 2170 2171 } 2172 2173 /** 2174 2175 * Create a new TR element (and it's TD children) for a row 2176 2177 * @param {object} oSettings dataTables settings object 2178 2179 * @param {int} iRow Row to consider 2180 2181 * @memberof DataTable#oApi 2182 2183 */ 2184 2185 function _fnCreateTr ( oSettings, iRow ) 2186 2187 { 2188 2189 var oData = oSettings.aoData[iRow]; 2190 2191 var nTd; 2192 2193 2194 2195 if ( oData.nTr === null ) 2196 2197 { 2198 2199 oData.nTr = document.createElement('tr'); 2200 2201 2202 2203 /* Use a private property on the node to allow reserve mapping from the node 2204 2205 * to the aoData array for fast look up 2206 2207 */ 2208 2209 oData.nTr._DT_RowIndex = iRow; 2210 2211 2212 2213 /* Special parameters can be given by the data source to be used on the row */ 2214 2215 if ( oData._aData.DT_RowId ) 2216 2217 { 2218 2219 oData.nTr.id = oData._aData.DT_RowId; 2220 2221 } 2222 2223 2224 2225 if ( oData._aData.DT_RowClass ) 2226 2227 { 2228 2229 oData.nTr.className = oData._aData.DT_RowClass; 2230 2231 } 2232 2233 2234 2235 /* Process each column */ 2236 2237 for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 2238 2239 { 2240 2241 var oCol = oSettings.aoColumns[i]; 2242 2243 nTd = document.createElement( oCol.sCellType ); 2244 2245 2246 2247 /* Render if needed - if bUseRendered is true then we already have the rendered 2248 2249 * value in the data source - so can just use that 2250 2251 */ 2252 2253 nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ? 2254 2255 _fnRender( oSettings, iRow, i ) : 2256 2257 _fnGetCellData( oSettings, iRow, i, 'display' ); 2258 2259 2260 2261 /* Add user defined class */ 2262 2263 if ( oCol.sClass !== null ) 2264 2265 { 2266 2267 nTd.className = oCol.sClass; 2268 2269 } 2270 2271 2272 2273 if ( oCol.bVisible ) 2274 2275 { 2276 2277 oData.nTr.appendChild( nTd ); 2278 2279 oData._anHidden[i] = null; 2280 2281 } 2282 2283 else 2284 2285 { 2286 2287 oData._anHidden[i] = nTd; 2288 2289 } 2290 2291 2292 2293 if ( oCol.fnCreatedCell ) 2294 2295 { 2296 2297 oCol.fnCreatedCell.call( oSettings.oInstance, 2298 2299 nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i 2300 2301 ); 2302 2303 } 2304 2305 } 2306 2307 2308 2309 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] ); 2310 2311 } 2312 2313 } 2314 2315 2316 2317 2318 2319 /** 2320 2321 * Create the HTML header for the table 2322 2323 * @param {object} oSettings dataTables settings object 2324 2325 * @memberof DataTable#oApi 2326 2327 */ 2328 2329 function _fnBuildHead( oSettings ) 2330 2331 { 2332 2333 var i, nTh, iLen, j, jLen; 2334 2335 var iThs = $('th, td', oSettings.nTHead).length; 2336 2337 var iCorrector = 0; 2338 2339 var jqChildren; 2340 2341 2342 2343 /* If there is a header in place - then use it - otherwise it's going to get nuked... */ 2344 2345 if ( iThs !== 0 ) 2346 2347 { 2348 2349 /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */ 2350 2351 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 2352 2353 { 2354 2355 nTh = oSettings.aoColumns[i].nTh; 2356 2357 nTh.setAttribute('role', 'columnheader'); 2358 2359 if ( oSettings.aoColumns[i].bSortable ) 2360 2361 { 2362 2363 nTh.setAttribute('tabindex', oSettings.iTabIndex); 2364 2365 nTh.setAttribute('aria-controls', oSettings.sTableId); 2366 2367 } 2368 2369 2370 2371 if ( oSettings.aoColumns[i].sClass !== null ) 2372 2373 { 2374 2375 $(nTh).addClass( oSettings.aoColumns[i].sClass ); 2376 2377 } 2378 2379 2380 2381 /* Set the title of the column if it is user defined (not what was auto detected) */ 2382 2383 if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML ) 2384 2385 { 2386 2387 nTh.innerHTML = oSettings.aoColumns[i].sTitle; 2388 2389 } 2390 2391 } 2392 2393 } 2394 2395 else 2396 2397 { 2398 2399 /* We don't have a header in the DOM - so we are going to have to create one */ 2400 2401 var nTr = document.createElement( "tr" ); 2402 2403 2404
2405 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 2406 2407 { 2408 2409 nTh = oSettings.aoColumns[i].nTh; 2410 2411 nTh.innerHTML = oSettings.aoColumns[i].sTitle; 2412 2413 nTh.setAttribute('tabindex', '0'); 2414 2415 2416 2417 if ( oSettings.aoColumns[i].sClass !== null ) 2418 2419 { 2420 2421 $(nTh).addClass( oSettings.aoColumns[i].sClass ); 2422 2423 } 2424 2425 2426 2427 nTr.appendChild( nTh ); 2428 2429 } 2430 2431 $(oSettings.nTHead).html( '' )[0].appendChild( nTr ); 2432 2433 _fnDetectHeader( oSettings.aoHeader, oSettings.nTHead ); 2434 2435 } 2436 2437 2438 2439 /* ARIA role for the rows */ 2440 2441 $(oSettings.nTHead).children('tr').attr('role', 'row'); 2442 2443 2444 2445 /* Add the extra markup needed by jQuery UI's themes */ 2446 2447 if ( oSettings.bJUI ) 2448 2449 { 2450 2451 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 2452 2453 { 2454 2455 nTh = oSettings.aoColumns[i].nTh; 2456 2457 2458 2459 var nDiv = document.createElement('div'); 2460 2461 nDiv.className = oSettings.oClasses.sSortJUIWrapper; 2462 2463 $(nTh).contents().appendTo(nDiv); 2464 2465 2466 2467 var nSpan = document.createElement('span'); 2468 2469 nSpan.className = oSettings.oClasses.sSortIcon; 2470 2471 nDiv.appendChild( nSpan ); 2472 2473 nTh.appendChild( nDiv ); 2474 2475 } 2476 2477 } 2478 2479 2480 2481 if ( oSettings.oFeatures.bSort ) 2482 2483 { 2484 2485 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) 2486 2487 { 2488 2489 if ( oSettings.aoColumns[i].bSortable !== false ) 2490 2491 { 2492 2493 _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i ); 2494 2495 } 2496 2497 else 2498 2499 { 2500 2501 $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone ); 2502 2503 } 2504 2505 } 2506 2507 } 2508 2509 2510 2511 /* Deal with the footer - add classes if required */ 2512 2513 if ( oSettings.oClasses.sFooterTH !== "" ) 2514 2515 { 2516 2517 $(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH ); 2518 2519 } 2520 2521 2522 2523 /* Cache the footer elements */ 2524 2525 if ( oSettings.nTFoot !== null ) 2526 2527 { 2528 2529 var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter ); 2530 2531 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 2532 2533 { 2534 2535 if ( anCells[i] ) 2536 2537 { 2538 2539 oSettings.aoColumns[i].nTf = anCells[i]; 2540 2541 if ( oSettings.aoColumns[i].sClass ) 2542 2543 { 2544 2545 $(anCells[i]).addClass( oSettings.aoColumns[i].sClass ); 2546 2547 } 2548 2549 } 2550 2551 } 2552 2553 } 2554 2555 } 2556 2557 2558 2559 2560 2561 /** 2562 2563 * Draw the header (or footer) element based on the column visibility states. The 2564 2565 * methodology here is to use the layout array from _fnDetectHeader, modified for 2566 2567 * the instantaneous column visibility, to construct the new layout. The grid is 2568 2569 * traversed over cell at a time in a rows x columns grid fashion, although each 2570 2571 * cell insert can cover multiple elements in the grid - which is tracks using the 2572 2573 * aApplied array. Cell inserts in the grid will only occur where there isn't 2574 2575 * already a cell in that position. 2576 2577 * @param {object} oSettings dataTables settings object 2578 2579 * @param array {objects} aoSource Layout array from _fnDetectHeader 2580 2581 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 2582 2583 * @memberof DataTable#oApi 2584 2585 */ 2586 2587 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 2588 2589 { 2590 2591 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 2592 2593 var aoLocal = []; 2594 2595 var aApplied = []; 2596 2597 var iColumns = oSettings.aoColumns.length; 2598 2599 var iRowspan, iColspan; 2600 2601 2602 2603 if ( bIncludeHidden === undefined ) 2604 2605 { 2606 2607 bIncludeHidden = false; 2608 2609 } 2610 2611 2612 2613 /* Make a copy of the master layout array, but without the visible columns in it */ 2614 2615 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 2616 2617 { 2618 2619 aoLocal[i] = aoSource[i].slice(); 2620 2621 aoLocal[i].nTr = aoSource[i].nTr; 2622 2623 2624 2625 /* Remove any columns which are currently hidden */ 2626 2627 for ( j=iColumns-1 ; j>=0 ; j-- ) 2628 2629 { 2630 2631 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 2632 2633 { 2634 2635 aoLocal[i].splice( j, 1 ); 2636 2637 } 2638 2639 } 2640 2641 2642 2643 /* Prep the applied array - it needs an element for each row */ 2644 2645 aApplied.push( [] ); 2646 2647 } 2648 2649 2650 2651 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 2652 2653 { 2654 2655 nLocalTr = aoLocal[i].nTr; 2656 2657 2658 2659 /* All cells are going to be replaced, so empty out the row */ 2660 2661 if ( nLocalTr ) 2662 2663 { 2664 2665 while( (n = nLocalTr.firstChild) ) 2666 2667 { 2668 2669 nLocalTr.removeChild( n ); 2670 2671 } 2672 2673 } 2674 2675 2676 2677 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 2678 2679 { 2680
2681 iRowspan = 1; 2682 2683 iColspan = 1; 2684 2685 2686 2687 /* Check to see if there is already a cell (row/colspan) covering our target 2688 2689 * insert point. If there is, then there is nothing to do. 2690 2691 */ 2692 2693 if ( aApplied[i][j] === undefined ) 2694 2695 { 2696 2697 nLocalTr.appendChild( aoLocal[i][j].cell ); 2698 2699 aApplied[i][j] = 1; 2700 2701 2702 2703 /* Expand the cell to cover as many rows as needed */ 2704 2705 while ( aoLocal[i+iRowspan] !== undefined && 2706 2707 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 2708 2709 { 2710 2711 aApplied[i+iRowspan][j] = 1; 2712 2713 iRowspan++; 2714 2715 } 2716 2717 2718 2719 /* Expand the cell to cover as many columns as needed */ 2720 2721 while ( aoLocal[i][j+iColspan] !== undefined && 2722 2723 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 2724 2725 { 2726 2727 /* Must update the applied array over the rows for the columns */ 2728 2729 for ( k=0 ; k<iRowspan ; k++ ) 2730 2731 { 2732 2733 aApplied[i+k][j+iColspan] = 1; 2734 2735 } 2736 2737 iColspan++; 2738 2739 } 2740 2741 2742 2743 /* Do the actual expansion in the DOM */ 2744 2745 aoLocal[i][j].cell.rowSpan = iRowspan; 2746 2747 aoLocal[i][j].cell.colSpan = iColspan; 2748 2749 } 2750 2751 } 2752 2753 } 2754 2755 } 2756 2757 2758 2759 2760 2761 /** 2762 2763 * Insert the required TR nodes into the table for display 2764 2765 * @param {object} oSettings dataTables settings object 2766 2767 * @memberof DataTable#oApi 2768 2769 */ 2770 2771 function _fnDraw( oSettings ) 2772 2773 { 2774 2775 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 2776 2777 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 2778 2779 if ( $.inArray( false, aPreDraw ) !== -1 ) 2780 2781 { 2782 2783 _fnProcessingDisplay( oSettings, false ); 2784 2785 return; 2786 2787 } 2788 2789 2790 2791 var i, iLen, n; 2792 2793 var anRows = []; 2794 2795 var iRowCount = 0; 2796 2797 var iStripes = oSettings.asStripeClasses.length; 2798 2799 var iOpenRows = oSettings.aoOpenRows.length; 2800 2801 2802 2803 oSettings.bDrawing = true; 2804 2805 2806 2807 /* Check and see if we have an initial draw position from state saving */ 2808 2809 if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 ) 2810 2811 { 2812 2813 if ( oSettings.oFeatures.bServerSide ) 2814 2815 { 2816 2817 oSettings._iDisplayStart = oSettings.iInitDisplayStart; 2818 2819 } 2820 2821 else 2822 2823 { 2824 2825 oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ? 2826 2827 0 : oSettings.iInitDisplayStart; 2828 2829 } 2830 2831 oSettings.iInitDisplayStart = -1; 2832 2833 _fnCalculateEnd( oSettings ); 2834 2835 } 2836 2837 2838 2839 /* Server-side processing draw intercept */ 2840 2841 if ( oSettings.bDeferLoading ) 2842 2843 { 2844 2845 oSettings.bDeferLoading = false; 2846 2847 oSettings.iDraw++; 2848 2849 } 2850 2851 else if ( !oSettings.oFeatures.bServerSide ) 2852 2853 { 2854 2855 oSettings.iDraw++; 2856 2857 } 2858 2859 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) 2860 2861 { 2862 2863 return; 2864 2865 } 2866 2867 2868 2869 if ( oSettings.aiDisplay.length !== 0 ) 2870 2871 { 2872 2873 var iStart = oSettings._iDisplayStart; 2874 2875 var iEnd = oSettings._iDisplayEnd;
2876 2877 2878 2879 if ( oSettings.oFeatures.bServerSide ) 2880 2881 { 2882 2883 iStart = 0; 2884 2885 iEnd = oSettings.aoData.length; 2886 2887 } 2888 2889 2890 2891 for ( var j=iStart ; j<iEnd ; j++ ) 2892 2893 { 2894 2895 var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ]; 2896 2897 if ( aoData.nTr === null ) 2898 2899 { 2900 2901 _fnCreateTr( oSettings, oSettings.aiDisplay[j] ); 2902 2903 } 2904 2905 2906 2907 var nRow = aoData.nTr; 2908 2909 2910 2911 /* Remove the old striping classes and then add the new one */ 2912 2913 if ( iStripes !== 0 ) 2914 2915 { 2916 2917 var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ]; 2918 2919 if ( aoData._sRowStripe != sStripe ) 2920 2921 { 2922 2923 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 2924 2925 aoData._sRowStripe = sStripe; 2926 2927 } 2928 2929 } 2930 2931 2932 2933 /* Row callback functions - might want to manipulate the row */ 2934 2935 _fnCallbackFire( oSettings, 'aoRowCallback', null, 2936 2937 [nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] ); 2938 2939 2940 2941 anRows.push( nRow ); 2942 2943 iRowCount++; 2944 2945 2946 2947 /* If there is an open row - and it is attached to this parent - attach it on redraw */ 2948 2949 if ( iOpenRows !== 0 ) 2950 2951 { 2952 2953 for ( var k=0 ; k<iOpenRows ; k++ ) 2954 2955 { 2956 2957 if ( nRow == oSettings.aoOpenRows[k].nParent ) 2958 2959 { 2960 2961 anRows.push( oSettings.aoOpenRows[k].nTr ); 2962 2963 break; 2964 2965 } 2966 2967 } 2968 2969 } 2970 2971 } 2972 2973 } 2974 2975 else 2976 2977 { 2978 2979 /* Table is empty - create a row with an empty message in it */ 2980 2981 anRows[ 0 ] = document.createElement( 'tr' ); 2982 2983 2984 2985 if ( oSettings.asStripeClasses[0] ) 2986 2987 { 2988 2989 anRows[ 0 ].className = oSettings.asStripeClasses[0]; 2990 2991 } 2992 2993 2994 2995 var oLang = oSettings.oLanguage; 2996 2997 var sZero = oLang.sZeroRecords; 2998 2999 if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide ) 3000 3001 { 3002 3003 sZero = oLang.sLoadingRecords; 3004 3005 } 3006 3007 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 3008 3009 { 3010 3011 sZero = oLang.sEmptyTable; 3012 3013 } 3014 3015 3016 3017 var nTd = document.createElement( 'td' ); 3018 3019 nTd.setAttribute( 'valign', "top" ); 3020 3021 nTd.colSpan = _fnVisbleColumns( oSettings ); 3022 3023 nTd.className = oSettings.oClasses.sRowEmpty; 3024 3025 nTd.innerHTML = _fnInfoMacros( oSettings, sZero ); 3026 3027 3028 3029 anRows[ iRowCount ].appendChild( nTd ); 3030 3031 } 3032 3033 3034 3035 /* Header and footer callbacks */ 3036 3037 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 3038 3039 _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] ); 3040 3041 3042 3043 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 3044 3045 _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] ); 3046 3047 3048 3049 /* 3050 3051 * Need to remove any old row from the display - note we can't just empty the tbody using 3052 3053 * $().html('') since this will unbind the jQuery event handlers (even although the node 3054 3055 * still exists!) - equally we can't use innerHTML, since IE throws an exception. 3056 3057 */ 3058 3059 var 3060 3061 nAddFrag = document.createDocumentFragment(), 3062 3063 nRemoveFrag = document.createDocumentFragment(), 3064 3065 nBodyPar, nTrs; 3066 3067 3068 3069 if ( oSettings.nTBody ) 3070 3071 { 3072 3073 nBodyPar = oSettings.nTBody.parentNode; 3074 3075 nRemoveFrag.appendChild( oSettings.nTBody ); 3076 3077 3078 3079 /* When doing infinite scrolling, only remove child rows when sorting, filtering or start 3080 3081 * up. When not infinite scroll, always do it. 3082 3083 */ 3084 3085 if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete || 3086 3087 oSettings.bSorted || oSettings.bFiltered ) 3088 3089 { 3090 3091 while( (n = oSettings.nTBody.firstChild) ) 3092 3093 { 3094 3095 oSettings.nTBody.removeChild( n ); 3096 3097 } 3098 3099 } 3100 3101 3102 3103 /* Put the draw table into the dom */ 3104 3105 for ( i=0, iLen=anRows.length ; i<iLen ; i++ ) 3106 3107 { 3108 3109 nAddFrag.appendChild( anRows[i] ); 3110 3111 } 3112 3113 3114 3115 oSettings.nTBody.appendChild( nAddFrag ); 3116 3117 if ( nBodyPar !== null ) 3118 3119 { 3120 3121 nBodyPar.appendChild( oSettings.nTBody ); 3122 3123 } 3124 3125 } 3126 3127 3128 3129 /* Call all required callback functions for the end of a draw */ 3130 3131 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 3132 3133 3134 3135 /* Draw is complete, sorting and filtering must be as well */ 3136 3137 oSettings.bSorted = false; 3138 3139 oSettings.bFiltered = false; 3140 3141 oSettings.bDrawing = false; 3142 3143 3144 3145 if ( oSettings.oFeatures.bServerSide ) 3146 3147 { 3148 3149 _fnProcessingDisplay( oSettings, false ); 3150 3151 if ( !oSettings._bInitComplete ) 3152 3153 { 3154 3155 _fnInitComplete( oSettings ); 3156 3157 } 3158 3159 } 3160 3161 } 3162 3163 3164 3165 3166 3167 /** 3168 3169 * Redraw the table - taking account of the various features which are enabled 3170 3171 * @param {object} oSettings dataTables settings object 3172 3173 * @memberof DataTable#oApi 3174 3175 */ 3176 3177 function _fnReDraw( oSettings ) 3178 3179 { 3180 3181 if ( oSettings.oFeatures.bSort ) 3182 3183 { 3184 3185 /* Sorting will refilter and draw for us */ 3186 3187 _fnSort( oSettings, oSettings.oPreviousSearch ); 3188 3189 } 3190 3191 else if ( oSettings.oFeatures.bFilter ) 3192 3193 { 3194 3195 /* Filtering will redraw for us */ 3196 3197 _fnFilterComplete( oSettings, oSettings.oPreviousSearch ); 3198 3199 } 3200 3201 else 3202 3203 { 3204 3205 _fnCalculateEnd( oSettings ); 3206 3207 _fnDraw( oSettings ); 3208 3209 } 3210 3211 } 3212 3213 3214 3215 3216 3217 /** 3218 3219 * Add the options to the page HTML for the table 3220 3221 * @param {object} oSettings dataTables settings object 3222 3223 * @memberof DataTable#oApi 3224 3225 */ 3226 3227 function _fnAddOptionsHtml ( oSettings ) 3228 3229 { 3230 3231 /* 3232 3233 * Create a temporary, empty, div which we can later on replace with what we have generated 3234 3235 * we do it this way to rendering the 'options' html offline - speed :-) 3236 3237 */ 3238 3239 var nHolding = $('<div></div>')[0]; 3240 3241 oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable ); 3242 3243 3244 3245 /* 3246 3247 * All DataTables are wrapped in a div 3248 3249 */ 3250
3251 oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0]; 3252 3253 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 3254 3255 3256 3257 /* Track where we want to insert the option */ 3258 3259 var nInsertNode = oSettings.nTableWrapper; 3260 3261 3262 3263 /* Loop over the user set positioning and place the elements as needed */ 3264 3265 var aDom = oSettings.sDom.split(''); 3266 3267 var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j; 3268 3269 for ( var i=0 ; i<aDom.length ; i++ ) 3270 3271 { 3272 3273 iPushFeature = 0; 3274 3275 cOption = aDom[i]; 3276 3277 3278 3279 if ( cOption == '<' ) 3280 3281 { 3282 3283 /* New container div */ 3284 3285 nNewNode = $('<div></div>')[0]; 3286 3287 3288 3289 /* Check to see if we should append an id and/or a class name to the container */ 3290 3291 cNext = aDom[i+1]; 3292 3293 if ( cNext == "'" || cNext == '"' ) 3294 3295 { 3296 3297 sAttr = ""; 3298 3299 j = 2; 3300 3301 while ( aDom[i+j] != cNext ) 3302 3303 { 3304 3305 sAttr += aDom[i+j]; 3306 3307 j++; 3308 3309 } 3310 3311 3312 3313 /* Replace jQuery UI constants */ 3314 3315 if ( sAttr == "H" ) 3316 3317 { 3318 3319 sAttr = oSettings.oClasses.sJUIHeader; 3320 3321 } 3322 3323 else if ( sAttr == "F" ) 3324 3325 { 3326 3327 sAttr = oSettings.oClasses.sJUIFooter; 3328 3329 } 3330 3331 3332 3333 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 3334 3335 * breaks the string into parts and applies them as needed 3336 3337 */ 3338 3339 if ( sAttr.indexOf('.') != -1 ) 3340 3341 { 3342 3343 var aSplit = sAttr.split('.'); 3344 3345 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 3346 3347 nNewNode.className = aSplit[1]; 3348 3349 } 3350 3351 else if ( sAttr.charAt(0) == "#" ) 3352 3353 { 3354 3355 nNewNode.id = sAttr.substr(1, sAttr.length-1); 3356 3357 } 3358 3359 else 3360 3361 { 3362 3363 nNewNode.className = sAttr; 3364 3365 } 3366 3367 3368 3369 i += j; /* Move along the position array */ 3370 3371 } 3372 3373 3374 3375 nInsertNode.appendChild( nNewNode ); 3376 3377 nInsertNode = nNewNode; 3378 3379 } 3380 3381 else if ( cOption == '>' ) 3382 3383 { 3384 3385 /* End container div */ 3386
3387 nInsertNode = nInsertNode.parentNode; 3388 3389 } 3390 3391 else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange ) 3392 3393 { 3394 3395 /* Length */ 3396 3397 nTmp = _fnFeatureHtmlLength( oSettings ); 3398 3399 iPushFeature = 1; 3400 3401 } 3402 3403 else if ( cOption == 'f' && oSettings.oFeatures.bFilter ) 3404 3405 { 3406 3407 /* Filter */ 3408 3409 nTmp = _fnFeatureHtmlFilter( oSettings ); 3410 3411 iPushFeature = 1; 3412 3413 } 3414 3415 else if ( cOption == 'r' && oSettings.oFeatures.bProcessing ) 3416 3417 { 3418 3419 /* pRocessing */ 3420 3421 nTmp = _fnFeatureHtmlProcessing( oSettings ); 3422 3423 iPushFeature = 1; 3424 3425 } 3426 3427 else if ( cOption == 't' ) 3428 3429 { 3430 3431 /* Table */ 3432 3433 nTmp = _fnFeatureHtmlTable( oSettings ); 3434 3435 iPushFeature = 1; 3436 3437 } 3438 3439 else if ( cOption == 'i' && oSettings.oFeatures.bInfo ) 3440 3441 { 3442 3443 /* Info */ 3444 3445 nTmp = _fnFeatureHtmlInfo( oSettings ); 3446 3447 iPushFeature = 1; 3448 3449 } 3450 3451 else if ( cOption == 'p' && oSettings.oFeatures.bPaginate ) 3452 3453 { 3454 3455 /* Pagination */ 3456 3457 nTmp = _fnFeatureHtmlPaginate( oSettings ); 3458 3459 iPushFeature = 1; 3460 3461 } 3462 3463 else if ( DataTable.ext.aoFeatures.length !== 0 ) 3464 3465 { 3466 3467 /* Plug-in features */ 3468 3469 var aoFeatures = DataTable.ext.aoFeatures; 3470 3471 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 3472 3473 { 3474 3475 if ( cOption == aoFeatures[k].cFeature ) 3476 3477 { 3478 3479 nTmp = aoFeatures[k].fnInit( oSettings ); 3480 3481 if ( nTmp ) 3482 3483 { 3484 3485 iPushFeature = 1; 3486 3487 } 3488 3489 break; 3490 3491 } 3492 3493 } 3494 3495 } 3496 3497 3498 3499 /* Add to the 2D features array */ 3500 3501 if ( iPushFeature == 1 && nTmp !== null ) 3502 3503 { 3504 3505 if ( typeof oSettings.aanFeatures[cOption] !== 'object' ) 3506 3507 { 3508 3509 oSettings.aanFeatures[cOption] = []; 3510 3511 } 3512 3513 oSettings.aanFeatures[cOption].push( nTmp ); 3514 3515 nInsertNode.appendChild( nTmp ); 3516 3517 } 3518 3519 } 3520 3521 3522 3523 /* Built our DOM structure - replace the holding div with what we want */ 3524 3525 nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding ); 3526 3527 } 3528 3529 3530 3531 3532 3533 /** 3534 3535 * Use the DOM source to create up an array of header cells. The idea here is to 3536 3537 * create a layout grid (array) of rows x columns, which contains a reference 3538 3539 * to the cell that that point in the grid (regardless of col/rowspan), such that 3540 3541 * any column / row could be removed and the new grid constructed 3542 3543 * @param array {object} aLayout Array to store the calculated layout in 3544 3545 * @param {node} nThead The header/footer element for the table 3546 3547 * @memberof DataTable#oApi 3548 3549 */ 3550 3551 function _fnDetectHeader ( aLayout, nThead ) 3552 3553 { 3554 3555 var nTrs = $(nThead).children('tr'); 3556 3557 var nTr, nCell; 3558 3559 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 3560 3561 var bUnique; 3562 3563 var fnShiftCol = function ( a, i, j ) { 3564 3565 var k = a[i]; 3566 3567 while ( k[j] ) { 3568 3569 j++; 3570 3571 } 3572 3573 return j; 3574 3575 }; 3576 3577 3578 3579 aLayout.splice( 0, aLayout.length ); 3580 3581 3582 3583 /* We know how many rows there are in the layout - so prep it */ 3584 3585 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3586 3587 { 3588 3589 aLayout.push( [] ); 3590 3591 } 3592 3593 3594 3595 /* Calculate a layout array */ 3596 3597 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 3598 3599 { 3600 3601 nTr = nTrs[i]; 3602 3603 iColumn = 0; 3604 3605 3606 3607 /* For every cell in the row... */ 3608 3609 nCell = nTr.firstChild; 3610 3611 while ( nCell ) { 3612 3613 if ( nCell.nodeName.toUpperCase() == "TD" || 3614 3615 nCell.nodeName.toUpperCase() == "TH" ) 3616 3617 { 3618 3619 /* Get the col and rowspan attributes from the DOM and sanitise them */ 3620 3621 iColspan = nCell.getAttribute('colspan') * 1; 3622 3623 iRowspan = nCell.getAttribute('rowspan') * 1; 3624 3625 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 3626 3627 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 3628 3629 3630 3631 /* There might be colspan cells already in this row, so shift our target 3632 3633 * accordingly 3634 3635 */ 3636 3637 iColShifted = fnShiftCol( aLayout, i, iColumn ); 3638 3639 3640 3641 /* Cache calculation for unique columns */ 3642 3643 bUnique = iColspan === 1 ? true : false; 3644 3645 3646 3647 /* If there is col / rowspan, copy the information into the layout grid */ 3648 3649 for ( l=0 ; l<iColspan ; l++ ) 3650 3651 { 3652 3653 for ( k=0 ; k<iRowspan ; k++ ) 3654 3655 { 3656 3657 aLayout[i+k][iColShifted+l] = { 3658 3659 "cell": nCell, 3660 3661 "unique": bUnique 3662 3663 }; 3664 3665 aLayout[i+k].nTr = nTr; 3666 3667 } 3668 3669 } 3670 3671 } 3672 3673 nCell = nCell.nextSibling; 3674 3675 } 3676 3677 } 3678 3679 } 3680 3681 3682 3683 3684 3685 /** 3686 3687 * Get an array of unique th elements, one for each column 3688 3689 * @param {object} oSettings dataTables settings object 3690 3691 * @param {node} nHeader automatically detect the layout from this node - optional 3692 3693 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 3694 3695 * @returns array {node} aReturn list of unique th's 3696 3697 * @memberof DataTable#oApi 3698 3699 */ 3700 3701 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 3702 3703 { 3704 3705 var aReturn = []; 3706 3707 if ( !aLayout ) 3708 3709 { 3710 3711 aLayout = oSettings.aoHeader; 3712 3713 if ( nHeader ) 3714 3715 { 3716 3717 aLayout = []; 3718 3719 _fnDetectHeader( aLayout, nHeader ); 3720 3721 } 3722 3723 } 3724 3725 3726 3727 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 3728 3729 { 3730 3731 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 3732 3733 { 3734 3735 if ( aLayout[i][j].unique && 3736 3737 (!aReturn[j] || !oSettings.bSortCellsTop) ) 3738 3739 { 3740 3741 aReturn[j] = aLayout[i][j].cell; 3742 3743 } 3744 3745 } 3746 3747 } 3748 3749 3750 3751 return aReturn; 3752 3753 } 3754 3755 3756 3757 3758 3759 3760 3761 /** 3762 3763 * Update the table using an Ajax call 3764 3765 * @param {object} oSettings dataTables settings object 3766 3767 * @returns {boolean} Block the table drawing or not 3768 3769 * @memberof DataTable#oApi 3770 3771 */ 3772 3773 function _fnAjaxUpdate( oSettings ) 3774 3775 { 3776 3777 if ( oSettings.bAjaxDataGet ) 3778 3779 { 3780 3781 oSettings.iDraw++; 3782 3783 _fnProcessingDisplay( oSettings, true ); 3784 3785 var iColumns = oSettings.aoColumns.length; 3786 3787 var aoData = _fnAjaxParameters( oSettings ); 3788 3789 _fnServerParams( oSettings, aoData ); 3790 3791 3792 3793 oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, ao
3793Data, 3794 3795 function(json) { 3796 3797 _fnAjaxUpdateDraw( oSettings, json ); 3798 3799 }, oSettings ); 3800 3801 return false; 3802 3803 } 3804 3805 else 3806 3807 { 3808 3809 return true; 3810 3811 } 3812 3813 } 3814 3815 3816 3817 3818 3819 /** 3820 3821 * Build up the parameters in an object needed for a server-side processing request 3822 3823 * @param {object} oSettings dataTables settings object 3824 3825 * @returns {bool} block the table drawing or not 3826 3827 * @memberof DataTable#oApi 3828 3829 */ 3830 3831 function _fnAjaxParameters( oSettings ) 3832 3833 { 3834 3835 var iColumns = oSettings.aoColumns.length; 3836 3837 var aoData = [], mDataProp, aaSort, aDataSort; 3838 3839 var i, j; 3840 3841 3842 3843 aoData.push( { "name": "sEcho", "value": oSettings.iDraw } ); 3844 3845 aoData.push( { "name": "iColumns", "value": iColumns } ); 3846 3847 aoData.push( { "name": "sColumns", "value": _fnColumnOrdering(oSettings) } ); 3848 3849 aoData.push( { "name": "iDisplayStart", "value": oSettings._iDisplayStart } ); 3850 3851 aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ? 3852 3853 oSettings._iDisplayLength : -1 } ); 3854 3855 3856 3857 for ( i=0 ; i<iColumns ; i++ ) 3858 3859 { 3860 3861 mDataProp = oSettings.aoColumns[i].mData; 3862 3863 aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } ); 3864 3865 } 3866 3867 3868 3869 /* Filtering */ 3870 3871 if ( oSettings.oFeatures.bFilter !== false ) 3872 3873 { 3874 3875 aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } ); 3876 3877 aoData.push( { "name": "bRegex", "value": oSettings.oPreviousSearch.bRegex } ); 3878 3879 for ( i=0 ; i<iColumns ; i++ ) 3880 3881 { 3882 3883 aoData.push( { "name": "sSearch_"+i, "value": oSettings.aoPreSearchCols[i].sSearch } ); 3884 3885 aoData.push( { "name": "bRegex_"+i, "value": oSettings.aoPreSearchCols[i].bRegex } ); 3886 3887 aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } ); 3888 3889 } 3890 3891 } 3892 3893 3894 3895 /* Sorting */ 3896 3897 if ( oSettings.oFeatures.bSort !== false ) 3898 3899 { 3900 3901 var iCounter = 0; 3902 3903 3904 3905 aaSort = ( oSettings.aaSortingFixed !== null ) ? 3906 3907 oSettings.aaSortingFixed.concat( oSettings.aaSorting ) : 3908 3909 oSettings.aaSorting.slice(); 3910 3911 3912 3913 for ( i=0 ; i<aaSort.length ; i++ ) 3914 3915 { 3916 3917 aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort; 3918 3919 3920 3921 for ( j=0 ; j<aDataSort.length ; j++ ) 3922 3923 { 3924 3925 aoData.push( { "name": "iSortCol_"+iCounter, "value": aDataSort[j] } ); 3926 3927 aoData.push( { "name": "sSortDir_"+iCounter, "value": aaSort[i][1] } ); 3928 3929 iCounter++; 3930 3931 } 3932 3933 } 3934 3935 aoData.push( { "name": "iSortingCols", "value": iCounter } ); 3936 3937 3938 3939 for ( i=0 ; i<iColumns ; i++ ) 3940 3941 { 3942 3943 aoData.push( { "name": "bSortable_"+i, "value": oSettings.aoColumns[i].bSortable } ); 3944 3945 } 3946 3947 } 3948 3949 3950 3951 return aoData; 3952 3953 } 3954 3955 3956 3957 3958 3959 /** 3960 3961 * Add Ajax parameters from plug-ins 3962 3963 * @param {object} oSettings dataTables settings object 3964 3965 * @param array {objects} aoData name/value pairs to send to the server 3966 3967 * @memberof DataTable#oApi 3968 3969 */ 3970 3971 function _fnServerParams( oSettings, aoData ) 3972 3973 { 3974 3975 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] ); 3976 3977 } 3978 3979 3980 3981 3982 3983 /** 3984 3985 * Data the data from the server (nuking the old) and redraw the table 3986 3987 * @param {object} oSettings dataTables settings object 3988 3989 * @param {object} json json data return from the server. 3990 3991 * @param {string} json.sEcho Tracking flag for DataTables to match requests 3992 3993 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 3994 3995 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 3996 3997 * @param {array} json.aaData The data to display on this page 3998 3999 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 4000 4001 * @memberof DataTable#oApi 4002 4003 */ 4004 4005 function _fnAjaxUpdateDraw ( oSettings, json ) 4006 4007 { 4008 4009 if ( json.sEcho !== undefined ) 4010 4011 { 4012 4013 /* Protect against old returns over-writing a new one. Possible when you get
4014 4015 * very fast interaction, and later queries are completed much faster 4016 4017 */ 4018 4019 if ( json.sEcho*1 < oSettings.iDraw ) 4020 4021 { 4022 4023 return; 4024 4025 } 4026 4027 else 4028 4029 { 4030 4031 oSettings.iDraw = json.sEcho * 1; 4032 4033 } 4034 4035 } 4036 4037 4038 4039 if ( !oSettings.oScroll.bInfinite || 4040 4041 (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) ) 4042 4043 { 4044 4045 _fnClearTable( oSettings ); 4046 4047 } 4048 4049 oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10); 4050 4051 oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10); 4052 4053 4054 4055 /* Determine if reordering is required */ 4056 4057 var sOrdering = _fnColumnOrdering(oSettings); 4058 4059 var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering ); 4060 4061 var aiIndex; 4062 4063 if ( bReOrder ) 4064 4065 { 4066 4067 aiIndex = _fnReOrderIndex( oSettings, json.sColumns ); 4068 4069 } 4070 4071 4072 4073 var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json ); 4074 4075 for ( var i=0, iLen=aData.length ; i<iLen ; i++ ) 4076 4077 { 4078 4079 if ( bReOrder ) 4080 4081 { 4082 4083 /* If we need to re-order, then create a new array with the correct order and add it */ 4084 4085 var aDataSorted = []; 4086 4087 for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ ) 4088 4089 { 4090 4091 aDataSorted.push( aData[i][ aiIndex[j] ] ); 4092 4093 } 4094 4095 _fnAddData( oSettings, aDataSorted ); 4096 4097 } 4098 4099 else 4100 4101 { 4102 4103 /* No re-order required, sever got it "right" - just straight add */ 4104 4105 _fnAddData( oSettings, aData[i] ); 4106 4107 } 4108 4109 } 4110 4111 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 4112 4113 4114 4115 oSettings.bAjaxDataGet = false; 4116 4117 _fnDraw( oSettings ); 4118 4119 oSettings.bAjaxDataGet = true; 4120 4121 _fnProcessingDisplay( oSettings, false ); 4122 4123 } 4124 4125 4126 4127 4128 4129 4130 4131 /** 4132 4133 * Generate the node required for filtering text 4134 4135 * @returns {node} Filter control element 4136 4137 * @param {object} oSettings dataTables settings object 4138 4139 * @memberof DataTable#oApi 4140 4141 */ 4142 4143 function _fnFeatureHtmlFilter ( oSettings ) 4144 4145 { 4146 4147 var oPreviousSearch = oSettings.oPreviousSearch; 4148 4149 4150 4151 var sSearchStr = oSettings.oLanguage.sSearch; 4152 4153 sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ? 4154 4155 sSearchStr.replace('_INPUT_', '<input type="text" />') : 4156 4157 sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />'; 4158 4159 4160 4161 var nFilter = document.createElement( 'div' ); 4162 4163 nFilter.className = oSettings.oClasses.sFilter; 4164 4165 nFilter.innerHTML = '<label>'+sSearchStr+'</label>'; 4166 4167 if ( !oSettings.aanFeatures.f ) 4168 4169 { 4170 4171 nFilter.id = oSettings.sTableId+'_filter'; 4172 4173 } 4174 4175 4176 4177 var jqFilter = $('input[type="text"]', nFilter); 4178 4179 4180 4181 // Store a reference to the input element, so other input elements could be 4182 4183 // added to the filter wrapper if needed (submit button for example) 4184 4185 nFilter._DT_Input = jqFilter[0]; 4186 4187 4188 4189 jqFilter.val( oPreviousSearch.sSearch.replace('"','"') ); 4190 4191 jqFilter.bind( 'keyup.DT', function(e) { 4192 4193 /* Update all other filter input elements for the new display */ 4194 4195 var n = oSettings.aanFeatures.f; 4196 4197 var val = this.value==="" ? "" : this.value; // mental IE8 fix :-( 4198 4199 4200 4201 for ( var i=0, iLen=n.length ; i<iLen ; i++ ) 4202 4203 { 4204 4205 if ( n[i] != $(this).parents('div.dataTables_filter')[0] ) 4206 4207 { 4208 4209 $(n[i]._DT_Input).val( val ); 4210 4211 } 4212 4213 } 4214 4215 4216 4217 /* Now do the filter */ 4218 4219 if ( val != oPreviousSearch.sSearch ) 4220 4221 { 4222 4223 _fnFilterComplete( oSettings, { 4224 4225 "sSearch": val, 4226 4227 "bRegex": oPreviousSearch.bRegex, 4228 4229 "bSmart": oPreviousSearch.bSmart , 4230 4231 "bCaseInsensitive": oPreviousSearch.bCaseInsensitive 4232 4233 } ); 4234 4235 } 4236 4237 } ); 4238 4239 4240 4241 jqFilter 4242 4243 .attr('aria-controls', oSettings.sTableId) 4244 4245 .bind( 'keypress.DT', function(e) { 4246 4247 /* Prevent form submission */ 4248 4249 if ( e.keyCode == 13 ) 4250 4251 { 4252 4253 return false; 4254 4255 } 4256 4257 } 4258 4259 ); 4260 4261 4262 4263 return nFilter; 4264 4265 } 4266 4267 4268 4269 4270 4271 /** 4272 4273 * Filter the table using both the global filter and column based filtering 4274 4275 * @param {object} oSettings dataTables settings object 4276 4277 * @param {object} oSearch search information 4278 4279 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 4280 4281 * @memberof DataTable#oApi 4282 4283 */ 4284 4285 function _fnFilterComplete ( oSettings, oInput, iForce ) 4286 4287 { 4288 4289 var oPrevSearch = oSettings.oPreviousSearch; 4290 4291 var aoPrevSearch = oSettings.aoPreSearchCols; 4292 4293 var fnSaveFilter = function ( oFilter ) { 4294 4295 /* Save the filtering values */ 4296 4297 oPrevSearch.sSearch = oFilter.sSearch; 4298 4299 oPrevSearch.bRegex = oFilter.bRegex; 4300 4301 oPrevSearch.bSmart = oFilter.bSmart; 4302 4303 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 4304 4305 }; 4306 4307 4308 4309 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 4310 4311 if ( !oSettings.oFeatures.bServerSide ) 4312 4313 { 4314 4315 /* Global filter */ 4316 4317 _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive ); 4318 4319 fnSaveFilter( oInput ); 4320 4321 4322 4323 /* Now do the individual column filter */ 4324 4325 for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ ) 4326 4327 { 4328 4329 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex, 4330 4331 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 4332 4333 } 4334 4335 4336 4337 /* Custom filtering */ 4338 4339 _fnFilterCustom( oSettings ); 4340 4341 } 4342 4343 else 4344 4345 { 4346 4347 fnSaveFilter( oInput ); 4348 4349 } 4350 4351 4352 4353 /* Tell the draw function we have been filtering */ 4354 4355 oSettings.bFiltered = true; 4356 4357 $(oSettings.oInstance).trigger('filter', oSettings); 4358 4359 4360langleywa 4361 /* Redraw the table */ 4362 4363 oSettings._iDisplayStart = 0; 4364 4365 _fnCalculateEnd( oSettings ); 4366 4367 _fnDraw( oSettings ); 4368 4369 4370 4371 /* Rebuild search array 'offline' */ 4372 4373 _fnBuildSearchArray( oSettings, 0 ); 4374 4375 } 4376 4377 4378 4379 4380 4381 /** 4382 4383 * Apply custom filtering functions 4384 4385 * @param {object} oSettings dataTables settings object 4386 4387 * @memberof DataTable#oApi 4388 4389 */ 4390 4391 function _fnFilterCustom( oSettings ) 4392 4393 { 4394 4395 var afnFilters = DataTable.ext.afnFiltering; 4396 4397 var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' ); 4398 4399 4400 4401 for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ ) 4402 4403 { 4404 4405 var iCorrector = 0; 4406
4407 for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ ) 4408 4409 { 4410 4411 var iDisIndex = oSettings.aiDisplay[j-iCorrector]; 4412 4413 var bTest = afnFilters[i]( 4414 4415 oSettings, 4416 4417 _fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ), 4418 4419 iDisIndex 4420 4421 ); 4422 4423 4424 4425 /* Check if we should use this row based on the filtering function */ 4426 4427 if ( !bTest ) 4428 4429 { 4430 4431 oSettings.aiDisplay.splice( j-iCorrector, 1 ); 4432 4433 iCorrector++; 4434 4435 } 4436 4437 } 4438 4439 } 4440 4441 } 4442 4443 4444 4445 4446 4447 /** 4448 4449 * Filter the table on a per-column basis 4450 4451 * @param {object} oSettings dataTables settings object 4452 4453 * @param {string} sInput string to filter on 4454 4455 * @param {int} iColumn column to filter 4456 4457 * @param {bool} bRegex treat search string as a regular expression or not 4458 4459 * @param {bool} bSmart use smart filtering or not 4460 4461 * @param {bool} bCaseInsensitive Do case insenstive matching or not 4462 4463 * @memberof DataTable#oApi 4464 4465 */ 4466 4467 function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive ) 4468 4469 { 4470 4471 if ( sInput === "" ) 4472 4473 { 4474 4475 return; 4476 4477 } 4478 4479 4480 4481 var iIndexCorrector = 0; 4482 4483 var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive ); 4484 4485 4486 4487 for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- ) 4488 4489 { 4490 4491 var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ), 4492 4493 oSettings.aoColumns[iColumn].sType ); 4494 4495 if ( ! rpSearch.test( sData ) ) 4496 4497 { 4498 4499 oSettings.aiDisplay.splice( i, 1 ); 4500 4501 iIndexCorrector++; 4502 4503 } 4504 4505 } 4506 4507 } 4508 4509 4510 4511 4512 4513 /** 4514 4515 * Filter the data table based on user input and draw the table 4516 4517 * @param {object} oSettings dataTables settings object 4518 4519 * @param {string} sInput string to filter on 4520 4521 * @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0) 4522 4523 * @param {bool} bRegex treat as a regular expression or not 4524 4525 * @param {bool} bSmart perform smart filtering or not 4526 4527 * @param {bool} bCaseInsensitive Do case insenstive matching or not 4528 4529 * @memberof DataTable#oApi 4530 4531 */ 4532 4533 function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive ) 4534 4535 { 4536 4537 var i; 4538 4539 var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive ); 4540 4541 var oPrevSearch = oSettings.oPreviousSearch; 4542 4543 4544 4545 /* Check if we are forcing or not - optional parameter */ 4546 4547 if ( !iForce ) 4548 4549 { 4550 4551 iForce = 0; 4552 4553 } 4554 4555 4556 4557 /* Need to take account of custom filtering functions - always filter */ 4558 4559 if ( DataTable.ext.afnFiltering.length !== 0 ) 4560 4561 { 4562 4563 iForce = 1; 4564 4565 } 4566 4567 4568 4569 /* 4570 4571 * If the input is blank - we want the full data set 4572 4573 */ 4574 4575 if ( sInput.length <= 0 ) 4576 4577 { 4578 4579 oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length); 4580 4581 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 4582 4583 } 4584 4585 else 4586 4587 { 4588 4589 /* 4590 4591 * We are starting a new search or the new search string is smaller 4592 4593 * then the old one (i.e. delete). Search from the master array 4594 4595 */ 4596 4597 if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length || 4598 4599 oPrevSearch.sSearch.length > sInput.length || iForce == 1 || 4600 4601 sInput.indexOf(oPrevSearch.sSearch) !== 0 ) 4602 4603 { 4604 4605 /* Nuke the old display array - we are going to rebuild it */ 4606 4607 oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length); 4608 4609 4610 4611 /* Force a rebuild of the search array */ 4612 4613 _fnBuildSearchArray( oSettings, 1 ); 4614 4615 4616 4617 /* Search through all records to populate the search array 4618 4619 * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 4620 4621 * mapping 4622 4623 */ 4624 4625 for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ ) 4626 4627 { 4628 4629 if ( rpSearch.test(oSettings.asDataSearch[i]) ) 4630 4631 { 4632 4633 oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] ); 4634 4635 } 4636 4637 } 4638 4639 } 4640 4641 else 4642 4643 { 4644 4645 /* Using old search array - refine it - do it this way for speed 4646 4647 * Don't have to search the whole master array again 4648 4649 */ 4650 4651 var iIndexCorrector = 0; 4652 4653 4654 4655 /* Search the current results */ 4656 4657 for ( i=0 ; i<oSettings.asDataSearch.length ; i++ ) 4658 4659 { 4660 4661 if ( ! rpSearch.test(oSettings.asDataSearch[i]) ) 4662 4663 { 4664 4665 oSettings.aiDisplay.splice( i-iIndexCorrector, 1 ); 4666 4667 iIndexCorrector++; 4668 4669 } 4670 4671 } 4672 4673 } 4674 4675 } 4676 4677 } 4678 4679 4680 4681 4682 4683 /** 4684 4685 * Create an array which can be quickly search through 4686 4687 * @param {object} oSettings dataTables settings object 4688 4689 * @param {int} iMaster use the master data array - optional 4690 4691 * @memberof DataTable#oApi 4692 4693 */ 4694 4695 function _fnBuildSearchArray ( oSettings, iMaster ) 4696 4697 { 4698 4699 if ( !oSettings.oFeatures.bServerSide ) 4700 4701 { 4702 4703 /* Clear out the old data */ 4704 4705 oSettings.asDataSearch = []; 4706 4707 4708 4709 var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' ); 4710 4711 var aiIndex = (iMaster===1) ? 4712 4713 oSettings.aiDisplayMaster : 4714 4715 oSettings.aiDisplay; 4716 4717 4718 4719 for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ ) 4720 4721 { 4722 4723 oSettings.asDataSearch[i] = _fnBuildSearchRow( 4724 4725 oSettings, 4726 4727 _fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns ) 4728 4729 ); 4730 4731 } 4732 4733 } 4734 4735 } 4736 4737 4738 4739 4740 4741 /** 4742 4743 * Create a searchable string from a single data row 4744 4745 * @param {object} oSettings dataTables settings object 4746 4747 * @param {array} aData Row data array to use for the data to search 4748 4749 * @memberof DataTable#oApi 4750 4751 */ 4752 4753 function _fnBuildSearchRow( oSettings, aData ) 4754 4755 { 4756 4757 var sSearch = aData.join(' '); 4758 4759 4760 4761 /* If it looks like there is an HTML entity in the string, attempt to decode it */ 4762 4763 if ( sSearch.indexOf('&') !== -1 ) 4764 4765 { 4766 4767 sSearch = $('<div>').html(sSearch).text(); 4768 4769 } 4770 4771 4772 4773 // Strip newline characters 4774 4775 return sSearch.replace( /[\n\r]/g, " " ); 4776 4777 } 4778 4779 4780 4781 /** 4782 4783 * Build a regular expression object suitable for searching a table 4784 4785 * @param {string} sSearch string to search for 4786 4787 * @param {bool} bRegex treat as a regular expression or not 4788 4789 * @param {bool} bSmart perform smart filtering or not 4790 4791 * @param {bool} bCaseInsensitive Do case insensitive matching or not 4792 4793 * @returns {RegExp} constructed object 4794 4795 * @memberof DataTable#oApi 4796 4797 */ 4798 4799 function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive ) 4800 4801 { 4802 4803 var asSearch, sRegExpString; 4804 4805 4806 4807 if ( bSmart ) 4808 4809 { 4810 4811 /* Generate the regular expression to use. Something along the lines of: 4812 4813 * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$ 4814 4815 */ 4816 4817 asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' ); 4818 4819 sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$'; 4820 4821 return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" ); 4822 4823 } 4824 4825 else 4826 4827 { 4828 4829 sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch ); 4830 4831 return new RegExp( sSearch, bCaseInsensitive ? "i" : "" ); 4832 4833 } 4834 4835 } 4836 4837 4838 4839 4840 4841 /** 4842 4843 * Convert raw data into something that the user can search on 4844 4845 * @param {string} sData data to be modified 4846 4847 * @param {string} sType data type 4848 4849 * @returns {string} search string 4850 4851 * @memberof DataTable#oApi 4852 4853 */ 4854 4855 function _fnDataToSearch ( sData, sType ) 4856 4857 { 4858 4859 if ( typeof DataTable.ext.ofnSearch[sType] === "function" ) 4860 4861 { 4862 4863 return DataTable.ext.ofnSearch[sType]( sData ); 4864 4865 } 4866
4867 else if ( sData === null ) 4868langleywa 4869 { 4870 4871 return ''; 4872 4873 } 4874 4875 else if ( sType == "html" ) 4876 4877 { 4878 4879 return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" ); 4880 4881 } 4882 4883 else if ( typeof sData === "string" ) 4884 4885 { 4886 4887 return sData.replace(/[\r\n]/g," "); 4888 4889 } 4890 4891 return sData; 4892 4893 } 4894 4895 4896 4897 4898 4899 /** 4900 4901 * scape a string such that it can be used in a regular expression 4902 4903 * @param {string} sVal string to escape 4904 4905 * @returns {string} escaped string 4906 4907 * @memberof DataTable#oApi 4908 4909 */ 4910 4911 function _fnEscapeRegex ( sVal ) 4912 4913 { 4914 4915 var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ]; 4916 4917 var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' ); 4918 4919 return sVal.replace(reReplace, '\\$1'); 4920 4921 } 4922 4923 4924 4925 4926 4927 /** 4928 4929 * Generate the node required for the info display 4930 4931 * @param {object} oSettings dataTables settings object 4932 4933 * @returns {node} Information element 4934 4935 * @memberof DataTable#oApi 4936 4937 */ 4938 4939 function _fnFeatureHtmlInfo ( oSettings ) 4940 4941 { 4942 4943 var nInfo = document.createElement( 'div' ); 4944 4945 nInfo.className = oSettings.oClasses.sInfo; 4946 4947 4948 4949 /* Actions that are to be taken once only for this feature */ 4950 4951 if ( !oSettings.aanFeatures.i ) 4952 4953 { 4954 4955 /* Add draw callback */ 4956 4957 oSettings.aoDrawCallback.push( { 4958 4959 "fn": _fnUpdateInfo, 4960 4961 "sName": "information" 4962 4963 } ); 4964 4965 4966 4967 /* Add id */ 4968 4969 nInfo.id = oSettings.sTableId+'_info'; 4970 4971 } 4972 4973 oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' ); 4974 4975 4976 4977 return nInfo; 4978 4979 } 4980 4981 4982 4983 4984 4985 /** 4986 4987 * Update the information elements in the display 4988 4989 * @param {object} oSettings dataTables settings object 4990 4991 * @memberof DataTable#oApi 4992 4993 */ 4994 4995 function _fnUpdateInfo ( oSettings ) 4996 4997 { 4998 4999 /* Show information about the table */ 5000 5001 if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 ) 5002 5003 { 5004 5005 return; 5006 5007 } 5008 5009 5010 5011 var 5012 5013 oLang = oSettings.oLanguage, 5014 5015 iStart = oSettings._iDisplayStart+1, 5016 5017 iEnd = oSettings.fnDisplayEnd(), 5018 5019 iMax = oSettings.fnRecordsTotal(), 5020 5021 iTotal = oSettings.fnRecordsDisplay(), 5022 5023 sOut; 5024 5025 5026 5027 if ( iTotal === 0 ) 5028 5029 { 5030 5031 /* Empty record set */ 5032 5033 sOut = oLang.sInfoEmpty; 5034 5035 } 5036 5037 else { 5038 5039 /* Normal record set */ 5040 5041 sOut = oLang.sInfo; 5042 5043 } 5044 5045 5046 5047 if ( iTotal != iMax ) 5048 5049 { 5050 5051 /* Record set after filtering */ 5052 5053 sOut += ' ' + oLang.sInfoFiltered; 5054 5055 } 5056 5057 5058 5059 // Convert the macros 5060 5061 sOut += oLang.sInfoPostFix; 5062 5063 sOut = _fnInfoMacros( oSettings, sOut ); 5064 5065 5066 5067 if ( oLang.fnInfoCallback !== null ) 5068 5069 { 5070 5071 sOut = oLang.fnInfoCallback.call( oSettings.oInstance, 5072 5073 oSettings, iStart, iEnd, iMax, iTotal, sOut ); 5074 5075 } 5076 5077 5078 5079 var n = oSettings.aanFeatures.i; 5080 5081 for ( var i=0, iLen=n.length ; i<iLen ; i++ ) 5082 5083 { 5084 5085 $(n[i]).html( sOut ); 5086 5087 } 5088 5089 } 5090 5091 5092 5093 5094 5095 function _fnInfoMacros ( oSettings, str ) 5096 5097 { 5098 5099 var 5100 5101 iStart = oSettings._iDisplayStart+1, 5102 5103 sStart = oSettings.fnFormatNumber( iStart ), 5104 5105 iEnd = oSettings.fnDisplayEnd(), 5106 5107 sEnd = oSettings.fnFormatNumber( iEnd ), 5108 5109 iTotal = oSettings.fnRecordsDisplay(), 5110 5111 sTotal = oSettings.fnFormatNumber( iTotal ), 5112 5113 iMax = oSettings.fnRecordsTotal(), 5114 5115 sMax = oSettings.fnFormatNumber( iMax ); 5116 5117 5118 5119 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 5120 5121 // internally 5122 5123 if ( oSettings.oScroll.bInfinite ) 5124 5125 { 5126 5127 sStart = oSettings.fnFormatNumber( 1 ); 5128 5129 } 5130 5131 5132 5133 return str. 5134 5135 replace(/_START_/g, sStart). 5136 5137 replace(/_END_/g, sEnd). 5138 5139 replace(/_TOTAL_/g, sTotal). 5140 5141 replace(/_MAX_/g, sMax); 5142 5143 } 5144 5145 5146 5147 5148 5149 5150 5151 /** 5152 5153 * Draw the table for the first time, adding all required features 5154 5155 * @param {object} oSettings dataTables settings object 5156 5157 * @memberof DataTable#oApi 5158 5159 */ 5160 5161 function _fnInitialise ( oSettings ) 5162 5163 { 5164 5165 var i, iLen, iAjaxStart=oSettings.iInitDisplayStart; 5166 5167 5168 5169 /* Ensure that the table data is fully initialised */ 5170
5171 if ( oSettings.bInitialised === false ) 5172 5173 { 5174 5175 setTimeout( function(){ _fnInitialise( oSettings ); }, 200 ); 5176 5177 return; 5178 5179 } 5180 5181 5182 5183 /* Show the display HTML options */ 5184 5185 _fnAddOptionsHtml( oSettings ); 5186 5187 5188 5189 /* Build and draw the header / footer for the table */ 5190 5191 _fnBuildHead( oSettings ); 5192 5193 _fnDrawHead( oSettings, oSettings.aoHeader ); 5194 5195 if ( oSettings.nTFoot ) 5196 5197 { 5198 5199 _fnDrawHead( oSettings, oSettings.aoFooter ); 5200 5201 } 5202 5203 5204 5205 /* Okay to show that something is going on now */ 5206 5207 _fnProcessingDisplay( oSettings, true ); 5208 5209 5210 5211 /* Calculate sizes for columns */ 5212 5213 if ( oSettings.oFeatures.bAutoWidth ) 5214 5215 { 5216 5217 _fnCalculateColumnWidths( oSettings ); 5218 5219 } 5220 5221 5222 5223 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 5224 5225 { 5226 5227 if ( oSettings.aoColumns[i].sWidth !== null ) 5228 5229 { 5230 5231 oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth ); 5232 5233 } 5234 5235 } 5236 5237 5238 5239 /* If there is default sorting required - let's do it. The sort function will do the 5240 5241 * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows 5242 5243 * the table to look initialised for Ajax sourcing data (show 'loading' message possibly) 5244 5245 */ 5246 5247 if ( oSettings.oFeatures.bSort ) 5248 5249 { 5250 5251 _fnSort( oSettings ); 5252 5253 } 5254 5255 else if ( oSettings.oFeatures.bFilter ) 5256 5257 { 5258 5259 _fnFilterComplete( oSettings, oSettings.oPreviousSearch ); 5260 5261 } 5262 5263 else 5264 5265 { 5266 5267 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 5268 5269 _fnCalculateEnd( oSettings ); 5270 5271 _fnDraw( oSettings ); 5272 5273 } 5274 5275 5276 5277 /* if there is an ajax source load the data */ 5278 5279 if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide ) 5280 5281 { 5282 5283 var aoData = []; 5284 5285 _fnServerParams( oSettings, aoData ); 5286 5287 oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) { 5288 5289 var aData = (oSettings.sAjaxDataProp !== "") ? 5290 5291 _fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json; 5292 5293 5294 5295 /* Got the data - add it to the table */ 5296 5297 for ( i=0 ; i<aData.length ; i++ ) 5298 5299 { 5300 5301 _fnAddData( oSettings, aData[i] ); 5302 5303 } 5304 5305 5306 5307 /* Reset the init display for cookie saving. We've already done a filter, and 5308 5309 * therefore cleared it before. So we need to make it appear 'fresh' 5310 5311 */ 5312 5313 oSettings.iInitDisplayStart = iAjaxStart; 5314 5315 5316 5317 if ( oSettings.oFeatures.bSort ) 5318 5319 { 5320 5321 _fnSort( oSettings ); 5322 5323 } 5324 5325 else 5326 5327 { 5328 5329 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 5330 5331 _fnCalculateEnd( oSettings ); 5332 5333 _fnDraw( oSettings ); 5334 5335 } 5336 5337 5338 5339 _fnProcessingDisplay( oSettings, false ); 5340 5341 _fnInitComplete( oSettings, json ); 5342 5343 }, oSettings ); 5344 5345 return; 5346 5347 } 5348 5349 5350 5351 /* Server-side processing initialisation complete is done at the end of _fnDraw */ 5352 5353 if ( !oSettings.oFeatures.bServerSide ) 5354 5355 { 5356 5357 _fnProcessingDisplay( oSettings, false ); 5358 5359 _fnInitComplete( oSettings ); 5360 5361 } 5362 5363 } 5364 5365 5366 5367 5368 5369 /** 5370 5371 * Draw the table for the first time, adding all required features 5372 5373 * @param {object} oSettings dataTables settings object 5374 5375 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 5376 5377 * with client-side processing (optional) 5378 5379 * @memberof DataTable#oApi 5380 5381 */ 5382 5383 function _fnInitComplete ( oSettings, json ) 5384 5385 { 5386 5387 oSettings._bInitComplete = true; 5388 5389 _fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] ); 5390 5391 } 5392 5393 5394 5395 5396 5397 /** 5398 5399 * Language compatibility - when certain options are given, and others aren't, we 5400 5401 * need to duplicate the values over, in order to provide backwards compatibility 5402 5403 * with older language files. 5404 5405 * @param {object} oSettings dataTables settings object 5406 5407 * @memberof DataTable#oApi 5408 5409 */ 5410 5411 function _fnLanguageCompat( oLanguage ) 5412 5413 { 5414 5415 var oDefaults = DataTable.defaults.oLanguage; 5416 5417 5418 5419 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as 5420 5421 * sZeroRecords - assuming that is given. 5422 5423 */ 5424 5425 if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords && 5426 5427 oDefaults.sEmptyTable === "No data available in table" ) 5428 5429 { 5430 5431 _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' ); 5432 5433 } 5434 5435 5436 5437 /* Likewise with loading records */ 5438 5439 if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords && 5440 5441 oDefaults.sLoadingRecords === "Loading..." ) 5442 5443 { 5444 5445 _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' ); 5446 5447 } 5448 5449 } 5450 5451 5452 5453 5454 5455 5456 5457 /** 5458 5459 * Generate the node required for user display length changing 5460 5461 * @param {object} oSettings dataTables settings object 5462 5463 * @returns {node} Display length feature node 5464 5465 * @memberof DataTable#oApi 5466 5467 */ 5468 5469 function _fnFeatureHtmlLength ( oSettings ) 5470 5471 { 5472 5473 if ( oSettings.oScroll.bInfinite ) 5474 5475 { 5476 5477 return null; 5478 5479 } 5480 5481 5482 5483 /* This can be overruled by not using the _MENU_ var/macro in the language variable */ 5484 5485 var sName = 'name="'+oSettings.sTableId+'_length"'; 5486 5487 var sStdMenu = '<select id="e1" size="1" '+sName+'>'; 5488 5489 var i, iLen; 5490 5491 var aLengthMenu = oSettings.aLengthMenu; 5492 5493 5494 5495 if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && 5496 5497 typeof aLengthMenu[1] === 'object' ) 5498 5499 { 5500 5501 for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ ) 5502 5503 { 5504 5505 sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>'; 5506 5507 } 5508 5509 } 5510 5511 else 5512 5513 { 5514 5515 for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ ) 5516 5517 { 5518 5519 sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>'; 5520 5521 } 5522 5523 } 5524 5525 sStdMenu += '</select>'; 5526 5527 5528 5529 var nLength = document.createElement( 'div' ); 5530 5531 if ( !oSettings.aanFeatures.l ) 5532 5533 { 5534 5535 nLength.id = oSettings.sTableId+'_length'; 5536 5537 } 5538 5539 nLength.className = oSettings.oClasses.sLength; 5540 5541 nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>'; 5542 5543 5544 5545 /* 5546 5547 * Set the length to the current display length - thanks to Andrea Pavlovic for this fix, 5548 5549 * and Stefan Skopnik for fixing the fix! 5550 5551 */ 5552 5553 $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true); 5554 5555 5556 5557 $('select', nLength).bind( 'change.DT', function(e) { 5558 5559 var iVal = $(this).val(); 5560 5561 5562
5563 /* Update all other length options for the new display */ 5564 5565 var n = oSettings.aanFeatures.l; 5566 5567 for ( i=0, iLen=n.length ; i<iLen ; i++ ) 5568 5569 { 5570 5571 if ( n[i] != this.parentNode ) 5572 5573 { 5574 5575 $('select', n[i]).val( iVal ); 5576 5577 } 5578 5579 } 5580 5581 5582 5583 /* Redraw the table */ 5584 5585 oSettings._iDisplayLength = parseInt(iVal, 10); 5586 5587 _fnCalculateEnd( oSettings ); 5588 5589 5590 5591 /* If we have space to show extra rows (backing up from the end point - then do so */ 5592 5593 if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) 5594 5595 { 5596 5597 oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength; 5598 5599 if ( oSettings._iDisplayStart < 0 ) 5600 5601 { 5602 5603 oSettings._iDisplayStart = 0; 5604 5605 } 5606 5607 } 5608 5609 5610 5611 if ( oSettings._iDisplayLength == -1 ) 5612 5613 { 5614 5615 oSettings._iDisplayStart = 0; 5616 5617 } 5618 5619 5620 5621 _fnDraw( oSettings ); 5622 5623 } ); 5624 5625 5626 5627 5628 5629 $('select', nLength).attr('aria-controls', oSettings.sTableId); 5630 5631 5632 5633 return nLength; 5634 5635 } 5636 5637 5638 5639 5640 5641 /** 5642 5643 * Recalculate the end point based on the start point 5644 5645 * @param {object} oSettings dataTables settings object 5646 5647 * @memberof DataTable#oApi 5648 5649 */ 5650 5651 function _fnCalculateEnd( oSettings ) 5652 5653 { 5654 5655 if ( oSettings.oFeatures.bPaginate === false ) 5656 5657 { 5658 5659 oSettings._iDisplayEnd = oSettings.aiDisplay.length; 5660 5661 } 5662 5663 else 5664 5665 { 5666 5667 /* Set the end point of the display - based on how many elements there are 5668 5669 * still to display 5670 5671 */ 5672 5673 if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length || 5674 5675 oSettings._iDisplayLength == -1 ) 5676 5677 { 5678 5679 oSettings._iDisplayEnd = oSettings.aiDisplay.length; 5680 5681 } 5682 5683 else 5684 5685 { 5686 5687 oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength; 5688 5689 } 5690 5691 } 5692 5693 } 5694 5695 5696 5697 5698 5699 5700 5701 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 5702 5703 * Note that most of the paging logic is done in 5704 5705 * DataTable.ext.oPagination 5706 5707 */ 5708 5709 5710 5711 /** 5712 5713 * Generate the node required for default pagination 5714 5715 * @param {object} oSettings dataTables settings object 5716 5717 * @returns {node} Pagination feature node 5718 5719 * @memberof DataTable#oApi 5720 5721 */ 5722 5723 function _fnFeatureHtmlPaginate ( oSettings ) 5724 5725 { 5726 5727 if ( oSettings.oScroll.bInfinite ) 5728 5729 { 5730 5731 return null; 5732 5733 } 5734 5735 5736 5737 var nPaginate = document.createElement( 'div' ); 5738 5739 nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType; 5740 5741 5742 5743 DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, 5744 5745 function( oSettings ) { 5746 5747 _fnCalculateEnd( oSettings ); 5748 5749 _fnDraw( oSettings ); 5750 5751 } 5752 5753 ); 5754 5755 5756 5757 /* Add a draw callback for the pagination on first instance, to update the paging display */ 5758 5759 if ( !oSettings.aanFeatures.p ) 5760 5761 { 5762 5763 oSettings.aoDrawCallback.push( { 5764 5765 "fn": function( oSettings ) { 5766 5767 DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) { 5768 5769 _fnCalculateEnd( oSettings ); 5770 5771 _fnDraw( oSettings ); 5772 5773 } ); 5774 5775 }, 5776 5777 "sName": "pagination" 5778 5779 } ); 5780 5781 } 5782 5783 return nPaginate; 5784 5785 } 5786 5787 5788 5789 5790 5791 /** 5792 5793 * Alter the display settings to change the page 5794 5795 * @param {object} oSettings dataTables settings object 5796 5797 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 5798 5799 * or page number to jump to (integer) 5800 5801 * @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1 5802 5803 * @memberof DataTable#oApi 5804 5805 */ 5806 5807 function _fnPageChange ( oSettings, mAction ) 5808 5809 { 5810 5811 var iOldStart = oSettings._iDisplayStart; 5812 5813 5814 5815 if ( typeof mAction === "number" ) 5816 5817 { 5818 5819 oSettings._iDisplayStart = mAction * oSettings._iDisplayLength; 5820 5821 if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() ) 5822 5823 { 5824 5825 oSettings._iDisplayStart = 0; 5826 5827 } 5828 5829 } 5830 5831 else if ( mAction == "first" ) 5832 5833 { 5834 5835 oSettings._iDisplayStart = 0; 5836 5837 } 5838 5839 else if ( mAction == "previous" ) 5840 5841 { 5842 5843 oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ? 5844 5845 oSettings._iDisplayStart - oSettings._iDisplayLength : 5846 5847 0; 5848 5849 5850 5851 /* Correct for under-run */ 5852 5853 if ( oSettings._iDisplayStart < 0 ) 5854 5855 { 5856 5857 oSettings._iDisplayStart = 0; 5858 5859 } 5860 5861 } 5862 5863 else if ( mAction == "next" ) 5864 5865 { 5866 5867 if ( oSettings._iDisplayLength >= 0 ) 5868 5869 { 5870 5871 /* Make sure we are not over running the display array */ 5872 5873 if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() ) 5874 5875 { 5876 5877 oSettings._iDisplayStart += oSettings._iDisplayLength; 5878 5879 } 5880 5881 } 5882 5883 else 5884 5885 { 5886 5887 oSettings._iDisplayStart = 0; 5888 5889 } 5890 5891 } 5892 5893 else if ( mAction == "last" ) 5894 5895 { 5896 5897 if ( oSettings._iDisplayLength >= 0 ) 5898 5899 { 5900 5901 var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1; 5902 5903 oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength; 5904 5905 } 5906 5907 else 5908 5909 { 5910 5911 oSettings._iDisplayStart = 0; 5912 5913 } 5914 5915 } 5916 5917 else 5918 5919 { 5920 5921 _fnLog( oSettings, 0, "Unknown paging action: "+mAction ); 5922 5923 } 5924 5925 $(oSettings.oInstance).trigger('page', oSettings); 5926 5927 5928 5929 return iOldStart != oSettings._iDisplayStart; 5930 5931 } 5932 5933 5934 5935 5936 5937 5938 5939 /** 5940 5941 * Generate the node required for the processing node 5942 5943 * @param {object} oSettings dataTables settings object 5944 5945 * @returns {node} Processing element 5946 5947 * @memberof DataTable#oApi 5948 5949 */ 5950 5951 function _fnFeatureHtmlProcessing ( oSettings ) 5952 5953 { 5954 5955 var nProcessing = document.createElement( 'div' ); 5956 5957 5958 5959 if ( !oSettings.aanFeatures.r ) 5960 5961 { 5962 5963 nProcessing.id = oSettings.sTableId+'_processing'; 5964 5965 } 5966 5967 nProcessing.innerHTML = oSettings.oLanguage.sProcessing; 5968 5969 nProcessing.className = oSettings.oClasses.sProcessing; 5970 5971 oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable ); 5972 5973 5974 5975 return nProcessing; 5976 5977 } 5978 5979 5980 5981 5982 5983 /** 5984 5985 * Display or hide the processing indicator 5986 5987 * @param {object} oSettings dataTables settings object 5988 5989 * @param {bool} bShow Show the processing indicator (true) or not (false) 5990 5991 * @memberof DataTable#oApi 5992 5993 */ 5994 5995 function _fnProcessingDisplay ( oSettings, bShow ) 5996 5997 { 5998 5999 if ( oSettings.oFeatures.bProcessing ) 6000 6001 { 6002 6003 var an = oSettings.aanFeatures.r; 6004 6005 for ( var i=0, iLen=an.length ; i<iLen ; i++ ) 6006 6007 { 6008 6009 an[i].style.visibility = bShow ? "visible" : "hidden"; 6010 6011 } 6012 6013 } 6014 6015 6016 6017 $(oSettings.oInstance).trigger('processing', [oSettings, bShow]); 6018 6019 } 6020 6021 6022 6023 /** 6024 6025 * Add any control elements for the table - specifically scrolling 6026 6027 * @param {object} oSettings dataTables settings object 6028 6029 * @returns {node} Node to add to the DOM 6030 6031 * @memberof DataTable#oApi 6032 6033 */ 6034 6035 function _fnFeatureHtmlTable ( oSettings ) 6036 6037 { 6038 6039 /* Check if scrolling is enabled or not - if not then leave the DOM unaltered */ 6040 6041 if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" ) 6042 6043 { 6044 6045 return oSettings.nTable; 6046 6047 } 6048 6049 6050 6051 /* 6052 6053 * The HTML structure that we want to generate in this function is: 6054 6055 * div - nScroller 6056 6057 * div - nScrollHead 6058 6059 * div - nScrollHeadInner 6060 6061 * table - nScrollHeadTable 6062 6063 * thead - nThead 6064 6065 * div - nScrollBody 6066 6067 * table - oSettings.nTable 6068 6069 * thead - nTheadSize 6070 6071 * tbody - nTbody 6072 6073 * div - nScrollFoot 6074 6075 * div - nScrollFootInner 6076 6077 * table - nScrollFootTable 6078 6079 * tfoot - nTfoot 6080 6081 */ 6082 6083 var 6084 6085 nScroller = document.createElement('div'), 6086 6087 nScrollHead = document.createElement('div'), 6088 6089 nScrollHeadInner = document.createElement('div'), 6090 6091 nScrollBody = document.createElement('div'), 6092 6093 nScrollFoot = document.createElement('div'), 6094 6095 nScrollFootInner = document.createElement('div'), 6096 6097 nScrollHeadTable = oSettings.nTable.cloneNode(false), 6098 6099 nScrollFootTable = oSettings.nTable.cloneNode(false), 6100 6101 nThead = oSettings.nTable.getElementsByTagName('thead')[0], 6102 6103 nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null :
6104 6105 oSettings.nTable.getElementsByTagName('tfoot')[0], 6106 6107 oClasses = oSettings.oClasses; 6108 6109 6110 6111 nScrollHead.appendChild( nScrollHeadInner ); 6112 6113 nScrollFoot.appendChild( nScrollFootInner ); 6114 6115 nScrollBody.appendChild( oSettings.nTable ); 6116 6117 nScroller.appendChild( nScrollHead ); 6118 6119 nScroller.appendChild( nScrollBody ); 6120 6121 nScrollHeadInner.appendChild( nScrollHeadTable ); 6122 6123 nScrollHeadTable.appendChild( nThead ); 6124 6125 if ( nTfoot !== null ) 6126 6127 { 6128 6129 nScroller.appendChild( nScrollFoot ); 6130 6131 nScrollFootInner.appendChild( nScrollFootTable ); 6132 6133 nScrollFootTable.appendChild( nTfoot ); 6134 6135 } 6136 6137 6138 6139 nScroller.className = oClasses.sScrollWrapper; 6140 6141 nScrollHead.className = oClasses.sScrollHead; 6142 6143 nScrollHeadInner.className = oClasses.sScrollHeadInner; 6144 6145 nScrollBody.className = oClasses.sScrollBody; 6146 6147 nScrollFoot.className = oClasses.sScrollFoot; 6148 6149 nScrollFootInner.className = oClasses.sScrollFootInner; 6150 6151 6152 6153 if ( oSettings.oScroll.bAutoCss ) 6154 6155 { 6156 6157 nScrollHead.style.overflow = "hidden"; 6158 6159 nScrollHead.style.position = "relative"; 6160 6161 nScrollFoot.style.overflow = "hidden"; 6162 6163 nScrollBody.style.overflow = "auto"; 6164 6165 } 6166 6167 6168 6169 nScrollHead.style.border = "0"; 6170 6171 nScrollHead.style.width = "100%"; 6172 6173 nScrollFoot.style.border = "0"; 6174 6175 nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ? 6176 6177 oSettings.oScroll.sXInner : "100%"; /* will be overwritten */ 6178 6179 6180 6181 /* Modify attributes to respect the clones */ 6182 6183 nScrollHeadTable.removeAttribute('id'); 6184 6185 nScrollHeadTable.style.marginLeft = "0"; 6186 6187 oSettings.nTable.style.marginLeft = "0"; 6188 6189 if ( nTfoot !== null ) 6190 6191 { 6192 6193 nScrollFootTable.removeAttribute('id'); 6194 6195 nScrollFootTable.style.marginLeft = "0"; 6196 6197 } 6198 6199 6200 6201 /* Move caption elements from the body to the header, footer or leave where it is 6202 6203 * depending on the configuration. Note that the DTD says there can be only one caption */ 6204 6205 var nCaption = $(oSettings.nTable).children('caption'); 6206 6207 if ( nCaption.length > 0 ) 6208 6209 { 6210 6211 nCaption = nCaption[0]; 6212 6213 if ( nCaption._captionSide === "top" ) 6214 6215 { 6216 6217 nScrollHeadTable.appendChild( nCaption ); 6218 6219 } 6220 6221 else if ( nCaption._captionSide === "bottom" && nTfoot ) 6222 6223 { 6224 6225 nScrollFootTable.appendChild( nCaption ); 6226 6227 } 6228 6229 } 6230 6231 6232 6233 /* 6234 6235 * Sizing 6236 6237 */ 6238 6239 /* When x-scrolling add the width and a scroller to move the header with the body */ 6240 6241 if ( oSettings.oScroll.sX !== "" ) 6242 6243 { 6244 6245 nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX ); 6246 6247 nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX ); 6248 6249 6250 6251 if ( nTfoot !== null ) 6252 6253 { 6254 6255 nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX ); 6256 6257 } 6258 6259 6260 6261 /* When the body is scrolled, then we also want to scroll the headers */ 6262 6263 $(nScrollBody).scroll( function (e) { 6264 6265 nScrollHead.scrollLeft = this.scrollLeft; 6266 6267 6268 6269 if ( nTfoot !== null ) 6270 6271 { 6272 6273 nScrollFoot.scrollLeft = this.scrollLeft; 6274 6275 } 6276 6277 } ); 6278 6279 } 6280 6281 6282 6283 /* When yscrolling, add the height */ 6284 6285 if ( oSettings.oScroll.sY !== "" ) 6286 6287 { 6288 6289 nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY ); 6290 6291 } 6292 6293 6294 6295 /* Redraw - align columns across the tables */ 6296 6297 oSettings.aoDrawCallback.push( { 6298 6299 "fn": _fnScrollDraw, 6300 6301 "sName": "scrolling" 6302 6303 } ); 6304 6305 6306 6307 /* Infinite scrolling event handlers */ 6308 6309 if ( oSettings.oScroll.bInfinite ) 6310 6311 { 6312 6313 $(nScrollBody).scroll( function() { 6314 6315 /* Use a blocker to stop scrolling from loading more data while other data is still loading */ 6316 6317 if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 ) 6318 6319 { 6320 6321 /* Check if we should load the next data set */ 6322 6323 if ( $(this).scrollTop() + $(this).height() > 6324 6325 $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap ) 6326 6327 { 6328 6329 /* Only do the redraw if we have to - we might be at the end of the data */ 6330 6331 if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() ) 6332 6333 { 6334 6335 _fnPageChange( oSettings, 'next' ); 6336 6337 _fnCalculateEnd( oSettings ); 6338 6339 _fnDraw( oSettings ); 6340 6341 } 6342 6343 } 6344 6345 } 6346 6347 } ); 6348 6349 } 6350 6351 6352 6353 oSettings.nScrollHead = nScrollHead; 6354 6355 oSettings.nScrollFoot = nScrollFoot; 6356 6357 6358 6359 return nScroller; 6360 6361 } 6362 6363 6364 6365 6366 6367 /** 6368 6369 * Update the various tables for resizing. It's a bit of a pig this function, but 6370 6371 * basically the idea to: 6372 6373 * 1. Re-create the table inside the scrolling div 6374 6375 * 2. Take live measurements from the DOM 6376 6377 * 3. Apply the measurements 6378 6379 * 4. Clean up 6380 6381 * @param {object} o dataTables settings object 6382 6383 * @returns {node} Node to add to the DOM 6384 6385 * @memberof DataTable#oApi 6386 6387 */ 6388 6389 function _fnScrollDraw ( o ) 6390 6391 { 6392 6393 var 6394 6395 nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0], 6396 6397 nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0], 6398 6399 nScrollBody = o.nTable.parentNode, 6400 6401 i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis, 6402 6403 nTheadSize, nTfootSize, 6404 6405 iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth, 6406 6407 nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null, 6408 6409 nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null, 6410 6411 ie67 = o.oBrowser.bScrollOversize, 6412 6413 zeroOut = function(nSizer) { 6414 6415 oStyle = nSizer.style; 6416 6417 oStyle.paddingTop = "0"; 6418 6419 oStyle.paddingBottom = "0"; 6420 6421 oStyle.borderTopWidth = "0"; 6422 6423 oStyle.borderBottomWidth = "0"; 6424 6425 oStyle.height = 0; 6426 6427 }; 6428 6429 6430 6431 /* 6432 6433 * 1. Re-create the table inside the scrolling div 6434 6435 */ 6436 6437 6438 6439 /* Remove the old minimised thead and tfoot elements in the inner table */ 6440 6441 $(o.nTable).children('thead, tfoot').remove(); 6442 6443 6444 6445 /* Clone the current header and footer elements and then place it into the inner table */ 6446 6447 nTheadSize = $(o.nTHead).clone()[0]; 6448 6449 o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] ); 6450 6451 anHeadToSize = o.nTHead.getElementsByTagName('tr'); 6452 6453 anHeadSizers = nTheadSize.getElementsByTagName('tr'); 6454 6455 6456 6457 if ( o.nTFoot !== null ) 6458 6459 { 6460 6461 nTfootSize = $(o.nTFoot).clone()[0]; 6462 6463 o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] ); 6464 6465 anFootToSize = o.nTFoot.getElementsByTagName('tr'); 6466 6467 anFootSizers = nTfootSize.getElementsByTagName('tr'); 6468 6469 } 6470 6471 6472 6473 /* 6474 6475 * 2. Take live measurements from the DOM - do not alter the DOM itself! 6476 6477 */ 6478 6479 6480 6481 /* Remove old sizing and apply the calculated column widths 6482 6483 * Get the unique column headers in the newly created (cloned) header. We want to apply the 6484 6485 * calculated sizes to this header 6486 6487 */ 6488 6489 if ( o.oScroll.sX === "" ) 6490 6491 { 6492 6493 nScrollBody.style.width = '100%'; 6494 6495 nScrollHeadInner.parentNode.style.width = '100%'; 6496 6497 } 6498 6499 6500 6501 var nThs = _fnGetUniqueThs( o, nTheadSize ); 6502 6503 for ( i=0, iLen=nThs.length ; i<iLen ; i++ ) 6504 6505 { 6506 6507 iVis = _fnVisibleToColumnIndex( o, i ); 6508 6509 nThs[i].style.width = o.aoColumns[iVis].sWidth; 6510 6511 } 6512 6513 6514 6515 if ( o.nTFoot !== null ) 6516 6517 { 6518 6519 _fnApplyToChildren( function(n) { 6520 6521 n.style.width = ""; 6522 6523 }, anFootSizers ); 6524 6525 } 6526 6527 6528 6529 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we 6530 6531 // will end up forcing the scrollbar to appear, making our measurements wrong for when we 6532 6533 // then hide it (end of this function), so add the header height to the body scroller. 6534 6535 if ( o.oScroll.bCollapse && o.oScroll.sY !== "" ) 6536 6537 { 6538 6539 nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px"; 6540 6541 } 6542 6543 6544 6545 /* Size the table as a whole */ 6546 6547 iSanityWidth = $(o.nTable).outerWidth(); 6548 6549 if ( o.oScroll.sX === "" ) 6550 6551 { 6552 6553 /* No x scrolling */ 6554 6555 o.nTable.style.width = "100%"; 6556 6557 6558 6559 /* I know this is rubbish - but IE7 will make the width of the table when 100% include 6560 6561 * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this 6562 6563 * into account. 6564 6565 */ 6566 6567 if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || 6568 6569 $(nScrollBody).css('overflow-y') == "scroll") ) 6570 6571 { 6572 6573 o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
6574 6575 } 6576 6577 } 6578 6579 else 6580 6581 { 6582 6583 if ( o.oScroll.sXInner !== "" ) 6584 6585 { 6586 6587 /* x scroll inner has been given - use it */ 6588 6589 o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner); 6590 6591 } 6592 6593 else if ( iSanityWidth == $(nScrollBody).width() && 6594 6595 $(nScrollBody).height() < $(o.nTable).height() ) 6596 6597 { 6598 6599 /* There is y-scrolling - try to take account of the y scroll bar */ 6600 6601 o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth ); 6602 6603 if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth ) 6604 6605 { 6606 6607 /* Not possible to take account of it */ 6608 6609 o.nTable.style.width = _fnStringToCss( iSanityWidth ); 6610 6611 } 6612 6613 } 6614 6615 else 6616 6617 { 6618 6619 /* All else fails */ 6620 6621 o.nTable.style.width = _fnStringToCss( iSanityWidth ); 6622 6623 } 6624 6625 } 6626 6627 6628 6629 /* Recalculate the sanity width - now that we've applied the required width, before it was 6630 6631 * a temporary variable. This is required because the column width calculation is done 6632 6633 * before this table DOM is created. 6634 6635 */ 6636 6637 iSanityWidth = $(o.nTable).outerWidth(); 6638 6639 6640 6641 /* We want the hidden header to have zero height, so remove padding and borders. Then 6642 6643 * set the width based on the real headers 6644 6645 */ 6646 6647 6648 6649 // Apply all styles in one pass. Invalidates layout only once because we don't read any 6650 6651 // DOM properties. 6652 6653 _fnApplyToChildren( zeroOut, anHeadSizers ); 6654 6655 6656 6657 // Read all widths in next pass. Forces layout only once because we do not change 6658 6659 // any DOM properties. 6660 6661 _fnApplyToChildren( function(nSizer) { 6662 6663 aApplied.push( _fnStringToCss( $(nSizer).width() ) ); 6664 6665 }, anHeadSizers ); 6666 6667 6668 6669 // Apply all widths in final pass. Invalidates layout only once because we do not 6670 6671 // read any DOM properties. 6672 6673 _fnApplyToChildren( function(nToSize, i) { 6674 6675 nToSize.style.width = aApplied[i]; 6676 6677 }, anHeadToSize ); 6678 6679 6680 6681 $(anHeadSizers).height(0); 6682 6683 6684 6685 /* Same again with the footer if we have one */ 6686 6687 if ( o.nTFoot !== null ) 6688 6689 { 6690 6691 _fnApplyToChildren( zeroOut, anFootSizers ); 6692 6693 6694 6695 _fnApplyToChildren( function(nSizer) { 6696 6697 aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) ); 6698 6699 }, anFootSizers ); 6700 6701 6702 6703 _fnApplyToChildren( function(nToSize, i) { 6704 6705 nToSize.style.width = aAppliedFooter[i]; 6706 6707 }, anFootToSize ); 6708 6709 6710 6711 $(anFootSizers).height(0); 6712 6713 } 6714 6715 6716 6717 /* 6718 6719 * 3. Apply the measurements 6720 6721 */ 6722 6723 6724 6725 /* "Hide" the header and footer that we used for the sizing. We want to also fix their width 6726 6727 * to what they currently are 6728 6729 */ 6730 6731 _fnApplyToChildren( function(nSizer, i) { 6732 6733 nSizer.innerHTML = ""; 6734 6735 nSizer.style.width = aApplied[i]; 6736 6737 }, anHeadSizers ); 6738 6739 6740 6741 if ( o.nTFoot !== null ) 6742 6743 { 6744 6745 _fnApplyToChildren( function(nSizer, i) { 6746 6747 nSizer.innerHTML = ""; 6748 6749 nSizer.style.width = aAppliedFooter[i]; 6750 6751 }, anFootSizers ); 6752 6753 } 6754 6755 6756 6757 /* Sanity check that the table is of a sensible width. If not then we are going to get 6758 6759 * misalignment - try to prevent this by not allowing the table to shrink below its min width 6760 6761 */ 6762 6763 if ( $(o.nTable).outerWidth() < iSanityWidth ) 6764 6765 { 6766 6767 /* The min width depends upon if we have a vertical scrollbar visible or not */ 6768 6769 var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || 6770 6771 $(nScrollBody).css('overflow-y') == "scroll")) ? 6772 6773 iSanityWidth+o.oScroll.iBarWidth : iSanityWidth; 6774 6775 6776 6777 /* IE6/7 are a law unto themselves... */ 6778 6779 if ( ie67 && (nScrollBody.scrollHeight > 6780 6781 nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll") ) 6782 6783 { 6784 6785 o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth ); 6786 6787 } 6788 6789 6790 6791 /* Apply the calculated minimum width to the table wrappers */ 6792 6793 nScrollBody.style.width = _fnStringToCss( iCorrection ); 6794 6795 o.nScrollHead.style.width = _fnStringToCss( iCorrection ); 6796 6797 6798 6799 if ( o.nTFoot !== null ) 6800 6801 { 6802 6803 o.nScrollFoot.style.width = _fnStringToCss( iCorrection ); 6804 6805 } 6806 6807 6808 6809 /* And give the user a warning that we've stopped the table getting too small */ 6810 6811 if ( o.oScroll.sX === "" ) 6812 6813 { 6814 6815 _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ 6816 6817 " misalignment. The table has been drawn at its minimum possible width." ); 6818 6819 } 6820 6821 else if ( o.oScroll.sXInner !== "" ) 6822 6823 { 6824 6825 _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+ 6826 6827 " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+ 6828 6829 " calculation" ); 6830 6831 } 6832 6833 } 6834 6835 else 6836 6837 { 6838 6839 nScrollBody.style.width = _fnStringToCss( '100%' ); 6840 6841 o.nScrollHead.style.width = _fnStringToCss( '100%' ); 6842 6843 6844 6845 if ( o.nTFoot !== null ) 6846 6847 { 6848 6849 o.nScrollFoot.style.width = _fnStringToCss( '100%' ); 6850 6851 } 6852 6853 } 6854 6855 6856 6857 6858 6859 /* 6860 6861 * 4. Clean up 6862 6863 */ 6864 6865 if ( o.oScroll.sY === "" ) 6866 6867 { 6868 6869 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 6870 6871 * the scrollbar height from the visible display, rather than adding it on. We need to 6872 6873 * set the height in order to sort this. Don't want to do it in any other browsers. 6874 6875 */ 6876 6877 if ( ie67 ) 6878 6879 { 6880 6881 nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth ); 6882 6883 } 6884 6885 } 6886 6887 6888 6889 if ( o.oScroll.sY !== "" && o.oScroll.bCollapse ) 6890 6891 { 6892 6893 nScrollBody.style.height = _fnStringToCss( o.oScroll.sY ); 6894 6895 6896 6897 var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ? 6898 6899 o.oScroll.iBarWidth : 0; 6900 6901 if ( o.nTable.offsetHeight < nScrollBody.offsetHeight ) 6902 6903 { 6904 6905 nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra ); 6906 6907 } 6908 6909 } 6910 6911 6912 6913 /* Finally set the width's of the header and footer tables */ 6914 6915 var iOuterWidth = $(o.nTable).outerWidth(); 6916 6917 nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth ); 6918 6919 nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth ); 6920 6921 6922 6923 // Figure out if there are scrollbar present - if so then we need a the header and footer to 6924 6925 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 6926 6927 var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll"; 6928 6929 nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; 6930 6931 6932 6933 if ( o.nTFoot !== null ) 6934 6935 { 6936 6937 nScrollFootTable.style.width = _fnStringToCss( iOuterWidth ); 6938 6939 nScrollFootInner.style.width = _fnStringToCss( iOuterWidth ); 6940 6941 nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px"; 6942 6943 } 6944 6945 6946 6947 /* Adjust the position of the header in case we loose the y-scrollbar */ 6948 6949 $(nScrollBody).scroll(); 6950 6951 6952 6953 /* If sorting or filtering has occurred, jump the scrolling back to the top */ 6954 6955 if ( o.bSorted || o.bFiltered ) 6956 6957 { 6958 6959 nScrollBody.scrollTop = 0; 6960 6961 } 6962 6963 } 6964 6965 6966 6967 6968 6969 /** 6970 6971 * Apply a given function to the display child nodes of an element array (typically 6972 6973 * TD children of TR rows 6974 6975 * @param {function} fn Method to apply to the objects 6976 6977 * @param array {nodes} an1 List of elements to look through for display children 6978 6979 * @param array {nodes} an2 Another list (identical structure to the first) - optional 6980 6981 * @memberof DataTable#oApi 6982 6983 */ 6984 6985 function _fnApplyToChildren( fn, an1, an2 ) 6986 6987 { 6988 6989 var index=0, i=0, iLen=an1.length; 6990 6991 var nNode1, nNode2; 6992 6993 6994 6995 while ( i < iLen ) 6996 6997 { 6998 6999 nNode1 = an1[i].firstChild; 7000 7001 nNode2 = an2 ? an2[i].firstChild : null; 7002 7003 while ( nNode1 ) 7004 7005 { 7006 7007 if ( nNode1.nodeType === 1 ) 7008 7009 { 7010 7011 if ( an2 ) 7012 7013 { 7014 7015 fn( nNode1, nNode2, index ); 7016 7017 } 7018 7019 else 7020 7021 { 7022 7023 fn( nNode1, index ); 7024 7025 } 7026 7027 index++; 7028 7029 } 7030 7031 nNode1 = nNode1.nextSibling; 7032 7033 nNode2 = an2 ? nNode2.nextSibling : null; 7034 7035 } 7036 7037 i++; 7038 7039 } 7040 7041 } 7042 7043 7044 7045 /** 7046 7047 * Convert a CSS unit width to pixels (e.g. 2em) 7048 7049 * @param {string} sWidth width to be converted 7050 7051 * @param {node} nParent parent to get the with for (required for relative widths) - optional 7052 7053 * @returns {int} iWidth width in pixels 7054 7055 * @memberof DataTable#oApi 7056 7057 */ 7058 7059 function _fnConvertToWidth ( sWidth, nParent ) 7060 7061 { 7062 7063 if ( !sWidth || sWidth === null || sWidth === '' ) 7064 7065 { 7066 7067 return 0; 7068 7069 } 7070 7071 7072 7073 if ( !nParent ) 7074 7075 { 7076 7077 nParent = document.body; 7078 7079 } 7080 7081 7082 7083 var iWidth; 7084 7085 var nTmp = document.createElement( "div" ); 7086 7087 nTmp.style.width = _fnStringToCss( sWidth ); 7088 7089 7090 7091 nParent.appendChild( nTmp ); 7092 7093 iWidth = nTmp.offsetWidth; 7094 7095 nParent.removeChild( nTmp ); 7096 7097 7098 7099 return ( iWidth ); 7100 7101 } 7102 7103 7104 7105 7106 7107 /** 7108 7109 * Calculate the width of columns for the table 7110 7111 * @param {object} oSettings dataTables settings object 7112 7113 * @memberof DataTable#oApi 7114 7115 */ 7116 7117 function _fnCalculateColumnWidths ( oSettings ) 7118 7119 { 7120 7121 var iTableWidth = oSettings.nTable.offsetWidth; 7122 7123 var iUserInputs = 0; 7124 7125 var iTmpWidth; 7126 7127 var iVisibleColumns = 0; 7128 7129 var iColums = oSettings.aoColumns.length; 7130 7131 var i, iIndex, iCorrector, iWidth; 7132 7133 var oHeaders = $('th', oSettings.nTHead); 7134 7135 var widthAttr = oSettings.nTable.getAttribute('width'); 7136 7137 var nWrapper = oSettings.nTable.parentNode; 7138 7139 7140 7141 /* Convert any user input sizes into pixel sizes */ 7142 7143 for ( i=0 ; i<iColums ; i++ ) 7144 7145 { 7146 7147 if ( oSettings.aoColumns[i].bVisible ) 7148 7149 { 7150 7151 iVisibleColumns++; 7152 7153 7154 7155 if ( oSettings.aoColumns[i].sWidth !== null ) 7156 7157 { 7158 7159 iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, 7160 7161 nWrapper ); 7162 7163 if ( iTmpWidth !== null ) 7164 7165 { 7166 7167 oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth ); 7168 7169 } 7170 7171 7172 7173 iUserInputs++; 7174 7175 } 7176 7177 } 7178 7179 } 7180 7181 7182 7183 /* If the number of columns in the DOM equals the number that we have to process in 7184 7185 * DataTables, then we can use the offsets that are created by the web-browser. No custom 7186 7187 * sizes can be set in order for this to happen, nor scrolling used 7188 7189 */ 7190 7191 if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums && 7192 7193 oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" ) 7194 7195 { 7196 7197 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) 7198 7199 { 7200 7201 iTmpWidth = $(oHeaders[i]).width(); 7202 7203 if ( iTmpWidth !== null ) 7204 7205 { 7206 7207 oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth ); 7208 7209 } 7210 7211 } 7212 7213 } 7214 7215 else 7216 7217 { 7218 7219 /* Otherwise we are going to have to do some calculations to get the width of each column. 7220 7221 * Construct a 1 row table with the widest node in the data, and any user defined widths, 7222 7223 * then insert it into the DOM and allow the browser to do all the hard
7223work of 7224 7225 * calculating table widths. 7226 7227 */ 7228 7229 var 7230 7231 nCalcTmp = oSettings.nTable.cloneNode( false ), 7232 7233 nTheadClone = oSettings.nTHead.cloneNode(true), 7234 7235 nBody = document.createElement( 'tbody' ), 7236 7237 nTr = document.createElement( 'tr' ), 7238 7239 nDivSizing; 7240 7241 7242 7243 nCalcTmp.removeAttribute( "id" ); 7244 7245 nCalcTmp.appendChild( nTheadClone ); 7246 7247 if ( oSettings.nTFoot !== null ) 7248 7249 { 7250 7251 nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) ); 7252 7253 _fnApplyToChildren( function(n) { 7254 7255 n.style.width = ""; 7256 7257 }, nCalcTmp.getElementsByTagName('tr') ); 7258 7259 } 7260 7261 7262 7263 nCalcTmp.appendChild( nBody ); 7264 7265 nBody.appendChild( nTr ); 7266 7267 7268 7269 /* Remove any sizing that was previously applied by the styles */ 7270 7271 var jqColSizing = $('thead th', nCalcTmp); 7272 7273 if ( jqColSizing.length === 0 ) 7274 7275 { 7276 7277 jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp); 7278 7279 } 7280 7281 7282 7283 /* Apply custom sizing to the cloned header */ 7284 7285 var nThs = _fnGetUniqueThs( oSettings, nTheadClone ); 7286 7287 iCorrector = 0; 7288 7289 for ( i=0 ; i<iColums ; i++ ) 7290 7291 { 7292 7293 var oColumn = oSettings.aoColumns[i]; 7294 7295 if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" ) 7296 7297 { 7298 7299 nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig ); 7300 7301 } 7302 7303 else if ( oColumn.bVisible ) 7304 7305 { 7306 7307 nThs[i-iCorrector].style.width = ""; 7308 7309 } 7310 7311 else 7312 7313 { 7314 7315 iCorrector++; 7316 7317 } 7318 7319 } 7320 7321 7322 7323 /* Find the biggest td for each column and put it into the table */ 7324 7325 for ( i=0 ; i<iColums ; i++ ) 7326 7327 { 7328 7329 if ( oSettings.aoColumns[i].bVisible ) 7330 7331 { 7332 7333 var nTd = _fnGetWidestNode( oSettings, i ); 7334 7335 if ( nTd !== null ) 7336 7337 { 7338 7339 nTd = nTd.cloneNode(true); 7340 7341 if ( oSettings.aoColumns[i].sContentPadding !== "" ) 7342 7343 { 7344 7345 nTd.innerHTML += oSettings.aoColumns[i].sContentPadding; 7346 7347 } 7348 7349 nTr.appendChild( nTd ); 7350 7351 } 7352 7353 } 7354 7355 } 7356 7357 7358 7359 /* Build the table and 'display' it */ 7360 7361 nWrapper.appendChild( nCalcTmp ); 7362 7363 7364 7365 /* When scrolling (X or Y) we want to set the width of the table as appropriate. However, 7366 7367 * when not scrolling leave the table width as it is. This results in slightly different, 7368 7369 * but I think correct behaviour 7370 7371 */ 7372 7373 if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" ) 7374 7375 { 7376 7377 nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner); 7378 7379 } 7380 7381 else if ( oSettings.oScroll.sX !== "" ) 7382 7383 { 7384 7385 nCalcTmp.style.width = ""; 7386 7387 if ( $(nCalcTmp).width() < nWrapper.offsetWidth ) 7388 7389 { 7390 7391 nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth ); 7392 7393 } 7394 7395 } 7396 7397 else if ( oSettings.oScroll.sY !== "" ) 7398 7399 { 7400 7401 nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth ); 7402 7403 } 7404 7405 else if ( widthAttr ) 7406 7407 { 7408 7409 nCalcTmp.style.width = _fnStringToCss( widthAttr ); 7410 7411 } 7412 7413 nCalcTmp.style.visibility = "hidden"; 7414 7415 7416 7417 /* Scrolling considerations */ 7418 7419 _fnScrollingWidthAdjust( oSettings, nCalcTmp ); 7420 7421 7422 7423 /* Read the width's calculated by the browser and store them for use by the caller. We 7424 7425 * first of all try to use the elements in the body, but it is possible that there are 7426 7427 * no elements there, under which circumstances we use the header elements 7428 7429 */ 7430 7431 var oNodes = $("tbody tr:eq(0)", nCalcTmp).children(); 7432 7433 if ( oNodes.length === 0 ) 7434 7435 { 7436 7437 oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] ); 7438 7439 } 7440 7441 7442 7443 /* Browsers need a bit of a hand when a width is assigned to any columns when 7444 7445 * x-scrolling as they tend to collapse the table to the min-width, even if 7446 7447 * we sent the column widths. So we need to keep track of what the table width 7448 7449 * should be by summing the user given values, and the automatic values 7450 7451 */ 7452 7453 if ( oSettings.oScroll.sX !== "" ) 7454 7455 { 7456 7457 var iTotal = 0; 7458 7459 iCorrector = 0; 7460 7461 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) 7462 7463 { 7464 7465 if ( oSettings.aoColumns[i].bVisible ) 7466 7467 { 7468 7469 if ( oSettings.aoColumns[i].sWidthOrig === null ) 7470 7471 { 7472 7473 iTotal += $(oNodes[iCorrector]).outerWidth(); 7474 7475 } 7476 7477 else 7478 7479 { 7480 7481 iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) + 7482 7483 ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width()); 7484 7485 } 7486 7487 iCorrector++; 7488 7489 } 7490 7491 } 7492 7493 7494 7495 nCalcTmp.style.width = _fnStringToCss( iTotal ); 7496 7497 oSettings.nTable.style.width = _fnStringToCss( iTotal ); 7498 7499 } 7500 7501 7502 7503 iCorrector = 0; 7504 7505 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) 7506 7507 { 7508 7509 if ( oSettings.aoColumns[i].bVisible ) 7510 7511 { 7512 7513 iWidth = $(oNodes[iCorrector]).width(); 7514 7515 if ( iWidth !== null && iWidth > 0 ) 7516 7517 { 7518 7519 oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth ); 7520 7521 } 7522 7523 iCorrector++; 7524 7525 } 7526 7527 } 7528 7529 7530 7531 var cssWidth = $(nCalcTmp).css('width'); 7532 7533 oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ? 7534 7535 cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() ); 7536 7537 nCalcTmp.parentNode.removeChild( nCalcTmp ); 7538 7539 } 7540 7541 7542 7543 if ( widthAttr ) 7544 7545 { 7546 7547 oSettings.nTable.style.width = _fnStringToCss( widthAttr ); 7548 7549 } 7550 7551 } 7552 7553 7554 7555 7556 7557 /** 7558 7559 * Adjust a table's width to take account of scrolling 7560 7561 * @param {object} oSettings dataTables settings object 7562 7563 * @param {node} n table node 7564 7565 * @memberof DataTable#oApi 7566 7567 */ 7568 7569 function _fnScrollingWidthAdjust ( oSettings, n ) 7570 7571 { 7572 7573 if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" ) 7574 7575 { 7576 7577 /* When y-scrolling only, we want to remove the width of the scroll bar so the table 7578 7579 * + scroll bar will fit into the area avaialble. 7580 7581 */ 7582 7583 var iOrigWidth = $(n).width(); 7584
7585 n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth ); 7586 7587 } 7588 7589 else if ( oSettings.oScroll.sX !== "" ) 7590 7591 { 7592 7593 /* When x-scrolling both ways, fix the table at it's current size, without adjusting */ 7594 7595 n.style.width = _fnStringToCss( $(n).outerWidth() ); 7596 7597 } 7598 7599 } 7600 7601 7602 7603 7604 7605 /** 7606 7607 * Get the widest node 7608 7609 * @param {object} oSettings dataTables settings object 7610 7611 * @param {int} iCol column of interest 7612 7613 * @returns {node} widest table node 7614 7615 * @memberof DataTable#oApi 7616 7617 */ 7618 7619 function _fnGetWidestNode( oSettings, iCol ) 7620 7621 { 7622 7623 var iMaxIndex = _fnGetMaxLenString( oSettings, iCol ); 7624 7625 if ( iMaxIndex < 0 ) 7626 7627 { 7628 7629 return null; 7630 7631 } 7632 7633 7634 7635 if ( oSettings.aoData[iMaxIndex].nTr === null ) 7636 7637 { 7638 7639 var n = document.createElement('td'); 7640 7641 n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' ); 7642 7643 return n; 7644 7645 } 7646 7647 return _fnGetTdNodes(oSettings, iMaxIndex)[iCol]; 7648 7649 } 7650 7651 7652 7653 7654 7655 /** 7656 7657 * Get the maximum strlen for each data column 7658 7659 * @param {object} oSettings dataTables settings object 7660 7661 * @param {int} iCol column of interest 7662 7663 * @returns {string} max string length for each column 7664 7665 * @memberof DataTable#oApi 7666 7667 */ 7668 7669 function _fnGetMaxLenString( oSettings, iCol ) 7670 7671 { 7672 7673 var iMax = -1; 7674 7675 var iMaxIndex = -1; 7676 7677 7678 7679 for ( var i=0 ; i<oSettings.aoData.length ; i++ ) 7680 7681 { 7682 7683 var s = _fnGetCellData( oSettings, i, iCol, 'display' )+""; 7684 7685 s = s.replace( /<.*?>/g, "" ); 7686 7687 if ( s.length > iMax ) 7688 7689 { 7690 7691 iMax = s.length; 7692 7693 iMaxIndex = i; 7694 7695 } 7696 7697 } 7698 7699 7700 7701 return iMaxIndex; 7702 7703 } 7704 7705 7706 7707 7708 7709 /** 7710 7711 * Append a CSS unit (only if required) to a string 7712 7713 * @param {array} aArray1 first array 7714 7715 * @param {array} aArray2 second array 7716 7717 * @returns {int} 0 if match, 1 if length is different, 2 if no match 7718 7719 * @memberof DataTable#oApi 7720 7721 */ 7722 7723 function _fnStringToCss( s ) 7724 7725 { 7726 7727 if ( s === null ) 7728 7729 { 7730 7731 return "0px"; 7732 7733 } 7734 7735 7736 7737 if ( typeof s == 'number' ) 7738 7739 { 7740 7741 if ( s < 0 ) 7742 7743 { 7744 7745 return "0px"; 7746 7747 } 7748 7749 return s+"px"; 7750 7751 } 7752 7753 7754 7755 /* Check if the last character is not 0-9 */ 7756 7757 var c = s.charCodeAt( s.length-1 ); 7758 7759 if (c < 0x30 || c > 0x39) 7760 7761 { 7762 7763 return s; 7764 7765 } 7766 7767 return s+"px"; 7768 7769 } 7770 7771 7772 7773 7774 7775 /** 7776 7777 * Get the width of a scroll bar in this browser being used 7778 7779 * @returns {int} width in pixels 7780 7781 * @memberof DataTable#oApi 7782 7783 */ 7784 7785 function _fnScrollBarWidth () 7786 7787 { 7788 7789 var inner = document.createElement('p'); 7790 7791 var style = inner.style; 7792 7793 style.width = "100%"; 7794 7795 style.height = "200px"; 7796 7797 style.padding = "0px"; 7798 7799 7800 7801 var outer = document.createElement('div'); 7802 7803 style = outer.style; 7804 7805 style.position = "absolute"; 7806 7807 style.top = "0px"; 7808 7809 style.left = "0px"; 7810 7811 style.visibility = "hidden"; 7812 7813 style.width = "200px"; 7814 7815 style.height = "150px"; 7816 7817 style.padding = "0px"; 7818 7819 style.overflow = "hidden"; 7820 7821 outer.appendChild(inner); 7822 7823 7824 7825 document.body.appendChild(outer); 7826 7827 var w1 = inner.offsetWidth; 7828 7829 outer.style.overflow = 'scroll'; 7830 7831 var w2 = inner.offsetWidth; 7832 7833 if ( w1 == w2 ) 7834 7835 { 7836 7837 w2 = outer.clientWidth; 7838 7839 } 7840 7841 7842 7843 document.body.removeChild(outer); 7844 7845 return (w1 - w2); 7846 7847 } 7848 7849 7850 7851 /** 7852 7853 * Change the order of the table 7854 7855 * @param {object} oSettings dataTables settings object 7856 7857 * @param {bool} bApplyClasses optional - should we apply classes or not 7858 7859 * @memberof DataTable#oApi 7860 7861 */ 7862 7863 function _fnSort ( oSettings, bApplyClasses ) 7864 7865 { 7866 7867 var 7868 7869 i, iLen, j, jLen, k, kLen, 7870 7871 sDataType, nTh, 7872 7873 aaSort = [], 7874 7875 aiOrig = [], 7876 7877 oSort = DataTable.ext.oSort, 7878 7879 aoData = oSettings.aoData, 7880 7881 aoColumns = oSettings.aoColumns, 7882 7883 oAria = oSettings.oLanguage.oAria; 7884 7885 7886 7887 /* No sorting required if server-side or no sorting array */ 7888 7889 if ( !oSettings.oFeatures.bServerSide && 7890 7891 (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) ) 7892 7893 { 7894 7895 aaSort = ( oSettings.aaSortingFixed !== null ) ? 7896 7897 oSettings.aaSortingFixed.concat( oSettings.aaSorting ) : 7898 7899 oSettings.aaSorting.slice(); 7900 7901 7902 7903 /* If there is a sorting data type, and a function belonging to it, then we need to 7904 7905 * get the data from the developer's function and apply it for this column 7906 7907 */ 7908 7909 for ( i=0 ; i<aaSort.length ; i++ ) 7910 7911 { 7912 7913 var iColumn = aaSort[i][0]; 7914 7915 var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn ); 7916 7917 sDataType = oSettings.aoColumns[ iColumn ].sSortDataType; 7918 7919 if ( DataTable.ext.afnSortData[sDataType] ) 7920 7921 { 7922 7923 var aData = DataTable.ext.afnSortData[sDataType].call( 7924 7925 oSettings.oInstance, oSettings, iColumn, iVisColumn 7926 7927 ); 7928 7929 if ( aData.length === aoData.length ) 7930 7931 { 7932 7933 for ( j=0, jLen=aoData.length ; j<jLen ; j++ ) 7934 7935 { 7936 7937 _fnSetCellData( oSettings, j, iColumn, aData[j] ); 7938 7939 } 7940 7941 } 7942 7943 else 7944 7945 { 7946 7947 _fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" ); 7948 7949 } 7950 7951 } 7952 7953 } 7954 7955 7956 7957 /* Create a value - key array of the current row positions such that we can use their 7958 7959 * current position during the sort, if values match, in order to perform stable sorting 7960 7961 */ 7962
7963 for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ ) 7964 7965 { 7966 7967 aiOrig[ oSettings.aiDisplayMaster[i] ] = i; 7968 7969 } 7970 7971 7972 7973 /* Build an internal data array which is specific to the sort, so we can get and prep 7974 7975 * the data to be sorted only once, rather than needing to do it every time the sorting 7976 7977 * function runs. This make the sorting function a very simple comparison 7978 7979 */ 7980 7981 var iSortLen = aaSort.length; 7982 7983 var fnSortFormat, aDataSort; 7984 7985 for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) 7986 7987 { 7988 7989 for ( j=0 ; j<iSortLen ; j++ ) 7990 7991 { 7992 7993 aDataSort = aoColumns[ aaSort[j][0] ].aDataSort; 7994 7995 7996 7997 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 7998 7999 { 8000 8001 sDataType = aoColumns[ aDataSort[k] ].sType; 8002 8003 fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ]; 8004 8005 8006 8007 aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ? 8008 8009 fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) : 8010 8011 _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ); 8012 8013 } 8014 8015 } 8016 8017 } 8018 8019 8020 8021 /* Do the sort - here we want multi-column sorting based on a given data source (column) 8022 8023 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 8024 8025 * follow on it's own, but this is what we want (example two column sorting): 8026 8027 * fnLocalSorting = function(a,b){ 8028 8029 * var iTest; 8030 8031 * iTest = oSort['string-asc']('data11', 'data12'); 8032 8033 * if (iTest !== 0) 8034 8035 * return iTest; 8036 8037 * iTest = oSort['numeric-desc']('data21', 'data22'); 8038 8039 * if (iTest !== 0) 8040 8041 * return iTest; 8042 8043 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 8044 8045 * } 8046 8047 * Basically we have a test for each sorting column, if the data in that column is equal, 8048 8049 * test the next column. If all columns match, then we use a numeric sort on the row 8050 8051 * positions in the original data array to provide a stable sort. 8052 8053 */ 8054 8055 oSettings.aiDisplayMaster.sort( function ( a, b ) { 8056 8057 var k, l, lLen, iTest, aDataSort, sDataType; 8058 8059 for ( k=0 ; k<iSortLen ; k++ ) 8060 8061 { 8062 8063 aDataSort = aoColumns[ aaSort[k][0] ].aDataSort; 8064 8065 8066 8067 for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ ) 8068 8069 { 8070 8071 sDataType = aoColumns[ aDataSort[l] ].sType; 8072 8073 8074 8075 iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ]( 8076 8077 aoData[a]._aSortData[ aDataSort[l] ], 8078 8079 aoData[b]._aSortData[ aDataSort[l] ] 8080 8081 ); 8082 8083 8084 8085 if ( iTest !== 0 ) 8086 8087 { 8088 8089 return iTest; 8090 8091 } 8092 8093 } 8094 8095 } 8096 8097 8098 8099 return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 8100 8101 } ); 8102 8103 } 8104 8105 8106 8107 /* Alter the sorting classes to take account of the changes */ 8108 8109 if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender ) 8110 8111 { 8112 8113 _fnSortingClasses( oSettings ); 8114 8115 } 8116 8117 8118 8119 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 8120 8121 { 8122 8123 var sTitle = aoColumns[i].sTitle.replace( /<.*?>/g, "" ); 8124 8125 nTh = aoColumns[i].nTh; 8126 8127 nTh.removeAttribute('aria-sort'); 8128 8129 nTh.removeAttribute('aria-label'); 8130 8131 8132 8133 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 8134 8135 if ( aoColumns[i].bSortable ) 8136 8137 { 8138 8139 if ( aaSort.length > 0 && aaSort[0][0] == i ) 8140 8141 { 8142 8143 nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" ); 8144 8145 8146 8147 var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ? 8148 8149 aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0]; 8150 8151 nTh.setAttribute('aria-label', sTitle+ 8152 8153 (nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) ); 8154 8155 } 8156 8157 else 8158 8159 { 8160 8161 nTh.setAttribute('aria-label', sTitle+ 8162 8163 (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) ); 8164 8165 } 8166 8167 } 8168 8169 else 8170 8171 { 8172 8173 nTh.setAttribute('aria-label', sTitle); 8174 8175 } 8176 8177 } 8178 8179 8180 8181 /* Tell the draw function that we have sorted the data */ 8182 8183 oSettings.bSorted = true; 8184 8185 $(oSettings.oInstance).trigger('sort', oSettings); 8186 8187 8188 8189 /* Copy the master data into the draw array and re-draw */ 8190 8191 if ( oSettings.oFeatures.bFilter ) 8192 8193 { 8194 8195 /* _fnFilter() will redraw the table for us */ 8196 8197 _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 ); 8198 8199 } 8200 8201 else 8202 8203 { 8204 8205 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 8206 8207 oSettings._iDisplayStart = 0; /* reset display back to page 0 */ 8208 8209 _fnCalculateEnd( oSettings ); 8210 8211 _fnDraw( oSettings ); 8212 8213 } 8214 8215 } 8216 8217 8218 8219 8220 8221 /** 8222 8223 * Attach a sort handler (click) to a node 8224 8225 * @param {object} oSettings dataTables settings object 8226 8227 * @param {node} nNode node to attach the handler to 8228 8229 * @param {int} iDataIndex column sorting index 8230 8231 * @param {function}
8231 [fnCallback] callback function 8232 8233 * @memberof DataTable#oApi 8234 8235 */ 8236 8237 function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback ) 8238 8239 { 8240 8241 _fnBindAction( nNode, {}, function (e) { 8242 8243 /* If the column is not sortable - don't to anything */ 8244 8245 if ( oSettings.aoColumns[iDataIndex].bSortable === false ) 8246 8247 { 8248 8249 return; 8250 8251 } 8252 8253 8254 8255 /* 8256 8257 * This is a little bit odd I admit... I declare a temporary function inside the scope of 8258 8259 * _fnBuildHead and the click handler in order that the code presented here can be used 8260 8261 * twice - once for when bProcessing is enabled, and another time for when it is 8262 8263 * disabled, as we need to perform slightly different actions. 8264 8265 * Basically the issue here is that the Javascript engine in modern browsers don't 8266 8267 * appear to allow the rendering engine to update the display while it is still executing 8268 8269 * it's thread (well - it does but only after long intervals). This means that the 8270 8271 * 'processing' display doesn't appear for a table sort. To break the js thread up a bit 8272 8273 * I force an execution break by using setTimeout - but this breaks the expected 8274 8275 * thread continuation for the end-developer's point of view (their code would execute 8276 8277 * too early), so we only do it when we absolutely have to. 8278 8279 */ 8280 8281 var fnInnerSorting = function () { 8282 8283 var iColumn, iNextSort; 8284 8285 8286 8287 /* If the shift key is pressed then we are multiple column sorting */ 8288 8289 if ( e.shiftKey ) 8290 8291 { 8292 8293 /* Are we already doing some kind of sort on this column? */ 8294 8295 var bFound = false; 8296 8297 for ( var i=0 ; i<oSettings.aaSorting.length ; i++ ) 8298 8299 { 8300 8301 if ( oSettings.aaSorting[i][0] == iDataIndex ) 8302 8303 { 8304 8305 bFound = true; 8306 8307 iColumn = oSettings.aaSorting[i][0]; 8308 8309 iNextSort = oSettings.aaSorting[i][2]+1; 8310 8311 8312 8313 if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] ) 8314 8315 { 8316 8317 /* Reached the end of the sorting options, remove from multi-col sort */ 8318 8319 oSettings.aaSorting.splice( i, 1 ); 8320 8321 } 8322 8323 else 8324 8325 { 8326 8327 /* Move onto next sorting direction */ 8328 8329 oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort]; 8330 8331 oSettings.aaSorting[i][2] = iNextSort; 8332 8333 } 8334 8335 break; 8336 8337 } 8338 8339 } 8340 8341 8342 8343 /* No sort yet - add it in */ 8344 8345 if ( bFound === false ) 8346 8347 { 8348 8349 oSettings.aaSorting.push( [ iDataIndex, 8350 8351 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] ); 8352 8353 } 8354 8355 } 8356 8357 else 8358 8359 { 8360 8361 /* If no shift key then single column sort */ 8362 8363 if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex ) 8364 8365 { 8366 8367 iColumn = oSettings.aaSorting[0][0]; 8368 8369 iNextSort = oSettings.aaSorting[0][2]+1; 8370 8371 if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] ) 8372 8373 { 8374 8375 iNextSort = 0; 8376 8377 } 8378 8379 oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort]; 8380 8381 oSettings.aaSorting[0][2] = iNextSort; 8382 8383 } 8384 8385 else 8386 8387 { 8388 8389 oSettings.aaSorting.splice( 0, oSettings.aaSorting.length ); 8390 8391 oSettings.aaSorting.push( [ iDataIndex, 8392 8393 oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] ); 8394 8395 } 8396 8397 } 8398 8399 8400 8401 /* Run the sort */ 8402 8403 _fnSort( oSettings ); 8404 8405 }; /* /fnInnerSorting */ 8406 8407 8408 8409 if ( !oSettings.oFeatures.bProcessing ) 8410 8411 { 8412 8413 fnInnerSorting(); 8414 8415 } 8416 8417 else 8418 8419 { 8420 8421 _fnProcessingDisplay( oSettings, true ); 8422 8423 setTimeout( function() { 8424 8425 fnInnerSorting(); 8426 8427 if ( !oSettings.oFeatures.bServerSide ) 8428 8429 { 8430 8431 _fnProcessingDisplay( oSettings, false ); 8432 8433 } 8434 8435 }, 0 ); 8436 8437 } 8438 8439 8440 8441 /* Call the user specified callback function - used for async user interaction */ 8442 8443 if ( typeof fnCallback == 'function' ) 8444 8445 { 8446 8447 fnCallback( oSettings ); 8448 8449 } 8450 8451 } ); 8452 8453 } 8454 8455 8456 8457 8458 8459 /** 8460 8461 * Set the sorting classes on the header, Note: it is safe to call this function 8462 8463 * when bSort and bSortClasses are false 8464 8465 * @param {object} oSettings dataTables settings object 8466 8467 * @memberof DataTable#oApi 8468 8469 */ 8470 8471 function _fnSortingClasses( oSettings ) 8472 8473 { 8474 8475 var i, iLen, j, jLen, iFound; 8476 8477 var aaSort, sClass; 8478 8479 var iColumns = oSettings.aoColumns.length; 8480 8481 var oClasses = oSettings.oClasses; 8482 8483 8484 8485 for ( i=0 ; i<iColumns ; i++ ) 8486 8487 { 8488 8489 if ( oSettings.aoColumns[i].bSortable ) 8490 8491 { 8492
8493 $(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc + 8494 8495 " "+ oSettings.aoColumns[i].sSortingClass ); 8496 8497 } 8498 8499 } 8500 8501 8502 8503 if ( oSettings.aaSortingFixed !== null ) 8504 8505 { 8506 8507 aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting ); 8508 8509 } 8510 8511 else 8512 8513 { 8514 8515 aaSort = oSettings.aaSorting.slice(); 8516 8517 } 8518 8519 8520 8521 /* Apply the required classes to the header */ 8522 8523 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) 8524 8525 { 8526 8527 if ( oSettings.aoColumns[i].bSortable ) 8528 8529 { 8530 8531 sClass = oSettings.aoColumns[i].sSortingClass; 8532 8533 iFound = -1; 8534 8535 for ( j=0 ; j<aaSort.length ; j++ ) 8536 8537 { 8538 8539 if ( aaSort[j][0] == i ) 8540 8541 { 8542 8543 sClass = ( aaSort[j][1] == "asc" ) ? 8544 8545 oClasses.sSortAsc : oClasses.sSortDesc; 8546 8547 iFound = j; 8548 8549 break; 8550 8551 } 8552 8553 } 8554 8555 $(oSettings.aoColumns[i].nTh).addClass( sClass ); 8556 8557 8558 8559 if ( oSettings.bJUI ) 8560 8561 { 8562 8563 /* jQuery UI uses extra markup */ 8564 8565 var jqSpan = $("span."+oClasses.sSortIcon, oSettings.aoColumns[i].nTh); 8566 8567 jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+ 8568 8569 oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed ); 8570 8571 8572 8573 var sSpanClass; 8574 8575 if ( iFound == -1 ) 8576 8577 { 8578 8579 sSpanClass = oSettings.aoColumns[i].sSortingClassJUI; 8580 8581 } 8582 8583 else if ( aaSort[iFound][1] == "asc" ) 8584 8585 { 8586 8587 sSpanClass = oClasses.sSortJUIAsc; 8588 8589 } 8590 8591 else 8592 8593 { 8594 8595 sSpanClass = oClasses.sSortJUIDesc; 8596 8597 } 8598 8599 8600 8601 jqSpan.addClass( sSpanClass ); 8602 8603 } 8604 8605 } 8606 8607 else 8608 8609 { 8610 8611 /* No sorting on this column, so add the base class. This will have been assigned by 8612 8613 * _fnAddColumn 8614 8615 */ 8616 8617 $(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass ); 8618 8619 } 8620 8621 } 8622 8623 8624 8625 /* 8626 8627 * Apply the required classes to the table body 8628 8629 * Note that this is given as a feature switch since it can significantly slow down a sort 8630 8631 * on large data sets (adding and removing of classes is always slow at the best of times..) 8632 8633 * Further to this, note that this code is admittedly fairly ugly. It could be made a lot 8634 8635 * simpler using jQuery selectors and add/removeClass, but that is significantly slower 8636 8637 * (on the order of 5 times slower) - hence the direct DOM manipulation here. 8638 8639 * Note that for deferred drawing we do use jQuery - the reason being that taking the first 8640 8641 * row found to see if the whole column needs processed can miss classes since the first 8642 8643 * column might be new. 8644 8645 */ 8646 8647 sClass = oClasses.sSortColumn; 8648 8649 8650 8651 if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses ) 8652 8653 { 8654 8655 var nTds = _fnGetTdNodes( oSettings ); 8656 8657 8658 8659 /* Determine what the sorting class for each column should be */ 8660 8661 var iClass, iTargetCol; 8662 8663 var asClasses = []; 8664 8665 for (i = 0; i < iColumns; i++) 8666 8667 { 8668 8669 asClasses.push(""); 8670 8671 } 8672 8673 for (i = 0, iClass = 1; i < aaSort.length; i++) 8674 8675 { 8676 8677 iTargetCol = parseInt( aaSort[i][0], 10 ); 8678 8679 asClasses[iTargetCol] = sClass + iClass; 8680 8681 8682 8683 if ( iClass < 3 ) 8684 8685 { 8686 8687 iClass++; 8688 8689 } 8690 8691 } 8692 8693 8694 8695 /* Make changes to the classes for each cell as needed */ 8696 8697 var reClass = new RegExp(sClass + "[123]"); 8698 8699 var sTmpClass, sCurrentClass, sNewClass; 8700 8701 for ( i=0, iLen=nTds.length; i<iLen; i++ ) 8702 8703 { 8704 8705 /* Determine which column we're looking at */ 8706 8707 iTargetCol = i % iColumns; 8708 8709 8710 8711 /* What is the full list of classes now */ 8712 8713 sCurrentClass = nTds[i].className; 8714 8715 /* What sorting class should be applied? */ 8716 8717 sNewClass = asClasses[iTargetCol]; 8718 8719 /* What would the new full list be if we did a replacement? */ 8720 8721 sTmpClass = sCurrentClass.replace(reClass, sNewClass); 8722 8723 8724 8725 if ( sTmpClass != sCurrentClass ) 8726 8727 { 8728 8729 /* We changed something */ 8730 8731 nTds[i].className = $.trim( sTmpClass ); 8732 8733 } 8734 8735 else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 ) 8736 8737 { 8738 8739 /* We need to add a class */ 8740 8741 nTds[i].className = sCurrentClass + " " + sNewClass; 8742 8743 } 8744 8745 } 8746 8747 } 8748 8749 } 8750 8751 8752 8753 8754 8755 8756 8757 /** 8758 8759 * Save the state of a table in a cookie such that the page can be reloaded 8760 8761 * @param {object} oSettings dataTables settings object 8762 8763 * @memberof DataTable#oApi 8764 8765 */ 8766 8767 function _fnSaveState ( oSettings ) 8768 8769 { 8770 8771 if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying ) 8772 8773 { 8774 8775 return; 8776 8777 } 8778 8779 8780 8781 /* Store the interesting variables */ 8782 8783 var i, iLen, bInfinite=oSettings.oScroll.bInfinite; 8784 8785 var oState = { 8786 8787 "iCreate": new Date().getTime(), 8788 8789 "iStart": (bInfinite ? 0 : oSettings._iDisplayStart), 8790 8791 "iEnd": (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd), 8792 8793 "iLength": oSettings._iDisplayLength, 8794 8795 "aaSorting": $.extend( true, [], oSettings.aaSorting ), 8796 8797 "oSearch": $.extend( true, {}, oSettings.oPreviousSearch ), 8798 8799 "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ), 8800 8801 "abVisCols": [] 8802 8803 }; 8804 8805 8806
8807 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 8808 8809 { 8810 8811 oState.abVisCols.push( oSettings.aoColumns[i].bVisible ); 8812 8813 } 8814 8815 8816 8817 _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] ); 8818 8819 8820 8821 oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState ); 8822 8823 } 8824 8825 8826 8827 8828 8829 /** 8830 8831 * Attempt to load a saved table state from a cookie 8832 8833 * @param {object} oSettings dataTables settings object 8834 8835 * @param {object} oInit DataTables init object so we can override settings 8836 8837 * @memberof DataTable#oApi 8838 8839 */ 8840 8841 function _fnLoadState ( oSettings, oInit ) 8842 8843 { 8844 8845 if ( !oSettings.oFeatures.bStateSave ) 8846 8847 { 8848 8849 return; 8850 8851 } 8852 8853 8854 8855 var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings ); 8856 8857 if ( !oData ) 8858 8859 { 8860 8861 return; 8862 8863 } 8864 8865 8866 8867 /* Allow custom and plug-in manipulation functions to alter the saved data set and 8868 8869 * cancelling of loading by returning false 8870 8871 */ 8872 8873 var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] ); 8874 8875 if ( $.inArray( false, abStateLoad ) !== -1 ) 8876 8877 { 8878 8879 return; 8880 8881 } 8882 8883 8884 8885 /* Store the saved state so it might be accessed at any time */ 8886 8887 oSettings.oLoadedState = $.extend( true, {}, oData ); 8888 8889 8890 8891 /* Restore key features */ 8892 8893 oSettings._iDisplayStart = oData.iStart; 8894 8895 oSettings.iInitDisplayStart = oData.iStart; 8896 8897 oSettings._iDisplayEnd = oData.iEnd; 8898 8899 oSettings._iDisplayLength = oData.iLength; 8900 8901 oSettings.aaSorting = oData.aaSorting.slice(); 8902 8903 oSettings.saved_aaSorting = oData.aaSorting.slice(); 8904 8905 8906 8907 /* Search filtering */ 8908 8909 $.extend( oSettings.oPreviousSearch, oData.oSearch ); 8910 8911 $.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols ); 8912 8913 8914 8915 /* Column visibility state 8916 8917 * Pass back visibility settings to the init handler, but to do not here override 8918 8919 * the init object that the user might have passed in 8920 8921 */ 8922 8923 oInit.saved_aoColumns = []; 8924 8925 for ( var i=0 ; i<oData.abVisCols.length ; i++ ) 8926 8927 { 8928 8929 oInit.saved_aoColumns[i] = {}; 8930 8931 oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i]; 8932 8933 } 8934 8935 8936 8937 _fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] ); 8938 8939 } 8940 8941 8942 8943 8944 8945 /** 8946 8947 * Create a new cookie with a value to store the state of a table 8948 8949 * @param {string} sName name of the cookie to create 8950 8951 * @param {string} sValue the value the cookie should take 8952 8953 * @param {int} iSecs duration of the cookie 8954 8955 * @param {string} sBaseName sName is made up of the base + file name - this is the base 8956 8957 * @param {function} fnCallback User definable function to modify the cookie 8958 8959 * @memberof DataTable#oApi 8960 8961 */ 8962 8963 function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback ) 8964 8965 { 8966 8967 var date = new Date(); 8968 8969 date.setTime( date.getTime()+(iSecs*1000) ); 8970 8971 8972 8973 /* 8974 8975 * Shocking but true - it would appear IE has major issues with having the path not having 8976 8977 * a trailing slash on it. We need the cookie to be available based on the path, so we 8978 8979 * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the 8980 8981 * patch to use at least some of the path 8982 8983 */ 8984 8985 var aParts = window.location.pathname.split('/'); 8986 8987 var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase(); 8988 8989 var sFullCookie, oData; 8990 8991 8992 8993 if ( fnCallback !== null ) 8994 8995 { 8996 8997 oData = (typeof $.parseJSON === 'function') ? 8998 8999 $.parseJSON( sValue ) : eval( '('+sValue+')' ); 9000 9001 sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(), 9002 9003 aParts.join('/')+"/" ); 9004 9005 } 9006 9007 else 9008 9009 { 9010 9011 sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) + 9012 9013 "; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/"; 9014 9015 } 9016 9017 9018 9019 /* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies 9020 9021 * belonging to DataTables. 9022 9023 */ 9024 9025 var 9026 9027 aCookies =document.cookie.split(';'), 9028 9029 iNewCookieLen = sFullCookie.split(';')[0].length, 9030 9031 aOldCookies = []; 9032 9033 9034 9035 if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */ 9036 9037 { 9038
9039 for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ ) 9040 9041 { 9042 9043 if ( aCookies[i].indexOf( sBaseName ) != -1 ) 9044 9045 { 9046 9047 /* It's a DataTables cookie, so eval it and check the time stamp */ 9048 9049 var aSplitCookie = aCookies[i].split('='); 9050 9051 try { 9052 9053 oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' ); 9054 9055 9056 9057 if ( oData && oData.iCreate ) 9058 9059 { 9060 9061 aOldCookies.push( { 9062 9063 "name": aSplitCookie[0], 9064 9065 "time": oData.iCreate 9066 9067 } ); 9068 9069 } 9070 9071 } 9072 9073 catch( e ) {} 9074 9075 } 9076 9077 } 9078 9079 9080 9081 // Make sure we delete the oldest ones first 9082 9083 aOldCookies.sort( function (a, b) { 9084 9085 return b.time - a.time; 9086 9087 } ); 9088 9089 9090 9091 // Eliminate as many old DataTables cookies as we need to 9092 9093 while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) { 9094 9095 if ( aOldCookies.length === 0 ) { 9096 9097 // Deleted all DT cookies and still not enough space. Can't state save 9098 9099 return; 9100 9101 } 9102 9103 9104 9105 var old = aOldCookies.pop(); 9106 9107 document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+ 9108 9109 aParts.join('/') + "/"; 9110 9111 } 9112 9113 } 9114 9115 9116 9117 document.cookie = sFullCookie; 9118 9119 } 9120 9121 9122 9123 9124 9125 /** 9126 9127 * Read an old cookie to get a cookie with an old table state 9128 9129 * @param {string} sName name of the cookie to read 9130 9131 * @returns {string} contents of the cookie - or null if no cookie with that name found 9132 9133 * @memberof DataTable#oApi 9134 9135 */ 9136 9137 function _fnReadCookie ( sName ) 9138 9139 { 9140 9141 var 9142 9143 aParts = window.location.pathname.split('/'), 9144 9145 sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=', 9146 9147 sCookieContents = document.cookie.split(';'); 9148 9149 9150 9151 for( var i=0 ; i<sCookieContents.length ; i++ ) 9152 9153 { 9154 9155 var c = sCookieContents[i]; 9156 9157 9158 9159 while (c.charAt(0)==' ') 9160 9161 { 9162 9163 c = c.substring(1,c.length); 9164 9165 } 9166 9167 9168 9169 if (c.indexOf(sNameEQ) === 0) 9170 9171 { 9172 9173 return decodeURIComponent( c.substring(sNameEQ.length,c.length) ); 9174 9175 } 9176 9177 } 9178 9179 return null; 9180 9181 } 9182 9183 9184 9185 9186 9187 /** 9188 9189 * Return the settings object for a particular table 9190 9191 * @param {node} nTable table we are using as a dataTable 9192 9193 * @returns {object} Settings object - or null if not found 9194 9195 * @memberof DataTable#oApi 9196 9197 */ 9198 9199 function _fnSettingsFromNode ( nTable ) 9200 9201 { 9202 9203 for ( var i=0 ; i<DataTable.settings.length ; i++ ) 9204 9205 { 9206 9207 if ( DataTable.settings[i].nTable === nTable ) 9208 9209 { 9210 9211 return DataTable.settings[i]; 9212 9213 } 9214 9215 } 9216 9217 9218 9219 return null; 9220 9221 } 9222 9223 9224 9225 9226 9227 /** 9228 9229 * Return an array with the TR nodes for the table 9230 9231 * @param {object} oSettings dataTables settings object 9232 9233 * @returns {array} TR array 9234 9235 * @memberof DataTable#oApi 9236 9237 */ 9238 9239 function _fnGetTrNodes ( oSettings ) 9240 9241 { 9242 9243 var aNodes = []; 9244 9245 var aoData = oSettings.aoData; 9246 9247 for ( var i=0, iLen=aoData.length ; i<iLen ; i++ ) 9248 9249 { 9250 9251 if ( aoData[i].nTr !== null ) 9252 9253 { 9254 9255 aNodes.push( aoData[i].nTr ); 9256 9257 } 9258 9259 } 9260 9261 return aNodes; 9262 9263 } 9264 9265 9266 9267 9268 9269 /** 9270 9271 * Return an flat array with all TD nodes for the table, or row 9272 9273 * @param {object} oSettings dataTables settings object 9274 9275 * @param {int} [iIndividualRow] aoData index to get the nodes for - optional 9276 9277 * if not given then the return array will contain all nodes for the table 9278 9279 * @returns {array} TD array 9280 9281 * @memberof DataTable#oApi 9282 9283 */ 9284 9285 function _fnGetTdNodes ( oSettings, iIndividualRow ) 9286 9287 { 9288 9289 var anReturn = []; 9290 9291 var iCorrector; 9292 9293 var anTds, nTd; 9294 9295 var iRow, iRows=oSettings.aoData.length, 9296 9297 iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows; 9298 9299 9300 9301 /* Allow the collection to be limited to just one row */ 9302 9303 if ( iIndividualRow !== undefined ) 9304 9305 { 9306 9307 iStart = iIndividualRow; 9308 9309 iEnd = iIndividualRow+1; 9310 9311 } 9312 9313 9314 9315 for ( iRow=iStart ; iRow<iEnd ; iRow++ ) 9316 9317 { 9318 9319 oData = oSettings.aoData[iRow]; 9320 9321 if ( oData.nTr !== null ) 9322 9323 { 9324 9325 /* get the TD child nodes - taking into account text etc nodes */ 9326 9327 anTds = []; 9328 9329 nTd = oData.nTr.firstChild; 9330 9331 while ( nTd ) 9332 9333 { 9334 9335 sNodeName = nTd.nodeName.toLowerCase(); 9336 9337 if ( sNodeName == 'td' || sNodeName == 'th' ) 9338 9339 { 9340 9341 anTds.push( nTd ); 9342 9343 } 9344 9345 nTd = nTd.nextSibling; 9346 9347 } 9348 9349 9350 9351 iCorrector = 0; 9352 9353 for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ ) 9354 9355 { 9356 9357 if ( oSettings.aoColumns[iColumn].bVisible ) 9358 9359 { 9360 9361 anReturn.push( anTds[iColumn-iCorrector] ); 9362 9363 } 9364 9365 else 9366 9367 { 9368 9369 anReturn.push( oData._anHidden[iColumn] ); 9370 9371 iCorrector++; 9372 9373 } 9374 9375 } 9376 9377 } 9378 9379 } 9380 9381 9382 9383 return anReturn; 9384 9385 } 9386 9387 9388 9389 9390 9391 /** 9392 9393 * Log an error message 9394 9395 * @param {object} oSettings dataTables settings object 9396 9397 * @param {int} iLevel log error messages, or display them to the user 9398 9399 * @param {string} sMesg error message 9400 9401 * @memberof DataTable#oApi 9402 9403 */ 9404 9405 function _fnLog( oSettings, iLevel, sMesg ) 9406 9407 { 9408 9409 var sAlert = (oSettings===null) ? 9410 9411 "DataTables warning: "+sMesg : 9412 9413 "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg; 9414 9415 9416 9417 if ( iLevel === 0 ) 9418 9419 { 9420 9421 if ( DataTable.ext.sErrMode == 'alert' ) 9422 9423 { 9424 9425 alert( sAlert ); 9426 9427 } 9428 9429 else 9430 9431 { 9432 9433 throw new Error(sAlert); 9434 9435 } 9436 9437 return; 9438 9439 } 9440 9441 else if ( window.console && console.log ) 9442 9443 { 9444 9445 console.log( sAlert ); 9446 9447 } 9448 9449 } 9450 9451 9452 9453 9454 9455 /** 9456 9457 * See if a property is defined on one object, if so assign it to the other object 9458 9459 * @param {object} oRet target object 9460 9461 * @param {object} oSrc source object 9462 9463 * @param {string} sName property 9464 9465 * @param {string} [sMappedName] name to map too - optional, sName used if not given 9466 9467 * @memberof DataTable#oApi 9468 9469 */ 9470 9471 function _fnMap( oRet, oSrc, sName, sMappedName ) 9472 9473 { 9474 9475 if ( sMappedName === undefined ) 9476 9477 { 9478 9479 sMappedName = sName; 9480 9481 } 9482 9483 if ( oSrc[sName] !== undefined ) 9484 9485 { 9486 9487 oRet[sMappedName] = oSrc[sName]; 9488 9489 } 9490 9491 } 9492 9493 9494 9495 9496 9497 /** 9498 9499 * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow 9500 9501 * copy arrays. The reason we need to do this, is that we don't want to deep copy array 9502 9503 * init values (such as aaSorting) since the dev wouldn't be able to override them, but 9504 9505 * we do want to deep copy arrays. 9506 9507 * @param {object} oOut Object to extend 9508 9509 * @param {object} oExtender Object from which the properties will be applied to oOut 9510 9511 * @returns {object} oOut Reference, just for convenience - oOut === the return. 9512 9513 * @memberof DataTable#oApi 9514 9515 * @todo This doesn't take account of arrays inside the deep copied objects. 9516 9517 */ 9518 9519 function _fnExtend( oOut, oExtender ) 9520 9521 { 9522 9523 var val; 9524 9525 9526 9527 for ( var prop in oExtender ) 9528 9529 { 9530 9531 if ( oExtender.hasOwnProperty(prop) ) 9532 9533 { 9534 9535 val = oExtender[prop]; 9536 9537 9538 9539 if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false ) 9540 9541 { 9542 9543 $.extend( true, oOut[prop], val ); 9544 9545 } 9546 9547 else 9548 9549 { 9550 9551 oOut[prop] = val; 9552 9553 } 9554 9555 } 9556 9557 } 9558 9559 9560 9561 return oOut; 9562 9563 } 9564 9565 9566 9567 9568 9569 /** 9570 9571 * Bind an event handers to allow a click or return key to activate the callback. 9572 9573 * This is good for accessibility since a return on the keyboard will have the 9574 9575 * same effect as a click, if the element has focus. 9576 9577 * @param {element} n Element to bind the action to 9578 9579 * @param {object} oData Data object to pass to the triggered function 9580 9581 * @param {function} fn Callback function for when the event is triggered 9582 9583 * @memberof DataTable#oApi 9584 9585 */ 9586 9587 function _fnBindAction( n, oData, fn ) 9588 9589 { 9590 9591 $(n) 9592 9593 .bind( 'click.DT', oData, function (e) { 9594 9595 n.blur(); // Remove focus outline for mouse users 9596 9597 fn(e); 9598 9599 } ) 9600 9601 .bind( 'keypress.DT', oData, function (e){ 9602 9603 if ( e.which === 13 ) { 9604 9605 fn(e); 9606 9607 } } ) 9608 9609 .bind( 'selectstart.DT', function () { 9610 9611 /* Take the brutal approach to cancelling text selection */ 9612 9613 return false; 9614 9615 } ); 9616 9617 } 9618 9619 9620 9621 9622 9623 /** 9624 9625 * Register a callback function. Easily allows a callback function to be added to 9626 9627 * an array store of callback functions that can then all be called together. 9628 9629 * @param {object} oSettings dataTables settings object 9630 9631 * @param {string} sStore Name of the array storage for the callbacks in oSettings 9632 9633 * @param {function} fn Function to be called back 9634 9635 * @param {string} sName Identifying name for the callback (i.e. a label) 9636 9637 * @memberof DataTable#oApi 9638 9639 */ 9640 9641 function _fnCallbackReg( oSettings, sStore, fn, sName ) 9642 9643 { 9644 9645 if ( fn ) 9646 9647 { 9648 9649 oSettings[sStore].push( { 9650 9651 "fn": fn, 9652 9653 "sName": sName 9654 9655 } ); 9656 9657 } 9658 9659 } 9660 9661 9662 9663 9664 9665 /** 9666 9667 * Fire callback functions and trigger Businesses. Note that the loop over the callback 9668 9669 * array store is done backwards! Further note that you do not want to fire off triggers 9670 9671 * in time sensitive applications (for example cell creation) as its slow. 9672 9673 * @param {object} oSettings dataTables settings object 9674 9675 * @param {string} sStore Name of the array storage for the callbacks in oSettings 9676 9677 * @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger 9678 9679 * is fired 9680 9681 * @param {array} aArgs Array of arguments to pass to the callback function / trigger 9682 9683 * @memberof DataTable#oApi 9684 9685 */ 9686 9687 function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs ) 9688 9689 { 9690 9691 var aoStore = oSettings[sStore]; 9692 9693 var aRet =[]; 9694 9695 9696 9697 for ( var i=aoStore.length-1 ; i>=0 ; i-- ) 9698 9699 { 9700 9701 aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) ); 9702 9703 } 9704 9705 9706 9707 if ( sTrigger !== null ) 9708 9709 { 9710 9711 $(oSettings.oInstance).trigger(sTrigger, aArgs); 9712 9713 } 9714 9715 9716 9717 return aRet; 9718 9719 } 9720 9721 9722 9723 9724 9725 /** 9726 9727 * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other 9728 9729 * library, then we use that as it is fast, safe and accurate. If the function isn't 9730 9731 * available then we need to built it ourselves - the inspiration for this function comes 9732 9733 * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is 9734 9735 * not perfect and absolutely should not be used as a replacement to json2.js - but it does 9736 9737 * do what we need, without requiring a dependency for DataTables. 9738 9739 * @param {object} o JSON object to be converted 9740 9741 * @returns {string} JSON string 9742 9743 * @memberof DataTable#oApi 9744 9745 */ 9746 9747 var _fnJsonString = (window.JSON) ? JSON.stringify : function( o ) 9748 9749 { 9750 9751 /* Not an object or array */ 9752 9753 var sType = typeof o; 9754 9755 if (sType !== "object" || o === null) 9756 9757 { 9758 9759 // simple data type 9760 9761 if (sType === "string") 9762 9763 { 9764 9765 o = '"'+o+'"'; 9766 9767 } 9768 9769 return o+""; 9770 9771 } 9772 9773 9774 9775 /* If object or array, need to recurse over it */ 9776 9777 var 9778
9779 sProp, mValue, 9780 9781 json = [], 9782 9783 bArr = $.isArray(o); 9784 9785 9786 9787 for (sProp in o) 9788 9789 { 9790 9791 mValue = o[sProp]; 9792 9793 sType = typeof mValue; 9794 9795 9796 9797 if (sType === "string") 9798 9799 { 9800 9801 mValue = '"'+mValue+'"'; 9802 9803 } 9804 9805 else if (sType === "object" && mValue !== null) 9806 9807 { 9808 9809 mValue = _fnJsonString(mValue); 9810 9811 } 9812 9813 9814 9815 json.push((bArr ? "" : '"'+sProp+'":') + mValue); 9816 9817 } 9818 9819 9820 9821 return (bArr ? "[" : "{") + json + (bArr ? "]" : "}"); 9822 9823 }; 9824 9825 9826 9827 9828 9829 /** 9830 9831 * From some browsers (specifically IE6/7) we need special handling to work around browser 9832 9833 * bugs - this function is used to detect when these workarounds are needed. 9834 9835 * @param {object} oSettings dataTables settings object 9836 9837 * @memberof DataTable#oApi 9838 9839 */ 9840 9841 function _fnBrowserDetect( oSettings ) 9842 9843 { 9844 9845 /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the 9846 9847 * width of the scrollbar, while other browsers ensure the inner element is contained 9848 9849 * without forcing scrolling 9850 9851 */ 9852 9853 var n = $( 9854 9855 '<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+ 9856 9857 '<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+ 9858 9859 '<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+ 9860 9861 '</div>'+ 9862 9863 '</div>')[0]; 9864 9865 9866 9867 document.body.appendChild( n ); 9868 9869 oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false; 9870 9871 document.body.removeChild( n ); 9872 9873 } 9874 9875 9876 9877 9878 9879 /** 9880 9881 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 9882 9883 * return the resulting jQuery object. 9884 9885 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 9886 9887 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 9888 9889 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 9890 9891 * criterion ("applied") or all TR elements (i.e. no filter). 9892 9893 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 9894 9895 * Can be either 'current', whereby the current sorting of the table is used, or 9896 9897 * 'original' whereby the original order the data was read into the table is used. 9898 9899 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 9900 9901 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 9902 9903 * 'current' and filter is 'applied', regardless of what they might be given as. 9904 9905 * @returns {object} jQuery object, filtered by the given selector. 9906 9907 * @dtopt API 9908 9909 * 9910 9911 * @example 9912 9913 * $(document).ready(function() { 9914 9915 * var oTable = $('#example').dataTable(); 9916 9917 * 9918 9919 * // Highlight every second row 9920 9921 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 9922 9923 * } ); 9924 9925 * 9926 9927 * @example 9928 9929 * $(document).ready(function() { 9930 9931 * var oTable = $('#example').dataTable(); 9932 9933 * 9934 9935 * // Filter to rows with 'Webkit' in them, add a background colour and then 9936 9937 * // remove the filter, thus highlighting the 'Webkit' rows only. 9938 9939 * oTable.fnFilter('Webkit'); 9940 9941 * oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue'); 9942 9943 * oTable.fnFilter(''); 9944 9945 * } ); 9946 9947 */ 9948 9949 this.$ = function ( sSelector, oOpts ) 9950 9951 { 9952 9953 var i, iLen, a = [], tr; 9954 9955 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 9956 9957 var aoData = oSettings.aoData; 9958 9959 var aiDisplay = oSettings.aiDisplay; 9960 9961 var aiDisplayMaster = oSettings.aiDisplayMaster; 9962 9963 9964 9965 if ( !oOpts ) 9966 9967 { 9968 9969 oOpts = {}; 9970 9971 } 9972 9973 9974 9975 oOpts = $.extend( {}, { 9976 9977 "filter": "none", // applied 9978 9979 "order": "current", // "original" 9980 9981 "page": "all" // current 9982 9983 }, oOpts ); 9984 9985 9986 9987 // Current page implies that order=current and fitler=applied, since it is fairly 9988 9989 // senseless otherwise 9990 9991 if ( oOpts.page == 'current' ) 9992 9993 { 9994
9995 for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ ) 9996 9997 { 9998 9999 tr = aoData[ aiDisplay[i] ].nTr; 10000 10001 if ( tr ) 10002 10003 { 10004 10005 a.push( tr ); 10006 10007 } 10008 10009 } 10010 10011 } 10012 10013 else if ( oOpts.order == "current" && oOpts.filter == "none" ) 10014 10015 { 10016 10017 for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ ) 10018 10019 { 10020 10021 tr = aoData[ aiDisplayMaster[i] ].nTr; 10022 10023 if ( tr ) 10024 10025 { 10026 10027 a.push( tr ); 10028 10029 } 10030 10031 } 10032 10033 } 10034 10035 else if ( oOpts.order == "current" && oOpts.filter == "applied" ) 10036 10037 { 10038 10039 for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ ) 10040 10041 { 10042 10043 tr = aoData[ aiDisplay[i] ].nTr; 10044 10045 if ( tr ) 10046 10047 { 10048 10049 a.push( tr ); 10050 10051 } 10052 10053 } 10054 10055 } 10056 10057 else if ( oOpts.order == "original" && oOpts.filter == "none" ) 10058 10059 { 10060 10061 for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) 10062 10063 { 10064 10065 tr = aoData[ i ].nTr ; 10066 10067 if ( tr ) 10068 10069 { 10070 10071 a.push( tr ); 10072 10073 } 10074 10075 } 10076 10077 } 10078 10079 else if ( oOpts.order == "original" && oOpts.filter == "applied" ) 10080 10081 { 10082 10083 for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) 10084 10085 { 10086 10087 tr = aoData[ i ].nTr; 10088 10089 if ( $.inArray( i, aiDisplay ) !== -1 && tr ) 10090 10091 { 10092 10093 a.push( tr ); 10094 10095 } 10096 10097 } 10098 10099 } 10100 10101 else 10102 10103 { 10104 10105 _fnLog( oSettings, 1, "Unknown selection options" ); 10106 10107 } 10108 10109 10110 10111 /* We need to filter on the TR elements and also 'find' in their descendants 10112 10113 * to make the selector act like it would in a full table - so we need 10114 10115 * to build both results and then combine them together 10116 10117 */ 10118 10119 var jqA = $(a); 10120 10121 var jqTRs = jqA.filter( sSelector ); 10122 10123 var jqDescendants = jqA.find( sSelector ); 10124 10125 10126 10127 return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) ); 10128 10129 }; 10130 10131 10132 10133 10134 10135 /** 10136 10137 * Almost identical to $ in operation, but in this case returns the data for the matched 10138 10139 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 10140 10141 * rather than any descendants, so the data can be obtained for the row/cell. If matching 10142 10143 * rows are found, the data returned is the original data array/object that was used to 10144 10145 * create the row (or a generated array if from a DOM source). 10146 10147 * 10148 10149 * This method is often useful in-combination with $ where both functions are given the 10150 10151 * same parameters and the array indexes will match identically. 10152 10153 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 10154 10155 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 10156 10157 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 10158 10159 * criterion ("applied") or all elements (i.e. no filter). 10160 10161 * @param {string} [oOpts.order=current] Order of the data in the processed array. 10162 10163 * Can be either 'current', whereby the current sorting of the table is used, or 10164 10165 * 'original' whereby the original order the data was read into the table is used. 10166 10167 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 10168 10169 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 10170 10171 * 'current' and filter is 'applied', regardless of what they might be given as. 10172 10173 * @returns {array} Data for the matched elements. If any elements, as a result of the 10174 10175 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 10176 10177 * entry in the array. 10178 10179 * @dtopt API 10180 10181 * 10182 10183 * @example 10184 10185 * $(document).ready(function() { 10186 10187 * var oTable = $('#example').dataTable(); 10188 10189 * 10190 10191 * // Get the data from the first row in the table 10192 10193 * var data = oTable._('tr:first'); 10194 10195 * 10196 10197 * // Do something useful with the data 10198 10199 * alert( "First cell is: "+data[0] ); 10200 10201 * } ); 10202 10203 * 10204 10205 * @example 10206 10207 * $(document).ready(function() { 10208 10209 * var oTable = $('#example').dataTable(); 10210 10211 * 10212 10213 * // Filter to 'Webkit' and get all data for 10214 10215 * oTable.fnFilter('Webkit'); 10216 10217 * var data = oTable._('tr', {"filter": "applied"});
10218 10219 * 10220 10221 * // Do something with the data 10222 10223 * alert( data.length+" rows matched the filter" ); 10224 10225 * } ); 10226 10227 */ 10228 10229 this._ = function ( sSelector, oOpts ) 10230 10231 { 10232 10233 var aOut = []; 10234 10235 var i, iLen, iIndex; 10236 10237 var aTrs = this.$( sSelector, oOpts ); 10238 10239 10240 10241 for ( i=0, iLen=aTrs.length ; i<iLen ; i++ ) 10242 10243 { 10244 10245 aOut.push( this.fnGetData(aTrs[i]) ); 10246 10247 } 10248 10249 10250 10251 return aOut; 10252 10253 }; 10254 10255 10256 10257 10258 10259 /** 10260 10261 * Add a single new row or multiple rows of data to the table. Please note 10262 10263 * that this is suitable for client-side processing only - if you are using 10264 10265 * server-side processing (i.e. "bServerSide": true), then to add data, you 10266 10267 * must add it to the data source, i.e. the server-side, through an Ajax call. 10268 10269 * @param {array|object} mData The data to be added to the table. This can be: 10270 10271 * <ul> 10272 10273 * <li>1D array of data - add a single row with the data provided</li> 10274 10275 * <li>2D array of arrays - add multiple rows in a single call</li> 10276 10277 * <li>object - data object when using <i>mData</i></li> 10278 10279 * <li>array of objects - multiple data objects when using <i>mData</i></li> 10280 10281 * </ul> 10282 10283 * @param {bool} [bRedraw=true] redraw the table or not 10284 10285 * @returns {array} An array of integers, representing the list of indexes in 10286 10287 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 10288 10289 * the table. 10290 10291 * @dtopt API 10292 10293 * 10294 10295 * @example 10296 10297 * // Global var for counter 10298 10299 * var giCount = 2; 10300 10301 * 10302 10303 * $(document).ready(function() { 10304 10305 * $('#example').dataTable(); 10306 10307 * } ); 10308 10309 * 10310 10311 * function fnClickAddRow() { 10312 10313 * $('#example').dataTable().fnAddData( [ 10314 10315 * giCount+".1", 10316 10317 * giCount+".2", 10318 10319 * giCount+".3", 10320 10321 * giCount+".4" ] 10322 10323 * ); 10324 10325 * 10326 10327 * giCount++; 10328 10329 * } 10330 10331 */ 10332 10333 this.fnAddData = function( mData, bRedraw ) 10334 10335 { 10336 10337 if ( mData.length === 0 ) 10338 10339 { 10340 10341 return []; 10342 10343 } 10344 10345 10346 10347 var aiReturn = []; 10348 10349 var iTest; 10350 10351 10352 10353 /* Find settings from table node */ 10354 10355 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 10356 10357 10358 10359 /* Check if we want to add multiple rows or not */ 10360 10361 if ( typeof mData[0] === "object" && mData[0] !== null ) 10362 10363 { 10364 10365 for ( var i=0 ; i<mData.length ; i++ ) 10366 10367 { 10368 10369 iTest = _fnAddData( oSettings, mData[i] ); 10370 10371 if ( iTest == -1 ) 10372 10373 { 10374 10375 return aiReturn; 10376 10377 } 10378 10379 aiReturn.push( iTest ); 10380 10381 } 10382 10383 } 10384 10385 else 10386 10387 { 10388 10389 iTest = _fnAddData( oSettings, mData ); 10390 10391 if ( iTest == -1 ) 10392 10393 { 10394 10395 return aiReturn; 10396 10397 } 10398 10399 aiReturn.push( iTest ); 10400 10401 } 10402 10403 10404 10405 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 10406 10407 10408 10409 if ( bRedraw === undefined || bRedraw ) 10410 10411 { 10412 10413 _fnReDraw( oSettings ); 10414 10415 } 10416 10417 return aiReturn; 10418 10419 }; 10420 10421 10422 10423 10424 10425 /** 10426 10427 * This function will make DataTables recalculate the column sizes, based on the data 10428 10429 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 10430 10431 * through the sWidth parameter). This can be useful when the width of the table's 10432 10433 * parent element changes (for example a window resize). 10434 10435 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 10436 10437 * @dtopt API 10438 10439 * 10440 10441 * @example 10442 10443 * $(document).ready(function() { 10444 10445 * var oTable = $('#example').dataTable( { 10446 10447 * "sScrollY": "200px", 10448 10449 * "bPaginate": false 10450 10451 * } ); 10452 10453 * 10454 10455 * $(window).bind('resize', function () { 10456 10457 * oTable.fnAdjustColumnSizing(); 10458 10459 * } ); 10460 10461 * } ); 10462 10463 */ 10464 10465 this.fnAdjustColumnSizing = function ( bRedraw ) 10466 10467 { 10468 10469 var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]); 10470 10471 _fnAdjustColumnSizing( oSettings ); 10472 10473 10474 10475 if ( bRedraw === undefined || bRedraw ) 10476 10477 { 10478 10479 this.fnDraw( false ); 10480 10481 } 10482 10483 else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" ) 10484 10485 { 10486 10487 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 10488 10489 this.oApi._fnScrollDraw(oSettings); 10490 10491 } 10492 10493 }; 10494 10495 10496 10497 10498 10499 /** 10500 10501 * Quickly and simply clear a table 10502 10503 * @param {bool} [bRedraw=true] redraw the table or not 10504 10505 * @dtopt API 10506 10507 * 10508 10509 * @example 10510 10511 * $(document).ready(function() { 10512 10513 * var oTable = $('#example').dataTable(); 10514 10515 * 10516 10517 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 10518 10519 * oTable.fnClearTable(); 10520 10521 * } ); 10522 10523 */ 10524 10525 this.fnClearTable = function( bRedraw ) 10526 10527 { 10528 10529 /* Find settings from table node */ 10530 10531 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 10532 10533 _fnClearTable( oSettings ); 10534 10535 10536 10537 if ( bRedraw === undefined || bRedraw ) 10538 10539 { 10540 10541 _fnDraw( oSettings ); 10542 10543 } 10544 10545 }; 10546 10547 10548 10549 10550 10551 /** 10552 10553 * The exact opposite of 'opening' a row, this function will close any rows which 10554 10555 * are currently 'open'. 10556 10557 * @param {node} nTr the table row to 'close' 10558 10559 * @returns {int} 0 on success, or 1 if failed (can't find the row) 10560 10561 * @dtopt API 10562 10563 * 10564 10565 * @example 10566 10567 * $(document).ready(function() { 10568 10569 * var oTable; 10570 10571 * 10572 10573 * // 'open' an information row when a row is clicked on 10574 10575 * $('#example tbody tr').click( function () { 10576 10577 * if ( oTable.fnIsOpen(this) ) { 10578 10579 * oTable.fnClose( this ); 10580 10581 * } else { 10582 10583 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 10584 10585 * } 10586 10587 * } ); 10588 10589 * 10590 10591 * oTable = $('#example').dataTable(); 10592 10593 * } ); 10594 10595 */ 10596 10597 this.fnClose = function( nTr ) 10598 10599 { 10600 10601 /* Find settings from table node */ 10602 10603 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 10604 10605 10606 10607 for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ ) 10608 10609 { 10610 10611 if ( oSettings.aoOpenRows[i].nParent == nTr ) 10612 10613 { 10614 10615 var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode; 10616 10617 if ( nTrParent ) 10618 10619 { 10620 10621 /* Remove it if it is currently on display */ 10622 10623 nTrParent.removeChild( oSettings.aoOpenRows[i].nTr ); 10624 10625 } 10626 10627 oSettings.aoOpenRows.splice( i, 1 ); 10628 10629 return 0; 10630 10631 } 10632 10633 } 10634 10635 return 1; 10636 10637 }; 10638 10639 10640 10641 10642 10643 /** 10644 10645 * Remove a row for the table 10646 10647 * @param {mixed} mTarget The index of the row from aoData to be deleted, or 10648 10649 * the TR element you want to delete 10650 10651 * @param {function|null} [fnCallBack] Callback function 10652 10653 * @param {bool} [bRedraw=true] Redraw the table or not 10654 10655 * @returns {array} The row that was deleted 10656 10657 * @dtopt API 10658 10659 * 10660 10661 * @example 10662 10663 * $(document).ready(function() { 10664 10665 * var oTable = $('#example').dataTable(); 10666 10667 * 10668 10669 * // Immediately remove the first row 10670 10671 * oTable.fnDeleteRow( 0 ); 10672 10673 * } ); 10674 10675 */ 10676 10677 this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw ) 10678 10679 { 10680 10681 /* Find settings from table node */ 10682 10683 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 10684 10685 var i, iLen, iAODataIndex; 10686 10687 10688 10689 iAODataIndex = (typeof mTarget === 'object') ? 10690 10691 _fnNodeToDataIndex(oSettings, mTarget) : mTarget; 10692 10693 10694 10695 /* Return the data array from this row */ 10696 10697 var oData = oSettings.aoData.splice( iAODataIndex, 1 ); 10698 10699 10700
10701 /* Update the _DT_RowIndex parameter */ 10702 10703 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) 10704 10705 { 10706 10707 if ( oSettings.aoData[i].nTr !== null ) 10708 10709 { 10710 10711 oSettings.aoData[i].nTr._DT_RowIndex = i; 10712 10713 } 10714 10715 } 10716 10717 10718 10719 /* Remove the target row from the search array */ 10720 10721 var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay ); 10722 10723 oSettings.asDataSearch.splice( iDisplayIndex, 1 ); 10724 10725 10726 10727 /* Delete from the display arrays */ 10728 10729 _fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex ); 10730 10731 _fnDeleteIndex( oSettings.aiDisplay, iAODataIndex ); 10732 10733 10734 10735 /* If there is a user callback function - call it */ 10736 10737 if ( typeof fnCallBack === "function" ) 10738 10739 { 10740 10741 fnCallBack.call( this, oSettings, oData ); 10742 10743 } 10744 10745 10746 10747 /* Check for an 'overflow' they case for displaying the table */ 10748 10749 if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() ) 10750 10751 { 10752 10753 oSettings._iDisplayStart -= oSettings._iDisplayLength; 10754 10755 if ( oSettings._iDisplayStart < 0 ) 10756 10757 { 10758 10759 oSettings._iDisplayStart = 0; 10760 10761 } 10762 10763 } 10764 10765 10766 10767 if ( bRedraw === undefined || bRedraw ) 10768 10769 { 10770 10771 _fnCalculateEnd( oSettings ); 10772 10773 _fnDraw( oSettings ); 10774 10775 } 10776 10777 10778 10779 return oData; 10780 10781 }; 10782 10783 10784 10785 10786 10787 /** 10788 10789 * Restore the table to it's original state in the DOM by removing all of DataTables 10790 10791 * enhancements, alterations to the DOM structure of the table and event listeners. 10792 10793 * @param {boolean} [bRemove=false] Completely remove the table from the DOM 10794 10795 * @dtopt API 10796 10797 * 10798 10799 * @example 10800 10801 * $(document).ready(function() { 10802 10803 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 10804 10805 * var oTable = $('#example').dataTable(); 10806 10807 * oTable.fnDestroy(); 10808 10809 * } ); 10810 10811 */ 10812 10813 this.fnDestroy = function ( bRemove ) 10814 10815 { 10816 10817 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 10818 10819 var nOrig = oSettings.nTableWrapper.parentNode; 10820 10821 var nBody = oSettings.nTBody; 10822 10823 var i, iLen; 10824 10825 10826 10827 bRemove = (bRemove===undefined) ? false : bRemove; 10828 10829 10830 10831 /* Flag to note that the table is currently being destroyed - no action should be taken */ 10832 10833 oSettings.bDestroying = true; 10834 10835 10836 10837 /* Fire off the destroy callbacks for plug-ins etc */ 10838 10839 _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] ); 10840 10841 10842 10843 /* If the table is not being removed, restore the hidden columns */ 10844 10845 if ( !bRemove ) 10846 10847 { 10848 10849 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 10850 10851 { 10852 10853 if ( oSettings.aoColumns[i].bVisible === false ) 10854 10855 { 10856 10857 this.fnSetColumnVis( i, true ); 10858 10859 } 10860 10861 } 10862 10863 } 10864 10865 10866 10867 /* Blitz all DT Businesses */ 10868 10869 $(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT'); 10870 10871 10872 10873 /* If there is an 'empty' indicator row, remove it */ 10874 10875 $('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove(); 10876 10877 10878 10879 /* When scrolling we had to break the table up - restore it */ 10880 10881 if ( oSettings.nTable != oSettings.nTHead.parentNode ) 10882 10883 { 10884 10885 $(oSettings.nTable).children('thead').remove(); 10886 10887 oSettings.nTable.appendChild( oSettings.nTHead ); 10888 10889 } 10890 10891 10892 10893 if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode ) 10894 10895 { 10896 10897 $(oSettings.nTable).children('tfoot').remove(); 10898 10899 oSettings.nTable.appendChild( oSettings.nTFoot ); 10900 10901 } 10902 10903 10904 10905 /* Remove the DataTables generated nodes, Businesses and classes */ 10906 10907 oSettings.nTable.parentNode.removeChild( oSettings.nTable ); 10908 10909 $(oSettings.nTableWrapper).remove(); 10910 10911 10912 10913 oSettings.aaSorting = []; 10914 10915 oSettings.aaSortingFixed = []; 10916 10917 _fnSortingClasses( oSettings ); 10918 10919 10920 10921 $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') ); 10922 10923 10924 10925 $('th, td', oSettings.nTHead).removeClass( [ 10926 10927 oSettings.oClasses.sSortable, 10928 10929 oSettings.oClasses.sSortableAsc, 10930 10931 oSettings.oClasses.sSortableDesc, 10932 10933 oSettings.oClasses.sSortableNone ].join(' ') 10934 10935 ); 10936 10937 if ( oSettings.bJUI ) 10938 10939 { 10940 10941 $('th span.'+oSettings.oClasses.sSortIcon 10942 10943 + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove(); 10944 10945 10946 10947 $('th, td', oSettings.nTHead).each( function () { 10948 10949 var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this); 10950 10951 var kids = jqWrapper.contents(); 10952 10953 $(this).append( kids ); 10954 10955 jqWrapper.remove(); 10956 10957 } ); 10958 10959 } 10960 10961 10962 10963 /* Add the TR elements back into the table in their original order */ 10964
10965 if ( !bRemove && oSettings.nTableReinsertBefore ) 10966 10967 { 10968 10969 nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore ); 10970 10971 } 10972 10973 else if ( !bRemove ) 10974 10975 { 10976 10977 nOrig.appendChild( oSettings.nTable ); 10978 10979 } 10980 10981 10982 10983 for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ ) 10984 10985 { 10986 10987 if ( oSettings.aoData[i].nTr !== null ) 10988 10989 { 10990 10991 nBody.appendChild( oSettings.aoData[i].nTr ); 10992 10993 } 10994 10995 } 10996 10997 10998 10999 /* Restore the width of the original table */ 11000 11001 if ( oSettings.oFeatures.bAutoWidth === true ) 11002 11003 { 11004 11005 oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth); 11006 11007 } 11008 11009 11010 11011 /* If the were originally stripe classes - then we add them back here. Note 11012 11013 * this is not fool proof (for example if not all rows had stripe classes - but 11014 11015 * it's a good effort without getting carried away 11016 11017 */ 11018 11019 iLen = oSettings.asDestroyStripes.length; 11020 11021 if (iLen) 11022 11023 { 11024 11025 var anRows = $(nBody).children('tr'); 11026 11027 for ( i=0 ; i<iLen ; i++ ) 11028 11029 { 11030 11031 anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] ); 11032 11033 } 11034 11035 } 11036 11037 11038 11039 /* Remove the settings object from the settings array */ 11040 11041 for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ ) 11042 11043 { 11044 11045 if ( DataTable.settings[i] == oSettings ) 11046 11047 { 11048 11049 DataTable.settings.splice( i, 1 ); 11050 11051 } 11052 11053 } 11054 11055 11056 11057 /* End it all */ 11058 11059 oSettings = null; 11060 11061 oInit = null; 11062 11063 }; 11064 11065 11066 11067 11068 11069 /** 11070 11071 * Redraw the table 11072 11073 * @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw. 11074 11075 * @dtopt API 11076 11077 * 11078 11079 * @example 11080 11081 * $(document).ready(function() { 11082 11083 * var oTable = $('#example').dataTable(); 11084 11085 * 11086 11087 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 11088 11089 * oTable.fnDraw(); 11090 11091 * } ); 11092 11093 */ 11094 11095 this.fnDraw = function( bComplete ) 11096 11097 { 11098 11099 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11100 11101 if ( bComplete === false ) 11102 11103 { 11104 11105 _fnCalculateEnd( oSettings ); 11106 11107 _fnDraw( oSettings ); 11108 11109 } 11110 11111 else 11112 11113 { 11114 11115 _fnReDraw( oSettings ); 11116 11117 } 11118 11119 }; 11120 11121 11122 11123 11124 11125 /** 11126 11127 * Filter the input based on data 11128 11129 * @param {string} sInput String to filter the table on 11130 11131 * @param {int|null} [iColumn] Column to limit filtering to 11132 11133 * @param {bool} [bRegex=false] Treat as regular expression or not 11134 11135 * @param {bool} [bSmart=true] Perform smart filtering or not 11136 11137 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 11138 11139 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 11140 11141 * @dtopt API 11142 11143 * 11144 11145 * @example 11146 11147 * $(document).ready(function() { 11148 11149 * var oTable = $('#example').dataTable(); 11150 11151 * 11152 11153 * // Sometime later - filter... 11154 11155 * oTable.fnFilter( 'test string' ); 11156 11157 * } ); 11158 11159 */ 11160 11161 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 11162 11163 { 11164 11165 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11166 11167 11168 11169 if ( !oSettings.oFeatures.bFilter ) 11170 11171 { 11172 11173 return; 11174 11175 } 11176 11177 11178 11179 if ( bRegex === undefined || bRegex === null ) 11180 11181 { 11182 11183 bRegex = false; 11184 11185 } 11186 11187 11188 11189 if ( bSmart === undefined || bSmart === null ) 11190 11191 { 11192 11193 bSmart = true; 11194 11195 } 11196 11197 11198 11199 if ( bShowGlobal === undefined || bShowGlobal === null ) 11200 11201 { 11202 11203 bShowGlobal = true; 11204 11205 } 11206 11207 11208 11209 if ( bCaseInsensitive === undefined || bCaseInsensitive === null ) 11210 11211 { 11212 11213 bCaseInsensitive = true; 11214 11215 } 11216 11217 11218 11219 if ( iColumn === undefined || iColumn === null ) 11220 11221 { 11222 11223 /* Global filter */ 11224 11225 _fnFilterComplete( oSettings, { 11226 11227 "sSearch":sInput+"", 11228 11229 "bRegex": bRegex, 11230 11231 "bSmart": bSmart, 11232 11233 "bCaseInsensitive": bCaseInsensitive 11234 11235 }, 1 ); 11236 11237 11238 11239 if ( bShowGlobal && oSettings.aanFeatures.f ) 11240 11241 { 11242 11243 var n = oSettings.aanFeatures.f; 11244 11245 for ( var i=0, iLen=n.length ; i<iLen ; i++ ) 11246 11247 { 11248 11249 // IE9 throws an 'unknown error' if document.activeElement is used 11250 11251 // inside an iframe or frame... 11252 11253 try { 11254 11255 if ( n[i]._DT_Input != document.activeElement ) 11256 11257 { 11258 11259 $(n[i]._DT_Input).val( sInput ); 11260 11261 } 11262 11263 } 11264 11265 catch ( e ) { 11266 11267 $(n[i]._DT_Input).val( sInput ); 11268 11269 } 11270 11271 } 11272 11273 } 11274 11275 } 11276 11277 else 11278 11279 { 11280 11281 /* Single column filter */ 11282 11283 $.extend( oSettings.aoPreSearchCols[ iColumn ], { 11284 11285 "sSearch": sInput+"", 11286 11287 "bRegex": bRegex, 11288 11289 "bSmart": bSmart, 11290 11291 "bCaseInsensitive": bCaseInsensitive 11292 11293 } ); 11294 11295 _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 ); 11296 11297 } 11298 11299 }; 11300 11301 11302 11303 11304 11305 /** 11306 11307 * Get the data for the whole table, an individual row or an individual cell based on the 11308 11309 * provided parameters. 11310 11311 * @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as 11312 11313 * a TR node then the data source for the whole row will be returned. If given as a 11314 11315 * TD/TH cell node then iCol will be automatically calculated and the data for the 11316 11317 * cell returned. If given as an integer, then this is treated as the aoData internal 11318 11319 * data index for the row (see fnGetPosition) and the data for that row used. 11320 11321 * @param {int} [iCol] Optional column index that you want the data of. 11322 11323 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 11324 11325 * returned. If mRow is defined, just data for that row, and is iCol is 11326 11327 * defined, only data for the designated cell is returned. 11328 11329 * @dtopt API 11330 11331 * 11332 11333 * @example 11334 11335 * // Row data 11336 11337 * $(document).ready(function() { 11338 11339 * oTable = $('#example').dataTable(); 11340 11341 * 11342 11343 * oTable.$('tr').click( function () { 11344 11345 * var data = oTable.fnGetData( this ); 11346 11347 * // ... do something with the array / object of data for the row 11348 11349 * } ); 11350 11351 * } ); 11352 11353 * 11354 11355 * @example 11356 11357 * // Individual cell data 11358 11359 * $(document).ready(function() { 11360 11361 * oTable = $('#example').dataTable(); 11362 11363 * 11364 11365 * oTable.$('td').click( function () { 11366 11367 * var sData = oTable.fnGetData( this ); 11368 11369 * alert( 'The cell clicked on had the value of '+sData ); 11370 11371 * } ); 11372 11373 * } ); 11374 11375 */ 11376 11377 this.fnGetData = function( mRow, iCol ) 11378 11379 { 11380 11381 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11382 11383 11384 11385 if ( mRow !== undefined ) 11386 11387 { 11388 11389 var iRow = mRow; 11390 11391 if ( typeof mRow === 'object' ) 11392 11393 { 11394 11395 var sNode = mRow.nodeName.toLowerCase(); 11396 11397 if (sNode === "tr" ) 11398 11399 { 11400 11401 iRow = _fnNodeToDataIndex(oSettings, mRow); 11402 11403 } 11404 11405 else if ( sNode === "td" ) 11406 11407 { 11408 11409 iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode); 11410 11411 iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow ); 11412 11413 } 11414 11415 } 11416 11417 11418 11419 if ( iCol !== undefined ) 11420 11421 { 11422 11423 return _fnGetCellData( oSettings, iRow, iCol, '' ); 11424 11425 } 11426 11427 return (oSettings.aoData[iRow]!==undefined) ? 11428 11429 oSettings.aoData[iRow]._aData : null; 11430 11431 } 11432 11433 return _fnGetDataMaster( oSettings ); 11434 11435 }; 11436 11437 11438 11439 11440 11441 /** 11442 11443 * Get an array of the TR nodes that are used in the table's body. Note that you will 11444 11445 * typically want to use the '$' API method in preference to this as it is more 11446 11447 * flexible. 11448 11449 * @param {int} [iRow] Optional row index for the TR element you want 11450 11451 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 11452 11453 * in the table's body, or iRow is defined, just the TR element requested. 11454 11455 * @dtopt API 11456 11457 * 11458 11459 * @example 11460 11461 * $(document).ready(function() { 11462 11463 * var oTable = $('#example').dataTable(); 11464 11465 * 11466 11467 * // Get the nodes from the table 11468 11469 * var nNodes = oTable.fnGetNodes( ); 11470 11471 * } ); 11472 11473 */ 11474 11475 this.fnGetNodes = function( iRow ) 11476 11477 { 11478 11479 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11480 11481 11482 11483 if ( iRow !== undefined ) { 11484 11485 return (oSettings.aoData[iRow]!==undefined) ? 11486 11487 oSettings.aoData[iRow].nTr : null; 11488 11489 } 11490 11491 return _fnGetTrNodes( oSettings ); 11492 11493 }; 11494 11495 11496 11497 11498 11499 /** 11500 11501 * Get the array indexes of a particular cell from it's DOM element 11502 11503 * and column index including hidden columns 11504 11505 * @param {node} nNode this can either be a TR, TD or TH in the table's body 11506 11507 * @returns {int} If nNode is given as a TR, then a single index is returned, or 11508 11509 * if given as a cell, an array of [row index, column index (visible), 11510 11511 * column index (all)] is given. 11512 11513 * @dtopt API 11514 11515 * 11516 11517 * @example 11518 11519 * $(document).ready(function() { 11520 11521 * $('#example tbody td').click( function () { 11522 11523 * // Get the position of the current data from the node 11524 11525 * var aPos = oTable.fnGetPosition( this ); 11526 11527 * 11528 11529 * // Get the data array for this row 11530 11531 * var aData = oTable.fnGetData( aPos[0] ); 11532 11533 * 11534 11535 * // Update the data array and return the value 11536 11537 * aData[ aPos[1] ] = 'clicked'; 11538 11539 * this.innerHTML = 'clicked'; 11540 11541 * } ); 11542 11543 * 11544 11545 * // Init DataTables 11546 11547 * oTable = $('#example').dataTable(); 11548 11549 * } ); 11550 11551 */ 11552 11553 this.fnGetPosition = function( nNode ) 11554 11555 { 11556 11557 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11558 11559 var sNodeName = nNode.nodeName.toUpperCase(); 11560 11561 11562 11563 if ( sNodeName == "TR" ) 11564 11565 { 11566 11567 return _fnNodeToDataIndex(oSettings, nNode); 11568 11569 } 11570 11571 else if ( sNodeName == "TD" || sNodeName == "TH" ) 11572 11573 { 11574 11575 var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode ); 11576 11577 var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode ); 11578 11579 return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ]; 11580 11581 } 11582 11583 return null; 11584 11585 }; 11586 11587 11588 11589 11590 11591 /** 11592 11593 * Check to see if a row is 'open' or not. 11594 11595 * @param {node} nTr the table row to check 11596 11597 * @returns {boolean} true if the row is currently open, false otherwise 11598 11599 * @dtopt API 11600 11601 * 11602 11603 * @example 11604 11605 * $(document).ready(function() { 11606 11607 * var oTable; 11608 11609 * 11610 11611 * // 'open' an information row when a row is clicked on 11612 11613 * $('#example tbody tr').click( function () { 11614 11615 * if ( oTable.fnIsOpen(this) ) { 11616 11617 * oTable.fnClose( this ); 11618 11619 * } else { 11620 11621 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 11622 11623 * } 11624 11625 * } ); 11626 11627 * 11628 11629 * oTable = $('#example').dataTable(); 11630 11631 * } ); 11632 11633 */ 11634 11635 this.fnIsOpen = function( nTr ) 11636 11637 { 11638 11639 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11640 11641 var aoOpenRows = oSettings.aoOpenRows; 11642 11643 11644 11645 for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ ) 11646 11647 { 11648 11649 if ( oSettings.aoOpenRows[i].nParent == nTr ) 11650 11651 { 11652 11653 return true; 11654 11655 } 11656 11657 } 11658 11659 return false; 11660 11661 }; 11662 11663 11664 11665 11666 11667 /** 11668 11669 * This function will place a new row directly after a row which is currently 11670 11671 * on display on the page, with the HTML contents that is passed into the 11672 11673 * function. This can be used, for example, to ask for confirmation that a 11674 11675 * particular record should be deleted. 11676 11677 * @param {node} nTr The table row to 'open' 11678 11679 * @param {string|node|jQuery} mHtml The HTML to put into the row 11680 11681 * @param {string} sClass Class to give the new TD cell 11682 11683 * @returns {node} The row opened. Note that if the table row passed in as the 11684 11685 * first parameter, is not found in the table, this method will silently 11686 11687 * return. 11688 11689 * @dtopt API 11690 11691 * 11692 11693 * @example 11694 11695 * $(document).ready(function() { 11696 11697 * var oTable; 11698 11699 * 11700 11701 * // 'open' an information row when a row is clicked on 11702 11703 * $('#example tbody tr').click( function () { 11704 11705 * if ( oTable.fnIsOpen(this) ) { 11706 11707 * oTable.fnClose( this ); 11708 11709 * } else { 11710 11711 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 11712 11713 * } 11714 11715 * } ); 11716 11717 * 11718 11719 * oTable = $('#example').dataTable(); 11720 11721 * } ); 11722 11723 */ 11724 11725 this.fnOpen = function( nTr, mHtml, sClass ) 11726 11727 { 11728 11729 /* Find settings from table node */ 11730 11731 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11732 11733 11734 11735 /* Check that the row given is in the table */ 11736 11737 var nTableRows = _fnGetTrNodes( oSettings ); 11738 11739 if ( $.inArray(nTr, nTableRows) === -1 ) 11740 11741 { 11742 11743 return; 11744 11745 } 11746 11747 11748 11749 /* the old open one if there is one */ 11750 11751 this.fnClose( nTr ); 11752 11753 11754 11755 var nNewRow = document.createElement("tr"); 11756 11757 var nNewCell = document.createElement("td"); 11758 11759 nNewRow.appendChild( nNewCell ); 11760 11761 nNewCell.className = sClass; 11762 11763 nNewCell.colSpan = _fnVisbleColumns( oSettings ); 11764 11765 11766 11767 if (typeof mHtml === "string") 11768 11769 { 11770 11771 nNewCell.innerHTML = mHtml; 11772 11773 } 11774 11775 else 11776 11777 { 11778 11779 $(nNewCell).html( mHtml ); 11780 11781 } 11782 11783 11784 11785 /* If the nTr isn't on the page at the moment - then we don't insert at the moment */ 11786 11787 var nTrs = $('tr', oSettings.nTBody); 11788 11789 if ( $.inArray(nTr, nTrs) != -1 ) 11790 11791 { 11792 11793 $(nNewRow).insertAfter(nTr); 11794 11795 } 11796 11797 11798 11799 oSettings.aoOpenRows.push( { 11800 11801 "nTr": nNewRow, 11802 11803 "nParent": nTr 11804 11805 } ); 11806 11807 11808 11809 return nNewRow; 11810 11811 }; 11812 11813 11814 11815 11816 11817 /** 11818 11819 * Change the pagination - provides the internal logic for pagination in a simple API 11820 11821 * function. With this function you can have a DataTables table go to the next, 11822 11823 * previous, first or last pages. 11824 11825 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 11826 11827 * or page number to jump to (integer), note that page 0 is the first page. 11828 11829 * @param {bool} [bRedraw=true] Redraw the table or not 11830 11831 * @dtopt API 11832 11833 * 11834 11835 * @example 11836 11837 * $(document).ready(function() { 11838 11839 * var oTable = $('#example').dataTable(); 11840 11841 * oTable.fnPageChange( 'next' ); 11842 11843 * } ); 11844 11845 */ 11846 11847 this.fnPageChange = function ( mAction, bRedraw ) 11848 11849 { 11850 11851 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11852 11853 _fnPageChange( oSettings, mAction ); 11854 11855 _fnCalculateEnd( oSettings ); 11856 11857 11858 11859 if ( bRedraw === undefined || bRedraw ) 11860 11861 { 11862 11863 _fnDraw( oSettings ); 11864 11865 } 11866 11867 }; 11868 11869 11870 11871 11872 11873 /** 11874 11875 * Show a particular column 11876 11877 * @param {int} iCol The column whose display should be changed 11878 11879 * @param {bool} bShow Show (true) or hide (false) the column 11880 11881 * @param {bool} [bRedraw=true] Redraw the table or not 11882 11883 * @dtopt API 11884 11885 * 11886 11887 * @example 11888 11889 * $(document).ready(function() { 11890 11891 * var oTable = $('#example').dataTable(); 11892 11893 * 11894 11895 * // Hide the second column after initialisation 11896 11897 * oTable.fnSetColumnVis( 1, false ); 11898 11899 * } ); 11900 11901 */ 11902 11903 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 11904 11905 { 11906 11907 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 11908 11909 var i, iLen; 11910 11911 var aoColumns = oSettings.aoColumns; 11912 11913 var aoData = oSettings.aoData; 11914 11915 var nTd, bAppend, iBefore; 11916 11917 11918 11919 /* No point in doing anything if we are requesting what is already true */ 11920 11921 if ( aoColumns[iCol].bVisible == bShow ) 11922 11923 { 11924 11925 return; 11926 11927 } 11928 11929 11930 11931 /* Show the column */ 11932 11933 if ( bShow ) 11934 11935 { 11936 11937 var iInsert = 0; 11938 11939 for ( i=0 ; i<iCol ; i++ ) 11940 11941 { 11942 11943 if ( aoColumns[i].bVisible ) 11944 11945 { 11946 11947 iInsert++; 11948 11949 } 11950 11951 } 11952 11953 11954 11955 /* Need to decide if we should use appendChild or insertBefore */ 11956 11957 bAppend = (iInsert >= _fnVisbleColumns( oSettings )); 11958 11959 11960 11961 /* Which coloumn should we be inserting before? */ 11962 11963 if ( !bAppend ) 11964 11965 { 11966 11967 for ( i=iCol ; i<aoColumns.length ; i++ ) 11968 11969 { 11970 11971 if ( aoCol
11971umns[i].bVisible ) 11972 11973 { 11974 11975 iBefore = i; 11976 11977 break; 11978 11979 } 11980 11981 } 11982 11983 } 11984 11985 11986 11987 for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) 11988 11989 { 11990 11991 if ( aoData[i].nTr !== null ) 11992 11993 { 11994 11995 if ( bAppend ) 11996 11997 { 11998 11999 aoData[i].nTr.appendChild( 12000 12001 aoData[i]._anHidden[iCol] 12002 12003 ); 12004 12005 } 12006 12007 else 12008 12009 { 12010 12011 aoData[i].nTr.insertBefore( 12012 12013 aoData[i]._anHidden[iCol], 12014 12015 _fnGetTdNodes( oSettings, i )[iBefore] ); 12016 12017 } 12018 12019 } 12020 12021 } 12022 12023 } 12024 12025 else 12026 12027 { 12028 12029 /* Remove a column from display */ 12030 12031 for ( i=0, iLen=aoData.length ; i<iLen ; i++ ) 12032 12033 { 12034 12035 if ( aoData[i].nTr !== null ) 12036 12037 { 12038 12039 nTd = _fnGetTdNodes( oSettings, i )[iCol]; 12040 12041 aoData[i]._anHidden[iCol] = nTd; 12042 12043 nTd.parentNode.removeChild( nTd ); 12044 12045 } 12046 12047 } 12048 12049 } 12050 12051 12052 12053 /* Clear to set the visible flag */ 12054 12055 aoColumns[iCol].bVisible = bShow; 12056 12057 12058 12059 /* Redraw the header and footer based on the new column visibility */ 12060 12061 _fnDrawHead( oSettings, oSettings.aoHeader ); 12062 12063 if ( oSettings.nTFoot ) 12064 12065 { 12066 12067 _fnDrawHead( oSettings, oSettings.aoFooter ); 12068 12069 } 12070 12071 12072 12073 /* If there are any 'open' rows, then we need to alter the colspan for this col change */ 12074 12075 for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ ) 12076 12077 { 12078 12079 oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings ); 12080 12081 } 12082 12083 12084 12085 /* Do a redraw incase anything depending on the table columns needs it 12086 12087 * (built-in: scrolling) 12088 12089 */ 12090 12091 if ( bRedraw === undefined || bRedraw ) 12092 12093 { 12094 12095 _fnAdjustColumnSizing( oSettings ); 12096 12097 _fnDraw( oSettings ); 12098 12099 } 12100 12101 12102 12103 _fnSaveState( oSettings ); 12104 12105 }; 12106 12107 12108 12109 12110 12111 /** 12112 12113 * Get the settings for a particular table for external manipulation 12114 12115 * @returns {object} DataTables settings object. See 12116 12117 * {@link DataTable.models.oSettings} 12118 12119 * @dtopt API 12120 12121 * 12122 12123 * @example 12124 12125 * $(document).ready(function() { 12126 12127 * var oTable = $('#example').dataTable(); 12128 12129 * var oSettings = oTable.fnSettings(); 12130 12131 * 12132 12133 * // Show an example parameter from the settings 12134 12135 * alert( oSettings._iDisplayStart ); 12136 12137 * } ); 12138 12139 */ 12140 12141 this.fnSettings = function() 12142 12143 { 12144 12145 return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 12146 12147 }; 12148 12149 12150 12151 12152 12153 /** 12154 12155 * Sort the table by a particular column 12156 12157 * @param {int} iCol the data index to sort on. Note that this will not match the 12158 12159 * 'display index' if you have hidden data Businesses 12160 12161 * @dtopt API 12162 12163 * 12164 12165 * @example 12166 12167 * $(document).ready(function() { 12168 12169 * var oTable = $('#example').dataTable(); 12170 12171 * 12172 12173 * // Sort immediately with columns 0 and 1 12174 12175 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 12176 12177 * } ); 12178 12179 */ 12180 12181 this.fnSort = function( aaSort ) 12182 12183 { 12184 12185 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 12186 12187 oSettings.aaSorting = aaSort; 12188 12189 _fnSort( oSettings ); 12190 12191 }; 12192 12193 12194 12195 12196 12197 /** 12198 12199 * Attach a sort listener to an element for a given column 12200 12201 * @param {node} nNode the element to attach the sort listener to 12202 12203 * @param {int} iColumn the column that a click on this node will sort on 12204 12205 * @param {function} [fnCallback] callback function when sort is run 12206 12207 * @dtopt API 12208 12209 * 12210 12211 * @example 12212 12213 * $(document).ready(function() { 12214 12215 * var oTable = $('#example').dataTable(); 12216 12217 * 12218 12219 * // Sort on column 1, when 'sorter' is clicked on 12220 12221 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 12222 12223 * } ); 12224 12225 */ 12226 12227 this.fnSortListener = function( nNode, iColumn, fnCallback ) 12228 12229 { 12230 12231 _fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn, 12232 12233 fnCallback ); 12234 12235 }; 12236 12237 12238 12239 12240 12241 /** 12242 12243 * Update a table cell or row - this method will accept either a single value to 12244 12245 * update the cell with, an array of values with one element for each column or 12246 12247 * an object in the same format as the original data source. The function is 12248 12249 * self-referencing in order to make the multi column updates easier. 12250 12251 * @param {object|array|string} mData Data to update the cell/row with 12252 12253 * @param {node|int} mRow TR element you want to update or the aoData index 12254 12255 * @param {int} [iColumn] The column to update (not used of mData is an array or object) 12256 12257 * @param {bool} [bRedraw=true] Redraw the table or not 12258 12259 * @param {bool} [bAction=true] Perform pre-draw actions or not 12260 12261 * @returns {int} 0 on success, 1 on error 12262 12263 * @dtopt API 12264 12265 * 12266 12267 * @example 12268 12269 * $(document).ready(function() { 12270 12271 * var oTable = $('#example').dataTable(); 12272 12273 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 12274 12275 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row 12276 12277 * } ); 12278 12279 */ 12280 12281 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 12282 12283 { 12284 12285 var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ); 12286 12287 var i, iLen, sDisplay; 12288 12289 var iRow = (typeof mRow === 'object') ? 12290 12291 _fnNodeToDataIndex(oSettings, mRow) : mRow; 12292 12293 12294 12295 if ( $.isArray(mData) && iColumn === undefined ) 12296 12297 { 12298 12299 /* Array update - update the whole row */ 12300 12301 oSettings.aoData[iRow]._aData = mData.slice(); 12302 12303 12304 12305 /* Flag to the function that we are recursing */ 12306 12307 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) 12308 12309 { 12310 12311 this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false ); 12312 12313 } 12314 12315 } 12316 12317 else if ( $.isPlainObject(mData) && iColumn === undefined ) 12318 12319 { 12320 12321 /* Object update - update the whole row - assume the developer gets the object right */ 12322 12323 oSettings.aoData[iRow]._aData = $.extend( true, {}, mData ); 12324 12325 12326 12327 for ( i=0 ; i<oSettings.aoColumns.length ; i++ ) 12328 12329 { 12330 12331 this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false ); 12332 12333 } 12334 12335 } 12336 12337 else 12338 12339 { 12340 12341 /* Individual cell update */ 12342 12343 _fnSetCellData( oSettings, iRow, iColumn, mData ); 12344 12345 sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' ); 12346 12347 12348 12349 var oCol = oSettings.aoColumns[iColumn]; 12350 12351 if ( oCol.fnRender !== null ) 12352 12353 { 12354 12355 sDisplay = _fnRender( oSettings, iRow, iColumn ); 12356 12357 if ( oCol.bUseRendered ) 12358 12359 { 12360 12361 _fnSetCellData( oSettings, iRow, iColumn, sDisplay ); 12362 12363 } 12364 12365 } 12366 12367 12368 12369 if ( oSettings.aoData[iRow].nTr !== null ) 12370 12371 { 12372 12373 /* Do the actual HTML update */ 12374 12375 _fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay; 12376 12377 } 12378 12379 } 12380 12381 12382 12383 /* Modify the search index for this row (strictly this is likely not needed, since fnReDraw 12384 12385 * will rebuild the search array - however, the redraw might be disabled by the user) 12386 12387 */ 12388 12389 var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay ); 12390 12391 oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow( 12392 12393 oSettings, 12394 12395 _fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) ) 12396 12397 ); 12398 12399 12400 12401 /* Perform pre-draw actions */ 12402 12403 if ( bAction === undefined || bAction ) 12404 12405 { 12406 12407 _fnAdjustColumnSizing( oSettings ); 12408 12409 } 12410 12411 12412 12413 /* Redraw the table */ 12414 12415 if ( bRedraw === undefined || bRedraw ) 12416 12417 { 12418 12419 _fnReDraw( oSettings ); 12420 12421 } 12422 12423 return 0; 12424 12425 }; 12426 12427 12428 12429 12430 12431 /** 12432
12433 * Provide a common method for plug-ins to check the version of DataTables being used, in order 12434 12435 * to ensure compatibility. 12436 12437 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 12438 12439 * formats "X" and "X.Y" are also acceptable. 12440 12441 * @returns {boolean} true if this version of DataTables is greater or equal to the required 12442 12443 * version, or false if this version of DataTales is not suitable 12444 12445 * @method 12446 12447 * @dtopt API 12448 12449 * 12450 12451 * @example 12452 12453 * $(document).ready(function() { 12454 12455 * var oTable = $('#example').dataTable(); 12456 12457 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 12458 12459 * } ); 12460 12461 */ 12462 12463 this.fnVersionCheck = DataTable.ext.fnVersionCheck; 12464 12465 12466 12467 12468 12469 /* 12470 12471 * This is really a good bit rubbish this method of exposing the internal methods 12472 12473 * publicly... - To be fixed in 2.0 using methods on the prototype 12474 12475 */ 12476 12477 12478 12479 12480 12481 /** 12482 12483 * Create a wrapper function for exporting an internal functions to an external API. 12484 12485 * @param {string} sFunc API function name 12486 12487 * @returns {function} wrapped function 12488 12489 * @memberof DataTable#oApi 12490 12491 */ 12492 12493 function _fnExternApiFunc (sFunc) 12494 12495 { 12496 12497 return function() { 12498 12499 var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat( 12500 12501 Array.prototype.slice.call(arguments) ); 12502 12503 return DataTable.ext.oApi[sFunc].apply( this, aArgs ); 12504 12505 }; 12506 12507 } 12508 12509 12510 12511 12512 12513 /** 12514 12515 * Reference to internal functions for use by plug-in developers. Note that these 12516 12517 * methods are references to internal functions and are considered to be private. 12518 12519 * If you use these methods, be aware that they are liable to change between versions 12520 12521 * (check the upgrade notes). 12522 12523 * @namespace 12524 12525 */ 12526 12527 this.oApi = { 12528 12529 "_fnExternApiFunc": _fnExternApiFunc, 12530 12531 "_fnInitialise": _fnInitialise, 12532 12533 "_fnInitComplete": _fnInitComplete, 12534 12535 "_fnLanguageCompat": _fnLanguageCompat, 12536 12537 "_fnAddColumn": _fnAddColumn, 12538 12539 "_fnColumnOptions": _fnColumnOptions, 12540 12541 "_fnAddData": _fnAddData, 12542 12543 "_fnCreateTr": _fnCreateTr, 12544 12545 "_fnGatherData": _fnGatherData, 12546 12547 "_fnBuildHead": _fnBuildHead, 12548 12549 "_fnDrawHead": _fnDrawHead, 12550 12551 "_fnDraw": _fnDraw, 12552 12553 "_fnReDraw": _fnReDraw, 12554 12555 "_fnAjaxUpdate": _fnAjaxUpdate, 12556 12557 "_fnAjaxParameters": _fnAjaxParameters, 12558 12559 "_fnAjaxUpdateDraw": _fnAjaxUpdateDraw, 12560 12561 "_fnServerParams": _fnServerParams, 12562 12563 "_fnAddOptionsHtml": _fnAddOptionsHtml, 12564 12565 "_fnFeatureHtmlTable": _fnFeatureHtmlTable, 12566 12567 "_fnScrollDraw": _fnScrollDraw, 12568 12569 "_fnAdjustColumnSizing": _fnAdjustColumnSizing, 12570 12571 "_fnFeatureHtmlFilter": _fnFeatureHtmlFilter, 12572 12573 "_fnFilterComplete": _fnFilterComplete, 12574
12575 "_fnFilterCustom": _fnFilterCustom, 12576 12577 "_fnFilterColumn": _fnFilterColumn, 12578 12579 "_fnFilter": _fnFilter, 12580 12581 "_fnBuildSearchArray": _fnBuildSearchArray, 12582 12583 "_fnBuildSearchRow": _fnBuildSearchRow, 12584 12585 "_fnFilterCreateSearch": _fnFilterCreateSearch, 12586 12587 "_fnDataToSearch": _fnDataToSearch, 12588 12589 "_fnSort": _fnSort, 12590 12591 "_fnSortAttachListener": _fnSortAttachListener, 12592 12593 "_fnSortingClasses": _fnSortingClasses, 12594 12595 "_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate, 12596 12597 "_fnPageChange": _fnPageChange, 12598 12599 "_fnFeatureHtmlInfo": _fnFeatureHtmlInfo, 12600 12601 "_fnUpdateInfo": _fnUpdateInfo, 12602 12603 "_fnFeatureHtmlLength": _fnFeatureHtmlLength, 12604 12605 "_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing, 12606 12607 "_fnProcessingDisplay": _fnProcessingDisplay, 12608 12609 "_fnVisibleToColumnIndex": _fnVisibleToColumnIndex, 12610 12611 "_fnColumnIndexToVisible": _fnColumnIndexToVisible, 12612 12613 "_fnNodeToDataIndex": _fnNodeToDataIndex, 12614 12615 "_fnVisbleColumns": _fnVisbleColumns, 12616 12617 "_fnCalculateEnd": _fnCalculateEnd, 12618 12619 "_fnConvertToWidth": _fnConvertToWidth, 12620 12621 "_fnCalculateColumnWidths": _fnCalculateColumnWidths, 12622 12623 "_fnScrollingWidthAdjust": _fnScrollingWidthAdjust, 12624 12625 "_fnGetWidestNode": _fnGetWidestNode, 12626 12627 "_fnGetMaxLenString": _fnGetMaxLenString, 12628 12629 "_fnStringToCss": _fnStringToCss, 12630 12631 "_fnDetectType": _fnDetectType, 12632 12633 "_fnSettingsFromNode": _fnSettingsFromNode, 12634 12635 "_fnGetDataMaster": _fnGetDataMaster, 12636 12637 "_fnGetTrNodes": _fnGetTrNodes, 12638 12639 "_fnGetTdNodes": _fnGetTdNodes, 12640 12641 "_fnEscapeRegex": _fnEscapeRegex, 12642 12643 "_fnDeleteIndex": _fnDeleteIndex, 12644 12645 "_fnReOrderIndex": _fnReOrderIndex, 12646 12647 "_fnColumnOrdering": _fnColumnOrdering, 12648 12649 "_fnLog": _fnLog, 12650 12651 "_fnClearTable": _fnClearTable, 12652 12653 "_fnSaveState": _fnSaveState, 12654 12655 "_fnLoadState": _fnLoadState, 12656 12657 "_fnCreateCookie": _fnCreateCookie, 12658 12659 "_fnReadCookie": _fnReadCookie, 12660 12661 "_fnDetectHeader": _fnDetectHeader, 12662 12663 "_fnGetUniqueThs": _fnGetUniqueThs, 12664 12665 "_fnScrollBarWidth": _fnScrollBarWidth, 12666 12667 "_fnApplyToChildren": _fnApplyToChildren, 12668 12669 "_fnMap": _fnMap, 12670 12671 "_fnGetRowData": _fnGetRowData, 12672 12673 "_fnGetCellData": _fnGetCellData, 12674 12675 "_fnSetCellData": _fnSetCellData, 12676 12677 "_fnGetObjectDataFn": _fnGetObjectDataFn, 12678 12679 "_fnSetObjectDataFn": _fnSetObjectDataFn, 12680 12681 "_fnApplyColumnDefs": _fnApplyColumnDefs, 12682 12683 "_fnBindAction": _fnBindAction, 12684 12685 "_fnExtend": _fnExtend, 12686 12687 "_fnCallbackReg": _fnCallbackReg, 12688 12689 "_fnCallbackFire": _fnCallbackFire, 12690 12691 "_fnJsonString": _fnJsonString, 12692 12693 "_fnRender": _fnRender, 12694 12695 "_fnNodeToColumnIndex": _fnNodeToColumnIndex, 12696 12697 "_fnInfoMacros": _fnInfoMacros, 12698 12699 "_fnBrowserDetect": _fnBrowserDetect, 12700 12701 "_fnGetColumns": _fnGetColumns 12702 12703 }; 12704 12705 12706 12707 $.extend( DataTable.ext.oApi, this.oApi ); 12708 12709 12710 12711 for ( var sFunc in DataTable.ext.oApi ) 12712 12713 { 12714 12715 if ( sFunc ) 12716 12717 { 12718 12719 this[sFunc] = _fnExternApiFunc(sFunc); 12720 12721 } 12722 12723 } 12724 12725 12726 12727 12728 12729 var _that = this; 12730 12731 this.each(function() { 12732 12733 var i=0, iLen, j, jLen, k, kLen; 12734 12735 var sId = this.getAttribute( 'id' ); 12736 12737 var bInitHandedOff = false; 12738 12739 var bUsePassedData = false; 12740 12741 12742 12743 12744 12745 /* Sanity check */ 12746 12747 if ( this.nodeName.toLowerCase() != 'table' ) 12748 12749 { 12750 12751 _fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+ 12752 12753 "table: "+this.nodeName ); 12754 12755 return; 12756 12757 } 12758 12759 12760 12761 /* Check to see if we are re-initialising a table */ 12762 12763 for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ ) 12764 12765 { 12766 12767 /* Base check on table node */ 12768 12769 if ( DataTable.settings[i].nTable == this ) 12770 12771 { 12772 12773 if ( oInit === undefined || oInit.bRetrieve ) 12774 12775 { 12776 12777 return DataTable.settings[i].oInstance; 12778 12779 } 12780 12781 else if ( oInit.bDestroy ) 12782 12783 { 12784 12785 DataTable.settings[i].oInstance.fnDestroy(); 12786 12787 break; 12788 12789 } 12790 12791 else 12792 12793 { 12794 12795 _fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+ 12796 12797 "To retrieve the DataTables object for this table, pass no arguments or see "+ 12798 12799 "the docs for bRetrieve and bDestroy" ); 12800 12801 return; 12802 12803 } 12804 12805 } 12806 12807 12808 12809 /* If the element we are initialising has the same ID as a table which was previously 12810 12811 * initialised, but the table nodes don't match (from before) then we destroy the old 12812 12813 * instance by simply deleting it. This is under the assumption that the table has been 12814 12815 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 12816 12817 */ 12818 12819 if ( DataTable.settings[i].sTableId == this.id ) 12820 12821 { 12822 12823 DataTable.settings.splice( i, 1 ); 12824 12825 break; 12826 12827 } 12828 12829 } 12830 12831 12832 12833 /* Ensure the table has an ID - required for accessibility */ 12834 12835 if ( sId === null || sId === "" ) 12836 12837 { 12838 12839 sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++); 12840 12841 this.id = sId; 12842 12843 } 12844 12845 12846 12847 /* Create the settings object for this table and set some of the default parameters */ 12848 12849 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 12850 12851 "nTable": this, 12852 12853 "oApi": _that.oApi, 12854 12855 "oInit": oInit, 12856 12857 "sDestroyWidth": $(this).width(), 12858 12859 "sInstance": sId, 12860 12861 "sTableId": sId 12862 12863 } ); 12864 12865 DataTable.settings.push( oSettings ); 12866 12867 12868 12869 // Need to add the instance after the instance after the settings object has been added 12870 12871 // to the settings array, so we can self reference the table instance if more than one 12872 12873 oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable(); 12874 12875 12876 12877 /* Setting up the initialisation object */ 12878 12879 if ( !oInit ) 12880 12881 { 12882 12883 oInit = {}; 12884 12885 } 12886 12887 12888 12889 // Backwards compatibility, before we apply all the defaults 12890 12891 if ( oInit.oLanguage ) 12892 12893 { 12894 12895 _fnLanguageCompat( oInit.oLanguage ); 12896 12897 } 12898 12899 12900 12901 oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit ); 12902 12903 12904 12905 // Map the initialisation options onto the settings object 12906 12907 _fnMap( oSettings.oFeatures, oInit, "bPaginate" ); 12908 12909 _fnMap( oSettings.oFeatures, oInit, "bLengthChange" ); 12910 12911 _fnMap( oSettings.oFeatures, oInit, "bFilter" ); 12912 12913 _fnMap( oSettings.oFeatures, oInit, "bSort" ); 12914 12915 _fnMap( oSettings.oFeatures, oInit, "bInfo" ); 12916 12917 _fnMap( oSettings.oFeatures, oInit, "bProcessing" ); 12918 12919 _fnMap( oSettings.oFeatures, oInit, "bAutoWidth" ); 12920 12921 _fnMap( oSettings.oFeatures, oInit, "bSortClasses" ); 12922 12923 _fnMap( oSettings.oFeatures, oInit, "bServerSide" ); 12924 12925 _fnMap( oSettings.oFeatures, oInit, "bDeferRender" ); 12926 12927 _fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" ); 12928 12929 _fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" ); 12930 12931 _fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" ); 12932
12933 _fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" ); 12934 12935 _fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" ); 12936 12937 _fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" ); 12938 12939 _fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" ); 12940 12941 _fnMap( oSettings, oInit, "asStripeClasses" ); 12942 12943 _fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy 12944 12945 _fnMap( oSettings, oInit, "fnServerData" ); 12946 12947 _fnMap( oSettings, oInit, "fnFormatNumber" ); 12948 12949 _fnMap( oSettings, oInit, "sServerMethod" ); 12950 12951 _fnMap( oSettings, oInit, "aaSorting" ); 12952 12953 _fnMap( oSettings, oInit, "aaSortingFixed" ); 12954 12955 _fnMap( oSettings, oInit, "aLengthMenu" ); 12956 12957 _fnMap( oSettings, oInit, "sPaginationType" ); 12958 12959 _fnMap( oSettings, oInit, "sAjaxSource" ); 12960 12961 _fnMap( oSettings, oInit, "sAjaxDataProp" ); 12962 12963 _fnMap( oSettings, oInit, "iCookieDuration" ); 12964 12965 _fnMap( oSettings, oInit, "sCookiePrefix" ); 12966 12967 _fnMap( oSettings, oInit, "sDom" ); 12968 12969 _fnMap( oSettings, oInit, "bSortCellsTop" ); 12970 12971 _fnMap( oSettings, oInit, "iTabIndex" ); 12972 12973 _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" ); 12974 12975 _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" ); 12976 12977 _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" ); 12978 12979 _fnMap( oSettings, oInit, "bJQueryUI", "bJUI" ); 12980 12981 _fnMap( oSettings, oInit, "fnCookieCallback" ); 12982 12983 _fnMap( oSettings, oInit, "fnStateLoad" ); 12984 12985 _fnMap( oSettings, oInit, "fnStateSave" ); 12986 12987 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 12988 12989 12990 12991 /* Callback functions which are array driven */ 12992 12993 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 12994 12995 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 12996 12997 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 12998 12999 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 13000 13001 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 13002 13003 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 13004 13005 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 13006 13007 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 13008 13009 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 13010 13011 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 13012 13013 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 13014 13015 13016 13017 if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort && 13018 13019 oSettings.oFeatures.bSortClasses ) 13020 13021 { 13022 13023 /* Enable sort classes for server-side processing. Safe to do it here, since server-side 13024 13025 * processing must be enabled by the developer 13026 13027 */ 13028 13029 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' ); 13030 13031 } 13032 13033 else if ( oSettings.oFeatures.bDeferRender ) 13034 13035 { 13036 13037 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' ); 13038 13039 } 13040 13041 13042 13043 if ( oInit.bJQueryUI ) 13044 13045 { 13046 13047 /* Use the JUI classes object for display. You could clone the oStdClasses object if 13048 13049 * you want to have multiple tables with multiple independent classes 13050 13051 */ 13052 13053 $.extend( oSettings.oClasses, DataTable.ext.oJUIClasses ); 13054 13055 13056 13057 if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" ) 13058 13059 { 13060 13061 /* Set the DOM to use a layout suitable for jQuery UI's theming */ 13062 13063 oSettings.sDom = '<"H"lfr>t<"F"ip>'; 13064 13065 } 13066 13067 } 13068 13069 else 13070 13071 { 13072 13073 $.extend( oSettings.oClasses, DataTable.ext.oStdClasses ); 13074 13075 } 13076 13077 $(this).addClass( oSettings.oClasses.sTable ); 13078 13079 13080 13081 /* Calculate the scroll bar width and cache it for use later on */ 13082 13083 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" ) 13084 13085 { 13086 13087 oSettings.oScroll.iBarWidth = _fnScrollBarWidth(); 13088 13089 } 13090 13091 13092 13093 if ( oSettings.iInitDisplayStart === undefined ) 13094 13095 { 13096 13097 /* Display start point, taking into account the save saving */ 13098 13099 oSettings.iInitDisplayStart = oInit.iDisplayStart; 13100 13101 oSettings._iDisplayStart = oInit.iDisplayStart; 13102 13103 } 13104 13105 13106 13107 /* Must be done after everything which can be overridden by a cookie! */ 13108 13109 if ( oInit.bStateSave ) 13110 13111 { 13112 13113 oSettings.oFeatures.bStateSave = true; 13114 13115 _fnLoadState( oSettings, oInit ); 13116 13117 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 13118 13119 } 13120 13121 13122 13123 if ( oInit.iDeferLoading !== null ) 13124 13125 { 13126 13127 oSettings.bDeferLoading = true; 13128 13129 var tmp = $.isArray( oInit.iDeferLoading ); 13130 13131 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 13132 13133 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 13134 13135 } 13136 13137 13138 13139 if ( oInit.aaData !== null ) 13140 13141 { 13142 13143 bUsePassedData = true; 13144 13145 } 13146 13147 13148 13149 /* Language definitions */ 13150 13151 if ( oInit.oLanguage.sUrl !== "" ) 13152 13153 { 13154 13155 /* Get the language definitions from a file - because this Ajax call makes the language 13156 13157 * get async to the remainder of this function we use bInitHandedOff to indicate that 13158 13159 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 13160 13161 */ 13162 13163 oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl; 13164 13165 $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) { 13166 13167 _fnLanguageCompat( json ); 13168 13169 $.extend( true, oSettings.oLanguage, oInit.oLanguage, json ); 13170 13171 _fnInitialise( oSettings ); 13172 13173 } ); 13174 13175 bInitHandedOff = true; 13176 13177 } 13178 13179 else 13180 13181 { 13182 13183 $.extend( true, oSettings.oLanguage, oInit.oLanguage ); 13184 13185 } 13186 13187 13188 13189 13190 13191 /* 13192 13193 * Stripes 13194 13195 */ 13196 13197 if ( oInit.asStripeClasses === null ) 13198 13199 { 13200 13201 oSettings.asStripeClasses =[ 13202 13203 oSettings.oClasses.sStripeOdd, 13204 13205 oSettings.oClasses.sStripeEven 13206 13207 ]; 13208 13209 } 13210 13211 13212 13213 /* Remove row stripe classes if they are already on the table row */ 13214
13215 iLen=oSettings.asStripeClasses.length; 13216 13217 oSettings.asDestroyStripes = []; 13218 13219 if (iLen) 13220 13221 { 13222 13223 var bStripeRemove = false; 13224 13225 var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')'); 13226 13227 for ( i=0 ; i<iLen ; i++ ) 13228 13229 { 13230 13231 if ( anRows.hasClass( oSettings.asStripeClasses[i] ) ) 13232 13233 { 13234 13235 bStripeRemove = true; 13236 13237 13238 13239 /* Store the classes which we are about to remove so they can be re-added on destroy */ 13240 13241 oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] ); 13242 13243 } 13244 13245 } 13246 13247 13248 13249 if ( bStripeRemove ) 13250 13251 { 13252 13253 anRows.removeClass( oSettings.asStripeClasses.join(' ') ); 13254 13255 } 13256 13257 } 13258 13259 13260 13261 /* 13262 13263 * Columns 13264 13265 * See if we should load columns automatically or use defined ones 13266 13267 */ 13268 13269 var anThs = []; 13270 13271 var aoColumnsInit; 13272 13273 var nThead = this.getElementsByTagName('thead'); 13274 13275 if ( nThead.length !== 0 ) 13276 13277 { 13278 13279 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 13280 13281 anThs = _fnGetUniqueThs( oSettings ); 13282 13283 } 13284 13285 13286 13287 /* If not given a column array, generate one with nulls */ 13288 13289 if ( oInit.aoColumns === null ) 13290 13291 { 13292 13293 aoColumnsInit = []; 13294 13295 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 13296 13297 { 13298 13299 aoColumnsInit.push( null ); 13300 13301 } 13302 13303 } 13304 13305 else 13306 13307 { 13308 13309 aoColumnsInit = oInit.aoColumns; 13310 13311 } 13312 13313 13314 13315 /* Add the columns */ 13316 13317 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 13318 13319 { 13320 13321 /* Short cut - use the loop to check if we have column visibility state to restore */ 13322 13323 if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen ) 13324 13325 { 13326 13327 if ( aoColumnsInit[i] === null ) 13328 13329 { 13330 13331 aoColumnsInit[i] = {}; 13332 13333 } 13334 13335 aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible; 13336 13337 } 13338 13339 13340 13341 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 13342 13343 } 13344 13345 13346 13347 /* Apply the column definitions */ 13348 13349 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 13350 13351 _fnColumnOptions( oSettings, iCol, oDef ); 13352 13353 } ); 13354 13355 13356 13357 13358 13359 /* 13360 13361 * Sorting 13362 13363 * Check the aaSorting array 13364 13365 */ 13366 13367 for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ ) 13368 13369 { 13370 13371 if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length ) 13372 13373 { 13374 13375 oSettings.aaSorting[i][0] = 0; 13376 13377 } 13378 13379 var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ]; 13380 13381 13382 13383 /* Add a default sorting index */ 13384 13385 if ( oSettings.aaSorting[i][2] === undefined ) 13386 13387 { 13388 13389 oSettings.aaSorting[i][2] = 0; 13390 13391 } 13392 13393 13394 13395 /* If aaSorting is not defined, then we use the first indicator in asSorting */ 13396 13397 if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined ) 13398 13399 { 13400 13401 oSettings.aaSorting[i][1] = oColumn.asSorting[0]; 13402 13403 } 13404 13405 13406 13407 /* Set the current sorting index based on aoColumns.asSorting */ 13408 13409 for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ ) 13410 13411 { 13412 13413 if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] ) 13414 13415 { 13416 13417 oSettings.aaSorting[i][2] = j; 13418 13419 break; 13420 13421 } 13422 13423 } 13424 13425 } 13426 13427 13428 13429 /* Do a first pass on the sorting classes (allows any size changes to be taken into 13430 13431 * account, and also will apply sorting disabled classes if disabled 13432 13433 */ 13434 13435 _fnSortingClasses( oSettings ); 13436 13437 13438 13439 13440 13441 /* 13442 13443 * Final init 13444 13445 * Cache the header, body and footer as required, creating them if needed 13446 13447 */ 13448 13449 13450 13451 /* Browser support detection */ 13452 13453 _fnBrowserDetect( oSettings ); 13454 13455 13456 13457 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 13458 13459 var captions = $(this).children('caption').each( function () { 13460 13461 this._captionSide = $(this).css('caption-side'); 13462 13463 } ); 13464 13465 13466 13467 var thead = $(this).children('thead'); 13468 13469 if ( thead.length === 0 ) 13470 13471 { 13472 13473 thead = [ document.createElement( 'thead' ) ]; 13474 13475 this.appendChild( thead[0] ); 13476 13477 } 13478 13479 oSettings.nTHead = thead[0]; 13480 13481 13482 13483 var tbody = $(this).children('tbody'); 13484 13485 if ( tbody.length === 0 ) 13486 13487 { 13488 13489 tbody = [ document.createElement( 'tbody' ) ]; 13490 13491 this.appendChild( tbody[0] ); 13492 13493 } 13494 13495 oSettings.nTBody = tbody[0]; 13496 13497 oSettings.nTBody.setAttribute( "role", "alert" ); 13498 13499 oSettings.nTBody.setAttribute( "aria-live", "polite" ); 13500 13501 oSettings.nTBody.setAttribute( "aria-relevant", "all" ); 13502 13503 13504 13505 var tfoot = $(this).children('tfoot'); 13506 13507 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) 13508 13509 { 13510 13511 // If we are a scrolling table, and no footer has been given, then we need to create 13512 13513 // a tfoot element for the caption element to be appended to 13514 13515 tfoot = [ document.createElement( 'tfoot' ) ]; 13516 13517 this.appendChild( tfoot[0] ); 13518 13519 } 13520 13521 13522 13523 if ( tfoot.length > 0 ) 13524 13525 { 13526 13527 oSettings.nTFoot = tfoot[0]; 13528 13529 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 13530 13531 } 13532 13533 13534 13535 /* Check if there is data passing into the constructor */ 13536 13537 if ( bUsePassedData ) 13538 13539 { 13540 13541 for ( i=0 ; i<oInit.aaData.length ; i++ ) 13542 13543 { 13544 13545 _fnAddData( oSettings, oInit.aaData[ i ] ); 13546 13547 } 13548 13549 } 13550 13551 else 13552 13553 { 13554 13555 /* Grab the data from the page */ 13556 13557 _fnGatherData( oSettings ); 13558 13559 } 13560 13561 13562 13563 /* Copy the data index array */ 13564 13565 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 13566 13567 13568 13569 /* Initialisation complete - table can be drawn */ 13570
13571 oSettings.bInitialised = true; 13572 13573 13574 13575 /* Check if we need to initialise the table (it might not have been handed off to the 13576 13577 * language processor) 13578 13579 */ 13580 13581 if ( bInitHandedOff === false ) 13582 13583 { 13584 13585 _fnInitialise( oSettings ); 13586 13587 } 13588 13589 } ); 13590 13591 _that = null; 13592 13593 return this; 13594 13595 }; 13596 13597 13598 13599 13600 13601 13602 13603 /** 13604 13605 * Provide a common method for plug-ins to check the version of DataTables being used, in order 13606 13607 * to ensure compatibility. 13608 13609 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 13610 13611 * formats "X" and "X.Y" are also acceptable. 13612 13613 * @returns {boolean} true if this version of DataTables is greater or equal to the required 13614 13615 * version, or false if this version of DataTales is not suitable 13616 13617 * @static 13618 13619 * @dtopt API-Static 13620 13621 * 13622 13623 * @example 13624 13625 * alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) ); 13626 13627 */ 13628 13629 DataTable.fnVersionCheck = function( sVersion ) 13630 13631 { 13632 13633 /* This is cheap, but effective */ 13634 13635 var fnZPad = function (Zpad, count) 13636 13637 { 13638 13639 while(Zpad.length < count) { 13640 13641 Zpad += '0'; 13642 13643 } 13644 13645 return Zpad; 13646 13647 }; 13648 13649 var aThis = DataTable.ext.sVersion.split('.'); 13650 13651 var aThat = sVersion.split('.'); 13652 13653 var sThis = '', sThat = ''; 13654 13655 13656 13657 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) 13658 13659 { 13660 13661 sThis += fnZPad( aThis[i], 3 ); 13662 13663 sThat += fnZPad( aThat[i], 3 ); 13664 13665 } 13666 13667 13668 13669 return parseInt(sThis, 10) >= parseInt(sThat, 10); 13670 13671 }; 13672 13673 13674 13675 13676 13677 /** 13678 13679 * Check if a TABLE node is a DataTable table already or not. 13680 13681 * @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other 13682 13683 * node types can be passed in, but will always return false). 13684 13685 * @returns {boolean} true the table given is a DataTable, or false otherwise 13686 13687 * @static 13688 13689 * @dtopt API-Static 13690 13691 * 13692 13693 * @example 13694 13695 * var ex = document.getElementById('example'); 13696 13697 * if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) { 13698 13699 * $(ex).dataTable(); 13700 13701 * } 13702 13703 */ 13704 13705 DataTable.fnIsDataTable = function ( nTable ) 13706 13707 { 13708 13709 var o = DataTable.settings; 13710 13711 13712 13713 for ( var i=0 ; i<o.length ; i++ ) 13714 13715 { 13716 13717 if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable ) 13718 13719 { 13720 13721 return true; 13722 13723 } 13724 13725 } 13726 13727 13728 13729 return false; 13730 13731 }; 13732 13733 13734 13735 13736 13737 /** 13738 13739 * Get all DataTable tables that have been initialised - optionally you can select to 13740 13741 * get only currently visible tables. 13742 13743 * @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or 13744 13745 * visible tables only. 13746 13747 * @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables 13748 13749 * @static 13750 13751 * @dtopt API-Static 13752 13753 * 13754 13755 * @example 13756 13757 * var table = $.fn.dataTable.fnTables(true); 13758 13759 * if ( table.length > 0 ) { 13760 13761 * $(table).dataTable().fnAdjustColumnSizing(); 13762 13763 * } 13764 13765 */ 13766 13767 DataTable.fnTables = function ( bVisible ) 13768 13769 { 13770 13771 var out = []; 13772 13773 13774 13775 jQuery.each( DataTable.settings, function (i, o) { 13776 13777 if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) ) 13778 13779 { 13780 13781 out.push( o.nTable ); 13782 13783 } 13784 13785 } ); 13786 13787 13788 13789 return out; 13790 13791 }; 13792 13793 13794 13795 13796 13797 /** 13798 13799 * Version string for plug-ins to check compatibility. Allowed format is 13800 13801 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and 13802 13803 * e are optional 13804 13805 * @member 13806 13807 * @type string 13808 13809 * @default Version number 13810 13811 */ 13812 13813 DataTable.version = "1.9.4"; 13814 13815 13816 13817 /** 13818 13819 * Private data store, containing all of the settings objects that are created for the 13820 13821 * tables on a given page. 13822 13823 * 13824 13825 * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i> 13826 13827 * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>. 13828 13829 * @member 13830 13831 * @type array 13832 13833 * @default [] 13834 13835 * @private 13836 13837 */ 13838 13839 DataTable.settings = []; 13840 13841 13842 13843 /** 13844 13845 * Object models container, for the various models that DataTables has available 13846 13847 * to it. These models define the objects that are used to hold the active state 13848 13849 * and configuration of the table. 13850 13851 * @namespace 13852 13853 */ 13854 13855 DataTable.models = {}; 13856 13857 13858 13859 13860 13861 /** 13862
13863 * DataTables extension options and plug-ins. This namespace acts as a collection "area" 13864 13865 * for plug-ins that can be used to extend the default DataTables behaviour - indeed many 13866 13867 * of the build in methods use this method to provide their own capabilities (sorting methods 13868 13869 * for example). 13870 13871 * 13872 13873 * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed 13874 13875 * and modified by plug-ins. 13876 13877 * @namespace 13878 13879 */ 13880 13881 DataTable.models.ext = { 13882 13883 /** 13884 13885 * Plug-in filtering functions - this method of filtering is complimentary to the default 13886 13887 * type based filtering, and a lot more comprehensive as it allows you complete control 13888 13889 * over the filtering logic. Each element in this array is a function (parameters 13890 13891 * described below) that is called for every row in the table, and your logic decides if 13892 13893 * it should be included in the filtered data set or not. 13894 13895 * <ul> 13896 13897 * <li> 13898 13899 * Function input parameters: 13900 13901 * <ul> 13902 13903 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> 13904 13905 * <li>{array|object} Data for the row to be processed (same as the original format 13906 13907 * that was passed in as the data source, or an array from a DOM data source</li> 13908 13909 * <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can 13910 13911 * be useful to retrieve the TR element if you need DOM interaction.</li> 13912 13913 * </ul> 13914 13915 * </li> 13916 13917 * <li> 13918 13919 * Function return: 13920 13921 * <ul> 13922 13923 * <li>{boolean} Include the row in the filtered result set (true) or not (false)</li> 13924 13925 * </ul> 13926 13927 * </il> 13928 13929 * </ul> 13930 13931 * @type array 13932 13933 * @default [] 13934 13935 * 13936 13937 * @example 13938 13939 * // The following example shows custom filtering being applied to the fourth column (i.e. 13940 13941 * // the aData[3] index) based on two input values from the end-user, matching the data in 13942 13943 * // a certain range. 13944 13945 * $.fn.dataTableExt.afnFiltering.push( 13946 13947 * function( oSettings, aData, iDataIndex ) { 13948 13949 * var iMin = document.getElementById('min').value * 1; 13950 13951 * var iMax = document.getElementById('max').value * 1; 13952 13953 * var iVersion = aData[3] == "-" ? 0 : aData[3]*1; 13954 13955 * if ( iMin == "" && iMax == "" ) { 13956 13957 * return true; 13958 13959 * } 13960 13961 * else if ( iMin == "" && iVersion < iMax ) { 13962 13963 * return true; 13964 13965 * } 13966 13967 * else if ( iMin < iVersion && "" == iMax ) { 13968 13969 * return true; 13970 13971 * } 13972 13973 * else if ( iMin < iVersion && iVersion < iMax ) { 13974 13975 * return true; 13976 13977 * } 13978 13979 * return false; 13980 13981 * } 13982 13983 * ); 13984 13985 */ 13986 13987 "afnFiltering": [], 13988 13989 13990 13991 13992 13993 /** 13994 13995 * Plug-in sorting functions - this method of sorting is complimentary to the default type 13996 13997 * based sorting that DataTables does automatically, allowing much greater control over the 13998 13999 * the data that is being used to sort a column. This is useful if you want to do sorting 14000 14001 * based on live data (for example the contents of an 'input' element) rather than just the 14002 14003 * static string that DataTables knows of. The way these plug-ins work is that you create 14004 14005 * an array of the values you wish to be sorted for the column in question and then return 14006 14007 * that array. Which pre-sorting function is run here depends on the sSortDataType parameter 14008 14009 * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort 14010 14011 * data. 14012 14013 * <ul> 14014 14015 * <li> 14016 14017 * Function input parameters: 14018 14019 * <ul> 14020 14021 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> 14022 14023 * <li>{int} Target column index</li> 14024 14025 * </ul> 14026 14027 * </li> 14028 14029 * <li> 14030 14031 * Function return: 14032 14033 * <ul> 14034 14035 * <li>{array} Data for the column to be sorted upon</li> 14036 14037 * </ul> 14038 14039 * </il> 14040 14041 * </ul> 14042 14043 * 14044 14045 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for 14046 14047 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when 14048 14049 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 14050 14051 * prepare the data as required for the different types. As such, this method is deprecated. 14052 14053 * @type array 14054 14055 * @default [] 14056 14057 * @deprecated 14058 14059 * 14060 14061 * @example 14062 14063 * // Updating the cached sorting information with user entered values in HTML input elements 14064 14065 * jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn ) 14066 14067 * { 14068 14069 * var aData = []; 14070 14071 * $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () { 14072 14073 * aData.push( this.value ); 14074 14075 * } ); 14076 14077 * return aData; 14078 14079 * } 14080 14081 */ 14082 14083 "afnSortData": [], 14084 14085 14086 14087 14088 14089 /** 14090
14091 * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are 14092 14093 * available to DataTables. These feature plug-ins are accessible through the sDom initialisation 14094 14095 * option. As such, each feature plug-in must describe a function that is used to initialise 14096 14097 * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name 14098 14099 * of the feature (sFeature). Thus the objects attached to this method must provide: 14100 14101 * <ul> 14102 14103 * <li>{function} fnInit Initialisation of the plug-in 14104 14105 * <ul> 14106 14107 * <li> 14108 14109 * Function input parameters: 14110 14111 * <ul> 14112 14113 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> 14114 14115 * </ul> 14116 14117 * </li> 14118 14119 * <li> 14120 14121 * Function return: 14122 14123 * <ul> 14124 14125 * <li>{node|null} The element which contains your feature. Note that the return 14126 14127 * may al
14127so be void if your plug-in does not require to inject any DOM elements 14128 14129 * into DataTables control (sDom) - for example this might be useful when 14130 14131 * developing a plug-in which allows table control via keyboard entry.</li> 14132 14133 * </ul> 14134 14135 * </il> 14136 14137 * </ul> 14138 14139 * </li> 14140 14141 * <li>{character} cFeature Character that will be matched in sDom - case sensitive</li> 14142 14143 * <li>{string} sFeature Feature name</li> 14144 14145 * </ul> 14146 14147 * @type array 14148 14149 * @default [] 14150 14151 * 14152 14153 * @example 14154 14155 * // How TableTools initialises itself. 14156 14157 * $.fn.dataTableExt.aoFeatures.push( { 14158 14159 * "fnInit": function( oSettings ) { 14160 14161 * return new TableTools( { "oDTSettings": oSettings } ); 14162 14163 * }, 14164 14165 * "cFeature": "T", 14166 14167 * "sFeature": "TableTools" 14168 14169 * } ); 14170 14171 */ 14172 14173 "aoFeatures": [], 14174 14175 14176 14177 14178 14179 /** 14180 14181 * Type detection plug-in functions - DataTables utilises types to define how sorting and 14182 14183 * filtering behave, and types can be either be defined by the developer (sType for the 14184 14185 * column) or they can be automatically detected by the methods in this array. The functions 14186 14187 * defined in the array are quite simple, taking a single parameter (the data to analyse) 14188 14189 * and returning the type if it is a known type, or null otherwise. 14190 14191 * <ul> 14192 14193 * <li> 14194 14195 * Function input parameters: 14196 14197 * <ul> 14198 14199 * <li>{*} Data from the column cell to be analysed</li> 14200 14201 * </ul> 14202 14203 * </li> 14204 14205 * <li> 14206 14207 * Function return: 14208 14209 * <ul> 14210 14211 * <li>{string|null} Data type detected, or null if unknown (and thus pass it 14212 14213 * on to the other type detection functions.</li> 14214 14215 * </ul> 14216 14217 * </il> 14218 14219 * </ul> 14220 14221 * @type array 14222 14223 * @default [] 14224 14225 * 14226 14227 * @example 14228 14229 * // Currency type detection plug-in: 14230 14231 * jQuery.fn.dataTableExt.aTypes.push( 14232 14233 * function ( sData ) { 14234 14235 * var sValidChars = "0123456789.-"; 14236 14237 * var Char; 14238 14239 * 14240 14241 * // Check the numeric part 14242 14243 * for ( i=1 ; i<sData.length ; i++ ) { 14244 14245 * Char = sData.charAt(i); 14246 14247 * if (sValidChars.indexOf(Char) == -1) { 14248 14249 * return null; 14250 14251 * } 14252 14253 * } 14254 14255 * 14256 14257 * // Check prefixed by currency 14258 14259 * if ( sData.charAt(0) == '$' || sData.charAt(0) == '£' ) { 14260 14261 * return 'currency'; 14262 14263 * } 14264 14265 * return null; 14266 14267 * } 14268 14269 * ); 14270 14271 */ 14272 14273 "aTypes": [], 14274 14275 14276 14277 14278 14279 /** 14280 14281 * Provide a common method for plug-ins to check the version of DataTables being used, 14282 14283 * in order to ensure compatibility. 14284 14285 * @type function 14286 14287 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note 14288 14289 * that the formats "X" and "X.Y" are also acceptable. 14290 14291 * @returns {boolean} true if this version of DataTables is greater or equal to the 14292 14293 * required version, or false if this version of DataTales is not suitable 14294 14295 * 14296 14297 * @example 14298 14299 * $(document).ready(function() { 14300 14301 * var oTable = $('#example').dataTable(); 14302 14303 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 14304 14305 * } ); 14306 14307 */ 14308 14309 "fnVersionCheck": DataTable.fnVersionCheck, 14310 14311 14312 14313 14314 14315 /** 14316 14317 * Index for what 'this' index API functions should use 14318 14319 * @type int 14320 14321 * @default 0 14322 14323 */ 14324 14325 "iApiIndex": 0, 14326 14327 14328 14329 14330 14331 /** 14332 14333 * Pre-processing of filtering data plug-ins - When you assign the sType for a column 14334 14335 * (or have it automatically detected for you by DataTables or a type detection plug-in), 14336 14337 * you will typically be using this for custom sorting, but it can also be used to provide 14338 14339 * custom filtering by allowing you to pre-processing the data and returning the data in 14340 14341 * the format that should be filtered upon. This is done by adding functions this object 14342 14343 * with a parameter name which matches the sType for that target column. This is the 14344 14345 * corollary of <i>afnSortData</i> for filtering data. 14346 14347 * <ul> 14348 14349 * <li> 14350 14351 * Function input parameters: 14352 14353 * <ul> 14354 14355 * <li>{*} Data from the column cell to be prepared for filtering</li> 14356 14357 * </ul> 14358 14359 * </li> 14360 14361 * <li> 14362 14363 * Function return: 14364 14365 * <ul> 14366 14367 * <li>{string|null} Formatted string that will be used for the filtering.</li> 14368 14369 * </ul> 14370 14371 * </il> 14372 14373 * </ul> 14374 14375 * 14376 14377 * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for 14378 14379 * the different uses that DataTables can put the data to. Specifically <i>mData</i> when 14380 14381 * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 14382 14383 * prepare the data as required for the different types. As such, this method is deprecated. 14384 14385 * @type object 14386 14387 * @default {} 14388 14389 * @deprecated 14390 14391 * 14392 14393 * @example 14394 14395 * $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) { 14396 14397 * return sData.replace(/\n/g," ").replace( /<.*?>/g, "" ); 14398 14399 * } 14400 14401 */ 14402 14403 "ofnSearch": {}, 14404 14405 14406 14407 14408 14409 /** 14410
14411 * Container for all private functions in DataTables so they can be exposed externally 14412 14413 * @type object 14414 14415 * @default {} 14416 14417 */ 14418 14419 "oApi": {}, 14420 14421 14422 14423 14424 14425 /** 14426 14427 * Storage for the various classes that DataTables uses 14428 14429 * @type object 14430 14431 * @default {} 14432 14433 */ 14434 14435 "oStdClasses": {}, 14436 14437 14438 14439 14440 14441 /** 14442 14443 * Storage for the various classes that DataTables uses - jQuery UI suitable 14444 14445 * @type object 14446 14447 * @default {} 14448 14449 */ 14450 14451 "oJUIClasses": {}, 14452 14453 14454 14455 14456 14457 /** 14458 14459 * Pagination plug-in methods - The style and controls of the pagination can significantly 14460 14461 * impact on how the end user interacts with the data in your table, and DataTables allows 14462 14463 * the addition of pagination controls by extending this object, which can then be enabled 14464 14465 * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that 14466 14467 * is added is an object (the property name of which is what <i>sPaginationType</i> refers 14468 14469 * to) that has two properties, both methods that are used by DataTables to update the 14470 14471 * control's state. 14472 14473 * <ul> 14474 14475 * <li> 14476 14477 * fnInit - Initialisation of the paging controls. Called only during initialisation 14478 14479 * of the table. It is expected that this function will add the required DOM elements 14480 14481 * to the page for the paging controls to work. The element pointer 14482 14483 * 'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging 14484 14485 * controls (note that this is a 2D array to allow for multiple instances of each 14486 14487 * DataTables DOM element). It is suggested that you add the controls to this element 14488 14489 * as children 14490 14491 * <ul> 14492 14493 * <li> 14494 14495 * Function input parameters: 14496 14497 * <ul> 14498 14499 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> 14500 14501 * <li>{node} Container into which the pagination controls must be inserted</li> 14502 14503 * <li>{function} Draw callback function - whenever the controls cause a page 14504 14505 * change, this method must be called to redraw the table.</li> 14506 14507 * </ul> 14508 14509 * </li> 14510 14511 * <li> 14512 14513 * Function return: 14514 14515 * <ul> 14516 14517 * <li>No return required</li> 14518 14519 * </ul> 14520 14521 * </il> 14522 14523 * </ul> 14524 14525 * </il> 14526 14527 * <li> 14528 14529 * fnInit - This function is called whenever the paging status of the table changes and is 14530 14531 * typically used to update classes and/or text of the paging controls to reflex the new 14532 14533 * status. 14534 14535 * <ul> 14536 14537 * <li> 14538 14539 * Function input parameters: 14540 14541 * <ul> 14542 14543 * <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li> 14544 14545 * <li>{function} Draw callback function - in case you need to redraw the table again 14546 14547 * or attach new event listeners</li> 14548 14549 * </ul> 14550 14551 * </li> 14552 14553 * <li> 14554 14555 * Function return: 14556 14557 * <ul> 14558 14559 * <li>No return required</li> 14560 14561 * </ul> 14562 14563 * </il> 14564 14565 * </ul> 14566 14567 * </il> 14568 14569 * </ul> 14570 14571 * @type object 14572 14573 * @default {} 14574 14575 * 14576 14577 * @example 14578 14579 * $.fn.dataTableExt.oPagination.four_button = { 14580 14581 * "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) { 14582 14583 * nFirst = document.createElement( 'span' ); 14584 14585 * nPrevious = document.createElement( 'span' ); 14586 14587 * nNext = document.createElement( 'span' ); 14588 14589 * nLast = document.createElement( 'span' ); 14590 14591 * 14592 14593 * nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) ); 14594 14595 * nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) ); 14596 14597 * nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) ); 14598 14599 * nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) ); 14600 14601 * 14602 14603 * nFirst.className = "paginate_button first"; 14604 14605 * nPrevious.className = "paginate_button previous"; 14606 14607 * nNext.className="paginate_button next"; 14608 14609 * nLast.className = "paginate_button last"; 14610 14611 * 14612 14613 * nPaging.appendChild( nFirst ); 14614 14615 * nPaging.appendChild( nPrevious ); 14616 14617 * nPaging.appendChild( nNext ); 14618 14619 * nPaging.appendChild( nLast ); 14620 14621 * 14622 14623 * $(nFirst).click( function () { 14624 14625 * oSettings.oApi._fnPageChange( oSettings, "first" ); 14626 14627 * fnCallbackDraw( oSettings ); 14628 14629 * } ); 14630 14631 * 14632 14633 * $(nPrevious).click( function() { 14634 14635 * oSettings.oApi._fnPageChange( oSettings, "previous" ); 14636 14637 * fnCallbackDraw( oSettings ); 14638 14639 * } ); 14640 14641 * 14642 14643 * $(nNext).click( function() { 14644 14645 * oSettings.oApi._fnPageChange( oSettings, "next" ); 14646 14647 * fnCallbackDraw( oSettings ); 14648 14649 * } ); 14650 14651 * 14652 14653 * $(nLast).click( function() { 14654 14655 * oSettings.oApi._fnPageChange( oSettings, "last" ); 14656 14657 * fnCallbackDraw( oSettings ); 14658 14659 * } ); 14660 14661 * 14662 14663 * $(nFirst).bind( 'selectstart', function () { return false; } ); 14664 14665 * $(nPrevious).bind( 'selectstart', function () { return false; } ); 14666 14667 * $(nNext).bind( 'selectstart', function () { return false; } ); 14668 14669 * $(nLast).bind( 'selectstart', function () { return false; } ); 14670 14671 * }, 14672 14673 * 14674 14675 * "fnUpdate": function ( oSettings, fnCallbackDraw ) { 14676 14677 * if ( !oSettings.aanFeatures.p ) { 14678 14679 * return; 14680 14681 * } 14682 14683 * 14684 14685 * // Loop over each instance of the pager 14686 14687 * var an = oSettings.aanFeatures.p; 14688 14689 * for ( var i=0, iLen=an.length ; i<iLen ; i++ ) { 14690 14691 * var buttons = an[i].getElementsByTagName('span'); 14692 14693 * if ( oSettings._iDisplayStart === 0 ) { 14694 14695 * buttons[0].className = "paginate_disabled_previous"; 14696 14697 * buttons[1].className = "paginate_disabled_previous"; 14698 14699 * } 14700 14701 * else { 14702 14703 * buttons[0].className = "paginate_enabled_previous"; 14704 14705 * buttons[1].className = "paginate_enabled_previous"; 14706 14707 * } 14708 14709 * 14710 14711 * if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) { 14712 14713 * buttons[2].className = "paginate_disabled_next"; 14714 14715 * buttons[3].className = "paginate_disabled_next"; 14716 14717 * } 14718 14719 * else { 14720 14721 * buttons[2].className = "paginate_enabled_next"; 14722 14723 * buttons[3].className = "paginate_enabled_next"; 14724 14725 * } 14726 14727 * } 14728 14729 * } 14730 14731 * }; 14732 14733 */ 14734 14735 "oPagination": {}, 14736 14737 14738 14739 14740 14741 /** 14742 14743 * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the 14744 14745 * data column (you can add your own type detection functions, or override automatic 14746 14747 * detection using sType). With this specific type given to the column, DataTables will 14748 14749 * apply the required sort from the functions in the object. Each sort type must provide 14750
14751 * two mandatory methods, one each for ascending and descending sorting, and can optionally 14752 14753 * provide a pre-formatting method that will help speed up sorting by allowing DataTables 14754 14755 * to pre-format the sort data only once (rather than every time the actual sort functions 14756 14757 * are run). The two sorting functions are typical Javascript sort methods: 14758 14759 * <ul> 14760 14761 * <li> 14762 14763 * Function input parameters: 14764 14765 * <ul> 14766 14767 * <li>{*} Data to compare to the second parameter</li> 14768 14769 * <li>{*} Data to compare to the first parameter</li> 14770 14771 * </ul> 14772 14773 * </li> 14774 14775 * <li> 14776 14777 * Function return: 14778 14779 * <ul> 14780 14781 * <li>{int} Sorting match: <0 if first parameter should be sorted lower than 14782 14783 * the second parameter, ===0 if the two parameters are equal and >0 if 14784 14785 * the first parameter should be sorted height than the second parameter.</li> 14786 14787 * </ul> 14788 14789 * </il> 14790 14791 * </ul> 14792 14793 * @type object 14794 14795 * @default {} 14796 14797 * 14798 14799 * @example 14800 14801 * // Case-sensitive string sorting, with no pre-formatting method 14802 14803 * $.extend( $.fn.dataTableExt.oSort, { 14804 14805 * "string-case-asc": function(x,y) { 14806 14807 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14808 14809 * }, 14810 14811 * "string-case-desc": function(x,y) { 14812 14813 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14814 14815 * } 14816 14817 * } ); 14818 14819 * 14820 14821 * @example 14822 14823 * // Case-insensitive string sorting, with pre-formatting 14824 14825 * $.extend( $.fn.dataTableExt.oSort, { 14826 14827 * "string-pre": function(x) { 14828 14829 * return x.toLowerCase(); 14830 14831 * }, 14832 14833 * "string-asc": function(x,y) { 14834 14835 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14836 14837 * }, 14838 14839 * "string-desc": function(x,y) { 14840 14841 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14842 14843 * } 14844 14845 * } ); 14846 14847 */ 14848 14849 "oSort": {}, 14850 14851 14852 14853 14854 14855 /** 14856 14857 * Version string for plug-ins to check compatibility. Allowed format is 14858 14859 * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and 14860 14861 * e are optional 14862 14863 * @type string 14864 14865 * @default Version number 14866 14867 */ 14868 14869 "sVersion": DataTable.version, 14870 14871 14872 14873 14874 14875 /** 14876 14877 * How should DataTables report an error. Can take the value 'alert' or 'throw' 14878 14879 * @type string 14880 14881 * @default alert 14882 14883 */ 14884 14885 "sErrMode": "alert", 14886 14887 14888 14889 14890 14891 /** 14892 14893 * Store information for DataTables to access globally about other instances 14894 14895 * @namespace 14896 14897 * @private 14898 14899 */ 14900 14901 "_oExternConfig": { 14902 14903 /* int:iNextUnique - next unique number for an instance */ 14904 14905 "iNextUnique": 0 14906 14907 } 14908 14909 }; 14910 14911 14912 14913 14914 14915 14916 14917 14918 14919 /** 14920 14921 * Template object for the way in which DataTables holds information about 14922 14923 * search information for the global filter and individual column filters. 14924 14925 * @namespace 14926 14927 */ 14928 14929 DataTable.models.oSearch = { 14930 14931 /** 14932 14933 * Flag to indicate if the filtering should be case insensitive or not 14934 14935 * @type boolean 14936 14937 * @default true 14938 14939 */ 14940 14941 "bCaseInsensitive": true, 14942 14943 14944 14945 /** 14946 14947 * Applied search term 14948 14949 * @type string 14950 14951 * @default <i>Empty string</i> 14952 14953 */ 14954 14955 "sSearch": "", 14956 14957 14958 14959 /** 14960 14961 * Flag to indicate if the search term should be interpreted as a 14962 14963 * regular expression (true) or not (false) and therefore and special 14964 14965 * regex characters escaped. 14966 14967 * @type boolean 14968 14969 * @default false 14970 14971 */ 14972 14973 "bRegex": false, 14974 14975 14976 14977 /** 14978 14979 * Flag to indicate if DataTables is to use its smart filtering or not. 14980 14981 * @type boolean 14982 14983 * @default true 14984 14985 */ 14986 14987 "bSmart": true 14988 14989 }; 14990 14991 14992 14993 14994 14995 14996 14997 14998 14999 /** 15000 15001 * Template object for the way in which DataTables holds information about 15002 15003 * each individual row. This is the object format used for the settings 15004 15005 * aoData array. 15006 15007 * @namespace 15008 15009 */ 15010 15011 DataTable.models.oRow = { 15012 15013 /** 15014 15015 * TR element for the row 15016 15017 * @type node 15018 15019 * @default null 15020 15021 */ 15022 15023 "nTr": null, 15024 15025 15026 15027 /** 15028 15029 * Data object from the original data source for the row. This is either 15030 15031 * an array if using the traditional form of DataTables, or an object if 15032 15033 * using mData options. The exact type will depend on the passed in 15034 15035 * data from the data source, or will be an array if using DOM a data 15036 15037 * source. 15038 15039 * @type array|object 15040 15041 * @default [] 15042 15043 */ 15044 15045 "_aData": [], 15046 15047 15048 15049 /** 15050 15051 * Sorting data cache - this array is ostensibly the same length as the 15052 15053 * number of columns (although each index is generated only as it is 15054 15055 * needed), and holds the data that is used for sorting each column in the 15056 15057 * row. We do this cache generation at the start of the sort in order that 15058 15059 * the formatting of the sort data need be done only once for each cell 15060 15061 * per sort. This array should not be read from or written to by anything 15062 15063 * other than the master sorting methods. 15064 15065 * @type array 15066 15067 * @default [] 15068 15069 * @private 15070 15071 */ 15072 15073 "_aSortData": [], 15074 15075 15076 15077 /** 15078 15079 * Array of TD elements that are cached for hidden rows, so they can be 15080 15081 * reinserted into the table if a column is made visible again (or to act 15082 15083 * as a store if a column is made hidden). Only hidden columns have a 15084 15085 * reference in the array. For non-hidden columns the value is either 15086 15087 * undefined or null. 15088
15089 * @type array nodes 15090 15091 * @default [] 15092 15093 * @private 15094 15095 */ 15096 15097 "_anHidden": [], 15098 15099 15100 15101 /** 15102 15103 * Cache of the class name that DataTables has applied to the row, so we 15104 15105 * can quickly look at this variable rather than needing to do a DOM check 15106 15107 * on className for the nTr property. 15108 15109 * @type string 15110 15111 * @default <i>Empty string</i> 15112 15113 * @private 15114 15115 */ 15116 15117 "_sRowStripe": "" 15118 15119 }; 15120 15121 15122 15123 15124 15125 15126 15127 /** 15128 15129 * Template object for the column information object in DataTables. This object 15130 15131 * is held in the settings aoColumns array and contains all the information that 15132 15133 * DataTables needs about each individual column. 15134 15135 * 15136 15137 * Note that this object is related to {@link DataTable.defaults.columns} 15138 15139 * but this one is the internal data store for DataTables's cache of columns. 15140 15141 * It should NOT be manipulated outside of DataTables. Any configuration should 15142 15143 * be done through the initialisation options. 15144 15145 * @namespace 15146 15147 */ 15148 15149 DataTable.models.oColumn = { 15150 15151 /** 15152 15153 * A list of the columns that sorting should occur on when this column 15154 15155 * is sorted. That this property is an array allows multi-column sorting 15156 15157 * to be defined for a column (for example first name / last name columns 15158 15159 * would benefit from this). The values are integers pointing to the 15160 15161 * columns to be sorted on (typically it will be a single integer pointing 15162 15163 * at itself, but that doesn't need to be the case). 15164 15165 * @type array 15166 15167 */ 15168 15169 "aDataSort": null, 15170 15171 15172 15173 /** 15174 15175 * Define the sorting directions that are applied to the column, in sequence 15176 15177 * as the column is repeatedly sorted upon - i.e. the first value is used 15178 15179 * as the sorting direction when the column if first sorted (clicked on). 15180 15181 * Sort it again (click again) and it will move on to the next index. 15182 15183 * Repeat until loop. 15184 15185 * @type array 15186 15187 */ 15188 15189 "asSorting": null, 15190 15191 15192 15193 /** 15194 15195 * Flag to indicate if the column is searchable, and thus should be included 15196 15197 * in the filtering or not. 15198 15199 * @type boolean 15200 15201 */ 15202 15203 "bSearchable": null, 15204 15205 15206 15207 /** 15208 15209 * Flag to indicate if the column is sortable or not. 15210 15211 * @type boolean 15212 15213 */ 15214 15215 "bSortable": null, 15216 15217 15218 15219 /** 15220 15221 * <code>Deprecated</code> When using fnRender, you have two options for what 15222 15223 * to do with the data, and this property serves as the switch. Firstly, you 15224 15225 * can have the sorting and filtering use the rendered value (true - default), 15226 15227 * or you can have the sorting and filtering us the original value (false). 15228 15229 * 15230 15231 * Please note that this option has now been deprecated and will be removed 15232 15233 * in the next version of DataTables. Please use mRender / mData rather than 15234 15235 * fnRender. 15236 15237 * @type boolean 15238 15239 * @deprecated 15240 15241 */ 15242 15243 "bUseRendered": null, 15244 15245 15246 15247 /** 15248 15249 * Flag to indicate if the column is currently visible in the table or not 15250 15251 * @type boolean 15252 15253 */ 15254 15255 "bVisible": null, 15256 15257 15258 15259 /** 15260 15261 * Flag to indicate to the type detection method if the automatic type 15262 15263 * detection should be used, or if a column type (sType) has been specified 15264 15265 * @type boolean 15266 15267 * @default true 15268 15269 * @private 15270 15271 */ 15272 15273 "_bAutoType": true, 15274 15275 15276 15277 /** 15278 15279 * Developer definable function that is called whenever a cell is created (Ajax source, 15280 15281 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 15282 15283 * allowing you to modify the DOM element (add background colour for example) when the 15284 15285 * element is available. 15286 15287 * @type function 15288 15289 * @param {element} nTd The TD node that has been created 15290 15291 * @param {*} sData The Data for the cell 15292 15293 * @param {array|object} oData The data for the whole row 15294 15295 * @param {int} iRow The row index for the aoData data store 15296 15297 * @default null 15298 15299 */ 15300 15301 "fnCreatedCell": null, 15302 15303 15304 15305 /** 15306 15307 * Function to get data from a cell in a column. You should <b>never</b> 15308 15309 * access data directly through _aData internally in DataTables - always use 15310 15311 * the method attached to this property. It allows mData to function as 15312 15313 * required. This function is automatically assigned by the column 15314 15315 * initialisation method 15316 15317 * @type function 15318 15319 * @param {array|object} oData The data array/object for the array 15320 15321 * (i.e. aoData[]._aData) 15322 15323 * @param {string} sSpecific The specific data type you want to get - 15324 15325 * 'display', 'type' 'filter' 'sort' 15326 15327 * @returns {*} The data for the cell from the given row's data 15328 15329 * @default null 15330 15331 */ 15332 15333 "fnGetData": null, 15334 15335 15336 15337 /** 15338 15339 * <code>Deprecated</code> Custom display function that will be called for the 15340 15341 * display of each cell in this column. 15342 15343 * 15344 15345 * Please note that this option has now been deprecated and will be removed 15346 15347 * in the next version of DataTables. Please use mRender / mData rather than 15348 15349 * fnRender. 15350 15351 * @type function 15352 15353 * @param {object} o Object with the following parameters: 15354 15355 * @param {int} o.iDataRow The row in aoData 15356 15357 * @param {int} o.iDataColumn The column in question 15358 15359 * @param {array} o.aData The data for the row in question 15360 15361 * @param {object} o.oSettings The settings object for this DataTables instance 15362 15363 * @returns {string} The string you which to use in the display 15364 15365 * @default null 15366 15367 * @deprecated 15368 15369 */ 15370 15371 "fnRender": null, 15372 15373 15374 15375 /** 15376 15377 * Function to set data for a cell in the column. You should <b>never</b> 15378 15379 * set the data directly to _aData internally in DataTables - always use 15380 15381 * this method. It allows mData to function as required. This function 15382 15383 * is automatically assigned by the column initialisation method 15384 15385 * @type function 15386 15387 * @param {array|object} oData The data array/object for the array 15388 15389 * (i.e. aoData[]._aData) 15390 15391 * @param {*} sValue Value to set 15392 15393 * @default null 15394 15395 */ 15396 15397 "fnSetData": null, 15398 15399 15400 15401 /** 15402 15403 * Property to read the value for the cells in the column from the data 15404 15405 * source array / object. If null, then the default content is used, if a 15406 15407 * function is given then the return from the function is used. 15408 15409 * @type function|int|string|null 15410 15411 * @default null 15412 15413 */ 15414 15415 "mData": null, 15416 15417 15418 15419 /** 15420 15421 * Partner property to mData which is used (only when defined) to get 15422 15423 * the data - i.e. it is basically the same as mData, but without the 15424 15425 * 'set' option, and also the data fed to it is the result from mData. 15426 15427 * This is the rendering method to match the data method of mData. 15428 15429 * @type function|int|string|null 15430 15431 * @default null 15432 15433 */ 15434 15435 "mRender": null, 15436 15437 15438 15439 /** 15440 15441 * Unique header TH/TD element for this column - this is what the sorting 15442 15443 * listener is attached to (if sorting is enabled.) 15444 15445 * @type node 15446 15447 * @default null 15448 15449 */ 15450 15451 "nTh": null, 15452 15453 15454 15455 /** 15456 15457 * Unique footer TH/TD element for this column (if there is one). Not used 15458
15459 * in DataTables as such, but can be used for plug-ins to reference the 15460 15461 * footer for each column. 15462 15463 * @type node 15464 15465 * @default null 15466 15467 */ 15468 15469 "nTf": null, 15470 15471 15472 15473 /** 15474 15475 * The class to apply to all TD elements in the table's TBODY for the column 15476 15477 * @type string 15478 15479 * @default null 15480 15481 */ 15482 15483 "sClass": null, 15484 15485 15486 15487 /** 15488 15489 * When DataTables calculates the column widths to assign to each column, 15490 15491 * it finds the longest string in each column and then constructs a 15492 15493 * temporary table and reads the widths from that. The problem with this 15494 15495 * is that "mmm" is much wider then "iiii", but the latter is a longer 15496 15497 * string - thus the calculation can go wrong (doing it properly and putting 15498 15499 * it into an DOM object and measuring that is horribly(!) slow). Thus as 15500 15501 * a "work around" we provide this option. It will append its value to the 15502 15503 * text that is found to be the longest string for the column - i.e. padding. 15504 15505 * @type string 15506 15507 */ 15508 15509 "sContentPadding": null, 15510 15511 15512 15513 /** 15514 15515 * Allows a default value to be given for a column's data, and will be used 15516 15517 * whenever a null data source is encountered (this can be because mData 15518 15519 * is set to null, or because the data source itself is null). 15520 15521 * @type string 15522 15523 * @default null 15524 15525 */ 15526 15527 "sDefaultContent": null, 15528 15529 15530 15531 /** 15532 15533 * Name for the column, allowing reference to the column by name as well as 15534 15535 * by index (needs a lookup to work by name). 15536 15537 * @type string 15538 15539 */ 15540 15541 "sName": null, 15542 15543 15544 15545 /** 15546 15547 * Custom sorting data type - defines which of the available plug-ins in 15548 15549 * afnSortData the custom sorting will use - if any is defined. 15550 15551 * @type string 15552 15553 * @default std 15554 15555 */ 15556 15557 "sSortDataType": 'std', 15558 15559 15560 15561 /** 15562 15563 * Class to be applied to the header element when sorting on this column 15564 15565 * @type string 15566 15567 * @default null 15568 15569 */ 15570 15571 "sSortingClass": null, 15572 15573 15574 15575 /** 15576 15577 * Class to be applied to the header element when sorting on this column - 15578 15579 * when jQuery UI theming is used. 15580 15581 * @type string 15582 15583 * @default null 15584 15585 */ 15586 15587 "sSortingClassJUI": null, 15588 15589 15590 15591 /** 15592 15593 * Title of the column - what is seen in the TH element (nTh). 15594 15595 * @type string 15596 15597 */ 15598 15599 "sTitle": null, 15600 15601 15602 15603 /** 15604 15605 * Column sorting and filtering type 15606 15607 * @type string 15608 15609 * @default null 15610 15611 */ 15612 15613 "sType": null, 15614 15615 15616 15617 /** 15618 15619 * Width of the column 15620 15621 * @type string 15622 15623 * @default null 15624 15625 */ 15626 15627 "sWidth": null, 15628 15629 15630 15631 /** 15632 15633 * Width of the column when it was first "encountered" 15634 15635 * @type string 15636 15637 * @default null 15638 15639 */ 15640 15641 "sWidthOrig": null 15642 15643 }; 15644 15645 15646 15647 15648 15649 15650 15651 /** 15652 15653 * Initialisation options that can be given to DataTables at initialisation 15654 15655 * time. 15656 15657 * @namespace 15658 15659 */ 15660 15661 DataTable.defaults = { 15662 15663 /** 15664 15665 * An array of data to use for the table, passed in at initialisation which 15666 15667 * will be used in preference to any data which is already in the DOM. This is 15668 15669 * particularly useful for constructing tables purely in Javascript, for 15670 15671 * example with a custom Ajax call. 15672 15673 * @type array 15674 15675 * @default null 15676 15677 * @dtopt Option 15678 15679 * 15680 15681 * @example 15682 15683 * // Using a 2D array data source 15684 15685 * $(document).ready( function () { 15686 15687 * $('#example').dataTable( { 15688 15689 * "aaData": [ 15690 15691 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 15692 15693 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 15694 15695 * ], 15696 15697 * "aoColumns": [ 15698 15699 * { "sTitle": "Engine" }, 15700 15701 * { "sTitle": "Browser" }, 15702 15703 * { "sTitle": "Platform" }, 15704 15705 * { "sTitle": "Version" }, 15706 15707 * { "sTitle": "Grade" } 15708 15709 * ] 15710 15711 * } ); 15712 15713 * } ); 15714 15715 * 15716 15717 * @example 15718 15719 * // Using an array of objects as a data source (mData) 15720 15721 * $(document).ready( function () { 15722 15723 * $('#example').dataTable( { 15724 15725 * "aaData": [ 15726 15727 * { 15728
15729 * "engine": "Trident", 15730 15731 * "browser": "Internet Explorer 4.0", 15732 15733 * "platform": "Win 95+", 15734 15735 * "version": 4, 15736 15737 * "grade": "X" 15738 15739 * }, 15740 15741 * { 15742 15743 * "engine": "Trident", 15744 15745 * "browser": "Internet Explorer 5.0", 15746 15747 * "platform": "Win 95+", 15748 15749 * "version": 5, 15750 15751 * "grade": "C" 15752 15753 * } 15754 15755 * ], 15756 15757 * "aoColumns": [ 15758 15759 * { "sTitle": "Engine", "mData": "engine" }, 15760 15761 * { "sTitle": "Browser", "mData": "browser" }, 15762 15763 * { "sTitle": "Platform", "mData": "platform" }, 15764 15765 * { "sTitle": "Version", "mData": "version" }, 15766 15767 * { "sTitle": "Grade", "mData": "grade" } 15768 15769 * ] 15770 15771 * } ); 15772 15773 * } ); 15774 15775 */ 15776 15777 "aaData": null, 15778 15779 15780 15781 15782 15783 /** 15784 15785 * If sorting is enabled, then DataTables will perform a first pass sort on 15786 15787 * initialisation. You can define which column(s) the sort is performed upon, 15788 15789 * and the sorting direction, with this variable. The aaSorting array should 15790 15791 * contain an array for each column to be sorted initially containing the 15792 15793 * column's index and a direction string ('asc' or 'desc'). 15794 15795 * @type array 15796 15797 * @default [[0,'asc']] 15798 15799 * @dtopt Option 15800 15801 * 15802 15803 * @example 15804 15805 * // Sort by 3rd column first, and then 4th column 15806 15807 * $(document).ready( function() { 15808 15809 * $('#example').dataTable( { 15810 15811 * "aaSorting": [[2,'asc'], [3,'desc']] 15812 15813 * } ); 15814 15815 * } ); 15816 15817 * 15818 15819 * // No initial sorting 15820 15821 * $(document).ready( function() { 15822 15823 * $('#example').dataTable( { 15824 15825 * "aaSorting": [] 15826 15827 * } ); 15828 15829 * } ); 15830 15831 */ 15832 15833 "aaSorting": [[0,'asc']], 15834 15835 15836 15837 15838 15839 /** 15840 15841 * This parameter is basically identical to the aaSorting parameter, but 15842 15843 * cannot be overridden by user interaction with the table. What this means 15844 15845 * is that you could have a column (visible or hidden) which the sorting will 15846 15847 * always be forced on first - any sorting after that (from the user) will 15848 15849 * then be performed as required. This can be useful for grouping rows 15850 15851 * together. 15852 15853 * @type array 15854 15855 * @default null 15856 15857 * @dtopt Option 15858 15859 * 15860 15861 * @example 15862 15863 * $(document).ready( function() { 15864 15865 * $('#example').dataTable( { 15866 15867 * "aaSortingFixed": [[0,'asc']] 15868 15869 * } ); 15870 15871 * } ) 15872 15873 */ 15874 15875 "aaSortingFixed": null, 15876 15877 15878 15879 15880 15881 /** 15882 15883 * This parameter allows you to readily specify the Businesses in the length drop 15884 15885 * down menu that DataTables shows when pagination is enabled. It can be 15886 15887 * either a 1D array of options which will be used for both the displayed 15888 15889 * option and the value, or a 2D array which will use the array in the first 15890 15891 * position as the value, and the array in the second position as the 15892 15893 * displayed options (useful for language strings such as 'All'). 15894 15895 * @type array 15896 15897 * @default [ 10, 25, 50, 100 ] 15898 15899 * @dtopt Option 15900 15901 * 15902 15903 * @example 15904 15905 * $(document).ready( function() { 15906 15907 * $('#example').dataTable( { 15908 15909 * "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 15910 15911 * } ); 15912 15913 * } ); 15914 15915 * 15916 15917 * @example 15918 15919 * // Setting the default display length as well as length menu 15920 15921 * // This is likely to be wanted if you remove the '10' option which 15922 15923 * // is the iDisplayLength default. 15924 15925 * $(document).ready( function() { 15926 15927 * $('#example').dataTable( { 15928 15929 * "iDisplayLength": 25, 15930 15931 * "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]] 15932 15933 * } ); 15934 15935 * } ); 15936 15937 */ 15938 15939 "aLengthMenu": [ 10, 25, 50, 100 ], 15940 15941 15942 15943 15944 15945 /** 15946 15947 * The aoColumns option in the initialisation parameter allows you to define 15948 15949 * details about the way individual columns behave. For a full list of 15950 15951 * column options that can be set, please see 15952 15953 * {@link DataTable.defaults.columns}. Note that if you use aoColumns to 15954 15955 * define your columns, you must have an entry in the array for every single 15956 15957 * column that you have in your table (these can be null if you don't which 15958 15959 * to specify any options). 15960 15961 * @member 15962 15963 */ 15964 15965 "aoColumns": null, 15966 15967 15968 15969 /** 15970 15971 * Very similar to aoColumns, aoColumnDefs allows you to target a specific 15972
15973 * column, multiple columns, or all columns, using the aTargets property of 15974 15975 * each object in the array. This allows great flexibility when creating 15976 15977 * tables, as the aoColumnDefs arrays can be of any length, targeting the 15978 15979 * columns you specifically want. aoColumnDefs may use any of the column 15980 15981 * options available: {@link DataTable.defaults.columns}, but it _must_ 15982 15983 * have aTargets defined in each object in the array. Values in the aTargets 15984 15985 * array may be: 15986 15987 * <ul> 15988 15989 * <li>a string - class name will be matched on the TH for the column</li> 15990 15991 * <li>0 or a positive integer - column index counting from the left</li> 15992 15993 * <li>a negative integer - column index counting from the right</li> 15994 15995 * <li>the string "_all" - all columns (i.e. assign a default)</li> 15996 15997 * </ul> 15998 15999 * @member 16000 16001 */ 16002 16003 "aoColumnDefs": null, 16004 16005 16006 16007 16008 16009 /** 16010 16011 * Basically the same as oSearch, this parameter defines the individual column 16012 16013 * filtering state at initialisation time. The array must be of the same size 16014 16015 * as the number of columns, and each element be an object with the parameters 16016 16017 * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also 16018 16019 * accepted and the default will be used. 16020 16021 * @type array 16022 16023 * @default [] 16024 16025 * @dtopt Option 16026 16027 * 16028 16029 * @example 16030 16031 * $(document).ready( function() { 16032 16033 * $('#example').dataTable( { 16034 16035 * "aoSearchCols": [ 16036 16037 * null, 16038 16039 * { "sSearch": "My filter" }, 16040 16041 * null, 16042 16043 * { "sSearch": "^[0-9]", "bEscapeRegex": false } 16044 16045 * ] 16046 16047 * } ); 16048 16049 * } ) 16050 16051 */ 16052 16053 "aoSearchCols": [], 16054 16055 16056 16057 16058 16059 /** 16060 16061 * An array of CSS classes that should be applied to displayed rows. This 16062 16063 * array may be of any length, and DataTables will apply each class 16064 16065 * sequentially, looping when required. 16066 16067 * @type array 16068 16069 * @default null <i>Will take the values determined by the oClasses.sStripe* 16070 16071 * options</i> 16072 16073 * @dtopt Option 16074 16075 * 16076 16077 * @example 16078 16079 * $(document).ready( function() { 16080 16081 * $('#example').dataTable( { 16082 16083 * "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ] 16084 16085 * } ); 16086 16087 * } ) 16088 16089 */ 16090 16091 "asStripeClasses": null, 16092 16093 16094 16095 16096 16097 /** 16098 16099 * Enable or disable automatic column width calculation. This can be disabled 16100 16101 * as an optimisation (it takes some time to calculate the widths) if the 16102 16103 * tables widths are passed in using aoColumns. 16104 16105 * @type boolean 16106 16107 * @default true 16108 16109 * @dtopt Features 16110 16111 * 16112 16113 * @example 16114 16115 * $(document).ready( function () { 16116 16117 * $('#example').dataTable( { 16118 16119 * "bAutoWidth": false 16120 16121 * } ); 16122 16123 * } ); 16124 16125 */ 16126 16127 "bAutoWidth": true, 16128 16129 16130 16131 16132 16133 /** 16134 16135 * Deferred rendering can provide DataTables with a huge speed boost when you 16136 16137 * are using an Ajax or JS data source for the table. This option, when set to 16138 16139 * true, will cause DataTables to defer the creation of the table elements for 16140 16141 * each row until they are needed for a draw - saving a significant amount of 16142 16143 * time. 16144 16145 * @type boolean 16146 16147 * @default false 16148 16149 * @dtopt Features 16150 16151 * 16152 16153 * @example 16154 16155 * $(document).ready( function() { 16156 16157 * var oTable = $('#example').dataTable( { 16158 16159 * "sAjaxSource": "sources/arrays.txt", 16160 16161 * "bDeferRender": true 16162 16163 * } ); 16164 16165 * } ); 16166 16167 */ 16168 16169 "bDeferRender": false, 16170 16171 16172 16173 16174 16175 /** 16176 16177 * Replace a DataTable which matches the given selector and replace it with 16178 16179 * one which has the properties of the new initialisation object passed. If no 16180 16181 * table matches the selector, then the new DataTable will be constructed as 16182 16183 * per normal. 16184 16185 * @type boolean 16186 16187 * @default false 16188 16189 * @dtopt Options 16190 16191 * 16192 16193 * @example 16194 16195 * $(document).ready( function() { 16196 16197 * $('#example').dataTable( { 16198 16199 * "sScrollY": "200px", 16200 16201 * "bPaginate": false 16202 16203 * } ); 16204 16205 * 16206 16207 * // Some time later.... 16208 16209 * $('#example').dataTable( { 16210 16211 * "bFilter": false, 16212 16213 * "bDestroy": true 16214 16215 * } ); 16216 16217 * } ); 16218 16219 */ 16220 16221 "bDestroy": false, 16222 16223 16224 16225 16226 16227 /** 16228 16229 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 16230 16231 * that it allows the end user to input multiple words (space separated) and 16232 16233 * will match a row containing those words, even if not in the order that was 16234 16235 * specified (this allow matching across multiple columns). Note that if you 16236 16237 * wish to use filtering in DataTables this must remain 'true' - to remove the 16238 16239 * default filtering input box and retain filtering abilities, please use 16240 16241 * {@link DataTable.defaults.sDom}. 16242 16243 * @type boolean 16244 16245 * @default true 16246 16247 * @dtopt Features 16248 16249 * 16250 16251 * @example 16252 16253 * $(document).ready( function () { 16254 16255 * $('#example').dataTable( { 16256 16257 * "bFilter": false 16258 16259 * } ); 16260 16261 * } ); 16262 16263 */ 16264 16265 "bFilter": true, 16266 16267 16268 16269 16270 16271 /** 16272 16273 * Enable or disable the table information display. This shows information 16274 16275 * about the data that is currently visible on the page, including information 16276 16277 * about filtered data if that action is being performed. 16278 16279 * @type boolean 16280 16281 * @default true 16282 16283 * @dtopt Features 16284 16285 * 16286 16287 * @example 16288 16289 * $(document).ready( function () { 16290 16291 * $('#example').dataTable( { 16292 16293 * "bInfo": false 16294 16295 * } ); 16296 16297 * } ); 16298 16299 */ 16300 16301 "bInfo": true, 16302 16303 16304 16305 16306 16307 /** 16308 16309 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some 16310 16311 * slightly different and additional mark-up from what DataTables has 16312 16313 * traditionally used). 16314 16315 * @type boolean 16316 16317 * @default false 16318 16319 * @dtopt Features 16320 16321 * 16322 16323 * @example 16324 16325 * $(document).ready( function() { 16326 16327 * $('#example').dataTable( { 16328 16329 * "bJQueryUI": true 16330 16331 * } ); 16332 16333 * } ); 16334 16335 */ 16336 16337 "bJQueryUI": false, 16338 16339 16340 16341 16342 16343 /** 16344 16345 * Allows the end user to select the size of a formatted page from a select 16346 16347 * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate). 16348 16349 * @type boolean 16350 16351 * @default true 16352 16353 * @dtopt Features 16354 16355 * 16356 16357 * @example 16358 16359 * $(document).ready( function () { 16360 16361 * $('#example').dataTable( { 16362 16363 * "bLengthChange": false 16364 16365 * } ); 16366 16367 * } ); 16368 16369 */ 16370 16371 "bLengthChange": true, 16372 16373 16374 16375 16376 16377 /** 16378 16379 * Enable or disable pagination. 16380 16381 * @type boolean 16382 16383 * @default true 16384 16385 * @dtopt Features 16386 16387 * 16388 16389 * @example 16390 16391 * $(document).ready( function () { 16392 16393 * $('#example').dataTable( { 16394 16395 * "bPaginate": false 16396 16397 * } ); 16398 16399 * } ); 16400 16401 */ 16402 16403 "bPaginate": true, 16404 16405 16406 16407 16408 16409 /** 16410 16411 * Enable or disable the display of a 'processing' indicator when the table is 16412 16413 * being processed (e.g. a sort). This is particularly useful for tables with 16414 16415 * large amounts of data where it can take a noticeable amount of time to sort 16416 16417 * the Businesses. 16418 16419 * @type boolean 16420 16421 * @default false 16422 16423 * @dtopt Features 16424 16425 * 16426 16427 * @example 16428 16429 * $(document).ready( function () { 16430 16431 * $('#example').dataTable( { 16432 16433 * "bProcessing": true 16434 16435 * } ); 16436 16437 * } ); 16438 16439 */ 16440 16441 "bProcessing": false, 16442 16443 16444 16445 16446 16447 /** 16448 16449 * Retrieve the DataTables object for the given selector. Note that if the 16450 16451 * table has already been initialised, this parameter will cause DataTables 16452 16453 * to simply return the object that has already been set up - it will not take 16454 16455 * account of any changes you might have made to the initialisation object 16456 16457 * passed to DataTables (setting this parameter to true is an acknowledgement 16458 16459 * that you understand this). bDestroy can be used to reinitialise a table if 16460 16461 * you need. 16462 16463 * @type boolean 16464 16465 * @default false 16466 16467 * @dtopt Options 16468 16469 * 16470 16471 * @example 16472 16473 * $(document).ready( function() { 16474 16475 * initTable(); 16476 16477 * tableActions(); 16478 16479 * } ); 16480 16481 * 16482 16483 * function initTable () 16484 16485 * { 16486 16487 * return $('#example').dataTable( { 16488 16489 * "sScrollY": "200px", 16490 16491 * "bPaginate": false, 16492 16493 * "bRetrieve": true 16494 16495 * } ); 16496 16497 * } 16498 16499 * 16500 16501 * function tableActions () 16502 16503 * { 16504 16505 * var oTable = initTable(); 16506 16507 * // perform API operations with oTable 16508 16509 * } 16510 16511 */ 16512 16513 "bRetrieve": false, 16514 16515 16516 16517 16518 16519 /** 16520 16521 * Indicate if DataTables should be allowed to set the padding / margin 16522 16523 * etc for the scrolling header elements or not. Typically you will want 16524 16525 * this. 16526 16527 * @type boolean 16528 16529 * @default true 16530 16531 * @dtopt Options 16532 16533 * 16534 16535 * @example 16536 16537 * $(document).ready( function() { 16538 16539 * $('#example').dataTable( { 16540 16541 * "bScrollAutoCss": false, 16542 16543 * "sScrollY": "200px" 16544 16545 * } ); 16546 16547 * } ); 16548 16549 */ 16550 16551 "bScrollAutoCss": true, 16552 16553 16554 16555 16556 16557 /** 16558 16559 * When vertical (y) scrolling is enabled, DataTables will force the height of 16560
16561 * the table's viewport to the given height at all times (useful for layout). 16562 16563 * However, this can look odd when filtering data down to a small data set, 16564 16565 * and the footer is left "floating" further down. This parameter (when 16566 16567 * enabled) will cause DataTables to collapse the table's viewport down when 16568 16569 * the result set will fit within the given Y height. 16570 16571 * @type boolean 16572 16573 * @default false 16574 16575 * @dtopt Options 16576 16577 * 16578 16579 * @example 16580 16581 * $(document).ready( function() { 16582 16583 * $('#example').dataTable( { 16584 16585 * "sScrollY": "200", 16586 16587 * "bScrollCollapse": true 16588 16589 * } ); 16590 16591 * } ); 16592 16593 */ 16594 16595 "bScrollCollapse": false, 16596 16597 16598 16599 16600 16601 /** 16602 16603 * Enable infinite scrolling for DataTables (to be used in combination with 16604 16605 * sScrollY). Infinite scrolling means that DataTables will continually load 16606 16607 * data as a user scrolls through a table, which is very useful for large 16608 16609 * dataset. This cannot be used with pagination, which is automatically 16610 16611 * disabled. Note - the Scroller extra for DataTables is recommended in 16612 16613 * in preference to this option. 16614 16615 * @type boolean 16616 16617 * @default false 16618 16619 * @dtopt Features 16620 16621 * 16622 16623 * @example 16624 16625 * $(document).ready( function() { 16626 16627 * $('#example').dataTable( { 16628 16629 * "bScrollInfinite": true, 16630 16631 * "bScrollCollapse": true, 16632 16633 * "sScrollY": "200px" 16634 16635 * } ); 16636 16637 * } ); 16638 16639 */ 16640 16641 "bScrollInfinite": false, 16642 16643 16644 16645 16646 16647 /** 16648 16649 * Configure DataTables to use server-side processing. Note that the 16650 16651 * sAjaxSource parameter must also be given in order to give DataTables a 16652 16653 * source to obtain the required data for each draw. 16654 16655 * @type boolean 16656 16657 * @default false 16658 16659 * @dtopt Features 16660 16661 * @dtopt Server-side 16662 16663 * 16664 16665 * @example 16666 16667 * $(document).ready( function () { 16668 16669 * $('#example').dataTable( { 16670 16671 * "bServerSide": true, 16672 16673 * "sAjaxSource": "xhr.php" 16674 16675 * } ); 16676 16677 * } ); 16678 16679 */ 16680 16681 "bServerSide": false, 16682 16683 16684 16685 16686 16687 /** 16688 16689 * Enable or disable sorting of columns. Sorting of individual columns can be 16690 16691 * disabled by the "bSortable" option for each column. 16692 16693 * @type boolean 16694 16695 * @default true 16696 16697 * @dtopt Features 16698 16699 * 16700 16701 * @example 16702 16703 * $(document).ready( function () { 16704 16705 * $('#example').dataTable( { 16706 16707 * "bSort": false 16708 16709 * } ); 16710 16711 * } ); 16712 16713 */ 16714 16715 "bSort": true, 16716 16717 16718 16719 16720 16721 /** 16722 16723 * Allows control over whether DataTables should use the top (true) unique 16724 16725 * cell that is found for a single column, or the bottom (false - default). 16726 16727 * This is useful when using complex headers. 16728 16729 * @type boolean 16730 16731 * @default false 16732 16733 * @dtopt Options 16734 16735 * 16736 16737 * @example 16738 16739 * $(document).ready( function() { 16740 16741 * $('#example').dataTable( { 16742 16743 * "bSortCellsTop": true 16744 16745 * } ); 16746 16747 * } ); 16748 16749 */ 16750 16751 "bSortCellsTop": false, 16752 16753 16754 16755 16756 16757 /** 16758 16759 * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and 16760 16761 * 'sorting_3' to the columns which are currently being sorted on. This is 16762 16763 * presented as a feature switch as it can increase processing time (while 16764 16765 * classes are removed and added) so for large data sets you might want to 16766 16767 * turn this off. 16768 16769 * @type boolean 16770 16771 * @default true 16772 16773 * @dtopt Features 16774 16775 * 16776 16777 * @example 16778 16779 * $(document).ready( function () { 16780 16781 * $('#example').dataTable( { 16782 16783 * "bSortClasses": false 16784 16785 * } ); 16786 16787 * } ); 16788 16789 */ 16790 16791 "bSortClasses": true, 16792 16793 16794 16795 16796 16797 /** 16798 16799 * Enable or disable state saving. When enabled a cookie will be used to save 16800 16801 * table display information such as pagination information, display length, 16802 16803 * filtering and sorting. As such when the end user reloads the page the 16804 16805 * display display will match what thy had previously set up. 16806 16807 * @type boolean 16808 16809 * @default false 16810 16811 * @dtopt Features 16812 16813 * 16814 16815 * @example 16816 16817 * $(document).ready( function () { 16818 16819 * $('#example').dataTable( { 16820 16821 * "bStateSave": true 16822 16823 * } ); 16824 16825 * } ); 16826 16827 */ 16828 16829 "bStateSave": false, 16830 16831 16832 16833 16834 16835 /** 16836 16837 * Customise the cookie and / or the parameters being stored when using 16838 16839 * DataTables with state saving enabled. This function is called whenever 16840 16841 * the cookie is modified, and it expects a fully formed cookie string to be 16842 16843 * returned. Note that the data object passed in is a Javascript object which 16844 16845 * must be converted to a string (JSON.stringify for example). 16846 16847 * @type function 16848 16849 * @param {string} sName Name of the cookie defined by DataTables 16850 16851 * @param {object} oData Data to be stored in the cookie 16852 16853 * @param {string} sExpires Cookie expires string 16854 16855 * @param {string} sPath Path of the cookie to set 16856 16857 * @returns {string} Cookie formatted string (which should be encoded by 16858 16859 * using encodeURIComponent()) 16860 16861 * @dtopt Callbacks 16862 16863 * 16864 16865 * @example 16866 16867 * $(document).ready( function () { 16868 16869 * $('#example').dataTable( { 16870 16871 * "fnCookieCallback": function (sName, oData, sExpires, sPath) { 16872 16873 * // Customise oData or sName or whatever else here 16874 16875 * return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath; 16876 16877 * } 16878 16879 * } ); 16880 16881 * } ); 16882 16883 */ 16884 16885 "fnCookieCallback": null, 16886 16887 16888 16889 16890 16891 /** 16892 16893 * This function is called when a TR element is created (and all TD child 16894 16895 * elements have been inserted), or registered if using a DOM source, allowing 16896 16897 * manipulation of the TR element (adding classes etc). 16898 16899 * @type function 16900 16901 * @param {node} nRow "TR" element for the current row 16902 16903 * @param {array} aData Raw data array for this row 16904 16905 * @param {int} iDataIndex The index of this row in aoData 16906 16907 * @dtopt Callbacks 16908 16909 * 16910 16911 * @example 16912 16913 * $(document).ready( function() { 16914 16915 * $('#example').dataTable( { 16916 16917 * "fnCreatedRow": function( nRow, aData, iDataIndex ) { 16918 16919 * // Bold the grade for all 'A' grade browsers 16920 16921 * if ( aData[4] == "A" ) 16922 16923 * { 16924 16925 * $('td:eq(4)', nRow).html( '<b>A</b>' ); 16926 16927 * } 16928 16929 * } 16930 16931 * } ); 16932 16933 * } ); 16934 16935 */ 16936 16937 "fnCreatedRow": null, 16938 16939 16940 16941 16942 16943 /** 16944 16945 * This function is called on every 'draw' event, and allows you to 16946 16947 * dynamically modify any aspect you want about the created DOM. 16948 16949 * @type function 16950 16951 * @param {object} oSettings DataTables settings object 16952 16953 * @dtopt Callbacks 16954 16955 * 16956 16957 * @example 16958 16959 * $(document).ready( function() { 16960 16961 * $('#example').dataTable( { 16962 16963 * "fnDrawCallback": function( oSettings ) { 16964 16965 * alert( 'DataTables has redrawn the table' ); 16966 16967 * } 16968 16969 * } ); 16970 16971 * } ); 16972 16973 */ 16974 16975 "fnDrawCallback": null, 16976 16977 16978 16979 16980 16981 /** 16982 16983 * Identical to fnHeaderCallback() but for the table footer this function 16984 16985 * allows you to modify the table footer on every 'draw' even. 16986 16987 * @type function 16988 16989 * @param {node} nFoot "TR" element for the footer 16990 16991 * @param {array} aData Full table data (as derived from the original HTML) 16992 16993 * @param {int} iStart Index for the current display starting point in the 16994 16995 * display array 16996 16997 * @param {int} iEnd Index for the current display ending point in the 16998 16999 * display array 17000 17001 * @param {array int} aiDisplay Index array to translate the visual position 17002 17003 * to the full data array 17004 17005 * @dtopt Callbacks 17006 17007 * 17008 17009 * @example 17010 17011 * $(document).ready( function() { 17012 17013 * $('#example').dataTable( { 17014 17015 * "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) { 17016 17017 * nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart; 17018 17019 * } 17020 17021 * } ); 17022 17023 * } ) 17024 17025 */ 17026 17027 "fnFooterCallback": null, 17028 17029 17030 17031 17032 17033 /** 17034 17035 * When rendering large numbers in the information element for the table 17036 17037 * (i.e. "Showing 1 to 10 of 57 Businesses") DataTables will render large numbers 17038 17039 * to have a comma separator for the 'thousands' units (e.g. 1 million is 17040 17041 * rendered as "1,000,000") to help readability for the end user. This 17042 17043 * function will override the default method DataTables uses. 17044 17045 * @type function 17046 17047 * @member 17048 17049 * @param {int} iIn number to be formatted 17050 17051 * @returns {string} formatted string for DataTables to show the number 17052 17053 * @dtopt Callbacks 17054 17055 * 17056 17057 * @example 17058 17059 * $(document).ready( function() { 17060 17061 * $('#example').dataTable( { 17062 17063 * "fnFormatNumber": function ( iIn ) { 17064 17065 * if ( iIn < 1000 ) { 17066 17067 * return iIn; 17068 17069 * } else { 17070 17071 * var 17072 17073 * s=(iIn+""), 17074 17075 * a=s.split(""), out="", 17076 17077 * iLen=s.length; 17078 17079 * 17080 17081 * for ( var i=0 ; i<iLen ; i++ ) { 17082 17083 * if ( i%3 === 0 && i !== 0 ) { 17084 17085 * out = "'"+out; 17086 17087 * } 17088 17089 * out = a[iLen-i-1]+out; 17090 17091 * } 17092 17093 * } 17094 17095 * return out; 17096 17097 * }; 17098 17099 * } ); 17100 17101 * } ); 17102 17103 */ 17104 17105 "fnFormatNumber": function ( iIn ) { 17106 17107 if ( iIn < 1000 ) 17108 17109 { 17110 17111 // A small optimisation for what is likely to be the majority of use cases 17112 17113 return iIn; 17114 17115 } 17116 17117 17118 17119 var s=(iIn+""), a=s.split(""), out="", iLen=s.length; 17120 17121 17122 17123 for ( var i=0 ; i<iLen ; i++ ) 17124 17125 { 17126 17127 if ( i%3 === 0 && i !== 0 ) 17128 17129 { 17130 17131 out = this.oLanguage.sInfoThousands+out; 17132 17133 } 17134 17135 out = a[iLen-i-1]+out; 17136 17137 } 17138 17139 return out; 17140 17141 }, 17142 17143 17144 17145 17146 17147 /** 17148 17149 * This function is called on every 'draw' event, and allows you to 17150 17151 * dynamically modify the header row. This can be used to calculate and 17152 17153 * display useful information about the table. 17154 17155 * @type function 17156 17157 * @param {node} nHead "TR" element for the header 17158 17159 * @param {array} aData Full table data (as derived from the original HTML) 17160 17161 * @param {int} iStart Index for the current display starting point in the 17162 17163 * display array 17164 17165 * @param {int} iEnd Index for the current display ending point in the 17166 17167 * display array 17168 17169 * @param {array int} aiDisplay Index array to translate the visual position 17170 17171 * to the full data array 17172 17173 * @dtopt Callbacks 17174 17175 * 17176 17177 * @example 17178 17179 * $(document).ready( function() { 17180 17181 * $('#example').dataTable( { 17182 17183 * "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) { 17184 17185 * nHead.getElementsByTagName('th')[0].innerHTML = "Dis
17185playing "+(iEnd-iStart)+" records"; 17186 17187 * } 17188 17189 * } ); 17190 17191 * } ) 17192 17193 */ 17194 17195 "fnHeaderCallback": null, 17196 17197 17198 17199 17200 17201 /** 17202 17203 * The information element can be used to convey information about the current 17204 17205 * state of the table. Although the internationalisation options presented by 17206 17207 * DataTables are quite capable of dealing with most customisations, there may 17208 17209 * be times where you wish to customise the string further. This callback 17210 17211 * allows you to do exactly that. 17212 17213 * @type function 17214 17215 * @param {object} oSettings DataTables settings object 17216 17217 * @param {int} iStart Starting position in data for the draw 17218 17219 * @param {int} iEnd End position in data for the draw 17220 17221 * @param {int} iMax Total number of rows in the table (regardless of 17222 17223 * filtering) 17224 17225 * @param {int} iTotal Total number of rows in the data set, after filtering 17226 17227 * @param {string} sPre The string that DataTables has formatted using it's 17228 17229 * own rules 17230 17231 * @returns {string} The string to be displayed in the information element. 17232 17233 * @dtopt Callbacks 17234 17235 * 17236 17237 * @example 17238 17239 * $('#example').dataTable( { 17240 17241 * "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) { 17242 17243 * return iStart +" to "+ iEnd; 17244 17245 * } 17246 17247 * } ); 17248 17249 */ 17250 17251 "fnInfoCallback": null, 17252 17253 17254 17255 17256 17257 /** 17258 17259 * Called when the table has been initialised. Normally DataTables will 17260 17261 * initialise sequentially and there will be no need for this function, 17262 17263 * however, this does not hold true when using external language information 17264 17265 * since that is obtained using an async XHR call. 17266 17267 * @type function 17268 17269 * @param {object} oSettings DataTables settings object 17270 17271 * @param {object} json The JSON object request from the server - only 17272 17273 * present if client-side Ajax sourced data is used 17274 17275 * @dtopt Callbacks 17276 17277 * 17278 17279 * @example 17280 17281 * $(document).ready( function() { 17282 17283 * $('#example').dataTable( { 17284 17285 * "fnInitComplete": function(oSettings, json) { 17286 17287 * alert( 'DataTables has finished its initialisation.' ); 17288 17289 * } 17290 17291 * } ); 17292 17293 * } ) 17294 17295 */ 17296 17297 "fnInitComplete": null, 17298 17299 17300 17301 17302 17303 /** 17304 17305 * Called at the very start of each table draw and can be used to cancel the 17306 17307 * draw by returning false, any other return (including undefined) results in 17308 17309 * the full draw occurring). 17310 17311 * @type function 17312 17313 * @param {object} oSettings DataTables settings object 17314 17315 * @returns {boolean} False will cancel the draw, anything else (including no 17316 17317 * return) will allow it to complete. 17318 17319 * @dtopt Callbacks 17320 17321 * 17322 17323 * @example 17324 17325 * $(document).ready( function() { 17326 17327 * $('#example').dataTable( { 17328 17329 * "fnPreDrawCallback": function( oSettings ) { 17330 17331 * if ( $('#test').val() == 1 ) { 17332 17333 * return false; 17334 17335 * } 17336 17337 * } 17338 17339 * } ); 17340 17341 * } ); 17342 17343 */ 17344 17345 "fnPreDrawCallback": null, 17346 17347 17348 17349 17350 17351 /** 17352 17353 * This function allows you to 'post process' each row after it have been 17354 17355 * generated for each table draw, but before it is rendered on screen. This 17356 17357 * function might be used for setting the row class name etc. 17358 17359 * @type function 17360 17361 * @param {node} nRow "TR" element for the current row 17362 17363 * @param {array} aData Raw data array for this row 17364 17365 * @param {int} iDisplayIndex The display index for the current table draw 17366 17367 * @param {int} iDisplayIndexFull The index of the data in the full list of 17368 17369 * rows (after filtering) 17370 17371 * @dtopt Callbacks 17372 17373 * 17374 17375 * @example 17376 17377 * $(document).ready( function() { 17378 17379 * $('#example').dataTable( { 17380 17381 * "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) { 17382 17383 * // Bold the grade for all 'A' grade browsers 17384 17385 * if ( aData[4] == "A" ) 17386 17387 * { 17388 17389 * $('td:eq(4)', nRow).html( '<b>A</b>' ); 17390 17391 * } 17392 17393 * } 17394 17395 * } ); 17396 17397 * } ); 17398 17399 */ 17400 17401 "fnRowCallback": null, 17402 17403 17404 17405 17406 17407 /** 17408 17409 * This parameter allows you to override the default function which obtains 17410 17411 * the data from the server ($.getJSON) so something more suitable for your 17412 17413 * application. For example you could use POST data, or pull information from 17414 17415 * a Gears or AIR database. 17416 17417 * @type function 17418 17419 * @member 17420 17421 * @param {string} sSource HTTP source to obtain the data from (sAjaxSource) 17422 17423 * @param {array}
17423 aoData A key/value pair object containing the data to send 17424 17425 * to the server 17426 17427 * @param {function} fnCallback to be called on completion of the data get 17428 17429 * process that will draw the data on the page. 17430 17431 * @param {object} oSettings DataTables settings object 17432 17433 * @dtopt Callbacks 17434 17435 * @dtopt Server-side 17436 17437 * 17438 17439 * @example 17440 17441 * // POST data to server 17442 17443 * $(document).ready( function() { 17444 17445 * $('#example').dataTable( { 17446 17447 * "bProcessing": true, 17448 17449 * "bServerSide": true, 17450 17451 * "sAjaxSource": "xhr.php", 17452 17453 * "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) { 17454 17455 * oSettings.jqXHR = $.ajax( { 17456 17457 * "dataType": 'json', 17458 17459 * "type": "POST", 17460 17461 * "url": sSource, 17462 17463 * "data": aoData, 17464 17465 * "success": fnCallback 17466 17467 * } ); 17468 17469 * } 17470 17471 * } ); 17472 17473 * } ); 17474 17475 */ 17476 17477 "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) { 17478 17479 oSettings.jqXHR = $.ajax( { 17480 17481 "url": sUrl, 17482 17483 "data": aoData, 17484 17485 "success": function (json) { 17486 17487 if ( json.sError ) { 17488 17489 oSettings.oApi._fnLog( oSettings, 0, json.sError ); 17490 17491 } 17492 17493 17494 17495 $(oSettings.oInstance).trigger('xhr', [oSettings, json]); 17496 17497 fnCallback( json ); 17498 17499 }, 17500 17501 "dataType": "json", 17502 17503 "cache": false, 17504 17505 "type": oSettings.sServerMethod, 17506 17507 "error": function (xhr, error, thrown) { 17508 17509 if ( error == "parsererror" ) { 17510 17511 oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+ 17512 17513 "server could not be parsed. This is caused by a JSON formatting error." ); 17514 17515 } 17516 17517 } 17518 17519 } ); 17520 17521 }, 17522 17523 17524 17525 17526 17527 /** 17528 17529 * It is often useful to send extra data to the server when making an Ajax 17530 17531 * request - for example custom filtering information, and this callback 17532 17533 * function makes it trivial to send extra information to the server. The 17534 17535 * passed in parameter is the data set that has been constructed by 17536 17537 * DataTables, and you can add to this or modify it as you require. 17538 17539 * @type function 17540 17541 * @param {array} aoData Data array (array of objects which are name/value 17542 17543 * pairs) that has been constructed by DataTables and will be sent to the 17544 17545 * server. In the case of Ajax sourced data with server-side processing 17546 17547 * this will be an empty array, for server-side processing there will be a 17548 17549 * significant number of parameters! 17550 17551 * @returns {undefined} Ensure that you modify the aoData array passed in, 17552 17553 * as this is passed by reference. 17554 17555 * @dtopt Callbacks 17556 17557 * @dtopt Server-side 17558 17559 * 17560 17561 * @example 17562 17563 * $(document).ready( function() { 17564 17565 * $('#example').dataTable( { 17566 17567 * "bProcessing": true, 17568 17569 * "bServerSide": true, 17570 17571 * "sAjaxSource": "scripts/server_processing.php", 17572 17573 * "fnServerParams": function ( aoData ) { 17574 17575 * aoData.push( { "name": "more_data", "value": "my_value" } ); 17576 17577 * } 17578 17579 * } ); 17580 17581 * } ); 17582 17583 */ 17584 17585 "fnServerParams": null, 17586 17587 17588 17589 17590 17591 /** 17592 17593 * Load the table state. With this function you can define from where, and how, the 17594 17595 * state of a table is loaded. By default DataTables will load from its state saving 17596 17597 * cookie, but you might wish to use local storage (HTML5) or a server-side database. 17598 17599 * @type function 17600 17601 * @member 17602 17603 * @param {object} oSettings DataTables settings object 17604 17605 * @return {object} The DataTables state object to be loaded 17606 17607 * @dtopt Callbacks 17608 17609 * 17610 17611 * @example 17612 17613 * $(document).ready( function() { 17614 17615 * $('#example').dataTable( { 17616 17617 * "bStateSave": true, 17618 17619 * "fnStateLoad": function (oSettings) { 17620 17621 * var o; 17622 17623 * 17624 17625 * // Send an Ajax request to the server to get the data. Note that 17626 17627 * // this is a synchronous request. 17628 17629 * $.ajax( { 17630 17631 * "url": "/state_load", 17632 17633 * "async": false, 17634 17635 * "dataType": "json", 17636 17637 * "success": function (json) { 17638 17639 * o = json; 17640 17641 * } 17642 17643 * } ); 17644 17645 * 17646 17647 * return o; 17648 17649 * } 17650 17651 * } ); 17652 17653 * } ); 17654 17655 */ 17656 17657 "fnStateLoad": function ( oSettings ) { 17658 17659 var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance ); 17660 17661 var oData; 17662 17663 17664 17665 try { 17666 17667 oData = (typeof $.parseJSON === 'function') ? 17668 17669 $.parseJSON(sData) : eval( '('+sData+')' ); 17670 17671 } catch (e) { 17672 17673 oData = null; 17674 17675 } 17676 17677 17678 17679 return oData; 17680 17681 }, 17682 17683 17684 17685 17686 17687 /** 17688 17689 * Callback which allows modification of the saved state prior to loading that state. 17690 17691 * This callback is called when the table is loading state from the stored data, but 17692 17693 * prior to the settings object being modified by the saved state. Note that for 17694 17695 * plug-in authors, you should use the 'stateLoadParams' event to load parameters for 17696 17697 * a plug-in. 17698 17699 * @type function 17700 17701 * @param {object} oSettings DataTables settings object 17702 17703 * @param {object} oData The state object that is to be loaded 17704 17705 * @dtopt Callbacks 17706 17707 * 17708 17709 * @example 17710 17711 * // Remove a saved filter, so filtering is never loaded 17712 17713 * $(document).ready( function() { 17714 17715 * $('#example').dataTable( { 17716 17717 * "bStateSave": true, 17718 17719 * "fnStateLoadParams": function (oSettings, oData) { 17720 17721 * oData.oSearch.sSearch = ""; 17722 17723 * } 17724 17725 * } ); 17726 17727 * } ); 17728 17729 * 17730 17731 * @example 17732 17733 * // Disallow state loading by returning false 17734 17735 * $(document).ready( function() { 17736 17737 * $('#example').dataTable( { 17738 17739 * "bStateSave": true, 17740 17741 * "fnStateLoadParams": function (oSettings, oData) { 17742 17743 * return false; 17744 17745 * } 17746 17747 * } ); 17748 17749 * } ); 17750 17751 */ 17752 17753 "fnStateLoadParams": null, 17754 17755 17756 17757 17758 17759 /** 17760 17761 * Callback that is called when the state has been loaded from the state saving method 17762 17763 * and the DataTables settings object has been modified as a result of the loaded state. 17764 17765 * @type function 17766 17767 * @param {object} oSettings DataTables settings object 17768 17769 * @param {object} oData The state object that was loaded 17770 17771 * @dtopt Callbacks 17772 17773 * 17774 17775 * @example 17776 17777 * // Show an alert with the filtering value that was saved 17778 17779 * $(document).ready( function() { 17780 17781 * $('#example').dataTable( { 17782 17783 * "bStateSave": true, 17784 17785 * "fnStateLoaded": function (oSettings, oData) { 17786 17787 * alert( 'Saved filter was: '+oData.oSearch.sSearch ); 17788 17789 * } 17790 17791 * } ); 17792 17793 * } ); 17794 17795 */ 17796 17797 "fnStateLoaded": null, 17798 17799 17800 17801 17802 17803 /** 17804 17805 * Save the table state. This function allows you to define where and how the state 17806 17807 * information for the table is stored - by default it will use a cookie, but you 17808 17809 * might want to use local storage (HTML5) or a server-side database. 17810 17811 * @type function 17812 17813 * @member 17814 17815 * @param {object} oSettings DataTables settings object 17816 17817 * @param {object} oData The state object to be saved 17818 17819 * @dtopt Callbacks 17820 17821 * 17822 17823 * @example 17824 17825 * $(document).ready( function() { 17826 17827 * $('#example').dataTable( { 17828 17829 * "bStateSave": true, 17830 17831 * "fnStateSave": function (oSettings, oData) { 17832 17833 * // Send an Ajax request to the server with the state object 17834 17835 * $.ajax( { 17836 17837 * "url": "/state_save", 17838 17839 * "data": oData, 17840 17841 * "dataType": "json", 17842 17843 * "method": "POST" 17844 17845 * "success": function () {} 17846 17847 * } ); 17848 17849 * } 17850 17851 * } ); 17852 17853 * } ); 17854 17855 */ 17856 17857 "fnStateSave": function ( oSettings, oData ) { 17858 17859 this.oApi._fnCreateCookie( 17860 17861 oSettings.sCookiePrefix+oSettings.sInstance, 17862 17863 this.oApi._fnJsonString(oData), 17864 17865 oSettings.iCookieDuration, 17866 17867 oSettings.sCookiePrefix, 17868 17869 oSettings.fnCookieCallback 17870 17871 ); 17872 17873 }, 17874 17875 17876 17877 17878 17879 /** 17880 17881 * Callback which allows modification of the state to be saved. Called when the table 17882 17883 * has changed state a new state save is required. This method allows modification of 17884 17885 * the state saving object prior to actually doing the save, including addition or 17886
17887 * other state properties or modification. Note that for plug-in authors, you should 17888 17889 * use the 'stateSaveParams' event to save parameters for a plug-in. 17890 17891 * @type function 17892 17893 * @param {object} oSettings DataTables settings object 17894 17895 * @param {object} oData The state object to be saved 17896 17897 * @dtopt Callbacks 17898 17899 * 17900 17901 * @example 17902 17903 * // Remove a saved filter, so filtering is never saved 17904 17905 * $(document).ready( function() { 17906 17907 * $('#example').dataTable( { 17908 17909 * "bStateSave": true, 17910 17911 * "fnStateSaveParams": function (oSettings, oData) { 17912 17913 * oData.oSearch.sSearch = ""; 17914 17915 * } 17916 17917 * } ); 17918 17919 * } ); 17920 17921 */ 17922 17923 "fnStateSaveParams": null, 17924 17925 17926 17927 17928 17929 /** 17930 17931 * Duration of the cookie which is used for storing session information. This 17932 17933 * value is given in seconds. 17934 17935 * @type int 17936 17937 * @default 7200 <i>(2 hours)</i> 17938 17939 * @dtopt Options 17940 17941 * 17942 17943 * @example 17944 17945 * $(document).ready( function() { 17946 17947 * $('#example').dataTable( { 17948 17949 * "iCookieDuration": 60*60*24; // 1 day 17950 17951 * } ); 17952 17953 * } ) 17954 17955 */ 17956 17957 "iCookieDuration": 7200, 17958 17959 17960 17961 17962 17963 /** 17964 17965 * When enabled DataTables will not make a request to the server for the first 17966 17967 * page draw - rather it will use the data already on the page (no sorting etc 17968 17969 * will be applied to it), thus saving on an XHR at load time. iDeferLoading 17970 17971 * is used to indicate that deferred loading is required, but it is also used 17972 17973 * to tell DataTables how many records there are in the full table (allowing 17974 17975 * the information element and pagination to be displayed correctly). In the case 17976 17977 * where a filtering is applied to the table on initial load, this can be 17978 17979 * indicated by giving the parameter as an array, where the first element is 17980 17981 * the number of records available after filtering and the second element is the 17982 17983 * number of records without filtering (allowing the table information element 17984 17985 * to be shown correctly). 17986 17987 * @type int | array 17988 17989 * @default null 17990 17991 * @dtopt Options 17992 17993 * 17994 17995 * @example 17996 17997 * // 57 records available in the table, no filtering applied 17998 17999 * $(document).ready( function() { 18000 18001 * $('#example').dataTable( { 18002 18003 * "bServerSide": true, 18004 18005 * "sAjaxSource": "scripts/server_processing.php", 18006 18007 * "iDeferLoading": 57 18008 18009 * } ); 18010 18011 * } ); 18012 18013 * 18014 18015 * @example 18016 18017 * // 57 records after filtering, 100 without filtering (an initial filter applied) 18018 18019 * $(document).ready( function() { 18020 18021 * $('#example').dataTable( { 18022 18023 * "bServerSide": true, 18024 18025 * "sAjaxSource": "scripts/server_processing.php", 18026 18027 * "iDeferLoading": [ 57, 100 ], 18028 18029 * "oSearch": { 18030 18031 * "sSearch": "my_filter" 18032 18033 * } 18034 18035 * } ); 18036 18037 * } ); 18038 18039 */ 18040 18041 "iDeferLoading": null, 18042 18043 18044 18045 18046 18047 /** 18048 18049 * Number of rows to display on a single page when using pagination. If 18050 18051 * feature enabled (bLengthChange) then the end user will be able to override 18052 18053 * this to a custom setting using a pop-up menu. 18054 18055 * @type int 18056 18057 * @default 10 18058 18059 * @dtopt Options 18060 18061 * 18062 18063 * @example 18064 18065 * $(document).ready( function() { 18066 18067 * $('#example').dataTable( { 18068 18069 * "iDisplayLength": 50 18070 18071 * } ); 18072 18073 * } ) 18074 18075 */ 18076 18077 "iDisplayLength": 10, 18078 18079 18080 18081 18082 18083 /** 18084 18085 * Define the starting point for data display when using DataTables with 18086 18087 * pagination. Note that this parameter is the number of records, rather than 18088 18089 * the page number, so if you have 10 records per page and want to start on 18090 18091 * the third page, it should be "20". 18092 18093 * @type int 18094 18095 * @default 0 18096 18097 * @dtopt Options 18098 18099 * 18100 18101 * @example 18102 18103 * $(document).ready( function() { 18104 18105 * $('#example').dataTable( { 18106 18107 * "iDisplayStart": 20 18108 18109 * } ); 18110 18111 * } ) 18112 18113 */ 18114 18115 "iDisplayStart": 0, 18116 18117 18118 18119 18120 18121 /** 18122 18123 * The scroll gap is the amount of scrolling that is left to go before 18124 18125 * DataTables will load the next 'page' of data automatically. You typically 18126 18127 * want a gap which is big enough that the scrolling will be smooth for the 18128 18129 * user, while not so large that it will load more data than need. 18130 18131 * @type int 18132 18133 * @default 100 18134 18135 * @dtopt Options 18136 18137 * 18138 18139 * @example 18140 18141 * $(document).ready( function() { 18142 18143 * $('#example').dataTable( { 18144 18145 * "bScrollInfinite": true, 18146
18147 * "bScrollCollapse": true, 18148 18149 * "sScrollY": "200px", 18150 18151 * "iScrollLoadGap": 50 18152 18153 * } ); 18154 18155 * } ); 18156 18157 */ 18158 18159 "iScrollLoadGap": 100, 18160 18161 18162 18163 18164 18165 /** 18166 18167 * By default DataTables allows keyboard navigation of the table (sorting, paging, 18168 18169 * and filtering) by adding a tabindex attribute to the required elements. This 18170 18171 * allows you to tab through the controls and press the enter key to activate them. 18172 18173 * The tabindex is default 0, meaning that the tab follows the flow of the document. 18174 18175 * You can overrule this using this parameter if you wish. Use a value of -1 to 18176 18177 * disable built-in keyboard navigation. 18178 18179 * @type int 18180 18181 * @default 0 18182 18183 * @dtopt Options 18184 18185 * 18186 18187 * @example 18188 18189 * $(document).ready( function() { 18190 18191 * $('#example').dataTable( { 18192 18193 * "iTabIndex": 1 18194 18195 * } ); 18196 18197 * } ); 18198 18199 */ 18200 18201 "iTabIndex": 0, 18202 18203 18204 18205 18206 18207 /** 18208 18209 * All strings that DataTables uses in the user interface that it creates 18210 18211 * are defined in this object, allowing you to modified them individually or 18212 18213 * completely replace them all as required. 18214 18215 * @namespace 18216 18217 */ 18218 18219 "oLanguage": { 18220 18221 /** 18222 18223 * Strings that are used for WAI-ARIA labels and controls only (these are not 18224 18225 * actually visible on the page, but will be read by screenreaders, and thus 18226 18227 * must be internationalised as well). 18228 18229 * @namespace 18230 18231 */ 18232 18233 "oAria": { 18234 18235 /** 18236 18237 * ARIA label that is added to the table headers when the column may be 18238 18239 * sorted ascending by activing the column (click or return when focused). 18240 18241 * Note that the column header is prefixed to this string. 18242 18243 * @type string 18244 18245 * @default : activate to sort column ascending 18246 18247 * @dtopt Language 18248 18249 * 18250 18251 * @example 18252 18253 * $(document).ready( function() { 18254 18255 * $('#example').dataTable( { 18256 18257 * "oLanguage": { 18258 18259 * "oAria": { 18260 18261 * "sSortAscending": " - click/return to sort ascending" 18262 18263 * } 18264 18265 * } 18266 18267 * } ); 18268 18269 * } ); 18270 18271 */ 18272 18273 "sSortAscending": ": activate to sort column ascending", 18274 18275 18276 18277 /** 18278 18279 * ARIA label that is added to the table headers when the column may be 18280 18281 * sorted descending by activing the column (click or return when focused). 18282 18283 * Note that the column header is prefixed to this string. 18284 18285 * @type string 18286 18287 * @default : activate to sort column ascending 18288 18289 * @dtopt Language 18290 18291 * 18292 18293 * @example 18294 18295 * $(document).ready( function() { 18296 18297 * $('#example').dataTable( { 18298 18299 * "oLanguage": { 18300 18301 * "oAria": { 18302 18303 * "sSortDescending": " - click/return to sort descending" 18304 18305 * } 18306 18307 * } 18308 18309 * } ); 18310 18311 * } ); 18312 18313 */ 18314 18315 "sSortDescending": ": activate to sort column descending" 18316 18317 }, 18318 18319 18320 18321 /** 18322 18323 * Pagination string used by DataTables for the two built-in pagination 18324 18325 * control types ("two_button" and "full_numbers") 18326 18327 * @namespace 18328 18329 */ 18330 18331 "oPaginate": { 18332 18333 /** 18334 18335 * Text to use when using the 'full_numbers' type of pagination for the 18336 18337 * button to take the user to the first page. 18338 18339 * @type string 18340 18341 * @default First 18342 18343 * @dtopt Language 18344 18345 * 18346 18347 * @example 18348 18349 * $(document).ready( function() { 18350 18351 * $('#example').dataTable( { 18352 18353 * "oLanguage": { 18354 18355 * "oPaginate": { 18356 18357 * "sFirst": "First page" 18358 18359 * } 18360 18361 * } 18362 18363 * } ); 18364 18365 * } ); 18366 18367 */ 18368 18369 "sFirst": "First", 18370 18371 18372 18373 18374 18375 /** 18376 18377 * Text to use when using the 'full_numbers' type of pagination for the 18378 18379 * button to take the user to the last page. 18380 18381 * @type string 18382 18383 * @default Last 18384 18385 * @dtopt Language 18386 18387 * 18388 18389 * @example 18390 18391 * $(document).ready( function() { 18392 18393 * $('#example').dataTable( { 18394 18395 * "oLanguage": { 18396 18397 * "oPaginate": { 18398 18399 * "sLast": "Last page" 18400 18401 * } 18402 18403 * } 18404 18405 * } ); 18406 18407 * } ); 18408 18409 */ 18410 18411 "sLast": "Last", 18412 18413 18414 18415 18416 18417 /** 18418 18419 * Text to use for the 'next' pagination button (to take the user to the 18420 18421 * next page). 18422 18423 * @type string 18424 18425 * @default Next 18426 18427 * @dtopt Language 18428 18429 * 18430 18431 * @example 18432 18433 * $(document).ready( function() { 18434 18435 * $('#example').dataTable( { 18436 18437 * "oLanguage": { 18438 18439 * "oPaginate": { 18440 18441 * "sNext": "Next page" 18442 18443 * } 18444 18445 * } 18446 18447 * } ); 18448 18449 * } ); 18450 18451 */ 18452 18453 "sNext": "Next", 18454 18455 18456 18457 18458 18459 /** 18460 18461 * Text to use for the 'previous' pagination button (to take the user to 18462 18463 * the previous page). 18464 18465 * @type string 18466 18467 * @default Previous 18468 18469 * @dtopt Language 18470 18471 * 18472 18473 * @example 18474 18475 * $(document).ready( function() { 18476 18477 * $('#example').dataTable( { 18478 18479 * "oLanguage": { 18480 18481 * "oPaginate": { 18482 18483 * "sPrevious": "Previous page" 18484 18485 * } 18486 18487 * } 18488 18489 * } ); 18490 18491 * } ); 18492 18493 */ 18494 18495 "sPrevious": "Previous" 18496 18497 }, 18498 18499 18500 18501 /** 18502 18503 * This string is shown in preference to sZeroRecords when the table is 18504 18505 * empty of data (regardless of filtering). Note that this is an optional 18506 18507 * parameter - if it is not given, the value of sZeroRecords will be used 18508 18509 * instead (either the default or given value). 18510 18511 * @type string 18512 18513 * @default No data available in table 18514 18515 * @dtopt Language 18516 18517 * 18518 18519 * @example 18520 18521 * $(document).ready( function() { 18522 18523 * $('#example').dataTable( { 18524 18525 * "oLanguage": { 18526 18527 * "sEmptyTable": "No data available in table" 18528 18529 * } 18530 18531 * } ); 18532 18533 * } ); 18534 18535 */ 18536 18537 "sEmptyTable": "No data available in table", 18538 18539 18540 18541 18542 18543 /** 18544 18545 * This string gives information to the end user about the information that 18546 18547 * is current on display on the page. The _START_, _END_ and _TOTAL_ 18548 18549 * variables are all dynamically replaced as the table display updates, and 18550 18551 * can be freely moved or removed as the language requirements change. 18552 18553 * @type string 18554 18555 * @default Showing _START_ to _END_ of _TOTAL_ Businesses 18556 18557 * @dtopt Language 18558 18559 * 18560 18561 * @example 18562 18563 * $(document).ready( function() { 18564 18565 * $('#example').dataTable( { 18566 18567 * "oLanguage": { 18568
18569 * "sInfo": "Got a total of _TOTAL_ Businesses to show (_START_ to _END_)" 18570 18571 * } 18572 18573 * } ); 18574 18575 * } ); 18576 18577 */ 18578 18579 "sInfo": "Showing _START_ to _END_ of _TOTAL_", 18580 18581 18582 18583 18584 18585 /** 18586 18587 * Display information string for when the table is empty. Typically the 18588 18589 * format of this string should match sInfo. 18590 18591 * @type string 18592 18593 * @default Showing 0 to 0 of 0 Businesses 18594 18595 * @dtopt Language 18596 18597 * 18598 18599 * @example 18600 18601 * $(document).ready( function() { 18602 18603 * $('#example').dataTable( { 18604 18605 * "oLanguage": { 18606 18607 * "sInfoEmpty": "No Businesses to show" 18608 18609 * } 18610 18611 * } ); 18612 18613 * } ); 18614 18615 */ 18616 18617 "sInfoEmpty": "Showing 0 to 0 of 0", 18618 18619 18620 18621 18622 18623 /** 18624 18625 * When a user filters the information in a table, this string is appended 18626 18627 * to the information (sInfo) to give an idea of how strong the filtering 18628 18629 * is. The variable _MAX_ is dynamically updated. 18630 18631 * @type string 18632 18633 * @default (filtered from _MAX_ total Businesses) 18634 18635 * @dtopt Language 18636 18637 * 18638 18639 * @example 18640 18641 * $(document).ready( function() { 18642 18643 * $('#example').dataTable( { 18644 18645 * "oLanguage": { 18646 18647 * "sInfoFiltered": " - filtering from _MAX_ records" 18648 18649 * } 18650 18651 * } ); 18652 18653 * } ); 18654 18655 */ 18656 18657 "sInfoFiltered": "(filtered from _MAX_ total)", 18658 18659 18660 18661 18662 18663 /** 18664 18665 * If can be useful to append extra information to the info string at times, 18666 18667 * and this variable does exactly that. This information will be appended to 18668 18669 * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are 18670 18671 * being used) at all times. 18672 18673 * @type string 18674 18675 * @default <i>Empty string</i> 18676 18677 * @dtopt Language 18678 18679 * 18680 18681 * @example 18682 18683 * $(document).ready( function() { 18684 18685 * $('#example').dataTable( { 18686 18687 * "oLanguage": { 18688 18689 * "sInfoPostFix": "All records shown are derived from real information." 18690 18691 * } 18692 18693 * } ); 18694 18695 * } ); 18696 18697 */ 18698 18699 "sInfoPostFix": "", 18700 18701 18702 18703 18704 18705 /** 18706 18707 * DataTables has a build in number formatter (fnFormatNumber) which is used 18708 18709 * to format large numbers that are used in the table information. By 18710 18711 * default a comma is used, but this can be trivially changed to any 18712 18713 * character you wish with this parameter. 18714 18715 * @type string 18716 18717 * @default , 18718 18719 * @dtopt Language 18720 18721 * 18722 18723 * @example 18724 18725 * $(document).ready( function() { 18726 18727 * $('#example').dataTable( { 18728 18729 * "oLanguage": { 18730 18731 * "sInfoThousands": "'" 18732 18733 * } 18734 18735 * } ); 18736 18737 * } ); 18738 18739 */ 18740 18741 "sInfoThousands": ",", 18742 18743 18744 18745 18746 18747 /** 18748 18749 * Detail the action that will be taken when the drop down menu for the 18750 18751 * pagination length option is changed. The '_MENU_' variable is replaced 18752 18753 * with a default select list of 10, 25, 50 and 100, and can be replaced 18754 18755 * with a custom select box if required. 18756 18757 * @type string 18758 18759 * @default Show _MENU_ Businesses 18760 18761 * @dtopt Language 18762 18763 * 18764 18765 * @example 18766 18767 * // Language change only 18768 18769 * $(document).ready( function() { 18770 18771 * $('#example').dataTable( { 18772 18773 * "oLanguage": { 18774 18775 * "sLengthMenu": "Display _MENU_ records" 18776 18777 * } 18778 18779 * } ); 18780 18781 * } ); 18782 18783 * 18784 18785 * @example 18786 18787 * // Language and options change 18788 18789 * $(document).ready( function() { 18790 18791 * $('#example').dataTable( { 18792 18793 * "oLanguage": { 18794 18795 * "sLengthMenu": 'Display <select>'+ 18796 18797 * '<option value="10">10</option>'+ 18798 18799 * '<option value="20">20</option>'+ 18800 18801 * '<option value="30">30</option>'+ 18802 18803 * '<option value="40">40</option>'+ 18804 18805 * '<option value="50">50</option>'+ 18806 18807 * '<option value="-1">All</option>'+ 18808 18809 * '</select> records' 18810 18811 * } 18812 18813 * } ); 18814 18815 * } ); 18816 18817 */ 18818 18819 "sLengthMenu": "Show _MENU_", 18820 18821 18822 18823 18824 18825 /** 18826 18827 * When using Ajax sourced data and during the first draw when DataTables is 18828 18829 * gathering the data, this message is shown in an empty row in the table to 18830 18831 * indicate to the end user the the data is being loaded. Note that this 18832 18833 * parameter is not used when loading data by server-side processing, just 18834 18835 * Ajax sourced data with client-side processing. 18836 18837 * @type string 18838 18839 * @default Loading... 18840 18841 * @dtopt Language 18842 18843 * 18844 18845 * @example 18846 18847 * $(document).ready( function() { 18848 18849 * $('#example').dataTable( { 18850 18851 * "oLanguage": { 18852 18853 * "sLoadingRecords": "Please wait - loading..." 18854 18855 * } 18856 18857 * } ); 18858 18859 * } ); 18860 18861 */ 18862 18863 "sLoadingRecords": "Loading...", 18864 18865 18866 18867 18868 18869 /** 18870 18871 * Text which is displayed when the table is processing a user action 18872 18873 * (usually a sort command or similar). 18874 18875 * @type string 18876 18877 * @default Processing... 18878 18879 * @dtopt Language 18880 18881 * 18882 18883 * @example 18884 18885 * $(document).ready( function() { 18886 18887 * $('#example').dataTable( { 18888 18889 * "oLanguage": { 18890 18891 * "sProcessing": "DataTables is currently busy" 18892 18893 * } 18894 18895 * } ); 18896 18897 * } ); 18898 18899 */ 18900 18901 "sProcessing": "Processing...", 18902 18903 18904 18905 18906 18907 /** 18908 18909 * Details the actions that will be taken when the user types into the 18910 18911 * filtering input text box. The variable "_INPUT_", if used in the string, 18912 18913 * is replaced with the HTML text box for the filtering input allowing 18914 18915 * control over where it appears in the string. If "_INPUT_" is not given 18916 18917 * then the input box is appended to the string automatically. 18918 18919 * @type string 18920 18921 * @default Search: 18922 18923 * @dtopt Language 18924 18925 * 18926 18927 * @example 18928
18929 * // Input text box will be appended at the end automatically 18930 18931 * $(document).ready( function() { 18932 18933 * $('#example').dataTable( { 18934 18935 * "oLanguage": { 18936 18937 * "sSearch": "Filter records:" 18938 18939 * } 18940 18941 * } ); 18942 18943 * } ); 18944 18945 * 18946 18947 * @example 18948 18949 * // Specify where the filter should appear 18950 18951 * $(document).ready( function() { 18952 18953 * $('#example').dataTable( { 18954 18955 * "oLanguage": { 18956 18957 * "sSearch": "Apply filter _INPUT_ to table" 18958 18959 * } 18960 18961 * } ); 18962 18963 * } ); 18964 18965 */ 18966 18967 "sSearch": "Search:", 18968 18969 18970 18971 18972 18973 /** 18974 18975 * All of the language information can be stored in a file on the 18976 18977 * server-side, which DataTables will look up if this parameter is passed. 18978 18979 * It must store the URL of the language file, which is in a JSON format, 18980 18981 * and the object has the same properties as the oLanguage object in the 18982 18983 * initialiser object (i.e. the above parameters). Please refer to one of 18984 18985 * the example language files to see how this works in action. 18986 18987 * @type string 18988 18989 * @default <i>Empty string - i.e. disabled</i> 18990 18991 * @dtopt Language 18992 18993 * 18994 18995 * @example 18996 18997 * $(document).ready( function() { 18998 18999 * $('#example').dataTable( { 19000 19001 * "oLanguage": { 19002 19003 * "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt" 19004 19005 * } 19006 19007 * } ); 19008 19009 * } ); 19010 19011 */ 19012 19013 "sUrl": "", 19014 19015 19016 19017 19018 19019 /** 19020 19021 * Text shown inside the table records when the is no information to be 19022 19023 * displayed after filtering. sEmptyTable is shown when there is simply no 19024 19025 * information in the table at all (regardless of filtering). 19026 19027 * @type string 19028 19029 * @default No matching records found 19030 19031 * @dtopt Language 19032 19033 * 19034 19035 * @example 19036 19037 * $(document).ready( function() { 19038 19039 * $('#example').dataTable( { 19040 19041 * "oLanguage": { 19042 19043 * "sZeroRecords": "No records to display" 19044 19045 * } 19046 19047 * } ); 19048 19049 * } ); 19050 19051 */ 19052 19053 "sZeroRecords": "Sorry no found. Try a different search. " 19054 19055 }, 19056 19057 19058 19059 19060 19061 /** 19062 19063 * This parameter allows you to have define the global filtering state at 19064 19065 * initialisation time. As an object the "sSearch" parameter must be 19066 19067 * defined, but all other parameters are optional. When "bRegex" is true, 19068 19069 * the search string will be treated as a regular expression, when false 19070 19071 * (default) it will be treated as a straight string. When "bSmart" 19072 19073 * DataTables will use it's smart filtering methods (to word match at 19074 19075 * any point in the data), when false this will not be done. 19076 19077 * @namespace 19078 19079 * @extends DataTable.models.oSearch 19080 19081 * @dtopt Options 19082 19083 * 19084 19085 * @example 19086 19087 * $(document).ready( function() { 19088 19089 * $('#example').dataTable( { 19090 19091 * "oSearch": {"sSearch": "Initial search"} 19092 19093 * } ); 19094 19095 * } ) 19096 19097 */ 19098 19099 "oSearch": $.extend( {}, DataTable.models.oSearch ), 19100 19101 19102 19103 19104 19105 /** 19106 19107 * By default DataTables will look for the property 'aaData' when obtaining 19108 19109 * data from an Ajax source or for server-side processing - this parameter 19110 19111 * allows that property to be changed. You can use Javascript dotted object 19112 19113 * notation to get a data source for multiple levels of nesting. 19114 19115 * @type string 19116 19117 * @default aaData 19118 19119 * @dtopt Options 19120 19121 * @dtopt Server-side 19122 19123 * 19124 19125 * @example 19126 19127 * // Get data from { "data": [...] } 19128 19129 * $(document).ready( function() { 19130 19131 * var oTable = $('#example').dataTable( { 19132 19133 * "sAjaxSource": "sources/data.txt", 19134 19135 * "sAjaxDataProp": "data" 19136 19137 * } ); 19138 19139 * } ); 19140 19141 * 19142 19143 * @example 19144 19145 * // Get data from { "data": { "inner": [...] } } 19146 19147 * $(document).ready( function() { 19148 19149 * var oTable = $('#example').dataTable( { 19150 19151 * "sAjaxSource": "sources/data.txt", 19152 19153 * "sAjaxDataProp": "data.inner" 19154 19155 * } ); 19156 19157 * } ); 19158 19159 */ 19160 19161 "sAjaxDataProp": "aaData", 19162 19163 19164 19165 19166 19167 /** 19168 19169 * You can instruct DataTables to load data from an external source using this 19170 19171 * parameter (use aData if you want to pass data in you already have). Simply 19172 19173 * provide a url a JSON object can be obtained from. This object must include 19174 19175 * the parameter 'aaData' which is the data source for the table. 19176 19177 * @type string 19178 19179 * @default null 19180 19181 * @dtopt Options 19182 19183 * @dtopt Server-side 19184 19185 * 19186 19187 * @example 19188 19189 * $(document).ready( function() { 19190 19191 * $('#example').dataTable( { 19192 19193 * "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php" 19194 19195 * } ); 19196 19197 * } ) 19198 19199 */ 19200 19201 "sAjaxSource": null, 19202 19203 19204 19205 19206 19207 /** 19208 19209 * This parameter can be used to override the default prefix that DataTables 19210 19211 * assigns to a cookie when state saving is enabled. 19212 19213 * @type string 19214 19215 * @default SpryMedia_DataTables_ 19216 19217 * @dtopt Options 19218 19219 * 19220 19221 * @example 19222 19223 * $(document).ready( function() { 19224 19225 * $('#example').dataTable( { 19226 19227 * "sCookiePrefix": "my_datatable_", 19228 19229 * } ); 19230 19231 * } ); 19232 19233 */ 19234 19235 "sCookiePrefix": "SpryMedia_DataTables_", 19236 19237 19238 19239 19240 19241 /** 19242 19243 * This initialisation variable allows you to specify exactly where in the 19244 19245 * DOM you want DataTables to inject the various controls it adds to the page 19246 19247 * (for example you might want the pagination controls at the top of the 19248 19249 * table). DIV elements (with or without a custom class) can also be added to 19250 19251 * aid styling. The follow syntax is used: 19252 19253 * <ul> 19254 19255 * <li>The following options are allowed: 19256 19257 * <ul> 19258 19259 * <li>'l' - Length changing</li 19260 19261 * <li>'f' - Filtering input</li> 19262 19263 * <li>'t' - The table!</li> 19264 19265 * <li>'i' - Information</li> 19266 19267 * <li>'p' - Pagination</li> 19268 19269 * <li>'r' - pRocessing</li> 19270 19271 * </ul> 19272 19273 * </li> 19274 19275 * <li>The following constants are allowed: 19276 19277 * <ul> 19278 19279 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 19280 19281 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 19282 19283 * </ul> 19284 19285 * </li> 19286 19287 * <li>The following syntax is expected: 19288 19289 * <ul> 19290 19291 * <li>'<' and '>' - div elements</li> 19292 19293 * <li>'<"class" and '>' - div with a class</li> 19294 19295 * <li>'<"#id" and '>' - div with an ID</li> 19296 19297 * </ul> 19298 19299 * </li> 19300 19301 * <li>Examples: 19302 19303 * <ul> 19304 19305 * <li>'<"wrapper"flipt>'</li> 19306 19307 * <li>'<lf<t>ip>'</li> 19308 19309 * </ul> 19310 19311 * </li> 19312 19313 * </ul> 19314 19315 * @type string 19316 19317 * @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b> 19318 19319 * <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i> 19320 19321 * @dtopt Options 19322 19323 * 19324 19325 * @example 19326 19327 * $(document).ready( function() { 19328 19329 * $('#example').dataTable( { 19330 19331 * "sDom": '<"top"i>rt<"bottom"flp><"clear">'
19332 19333 * } ); 19334 19335 * } ); 19336 19337 */ 19338 19339 "sDom": "lfrtip", 19340 19341 19342 19343 19344 19345 /** 19346 19347 * DataTables features two different built-in pagination interaction methods 19348 19349 * ('two_button' or 'full_numbers') which present different page controls to 19350 19351 * the end user. Further methods can be added using the API (see below). 19352 19353 * @type string 19354 19355 * @default two_button 19356 19357 * @dtopt Options 19358 19359 * 19360 19361 * @example 19362 19363 * $(document).ready( function() { 19364 19365 * $('#example').dataTable( { 19366 19367 * "sPaginationType": "full_numbers" 19368 19369 * } ); 19370 19371 * } ) 19372 19373 */ 19374 19375 "sPaginationType": "two_button", 19376 19377 19378 19379 19380 19381 /** 19382 19383 * Enable horizontal scrolling. When a table is too wide to fit into a certain 19384 19385 * layout, or you have a large number of columns in the table, you can enable 19386 19387 * x-scrolling to show the table in a viewport, which can be scrolled. This 19388 19389 * property can be any CSS unit, or a number (in which case it will be treated 19390 19391 * as a pixel measurement). 19392 19393 * @type string 19394 19395 * @default <i>blank string - i.e. disabled</i> 19396 19397 * @dtopt Features 19398 19399 * 19400 19401 * @example 19402 19403 * $(document).ready( function() { 19404 19405 * $('#example').dataTable( { 19406 19407 * "sScrollX": "100%", 19408 19409 * "bScrollCollapse": true 19410 19411 * } ); 19412 19413 * } ); 19414 19415 */ 19416 19417 "sScrollX": "", 19418 19419 19420 19421 19422 19423 /** 19424 19425 * This property can be used to force a DataTable to use more width than it 19426 19427 * might otherwise do when x-scrolling is enabled. For example if you have a 19428 19429 * table which requires to be well spaced, this parameter is useful for 19430 19431 * "over-sizing" the table, and thus forcing scrolling. This property can by 19432 19433 * any CSS unit, or a number (in which case it will be treated as a pixel 19434 19435 * measurement). 19436 19437 * @type string 19438 19439 * @default <i>blank string - i.e. disabled</i> 19440 19441 * @dtopt Options 19442 19443 * 19444 19445 * @example 19446 19447 * $(document).ready( function() { 19448 19449 * $('#example').dataTable( { 19450 19451 * "sScrollX": "100%", 19452 19453 * "sScrollXInner": "110%" 19454 19455 * } ); 19456 19457 * } ); 19458 19459 */ 19460 19461 "sScrollXInner": "", 19462 19463 19464 19465 19466 19467 /** 19468 19469 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 19470 19471 * to the given height, and enable scrolling for any data which overflows the 19472 19473 * current viewport. This can be used as an alternative to paging to display 19474 19475 * a lot of data in a small area (although paging and scrolling can both be 19476 19477 * enabled at the same time). This property can be any CSS unit, or a number 19478 19479 * (in which case it will be treated as a pixel measurement). 19480 19481 * @type string 19482 19483 * @default <i>blank string - i.e. disabled</i> 19484 19485 * @dtopt Features 19486 19487 * 19488 19489 * @example 19490 19491 * $(document).ready( function() { 19492 19493 * $('#example').dataTable( { 19494 19495 * "sScrollY": "200px", 19496 19497 * "bPaginate": false 19498 19499 * } ); 19500 19501 * } ); 19502 19503 */ 19504 19505 "sScrollY": "", 19506 19507 19508 19509 19510 19511 /** 19512 19513 * Set the HTTP method that is used to make the Ajax call for server-side 19514 19515 * processing or Ajax sourced data. 19516 19517 * @type string 19518 19519 * @default GET 19520 19521 * @dtopt Options 19522 19523 * @dtopt Server-side 19524 19525 * 19526 19527 * @example 19528 19529 * $(document).ready( function() { 19530 19531 * $('#example').dataTable( { 19532 19533 * "bServerSide": true, 19534 19535 * "sAjaxSource": "scripts/post.php", 19536 19537 * "sServerMethod": "POST" 19538 19539 * } ); 19540 19541 * } ); 19542 19543 */ 19544 19545 "sServerMethod": "GET" 19546 19547 }; 19548 19549 19550 19551 19552 19553 19554 19555 /** 19556 19557 * Column options that can be given to DataTables at initialisation time. 19558 19559 * @namespace 19560 19561 */ 19562 19563 DataTable.defaults.columns = { 19564 19565 /** 19566 19567 * Allows a column's sorting to take multiple columns into account when 19568 19569 * doing a sort. For example first name / last name columns make sense to 19570 19571 * do a multi-column sort over the two columns. 19572 19573 * @type array 19574 19575 * @default null <i>Takes the value of the column index automatically</i> 19576 19577 * @dtopt Columns 19578 19579 * 19580 19581 * @example 19582 19583 * // Using aoColumnDefs 19584 19585 * $(document).ready( function() { 19586 19587 * $('#example').dataTable( { 19588 19589 * "aoColumnDefs": [ 19590 19591 * { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] }, 19592 19593 * { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] }, 19594 19595 * { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] } 19596 19597 * ] 19598 19599 * } ); 19600 19601 * } ); 19602 19603 * 19604 19605 * @example 19606 19607 * // Using aoColumns 19608 19609 * $(document).ready( function() { 19610 19611 * $('#example').dataTable( { 19612 19613 * "aoColumns": [ 19614 19615 * { "aDataSort": [ 0, 1 ] }, 19616 19617 * { "aDataSort": [ 1, 0 ] }, 19618 19619 * { "aDataSort": [ 2, 3, 4 ] }, 19620 19621 * null, 19622 19623 * null 19624 19625 * ] 19626 19627 * } ); 19628 19629 * } ); 19630 19631 */ 19632 19633 "aDataSort": null, 19634 19635 19636 19637 19638 19639 /** 19640 19641 * You can control the default sorting direction, and even alter the behaviour 19642 19643 * of the sort handler (i.e. only allow ascending sorting etc) using this 19644 19645 * parameter. 19646 19647 * @type array 19648 19649 * @default [ 'asc', 'desc' ] 19650 19651 * @dtopt Columns 19652 19653 * 19654 19655 * @example 19656 19657 * // Using aoColumnDefs 19658 19659 * $(document).ready( function() { 19660 19661 * $('#example').dataTable( { 19662 19663 * "aoColumnDefs": [ 19664 19665 * { "asSorting": [ "asc" ], "aTargets": [ 1 ] }, 19666 19667 * { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] }, 19668 19669 * { "asSorting": [ "desc" ], "aTargets": [ 3 ] } 19670 19671 * ] 19672 19673 * } ); 19674 19675 * } ); 19676 19677 * 19678 19679 * @example 19680 19681 * // Using aoColumns 19682 19683 * $(document).ready( function() { 19684 19685 * $('#example').dataTable( { 19686 19687 * "aoColumns": [ 19688 19689 * null, 19690 19691 * { "asSorting": [ "asc" ] }, 19692 19693 * { "asSorting": [ "desc", "asc", "asc" ] }, 19694 19695 * { "asSorting": [ "desc" ] }, 19696 19697 * null 19698 19699 * ] 19700 19701 * } ); 19702 19703 * } ); 19704 19705 */ 19706 19707 "asSorting": [ 'asc', 'desc' ], 19708 19709 19710 19711 19712 19713 /** 19714 19715 * Enable or disable filtering on the data in this column. 19716 19717 * @type boolean 19718 19719 * @default true 19720 19721 * @dtopt Columns 19722 19723 * 19724 19725 * @example 19726 19727 * // Using aoColumnDefs 19728 19729 * $(document).ready( function() { 19730 19731 * $('#example').dataTable( { 19732 19733 * "aoColumnDefs": [ 19734 19735 * { "bSearchable": false, "aTargets": [ 0 ] } 19736 19737 * ] } ); 19738 19739 * } ); 19740 19741 * 19742 19743 * @example 19744 19745 * // Using aoColumns 19746 19747 * $(document).ready( function() { 19748 19749 * $('#example').dataTable( { 19750 19751 * "aoColumns": [ 19752 19753 * { "bSearchable": false }, 19754 19755 * null, 19756 19757 * null, 19758 19759 * null, 19760 19761 * null 19762 19763 * ] } ); 19764 19765 * } ); 19766 19767 */ 19768 19769 "bSearchable": true, 19770 19771 19772 19773 19774 19775 /** 19776 19777 * Enable or disable sorting on this column. 19778 19779 * @type boolean 19780 19781 * @default true 19782 19783 * @dtopt Columns 19784 19785 * 19786 19787 * @example 19788 19789 * // Using aoColumnDefs 19790 19791 * $(document).ready( function() { 19792 19793 * $('#example').dataTable( { 19794 19795 * "aoColumnDefs": [ 19796
19797 * { "bSortable": false, "aTargets": [ 0 ] } 19798 19799 * ] } ); 19800 19801 * } ); 19802 19803 * 19804 19805 * @example 19806 19807 * // Using aoColumns 19808 19809 * $(document).ready( function() { 19810 19811 * $('#example').dataTable( { 19812 19813 * "aoColumns": [ 19814 19815 * { "bSortable": false }, 19816 19817 * null, 19818 19819 * null, 19820 19821 * null, 19822 19823 * null 19824 19825 * ] } ); 19826 19827 * } ); 19828 19829 */ 19830 19831 "bSortable": true, 19832 19833 19834 19835 19836 19837 /** 19838 19839 * <code>Deprecated</code> When using fnRender() for a column, you may wish 19840 19841 * to use the original data (before rendering) for sorting and filtering 19842 19843 * (the default is to used the rendered data that the user can see). This 19844 19845 * may be useful for dates etc. 19846 19847 * 19848 19849 * Please note that this option has now been deprecated and will be removed 19850 19851 * in the next version of DataTables. Please use mRender / mData rather than 19852 19853 * fnRender. 19854 19855 * @type boolean 19856 19857 * @default true 19858 19859 * @dtopt Columns 19860 19861 * @deprecated 19862 19863 */ 19864 19865 "bUseRendered": true, 19866 19867 19868 19869 19870 19871 /** 19872 19873 * Enable or disable the display of this column. 19874 19875 * @type boolean 19876 19877 * @default true 19878 19879 * @dtopt Columns 19880 19881 * 19882 19883 * @example 19884 19885 * // Using aoColumnDefs 19886 19887 * $(document).ready( function() { 19888 19889 * $('#example').dataTable( { 19890 19891 * "aoColumnDefs": [ 19892 19893 * { "bVisible": false, "aTargets": [ 0 ] } 19894 19895 * ] } ); 19896 19897 * } ); 19898 19899 * 19900 19901 * @example 19902 19903 * // Using aoColumns 19904 19905 * $(document).ready( function() { 19906 19907 * $('#example').dataTable( { 19908 19909 * "aoColumns": [ 19910 19911 * { "bVisible": false }, 19912 19913 * null, 19914 19915 * null, 19916 19917 * null, 19918 19919 * null 19920 19921 * ] } ); 19922 19923 * } ); 19924 19925 */ 19926 19927 "bVisible": true, 19928 19929 19930 19931 19932 19933 /** 19934 19935 * Developer definable function that is called whenever a cell is created (Ajax source, 19936 19937 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 19938 19939 * allowing you to modify the DOM element (add background colour for example) when the 19940 19941 * element is available. 19942 19943 * @type function 19944 19945 * @param {element} nTd The TD node that has been created 19946 19947 * @param {*} sData The Data for the cell 19948 19949 * @param {array|object} oData The data for the whole row 19950 19951 * @param {int} iRow The row index for the aoData data store 19952 19953 * @param {int} iCol The column index for aoColumns 19954 19955 * @dtopt Columns 19956 19957 * 19958 19959 * @example 19960 19961 * $(document).ready( function() { 19962 19963 * $('#example').dataTable( { 19964 19965 * "aoColumnDefs": [ { 19966 19967 * "aTargets": [3], 19968 19969 * "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) { 19970 19971 * if ( sData == "1.7" ) { 19972 19973 * $(nTd).css('color', 'blue') 19974 19975 * } 19976 19977 * } 19978 19979 * } ] 19980 19981 * }); 19982 19983 * } ); 19984 19985 */ 19986 19987 "fnCreatedCell": null, 19988 19989 19990 19991 19992 19993 /** 19994 19995 * <code>Deprecated</code> Custom display function that will be called for the 19996 19997 * display of each cell in this column. 19998 19999 * 20000 20001 * Please note that this option has now been deprecated and will be removed 20002 20003 * in the next version of DataTables. Please use mRender / mData rather than 20004 20005 * fnRender. 20006 20007 * @type function 20008 20009 * @param {object} o Object with the following parameters: 20010 20011 * @param {int} o.iDataRow The row in aoData 20012 20013 * @param {int} o.iDataColumn The column in question 20014 20015 * @param {array} o.aData The data for the row in question 20016 20017 * @param {object} o.oSettings The settings object for this DataTables instance 20018 20019 * @param {object} o.mDataProp The data property used for this column 20020 20021 * @param {*} val The current cell value 20022 20023 * @returns {string} The string you which to use in the display 20024 20025 * @dtopt Columns 20026 20027 * @deprecated 20028 20029 */ 20030 20031 "fnRender": null, 20032 20033 20034 20035 20036 20037 /** 20038 20039 * The column index (starting from 0!) that you wish a sort to be performed 20040 20041 * upon when this column is selected for sorting. This can be used for sorting 20042 20043 * on hidden columns for example. 20044 20045 * @type int 20046 20047 * @default -1 <i>Use automatically calculated column index</i> 20048 20049 * @dtopt Columns 20050 20051 * 20052 20053 * @example 20054 20055 * // Using aoColumnDefs 20056 20057 * $(document).ready( function() { 20058 20059 * $('#example').dataTable( { 20060 20061 * "aoColumnDefs": [ 20062
20063 * { "iDataSort": 1, "aTargets": [ 0 ] } 20064 20065 * ] 20066 20067 * } ); 20068 20069 * } ); 20070 20071 * 20072 20073 * @example 20074 20075 * // Using aoColumns 20076 20077 * $(document).ready( function() { 20078 20079 * $('#example').dataTable( { 20080 20081 * "aoColumns": [ 20082 20083 * { "iDataSort": 1 }, 20084 20085 * null, 20086 20087 * null, 20088 20089 * null, 20090 20091 * null 20092 20093 * ] 20094 20095 * } ); 20096 20097 * } ); 20098 20099 */ 20100 20101 "iDataSort": -1, 20102 20103 20104 20105 20106 20107 /** 20108 20109 * This parameter has been replaced by mData in DataTables to ensure naming 20110 20111 * consistency. mDataProp can still be used, as there is backwards compatibility 20112 20113 * in DataTables for this option, but it is strongly recommended that you use 20114 20115 * mData in preference to mDataProp. 20116 20117 * @name DataTable.defaults.columns.mDataProp 20118 20119 */ 20120 20121 20122 20123 20124 20125 /** 20126 20127 * This property can be used to read data from any JSON data source property, 20128 20129 * including deeply nested objects / properties. mData can be given in a 20130 20131 * number of different ways which effect its behaviour: 20132 20133 * <ul> 20134 20135 * <li>integer - treated as an array index for the data source. This is the 20136 20137 * default that DataTables uses (incrementally increased for each column).</li> 20138 20139 * <li>string - read an object property from the data source. Note that you can 20140 20141 * use Javascript dotted notation to read deep properties / arrays from the 20142 20143 * data source.</li> 20144 20145 * <li>null - the sDefaultContent option will be used for the cell (null 20146 20147 * by default, so you will need to specify the default content you want - 20148 20149 * typically an empty string). This can be useful on generated columns such 20150 20151 * as edit / delete action columns.</li> 20152 20153 * <li>function - the function given will be executed whenever DataTables 20154 20155 * needs to set or get the data for a cell in the column. The function 20156 20157 * takes three parameters: 20158 20159 * <ul> 20160 20161 * <li>{array|object} The data source for the row</li> 20162 20163 * <li>{string} The type call data requested - this will be 'set' when 20164 20165 * setting data or 'filter', 'display', 'type', 'sort' or undefined when 20166 20167 * gathering data. Note that when <i>undefined</i> is given for the type 20168 20169 * DataTables expects to get the raw data for the object back</li> 20170 20171 * <li>{*} Data to set when the second parameter is 'set'.</li> 20172 20173 * </ul> 20174 20175 * The return value from the function is not required when 'set' is the type 20176 20177 * of call, but otherwise the return is what will be used for the data 20178 20179 * requested.</li> 20180 20181 * </ul> 20182 20183 * 20184 20185 * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change 20186 20187 * reflects the flexibility of this property and is consistent with the naming of 20188 20189 * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as 20190 20191 * it automatically maps the old name to the new if required. 20192 20193 * @type string|int|function|null 20194 20195 * @default null <i>Use automatically calculated column index</i> 20196 20197 * @dtopt Columns 20198 20199 * 20200 20201 * @example 20202 20203 * // Read table data from objects 20204 20205 * $(document).ready( function() { 20206 20207 * var oTable = $('#example').dataTable( { 20208 20209 * "sAjaxSource": "sources/deep.txt", 20210 20211 * "aoColumns": [ 20212 20213 * { "mData": "engine" }, 20214 20215 * { "mData": "browser" }, 20216 20217 * { "mData": "platform.inner" }, 20218 20219 * { "mData": "platform.details.0" }, 20220 20221 * { "mData": "platform.details.1" } 20222 20223 * ] 20224 20225 * } ); 20226 20227 * } ); 20228 20229 * 20230 20231 * @example 20232 20233 * // Using mData as a function to provide different information for 20234 20235 * // sorting, filtering and display. In this case, currency (price) 20236 20237 * $(document).ready( function() { 20238 20239 * var oTable = $('#example').dataTable( { 20240 20241 * "aoColumnDefs": [ { 20242 20243 * "aTargets": [ 0 ], 20244 20245 * "mData": function ( source, type, val ) { 20246 20247 * if (type === 'set') { 20248 20249 * source.price = val; 20250 20251 * // Store the computed dislay and filter values for efficiency 20252 20253 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 20254 20255 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 20256 20257 * return; 20258 20259 * } 20260 20261 * else if (type === 'display') { 20262 20263 * return source.price_display; 20264 20265 * } 20266 20267 * else if (type === 'filter') { 20268 20269 * return source.price_filter; 20270 20271 * } 20272 20273 * // 'sort', 'type' and undefined all just use the integer 20274 20275 * return source.price; 20276 20277 * } 20278 20279 * } ] 20280 20281 * } ); 20282 20283 * } ); 20284 20285 */ 20286 20287 "mData": null, 20288 20289 20290 20291 20292 20293 /** 20294 20295 * This property is the rendering partner to mData and it is suggested that 20296 20297 * when you want to manipulate data for display (including filtering, sorting etc) 20298 20299 * but not altering the underlying data for the table, use this property. mData 20300 20301 * can actually do everything this property can and more, but this parameter is 20302 20303 * easier to use since there is no 'set' option. Like mData is can be given 20304 20305 * in a number of different ways to effect its behaviour, with the addition of 20306 20307 * supporting array syntax for easy outputting of arrays (including arrays of 20308 20309 * objects): 20310 20311 * <ul> 20312 20313 * <li>integer - treated as an array index for the data source. This is the 20314 20315 * default that DataTables uses (incrementally increased for each column).</li> 20316 20317 * <li>string - read an object property from the data source. Note that you can 20318 20319 * use Javascript dotted notation to read deep properties / arrays from the 20320 20321 * data source and also array brackets to indicate that the data reader should 20322 20323 * loop over the data source array. When characters are given between the array 20324 20325 * brackets, these characters are used to join the data source array together. 20326 20327 * For example: "accounts[, ].name" would result in a comma separated list with 20328 20329 * the 'name' value from the 'accounts' array of objects.</li> 20330 20331 * <li>function - the function given will be executed whenever DataTables 20332 20333 * needs to set or get the data for a cell in the column. The function 20334 20335 * takes three parameters: 20336 20337 * <ul> 20338 20339 * <li>{array|object} The data source for the row (based on mData)</li> 20340 20341 * <li>{string} The type call data requested - this will be 'filter', 'display', 20342 20343 * 'type' or 'sort'.</li> 20344 20345 * <li>{array|object} The full data source for the row (not based on mData)</li> 20346 20347 * </ul> 20348 20349 * The return value from the function is what will be used for the data 20350 20351 * requested.</li> 20352 20353 * </ul> 20354 20355 * @type string|int|function|null 20356 20357 * @default null <i>Use mData</i> 20358 20359 * @dtopt Columns 20360 20361 * 20362 20363 * @example 20364 20365 * // Create a comma separated list from an array of objects 20366 20367 * $(document).ready( function() { 20368 20369 * var oTable = $('#example').dataTable( { 20370 20371 * "sAjaxSource": "sources/deep.txt", 20372 20373 * "aoColumns": [ 20374 20375 * { "mData": "engine" }, 20376 20377 * { "mData": "browser" }, 20378 20379 * { 20380 20381 * "mData": "platform", 20382 20383 * "mRender": "[, ].name" 20384 20385 * } 20386 20387 * ] 20388 20389 * } ); 20390 20391 * } ); 20392 20393 * 20394 20395 * @example 20396 20397 * // Use as a function to create a link from the data source 20398 20399 * $(document).ready( function() { 20400 20401 * var oTable = $('#example').dataTable( { 20402 20403 * "aoColumnDefs": [ 20404 20405 * { 20406 20407 * "aTargets": [ 0 ], 20408 20409 * "mData": "download_link", 20410 20411 * "mRender": function ( data, type, full ) { 20412 20413 * return '<a href="'+data+'">Download</a>'; 20414 20415 * } 20416 20417 * ] 20418 20419 * } ); 20420 20421 * } ); 20422 20423 */ 20424 20425 "mRender": null, 20426 20427 20428 20429 20430 20431 /** 20432 20433 * Change the cell type created for the column - either TD cells or TH cells. This 20434 20435 * can be useful as TH cells have semantic meaning in the table body, allowing them 20436 20437 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 20438 20439 * @type string 20440 20441 * @default td 20442 20443 * @dtopt Columns 20444 20445 * 20446 20447 * @example 20448 20449 * // Make the first column use TH cells 20450 20451 * $(document).ready( function() { 20452 20453 * var oTable = $('#example').dataTable( { 20454 20455 * "aoColumnDefs": [ { 20456 20457 * "aTargets": [ 0 ], 20458 20459 * "sCellType": "th" 20460 20461 * } ] 20462 20463 * } ); 20464 20465 * } ); 20466 20467 */ 20468 20469 "sCellType": "td", 20470 20471 20472 20473 20474 20475 /** 20476 20477 * Class to give to each cell in this column. 20478 20479 * @type string 20480 20481 * @default <i>Empty string</i> 20482 20483 * @dtopt Columns 20484 20485 * 20486 20487 * @example 20488 20489 * // Using aoColumnDefs 20490 20491 * $(document).ready( function() { 20492 20493 * $('#example').dataTable( { 20494 20495 * "aoColumnDefs": [ 20496 20497 * { "sClass": "my_class", "aTargets": [ 0 ] } 20498 20499 * ] 20500 20501 * } ); 20502 20503 * } ); 20504 20505 * 20506 20507 * @example 20508 20509 * // Using aoColumns 20510 20511 * $(document).ready( function() { 20512 20513 * $('#example').dataTable( { 20514 20515 * "aoColumns": [ 20516 20517 * { "sClass": "my_class" }, 20518 20519 * null, 20520 20521 * null, 20522 20523 * null, 20524 20525 * null 20526 20527 * ] 20528 20529 * } ); 20530 20531 * } ); 20532 20533 */ 20534 20535 "sClass": "", 20536 20537 20538 20539 /** 20540 20541 * When DataTables calculates the column widths to assign to each column, 20542 20543 * it finds the longest string in each column and then constructs a 20544 20545 * temporary table and reads the widths from that. The problem with this 20546 20547 * is that "mmm" is much wider then "iiii", but the latter is a longer 20548 20549 * string - thus the calculation can go wrong (doing it properly and putting 20550 20551 * it into an DOM object and measuring that is horribly(!) slow). Thus as 20552 20553 * a "work around" we provide this option. It will append its value to the 20554 20555 * text that is found to be the longest string for the column - i.e. padding. 20556 20557 * Generally you shouldn't need this, and it is not documented on the 20558 20559 * general DataTables.net documentation 20560 20561 * @type string 20562 20563 * @default <i>Empty string<i> 20564 20565 * @dtopt Columns 20566 20567 * 20568 20569 * @example 20570 20571 * // Using aoColumns 20572 20573 * $(document).ready( function() { 20574 20575 * $('#example').dataTable( { 20576 20577 * "aoColumns": [ 20578 20579 * null, 20580 20581 * null, 20582 20583 * null, 20584 20585 * { 20586 20587 * "sContentPadding": "mmm" 20588 20589 * } 20590 20591 * ] 20592 20593 * } ); 20594 20595 * } ); 20596 20597 */ 20598 20599 "sContentPadding": "", 20600 20601 20602 20603 20604 20605 /** 20606 20607 * Allows a default value to be given for a column's data, and will be used 20608 20609 * whenever a null data source is encountered (this can be because mData 20610 20611 * is set to null, or because the data source itself is null). 20612 20613 * @type string 20614 20615 * @default null 20616 20617 * @dtopt Columns 20618 20619 * 20620 20621 * @example 20622 20623 * // Using aoColumnDefs 20624 20625 * $(document).ready( function() { 20626 20627 * $('#example').dataTable( { 20628 20629 * "aoColumnDefs": [ 20630 20631 * { 20632 20633 * "mData": null, 20634 20635 * "sDefaultContent": "Edit", 20636 20637 * "aTargets": [ -1 ] 20638 20639 * } 20640 20641 * ] 20642 20643 * } ); 20644 20645 * } ); 20646 20647 * 20648 20649 * @example 20650 20651 * // Using aoColumns 20652 20653 * $(document).ready( function() { 20654 20655 * $('#example').dataTable( { 20656 20657 * "aoColumns": [ 20658 20659 * null, 20660 20661 * null, 20662 20663 * null, 20664 20665 * { 20666 20667 * "mData": null, 20668 20669 * "sDefaultContent": "Edit" 20670 20671 * } 20672 20673 * ] 20674 20675 * } ); 20676 20677 * } ); 20678 20679 */ 20680 20681 "sDefaultContent": null, 20682 20683 20684 20685 20686 20687 /** 20688 20689 * This parameter is only used in DataTables' server-side processing. It can 20690 20691 * be exceptionally useful to know what columns are being displayed on the 20692 20693 * client side, and to map these to database fields. When defined, the names 20694 20695 * also allow DataTables to reorder information from the server if it comes 20696 20697 * back in an unexpected order (i.e. if you switch your columns around on the 20698 20699 * client-side, your server-side code does not also need updating). 20700 20701 * @type string 20702 20703 * @default <i>Empty string</i> 20704 20705 * @dtopt Columns 20706 20707 * 20708 20709 * @example 20710 20711 * // Using aoColumnDefs 20712 20713 * $(document).ready( function() { 20714 20715 * $('#example').dataTable( { 20716 20717 * "aoColumnDefs": [ 20718 20719 * { "sName": "engine", "aTargets": [ 0 ] }, 20720 20721 * { "sName": "browser", "aTargets": [ 1 ] }, 20722 20723 * { "sName": "platform", "aTargets": [ 2 ] }, 20724 20725 * { "sName": "version", "aTargets": [ 3 ] }, 20726 20727 * { "sName": "grade", "aTargets": [ 4 ] } 20728 20729 * ] 20730 20731 * } ); 20732 20733 * } ); 20734 20735 * 20736 20737 * @example 20738 20739 * // Using aoColumns 20740 20741 * $(document).ready( function() { 20742 20743 * $('#example').dataTable( { 20744 20745 * "aoColumns": [ 20746 20747 * { "sName": "engine" }, 20748 20749 * { "sName": "browser" }, 20750 20751 * { "sName": "platform" }, 20752 20753 * { "sName": "version" }, 20754 20755 * { "sName": "grade" } 20756 20757 * ] 20758 20759 * } ); 20760 20761 * } ); 20762 20763 */ 20764 20765 "sName": "", 20766 20767 20768 20769 20770 20771 /** 20772 20773 * Defines a data source type for the sorting which can be used to read 20774 20775 * real-time information from the table (updating the internally cached 20776 20777 * version) prior to sorting. This allows sorting to occur on user editable 20778 20779 * elements such as form inputs. 20780 20781 * @type string 20782 20783 * @default std 20784 20785 * @dtopt Columns 20786 20787 * 20788 20789 * @example 20790 20791 * // Using aoColumnDefs 20792 20793 * $(document).ready( function() { 20794 20795 * $('#example').dataTable( { 20796 20797 * "aoColumnDefs": [ 20798 20799 * { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] }, 20800 20801 * { "sType": "numeric", "aTargets": [ 3 ] }, 20802 20803 * { "sSortDataType": "dom-select", "aTargets": [ 4 ] }, 20804 20805 * { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] } 20806 20807 * ] 20808 20809 * } ); 20810 20811 * } ); 20812 20813 * 20814 20815 * @example 20816 20817 * // Using aoColumns 20818 20819 * $(document).ready( function() { 20820 20821 * $('#example').dataTable( { 20822 20823 * "aoColumns": [ 20824 20825 * null, 20826 20827 * null, 20828 20829 * { "sSortDataType": "dom-text" }, 20830 20831 * { "sSortDataType": "dom-text", "sType": "numeric" }, 20832 20833 * { "sSortDataType": "dom-select" }, 20834 20835 * { "sSortDataType": "dom-checkbox" } 20836 20837 * ] 20838 20839 * } ); 20840 20841 * } ); 20842 20843 */ 20844 20845 "sSortDataType": "std", 20846 20847 20848 20849 20850 20851 /** 20852 20853 * The title of this column. 20854 20855 * @type string 20856 20857 * @default null <i>Derived from the 'TH' value for this column in the 20858 20859 * original HTML table.</i> 20860 20861 * @dtopt Columns 20862 20863 * 20864 20865 * @example 20866 20867 * // Using aoColumnDefs 20868 20869 * $(document).ready( function() { 20870 20871 * $('#example').dataTable( { 20872 20873 * "aoColumnDefs": [ 20874 20875 * { "sTitle": "My column title", "aTargets": [ 0 ] } 20876 20877 * ] 20878 20879 * } ); 20880 20881 * } ); 20882 20883 * 20884 20885 * @example 20886 20887 * // Using aoColumns 20888 20889 * $(document).ready( function() { 20890 20891 * $('#example').dataTable( { 20892 20893 * "aoColumns": [ 20894 20895 * { "sTitle": "My column title" }, 20896 20897 * null, 20898 20899 * null, 20900 20901 * null, 20902 20903 * null 20904 20905 * ] 20906 20907 * } ); 20908 20909 * } ); 20910 20911 */ 20912 20913 "sTitle": null, 20914 20915 20916 20917 20918 20919 /** 20920 20921 * The type allows you to specify how the data for this column will be sorted. 20922 20923 * Four types (string, numeric, date and html (which will strip HTML tags 20924 20925 * before sorting)) are currently available. Note that only date formats 20926 20927
20927 * understood by Javascript's Date() object will be accepted as type date. For 20928 20929 * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric', 20930 20931 * 'date' or 'html' (by default). Further types can be adding through 20932 20933 * plug-ins. 20934 20935 * @type string 20936 20937 * @default null <i>Auto-detected from raw data</i> 20938 20939 * @dtopt Columns 20940 20941 * 20942 20943 * @example 20944 20945 * // Using aoColumnDefs 20946 20947 * $(document).ready( function() { 20948 20949 * $('#example').dataTable( { 20950 20951 * "aoColumnDefs": [ 20952 20953 * { "sType": "html", "aTargets": [ 0 ] } 20954 20955 * ] 20956 20957 * } ); 20958 20959 * } ); 20960 20961 * 20962 20963 * @example 20964 20965 * // Using aoColumns 20966 20967 * $(document).ready( function() { 20968 20969 * $('#example').dataTable( { 20970 20971 * "aoColumns": [ 20972 20973 * { "sType": "html" }, 20974 20975 * null, 20976 20977 * null, 20978 20979 * null, 20980 20981 * null 20982 20983 * ] 20984 20985 * } ); 20986 20987 * } ); 20988 20989 */ 20990 20991 "sType": null, 20992 20993 20994 20995 20996 20997 /** 20998 20999 * Defining the width of the column, this parameter may take any CSS value 21000 21001 * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not 21002 21003 * been given a specific width through this interface ensuring that the table 21004 21005 * remains readable. 21006 21007 * @type string 21008 21009 * @default null <i>Automatic</i> 21010 21011 * @dtopt Columns 21012 21013 * 21014 21015 * @example 21016 21017 * // Using aoColumnDefs 21018 21019 * $(document).ready( function() { 21020 21021 * $('#example').dataTable( { 21022 21023 * "aoColumnDefs": [ 21024 21025 * { "sWidth": "20%", "aTargets": [ 0 ] } 21026 21027 * ] 21028 21029 * } ); 21030 21031 * } ); 21032 21033 * 21034 21035 * @example 21036 21037 * // Using aoColumns 21038 21039 * $(document).ready( function() { 21040 21041 * $('#example').dataTable( { 21042 21043 * "aoColumns": [ 21044 21045 * { "sWidth": "20%" }, 21046 21047 * null, 21048 21049 * null, 21050 21051 * null, 21052 21053 * null 21054 21055 * ] 21056 21057 * } ); 21058 21059 * } ); 21060 21061 */ 21062 21063 "sWidth": null 21064 21065 }; 21066 21067 21068 21069 21070 21071 21072 21073 /** 21074 21075 * DataTables settings object - this holds all the information needed for a 21076 21077 * given table, including configuration, data and current application of the 21078 21079 * table options. DataTables does not have a single instance for each DataTable 21080 21081 * with the settings attached to that instance, but rather instances of the 21082 21083 * DataTable "class" are created on-the-fly as needed (typically by a 21084 21085 * $().dataTable() call) and the settings object is then applied to that 21086 21087 * instance. 21088 21089 * 21090 21091 * Note that this object is related to {@link DataTable.defaults} but this 21092 21093 * one is the internal data store for DataTables's cache of columns. It should 21094 21095 * NOT be manipulated outside of DataTables. Any configuration should be done 21096 21097 * through the initialisation options. 21098 21099 * @namespace 21100 21101 * @todo Really should attach the settings object to individual instances so we 21102 21103 * don't need to create new instances on each $().dataTable() call (if the 21104 21105 * table already exists). It would also save passing oSettings around and 21106 21107 * into every single function. However, this is a very significant 21108 21109 * architecture change for DataTables and will almost certainly break 21110 21111 * backwards compatibility with older installations. This is something that 21112 21113 * will be done in 2.0. 21114 21115 */ 21116 21117 DataTable.models.oSettings = { 21118 21119 /** 21120 21121 * Primary features of DataTables and their enablement state. 21122 21123 * @namespace 21124 21125 */ 21126 21127 "oFeatures": { 21128 21129 21130 21131 /** 21132 21133 * Flag to say if DataTables should automatically try to calculate the 21134 21135 * optimum table and columns widths (true) or not (false). 21136 21137 * Note that this parameter will be set by the initialisation routine. To 21138 21139 * set a default use {@link DataTable.defaults}. 21140 21141 * @type boolean 21142 21143 */ 21144 21145 "bAutoWidth": null, 21146 21147 21148 21149 /** 21150 21151 * Delay the creation of TR and TD elements until they are actually 21152 21153 * needed by a driven page draw. This can give a significant speed 21154 21155 * increase for Ajax source and Javascript source data, but makes no 21156 21157 * difference at all fro DOM and server-side processing tables. 21158 21159 * Note that this parameter will be set by the initialisation routine. To 21160 21161 * set a default use {@link DataTable.defaults}. 21162 21163 * @type boolean 21164 21165 */ 21166 21167 "bDeferRender": null, 21168 21169 21170 21171 /** 21172 21173 * Enable filtering on the table or not. Note that if this is disabled 21174 21175 * then there is no filtering at all on the table, including fnFilter. 21176 21177 * To just remove the filtering input use sDom and remove the 'f' option. 21178 21179 * Note that this parameter will be set by the initialisation routine. To 21180 21181 * set a default use {@link DataTable.defaults}. 21182 21183 * @type boolean 21184 21185 */ 21186 21187 "bFilter": null, 21188 21189 21190 21191 /** 21192 21193 * Table information element (the 'Showing x of y records' div) enable 21194 21195 * flag. 21196 21197 * Note that this parameter will be set by the initialisation routine. To 21198 21199 * set a default use {@link DataTable.defaults}. 21200 21201 * @type boolean 21202 21203 */ 21204 21205 "bInfo": null, 21206 21207 21208 21209 /** 21210 21211 * Present a user control allowing the end user to change the page size 21212 21213 * when pagination is enabled. 21214 21215 * Note that this parameter will be set by the initialisation routine. To 21216 21217 * set a default use {@link DataTable.defaults}. 21218 21219 * @type boolean 21220 21221 */ 21222 21223 "bLengthChange": null, 21224 21225 21226 21227 /** 21228 21229 * Pagination enabled or not. Note that if this is disabled then length 21230 21231 * changing must also be disabled. 21232 21233 * Note that this parameter will be set by the initialisation routine. To 21234 21235 * set a default use {@link DataTable.defaults}. 21236 21237 * @type boolean 21238 21239 */ 21240 21241 "bPaginate": null, 21242 21243 21244 21245 /** 21246 21247 * Processing indicator enable flag whenever DataTables is enacting a 21248 21249 * user request - typically an Ajax request for server-side processing. 21250 21251 * Note that this parameter will be set by the initialisation routine. To 21252 21253 * set a default use {@link DataTable.defaults}. 21254 21255 * @type boolean 21256 21257 */ 21258 21259 "bProcessing": null, 21260 21261 21262 21263 /** 21264 21265 * Server-side processing enabled flag - when enabled DataTables will 21266 21267 * get all data from the server for every draw - there is no filtering, 21268 21269 * sorting or paging done on the client-side. 21270 21271 * Note that this parameter will be set by the initialisation routine. To 21272 21273 * set a default use {@link DataTable.defaults}. 21274 21275 * @type boolean 21276 21277 */ 21278 21279 "bServerSide": null, 21280 21281 21282 21283 /** 21284 21285 * Sorting enablement flag. 21286 21287 * Note that this parameter will be set by the initialisation routine. To 21288 21289 * set a default use {@link DataTable.defaults}. 21290 21291 * @type boolean 21292 21293 */ 21294 21295 "bSort": null, 21296 21297 21298 21299 /** 21300 21301 * Apply a class to the columns which are being sorted to provide a 21302 21303 * visual highlight or not. This can slow things down when enabled since 21304 21305 * there is a lot of DOM interaction. 21306 21307 * Note that this parameter will be set by the initialisation routine. To 21308 21309 * set a default use {@link DataTable.defaults}. 21310 21311 * @type boolean 21312 21313 */ 21314 21315 "bSortClasses": null, 21316 21317 21318 21319 /** 21320 21321 * State saving enablement flag. 21322 21323 * Note that this parameter will be set by the initialisation routine. To 21324 21325 * set a default use {@link DataTable.defaults}. 21326 21327 * @type boolean 21328 21329 */ 21330 21331 "bStateSave": null 21332 21333 }, 21334 21335 21336 21337 21338 21339 /** 21340 21341 * Scrolling settings for a table. 21342 21343 * @namespace 21344 21345 */ 21346 21347 "oScroll": { 21348 21349 /** 21350 21351 * Indicate if DataTables should be allowed to set the padding / margin 21352 21353 * etc for the scrolling header elements or not. Typically you will want 21354 21355 * this. 21356 21357 * Note that this parameter will be set by the initialisation routine. To 21358 21359 * set a default use {@link DataTable.defaults}. 21360 21361 * @type boolean 21362 21363 */ 21364 21365 "bAutoCss": null, 21366 21367 21368 21369 /** 21370 21371 * When the table is shorter in height than sScrollY, collapse the 21372 21373 * table container down to the height of the table (when true). 21374 21375 * Note that this parameter will be set by the initialisation routine. To 21376 21377 * set a default use {@link DataTable.defaults}. 21378 21379 * @type boolean 21380 21381 */ 21382 21383 "bCollapse": null, 21384 21385 21386 21387 /** 21388
21389 * Infinite scrolling enablement flag. Now deprecated in favour of 21390 21391 * using the Scroller plug-in. 21392 21393 * Note that this parameter will be set by the initialisation routine. To 21394 21395 * set a default use {@link DataTable.defaults}. 21396 21397 * @type boolean 21398 21399 */ 21400 21401 "bInfinite": null, 21402 21403 21404 21405 /** 21406 21407 * Width of the scrollbar for the web-browser's platform. Calculated 21408 21409 * during table initialisation. 21410 21411 * @type int 21412 21413 * @default 0 21414 21415 */ 21416 21417 "iBarWidth": 0, 21418 21419 21420 21421 /** 21422 21423 * Space (in pixels) between the bottom of the scrolling container and 21424 21425 * the bottom of the scrolling viewport before the next page is loaded 21426 21427 * when using infinite scrolling. 21428 21429 * Note that this parameter will be set by the initialisation routine. To 21430 21431 * set a default use {@link DataTable.defaults}. 21432 21433 * @type int 21434 21435 */ 21436 21437 "iLoadGap": null, 21438 21439 21440 21441 /** 21442 21443 * Viewport width for horizontal scrolling. Horizontal scrolling is 21444 21445 * disabled if an empty string. 21446 21447 * Note that this parameter will be set by the initialisation routine. To 21448 21449 * set a default use {@link DataTable.defaults}. 21450 21451 * @type string 21452 21453 */ 21454 21455 "sX": null, 21456 21457 21458 21459 /** 21460 21461 * Width to expand the table to when using x-scrolling. Typically you 21462 21463 * should not need to use this. 21464 21465 * Note that this parameter will be set by the initialisation routine. To 21466 21467 * set a default use {@link DataTable.defaults}. 21468 21469 * @type string 21470 21471 * @deprecated 21472 21473 */ 21474 21475 "sXInner": null, 21476 21477 21478 21479 /** 21480 21481 * Viewport height for vertical scrolling. Vertical scrolling is disabled 21482 21483 * if an empty string. 21484 21485 * Note that this parameter will be set by the initialisation routine. To 21486 21487 * set a default use {@link DataTable.defaults}. 21488 21489 * @type string 21490 21491 */ 21492 21493 "sY": null 21494 21495 }, 21496 21497 21498 21499 /** 21500 21501 * Language information for the table. 21502 21503 * @namespace 21504 21505 * @extends DataTable.defaults.oLanguage 21506 21507 */ 21508 21509 "oLanguage": { 21510 21511 /** 21512 21513 * Information callback function. See 21514 21515 * {@link DataTable.defaults.fnInfoCallback} 21516 21517 * @type function 21518 21519 * @default null 21520 21521 */ 21522 21523 "fnInfoCallback": null 21524 21525 }, 21526 21527 21528 21529 /** 21530 21531 * Browser support parameters 21532 21533 * @namespace 21534 21535 */ 21536 21537 "oBrowser": { 21538 21539 /** 21540 21541 * Indicate if the browser incorrectly calculates width:100% inside a 21542 21543 * scrolling element (IE6/7) 21544 21545 * @type boolean 21546 21547 * @default false 21548 21549 */ 21550 21551 "bScrollOversize": false 21552 21553 }, 21554 21555 21556 21557 /** 21558 21559 * Array referencing the nodes which are used for the features. The 21560 21561 * parameters of this object match what is allowed by sDom - i.e. 21562 21563 * <ul> 21564 21565 * <li>'l' - Length changing</li> 21566 21567 * <li>'f' - Filtering input</li> 21568 21569 * <li>'t' - The table!</li> 21570 21571 * <li>'i' - Information</li> 21572 21573 * <li>'p' - Pagination</li> 21574 21575 * <li>'r' - pRocessing</li> 21576 21577 * </ul> 21578 21579 * @type array 21580 21581 * @default [] 21582 21583 */ 21584 21585 "aanFeatures": [], 21586 21587 21588 21589 /** 21590 21591 * Store data information - see {@link DataTable.models.oRow} for detailed 21592 21593 * information. 21594 21595 * @type array 21596 21597 * @default [] 21598 21599 */ 21600 21601 "aoData": [], 21602 21603 21604 21605 /** 21606 21607 * Array of indexes which are in the current display (after filtering etc) 21608 21609 * @type array 21610 21611 * @default [] 21612 21613 */ 21614 21615 "aiDisplay": [], 21616 21617 21618 21619 /** 21620 21621 * Array of indexes for display - no filtering 21622 21623 * @type array 21624 21625 * @default [] 21626 21627 */ 21628 21629 "aiDisplayMaster": [], 21630 21631 21632 21633 /** 21634 21635 * Store information about each column that is in use 21636 21637 * @type array 21638 21639 * @default [] 21640 21641 */ 21642 21643 "aoColumns": [], 21644 21645 21646 21647 /** 21648 21649 * Store information about the table's header 21650 21651 * @type array 21652 21653 * @default [] 21654 21655 */ 21656 21657 "aoHeader": [], 21658 21659 21660 21661 /** 21662 21663 * Store information about the table's footer 21664 21665 * @type array 21666 21667 * @default [] 21668 21669 */ 21670 21671 "aoFooter": [], 21672 21673 21674 21675 /** 21676 21677 * Search data array for regular expression searching 21678 21679 * @type array 21680 21681 * @default [] 21682 21683 */ 21684 21685 "asDataSearch": [], 21686 21687 21688 21689 /** 21690 21691 * Store the applied global search information in case we want to force a 21692 21693 * research or compare the old search to a new one. 21694 21695 * Note that this parameter will be set by the initialisation routine. To 21696 21697 * set a default use {@link DataTable.defaults}. 21698 21699 * @namespace 21700 21701 * @extends DataTable.models.oSearch 21702 21703 */ 21704 21705 "oPreviousSearch": {}, 21706 21707 21708 21709 /** 21710 21711 * Store the applied search for each column - see 21712 21713 * {@link DataTable.models.oSearch} for the format that is used for the 21714 21715 * filtering information for each column. 21716 21717 * @type array 21718 21719 * @default [] 21720 21721 */ 21722 21723 "aoPreSearchCols": [], 21724 21725 21726 21727 /** 21728 21729 * Sorting that is applied to the table. Note that the inner arrays are 21730 21731 * used in the following manner: 21732 21733 * <ul> 21734 21735 * <li>Index 0 - column number</li> 21736 21737 * <li>Index 1 - current sorting direction</li> 21738 21739 * <li>Index 2 - index of asSorting for this column</li> 21740 21741 * </ul> 21742 21743 * Note that this parameter will be set by the initialisation routine. To 21744 21745 * set a default use {@link DataTable.defaults}. 21746 21747 * @type array 21748 21749 * @todo These inner arrays should really be objects 21750 21751 */ 21752 21753 "aaSorting": null, 21754 21755 21756 21757 /** 21758 21759 * Sorting that is always applied to the table (i.e. prefixed in front of 21760 21761 * aaSorting). 21762 21763 * Note that this parameter will be set by the initialisation routine. To 21764 21765 * set a default use {@link DataTable.defaults}. 21766 21767 * @type array|null 21768 21769 * @default null 21770 21771 */ 21772 21773 "aaSortingFixed": null, 21774 21775 21776 21777 /** 21778 21779 * Classes to use for the striping of a table. 21780 21781 * Note that this parameter will be set by the initialisation routine. To 21782 21783 * set a default use {@link DataTable.defaults}. 21784 21785 * @type array 21786 21787 * @default [] 21788 21789 */ 21790 21791 "asStripeClasses": null, 21792 21793 21794 21795 /** 21796 21797 * If restoring a table - we should restore its striping classes as well 21798 21799 * @type array 21800 21801 * @default [] 21802 21803 */ 21804 21805 "asDestroyStripes": [], 21806 21807 21808 21809 /** 21810 21811 * If restoring a table - we should restore its width 21812 21813 * @type int 21814 21815 * @default 0 21816 21817 */ 21818 21819 "sDestroyWidth": 0, 21820 21821 21822 21823 /** 21824 21825 * Callback functions array for every time a row is inserted (i.e. on a draw). 21826 21827 * @type array 21828 21829 * @default [] 21830 21831 */ 21832 21833 "aoRowCallback": [], 21834 21835 21836 21837 /** 21838 21839 * Callback functions for the header on each draw. 21840 21841 * @type array 21842 21843 * @default [] 21844 21845 */ 21846 21847 "aoHeaderCallback": [], 21848 21849 21850 21851 /** 21852 21853 * Callback function for the footer on each draw. 21854 21855 * @type array 21856 21857 * @default [] 21858 21859 */ 21860 21861 "aoFooterCallback": [], 21862 21863 21864 21865 /** 21866 21867 * Array of callback functions for draw callback functions 21868 21869 * @type array 21870 21871 * @default [] 21872 21873 */ 21874 21875 "aoDrawCallback": [], 21876 21877 21878 21879 /** 21880 21881 * Array of callback functions for row created function 21882 21883 * @type array 21884 21885 * @default [] 21886 21887 */ 21888 21889 "aoRowCreatedCallback": [], 21890 21891 21892 21893 /** 21894 21895 * Callback functions for just before the table is redrawn. A return of 21896 21897 * false will be used to cancel the draw. 21898 21899 * @type array 21900 21901 * @default [] 21902 21903 */ 21904 21905 "aoPreDrawCallback": [], 21906 21907 21908 21909 /** 21910 21911 * Callback functions for when the table has been initialised. 21912 21913 * @type array 21914 21915 * @default [] 21916 21917 */ 21918 21919 "aoInitComplete": [], 21920 21921 21922 21923 21924 21925 /** 21926 21927 * Callbacks for modifying the settings to be stored for state saving, prior to 21928 21929 * saving state. 21930 21931 * @type array 21932 21933 * @default [] 21934 21935 */ 21936 21937 "aoStateSaveParams": [], 21938 21939 21940 21941 /** 21942 21943 * Callbacks for modifying the settings that have been stored for state saving 21944 21945 * prior to using the stored values to restore the state. 21946 21947 * @type array 21948 21949 * @default [] 21950 21951 */ 21952 21953 "aoStateLoadParams": [], 21954 21955 21956 21957 /** 21958 21959 * Callbacks for operating on the settings object once the saved state has been 21960 21961 * loaded 21962 21963 * @type array 21964 21965 * @default [] 21966 21967 */ 21968 21969 "aoStateLoaded": [], 21970 21971 21972 21973 /** 21974 21975 * Cache the table ID for quick access 21976 21977 * @type string 21978 21979 * @default <i>Empty string</i> 21980 21981 */ 21982 21983 "sTableId": "", 21984 21985 21986 21987 /** 21988 21989 * The TABLE node for the main table 21990 21991 * @type node 21992 21993 * @default null 21994 21995 */ 21996 21997 "nTable": null, 21998 21999 22000 22001 /** 22002 22003 * Permanent ref to the thead element 22004 22005 * @type node 22006 22007 * @default null 22008 22009 */ 22010 22011 "nTHead": null, 22012 22013 22014 22015 /** 22016 22017 * Permanent ref to the tfoot element - if it exists 22018 22019 * @type node 22020 22021 * @default null 22022 22023 */ 22024 22025 "nTFoot": null, 22026 22027 22028 22029 /** 22030 22031 * Permanent ref to the tbody element 22032 22033 * @type node 22034 22035 * @default null 22036 22037 */ 22038 22039 "nTBody": null, 22040 22041 22042 22043 /** 22044 22045 * Cache the wrapper node (contains all DataTables controlled elements) 22046 22047 * @type node 22048 22049 * @default null 22050 22051 */ 22052 22053 "nTableWrapper": null, 22054 22055 22056 22057 /** 22058 22059 * Indicate if when using server-side processing the loading of data 22060 22061 * should be deferred until the second draw. 22062 22063 * Note that this parameter will be set by the initialisation routine. To 22064 22065 * set a default use {@link DataTable.defaults}. 22066 22067 * @type boolean 22068 22069 * @default false 22070 22071 */ 22072 22073 "bDeferLoading": false, 22074 22075 22076 22077 /** 22078 22079 * Indicate if all required information has been read in 22080 22081 * @type boolean 22082 22083 * @default false 22084 22085 */ 22086 22087 "bInitialised": false, 22088 22089 22090 22091 /** 22092 22093 * Information about open rows. Each object in the array has the parameters 22094 22095 * 'nTr' and 'nParent' 22096 22097 * @type array 22098 22099 * @default [] 22100 22101 */ 22102 22103 "aoOpenRows": [], 22104 22105 22106 22107 /** 22108
22109 * Dictate the positioning of DataTables' control elements - see 22110 22111 * {@link DataTable.model.oInit.sDom}. 22112 22113 * Note that this parameter will be set by the initialisation routine. To 22114 22115 * set a default use {@link DataTable.defaults}. 22116 22117 * @type string 22118 22119 * @default null 22120 22121 */ 22122 22123 "sDom": null, 22124 22125 22126 22127 /** 22128 22129 * Which type of pagination should be used. 22130 22131 * Note that this parameter will be set by the initialisation routine. To 22132 22133 * set a default use {@link DataTable.defaults}. 22134 22135 * @type string 22136 22137 * @default two_button 22138 22139 */ 22140 22141 "sPaginationType": "two_button", 22142 22143 22144 22145 /** 22146 22147 * The cookie duration (for bStateSave) in seconds. 22148 22149 * Note that this parameter will be set by the initialisation routine. To 22150 22151 * set a default use {@link DataTable.defaults}. 22152 22153 * @type int 22154 22155 * @default 0 22156 22157 */ 22158 22159 "iCookieDuration": 0, 22160 22161 22162 22163 /** 22164 22165 * The cookie name prefix. 22166 22167 * Note that this parameter will be set by the initialisation routine. To 22168 22169 * set a default use {@link DataTable.defaults}. 22170 22171 * @type string 22172 22173 * @default <i>Empty string</i> 22174 22175 */ 22176 22177 "sCookiePrefix": "", 22178 22179 22180 22181 /** 22182 22183 * Callback function for cookie creation. 22184 22185 * Note that this parameter will be set by the initialisation routine. To 22186 22187 * set a default use {@link DataTable.defaults}. 22188 22189 * @type function 22190 22191 * @default null 22192 22193 */ 22194 22195 "fnCookieCallback": null, 22196 22197 22198 22199 /** 22200 22201 * Array of callback functions for state saving. Each array element is an 22202 22203 * object with the following parameters: 22204 22205 * <ul> 22206 22207 * <li>function:fn - function to call. Takes two parameters, oSettings 22208 22209 * and the JSON string to save that has been thus far created. Returns 22210 22211 * a JSON string to be inserted into a json object 22212 22213 * (i.e. '"param": [ 0, 1, 2]')</li> 22214 22215 * <li>string:sName - name of callback</li> 22216 22217 * </ul> 22218 22219 * @type array 22220 22221 * @default [] 22222 22223 */ 22224 22225 "aoStateSave": [], 22226 22227 22228 22229 /** 22230 22231 * Array of callback functions for state loading. Each array element is an 22232 22233 * object with the following parameters: 22234 22235 * <ul> 22236 22237 * <li>function:fn - function to call. Takes two parameters, oSettings 22238 22239 * and the object stored. May return false to cancel state loading</li> 22240 22241 * <li>string:sName - name of callback</li> 22242 22243 * </ul> 22244 22245 * @type array 22246 22247 * @default [] 22248 22249 */ 22250 22251 "aoStateLoad": [], 22252 22253 22254 22255 /** 22256 22257 * State that was loaded from the cookie. Useful for back reference 22258 22259 * @type object 22260 22261 * @default null 22262 22263 */ 22264 22265 "oLoadedState": null, 22266 22267 22268 22269 /** 22270 22271 * Source url for AJAX data for the table. 22272 22273 * Note that this parameter will be set by the initialisation routine. To 22274 22275 * set a default use {@link DataTable.defaults}. 22276 22277 * @type string 22278 22279 * @default null 22280 22281 */ 22282 22283 "sAjaxSource": null, 22284 22285 22286 22287 /** 22288 22289 * Property from a given object from which to read the table data from. This 22290 22291 * can be an empty string (when not server-side processing), in which case 22292 22293 * it is assumed an an array is given directly. 22294 22295 * Note that this parameter will be set by the initialisation routine. To 22296 22297 * set a default use {@link DataTable.defaults}. 22298 22299 * @type string 22300 22301 */ 22302 22303 "sAjaxDataProp": null, 22304 22305 22306 22307 /** 22308 22309 * Note if draw should be blocked while getting data 22310 22311 * @type boolean 22312 22313 * @default true 22314 22315 */ 22316 22317 "bAjaxDataGet": true, 22318 22319 22320 22321 /** 22322 22323 * The last jQuery XHR object that was used for server-side data gathering. 22324 22325 * This can be used for working with the XHR information in one of the 22326 22327 * callbacks 22328 22329 * @type object 22330 22331 * @default null 22332 22333 */ 22334 22335 "jqXHR": null, 22336 22337 22338 22339 /** 22340 22341 * Function to get the server-side data. 22342 22343 * Note that this parameter will be set by the initialisation routine. To 22344 22345 * set a default use {@link DataTable.defaults}. 22346 22347 * @type function 22348 22349 */ 22350 22351 "fnServerData": null, 22352 22353 22354 22355 /** 22356 22357 * Functions which are called prior to sending an Ajax request so extra 22358 22359 * parameters can easily be sent to the server 22360 22361 * @type array 22362 22363 * @default [] 22364 22365 */ 22366 22367 "aoServerParams": [], 22368 22369 22370 22371 /** 22372 22373 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 22374 22375 * required). 22376 22377 * Note that this parameter will be set by the initialisation routine. To 22378 22379 * set a default use {@link DataTable.defaults}. 22380 22381 * @type string 22382 22383 */ 22384 22385 "sServerMethod": null, 22386 22387 22388 22389 /** 22390 22391 * Format numbers for display. 22392 22393 * Note that this parameter will be set by the initialisation routine. To 22394 22395 * set a default use {@link DataTable.defaults}. 22396 22397 * @type function 22398 22399 */ 22400 22401 "fnFormatNumber": null, 22402 22403 22404 22405 /** 22406 22407 * List of options that can be used for the user selectable length menu. 22408 22409 * Note that this parameter will be set by the initialisation routine. To 22410 22411 * set a default use {@link DataTable.defaults}. 22412 22413 * @type array 22414 22415 * @default [] 22416 22417 */ 22418 22419 "aLengthMenu": null, 22420 22421 22422 22423 /** 22424 22425 * Counter for the draws that the table does. Also used as a tracker for 22426 22427 * server-side processing 22428 22429 * @type int 22430 22431 * @default 0 22432 22433 */ 22434 22435 "iDraw": 0, 22436 22437 22438 22439 /** 22440 22441 * Indicate if a redraw is being done - useful for Ajax 22442 22443 * @type boolean 22444 22445 * @default false 22446 22447 */ 22448 22449 "bDrawing": false, 22450 22451 22452 22453 /** 22454 22455 * Draw index (iDraw) of the last error when parsing the returned data 22456 22457 * @type int 22458 22459 * @default -1 22460 22461 */ 22462 22463 "iDrawError": -1, 22464 22465 22466 22467 /** 22468 22469 * Paging display length 22470 22471 * @type int 22472 22473 * @default 10 22474 22475 */ 22476 22477 "_iDisplayLength": 10, 22478 22479 22480 22481 /** 22482 22483 * Paging start point - aiDisplay index 22484 22485 * @type int 22486 22487 * @default 0 22488 22489 */ 22490 22491 "_iDisplayStart": 0, 22492 22493 22494 22495 /** 22496 22497 * Paging end point - aiDisplay index. Use fnDisplayEnd rather than 22498 22499 * this property to get the end point 22500 22501 * @type int 22502 22503 * @default 10 22504 22505 * @private 22506 22507 */ 22508 22509 "_iDisplayEnd": 10, 22510 22511 22512 22513 /** 22514 22515 * Server-side processing - number of records in the result set 22516 22517 * (i.e. before filtering), Use fnRecordsTotal rather than 22518 22519 * this property to get the value of the number of records, regardless of 22520 22521 * the server-side processing setting. 22522 22523 * @type int 22524 22525 * @default 0 22526 22527 * @private 22528 22529 */ 22530 22531 "_iRecordsTotal": 0, 22532 22533 22534 22535 /** 22536 22537 * Server-side processing - number of records in the current display set 22538 22539 * (i.e. after filtering). Use fnRecordsDisplay rather than 22540 22541 * this property to get the value of the number of records, regardless of 22542 22543 * the server-side processing setting. 22544 22545 * @type boolean 22546 22547 * @default 0 22548 22549 * @private 22550 22551 */ 22552 22553 "_iRecordsDisplay": 0, 22554 22555 22556 22557 /** 22558 22559 * Flag to indicate if jQuery UI marking and classes should be used. 22560 22561 * Note that this parameter will be set by the initialisation routine. To 22562 22563 * set a default use {@link DataTable.defaults}. 22564 22565 * @type boolean 22566 22567 */ 22568 22569 "bJUI": null, 22570 22571 22572 22573 /** 22574 22575 * The classes to use for the table 22576 22577 * @type object 22578 22579 * @default {} 22580 22581 */ 22582
22583 "oClasses": {}, 22584 22585 22586 22587 /** 22588 22589 * Flag attached to the settings object so you can check in the draw 22590 22591 * callback if filtering has been done in the draw. Deprecated in favour of 22592 22593 * Businesses. 22594 22595 * @type boolean 22596 22597 * @default false 22598 22599 * @deprecated 22600 22601 */ 22602 22603 "bFiltered": false, 22604 22605 22606 22607 /** 22608 22609 * Flag attached to the settings object so you can check in the draw 22610 22611 * callback if sorting has been done in the draw. Deprecated in favour of 22612 22613 * Businesses. 22614 22615 * @type boolean 22616 22617 * @default false 22618 22619 * @deprecated 22620 22621 */ 22622 22623 "bSorted": false, 22624 22625 22626 22627 /** 22628 22629 * Indicate that if multiple rows are in the header and there is more than 22630 22631 * one unique cell per column, if the top one (true) or bottom one (false) 22632 22633 * should be used for sorting / title by DataTables. 22634 22635 * Note that this parameter will be set by the initialisation routine. To 22636 22637 * set a default use {@link DataTable.defaults}. 22638 22639 * @type boolean 22640 22641 */ 22642 22643 "bSortCellsTop": null, 22644 22645 22646 22647 /** 22648 22649 * Initialisation object that is used for the table 22650 22651 * @type object 22652 22653 * @default null 22654 22655 */ 22656 22657 "oInit": null, 22658 22659 22660 22661 /** 22662 22663 * Destroy callback functions - for plug-ins to attach themselves to the 22664 22665 * destroy so they can clean up markup and Businesses. 22666 22667 * @type array 22668 22669 * @default [] 22670 22671 */ 22672 22673 "aoDestroyCallback": [], 22674 22675 22676 22677 22678 22679 /** 22680 22681 * Get the number of records in the current record set, before filtering 22682 22683 * @type function 22684 22685 */ 22686 22687 "fnRecordsTotal": function () 22688 22689 { 22690 22691 if ( this.oFeatures.bServerSide ) { 22692 22693 return parseInt(this._iRecordsTotal, 10); 22694 22695 } else { 22696 22697 return this.aiDisplayMaster.length; 22698 22699 } 22700 22701 }, 22702 22703 22704 22705 /** 22706 22707 * Get the number of records in the current record set, after filtering 22708 22709 * @type function 22710 22711 */ 22712 22713 "fnRecordsDisplay": function () 22714 22715 { 22716 22717 if ( this.oFeatures.bServerSide ) { 22718 22719 return parseInt(this._iRecordsDisplay, 10); 22720 22721 } else { 22722 22723 return this.aiDisplay.length; 22724 22725 } 22726 22727 }, 22728 22729 22730 22731 /** 22732 22733 * Set the display end point - aiDisplay index 22734 22735 * @type function 22736 22737 * @todo Should do away with _iDisplayEnd and calculate it on-the-fly here 22738 22739 */ 22740 22741 "fnDisplayEnd": function () 22742 22743 { 22744 22745 if ( this.oFeatures.bServerSide ) { 22746 22747 if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) { 22748 22749 return this._iDisplayStart+this.aiDisplay.length; 22750 22751 } else { 22752 22753 return Math.min( this._iDisplayStart+this._iDisplayLength, 22754 22755 this._iRecordsDisplay ); 22756 22757 } 22758 22759 } else { 22760 22761 return this._iDisplayEnd;
22762 22763 } 22764 22765 }, 22766 22767 22768 22769 /** 22770 22771 * The DataTables object for this table 22772 22773 * @type object 22774 22775 * @default null 22776 22777 */ 22778 22779 "oInstance": null, 22780 22781 22782 22783 /** 22784 22785 * Unique identifier for each instance of the DataTables object. If there 22786 22787 * is an ID on the table node, then it takes that value, otherwise an 22788 22789 * incrementing internal counter is used. 22790 22791 * @type string 22792 22793 * @default null 22794 22795 */ 22796 22797 "sInstance": null, 22798 22799 22800 22801 /** 22802 22803 * tabindex attribute value that is added to DataTables control elements, allowing 22804 22805 * keyboard navigation of the table and its controls. 22806 22807 */ 22808 22809 "iTabIndex": 0, 22810 22811 22812 22813 /** 22814 22815 * DIV container for the footer scrolling table if scrolling 22816 22817 */ 22818 22819 "nScrollHead": null, 22820 22821 22822 22823 /** 22824 22825 * DIV container for the footer scrolling table if scrolling 22826 22827 */ 22828 22829 "nScrollFoot": null 22830 22831 }; 22832 22833 22834 22835 /** 22836 22837 * Extension object for DataTables that is used to provide all extension options. 22838 22839 * 22840 22841 * Note that the <i>DataTable.ext</i> object is available through 22842 22843 * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is 22844 22845 * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons. 22846 22847 * @namespace 22848 22849 * @extends DataTable.models.ext 22850 22851 */ 22852 22853 DataTable.ext = $.extend( true, {}, DataTable.models.ext ); 22854 22855 22856 22857 $.extend( DataTable.ext.oStdClasses, { 22858 22859 "sTable": "dataTable", 22860 22861 22862 22863 /* Two buttons buttons */ 22864 22865 "sPagePrevEnabled": "paginate_enabled_previous", 22866 22867 "sPagePrevDisabled": "paginate_disabled_previous", 22868 22869 "sPageNextEnabled": "paginate_enabled_next", 22870 22871 "sPageNextDisabled": "paginate_disabled_next", 22872 22873 "sPageJUINext": "", 22874 22875 "sPageJUIPrev": "", 22876 22877 22878 22879 /* Full numbers paging buttons */ 22880 22881 "sPageButton": "paginate_button", 22882 22883 "sPageButtonActive": "paginate_active", 22884 22885 "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled", 22886 22887 "sPageFirst": "first", 22888 22889 "sPagePrevious": "previous", 22890 22891 "sPageNext": "next", 22892 22893 "sPageLast": "last", 22894 22895 22896 22897 /* Striping classes */ 22898 22899 "sStripeOdd": "odd", 22900 22901 "sStripeEven": "even", 22902 22903 22904 22905 /* Empty row */ 22906 22907 "sRowEmpty": "dataTables_empty", 22908 22909 22910 22911 /* Features */ 22912 22913 "sWrapper": "dataTables_wrapper", 22914 22915 "sFilter": "dataTables_filter", 22916 22917 "sInfo": "dataTables_info", 22918 22919 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 22920 22921 "sLength": "dataTables_length", 22922 22923 "sProcessing": "dataTables_processing", 22924 22925 22926 22927 /* Sorting */ 22928 22929 "sSortAsc": "sorting_asc", 22930 22931 "sSortDesc": "sorting_desc", 22932 22933 "sSortable": "sorting", /* Sortable in both directions */ 22934 22935 "sSortableAsc": "sorting_asc_disabled", 22936 22937 "sSortableDesc": "sorting_desc_disabled", 22938 22939 "sSortableNone": "sorting_disabled", 22940 22941 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 22942 22943 "sSortJUIAsc": "", 22944 22945 "sSortJUIDesc": "", 22946 22947 "sSortJUI": "", 22948 22949 "sSortJUIAscAllowed": "", 22950 22951 "sSortJUIDescAllowed": "", 22952 22953 "sSortJUIWrapper": "", 22954 22955 "sSortIcon": "", 22956 22957 22958 22959 /* Scrolling */ 22960 22961 "sScrollWrapper": "dataTables_scroll", 22962 22963 "sScrollHead": "dataTables_scrollHead", 22964 22965 "sScrollHeadInner": "dataTables_scrollHeadInner", 22966 22967 "sScrollBody": "dataTables_scrollBody", 22968 22969 "sScrollFoot": "dataTables_scrollFoot", 22970 22971 "sScrollFootInner": "dataTables_scrollFootInner", 22972 22973 22974 22975 /* Misc */ 22976 22977 "sFooterTH": "", 22978 22979 "sJUIHeader": "", 22980 22981 "sJUIFooter": "" 22982 22983 } ); 22984 22985 22986 22987 22988 22989 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, { 22990 22991 /* Two buttons buttons */ 22992 22993 "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left", 22994 22995 "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled", 22996 22997 "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right", 22998 22999 "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled", 23000 23001 "sPageJUINext": "ui-icon ui-icon-circle-arrow-e", 23002 23003 "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w", 23004 23005 23006 23007 /* Full numbers paging buttons */ 23008 23009 "sPageButton": "fg-button ui-button ui-state-default", 23010 23011 "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled", 23012 23013 "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled", 23014 23015 "sPageFirst": "first ui-corner-tl ui-corner-bl", 23016 23017 "sPageLast": "last ui-corner-tr ui-corner-br", 23018 23019 23020 23021 /* Features */ 23022 23023 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ 23024 23025 "ui-buttonset-multi paging_", /* Note that the type is postfixed */ 23026 23027 23028 23029 /* Sorting */ 23030 23031 "sSortAsc": "ui-state-default", 23032 23033 "sSortDesc": "ui-state-default", 23034 23035 "sSortable": "ui-state-default", 23036 23037 "sSortableAsc": "ui-state-default", 23038 23039 "sSortableDesc": "ui-state-default", 23040 23041 "sSortableNone": "ui-state-default", 23042 23043 "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n", 23044 23045 "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s", 23046 23047 "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s", 23048 23049 "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n", 23050 23051 "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s", 23052 23053 "sSortJUIWrapper": "DataTables_sort_wrapper", 23054 23055 "sSortIcon": "DataTables_sort_icon", 23056 23057 23058 23059 /* Scrolling */ 23060 23061 "sScrollHead": "dataTables_scrollHead ui-state-default", 23062 23063 "sScrollFoot": "dataTables_scrollFoot ui-state-default", 23064 23065 23066 23067 /* Misc */ 23068 23069 "sFooterTH": "ui-state-default", 23070 23071 "sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix", 23072 23073 "sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix" 23074 23075 } ); 23076 23077 23078 23079 /* 23080 23081 * Variable: oPagination 23082 23083 * Purpose: 23084 23085 * Scope: jQuery.fn.dataTableExt 23086 23087 */ 23088 23089 $.extend( DataTable.ext.oPagination, { 23090 23091 /* 23092 23093 * Variable: two_button 23094 23095 * Purpose: Standard two button (forward/back) pagination 23096 23097 * Scope: jQuery.fn.dataTableExt.oPagination 23098 23099 */ 23100 23101 "two_button": { 23102 23103 /* 23104 23105 * Function: oPagination.two_button.fnInit 23106 23107 * Purpose: Initialise dom elements required for pagination with forward/back buttons only 23108 23109 * Returns: - 23110 23111 * Inputs: object:oSettings - dataTables settings object 23112 23113 * node:nPaging - the DIV which contains this pagination control 23114 23115 * function:fnCallbackDraw - draw function which must be called on update 23116 23117 */ 23118 23119 "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) 23120 23121 { 23122 23123 var oLang = oSettings.oLanguage.oPaginate; 23124 23125 var oClasses = oSettings.oClasses; 23126 23127 var fnClickHandler = function ( e ) { 23128 23129 if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) ) 23130 23131 { 23132 23133 fnCallbackDraw( oSettings ); 23134 23135 } 23136 23137 }; 23138 23139 23140 23141 var sAppend = (!oSettings.bJUI) ? 23142 23143 '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+ 23144 23145 '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>' 23146 23147 : 23148 23149 '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+ 23150 23151 '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>'; 23152 23153 $(nPaging).append( sAppend ); 23154 23155 23156 23157 var els = $('a', nPaging); 23158 23159 var nPrevious = els[0], 23160 23161 nNext = els[1]; 23162 23163 23164 23165 oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler ); 23166 23167 oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler ); 23168 23169 23170 23171 /* ID the first elements only */ 23172 23173 if ( !oSettings.aanFeatures.p ) 23174 23175 { 23176 23177 nPaging.id = oSettings.sTableId+'_paginate'; 23178 23179 nPrevious.id = oSettings.sTableId+'_previous'; 23180 23181 nNext.id = oSettings.sTableId+'_next'; 23182 23183 23184 23185 nPrevious.setAttribute('aria-controls', oSettings.sTableId); 23186 23187 nNext.setAttribute('aria-controls', oSettings.sTableId); 23188 23189 } 23190 23191 }, 23192 23193 23194 23195 /* 23196 23197 * Function: oPagination.two_button.fnUpdate 23198 23199 * Purpose: Update the two button pagination at the end of the draw 23200 23201 * Returns: - 23202 23203 * Inputs: object:oSettings - dataTables settings object 23204 23205 * function:fnCallbackDraw - draw function to call on page change 23206 23207 */ 23208 23209 "fnUpdate": function ( oSettings, fnCallbackDraw ) 23210 23211 { 23212 23213 if ( !oSettings.aanFeatures.p ) 23214 23215 { 23216 23217 return; 23218 23219 } 23220 23221 23222 23223 var oClasses = oSettings.oClasses; 23224 23225 var an = oSettings.aanFeatures.p; 23226 23227 var nNode; 23228 23229 23230 23231 /* Loop over each instance of the pager */ 23232 23233 for ( var i=0, iLen=an.length ; i<iLen ; i++ ) 23234 23235 { 23236 23237 nNode = an[i].firstChild; 23238 23239 if ( nNode ) 23240 23241 { 23242 23243 /* Previous page */ 23244 23245 nNode.className = ( oSettings._iDisplayStart === 0 ) ? 23246
23247 oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled; 23248 23249 23250 23251 /* Next page */ 23252 23253 nNode = nNode.nextSibling; 23254 23255 nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ? 23256 23257 oClasses.sPageNextDisabled : oClasses.sPageNextEnabled; 23258 23259 } 23260 23261 } 23262 23263 } 23264 23265 }, 23266 23267 23268 23269 23270 23271 /* 23272 23273 * Variable: iFullNumbersShowPages 23274 23275 * Purpose: Change the number of pages which can be seen 23276 23277 * Scope: jQuery.fn.dataTableExt.oPagination 23278 23279 */ 23280 23281 "iFullNumbersShowPages": 5, 23282 23283 23284 23285 /* 23286 23287 * Variable: full_numbers 23288 23289 * Purpose: Full numbers pagination 23290 23291 * Scope: jQuery.fn.dataTableExt.oPagination 23292 23293 */ 23294 23295 "full_numbers": { 23296 23297 /* 23298 23299 * Function: oPagination.full_numbers.fnInit 23300 23301 * Purpose: Initialise dom elements required for pagination with a list of the pages 23302 23303 * Returns: - 23304 23305 * Inputs: object:oSettings - dataTables settings object 23306 23307 * node:nPaging - the DIV which contains this pagination control 23308 23309 * function:fnCallbackDraw - draw function which must be called on update 23310 23311 */ 23312 23313 "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) 23314 23315 { 23316 23317 var oLang = oSettings.oLanguage.oPaginate; 23318 23319 var oClasses = oSettings.oClasses; 23320 23321 var fnClickHandler = function ( e ) { 23322 23323 if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) ) 23324 23325 { 23326 23327 fnCallbackDraw( oSettings ); 23328 23329 } 23330 23331 }; 23332 23333 23334 23335 $(nPaging).append( 23336 23337 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+ 23338 23339 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+ 23340 23341 '<span></span>'+ 23342 23343 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+ 23344 23345 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>' 23346 23347 ); 23348 23349 var els = $('a', nPaging); 23350 23351 var nFirst = els[0], 23352 23353 nPrev = els[1], 23354 23355 nNext = els[2], 23356 23357 nLast = els[3]; 23358 23359 23360 23361 oSettings.oApi._fnBindAction( nFirst, {action: "first"}, fnClickHandler ); 23362 23363 oSettings.oApi._fnBindAction( nPrev, {action: "previous"}, fnClickHandler ); 23364 23365 oSettings.oApi._fnBindAction( nNext, {action: "next"}, fnClickHandler ); 23366 23367 oSettings.oApi._fnBindAction( nLast, {action: "last"}, fnClickHandler ); 23368 23369 23370 23371 /* ID the first elements only */ 23372 23373 if ( !oSettings.aanFeatures.p ) 23374 23375 { 23376 23377 nPaging.id = oSettings.sTableId+'_paginate'; 23378 23379 nFirst.id =oSettings.sTableId+'_first'; 23380 23381 nPrev.id =oSettings.sTableId+'_previous'; 23382 23383 nNext.id =oSettings.sTableId+'_next'; 23384 23385 nLast.id =oSettings.sTableId+'_last'; 23386 23387 } 23388 23389 }, 23390 23391 23392 23393 /* 23394 23395 * Function: oPagination.full_numbers.fnUpdate 23396 23397 * Purpose: Update the list of page buttons shows 23398 23399 * Returns: - 23400 23401 * Inputs: object:oSettings - dataTables settings object 23402 23403 * function:fnCallbackDraw - draw function to call on page change 23404 23405 */ 23406 23407 "fnUpdate": function ( oSettings, fnCallbackDraw ) 23408 23409 { 23410 23411 if ( !oSettings.aanFeatures.p ) 23412 23413 { 23414 23415 return; 23416 23417 } 23418 23419 23420 23421 var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages; 23422 23423 var iPageCountHalf = Math.floor(iPageCount / 2); 23424 23425 var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength); 23426 23427 var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1; 23428 23429 var sList = ""; 23430 23431 var iStartButton, iEndButton, i, iLen; 23432 23433 var oClasses = oSettings.oClasses; 23434 23435 var anButtons, anStatic, nPaginateList, nNode; 23436 23437 var an = oSettings.aanFeatures.p; 23438 23439 var fnBind = function (j) { 23440 23441 oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) { 23442 23443 /* Use the information in the element to jump to the required page */ 23444 23445 oSettings.oApi._fnPageChange( oSettings, e.data.page ); 23446 23447 fnCallbackDraw( oSettings ); 23448 23449 e.preventDefault(); 23450 23451 } ); 23452 23453 }; 23454 23455 23456 23457 /* Pages calculation */ 23458 23459 if ( oSettings._iDisplayLength === -1 ) 23460 23461 { 23462 23463 iStartButton = 1; 23464 23465 iEndButton = 1; 23466 23467 iCurrentPage = 1; 23468 23469 } 23470 23471 else if (iPages < iPageCount) 23472 23473 { 23474 23475 iStartButton = 1; 23476 23477 iEndButton = iPages; 23478 23479 } 23480 23481 else if (iCurrentPage <= iPageCountHalf) 23482 23483 { 23484 23485 iStartButton = 1; 23486 23487 iEndButton = iPageCount; 23488 23489 } 23490 23491 else if (iCurrentPage >= (iPages - iPageCountHalf)) 23492 23493 { 23494 23495 iStartButton = iPages - iPageCount + 1; 23496 23497 iEndButton = iPages; 23498 23499 } 23500 23501 else 23502 23503 { 23504
23505 iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1; 23506 23507 iEndButton = iStartButton + iPageCount - 1; 23508 23509 } 23510 23511 23512 23513 23514 23515 /* Build the dynamic list */ 23516 23517 for ( i=iStartButton ; i<=iEndButton ; i++ ) 23518 23519 { 23520 23521 sList += (iCurrentPage !== i) ? 23522 23523 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' : 23524 23525 '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>'; 23526 23527 } 23528 23529 23530 23531 /* Loop over each instance of the pager */ 23532 23533 for ( i=0, iLen=an.length ; i<iLen ; i++ ) 23534 23535 { 23536 23537 nNode = an[i]; 23538 23539 if ( !nNode.hasChildNodes() ) 23540 23541 { 23542 23543 continue; 23544 23545 } 23546 23547 23548 23549 /* Build up the dynamic list first - html and listeners */ 23550 23551 $('span:eq(0)', nNode) 23552 23553 .html( sList ) 23554 23555 .children('a').each( fnBind ); 23556 23557 23558 23559 /* Update the permanent button's classes */ 23560 23561 anButtons = nNode.getElementsByTagName('a'); 23562 23563 anStatic = [ 23564 23565 anButtons[0], anButtons[1], 23566 23567 anButtons[anButtons.length-2], anButtons[anButtons.length-1] 23568 23569 ]; 23570 23571 23572 23573 $(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled ); 23574 23575 $([anStatic[0], anStatic[1]]).addClass( 23576 23577 (iCurrentPage==1) ? 23578 23579 oClasses.sPageButtonStaticDisabled : 23580 23581 oClasses.sPageButton 23582 23583 ); 23584 23585 $([anStatic[2], anStatic[3]]).addClass( 23586 23587 (iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ? 23588 23589 oClasses.sPageButtonStaticDisabled : 23590 23591 oClasses.sPageButton 23592 23593 ); 23594 23595 } 23596 23597 } 23598 23599 } 23600 23601 } ); 23602 23603 23604 23605 $.extend( DataTable.ext.oSort, { 23606 23607 /* 23608 23609 * text sorting 23610 23611 */ 23612 23613 "string-pre": function ( a ) 23614 23615 { 23616 23617 if ( typeof a != 'string' ) { 23618 23619 a = (a !== null && a.toString) ? a.toString() : ''; 23620 23621 } 23622 23623 return a.toLowerCase(); 23624 23625 }, 23626 23627 23628 23629 "string-asc": function ( x, y ) 23630 23631 { 23632 23633 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 23634 23635 }, 23636 23637 23638 23639 "string-desc": function ( x, y ) 23640 23641 { 23642 23643 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 23644 23645 }, 23646 23647 23648 23649 23650 23651 /* 23652 23653 * html sorting (ignore html tags) 23654 23655 */ 23656 23657 "html-pre": function ( a ) 23658 23659 { 23660 23661 return a.replace( /<.*?>/g, "" ).toLowerCase(); 23662 23663 }, 23664 23665 23666 23667 "html-asc": function ( x, y ) 23668 23669 { 23670 23671 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 23672 23673 }, 23674 23675 23676 23677 "html-desc": function ( x, y ) 23678 23679 { 23680 23681 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 23682 23683 }, 23684 23685 23686 23687 23688 23689 /* 23690 23691 * date sorting 23692 23693 */ 23694 23695 "date-pre": function ( a ) 23696 23697 { 23698 23699 var x = Date.parse( a ); 23700 23701 23702 23703 if ( isNaN(x) || x==="" ) 23704 23705 { 23706 23707 x = Date.parse( "01/01/1970 00:00:00" ); 23708 23709 } 23710 23711 return x; 23712 23713 }, 23714 23715 23716 23717 "date-asc": function ( x, y ) 23718 23719 { 23720 23721 return x - y; 23722 23723 }, 23724 23725 23726 23727 "date-desc": function ( x, y ) 23728 23729 { 23730 23731 return y - x; 23732 23733 }, 23734 23735 23736 23737 23738 23739 /* 23740 23741 * numerical sorting 23742 23743 */ 23744 23745 "numeric-pre": function ( a ) 23746 23747 { 23748 23749 return (a=="-" || a==="") ? 0 : a*1; 23750 23751 }, 23752 23753 23754 23755 "numeric-asc": function ( x, y ) 23756 23757 { 23758 23759 return x - y; 23760 23761 }, 23762 23763 23764 23765 "numeric-desc": function ( x, y ) 23766 23767 { 23768 23769 return y - x; 23770 23771 } 23772 23773 } ); 23774 23775 23776 23777 23778 23779 $.extend( DataTable.ext.aTypes, [ 23780 23781 /* 23782 23783 * Function: - 23784 23785 * Purpose: Check to see if a string is numeric 23786 23787 * Returns: string:'numeric' or null 23788 23789 * Inputs: mixed:sText - string to check 23790 23791 */ 23792 23793 function ( sData ) 23794 23795 { 23796 23797 /* Allow zero length strings as a number */ 23798 23799 if ( typeof sData === 'number' ) 23800 23801 { 23802 23803 return 'numeric'; 23804 23805 } 23806 23807 else if ( typeof sData !== 'string' ) 23808 23809 { 23810 23811 return null; 23812 23813 } 23814 23815 23816 23817 var sValidFirstChars = "0123456789-"; 23818 23819 var sValidChars = "0123456789."; 23820 23821 var Char; 23822 23823 var bDecimal = false; 23824 23825 23826 23827 /* Check for a valid first char (no period and allow negatives) */ 23828 23829 Char = sData.charAt(0); 23830 23831 if (sValidFirstChars.indexOf(Char) == -1) 23832 23833 { 23834 23835 return null; 23836 23837 } 23838 23839 23840 23841 /* Check all the other characters are valid */ 23842 23843 for ( var i=1 ; i<sData.length ; i++ ) 23844 23845 { 23846 23847 Char = sData.charAt(i); 23848 23849 if (sValidChars.indexOf(Char) == -1) 23850 23851 { 23852 23853 return null; 23854 23855 } 23856 23857 23858 23859 /* Only allowed one decimal place... */ 23860 23861 if ( Char == "." ) 23862 23863 { 23864 23865 if ( bDecimal ) 23866 23867 { 23868 23869 return null; 23870 23871 } 23872 23873 bDecimal = true; 23874 23875 } 23876 23877 } 23878 23879 23880 23881 return 'numeric'; 23882 23883 }, 23884 23885 23886 23887 /* 23888 23889 * Function: - 23890 23891 * Purpose: Check to see if a string is actually a formatted date 23892 23893 * Returns: string:'date' or null 23894 23895 * Inputs: string:sText - string to check 23896 23897 */ 23898 23899 function ( sData ) 23900 23901 { 23902 23903 var iParse = Date.parse(sData); 23904 23905 if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) ) 23906 23907 { 23908 23909 return 'date'; 23910 23911 } 23912 23913 return null; 23914 23915 }, 23916 23917 23918 23919 /* 23920 23921 * Function: - 23922 23923 * Purpose: Check to see if a string should be treated as an HTML string 23924 23925 * Returns: string:'html' or null 23926 23927 * Inputs: string:sText - string to check 23928 23929 */ 23930 23931 function ( sData ) 23932 23933 { 23934 23935 if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 ) 23936 23937 { 23938 23939 return 'html'; 23940 23941 } 23942 23943 return null; 23944 23945 } 23946 23947 ] ); 23948 23949 23950 23951 23952 23953 // jQuery aliases 23954 23955 $.fn.DataTable = DataTable; 23956 23957 $.fn.dataTable = DataTable; 23958 23959 $.fn.dataTableSettings = DataTable.settings; 23960 23961 $.fn.dataTableExt = DataTable.ext; 23962 23963 23964 23965 23966 23967 // Information about Businesses fired by DataTables - for documentation. 23968 23969 /** 23970 23971 * Draw event, fired whenever the table is redrawn on the page, at the same point as 23972 23973 * fnDrawCallback. This may be useful for binding Businesses or performing calculations when 23974 23975 * the table is altered at all. 23976 23977 * @name DataTable#draw 23978 23979 * @event 23980 23981 * @param {event} e jQuery event object 23982 23983 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 23984 23985 */ 23986 23987 23988 23989 /** 23990 23991 * Filter event, fired when the filtering applied to the table (using the build in global 23992 23993 * global filter, or column filters) is altered. 23994 23995 * @name DataTable#filter 23996 23997 * @event 23998 23999 * @param {event} e jQuery event object 24000 24001 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24002 24003 */ 24004 24005 24006 24007 /** 24008 24009 * Page change event, fired when the paging of the table is altered. 24010 24011 * @name DataTable#page 24012 24013 * @event 24014 24015 * @param {event} e jQuery event object 24016 24017 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24018 24019 */ 24020 24021 24022 24023 /** 24024 24025 * Sort event, fired when the sorting applied to the table is altered. 24026 24027 * @name DataTable#sort 24028 24029 * @event 24030 24031 * @param {event} e jQuery event object 24032 24033 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24034 24035 */ 24036 24037 24038 24039 /** 24040 24041 * DataTables initialisation complete event, fired when the table is fully drawn, 24042 24043 * including Ajax data loaded, if Ajax data is required. 24044 24045 * @name DataTable#init 24046 24047 * @event 24048 24049 * @param {event} e jQuery event object 24050 24051 * @param {object} oSettings DataTables settings object 24052 24053 * @param {object} json The JSON object request from the server - only 24054 24055 * present if client-side Ajax sourced data is used</li></ol> 24056 24057 */ 24058 24059 24060 24061 /** 24062 24063 * State save event, fired when the table has changed state a new state save is required. 24064 24065 * This method allows modification of the state saving object prior to actually doing the 24066 24067 * save, including addition or other state properties (for plug-ins) or modification 24068 24069 * of a DataTables core property. 24070 24071 * @name DataTable#stateSaveParams 24072 24073 * @event 24074 24075 * @param {event} e jQuery event object 24076 24077 * @param {object} oSettings DataTables settings object 24078 24079 * @param {object} json The state information to be saved 24080 24081 */ 24082 24083 24084 24085 /** 24086 24087 * State load event, fired when the table is loading state from the stored data, but 24088 24089 * prior to the settings object being modified by the saved state - allowing modification 24090 24091 * of the saved state is required or loading of state for a plug-in. 24092 24093 * @name DataTable#stateLoadParams 24094 24095 * @event 24096 24097 * @param {event} e jQuery event object 24098 24099 * @param {object} oSettings DataTables settings object 24100 24101 * @param {object} json The saved state information 24102 24103 */ 24104 24105 24106 24107 /** 24108 24109 * State loaded event, fired when state has been loaded from stored data and the settings 24110 24111 * object has been modified by the loaded data. 24112 24113 * @name DataTable#stateLoaded 24114 24115 * @event 24116 24117 * @param {event} e jQuery event object 24118 24119 * @param {object} oSettings DataTables settings object 24120 24121 * @param {object} json The saved state information 24122 24123 */ 24124 24125 24126 24127 /** 24128 24129 * Processing event, fired when DataTables is doing some kind of processing (be it, 24130 24131 * sort, filter or anything else). Can be used to indicate to the end user that 24132 24133 * there is something happening, or that something has finished. 24134 24135 * @name DataTable#processing 24136 24137 * @event 24138 24139 * @param {event} e jQuery event object 24140 24141 * @param {object} oSettings DataTables settings object 24142 24143 * @param {boolean} bShow Flag for if DataTables is doing processing or not 24144 24145 */ 24146 24147 24148 24149 /** 24150 24151 * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to 24152 24153 * made to the server for new data (note that this trigger is called
24153in fnServerData, 24154 24155 * if you override fnServerData and which to use this event, you need to trigger it in 24156 24157 * you success function). 24158 24159 * @name DataTable#xhr 24160 24161 * @event 24162 24163 * @param {event} e jQuery event object 24164 24165 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24166 24167 * @param {object} json JSON returned from the server 24168 24169 */ 24170 24171 24172 24173 /** 24174 24175 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing 24176 24177 * the bDestroy:true parameter in the initialisation object. This can be used to remove 24178 24179 * bound Businesses, added DOM nodes, etc. 24180 24181 * @name DataTable#destroy 24182 24183 * @event 24184 24185 * @param {event} e jQuery event object 24186 24187 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 24188 24189 */ 24190 24191})); 24192 24193 24194 24195}(window, document)); 24196 24197 24198
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.