1/*! DataTables 1.10.5 2 * ©2008-2014 SpryMedia Ltd - datatables.net/license 3 */ 4 5/** 6 * @summary DataTables 7 * @description Paginate, search and order HTML tables 8 * @version 1.10.5 9 * @file jquery.dataTables.js 10 * @author SpryMedia Ltd (www.sprymedia.co.uk) 11 * @contact www.sprymedia.co.uk/contact 12 * @copyright Copyright 2008-2014 SpryMedia Ltd. 13 * 14 * This source file is free software, available under the following license: 15 * MIT license - http://datatables.net/license 16 * 17 * This source file is distributed in the hope that it will be useful, but 18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 19 * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. 20 * 21 * For details please refer to: http://www.datatables.net 22 */ 23 24/*jslint evil: true, undef: true, browser: true */ 25/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/ 26 27(/** @lends <global> */function( window, document, undefined ) { 28 29(function( factory ) { 30 "use strict"; 31 32 if ( typeof define === 'function' && define.amd ) { 33 // Define as an AMD module if possible 34 define( 'datatables', ['jquery'], factory ); 35 } 36 else if ( typeof exports === 'object' ) { 37 // Node/CommonJS 38 module.exports = factory( require( 'jquery' ) ); 39 } 40 else if ( jQuery && !jQuery.fn.dataTable ) { 41 // Define using browser globals otherwise 42 // Prevent multiple instantiations if the script is loaded twice 43 factory( jQuery ); 44 } 45} 46(/** @lends <global> */function( $ ) { 47 "use strict"; 48 49 /** 50 * DataTables is a plug-in for the jQuery Javascript library. It is a highly 51 * flexible tool, based upon the foundations of progressive enhancement, 52 * which will add advanced interaction controls to any HTML table. For a 53 * full list of features please refer to 54 * [DataTables.net](href="http://datatables.net). 55 * 56 * Note that the `DataTable` object is not a global variable but is aliased 57 * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may 58 * be accessed. 59 * 60 * @class 61 * @param {object} [init={}] Configuration object for DataTables. Options 62 * are defined by {@link DataTable.defaults} 63 * @requires jQuery 1.7+ 64 * 65 * @example 66 * // Basic initialisation 67 * $(document).ready( function { 68 * $('#example').dataTable(); 69 * } ); 70 * 71 * @example 72 * // Initialisation with configuration options - in this case, disable 73 * // pagination and sorting. 74 * $(document).ready( function { 75 * $('#example').dataTable( { 76 * "paginate": false, 77 * "sort": false 78 * } ); 79 * } ); 80 */ 81 var DataTable; 82 83 84 /*
85 * It is useful to have variables which are scoped locally so only the 86 * DataTables functions can access them and they don't leak into global space. 87 * At the same time these functions are often useful over multiple files in the 88 * core and API, so we list, or at least document, all variables which are used 89 * by DataTables as private variables here. This also ensures that there is no 90 * clashing of variable names and that they can easily referenced for reuse. 91 */ 92 93 94 // Defined else where 95 // _selector_run 96 // _selector_opts 97 // _selector_first 98 // _selector_row_indexes 99 100 var _ext; // DataTable.ext 101 var _Api; // DataTable.Api 102 var _api_register; // DataTable.Api.register 103 var _api_registerPlural; // DataTable.Api.registerPlural 104 105 var _re_dic = {}; 106 var _re_new_lines = /[\r\n]/g; 107 var _re_html = /<.*?>/g; 108 var _re_date_start = /^[\w\+\-]/; 109 var _re_date_end = /[\w\+\-]$/; 110 111 // Escape regular expression special characters 112 var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' ); 113 114 // U+2009 is thin space and U+202F is narrow no-break space, both used in many 115 // standards as thousands separators 116 var _re_formatted_numeric = /[',$£â¬Â¥%\u2009\u202F]/g; 117 118 119 var _empty = function ( d ) { 120 return !d || d === true || d === '-' ? true : false; 121 }; 122 123 124 var _intVal = function ( s ) { 125 var integer = parseInt( s, 10 ); 126 return !isNaN(integer) && isFinite(s) ? integer : null; 127 }; 128 129 // Convert from a formatted number with characters other than `.` as the 130 // decimal place, to a Javascript number 131 var _numToDecimal = function ( num, decimalPoint ) { 132 // Cache created regular expressions for speed as this function is called often 133 if ( ! _re_dic[ decimalPoint ] ) { 134 _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' ); 135 } 136 return typeof num === 'string' && decimalPoint !== '.' ? 137 num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) : 138 num; 139 }; 140 141 142 var _isNumber = function ( d, decimalPoint, formatted ) { 143 var strType = typeof d === 'string'; 144 145 if ( decimalPoint && strType ) { 146 d = _numToDecimal( d, decimalPoint ); 147 } 148 149 if ( formatted && strType ) { 150 d = d.replace( _re_formatted_numeric, '' ); 151 } 152 153 return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d )); 154 }; 155 156 157 // A string without HTML in it can be considered to be HTML still 158 var _isHtml = function ( d ) { 159 return _empty( d ) || typeof d === 'string'; 160 }; 161 162 163 var _htmlNumeric = function ( d, decimalPoint, formatted ) { 164 if ( _empty( d ) ) { 165 return true; 166 } 167 168 var html = _isHtml( d ); 169 return ! html ? 170 null : 171 _isNumber( _stripHtml( d ), decimalPoint, formatted ) ? 172 true : 173 null; 174 }; 175 176 177 var _pluck = function ( a, prop, prop2 ) { 178 var out = []; 179 var i=0, ien=a.length; 180 181 // Could have the test in the loop for slightly smaller code, but speed 182 // is essential here 183 if ( prop2 !== undefined ) { 184 for ( ; i<ien ; i++ ) { 185 if ( a[i] && a[i][ prop ] ) { 186 out.push( a[i][ prop ][ prop2 ] ); 187 } 188 } 189 } 190 else { 191 for ( ; i<ien ; i++ ) { 192 if ( a[i] ) { 193 out.push( a[i][ prop ] ); 194 } 195 } 196 } 197 198 return out; 199 }; 200 201 202 // Basically the same as _pluck, but rather than looping over `a` we use `order` 203 // as the indexes to pick from `a` 204 var _pluck_order = function ( a, order, prop, prop2 ) 205 { 206 var out = []; 207 var i=0, ien=order.length; 208 209 // Could have the test in the loop for slightly smaller code, but speed 210 // is essential here 211 if ( prop2 !== undefined ) { 212 for ( ; i<ien ; i++ ) { 213 if ( a[ order[i] ][ prop ] ) { 214 out.push( a[ order[i] ][ prop ][ prop2 ] ); 215 } 216 } 217 } 218 else { 219 for ( ; i<ien ; i++ ) { 220 out.push( a[ order[i] ][ prop ] ); 221 } 222 } 223 224 return out; 225 }; 226 227 228 var _range = function ( len, start ) 229 { 230 var out = []; 231 var end; 232 233 if ( start === undefined ) { 234 start = 0; 235 end = len; 236 } 237 else { 238 end = start; 239 start = len; 240 } 241 242 for ( var i=start ; i<end ; i++ ) { 243 out.push( i ); 244 } 245 246 return out; 247 }; 248 249 250 var _removeEmpty = function ( a ) 251 { 252 var out = []; 253 254 for ( var i=0, ien=a.length ; i<ien ; i++ ) { 255 if ( a[i] ) { // careful - will remove all falsy values! 256 out.push( a[i] ); 257 } 258 } 259 260 return out; 261 }; 262 263 264 var _stripHtml = function ( d ) { 265 return d.replace( _re_html, '' ); 266 }; 267 268 269 /** 270 * Find the unique elements in a source array. 271 * 272 * @param {array} src Source array 273 * @return {array} Array of unique items 274 * @ignore 275 */ 276 var _unique = function ( src ) 277 {
278 // A faster unique method is to use object keys to identify used values, 279 // but this doesn't work with arrays or objects, which we must also 280 // consider. See jsperf.com/compare-array-unique-versions/4 for more 281 // information. 282 var 283 out = [], 284 val, 285 i, ien=src.length, 286 j, k=0; 287 288 again: for ( i=0 ; i<ien ; i++ ) { 289 val = src[i]; 290 291 for ( j=0 ; j<k ; j++ ) { 292 if ( out[j] === val ) { 293 continue again; 294 } 295 } 296 297 out.push( val ); 298 k++; 299 } 300 301 return out; 302 }; 303 304 305 306 /** 307 * Create a mapping object that allows camel case parameters to be looked up 308 * for their Hungarian counterparts. The mapping is stored in a private 309 * parameter called `_hungarianMap` which can be accessed on the source object. 310 * @param {object} o 311 * @memberof DataTable#oApi 312 */ 313 function _fnHungarianMap ( o ) 314 { 315 var 316 hungarian = 'a aa ai ao as b fn i m o s ', 317 match, 318 newKey, 319 map = {}; 320 321 $.each( o, function (key, val) { 322 match = key.match(/^([^A-Z]+?)([A-Z])/); 323 324 if ( match && hungarian.indexOf(match[1]+' ') !== -1 ) 325 { 326 newKey = key.replace( match[0], match[2].toLowerCase() ); 327 map[ newKey ] = key; 328 329 if ( match[1] === 'o' ) 330 { 331 _fnHungarianMap( o[key] ); 332 } 333 } 334 } ); 335 336 o._hungarianMap = map; 337 } 338 339 340 /** 341 * Convert from camel case parameters to Hungarian, based on a Hungarian map 342 * created by _fnHungarianMap. 343 * @param {object} src The model object which holds all parameters that can be 344 * mapped. 345 * @param {object} user The object to convert from camel case to Hungarian. 346 * @param {boolean} force When set to `true`, properties which already have a 347 * Hungarian value in the `user` object will be overwritten. Otherwise they 348 * won't be. 349 * @memberof DataTable#oApi 350 */ 351 function _fnCamelToHungarian ( src, user, force ) 352 { 353 if ( ! src._hungarianMap ) { 354 _fnHungarianMap( src ); 355 } 356 357 var hungarianKey; 358 359 $.each( user, function (key, val) { 360 hungarianKey = src._hungarianMap[ key ]; 361 362 if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) ) 363 { 364 // For objects, we need to buzz down into the object to copy parameters 365 if ( hungarianKey.charAt(0) === 'o' ) 366 { 367 // Copy the camelCase options over to the hungarian 368 if ( ! user[ hungarianKey ] ) { 369 user[ hungarianKey ] = {}; 370 } 371 $.extend( true, user[hungarianKey], user[key] ); 372 373 _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force ); 374 } 375 else { 376 user[hungarianKey] = user[ key ]; 377 } 378 } 379 } ); 380 } 381 382 383 /** 384 * Language compatibility - when certain options are given, and others aren't, we 385 * need to duplicate the values over, in order to provide backwards compatibility 386 * with older language files. 387 * @param {object} oSettings dataTables settings object 388 * @memberof DataTable#oApi 389 */ 390 function _fnLanguageCompat( lang ) 391 { 392 var defaults = DataTable.defaults.oLanguage; 393 var zeroRecords = lang.sZeroRecords; 394 395 /* Backwards compatibility - if there is no sEmptyTable given, then use the same as 396 * sZeroRecords - assuming that is given. 397 */ 398 if ( ! lang.sEmptyTable && zeroRecords && 399 defaults.sEmptyTable === "No data available in table" ) 400 { 401 _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' ); 402 } 403 404 /* Likewise with loading records */ 405 if ( ! lang.sLoadingRecords && zeroRecords && 406 defaults.sLoadingRecords === "Loading..." ) 407 { 408 _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' ); 409 } 410 411 // Old parameter name of the thousands separator mapped onto the new 412 if ( lang.sInfoThousands ) { 413 lang.sThousands = lang.sInfoThousands; 414 } 415 416 var decimal = lang.sDecimal; 417 if ( decimal ) { 418 _addNumericSort( decimal ); 419 } 420 } 421 422 423 /** 424 * Map one parameter onto another 425 * @param {object} o Object to map 426 * @param {*} knew The new parameter name 427 * @param {*} old The old parameter name 428 */ 429 var _fnCompatMap = function ( o, knew, old ) { 430 if ( o[ knew ] !== undefined ) { 431 o[ old ] = o[ knew ]; 432 } 433 }; 434 435 436 /** 437 * Provide backwards compatibility for the main DT options. Note that the new 438 * options are mapped onto the old parameters, so this is an external interface 439 * change only. 440 * @param {object} init Object to map 441 */ 442 function _fnCompatOpts ( init ) 443 { 444 _fnCompatMap( init, 'ordering', 'bSort' ); 445 _fnCompatMap( init, 'orderMulti', 'bSortMulti' ); 446 _fnCompatMap( init, 'orderClasses', 'bSortClasses' ); 447 _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' ); 448 _fnCompatMap( init, 'order', 'aaSorting' ); 449 _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' ); 450 _fnCompatMap( init, 'paging', 'bPaginate' ); 451 _fnCompatMap( init, 'pagingType', 'sPaginationType' ); 452 _fnCompatMap( init, 'pageLength', 'iDisplayLength' ); 453 _fnCompatMap( init, 'searching', 'bFilter' ); 454 455 // Column search objects are in an array, so it needs to be converted 456 // element by element 457 var searchCols = init.aoSearchCols; 458 459 if ( searchCols ) { 460 for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) { 461 if ( searchCols[i] ) { 462 _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] ); 463 } 464 } 465 } 466 } 467 468 469 /** 470 * Provide backwards compatibility for column options. Note that the new options 471 * are mapped onto the old parameters, so this is an external interface change 472 * only. 473 * @param {object} init Object to map 474 */ 475 function _fnCompatCols ( init ) 476 { 477 _fnCompatMap( init, 'orderable', 'bSortable' ); 478 _fnCompatMap( init, 'orderData', 'aDataSort' ); 479 _fnCompatMap( init, 'orderSequence', 'asSorting' ); 480 _fnCompatMap( init, 'orderDataType', 'sortDataType' ); 481 } 482 483 484 /** 485 * Browser feature detection for capabilities, quirks 486 * @param {object} settings dataTables settings object 487 * @memberof DataTable#oApi 488 */ 489 function _fnBrowserDetect( settings ) 490 { 491 var browser = settings.oBrowser; 492 493 // Scrolling feature / quirks detection 494 var n = $('<div/>') 495 .css( { 496 position: 'absolute', 497 top: 0, 498 left: 0, 499 height: 1, 500 width: 1, 501 overflow: 'hidden' 502 } ) 503 .append( 504 $('<div/>') 505 .css( { 506 position: 'absolute', 507 top: 1, 508 left: 1, 509 width: 100, 510 overflow: 'scroll' 511 } ) 512 .append( 513 $('<div class="test"/>') 514 .css( { 515 width: '100%', 516 height: 10 517 } ) 518 ) 519 ) 520 .appendTo( 'body' ); 521 522 var test = n.find('.test'); 523 524 // IE6/7 will oversize a width 100% element inside a scrolling element, to 525 // include the width of the scrollbar, while other browsers ensure the inner 526 // element is contained without forcing scrolling 527 browser.bScrollOversize = test[0].offsetWidth === 100; 528 529 // In rtl text layout, some browsers (most, but not all) will place the 530 // scrollbar on the left, rather than the right. 531 browser.bScrollbarLeft = test.offset().left !== 1; 532 533 n.remove(); 534 } 535 536 537 /** 538 * Array.prototype reduce[Right] method, used for browsers which don't support 539 * JS 1.6. Done this way to reduce code size, since we iterate either way 540 * @param {object} settings dataTables settings object 541 * @memberof DataTable#oApi 542 */ 543 function _fnReduce ( that, fn, init, start, end, inc ) 544 { 545 var 546 i = start, 547 value, 548 isSet = false;
549 550 if ( init !== undefined ) { 551 value = init; 552 isSet = true; 553 } 554 555 while ( i !== end ) { 556 if ( ! that.hasOwnProperty(i) ) { 557 continue; 558 } 559 560 value = isSet ? 561 fn( value, that[i], i, that ) : 562 that[i]; 563 564 isSet = true; 565 i += inc; 566 } 567 568 return value; 569 } 570 571 /** 572 * Add a column to the list used for the table with default values 573 * @param {object} oSettings dataTables settings object 574 * @param {node} nTh The th element for this column 575 * @memberof DataTable#oApi 576 */ 577 function _fnAddColumn( oSettings, nTh ) 578 { 579 // Add column to aoColumns array 580 var oDefaults = DataTable.defaults.column; 581 var iCol = oSettings.aoColumns.length; 582 var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, { 583 "nTh": nTh ? nTh : document.createElement('th'), 584 "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '', 585 "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol], 586 "mData": oDefaults.mData ? oDefaults.mData : iCol, 587 idx: iCol 588 } ); 589 oSettings.aoColumns.push( oCol ); 590 591 // Add search object for column specific search. Note that the `searchCols[ iCol ]` 592 // passed into extend can be undefined. This allows the user to give a default 593 // with only some of the parameters defined, and also not give a default 594 var searchCols = oSettings.aoPreSearchCols; 595 searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] ); 596 597 // Use the default column options function to initialise classes etc 598 _fnColumnOptions( oSettings, iCol, $(nTh).data() ); 599 } 600 601 602 /** 603 * Apply options for a column 604 * @param {object} oSettings dataTables settings object 605 * @param {int} iCol column index to consider 606 * @param {object} oOptions object with sType, bVisible and bSearchable etc 607 * @memberof DataTable#oApi 608 */ 609 function _fnColumnOptions( oSettings, iCol, oOptions ) 610 { 611 var oCol = oSettings.aoColumns[ iCol ]; 612 var oClasses = oSettings.oClasses; 613 var th = $(oCol.nTh); 614 615 // Try to get width information from the DOM. We can't get it from CSS 616 // as we'd need to parse the CSS stylesheet. `width` option can override 617 if ( ! oCol.sWidthOrig ) { 618 // Width attribute 619 oCol.sWidthOrig = th.attr('width') || null; 620 621 // Style attribute 622 var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/); 623 if ( t ) { 624 oCol.sWidthOrig = t[1]; 625 } 626 } 627 628 /* User specified column options */ 629 if ( oOptions !== undefined && oOptions !== null ) 630 { 631 // Backwards compatibility 632 _fnCompatCols( oOptions ); 633 634 // Map camel case parameters to their Hungarian counterparts 635 _fnCamelToHungarian( DataTable.defaults.column, oOptions ); 636 637 /* Backwards compatibility for mDataProp */ 638 if ( oOptions.mDataProp !== undefined && !oOptions.mData ) 639 { 640 oOptions.mData = oOptions.mDataProp; 641 } 642 643 if ( oOptions.sType ) 644 { 645 oCol._sManualType = oOptions.sType; 646 } 647 648 // `class` is a reserved word in Javascript, so we need to provide 649 // the ability to use a valid name for the camel case input 650 if ( oOptions.className && ! oOptions.sClass ) 651 { 652 oOptions.sClass = oOptions.className; 653 } 654 655 $.extend( oCol, oOptions ); 656 _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" ); 657 658 /* iDataSort to be applied (backwards compatibility), but aDataSort will take 659 * priority if defined 660 */ 661 if ( typeof oOptions.iDataSort === 'number' ) 662 { 663 oCol.aDataSort = [ oOptions.iDataSort ]; 664 } 665 _fnMap( oCol, oOptions, "aDataSort" ); 666 } 667 668 /* Cache the data get and set functions for speed */ 669 var mDataSrc = oCol.mData; 670 var mData = _fnGetObjectDataFn( mDataSrc ); 671 var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null; 672 673 var attrTest = function( src ) { 674 return typeof src === 'string' && src.indexOf('@') !== -1; 675 }; 676 oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && ( 677 attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter) 678 ); 679 680 oCol.fnGetData = function (rowData, type, meta) { 681 var innerData = mData( rowData, type, undefined, meta ); 682 683 return mRender && type ? 684 mRender( innerData, type, rowData, meta ) : 685 innerData; 686 }; 687 oCol.fnSetData = function ( rowData, val, meta ) { 688 return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta ); 689 }; 690 691 // Indicate if DataTables should read DOM data as an object or array 692 // Used in _fnGetRowElements 693 if ( typeof mDataSrc !== 'number' ) { 694 oSettings._rowReadObject = true; 695 } 696 697 /* Feature sorting overrides column specific when off */ 698 if ( !oSettings.oFeatures.bSort ) 699 { 700 oCol.bSortable = false;
701 th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called 702 } 703 704 /* Check that the class assignment is correct for sorting */ 705 var bAsc = $.inArray('asc', oCol.asSorting) !== -1; 706 var bDesc = $.inArray('desc', oCol.asSorting) !== -1; 707 if ( !oCol.bSortable || (!bAsc && !bDesc) ) 708 { 709 oCol.sSortingClass = oClasses.sSortableNone; 710 oCol.sSortingClassJUI = ""; 711 } 712 else if ( bAsc && !bDesc ) 713 { 714 oCol.sSortingClass = oClasses.sSortableAsc; 715 oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed; 716 } 717 else if ( !bAsc && bDesc ) 718 { 719 oCol.sSortingClass = oClasses.sSortableDesc; 720 oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed; 721 } 722 else 723 { 724 oCol.sSortingClass = oClasses.sSortable; 725 oCol.sSortingClassJUI = oClasses.sSortJUI; 726 } 727 } 728 729 730 /** 731 * Adjust the table column widths for new data. Note: you would probably want to 732 * do a redraw after calling this function! 733 * @param {object} settings dataTables settings object 734 * @memberof DataTable#oApi 735 */ 736 function _fnAdjustColumnSizing ( settings ) 737 { 738 /* Not interested in doing column width calculation if auto-width is disabled */ 739 if ( settings.oFeatures.bAutoWidth !== false ) 740 { 741 var columns = settings.aoColumns; 742 743 _fnCalculateColumnWidths( settings ); 744 for ( var i=0 , iLen=columns.length ; i<iLen ; i++ ) 745 { 746 columns[i].nTh.style.width = columns[i].sWidth; 747 } 748 } 749 750 var scroll = settings.oScroll; 751 if ( scroll.sY !== '' || scroll.sX !== '') 752 { 753 _fnScrollDraw( settings ); 754 } 755 756 _fnCallbackFire( settings, null, 'column-sizing', [settings] ); 757 } 758 759 760 /** 761 * Covert the index of a visible column to the index in the data array (take account 762 * of hidden columns) 763 * @param {object} oSettings dataTables settings object 764 * @param {int} iMatch Visible column index to lookup 765 * @returns {int} i the data index 766 * @memberof DataTable#oApi 767 */ 768 function _fnVisibleToColumnIndex( oSettings, iMatch ) 769 { 770 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 771 772 return typeof aiVis[iMatch] === 'number' ? 773 aiVis[iMatch] : 774 null; 775 } 776 777 778 /** 779 * Covert the index of an index in the data array and convert it to the visible 780 * column index (take account of hidden columns) 781 * @param {int} iMatch Column index to lookup 782 * @param {object} oSettings dataTables settings object 783 * @returns {int} i the data index 784 * @memberof DataTable#oApi 785 */ 786 function _fnColumnIndexToVisible( oSettings, iMatch ) 787 { 788 var aiVis = _fnGetColumns( oSettings, 'bVisible' ); 789 var iPos = $.inArray( iMatch, aiVis ); 790 791 return iPos !== -1 ? iPos : null; 792 } 793 794 795 /** 796 * Get the number of visible columns 797 * @param {object} oSettings dataTables settings object 798 * @returns {int} i the number of visible columns 799 * @memberof DataTable#oApi 800 */ 801 function _fnVisbleColumns( oSettings ) 802 { 803 return _fnGetColumns( oSettings, 'bVisible' ).length; 804 } 805 806 807 /** 808 * Get an array of column indexes that match a given property 809 * @param {object} oSettings dataTables settings object 810 * @param {string} sParam Parameter in aoColumns to look for - typically 811 * bVisible or bSearchable 812 * @returns {array} Array of indexes with matched properties 813 * @memberof DataTable#oApi 814 */ 815 function _fnGetColumns( oSettings, sParam ) 816 { 817 var a = []; 818 819 $.map( oSettings.aoColumns, function(val, i) { 820 if ( val[sParam] ) { 821 a.push( i ); 822 } 823 } ); 824 825 return a; 826 } 827 828 829 /** 830 * Calculate the 'type' of a column 831 * @param {object} settings dataTables settings object 832 * @memberof DataTable#oApi 833 */ 834 function _fnColumnTypes ( settings ) 835 { 836 var columns = settings.aoColumns; 837 var data = settings.aoData; 838 var types = DataTable.ext.type.detect; 839 var i, ien, j, jen, k, ken; 840 var col, cell, detectedType, cache; 841 842 // For each column, spin over the 843 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 844 col = columns[i]; 845 cache = []; 846 847 if ( ! col.sType && col._sManualType ) { 848 col.sType = col._sManualType; 849 } 850 else if ( ! col.sType ) { 851 for ( j=0, jen=types.length ; j<jen ; j++ ) { 852 for ( k=0, ken=data.length ; k<ken ; k++ ) { 853 // Use a cache array so we only need to get the type data 854 // from the formatter once (when using multiple detectors) 855 if ( cache[k] === undefined ) { 856 cache[k] = _fnGetCellData( settings, k, i, 'type' ); 857 } 858 859 detectedType = types[j]( cache[k], settings ); 860 861 // If null, then this type can't apply to this column, so 862 // rather than testing all cells, break out. There is an 863 // exception for the last type which is `html`. We need to 864 // scan all rows since it is possible to mix string and HTML 865 // types 866 if ( ! detectedType && j !== types.length-1 ) { 867 break; 868 } 869 870 // Only a single match is needed for html type since it is 871 // bottom of the pile and very similar to string 872 if ( detectedType === 'html' ) { 873 break; 874 } 875 } 876 877 // Type is valid for all data points in the column - use this 878 // type 879 if ( detectedType ) {
880 col.sType = detectedType; 881 break; 882 } 883 } 884 885 // Fall back - if no type was detected, always use string 886 if ( ! col.sType ) { 887 col.sType = 'string'; 888 } 889 } 890 } 891 } 892 893 894 /** 895 * Take the column definitions and static columns arrays and calculate how 896 * they relate to column indexes. The callback function will then apply the 897 * definition found for a column to a suitable configuration object. 898 * @param {object} oSettings dataTables settings object 899 * @param {array} aoColDefs The aoColumnDefs array that is to be applied 900 * @param {array} aoCols The aoColumns array that defines columns individually 901 * @param {function} fn Callback function - takes two parameters, the calculated 902 * column index and the definition for that column. 903 * @memberof DataTable#oApi 904 */ 905 function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn ) 906 { 907 var i, iLen, j, jLen, k, kLen, def; 908 var columns = oSettings.aoColumns; 909 910 // Column definitions with aTargets 911 if ( aoColDefs ) 912 { 913 /* Loop over the definitions array - loop in reverse so first instance has priority */ 914 for ( i=aoColDefs.length-1 ; i>=0 ; i-- ) 915 { 916 def = aoColDefs[i]; 917 918 /* Each definition can target multiple columns, as it is an array */ 919 var aTargets = def.targets !== undefined ? 920 def.targets : 921 def.aTargets; 922 923 if ( ! $.isArray( aTargets ) ) 924 { 925 aTargets = [ aTargets ]; 926 } 927 928 for ( j=0, jLen=aTargets.length ; j<jLen ; j++ ) 929 { 930 if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 ) 931 { 932 /* Add columns that we don't yet know about */ 933 while( columns.length <= aTargets[j] ) 934 { 935 _fnAddColumn( oSettings ); 936 } 937 938 /* Integer, basic index */ 939 fn( aTargets[j], def ); 940 } 941 else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 ) 942 { 943 /* Negative integer, right to left column counting */ 944 fn( columns.length+aTargets[j], def ); 945 } 946 else if ( typeof aTargets[j] === 'string' ) 947 { 948 /* Class name matching on TH element */ 949 for ( k=0, kLen=columns.length ; k<kLen ; k++ ) 950 { 951 if ( aTargets[j] == "_all" || 952 $(columns[k].nTh).hasClass( aTargets[j] ) ) 953 { 954 fn( k, def ); 955 } 956 } 957 } 958 } 959 } 960 } 961 962 // Statically defined columns array 963 if ( aoCols ) 964 { 965 for ( i=0, iLen=aoCols.length ; i<iLen ; i++ ) 966 { 967 fn( i, aoCols[i] ); 968 } 969 } 970 } 971 972 /** 973 * Add a data array to the table, creating DOM node etc. This is the parallel to 974 * _fnGatherData, but for adding rows from a Javascript source, rather than a 975 * DOM source. 976 * @param {object} oSettings dataTables settings object 977 * @param {array} aData data array to be added 978 * @param {node} [nTr] TR element to add to the table - optional. If not given, 979 * DataTables will create a row automatically 980 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 981 * if nTr is. 982 * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed 983 * @memberof DataTable#oApi 984 */ 985 function _fnAddData ( oSettings, aDataIn, nTr, anTds ) 986 { 987 /* Create the object for storing information about this new row */ 988 var iRow = oSettings.aoData.length; 989 var oData = $.extend( true, {}, DataTable.models.oRow, { 990 src: nTr ? 'dom' : 'data' 991 } ); 992 993 oData._aData = aDataIn; 994 oSettings.aoData.push( oData ); 995 996 /* Create the cells */ 997 var nTd, sThisType; 998 var columns = oSettings.aoColumns; 999 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 1000 { 1001 // When working with a row, the data source object must be populated. In 1002 // all other cases, the data source object is already populated, so we 1003 // don't overwrite it, which might break bindings etc 1004 if ( nTr ) { 1005 _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) ); 1006 } 1007 columns[i].sType = null; 1008 } 1009 1010 /* Add to the display array */ 1011 oSettings.aiDisplayMaster.push( iRow ); 1012 1013 /* Create the DOM information, or register it if already present */ 1014 if ( nTr || ! oSettings.oFeatures.bDeferRender ) 1015 { 1016 _fnCreateTr( oSettings, iRow, nTr, anTds ); 1017 } 1018 1019 return iRow; 1020 } 1021 1022 1023 /** 1024 * Add one or more TR elements to the table. Generally we'd expect to 1025 * use this for reading data from a DOM sourced table, but it could be 1026 * used for an TR element. Note that if a TR is given, it is used (i.e.
1027 * it is not cloned). 1028 * @param {object} settings dataTables settings object 1029 * @param {array|node|jQuery} trs The TR element(s) to add to the table 1030 * @returns {array} Array of indexes for the added rows 1031 * @memberof DataTable#oApi 1032 */ 1033 function _fnAddTr( settings, trs ) 1034 { 1035 var row; 1036 1037 // Allow an individual node to be passed in 1038 if ( ! (trs instanceof $) ) { 1039 trs = $(trs); 1040 } 1041 1042 return trs.map( function (i, el) { 1043 row = _fnGetRowElements( settings, el ); 1044 return _fnAddData( settings, row.data, el, row.cells ); 1045 } ); 1046 } 1047 1048 1049 /** 1050 * Take a TR element and convert it to an index in aoData 1051 * @param {object} oSettings dataTables settings object 1052 * @param {node} n the TR element to find 1053 * @returns {int} index if the node is found, null if not 1054 * @memberof DataTable#oApi 1055 */ 1056 function _fnNodeToDataIndex( oSettings, n ) 1057 { 1058 return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null; 1059 } 1060 1061 1062 /** 1063 * Take a TD element and convert it into a column data index (not the visible index) 1064 * @param {object} oSettings dataTables settings object 1065 * @param {int} iRow The row number the TD/TH can be found in 1066 * @param {node} n The TD/TH element to find 1067 * @returns {int} index if the node is found, -1 if not 1068 * @memberof DataTable#oApi 1069 */ 1070 function _fnNodeToColumnIndex( oSettings, iRow, n ) 1071 { 1072 return $.inArray( n, oSettings.aoData[ iRow ].anCells ); 1073 } 1074 1075 1076 /** 1077 * Get the data for a given cell from the internal cache, taking into account data mapping 1078 * @param {object} settings dataTables settings object 1079 * @param {int} rowIdx aoData row id 1080 * @param {int} colIdx Column index 1081 * @param {string} type data get type ('display', 'type' 'filter' 'sort') 1082 * @returns {*} Cell data 1083 * @memberof DataTable#oApi 1084 */ 1085 function _fnGetCellData( settings, rowIdx, colIdx, type ) 1086 { 1087 var draw = settings.iDraw; 1088 var col = settings.aoColumns[colIdx]; 1089 var rowData = settings.aoData[rowIdx]._aData; 1090 var defaultContent = col.sDefaultContent; 1091 var cellData = col.fnGetData( rowData, type, { 1092 settings: settings, 1093 row: rowIdx, 1094 col: colIdx 1095 } ); 1096 1097 if ( cellData === undefined ) { 1098 if ( settings.iDrawError != draw && defaultContent === null ) { 1099 _fnLog( settings, 0, "Requested unknown parameter "+ 1100 (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+ 1101 " for row "+rowIdx, 4 ); 1102 settings.iDrawError = draw; 1103 } 1104 return defaultContent; 1105 } 1106 1107 /* When the data source is null, we can use default column data */ 1108 if ( (cellData === rowData || cellData === null) && defaultContent !== null ) { 1109 cellData = defaultContent; 1110 } 1111 else if ( typeof cellData === 'function' ) { 1112 // If the data source is a function, then we run it and use the return, 1113 // executing in the scope of the data object (for instances) 1114 return cellData.call( rowData ); 1115 } 1116 1117 if ( cellData === null && type == 'display' ) { 1118 return ''; 1119 } 1120 return cellData; 1121 } 1122 1123 1124 /** 1125 * Set the value for a specific cell, into the internal data cache 1126 * @param {object} settings dataTables settings object 1127 * @param {int} rowIdx aoData row id 1128 * @param {int} colIdx Column index 1129 * @param {*} val Value to set 1130 * @memberof DataTable#oApi 1131 */ 1132 function _fnSetCellData( settings, rowIdx, colIdx, val ) 1133 { 1134 var col = settings.aoColumns[colIdx]; 1135 var rowData = settings.aoData[rowIdx]._aData; 1136 1137 col.fnSetData( rowData, val, { 1138 settings: settings, 1139 row: rowIdx, 1140 col: colIdx 1141 } ); 1142 } 1143 1144 1145 // Private variable that is used to match action syntax in the data property object 1146 var __reArray = /\[.*?\]$/; 1147 var __reFn = /\(\)$/; 1148 1149 /** 1150 * Split string on periods, taking into account escaped periods 1151 * @param {string} str String to split 1152 * @return {array} Split string 1153 */ 1154 function _fnSplitObjNotation( str ) 1155 { 1156 return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) { 1157 return s.replace(/\\./g, '.'); 1158 } ); 1159 } 1160 1161 1162 /** 1163 * Return a function that can be used to get data from a source object, taking 1164 * into account the ability to use nested objects as a source 1165 * @param {string|int|function} mSource The data source for the object 1166 * @returns {function} Data get function 1167 * @memberof DataTable#oApi 1168 */ 1169 function _fnGetObjectDataFn( mSource ) 1170 { 1171 if ( $.isPlainObject( mSource ) ) 1172 { 1173 /* Build an object of get functions, and wrap them in a single call */ 1174 var o = {}; 1175 $.each( mSource, function (key, val) { 1176 if ( val ) { 1177 o[key] = _fnGetObjectDataFn( val ); 1178 } 1179 } ); 1180 1181 return function (data, type, row, meta) { 1182 var t = o[type] || o._; 1183 return t !== undefined ? 1184 t(data, type, row, meta) : 1185 data; 1186 }; 1187 } 1188 else if ( mSource === null ) 1189 { 1190 /* Give an empty string for rendering / sorting etc */ 1191 return function (data) { // type, row and meta also passed, but not used 1192 return data; 1193 }; 1194 } 1195 else if ( typeof mSource === 'function' ) 1196 { 1197 return function (data, type, row, meta) { 1198 return mSource( data, type, row, meta ); 1199 }; 1200 } 1201 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 1202 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 1203 { 1204 /* If there is a . in the source string then the data source is in a 1205 * nested object so we loop over the data for each level to get the next 1206 * level down. On each loop we test for undefined, and if found immediately 1207 * return. This allows entire objects to be missing and sDefaultContent to 1208 * be used if defined, rather than throwing an error 1209 */
1210 var fetchData = function (data, type, src) { 1211 var arrayNotation, funcNotation, out, innerSrc; 1212 1213 if ( src !== "" ) 1214 { 1215 var a = _fnSplitObjNotation( src ); 1216 1217 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 1218 { 1219 // Check if we are dealing with special notation 1220 arrayNotation = a[i].match(__reArray); 1221 funcNotation = a[i].match(__reFn); 1222 1223 if ( arrayNotation ) 1224 { 1225 // Array notation 1226 a[i] = a[i].replace(__reArray, ''); 1227 1228 // Condition allows simply [] to be passed in 1229 if ( a[i] !== "" ) { 1230 data = data[ a[i] ]; 1231 } 1232 out = []; 1233 1234 // Get the remainder of the nested object to get 1235 a.splice( 0, i+1 ); 1236 innerSrc = a.join('.'); 1237 1238 // Traverse each entry in the array getting the properties requested 1239 for ( var j=0, jLen=data.length ; j<jLen ; j++ ) { 1240 out.push( fetchData( data[j], type, innerSrc ) ); 1241 } 1242 1243 // If a string is given in between the array notation indicators, that 1244 // is used to join the strings together, otherwise an array is returned 1245 var join = arrayNotation[0].substring(1, arrayNotation[0].length-1); 1246 data = (join==="") ? out : out.join(join); 1247 1248 // The inner call to fetchData has already traversed through the remainder 1249 // of the source requested, so we exit from the loop 1250 break; 1251 } 1252 else if ( funcNotation ) 1253 { 1254 // Function call 1255 a[i] = a[i].replace(__reFn, ''); 1256 data = data[ a[i] ](); 1257 continue; 1258 } 1259 1260 if ( data === null || data[ a[i] ] === undefined ) 1261 { 1262 return undefined; 1263 } 1264 data = data[ a[i] ]; 1265 } 1266 } 1267 1268 return data; 1269 }; 1270 1271 return function (data, type) { // row and meta also passed, but not used 1272 return fetchData( data, type, mSource ); 1273 }; 1274 } 1275 else 1276 { 1277 /* Array or flat object mapping */ 1278 return function (data, type) { // row and meta also passed, but not used 1279 return data[mSource]; 1280 }; 1281 } 1282 } 1283 1284 1285 /** 1286 * Return a function that can be used to set data from a source object, taking 1287 * into account the ability to use nested objects as a source 1288 * @param {string|int|function} mSource The data source for the object 1289 * @returns {function} Data set function 1290 * @memberof DataTable#oApi 1291 */ 1292 function _fnSetObjectDataFn( mSource ) 1293 { 1294 if ( $.isPlainObject( mSource ) ) 1295 { 1296 /* Unlike get, only the underscore (global) option is used for for 1297 * setting data since we don't know the type here. This is why an object 1298 * option is not documented for `mData` (which is read/write), but it is 1299 * for `mRender` which is read only. 1300 */ 1301 return _fnSetObjectDataFn( mSource._ ); 1302 } 1303 else if ( mSource === null ) 1304 { 1305 /* Nothing to do when the data source is null */ 1306 return function () {}; 1307 } 1308 else if ( typeof mSource === 'function' ) 1309 { 1310 return function (data, val, meta) { 1311 mSource( data, 'set', val, meta ); 1312 }; 1313 } 1314 else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || 1315 mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) ) 1316 { 1317 /* Like the get, we need to get data from a nested object */ 1318 var setData = function (data, val, src) { 1319 var a = _fnSplitObjNotation( src ), b; 1320 var aLast = a[a.length-1]; 1321 var arrayNotation, funcNotation, o, innerSrc; 1322 1323 for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) 1324 { 1325 // Check if we are dealing with an array notation request 1326 arrayNotation = a[i].match(__reArray); 1327 funcNotation = a[i].match(__reFn); 1328 1329 if ( arrayNotation ) 1330 { 1331 a[i] = a[i].replace(__reArray, ''); 1332 data[ a[i] ] = []; 1333 1334 // Get the remainder of the nested object to set so we can recurse 1335 b = a.slice(); 1336 b.splice( 0, i+1 ); 1337 innerSrc = b.join('.'); 1338 1339 // Traverse each entry in the array setting the properties requested 1340 for ( var j=0, jLen=val.length ; j<jLen ; j++ ) 1341 { 1342 o = {}; 1343 setData( o, val[j], innerSrc ); 1344 data[ a[i] ].push( o ); 1345 } 1346 1347 // The inner call to setData has already traversed through the remainder 1348 // of the source and has set the data, thus we can exit here 1349 return; 1350 } 1351 else if ( funcNotation ) 1352 { 1353 // Function call 1354 a[i] = a[i].replace(__reFn, ''); 1355 data = data[ a[i] ]( val ); 1356 } 1357 1358 // If the nested object doesn't currently exist - since we are 1359 // trying to set the value - create it 1360 if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) 1361 { 1362 data[ a[i] ] = {}; 1363 } 1364 data = data[ a[i] ]; 1365 } 1366 1367 // Last item in the input - i.e, the actual set 1368 if ( aLast.match(__reFn ) ) 1369 { 1370 // Function call 1371 data = data[ aLast.replace(__reFn, '') ]( val ); 1372 } 1373 else 1374 { 1375 // If array notation is used, we just want to strip it and use the property name 1376 // and assign the value. If it isn't used, then we get the result we want anyway 1377 data[ aLast.replace(__reArray, '') ] = val; 1378 } 1379 }; 1380 1381 return function (data, val) { // meta is also passed in, but not used 1382 return setData( data, val, mSource ); 1383 }; 1384 } 1385 else 1386 { 1387 /* Array or flat object mapping */ 1388 return function (data, val) { // meta is also passed in, but not used 1389 data[mSource] = val; 1390 }; 1391 } 1392 } 1393 1394 1395 /** 1396 * Return an array with the full table data 1397 * @param {object} oSettings dataTables settings object 1398 * @returns array {array} aData Master data array 1399 * @memberof DataTable#oApi 1400 */ 1401 function _fnGetDataMaster ( settings ) 1402 { 1403 return _pluck( settings.aoData, '_aData' ); 1404 } 1405 1406 1407 /** 1408 * Nuke the table 1409 * @param {object} oSettings dataTables settings object 1410 * @memberof DataTable#oApi 1411 */ 1412 function _fnClearTable( settings ) 1413 { 1414 settings.aoData.length = 0; 1415 settings.aiDisplayMaster.length = 0; 1416 settings.aiDisplay.length = 0; 1417 } 1418 1419 1420 /** 1421 * Take an array of integers (index array) and remove a target integer (value - not 1422 * the key!) 1423 * @param {array} a Index array to target 1424 * @param {int} iTarget value to find 1425 * @memberof DataTable#oApi 1426 */ 1427 function _fnDeleteIndex( a, iTarget, splice ) 1428 { 1429 var iTargetIndex = -1; 1430 1431 for ( var i=0, iLen=a.length ; i<iLen ; i++ ) 1432 { 1433 if ( a[i] == iTarget ) 1434 { 1435 iTargetIndex = i; 1436 } 1437 else if ( a[i] > iTarget ) 1438 { 1439 a[i]--; 1440 } 1441 } 1442 1443 if ( iTargetIndex != -1 && splice === undefined ) 1444 { 1445 a.splice( iTargetIndex, 1 ); 1446 } 1447 } 1448 1449 1450 /**
1451 * Mark cached data as invalid such that a re-read of the data will occur when 1452 * the cached data is next requested. Also update from the data source object. 1453 * 1454 * @param {object} settings DataTables settings object 1455 * @param {int} rowIdx Row index to invalidate 1456 * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom' 1457 * or 'data' 1458 * @param {int} [colIdx] Column index to invalidate. If undefined the whole 1459 * row will be invalidated 1460 * @memberof DataTable#oApi 1461 * 1462 * @todo For the modularisation of v1.11 this will need to become a callback, so 1463 * the sort and filter methods can subscribe to it. That will required 1464 * initialisation options for sorting, which is why it is not already baked in 1465 */ 1466 function _fnInvalidate( settings, rowIdx, src, colIdx ) 1467 { 1468 var row = settings.aoData[ rowIdx ]; 1469 var i, ien; 1470 var cellWrite = function ( cell, col ) { 1471 // This is very frustrating, but in IE if you just write directly 1472 // to innerHTML, and elements that are overwritten are GC'ed, 1473 // even if there is a reference to them elsewhere 1474 while ( cell.childNodes.length ) { 1475 cell.removeChild( cell.firstChild ); 1476 } 1477 1478 cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' ); 1479 }; 1480 1481 // Are we reading last data from DOM or the data object? 1482 if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) { 1483 // Read the data from the DOM 1484 row._aData = _fnGetRowElements( 1485 settings, row, colIdx, colIdx === undefined ? undefined : row._aData 1486 ) 1487 .data; 1488 } 1489 else { 1490 // Reading from data object, update the DOM 1491 var cells = row.anCells; 1492 1493 if ( cells ) { 1494 if ( colIdx !== undefined ) { 1495 cellWrite( cells[colIdx], colIdx ); 1496 } 1497 else { 1498 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 1499 cellWrite( cells[i], i ); 1500 } 1501 } 1502 } 1503 } 1504 1505 // For both row and cell invalidation, the cached data for sorting and 1506 // filtering is nulled out 1507 row._aSortData = null; 1508 row._aFilterData = null; 1509 1510 // Invalidate the type for a specific column (if given) or all columns since 1511 // the data might have changed 1512 var cols = settings.aoColumns; 1513 if ( colIdx !== undefined ) { 1514 cols[ colIdx ].sType = null; 1515 } 1516 else { 1517 for ( i=0, ien=cols.length ; i<ien ; i++ ) { 1518 cols[i].sType = null; 1519 } 1520 1521 // Update DataTables special `DT_*` attributes for the row 1522 _fnRowAttributes( row ); 1523 } 1524 } 1525 1526 1527 /** 1528 * Build a data source object from an HTML row, reading the contents of the 1529 * cells that are in the row. 1530 * 1531 * @param {object} settings DataTables settings object 1532 * @param {node|object} TR element from which to read data or existing row 1533 * object from which to re-read the data from the cells 1534 * @param {int} [colIdx] Optional column index 1535 * @param {array|object} [d] Data source object. If `colIdx` is given then this 1536 * parameter should also be given and will be used to write the data into. 1537 * Only the column in question will be written 1538 * @returns {object} Object with two parameters: `data` the data read, in 1539 * document order, and `cells` and array of nodes (they can be useful to the 1540 * caller, so rather than needing a second traversal to get them, just return 1541 * them from here). 1542 * @memberof DataTable#oApi 1543 */ 1544 function _fnGetRowElements( settings, row, colIdx, d ) 1545 { 1546 var 1547 tds = [], 1548 td = row.firstChild, 1549 name, col, o, i=0, contents, 1550 columns = settings.aoColumns, 1551 objectRead = settings._rowReadObject; 1552 1553 // Allow the data object to be passed in, or construct 1554 d = d || objectRead ? {} : []; 1555 1556 var attr = function ( str, td ) { 1557 if ( typeof str === 'string' ) { 1558 var idx = str.indexOf('@'); 1559 1560 if ( idx !== -1 ) { 1561 var attr = str.substring( idx+1 ); 1562 var setter = _fnSetObjectDataFn( str ); 1563 setter( d, td.getAttribute( attr ) ); 1564 } 1565 } 1566 }; 1567 1568 // Read data from a cell and store into the data object 1569 var cellProcess = function ( cell ) { 1570 if ( colIdx === undefined || colIdx === i ) { 1571 col = columns[i]; 1572 contents = $.trim(cell.innerHTML); 1573 1574 if ( col && col._bAttrSrc ) { 1575 var setter = _fnSetObjectDataFn( col.mData._ ); 1576 setter( d, contents ); 1577 1578 attr( col.mData.sort, cell ); 1579 attr( col.mData.type, cell ); 1580 attr( col.mData.filter, cell ); 1581 } 1582 else { 1583 // Depending on the `data` option for the columns the data can 1584 // be read to either an object or an array.
1585 if ( objectRead ) { 1586 if ( ! col._setter ) { 1587 // Cache the setter function 1588 col._setter = _fnSetObjectDataFn( col.mData ); 1589 } 1590 col._setter( d, contents ); 1591 } 1592 else { 1593 d[i] = contents; 1594 } 1595 } 1596 } 1597 1598 i++; 1599 }; 1600 1601 if ( td ) { 1602 // `tr` element was passed in 1603 while ( td ) { 1604 name = td.nodeName.toUpperCase(); 1605 1606 if ( name == "TD" || name == "TH" ) { 1607 cellProcess( td ); 1608 tds.push( td ); 1609 } 1610 1611 td = td.nextSibling; 1612 } 1613 } 1614 else { 1615 // Existing row object passed in 1616 tds = row.anCells; 1617 1618 for ( var j=0, jen=tds.length ; j<jen ; j++ ) { 1619 cellProcess( tds[j] ); 1620 } 1621 } 1622 1623 return { 1624 data: d, 1625 cells: tds 1626 }; 1627 } 1628 /** 1629 * Create a new TR element (and it's TD children) for a row 1630 * @param {object} oSettings dataTables settings object 1631 * @param {int} iRow Row to consider 1632 * @param {node} [nTrIn] TR element to add to the table - optional. If not given, 1633 * DataTables will create a row automatically 1634 * @param {array} [anTds] Array of TD|TH elements for the row - must be given 1635 * if nTr is. 1636 * @memberof DataTable#oApi 1637 */ 1638 function _fnCreateTr ( oSettings, iRow, nTrIn, anTds ) 1639 { 1640 var 1641 row = oSettings.aoData[iRow], 1642 rowData = row._aData, 1643 cells = [], 1644 nTr, nTd, oCol, 1645 i, iLen; 1646 1647 if ( row.nTr === null ) 1648 { 1649 nTr = nTrIn || document.createElement('tr'); 1650 1651 row.nTr = nTr; 1652 row.anCells = cells; 1653 1654 /* Use a private property on the node to allow reserve mapping from the node 1655 * to the aoData array for fast look up 1656 */ 1657 nTr._DT_RowIndex = iRow; 1658 1659 /* Special parameters can be given by the data source to be used on the row */ 1660 _fnRowAttributes( row ); 1661 1662 /* Process each column */ 1663 for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ ) 1664 { 1665 oCol = oSettings.aoColumns[i]; 1666 1667 nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType ); 1668 cells.push( nTd ); 1669 1670 // Need to create the HTML if new, or if a rendering function is defined 1671 if ( !nTrIn || oCol.mRender || oCol.mData !== i ) 1672 { 1673 nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' ); 1674 } 1675 1676 /* Add user defined class */ 1677 if ( oCol.sClass ) 1678 { 1679 nTd.className += ' '+oCol.sClass; 1680 } 1681 1682 // Visibility - add or remove as required 1683 if ( oCol.bVisible && ! nTrIn ) 1684 { 1685 nTr.appendChild( nTd ); 1686 } 1687 else if ( ! oCol.bVisible && nTrIn ) 1688 { 1689 nTd.parentNode.removeChild( nTd ); 1690 } 1691 1692 if ( oCol.fnCreatedCell ) 1693 { 1694 oCol.fnCreatedCell.call( oSettings.oInstance, 1695 nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i 1696 ); 1697 } 1698 } 1699 1700 _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] ); 1701 } 1702 1703 // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved 1704 // and deployed 1705 row.nTr.setAttribute( 'role', 'row' ); 1706 } 1707 1708 1709 /** 1710 * Add attributes to a row based on the special `DT_*` parameters in a data 1711 * source object. 1712 * @param {object} DataTables row object for the row to be modified 1713 * @memberof DataTable#oApi 1714 */ 1715 function _fnRowAttributes( row ) 1716 { 1717 var tr = row.nTr; 1718 var data = row._aData; 1719 1720 if ( tr ) { 1721 if ( data.DT_RowId ) { 1722 tr.id = data.DT_RowId; 1723 } 1724 1725 if ( data.DT_RowClass ) { 1726 // Remove any classes added by DT_RowClass before 1727 var a = data.DT_RowClass.split(' '); 1728 row.__rowc = row.__rowc ? 1729 _unique( row.__rowc.concat( a ) ) : 1730 a; 1731 1732 $(tr) 1733 .removeClass( row.__rowc.join(' ') ) 1734 .addClass( data.DT_RowClass ); 1735 } 1736 1737 if ( data.DT_RowAttr ) { 1738 $(tr).attr( data.DT_RowAttr ); 1739 } 1740 1741 if ( data.DT_RowData ) { 1742 $(tr).data( data.DT_RowData ); 1743 } 1744 } 1745 } 1746 1747 1748 /** 1749 * Create the HTML header for the table 1750 * @param {object} oSettings dataTables settings object 1751 * @memberof DataTable#oApi 1752 */ 1753 function _fnBuildHead( oSettings ) 1754 { 1755 var i, ien, cell, row, column; 1756 var thead = oSettings.nTHead; 1757 var tfoot = oSettings.nTFoot; 1758 var createHeader = $('th, td', thead).length === 0; 1759 var classes = oSettings.oClasses; 1760 var columns = oSettings.aoColumns; 1761 1762 if ( createHeader ) { 1763 row = $('<tr/>').appendTo( thead ); 1764 } 1765 1766 for ( i=0, ien=columns.length ; i<ien ; i++ ) { 1767 column = columns[i]; 1768 cell = $( column.nTh ).addClass( column.sClass ); 1769 1770 if ( createHeader ) { 1771 cell.appendTo( row ); 1772 } 1773 1774 // 1.11 move into sorting 1775 if ( oSettings.oFeatures.bSort ) { 1776 cell.addClass( column.sSortingClass ); 1777 1778 if ( column.bSortable !== false ) { 1779 cell 1780 .attr( 'tabindex', oSettings.iTabIndex ) 1781 .attr( 'aria-controls', oSettings.sTableId ); 1782 1783 _fnSortAttachListener( oSettings, column.nTh, i ); 1784 } 1785 } 1786 1787 if ( column.sTitle != cell.html() ) { 1788 cell.html( column.sTitle ); 1789 } 1790 1791 _fnRenderer( oSettings, 'header' )( 1792 oSettings, cell, column, classes 1793 ); 1794 } 1795 1796 if ( createHeader ) { 1797 _fnDetectHeader( oSettings.aoHeader, thead ); 1798 } 1799 1800 /* ARIA role for the rows */ 1801 $(thead).find('>tr').attr('role', 'row'); 1802 1803 /* Deal with the footer - add classes if required */ 1804 $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH ); 1805 $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH ); 1806 1807 // Cache the footer cells. Note that we only take the cells from the first 1808 // row in the footer. If there is more than one row the user wants to 1809 // interact with, they need to use the table().foot() method. Note also this 1810 // allows cells to be used for multiple columns using colspan 1811 if ( tfoot !== null ) { 1812 var cells = oSettings.aoFooter[0]; 1813 1814 for ( i=0, ien=cells.length ; i<ien ; i++ ) { 1815 column = columns[i]; 1816 column.nTf = cells[i].cell; 1817 1818 if ( column.sClass ) { 1819 $(column.nTf).addClass( column.sClass ); 1820 } 1821 } 1822 } 1823 } 1824 1825 1826 /** 1827 * Draw the header (or footer) element based on the column visibility states. The 1828 * methodology here is to use the layout array from _fnDetectHeader, modified for 1829 * the instantaneous column visibility, to construct the new layout. The grid is 1830 * traversed over cell at a time in a rows x columns grid fashion, although each 1831 * cell insert can cover multiple elements in the grid - which is tracks using the 1832 * aApplied array. Cell inserts in the grid will only occur where there isn't 1833 * already a cell in that position. 1834 * @param {object} oSettings dataTables settings object 1835 * @param array {objects} aoSource Layout array from _fnDetectHeader 1836 * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 1837 * @memberof DataTable#oApi 1838 */ 1839 function _fnDrawHead( oSettings, aoSource, bIncludeHidden ) 1840 { 1841 var i, iLen, j, jLen, k, kLen, n, nLocalTr; 1842 var aoLocal = []; 1843 var aApplied = []; 1844 var iColumns = oSettings.aoColumns.length; 1845 var iRowspan, iColspan; 1846 1847 if ( ! aoSource ) 1848 { 1849 return; 1850 } 1851 1852 if ( bIncludeHidden === undefined ) 1853 { 1854 bIncludeHidden = false;
1855 } 1856 1857 /* Make a copy of the master layout array, but without the visible columns in it */ 1858 for ( i=0, iLen=aoSource.length ; i<iLen ; i++ ) 1859 { 1860 aoLocal[i] = aoSource[i].slice(); 1861 aoLocal[i].nTr = aoSource[i].nTr; 1862 1863 /* Remove any columns which are currently hidden */ 1864 for ( j=iColumns-1 ; j>=0 ; j-- ) 1865 { 1866 if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden ) 1867 { 1868 aoLocal[i].splice( j, 1 ); 1869 } 1870 } 1871 1872 /* Prep the applied array - it needs an element for each row */ 1873 aApplied.push( [] ); 1874 } 1875 1876 for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ ) 1877 { 1878 nLocalTr = aoLocal[i].nTr; 1879 1880 /* All cells are going to be replaced, so empty out the row */ 1881 if ( nLocalTr ) 1882 { 1883 while( (n = nLocalTr.firstChild) ) 1884 { 1885 nLocalTr.removeChild( n ); 1886 } 1887 } 1888 1889 for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ ) 1890 { 1891 iRowspan = 1; 1892 iColspan = 1; 1893 1894 /* Check to see if there is already a cell (row/colspan) covering our target 1895 * insert point. If there is, then there is nothing to do. 1896 */ 1897 if ( aApplied[i][j] === undefined ) 1898 { 1899 nLocalTr.appendChild( aoLocal[i][j].cell ); 1900 aApplied[i][j] = 1; 1901 1902 /* Expand the cell to cover as many rows as needed */ 1903 while ( aoLocal[i+iRowspan] !== undefined && 1904 aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell ) 1905 { 1906 aApplied[i+iRowspan][j] = 1; 1907 iRowspan++; 1908 } 1909 1910 /* Expand the cell to cover as many columns as needed */ 1911 while ( aoLocal[i][j+iColspan] !== undefined && 1912 aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell ) 1913 { 1914 /* Must update the applied array over the rows for the columns */ 1915 for ( k=0 ; k<iRowspan ; k++ ) 1916 { 1917 aApplied[i+k][j+iColspan] = 1; 1918 } 1919 iColspan++; 1920 } 1921 1922 /* Do the actual expansion in the DOM */ 1923 $(aoLocal[i][j].cell) 1924 .attr('rowspan', iRowspan) 1925 .attr('colspan', iColspan); 1926 } 1927 } 1928 } 1929 } 1930 1931 1932 /** 1933 * Insert the required TR nodes into the table for display 1934 * @param {object} oSettings dataTables settings object 1935 * @memberof DataTable#oApi 1936 */ 1937 function _fnDraw( oSettings ) 1938 { 1939 /* Provide a pre-callback function which can be used to cancel the draw is false is returned */ 1940 var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] ); 1941 if ( $.inArray( false, aPreDraw ) !== -1 ) 1942 { 1943 _fnProcessingDisplay( oSettings, false ); 1944 return; 1945 } 1946 1947 var i, iLen, n; 1948 var anRows = []; 1949 var iRowCount = 0; 1950 var asStripeClasses = oSettings.asStripeClasses; 1951 var iStripes = asStripeClasses.length; 1952 var iOpenRows = oSettings.aoOpenRows.length; 1953 var oLang = oSettings.oLanguage; 1954 var iInitDisplayStart = oSettings.iInitDisplayStart; 1955 var bServerSide = _fnDataSource( oSettings ) == 'ssp'; 1956 var aiDisplay = oSettings.aiDisplay; 1957 1958 oSettings.bDrawing = true; 1959 1960 /* Check and see if we have an initial draw position from state saving */ 1961 if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 ) 1962 { 1963 oSettings._iDisplayStart = bServerSide ? 1964 iInitDisplayStart : 1965 iInitDisplayStart >= oSettings.fnRecordsDisplay() ? 1966 0 : 1967 iInitDisplayStart; 1968 1969 oSettings.iInitDisplayStart = -1; 1970 } 1971 1972 var iDisplayStart = oSettings._iDisplayStart; 1973 var iDisplayEnd = oSettings.fnDisplayEnd(); 1974 1975 /* Server-side processing draw intercept */ 1976 if ( oSettings.bDeferLoading ) 1977 { 1978 oSettings.bDeferLoading = false; 1979 oSettings.iDraw++; 1980 _fnProcessingDisplay( oSettings, false ); 1981 } 1982 else if ( !bServerSide ) 1983 { 1984 oSettings.iDraw++; 1985 } 1986 else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) ) 1987 { 1988 return; 1989 } 1990 1991 if ( aiDisplay.length !== 0 ) 1992 { 1993 var iStart = bServerSide ? 0 : iDisplayStart; 1994 var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd; 1995 1996 for ( var j=iStart ; j<iEnd ; j++ ) 1997 { 1998 var iDataIndex = aiDisplay[j]; 1999 var aoData = oSettings.aoData[ iDataIndex ]; 2000 if ( aoData.nTr === null ) 2001 { 2002 _fnCreateTr( oSettings, iDataIndex ); 2003 } 2004 2005 var nRow = aoData.nTr; 2006 2007 /* Remove the old striping classes and then add the new one */ 2008 if ( iStripes !== 0 ) 2009 { 2010 var sStripe = asStripeClasses[ iRowCount % iStripes ]; 2011 if ( aoData._sRowStripe != sStripe ) 2012 { 2013 $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe ); 2014 aoData._sRowStripe = sStripe; 2015 } 2016 } 2017 2018 // Row callback functions - might want to manipulate the row 2019 // iRowCount and j are not currently documented. Are they at all 2020 // useful? 2021 _fnCallbackFire( oSettings, 'aoRowCallback', null, 2022 [nRow, aoData._aData, iRowCount, j] ); 2023 2024 anRows.push( nRow ); 2025 iRowCount++; 2026 } 2027 } 2028 else 2029 { 2030 /* Table is empty - create a row with an empty message in it */ 2031 var sZero = oLang.sZeroRecords; 2032 if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' ) 2033 { 2034 sZero = oLang.sLoadingRecords; 2035 } 2036 else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 ) 2037 { 2038 sZero = oLang.sEmptyTable; 2039 } 2040 2041 anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } ) 2042 .append( $('<td />', { 2043 'valign': 'top', 2044 'colSpan': _fnVisbleColumns( oSettings ), 2045 'class': oSettings.oClasses.sRowEmpty 2046 } ).html( sZero ) )[0]; 2047 } 2048 2049 /* Header and footer callbacks */ 2050 _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 2051 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 2052 2053 _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 2054 _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] ); 2055 2056 var body = $(oSettings.nTBody); 2057 2058 body.children().detach(); 2059 body.append( $(anRows) ); 2060 2061 /* Call all required callback functions for the end of a draw */ 2062 _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] ); 2063 2064 /* Draw is complete, sorting and filtering must be as well */ 2065 oSettings.bSorted = false;
2066 oSettings.bFiltered = false; 2067 oSettings.bDrawing = false; 2068 } 2069 2070 2071 /** 2072 * Redraw the table - taking account of the various features which are enabled 2073 * @param {object} oSettings dataTables settings object 2074 * @param {boolean} [holdPosition] Keep the current paging position. By default 2075 * the paging is reset to the first page 2076 * @memberof DataTable#oApi 2077 */ 2078 function _fnReDraw( settings, holdPosition ) 2079 { 2080 var 2081 features = settings.oFeatures, 2082 sort = features.bSort, 2083 filter = features.bFilter; 2084 2085 if ( sort ) { 2086 _fnSort( settings ); 2087 } 2088 2089 if ( filter ) { 2090 _fnFilterComplete( settings, settings.oPreviousSearch ); 2091 } 2092 else { 2093 // No filtering, so we want to just use the display master 2094 settings.aiDisplay = settings.aiDisplayMaster.slice(); 2095 } 2096 2097 if ( holdPosition !== true ) { 2098 settings._iDisplayStart = 0; 2099 } 2100 2101 // Let any modules know about the draw hold position state (used by 2102 // scrolling internally) 2103 settings._drawHold = holdPosition; 2104 2105 _fnDraw( settings ); 2106 2107 settings._drawHold = false; 2108 } 2109 2110 2111 /** 2112 * Add the options to the page HTML for the table 2113 * @param {object} oSettings dataTables settings object 2114 * @memberof DataTable#oApi 2115 */ 2116 function _fnAddOptionsHtml ( oSettings ) 2117 { 2118 var classes = oSettings.oClasses; 2119 var table = $(oSettings.nTable); 2120 var holding = $('<div/>').insertBefore( table ); // Holding element for speed 2121 var features = oSettings.oFeatures; 2122 2123 // All DataTables are wrapped in a div 2124 var insert = $('<div/>', { 2125 id: oSettings.sTableId+'_wrapper', 2126 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter) 2127 } ); 2128 2129 oSettings.nHolding = holding[0]; 2130 oSettings.nTableWrapper = insert[0]; 2131 oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling; 2132
2133 /* Loop over the user set positioning and place the elements as needed */ 2134 var aDom = oSettings.sDom.split(''); 2135 var featureNode, cOption, nNewNode, cNext, sAttr, j; 2136 for ( var i=0 ; i<aDom.length ; i++ ) 2137 { 2138 featureNode = null; 2139 cOption = aDom[i]; 2140 2141 if ( cOption == '<' ) 2142 { 2143 /* New container div */ 2144 nNewNode = $('<div/>')[0]; 2145 2146 /* Check to see if we should append an id and/or a class name to the container */ 2147 cNext = aDom[i+1]; 2148 if ( cNext == "'" || cNext == '"' ) 2149 { 2150 sAttr = ""; 2151 j = 2; 2152 while ( aDom[i+j] != cNext ) 2153 { 2154 sAttr += aDom[i+j]; 2155 j++; 2156 } 2157 2158 /* Replace jQuery UI constants @todo depreciated */ 2159 if ( sAttr == "H" ) 2160 { 2161 sAttr = classes.sJUIHeader; 2162 } 2163 else if ( sAttr == "F" ) 2164 { 2165 sAttr = classes.sJUIFooter; 2166 } 2167 2168 /* The attribute can be in the format of "#id.class", "#id" or "class" This logic 2169 * breaks the string into parts and applies them as needed 2170 */ 2171 if ( sAttr.indexOf('.') != -1 ) 2172 { 2173 var aSplit = sAttr.split('.'); 2174 nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1); 2175 nNewNode.className = aSplit[1]; 2176 } 2177 else if ( sAttr.charAt(0) == "#" ) 2178 { 2179 nNewNode.id = sAttr.substr(1, sAttr.length-1); 2180 } 2181 else 2182 { 2183 nNewNode.className = sAttr; 2184 } 2185 2186 i += j; /* Move along the position array */ 2187 } 2188 2189 insert.append( nNewNode ); 2190 insert = $(nNewNode); 2191 } 2192 else if ( cOption == '>' ) 2193 { 2194 /* End container div */ 2195 insert = insert.parent(); 2196 } 2197 // @todo Move options into their own plugins? 2198 else if ( cOption == 'l' && features.bPaginate && features.bLengthChange ) 2199 { 2200 /* Length */ 2201 featureNode = _fnFeatureHtmlLength( oSettings ); 2202 } 2203 else if ( cOption == 'f' && features.bFilter ) 2204 { 2205 /* Filter */ 2206 featureNode = _fnFeatureHtmlFilter( oSettings ); 2207 } 2208 else if ( cOption == 'r' && features.bProcessing ) 2209 { 2210 /* pRocessing */ 2211 featureNode = _fnFeatureHtmlProcessing( oSettings ); 2212 } 2213 else if ( cOption == 't' ) 2214 { 2215 /* Table */ 2216 featureNode = _fnFeatureHtmlTable( oSettings ); 2217 } 2218 else if ( cOption == 'i' && features.bInfo ) 2219 { 2220 /* Info */ 2221 featureNode = _fnFeatureHtmlInfo( oSettings ); 2222 } 2223 else if ( cOption == 'p' && features.bPaginate ) 2224 { 2225 /* Pagination */ 2226 featureNode = _fnFeatureHtmlPaginate( oSettings ); 2227 } 2228 else if ( DataTable.ext.feature.length !== 0 ) 2229 { 2230 /* Plug-in features */ 2231 var aoFeatures = DataTable.ext.feature; 2232 for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ ) 2233 { 2234 if ( cOption == aoFeatures[k].cFeature ) 2235 { 2236 featureNode = aoFeatures[k].fnInit( oSettings ); 2237 break; 2238 } 2239 } 2240 } 2241 2242 /* Add to the 2D features array */ 2243 if ( featureNode ) 2244 { 2245 var aanFeatures = oSettings.aanFeatures; 2246 2247 if ( ! aanFeatures[cOption] ) 2248 { 2249 aanFeatures[cOption] = []; 2250 } 2251 2252 aanFeatures[cOption].push( featureNode ); 2253 insert.append( featureNode ); 2254 } 2255 } 2256 2257 /* Built our DOM structure - replace the holding div with what we want */ 2258 holding.replaceWith( insert ); 2259 } 2260 2261 2262 /** 2263 * Use the DOM source to create up an array of header cells. The idea here is to 2264 * create a layout grid (array) of rows x columns, which contains a reference 2265 * to the cell that that point in the grid (regardless of col/rowspan), such that 2266 * any column / row could be removed and the new grid constructed 2267 * @param array {object} aLayout Array to store the calculated layout in 2268 * @param {node} nThead The header/footer element for the table 2269 * @memberof DataTable#oApi 2270 */ 2271 function _fnDetectHeader ( aLayout, nThead ) 2272 { 2273 var nTrs = $(nThead).children('tr'); 2274 var nTr, nCell; 2275 var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan; 2276 var bUnique; 2277 var fnShiftCol = function ( a, i, j ) { 2278 var k = a[i]; 2279 while ( k[j] ) { 2280 j++; 2281 } 2282 return j; 2283 }; 2284 2285 aLayout.splice( 0, aLayout.length ); 2286 2287 /* We know how many rows there are in the layout - so prep it */ 2288 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 2289 { 2290 aLayout.push( [] ); 2291 } 2292 2293 /* Calculate a layout array */ 2294 for ( i=0, iLen=nTrs.length ; i<iLen ; i++ ) 2295 { 2296 nTr = nTrs[i]; 2297 iColumn = 0; 2298 2299 /* For every cell in the row... */ 2300 nCell = nTr.firstChild; 2301 while ( nCell ) { 2302 if ( nCell.nodeName.toUpperCase() == "TD" || 2303 nCell.nodeName.toUpperCase() == "TH" ) 2304 { 2305 /* Get the col and rowspan attributes from the DOM and sanitise them */ 2306 iColspan = nCell.getAttribute('colspan') * 1;
2307 iRowspan = nCell.getAttribute('rowspan') * 1; 2308 iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan; 2309 iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan; 2310 2311 /* There might be colspan cells already in this row, so shift our target 2312 * accordingly 2313 */ 2314 iColShifted = fnShiftCol( aLayout, i, iColumn ); 2315 2316 /* Cache calculation for unique columns */ 2317 bUnique = iColspan === 1 ? true : false; 2318 2319 /* If there is col / rowspan, copy the information into the layout grid */ 2320 for ( l=0 ; l<iColspan ; l++ ) 2321 { 2322 for ( k=0 ; k<iRowspan ; k++ ) 2323 { 2324 aLayout[i+k][iColShifted+l] = { 2325 "cell": nCell, 2326 "unique": bUnique 2327 }; 2328 aLayout[i+k].nTr = nTr; 2329 } 2330 } 2331 } 2332 nCell = nCell.nextSibling; 2333 } 2334 } 2335 } 2336 2337 2338 /** 2339 * Get an array of unique th elements, one for each column 2340 * @param {object} oSettings dataTables settings object 2341 * @param {node} nHeader automatically detect the layout from this node - optional 2342 * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional 2343 * @returns array {node} aReturn list of unique th's 2344 * @memberof DataTable#oApi 2345 */ 2346 function _fnGetUniqueThs ( oSettings, nHeader, aLayout ) 2347 { 2348 var aReturn = []; 2349 if ( !aLayout ) 2350 { 2351 aLayout = oSettings.aoHeader; 2352 if ( nHeader ) 2353 { 2354 aLayout = []; 2355 _fnDetectHeader( aLayout, nHeader ); 2356 } 2357 } 2358 2359 for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ ) 2360 { 2361 for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ ) 2362 { 2363 if ( aLayout[i][j].unique && 2364 (!aReturn[j] || !oSettings.bSortCellsTop) ) 2365 { 2366 aReturn[j] = aLayout[i][j].cell; 2367 } 2368 } 2369 } 2370 2371 return aReturn; 2372 } 2373 2374 2375 2376 /** 2377 * Create an Ajax call based on the table's settings, taking into account that 2378 * parameters can have multiple forms, and backwards compatibility. 2379 * 2380 * @param {object} oSettings dataTables settings object 2381 * @param {array} data Data to send to the server, required by 2382 * DataTables - may be augmented by developer callbacks 2383 * @param {function} fn Callback function to run when data is obtained 2384 */ 2385 function _fnBuildAjax( oSettings, data, fn ) 2386 { 2387 // Compatibility with 1.9-, allow fnServerData and event to manipulate 2388 _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] ); 2389 2390 // Convert to object based for 1.10+ if using the old array scheme which can 2391 // come from server-side processing or serverParams 2392 if ( data && $.isArray(data) ) { 2393 var tmp = {}; 2394 var rbracket = /(.*?)\[\]$/; 2395 2396 $.each( data, function (key, val) { 2397 var match = val.name.match(rbracket); 2398 2399 if ( match ) { 2400 // Support for arrays 2401 var name = match[0]; 2402 2403 if ( ! tmp[ name ] ) { 2404 tmp[ name ] = []; 2405 } 2406 tmp[ name ].push( val.value ); 2407 } 2408 else { 2409 tmp[val.name] = val.value; 2410 } 2411 } ); 2412 data = tmp; 2413 } 2414 2415 var ajaxData; 2416 var ajax = oSettings.ajax; 2417 var instance = oSettings.oInstance; 2418 2419 if ( $.isPlainObject( ajax ) && ajax.data ) 2420 { 2421 ajaxData = ajax.data; 2422 2423 var newData = $.isFunction( ajaxData ) ? 2424 ajaxData( data ) : // fn can manipulate data or return an object 2425 ajaxData; // object or array to merge 2426 2427 // If the function returned something, use that alone 2428 data = $.isFunction( ajaxData ) && newData ? 2429 newData : 2430 $.extend( true, data, newData ); 2431 2432 // Remove the data property as we've resolved it already and don't want 2433 // jQuery to do it again (it is restored at the end of the function) 2434 delete ajax.data; 2435 } 2436 2437 var baseAjax = { 2438 "data": data, 2439 "success": function (json) { 2440 var error = json.error || json.sError; 2441 if ( error ) { 2442 oSettings.oApi._fnLog( oSettings, 0, error ); 2443 } 2444 2445 oSettings.json = json; 2446 _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] ); 2447 fn( json ); 2448 }, 2449 "dataType": "json", 2450 "cache": false, 2451 "type": oSettings.sServerMethod, 2452 "error": function (xhr, error, thrown) { 2453 var log = oSettings.oApi._fnLog; 2454 2455 if ( error == "parsererror" ) { 2456 log( oSettings, 0, 'Invalid JSON response', 1 ); 2457 } 2458 else if ( xhr.readyState === 4 ) { 2459 log( oSettings, 0, 'Ajax error', 7 ); 2460 } 2461 2462 _fnProcessingDisplay( oSettings, false ); 2463 } 2464 }; 2465 2466 // Store the data submitted for the API 2467 oSettings.oAjaxData = data; 2468 2469 // Allow plug-ins and external processes to modify the data 2470 _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] ); 2471 2472 if ( oSettings.fnServerData ) 2473 { 2474 // DataTables 1.9- compatibility 2475 oSettings.fnServerData.call( instance, 2476 oSettings.sAjaxSource, 2477 $.map( data, function (val, key) { // Need to convert back to 1.9 trad format 2478 return { name: key, value: val }; 2479 } ), 2480 fn, 2481 oSettings 2482 ); 2483 } 2484 else if ( oSettings.sAjaxSource || typeof ajax === 'string' ) 2485 { 2486 // DataTables 1.9- compatibility 2487 oSettings.jqXHR = $.ajax( $.extend( baseAjax, { 2488 url: ajax || oSettings.sAjaxSource 2489 } ) ); 2490 } 2491 else if ( $.isFunction( ajax ) ) 2492 { 2493 // Is a function - let the caller define what needs to be done 2494 oSettings.jqXHR = ajax.call( instance, data, fn, oSettings ); 2495 } 2496 else 2497 { 2498 // Object to extend the base settings 2499 oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) ); 2500 2501 // Restore for next time around 2502 ajax.data = ajaxData; 2503 } 2504 } 2505 2506 2507 /** 2508 * Update the table using an Ajax call 2509 * @param {object} settings dataTables settings object 2510 * @returns {boolean} Block the table drawing or not 2511 * @memberof DataTable#oApi 2512 */ 2513 function _fnAjaxUpdate( settings ) 2514 { 2515 if ( settings.bAjaxDataGet ) { 2516 settings.iDraw++; 2517 _fnProcessingDisplay( settings, true ); 2518 2519 _fnBuildAjax( 2520 settings, 2521 _fnAjaxParameters( settings ), 2522 function(json) { 2523 _fnAjaxUpdateDraw( settings, json ); 2524 } 2525 ); 2526 2527 return false;
2528 } 2529 return true; 2530 } 2531 2532 2533 /** 2534 * Build up the parameters in an object needed for a server-side processing 2535 * request. Note that this is basically done twice, is different ways - a modern 2536 * method which is used by default in DataTables 1.10 which uses objects and 2537 * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if 2538 * the sAjaxSource option is used in the initialisation, or the legacyAjax 2539 * option is set. 2540 * @param {object} oSettings dataTables settings object 2541 * @returns {bool} block the table drawing or not 2542 * @memberof DataTable#oApi 2543 */ 2544 function _fnAjaxParameters( settings ) 2545 { 2546 var 2547 columns = settings.aoColumns, 2548 columnCount = columns.length, 2549 features = settings.oFeatures, 2550 preSearch = settings.oPreviousSearch, 2551 preColSearch = settings.aoPreSearchCols, 2552 i, data = [], dataProp, column, columnSearch, 2553 sort = _fnSortFlatten( settings ), 2554 displayStart = settings._iDisplayStart, 2555 displayLength = features.bPaginate !== false ? 2556 settings._iDisplayLength : 2557 -1; 2558 2559 var param = function ( name, value ) { 2560 data.push( { 'name': name, 'value': value } ); 2561 }; 2562 2563 // DataTables 1.9- compatible method 2564 param( 'sEcho', settings.iDraw ); 2565 param( 'iColumns', columnCount ); 2566 param( 'sColumns', _pluck( columns, 'sName' ).join(',') ); 2567 param( 'iDisplayStart', displayStart ); 2568 param( 'iDisplayLength', displayLength ); 2569 2570 // DataTables 1.10+ method 2571 var d = { 2572 draw: settings.iDraw, 2573 columns: [], 2574 order: [], 2575 start: displayStart, 2576 length: displayLength, 2577 search: { 2578 value: preSearch.sSearch, 2579 regex: preSearch.bRegex 2580 } 2581 }; 2582 2583 for ( i=0 ; i<columnCount ; i++ ) { 2584 column = columns[i]; 2585 columnSearch = preColSearch[i]; 2586 dataProp = typeof column.mData=="function" ? 'function' : column.mData ; 2587 2588 d.columns.push( { 2589 data: dataProp, 2590 name: column.sName, 2591 searchable: column.bSearchable, 2592 orderable: column.bSortable, 2593 search: { 2594 value: columnSearch.sSearch, 2595 regex: columnSearch.bRegex 2596 } 2597 } ); 2598 2599 param( "mDataProp_"+i, dataProp ); 2600 2601 if ( features.bFilter ) { 2602 param( 'sSearch_'+i, columnSearch.sSearch ); 2603 param( 'bRegex_'+i, columnSearch.bRegex ); 2604 param( 'bSearchable_'+i, column.bSearchable ); 2605 } 2606 2607 if ( features.bSort ) { 2608 param( 'bSortable_'+i, column.bSortable ); 2609 } 2610 } 2611 2612 if ( features.bFilter ) { 2613 param( 'sSearch', preSearch.sSearch ); 2614 param( 'bRegex', preSearch.bRegex ); 2615 } 2616 2617 if ( features.bSort ) { 2618 $.each( sort, function ( i, val ) { 2619 d.order.push( { column: val.col, dir: val.dir } ); 2620 2621 param( 'iSortCol_'+i, val.col ); 2622 param( 'sSortDir_'+i, val.dir ); 2623 } ); 2624 2625 param( 'iSortingCols', sort.length ); 2626 } 2627 2628 // If the legacy.ajax parameter is null, then we automatically decide which 2629 // form to use, based on sAjaxSource 2630 var legacy = DataTable.ext.legacy.ajax; 2631 if ( legacy === null ) { 2632 return settings.sAjaxSource ? data : d; 2633 } 2634 2635 // Otherwise, if legacy has been specified then we use that to decide on the 2636 // form 2637 return legacy ? data : d; 2638 } 2639 2640 2641 /** 2642 * Data the data from the server (nuking the old) and redraw the table 2643 * @param {object} oSettings dataTables settings object 2644 * @param {object} json json data return from the server. 2645 * @param {string} json.sEcho Tracking flag for DataTables to match requests 2646 * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering 2647 * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering 2648 * @param {array} json.aaData The data to display on this page 2649 * @param {string} [json.sColumns] Column ordering (sName, comma separated) 2650 * @memberof DataTable#oApi 2651 */ 2652 function _fnAjaxUpdateDraw ( settings, json ) 2653 { 2654 // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2655 // Support both 2656 var compat = function ( old, modern ) { 2657 return json[old] !== undefined ? json[old] : json[modern]; 2658 }; 2659 2660 var draw = compat( 'sEcho', 'draw' ); 2661 var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' ); 2662 var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' ); 2663 2664 if ( draw ) { 2665 // Protect against out of sequence returns 2666 if ( draw*1 < settings.iDraw ) { 2667 return; 2668 } 2669 settings.iDraw = draw * 1; 2670 } 2671 2672 _fnClearTable( settings ); 2673 settings._iRecordsTotal = parseInt(recordsTotal, 10); 2674 settings._iRecordsDisplay = parseInt(recordsFiltered, 10); 2675 2676 var data = _fnAjaxDataSrc( settings, json ); 2677 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 2678 _fnAddData( settings, data[i] ); 2679 } 2680 settings.aiDisplay = settings.aiDisplayMaster.slice(); 2681 2682 settings.bAjaxDataGet = false; 2683 _fnDraw( settings ); 2684 2685 if ( ! settings._bInitComplete ) { 2686 _fnInitComplete( settings, json ); 2687 } 2688 2689 settings.bAjaxDataGet = true; 2690 _fnProcessingDisplay( settings, false ); 2691 } 2692 2693 2694 /** 2695 * Get the data from the JSON data source to use for drawing a table. Using 2696 * `_fnGetObjectDataFn` allows the data to be sourced from a property of the 2697 * source object, or from a processing function. 2698 * @param {object} oSettings dataTables settings object 2699 * @param {object} json Data source object / array from the server 2700 * @return {array} Array of data to use 2701 */ 2702 function _fnAjaxDataSrc ( oSettings, json ) 2703 { 2704 var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ? 2705 oSettings.ajax.dataSrc : 2706 oSettings.sAjaxDataProp; // Compatibility with 1.9-. 2707 2708 // Compatibility with 1.9-. In order to read from aaData, check if the 2709 // default has been changed, if not, check for aaData 2710 if ( dataSrc === 'data' ) { 2711 return json.aaData || json[dataSrc]; 2712 } 2713 2714 return dataSrc !== "" ? 2715 _fnGetObjectDataFn( dataSrc )( json ) : 2716 json; 2717 } 2718 2719 2720 /** 2721 * Generate the node required for filtering text 2722 * @returns {node} Filter control element 2723 * @param {object} oSettings dataTables settings object 2724 * @memberof DataTable#oApi 2725 */ 2726 function _fnFeatureHtmlFilter ( settings ) 2727 { 2728 var classes = settings.oClasses; 2729 var tableId = settings.sTableId; 2730 var language = settings.oLanguage; 2731 var previousSearch = settings.oPreviousSearch; 2732 var features = settings.aanFeatures; 2733 var input = '<input type="search" class="'+classes.sFilterInput+'"/>'; 2734 2735 var str = language.sSearch; 2736 str = str.match(/_INPUT_/) ? 2737 str.replace('_INPUT_', input) : 2738 str+input; 2739 2740 var filter = $('<div/>', { 2741 'id': ! features.f ? tableId+'_filter' : null, 2742 'class': classes.sFilter 2743 } ) 2744 .append( $('<label/>' ).append( str ) ); 2745 2746 var searchFn = function() { 2747 /* Update all other filter input elements for the new display */ 2748 var n = features.f; 2749 var val = !this.value ? "" : this.value; // mental IE8 fix :-( 2750 2751 /* Now do the filter */ 2752 if ( val != previousSearch.sSearch ) { 2753 _fnFilterComplete( settings, { 2754 "sSearch": val, 2755 "bRegex": previousSearch.bRegex, 2756 "bSmart": previousSearch.bSmart , 2757 "bCaseInsensitive": previousSearch.bCaseInsensitive 2758 } ); 2759 2760 // Need to redraw, without resorting 2761 settings._iDisplayStart = 0; 2762 _fnDraw( settings ); 2763 } 2764 }; 2765 2766 var searchDelay = settings.searchDelay !== null ? 2767 settings.searchDelay : 2768 _fnDataSource( settings ) === 'ssp' ? 2769 400 : 2770 0; 2771 2772 var jqFilter = $('input', filter) 2773 .val( previousSearch.sSearch ) 2774 .attr( 'placeholder', language.sSearchPlaceholder ) 2775 .bind( 2776 'keyup.DT search.DT input.DT paste.DT cut.DT', 2777 searchDelay ? 2778 _fnThrottle( searchFn, searchDelay ) : 2779 searchFn 2780 ) 2781 .bind( 'keypress.DT', function(e) { 2782 /* Prevent form submission */ 2783 if ( e.keyCode == 13 ) { 2784 return false; 2785 } 2786 } ) 2787 .attr('aria-controls', tableId); 2788 2789 // Update the input elements whenever the table is filtered 2790 $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) { 2791 if ( settings === s ) { 2792 // IE9 throws an 'unknown error' if document.activeElement is used 2793 // inside an iframe or frame...
2794 try { 2795 if ( jqFilter[0] !== document.activeElement ) { 2796 jqFilter.val( previousSearch.sSearch ); 2797 } 2798 } 2799 catch ( e ) {} 2800 } 2801 } ); 2802 2803 return filter[0]; 2804 } 2805 2806 2807 /** 2808 * Filter the table using both the global filter and column based filtering 2809 * @param {object} oSettings dataTables settings object 2810 * @param {object} oSearch search information 2811 * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0) 2812 * @memberof DataTable#oApi 2813 */ 2814 function _fnFilterComplete ( oSettings, oInput, iForce ) 2815 { 2816 var oPrevSearch = oSettings.oPreviousSearch; 2817 var aoPrevSearch = oSettings.aoPreSearchCols; 2818 var fnSaveFilter = function ( oFilter ) { 2819 /* Save the filtering values */ 2820 oPrevSearch.sSearch = oFilter.sSearch; 2821 oPrevSearch.bRegex = oFilter.bRegex; 2822 oPrevSearch.bSmart = oFilter.bSmart; 2823 oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive; 2824 }; 2825 var fnRegex = function ( o ) { 2826 // Backwards compatibility with the bEscapeRegex option 2827 return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex; 2828 }; 2829 2830 // Resolve any column types that are unknown due to addition or invalidation 2831 // @todo As per sort - can this be moved into an event handler? 2832 _fnColumnTypes( oSettings ); 2833 2834 /* In server-side processing all filtering is done by the server, so no point hanging around here */ 2835 if ( _fnDataSource( oSettings ) != 'ssp' ) 2836 { 2837 /* Global filter */ 2838 _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive ); 2839 fnSaveFilter( oInput ); 2840 2841 /* Now do the individual column filter */ 2842 for ( var i=0 ; i<aoPrevSearch.length ; i++ ) 2843 { 2844 _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]), 2845 aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive ); 2846 } 2847 2848 /* Custom filtering */ 2849 _fnFilterCustom( oSettings ); 2850 } 2851 else 2852 { 2853 fnSaveFilter( oInput ); 2854 } 2855 2856 /* Tell the draw function we have been filtering */ 2857 oSettings.bFiltered = true; 2858 _fnCallbackFire( oSettings, null, 'search', [oSettings] ); 2859 } 2860 2861 2862 /** 2863 * Apply custom filtering functions 2864 * @param {object} oSettings dataTables settings object 2865 * @memberof DataTable#oApi 2866 */ 2867 function _fnFilterCustom( settings ) 2868 { 2869 var filters = DataTable.ext.search; 2870 var displayRows = settings.aiDisplay; 2871 var row, rowIdx; 2872 2873 for ( var i=0, ien=filters.length ; i<ien ; i++ ) { 2874 var rows = []; 2875 2876 // Loop over each row and see if it should be included 2877 for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) { 2878 rowIdx = displayRows[ j ]; 2879 row = settings.aoData[ rowIdx ]; 2880 2881 if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) { 2882 rows.push( rowIdx ); 2883 } 2884 } 2885 2886 // So the array reference doesn't break set the results into the 2887 // existing array 2888 displayRows.length = 0; 2889 displayRows.push.apply( displayRows, rows ); 2890 } 2891 } 2892 2893 2894 /** 2895 * Filter the table on a per-column basis 2896 * @param {object} oSettings dataTables settings object 2897 * @param {string} sInput string to filter on 2898 * @param {int} iColumn column to filter 2899 * @param {bool} bRegex treat search string as a regular expression or not 2900 * @param {bool} bSmart use smart filtering or not 2901 * @param {bool} bCaseInsensitive Do case insenstive matching or not 2902 * @memberof DataTable#oApi 2903 */ 2904 function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive ) 2905 { 2906 if ( searchStr === '' ) { 2907 return; 2908 } 2909 2910 var data; 2911 var display = settings.aiDisplay; 2912 var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive ); 2913 2914 for ( var i=display.length-1 ; i>=0 ; i-- ) { 2915 data = settings.aoData[ display[i] ]._aFilterData[ colIdx ]; 2916 2917 if ( ! rpSearch.test( data ) ) { 2918 display.splice( i, 1 ); 2919 } 2920 } 2921 } 2922 2923 2924 /** 2925 * Filter the data table based on user input and draw the table 2926 * @param {object} settings dataTables settings object 2927 * @param {string} input string to filter on 2928 * @param {int} force optional - force a research of the master array (1) or not (undefined or 0) 2929 * @param {bool} regex treat as a regular expression or not 2930 * @param {bool} smart perform smart filtering or not 2931 * @param {bool} caseInsensitive Do case insenstive matching or not 2932 * @memberof DataTable#oApi 2933 */ 2934 function _fnFilter( settings, input, force, regex, smart, caseInsensitive ) 2935 { 2936 var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive ); 2937 var prevSearch = settings.oPreviousSearch.sSearch; 2938 var displayMaster = settings.aiDisplayMaster; 2939 var display, invalidated, i; 2940 2941 // Need to take account of custom filtering functions - always filter 2942 if ( DataTable.ext.search.length !== 0 ) { 2943 force = true; 2944 } 2945 2946 // Check if any of the rows were invalidated 2947 invalidated = _fnFilterData( settings ); 2948 2949 // If the input is blank - we just want the full data set 2950 if ( input.length <= 0 ) { 2951 settings.aiDisplay = displayMaster.slice(); 2952 } 2953 else { 2954 // New search - start from the master array 2955 if ( invalidated || 2956 force || 2957 prevSearch.length > input.length || 2958 input.indexOf(prevSearch) !== 0 || 2959 settings.bSorted // On resort, the display master needs to be 2960 // re-filtered since indexes will have changed 2961 ) { 2962 settings.aiDisplay = displayMaster.slice(); 2963 } 2964 2965 // Search the display array 2966 display = settings.aiDisplay; 2967 2968 for ( i=display.length-1 ; i>=0 ; i-- ) { 2969 if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) { 2970 display.splice( i, 1 ); 2971 } 2972 } 2973 } 2974 } 2975 2976 2977 /** 2978 * Build a regular expression object suitable for searching a table 2979 * @param {string} sSearch string to search for 2980 * @param {bool} bRegex treat as a regular expression or not 2981 * @param {bool} bSmart perform smart filtering or not 2982 * @param {bool} bCaseInsensitive Do case insensitive matching or not 2983 * @returns {RegExp} constructed object 2984 * @memberof DataTable#oApi 2985 */ 2986 function _fnFilterCreateSearch( search, regex, smart, caseInsensitive ) 2987 { 2988 search = regex ? 2989 search : 2990 _fnEscapeRegex( search ); 2991 2992 if ( smart ) { 2993 /* For smart filtering we want to allow the search to work regardless of 2994 * word order. We also want double quoted text to be preserved, so word 2995 * order is important - a la google. So this is what we want to 2996 * generate: 2997 * 2998 * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$ 2999 */ 3000 var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) { 3001 if ( word.charAt(0) === '"' ) { 3002 var m = word.match( /^"(.*)"$/ ); 3003 word = m ? m[1] : word; 3004 } 3005 3006 return word.replace('"', ''); 3007 } ); 3008 3009 search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$'; 3010 } 3011 3012 return new RegExp( search, caseInsensitive ? 'i' : '' ); 3013 } 3014 3015 3016 /** 3017 * Escape a string such that it can be used in a regular expression 3018 * @param {string} sVal string to escape 3019 * @returns {string} escaped string 3020 * @memberof DataTable#oApi 3021 */ 3022 function _fnEscapeRegex ( sVal ) 3023 { 3024 return sVal.replace( _re_escape_regex, '\\$1' ); 3025 } 3026 3027 3028
3029 var __filter_div = $('<div>')[0]; 3030 var __filter_div_textContent = __filter_div.textContent !== undefined; 3031 3032 // Update the filtering data for each row if needed (by invalidation or first run) 3033 function _fnFilterData ( settings ) 3034 { 3035 var columns = settings.aoColumns; 3036 var column; 3037 var i, j, ien, jen, filterData, cellData, row; 3038 var fomatters = DataTable.ext.type.search; 3039 var wasInvalidated = false; 3040 3041 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 3042 row = settings.aoData[i]; 3043 3044 if ( ! row._aFilterData ) { 3045 filterData = []; 3046 3047 for ( j=0, jen=columns.length ; j<jen ; j++ ) { 3048 column = columns[j]; 3049 3050 if ( column.bSearchable ) { 3051 cellData = _fnGetCellData( settings, i, j, 'filter' ); 3052 3053 if ( fomatters[ column.sType ] ) { 3054 cellData = fomatters[ column.sType ]( cellData ); 3055 } 3056 3057 // Search in DataTables 1.10 is string based. In 1.11 this 3058 // should be altered to also allow strict type checking. 3059 if ( cellData === null ) { 3060 cellData = ''; 3061 } 3062 3063 if ( typeof cellData !== 'string' && cellData.toString ) { 3064 cellData = cellData.toString(); 3065 } 3066 } 3067 else { 3068 cellData = ''; 3069 } 3070 3071 // If it looks like there is an HTML entity in the string, 3072 // attempt to decode it so sorting works as expected. Note that 3073 // we could use a single line of jQuery to do this, but the DOM 3074 // method used here is much faster http://jsperf.com/html-decode 3075 if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) { 3076 __filter_div.innerHTML = cellData; 3077 cellData = __filter_div_textContent ? 3078 __filter_div.textContent : 3079 __filter_div.innerText; 3080 } 3081 3082 if ( cellData.replace ) { 3083 cellData = cellData.replace(/[\r\n]/g, ''); 3084 } 3085 3086 filterData.push( cellData ); 3087 } 3088 3089 row._aFilterData = filterData; 3090 row._sFilterRow = filterData.join(' '); 3091 wasInvalidated = true; 3092 } 3093 } 3094 3095 return wasInvalidated; 3096 } 3097 3098 3099 /** 3100 * Convert from the internal Hungarian notation to camelCase for external 3101 * interaction 3102 * @param {object} obj Object to convert 3103 * @returns {object} Inverted object 3104 * @memberof DataTable#oApi 3105 */ 3106 function _fnSearchToCamel ( obj ) 3107 { 3108 return { 3109 search: obj.sSearch, 3110 smart: obj.bSmart, 3111 regex: obj.bRegex, 3112 caseInsensitive: obj.bCaseInsensitive 3113 }; 3114 } 3115 3116 3117 3118 /** 3119 * Convert from camelCase notation to the internal Hungarian. We could use the 3120 * Hungarian convert function here, but this is cleaner 3121 * @param {object} obj Object to convert 3122 * @returns {object} Inverted object 3123 * @memberof DataTable#oApi 3124 */ 3125 function _fnSearchToHung ( obj ) 3126 { 3127 return { 3128 sSearch: obj.search, 3129 bSmart: obj.smart, 3130 bRegex: obj.regex, 3131 bCaseInsensitive: obj.caseInsensitive 3132 }; 3133 } 3134 3135 /** 3136 * Generate the node required for the info display 3137 * @param {object} oSettings dataTables settings object 3138 * @returns {node} Information element 3139 * @memberof DataTable#oApi 3140 */ 3141 function _fnFeatureHtmlInfo ( settings ) 3142 { 3143 var 3144 tid = settings.sTableId, 3145 nodes = settings.aanFeatures.i, 3146 n = $('<div/>', { 3147 'class': settings.oClasses.sInfo, 3148 'id': ! nodes ? tid+'_info' : null 3149 } ); 3150 3151 if ( ! nodes ) { 3152 // Update display on each draw 3153 settings.aoDrawCallback.push( { 3154 "fn": _fnUpdateInfo, 3155 "sName": "information" 3156 } ); 3157 3158 n 3159 .attr( 'role', 'status' ) 3160 .attr( 'aria-live', 'polite' ); 3161 3162 // Table is described by our info div 3163 $(settings.nTable).attr( 'aria-describedby', tid+'_info' ); 3164 } 3165 3166 return n[0]; 3167 } 3168 3169 3170 /** 3171 * Update the information elements in the display 3172 * @param {object} settings dataTables settings object 3173 * @memberof DataTable#oApi 3174 */ 3175 function _fnUpdateInfo ( settings ) 3176 { 3177 /* Show information about the table */ 3178 var nodes = settings.aanFeatures.i; 3179 if ( nodes.length === 0 ) { 3180 return; 3181 } 3182 3183 var 3184 lang = settings.oLanguage, 3185 start = settings._iDisplayStart+1, 3186 end = settings.fnDisplayEnd(), 3187 max = settings.fnRecordsTotal(), 3188 total = settings.fnRecordsDisplay(), 3189 out = total ? 3190 lang.sInfo : 3191 lang.sInfoEmpty; 3192 3193 if ( total !== max ) { 3194 /* Record set after filtering */ 3195 out += ' ' + lang.sInfoFiltered; 3196 } 3197 3198 // Convert the macros 3199 out += lang.sInfoPostFix; 3200 out = _fnInfoMacros( settings, out ); 3201 3202 var callback = lang.fnInfoCallback; 3203 if ( callback !== null ) { 3204 out = callback.call( settings.oInstance, 3205 settings, start, end, max, total, out 3206 ); 3207 } 3208 3209 $(nodes).html( out ); 3210 } 3211 3212 3213 function _fnInfoMacros ( settings, str ) 3214 { 3215 // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only 3216 // internally 3217 var
3218 formatter = settings.fnFormatNumber, 3219 start = settings._iDisplayStart+1, 3220 len = settings._iDisplayLength, 3221 vis = settings.fnRecordsDisplay(), 3222 all = len === -1; 3223 3224 return str. 3225 replace(/_START_/g, formatter.call( settings, start ) ). 3226 replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ). 3227 replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ). 3228 replace(/_TOTAL_/g, formatter.call( settings, vis ) ). 3229 replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ). 3230 replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) ); 3231 } 3232 3233 3234 3235 /** 3236 * Draw the table for the first time, adding all required features 3237 * @param {object} settings dataTables settings object 3238 * @memberof DataTable#oApi 3239 */ 3240 function _fnInitialise ( settings ) 3241 { 3242 var i, iLen, iAjaxStart=settings.iInitDisplayStart; 3243 var columns = settings.aoColumns, column; 3244 var features = settings.oFeatures; 3245 3246 /* Ensure that the table data is fully initialised */ 3247 if ( ! settings.bInitialised ) { 3248 setTimeout( function(){ _fnInitialise( settings ); }, 200 ); 3249 return; 3250 } 3251 3252 /* Show the display HTML options */ 3253 _fnAddOptionsHtml( settings ); 3254 3255 /* Build and draw the header / footer for the table */ 3256 _fnBuildHead( settings ); 3257 _fnDrawHead( settings, settings.aoHeader ); 3258 _fnDrawHead( settings, settings.aoFooter ); 3259 3260 /* Okay to show that something is going on now */ 3261 _fnProcessingDisplay( settings, true ); 3262 3263 /* Calculate sizes for columns */ 3264 if ( features.bAutoWidth ) { 3265 _fnCalculateColumnWidths( settings ); 3266 } 3267 3268 for ( i=0, iLen=columns.length ; i<iLen ; i++ ) { 3269 column = columns[i]; 3270 3271 if ( column.sWidth ) { 3272 column.nTh.style.width = _fnStringToCss( column.sWidth ); 3273 } 3274 } 3275 3276 // If there is default sorting required - let's do it. The sort function 3277 // will do the drawing for us. Otherwise we draw the table regardless of the 3278 // Ajax source - this allows the table to look initialised for Ajax sourcing 3279 // data (show 'loading' message possibly) 3280 _fnReDraw( settings ); 3281 3282 // Server-side processing init complete is done by _fnAjaxUpdateDraw 3283 var dataSrc = _fnDataSource( settings ); 3284 if ( dataSrc != 'ssp' ) { 3285 // if there is an ajax source load the data 3286 if ( dataSrc == 'ajax' ) { 3287 _fnBuildAjax( settings, [], function(json) { 3288 var aData = _fnAjaxDataSrc( settings, json ); 3289 3290 // Got the data - add it to the table 3291 for ( i=0 ; i<aData.length ; i++ ) { 3292 _fnAddData( settings, aData[i] ); 3293 } 3294 3295 // Reset the init display for cookie saving. We've already done 3296 // a filter, and therefore cleared it before. So we need to make 3297 // it appear 'fresh' 3298 settings.iInitDisplayStart = iAjaxStart; 3299 3300 _fnReDraw( settings ); 3301 3302 _fnProcessingDisplay( settings, false ); 3303 _fnInitComplete( settings, json ); 3304 }, settings ); 3305 } 3306 else { 3307 _fnProcessingDisplay( settings, false ); 3308 _fnInitComplete( settings ); 3309 } 3310 } 3311 } 3312 3313 3314 /** 3315 * Draw the table for the first time, adding all required features 3316 * @param {object} oSettings dataTables settings object 3317 * @param {object} [json] JSON from the server that completed the table, if using Ajax source 3318 * with client-side processing (optional) 3319 * @memberof DataTable#oApi 3320 */ 3321 function _fnInitComplete ( settings, json ) 3322 { 3323 settings._bInitComplete = true; 3324 3325 // On an Ajax load we now have data and therefore want to apply the column 3326 // sizing 3327 if ( json ) { 3328 _fnAdjustColumnSizing( settings ); 3329 } 3330 3331 _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] ); 3332 } 3333 3334 3335 function _fnLengthChange ( settings, val ) 3336 { 3337 var len = parseInt( val, 10 ); 3338 settings._iDisplayLength = len; 3339 3340 _fnLengthOverflow( settings ); 3341 3342 // Fire length change event 3343 _fnCallbackFire( settings, null, 'length', [settings, len] ); 3344 } 3345 3346 3347 /** 3348 * Generate the node required for user display length changing 3349 * @param {object} settings dataTables settings object 3350 * @returns {node} Display length feature node 3351 * @memberof DataTable#oApi 3352 */ 3353 function _fnFeatureHtmlLength ( settings ) 3354 { 3355 var 3356 classes = settings.oClasses, 3357 tableId = settings.sTableId, 3358 menu = settings.aLengthMenu, 3359 d2 = $.isArray( menu[0] ), 3360 lengths = d2 ? menu[0] : menu, 3361 language = d2 ? menu[1] : menu; 3362 3363 var select = $('<select/>', { 3364 'name': tableId+'_length', 3365 'aria-controls': tableId, 3366 'class': classes.sLengthSelect 3367 } ); 3368 3369 for ( var i=0, ien=lengths.length ; i<ien ; i++ ) { 3370 select[0][ i ] = new Option( language[i], lengths[i] ); 3371 } 3372
3373 var div = $('<div><label/></div>').addClass( classes.sLength ); 3374 if ( ! settings.aanFeatures.l ) { 3375 div[0].id = tableId+'_length'; 3376 } 3377 3378 div.children().append( 3379 settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML ) 3380 ); 3381 3382 // Can't use `select` variable as user might provide their own and the 3383 // reference is broken by the use of outerHTML 3384 $('select', div) 3385 .val( settings._iDisplayLength ) 3386 .bind( 'change.DT', function(e) { 3387 _fnLengthChange( settings, $(this).val() ); 3388 _fnDraw( settings ); 3389 } ); 3390 3391 // Update node value whenever anything changes the table's length 3392 $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) { 3393 if ( settings === s ) { 3394 $('select', div).val( len ); 3395 } 3396 } ); 3397 3398 return div[0]; 3399 } 3400 3401 3402 3403 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 3404 * Note that most of the paging logic is done in 3405 * DataTable.ext.pager 3406 */ 3407 3408 /** 3409 * Generate the node required for default pagination 3410 * @param {object} oSettings dataTables settings object 3411 * @returns {node} Pagination feature node 3412 * @memberof DataTable#oApi 3413 */ 3414 function _fnFeatureHtmlPaginate ( settings ) 3415 { 3416 var 3417 type = settings.sPaginationType, 3418 plugin = DataTable.ext.pager[ type ], 3419 modern = typeof plugin === 'function', 3420 redraw = function( settings ) { 3421 _fnDraw( settings ); 3422 }, 3423 node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0], 3424 features = settings.aanFeatures; 3425 3426 if ( ! modern ) { 3427 plugin.fnInit( settings, node, redraw ); 3428 } 3429 3430 /* Add a draw callback for the pagination on first instance, to update the paging display */ 3431 if ( ! features.p ) 3432 { 3433 node.id = settings.sTableId+'_paginate'; 3434 3435 settings.aoDrawCallback.push( { 3436 "fn": function( settings ) { 3437 if ( modern ) { 3438 var 3439 start = settings._iDisplayStart, 3440 len = settings._iDisplayLength, 3441 visRecords = settings.fnRecordsDisplay(), 3442 all = len === -1, 3443 page = all ? 0 : Math.ceil( start / len ), 3444 pages = all ? 1 : Math.ceil( visRecords / len ), 3445 buttons = plugin(page, pages), 3446 i, ien; 3447 3448 for ( i=0, ien=features.p.length ; i<ien ; i++ ) { 3449 _fnRenderer( settings, 'pageButton' )( 3450 settings, features.p[i], i, buttons, page, pages 3451 ); 3452 } 3453 } 3454 else { 3455 plugin.fnUpdate( settings, redraw ); 3456 } 3457 }, 3458 "sName": "pagination" 3459 } ); 3460 } 3461 3462 return node; 3463 } 3464 3465 3466 /** 3467 * Alter the display settings to change the page 3468 * @param {object} settings DataTables settings object 3469 * @param {string|int} action Paging action to take: "first", "previous", 3470 * "next" or "last" or page number to jump to (integer) 3471 * @param [bool] redraw Automatically draw the update or not 3472 * @returns {bool} true page has changed, false - no change 3473 * @memberof DataTable#oApi 3474 */ 3475 function _fnPageChange ( settings, action, redraw ) 3476 { 3477 var 3478 start = settings._iDisplayStart, 3479 len = settings._iDisplayLength, 3480 records = settings.fnRecordsDisplay(); 3481 3482 if ( records === 0 || len === -1 ) 3483 { 3484 start = 0; 3485 } 3486 else if ( typeof action === "number" ) 3487 { 3488 start = action * len; 3489 3490 if ( start > records ) 3491 { 3492 start = 0; 3493 } 3494 } 3495 else if ( action == "first" ) 3496 { 3497 start = 0; 3498 } 3499 else if ( action == "previous" ) 3500 { 3501 start = len >= 0 ? 3502 start - len : 3503 0; 3504 3505 if ( start < 0 ) 3506 { 3507 start = 0; 3508 } 3509 } 3510 else if ( action == "next" ) 3511 { 3512 if ( start + len < records ) 3513 { 3514 start += len; 3515 } 3516 } 3517 else if ( action == "last" ) 3518 { 3519 start = Math.floor( (records-1) / len) * len; 3520 } 3521 else 3522 { 3523 _fnLog( settings, 0, "Unknown paging action: "+action, 5 ); 3524 } 3525 3526 var changed = settings._iDisplayStart !== start; 3527 settings._iDisplayStart = start; 3528 3529 if ( changed ) { 3530 _fnCallbackFire( settings, null, 'page', [settings] ); 3531 3532 if ( redraw ) { 3533 _fnDraw( settings ); 3534 } 3535 } 3536 3537 return changed; 3538 } 3539 3540 3541 3542 /** 3543 * Generate the node required for the processing node 3544 * @param {object} settings dataTables settings object 3545 * @returns {node} Processing element 3546 * @memberof DataTable#oApi 3547 */ 3548 function _fnFeatureHtmlProcessing ( settings ) 3549 { 3550 return $('<div/>', { 3551 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null, 3552 'class': settings.oClasses.sProcessing 3553 } ) 3554 .html( settings.oLanguage.sProcessing ) 3555 .insertBefore( settings.nTable )[0]; 3556 } 3557 3558 3559 /** 3560 * Display or hide the processing indicator 3561 * @param {object} settings dataTables settings object 3562 * @param {bool} show Show the processing indicator (true) or not (false) 3563 * @memberof DataTable#oApi 3564 */ 3565 function _fnProcessingDisplay ( settings, show ) 3566 { 3567 if ( settings.oFeatures.bProcessing ) { 3568 $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' ); 3569 } 3570 3571 _fnCallbackFire( settings, null, 'processing', [settings, show] ); 3572 } 3573 3574 /** 3575 * Add any control elements for the table - specifically scrolling 3576 * @param {object} settings dataTables settings object 3577 * @returns {node} Node to add to the DOM 3578 * @memberof DataTable#oApi 3579 */ 3580 function _fnFeatureHtmlTable ( settings ) 3581 { 3582 var table = $(settings.nTable); 3583 3584 // Add the ARIA grid role to the table 3585 table.attr( 'role', 'grid' ); 3586 3587 // Scrolling from here on in 3588 var scroll = settings.oScroll; 3589
3590 if ( scroll.sX === '' && scroll.sY === '' ) { 3591 return settings.nTable; 3592 } 3593 3594 var scrollX = scroll.sX; 3595 var scrollY = scroll.sY; 3596 var classes = settings.oClasses; 3597 var caption = table.children('caption'); 3598 var captionSide = caption.length ? caption[0]._captionSide : null; 3599 var headerClone = $( table[0].cloneNode(false) ); 3600 var footerClone = $( table[0].cloneNode(false) ); 3601 var footer = table.children('tfoot'); 3602 var _div = '<div/>'; 3603 var size = function ( s ) { 3604 return !s ? null : _fnStringToCss( s ); 3605 }; 3606 3607 // This is fairly messy, but with x scrolling enabled, if the table has a 3608 // width attribute, regardless of any width applied using the column width 3609 // options, the browser will shrink or grow the table as needed to fit into 3610 // that 100%. That would make the width options useless. So we remove it. 3611 // This is okay, under the assumption that width:100% is applied to the 3612 // table in CSS (it is in the default stylesheet) which will set the table 3613 // width as appropriate (the attribute and css behave differently...) 3614 if ( scroll.sX && table.attr('width') === '100%' ) { 3615 table.removeAttr('width'); 3616 } 3617 3618 if ( ! footer.length ) { 3619 footer = null; 3620 } 3621 3622 /* 3623 * The HTML structure that we want to generate in this function is: 3624 * div - scroller 3625 * div - scroll head 3626 * div - scroll head inner 3627 * table - scroll head table 3628 * thead - thead 3629 * div - scroll body 3630 * table - table (master table) 3631 * thead - thead clone for sizing 3632 * tbody - tbody 3633 * div - scroll foot 3634 * div - scroll foot inner 3635 * table - scroll foot table 3636 * tfoot - tfoot 3637 */ 3638 var scroller = $( _div, { 'class': classes.sScrollWrapper } ) 3639 .append( 3640 $(_div, { 'class': classes.sScrollHead } ) 3641 .css( { 3642 overflow: 'hidden', 3643 position: 'relative', 3644 border: 0, 3645 width: scrollX ? size(scrollX) : '100%' 3646 } ) 3647 .append( 3648 $(_div, { 'class': classes.sScrollHeadInner } ) 3649 .css( { 3650 'box-sizing': 'content-box', 3651 width: scroll.sXInner || '100%' 3652 } ) 3653 .append( 3654 headerClone 3655 .removeAttr('id') 3656 .css( 'margin-left', 0 ) 3657 .append( captionSide === 'top' ? caption : null ) 3658 .append( 3659 table.children('thead') 3660 ) 3661 ) 3662 ) 3663 ) 3664 .append( 3665 $(_div, { 'class': classes.sScrollBody } ) 3666 .css( { 3667 overflow: 'auto', 3668 height: size( scrollY ), 3669 width: size( scrollX ) 3670 } ) 3671 .append( table ) 3672 ); 3673 3674 if ( footer ) { 3675 scroller.append( 3676 $(_div, { 'class': classes.sScrollFoot } ) 3677 .css( { 3678 overflow: 'hidden', 3679 border: 0, 3680 width: scrollX ? size(scrollX) : '100%' 3681 } ) 3682 .append( 3683 $(_div, { 'class': classes.sScrollFootInner } ) 3684 .append( 3685 footerClone 3686 .removeAttr('id') 3687 .css( 'margin-left', 0 ) 3688 .append( captionSide === 'bottom' ? caption : null ) 3689 .append( 3690 table.children('tfoot') 3691 ) 3692 ) 3693 ) 3694 ); 3695 } 3696 3697 var children = scroller.children(); 3698 var scrollHead = children[0]; 3699 var scrollBody = children[1]; 3700 var scrollFoot = footer ? children[2] : null; 3701 3702 // When the body is scrolled, then we also want to scroll the headers 3703 if ( scrollX ) { 3704 $(scrollBody).on( 'scroll.DT', function (e) { 3705 var scrollLeft = this.scrollLeft; 3706 3707 scrollHead.scrollLeft = scrollLeft; 3708 3709 if ( footer ) { 3710 scrollFoot.scrollLeft = scrollLeft; 3711 } 3712 } ); 3713 } 3714 3715 settings.nScrollHead = scrollHead; 3716 settings.nScrollBody = scrollBody; 3717 settings.nScrollFoot = scrollFoot; 3718 3719 // On redraw - align columns 3720 settings.aoDrawCallback.push( { 3721 "fn": _fnScrollDraw, 3722 "sName": "scrolling" 3723 } ); 3724 3725 return scroller[0]; 3726 } 3727 3728 3729 3730 /** 3731 * Update the header, footer and body tables for resizing - i.e. column 3732 * alignment. 3733 * 3734 * Welcome to the most horrible function DataTables. The process that this 3735 * function follows is basically: 3736 * 1. Re-create the table inside the scrolling div 3737 * 2. Take live measurements from the DOM 3738 * 3. Apply the measurements to align the columns 3739 * 4. Clean up 3740 * 3741 * @param {object} settings dataTables settings object 3742 * @memberof DataTable#oApi 3743 */ 3744 function _fnScrollDraw ( settings ) 3745 { 3746 // Given that this is such a monster function, a lot of variables are use 3747 // to try and keep the minimised size as small as possible 3748 var 3749 scroll = settings.oScroll, 3750 scrollX = scroll.sX, 3751 scrollXInner = scroll.sXInner, 3752 scrollY = scroll.sY, 3753 barWidth = scroll.iBarWidth, 3754 divHeader = $(settings.nScrollHead), 3755 divHeaderStyle = divHeader[0].style, 3756 divHeaderInner = divHeader.children('div'), 3757 divHeaderInnerStyle = divHeaderInner[0].style, 3758 divHeaderTable = divHeaderInner.children('table'), 3759 divBodyEl = settings.nScrollBody,
3760 divBody = $(divBodyEl), 3761 divBodyStyle = divBodyEl.style, 3762 divFooter = $(settings.nScrollFoot), 3763 divFooterInner = divFooter.children('div'), 3764 divFooterTable = divFooterInner.children('table'), 3765 header = $(settings.nTHead), 3766 table = $(settings.nTable), 3767 tableEl = table[0], 3768 tableStyle = tableEl.style, 3769 footer = settings.nTFoot ? $(settings.nTFoot) : null, 3770 browser = settings.oBrowser, 3771 ie67 = browser.bScrollOversize, 3772 headerTrgEls, footerTrgEls, 3773 headerSrcEls, footerSrcEls, 3774 headerCopy, footerCopy, 3775 headerWidths=[], footerWidths=[], 3776 headerContent=[], 3777 idx, correction, sanityWidth, 3778 zeroOut = function(nSizer) { 3779 var style = nSizer.style; 3780 style.paddingTop = "0"; 3781 style.paddingBottom = "0"; 3782 style.borderTopWidth = "0"; 3783 style.borderBottomWidth = "0"; 3784 style.height = 0; 3785 }; 3786 3787 /* 3788 * 1. Re-create the table inside the scrolling div 3789 */ 3790 3791 // Remove the old minimised thead and tfoot elements in the inner table 3792 table.children('thead, tfoot').remove(); 3793 3794 // Clone the current header and footer elements and then place it into the inner table 3795 headerCopy = header.clone().prependTo( table ); 3796 headerTrgEls = header.find('tr'); // original header is in its own table 3797 headerSrcEls = headerCopy.find('tr'); 3798 headerCopy.find('th, td').removeAttr('tabindex'); 3799 3800 if ( footer ) { 3801 footerCopy = footer.clone().prependTo( table ); 3802 footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized 3803 footerSrcEls = footerCopy.find('tr'); 3804 } 3805 3806 3807 /* 3808 * 2. Take live measurements from the DOM - do not alter the DOM itself! 3809 */ 3810 3811 // Remove old sizing and apply the calculated column widths 3812 // Get the unique column headers in the newly created (cloned) header. We want to apply the 3813 // calculated sizes to this header 3814 if ( ! scrollX ) 3815 { 3816 divBodyStyle.width = '100%'; 3817 divHeader[0].style.width = '100%'; 3818 } 3819 3820 $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) { 3821 idx = _fnVisibleToColumnIndex( settings, i ); 3822 el.style.width = settings.aoColumns[idx].sWidth; 3823 } ); 3824 3825 if ( footer ) { 3826 _fnApplyToChildren( function(n) { 3827 n.style.width = ""; 3828 }, footerSrcEls ); 3829 } 3830 3831 // If scroll collapse is enabled, when we put the headers back into the body for sizing, we 3832 // will end up forcing the scrollbar to appear, making our measurements wrong for when we 3833 // then hide it (end of this function), so add the header height to the body scroller. 3834 if ( scroll.bCollapse && scrollY !== "" ) { 3835 divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px"; 3836 } 3837 3838 // Size the table as a whole 3839 sanityWidth = table.outerWidth(); 3840 if ( scrollX === "" ) { 3841 // No x scrolling 3842 tableStyle.width = "100%"; 3843 3844 // IE7 will make the width of the table when 100% include the scrollbar 3845 // - which is shouldn't. When there is a scrollbar we need to take this 3846 // into account. 3847 if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight || 3848 divBody.css('overflow-y') == "scroll") 3849 ) { 3850 tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth); 3851 } 3852 } 3853 else 3854 { 3855 // x scrolling 3856 if ( scrollXInner !== "" ) { 3857 // x scroll inner has been given - use it 3858 tableStyle.width = _fnStringToCss(scrollXInner); 3859 } 3860 else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) { 3861 // There is y-scrolling - try to take account of the y scroll bar 3862 tableStyle.width = _fnStringToCss( sanityWidth-barWidth ); 3863 if ( table.outerWidth() > sanityWidth-barWidth ) { 3864 // Not possible to take account of it 3865 tableStyle.width = _fnStringToCss( sanityWidth ); 3866 } 3867 } 3868 else { 3869 // When all else fails 3870 tableStyle.width = _fnStringToCss( sanityWidth ); 3871 } 3872 } 3873 3874 // Recalculate the sanity width - now that we've applied the required width, 3875 // before it was a temporary variable. This is required because the column 3876 // width calculation is done before this table DOM is created. 3877 sanityWidth = table.outerWidth(); 3878 3879 // Hidden header should have zero height, so remove padding and borders. Then 3880 // set the width based on the real headers 3881 3882 // Apply all styles in one pass 3883 _fnApplyToChildren( zeroOut, headerSrcEls ); 3884 3885 // Read all widths in next pass 3886 _fnApplyToChildren( function(nSizer) { 3887 headerContent.push( nSizer.innerHTML ); 3888 headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 3889 }, headerSrcEls ); 3890 3891 // Apply all widths in final pass 3892 _fnApplyToChildren( function(nToSize, i) { 3893 nToSize.style.width = headerWidths[i]; 3894 }, headerTrgEls ); 3895 3896 $(headerSrcEls).height(0); 3897 3898 /* Same again with the footer if we have one */ 3899 if ( footer ) 3900 { 3901 _fnApplyToChildren( zeroOut, footerSrcEls ); 3902 3903 _fnApplyToChildren( function(nSizer) {
3904 footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) ); 3905 }, footerSrcEls ); 3906 3907 _fnApplyToChildren( function(nToSize, i) { 3908 nToSize.style.width = footerWidths[i]; 3909 }, footerTrgEls ); 3910 3911 $(footerSrcEls).height(0); 3912 } 3913 3914 3915 /* 3916 * 3. Apply the measurements 3917 */ 3918 3919 // "Hide" the header and footer that we used for the sizing. We need to keep 3920 // the content of the cell so that the width applied to the header and body 3921 // both match, but we want to hide it completely. We want to also fix their 3922 // width to what they currently are 3923 _fnApplyToChildren( function(nSizer, i) { 3924 nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>'; 3925 nSizer.style.width = headerWidths[i]; 3926 }, headerSrcEls ); 3927 3928 if ( footer ) 3929 { 3930 _fnApplyToChildren( function(nSizer, i) { 3931 nSizer.innerHTML = ""; 3932 nSizer.style.width = footerWidths[i]; 3933 }, footerSrcEls ); 3934 } 3935 3936 // Sanity check that the table is of a sensible width. If not then we are going to get 3937 // misalignment - try to prevent this by not allowing the table to shrink below its min width 3938 if ( table.outerWidth() < sanityWidth ) 3939 { 3940 // The min width depends upon if we have a vertical scrollbar visible or not */ 3941 correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight || 3942 divBody.css('overflow-y') == "scroll")) ? 3943 sanityWidth+barWidth : 3944 sanityWidth; 3945 3946 // IE6/7 are a law unto themselves... 3947 if ( ie67 && (divBodyEl.scrollHeight > 3948 divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll") 3949 ) { 3950 tableStyle.width = _fnStringToCss( correction-barWidth ); 3951 } 3952 3953 // And give the user a warning that we've stopped the table getting too small 3954 if ( scrollX === "" || scrollXInner !== "" ) { 3955 _fnLog( settings, 1, 'Possible column misalignment', 6 ); 3956 } 3957 } 3958 else 3959 { 3960 correction = '100%'; 3961 } 3962 3963 // Apply to the container elements 3964 divBodyStyle.width = _fnStringToCss( correction ); 3965 divHeaderStyle.width = _fnStringToCss( correction ); 3966 3967 if ( footer ) { 3968 settings.nScrollFoot.style.width = _fnStringToCss( correction ); 3969 } 3970 3971 3972 /* 3973 * 4. Clean up 3974 */ 3975 if ( ! scrollY ) { 3976 /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting 3977 * the scrollbar height from the visible display, rather than adding it on. We need to 3978 * set the height in order to sort this. Don't want to do it in any other browsers. 3979 */ 3980 if ( ie67 ) { 3981 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth ); 3982 } 3983 } 3984 3985 if ( scrollY && scroll.bCollapse ) { 3986 divBodyStyle.height = _fnStringToCss( scrollY ); 3987 3988 var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ? 3989 barWidth : 3990 0; 3991 3992 if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) { 3993 divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra ); 3994 } 3995 } 3996 3997 /* Finally set the width's of the header and footer tables */ 3998 var iOuterWidth = table.outerWidth(); 3999 divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth ); 4000 divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth ); 4001 4002 // Figure out if there are scrollbar present - if so then we need a the header and footer to 4003 // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar) 4004 var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll"; 4005 var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' ); 4006 divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px"; 4007 4008 if ( footer ) { 4009 divFooterTable[0].style.width = _fnStringToCss( iOuterWidth ); 4010 divFooterInner[0].style.width = _fnStringToCss( iOuterWidth ); 4011 divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px"; 4012 } 4013 4014 /* Adjust the position of the header in case we loose the y-scrollbar */ 4015 divBody.scroll(); 4016 4017 // If sorting or filtering has occurred, jump the scrolling back to the top 4018 // only if we aren't holding the position 4019 if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) { 4020 divBodyEl.scrollTop = 0; 4021 } 4022 } 4023 4024 4025 4026 /** 4027 * Apply a given function to the display child nodes of an element array (typically 4028 * TD children of TR rows 4029 * @param {function} fn Method to apply to the objects 4030 * @param array {nodes} an1 List of elements to look through for display children 4031 * @param array {nodes} an2 Another list (identical structure to the first) - optional 4032 * @memberof DataTable#oApi 4033 */ 4034 function _fnApplyToChildren( fn, an1, an2 ) 4035 { 4036 var index=0, i=0, iLen=an1.length; 4037 var nNode1, nNode2; 4038 4039 while ( i < iLen ) { 4040 nNode1 = an1[i].firstChild; 4041 nNode2 = an2 ? an2[i].firstChild : null; 4042 4043 while ( nNode1 ) { 4044 if ( nNode1.nodeType === 1 ) { 4045 if ( an2 ) { 4046 fn( nNode1, nNode2, index ); 4047 } 4048 else { 4049 fn( nNode1, index ); 4050 } 4051 4052 index++; 4053 } 4054 4055 nNode1 = nNode1.nextSibling; 4056 nNode2 = an2 ? nNode2.nextSibling : null; 4057 } 4058 4059 i++; 4060 } 4061 } 4062 4063 4064 4065 var __re_html_remove = /<.*?>/g; 4066 4067 4068 /** 4069 * Calculate the width of columns for the table 4070 * @param {object} oSettings dataTables settings object 4071 * @memberof DataTable#oApi 4072 */ 4073 function _fnCalculateColumnWidths ( oSettings ) 4074 { 4075 var 4076 table = oSettings.nTable, 4077 columns = oSettings.aoColumns, 4078 scroll = oSettings.oScroll, 4079 scrollY = scroll.sY, 4080 scrollX = scroll.sX, 4081 scrollXInner = scroll.sXInner, 4082 columnCount = columns.length, 4083 visibleColumns = _fnGetColumns( oSettings, 'bVisible' ), 4084 headerCells = $('th', oSettings.nTHead), 4085 tableWidthAttr = table.style.width || table.getAttribute('width'), // from DOM element 4086 tableContainer = table.parentNode, 4087 userInputs = false, 4088 i, column, columnIdx, width, outerWidth; 4089 4090 /* Convert any user input sizes into pixel sizes */ 4091 for ( i=0 ; i<visibleColumns.length ; i++ ) { 4092 column = columns[ visibleColumns[i] ]; 4093 4094 if ( column.sWidth !== null ) { 4095 column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer ); 4096 4097 userInputs = true; 4098 } 4099 } 4100 4101 /* If the number of columns in the DOM equals the number that we have to 4102 * process in DataTables, then we can use the offsets that are created by 4103 * the web- browser. No custom sizes can be set in order for this to happen, 4104 * nor scrolling used 4105 */ 4106 if ( ! userInputs && ! scrollX && ! scrollY && 4107 columnCount == _fnVisbleColumns( oSettings ) && 4108 columnCount == headerCells.length 4109 ) { 4110 for ( i=0 ; i<columnCount ; i++ ) { 4111 columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() ); 4112 } 4113 } 4114 else 4115 { 4116 // Otherwise construct a single row table with the widest node in the 4117 // data, assign any user defined widths, then insert it into the DOM and
4118 // allow the browser to do all the hard work of calculating table widths 4119 var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table 4120 .empty() 4121 .css( 'visibility', 'hidden' ) 4122 .removeAttr( 'id' ) 4123 .append( $(oSettings.nTHead).clone( false ) ) 4124 .append( $(oSettings.nTFoot).clone( false ) ) 4125 .append( $('<tbody><tr/></tbody>') ); 4126 4127 // Remove any assigned widths from the footer (from scrolling) 4128 tmpTable.find('tfoot th, tfoot td').css('width', ''); 4129 4130 var tr = tmpTable.find( 'tbody tr' ); 4131 4132 // Apply custom sizing to the cloned header 4133 headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] ); 4134 4135 for ( i=0 ; i<visibleColumns.length ; i++ ) { 4136 column = columns[ visibleColumns[i] ]; 4137 4138 headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ? 4139 _fnStringToCss( column.sWidthOrig ) : 4140 ''; 4141 } 4142 4143 // Find the widest cell for each column and put it into the table 4144 if ( oSettings.aoData.length ) { 4145 for ( i=0 ; i<visibleColumns.length ; i++ ) { 4146 columnIdx = visibleColumns[i]; 4147 column = columns[ columnIdx ]; 4148 4149 $( _fnGetWidestNode( oSettings, columnIdx ) ) 4150 .clone( false ) 4151 .append( column.sContentPadding ) 4152 .appendTo( tr ); 4153 } 4154 } 4155 4156 // Table has been built, attach to the document so we can work with it 4157 tmpTable.appendTo( tableContainer ); 4158 4159 // When scrolling (X or Y) we want to set the width of the table as 4160 // appropriate. However, when not scrolling leave the table width as it 4161 // is. This results in slightly different, but I think correct behaviour 4162 if ( scrollX && scrollXInner ) { 4163 tmpTable.width( scrollXInner ); 4164 } 4165 else if ( scrollX ) { 4166 tmpTable.css( 'width', 'auto' ); 4167 4168 if ( tmpTable.width() < tableContainer.offsetWidth ) { 4169 tmpTable.width( tableContainer.offsetWidth ); 4170 } 4171 } 4172 else if ( scrollY ) { 4173 tmpTable.width( tableContainer.offsetWidth ); 4174 } 4175 else if ( tableWidthAttr ) { 4176 tmpTable.width( tableWidthAttr ); 4177 } 4178 4179 // Take into account the y scrollbar 4180 _fnScrollingWidthAdjust( oSettings, tmpTable[0] ); 4181 4182 // Browsers need a bit of a hand when a width is assigned to any columns 4183 // when x-scrolling as they tend to collapse the table to the min-width, 4184 // even if we sent the column widths. So we need to keep track of what 4185 // the table width should be by summing the user given values, and the 4186 // automatic values 4187 if ( scrollX ) 4188 { 4189 var total = 0; 4190 4191 for ( i=0 ; i<visibleColumns.length ; i++ ) { 4192 column = columns[ visibleColumns[i] ]; 4193 outerWidth = $(headerCells[i]).outerWidth(); 4194 4195 total += column.sWidthOrig === null ? 4196 outerWidth : 4197 parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width(); 4198 } 4199 4200 tmpTable.width( _fnStringToCss( total ) ); 4201 table.style.width = _fnStringToCss( total ); 4202 } 4203 4204 // Get the width of each column in the constructed table 4205 for ( i=0 ; i<visibleColumns.length ; i++ ) { 4206 column = columns[ visibleColumns[i] ]; 4207 width = $(headerCells[i]).width(); 4208 4209 if ( width ) { 4210 column.sWidth = _fnStringToCss( width ); 4211 } 4212 } 4213 4214 table.style.width = _fnStringToCss( tmpTable.css('width') ); 4215 4216 // Finished with the table - ditch it 4217 tmpTable.remove(); 4218 } 4219 4220 // If there is a width attr, we want to attach an event listener which 4221 // allows the table sizing to automatically adjust when the window is 4222 // resized. Use the width attr rather than CSS, since we can't know if the 4223 // CSS is a relative value or absolute - DOM read is always px. 4224 if ( tableWidthAttr ) { 4225 table.style.width = _fnStringToCss( tableWidthAttr ); 4226 } 4227 4228 if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) { 4229 $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () { 4230 _fnAdjustColumnSizing( oSettings ); 4231 } ) ); 4232 4233 oSettings._reszEvt = true; 4234 } 4235 } 4236 4237 4238 /** 4239 * Throttle the calls to a function. Arguments and context are maintained for 4240 * the throttled function 4241 * @param {function} fn Function to be called 4242 * @param {int} [freq=200] call frequency in mS 4243 * @returns {function} wrapped function 4244 * @memberof DataTable#oApi 4245 */ 4246 function _fnThrottle( fn, freq ) { 4247 var 4248 frequency = freq !== undefined ? freq : 200, 4249 last, 4250 timer; 4251 4252 return function () { 4253 var 4254 that = this, 4255 now = +new Date(), 4256 args = arguments; 4257 4258 if ( last && now < last + frequency ) { 4259 clearTimeout( timer ); 4260 4261 timer = setTimeout( function () { 4262 last = undefined; 4263 fn.apply( that, args ); 4264 }, frequency ); 4265 } 4266 else { 4267 last = now; 4268 fn.apply( that, args ); 4269 } 4270 }; 4271 } 4272 4273 4274 /** 4275 * Convert a CSS unit width to pixels (e.g. 2em) 4276 * @param {string} width width to be converted 4277 * @param {node} parent parent to get the with for (required for relative widths) - optional 4278 * @returns {int} width in pixels 4279 * @memberof DataTable#oApi 4280 */ 4281 function _fnConvertToWidth ( width, parent ) 4282 { 4283 if ( ! width ) { 4284 return 0; 4285 } 4286 4287 var n = $('<div/>') 4288 .css( 'width', _fnStringToCss( width ) ) 4289 .appendTo( parent || document.body ); 4290 4291 var val = n[0].offsetWidth; 4292 n.remove(); 4293 4294 return val; 4295 } 4296 4297 4298 /** 4299 * Adjust a table's width to take account of vertical scroll bar 4300 * @param {object} oSettings dataTables settings object 4301 * @param {node} n table node 4302 * @memberof DataTable#oApi 4303 */ 4304 4305 function _fnScrollingWidthAdjust ( settings, n ) 4306 { 4307 var scroll = settings.oScroll; 4308
4309 if ( scroll.sX || scroll.sY ) { 4310 // When y-scrolling only, we want to remove the width of the scroll bar 4311 // so the table + scroll bar will fit into the area available, otherwise 4312 // we fix the table at its current size with no adjustment 4313 var correction = ! scroll.sX ? scroll.iBarWidth : 0; 4314 n.style.width = _fnStringToCss( $(n).outerWidth() - correction ); 4315 } 4316 } 4317 4318 4319 /** 4320 * Get the widest node 4321 * @param {object} settings dataTables settings object 4322 * @param {int} colIdx column of interest 4323 * @returns {node} widest table node 4324 * @memberof DataTable#oApi 4325 */ 4326 function _fnGetWidestNode( settings, colIdx ) 4327 { 4328 var idx = _fnGetMaxLenString( settings, colIdx ); 4329 if ( idx < 0 ) { 4330 return null; 4331 } 4332 4333 var data = settings.aoData[ idx ]; 4334 return ! data.nTr ? // Might not have been created when deferred rendering 4335 $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] : 4336 data.anCells[ colIdx ]; 4337 } 4338 4339 4340 /** 4341 * Get the maximum strlen for each data column 4342 * @param {object} settings dataTables settings object 4343 * @param {int} colIdx column of interest 4344 * @returns {string} max string length for each column 4345 * @memberof DataTable#oApi 4346 */ 4347 function _fnGetMaxLenString( settings, colIdx ) 4348 { 4349 var s, max=-1, maxIdx = -1; 4350 4351 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 4352 s = _fnGetCellData( settings, i, colIdx, 'display' )+''; 4353 s = s.replace( __re_html_remove, '' ); 4354 4355 if ( s.length > max ) { 4356 max = s.length; 4357 maxIdx = i; 4358 } 4359 } 4360 4361 return maxIdx; 4362 } 4363 4364 4365 /** 4366 * Append a CSS unit (only if required) to a string 4367 * @param {string} value to css-ify 4368 * @returns {string} value with css unit 4369 * @memberof DataTable#oApi 4370 */ 4371 function _fnStringToCss( s ) 4372 { 4373 if ( s === null ) { 4374 return '0px'; 4375 } 4376 4377 if ( typeof s == 'number' ) { 4378 return s < 0 ? 4379 '0px' : 4380 s+'px'; 4381 } 4382 4383 // Check it has a unit character already 4384 return s.match(/\d$/) ? 4385 s+'px' : 4386 s; 4387 } 4388 4389 4390 /** 4391 * Get the width of a scroll bar in this browser being used 4392 * @returns {int} width in pixels 4393 * @memberof DataTable#oApi 4394 */ 4395 function _fnScrollBarWidth () 4396 { 4397 // On first run a static variable is set, since this is only needed once. 4398 // Subsequent runs will just use the previously calculated value 4399 if ( ! DataTable.__scrollbarWidth ) { 4400 var inner = $('<p/>').css( { 4401 width: '100%', 4402 height: 200, 4403 padding: 0 4404 } )[0]; 4405 4406 var outer = $('<div/>') 4407 .css( { 4408 position: 'absolute', 4409 top: 0, 4410 left: 0, 4411 width: 200, 4412 height: 150, 4413 padding: 0, 4414 overflow: 'hidden', 4415 visibility: 'hidden' 4416 } ) 4417 .append( inner ) 4418 .appendTo( 'body' ); 4419 4420 var w1 = inner.offsetWidth; 4421 outer.css( 'overflow', 'scroll' ); 4422 var w2 = inner.offsetWidth; 4423 4424 if ( w1 === w2 ) { 4425 w2 = outer[0].clientWidth; 4426 } 4427 4428 outer.remove(); 4429 4430 DataTable.__scrollbarWidth = w1 - w2; 4431 } 4432 4433 return DataTable.__scrollbarWidth; 4434 } 4435 4436 4437 4438 function _fnSortFlatten ( settings ) 4439 { 4440 var 4441 i, iLen, k, kLen, 4442 aSort = [], 4443 aiOrig = [], 4444 aoColumns = settings.aoColumns, 4445 aDataSort, iCol, sType, srcCol, 4446 fixed = settings.aaSortingFixed, 4447 fixedObj = $.isPlainObject( fixed ), 4448 nestedSort = [], 4449 add = function ( a ) { 4450 if ( a.length && ! $.isArray( a[0] ) ) { 4451 // 1D array 4452 nestedSort.push( a ); 4453 } 4454 else { 4455 // 2D array 4456 nestedSort.push.apply( nestedSort, a ); 4457 } 4458 }; 4459 4460 // Build the sort array, with pre-fix and post-fix options if they have been 4461 // specified 4462 if ( $.isArray( fixed ) ) { 4463 add( fixed ); 4464 } 4465 4466 if ( fixedObj && fixed.pre ) { 4467 add( fixed.pre ); 4468 } 4469 4470 add( settings.aaSorting ); 4471 4472 if (fixedObj && fixed.post ) { 4473 add( fixed.post ); 4474 } 4475 4476 for ( i=0 ; i<nestedSort.length ; i++ ) 4477 { 4478 srcCol = nestedSort[i][0]; 4479 aDataSort = aoColumns[ srcCol ].aDataSort; 4480 4481 for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ ) 4482 { 4483 iCol = aDataSort[k]; 4484 sType = aoColumns[ iCol ].sType || 'string'; 4485 4486 if ( nestedSort[i]._idx === undefined ) { 4487 nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting ); 4488 } 4489 4490 aSort.push( { 4491 src: srcCol, 4492 col: iCol, 4493 dir: nestedSort[i][1], 4494 index: nestedSort[i]._idx, 4495 type: sType, 4496 formatter: DataTable.ext.type.order[ sType+"-pre" ] 4497 } ); 4498 } 4499 } 4500 4501 return aSort; 4502 } 4503 4504 /** 4505 * Change the order of the table 4506 * @param {object} oSettings dataTables settings object 4507 * @memberof DataTable#oApi 4508 * @todo This really needs split up! 4509 */ 4510 function _fnSort ( oSettings ) 4511 { 4512 var 4513 i, ien, iLen, j, jLen, k, kLen, 4514 sDataType, nTh, 4515 aiOrig = [], 4516 oExtSort = DataTable.ext.type.order, 4517 aoData = oSettings.aoData, 4518 aoColumns = oSettings.aoColumns, 4519 aDataSort, data, iCol, sType, oSort, 4520 formatters = 0, 4521 sortCol, 4522 displayMaster = oSettings.aiDisplayMaster, 4523 aSort; 4524 4525 // Resolve any column types that are unknown due to addition or invalidation 4526 // @todo Can this be moved into a 'data-ready' handler which is called when 4527 // data is going to be used in the table? 4528 _fnColumnTypes( oSettings ); 4529 4530 aSort = _fnSortFlatten( oSettings ); 4531 4532 for ( i=0, ien=aSort.length ; i<ien ; i++ ) { 4533 sortCol = aSort[i]; 4534 4535 // Track if we can use the fast sort algorithm 4536 if ( sortCol.formatter ) { 4537 formatters++; 4538 } 4539 4540 // Load the data needed for the sort, for each cell 4541 _fnSortData( oSettings, sortCol.col ); 4542 } 4543 4544 /* No sorting required if server-side or no sorting array */ 4545 if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 ) 4546 { 4547 // Create a value - key array of the current row positions such that we can use their 4548 // current position during the sort, if values match, in order to perform stable sorting 4549 for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) { 4550 aiOrig[ displayMaster[i] ] = i; 4551 } 4552
4553 /* Do the sort - here we want multi-column sorting based on a given data source (column) 4554 * and sorting function (from oSort) in a certain direction. It's reasonably complex to 4555 * follow on it's own, but this is what we want (example two column sorting): 4556 * fnLocalSorting = function(a,b){ 4557 * var iTest; 4558 * iTest = oSort['string-asc']('data11', 'data12'); 4559 * if (iTest !== 0) 4560 * return iTest; 4561 * iTest = oSort['numeric-desc']('data21', 'data22'); 4562 * if (iTest !== 0) 4563 * return iTest; 4564 * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] ); 4565 * } 4566 * Basically we have a test for each sorting column, if the data in that column is equal, 4567 * test the next column. If all columns match, then we use a numeric sort on the row 4568 * positions in the original data array to provide a stable sort. 4569 * 4570 * Note - I know it seems excessive to have two sorting methods, but the first is around 4571 * 15% faster, so the second is only maintained for backwards compatibility with sorting 4572 * methods which do not have a pre-sort formatting function. 4573 */ 4574 if ( formatters === aSort.length ) { 4575 // All sort types have formatting functions 4576 displayMaster.sort( function ( a, b ) { 4577 var 4578 x, y, k, test, sort, 4579 len=aSort.length, 4580 dataA = aoData[a]._aSortData, 4581 dataB = aoData[b]._aSortData; 4582 4583 for ( k=0 ; k<len ; k++ ) { 4584 sort = aSort[k]; 4585 4586 x = dataA[ sort.col ]; 4587 y = dataB[ sort.col ]; 4588 4589 test = x<y ? -1 : x>y ? 1 : 0; 4590 if ( test !== 0 ) { 4591 return sort.dir === 'asc' ? test : -test; 4592 } 4593 } 4594 4595 x = aiOrig[a]; 4596 y = aiOrig[b]; 4597 return x<y ? -1 : x>y ? 1 : 0; 4598 } ); 4599 } 4600 else { 4601 // Depreciated - remove in 1.11 (providing a plug-in option) 4602 // Not all sort types have formatting methods, so we have to call their sorting 4603 // methods. 4604 displayMaster.sort( function ( a, b ) { 4605 var 4606 x, y, k, l, test, sort, fn, 4607 len=aSort.length, 4608 dataA = aoData[a]._aSortData, 4609 dataB = aoData[b]._aSortData; 4610 4611 for ( k=0 ; k<len ; k++ ) { 4612 sort = aSort[k]; 4613 4614 x = dataA[ sort.col ]; 4615 y = dataB[ sort.col ]; 4616 4617 fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ]; 4618 test = fn( x, y ); 4619 if ( test !== 0 ) { 4620 return test; 4621 } 4622 } 4623 4624 x = aiOrig[a]; 4625 y = aiOrig[b]; 4626 return x<y ? -1 : x>y ? 1 : 0; 4627 } ); 4628 } 4629 } 4630 4631 /* Tell the draw function that we have sorted the data */ 4632 oSettings.bSorted = true; 4633 } 4634 4635 4636 function _fnSortAria ( settings ) 4637 { 4638 var label; 4639 var nextSort; 4640 var columns = settings.aoColumns; 4641 var aSort = _fnSortFlatten( settings ); 4642 var oAria = settings.oLanguage.oAria; 4643 4644 // ARIA attributes - need to loop all columns, to update all (removing old 4645 // attributes as needed) 4646 for ( var i=0, iLen=columns.length ; i<iLen ; i++ ) 4647 { 4648 var col = columns[i]; 4649 var asSorting = col.asSorting; 4650 var sTitle = col.sTitle.replace( /<.*?>/g, "" ); 4651 var th = col.nTh; 4652 4653 // IE7 is throwing an error when setting these properties with jQuery's 4654 // attr() and removeAttr() methods... 4655 th.removeAttribute('aria-sort'); 4656 4657 /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */ 4658 if ( col.bSortable ) { 4659 if ( aSort.length > 0 && aSort[0].col == i ) { 4660 th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" ); 4661 nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0]; 4662 } 4663 else { 4664 nextSort = asSorting[0]; 4665 } 4666 4667 label = sTitle + ( nextSort === "asc" ? 4668 oAria.sSortAscending : 4669 oAria.sSortDescending 4670 ); 4671 } 4672 else { 4673 label = sTitle; 4674 } 4675 4676 th.setAttribute('aria-label', label); 4677 } 4678 } 4679 4680 4681 /** 4682 * Function to run on user sort request 4683 * @param {object} settings dataTables settings object 4684 * @param {node} attachTo node to attach the handler to 4685 * @param {int} colIdx column sorting index 4686 * @param {boolean} [append=false] Append the requested sort to the existing
4687 * sort if true (i.e. multi-column sort) 4688 * @param {function} [callback] callback function 4689 * @memberof DataTable#oApi 4690 */ 4691 function _fnSortListener ( settings, colIdx, append, callback ) 4692 { 4693 var col = settings.aoColumns[ colIdx ]; 4694 var sorting = settings.aaSorting; 4695 var asSorting = col.asSorting; 4696 var nextSortIdx; 4697 var next = function ( a, overflow ) { 4698 var idx = a._idx; 4699 if ( idx === undefined ) { 4700 idx = $.inArray( a[1], asSorting ); 4701 } 4702 4703 return idx+1 < asSorting.length ? 4704 idx+1 : 4705 overflow ? 4706 null : 4707 0; 4708 }; 4709 4710 // Convert to 2D array if needed 4711 if ( typeof sorting[0] === 'number' ) { 4712 sorting = settings.aaSorting = [ sorting ]; 4713 } 4714 4715 // If appending the sort then we are multi-column sorting 4716 if ( append && settings.oFeatures.bSortMulti ) { 4717 // Are we already doing some kind of sort on this column? 4718 var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') ); 4719 4720 if ( sortIdx !== -1 ) { 4721 // Yes, modify the sort 4722 nextSortIdx = next( sorting[sortIdx], true ); 4723 4724 if ( nextSortIdx === null ) { 4725 sorting.splice( sortIdx, 1 ); 4726 } 4727 else { 4728 sorting[sortIdx][1] = asSorting[ nextSortIdx ]; 4729 sorting[sortIdx]._idx = nextSortIdx; 4730 } 4731 } 4732 else { 4733 // No sort on this column yet 4734 sorting.push( [ colIdx, asSorting[0], 0 ] ); 4735 sorting[sorting.length-1]._idx = 0; 4736 } 4737 } 4738 else if ( sorting.length && sorting[0][0] == colIdx ) { 4739 // Single column - already sorting on this column, modify the sort 4740 nextSortIdx = next( sorting[0] ); 4741 4742 sorting.length = 1; 4743 sorting[0][1] = asSorting[ nextSortIdx ]; 4744 sorting[0]._idx = nextSortIdx; 4745 } 4746 else { 4747 // Single column - sort only on this column 4748 sorting.length = 0; 4749 sorting.push( [ colIdx, asSorting[0] ] ); 4750 sorting[0]._idx = 0; 4751 } 4752 4753 // Run the sort by calling a full redraw 4754 _fnReDraw( settings ); 4755 4756 // callback used for async user interaction 4757 if ( typeof callback == 'function' ) { 4758 callback( settings ); 4759 } 4760 } 4761 4762 4763 /** 4764 * Attach a sort handler (click) to a node 4765 * @param {object} settings dataTables settings object 4766 * @param {node} attachTo node to attach the handler to 4767 * @param {int} colIdx column sorting index 4768 * @param {function} [callback] callback function 4769 * @memberof DataTable#oApi 4770 */ 4771 function _fnSortAttachListener ( settings, attachTo, colIdx, callback ) 4772 { 4773 var col = settings.aoColumns[ colIdx ]; 4774 4775 _fnBindAction( attachTo, {}, function (e) { 4776 /* If the column is not sortable - don't to anything */ 4777 if ( col.bSortable === false ) { 4778 return; 4779 } 4780 4781 // If processing is enabled use a timeout to allow the processing 4782 // display to be shown - otherwise to it synchronously 4783 if ( settings.oFeatures.bProcessing ) { 4784 _fnProcessingDisplay( settings, true ); 4785 4786 setTimeout( function() { 4787 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 4788 4789 // In server-side processing, the draw callback will remove the 4790 // processing display 4791 if ( _fnDataSource( settings ) !== 'ssp' ) { 4792 _fnProcessingDisplay( settings, false ); 4793 } 4794 }, 0 ); 4795 } 4796 else { 4797 _fnSortListener( settings, colIdx, e.shiftKey, callback ); 4798 } 4799 } ); 4800 } 4801 4802 4803 /** 4804 * Set the sorting classes on table's body, Note: it is safe to call this function 4805 * when bSort and bSortClasses are false 4806 * @param {object} oSettings dataTables settings object 4807 * @memberof DataTable#oApi 4808 */ 4809 function _fnSortingClasses( settings ) 4810 { 4811 var oldSort = settings.aLastSort; 4812 var sortClass = settings.oClasses.sSortColumn; 4813 var sort = _fnSortFlatten( settings ); 4814 var features = settings.oFeatures; 4815 var i, ien, colIdx; 4816 4817 if ( features.bSort && features.bSortClasses ) { 4818 // Remove old sorting classes 4819 for ( i=0, ien=oldSort.length ; i<ien ; i++ ) { 4820 colIdx = oldSort[i].src; 4821 4822 // Remove column sorting 4823 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 4824 .removeClass( sortClass + (i<2 ? i+1 : 3) ); 4825 } 4826 4827 // Add new column sorting 4828 for ( i=0, ien=sort.length ; i<ien ; i++ ) { 4829 colIdx = sort[i].src; 4830 4831 $( _pluck( settings.aoData, 'anCells', colIdx ) ) 4832 .addClass( sortClass + (i<2 ? i+1 : 3) ); 4833 } 4834 } 4835 4836 settings.aLastSort = sort; 4837 } 4838 4839 4840 // Get the data to sort a column, be it from cache, fresh (populating the 4841 // cache), or from a sort formatter 4842 function _fnSortData( settings, idx ) 4843 { 4844 // Custom sorting function - provided by the sort data type 4845 var column = settings.aoColumns[ idx ]; 4846 var customSort = DataTable.ext.order[ column.sSortDataType ]; 4847 var customData; 4848 4849 if ( customSort ) { 4850 customData = customSort.call( settings.oInstance, settings, idx, 4851 _fnColumnIndexToVisible( settings, idx ) 4852 ); 4853 } 4854 4855 // Use / populate cache 4856 var row, cellData; 4857 var formatter = DataTable.ext.type.order[ column.sType+"-pre" ]; 4858 4859 for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 4860 row = settings.aoData[i]; 4861 4862 if ( ! row._aSortData ) { 4863 row._aSortData = []; 4864 } 4865 4866 if ( ! row._aSortData[idx] || customSort ) { 4867 cellData = customSort ? 4868 customData[i] : // If there was a custom sort function, use data from there 4869 _fnGetCellData( settings, i, idx, 'sort' ); 4870 4871 row._aSortData[ idx ] = formatter ? 4872 formatter( cellData ) : 4873 cellData; 4874 } 4875 } 4876 } 4877 4878 4879 4880 /** 4881 * Save the state of a table 4882 * @param {object} oSettings dataTables settings object 4883 * @memberof DataTable#oApi 4884 */ 4885 function _fnSaveState ( settings ) 4886 { 4887 if ( !settings.oFeatures.bStateSave || settings.bDestroying ) 4888 { 4889 return; 4890 } 4891 4892 /* Store the interesting variables */ 4893 var state = { 4894 time: +new Date(), 4895 start: settings._iDisplayStart, 4896 length: settings._iDisplayLength, 4897 order: $.extend( true, [], settings.aaSorting ), 4898 search: _fnSearchToCamel( settings.oPreviousSearch ),
4899 columns: $.map( settings.aoColumns, function ( col, i ) { 4900 return { 4901 visible: col.bVisible, 4902 search: _fnSearchToCamel( settings.aoPreSearchCols[i] ) 4903 }; 4904 } ) 4905 }; 4906 4907 _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] ); 4908 4909 settings.oSavedState = state; 4910 settings.fnStateSaveCallback.call( settings.oInstance, settings, state ); 4911 } 4912 4913 4914 /** 4915 * Attempt to load a saved table state 4916 * @param {object} oSettings dataTables settings object 4917 * @param {object} oInit DataTables init object so we can override settings 4918 * @memberof DataTable#oApi 4919 */ 4920 function _fnLoadState ( settings, oInit ) 4921 { 4922 var i, ien; 4923 var columns = settings.aoColumns; 4924 4925 if ( ! settings.oFeatures.bStateSave ) { 4926 return; 4927 } 4928 4929 var state = settings.fnStateLoadCallback.call( settings.oInstance, settings ); 4930 if ( ! state || ! state.time ) { 4931 return; 4932 } 4933 4934 /* Allow custom and plug-in manipulation functions to alter the saved data set and 4935 * cancelling of loading by returning false 4936 */ 4937 var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] ); 4938 if ( $.inArray( false, abStateLoad ) !== -1 ) { 4939 return; 4940 } 4941 4942 /* Reject old data */ 4943 var duration = settings.iStateDuration; 4944 if ( duration > 0 && state.time < +new Date() - (duration*1000) ) { 4945 return; 4946 } 4947 4948 // Number of columns have changed - all bets are off, no restore of settings 4949 if ( columns.length !== state.columns.length ) { 4950 return; 4951 } 4952 4953 // Store the saved state so it might be accessed at any time 4954 settings.oLoadedState = $.extend( true, {}, state ); 4955 4956 // Restore key features - todo - for 1.11 this needs to be done by 4957 // subscribed events 4958 settings._iDisplayStart = state.start; 4959 settings.iInitDisplayStart = state.start; 4960 settings._iDisplayLength = state.length; 4961 settings.aaSorting = []; 4962 4963 // Order 4964 $.each( state.order, function ( i, col ) { 4965 settings.aaSorting.push( col[0] >= columns.length ? 4966 [ 0, col[1] ] : 4967 col 4968 ); 4969 } ); 4970 4971 // Search 4972 $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) ); 4973 4974 // Columns 4975 for ( i=0, ien=state.columns.length ; i<ien ; i++ ) { 4976 var col = state.columns[i]; 4977 4978 // Visibility 4979 columns[i].bVisible = col.visible; 4980 4981 // Search 4982 $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) ); 4983 } 4984 4985 _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] ); 4986 } 4987 4988 4989 /** 4990 * Return the settings object for a particular table 4991 * @param {node} table table we are using as a dataTable 4992 * @returns {object} Settings object - or null if not found 4993 * @memberof DataTable#oApi 4994 */ 4995 function _fnSettingsFromNode ( table ) 4996 { 4997 var settings = DataTable.settings; 4998 var idx = $.inArray( table, _pluck( settings, 'nTable' ) ); 4999 5000 return idx !== -1 ? 5001 settings[ idx ] : 5002 null; 5003 } 5004 5005 5006 /** 5007 * Log an error message 5008 * @param {object} settings dataTables settings object 5009 * @param {int} level log error messages, or display them to the user 5010 * @param {string} msg error message 5011 * @param {int} tn Technical note id to get more information about the error. 5012 * @memberof DataTable#oApi 5013 */ 5014 function _fnLog( settings, level, msg, tn ) 5015 { 5016 msg = 'DataTables warning: '+ 5017 (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg; 5018 5019 if ( tn ) { 5020 msg += '. For more information about this error, please see '+ 5021 'http://datatables.net/tn/'+tn; 5022 } 5023 5024 if ( ! level ) { 5025 // Backwards compatibility pre 1.10 5026 var ext = DataTable.ext; 5027 var type = ext.sErrMode || ext.errMode; 5028 5029 _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] ); 5030 5031 if ( type == 'alert' ) { 5032 alert( msg ); 5033 } 5034 else if ( type == 'throw' ) { 5035 throw new Error(msg); 5036 } 5037 else if ( typeof type == 'function' ) { 5038 type( settings, tn, msg ); 5039 } 5040 } 5041 else if ( window.console && console.log ) { 5042 console.log( msg ); 5043 } 5044 } 5045 5046 5047 /** 5048 * See if a property is defined on one object, if so assign it to the other object 5049 * @param {object} ret target object 5050 * @param {object} src source object 5051 * @param {string} name property 5052 * @param {string} [mappedName] name to map too - optional, name used if not given 5053 * @memberof DataTable#oApi 5054 */ 5055 function _fnMap( ret, src, name, mappedName ) 5056 { 5057 if ( $.isArray( name ) ) { 5058 $.each( name, function (i, val) { 5059 if ( $.isArray( val ) ) { 5060 _fnMap( ret, src, val[0], val[1] ); 5061 } 5062 else { 5063 _fnMap( ret, src, val ); 5064 } 5065 } ); 5066 5067 return; 5068 } 5069 5070 if ( mappedName === undefined ) { 5071 mappedName = name; 5072 } 5073 5074 if ( src[name] !== undefined ) { 5075 ret[mappedName] = src[name]; 5076 } 5077 } 5078 5079 5080 /** 5081 * Extend objects - very similar to jQuery.extend, but deep copy objects, and 5082 * shallow copy arrays. The reason we need to do this, is that we don't want to 5083 * deep copy array init values (such as aaSorting) since the dev wouldn't be 5084 * able to override them, but we do want to deep copy arrays. 5085 * @param {object} out Object to extend 5086 * @param {object} extender Object from which the properties will be applied to 5087 * out 5088 * @param {boolean} breakRefs If true, then arrays will be sliced to take an 5089 * independent copy with the exception of the `data` or `aaData` parameters 5090 * if they are present. This is so you can pass in a collection to 5091 * DataTables and have that used as your data source without breaking the 5092 * references 5093 * @returns {object} out Reference, just for convenience - out === the return. 5094 * @memberof DataTable#oApi 5095 * @todo This doesn't take account of arrays inside the deep copied objects. 5096 */ 5097 function _fnExtend( out, extender, breakRefs ) 5098 { 5099 var val; 5100 5101 for ( var prop in extender ) { 5102 if ( extender.hasOwnProperty(prop) ) { 5103 val = extender[prop]; 5104 5105 if ( $.isPlainObject( val ) ) { 5106 if ( ! $.isPlainObject( out[prop] ) ) { 5107 out[prop] = {}; 5108 } 5109 $.extend( true, out[prop], val ); 5110 } 5111 else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) { 5112 out[prop] = val.slice(); 5113 } 5114 else { 5115 out[prop] = val; 5116 } 5117 } 5118 } 5119 5120 return out; 5121 } 5122 5123 5124 /** 5125 * Bind an event handers to allow a click or return key to activate the callback. 5126 * This is good for accessibility since a return on the keyboard will have the 5127 * same effect as a click, if the element has focus. 5128 * @param {element} n Element to bind the action to 5129 * @param {object} oData Data object to pass to the triggered function 5130 * @param {function} fn Callback function for when the event is triggered 5131 * @memberof DataTable#oApi 5132 */ 5133 function _fnBindAction( n, oData, fn ) 5134 { 5135 $(n) 5136 .bind( 'click.DT', oData, function (e) { 5137 n.blur(); // Remove focus outline for mouse users 5138 fn(e); 5139 } ) 5140 .bind( 'keypress.DT', oData, function (e){ 5141 if ( e.which === 13 ) { 5142 e.preventDefault(); 5143 fn(e); 5144 } 5145 } ) 5146 .bind( 'selectstart.DT', function () { 5147 /* Take the brutal approach to cancelling text selection */ 5148 return false;
5149 } ); 5150 } 5151 5152 5153 /** 5154 * Register a callback function. Easily allows a callback function to be added to 5155 * an array store of callback functions that can then all be called together. 5156 * @param {object} oSettings dataTables settings object 5157 * @param {string} sStore Name of the array storage for the callbacks in oSettings 5158 * @param {function} fn Function to be called back 5159 * @param {string} sName Identifying name for the callback (i.e. a label) 5160 * @memberof DataTable#oApi 5161 */ 5162 function _fnCallbackReg( oSettings, sStore, fn, sName ) 5163 { 5164 if ( fn ) 5165 { 5166 oSettings[sStore].push( { 5167 "fn": fn, 5168 "sName": sName 5169 } ); 5170 } 5171 } 5172 5173 5174 /** 5175 * Fire callback functions and trigger events. Note that the loop over the 5176 * callback array store is done backwards! Further note that you do not want to 5177 * fire off triggers in time sensitive applications (for example cell creation) 5178 * as its slow. 5179 * @param {object} settings dataTables settings object 5180 * @param {string} callbackArr Name of the array storage for the callbacks in 5181 * oSettings 5182 * @param {string} event Name of the jQuery custom event to trigger. If null no 5183 * trigger is fired 5184 * @param {array} args Array of arguments to pass to the callback function / 5185 * trigger 5186 * @memberof DataTable#oApi 5187 */ 5188 function _fnCallbackFire( settings, callbackArr, e, args ) 5189 { 5190 var ret = []; 5191 5192 if ( callbackArr ) { 5193 ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) { 5194 return val.fn.apply( settings.oInstance, args ); 5195 } ); 5196 } 5197 5198 if ( e !== null ) { 5199 $(settings.nTable).trigger( e+'.dt', args ); 5200 } 5201 5202 return ret; 5203 } 5204 5205 5206 function _fnLengthOverflow ( settings ) 5207 { 5208 var 5209 start = settings._iDisplayStart, 5210 end = settings.fnDisplayEnd(), 5211 len = settings._iDisplayLength; 5212 5213 /* If we have space to show extra rows (backing up from the end point - then do so */ 5214 if ( start >= end ) 5215 { 5216 start = end - len; 5217 } 5218 5219 // Keep the start record on the current page 5220 start -= (start % len); 5221 5222 if ( len === -1 || start < 0 ) 5223 { 5224 start = 0; 5225 } 5226 5227 settings._iDisplayStart = start; 5228 } 5229 5230 5231 function _fnRenderer( settings, type ) 5232 { 5233 var renderer = settings.renderer; 5234 var host = DataTable.ext.renderer[type]; 5235 5236 if ( $.isPlainObject( renderer ) && renderer[type] ) { 5237 // Specific renderer for this type. If available use it, otherwise use 5238 // the default. 5239 return host[renderer[type]] || host._; 5240 } 5241 else if ( typeof renderer === 'string' ) { 5242 // Common renderer - if there is one available for this type use it, 5243 // otherwise use the default 5244 return host[renderer] || host._; 5245 } 5246 5247 // Use the default 5248 return host._; 5249 } 5250 5251 5252 /** 5253 * Detect the data source being used for the table. Used to simplify the code 5254 * a little (ajax) and to make it compress a little smaller. 5255 * 5256 * @param {object} settings dataTables settings object 5257 * @returns {string} Data source 5258 * @memberof DataTable#oApi 5259 */ 5260 function _fnDataSource ( settings ) 5261 { 5262 if ( settings.oFeatures.bServerSide ) { 5263 return 'ssp'; 5264 } 5265 else if ( settings.ajax || settings.sAjaxSource ) { 5266 return 'ajax'; 5267 } 5268 return 'dom'; 5269 } 5270 5271 5272 DataTable = function( options ) 5273 { 5274 /** 5275 * Perform a jQuery selector action on the table's TR elements (from the tbody) and 5276 * return the resulting jQuery object. 5277 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 5278 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 5279 * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter 5280 * criterion ("applied") or all TR elements (i.e. no filter). 5281 * @param {string} [oOpts.order=current] Order of the TR elements in the processed array. 5282 * Can be either 'current', whereby the current sorting of the table is used, or 5283 * 'original' whereby the original order the data was read into the table is used. 5284 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 5285 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 5286 * 'current' and filter is 'applied', regardless of what they might be given as. 5287 * @returns {object} jQuery object, filtered by the given selector. 5288 * @dtopt API 5289 * @deprecated Since v1.10 5290 * 5291 * @example 5292 * $(document).ready(function() { 5293 * var oTable = $('#example').dataTable(); 5294 * 5295 * // Highlight every second row 5296 * oTable.$('tr:odd').css('backgroundColor', 'blue'); 5297 * } ); 5298 * 5299 * @example 5300 * $(document).ready(function() { 5301 * var oTable = $('#example').dataTable(); 5302 * 5303 * // Filter to rows with 'Webkit' in them, add a background colour and then 5304 * // remove the filter, thus highlighting the 'Webkit' rows only. 5305 * oTable.fnFilter('Webkit'); 5306 * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue'); 5307 * oTable.fnFilter(''); 5308 * } ); 5309 */ 5310 this.$ = function ( sSelector, oOpts ) 5311 { 5312 return this.api(true).$( sSelector, oOpts ); 5313 }; 5314
5315 5316 /** 5317 * Almost identical to $ in operation, but in this case returns the data for the matched 5318 * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes 5319 * rather than any descendants, so the data can be obtained for the row/cell. If matching 5320 * rows are found, the data returned is the original data array/object that was used to 5321 * create the row (or a generated array if from a DOM source). 5322 * 5323 * This method is often useful in-combination with $ where both functions are given the 5324 * same parameters and the array indexes will match identically. 5325 * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on 5326 * @param {object} [oOpts] Optional parameters for modifying the rows to be included 5327 * @param {string} [oOpts.filter=none] Select elements that meet the current filter 5328 * criterion ("applied") or all elements (i.e. no filter). 5329 * @param {string} [oOpts.order=current] Order of the data in the processed array. 5330 * Can be either 'current', whereby the current sorting of the table is used, or 5331 * 'original' whereby the original order the data was read into the table is used. 5332 * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page 5333 * ("current") or not ("all"). If 'current' is given, then order is assumed to be 5334 * 'current' and filter is 'applied', regardless of what they might be given as. 5335 * @returns {array} Data for the matched elements. If any elements, as a result of the 5336 * selector, were not TR, TD or TH elements in the DataTable, they will have a null 5337 * entry in the array. 5338 * @dtopt API 5339 * @deprecated Since v1.10 5340 * 5341 * @example 5342 * $(document).ready(function() { 5343 * var oTable = $('#example').dataTable(); 5344 * 5345 * // Get the data from the first row in the table 5346 * var data = oTable._('tr:first'); 5347 * 5348 * // Do something useful with the data 5349 * alert( "First cell is: "+data[0] ); 5350 * } ); 5351 * 5352 * @example 5353 * $(document).ready(function() { 5354 * var oTable = $('#example').dataTable(); 5355 * 5356 * // Filter to 'Webkit' and get all data for 5357 * oTable.fnFilter('Webkit'); 5358 * var data = oTable._('tr', {"search": "applied"}); 5359 * 5360 * // Do something with the data 5361 * alert( data.length+" rows matched the search" ); 5362 * } ); 5363 */ 5364 this._ = function ( sSelector, oOpts ) 5365 { 5366 return this.api(true).rows( sSelector, oOpts ).data(); 5367 }; 5368 5369 5370 /** 5371 * Create a DataTables Api instance, with the currently selected tables for 5372 * the Api's context. 5373 * @param {boolean} [traditional=false] Set the API instance's context to be 5374 * only the table referred to by the `DataTable.ext.iApiIndex` option, as was 5375 * used in the API presented by DataTables 1.9- (i.e. the traditional mode), 5376 * or if all tables captured in the jQuery object should be used. 5377 * @return {DataTables.Api} 5378 */ 5379 this.api = function ( traditional ) 5380 { 5381 return traditional ? 5382 new _Api( 5383 _fnSettingsFromNode( this[ _ext.iApiIndex ] ) 5384 ) : 5385 new _Api( this ); 5386 }; 5387 5388 5389 /** 5390 * Add a single new row or multiple rows of data to the table. Please note 5391 * that this is suitable for client-side processing only - if you are using 5392 * server-side processing (i.e. "bServerSide": true), then to add data, you 5393 * must add it to the data source, i.e. the server-side, through an Ajax call. 5394 * @param {array|object} data The data to be added to the table. This can be: 5395 * <ul> 5396 * <li>1D array of data - add a single row with the data provided</li> 5397 * <li>2D array of arrays - add multiple rows in a single call</li> 5398 * <li>object - data object when using <i>mData</i></li> 5399 * <li>array of objects - multiple data objects when using <i>mData</i></li> 5400 * </ul> 5401 * @param {bool} [redraw=true] redraw the table or not 5402 * @returns {array} An array of integers, representing the list of indexes in 5403 * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 5404 * the table. 5405 * @dtopt API 5406 * @deprecated Since v1.10 5407 * 5408 * @example 5409 * // Global var for counter 5410 * var giCount = 2; 5411 * 5412 * $(document).ready(function() { 5413 * $('#example').dataTable(); 5414 * } ); 5415 * 5416 * function fnClickAddRow() { 5417 * $('#example').dataTable().fnAddData( [ 5418 * giCount+".1", 5419 * giCount+".2", 5420 * giCount+".3", 5421 * giCount+".4" ] 5422 * ); 5423 * 5424 * giCount++; 5425 * } 5426 */ 5427 this.fnAddData = function( data, redraw ) 5428 { 5429 var api = this.api( true ); 5430 5431 /* Check if we want to add multiple rows or not */ 5432 var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ? 5433 api.rows.add( data ) : 5434 api.row.add( data ); 5435 5436 if ( redraw === undefined || redraw ) { 5437 api.draw(); 5438 } 5439 5440 return rows.flatten().toArray(); 5441 }; 5442
5443 5444 /** 5445 * This function will make DataTables recalculate the column sizes, based on the data 5446 * contained in the table and the sizes applied to the columns (in the DOM, CSS or 5447 * through the sWidth parameter). This can be useful when the width of the table's 5448 * parent element changes (for example a window resize). 5449 * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to 5450 * @dtopt API 5451 * @deprecated Since v1.10 5452 * 5453 * @example 5454 * $(document).ready(function() { 5455 * var oTable = $('#example').dataTable( { 5456 * "sScrollY": "200px", 5457 * "bPaginate": false 5458 * } ); 5459 * 5460 * $(window).bind('resize', function () { 5461 * oTable.fnAdjustColumnSizing(); 5462 * } ); 5463 * } ); 5464 */ 5465 this.fnAdjustColumnSizing = function ( bRedraw ) 5466 { 5467 var api = this.api( true ).columns.adjust(); 5468 var settings = api.settings()[0]; 5469 var scroll = settings.oScroll; 5470 5471 if ( bRedraw === undefined || bRedraw ) { 5472 api.draw( false ); 5473 } 5474 else if ( scroll.sX !== "" || scroll.sY !== "" ) { 5475 /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */ 5476 _fnScrollDraw( settings ); 5477 } 5478 }; 5479 5480 5481 /** 5482 * Quickly and simply clear a table 5483 * @param {bool} [bRedraw=true] redraw the table or not 5484 * @dtopt API 5485 * @deprecated Since v1.10 5486 * 5487 * @example 5488 * $(document).ready(function() { 5489 * var oTable = $('#example').dataTable(); 5490 * 5491 * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...) 5492 * oTable.fnClearTable(); 5493 * } ); 5494 */ 5495 this.fnClearTable = function( bRedraw ) 5496 { 5497 var api = this.api( true ).clear(); 5498 5499 if ( bRedraw === undefined || bRedraw ) { 5500 api.draw(); 5501 } 5502 }; 5503 5504 5505 /** 5506 * The exact opposite of 'opening' a row, this function will close any rows which 5507 * are currently 'open'. 5508 * @param {node} nTr the table row to 'close' 5509 * @returns {int} 0 on success, or 1 if failed (can't find the row) 5510 * @dtopt API 5511 * @deprecated Since v1.10 5512 * 5513 * @example 5514 * $(document).ready(function() { 5515 * var oTable; 5516 * 5517 * // 'open' an information row when a row is clicked on 5518 * $('#example tbody tr').click( function () { 5519 * if ( oTable.fnIsOpen(this) ) { 5520 * oTable.fnClose( this ); 5521 * } else { 5522 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 5523 * } 5524 * } ); 5525 * 5526 * oTable = $('#example').dataTable(); 5527 * } ); 5528 */ 5529 this.fnClose = function( nTr ) 5530 { 5531 this.api( true ).row( nTr ).child.hide(); 5532 }; 5533 5534 5535 /** 5536 * Remove a row for the table 5537 * @param {mixed} target The index of the row from aoData to be deleted, or 5538 * the TR element you want to delete 5539 * @param {function|null} [callBack] Callback function 5540 * @param {bool} [redraw=true] Redraw the table or not 5541 * @returns {array} The row that was deleted 5542 * @dtopt API 5543 * @deprecated Since v1.10 5544 * 5545 * @example 5546 * $(document).ready(function() { 5547 * var oTable = $('#example').dataTable(); 5548 * 5549 * // Immediately remove the first row 5550 * oTable.fnDeleteRow( 0 ); 5551 * } ); 5552 */ 5553 this.fnDeleteRow = function( target, callback, redraw ) 5554 { 5555 var api = this.api( true ); 5556 var rows = api.rows( target ); 5557 var settings = rows.settings()[0]; 5558 var data = settings.aoData[ rows[0][0] ]; 5559 5560 rows.remove(); 5561 5562 if ( callback ) { 5563 callback.call( this, settings, data ); 5564 } 5565 5566 if ( redraw === undefined || redraw ) { 5567 api.draw(); 5568 } 5569 5570 return data; 5571 }; 5572 5573 5574 /** 5575 * Restore the table to it's original state in the DOM by removing all of DataTables 5576 * enhancements, alterations to the DOM structure of the table and event listeners. 5577 * @param {boolean} [remove=false] Completely remove the table from the DOM 5578 * @dtopt API 5579 * @deprecated Since v1.10 5580 * 5581 * @example 5582 * $(document).ready(function() { 5583 * // This example is fairly pointless in reality, but shows how fnDestroy can be used 5584 * var oTable = $('#example').dataTable(); 5585 * oTable.fnDestroy(); 5586 * } ); 5587 */ 5588 this.fnDestroy = function ( remove ) 5589 { 5590 this.api( true ).destroy( remove ); 5591 }; 5592
5593 5594 /** 5595 * Redraw the table 5596 * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw. 5597 * @dtopt API 5598 * @deprecated Since v1.10 5599 * 5600 * @example 5601 * $(document).ready(function() { 5602 * var oTable = $('#example').dataTable(); 5603 * 5604 * // Re-draw the table - you wouldn't want to do it here, but it's an example :-) 5605 * oTable.fnDraw(); 5606 * } ); 5607 */ 5608 this.fnDraw = function( complete ) 5609 { 5610 // Note that this isn't an exact match to the old call to _fnDraw - it takes 5611 // into account the new data, but can old position. 5612 this.api( true ).draw( ! complete ); 5613 }; 5614 5615 5616 /** 5617 * Filter the input based on data 5618 * @param {string} sInput String to filter the table on 5619 * @param {int|null} [iColumn] Column to limit filtering to 5620 * @param {bool} [bRegex=false] Treat as regular expression or not 5621 * @param {bool} [bSmart=true] Perform smart filtering or not 5622 * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es) 5623 * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false) 5624 * @dtopt API 5625 * @deprecated Since v1.10 5626 * 5627 * @example 5628 * $(document).ready(function() { 5629 * var oTable = $('#example').dataTable(); 5630 * 5631 * // Sometime later - filter... 5632 * oTable.fnFilter( 'test string' ); 5633 * } ); 5634 */ 5635 this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive ) 5636 { 5637 var api = this.api( true ); 5638 5639 if ( iColumn === null || iColumn === undefined ) { 5640 api.search( sInput, bRegex, bSmart, bCaseInsensitive ); 5641 } 5642 else { 5643 api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive ); 5644 } 5645 5646 api.draw(); 5647 }; 5648 5649 5650 /** 5651 * Get the data for the whole table, an individual row or an individual cell based on the 5652 * provided parameters. 5653 * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as 5654 * a TR node then the data source for the whole row will be returned. If given as a 5655 * TD/TH cell node then iCol will be automatically calculated and the data for the 5656 * cell returned. If given as an integer, then this is treated as the aoData internal 5657 * data index for the row (see fnGetPosition) and the data for that row used. 5658 * @param {int} [col] Optional column index that you want the data of. 5659 * @returns {array|object|string} If mRow is undefined, then the data for all rows is 5660 * returned. If mRow is defined, just data for that row, and is iCol is 5661 * defined, only data for the designated cell is returned. 5662 * @dtopt API 5663 * @deprecated Since v1.10 5664 * 5665 * @example 5666 * // Row data 5667 * $(document).ready(function() { 5668 * oTable = $('#example').dataTable(); 5669 * 5670 * oTable.$('tr').click( function () { 5671 * var data = oTable.fnGetData( this ); 5672 * // ... do something with the array / object of data for the row 5673 * } ); 5674 * } ); 5675 * 5676 * @example 5677 * // Individual cell data 5678 * $(document).ready(function() { 5679 * oTable = $('#example').dataTable(); 5680 * 5681 * oTable.$('td').click( function () { 5682 * var sData = oTable.fnGetData( this ); 5683 * alert( 'The cell clicked on had the value of '+sData ); 5684 * } ); 5685 * } ); 5686 */ 5687 this.fnGetData = function( src, col ) 5688 { 5689 var api = this.api( true ); 5690 5691 if ( src !== undefined ) { 5692 var type = src.nodeName ? src.nodeName.toLowerCase() : ''; 5693 5694 return col !== undefined || type == 'td' || type == 'th' ? 5695 api.cell( src, col ).data() : 5696 api.row( src ).data() || null; 5697 } 5698 5699 return api.data().toArray(); 5700 }; 5701 5702 5703 /** 5704 * Get an array of the TR nodes that are used in the table's body. Note that you will 5705 * typically want to use the '$' API method in preference to this as it is more 5706 * flexible. 5707 * @param {int} [iRow] Optional row index for the TR element you want 5708 * @returns {array|node} If iRow is undefined, returns an array of all TR elements 5709 * in the table's body, or iRow is defined, just the TR element requested. 5710 * @dtopt API 5711 * @deprecated Since v1.10 5712 * 5713 * @example 5714 * $(document).ready(function() { 5715 * var oTable = $('#example').dataTable(); 5716 * 5717 * // Get the nodes from the table 5718 * var nNodes = oTable.fnGetNodes( ); 5719 * } ); 5720 */ 5721 this.fnGetNodes = function( iRow ) 5722 { 5723 var api = this.api( true ); 5724 5725 return iRow !== undefined ? 5726 api.row( iRow ).node() : 5727 api.rows().nodes().flatten().toArray(); 5728 }; 5729
5730 5731 /** 5732 * Get the array indexes of a particular cell from it's DOM element 5733 * and column index including hidden columns 5734 * @param {node} node this can either be a TR, TD or TH in the table's body 5735 * @returns {int} If nNode is given as a TR, then a single index is returned, or 5736 * if given as a cell, an array of [row index, column index (visible), 5737 * column index (all)] is given. 5738 * @dtopt API 5739 * @deprecated Since v1.10 5740 * 5741 * @example 5742 * $(document).ready(function() { 5743 * $('#example tbody td').click( function () { 5744 * // Get the position of the current data from the node 5745 * var aPos = oTable.fnGetPosition( this ); 5746 * 5747 * // Get the data array for this row 5748 * var aData = oTable.fnGetData( aPos[0] ); 5749 * 5750 * // Update the data array and return the value 5751 * aData[ aPos[1] ] = 'clicked'; 5752 * this.innerHTML = 'clicked'; 5753 * } ); 5754 * 5755 * // Init DataTables 5756 * oTable = $('#example').dataTable(); 5757 * } ); 5758 */ 5759 this.fnGetPosition = function( node ) 5760 { 5761 var api = this.api( true ); 5762 var nodeName = node.nodeName.toUpperCase(); 5763 5764 if ( nodeName == 'TR' ) { 5765 return api.row( node ).index(); 5766 } 5767 else if ( nodeName == 'TD' || nodeName == 'TH' ) { 5768 var cell = api.cell( node ).index(); 5769 5770 return [ 5771 cell.row, 5772 cell.columnVisible, 5773 cell.column 5774 ]; 5775 } 5776 return null; 5777 }; 5778 5779 5780 /** 5781 * Check to see if a row is 'open' or not. 5782 * @param {node} nTr the table row to check 5783 * @returns {boolean} true if the row is currently open, false otherwise 5784 * @dtopt API 5785 * @deprecated Since v1.10 5786 * 5787 * @example 5788 * $(document).ready(function() { 5789 * var oTable; 5790 * 5791 * // 'open' an information row when a row is clicked on 5792 * $('#example tbody tr').click( function () { 5793 * if ( oTable.fnIsOpen(this) ) { 5794 * oTable.fnClose( this ); 5795 * } else { 5796 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 5797 * } 5798 * } ); 5799 * 5800 * oTable = $('#example').dataTable(); 5801 * } ); 5802 */ 5803 this.fnIsOpen = function( nTr ) 5804 { 5805 return this.api( true ).row( nTr ).child.isShown(); 5806 }; 5807 5808 5809 /** 5810 * This function will place a new row directly after a row which is currently 5811 * on display on the page, with the HTML contents that is passed into the 5812 * function. This can be used, for example, to ask for confirmation that a 5813 * particular record should be deleted. 5814 * @param {node} nTr The table row to 'open' 5815 * @param {string|node|jQuery} mHtml The HTML to put into the row 5816 * @param {string} sClass Class to give the new TD cell 5817 * @returns {node} The row opened. Note that if the table row passed in as the 5818 * first parameter, is not found in the table, this method will silently 5819 * return. 5820 * @dtopt API 5821 * @deprecated Since v1.10 5822 * 5823 * @example 5824 * $(document).ready(function() { 5825 * var oTable; 5826 * 5827 * // 'open' an information row when a row is clicked on 5828 * $('#example tbody tr').click( function () { 5829 * if ( oTable.fnIsOpen(this) ) { 5830 * oTable.fnClose( this ); 5831 * } else { 5832 * oTable.fnOpen( this, "Temporary row opened", "info_row" ); 5833 * } 5834 * } ); 5835 * 5836 * oTable = $('#example').dataTable(); 5837 * } ); 5838 */ 5839 this.fnOpen = function( nTr, mHtml, sClass ) 5840 { 5841 return this.api( true ) 5842 .row( nTr ) 5843 .child( mHtml, sClass ) 5844 .show() 5845 .child()[0]; 5846 }; 5847 5848 5849 /** 5850 * Change the pagination - provides the internal logic for pagination in a simple API 5851 * function. With this function you can have a DataTables table go to the next, 5852 * previous, first or last pages. 5853 * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last" 5854 * or page number to jump to (integer), note that page 0 is the first page. 5855 * @param {bool} [bRedraw=true] Redraw the table or not 5856 * @dtopt API 5857 * @deprecated Since v1.10 5858 * 5859 * @example 5860 * $(document).ready(function() { 5861 * var oTable = $('#example').dataTable(); 5862 * oTable.fnPageChange( 'next' ); 5863 * } ); 5864 */ 5865 this.fnPageChange = function ( mAction, bRedraw ) 5866 { 5867 var api = this.api( true ).page( mAction ); 5868 5869 if ( bRedraw === undefined || bRedraw ) { 5870 api.draw(false); 5871 } 5872 }; 5873 5874 5875 /** 5876 * Show a particular column 5877 * @param {int} iCol The column whose display should be changed 5878 * @param {bool} bShow Show (true) or hide (false) the column 5879 * @param {bool} [bRedraw=true] Redraw the table or not 5880 * @dtopt API 5881 * @deprecated Since v1.10 5882 * 5883 * @example 5884 * $(document).ready(function() { 5885 * var oTable = $('#example').dataTable(); 5886 * 5887 * // Hide the second column after initialisation 5888 * oTable.fnSetColumnVis( 1, false ); 5889 * } ); 5890 */ 5891 this.fnSetColumnVis = function ( iCol, bShow, bRedraw ) 5892 { 5893 var api = this.api( true ).column( iCol ).visible( bShow ); 5894 5895 if ( bRedraw === undefined || bRedraw ) { 5896 api.columns.adjust().draw(); 5897 } 5898 }; 5899 5900 5901 /** 5902 * Get the settings for a particular table for external manipulation 5903 * @returns {object} DataTables settings object. See 5904 * {@link DataTable.models.oSettings} 5905 * @dtopt API 5906 * @deprecated Since v1.10 5907 * 5908 * @example 5909 * $(document).ready(function() { 5910 * var oTable = $('#example').dataTable(); 5911 * var oSettings = oTable.fnSettings(); 5912 * 5913 * // Show an example parameter from the settings 5914 * alert( oSettings._iDisplayStart ); 5915 * } ); 5916 */ 5917 this.fnSettings = function() 5918 {
5919 return _fnSettingsFromNode( this[_ext.iApiIndex] ); 5920 }; 5921 5922 5923 /** 5924 * Sort the table by a particular column 5925 * @param {int} iCol the data index to sort on. Note that this will not match the 5926 * 'display index' if you have hidden data entries 5927 * @dtopt API 5928 * @deprecated Since v1.10 5929 * 5930 * @example 5931 * $(document).ready(function() { 5932 * var oTable = $('#example').dataTable(); 5933 * 5934 * // Sort immediately with columns 0 and 1 5935 * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] ); 5936 * } ); 5937 */ 5938 this.fnSort = function( aaSort ) 5939 { 5940 this.api( true ).order( aaSort ).draw(); 5941 }; 5942 5943 5944 /** 5945 * Attach a sort listener to an element for a given column 5946 * @param {node} nNode the element to attach the sort listener to 5947 * @param {int} iColumn the column that a click on this node will sort on 5948 * @param {function} [fnCallback] callback function when sort is run 5949 * @dtopt API 5950 * @deprecated Since v1.10 5951 * 5952 * @example 5953 * $(document).ready(function() { 5954 * var oTable = $('#example').dataTable(); 5955 * 5956 * // Sort on column 1, when 'sorter' is clicked on 5957 * oTable.fnSortListener( document.getElementById('sorter'), 1 ); 5958 * } ); 5959 */ 5960 this.fnSortListener = function( nNode, iColumn, fnCallback ) 5961 { 5962 this.api( true ).order.listener( nNode, iColumn, fnCallback ); 5963 }; 5964 5965 5966 /** 5967 * Update a table cell or row - this method will accept either a single value to 5968 * update the cell with, an array of values with one element for each column or 5969 * an object in the same format as the original data source. The function is 5970 * self-referencing in order to make the multi column updates easier. 5971 * @param {object|array|string} mData Data to update the cell/row with 5972 * @param {node|int} mRow TR element you want to update or the aoData index 5973 * @param {int} [iColumn] The column to update, give as null or undefined to 5974 * update a whole row. 5975 * @param {bool} [bRedraw=true] Redraw the table or not 5976 * @param {bool} [bAction=true] Perform pre-draw actions or not 5977 * @returns {int} 0 on success, 1 on error 5978 * @dtopt API 5979 * @deprecated Since v1.10 5980 * 5981 * @example 5982 * $(document).ready(function() { 5983 * var oTable = $('#example').dataTable(); 5984 * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell 5985 * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row 5986 * } ); 5987 */ 5988 this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction ) 5989 { 5990 var api = this.api( true ); 5991 5992 if ( iColumn === undefined || iColumn === null ) { 5993 api.row( mRow ).data( mData ); 5994 } 5995 else { 5996 api.cell( mRow, iColumn ).data( mData ); 5997 } 5998 5999 if ( bAction === undefined || bAction ) { 6000 api.columns.adjust(); 6001 } 6002 6003 if ( bRedraw === undefined || bRedraw ) { 6004 api.draw(); 6005 } 6006 return 0; 6007 }; 6008 6009 6010 /** 6011 * Provide a common method for plug-ins to check the version of DataTables being used, in order 6012 * to ensure compatibility. 6013 * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the 6014 * formats "X" and "X.Y" are also acceptable. 6015 * @returns {boolean} true if this version of DataTables is greater or equal to the required 6016 * version, or false if this version of DataTales is not suitable 6017 * @method 6018 * @dtopt API 6019 * @deprecated Since v1.10 6020 * 6021 * @example 6022 * $(document).ready(function() { 6023 * var oTable = $('#example').dataTable(); 6024 * alert( oTable.fnVersionCheck( '1.9.0' ) ); 6025 * } ); 6026 */ 6027 this.fnVersionCheck = _ext.fnVersionCheck; 6028 6029 6030 var _that = this; 6031 var emptyInit = options === undefined; 6032 var len = this.length; 6033 6034 if ( emptyInit ) { 6035 options = {}; 6036 } 6037 6038 this.oApi = this.internal = _ext.internal; 6039 6040 // Extend with old style plug-in API methods 6041 for ( var fn in DataTable.ext.internal ) { 6042 if ( fn ) { 6043 this[fn] = _fnExternApiFunc(fn); 6044 } 6045 } 6046 6047 this.each(function() { 6048 // For each initialisation we want to give it a clean initialisation 6049 // object that can be bashed around 6050 var o = {}; 6051 var oInit = len > 1 ? // optimisation for single table case 6052 _fnExtend( o, options, true ) : 6053 options; 6054 6055 /*global oInit,_that,emptyInit*/ 6056 var i=0, iLen, j, jLen, k, kLen; 6057 var sId = this.getAttribute( 'id' ); 6058 var bInitHandedOff = false;
6059 var defaults = DataTable.defaults; 6060 var $this = $(this); 6061 6062 6063 /* Sanity check */ 6064 if ( this.nodeName.toLowerCase() != 'table' ) 6065 { 6066 _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 ); 6067 return; 6068 } 6069 6070 /* Backwards compatibility for the defaults */ 6071 _fnCompatOpts( defaults ); 6072 _fnCompatCols( defaults.column ); 6073 6074 /* Convert the camel-case defaults to Hungarian */ 6075 _fnCamelToHungarian( defaults, defaults, true ); 6076 _fnCamelToHungarian( defaults.column, defaults.column, true ); 6077 6078 /* Setting up the initialisation object */ 6079 _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ) ); 6080 6081 6082 6083 /* Check to see if we are re-initialising a table */ 6084 var allSettings = DataTable.settings; 6085 for ( i=0, iLen=allSettings.length ; i<iLen ; i++ ) 6086 { 6087 var s = allSettings[i]; 6088 6089 /* Base check on table node */ 6090 if ( s.nTable == this || s.nTHead.parentNode == this || (s.nTFoot && s.nTFoot.parentNode == this) ) 6091 { 6092 var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve; 6093 var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy; 6094 6095 if ( emptyInit || bRetrieve ) 6096 { 6097 return s.oInstance; 6098 } 6099 else if ( bDestroy ) 6100 { 6101 s.oInstance.fnDestroy(); 6102 break; 6103 } 6104 else 6105 { 6106 _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 ); 6107 return; 6108 } 6109 } 6110 6111 /* If the element we are initialising has the same ID as a table which was previously 6112 * initialised, but the table nodes don't match (from before) then we destroy the old 6113 * instance by simply deleting it. This is under the assumption that the table has been 6114 * destroyed by other methods. Anyone using non-id selectors will need to do this manually 6115 */ 6116 if ( s.sTableId == this.id ) 6117 { 6118 allSettings.splice( i, 1 ); 6119 break; 6120 } 6121 } 6122 6123 /* Ensure the table has an ID - required for accessibility */ 6124 if ( sId === null || sId === "" ) 6125 { 6126 sId = "DataTables_Table_"+(DataTable.ext._unique++); 6127 this.id = sId; 6128 } 6129 6130 /* Create the settings object for this table and set some of the default parameters */ 6131 var oSettings = $.extend( true, {}, DataTable.models.oSettings, { 6132 "nTable": this, 6133 "oApi": _that.internal, 6134 "oInit": oInit, 6135 "sDestroyWidth": $this[0].style.width, 6136 "sInstance": sId, 6137 "sTableId": sId 6138 } ); 6139 allSettings.push( oSettings ); 6140 6141 // Need to add the instance after the instance after the settings object has been added 6142 // to the settings array, so we can self reference the table instance if more than one 6143 oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable(); 6144 6145 // Backwards compatibility, before we apply all the defaults 6146 _fnCompatOpts( oInit ); 6147 6148 if ( oInit.oLanguage ) 6149 { 6150 _fnLanguageCompat( oInit.oLanguage ); 6151 } 6152 6153 // If the length menu is given, but the init display length is not, use the length menu 6154 if ( oInit.aLengthMenu && ! oInit.iDisplayLength ) 6155 { 6156 oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ? 6157 oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0]; 6158 } 6159 6160 // Apply the defaults and init options to make a single init object will all 6161 // options defined from defaults and instance options. 6162 oInit = _fnExtend( $.extend( true, {}, defaults ), oInit ); 6163 6164 6165 // Map the initialisation options onto the settings object 6166 _fnMap( oSettings.oFeatures, oInit, [ 6167 "bPaginate", 6168 "bLengthChange", 6169 "bFilter", 6170 "bSort", 6171 "bSortMulti", 6172 "bInfo", 6173 "bProcessing", 6174 "bAutoWidth", 6175 "bSortClasses", 6176 "bServerSide", 6177 "bDeferRender" 6178 ] ); 6179 _fnMap( oSettings, oInit, [ 6180 "asStripeClasses", 6181 "ajax", 6182 "fnServerData", 6183 "fnFormatNumber", 6184 "sServerMethod", 6185 "aaSorting", 6186 "aaSortingFixed", 6187 "aLengthMenu", 6188 "sPaginationType", 6189 "sAjaxSource", 6190 "sAjaxDataProp", 6191 "iStateDuration", 6192 "sDom", 6193 "bSortCellsTop", 6194 "iTabIndex", 6195 "fnStateLoadCallback", 6196 "fnStateSaveCallback", 6197 "renderer", 6198 "searchDelay", 6199 [ "iCookieDuration", "iStateDuration" ], // backwards compat 6200 [ "oSearch", "oPreviousSearch" ], 6201 [ "aoSearchCols", "aoPreSearchCols" ], 6202 [ "iDisplayLength", "_iDisplayLength" ], 6203 [ "bJQueryUI", "bJUI" ] 6204 ] ); 6205 _fnMap( oSettings.oScroll, oInit, [ 6206 [ "sScrollX", "sX" ], 6207 [ "sScrollXInner", "sXInner" ], 6208 [ "sScrollY", "sY" ],
6209 [ "bScrollCollapse", "bCollapse" ] 6210 ] ); 6211 _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" ); 6212 6213 /* Callback functions which are array driven */ 6214 _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' ); 6215 _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' ); 6216 _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' ); 6217 _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' ); 6218 _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' ); 6219 _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' ); 6220 _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' ); 6221 _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' ); 6222 _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' ); 6223 _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' ); 6224 _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' ); 6225 6226 var oClasses = oSettings.oClasses; 6227 6228 // @todo Remove in 1.11 6229 if ( oInit.bJQueryUI ) 6230 { 6231 /* Use the JUI classes object for display. You could clone the oStdClasses object if 6232 * you want to have multiple tables with multiple independent classes 6233 */ 6234 $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses ); 6235 6236 if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" ) 6237 { 6238 /* Set the DOM to use a layout suitable for jQuery UI's theming */ 6239 oSettings.sDom = '<"H"lfr>t<"F"ip>'; 6240 } 6241 6242 if ( ! oSettings.renderer ) { 6243 oSettings.renderer = 'jqueryui'; 6244 } 6245 else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) { 6246 oSettings.renderer.header = 'jqueryui'; 6247 } 6248 } 6249 else 6250 { 6251 $.extend( oClasses, DataTable.ext.classes, oInit.oClasses ); 6252 } 6253 $this.addClass( oClasses.sTable ); 6254 6255 /* Calculate the scroll bar width and cache it for use later on */ 6256 if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" ) 6257 { 6258 oSettings.oScroll.iBarWidth = _fnScrollBarWidth(); 6259 } 6260 if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling 6261 oSettings.oScroll.sX = '100%'; 6262 } 6263 6264 if ( oSettings.iInitDisplayStart === undefined ) 6265 { 6266 /* Display start point, taking into account the save saving */ 6267 oSettings.iInitDisplayStart = oInit.iDisplayStart; 6268 oSettings._iDisplayStart = oInit.iDisplayStart; 6269 } 6270 6271 if ( oInit.iDeferLoading !== null ) 6272 { 6273 oSettings.bDeferLoading = true; 6274 var tmp = $.isArray( oInit.iDeferLoading ); 6275 oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading; 6276 oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading; 6277 } 6278 6279 /* Language definitions */ 6280 var oLanguage = oSettings.oLanguage; 6281 $.extend( true, oLanguage, oInit.oLanguage ); 6282 6283 if ( oLanguage.sUrl !== "" ) 6284 { 6285 /* Get the language definitions from a file - because this Ajax call makes the language 6286 * get async to the remainder of this function we use bInitHandedOff to indicate that 6287 * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor 6288 */ 6289 $.ajax( { 6290 dataType: 'json', 6291 url: oLanguage.sUrl, 6292 success: function ( json ) { 6293 _fnLanguageCompat( json ); 6294 _fnCamelToHungarian( defaults.oLanguage, json ); 6295 $.extend( true, oLanguage, json ); 6296 _fnInitialise( oSettings ); 6297 }, 6298 error: function () { 6299 // Error occurred loading language file, continue on as best we can 6300 _fnInitialise( oSettings ); 6301 } 6302 } ); 6303 bInitHandedOff = true; 6304 } 6305 6306 /* 6307 * Stripes 6308 */ 6309 if ( oInit.asStripeClasses === null ) 6310 { 6311 oSettings.asStripeClasses =[ 6312 oClasses.sStripeOdd, 6313 oClasses.sStripeEven 6314 ]; 6315 } 6316 6317 /* Remove row stripe classes if they are already on the table row */ 6318 var stripeClasses = oSettings.asStripeClasses; 6319 var rowOne = $('tbody tr', this).eq(0); 6320 if ( $.inArray( true, $.map( stripeClasses, function(el, i) { 6321 return rowOne.hasClass(el); 6322 } ) ) !== -1 ) { 6323 $('tbody tr', this).removeClass( stripeClasses.join(' ') ); 6324 oSettings.asDestroyStripes = stripeClasses.slice(); 6325 } 6326 6327 /* 6328 * Columns 6329 * See if we should load columns automatically or use defined ones 6330 */ 6331 var anThs = []; 6332 var aoColumnsInit; 6333 var nThead = this.getElementsByTagName('thead'); 6334 if ( nThead.length !== 0 ) 6335 { 6336 _fnDetectHeader( oSettings.aoHeader, nThead[0] ); 6337 anThs = _fnGetUniqueThs( oSettings ); 6338 } 6339 6340 /* If not given a column array, generate one with nulls */ 6341 if ( oInit.aoColumns === null ) 6342 { 6343 aoColumnsInit = []; 6344 for ( i=0, iLen=anThs.length ; i<iLen ; i++ ) 6345 { 6346 aoColumnsInit.push( null ); 6347 } 6348 } 6349 else 6350 {
6351 aoColumnsInit = oInit.aoColumns; 6352 } 6353 6354 /* Add the columns */ 6355 for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ ) 6356 { 6357 _fnAddColumn( oSettings, anThs ? anThs[i] : null ); 6358 } 6359 6360 /* Apply the column definitions */ 6361 _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) { 6362 _fnColumnOptions( oSettings, iCol, oDef ); 6363 } ); 6364 6365 /* HTML5 attribute detection - build an mData object automatically if the 6366 * attributes are found 6367 */ 6368 if ( rowOne.length ) { 6369 var a = function ( cell, name ) { 6370 return cell.getAttribute( 'data-'+name ) !== null ? name : null; 6371 }; 6372 6373 $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) { 6374 var col = oSettings.aoColumns[i]; 6375 6376 if ( col.mData === i ) { 6377 var sort = a( cell, 'sort' ) || a( cell, 'order' ); 6378 var filter = a( cell, 'filter' ) || a( cell, 'search' ); 6379 6380 if ( sort !== null || filter !== null ) { 6381 col.mData = { 6382 _: i+'.display', 6383 sort: sort !== null ? i+'.@data-'+sort : undefined, 6384 type: sort !== null ? i+'.@data-'+sort : undefined, 6385 filter: filter !== null ? i+'.@data-'+filter : undefined 6386 }; 6387 6388 _fnColumnOptions( oSettings, i ); 6389 } 6390 } 6391 } ); 6392 } 6393 6394 var features = oSettings.oFeatures; 6395 6396 /* Must be done after everything which can be overridden by the state saving! */ 6397 if ( oInit.bStateSave ) 6398 { 6399 features.bStateSave = true; 6400 _fnLoadState( oSettings, oInit ); 6401 _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' ); 6402 } 6403 6404 6405 /* 6406 * Sorting 6407 * @todo For modularisation (1.11) this needs to do into a sort start up handler 6408 */ 6409 6410 // If aaSorting is not defined, then we use the first indicator in asSorting 6411 // in case that has been altered, so the default sort reflects that option 6412 if ( oInit.aaSorting === undefined ) 6413 { 6414 var sorting = oSettings.aaSorting; 6415 for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) 6416 { 6417 sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0]; 6418 } 6419 } 6420 6421 /* Do a first pass on the sorting classes (allows any size changes to be taken into 6422 * account, and also will apply sorting disabled classes if disabled 6423 */ 6424 _fnSortingClasses( oSettings ); 6425 6426 if ( features.bSort ) 6427 { 6428 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 6429 if ( oSettings.bSorted ) { 6430 var aSort = _fnSortFlatten( oSettings ); 6431 var sortedColumns = {}; 6432 6433 $.each( aSort, function (i, val) { 6434 sortedColumns[ val.src ] = val.dir; 6435 } ); 6436 6437 _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] ); 6438 _fnSortAria( oSettings ); 6439 } 6440 } ); 6441 } 6442 6443 _fnCallbackReg( oSettings, 'aoDrawCallback', function () { 6444 if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) { 6445 _fnSortingClasses( oSettings ); 6446 } 6447 }, 'sc' ); 6448 6449 6450 /* 6451 * Final init 6452 * Cache the header, body and footer as required, creating them if needed 6453 */ 6454 6455 /* Browser support detection */ 6456 _fnBrowserDetect( oSettings ); 6457 6458 // Work around for Webkit bug 83867 - store the caption-side before removing from doc 6459 var captions = $this.children('caption').each( function () { 6460 this._captionSide = $this.css('caption-side'); 6461 } ); 6462 6463 var thead = $this.children('thead'); 6464 if ( thead.length === 0 ) 6465 { 6466 thead = $('<thead/>').appendTo(this); 6467 } 6468 oSettings.nTHead = thead[0]; 6469 6470 var tbody = $this.children('tbody'); 6471 if ( tbody.length === 0 ) 6472 { 6473 tbody = $('<tbody/>').appendTo(this); 6474 } 6475 oSettings.nTBody = tbody[0]; 6476 6477 var tfoot = $this.children('tfoot'); 6478 if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) 6479 { 6480 // If we are a scrolling table, and no footer has been given, then we need to create 6481 // a tfoot element for the caption element to be appended to 6482 tfoot = $('<tfoot/>').appendTo(this); 6483 } 6484 6485 if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6486 $this.addClass( oClasses.sNoFooter ); 6487 } 6488 else if ( tfoot.length > 0 ) { 6489 oSettings.nTFoot = tfoot[0]; 6490 _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot ); 6491 } 6492 6493 /* Check if there is data passing into the constructor */ 6494 if ( oInit.aaData ) 6495 { 6496 for ( i=0 ; i<oInit.aaData.length ; i++ ) 6497 { 6498 _fnAddData( oSettings, oInit.aaData[ i ] ); 6499 } 6500 } 6501 else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) 6502 { 6503 /* Grab the data from the page - only do this when deferred loading or no Ajax 6504 * source since there is no point in reading the DOM data if we are then going 6505 * to replace it with Ajax data 6506 */ 6507 _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') ); 6508 } 6509 6510 /* Copy the data index array */ 6511 oSettings.aiDisplay = oSettings.aiDisplayMaster.slice(); 6512 6513 /* Initialisation complete - table can be drawn */ 6514 oSettings.bInitialised = true; 6515 6516 /* Check if we need to initialise the table (it might not have been handed off to the 6517 * language processor) 6518 */ 6519 if ( bInitHandedOff === false ) 6520 { 6521 _fnInitialise( oSettings ); 6522 } 6523 } ); 6524 _that = null; 6525 return this; 6526 }; 6527 6528 6529 6530 /** 6531 * Computed structure of the DataTables API, defined by the options passed to 6532 * `DataTable.Api.register()` when building the API. 6533 * 6534 * The structure is built in order to speed creation and extension of the Api 6535 * objects since the extensions are effectively pre-parsed. 6536 * 6537 * The array is an array of objects with the following structure, where this 6538 * base array represents the Api prototype base: 6539 * 6540 * [ 6541 * { 6542 * name: 'data' -- string - Property name 6543 * val: function () {}, -- function - Api method (or undefined if just an object 6544 * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 6545 * propExt: [ ... ] -- array - Array of Api object definitions to extend the property 6546 * }, 6547 * { 6548 * name: 'row' 6549 * val: {}, 6550 * methodExt: [ ... ], 6551 * propExt: [ 6552 * { 6553 * name: 'data' 6554 * val: function () {}, 6555 * methodExt: [ ... ], 6556 * propExt: [ ... ] 6557 * }, 6558 * ... 6559 * ] 6560 * } 6561 * ] 6562 * 6563 * @type {Array} 6564 * @ignore 6565 */ 6566 var __apiStruct = []; 6567 6568 6569 /** 6570 * `Array.prototype` reference. 6571 * 6572 * @type object 6573 * @ignore 6574 */ 6575 var __arrayProto = Array.prototype; 6576 6577 6578 /** 6579 * Abstraction for `context` parameter of the `Api` constructor to allow it to 6580 * take several different forms for ease of use. 6581 * 6582 * Each of the input parameter types will be converted to a DataTables settings 6583 * object where possible. 6584 * 6585 * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one 6586 * of: 6587 * 6588 * * `string` - jQuery selector. Any DataTables' matching the given selector 6589 * with be found and used. 6590 * * `node` - `TABLE` node which has already been formed into a DataTable. 6591 * * `jQuery` - A jQuery object of `TABLE` nodes. 6592 * * `object` - DataTables settings object 6593 * * `DataTables.Api` - API instance 6594 * @return {array|null} Matching DataTables settings objects. `null` or 6595 * `undefined` is returned if no matching DataTable is found. 6596 * @ignore 6597 */ 6598 var _toSettings = function ( mixed ) 6599 { 6600 var idx, jq; 6601 var settings = DataTable.settings; 6602 var tables = $.map( settings, function (el, i) { 6603 return el.nTable; 6604 } ); 6605 6606 if ( ! mixed ) { 6607 return []; 6608 } 6609 else if ( mixed.nTable && mixed.oApi ) { 6610 // DataTables settings object 6611 return [ mixed ]; 6612 } 6613 else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) { 6614 // Table node 6615 idx = $.inArray( mixed, tables ); 6616 return idx !== -1 ? [ settings[idx] ] : null; 6617 } 6618 else if ( mixed && typeof mixed.settings === 'function' ) { 6619 return mixed.settings().toArray(); 6620 } 6621 else if ( typeof mixed === 'string' ) { 6622 // jQuery selector 6623 jq = $(mixed); 6624 } 6625 else if ( mixed instanceof $ ) { 6626 // jQuery object (also DataTables instance) 6627 jq = mixed; 6628 } 6629 6630 if ( jq ) { 6631 return jq.map( function(i) { 6632 idx = $.inArray( this, tables ); 6633 return idx !== -1 ? settings[idx] : null; 6634 } ).toArray(); 6635 } 6636 }; 6637 6638 6639 /** 6640 * DataTables API class - used to control and interface with one or more 6641 * DataTables enhanced tables. 6642 * 6643 * The API class is heavily based on jQuery, presenting a chainable interface 6644 * that you can use to interact with tables. Each instance of the API class has 6645 * a "context" - i.e. the tables that it will operate on. This could be a single 6646 * table, all tables on a page or a sub-set thereof. 6647 * 6648 * Additionally the API is designed to allow you to easily work with the data in 6649 * the tables, retrieving and manipulating it as required. This is done by 6650 * presenting the API class as an array like interface. The contents of the 6651 * array depend upon the actions requested by each method (for example 6652 * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6653 * return an array of objects or arrays depending upon your table's 6654 * configuration). The API object has a number of array like methods (`push`, 6655 * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`, 6656 * `unique` etc) to assist your working with the data held in a table. 6657 * 6658 * Most methods (those which return an Api instance) are chainable, which means 6659 * the return from a method call also has all of the methods available that the 6660 * top level object had. For example, these two calls are equivalent: 6661 * 6662 * // Not chained 6663 * api.row.add( {...} ); 6664 * api.draw(); 6665 * 6666 * // Chained 6667 * api.row.add( {...} ).draw(); 6668 * 6669 * @class DataTable.Api 6670 * @param {array|object|string|jQuery} context DataTable identifier. This is 6671 * used to define which DataTables enhanced tables this API will operate on. 6672 * Can be one of: 6673 * 6674 * * `string` - jQuery selector. Any DataTables' matching the given selector 6675 * with be found and used. 6676 * * `node` - `TABLE` node which has already been formed into a DataTable. 6677 * * `jQuery` - A jQuery object of `TABLE` nodes. 6678 * * `object` - DataTables settings object 6679 * @param {array} [data] Data to initialise the Api instance with. 6680 * 6681 * @example 6682 * // Direct initialisation during DataTables construction 6683 * var api = $('#example').DataTable(); 6684 * 6685 * @example 6686 * // Initialisation using a DataTables jQuery object 6687 * var api = $('#example').dataTable().api(); 6688 * 6689 * @example 6690 * // Initialisation as a constructor 6691 * var api = new $.fn.DataTable.Api( 'table.dataTable' ); 6692 */ 6693 _Api = function ( context, data ) 6694 { 6695 if ( ! this instanceof _Api ) { 6696 throw 'DT API must be constructed as a new object'; 6697 // or should it do the 'new' for the caller? 6698 // return new _Api.apply( this, arguments ); 6699 } 6700 6701 var settings = []; 6702 var ctxSettings = function ( o ) { 6703 var a = _toSettings( o ); 6704 if ( a ) { 6705 settings.push.apply( settings, a ); 6706 } 6707 }; 6708 6709 if ( $.isArray( context ) ) { 6710 for ( var i=0, ien=context.length ; i<ien ; i++ ) { 6711 ctxSettings( context[i] ); 6712 } 6713 } 6714 else { 6715 ctxSettings( context ); 6716 } 6717 6718 // Remove duplicates 6719 this.context = _unique( settings ); 6720 6721 // Initial data 6722 if ( data ) { 6723 this.push.apply( this, data.toArray ? data.toArray() : data ); 6724 } 6725 6726 // selector 6727 this.selector = { 6728 rows: null, 6729 cols: null, 6730 opts: null 6731 }; 6732 6733 _Api.extend( this, this, __apiStruct ); 6734 }; 6735 6736 DataTable.Api = _Api; 6737 6738 _Api.prototype = /** @lends DataTables.Api */{ 6739 /** 6740 * Return a new Api instance, comprised of the data held in the current 6741 * instance, join with the other array(s) and/or value(s). 6742 * 6743 * An alias for `Array.prototype.concat`. 6744 * 6745 * @type method 6746 * @param {*} value1 Arrays and/or values to concatenate. 6747 * @param {*} [...] Additional arrays and/or values to concatenate. 6748 * @returns {DataTables.Api} New API instance, comprising of the combined 6749 * array. 6750 */ 6751 concat: __arrayProto.concat, 6752 6753 6754 context: [], // array of table settings objects 6755 6756 6757 each: function ( fn ) 6758 { 6759 for ( var i=0, ien=this.length ; i<ien; i++ ) { 6760 fn.call( this, this[i], i, this ); 6761 } 6762 6763 return this; 6764 }, 6765 6766 6767 eq: function ( idx ) 6768 { 6769 var ctx = this.context; 6770 6771 return ctx.length > idx ? 6772 new _Api( ctx[idx], this[idx] ) : 6773 null; 6774 }, 6775 6776 6777 filter: function ( fn ) 6778 { 6779 var a = []; 6780 6781 if ( __arrayProto.filter ) { 6782 a = __arrayProto.filter.call( this, fn, this ); 6783 } 6784 else { 6785 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 6786 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 6787 if ( fn.call( this, this[i], i, this ) ) { 6788 a.push( this[i] ); 6789 } 6790 } 6791 } 6792 6793 return new _Api( this.context, a ); 6794 }, 6795 6796 6797 flatten: function () 6798 { 6799 var a = []; 6800 return new _Api( this.context, a.concat.apply( a, this.toArray() ) ); 6801 }, 6802 6803 6804 join: __arrayProto.join, 6805 6806 6807 indexOf: __arrayProto.indexOf || function (obj, start) 6808 { 6809 for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) { 6810 if ( this[i] === obj ) { 6811 return i; 6812 } 6813 } 6814 return -1; 6815 }, 6816 6817 // Note that `alwaysNew` is internal - use iteratorNew externally 6818 iterator: function ( flatten, type, fn, alwaysNew ) { 6819 var 6820 a = [], ret, 6821 i, ien, j, jen, 6822 context = this.context, 6823 rows, items, item, 6824 selector = this.selector; 6825 6826 // Argument shifting 6827 if ( typeof flatten === 'string' ) { 6828 alwaysNew = fn; 6829 fn = type; 6830 type = flatten; 6831 flatten = false;
6832 } 6833 6834 for ( i=0, ien=context.length ; i<ien ; i++ ) { 6835 var apiInst = new _Api( context[i] ); 6836 6837 if ( type === 'table' ) { 6838 ret = fn.call( apiInst, context[i], i ); 6839 6840 if ( ret !== undefined ) { 6841 a.push( ret ); 6842 } 6843 } 6844 else if ( type === 'columns' || type === 'rows' ) { 6845 // this has same length as context - one entry for each table 6846 ret = fn.call( apiInst, context[i], this[i], i ); 6847 6848 if ( ret !== undefined ) { 6849 a.push( ret ); 6850 } 6851 } 6852 else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) { 6853 // columns and rows share the same structure. 6854 // 'this' is an array of column indexes for each context 6855 items = this[i]; 6856 6857 if ( type === 'column-rows' ) { 6858 rows = _selector_row_indexes( context[i], selector.opts ); 6859 } 6860 6861 for ( j=0, jen=items.length ; j<jen ; j++ ) { 6862 item = items[j]; 6863 6864 if ( type === 'cell' ) { 6865 ret = fn.call( apiInst, context[i], item.row, item.column, i, j ); 6866 } 6867 else { 6868 ret = fn.call( apiInst, context[i], item, i, j, rows ); 6869 } 6870 6871 if ( ret !== undefined ) { 6872 a.push( ret ); 6873 } 6874 } 6875 } 6876 } 6877 6878 if ( a.length || alwaysNew ) { 6879 var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a ); 6880 var apiSelector = api.selector; 6881 apiSelector.rows = selector.rows; 6882 apiSelector.cols = selector.cols; 6883 apiSelector.opts = selector.opts; 6884 return api; 6885 } 6886 return this; 6887 }, 6888 6889 6890 lastIndexOf: __arrayProto.lastIndexOf || function (obj, start) 6891 { 6892 // Bit cheeky... 6893 return this.indexOf.apply( this.toArray.reverse(), arguments ); 6894 }, 6895 6896 6897 length: 0, 6898 6899 6900 map: function ( fn ) 6901 { 6902 var a = []; 6903 6904 if ( __arrayProto.map ) { 6905 a = __arrayProto.map.call( this, fn, this ); 6906 } 6907 else { 6908 // Compatibility for browsers without EMCA-252-5 (JS 1.6) 6909 for ( var i=0, ien=this.length ; i<ien ; i++ ) { 6910 a.push( fn.call( this, this[i], i ) ); 6911 } 6912 } 6913 6914 return new _Api( this.context, a ); 6915 }, 6916 6917 6918 pluck: function ( prop ) 6919 { 6920 return this.map( function ( el ) { 6921 return el[ prop ]; 6922 } ); 6923 }, 6924 6925 pop: __arrayProto.pop, 6926 6927 6928 push: __arrayProto.push, 6929 6930 6931 // Does not return an API instance 6932 reduce: __arrayProto.reduce || function ( fn, init ) 6933 { 6934 return _fnReduce( this, fn, init, 0, this.length, 1 ); 6935 }, 6936 6937 6938 reduceRight: __arrayProto.reduceRight || function ( fn, init ) 6939 { 6940 return _fnReduce( this, fn, init, this.length-1, -1, -1 ); 6941 }, 6942 6943 6944 reverse: __arrayProto.reverse, 6945 6946 6947 // Object with rows, columns and opts 6948 selector: null, 6949 6950 6951 shift: __arrayProto.shift, 6952 6953 6954 sort: __arrayProto.sort, // ? name - order? 6955 6956 6957 splice: __arrayProto.splice, 6958 6959 6960 toArray: function () 6961 { 6962 return __arrayProto.slice.call( this ); 6963 }, 6964 6965 6966 to$: function () 6967 { 6968 return $( this ); 6969 }, 6970 6971 6972 toJQuery: function () 6973 { 6974 return $( this ); 6975 }, 6976 6977 6978 unique: function () 6979 { 6980 return new _Api( this.context, _unique(this) ); 6981 }, 6982 6983 6984 unshift: __arrayProto.unshift 6985 }; 6986 6987 6988 _Api.extend = function ( scope, obj, ext ) 6989 { 6990 // Only extend API instances and static properties of the API 6991 if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) { 6992 return; 6993 } 6994 6995 var 6996 i, ien, 6997 j, jen, 6998 struct, inner, 6999 methodScoping = function ( scope, fn, struc ) { 7000 return function () { 7001 var ret = fn.apply( scope, arguments ); 7002 7003 // Method extension 7004 _Api.extend( ret, ret, struc.methodExt ); 7005 return ret; 7006 }; 7007 }; 7008 7009 for ( i=0, ien=ext.length ; i<ien ; i++ ) { 7010 struct = ext[i]; 7011 7012 // Value 7013 obj[ struct.name ] = typeof struct.val === 'function' ? 7014 methodScoping( scope, struct.val, struct ) : 7015 $.isPlainObject( struct.val ) ? 7016 {} : 7017 struct.val; 7018 7019 obj[ struct.name ].__dt_wrapper = true; 7020 7021 // Property extension 7022 _Api.extend( scope, obj[ struct.name ], struct.propExt ); 7023 } 7024 }; 7025 7026 7027 // @todo - Is there need for an augment function? 7028 // _Api.augment = function ( inst, name ) 7029 // { 7030 // // Find src object in the structure from the name 7031 // var parts = name.split('.'); 7032 7033 // _Api.extend( inst, obj ); 7034 // }; 7035 7036 7037 // [ 7038 // { 7039 // name: 'data' -- string - Property name 7040 // val: function () {}, -- function - Api method (or undefined if just an object 7041 // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result 7042 // propExt: [ ... ] -- array - Array of Api object definitions to extend the property 7043 // }, 7044 // { 7045 // name: 'row' 7046 // val: {}, 7047 // methodExt: [ ... ], 7048 // propExt: [ 7049 // { 7050 // name: 'data' 7051 // val: function () {}, 7052 // methodExt: [ ... ], 7053 // propExt: [ ... ] 7054 // }, 7055 // ... 7056 // ] 7057 // } 7058 // ] 7059 7060 _Api.register = _api_register = function ( name, val ) 7061 { 7062 if ( $.isArray( name ) ) { 7063 for ( var j=0, jen=name.length ; j<jen ; j++ ) { 7064 _Api.register( name[j], val ); 7065 } 7066 return; 7067 } 7068 7069 var 7070 i, ien, 7071 heir = name.split('.'), 7072 struct = __apiStruct, 7073 key, method; 7074 7075 var find = function ( src, name ) { 7076 for ( var i=0, ien=src.length ; i<ien ; i++ ) { 7077 if ( src[i].name === name ) { 7078 return src[i]; 7079 } 7080 } 7081 return null; 7082 }; 7083 7084 for ( i=0, ien=heir.length ; i<ien ; i++ ) { 7085 method = heir[i].indexOf('()') !== -1; 7086 key = method ?
7087 heir[i].replace('()', '') : 7088 heir[i]; 7089 7090 var src = find( struct, key ); 7091 if ( ! src ) { 7092 src = { 7093 name: key, 7094 val: {}, 7095 methodExt: [], 7096 propExt: [] 7097 }; 7098 struct.push( src ); 7099 } 7100 7101 if ( i === ien-1 ) { 7102 src.val = val; 7103 } 7104 else { 7105 struct = method ? 7106 src.methodExt : 7107 src.propExt; 7108 } 7109 } 7110 }; 7111 7112 7113 _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) { 7114 _Api.register( pluralName, val ); 7115 7116 _Api.register( singularName, function () { 7117 var ret = val.apply( this, arguments ); 7118 7119 if ( ret === this ) { 7120 // Returned item is the API instance that was passed in, return it 7121 return this; 7122 } 7123 else if ( ret instanceof _Api ) { 7124 // New API instance returned, want the value from the first item 7125 // in the returned array for the singular result. 7126 return ret.length ? 7127 $.isArray( ret[0] ) ? 7128 new _Api( ret.context, ret[0] ) : // Array results are 'enhanced' 7129 ret[0] : 7130 undefined; 7131 } 7132 7133 // Non-API return - just fire it back 7134 return ret; 7135 } ); 7136 }; 7137 7138 7139 /** 7140 * Selector for HTML tables. Apply the given selector to the give array of 7141 * DataTables settings objects. 7142 * 7143 * @param {string|integer} [selector] jQuery selector string or integer 7144 * @param {array} Array of DataTables settings objects to be filtered 7145 * @return {array} 7146 * @ignore 7147 */ 7148 var __table_selector = function ( selector, a ) 7149 { 7150 // Integer is used to pick out a table by index 7151 if ( typeof selector === 'number' ) { 7152 return [ a[ selector ] ]; 7153 } 7154 7155 // Perform a jQuery selector on the table nodes 7156 var nodes = $.map( a, function (el, i) { 7157 return el.nTable; 7158 } ); 7159 7160 return $(nodes) 7161 .filter( selector ) 7162 .map( function (i) { 7163 // Need to translate back from the table node to the settings 7164 var idx = $.inArray( this, nodes ); 7165 return a[ idx ]; 7166 } ) 7167 .toArray(); 7168 }; 7169 7170 7171 7172 /** 7173 * Context selector for the API's context (i.e. the tables the API instance 7174 * refers to. 7175 * 7176 * @name DataTable.Api#tables 7177 * @param {string|integer} [selector] Selector to pick which tables the iterator 7178 * should operate on. If not given, all tables in the current context are 7179 * used. This can be given as a jQuery selector (for example `':gt(0)'`) to 7180 * select multiple tables or as an integer to select a single table. 7181 * @returns {DataTable.Api} Returns a new API instance if a selector is given. 7182 */ 7183 _api_register( 'tables()', function ( selector ) { 7184 // A new instance is created if there was a selector specified 7185 return selector ? 7186 new _Api( __table_selector( selector, this.context ) ) : 7187 this; 7188 } ); 7189 7190 7191 _api_register( 'table()', function ( selector ) { 7192 var tables = this.tables( selector ); 7193 var ctx = tables.context; 7194 7195 // Truncate to the first matched table 7196 return ctx.length ? 7197 new _Api( ctx[0] ) : 7198 tables; 7199 } ); 7200 7201 7202 _api_registerPlural( 'tables().nodes()', 'table().node()' , function () { 7203 return this.iterator( 'table', function ( ctx ) { 7204 return ctx.nTable; 7205 }, 1 ); 7206 } ); 7207 7208 7209 _api_registerPlural( 'tables().body()', 'table().body()' , function () { 7210 return this.iterator( 'table', function ( ctx ) { 7211 return ctx.nTBody; 7212 }, 1 ); 7213 } ); 7214 7215 7216 _api_registerPlural( 'tables().header()', 'table().header()' , function () { 7217 return this.iterator( 'table', function ( ctx ) { 7218 return ctx.nTHead; 7219 }, 1 ); 7220 } ); 7221 7222 7223 _api_registerPlural( 'tables().footer()', 'table().footer()' , function () { 7224 return this.iterator( 'table', function ( ctx ) { 7225 return ctx.nTFoot; 7226 }, 1 ); 7227 } ); 7228 7229 7230 _api_registerPlural( 'tables().containers()', 'table().container()' , function () { 7231 return this.iterator( 'table', function ( ctx ) { 7232 return ctx.nTableWrapper; 7233 }, 1 ); 7234 } ); 7235 7236 7237 7238 /** 7239 * Redraw the tables in the current context. 7240 * 7241 * @param {boolean} [reset=true] Reset (default) or hold the current paging 7242 * position. A full re-sort and re-filter is performed when this method is 7243 * called, which is why the pagination reset is the default action. 7244 * @returns {DataTables.Api} this 7245 */ 7246 _api_register( 'draw()', function ( resetPaging ) { 7247 return this.iterator( 'table', function ( settings ) { 7248 _fnReDraw( settings, resetPaging===false ); 7249 } ); 7250 } ); 7251 7252 7253 7254 /** 7255 * Get the current page index. 7256 * 7257 * @return {integer} Current page index (zero based) 7258 *//** 7259 * Set the current page. 7260 * 7261 * Note that if you attempt to show a page which does not exist, DataTables will 7262 * not throw an error, but rather reset the paging. 7263 * 7264 * @param {integer|string} action The paging action to take. This can be one of:
7265 * * `integer` - The page index to jump to 7266 * * `string` - An action to take: 7267 * * `first` - Jump to first page. 7268 * * `next` - Jump to the next page 7269 * * `previous` - Jump to previous page 7270 * * `last` - Jump to the last page. 7271 * @returns {DataTables.Api} this 7272 */ 7273 _api_register( 'page()', function ( action ) { 7274 if ( action === undefined ) { 7275 return this.page.info().page; // not an expensive call 7276 } 7277 7278 // else, have an action to take on all tables 7279 return this.iterator( 'table', function ( settings ) { 7280 _fnPageChange( settings, action ); 7281 } ); 7282 } ); 7283 7284 7285 /** 7286 * Paging information for the first table in the current context. 7287 * 7288 * If you require paging information for another table, use the `table()` method 7289 * with a suitable selector. 7290 * 7291 * @return {object} Object with the following properties set: 7292 * * `page` - Current page index (zero based - i.e. the first page is `0`) 7293 * * `pages` - Total number of pages 7294 * * `start` - Display index for the first record shown on the current page 7295 * * `end` - Display index for the last record shown on the current page 7296 * * `length` - Display length (number of records). Note that generally `start 7297 * + length = end`, but this is not always true, for example if there are 7298 * only 2 records to show on the final page, with a length of 10. 7299 * * `recordsTotal` - Full data set length 7300 * * `recordsDisplay` - Data set length once the current filtering criterion 7301 * are applied. 7302 */ 7303 _api_register( 'page.info()', function ( action ) { 7304 if ( this.context.length === 0 ) { 7305 return undefined; 7306 } 7307 7308 var 7309 settings = this.context[0], 7310 start = settings._iDisplayStart, 7311 len = settings._iDisplayLength, 7312 visRecords = settings.fnRecordsDisplay(), 7313 all = len === -1; 7314 7315 return { 7316 "page": all ? 0 : Math.floor( start / len ), 7317 "pages": all ? 1 : Math.ceil( visRecords / len ), 7318 "start": start, 7319 "end": settings.fnDisplayEnd(), 7320 "length": len, 7321 "recordsTotal": settings.fnRecordsTotal(), 7322 "recordsDisplay": visRecords 7323 }; 7324 } ); 7325 7326 7327 /** 7328 * Get the current page length. 7329 * 7330 * @return {integer} Current page length. Note `-1` indicates that all records 7331 * are to be shown. 7332 *//** 7333 * Set the current page length. 7334 * 7335 * @param {integer} Page length to set. Use `-1` to show all records. 7336 * @returns {DataTables.Api} this 7337 */ 7338 _api_register( 'page.len()', function ( len ) { 7339 // Note that we can't call this function 'length()' because `length` 7340 // is a Javascript property of functions which defines how many arguments 7341 // the function expects. 7342 if ( len === undefined ) { 7343 return this.context.length !== 0 ? 7344 this.context[0]._iDisplayLength : 7345 undefined; 7346 } 7347 7348 // else, set the page length 7349 return this.iterator( 'table', function ( settings ) { 7350 _fnLengthChange( settings, len ); 7351 } ); 7352 } ); 7353 7354 7355 7356 var __reload = function ( settings, holdPosition, callback ) { 7357 if ( _fnDataSource( settings ) == 'ssp' ) { 7358 _fnReDraw( settings, holdPosition ); 7359 } 7360 else { 7361 // Trigger xhr 7362 _fnProcessingDisplay( settings, true ); 7363 7364 _fnBuildAjax( settings, [], function( json ) { 7365 _fnClearTable( settings ); 7366 7367 var data = _fnAjaxDataSrc( settings, json ); 7368 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7369 _fnAddData( settings, data[i] ); 7370 } 7371 7372 _fnReDraw( settings, holdPosition ); 7373 _fnProcessingDisplay( settings, false ); 7374 } ); 7375 } 7376 7377 // Use the draw event to trigger a callback, regardless of if it is an async 7378 // or sync draw 7379 if ( callback ) { 7380 var api = new _Api( settings ); 7381 7382 api.one( 'draw', function () { 7383 callback( api.ajax.json() ); 7384 } ); 7385 } 7386 }; 7387 7388 7389 /** 7390 * Get the JSON response from the last Ajax request that DataTables made to the 7391 * server. Note that this returns the JSON from the first table in the current 7392 * context. 7393 * 7394 * @return {object} JSON received from the server. 7395 */ 7396 _api_register( 'ajax.json()', function () { 7397 var ctx = this.context; 7398 7399 if ( ctx.length > 0 ) { 7400 return ctx[0].json; 7401 } 7402 7403 // else return undefined; 7404 } ); 7405 7406 7407 /** 7408 * Get the data submitted in the last Ajax request 7409 */ 7410 _api_register( 'ajax.params()', function () { 7411 var ctx = this.context; 7412 7413 if ( ctx.length > 0 ) { 7414 return ctx[0].oAjaxData; 7415 } 7416 7417 // else return undefined; 7418 } ); 7419 7420 7421 /** 7422 * Reload tables from the Ajax data source. Note that this function will 7423 * automatically re-draw the table when the remote data has been loaded. 7424 * 7425 * @param {boolean} [reset=true] Reset (default) or hold the current paging 7426 * position. A full re-sort and re-filter is performed when this method is 7427 * called, which is why the pagination reset is the default action. 7428 * @returns {DataTables.Api} this 7429 */ 7430 _api_register( 'ajax.reload()', function ( callback, resetPaging ) { 7431 return this.iterator( 'table', function (settings) { 7432 __reload( settings, resetPaging===false, callback ); 7433 } ); 7434 } ); 7435 7436 7437 /** 7438 * Get the current Ajax URL. Note that this returns the URL from the first 7439 * table in the current context. 7440 * 7441 * @return {string} Current Ajax source URL 7442 *//** 7443 * Set the Ajax URL. Note that this will set the URL for all tables in the 7444 * current context. 7445 * 7446 * @param {string} url URL to set. 7447 * @returns {DataTables.Api} this 7448 */ 7449 _api_register( 'ajax.url()', function ( url ) { 7450 var ctx = this.context; 7451 7452 if ( url === undefined ) { 7453 // get 7454 if ( ctx.length === 0 ) { 7455 return undefined; 7456 } 7457 ctx = ctx[0]; 7458
7459 return ctx.ajax ? 7460 $.isPlainObject( ctx.ajax ) ? 7461 ctx.ajax.url : 7462 ctx.ajax : 7463 ctx.sAjaxSource; 7464 } 7465 7466 // set 7467 return this.iterator( 'table', function ( settings ) { 7468 if ( $.isPlainObject( settings.ajax ) ) { 7469 settings.ajax.url = url; 7470 } 7471 else { 7472 settings.ajax = url; 7473 } 7474 // No need to consider sAjaxSource here since DataTables gives priority 7475 // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any 7476 // value of `sAjaxSource` redundant. 7477 } ); 7478 } ); 7479 7480 7481 /** 7482 * Load data from the newly set Ajax URL. Note that this method is only 7483 * available when `ajax.url()` is used to set a URL. Additionally, this method 7484 * has the same effect as calling `ajax.reload()` but is provided for 7485 * convenience when setting a new URL. Like `ajax.reload()` it will 7486 * automatically redraw the table once the remote data has been loaded. 7487 * 7488 * @returns {DataTables.Api} this 7489 */ 7490 _api_register( 'ajax.url().load()', function ( callback, resetPaging ) { 7491 // Same as a reload, but makes sense to present it for easy access after a 7492 // url change 7493 return this.iterator( 'table', function ( ctx ) { 7494 __reload( ctx, resetPaging===false, callback ); 7495 } ); 7496 } ); 7497 7498 7499 7500 7501 var _selector_run = function ( selector, select ) 7502 { 7503 var 7504 out = [], res, 7505 a, i, ien, j, jen, 7506 selectorType = typeof selector; 7507 7508 // Can't just check for isArray here, as an API or jQuery instance might be 7509 // given with their array like look 7510 if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) { 7511 selector = [ selector ]; 7512 } 7513 7514 for ( i=0, ien=selector.length ; i<ien ; i++ ) { 7515 a = selector[i] && selector[i].split ? 7516 selector[i].split(',') : 7517 [ selector[i] ]; 7518 7519 for ( j=0, jen=a.length ; j<jen ; j++ ) { 7520 res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] ); 7521 7522 if ( res && res.length ) { 7523 out.push.apply( out, res ); 7524 } 7525 } 7526 } 7527 7528 return out; 7529 }; 7530 7531 7532 var _selector_opts = function ( opts ) 7533 { 7534 if ( ! opts ) { 7535 opts = {}; 7536 } 7537 7538 // Backwards compatibility for 1.9- which used the terminology filter rather 7539 // than search 7540 if ( opts.filter && ! opts.search ) { 7541 opts.search = opts.filter; 7542 } 7543 7544 return { 7545 search: opts.search || 'none', 7546 order: opts.order || 'current', 7547 page: opts.page || 'all' 7548 }; 7549 }; 7550 7551 7552 var _selector_first = function ( inst ) 7553 { 7554 // Reduce the API instance to the first item found 7555 for ( var i=0, ien=inst.length ; i<ien ; i++ ) { 7556 if ( inst[i].length > 0 ) { 7557 // Assign the first element to the first item in the instance 7558 // and truncate the instance and context 7559 inst[0] = inst[i]; 7560 inst.length = 1; 7561 inst.context = [ inst.context[i] ]; 7562 7563 return inst; 7564 } 7565 } 7566 7567 // Not found - return an empty instance 7568 inst.length = 0; 7569 return inst; 7570 }; 7571 7572 7573 var _selector_row_indexes = function ( settings, opts ) 7574 { 7575 var 7576 i, ien, tmp, a=[], 7577 displayFiltered = settings.aiDisplay, 7578 displayMaster = settings.aiDisplayMaster; 7579 7580 var 7581 search = opts.search, // none, applied, removed 7582 order = opts.order, // applied, current, index (original - compatibility with 1.9) 7583 page = opts.page; // all, current 7584 7585 if ( _fnDataSource( settings ) == 'ssp' ) { 7586 // In server-side processing mode, most options are irrelevant since 7587 // rows not shown don't exist and the index order is the applied order 7588 // Removed is a special case - for consistency just return an empty 7589 // array 7590 return search === 'removed' ? 7591 [] : 7592 _range( 0, displayMaster.length ); 7593 } 7594 else if ( page == 'current' ) { 7595 // Current page implies that order=current and fitler=applied, since it is 7596 // fairly senseless otherwise, regardless of what order and search actually 7597 // are 7598 for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) { 7599 a.push( displayFiltered[i] ); 7600 } 7601 } 7602 else if ( order == 'current' || order == 'applied' ) { 7603 a = search == 'none' ? 7604 displayMaster.slice() : // no search 7605 search == 'applied' ? 7606 displayFiltered.slice() : // applied search 7607 $.map( displayMaster, function (el, i) { // removed search 7608 return $.inArray( el, displayFiltered ) === -1 ? el : null; 7609 } ); 7610 } 7611 else if ( order == 'index' || order == 'original' ) { 7612 for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) { 7613 if ( search == 'none' ) { 7614 a.push( i ); 7615 } 7616 else { // applied | removed 7617 tmp = $.inArray( i, displayFiltered ); 7618 7619 if ((tmp === -1 && search == 'removed') || 7620 (tmp >= 0 && search == 'applied') ) 7621 { 7622 a.push( i ); 7623 } 7624 } 7625 } 7626 } 7627 7628 return a; 7629 }; 7630 7631 7632 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 7633 * Rows 7634 * 7635 * {} - no selector - use all available rows 7636 * {integer} - row aoData index 7637 * {node} - TR node 7638 * {string} - jQuery selector to apply to the TR elements 7639 * {array} - jQuery array of nodes, or simply an array of TR nodes 7640 * 7641 */ 7642 7643 7644 var __row_selector = function ( settings, selector, opts ) 7645 { 7646 return _selector_run( selector, function ( sel ) { 7647 var selInt = _intVal( sel ); 7648 var i, ien; 7649 7650 // Short cut - selector is a number and no options provided (default is 7651 // all records, so no need to check if the index is in there, since it 7652 // must be - dev error if the index doesn't exist). 7653 if ( selInt !== null && ! opts ) { 7654 return [ selInt ]; 7655 } 7656 7657 var rows = _selector_row_indexes( settings, opts ); 7658 7659 if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) { 7660 // Selector - integer 7661 return [ selInt ]; 7662 } 7663 else if ( ! sel ) { 7664 // Selector - none 7665 return rows; 7666 } 7667 7668 // Selector - function 7669 if ( typeof sel === 'function' ) { 7670 return $.map( rows, function (idx) { 7671 var row = settings.aoData[ idx ]; 7672 return sel( idx, row._aData, row.nTr ) ? idx : null; 7673 } ); 7674 } 7675
7676 // Get nodes in the order from the `rows` array with null values removed 7677 var nodes = _removeEmpty( 7678 _pluck_order( settings.aoData, rows, 'nTr' ) 7679 ); 7680 7681 // Selector - node 7682 if ( sel.nodeName ) { 7683 if ( $.inArray( sel, nodes ) !== -1 ) { 7684 return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table 7685 // and DataTables adds a prop for fast lookup 7686 } 7687 } 7688 7689 // Selector - jQuery selector string, array of nodes or jQuery object/ 7690 // As jQuery's .filter() allows jQuery objects to be passed in filter, 7691 // it also allows arrays, so this will cope with all three options 7692 return $(nodes) 7693 .filter( sel ) 7694 .map( function () { 7695 return this._DT_RowIndex; 7696 } ) 7697 .toArray(); 7698 } ); 7699 }; 7700 7701 7702 /** 7703 * 7704 */ 7705 _api_register( 'rows()', function ( selector, opts ) { 7706 // argument shifting 7707 if ( selector === undefined ) { 7708 selector = ''; 7709 } 7710 else if ( $.isPlainObject( selector ) ) { 7711 opts = selector; 7712 selector = ''; 7713 } 7714 7715 opts = _selector_opts( opts ); 7716 7717 var inst = this.iterator( 'table', function ( settings ) { 7718 return __row_selector( settings, selector, opts ); 7719 }, 1 ); 7720 7721 // Want argument shifting here and in __row_selector? 7722 inst.selector.rows = selector; 7723 inst.selector.opts = opts; 7724 7725 return inst; 7726 } ); 7727 7728 7729 _api_register( 'rows().nodes()', function () { 7730 return this.iterator( 'row', function ( settings, row ) { 7731 return settings.aoData[ row ].nTr || undefined; 7732 }, 1 ); 7733 } ); 7734 7735 _api_register( 'rows().data()', function () { 7736 return this.iterator( true, 'rows', function ( settings, rows ) { 7737 return _pluck_order( settings.aoData, rows, '_aData' ); 7738 }, 1 ); 7739 } ); 7740 7741 _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) { 7742 return this.iterator( 'row', function ( settings, row ) { 7743 var r = settings.aoData[ row ]; 7744 return type === 'search' ? r._aFilterData : r._aSortData; 7745 }, 1 ); 7746 } ); 7747 7748 _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) { 7749 return this.iterator( 'row', function ( settings, row ) { 7750 _fnInvalidate( settings, row, src ); 7751 } ); 7752 } ); 7753 7754 _api_registerPlural( 'rows().indexes()', 'row().index()', function () { 7755 return this.iterator( 'row', function ( settings, row ) { 7756 return row; 7757 }, 1 ); 7758 } ); 7759 7760 _api_registerPlural( 'rows().remove()', 'row().remove()', function () { 7761 var that = this; 7762 7763 return this.iterator( 'row', function ( settings, row, thatIdx ) { 7764 var data = settings.aoData; 7765 7766 data.splice( row, 1 ); 7767 7768 // Update the _DT_RowIndex parameter on all rows in the table 7769 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7770 if ( data[i].nTr !== null ) { 7771 data[i].nTr._DT_RowIndex = i; 7772 } 7773 } 7774 7775 // Remove the target row from the search array 7776 var displayIndex = $.inArray( row, settings.aiDisplay ); 7777 7778 // Delete from the display arrays 7779 _fnDeleteIndex( settings.aiDisplayMaster, row ); 7780 _fnDeleteIndex( settings.aiDisplay, row ); 7781 _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes 7782 7783 // Check for an 'overflow' they case for displaying the table 7784 _fnLengthOverflow( settings ); 7785 } ); 7786 } ); 7787 7788 7789 _api_register( 'rows.add()', function ( rows ) { 7790 var newRows = this.iterator( 'table', function ( settings ) { 7791 var row, i, ien; 7792 var out = []; 7793 7794 for ( i=0, ien=rows.length ; i<ien ; i++ ) { 7795 row = rows[i]; 7796 7797 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 7798 out.push( _fnAddTr( settings, row )[0] ); 7799 } 7800 else { 7801 out.push( _fnAddData( settings, row ) ); 7802 } 7803 } 7804 7805 return out; 7806 }, 1 ); 7807 7808 // Return an Api.rows() extended instance, so rows().nodes() etc can be used 7809 var modRows = this.rows( -1 ); 7810 modRows.pop(); 7811 modRows.push.apply( modRows, newRows.toArray() ); 7812 7813 return modRows; 7814 } ); 7815 7816 7817 7818 7819 7820 /** 7821 * 7822 */ 7823 _api_register( 'row()', function ( selector, opts ) { 7824 return _selector_first( this.rows( selector, opts ) ); 7825 } ); 7826 7827 7828 _api_register( 'row().data()', function ( data ) { 7829 var ctx = this.context; 7830 7831 if ( data === undefined ) { 7832 // Get 7833 return ctx.length && this.length ? 7834 ctx[0].aoData[ this[0] ]._aData : 7835 undefined; 7836 } 7837 7838 // Set 7839 ctx[0].aoData[ this[0] ]._aData = data; 7840 7841 // Automatically invalidate 7842 _fnInvalidate( ctx[0], this[0], 'data' ); 7843 7844 return this; 7845 } ); 7846 7847 7848 _api_register( 'row().node()', function () { 7849 var ctx = this.context; 7850 7851 return ctx.length && this.length ? 7852 ctx[0].aoData[ this[0] ].nTr || null : 7853 null; 7854 } ); 7855 7856 7857 _api_register( 'row.add()', function ( row ) { 7858 // Allow a jQuery object to be passed in - only a single row is added from 7859 // it though - the first element in the set 7860 if ( row instanceof $ && row.length ) { 7861 row = row[0]; 7862 } 7863 7864 var rows = this.iterator( 'table', function ( settings ) { 7865 if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) { 7866 return _fnAddTr( settings, row )[0]; 7867 } 7868 return _fnAddData( settings, row ); 7869 } ); 7870 7871 // Return an Api.rows() extended instance, with the newly added row selected 7872 return this.row( rows[0] ); 7873 } ); 7874 7875 7876 7877 var __details_add = function ( ctx, row, data, klass ) 7878 { 7879 // Convert to array of TR elements 7880 var rows = []; 7881 var addRow = function ( r, k ) { 7882 // If we get a TR element, then just add it directly - up to the dev 7883 // to add the correct number of columns etc 7884 if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) { 7885 rows.push( r ); 7886 } 7887 else { 7888 // Otherwise create a row with a wrapper 7889 var created = $('<tr><td/></tr>').addClass( k ); 7890 $('td', created) 7891 .addClass( k ) 7892 .html( r ) 7893 [0].colSpan = _fnVisbleColumns( ctx ); 7894 7895 rows.push( created[0] ); 7896 } 7897 }; 7898 7899 if ( $.isArray( data ) || data instanceof $ ) { 7900 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7901 addRow( data[i], klass ); 7902 } 7903 } 7904 else { 7905 addRow( data, klass ); 7906 } 7907 7908 if ( row._details ) { 7909 row._details.remove(); 7910 } 7911 7912 row._details = $(rows); 7913 7914 // If the children were already shown, that state should be retained 7915 if ( row._detailsShow ) { 7916 row._details.insertAfter( row.nTr ); 7917 } 7918 }; 7919 7920 7921 var __details_remove = function ( api, idx ) 7922 { 7923 var ctx = api.context; 7924 7925 if ( ctx.length ) { 7926 var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ]; 7927 7928 if ( row._details ) { 7929 row._details.remove(); 7930 7931 row._detailsShow = undefined; 7932 row._details = undefined; 7933 } 7934 } 7935 }; 7936 7937
7938 var __details_display = function ( api, show ) { 7939 var ctx = api.context; 7940 7941 if ( ctx.length && api.length ) { 7942 var row = ctx[0].aoData[ api[0] ]; 7943 7944 if ( row._details ) { 7945 row._detailsShow = show; 7946 7947 if ( show ) { 7948 row._details.insertAfter( row.nTr ); 7949 } 7950 else { 7951 row._details.detach(); 7952 } 7953 7954 __details_events( ctx[0] ); 7955 } 7956 } 7957 }; 7958 7959 7960 var __details_events = function ( settings ) 7961 { 7962 var api = new _Api( settings ); 7963 var namespace = '.dt.DT_details'; 7964 var drawEvent = 'draw'+namespace; 7965 var colvisEvent = 'column-visibility'+namespace; 7966 var destroyEvent = 'destroy'+namespace; 7967 var data = settings.aoData; 7968 7969 api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent ); 7970 7971 if ( _pluck( data, '_details' ).length > 0 ) { 7972 // On each draw, insert the required elements into the document 7973 api.on( drawEvent, function ( e, ctx ) { 7974 if ( settings !== ctx ) { 7975 return; 7976 } 7977 7978 api.rows( {page:'current'} ).eq(0).each( function (idx) { 7979 // Internal data grab 7980 var row = data[ idx ]; 7981 7982 if ( row._detailsShow ) { 7983 row._details.insertAfter( row.nTr ); 7984 } 7985 } ); 7986 } ); 7987 7988 // Column visibility change - update the colspan 7989 api.on( colvisEvent, function ( e, ctx, idx, vis ) { 7990 if ( settings !== ctx ) { 7991 return; 7992 } 7993 7994 // Update the colspan for the details rows (note, only if it already has 7995 // a colspan) 7996 var row, visible = _fnVisbleColumns( ctx ); 7997 7998 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 7999 row = data[i]; 8000 8001 if ( row._details ) { 8002 row._details.children('td[colspan]').attr('colspan', visible ); 8003 } 8004 } 8005 } ); 8006 8007 // Table destroyed - nuke any child rows 8008 api.on( destroyEvent, function ( e, ctx ) { 8009 if ( settings !== ctx ) { 8010 return; 8011 } 8012 8013 for ( var i=0, ien=data.length ; i<ien ; i++ ) { 8014 if ( data[i]._details ) { 8015 __details_remove( api, i ); 8016 } 8017 } 8018 } ); 8019 } 8020 }; 8021 8022 // Strings for the method names to help minification 8023 var _emp = ''; 8024 var _child_obj = _emp+'row().child'; 8025 var _child_mth = _child_obj+'()'; 8026 8027 // data can be: 8028 // tr 8029 // string 8030 // jQuery or array of any of the above 8031 _api_register( _child_mth, function ( data, klass ) { 8032 var ctx = this.context; 8033 8034 if ( data === undefined ) { 8035 // get 8036 return ctx.length && this.length ? 8037 ctx[0].aoData[ this[0] ]._details : 8038 undefined; 8039 } 8040 else if ( data === true ) { 8041 // show 8042 this.child.show(); 8043 } 8044 else if ( data === false ) { 8045 // remove 8046 __details_remove( this ); 8047 } 8048 else if ( ctx.length && this.length ) { 8049 // set 8050 __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass ); 8051 } 8052 8053 return this; 8054 } ); 8055 8056 8057 _api_register( [ 8058 _child_obj+'.show()', 8059 _child_mth+'.show()' // only when `child()` was called with parameters (without 8060 ], function ( show ) { // it returns an object and this method is not executed) 8061 __details_display( this, true ); 8062 return this; 8063 } ); 8064 8065 8066 _api_register( [ 8067 _child_obj+'.hide()', 8068 _child_mth+'.hide()' // only when `child()` was called with parameters (without 8069 ], function () { // it returns an object and this method is not executed) 8070 __details_display( this, false ); 8071 return this; 8072 } ); 8073 8074 8075 _api_register( [ 8076 _child_obj+'.remove()', 8077 _child_mth+'.remove()' // only when `child()` was called with parameters (without 8078 ], function () { // it returns an object and this method is not executed) 8079 __details_remove( this ); 8080 return this; 8081 } ); 8082 8083 8084 _api_register( _child_obj+'.isShown()', function () { 8085 var ctx = this.context; 8086 8087 if ( ctx.length && this.length ) { 8088 // _detailsShown as false or undefined will fall through to return false 8089 return ctx[0].aoData[ this[0] ]._detailsShow || false; 8090 } 8091 return false; 8092 } ); 8093 8094 8095 8096 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * 8097 * Columns 8098 * 8099 * {integer} - column index (>=0 count from left, <0 count from right) 8100 * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right) 8101 * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right) 8102 * "{string}:name" - column name 8103 * "{string}" - jQuery selector on column header nodes 8104 * 8105 */ 8106 8107 // can be an array of these items, comma separated list, or an array of comma 8108 // separated lists 8109 8110 var __re_column_selector = /^(.+):(name|visIdx|visible)$/; 8111 8112 8113 // r1 and r2 are redundant - but it means that the parameters match for the 8114 // iterator callback in columns().data() 8115 var __columnData = function ( settings, column, r1, r2, rows ) { 8116 var a = []; 8117 for ( var row=0, ien=rows.length ; row<ien ; row++ ) { 8118 a.push( _fnGetCellData( settings, rows[row], column ) ); 8119 } 8120 return a; 8121 }; 8122 8123 8124 var __column_selector = function ( settings, selector, opts ) 8125 { 8126 var 8127 columns = settings.aoColumns, 8128 names = _pluck( columns, 'sName' ), 8129 nodes = _pluck( columns, 'nTh' ); 8130 8131 return _selector_run( selector, function ( s ) { 8132 var selInt = _intVal( s ); 8133 8134 // Selector - all 8135 if ( s === '' ) { 8136 return _range( columns.length ); 8137 } 8138 8139 // Selector - index 8140 if ( selInt !== null ) { 8141 return [ selInt >= 0 ? 8142 selInt : // Count from left 8143 columns.length + selInt // Count from right (+ because its a negative value) 8144 ]; 8145 } 8146 8147 // Selector = function 8148 if ( typeof s === 'function' ) { 8149 var rows = _selector_row_indexes( settings, opts ); 8150 8151 return $.map( columns, function (col, idx) { 8152 return s( 8153 idx, 8154 __columnData( settings, idx, 0, 0, rows ), 8155 nodes[ idx ] 8156 ) ? idx : null; 8157 } ); 8158 } 8159 8160 // jQuery or string selector 8161 var match = typeof s === 'string' ? 8162 s.match( __re_column_selector ) : 8163 ''; 8164 8165 if ( match ) { 8166 switch( match[2] ) { 8167 case 'visIdx': 8168 case 'visible': 8169 var idx = parseInt( match[1], 10 ); 8170 // Visible index given, convert to column index 8171 if ( idx < 0 ) { 8172 // Counting from the right 8173 var visColumns = $.map( columns, function (col,i) { 8174 return col.bVisible ? i : null; 8175 } ); 8176 return [ visColumns[ visColumns.length + idx ] ]; 8177 } 8178 // Counting from the left 8179 return [ _fnVisibleToColumnIndex( settings, idx ) ]; 8180 8181 case 'name': 8182 // match by name. `names` is column index complete and in order 8183 return $.map( names, function (name, i) { 8184 return name === match[1] ? i : null; 8185 } ); 8186 } 8187 } 8188 else { 8189 // jQuery selector on the TH elements for the columns 8190 return $( nodes ) 8191 .filter( s ) 8192 .map( function () { 8193 return $.inArray( this, nodes ); // `nodes` is column index complete and in order 8194 } ) 8195 .toArray(); 8196 } 8197 } ); 8198 }; 8199 8200 8201 var __setColumnVis = function ( settings, column, vis, recalc ) { 8202 var 8203 cols = settings.aoColumns, 8204 col = cols[ column ], 8205 data = settings.aoData, 8206 row, cells, i, ien, tr; 8207 8208 // Get 8209 if ( vis === undefined ) { 8210 return col.bVisible; 8211 } 8212 8213 // Set 8214 // No change 8215 if ( col.bVisible === vis ) { 8216 return; 8217 } 8218 8219 if ( vis ) { 8220 // Insert column 8221 // Need to decide if we should use appendChild or insertBefore
8222 var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 ); 8223 8224 for ( i=0, ien=data.length ; i<ien ; i++ ) { 8225 tr = data[i].nTr; 8226 cells = data[i].anCells; 8227 8228 if ( tr ) { 8229 // insertBefore can act like appendChild if 2nd arg is null 8230 tr.insertBefore( cells[ column ], cells[ insertBefore ] || null ); 8231 } 8232 } 8233 } 8234 else { 8235 // Remove column 8236 $( _pluck( settings.aoData, 'anCells', column ) ).detach(); 8237 } 8238 8239 // Common actions 8240 col.bVisible = vis; 8241 _fnDrawHead( settings, settings.aoHeader ); 8242 _fnDrawHead( settings, settings.aoFooter ); 8243 8244 if ( recalc === undefined || recalc ) { 8245 // Automatically adjust column sizing 8246 _fnAdjustColumnSizing( settings ); 8247 8248 // Realign columns for scrolling 8249 if ( settings.oScroll.sX || settings.oScroll.sY ) { 8250 _fnScrollDraw( settings ); 8251 } 8252 } 8253 8254 _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] ); 8255 8256 _fnSaveState( settings ); 8257 }; 8258 8259 8260 /** 8261 * 8262 */ 8263 _api_register( 'columns()', function ( selector, opts ) { 8264 // argument shifting 8265 if ( selector === undefined ) { 8266 selector = ''; 8267 } 8268 else if ( $.isPlainObject( selector ) ) { 8269 opts = selector; 8270 selector = ''; 8271 } 8272 8273 opts = _selector_opts( opts ); 8274 8275 var inst = this.iterator( 'table', function ( settings ) { 8276 return __column_selector( settings, selector, opts ); 8277 }, 1 ); 8278 8279 // Want argument shifting here and in _row_selector? 8280 inst.selector.cols = selector; 8281 inst.selector.opts = opts; 8282 8283 return inst; 8284 } ); 8285 8286 8287 /** 8288 * 8289 */ 8290 _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) { 8291 return this.iterator( 'column', function ( settings, column ) { 8292 return settings.aoColumns[column].nTh; 8293 }, 1 ); 8294 } ); 8295 8296 8297 /** 8298 * 8299 */ 8300 _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) { 8301 return this.iterator( 'column', function ( settings, column ) { 8302 return settings.aoColumns[column].nTf; 8303 }, 1 ); 8304 } ); 8305 8306 8307 /** 8308 * 8309 */ 8310 _api_registerPlural( 'columns().data()', 'column().data()', function () { 8311 return this.iterator( 'column-rows', __columnData, 1 ); 8312 } ); 8313 8314 8315 _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () { 8316 return this.iterator( 'column', function ( settings, column ) { 8317 return settings.aoColumns[column].mData; 8318 }, 1 ); 8319 } ); 8320 8321 8322 _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) { 8323 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8324 return _pluck_order( settings.aoData, rows, 8325 type === 'search' ? '_aFilterData' : '_aSortData', column 8326 ); 8327 }, 1 ); 8328 } ); 8329 8330 8331 _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () { 8332 return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) { 8333 return _pluck_order( settings.aoData, rows, 'anCells', column ) ; 8334 }, 1 ); 8335 } ); 8336 8337 8338 8339 _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) { 8340 return this.iterator( 'column', function ( settings, column ) { 8341 if ( vis === undefined ) { 8342 return settings.aoColumns[ column ].bVisible; 8343 } // else 8344 __setColumnVis( settings, column, vis, calc ); 8345 } ); 8346 } ); 8347 8348 8349 8350 _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) { 8351 return this.iterator( 'column', function ( settings, column ) { 8352 return type === 'visible' ? 8353 _fnColumnIndexToVisible( settings, column ) : 8354 column; 8355 }, 1 ); 8356 } ); 8357 8358 8359 // _api_register( 'columns().show()', function () { 8360 // var selector = this.selector; 8361 // return this.columns( selector.cols, selector.opts ).visible( true ); 8362 // } ); 8363 8364 8365 // _api_register( 'columns().hide()', function () { 8366 // var selector = this.selector; 8367 // return this.columns( selector.cols, selector.opts ).visible( false ); 8368 // } ); 8369 8370 8371 8372 _api_register( 'columns.adjust()', function () { 8373 return this.iterator( 'table', function ( settings ) { 8374 _fnAdjustColumnSizing( settings ); 8375 }, 1 ); 8376 } ); 8377 8378 8379 // Convert from one column index type, to another type 8380 _api_register( 'column.index()', function ( type, idx ) { 8381 if ( this.context.length !== 0 ) { 8382 var ctx = this.context[0]; 8383 8384 if ( type === 'fromVisible' || type === 'toData' ) { 8385 return _fnVisibleToColumnIndex( ctx, idx ); 8386 } 8387 else if ( type === 'fromData' || type === 'toVisible' ) { 8388 return _fnColumnIndexToVisible( ctx, idx ); 8389 } 8390 } 8391 } ); 8392 8393 8394 _api_register( 'column()', function ( selector, opts ) { 8395 return _selector_first( this.columns( selector, opts ) ); 8396 } ); 8397 8398 8399 8400 8401 var __cell_selector = function ( settings, selector, opts ) 8402 { 8403 var data = settings.aoData; 8404 var rows = _selector_row_indexes( settings, opts ); 8405 var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) ); 8406 var allCells = $( [].concat.apply([], cells) ); 8407 var row; 8408 var columns = settings.aoColumns.length; 8409 var a, i, ien, j, o, host; 8410 8411 return _selector_run( selector, function ( s ) { 8412 var fnSelector = typeof s === 'function'; 8413 8414 if ( s === null || s === undefined || fnSelector ) { 8415 // All cells and function selectors 8416 a = []; 8417 8418 for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8419 row = rows[i]; 8420 8421 for ( j=0 ; j<columns ; j++ ) { 8422 o = { 8423 row: row, 8424 column: j 8425 }; 8426 8427 if ( fnSelector ) { 8428 // Selector - function 8429 host = settings.aoData[ row ]; 8430 8431 if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) { 8432 a.push( o ); 8433 } 8434 } 8435 else { 8436 // Selector - all 8437 a.push( o ); 8438 } 8439 } 8440 } 8441 8442 return a; 8443 } 8444 8445 // Selector - index 8446 if ( $.isPlainObject( s ) ) { 8447 return [s]; 8448 } 8449 8450 // Selector - jQuery filtered cells 8451 return allCells 8452 .filter( s ) 8453 .map( function (i, el) { 8454 row = el.parentNode._DT_RowIndex; 8455 8456 return { 8457 row: row, 8458 column: $.inArray( el, data[ row ].anCells ) 8459 }; 8460 } ) 8461 .toArray(); 8462 } ); 8463 }; 8464 8465 8466 8467 8468 _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) { 8469 // Argument shifting 8470 if ( $.isPlainObject( rowSelector ) ) { 8471 // Indexes 8472 if ( typeof rowSelector.row !== undefined ) { 8473 opts = columnSelector; 8474 columnSelector = null; 8475 } 8476 else { 8477 opts = rowSelector; 8478 rowSelector = null; 8479 } 8480 } 8481 if ( $.isPlainObject( columnSelector ) ) { 8482 opts = columnSelector; 8483 columnSelector = null; 8484 } 8485 8486 // Cell selector 8487 if ( columnSelector === null || columnSelector === undefined ) { 8488 return this.iterator( 'table', function ( settings ) { 8489 return __cell_selector( settings, rowSelector, _selector_opts( opts ) ); 8490 } ); 8491 } 8492 8493 // Row + column selector 8494 var columns = this.columns( columnSelector, opts ); 8495 var rows = this.rows( rowSelector, opts ); 8496 var a, i, ien, j, jen; 8497 8498 var cells = this.iterator( 'table', function ( settings, idx ) { 8499 a = []; 8500 8501 for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) { 8502 for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) { 8503 a.push( { 8504 row: rows[idx][i], 8505 column: columns[idx][j] 8506 } ); 8507 } 8508 } 8509 8510 return a; 8511 }, 1 ); 8512 8513 $.extend( cells.selector, { 8514 cols: columnSelector, 8515 rows: rowSelector, 8516 opts: opts 8517 } ); 8518 8519 return cells; 8520 } ); 8521 8522 8523 _api_registerPlural( 'cells().nodes()', 'cell().node()', function () { 8524 return this.iterator( 'cell', function ( settings, row, column ) { 8525 var cells = settings.aoData[ row ].anCells; 8526 return cells ? 8527 cells[ column ] : 8528 undefined; 8529 }, 1 ); 8530 } ); 8531 8532 8533 _api_register( 'cells().data()', function () { 8534 return this.iterator( 'cell', function ( settings, row, column ) { 8535 return _fnGetCellData( settings, row, column ); 8536 }, 1 ); 8537 } ); 8538 8539 8540 _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) { 8541 type = type === 'search' ? '_aFilterData' : '_aSortData'; 8542 8543 return this.iterator( 'cell', function ( settings, row, column ) { 8544 return settings.aoData[ row ][ type ][ column ]; 8545 }, 1 ); 8546 } ); 8547 8548 8549 _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) { 8550 return this.iterator( 'cell', function ( settings, row, column ) { 8551 return _fnGetCellData( settings, row, column, type ); 8552 }, 1 ); 8553 } ); 8554 8555 8556 _api_registerPlural( 'cells().indexes()', 'cell().index()', function () { 8557 return this.iterator( 'cell', function ( settings, row, column ) { 8558 return { 8559 row: row, 8560 column: column, 8561 columnVisible: _fnColumnIndexToVisible( settings, column ) 8562 }; 8563 }, 1 ); 8564 } ); 8565 8566 8567 _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) { 8568 return this.iterator( 'cell', function ( settings, row, column ) { 8569 _fnInvalidate( settings, row, src, column ); 8570 } ); 8571 } ); 8572 8573 8574 8575 _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) { 8576 return _selector_first( this.cells( rowSelector, columnSelector, opts ) ); 8577 } ); 8578 8579 8580 _api_register( 'cell().data()', function ( data ) { 8581 var ctx = this.context; 8582 var cell = this[0]; 8583 8584 if ( data === undefined ) { 8585 // Get 8586 return ctx.length && cell.length ? 8587 _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) : 8588 undefined; 8589 } 8590 8591 // Set 8592 _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data ); 8593 _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column ); 8594 8595 return this; 8596 } ); 8597 8598 8599 8600 /** 8601 * Get current ordering (sorting) that has been applied to the table. 8602 * 8603 * @returns {array} 2D array containing the sorting information for the first 8604 * table in the current context. Each element in the parent array represents 8605 * a column being sorted upon (i.e. multi-sorting with two columns would have 8606 * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is 8607 * the column index that the sorting condition applies to, the second is the 8608 * direction of the sort (`desc` or `asc`) and, optionally, the third is the 8609 * index of the sorting order from the `column.sorting` initialisation array.
8610 *//** 8611 * Set the ordering for the table. 8612 * 8613 * @param {integer} order Column index to sort upon. 8614 * @param {string} direction Direction of the sort to be applied (`asc` or `desc`) 8615 * @returns {DataTables.Api} this 8616 *//** 8617 * Set the ordering for the table. 8618 * 8619 * @param {array} order 1D array of sorting information to be applied. 8620 * @param {array} [...] Optional additional sorting conditions 8621 * @returns {DataTables.Api} this 8622 *//** 8623 * Set the ordering for the table. 8624 * 8625 * @param {array} order 2D array of sorting information to be applied. 8626 * @returns {DataTables.Api} this 8627 */ 8628 _api_register( 'order()', function ( order, dir ) { 8629 var ctx = this.context; 8630 8631 if ( order === undefined ) { 8632 // get 8633 return ctx.length !== 0 ? 8634 ctx[0].aaSorting : 8635 undefined; 8636 } 8637 8638 // set 8639 if ( typeof order === 'number' ) { 8640 // Simple column / direction passed in 8641 order = [ [ order, dir ] ]; 8642 } 8643 else if ( ! $.isArray( order[0] ) ) { 8644 // Arguments passed in (list of 1D arrays) 8645 order = Array.prototype.slice.call( arguments ); 8646 } 8647 // otherwise a 2D array was passed in 8648 8649 return this.iterator( 'table', function ( settings ) { 8650 settings.aaSorting = order.slice(); 8651 } ); 8652 } ); 8653 8654 8655 /** 8656 * Attach a sort listener to an element for a given column 8657 * 8658 * @param {node|jQuery|string} node Identifier for the element(s) to attach the 8659 * listener to. This can take the form of a single DOM node, a jQuery 8660 * collection of nodes or a jQuery selector which will identify the node(s). 8661 * @param {integer} column the column that a click on this node will sort on 8662 * @param {function} [callback] callback function when sort is run 8663 * @returns {DataTables.Api} this 8664 */ 8665 _api_register( 'order.listener()', function ( node, column, callback ) { 8666 return this.iterator( 'table', function ( settings ) { 8667 _fnSortAttachListener( settings, node, column, callback ); 8668 } ); 8669 } ); 8670 8671 8672 // Order by the selected column(s) 8673 _api_register( [ 8674 'columns().order()', 8675 'column().order()' 8676 ], function ( dir ) { 8677 var that = this; 8678 8679 return this.iterator( 'table', function ( settings, i ) { 8680 var sort = []; 8681 8682 $.each( that[i], function (j, col) { 8683 sort.push( [ col, dir ] ); 8684 } ); 8685 8686 settings.aaSorting = sort; 8687 } ); 8688 } ); 8689 8690 8691 8692 _api_register( 'search()', function ( input, regex, smart, caseInsen ) { 8693 var ctx = this.context; 8694 8695 if ( input === undefined ) { 8696 // get 8697 return ctx.length !== 0 ? 8698 ctx[0].oPreviousSearch.sSearch : 8699 undefined; 8700 } 8701 8702 // set 8703 return this.iterator( 'table', function ( settings ) { 8704 if ( ! settings.oFeatures.bFilter ) { 8705 return; 8706 } 8707 8708 _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, { 8709 "sSearch": input+"", 8710 "bRegex": regex === null ? false : regex, 8711 "bSmart": smart === null ? true : smart, 8712 "bCaseInsensitive": caseInsen === null ? true : caseInsen 8713 } ), 1 ); 8714 } ); 8715 } ); 8716 8717 8718 _api_registerPlural( 8719 'columns().search()', 8720 'column().search()', 8721 function ( input, regex, smart, caseInsen ) { 8722 return this.iterator( 'column', function ( settings, column ) { 8723 var preSearch = settings.aoPreSearchCols; 8724 8725 if ( input === undefined ) { 8726 // get 8727 return preSearch[ column ].sSearch; 8728 } 8729 8730 // set 8731 if ( ! settings.oFeatures.bFilter ) { 8732 return; 8733 } 8734 8735 $.extend( preSearch[ column ], { 8736 "sSearch": input+"", 8737 "bRegex": regex === null ? false : regex, 8738 "bSmart": smart === null ? true : smart, 8739 "bCaseInsensitive": caseInsen === null ? true : caseInsen 8740 } ); 8741 8742 _fnFilterComplete( settings, settings.oPreviousSearch, 1 ); 8743 } ); 8744 } 8745 ); 8746 8747 /* 8748 * State API methods 8749 */ 8750 8751 _api_register( 'state()', function () { 8752 return this.context.length ? 8753 this.context[0].oSavedState : 8754 null; 8755 } ); 8756 8757 8758 _api_register( 'state.clear()', function () { 8759 return this.iterator( 'table', function ( settings ) { 8760 // Save an empty object 8761 settings.fnStateSaveCallback.call( settings.oInstance, settings, {} ); 8762 } ); 8763 } ); 8764 8765 8766 _api_register( 'state.loaded()', function () { 8767 return this.context.length ? 8768 this.context[0].oLoadedState : 8769 null; 8770 } ); 8771 8772 8773 _api_register( 'state.save()', function () { 8774 return this.iterator( 'table', function ( settings ) { 8775 _fnSaveState( settings ); 8776 } ); 8777 } ); 8778 8779 8780 8781 /**
8782 * Provide a common method for plug-ins to check the version of DataTables being 8783 * used, in order to ensure compatibility. 8784 * 8785 * @param {string} version Version string to check for, in the format "X.Y.Z". 8786 * Note that the formats "X" and "X.Y" are also acceptable. 8787 * @returns {boolean} true if this version of DataTables is greater or equal to 8788 * the required version, or false if this version of DataTales is not 8789 * suitable 8790 * @static 8791 * @dtopt API-Static 8792 * 8793 * @example 8794 * alert( $.fn.dataTable.versionCheck( '1.9.0' ) ); 8795 */ 8796 DataTable.versionCheck = DataTable.fnVersionCheck = function( version ) 8797 { 8798 var aThis = DataTable.version.split('.'); 8799 var aThat = version.split('.'); 8800 var iThis, iThat; 8801 8802 for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) { 8803 iThis = parseInt( aThis[i], 10 ) || 0; 8804 iThat = parseInt( aThat[i], 10 ) || 0; 8805 8806 // Parts are the same, keep comparing 8807 if (iThis === iThat) { 8808 continue; 8809 } 8810 8811 // Parts are different, return immediately 8812 return iThis > iThat; 8813 } 8814 8815 return true; 8816 }; 8817 8818 8819 /** 8820 * Check if a `<table>` node is a DataTable table already or not. 8821 * 8822 * @param {node|jquery|string} table Table node, jQuery object or jQuery 8823 * selector for the table to test. Note that if more than more than one 8824 * table is passed on, only the first will be checked 8825 * @returns {boolean} true the table given is a DataTable, or false otherwise 8826 * @static 8827 * @dtopt API-Static 8828 * 8829 * @example 8830 * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) { 8831 * $('#example').dataTable(); 8832 * } 8833 */ 8834 DataTable.isDataTable = DataTable.fnIsDataTable = function ( table ) 8835 { 8836 var t = $(table).get(0); 8837 var is = false; 8838 8839 $.each( DataTable.settings, function (i, o) { 8840 if ( o.nTable === t || 8841 $('table', o.nScrollHead)[0] === t || 8842 $('table', o.nScrollFoot)[0] === t 8843 ) { 8844 is = true; 8845 } 8846 } ); 8847 8848 return is; 8849 }; 8850 8851 8852 /** 8853 * Get all DataTable tables that have been initialised - optionally you can 8854 * select to get only currently visible tables. 8855 * 8856 * @param {boolean} [visible=false] Flag to indicate if you want all (default) 8857 * or visible tables only. 8858 * @returns {array} Array of `table` nodes (not DataTable instances) which are 8859 * DataTables 8860 * @static 8861 * @dtopt API-Static 8862 * 8863 * @example 8864 * $.each( $.fn.dataTable.tables(true), function () { 8865 * $(table).DataTable().columns.adjust(); 8866 * } ); 8867 */ 8868 DataTable.tables = DataTable.fnTables = function ( visible ) 8869 { 8870 return $.map( DataTable.settings, function (o) { 8871 if ( !visible || (visible && $(o.nTable).is(':visible')) ) { 8872 return o.nTable; 8873 } 8874 } ); 8875 }; 8876 8877 8878 /** 8879 * DataTables utility methods 8880 * 8881 * This namespace provides helper methods that DataTables uses internally to 8882 * create a DataTable, but which are not exclusively used only for DataTables. 8883 * These methods can be used by extension authors to save the duplication of 8884 * code. 8885 * 8886 * @namespace 8887 */ 8888 DataTable.util = { 8889 /** 8890 * Throttle the calls to a function. Arguments and context are maintained 8891 * for the throttled function. 8892 * 8893 * @param {function} fn Function to be called 8894 * @param {integer} freq Call frequency in mS 8895 * @return {function} Wrapped function 8896 */ 8897 throttle: _fnThrottle, 8898 8899 8900 /** 8901 * Escape a string such that it can be used in a regular expression 8902 * 8903 * @param {string} sVal string to escape 8904 * @returns {string} escaped string 8905 */ 8906 escapeRegex: _fnEscapeRegex 8907 }; 8908 8909 8910 /** 8911 * Convert from camel case parameters to Hungarian notation. This is made public 8912 * for the extensions to provide the same ability as DataTables core to accept 8913 * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase 8914 * parameters. 8915 * 8916 * @param {object} src The model object which holds all parameters that can be 8917 * mapped. 8918 * @param {object} user The object to convert from camel case to Hungarian. 8919 * @param {boolean} force When set to `true`, properties which already have a 8920 * Hungarian value in the `user` object will be overwritten. Otherwise they 8921 * won't be. 8922 */ 8923 DataTable.camelToHungarian = _fnCamelToHungarian; 8924 8925 8926 8927 /** 8928 * 8929 */ 8930 _api_register( '$()', function ( selector, opts ) { 8931 var 8932 rows = this.rows( opts ).nodes(), // Get all rows 8933 jqRows = $(rows); 8934 8935 return $( [].concat( 8936 jqRows.filter( selector ).toArray(), 8937 jqRows.find( selector ).toArray() 8938 ) ); 8939 } ); 8940 8941 8942 // jQuery functions to operate on the tables 8943 $.each( [ 'on', 'one', 'off' ], function (i, key) { 8944 _api_register( key+'()', function ( /* event, handler */ ) { 8945 var args = Array.prototype.slice.call(arguments); 8946 8947 // Add the `dt` namespace automatically if it isn't already present 8948 if ( ! args[0].match(/\.dt\b/) ) { 8949 args[0] += '.dt'; 8950 } 8951 8952 var inst = $( this.tables().nodes() ); 8953 inst[key].apply( inst, args ); 8954 return this; 8955 } ); 8956 } ); 8957 8958 8959 _api_register( 'clear()', function () { 8960 return this.iterator( 'table', function ( settings ) { 8961 _fnClearTable( settings ); 8962 } ); 8963 } ); 8964 8965 8966 _api_register( 'settings()', function () { 8967 return new _Api( this.context, this.context ); 8968 } ); 8969 8970 8971 _api_register( 'data()', function () { 8972 return this.iterator( 'table', function ( settings ) { 8973 return _pluck( settings.aoData, '_aData' ); 8974 } ).flatten(); 8975 } ); 8976 8977 8978 _api_register( 'destroy()', function ( remove ) { 8979 remove = remove || false; 8980 8981 return this.iterator( 'table', function ( settings ) { 8982 var orig = settings.nTableWrapper.parentNode; 8983 var classes = settings.oClasses; 8984 var table = settings.nTable; 8985 var tbody = settings.nTBody; 8986 var thead = settings.nTHead; 8987 var tfoot = settings.nTFoot; 8988 var jqTable = $(table); 8989 var jqTbody = $(tbody); 8990 var jqWrapper = $(settings.nTableWrapper); 8991 var rows = $.map( settings.aoData, function (r) { return r.nTr; } ); 8992 var i, ien; 8993 8994 // Flag to note that the table is currently being destroyed - no action 8995 // should be taken 8996 settings.bDestroying = true; 8997
8998 // Fire off the destroy callbacks for plug-ins etc 8999 _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] ); 9000 9001 // If not being removed from the document, make all columns visible 9002 if ( ! remove ) { 9003 new _Api( settings ).columns().visible( true ); 9004 } 9005 9006 // Blitz all `DT` namespaced events (these are internal events, the 9007 // lowercase, `dt` events are user subscribed and they are responsible 9008 // for removing them 9009 jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT'); 9010 $(window).unbind('.DT-'+settings.sInstance); 9011 9012 // When scrolling we had to break the table up - restore it 9013 if ( table != thead.parentNode ) { 9014 jqTable.children('thead').detach(); 9015 jqTable.append( thead ); 9016 } 9017 9018 if ( tfoot && table != tfoot.parentNode ) { 9019 jqTable.children('tfoot').detach(); 9020 jqTable.append( tfoot ); 9021 } 9022 9023 // Remove the DataTables generated nodes, events and classes 9024 jqTable.detach(); 9025 jqWrapper.detach(); 9026 9027 settings.aaSorting = []; 9028 settings.aaSortingFixed = []; 9029 _fnSortingClasses( settings ); 9030 9031 $( rows ).removeClass( settings.asStripeClasses.join(' ') ); 9032 9033 $('th, td', thead).removeClass( classes.sSortable+' '+ 9034 classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone 9035 ); 9036 9037 if ( settings.bJUI ) { 9038 $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach(); 9039 $('th, td', thead).each( function () { 9040 var wrapper = $('div.'+classes.sSortJUIWrapper, this); 9041 $(this).append( wrapper.contents() ); 9042 wrapper.detach(); 9043 } ); 9044 } 9045 9046 if ( ! remove && orig ) { 9047 // insertBefore acts like appendChild if !arg[1] 9048 orig.insertBefore( table, settings.nTableReinsertBefore ); 9049 } 9050 9051 // Add the TR elements back into the table in their original order 9052 jqTbody.children().detach(); 9053 jqTbody.append( rows ); 9054 9055 // Restore the width of the original table - was read from the style property, 9056 // so we can restore directly to that 9057 jqTable 9058 .css( 'width', settings.sDestroyWidth ) 9059 .removeClass( classes.sTable ); 9060 9061 // If the were originally stripe classes - then we add them back here. 9062 // Note this is not fool proof (for example if not all rows had stripe 9063 // classes - but it's a good effort without getting carried away 9064 ien = settings.asDestroyStripes.length; 9065 9066 if ( ien ) { 9067 jqTbody.children().each( function (i) { 9068 $(this).addClass( settings.asDestroyStripes[i % ien] ); 9069 } ); 9070 } 9071 9072 /* Remove the settings object from the settings array */ 9073 var idx = $.inArray( settings, DataTable.settings ); 9074 if ( idx !== -1 ) { 9075 DataTable.settings.splice( idx, 1 ); 9076 } 9077 } ); 9078 } ); 9079 9080 9081 /** 9082 * Version string for plug-ins to check compatibility. Allowed format is 9083 * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used 9084 * only for non-release builds. See http://semver.org/ for more information. 9085 * @member 9086 * @type string 9087 * @default Version number 9088 */ 9089 DataTable.version = "1.10.5"; 9090 9091 /** 9092 * Private data store, containing all of the settings objects that are 9093 * created for the tables on a given page. 9094 * 9095 * Note that the `DataTable.settings` object is aliased to 9096 * `jQuery.fn.dataTableExt` through which it may be accessed and 9097 * manipulated, or `jQuery.fn.dataTable.settings`. 9098 * @member 9099 * @type array 9100 * @default [] 9101 * @private 9102 */ 9103 DataTable.settings = []; 9104 9105 /** 9106 * Object models container, for the various models that DataTables has 9107 * available to it. These models define the objects that are used to hold 9108 * the active state and configuration of the table. 9109 * @namespace 9110 */ 9111 DataTable.models = {}; 9112 9113 9114 9115 /** 9116 * Template object for the way in which DataTables holds information about 9117 * search information for the global filter and individual column filters. 9118 * @namespace 9119 */ 9120 DataTable.models.oSearch = { 9121 /** 9122 * Flag to indicate if the filtering should be case insensitive or not 9123 * @type boolean 9124 * @default true 9125 */ 9126 "bCaseInsensitive": true, 9127 9128 /** 9129 * Applied search term 9130 * @type string 9131 * @default <i>Empty string</i> 9132 */ 9133 "sSearch": "", 9134 9135 /** 9136 * Flag to indicate if the search term should be interpreted as a 9137 * regular expression (true) or not (false) and therefore and special 9138 * regex characters escaped. 9139 * @type boolean 9140 * @default false 9141 */ 9142 "bRegex": false, 9143 9144 /** 9145 * Flag to indicate if DataTables is to use its smart filtering or not. 9146 * @type boolean 9147 * @default true 9148 */ 9149 "bSmart": true 9150 }; 9151 9152 9153 9154 9155 /** 9156 * Template object for the way in which DataTables holds information about 9157 * each individual row. This is the object format used for the settings 9158 * aoData array.
9159 * @namespace 9160 */ 9161 DataTable.models.oRow = { 9162 /** 9163 * TR element for the row 9164 * @type node 9165 * @default null 9166 */ 9167 "nTr": null, 9168 9169 /** 9170 * Array of TD elements for each row. This is null until the row has been 9171 * created. 9172 * @type array nodes 9173 * @default [] 9174 */ 9175 "anCells": null, 9176 9177 /** 9178 * Data object from the original data source for the row. This is either 9179 * an array if using the traditional form of DataTables, or an object if 9180 * using mData options. The exact type will depend on the passed in 9181 * data from the data source, or will be an array if using DOM a data 9182 * source. 9183 * @type array|object 9184 * @default [] 9185 */ 9186 "_aData": [], 9187 9188 /** 9189 * Sorting data cache - this array is ostensibly the same length as the 9190 * number of columns (although each index is generated only as it is 9191 * needed), and holds the data that is used for sorting each column in the 9192 * row. We do this cache generation at the start of the sort in order that 9193 * the formatting of the sort data need be done only once for each cell 9194 * per sort. This array should not be read from or written to by anything 9195 * other than the master sorting methods. 9196 * @type array 9197 * @default null 9198 * @private 9199 */ 9200 "_aSortData": null, 9201 9202 /** 9203 * Per cell filtering data cache. As per the sort data cache, used to 9204 * increase the performance of the filtering in DataTables 9205 * @type array 9206 * @default null 9207 * @private 9208 */ 9209 "_aFilterData": null, 9210 9211 /** 9212 * Filtering data cache. This is the same as the cell filtering cache, but 9213 * in this case a string rather than an array. This is easily computed with 9214 * a join on `_aFilterData`, but is provided as a cache so the join isn't 9215 * needed on every search (memory traded for performance) 9216 * @type array 9217 * @default null 9218 * @private 9219 */ 9220 "_sFilterRow": null, 9221 9222 /** 9223 * Cache of the class name that DataTables has applied to the row, so we 9224 * can quickly look at this variable rather than needing to do a DOM check 9225 * on className for the nTr property. 9226 * @type string 9227 * @default <i>Empty string</i> 9228 * @private 9229 */ 9230 "_sRowStripe": "", 9231 9232 /** 9233 * Denote if the original data source was from the DOM, or the data source 9234 * object. This is used for invalidating data, so DataTables can 9235 * automatically read data from the original source, unless uninstructed 9236 * otherwise. 9237 * @type string 9238 * @default null 9239 * @private 9240 */ 9241 "src": null 9242 }; 9243 9244 9245 /** 9246 * Template object for the column information object in DataTables. This object 9247 * is held in the settings aoColumns array and contains all the information that 9248 * DataTables needs about each individual column. 9249 * 9250 * Note that this object is related to {@link DataTable.defaults.column} 9251 * but this one is the internal data store for DataTables's cache of columns. 9252 * It should NOT be manipulated outside of DataTables. Any configuration should 9253 * be done through the initialisation options. 9254 * @namespace 9255 */ 9256 DataTable.models.oColumn = { 9257 /** 9258 * Column index. This could be worked out on-the-fly with $.inArray, but it 9259 * is faster to just hold it as a variable 9260 * @type integer 9261 * @default null 9262 */ 9263 "idx": null, 9264 9265 /** 9266 * A list of the columns that sorting should occur on when this column 9267 * is sorted. That this property is an array allows multi-column sorting 9268 * to be defined for a column (for example first name / last name columns 9269 * would benefit from this). The values are integers pointing to the 9270 * columns to be sorted on (typically it will be a single integer pointing 9271 * at itself, but that doesn't need to be the case). 9272 * @type array 9273 */ 9274 "aDataSort": null, 9275 9276 /** 9277 * Define the sorting directions that are applied to the column, in sequence 9278 * as the column is repeatedly sorted upon - i.e. the first value is used 9279 * as the sorting direction when the column if first sorted (clicked on). 9280 * Sort it again (click again) and it will move on to the next index. 9281 * Repeat until loop. 9282 * @type array 9283 */ 9284 "asSorting": null, 9285 9286 /** 9287 * Flag to indicate if the column is searchable, and thus should be included 9288 * in the filtering or not. 9289 * @type boolean 9290 */ 9291 "bSearchable": null, 9292 9293 /** 9294 * Flag to indicate if the column is sortable or not. 9295 * @type boolean 9296 */ 9297 "bSortable": null, 9298 9299 /** 9300 * Flag to indicate if the column is currently visible in the table or not 9301 * @type boolean 9302 */ 9303 "bVisible": null, 9304 9305 /** 9306 * Store for manual type assignment using the `column.type` option. This 9307 * is held in store so we can manipulate the column's `sType` property. 9308 * @type string 9309 * @default null 9310 * @private 9311 */ 9312 "_sManualType": null, 9313 9314 /** 9315 * Flag to indicate if HTML5 data attributes should be used as the data 9316 * source for filtering or sorting. True is either are. 9317 * @type boolean 9318 * @default false 9319 * @private 9320 */ 9321 "_bAttrSrc": false, 9322 9323 /** 9324 * Developer definable function that is called whenever a cell is created (Ajax source, 9325 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 9326 * allowing you to modify the DOM element (add background colour for example) when the 9327 * element is available. 9328 * @type function 9329 * @param {element} nTd The TD node that has been created 9330 * @param {*} sData The Data for the cell 9331 * @param {array|object} oData The data for the whole row 9332 * @param {int} iRow The row index for the aoData data store 9333 * @default null 9334 */ 9335 "fnCreatedCell": null, 9336 9337 /** 9338 * Function to get data from a cell in a column. You should <b>never</b> 9339 * access data directly through _aData internally in DataTables - always use 9340 * the method attached to this property. It allows mData to function as 9341 * required. This function is automatically assigned by the column 9342 * initialisation method 9343 * @type function 9344 * @param {array|object} oData The data array/object for the array 9345 * (i.e. aoData[]._aData) 9346 * @param {string} sSpecific The specific data type you want to get - 9347 * 'display', 'type' 'filter' 'sort' 9348 * @returns {*} The data for the cell from the given row's data 9349 * @default null 9350 */ 9351 "fnGetData": null, 9352 9353 /** 9354 * Function to set data for a cell in the column. You should <b>never</b> 9355 * set the data directly to _aData internally in DataTables - always use 9356 * this method. It allows mData to function as required. This function 9357 * is automatically assigned by the column initialisation method 9358 * @type function 9359 * @param {array|object} oData The data array/object for the array 9360 * (i.e. aoData[]._aData) 9361 * @param {*} sValue Value to set 9362 * @default null 9363 */ 9364 "fnSetData": null, 9365 9366 /** 9367 * Property to read the value for the cells in the column from the data 9368 * source array / object. If null, then the default content is used, if a 9369 * function is given then the return from the function is used. 9370 * @type function|int|string|null 9371 * @default null 9372 */ 9373 "mData": null, 9374 9375 /** 9376 * Partner property to mData which is used (only when defined) to get 9377 * the data - i.e. it is basically the same as mData, but without the 9378 * 'set' option, and also the data fed to it is the result from mData. 9379 * This is the rendering method to match the data method of mData. 9380 * @type function|int|string|null 9381 * @default null 9382 */
9383 "mRender": null, 9384 9385 /** 9386 * Unique header TH/TD element for this column - this is what the sorting 9387 * listener is attached to (if sorting is enabled.) 9388 * @type node 9389 * @default null 9390 */ 9391 "nTh": null, 9392 9393 /** 9394 * Unique footer TH/TD element for this column (if there is one). Not used 9395 * in DataTables as such, but can be used for plug-ins to reference the 9396 * footer for each column. 9397 * @type node 9398 * @default null 9399 */ 9400 "nTf": null, 9401 9402 /** 9403 * The class to apply to all TD elements in the table's TBODY for the column 9404 * @type string 9405 * @default null 9406 */ 9407 "sClass": null, 9408 9409 /** 9410 * When DataTables calculates the column widths to assign to each column, 9411 * it finds the longest string in each column and then constructs a 9412 * temporary table and reads the widths from that. The problem with this 9413 * is that "mmm" is much wider then "iiii", but the latter is a longer 9414 * string - thus the calculation can go wrong (doing it properly and putting 9415 * it into an DOM object and measuring that is horribly(!) slow). Thus as 9416 * a "work around" we provide this option. It will append its value to the 9417 * text that is found to be the longest string for the column - i.e. padding. 9418 * @type string 9419 */ 9420 "sContentPadding": null, 9421 9422 /** 9423 * Allows a default value to be given for a column's data, and will be used 9424 * whenever a null data source is encountered (this can be because mData 9425 * is set to null, or because the data source itself is null). 9426 * @type string 9427 * @default null 9428 */ 9429 "sDefaultContent": null, 9430 9431 /** 9432 * Name for the column, allowing reference to the column by name as well as 9433 * by index (needs a lookup to work by name). 9434 * @type string 9435 */ 9436 "sName": null, 9437 9438 /** 9439 * Custom sorting data type - defines which of the available plug-ins in 9440 * afnSortData the custom sorting will use - if any is defined. 9441 * @type string 9442 * @default std 9443 */ 9444 "sSortDataType": 'std', 9445 9446 /** 9447 * Class to be applied to the header element when sorting on this column 9448 * @type string 9449 * @default null 9450 */ 9451 "sSortingClass": null, 9452 9453 /** 9454 * Class to be applied to the header element when sorting on this column - 9455 * when jQuery UI theming is used. 9456 * @type string 9457 * @default null 9458 */ 9459 "sSortingClassJUI": null, 9460 9461 /** 9462 * Title of the column - what is seen in the TH element (nTh). 9463 * @type string 9464 */ 9465 "sTitle": null, 9466 9467 /** 9468 * Column sorting and filtering type 9469 * @type string 9470 * @default null 9471 */ 9472 "sType": null, 9473 9474 /** 9475 * Width of the column 9476 * @type string 9477 * @default null 9478 */ 9479 "sWidth": null, 9480 9481 /** 9482 * Width of the column when it was first "encountered" 9483 * @type string 9484 * @default null 9485 */ 9486 "sWidthOrig": null 9487 }; 9488 9489 9490 /* 9491 * Developer note: The properties of the object below are given in Hungarian 9492 * notation, that was used as the interface for DataTables prior to v1.10, however 9493 * from v1.10 onwards the primary interface is camel case. In order to avoid 9494 * breaking backwards compatibility utterly with this change, the Hungarian 9495 * version is still, internally the primary interface, but is is not documented 9496 * - hence the @name tags in each doc comment. This allows a Javascript function 9497 * to create a map from Hungarian notation to camel case (going the other direction 9498 * would require each property to be listed, which would at around 3K to the size 9499 * of DataTables, while this method is about a 0.5K hit. 9500 * 9501 * Ultimately this does pave the way for Hungarian notation to be dropped 9502 * completely, but that is a massive amount of work and will break current 9503 * installs (therefore is on-hold until v2). 9504 */ 9505 9506 /** 9507 * Initialisation options that can be given to DataTables at initialisation 9508 * time. 9509 * @namespace 9510 */ 9511 DataTable.defaults = { 9512 /** 9513 * An array of data to use for the table, passed in at initialisation which 9514 * will be used in preference to any data which is already in the DOM. This is 9515 * particularly useful for constructing tables purely in Javascript, for 9516 * example with a custom Ajax call. 9517 * @type array 9518 * @default null 9519 * 9520 * @dtopt Option 9521 * @name DataTable.defaults.data 9522 * 9523 * @example 9524 * // Using a 2D array data source 9525 * $(document).ready( function () { 9526 * $('#example').dataTable( { 9527 * "data": [ 9528 * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'], 9529 * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'], 9530 * ], 9531 * "columns": [ 9532 * { "title": "Engine" }, 9533 * { "title": "Browser" }, 9534 * { "title": "Platform" }, 9535 * { "title": "Version" }, 9536 * { "title": "Grade" } 9537 * ] 9538 * } ); 9539 * } ); 9540 * 9541 * @example 9542 * // Using an array of objects as a data source (`data`) 9543 * $(document).ready( function () { 9544 * $('#example').dataTable( { 9545 * "data": [ 9546 * {
9547 * "engine": "Trident", 9548 * "browser": "Internet Explorer 4.0", 9549 * "platform": "Win 95+", 9550 * "version": 4, 9551 * "grade": "X" 9552 * }, 9553 * { 9554 * "engine": "Trident", 9555 * "browser": "Internet Explorer 5.0", 9556 * "platform": "Win 95+", 9557 * "version": 5, 9558 * "grade": "C" 9559 * } 9560 * ], 9561 * "columns": [ 9562 * { "title": "Engine", "data": "engine" }, 9563 * { "title": "Browser", "data": "browser" }, 9564 * { "title": "Platform", "data": "platform" }, 9565 * { "title": "Version", "data": "version" }, 9566 * { "title": "Grade", "data": "grade" } 9567 * ] 9568 * } ); 9569 * } ); 9570 */ 9571 "aaData": null, 9572 9573 9574 /** 9575 * If ordering is enabled, then DataTables will perform a first pass sort on 9576 * initialisation. You can define which column(s) the sort is performed 9577 * upon, and the sorting direction, with this variable. The `sorting` array 9578 * should contain an array for each column to be sorted initially containing 9579 * the column's index and a direction string ('asc' or 'desc'). 9580 * @type array 9581 * @default [[0,'asc']] 9582 * 9583 * @dtopt Option 9584 * @name DataTable.defaults.order 9585 * 9586 * @example 9587 * // Sort by 3rd column first, and then 4th column 9588 * $(document).ready( function() { 9589 * $('#example').dataTable( { 9590 * "order": [[2,'asc'], [3,'desc']] 9591 * } ); 9592 * } ); 9593 * 9594 * // No initial sorting 9595 * $(document).ready( function() { 9596 * $('#example').dataTable( { 9597 * "order": [] 9598 * } ); 9599 * } ); 9600 */ 9601 "aaSorting": [[0,'asc']], 9602 9603 9604 /** 9605 * This parameter is basically identical to the `sorting` parameter, but 9606 * cannot be overridden by user interaction with the table. What this means 9607 * is that you could have a column (visible or hidden) which the sorting 9608 * will always be forced on first - any sorting after that (from the user) 9609 * will then be performed as required. This can be useful for grouping rows 9610 * together. 9611 * @type array 9612 * @default null 9613 * 9614 * @dtopt Option 9615 * @name DataTable.defaults.orderFixed 9616 * 9617 * @example 9618 * $(document).ready( function() { 9619 * $('#example').dataTable( { 9620 * "orderFixed": [[0,'asc']] 9621 * } ); 9622 * } ) 9623 */ 9624 "aaSortingFixed": [], 9625 9626 9627 /** 9628 * DataTables can be instructed to load data to display in the table from a 9629 * Ajax source. This option defines how that Ajax call is made and where to. 9630 * 9631 * The `ajax` property has three different modes of operation, depending on 9632 * how it is defined. These are: 9633 * 9634 * * `string` - Set the URL from where the data should be loaded from. 9635 * * `object` - Define properties for `jQuery.ajax`. 9636 * * `function` - Custom data get function 9637 * 9638 * `string` 9639 * -------- 9640 * 9641 * As a string, the `ajax` property simply defines the URL from which 9642 * DataTables will load data. 9643 * 9644 * `object` 9645 * -------- 9646 * 9647 * As an object, the parameters in the object are passed to 9648 * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control 9649 * of the Ajax request. DataTables has a number of default parameters which 9650 * you can override using this option. Please refer to the jQuery 9651 * documentation for a full description of the options available, although 9652 * the following parameters provide additional options in DataTables or 9653 * require special consideration: 9654 * 9655 * * `data` - As with jQuery, `data` can be provided as an object, but it 9656 * can also be used as a function to manipulate the data DataTables sends 9657 * to the server. The function takes a single parameter, an object of 9658 * parameters with the values that DataTables has readied for sending. An 9659 * object may be returned which will be merged into the DataTables 9660 * defaults, or you can add the items to the object that was passed in and 9661 * not return anything from the function. This supersedes `fnServerParams` 9662 * from DataTables 1.9-. 9663 * 9664 * * `dataSrc` - By default DataTables will look for the property `data` (or 9665 * `aaData` for compatibility with DataTables 1.9-) when obtaining data 9666 * from an Ajax source or for server-side processing - this parameter 9667 * allows that property to be changed. You can use Javascript dotted 9668 * object notation to get a data source for multiple levels of nesting, or 9669 * it my be used as a function. As a function it takes a single parameter, 9670 * the JSON returned from the server, which can be manipulated as 9671 * required, with the returned value being that used by DataTables as the 9672 * data source for the table. This supersedes `sAjaxDataProp` from 9673 * DataTables 1.9-. 9674 * 9675 * * `success` - Should not be overridden it is used internally in 9676 * DataTables. To manipulate / transform the data returned by the server 9677 * use `ajax.dataSrc`, or use `ajax` as a function (see below). 9678 * 9679 * `function` 9680 * ---------- 9681 * 9682 * As a function, making the Ajax call is left up to yourself allowing 9683 * complete control of the Ajax request. Indeed, if desired, a method other 9684 * than Ajax could be used to obtain the required data, such as Web storage 9685 * or an AIR database. 9686 * 9687 * The function is given four parameters and no return is required. The 9688 * parameters are: 9689 * 9690 * 1. _object_ - Data to send to the server 9691 * 2. _function_ - Callback function that must be executed when the required 9692 * data has been obtained. That data should be passed into the callback 9693 * as the only parameter 9694 * 3. _object_ - DataTables settings object for the table 9695 * 9696 * Note that this supersedes `fnServerData` from DataTables 1.9-. 9697 * 9698 * @type string|object|function 9699 * @default null 9700 * 9701 * @dtopt Option 9702 * @name DataTable.defaults.ajax
9703 * @since 1.10.0 9704 * 9705 * @example 9706 * // Get JSON data from a file via Ajax. 9707 * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default). 9708 * $('#example').dataTable( { 9709 * "ajax": "data.json" 9710 * } ); 9711 * 9712 * @example 9713 * // Get JSON data from a file via Ajax, using `dataSrc` to change 9714 * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`) 9715 * $('#example').dataTable( { 9716 * "ajax": { 9717 * "url": "data.json", 9718 * "dataSrc": "tableData" 9719 * } 9720 * } ); 9721 * 9722 * @example 9723 * // Get JSON data from a file via Ajax, using `dataSrc` to read data 9724 * // from a plain array rather than an array in an object 9725 * $('#example').dataTable( { 9726 * "ajax": { 9727 * "url": "data.json", 9728 * "dataSrc": "" 9729 * } 9730 * } ); 9731 * 9732 * @example 9733 * // Manipulate the data returned from the server - add a link to data 9734 * // (note this can, should, be done using `render` for the column - this 9735 * // is just a simple example of how the data can be manipulated). 9736 * $('#example').dataTable( { 9737 * "ajax": { 9738 * "url": "data.json", 9739 * "dataSrc": function ( json ) { 9740 * for ( var i=0, ien=json.length ; i<ien ; i++ ) { 9741 * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>'; 9742 * } 9743 * return json; 9744 * } 9745 * } 9746 * } ); 9747 * 9748 * @example 9749 * // Add data to the request 9750 * $('#example').dataTable( { 9751 * "ajax": { 9752 * "url": "data.json", 9753 * "data": function ( d ) { 9754 * return { 9755 * "extra_search": $('#extra').val() 9756 * }; 9757 * } 9758 * } 9759 * } ); 9760 * 9761 * @example 9762 * // Send request as POST 9763 * $('#example').dataTable( { 9764 * "ajax": { 9765 * "url": "data.json", 9766 * "type": "POST" 9767 * } 9768 * } ); 9769 * 9770 * @example 9771 * // Get the data from localStorage (could interface with a form for 9772 * // adding, editing and removing rows). 9773 * $('#example').dataTable( { 9774 * "ajax": function (data, callback, settings) { 9775 * callback( 9776 * JSON.parse( localStorage.getItem('dataTablesData') ) 9777 * ); 9778 * } 9779 * } ); 9780 */ 9781 "ajax": null, 9782 9783 9784 /** 9785 * This parameter allows you to readily specify the entries in the length drop 9786 * down menu that DataTables shows when pagination is enabled. It can be 9787 * either a 1D array of options which will be used for both the displayed 9788 * option and the value, or a 2D array which will use the array in the first 9789 * position as the value, and the array in the second position as the 9790 * displayed options (useful for language strings such as 'All'). 9791 * 9792 * Note that the `pageLength` property will be automatically set to the 9793 * first value given in this array, unless `pageLength` is also provided. 9794 * @type array 9795 * @default [ 10, 25, 50, 100 ] 9796 * 9797 * @dtopt Option 9798 * @name DataTable.defaults.lengthMenu 9799 * 9800 * @example 9801 * $(document).ready( function() { 9802 * $('#example').dataTable( { 9803 * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]] 9804 * } ); 9805 * } ); 9806 */ 9807 "aLengthMenu": [ 10, 25, 50, 100 ], 9808 9809 9810 /** 9811 * The `columns` option in the initialisation parameter allows you to define 9812 * details about the way individual columns behave. For a full list of 9813 * column options that can be set, please see 9814 * {@link DataTable.defaults.column}. Note that if you use `columns` to 9815 * define your columns, you must have an entry in the array for every single 9816 * column that you have in your table (these can be null if you don't which 9817 * to specify any options). 9818 * @member 9819 * 9820 * @name DataTable.defaults.column 9821 */ 9822 "aoColumns": null, 9823 9824 /** 9825 * Very similar to `columns`, `columnDefs` allows you to target a specific 9826 * column, multiple columns, or all columns, using the `targets` property of 9827 * each object in the array. This allows great flexibility when creating 9828 * tables, as the `columnDefs` arrays can be of any length, targeting the 9829 * columns you specifically want. `columnDefs` may use any of the column 9830 * options available: {@link DataTable.defaults.column}, but it _must_ 9831 * have `targets` defined in each object in the array. Values in the `targets` 9832 * array may be: 9833 * <ul> 9834 * <li>
9834a string - class name will be matched on the TH for the column</li> 9835 * <li>0 or a positive integer - column index counting from the left</li> 9836 * <li>a negative integer - column index counting from the right</li> 9837 * <li>the string "_all" - all columns (i.e. assign a default)</li> 9838 * </ul> 9839 * @member 9840 * 9841 * @name DataTable.defaults.columnDefs 9842 */ 9843 "aoColumnDefs": null, 9844 9845 9846 /** 9847 * Basically the same as `search`, this parameter defines the individual column 9848 * filtering state at initialisation time. The array must be of the same size 9849 * as the number of columns, and each element be an object with the parameters 9850 * `search` and `escapeRegex` (the latter is optional). 'null' is also 9851 * accepted and the default will be used. 9852 * @type array 9853 * @default [] 9854 * 9855 * @dtopt Option 9856 * @name DataTable.defaults.searchCols 9857 * 9858 * @example 9859 * $(document).ready( function() { 9860 * $('#example').dataTable( { 9861 * "searchCols": [ 9862 * null, 9863 * { "search": "My filter" }, 9864 * null, 9865 * { "search": "^[0-9]", "escapeRegex": false } 9866 * ] 9867 * } ); 9868 * } ) 9869 */ 9870 "aoSearchCols": [], 9871 9872 9873 /** 9874 * An array of CSS classes that should be applied to displayed rows. This 9875 * array may be of any length, and DataTables will apply each class 9876 * sequentially, looping when required. 9877 * @type array 9878 * @default null <i>
9878Will take the values determined by the `oClasses.stripe*` 9879 * options</i> 9880 * 9881 * @dtopt Option 9882 * @name DataTable.defaults.stripeClasses 9883 * 9884 * @example 9885 * $(document).ready( function() { 9886 * $('#example').dataTable( { 9887 * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ] 9888 * } ); 9889 * } ) 9890 */ 9891 "asStripeClasses": null, 9892 9893 9894 /** 9895 * Enable or disable automatic column width calculation. This can be disabled 9896 * as an optimisation (it takes some time to calculate the widths) if the 9897 * tables widths are passed in using `columns`. 9898 * @type boolean 9899 * @default true 9900 * 9901 * @dtopt Features 9902 * @name DataTable.defaults.autoWidth 9903 * 9904 * @example 9905 * $(document).ready( function () { 9906 * $('#example').dataTable( { 9907 * "autoWidth": false 9908 * } ); 9909 * } ); 9910 */ 9911 "bAutoWidth": true, 9912 9913 9914 /** 9915 * Deferred rendering can provide DataTables with a huge speed boost when you 9916 * are using an Ajax or JS data source for the table. This option, when set to 9917 * true, will cause DataTables to defer the creation of the table elements for 9918 * each row until they are needed for a draw - saving a significant amount of 9919 * time. 9920 * @type boolean 9921 * @default false 9922 * 9923 * @dtopt Features 9924 * @name DataTable.defaults.deferRender 9925 * 9926 * @example 9927 * $(document).ready( function() { 9928 * $('#example').dataTable( { 9929 * "ajax": "sources/arrays.txt", 9930 * "deferRender": true 9931 * } ); 9932 * } ); 9933 */ 9934 "bDeferRender": false, 9935 9936 9937 /** 9938 * Replace a DataTable which matches the given selector and replace it with 9939 * one which has the properties of the new initialisation object passed. If no 9940 * table matches the selector, then the new DataTable will be constructed as 9941 * per normal. 9942 * @type boolean 9943 * @default false 9944 * 9945 * @dtopt Options 9946 * @name DataTable.defaults.destroy 9947 * 9948 * @example 9949 * $(document).ready( function() { 9950 * $('#example').dataTable( { 9951 * "srollY": "200px", 9952 * "paginate": false 9953 * } ); 9954 * 9955 * // Some time later.... 9956 * $('#example').dataTable( { 9957 * "filter": false, 9958 * "destroy": true 9959 * } ); 9960 * } ); 9961 */ 9962 "bDestroy": false, 9963 9964 9965 /** 9966 * Enable or disable filtering of data. Filtering in DataTables is "smart" in 9967 * that it allows the end user to input multiple words (space separated) and 9968 * will match a row containing those words, even if not in the order that was 9969 * specified (this allow matching across multiple columns). Note that if you 9970 * wish to use filtering in DataTables this must remain 'true' - to remove the 9971 * default filtering input box and retain filtering abilities, please use 9972 * {@link DataTable.defaults.dom}. 9973 * @type boolean 9974 * @default true 9975 * 9976 * @dtopt Features 9977 * @name DataTable.defaults.searching 9978 * 9979 * @example 9980 * $(document).ready( function () { 9981 * $('#example').dataTable( { 9982 * "searching": false 9983 * } ); 9984 * } ); 9985 */ 9986 "bFilter": true, 9987 9988 9989 /** 9990 * Enable or disable the table information display. This shows information 9991 * about the data that is currently visible on the page, including information 9992 * about filtered data if that action is being performed. 9993 * @type boolean 9994 * @default true 9995 * 9996 * @dtopt Features 9997 * @name DataTable.defaults.info 9998 * 9999 * @example 10000 * $(document).ready( function () { 10001 * $('#example').dataTable( { 10002 * "info": false 10003 * } ); 10004 * } ); 10005 */ 10006 "bInfo": true, 10007 10008 10009 /** 10010 * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some 10011 * slightly different and additional mark-up from what DataTables has 10012 * traditionally used). 10013 * @type boolean 10014 * @default false 10015 * 10016 * @dtopt Features 10017 * @name DataTable.defaults.jQueryUI 10018 * 10019 * @example 10020 * $(document).ready( function() { 10021 * $('#example').dataTable( { 10022 * "jQueryUI": true 10023 * } ); 10024 * } ); 10025 */ 10026 "bJQueryUI": false, 10027 10028 10029 /** 10030 * Allows the end user to select the size of a formatted page from a select 10031 * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`). 10032 * @type boolean 10033 * @default true 10034 * 10035 * @dtopt Features 10036 * @name DataTable.defaults.lengthChange 10037 * 10038 * @example 10039 * $(document).ready( function () { 10040 * $('#example').dataTable( { 10041 * "lengthChange": false 10042 * } ); 10043 * } ); 10044 */ 10045 "bLengthChange": true, 10046 10047 10048 /** 10049 * Enable or disable pagination. 10050 * @type boolean 10051 * @default true 10052 * 10053 * @dtopt Features 10054 * @name DataTable.defaults.paging 10055 * 10056 * @example 10057 * $(document).ready( function () { 10058 * $('#example').dataTable( { 10059 * "paging": false 10060 * } ); 10061 * } ); 10062 */ 10063 "bPaginate": true, 10064 10065 10066 /** 10067 * Enable or disable the display of a 'processing' indicator when the table is 10068 * being processed (e.g. a sort). This is particularly useful for tables with 10069 * large amounts of data where it can take a noticeable amount of time to sort 10070 * the entries. 10071 * @type boolean 10072 * @default false 10073 * 10074 * @dtopt Features 10075 * @name DataTable.defaults.processing 10076 * 10077 * @example 10078 * $(document).ready( function () { 10079 * $('#example').dataTable( { 10080 * "processing": true 10081 * } ); 10082 * } ); 10083 */ 10084 "bProcessing": false, 10085 10086 10087 /** 10088 * Retrieve the DataTables object for the given selector. Note that if the 10089 * table has already been initialised, this parameter will cause DataTables 10090 * to simply return the object that has already been set up - it will not take 10091 * account of any changes you might have made to the initialisation object 10092 * passed to DataTables (setting this parameter to true is an acknowledgement 10093 * that you understand this). `destroy` can be used to reinitialise a table if 10094 * you need. 10095 * @type boolean 10096 * @default false 10097 * 10098 * @dtopt Options 10099 * @name DataTable.defaults.retrieve 10100 * 10101 * @example 10102 * $(document).ready( function() { 10103 * initTable(); 10104 * tableActions(); 10105 * } ); 10106 * 10107 * function initTable () 10108 * { 10109 * return $('#example').dataTable( { 10110 * "scrollY": "200px", 10111 * "paginate": false, 10112 * "retrieve": true 10113 * } ); 10114 * } 10115 * 10116 * function tableActions () 10117 * { 10118 * var table = initTable(); 10119 * // perform API operations with oTable 10120 * } 10121 */ 10122 "bRetrieve": false, 10123 10124 10125 /** 10126 * When vertical (y) scrolling is enabled, DataTables will force the height of
10127 * the table's viewport to the given height at all times (useful for layout). 10128 * However, this can look odd when filtering data down to a small data set, 10129 * and the footer is left "floating" further down. This parameter (when 10130 * enabled) will cause DataTables to collapse the table's viewport down when 10131 * the result set will fit within the given Y height. 10132 * @type boolean 10133 * @default false 10134 * 10135 * @dtopt Options 10136 * @name DataTable.defaults.scrollCollapse 10137 * 10138 * @example 10139 * $(document).ready( function() { 10140 * $('#example').dataTable( { 10141 * "scrollY": "200", 10142 * "scrollCollapse": true 10143 * } ); 10144 * } ); 10145 */ 10146 "bScrollCollapse": false, 10147 10148 10149 /** 10150 * Configure DataTables to use server-side processing. Note that the 10151 * `ajax` parameter must also be given in order to give DataTables a 10152 * source to obtain the required data for each draw. 10153 * @type boolean 10154 * @default false 10155 * 10156 * @dtopt Features 10157 * @dtopt Server-side 10158 * @name DataTable.defaults.serverSide 10159 * 10160 * @example 10161 * $(document).ready( function () { 10162 * $('#example').dataTable( { 10163 * "serverSide": true, 10164 * "ajax": "xhr.php" 10165 * } ); 10166 * } ); 10167 */ 10168 "bServerSide": false, 10169 10170 10171 /** 10172 * Enable or disable sorting of columns. Sorting of individual columns can be 10173 * disabled by the `sortable` option for each column. 10174 * @type boolean 10175 * @default true 10176 * 10177 * @dtopt Features 10178 * @name DataTable.defaults.ordering 10179 * 10180 * @example 10181 * $(document).ready( function () { 10182 * $('#example').dataTable( { 10183 * "ordering": false 10184 * } ); 10185 * } ); 10186 */ 10187 "bSort": true, 10188 10189 10190 /** 10191 * Enable or display DataTables' ability to sort multiple columns at the 10192 * same time (activated by shift-click by the user). 10193 * @type boolean 10194 * @default true 10195 * 10196 * @dtopt Options 10197 * @name DataTable.defaults.orderMulti 10198 * 10199 * @example 10200 * // Disable multiple column sorting ability 10201 * $(document).ready( function () { 10202 * $('#example').dataTable( { 10203 * "orderMulti": false 10204 * } ); 10205 * } ); 10206 */ 10207 "bSortMulti": true, 10208 10209 10210 /** 10211 * Allows control over whether DataTables should use the top (true) unique 10212 * cell that is found for a single column, or the bottom (false - default). 10213 * This is useful when using complex headers. 10214 * @type boolean 10215 * @default false 10216 * 10217 * @dtopt Options 10218 * @name DataTable.defaults.orderCellsTop 10219 * 10220 * @example 10221 * $(document).ready( function() { 10222 * $('#example').dataTable( { 10223 * "orderCellsTop": true 10224 * } ); 10225 * } ); 10226 */ 10227 "bSortCellsTop": false, 10228 10229 10230 /** 10231 * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and 10232 * `sorting\_3` to the columns which are currently being sorted on. This is 10233 * presented as a feature switch as it can increase processing time (while 10234 * classes are removed and added) so for large data sets you might want to 10235 * turn this off. 10236 * @type boolean 10237 * @default true 10238 * 10239 * @dtopt Features 10240 * @name DataTable.defaults.orderClasses 10241 * 10242 * @example 10243 * $(document).ready( function () { 10244 * $('#example').dataTable( { 10245 * "orderClasses": false 10246 * } ); 10247 * } ); 10248 */ 10249 "bSortClasses": true, 10250 10251 10252 /** 10253 * Enable or disable state saving. When enabled HTML5 `localStorage` will be 10254 * used to save table display information such as pagination information, 10255 * display length, filtering and sorting. As such when the end user reloads 10256 * the page the display display will match what thy had previously set up. 10257 * 10258 * Due to the use of `localStorage` the default state saving is not supported 10259 * in IE6 or 7. If state saving is required in those browsers, use 10260 * `stateSaveCallback` to provide a storage solution such as cookies. 10261 * @type boolean 10262 * @default false 10263 * 10264 * @dtopt Features 10265 * @name DataTable.defaults.stateSave 10266 * 10267 * @example 10268 * $(document).ready( function () { 10269 * $('#example').dataTable( { 10270 * "stateSave": true 10271 * } ); 10272 * } ); 10273 */ 10274 "bStateSave": false, 10275 10276 10277 /** 10278 * This function is called when a TR element is created (and all TD child 10279 * elements have been inserted), or registered if using a DOM source, allowing 10280 * manipulation of the TR element (adding classes etc). 10281 * @type function 10282 * @param {node} row "TR" element for the current row 10283 * @param {array} data Raw data array for this row 10284 * @param {int} dataIndex The index of this row in the internal aoData array 10285 * 10286 * @dtopt Callbacks 10287 * @name DataTable.defaults.createdRow 10288 * 10289 * @example 10290 * $(document).ready( function() { 10291 * $('#example').dataTable( { 10292 * "createdRow": function( row, data, dataIndex ) { 10293 * // Bold the grade for all 'A' grade browsers 10294 * if ( data[4] == "A" ) 10295 * { 10296 * $('td:eq(4)', row).html( '<b>A</b>' ); 10297 * } 10298 * } 10299 * } ); 10300 * } ); 10301 */ 10302 "fnCreatedRow": null, 10303 10304 10305 /** 10306 * This function is called on every 'draw' event, and allows you to 10307 * dynamically modify any aspect you want about the created DOM. 10308 * @type function 10309 * @param {object} settings DataTables settings object 10310 * 10311 * @dtopt Callbacks 10312 * @name DataTable.defaults.drawCallback 10313 * 10314 * @example 10315 * $(document).ready( function() { 10316 * $('#example').dataTable( { 10317 * "drawCallback": function( settings ) { 10318 * alert( 'DataTables has redrawn the table' ); 10319 * } 10320 * } ); 10321 * } ); 10322 */ 10323 "fnDrawCallback": null, 10324 10325 10326 /** 10327 * Identical to fnHeaderCallback() but for the table footer this function 10328 * allows you to modify the table footer on every 'draw' event. 10329 * @type function 10330 * @param {node} foot "TR" element for the footer 10331 * @param {array} data Full table data (as derived from the original HTML) 10332 * @param {int} start Index for the current display starting point in the 10333 * display array 10334 * @param {int} end Index for the current display ending point in the 10335 * display array 10336 * @param {array int} display Index array to translate the visual position 10337 * to the full data array 10338 * 10339 * @dtopt Callbacks 10340 * @name DataTable.defaults.footerCallback 10341 * 10342 * @example 10343 * $(document).ready( function() { 10344 * $('#example').dataTable( { 10345 * "footerCallback": function( tfoot, data, start, end, display ) { 10346 * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start; 10347 * } 10348 * } ); 10349 * } ) 10350 */ 10351 "fnFooterCallback": null, 10352 10353 10354 /** 10355 * When rendering large numbers in the information element for the table 10356 * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers 10357 * to have a comma separator for the 'thousands' units (e.g. 1 million is 10358 * rendered as "1,000,000") to help readability for the end user. This 10359 * function will override the default method DataTables uses. 10360 * @type function 10361 * @member 10362 * @param {int} toFormat number to be formatted 10363 * @returns {string} formatted string for DataTables to show the number 10364 * 10365 * @dtopt Callbacks 10366 * @name DataTable.defaults.formatNumber 10367 * 10368 * @example 10369 * // Format a number using a single quote for the separator (note that
10370 * // this can also be done with the language.thousands option) 10371 * $(document).ready( function() { 10372 * $('#example').dataTable( { 10373 * "formatNumber": function ( toFormat ) { 10374 * return toFormat.toString().replace( 10375 * /\B(?=(\d{3})+(?!\d))/g, "'" 10376 * ); 10377 * }; 10378 * } ); 10379 * } ); 10380 */ 10381 "fnFormatNumber": function ( toFormat ) { 10382 return toFormat.toString().replace( 10383 /\B(?=(\d{3})+(?!\d))/g, 10384 this.oLanguage.sThousands 10385 ); 10386 }, 10387 10388 10389 /** 10390 * This function is called on every 'draw' event, and allows you to 10391 * dynamically modify the header row. This can be used to calculate and 10392 * display useful information about the table. 10393 * @type function 10394 * @param {node} head "TR" element for the header 10395 * @param {array} data Full table data (as derived from the original HTML) 10396 * @param {int} start Index for the current display starting point in the 10397 * display array 10398 * @param {int} end Index for the current display ending point in the 10399 * display array 10400 * @param {array int} display Index array to translate the visual position 10401 * to the full data array 10402 * 10403 * @dtopt Callbacks 10404 * @name DataTable.defaults.headerCallback 10405 * 10406 * @example 10407 * $(document).ready( function() { 10408 * $('#example').dataTable( { 10409 * "fheaderCallback": function( head, data, start, end, display ) { 10410 * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records"; 10411 * } 10412 * } ); 10413 * } ) 10414 */ 10415 "fnHeaderCallback": null, 10416 10417 10418 /** 10419 * The information element can be used to convey information about the current 10420 * state of the table. Although the internationalisation options presented by 10421 * DataTables are quite capable of dealing with most customisations, there may 10422 * be times where you wish to customise the string further. This callback 10423 * allows you to do exactly that. 10424 * @type function 10425 * @param {object} oSettings DataTables settings object 10426 * @param {int} start Starting position in data for the draw 10427 * @param {int} end End position in data for the draw 10428 * @param {int} max Total number of rows in the table (regardless of 10429 * filtering) 10430 * @param {int} total Total number of rows in the data set, after filtering 10431 * @param {string} pre The string that DataTables has formatted using it's 10432 * own rules 10433 * @returns {string} The string to be displayed in the information element. 10434 * 10435 * @dtopt Callbacks 10436 * @name DataTable.defaults.infoCallback 10437 * 10438 * @example 10439 * $('#example').dataTable( { 10440 * "infoCallback": function( settings, start, end, max, total, pre ) { 10441 * return start +" to "+ end; 10442 * } 10443 * } ); 10444 */ 10445 "fnInfoCallback": null, 10446 10447 10448 /** 10449 * Called when the table has been initialised. Normally DataTables will 10450 * initialise sequentially and there will be no need for this function, 10451 * however, this does not hold true when using external language information 10452 * since that is obtained using an async XHR call. 10453 * @type function 10454 * @param {object} settings DataTables settings object 10455 * @param {object} json The JSON object request from the server - only 10456 * present if client-side Ajax sourced data is used 10457 * 10458 * @dtopt Callbacks 10459 * @name DataTable.defaults.initComplete 10460 * 10461 * @example 10462 * $(document).ready( function() { 10463 * $('#example').dataTable( { 10464 * "initComplete": function(settings, json) { 10465 * alert( 'DataTables has finished its initialisation.' ); 10466 * } 10467 * } ); 10468 * } ) 10469 */ 10470 "fnInitComplete": null, 10471 10472 10473 /** 10474 * Called at the very start of each table draw and can be used to cancel the 10475 * draw by returning false, any other return (including undefined) results in 10476 * the full draw occurring). 10477 * @type function 10478 * @param {object} settings DataTables settings object 10479 * @returns {boolean} False will cancel the draw, anything else (including no 10480 * return) will allow it to complete. 10481 * 10482 * @dtopt Callbacks 10483 * @name DataTable.defaults.preDrawCallback 10484 * 10485 * @example 10486 * $(document).ready( function() { 10487 * $('#example').dataTable( { 10488 * "preDrawCallback": function( settings ) { 10489 * if ( $('#test').val() == 1 ) { 10490 * return false;
10491 * } 10492 * } 10493 * } ); 10494 * } ); 10495 */ 10496 "fnPreDrawCallback": null, 10497 10498 10499 /** 10500 * This function allows you to 'post process' each row after it have been 10501 * generated for each table draw, but before it is rendered on screen. This 10502 * function might be used for setting the row class name etc. 10503 * @type function 10504 * @param {node} row "TR" element for the current row 10505 * @param {array} data Raw data array for this row 10506 * @param {int} displayIndex The display index for the current table draw 10507 * @param {int} displayIndexFull The index of the data in the full list of 10508 * rows (after filtering) 10509 * 10510 * @dtopt Callbacks 10511 * @name DataTable.defaults.rowCallback 10512 * 10513 * @example 10514 * $(document).ready( function() { 10515 * $('#example').dataTable( { 10516 * "rowCallback": function( row, data, displayIndex, displayIndexFull ) { 10517 * // Bold the grade for all 'A' grade browsers 10518 * if ( data[4] == "A" ) { 10519 * $('td:eq(4)', row).html( '<b>A</b>' ); 10520 * } 10521 * } 10522 * } ); 10523 * } ); 10524 */ 10525 "fnRowCallback": null, 10526 10527 10528 /** 10529 * __Deprecated__ The functionality provided by this parameter has now been 10530 * superseded by that provided through `ajax`, which should be used instead. 10531 * 10532 * This parameter allows you to override the default function which obtains 10533 * the data from the server so something more suitable for your application. 10534 * For example you could use POST data, or pull information from a Gears or 10535 * AIR database. 10536 * @type function 10537 * @member 10538 * @param {string} source HTTP source to obtain the data from (`ajax`) 10539 * @param {array} data A key/value pair object containing the data to send 10540 * to the server 10541 * @param {function} callback to be called on completion of the data get 10542 * process that will draw the data on the page. 10543 * @param {object} settings DataTables settings object 10544 * 10545 * @dtopt Callbacks 10546 * @dtopt Server-side 10547 * @name DataTable.defaults.serverData 10548 * 10549 * @deprecated 1.10. Please use `ajax` for this functionality now. 10550 */ 10551 "fnServerData": null, 10552 10553 10554 /** 10555 * __Deprecated__ The functionality provided by this parameter has now been 10556 * superseded by that provided through `ajax`, which should be used instead. 10557 * 10558 * It is often useful to send extra data to the server when making an Ajax 10559 * request - for example custom filtering information, and this callback 10560 * function makes it trivial to send extra information to the server. The 10561 * passed in parameter is the data set that has been constructed by 10562 * DataTables, and you can add to this or modify it as you require. 10563 * @type function 10564 * @param {array} data Data array (array of objects which are name/value 10565 * pairs) that has been constructed by DataTables and will be sent to the 10566 * server. In the case of Ajax sourced data with server-side processing 10567 * this will be an empty array, for server-side processing there will be a 10568 * significant number of parameters! 10569 * @returns {undefined} Ensure that you modify the data array passed in, 10570 * as this is passed by reference. 10571 * 10572 * @dtopt Callbacks 10573 * @dtopt Server-side 10574 * @name DataTable.defaults.serverParams 10575 * 10576 * @deprecated 1.10. Please use `ajax` for this functionality now. 10577 */ 10578 "fnServerParams": null, 10579 10580 10581 /** 10582 * Load the table state. With this function you can define from where, and how, the 10583 * state of a table is loaded. By default DataTables will load from `localStorage` 10584 * but you might wish to use a server-side database or cookies. 10585 * @type function 10586 * @member 10587 * @param {object} settings DataTables settings object 10588 * @return {object} The DataTables state object to be loaded 10589 * 10590 * @dtopt Callbacks 10591 * @name DataTable.defaults.stateLoadCallback 10592 * 10593 * @example 10594 * $(document).ready( function() { 10595 * $('#example').dataTable( { 10596 * "stateSave": true, 10597 * "stateLoadCallback": function (settings) { 10598 * var o; 10599 * 10600 * // Send an Ajax request to the server to get the data. Note that 10601 * // this is a synchronous request. 10602 * $.ajax( { 10603 * "url": "/state_load", 10604 * "async": false, 10605 * "dataType": "json", 10606 * "success": function (json) { 10607 * o = json; 10608 * } 10609 * } ); 10610 * 10611 * return o; 10612 * } 10613 * } ); 10614 * } ); 10615 */ 10616 "fnStateLoadCallback": function ( settings ) { 10617 try { 10618 return JSON.parse(
10619 (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem( 10620 'DataTables_'+settings.sInstance+'_'+location.pathname 10621 ) 10622 ); 10623 } catch (e) {} 10624 }, 10625 10626 10627 /** 10628 * Callback which allows modification of the saved state prior to loading that state. 10629 * This callback is called when the table is loading state from the stored data, but 10630 * prior to the settings object being modified by the saved state. Note that for 10631 * plug-in authors, you should use the `stateLoadParams` event to load parameters for 10632 * a plug-in. 10633 * @type function 10634 * @param {object} settings DataTables settings object 10635 * @param {object} data The state object that is to be loaded 10636 * 10637 * @dtopt Callbacks 10638 * @name DataTable.defaults.stateLoadParams 10639 * 10640 * @example 10641 * // Remove a saved filter, so filtering is never loaded 10642 * $(document).ready( function() { 10643 * $('#example').dataTable( { 10644 * "stateSave": true, 10645 * "stateLoadParams": function (settings, data) { 10646 * data.oSearch.sSearch = ""; 10647 * } 10648 * } ); 10649 * } ); 10650 * 10651 * @example 10652 * // Disallow state loading by returning false 10653 * $(document).ready( function() { 10654 * $('#example').dataTable( { 10655 * "stateSave": true, 10656 * "stateLoadParams": function (settings, data) { 10657 * return false; 10658 * } 10659 * } ); 10660 * } ); 10661 */ 10662 "fnStateLoadParams": null, 10663 10664 10665 /** 10666 * Callback that is called when the state has been loaded from the state saving method 10667 * and the DataTables settings object has been modified as a result of the loaded state. 10668 * @type function 10669 * @param {object} settings DataTables settings object 10670 * @param {object} data The state object that was loaded 10671 * 10672 * @dtopt Callbacks 10673 * @name DataTable.defaults.stateLoaded 10674 * 10675 * @example 10676 * // Show an alert with the filtering value that was saved 10677 * $(document).ready( function() { 10678 * $('#example').dataTable( { 10679 * "stateSave": true, 10680 * "stateLoaded": function (settings, data) { 10681 * alert( 'Saved filter was: '+data.oSearch.sSearch ); 10682 * } 10683 * } ); 10684 * } ); 10685 */ 10686 "fnStateLoaded": null, 10687 10688 10689 /** 10690 * Save the table state. This function allows you to define where and how the state 10691 * information for the table is stored By default DataTables will use `localStorage` 10692 * but you might wish to use a server-side database or cookies. 10693 * @type function 10694 * @member 10695 * @param {object} settings DataTables settings object 10696 * @param {object} data The state object to be saved 10697 * 10698 * @dtopt Callbacks 10699 * @name DataTable.defaults.stateSaveCallback 10700 * 10701 * @example 10702 * $(document).ready( function() { 10703 * $('#example').dataTable( { 10704 * "stateSave": true, 10705 * "stateSaveCallback": function (settings, data) { 10706 * // Send an Ajax request to the server with the state object 10707 * $.ajax( { 10708 * "url": "/state_save", 10709 * "data": data, 10710 * "dataType": "json", 10711 * "method": "POST" 10712 * "success": function () {} 10713 * } ); 10714 * } 10715 * } ); 10716 * } ); 10717 */ 10718 "fnStateSaveCallback": function ( settings, data ) { 10719 try { 10720 (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem( 10721 'DataTables_'+settings.sInstance+'_'+location.pathname, 10722 JSON.stringify( data ) 10723 ); 10724 } catch (e) {} 10725 }, 10726 10727 10728 /** 10729 * Callback which allows modification of the state to be saved. Called when the table 10730 * has changed state a new state save is required. This method allows modification of 10731 * the state saving object prior to actually doing the save, including addition or 10732 * other state properties or modification. Note that for plug-in authors, you should 10733 * use the `stateSaveParams` event to save parameters for a plug-in. 10734 * @type function 10735 * @param {object} settings DataTables settings object 10736 * @param {object} data The state object to be saved 10737 * 10738 * @dtopt Callbacks 10739 * @name DataTable.defaults.stateSaveParams 10740 * 10741 * @example 10742 * // Remove a saved filter, so filtering is never saved 10743 * $(document).ready( function() { 10744 * $('#example').dataTable( { 10745 * "stateSave": true, 10746 * "stateSaveParams": function (settings, data) { 10747 * data.oSearch.sSearch = ""; 10748 * } 10749 * } ); 10750 * } ); 10751 */ 10752 "fnStateSaveParams": null, 10753 10754 10755 /** 10756 * Duration for which the saved state information is considered valid. After this period 10757 * has elapsed the state will be returned to the default. 10758 * Value is given in seconds. 10759 * @type int 10760 * @default 7200 <i>(2 hours)</i> 10761 * 10762 * @dtopt Options 10763 * @name DataTable.defaults.stateDuration 10764 * 10765 * @example 10766 * $(document).ready( function() { 10767 * $('#example').dataTable( { 10768 * "stateDuration": 60*60*24; // 1 day 10769 * } ); 10770 * } ) 10771 */ 10772 "iStateDuration": 7200, 10773 10774 10775 /** 10776 * When enabled DataTables will not make a request to the server for the first 10777 * page draw - rather it will use the data already on the page (no sorting etc 10778 * will be applied to it), thus saving on an XHR at load time. `deferLoading` 10779 * is used to indicate that deferred loading is required, but it is also used
10780 * to tell DataTables how many records there are in the full table (allowing 10781 * the information element and pagination to be displayed correctly). In the case 10782 * where a filtering is applied to the table on initial load, this can be 10783 * indicated by giving the parameter as an array, where the first element is 10784 * the number of records available after filtering and the second element is the 10785 * number of records without filtering (allowing the table information element 10786 * to be shown correctly). 10787 * @type int | array 10788 * @default null 10789 * 10790 * @dtopt Options 10791 * @name DataTable.defaults.deferLoading 10792 * 10793 * @example 10794 * // 57 records available in the table, no filtering applied 10795 * $(document).ready( function() { 10796 * $('#example').dataTable( { 10797 * "serverSide": true, 10798 * "ajax": "scripts/server_processing.php", 10799 * "deferLoading": 57 10800 * } ); 10801 * } ); 10802 * 10803 * @example 10804 * // 57 records after filtering, 100 without filtering (an initial filter applied) 10805 * $(document).ready( function() { 10806 * $('#example').dataTable( { 10807 * "serverSide": true, 10808 * "ajax": "scripts/server_processing.php", 10809 * "deferLoading": [ 57, 100 ], 10810 * "search": { 10811 * "search": "my_filter" 10812 * } 10813 * } ); 10814 * } ); 10815 */ 10816 "iDeferLoading": null, 10817 10818 10819 /** 10820 * Number of rows to display on a single page when using pagination. If 10821 * feature enabled (`lengthChange`) then the end user will be able to override 10822 * this to a custom setting using a pop-up menu. 10823 * @type int 10824 * @default 10 10825 * 10826 * @dtopt Options 10827 * @name DataTable.defaults.pageLength 10828 * 10829 * @example 10830 * $(document).ready( function() { 10831 * $('#example').dataTable( { 10832 * "pageLength": 50 10833 * } ); 10834 * } ) 10835 */ 10836 "iDisplayLength": 10, 10837 10838 10839 /** 10840 * Define the starting point for data display when using DataTables with 10841 * pagination. Note that this parameter is the number of records, rather than 10842 * the page number, so if you have 10 records per page and want to start on 10843 * the third page, it should be "20". 10844 * @type int 10845 * @default 0 10846 * 10847 * @dtopt Options 10848 * @name DataTable.defaults.displayStart 10849 * 10850 * @example 10851 * $(document).ready( function() { 10852 * $('#example').dataTable( { 10853 * "displayStart": 20 10854 * } ); 10855 * } ) 10856 */ 10857 "iDisplayStart": 0, 10858 10859 10860 /** 10861 * By default DataTables allows keyboard navigation of the table (sorting, paging, 10862 * and filtering) by adding a `tabindex` attribute to the required elements. This 10863 * allows you to tab through the controls and press the enter key to activate them. 10864 * The tabindex is default 0, meaning that the tab follows the flow of the document. 10865 * You can overrule this using this parameter if you wish. Use a value of -1 to 10866 * disable built-in keyboard navigation. 10867 * @type int 10868 * @default 0 10869 * 10870 * @dtopt Options 10871 * @name DataTable.defaults.tabIndex 10872 * 10873 * @example 10874 * $(document).ready( function() { 10875 * $('#example').dataTable( { 10876 * "tabIndex": 1 10877 * } ); 10878 * } ); 10879 */ 10880 "iTabIndex": 0, 10881 10882 10883 /** 10884 * Classes that DataTables assigns to the various components and features 10885 * that it adds to the HTML table. This allows classes to be configured 10886 * during initialisation in addition to through the static 10887 * {@link DataTable.ext.oStdClasses} object). 10888 * @namespace 10889 * @name DataTable.defaults.classes 10890 */ 10891 "oClasses": {}, 10892 10893 10894 /** 10895 * All strings that DataTables uses in the user interface that it creates 10896 * are defined in this object, allowing you to modified them individually or 10897 * completely replace them all as required. 10898 * @namespace 10899 * @name DataTable.defaults.language 10900 */ 10901 "oLanguage": { 10902 /** 10903 * Strings that are used for WAI-ARIA labels and controls only (these are not 10904 * actually visible on the page, but will be read by screenreaders, and thus 10905 * must be internationalised as well). 10906 * @namespace 10907 * @name DataTable.defaults.language.aria 10908 */ 10909 "oAria": { 10910 /** 10911 * ARIA label that is added to the table headers when the column may be 10912 * sorted ascending by activing the column (click or return when focu
10912sed). 10913 * Note that the column header is prefixed to this string. 10914 * @type string 10915 * @default : activate to sort column ascending 10916 * 10917 * @dtopt Language 10918 * @name DataTable.defaults.language.aria.sortAscending 10919 * 10920 * @example 10921 * $(document).ready( function() { 10922 * $('#example').dataTable( { 10923 * "language": { 10924 * "aria": { 10925 * "sortAscending": " - click/return to sort ascending" 10926 * } 10927 * } 10928 * } ); 10929 * } ); 10930 */ 10931 "sSortAscending": ": activate to sort column ascending", 10932 10933 /** 10934 * ARIA label that is added to the table headers when the column may be 10935 * sorted descending by activing the column (click or return when focused). 10936 * Note that the column header is prefixed to this string. 10937 * @type string 10938 * @default : activate to sort column ascending 10939 * 10940 * @dtopt Language 10941 * @name DataTable.defaults.language.aria.sortDescending 10942 * 10943 * @example 10944 * $(document).ready( function() { 10945 * $('#example').dataTable( { 10946 * "language": { 10947 * "aria": { 10948 * "sortDescending": " - click/return to sort descending" 10949 * } 10950 * } 10951 * } ); 10952 * } ); 10953 */ 10954 "sSortDescending": ": activate to sort column descending" 10955 }, 10956 10957 /** 10958 * Pagination string used by DataTables for the built-in pagination 10959 * control types. 10960 * @namespace 10961 * @name DataTable.defaults.language.paginate 10962 */ 10963 "oPaginate": { 10964 /** 10965 * Text to use when using the 'full_numbers' type of pagination for the 10966 * button to take the user to the first page. 10967 * @type string 10968 * @default First 10969 * 10970 * @dtopt Language 10971 * @name DataTable.defaults.language.paginate.first 10972 * 10973 * @example 10974 * $(document).ready( function() { 10975 * $('#example').dataTable( { 10976 * "language": { 10977 * "paginate": { 10978 * "first": "First page" 10979 * } 10980 * } 10981 * } ); 10982 * } ); 10983 */ 10984 "sFirst": "First", 10985 10986 10987 /** 10988 * Text to use when using the 'full_numbers' type of pagination for the 10989 * button to take the user to the last page. 10990 * @type string 10991 * @default Last 10992 * 10993 * @dtopt Language 10994 * @name DataTable.defaults.language.paginate.last 10995 * 10996 * @example 10997 * $(document).ready( function() { 10998 * $('#example').dataTable( { 10999 * "language": { 11000 * "paginate": { 11001 * "last": "Last page" 11002 * } 11003 * } 11004 * } ); 11005 * } ); 11006 */ 11007 "sLast": "Last", 11008 11009 11010 /** 11011 * Text to use for the 'next' pagination button (to take the user to the 11012 * next page). 11013 * @type string 11014 * @default Next 11015 * 11016 * @dtopt Language 11017 * @name DataTable.defaults.language.paginate.next 11018 * 11019 * @example 11020 * $(document).ready( function() { 11021 * $('#example').dataTable( { 11022 * "language": { 11023 * "paginate": { 11024 * "next": "Next page" 11025 * } 11026 * } 11027 * } ); 11028 * } ); 11029 */ 11030 "sNext": "Next", 11031 11032 11033 /** 11034 * Text to use for the 'previous' pagination button (to take the user to 11035 * the previous page). 11036 * @type string 11037 * @default Previous 11038 * 11039 * @dtopt Language 11040 * @name DataTable.defaults.language.paginate.previous 11041 * 11042 * @example 11043 * $(document).ready( function() { 11044 * $('#example').dataTable( { 11045 * "language": { 11046 * "paginate": { 11047 * "previous": "Previous page" 11048 * } 11049 * } 11050 * } ); 11051 * } ); 11052 */ 11053 "sPrevious": "Previous" 11054 }, 11055 11056 /** 11057 * This string is shown in preference to `zeroRecords` when the table is 11058 * empty of data (regardless of filtering). Note that this is an optional 11059 * parameter - if it is not given, the value of `zeroRecords` will be used 11060 * instead (either the default or given value). 11061 * @type string 11062 * @default No data available in table 11063 * 11064 * @dtopt Language 11065 * @name DataTable.defaults.language.emptyTable 11066 * 11067 * @example 11068 * $(document).ready( function() { 11069 * $('#example').dataTable( { 11070 * "language": { 11071 * "emptyTable": "No data available in table" 11072 * } 11073 * } ); 11074 * } ); 11075 */ 11076 "sEmptyTable": "No data available in table", 11077 11078 11079 /** 11080 * This string gives information to the end user about the information 11081 * that is current on display on the page. The following tokens can be 11082 * used in the string and will be dynamically replaced as the table 11083 * display updates. This tokens can be placed anywhere in the string, or 11084 * removed as needed by the language requires: 11085 * 11086 * * `\_START\_` - Display index of the first record on the current page 11087 * * `\_END\_` - Display index of the last record on the current page 11088 * * `\_TOTAL\_` - Number of records in the table after filtering 11089 * * `\_MAX\_` - Number of records in the table without filtering 11090 * * `\_PAGE\_` - Current page number 11091 * * `\_PAGES\_` - Total number of pages of data in the table 11092 * 11093 * @type string 11094 * @default Showing _START_ to _END_ of _TOTAL_ entries 11095 * 11096 * @dtopt Language 11097 * @name DataTable.defaults.language.info 11098 * 11099 * @example 11100 * $(document).ready( function() { 11101 * $('#example').dataTable( { 11102 * "language": { 11103 * "info": "Showing page _PAGE_ of _PAGES_" 11104 * } 11105 * } ); 11106 * } ); 11107 */ 11108 "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries", 11109 11110 11111 /**
11112 * Display information string for when the table is empty. Typically the 11113 * format of this string should match `info`. 11114 * @type string 11115 * @default Showing 0 to 0 of 0 entries 11116 * 11117 * @dtopt Language 11118 * @name DataTable.defaults.language.infoEmpty 11119 * 11120 * @example 11121 * $(document).ready( function() { 11122 * $('#example').dataTable( { 11123 * "language": { 11124 * "infoEmpty": "No entries to show" 11125 * } 11126 * } ); 11127 * } ); 11128 */ 11129 "sInfoEmpty": "Showing 0 to 0 of 0 entries", 11130 11131 11132 /** 11133 * When a user filters the information in a table, this string is appended 11134 * to the information (`info`) to give an idea of how strong the filtering 11135 * is. The variable _MAX_ is dynamically updated. 11136 * @type string 11137 * @default (filtered from _MAX_ total entries) 11138 * 11139 * @dtopt Language 11140 * @name DataTable.defaults.language.infoFiltered 11141 * 11142 * @example 11143 * $(document).ready( function() { 11144 * $('#example').dataTable( { 11145 * "language": { 11146 * "infoFiltered": " - filtering from _MAX_ records" 11147 * } 11148 * } ); 11149 * } ); 11150 */ 11151 "sInfoFiltered": "(filtered from _MAX_ total entries)", 11152 11153 11154 /** 11155 * If can be useful to append extra information to the info string at times, 11156 * and this variable does exactly that. This information will be appended to 11157 * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are 11158 * being used) at all times. 11159 * @type string 11160 * @default <i>Empty string</i> 11161 * 11162 * @dtopt Language 11163 * @name DataTable.defaults.language.infoPostFix 11164 * 11165 * @example 11166 * $(document).ready( function() { 11167 * $('#example').dataTable( { 11168 * "language": { 11169 * "infoPostFix": "All records shown are derived from real information." 11170 * } 11171 * } ); 11172 * } ); 11173 */ 11174 "sInfoPostFix": "", 11175 11176 11177 /** 11178 * This decimal place operator is a little different from the other 11179 * language options since DataTables doesn't output floating point 11180 * numbers, so it won't ever use this for display of a number. Rather, 11181 * what this parameter does is modify the sort methods of the table so 11182 * that numbers which are in a format which has a character other than 11183 * a period (`.`) as a decimal place will be sorted numerically. 11184 * 11185 * Note that numbers with different decimal places cannot be shown in 11186 * the same table and still be sortable, the table must be consistent. 11187 * However, multiple different tables on the page can use different 11188 * decimal place characters. 11189 * @type string 11190 * @default 11191 * 11192 * @dtopt Language 11193 * @name DataTable.defaults.language.decimal 11194 * 11195 * @example 11196 * $(document).ready( function() { 11197 * $('#example').dataTable( { 11198 * "language": { 11199 * "decimal": "," 11200 * "thousands": "." 11201 * } 11202 * } ); 11203 * } ); 11204 */ 11205 "sDecimal": "", 11206 11207 11208 /** 11209 * DataTables has a build in number formatter (`formatNumber`) which is 11210 * used to format large numbers that are used in the table information. 11211 * By default a comma is used, but this can be trivially changed to any 11212 * character you wish with this parameter. 11213 * @type string 11214 * @default , 11215 * 11216 * @dtopt Language 11217 * @name DataTable.defaults.language.thousands 11218 * 11219 * @example 11220 * $(document).ready( function() { 11221 * $('#example').dataTable( { 11222 * "language": { 11223 * "thousands": "'" 11224 * } 11225 * } ); 11226 * } ); 11227 */ 11228 "sThousands": ",", 11229 11230 11231 /** 11232 * Detail the action that will be taken when the drop down menu for the 11233 * pagination length option is changed. The '_MENU_' variable is replaced 11234 * with a default select list of 10, 25, 50 and 100, and can be replaced 11235 * with a custom select box if required. 11236 * @type string 11237 * @default Show _MENU_ entries 11238 * 11239 * @dtopt Language 11240 * @name DataTable.defaults.language.lengthMenu 11241 * 11242 * @example 11243 * // Language change only 11244 * $(document).ready( function() { 11245 * $('#example').dataTable( { 11246 * "language": {
11247 * "lengthMenu": "Display _MENU_ records" 11248 * } 11249 * } ); 11250 * } ); 11251 * 11252 * @example 11253 * // Language and options change 11254 * $(document).ready( function() { 11255 * $('#example').dataTable( { 11256 * "language": { 11257 * "lengthMenu": 'Display <select>'+ 11258 * '<option value="10">10</option>'+ 11259 * '<option value="20">20</option>'+ 11260 * '<option value="30">30</option>'+ 11261 * '<option value="40">40</option>'+ 11262 * '<option value="50">50</option>'+ 11263 * '<option value="-1">All</option>'+ 11264 * '</select> records' 11265 * } 11266 * } ); 11267 * } ); 11268 */ 11269 "sLengthMenu": "Show _MENU_ entries", 11270 11271 11272 /** 11273 * When using Ajax sourced data and during the first draw when DataTables is 11274 * gathering the data, this message is shown in an empty row in the table to 11275 * indicate to the end user the the data is being loaded. Note that this 11276 * parameter is not used when loading data by server-side processing, just 11277 * Ajax sourced data with client-side processing. 11278 * @type string 11279 * @default Loading... 11280 * 11281 * @dtopt Language 11282 * @name DataTable.defaults.language.loadingRecords 11283 * 11284 * @example 11285 * $(document).ready( function() { 11286 * $('#example').dataTable( { 11287 * "language": { 11288 * "loadingRecords": "Please wait - loading..." 11289 * } 11290 * } ); 11291 * } ); 11292 */ 11293 "sLoadingRecords": "Loading...", 11294 11295 11296 /** 11297 * Text which is displayed when the table is processing a user action 11298 * (usually a sort command or similar). 11299 * @type string 11300 * @default Processing... 11301 * 11302 * @dtopt Language 11303 * @name DataTable.defaults.language.processing 11304 * 11305 * @example 11306 * $(document).ready( function() { 11307 * $('#example').dataTable( { 11308 * "language": { 11309 * "processing": "DataTables is currently busy" 11310 * } 11311 * } ); 11312 * } ); 11313 */ 11314 "sProcessing": "Processing...", 11315 11316 11317 /** 11318 * Details the actions that will be taken when the user types into the 11319 * filtering input text box. The variable "_INPUT_", if used in the string, 11320 * is replaced with the HTML text box for the filtering input allowing 11321 * control over where it appears in the string. If "_INPUT_" is not given 11322 * then the input box is appended to the string automatically. 11323 * @type string 11324 * @default Search: 11325 * 11326 * @dtopt Language 11327 * @name DataTable.defaults.language.search 11328 * 11329 * @example 11330 * // Input text box will be appended at the end automatically 11331 * $(document).ready( function() { 11332 * $('#example').dataTable( { 11333 * "language": { 11334 * "search": "Filter records:" 11335 * } 11336 * } ); 11337 * } ); 11338 * 11339 * @example 11340 * // Specify where the filter should appear 11341 * $(document).ready( function() { 11342 * $('#example').dataTable( { 11343 * "language": { 11344 * "search": "Apply filter _INPUT_ to table" 11345 * } 11346 * } ); 11347 * } ); 11348 */ 11349 "sSearch": "Search:", 11350 11351 11352 /** 11353 * Assign a `placeholder` attribute to the search `input` element 11354 * @type string 11355 * @default 11356 * 11357 * @dtopt Language 11358 * @name DataTable.defaults.language.searchPlaceholder 11359 */ 11360 "sSearchPlaceholder": "", 11361 11362 11363 /** 11364 * All of the language information can be stored in a file on the 11365 * server-side, which DataTables will look up if this parameter is passed. 11366 * It must store the URL of the language file, which is in a JSON format, 11367 * and the object has the same properties as the oLanguage object in the 11368 * initialiser object (i.e. the above parameters). Please refer to one of 11369 * the example language files to see how this works in action. 11370 * @type string 11371 * @default <i>Empty string - i.e. disabled</i> 11372 * 11373 * @dtopt Language 11374 * @name DataTable.defaults.language.url 11375 * 11376 * @example 11377 * $(document).ready( function() { 11378 * $('#example').dataTable( { 11379 * "language": { 11380 * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt" 11381 * } 11382 * } ); 11383 * } ); 11384 */ 11385 "sUrl": "", 11386 11387 11388 /** 11389 * Text shown inside the table records when the is no information to be 11390 * displayed after filtering. `emptyTable` is shown when there is simply no 11391 * information in the table at all (regardless of filtering). 11392 * @type string
11393 * @default No matching records found 11394 * 11395 * @dtopt Language 11396 * @name DataTable.defaults.language.zeroRecords 11397 * 11398 * @example 11399 * $(document).ready( function() { 11400 * $('#example').dataTable( { 11401 * "language": { 11402 * "zeroRecords": "No records to display" 11403 * } 11404 * } ); 11405 * } ); 11406 */ 11407 "sZeroRecords": "No matching records found" 11408 }, 11409 11410 11411 /** 11412 * This parameter allows you to have define the global filtering state at 11413 * initialisation time. As an object the `search` parameter must be 11414 * defined, but all other parameters are optional. When `regex` is true, 11415 * the search string will be treated as a regular expression, when false 11416 * (default) it will be treated as a straight string. When `smart` 11417 * DataTables will use it's smart filtering methods (to word match at 11418 * any point in the data), when false this will not be done. 11419 * @namespace 11420 * @extends DataTable.models.oSearch 11421 * 11422 * @dtopt Options 11423 * @name DataTable.defaults.search 11424 * 11425 * @example 11426 * $(document).ready( function() { 11427 * $('#example').dataTable( { 11428 * "search": {"search": "Initial search"} 11429 * } ); 11430 * } ) 11431 */ 11432 "oSearch": $.extend( {}, DataTable.models.oSearch ), 11433 11434 11435 /** 11436 * __Deprecated__ The functionality provided by this parameter has now been 11437 * superseded by that provided through `ajax`, which should be used instead. 11438 * 11439 * By default DataTables will look for the property `data` (or `aaData` for 11440 * compatibility with DataTables 1.9-) when obtaining data from an Ajax 11441 * source or for server-side processing - this parameter allows that 11442 * property to be changed. You can use Javascript dotted object notation to 11443 * get a data source for multiple levels of nesting. 11444 * @type string 11445 * @default data 11446 * 11447 * @dtopt Options 11448 * @dtopt Server-side 11449 * @name DataTable.defaults.ajaxDataProp 11450 * 11451 * @deprecated 1.10. Please use `ajax` for this functionality now. 11452 */ 11453 "sAjaxDataProp": "data", 11454 11455 11456 /** 11457 * __Deprecated__ The functionality provided by this parameter has now been 11458 * superseded by that provided through `ajax`, which should be used instead. 11459 * 11460 * You can instruct DataTables to load data from an external 11461 * source using this parameter (use aData if you want to pass data in you 11462 * already have). Simply provide a url a JSON object can be obtained from. 11463 * @type string 11464 * @default null 11465 * 11466 * @dtopt Options 11467 * @dtopt Server-side 11468 * @name DataTable.defaults.ajaxSource 11469 * 11470 * @deprecated 1.10. Please use `ajax` for this functionality now. 11471 */ 11472 "sAjaxSource": null, 11473 11474 11475 /** 11476 * This initialisation variable allows you to specify exactly where in the 11477 * DOM you want DataTables to inject the various controls it adds to the page 11478 * (for example you might want the pagination controls at the top of the 11479 * table). DIV elements (with or without a custom class) can also be added to 11480 * aid styling. The follow syntax is used: 11481 * <ul> 11482 * <li>The following options are allowed: 11483 * <ul> 11484 * <li>'l' - Length changing</li> 11485 * <li>'f' - Filtering input</li> 11486 * <li>'t' - The table!</li> 11487 * <li>'i' - Information</li> 11488 * <li>'p' - Pagination</li> 11489 * <li>'r' - pRocessing</li> 11490 * </ul> 11491 * </li> 11492 * <li>The following constants are allowed: 11493 * <ul> 11494 * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li> 11495 * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li> 11496 * </ul> 11497 * </li> 11498 * <li>The following syntax is expected: 11499 * <ul> 11500 * <li>'<' and '>' - div elements</li> 11501 * <li>'<"class" and '>' - div with a class</li> 11502 * <li>'<"#id" and '>' - div with an ID</li> 11503 * </ul> 11504 * </li> 11505 * <li>Examples: 11506 * <ul> 11507 * <li>'<"wrapper"flipt>'</li> 11508 * <li>'<lf<t>ip>'</li> 11509 * </ul> 11510 * </li> 11511 * </ul> 11512 * @type string 11513 * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b> 11514 * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i> 11515 * 11516 * @dtopt Options 11517 * @name DataTable.defaults.dom 11518 * 11519 * @example 11520 * $(document).ready( function() { 11521 * $('#example').dataTable( { 11522 * "dom": '<"top"i>rt<"bottom"flp><"clear">' 11523 * } ); 11524 * } ); 11525 */ 11526 "sDom": "lfrtip", 11527 11528 11529 /** 11530 * Search delay option. This will throttle full table searches that use the 11531 * DataTables provided search input element (it does not effect calls to 11532 * `dt-api search()`, providing a delay before the search is made. 11533 * @type integer 11534 * @default 0 11535 * 11536 * @dtopt Options 11537 * @name DataTable.defaults.searchDelay 11538 * 11539 * @example 11540 * $(document).ready( function() { 11541 * $('#example').dataTable( { 11542 * "searchDelay": 200 11543 * } ); 11544 * } ) 11545 */ 11546 "searchDelay": null, 11547 11548 11549 /** 11550 * DataTables features four different built-in options for the buttons to 11551 * display for pagination control: 11552 * 11553 * * `simple` - 'Previous' and 'Next' buttons only 11554 * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers 11555 * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons 11556 * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus 11557 * page numbers 11558 * 11559 * Further methods can be added using {@link DataTable.ext.oPagination}. 11560 * @type string 11561 * @default simple_numbers 11562 * 11563 * @dtopt Options 11564 * @name DataTable.defaults.pagingType 11565 * 11566 * @example 11567 * $(document).ready( function() { 11568 * $('#example').dataTable( { 11569 * "pagingType": "full_numbers" 11570 * } ); 11571 * } ) 11572 */ 11573 "sPaginationType": "simple_numbers", 11574 11575 11576 /** 11577 * Enable horizontal scrolling. When a table is too wide to fit into a 11578 * certain layout, or you have a large number of columns in the table, you 11579 * can enable x-scrolling to show the table in a viewport, which can be 11580 * scrolled. This property can be `true` which will allow the table to 11581 * scroll horizontally when needed, or any CSS unit, or a number (in which 11582 * case it will be treated as a pixel measurement). Setting as simply `true` 11583 * is recommended.
11584 * @type boolean|string 11585 * @default <i>blank string - i.e. disabled</i> 11586 * 11587 * @dtopt Features 11588 * @name DataTable.defaults.scrollX 11589 * 11590 * @example 11591 * $(document).ready( function() { 11592 * $('#example').dataTable( { 11593 * "scrollX": true, 11594 * "scrollCollapse": true 11595 * } ); 11596 * } ); 11597 */ 11598 "sScrollX": "", 11599 11600 11601 /** 11602 * This property can be used to force a DataTable to use more width than it 11603 * might otherwise do when x-scrolling is enabled. For example if you have a 11604 * table which requires to be well spaced, this parameter is useful for 11605 * "over-sizing" the table, and thus forcing scrolling. This property can by 11606 * any CSS unit, or a number (in which case it will be treated as a pixel 11607 * measurement). 11608 * @type string 11609 * @default <i>blank string - i.e. disabled</i> 11610 * 11611 * @dtopt Options 11612 * @name DataTable.defaults.scrollXInner 11613 * 11614 * @example 11615 * $(document).ready( function() { 11616 * $('#example').dataTable( { 11617 * "scrollX": "100%", 11618 * "scrollXInner": "110%" 11619 * } ); 11620 * } ); 11621 */ 11622 "sScrollXInner": "", 11623 11624 11625 /** 11626 * Enable vertical scrolling. Vertical scrolling will constrain the DataTable 11627 * to the given height, and enable scrolling for any data which overflows the 11628 * current viewport. This can be used as an alternative to paging to display 11629 * a lot of data in a small area (although paging and scrolling can both be 11630 * enabled at the same time). This property can be any CSS unit, or a number 11631 * (in which case it will be treated as a pixel measurement). 11632 * @type string 11633 * @default <i>blank string - i.e. disabled</i> 11634 * 11635 * @dtopt Features 11636 * @name DataTable.defaults.scrollY 11637 * 11638 * @example 11639 * $(document).ready( function() { 11640 * $('#example').dataTable( { 11641 * "scrollY": "200px", 11642 * "paginate": false 11643 * } ); 11644 * } ); 11645 */ 11646 "sScrollY": "", 11647 11648 11649 /** 11650 * __Deprecated__ The functionality provided by this parameter has now been 11651 * superseded by that provided through `ajax`, which should be used instead. 11652 * 11653 * Set the HTTP method that is used to make the Ajax call for server-side 11654 * processing or Ajax sourced data. 11655 * @type string 11656 * @default GET 11657 * 11658 * @dtopt Options 11659 * @dtopt Server-side 11660 * @name DataTable.defaults.serverMethod 11661 * 11662 * @deprecated 1.10. Please use `ajax` for this functionality now. 11663 */ 11664 "sServerMethod": "GET", 11665 11666 11667 /** 11668 * DataTables makes use of renderers when displaying HTML elements for 11669 * a table. These renderers can be added or modified by plug-ins to 11670 * generate suitable mark-up for a site. For example the Bootstrap 11671 * integration plug-in for DataTables uses a paging button renderer to 11672 * display pagination buttons in the mark-up required by Bootstrap. 11673 * 11674 * For further information about the renderers available see 11675 * DataTable.ext.renderer 11676 * @type string|object 11677 * @default null 11678 * 11679 * @name DataTable.defaults.renderer 11680 * 11681 */ 11682 "renderer": null 11683 }; 11684 11685 _fnHungarianMap( DataTable.defaults ); 11686 11687 11688 11689 /* 11690 * Developer note - See note in model.defaults.js about the use of Hungarian 11691 * notation and camel case. 11692 */ 11693 11694 /** 11695 * Column options that can be given to DataTables at initialisation time. 11696 * @namespace 11697 */ 11698 DataTable.defaults.column = { 11699 /** 11700 * Define which column(s) an order will occur on for this column. This 11701 * allows a column's ordering to take multiple columns into account when 11702 * doing a sort or use the data from a different column. For example first 11703 * name / last name columns make sense to do a multi-column sort over the 11704 * two columns. 11705 * @type array|int 11706 * @default null <i>Takes the value of the column index automatically</i> 11707 * 11708 * @name DataTable.defaults.column.orderData 11709 * @dtopt Columns 11710 * 11711 * @example 11712 * // Using `columnDefs` 11713 * $(document).ready( function() { 11714 * $('#example').dataTable( { 11715 * "columnDefs": [ 11716 * { "orderData": [ 0, 1 ], "targets": [ 0 ] }, 11717 * { "orderData": [ 1, 0 ], "targets": [ 1 ] }, 11718 * { "orderData": 2, "targets": [ 2 ] } 11719 * ] 11720 * } ); 11721 * } ); 11722 * 11723 * @example 11724 * // Using `columns` 11725 * $(document).ready( function() { 11726 * $('#example').dataTable( { 11727 * "columns": [ 11728 * { "orderData": [ 0, 1 ] }, 11729 * { "orderData": [ 1, 0 ] }, 11730 * { "orderData": 2 }, 11731 * null, 11732 * null 11733 * ] 11734 * } ); 11735 * } ); 11736 */ 11737 "aDataSort": null, 11738 "iDataSort": -1, 11739 11740 11741 /** 11742 * You can control the default ordering direction, and even alter the 11743 * behaviour of the sort handler (i.e. only allow ascending ordering etc) 11744 * using this parameter. 11745 * @type array 11746 * @default [ 'asc', 'desc' ] 11747 * 11748 * @name DataTable.defaults.column.orderSequence 11749 * @dtopt Columns 11750 * 11751 * @example 11752 * // Using `columnDefs` 11753 * $(document).ready( function() { 11754 * $('#example').dataTable( { 11755 * "columnDefs": [ 11756 * { "orderSequence": [ "asc" ], "targets": [ 1 ] }, 11757 * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] }, 11758 * { "orderSequence": [ "desc" ], "targets": [ 3 ] } 11759 * ] 11760 * } ); 11761 * } ); 11762 * 11763 * @example 11764 * // Using `columns` 11765 * $(document).ready( function() { 11766 * $('#example').dataTable( { 11767 * "columns": [ 11768 * null, 11769 * { "orderSequence": [ "asc" ] }, 11770 * { "orderSequence": [ "desc", "asc", "asc" ] }, 11771 * { "orderSequence": [ "desc" ] }, 11772 * null 11773 * ] 11774 * } ); 11775 * } ); 11776 */ 11777 "asSorting": [ 'asc', 'desc' ], 11778 11779 11780 /** 11781 * Enable or disable filtering on the data in this column. 11782 * @type boolean 11783 * @default true 11784 * 11785 * @name DataTable.defaults.column.searchable 11786 * @dtopt Columns 11787 * 11788 * @example 11789 * // Using `columnDefs` 11790 * $(document).ready( function() { 11791 * $('#example').dataTable( { 11792 * "columnDefs": [ 11793 * { "searchable": false, "targets": [ 0 ] } 11794 * ] } ); 11795 * } ); 11796 * 11797 * @example 11798 * // Using `columns` 11799 * $(document).ready( function() { 11800 * $('#example').dataTable( { 11801 * "columns": [ 11802 * { "searchable": false }, 11803 * null, 11804 * null, 11805 * null, 11806 * null 11807 * ] } ); 11808 * } ); 11809 */ 11810 "bSearchable": true, 11811 11812 11813 /** 11814 * Enable or disable ordering on this column. 11815 * @type boolean 11816 * @default true 11817 * 11818 * @name DataTable.defaults.column.orderable 11819 * @dtopt Columns 11820 * 11821 * @example 11822 * // Using `columnDefs` 11823 * $(document).ready( function() { 11824 * $('#example').dataTable( { 11825 * "columnDefs": [ 11826 * { "orderable": false, "targets": [ 0 ] } 11827 * ] } ); 11828 * } ); 11829 * 11830 * @example 11831 * // Using `columns` 11832 * $(document).ready( function() { 11833 * $('#example').dataTable( { 11834 * "columns": [ 11835 * { "orderable": false }, 11836 * null, 11837 * null, 11838 * null, 11839 * null 11840 * ] } ); 11841 * } ); 11842 */ 11843 "bSortable": true, 11844 11845 11846 /** 11847 * Enable or disable the display of this column. 11848 * @type boolean 11849 * @default true 11850 * 11851 * @name DataTable.defaults.column.visible 11852 * @dtopt Columns 11853 * 11854 * @example 11855 * // Using `columnDefs` 11856 * $(document).ready( function() { 11857 * $('#example').dataTable( { 11858 * "columnDefs": [ 11859 * { "visible": false, "targets": [ 0 ] } 11860 * ] } ); 11861 * } ); 11862 * 11863 * @example 11864 * // Using `columns` 11865 * $(document).ready( function() { 11866 * $('#example').dataTable( { 11867 * "columns": [ 11868 * { "visible": false }, 11869 * null, 11870 * null, 11871 * null, 11872 * null 11873 * ] } ); 11874 * } ); 11875 */ 11876 "bVisible": true, 11877 11878 11879 /** 11880 * Developer definable function that is called whenever a cell is created (Ajax source, 11881 * etc) or processed for input (DOM source). This can be used as a compliment to mRender 11882 * allowing you to modify the DOM element (add background colour for example) when the 11883 * element is available. 11884 * @type function 11885 * @param {element} td The TD node that has been created 11886 * @param {*} cellData The Data for the cell 11887 * @param {array|object} rowData The data for the whole row 11888 * @param {int} row The row index for the aoData data store 11889 * @param {int} col The column index for aoColumns 11890 * 11891 * @name DataTable.defaults.column.createdCell 11892 * @dtopt Columns 11893 * 11894 * @example 11895 * $(document).ready( function() { 11896 * $('#example').dataTable( { 11897 * "columnDefs": [ { 11898 * "targets": [3], 11899 * "createdCell": function (td, cellData, rowData, row, c
11899ol) { 11900 * if ( cellData == "1.7" ) { 11901 * $(td).css('color', 'blue') 11902 * } 11903 * } 11904 * } ] 11905 * }); 11906 * } ); 11907 */ 11908 "fnCreatedCell": null, 11909 11910 11911 /** 11912 * This parameter has been replaced by `data` in DataTables to ensure naming 11913 * consistency. `dataProp` can still be used, as there is backwards 11914 * compatibility in DataTables for this option, but it is strongly 11915 * recommended that you use `data` in preference to `dataProp`. 11916 * @name DataTable.defaults.column.dataProp 11917 */ 11918 11919 11920 /** 11921 * This property can be used to read data from any data source property, 11922 * including deeply nested objects / properties. `data` can be given in a 11923 * number of different ways which effect its behaviour: 11924 * 11925 * * `integer` - treated as an array index for the data source. This is the 11926 * default that DataTables uses (incrementally increased for each column). 11927 * * `string` - read an object property from the data source. There are 11928 * three 'special' options that can be used in the string to alter how 11929 * DataTables reads the data from the source object: 11930 * * `.` - Dotted Javascript notation. Just as you use a `.` in 11931 * Javascript to read from nested objects, so to can the options 11932 * specified in `data`. For example: `browser.version` or 11933 * `browser.name`. If your object parameter name contains a period, use 11934 * `\\` to escape it - i.e. `first\\.name`. 11935 * * `[]` - Array notation. DataTables can automatically combine data 11936 * from and array source, joining the data with the characters provided 11937 * between the two brackets. For example: `name[, ]` would provide a 11938 * comma-space separated list from the source array. If no characters 11939 * are provided between the brackets, the original array source is 11940 * returned. 11941 * * `()` - Function notation. Adding `()` to the end of a parameter will 11942 * execute a function of the name given. For example: `browser()` for a 11943 * simple function on the data source, `browser.version()` for a 11944 * function in a nested property or even `browser().version` to get an 11945 * object property if the function called returns an object. Note that 11946 * function notation is recommended for use in `render` rather than 11947 * `data` as it is much simpler to use as a renderer. 11948 * * `null` - use the original data source for the row rather than plucking 11949 * data directly from it. This action has effects on two other 11950 * initialisation options: 11951 * * `defaultContent` - When null is given as the `data` option and 11952 * `defaultContent` is specified for the column, the value defined by 11953 * `defaultContent` will be used for the cell. 11954 * * `render` - When null is used for the `data` option and the `render` 11955 * option is specified for the column, the whole data source for the 11956 * row is used for the renderer. 11957 * * `function` - the function given will be executed whenever DataTables 11958 * needs to set or get the data for a cell in the column. The function 11959 * takes three parameters: 11960 * * Parameters: 11961 * * `{array|object}` The data source for the row 11962 * * `{string}` The type call data requested - this will be 'set' when 11963 * setting data or 'filter', 'display', 'type', 'sort' or undefined 11964 * when gathering data. Note that when `undefined` is given for the 11965 * type DataTables expects to get the raw data for the object back< 11966 * * `{*}` Data to set when the second parameter is 'set'. 11967 * * Return: 11968 * * The return value from the function is not required when 'set' is 11969 * the type of call, but otherwise the return is what will be used 11970 * for the data requested. 11971 * 11972 * Note that `data` is a getter and setter option. If you just require 11973 * formatting of data for output, you will likely want to use `render` which 11974 * is simply a getter and thus simpler to use. 11975 * 11976 * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The 11977 * name change reflects the flexibility of this property and is consistent 11978 * with the naming of mRender. If 'mDataProp' is given, then it will still 11979 * be used by DataTables, as it automatically maps the old name to the new 11980 * if required. 11981 * 11982 * @type string|int|function|null 11983 * @default null <i>Use automatically calculated column index</i> 11984 * 11985 * @name DataTable.defaults.column.data 11986 * @dtopt Columns 11987 * 11988 * @example 11989 * // Read table data from objects 11990 * // JSON structure for each row: 11991 * // { 11992 * // "engine": {value}, 11993 * // "browser": {value}, 11994 * // "platform": {value}, 11995 * // "version": {value}, 11996 * // "grade": {value} 11997 * // } 11998 * $(document).ready( function() { 11999 * $('#example').dataTable( { 12000 * "ajaxSource": "sources/objects.txt", 12001 * "columns": [ 12002 * { "data": "engine" }, 12003 * { "data": "browser" }, 12004 * { "data": "platform" }, 12005 * { "data": "version" }, 12006 * { "data": "grade" } 12007 * ] 12008 * } ); 12009 * } ); 12010 * 12011 * @example 12012 * // Read information from deeply nested objects 12013 * // JSON structure for each row: 12014 * // { 12015 * // "engine": {value}, 12016 * // "browser": {value}, 12017 * // "platform": { 12018 * // "inner": {value} 12019 * // }, 12020 * // "details": [ 12021 * // {value}, {value} 12022 * // ] 12023 * // } 12024 * $(document).ready( function() { 12025 * $('#example').dataTable( { 12026 * "ajaxSource": "sources/deep.txt", 12027 * "columns": [ 12028 * { "data": "engine" }, 12029 * { "data": "browser" }, 12030 * { "data": "platform.inner" }, 12031 * { "data": "platform.details.0" }, 12032 * { "data": "platform.details.1" } 12033 * ] 12034 * } ); 12035 * } ); 12036 * 12037 * @example 12038 * // Using `data` as a function to provide different information for 12039 * // sorting, filtering and display. In this case, currency (price) 12040 * $(document).ready( function() { 12041 * $('#example').dataTable( { 12042 * "columnDefs": [ { 12043 * "targets": [ 0 ], 12044 * "data": function ( source, type, val ) { 12045 * if (type === 'set') { 12046 * source.price = val; 12047 * // Store the computed dislay and filter values for efficiency 12048 * source.price_display = val=="" ? "" : "$"+numberFormat(val); 12049 * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val; 12050 * return; 12051 * } 12052 * else if (type === 'display') { 12053 * return source.price_display; 12054 * } 12055 * else if (type === 'filter') { 12056 * return source.price_filter; 12057 * } 12058 * // 'sort', 'type' and undefined all just use the integer 12059 * return source.price; 12060 * } 12061 * } ] 12062 * } ); 12063 * } ); 12064 * 12065 * @example 12066 * // Using default content 12067 * $(document).ready( function() { 12068 * $('#example').dataTable( { 12069 * "columnDefs": [ { 12070 * "targets": [ 0 ], 12071 * "data": null, 12072 * "defaultContent": "Click to edit" 12073 * } ] 12074 * } ); 12075 * } ); 12076 * 12077 * @example 12078 * // Using array notation - outputting a list from an array 12079 * $(document).ready( function() { 12080 * $('#example').dataTable( { 12081 * "columnDefs": [ { 12082 * "targets": [ 0 ], 12083 * "data": "name[, ]" 12084 * } ] 12085 * } ); 12086 * } ); 12087 * 12088 */ 12089 "mData": null, 12090 12091 12092 /** 12093 * This property is the rendering partner to `data` and it is suggested that 12094 * when you want to manipulate data for display (including filtering, 12095 * sorting etc) without altering the underlying data for the table, use this 12096 * property. `render` can be considered to be the the read only companion to 12097 * `data` which is read / write (then as such more complex). Like `data` 12098 * this option can be given in a number of different ways to effect its 12099 * behaviour: 12100 * 12101 * * `integer` - treated as an array index for the data source. This is the 12102 * default that DataTables uses (incrementally increased for each column). 12103 * * `string` - read an object property from the data source. There are 12104 * three 'special' options that can be used in the string to alter how 12105 * DataTables reads the data from the source object: 12106 * * `.` - Dotted Javascript notation. Just as you use a `.` in 12107 * Javascript to read from nested objects, so to can the options 12108 * specified in `data`. For example: `browser.version` or 12109 * `browser.name`. If your object parameter name contains a period, use 12110 * `\\` to escape it - i.e. `first\\.name`. 12111 * * `[]` - Array notation. DataTables can automatically combine data 12112 * from and array source, joining the data with the characters provided 12113 * between the two brackets. For example: `name[, ]` would provide a 12114 * comma-space separated list from the source array. If no characters 12115 * are provided between the brackets, the original array source is 12116 * returned. 12117 * * `()` - Function notation. Adding `()` to the end of a parameter will 12118 * execute a function of the name given. For example: `browser()` for a 12119 * simple function on the data source, `browser.version()` for a 12120 * function in a nested property or even `browser().version` to get an 12121 * object property if the function called returns an object. 12122 * * `object` - use different data for the different data types requested by 12123 * DataTables ('filter', 'display', 'type' or 'sort'). The property names 12124 * of the object is the data type the property refers to and the value can 12125 * defined using an integer, string or function using the same rules as 12126 * `render` normally does. Note that an `_` option _must_ be specified. 12127 * This is the default value to use if you haven't specified a value for 12128 * the data type requested by DataTables. 12129 * * `function` - the function given will be executed whenever DataTables 12130 * needs to set or get the data for a cell in the column. The function 12131 * takes three parameters: 12132 * * Parameters: 12133 * * {array|object} The data source for the row (based on `data`) 12134 * * {string} The type call data requested - this will be 'filter', 12135 * 'display', 'type' or 'sort'. 12136 * * {array|object} The full data source for the row (not based on 12137 * `data`) 12138 * * Return: 12139 * * The return value from the function is what will be used for the 12140 * data requested. 12141 * 12142 * @type string|int|function|object|null 12143 * @default null Use the data source value. 12144 * 12145 * @name DataTable.defaults.column.render 12146 * @dtopt Columns 12147 * 12148 * @example 12149 * // Create a comma separated list from an array of objects 12150 * $(document).ready( function() { 12151 * $('#example').dataTable( { 12152 * "ajaxSource": "sources/deep.txt", 12153 * "columns": [ 12154 * { "data": "engine" }, 12155 * { "data": "browser" }, 12156 * { 12157 * "data": "platform", 12158 * "render": "[, ].name" 12159 * } 12160 * ] 12161 * } ); 12162 * } ); 12163 * 12164 * @example 12165 * // Execute a function to obtain data 12166 * $(document).ready( function() { 12167 * $('#example').dataTable( { 12168 * "columnDefs": [ { 12169 * "targets": [ 0 ], 12170 * "data": null, // Use the full data source object for the renderer's source 12171 * "render": "browserName()" 12172 * } ] 12173 * } ); 12174 * } ); 12175 * 12176 * @example 12177 * // As an object, extracting different data for the different types 12178 * // This would be used with a data source such as: 12179 * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" } 12180 * // Here the `phone` integer is used for sorting and type detection, while `phone_filter` 12181 * // (which has both forms) is used for filtering for if a user inputs either format, while 12182 * // the formatted phone number is the one that is shown in the table. 12183 * $(document).ready( function() { 12184 * $('#example').dataTable( { 12185 * "columnDefs": [ { 12186 * "targets": [ 0 ], 12187 * "data": null, // Use the full data source object for the renderer's source 12188 * "render": { 12189 * "_": "phone", 12190 * "filter": "phone_filter", 12191 * "display": "phone_display" 12192 * } 12193 * } ] 12194 * } ); 12195 * } ); 12196 * 12197 * @example 12198 * // Use as a function to create a link from the data source 12199 * $(document).ready( function() { 12200 * $('#example').dataTable( { 12201 * "columnDefs": [ { 12202 * "targets": [ 0 ], 12203 * "data": "download_link", 12204 * "render": function ( data, type, full ) { 12205 * return '<a href="'+data+'">Download</a>'; 12206 * } 12207 * } ] 12208 * } ); 12209 * } ); 12210 */
12211 "mRender": null, 12212 12213 12214 /** 12215 * Change the cell type created for the column - either TD cells or TH cells. This 12216 * can be useful as TH cells have semantic meaning in the table body, allowing them 12217 * to act as a header for a row (you may wish to add scope='row' to the TH elements). 12218 * @type string 12219 * @default td 12220 * 12221 * @name DataTable.defaults.column.cellType 12222 * @dtopt Columns 12223 * 12224 * @example 12225 * // Make the first column use TH cells 12226 * $(document).ready( function() { 12227 * $('#example').dataTable( { 12228 * "columnDefs": [ { 12229 * "targets": [ 0 ], 12230 * "cellType": "th" 12231 * } ] 12232 * } ); 12233 * } ); 12234 */ 12235 "sCellType": "td", 12236 12237 12238 /** 12239 * Class to give to each cell in this column. 12240 * @type string 12241 * @default <i>Empty string</i> 12242 * 12243 * @name DataTable.defaults.column.class 12244 * @dtopt Columns 12245 * 12246 * @example 12247 * // Using `columnDefs` 12248 * $(document).ready( function() { 12249 * $('#example').dataTable( { 12250 * "columnDefs": [ 12251 * { "class": "my_class", "targets": [ 0 ] } 12252 * ] 12253 * } ); 12254 * } ); 12255 * 12256 * @example 12257 * // Using `columns` 12258 * $(document).ready( function() { 12259 * $('#example').dataTable( { 12260 * "columns": [ 12261 * { "class": "my_class" }, 12262 * null, 12263 * null, 12264 * null, 12265 * null 12266 * ] 12267 * } ); 12268 * } ); 12269 */ 12270 "sClass": "", 12271 12272 /** 12273 * When DataTables calculates the column widths to assign to each column, 12274 * it finds the longest string in each column and then constructs a 12275 * temporary table and reads the widths from that. The problem with this 12276 * is that "mmm" is much wider then "iiii", but the latter is a longer 12277 * string - thus the calculation can go wrong (doing it properly and putting 12278 * it into an DOM object and measuring that is horribly(!) slow). Thus as 12279 * a "work around" we provide this option. It will append its value to the 12280 * text that is found to be the longest string for the column - i.e. padding. 12281 * Generally you shouldn't need this! 12282 * @type string 12283 * @default <i>Empty string<i> 12284 * 12285 * @name DataTable.defaults.column.contentPadding 12286 * @dtopt Columns 12287 * 12288 * @example 12289 * // Using `columns` 12290 * $(document).ready( function() { 12291 * $('#example').dataTable( { 12292 * "columns": [ 12293 * null, 12294 * null, 12295 * null, 12296 * { 12297 * "contentPadding": "mmm" 12298 * } 12299 * ] 12300 * } ); 12301 * } ); 12302 */ 12303 "sContentPadding": "", 12304 12305 12306 /** 12307 * Allows a default value to be given for a column's data, and will be used 12308 * whenever a null data source is encountered (this can be because `data` 12309 * is set to null, or because the data source itself is null). 12310 * @type string 12311 * @default null 12312 * 12313 * @name DataTable.defaults.column.defaultContent 12314 * @dtopt Columns 12315 * 12316 * @example 12317 * // Using `columnDefs` 12318 * $(document).ready( function() { 12319 * $('#example').dataTable( { 12320 * "columnDefs": [ 12321 * { 12322 * "data": null, 12323 * "defaultContent": "Edit", 12324 * "targets": [ -1 ] 12325 * } 12326 * ] 12327 * } ); 12328 * } ); 12329 * 12330 * @example 12331 * // Using `columns` 12332 * $(document).ready( function() { 12333 * $('#example').dataTable( { 12334 * "columns": [ 12335 * null, 12336 * null, 12337 * null, 12338 * { 12339 * "data": null, 12340 * "defaultContent": "Edit" 12341 * } 12342 * ] 12343 * } ); 12344 * } ); 12345 */ 12346 "sDefaultContent": null, 12347 12348 12349 /** 12350 * This parameter is only used in DataTables' server-side processing. It can 12351 * be exceptionally useful to know what columns are being displayed on the 12352 * client side, and to map these to database fields. When defined, the names 12353 * also allow DataTables to reorder information from the server if it comes 12354 * back in an unexpected order (i.e. if you switch your columns around on the 12355 * client-side, your server-side code does not also need updating). 12356 * @type string 12357 * @default <i>Empty string</i> 12358 * 12359 * @name DataTable.defaults.column.name 12360 * @dtopt Columns 12361 * 12362 * @example 12363 * // Using `columnDefs` 12364 * $(document).ready( function() { 12365 * $('#example').dataTable( { 12366 * "columnDefs": [ 12367 * { "name": "engine", "targets": [ 0 ] }, 12368 * { "name": "browser", "targets": [ 1 ] }, 12369 * { "name": "platform", "targets": [ 2 ] }, 12370 * { "name": "version", "targets": [ 3 ] }, 12371 * { "name": "grade", "targets": [ 4 ] } 12372 * ] 12373 * } ); 12374 * } ); 12375 * 12376 * @example 12377 * // Using `columns` 12378 * $(document).ready( function() { 12379 * $('#example').dataTable( { 12380 * "columns": [ 12381 * { "name": "engine" }, 12382 * { "name": "browser" }, 12383 * { "name": "platform" }, 12384 * { "name": "version" }, 12385 * { "name": "grade" } 12386 * ] 12387 * } ); 12388 * } ); 12389 */ 12390 "sName": "", 12391 12392 12393 /** 12394 * Defines a data source type for the ordering which can be used to read 12395 * real-time information from the table (updating the internally cached 12396 * version) prior to ordering. This allows ordering to occur on user 12397 * editable elements such as form inputs. 12398 * @type string 12399 * @default std 12400 * 12401 * @name DataTable.defaults.column.orderDataType 12402 * @dtopt Columns 12403 * 12404 * @example 12405 * // Using `columnDefs` 12406 * $(document).ready( function() { 12407 * $('#example').dataTable( { 12408 * "columnDefs": [ 12409 * { "orderDataType": "dom-text", "targets": [ 2, 3 ] }, 12410 * { "type": "numeric", "targets": [ 3 ] }, 12411 * { "orderDataType": "dom-select", "targets": [ 4 ] }, 12412 * { "orderDataType": "dom-checkbox", "targets": [ 5 ] } 12413 * ] 12414 * } ); 12415 * } ); 12416 * 12417 * @example 12418 * // Using `columns` 12419 * $(document).ready( function() { 12420 * $('#example').dataTable( { 12421 * "columns": [ 12422 * null, 12423 * null, 12424 * { "orderDataType": "dom-text" }, 12425 * { "orderDataType": "dom-text", "type": "numeric" }, 12426 * { "orderDataType": "dom-select" }, 12427 * { "orderDataType": "dom-checkbox" } 12428 * ] 12429 * } ); 12430 * } ); 12431 */ 12432 "sSortDataType": "std", 12433 12434 12435 /** 12436 * The title of this column. 12437 * @type string 12438 * @default null <i>Derived from the 'TH' value for this column in the 12439 * original HTML table.</i> 12440 * 12441 * @name DataTable.defaults.column.title 12442 * @dtopt Columns 12443 * 12444 * @example 12445 * // Using `columnDefs` 12446 * $(document).ready( function() { 12447 * $('#example').dataTable( { 12448 * "columnDefs": [ 12449 * { "title": "My column title", "targets": [ 0 ] } 12450 * ] 12451 * } ); 12452 * } ); 12453 * 12454 * @example 12455 * // Using `columns` 12456 * $(document).ready( function() { 12457 * $('#example').dataTable( { 12458 * "columns": [ 12459 * { "title": "My column title" }, 12460 * null, 12461 * null, 12462 * null, 12463 * null 12464 * ] 12465 * } ); 12466 * } ); 12467 */ 12468 "sTitle": null, 12469 12470 12471 /** 12472 * The type allows you to specify how the data for this column will be
12473 * ordered. Four types (string, numeric, date and html (which will strip 12474 * HTML tags before ordering)) are currently available. Note that only date 12475 * formats understood by Javascript's Date() object will be accepted as type 12476 * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 12477 * 'numeric', 'date' or 'html' (by default). Further types can be adding 12478 * through plug-ins. 12479 * @type string 12480 * @default null <i>Auto-detected from raw data</i> 12481 * 12482 * @name DataTable.defaults.column.type 12483 * @dtopt Columns 12484 * 12485 * @example 12486 * // Using `columnDefs` 12487 * $(document).ready( function() { 12488 * $('#example').dataTable( { 12489 * "columnDefs": [ 12490 * { "type": "html", "targets": [ 0 ] } 12491 * ] 12492 * } ); 12493 * } ); 12494 * 12495 * @example 12496 * // Using `columns` 12497 * $(document).ready( function() { 12498 * $('#example').dataTable( { 12499 * "columns": [ 12500 * { "type": "html" }, 12501 * null, 12502 * null, 12503 * null, 12504 * null 12505 * ] 12506 * } ); 12507 * } ); 12508 */ 12509 "sType": null, 12510 12511 12512 /** 12513 * Defining the width of the column, this parameter may take any CSS value 12514 * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not 12515 * been given a specific width through this interface ensuring that the table 12516 * remains readable. 12517 * @type string 12518 * @default null <i>Automatic</i> 12519 * 12520 * @name DataTable.defaults.column.width 12521 * @dtopt Columns 12522 * 12523 * @example 12524 * // Using `columnDefs` 12525 * $(document).ready( function() { 12526 * $('#example').dataTable( { 12527 * "columnDefs": [ 12528 * { "width": "20%", "targets": [ 0 ] } 12529 * ] 12530 * } ); 12531 * } ); 12532 * 12533 * @example 12534 * // Using `columns` 12535 * $(document).ready( function() { 12536 * $('#example').dataTable( { 12537 * "columns": [ 12538 * { "width": "20%" }, 12539 * null, 12540 * null, 12541 * null, 12542 * null 12543 * ] 12544 * } ); 12545 * } ); 12546 */ 12547 "sWidth": null 12548 }; 12549 12550 _fnHungarianMap( DataTable.defaults.column ); 12551 12552 12553 12554 /** 12555 * DataTables settings object - this holds all the information needed for a 12556 * given table, including configuration, data and current application of the 12557 * table options. DataTables does not have a single instance for each DataTable 12558 * with the settings attached to that instance, but rather instances of the 12559 * DataTable "class" are created on-the-fly as needed (typically by a 12560 * $().dataTable() call) and the settings object is then applied to that 12561 * instance. 12562 * 12563 * Note that this object is related to {@link DataTable.defaults} but this 12564 * one is the internal data store for DataTables's cache of columns. It should 12565 * NOT be manipulated outside of DataTables. Any configuration should be done 12566 * through the initialisation options. 12567 * @namespace 12568 * @todo Really should attach the settings object to individual instances so we 12569 * don't need to create new instances on each $().dataTable() call (if the 12570 * table already exists). It would also save passing oSettings around and 12571 * into every single function. However, this is a very significant 12572 * architecture change for DataTables and will almost certainly break 12573 * backwards compatibility with older installations. This is something that 12574 * will be done in 2.0. 12575 */ 12576 DataTable.models.oSettings = { 12577 /** 12578 * Primary features of DataTables and their enablement state. 12579 * @namespace 12580 */ 12581 "oFeatures": { 12582 12583 /** 12584 * Flag to say if DataTables should automatically try to calculate the 12585 * optimum table and columns widths (true) or not (false). 12586 * Note that this parameter will be set by the initialisation routine. To 12587 * set a default use {@link DataTable.defaults}. 12588 * @type boolean 12589 */ 12590 "bAutoWidth": null, 12591 12592 /** 12593 * Delay the creation of TR and TD elements until they are actually 12594 * needed by a driven page draw. This can give a significant speed 12595 * increase for Ajax source and Javascript source data, but makes no 12596 * difference at all fro DOM and server-side processing tables. 12597 * Note that this parameter will be set by the initialisation routine. To 12598 * set a default use {@link DataTable.defaults}. 12599 * @type boolean 12600 */ 12601 "bDeferRender": null, 12602 12603 /** 12604 * Enable filtering on the table or not. Note that if this is disabled 12605 * then there is no filtering at all on the table, including fnFilter. 12606 * To just remove the filtering input use sDom and remove the 'f' option. 12607 * Note that this parameter will be set by the initialisation routine. To 12608 * set a default use {@link DataTable.defaults}. 12609 * @type boolean 12610 */ 12611 "bFilter": null, 12612 12613 /** 12614 * Table information element (the 'Showing x of y records' div) enable 12615 * flag. 12616 * Note that this parameter will be set by the initialisation routine. To 12617 * set a default use {@link DataTable.defaults}. 12618 * @type boolean 12619 */ 12620 "bInfo": null, 12621 12622 /** 12623 * Present a user control allowing the end user to change the page size 12624 * when pagination is enabled. 12625 * Note that this parameter will be set by the initialisation routine. To 12626 * set a default use {@link DataTable.defaults}. 12627 * @type boolean 12628 */ 12629 "bLengthChange": null, 12630 12631 /** 12632 * Pagination enabled or not. Note that if this is disabled then length 12633 * changing must also be disabled. 12634 * Note that this parameter will be set by the initialisation routine. To 12635 * set a default use {@link DataTable.defaults}. 12636 * @type boolean 12637 */ 12638 "bPaginate": null, 12639 12640 /** 12641 * Processing indicator enable flag whenever DataTables is enacting a 12642 * user request - typically an Ajax request for server-side processing. 12643 * Note that this parameter will be set by the initialisation routine. To 12644 * set a default use {@link DataTable.defaults}. 12645 * @type boolean 12646 */ 12647 "bProcessing": null, 12648 12649 /** 12650 * Server-side processing enabled flag - when enabled DataTables will 12651 * get all data from the server for every draw - there is no filtering, 12652 * sorting or paging done on the client-side. 12653 * Note that this parameter will be set by the initialisation routine. To 12654 * set a default use {@link DataTable.defaults}. 12655 * @type boolean 12656 */ 12657 "bServerSide": null, 12658 12659 /** 12660 * Sorting enablement flag. 12661 * Note that this parameter will be set by the initialisation routine. To 12662 * set a default use {@link DataTable.defaults}. 12663 * @type boolean 12664 */ 12665 "bSort": null, 12666 12667 /**
12668 * Multi-column sorting 12669 * Note that this parameter will be set by the initialisation routine. To 12670 * set a default use {@link DataTable.defaults}. 12671 * @type boolean 12672 */ 12673 "bSortMulti": null, 12674 12675 /** 12676 * Apply a class to the columns which are being sorted to provide a 12677 * visual highlight or not. This can slow things down when enabled since 12678 * there is a lot of DOM interaction. 12679 * Note that this parameter will be set by the initialisation routine. To 12680 * set a default use {@link DataTable.defaults}. 12681 * @type boolean 12682 */ 12683 "bSortClasses": null, 12684 12685 /** 12686 * State saving enablement flag. 12687 * Note that this parameter will be set by the initialisation routine. To 12688 * set a default use {@link DataTable.defaults}. 12689 * @type boolean 12690 */ 12691 "bStateSave": null 12692 }, 12693 12694 12695 /** 12696 * Scrolling settings for a table. 12697 * @namespace 12698 */ 12699 "oScroll": { 12700 /** 12701 * When the table is shorter in height than sScrollY, collapse the 12702 * table container down to the height of the table (when true). 12703 * Note that this parameter will be set by the initialisation routine. To 12704 * set a default use {@link DataTable.defaults}. 12705 * @type boolean 12706 */ 12707 "bCollapse": null, 12708 12709 /** 12710 * Width of the scrollbar for the web-browser's platform. Calculated 12711 * during table initialisation. 12712 * @type int 12713 * @default 0 12714 */ 12715 "iBarWidth": 0, 12716 12717 /** 12718 * Viewport width for horizontal scrolling. Horizontal scrolling is 12719 * disabled if an empty string. 12720 * Note that this parameter will be set by the initialisation routine. To 12721 * set a default use {@link DataTable.defaults}. 12722 * @type string 12723 */ 12724 "sX": null, 12725 12726 /** 12727 * Width to expand the table to when using x-scrolling. Typically you 12728 * should not need to use this. 12729 * Note that this parameter will be set by the initialisation routine. To 12730 * set a default use {@link DataTable.defaults}. 12731 * @type string 12732 * @deprecated 12733 */ 12734 "sXInner": null, 12735 12736 /** 12737 * Viewport height for vertical scrolling. Vertical scrolling is disabled 12738 * if an empty string. 12739 * Note that this parameter will be set by the initialisation routine. To 12740 * set a default use {@link DataTable.defaults}. 12741 * @type string 12742 */ 12743 "sY": null 12744 }, 12745 12746 /** 12747 * Language information for the table. 12748 * @namespace 12749 * @extends DataTable.defaults.oLanguage 12750 */ 12751 "oLanguage": { 12752 /** 12753 * Information callback function. See 12754 * {@link DataTable.defaults.fnInfoCallback} 12755 * @type function 12756 * @default null 12757 */ 12758 "fnInfoCallback": null 12759 }, 12760 12761 /** 12762 * Browser support parameters 12763 * @namespace 12764 */ 12765 "oBrowser": { 12766 /** 12767 * Indicate if the browser incorrectly calculates width:100% inside a 12768 * scrolling element (IE6/7) 12769 * @type boolean 12770 * @default false 12771 */ 12772 "bScrollOversize": false, 12773 12774 /** 12775 * Determine if the vertical scrollbar is on the right or left of the 12776 * scrolling container - needed for rtl language layout, although not 12777 * all browsers move the scrollbar (Safari). 12778 * @type boolean 12779 * @default false 12780 */ 12781 "bScrollbarLeft": false 12782 }, 12783 12784 12785 "ajax": null, 12786 12787 12788 /** 12789 * Array referencing the nodes which are used for the features. The 12790 * parameters of this object match what is allowed by sDom - i.e. 12791 * <ul> 12792 * <li>'l' - Length changing</li> 12793 * <li>'f' - Filtering input</li> 12794 * <li>'t' - The table!</li> 12795 * <li>'i' - Information</li> 12796 * <li>'p' - Pagination</li> 12797 * <li>'r' - pRocessing</li> 12798 * </ul> 12799 * @type array 12800 * @default [] 12801 */ 12802 "aanFeatures": [], 12803 12804 /** 12805 * Store data information - see {@link DataTable.models.oRow} for detailed 12806 * information. 12807 * @type array 12808 * @default [] 12809 */ 12810 "aoData": [], 12811 12812 /** 12813 * Array of indexes which are in the current display (after filtering etc) 12814 * @type array 12815 * @default [] 12816 */ 12817 "aiDisplay": [], 12818 12819 /** 12820 * Array of indexes for display - no filtering 12821 * @type array 12822 * @default [] 12823 */ 12824 "aiDisplayMaster": [], 12825 12826 /** 12827 * Store information about each column that is in use 12828 * @type array 12829 * @default [] 12830 */ 12831 "aoColumns": [], 12832 12833 /** 12834 * Store information about the table's header 12835 * @type array 12836 * @default [] 12837 */ 12838 "aoHeader": [], 12839 12840 /** 12841 * Store information about the table's footer 12842 * @type array 12843 * @default [] 12844 */ 12845 "aoFooter": [], 12846 12847 /** 12848 * Store the applied global search information in case we want to force a 12849 * research or compare the old search to a new one. 12850 * Note that this parameter will be set by the initialisation routine. To 12851 * set a default use {@link DataTable.defaults}. 12852 * @namespace 12853 * @extends DataTable.models.oSearch 12854 */ 12855 "oPreviousSearch": {}, 12856 12857 /** 12858 * Store the applied search for each column - see 12859 * {@link DataTable.models.oSearch} for the format that is used for the 12860 * filtering information for each column. 12861 * @type array 12862 * @default [] 12863 */ 12864 "aoPreSearchCols": [], 12865 12866 /** 12867 * Sorting that is applied to the table. Note that the inner arrays are 12868 * used in the following manner: 12869 * <ul> 12870 * <li>Index 0 - column number</li> 12871 * <li>Index 1 - current sorting direction</li> 12872 * </ul> 12873 * Note that this parameter will be set by the initialisation routine. To 12874 * set a default use {@link DataTable.defaults}. 12875 * @type array 12876 * @todo These inner arrays should really be objects 12877 */ 12878 "aaSorting": null, 12879 12880 /** 12881 * Sorting that is always applied to the table (i.e. prefixed in front of 12882 * aaSorting). 12883 * Note that this parameter will be set by the initialisation routine. To 12884 * set a default use {@link DataTable.defaults}. 12885 * @type array 12886 * @default [] 12887 */ 12888 "aaSortingFixed": [], 12889 12890 /** 12891 * Classes to use for the striping of a table. 12892 * Note that this parameter will be set by the initialisation routine. To 12893 * set a default use {@link DataTable.defaults}. 12894 * @type array 12895 * @default [] 12896 */ 12897 "asStripeClasses": null, 12898 12899 /** 12900 * If restoring a table - we should restore its striping classes as well 12901 * @type array 12902 * @default [] 12903 */ 12904 "asDestroyStripes": [], 12905 12906 /** 12907 * If restoring a table - we should restore its width 12908 * @type int 12909 * @default 0 12910 */ 12911 "sDestroyWidth": 0, 12912 12913 /** 12914 * Callback functions array for every time a row is inserted (i.e. on a draw). 12915 * @type array 12916 * @default [] 12917 */ 12918 "aoRowCallback": [], 12919 12920 /** 12921 * Callback functions for the header on each draw. 12922 * @type array 12923 * @default [] 12924 */ 12925 "aoHeaderCallback": [], 12926 12927 /** 12928 * Callback function for the footer on each draw. 12929 * @type array 12930 * @default [] 12931 */ 12932 "aoFooterCallback": [], 12933 12934 /** 12935 * Array of callback functions for draw callback functions 12936 * @type array 12937 * @default [] 12938 */ 12939 "aoDrawCallback": [], 12940 12941 /** 12942 * Array of callback functions for row created function 12943 * @type array 12944 * @default [] 12945 */ 12946 "aoRowCreatedCallback": [], 12947 12948 /** 12949 * Callback functions for just before the table is redrawn. A return of 12950 * false will be used to cancel the draw. 12951 * @type array 12952 * @default [] 12953 */ 12954 "aoPreDrawCallback": [], 12955 12956 /** 12957 * Callback functions for when the table has been initialised. 12958 * @type array 12959 * @default [] 12960 */ 12961 "aoInitComplete": [], 12962 12963 12964 /** 12965 * Callbacks for modifying the settings to be stored for state saving, prior to 12966 * saving state. 12967 * @type array 12968 * @default [] 12969 */ 12970 "aoStateSaveParams": [], 12971 12972 /** 12973 * Callbacks for modifying the settings that have been stored for state saving 12974 * prior to using the stored values to restore the state. 12975 * @type array 12976 * @default [] 12977 */ 12978 "aoStateLoadParams": [], 12979 12980 /** 12981 * Callbacks for operating on the settings object once the saved state has been 12982 * loaded 12983 * @type array 12984 * @default [] 12985 */ 12986 "aoStateLoaded": [], 12987 12988 /** 12989 * Cache the table ID for quick access 12990 * @type string 12991 * @default <i>Empty string</i> 12992 */ 12993 "sTableId": "", 12994 12995 /** 12996 * The TABLE node for the main table 12997 * @type node 12998 * @default null 12999 */ 13000 "nTable": null, 13001 13002 /** 13003 * Permanent ref to the thead element 13004 * @type node 13005 * @default null 13006 */ 13007 "nTHead": null, 13008 13009 /** 13010 * Permanent ref to the tfoot element - if it exists 13011 * @type node 13012 * @default null 13013 */ 13014 "nTFoot": null, 13015 13016 /** 13017 * Permanent ref to the tbody element 13018 * @type node 13019 * @default null 13020 */ 13021 "nTBody": null, 13022 13023 /** 13024 * Cache the wrapper node (contains all DataTables controlled elements) 13025 * @type node 13026 * @default null 13027 */ 13028 "nTableWrapper": null, 13029 13030 /** 13031 * Indicate if when using server-side processing the loading of data 13032 * should be deferred until the second draw. 13033 * Note that this parameter will be set by the initialisation routine. To 13034 * set a default use {@link DataTable.defaults}. 13035 * @type boolean 13036 * @default false 13037 */ 13038 "bDeferLoading": false, 13039 13040 /** 13041 * Indicate if all required information has been read in 13042 * @type boolean 13043 * @default false 13044 */ 13045 "bInitialised": false, 13046 13047 /** 13048 * Information about open rows. Each object in the array has the parameters 13049 * 'nTr' and 'nParent' 13050 * @type array 13051 * @default [] 13052 */ 13053 "aoOpenRows": [], 13054 13055 /**
13056 * Dictate the positioning of DataTables' control elements - see 13057 * {@link DataTable.model.oInit.sDom}. 13058 * Note that this parameter will be set by the initialisation routine. To 13059 * set a default use {@link DataTable.defaults}. 13060 * @type string 13061 * @default null 13062 */ 13063 "sDom": null, 13064 13065 /** 13066 * Search delay (in mS) 13067 * @type integer 13068 * @default null 13069 */ 13070 "searchDelay": null, 13071 13072 /** 13073 * Which type of pagination should be used. 13074 * Note that this parameter will be set by the initialisation routine. To 13075 * set a default use {@link DataTable.defaults}. 13076 * @type string 13077 * @default two_button 13078 */ 13079 "sPaginationType": "two_button", 13080 13081 /** 13082 * The state duration (for `stateSave`) in seconds. 13083 * Note that this parameter will be set by the initialisation routine. To 13084 * set a default use {@link DataTable.defaults}. 13085 * @type int 13086 * @default 0 13087 */ 13088 "iStateDuration": 0, 13089 13090 /** 13091 * Array of callback functions for state saving. Each array element is an 13092 * object with the following parameters: 13093 * <ul> 13094 * <li>function:fn - function to call. Takes two parameters, oSettings 13095 * and the JSON string to save that has been thus far created. Returns 13096 * a JSON string to be inserted into a json object 13097 * (i.e. '"param": [ 0, 1, 2]')</li> 13098 * <li>string:sName - name of callback</li> 13099 * </ul> 13100 * @type array 13101 * @default [] 13102 */ 13103 "aoStateSave": [], 13104 13105 /** 13106 * Array of callback functions for state loading. Each array element is an 13107 * object with the following parameters: 13108 * <ul> 13109 * <li>function:fn - function to call. Takes two parameters, oSettings 13110 * and the object stored. May return false to cancel state loading</li> 13111 * <li>string:sName - name of callback</li> 13112 * </ul> 13113 * @type array 13114 * @default [] 13115 */ 13116 "aoStateLoad": [], 13117 13118 /** 13119 * State that was saved. Useful for back reference 13120 * @type object 13121 * @default null 13122 */ 13123 "oSavedState": null, 13124 13125 /** 13126 * State that was loaded. Useful for back reference 13127 * @type object 13128 * @default null 13129 */ 13130 "oLoadedState": null, 13131 13132 /** 13133 * Source url for AJAX data for the table. 13134 * Note that this parameter will be set by the initialisation routine. To 13135 * set a default use {@link DataTable.defaults}. 13136 * @type string 13137 * @default null 13138 */ 13139 "sAjaxSource": null, 13140 13141 /** 13142 * Property from a given object from which to read the table data from. This 13143 * can be an empty string (when not server-side processing), in which case 13144 * it is assumed an an array is given directly. 13145 * Note that this parameter will be set by the initialisation routine. To 13146 * set a default use {@link DataTable.defaults}. 13147 * @type string 13148 */ 13149 "sAjaxDataProp": null, 13150 13151 /** 13152 * Note if draw should be blocked while getting data 13153 * @type boolean 13154 * @default true 13155 */ 13156 "bAjaxDataGet": true, 13157 13158 /** 13159 * The last jQuery XHR object that was used for server-side data gathering. 13160 * This can be used for working with the XHR information in one of the 13161 * callbacks 13162 * @type object 13163 * @default null 13164 */ 13165 "jqXHR": null, 13166 13167 /** 13168 * JSON returned from the server in the last Ajax request 13169 * @type object 13170 * @default undefined 13171 */ 13172 "json": undefined, 13173 13174 /** 13175 * Data submitted as part of the last Ajax request 13176 * @type object 13177 * @default undefined 13178 */ 13179 "oAjaxData": undefined, 13180 13181 /** 13182 * Function to get the server-side data. 13183 * Note that this parameter will be set by the initialisation routine. To 13184 * set a default use {@link DataTable.defaults}. 13185 * @type function 13186 */ 13187 "fnServerData": null, 13188 13189 /** 13190 * Functions which are called prior to sending an Ajax request so extra 13191 * parameters can easily be sent to the server 13192 * @type array 13193 * @default [] 13194 */ 13195 "aoServerParams": [], 13196 13197 /** 13198 * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 13199 * required). 13200 * Note that this parameter will be set by the initialisation routine. To 13201 * set a default use {@link DataTable.defaults}. 13202 * @type string 13203 */ 13204 "sServerMethod": null, 13205 13206 /** 13207 * Format numbers for display. 13208 * Note that this parameter will be set by the initialisation routine. To 13209 * set a default use {@link DataTable.defaults}. 13210 * @type function 13211 */ 13212 "fnFormatNumber": null, 13213 13214 /** 13215 * List of options that can be used for the user selectable length menu. 13216 * Note that this parameter will be set by the initialisation routine. To 13217 * set a default use {@link DataTable.defaults}. 13218 * @type array 13219 * @default [] 13220 */ 13221 "aLengthMenu": null, 13222 13223 /** 13224 * Counter for the draws that the table does. Also used as a tracker for 13225 * server-side processing 13226 * @type int 13227 * @default 0 13228 */ 13229 "iDraw": 0, 13230 13231 /** 13232 * Indicate if a redraw is being done - useful for Ajax 13233 * @type boolean 13234 * @default false 13235 */ 13236 "bDrawing": false, 13237 13238 /** 13239 * Draw index (iDraw) of the last error when parsing the returned data 13240 * @type int 13241 * @default -1 13242 */ 13243 "iDrawError": -1, 13244 13245 /** 13246 * Paging display length 13247 * @type int 13248 * @default 10 13249 */ 13250 "_iDisplayLength": 10, 13251 13252 /** 13253 * Paging start point - aiDisplay index 13254 * @type int 13255 * @default 0 13256 */ 13257 "_iDisplayStart": 0, 13258 13259 /** 13260 * Server-side processing - number of records in the result set 13261 * (i.e. before filtering), Use fnRecordsTotal rather than 13262 * this property to get the value of the number of records, regardless of 13263 * the server-side processing setting. 13264 * @type int 13265 * @default 0 13266 * @private 13267 */ 13268 "_iRecordsTotal": 0, 13269 13270 /** 13271 * Server-side processing - number of records in the current display set 13272 * (i.e. after filtering). Use fnRecordsDisplay rather than 13273 * this property to get the value of the number of records, regardless of 13274 * the server-side processing setting. 13275 * @type boolean 13276 * @default 0 13277 * @private 13278 */ 13279 "_iRecordsDisplay": 0, 13280 13281 /** 13282 * Flag to indicate if jQuery UI marking and classes should be used. 13283 * Note that this parameter will be set by the initialisation routine. To 13284 * set a default use {@link DataTable.defaults}. 13285 * @type boolean 13286 */ 13287 "bJUI": null, 13288 13289 /** 13290 * The classes to use for the table 13291 * @type object 13292 * @default {} 13293 */
13294 "oClasses": {}, 13295 13296 /** 13297 * Flag attached to the settings object so you can check in the draw 13298 * callback if filtering has been done in the draw. Deprecated in favour of 13299 * events. 13300 * @type boolean 13301 * @default false 13302 * @deprecated 13303 */ 13304 "bFiltered": false, 13305 13306 /** 13307 * Flag attached to the settings object so you can check in the draw 13308 * callback if sorting has been done in the draw. Deprecated in favour of 13309 * events. 13310 * @type boolean 13311 * @default false 13312 * @deprecated 13313 */ 13314 "bSorted": false, 13315 13316 /** 13317 * Indicate that if multiple rows are in the header and there is more than 13318 * one unique cell per column, if the top one (true) or bottom one (false) 13319 * should be used for sorting / title by DataTables. 13320 * Note that this parameter will be set by the initialisation routine. To 13321 * set a default use {@link DataTable.defaults}. 13322 * @type boolean 13323 */ 13324 "bSortCellsTop": null, 13325 13326 /** 13327 * Initialisation object that is used for the table 13328 * @type object 13329 * @default null 13330 */ 13331 "oInit": null, 13332 13333 /** 13334 * Destroy callback functions - for plug-ins to attach themselves to the 13335 * destroy so they can clean up markup and events. 13336 * @type array 13337 * @default [] 13338 */ 13339 "aoDestroyCallback": [], 13340 13341 13342 /** 13343 * Get the number of records in the current record set, before filtering 13344 * @type function 13345 */ 13346 "fnRecordsTotal": function () 13347 { 13348 return _fnDataSource( this ) == 'ssp' ? 13349 this._iRecordsTotal * 1 : 13350 this.aiDisplayMaster.length; 13351 }, 13352 13353 /** 13354 * Get the number of records in the current record set, after filtering 13355 * @type function 13356 */ 13357 "fnRecordsDisplay": function () 13358 { 13359 return _fnDataSource( this ) == 'ssp' ? 13360 this._iRecordsDisplay * 1 : 13361 this.aiDisplay.length; 13362 }, 13363 13364 /** 13365 * Get the display end point - aiDisplay index 13366 * @type function 13367 */ 13368 "fnDisplayEnd": function () 13369 { 13370 var 13371 len = this._iDisplayLength, 13372 start = this._iDisplayStart, 13373 calc = start + len, 13374 records = this.aiDisplay.length, 13375 features = this.oFeatures, 13376 paginate = features.bPaginate; 13377 13378 if ( features.bServerSide ) { 13379 return paginate === false || len === -1 ? 13380 start + records : 13381 Math.min( start+len, this._iRecordsDisplay ); 13382 } 13383 else { 13384 return ! paginate || calc>records || len===-1 ? 13385 records : 13386 calc; 13387 } 13388 }, 13389 13390 /** 13391 * The DataTables object for this table 13392 * @type object 13393 * @default null 13394 */ 13395 "oInstance": null, 13396 13397 /** 13398 * Unique identifier for each instance of the DataTables object. If there 13399 * is an ID on the table node, then it takes that value, otherwise an 13400 * incrementing internal counter is used. 13401 * @type string 13402 * @default null 13403 */ 13404 "sInstance": null, 13405 13406 /** 13407 * tabindex attribute value that is added to DataTables control elements, allowing 13408 * keyboard navigation of the table and its controls. 13409 */ 13410 "iTabIndex": 0, 13411 13412 /** 13413 * DIV container for the footer scrolling table if scrolling 13414 */ 13415 "nScrollHead": null, 13416 13417 /** 13418 * DIV container for the footer scrolling table if scrolling 13419 */ 13420 "nScrollFoot": null, 13421 13422 /** 13423 * Last applied sort 13424 * @type array 13425 * @default [] 13426 */ 13427 "aLastSort": [], 13428 13429 /** 13430 * Stored plug-in instances 13431 * @type object 13432 * @default {} 13433 */ 13434 "oPlugins": {} 13435 }; 13436 13437 /** 13438 * Extension object for DataTables that is used to provide all extension 13439 * options. 13440 * 13441 * Note that the `DataTable.ext` object is available through 13442 * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is 13443 * also aliased to `jQuery.fn.dataTableExt` for historic reasons. 13444 * @namespace 13445 * @extends DataTable.models.ext 13446 */ 13447 13448 13449 /** 13450 * DataTables extensions 13451 * 13452 * This namespace acts as a collection area for plug-ins that can be used to 13453 * extend DataTables capabilities. Indeed many of the build in methods 13454 * use this method to provide their own capabilities (sorting methods for 13455 * example). 13456 * 13457 * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy 13458 * reasons 13459 * 13460 * @namespace 13461 */ 13462 DataTable.ext = _ext = { 13463 /** 13464 * Buttons. For use with the Buttons extension for DataTables. This is 13465 * defined here so other extensions can define buttons regardless of load 13466 * order. It is _not_ used by DataTables core. 13467 * 13468 * @type object 13469 * @default {} 13470 */ 13471 buttons: {}, 13472 13473 13474 /** 13475 * Element class names 13476 * 13477 * @type object 13478 * @default {} 13479 */ 13480 classes: {}, 13481 13482 13483 /** 13484 * Error reporting. 13485 * 13486 * How should DataTables report an error. Can take the value 'alert', 13487 * 'throw', 'none' or a function. 13488 * 13489 * @type string|function 13490 * @default alert 13491 */ 13492 errMode: "alert", 13493 13494 13495 /**
13496 * Feature plug-ins. 13497 * 13498 * This is an array of objects which describe the feature plug-ins that are 13499 * available to DataTables. These feature plug-ins are then available for 13500 * use through the `dom` initialisation option. 13501 * 13502 * Each feature plug-in is described by an object which must have the 13503 * following properties: 13504 * 13505 * * `fnInit` - function that is used to initialise the plug-in, 13506 * * `cFeature` - a character so the feature can be enabled by the `dom` 13507 * instillation option. This is case sensitive. 13508 * 13509 * The `fnInit` function has the following input parameters: 13510 * 13511 * 1. `{object}` DataTables settings object: see 13512 * {@link DataTable.models.oSettings} 13513 * 13514 * And the following return is expected: 13515 * 13516 * * {node|null} The element which contains your feature. Note that the 13517 * return may also be void if your plug-in does not require to inject any 13518 * DOM elements into DataTables control (`dom`) - for example this might 13519 * be useful when developing a plug-in which allows table control via 13520 * keyboard entry 13521 * 13522 * @type array 13523 * 13524 * @example 13525 * $.fn.dataTable.ext.features.push( { 13526 * "fnInit": function( oSettings ) { 13527 * return new TableTools( { "oDTSettings": oSettings } ); 13528 * }, 13529 * "cFeature": "T" 13530 * } ); 13531 */ 13532 feature: [], 13533 13534 13535 /** 13536 * Row searching. 13537 * 13538 * This method of searching is complimentary to the default type based 13539 * searching, and a lot more comprehensive as it allows you complete control 13540 * over the searching logic. Each element in this array is a function 13541 * (parameters described below) that is called for every row in the table, 13542 * and your logic decides if it should be included in the searching data set 13543 * or not. 13544 * 13545 * Searching functions have the following input parameters: 13546 * 13547 * 1. `{object}` DataTables settings object: see 13548 * {@link DataTable.models.oSettings} 13549 * 2. `{array|object}` Data for the row to be processed (same as the 13550 * original format that was passed in as the data source, or an array 13551 * from a DOM data source 13552 * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which 13553 * can be useful to retrieve the `TR` element if you need DOM interaction. 13554 * 13555 * And the following return is expected: 13556 * 13557 * * {boolean} Include the row in the searched result set (true) or not 13558 * (false) 13559 * 13560 * Note that as with the main search ability in DataTables, technically this 13561 * is "filtering", since it is subtractive. However, for consistency in 13562 * naming we call it searching here. 13563 * 13564 * @type array 13565 * @default [] 13566 * 13567 * @example 13568 * // The following example shows custom search being applied to the 13569 * // fourth column (i.e. the data[3] index) based on two input values 13570 * // from the end-user, matching the data in a certain range. 13571 * $.fn.dataTable.ext.search.push( 13572 * function( settings, data, dataIndex ) { 13573 * var min = document.getElementById('min').value * 1; 13574 * var max = document.getElementById('max').value * 1; 13575 * var version = data[3] == "-" ? 0 : data[3]*1; 13576 * 13577 * if ( min == "" && max == "" ) { 13578 * return true; 13579 * } 13580 * else if ( min == "" && version < max ) { 13581 * return true; 13582 * } 13583 * else if ( min < version && "" == max ) { 13584 * return true; 13585 * } 13586 * else if ( min < version && version < max ) { 13587 * return true; 13588 * } 13589 * return false; 13590 * } 13591 * ); 13592 */ 13593 search: [], 13594 13595 13596 /** 13597 * Internal functions, exposed for used in plug-ins. 13598 * 13599 * Please note that you should not need to use the internal methods for 13600 * anything other than a plug-in (and even then, try to avoid if possible). 13601 * The internal function may change between releases. 13602 * 13603 * @type object 13604 * @default {} 13605 */ 13606 internal: {}, 13607 13608 13609 /** 13610 * Legacy configuration options. Enable and disable legacy options that 13611 * are available in DataTables. 13612 * 13613 * @type object 13614 */ 13615 legacy: { 13616 /** 13617 * Enable / disable DataTables 1.9 compatible server-side processing 13618 * requests 13619 * 13620 * @type boolean 13621 * @default null 13622 */ 13623 ajax: null 13624 }, 13625 13626 13627 /** 13628 * Pagination plug-in methods. 13629 * 13630 * Each entry in this object is a function and defines which buttons should 13631 * be shown by the pagination rendering method that is used for the table: 13632 * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the 13633 * buttons are displayed in the document, while the functions here tell it 13634 * what buttons to display. This is done by returning an array of button 13635 * descriptions (what each button will do). 13636 * 13637 * Pagination types (the four built in options and any additional plug-in 13638 * options defined here) can be used through the `paginationType` 13639 * initialisation parameter. 13640 * 13641 * The functions defined take two parameters: 13642 * 13643 * 1. `{int} page` The current page index 13644 * 2. `{int} pages` The number of pages in the table 13645 * 13646 * Each function is expected to return an array where each element of the 13647 * array can be one of: 13648 * 13649 * * `first` - Jump to first page when activated 13650 * * `last` - Jump to last page when activated 13651 * * `previous` - Show previous page when activated 13652 * * `next` - Show next page when activated 13653 * * `{int}` - Show page of the index given 13654 * * `{array}` - A nested array containing the above elements to add a 13655 * containing 'DIV' element (might be useful for styling). 13656 * 13657 * Note that DataTables v1.9- used this object slightly differently whereby 13658 * an object with two functions would be defined for each plug-in. That 13659 * ability is still supported by DataTables 1.10+ to provide backwards 13660 * compatibility, but this option of use is now decremented and no longer 13661 * documented in DataTables 1.10+. 13662 * 13663 * @type object 13664 * @default {} 13665 * 13666 * @example 13667 * // Show previous, next and current page buttons only 13668 * $.fn.dataTableExt.oPagination.current = function ( page, pages ) { 13669 * return [ 'previous', page, 'next' ]; 13670 * }; 13671 */ 13672 pager: {}, 13673 13674 13675 renderer: { 13676 pageButton: {}, 13677 header: {} 13678 }, 13679 13680 13681 /** 13682 * Ordering plug-ins - custom data source 13683 *
13684 * The extension options for ordering of data available here is complimentary 13685 * to the default type based ordering that DataTables typically uses. It 13686 * allows much greater control over the the data that is being used to 13687 * order a column, but is necessarily therefore more complex. 13688 * 13689 * This type of ordering is useful if you want to do ordering based on data 13690 * live from the DOM (for example the contents of an 'input' element) rather 13691 * than just the static string that DataTables knows of. 13692 * 13693 * The way these plug-ins work is that you create an array of the values you 13694 * wish to be ordering for the column in question and then return that 13695 * array. The data in the array much be in the index order of the rows in 13696 * the table (not the currently ordering order!). Which order data gathering 13697 * function is run here depends on the `dt-init columns.orderDataType` 13698 * parameter that is used for the column (if any). 13699 * 13700 * The functions defined take two parameters: 13701 * 13702 * 1. `{object}` DataTables settings object: see 13703 * {@link DataTable.models.oSettings} 13704 * 2. `{int}` Target column index 13705 * 13706 * Each function is expected to return an array: 13707 * 13708 * * `{array}` Data for the column to be ordering upon 13709 * 13710 * @type array 13711 * 13712 * @example 13713 * // Ordering using `input` node values 13714 * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col ) 13715 * { 13716 * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) { 13717 * return $('input', td).val(); 13718 * } ); 13719 * } 13720 */ 13721 order: {}, 13722 13723 13724 /** 13725 * Type based plug-ins. 13726 * 13727 * Each column in DataTables has a type assigned to it, either by automatic 13728 * detection or by direct assignment using the `type` option for the column. 13729 * The type of a column will effect how it is ordering and search (plug-ins 13730 * can also make use of the column type if required). 13731 * 13732 * @namespace 13733 */ 13734 type: { 13735 /** 13736 * Type detection functions. 13737 * 13738 * The functions defined in this object are used to automatically detect 13739 * a column's type, making initialisation of DataTables super easy, even 13740 * when complex data is in the table. 13741 * 13742 * The functions defined take two parameters: 13743 * 13744 * 1. `{*}` Data from the column cell to be analysed 13745 * 2. `{settings}` DataTables settings object. This can be used to 13746 * perform context specific type detection - for example detection 13747 * based on language settings such as using a comma for a decimal 13748 * place. Generally speaking the options from the settings will not 13749 * be required 13750 * 13751 * Each function is expected to return: 13752 * 13753 * * `{string|null}` Data type detected, or null if unknown (and thus 13754 * pass it on to the other type detection functions. 13755 * 13756 * @type array 13757 * 13758 * @example 13759 * // Currency type detection plug-in: 13760 * $.fn.dataTable.ext.type.detect.push( 13761 * function ( data, settings ) { 13762 * // Check the numeric part 13763 * if ( ! $.isNumeric( data.substring(1) ) ) { 13764 * return null; 13765 * } 13766 * 13767 * // Check prefixed by currency 13768 * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) { 13769 * return 'currency'; 13770 * } 13771 * return null; 13772 * } 13773 * ); 13774 */ 13775 detect: [], 13776 13777 13778 /** 13779 * Type based search formatting. 13780 * 13781 * The type based searching functions can be used to pre-format the 13782 * data to be search on. For example, it can be used to strip HTML 13783 * tags or to de-format telephone numbers for numeric only searching. 13784 * 13785 * Note that is a search is not defined for a column of a given type, 13786 * no search formatting will be performed. 13787 * 13788 * Pre-processing of searching data plug-ins - When you assign the sType 13789 * for a column (or have it automatically detected for you by DataTables 13790 * or a type detection plug-in), you will typically be using this for 13791 * custom sorting, but it can also be used to provide custom searching 13792 * by allowing you to pre-processing the data and returning the data in 13793 * the format that should be searched upon. This is done by adding 13794 * functions this object with a parameter name which matches the sType 13795 * for that target column. This is the corollary of <i>afnSortData</i> 13796 * for searching data. 13797 * 13798 * The functions defined take a single parameter: 13799 * 13800 * 1. `{*}` Data from the column cell to be prepared for searching 13801 *
13802 * Each function is expected to return: 13803 * 13804 * * `{string|null}` Formatted string that will be used for the searching. 13805 * 13806 * @type object 13807 * @default {} 13808 * 13809 * @example 13810 * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) { 13811 * return d.replace(/\n/g," ").replace( /<.*?>/g, "" ); 13812 * } 13813 */ 13814 search: {}, 13815 13816 13817 /** 13818 * Type based ordering. 13819 * 13820 * The column type tells DataTables what ordering to apply to the table 13821 * when a column is sorted upon. The order for each type that is defined, 13822 * is defined by the functions available in this object. 13823 * 13824 * Each ordering option can be described by three properties added to 13825 * this object: 13826 * 13827 * * `{type}-pre` - Pre-formatting function 13828 * * `{type}-asc` - Ascending order function 13829 * * `{type}-desc` - Descending order function 13830 * 13831 * All three can be used together, only `{type}-pre` or only 13832 * `{type}-asc` and `{type}-desc` together. It is generally recommended 13833 * that only `{type}-pre` is used, as this provides the optimal 13834 * implementation in terms of speed, although the others are provided 13835 * for compatibility with existing Javascript sort functions. 13836 * 13837 * `{type}-pre`: Functions defined take a single parameter: 13838 * 13839 * 1. `{*}` Data from the column cell to be prepared for ordering 13840 * 13841 * And return: 13842 * 13843 * * `{*}` Data to be sorted upon 13844 * 13845 * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort 13846 * functions, taking two parameters: 13847 * 13848 * 1. `{*}` Data to compare to the second parameter 13849 * 2. `{*}` Data to compare to the first parameter 13850 * 13851 * And returning: 13852 * 13853 * * `{*}` Ordering match: <0 if first parameter should be sorted lower 13854 * than the second parameter, ===0 if the two parameters are equal and 13855 * >0 if the first parameter should be sorted height than the second 13856 * parameter. 13857 * 13858 * @type object 13859 * @default {} 13860 * 13861 * @example 13862 * // Numeric ordering of formatted numbers with a pre-formatter 13863 * $.extend( $.fn.dataTable.ext.type.order, { 13864 * "string-pre": function(x) { 13865 * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" ); 13866 * return parseFloat( a ); 13867 * } 13868 * } ); 13869 * 13870 * @example 13871 * // Case-sensitive string ordering, with no pre-formatting method 13872 * $.extend( $.fn.dataTable.ext.order, { 13873 * "string-case-asc": function(x,y) { 13874 * return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 13875 * }, 13876 * "string-case-desc": function(x,y) { 13877 * return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 13878 * } 13879 * } ); 13880 */ 13881 order: {} 13882 }, 13883 13884 /** 13885 * Unique DataTables instance counter 13886 * 13887 * @type int 13888 * @private 13889 */ 13890 _unique: 0, 13891 13892 13893 // 13894 // Depreciated 13895 // The following properties are retained for backwards compatiblity only. 13896 // The should not be used in new projects and will be removed in a future 13897 // version 13898 // 13899 13900 /** 13901 * Version check function. 13902 * @type function 13903 * @depreciated Since 1.10 13904 */ 13905 fnVersionCheck: DataTable.fnVersionCheck, 13906 13907 13908 /** 13909 * Index for what 'this' index API functions should use 13910 * @type int 13911 * @deprecated Since v1.10 13912 */ 13913 iApiIndex: 0, 13914 13915 13916 /** 13917 * jQuery UI class container 13918 * @type object 13919 * @deprecated Since v1.10 13920 */ 13921 oJUIClasses: {}, 13922 13923 13924 /** 13925 * Software version 13926 * @type string 13927 * @deprecated Since v1.10 13928 */ 13929 sVersion: DataTable.version 13930 }; 13931 13932 13933 // 13934 // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts 13935 // 13936 $.extend( _ext, { 13937 afnFiltering: _ext.search, 13938 aTypes: _ext.type.detect, 13939 ofnSearch: _ext.type.search, 13940 oSort: _ext.type.order, 13941 afnSortData: _ext.order, 13942 aoFeatures: _ext.feature, 13943 oApi: _ext.internal, 13944 oStdClasses: _ext.classes, 13945 oPagination: _ext.pager 13946 } ); 13947 13948 13949 $.extend( DataTable.ext.classes, { 13950 "sTable": "dataTable", 13951 "sNoFooter": "no-footer", 13952 13953 /* Paging buttons */ 13954 "sPageButton": "paginate_button", 13955 "sPageButtonActive": "current", 13956 "sPageButtonDisabled": "disabled", 13957 13958 /* Striping classes */ 13959 "sStripeOdd": "odd", 13960 "sStripeEven": "even", 13961 13962 /* Empty row */ 13963 "sRowEmpty": "dataTables_empty", 13964 13965 /* Features */ 13966 "sWrapper": "dataTables_wrapper", 13967 "sFilter": "dataTables_filter", 13968 "sInfo": "dataTables_info", 13969 "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */ 13970 "sLength": "dataTables_length", 13971 "sProcessing": "dataTables_processing", 13972 13973 /* Sorting */ 13974 "sSortAsc": "sorting_asc", 13975 "sSortDesc": "sorting_desc", 13976 "sSortable": "sorting", /* Sortable in both directions */ 13977 "sSortableAsc": "sorting_asc_disabled", 13978 "sSortableDesc": "sorting_desc_disabled", 13979 "sSortableNone": "sorting_disabled", 13980 "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */ 13981 13982 /* Filtering */ 13983 "sFilterInput": "", 13984 13985 /* Page length */ 13986 "sLengthSelect": "", 13987 13988 /* Scrolling */ 13989 "sScrollWrapper": "dataTables_scroll", 13990 "sScrollHead": "dataTables_scrollHead", 13991 "sScrollHeadInner": "dataTables_scrollHeadInner", 13992 "sScrollBody": "dataTables_scrollBody", 13993 "sScrollFoot": "dataTables_scrollFoot", 13994 "sScrollFootInner": "dataTables_scrollFootInner", 13995 13996 /* Misc */ 13997 "sHeaderTH": "", 13998 "sFooterTH": "", 13999 14000 // Deprecated 14001 "sSortJUIAsc": "", 14002 "sSortJUIDesc": "", 14003 "sSortJUI": "", 14004 "sSortJUIAscAllowed": "", 14005 "sSortJUIDescAllowed": "", 14006 "sSortJUIWrapper": "", 14007 "sSortIcon": "", 14008 "sJUIHeader": "", 14009 "sJUIFooter": "" 14010 } ); 14011 14012 14013 (function() { 14014 14015 // Reused strings for better compression. Closure compiler appears to have a
14016 // weird edge case where it is trying to expand strings rather than use the 14017 // variable version. This results in about 200 bytes being added, for very 14018 // little preference benefit since it this run on script load only. 14019 var _empty = ''; 14020 _empty = ''; 14021 14022 var _stateDefault = _empty + 'ui-state-default'; 14023 var _sortIcon = _empty + 'css_right ui-icon ui-icon-'; 14024 var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix'; 14025 14026 $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, { 14027 /* Full numbers paging buttons */ 14028 "sPageButton": "fg-button ui-button "+_stateDefault, 14029 "sPageButtonActive": "ui-state-disabled", 14030 "sPageButtonDisabled": "ui-state-disabled", 14031 14032 /* Features */ 14033 "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+ 14034 "ui-buttonset-multi paging_", /* Note that the type is postfixed */ 14035 14036 /* Sorting */ 14037 "sSortAsc": _stateDefault+" sorting_asc", 14038 "sSortDesc": _stateDefault+" sorting_desc", 14039 "sSortable": _stateDefault+" sorting", 14040 "sSortableAsc": _stateDefault+" sorting_asc_disabled", 14041 "sSortableDesc": _stateDefault+" sorting_desc_disabled", 14042 "sSortableNone": _stateDefault+" sorting_disabled", 14043 "sSortJUIAsc": _sortIcon+"triangle-1-n", 14044 "sSortJUIDesc": _sortIcon+"triangle-1-s", 14045 "sSortJUI": _sortIcon+"carat-2-n-s", 14046 "sSortJUIAscAllowed": _sortIcon+"carat-1-n", 14047 "sSortJUIDescAllowed": _sortIcon+"carat-1-s", 14048 "sSortJUIWrapper": "DataTables_sort_wrapper", 14049 "sSortIcon": "DataTables_sort_icon", 14050 14051 /* Scrolling */ 14052 "sScrollHead": "dataTables_scrollHead "+_stateDefault, 14053 "sScrollFoot": "dataTables_scrollFoot "+_stateDefault, 14054 14055 /* Misc */ 14056 "sHeaderTH": _stateDefault, 14057 "sFooterTH": _stateDefault, 14058 "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr", 14059 "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br" 14060 } ); 14061 14062 }()); 14063 14064 14065 14066 var extPagination = DataTable.ext.pager; 14067 14068 function _numbers ( page, pages ) { 14069 var 14070 numbers = [], 14071 buttons = extPagination.numbers_length, 14072 half = Math.floor( buttons / 2 ), 14073 i = 1; 14074 14075 if ( pages <= buttons ) { 14076 numbers = _range( 0, pages ); 14077 } 14078 else if ( page <= half ) { 14079 numbers = _range( 0, buttons-2 ); 14080 numbers.push( 'ellipsis' ); 14081 numbers.push( pages-1 ); 14082 } 14083 else if ( page >= pages - 1 - half ) { 14084 numbers = _range( pages-(buttons-2), pages ); 14085 numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6 14086 numbers.splice( 0, 0, 0 ); 14087 } 14088 else { 14089 numbers = _range( page-1, page+2 ); 14090 numbers.push( 'ellipsis' ); 14091 numbers.push( pages-1 ); 14092 numbers.splice( 0, 0, 'ellipsis' ); 14093 numbers.splice( 0, 0, 0 ); 14094 } 14095 14096 numbers.DT_el = 'span'; 14097 return numbers; 14098 } 14099 14100 14101 $.extend( extPagination, { 14102 simple: function ( page, pages ) { 14103 return [ 'previous', 'next' ]; 14104 }, 14105 14106 full: function ( page, pages ) { 14107 return [ 'first', 'previous', 'next', 'last' ]; 14108 }, 14109 14110 simple_numbers: function ( page, pages ) { 14111 return [ 'previous', _numbers(page, pages), 'next' ]; 14112 }, 14113 14114 full_numbers: function ( page, pages ) { 14115 return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ]; 14116 }, 14117 14118 // For testing and plug-ins to use 14119 _numbers: _numbers, 14120 numbers_length: 7 14121 } ); 14122 14123 14124 $.extend( true, DataTable.ext.renderer, { 14125 pageButton: { 14126 _: function ( settings, host, idx, buttons, page, pages ) { 14127 var classes = settings.oClasses; 14128 var lang = settings.oLanguage.oPaginate; 14129 var btnDisplay, btnClass, counter=0; 14130 14131 var attach = function( container, buttons ) { 14132 var i, ien, node, button; 14133 var clickHandler = function ( e ) { 14134 _fnPageChange( settings, e.data.action, true ); 14135 }; 14136 14137 for ( i=0, ien=buttons.length ; i<ien ; i++ ) { 14138 button = buttons[i]; 14139 14140 if ( $.isArray( button ) ) { 14141 var inner = $( '<'+(button.DT_el || 'div')+'/>' ) 14142 .appendTo( container ); 14143 attach( inner, button ); 14144 } 14145 else { 14146 btnDisplay = ''; 14147 btnClass = ''; 14148 14149 switch ( button ) { 14150 case 'ellipsis': 14151 container.append('<span>…</span>'); 14152 break; 14153 14154 case 'first': 14155 btnDisplay = lang.sFirst; 14156 btnClass = button + (page > 0 ? 14157 '' : ' '+classes.sPageButtonDisabled); 14158 break; 14159 14160 case 'previous': 14161 btnDisplay = lang.sPrevious; 14162 btnClass = button + (page > 0 ? 14163 '' : ' '+classes.sPageButtonDisabled); 14164 break; 14165 14166 case 'next': 14167 btnDisplay = lang.sNext; 14168 btnClass = button + (page < pages-1 ? 14169 '' : ' '+classes.sPageButtonDisabled); 14170 break; 14171 14172 case 'last': 14173 btnDisplay = lang.sLast; 14174 btnClass = button + (page < pages-1 ? 14175 '' : ' '+classes.sPageButtonDisabled); 14176 break; 14177 14178 default: 14179 btnDisplay = button + 1; 14180 btnClass = page === button ? 14181 classes.sPageButtonActive : ''; 14182 break; 14183 } 14184 14185 if ( btnDisplay ) { 14186 node = $('<a>', { 14187 'class': classes.sPageButton+' '+btnClass, 14188 'aria-controls': settings.sTableId, 14189 'data-dt-idx': counter, 14190 'tabindex': settings.iTabIndex, 14191 'id': idx === 0 && typeof button === 'string' ? 14192 settings.sTableId +'_'+ button : 14193 null 14194 } ) 14195 .html( btnDisplay ) 14196 .appendTo( container ); 14197 14198 _fnBindAction( 14199 node, {action: button}, clickHandler 14200 ); 14201 14202 counter++; 14203 } 14204 } 14205 } 14206 }; 14207 14208 // IE9 throws an 'unknown error' if document.activeElement is used 14209 // inside an iframe or frame. Try / catch the error. Not good for 14210 // accessibility, but neither are frames. 14211 var activeEl; 14212
14213 try { 14214 // Because this approach is destroying and recreating the paging 14215 // elements, focus is lost on the select button which is bad for 14216 // accessibility. So we want to restore focus once the draw has 14217 // completed 14218 activeEl = $(document.activeElement).data('dt-idx'); 14219 } 14220 catch (e) {} 14221 14222 attach( $(host).empty(), buttons ); 14223 14224 if ( activeEl ) { 14225 $(host).find( '[data-dt-idx='+activeEl+']' ).focus(); 14226 } 14227 } 14228 } 14229 } ); 14230 14231 14232 14233 // Built in type detection. See model.ext.aTypes for information about 14234 // what is required from this methods. 14235 $.extend( DataTable.ext.type.detect, [ 14236 // Plain numbers - first since V8 detects some plain numbers as dates 14237 // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...). 14238 function ( d, settings ) 14239 { 14240 var decimal = settings.oLanguage.sDecimal; 14241 return _isNumber( d, decimal ) ? 'num'+decimal : null; 14242 }, 14243 14244 // Dates (only those recognised by the browser's Date.parse) 14245 function ( d, settings ) 14246 { 14247 // V8 will remove any unknown characters at the start and end of the 14248 // expression, leading to false matches such as `$245.12` or `10%` being 14249 // a valid date. See forum thread 18941 for detail. 14250 if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) { 14251 return null; 14252 } 14253 var parsed = Date.parse(d); 14254 return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null; 14255 }, 14256 14257 // Formatted numbers 14258 function ( d, settings ) 14259 { 14260 var decimal = settings.oLanguage.sDecimal; 14261 return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null; 14262 }, 14263 14264 // HTML numeric 14265 function ( d, settings ) 14266 { 14267 var decimal = settings.oLanguage.sDecimal; 14268 return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null; 14269 }, 14270 14271 // HTML numeric, formatted 14272 function ( d, settings ) 14273 { 14274 var decimal = settings.oLanguage.sDecimal; 14275 return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null; 14276 }, 14277 14278 // HTML (this is strict checking - there must be html) 14279 function ( d, settings ) 14280 { 14281 return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ? 14282 'html' : null; 14283 } 14284 ] ); 14285 14286 14287 14288 // Filter formatting functions. See model.ext.ofnSearch for information about 14289 // what is required from these methods. 14290 // 14291 // Note that additional search methods are added for the html numbers and 14292 // html formatted numbers by `_addNumericSort()` when we know what the decimal 14293 // place is 14294 14295 14296 $.extend( DataTable.ext.type.search, { 14297 html: function ( data ) { 14298 return _empty(data) ? 14299 data : 14300 typeof data === 'string' ? 14301 data 14302 .replace( _re_new_lines, " " ) 14303 .replace( _re_html, "" ) : 14304 ''; 14305 }, 14306 14307 string: function ( data ) { 14308 return _empty(data) ? 14309 data : 14310 typeof data === 'string' ? 14311 data.replace( _re_new_lines, " " ) : 14312 data; 14313 } 14314 } ); 14315 14316 14317 14318 var __numericReplace = function ( d, decimalPlace, re1, re2 ) { 14319 if ( d !== 0 && (!d || d === '-') ) { 14320 return -Infinity; 14321 } 14322 14323 // If a decimal place other than `.` is used, it needs to be given to the 14324 // function so we can detect it and replace with a `.` which is the only 14325 // decimal place Javascript recognises - it is not locale aware. 14326 if ( decimalPlace ) { 14327 d = _numToDecimal( d, decimalPlace ); 14328 } 14329 14330 if ( d.replace ) { 14331 if ( re1 ) { 14332 d = d.replace( re1, '' ); 14333 } 14334 14335 if ( re2 ) { 14336 d = d.replace( re2, '' ); 14337 } 14338 } 14339 14340 return d * 1; 14341 }; 14342 14343 14344 // Add the numeric 'deformatting' functions for sorting and search. This is done 14345 // in a function to provide an easy ability for the language options to add 14346 // additional methods if a non-period decimal place is used. 14347 function _addNumericSort ( decimalPlace ) { 14348 $.each( 14349 { 14350 // Plain numbers 14351 "num": function ( d ) { 14352 return __numericReplace( d, decimalPlace ); 14353 }, 14354 14355 // Formatted numbers 14356 "num-fmt": function ( d ) { 14357 return __numericReplace( d, decimalPlace, _re_formatted_numeric ); 14358 }, 14359 14360 // HTML numeric 14361 "html-num": function ( d ) { 14362 return __numericReplace( d, decimalPlace, _re_html ); 14363 }, 14364 14365 // HTML numeric, formatted 14366 "html-num-fmt": function ( d ) { 14367 return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric ); 14368 } 14369 }, 14370 function ( key, fn ) { 14371 // Add the ordering method 14372 _ext.type.order[ key+decimalPlace+'-pre' ] = fn; 14373 14374 // For HTML types add a search formatter that will strip the HTML 14375 if ( key.match(/^html\-/) ) { 14376 _ext.type.search[ key+decimalPlace ] = _ext.type.search.html; 14377 } 14378 } 14379 ); 14380 } 14381 14382 14383 // Default sort methods 14384 $.extend( _ext.type.order, { 14385 // Dates 14386 "date-pre": function ( d ) { 14387 return Date.parse( d ) || 0; 14388 }, 14389 14390 // html 14391 "html-pre": function ( a ) { 14392 return _empty(a) ? 14393 '' : 14394 a.replace ? 14395 a.replace( /<.*?>/g, "" ).toLowerCase() : 14396 a+''; 14397 }, 14398 14399 // string 14400 "string-pre": function ( a ) { 14401 // This is a little complex, but faster than always calling toString, 14402 // http://jsperf.com/tostring-v-check 14403 return _empty(a) ? 14404 '' : 14405 typeof a === 'string' ? 14406 a.toLowerCase() : 14407 ! a.toString ? 14408 '' : 14409 a.toString(); 14410 }, 14411 14412 // string-asc and -desc are retained only for compatibility with the old 14413 // sort methods 14414 "string-asc": function ( x, y ) { 14415 return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 14416 }, 14417 14418 "string-desc": function ( x, y ) { 14419 return ((x < y) ? 1 : ((x > y) ? -1 : 0)); 14420 } 14421 } ); 14422 14423 14424 // Numeric sorting types - order doesn't matter here 14425 _addNumericSort( '' ); 14426 14427 14428 $.extend( true, DataTable.ext.renderer, { 14429 header: { 14430 _: function ( settings, cell, column, classes ) { 14431 // No additional mark-up required
14432 // Attach a sort listener to update on sort - note that using the 14433 // `DT` namespace will allow the event to be removed automatically 14434 // on destroy, while the `dt` namespaced event is the one we are 14435 // listening for 14436 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 14437 if ( settings !== ctx ) { // need to check this this is the host 14438 return; // table, not a nested one 14439 } 14440 14441 var colIdx = column.idx; 14442 14443 cell 14444 .removeClass( 14445 column.sSortingClass +' '+ 14446 classes.sSortAsc +' '+ 14447 classes.sSortDesc 14448 ) 14449 .addClass( columns[ colIdx ] == 'asc' ? 14450 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 14451 classes.sSortDesc : 14452 column.sSortingClass 14453 ); 14454 } ); 14455 }, 14456 14457 jqueryui: function ( settings, cell, column, classes ) { 14458 $('<div/>') 14459 .addClass( classes.sSortJUIWrapper ) 14460 .append( cell.contents() ) 14461 .append( $('<span/>') 14462 .addClass( classes.sSortIcon+' '+column.sSortingClassJUI ) 14463 ) 14464 .appendTo( cell ); 14465 14466 // Attach a sort listener to update on sort 14467 $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) { 14468 if ( settings !== ctx ) { 14469 return; 14470 } 14471 14472 var colIdx = column.idx; 14473 14474 cell 14475 .removeClass( classes.sSortAsc +" "+classes.sSortDesc ) 14476 .addClass( columns[ colIdx ] == 'asc' ? 14477 classes.sSortAsc : columns[ colIdx ] == 'desc' ? 14478 classes.sSortDesc : 14479 column.sSortingClass 14480 ); 14481 14482 cell 14483 .find( 'span.'+classes.sSortIcon ) 14484 .removeClass( 14485 classes.sSortJUIAsc +" "+ 14486 classes.sSortJUIDesc +" "+ 14487 classes.sSortJUI +" "+ 14488 classes.sSortJUIAscAllowed +" "+ 14489 classes.sSortJUIDescAllowed 14490 ) 14491 .addClass( columns[ colIdx ] == 'asc' ? 14492 classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ? 14493 classes.sSortJUIDesc : 14494 column.sSortingClassJUI 14495 ); 14496 } ); 14497 } 14498 } 14499 } ); 14500 14501 /* 14502 * Public helper functions. These aren't used internally by DataTables, or 14503 * called by any of the options passed into DataTables, but they can be used 14504 * externally by developers working with DataTables. They are helper functions 14505 * to make working with DataTables a little bit easier. 14506 */ 14507 14508 /** 14509 * Helpers for `columns.render`. 14510 * 14511 * The options defined here can be used with the `columns.render` initialisation 14512 * option to provide a display renderer. The following functions are defined: 14513 * 14514 * * `number` - Will format numeric data (defined by `columns.data`) for 14515 * display, retaining the original unformatted data for sorting and filtering. 14516 * It takes 4 parameters: 14517 * * `string` - Thousands grouping separator 14518 * * `string` - Decimal point indicator 14519 * * `integer` - Number of decimal points to show 14520 * * `string` (optional) - Prefix. 14521 * 14522 * @example 14523 * // Column definition using the number renderer 14524 * { 14525 * data: "salary", 14526 * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' ) 14527 * } 14528 * 14529 * @namespace 14530 */ 14531 DataTable.render = { 14532 number: function ( thousands, decimal, precision, prefix ) { 14533 return { 14534 display: function ( d ) { 14535 var negative = d < 0 ? '-' : ''; 14536 d = Math.abs( parseFloat( d ) ); 14537 14538 var intPart = parseInt( d, 10 ); 14539 var floatPart = precision ? 14540 decimal+(d - intPart).toFixed( precision ).substring( 2 ): 14541 ''; 14542 14543 return negative + (prefix||'') + 14544 intPart.toString().replace( 14545 /\B(?=(\d{3})+(?!\d))/g, thousands 14546 ) + 14547 floatPart; 14548 } 14549 }; 14550 } 14551 }; 14552 14553 14554 /* 14555 * This is really a good bit rubbish this method of exposing the internal methods 14556 * publicly... - To be fixed in 2.0 using methods on the prototype 14557 */ 14558 14559 14560 /** 14561 * Create a wrapper function for exporting an internal functions to an external API. 14562 * @param {string} fn API function name 14563 * @returns {function} wrapped function 14564 * @memberof DataTable#internal 14565 */ 14566 function _fnExternApiFunc (fn) 14567 { 14568 return function() { 14569 var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat( 14570 Array.prototype.slice.call(arguments) 14571 ); 14572 return DataTable.ext.internal[fn].apply( this, args ); 14573 }; 14574 } 14575 14576 14577 /** 14578 * Reference to internal functions for use by plug-in developers. Note that 14579 * these methods are references to internal functions and are considered to be 14580 * private. If you use these methods, be aware that they are liable to change 14581 * between versions. 14582 * @namespace 14583 */ 14584 $.extend( DataTable.ext.internal, { 14585 _fnExternApiFunc: _fnExternApiFunc, 14586 _fnBuildAjax: _fnBuildAjax, 14587 _fnAjaxUpdate: _fnAjaxUpdate, 14588 _fnAjaxParameters: _fnAjaxParameters, 14589 _fnAjaxUpdateDraw: _fnAjaxUpdateDraw, 14590 _fnAjaxDataSrc: _fnAjaxDataSrc, 14591 _fnAddColumn: _fnAddColumn, 14592 _fnColumnOptions: _fnColumnOptions, 14593 _fnAdjustColumnSizing: _fnAdjustColumnSizing, 14594 _fnVisibleToColumnIndex: _fnVisibleToColumnIndex, 14595 _fnColumnIndexToVisible: _fnColumnIndexToVisible, 14596 _fnVisbleColumns: _fnVisbleColumns, 14597 _fnGetColumns: _fnGetColumns, 14598 _fnColumnTypes: _fnColumnTypes, 14599 _fnApplyColumnDefs: _fnApplyColumnDefs, 14600 _fnHungarianMap: _fnHungarianMap, 14601 _fnCamelToHungarian: _fnCamelToHungarian, 14602 _fnLanguageCompat: _fnLanguageCompat, 14603 _fnBrowserDetect: _fnBrowserDetect, 14604 _fnAddData: _fnAddData, 14605 _fnAddTr: _fnAddTr, 14606 _fnNodeToDataIndex: _fnNodeToDataIndex, 14607 _fnNodeToColumnIndex: _fnNodeToColumnIndex, 14608 _fnGetCellData: _fnGetCellData, 14609 _fnSetCellData: _fnSetCellData, 14610 _fnSplitObjNotation: _fnSplitObjNotation, 14611 _fnGetObjectDataFn: _fnGetObjectDataFn, 14612 _fnSetObjectDataFn: _fnSetObjectDataFn, 14613 _fnGetDataMaster: _fnGetDataMaster, 14614 _fnClearTable: _fnClearTable, 14615 _fnDeleteIndex: _fnDeleteIndex, 14616 _fnInvalidate: _fnInvalidate, 14617 _fnGetRowElements: _fnGetRowElements, 14618 _fnCreateTr: _fnCreateTr, 14619 _fnBuildHead: _fnBuildHead, 14620 _fnDrawHead: _fnDrawHead, 14621 _fnDraw: _fnDraw, 14622 _fnReDraw: _fnReDraw, 14623 _fnAddOptionsHtml: _fnAddOptionsHtml, 14624 _fnDetectHeader: _fnDetectHeader, 14625 _fnGetUniqueThs: _fnGetUniqueThs, 14626 _fnFeatureHtmlFilter: _fnFeatureHtmlFilter, 14627 _fnFilterComplete: _fnFilterComplete, 14628 _fnFilterCustom: _fnFilterCustom, 14629 _fnFilterColumn: _fnFilterColumn, 14630 _fnFilter: _fnFilter, 14631 _fnFilterCreateSearch: _fnFilterCreateSearch, 14632 _fnEscapeRegex: _fnEscapeRegex, 14633 _fnFilterData: _fnFilterData, 14634 _fnFeatureHtmlInfo: _fnFeatureHtmlInfo, 14635 _fnUpdateInfo: _fnUpdateInfo, 14636 _fnInfoMacros: _fnInfoMacros, 14637 _fnInitialise: _fnInitialise, 14638 _fnInitComplete: _fnInitComplete, 14639 _fnLengthChange: _fnLengthChange, 14640 _fnFeatureHtmlLength: _fnFeatureHtmlLength, 14641 _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate, 14642 _fnPageChange: _fnPageChange, 14643 _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing, 14644 _fnProcessingDisplay: _fnProcessingDisplay, 14645 _fnFeatureHtmlTable: _fnFeatureHtmlTable, 14646 _fnScrollDraw: _fnScrollDraw, 14647 _fnApplyToChildren: _fnApplyToChildren, 14648 _fnCalculateColumnWidths: _fnCalculateColumnWidths, 14649 _fnThrottle: _fnThrottle, 14650 _fnConvertToWidth: _fnConvertToWidth, 14651 _fnScrollingWidthAdjust: _fnScrollingWidthAdjust, 14652 _fnGetWidestNode: _fnGetWidestNode, 14653 _fnGetMaxLenString: _fnGetMaxLenString, 14654 _fnStringToCss: _fnStringToCss, 14655 _fnScrollBarWidth: _fnScrollBarWidth, 14656 _fnSortFlatten: _fnSortFlatten, 14657 _fnSort: _fnSort, 14658 _fnSortAria: _fnSortAria, 14659 _fnSortListener: _fnSortListener, 14660 _fnSortAttachListener: _fnSortAttachListener, 14661 _fnSortingClasses: _fnSortingClasses, 14662 _fnSortData: _fnSortData, 14663 _fnSaveState: _fnSaveState, 14664 _fnLoadState: _fnLoadState, 14665 _fnSettingsFromNode: _fnSettingsFromNode, 14666 _fnLog: _fnLog, 14667 _fnMap: _fnMap, 14668 _fnBindAction: _fnBindAction, 14669 _fnCallbackReg: _fnCallbackReg, 14670 _fnCallbackFire: _fnCallbackFire, 14671 _fnLengthOverflow: _fnLengthOverflow, 14672 _fnRenderer: _fnRenderer, 14673 _fnDataSource: _fnDataSource, 14674 _fnRowAttributes: _fnRowAttributes, 14675 _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant 14676 // in 1.10, so this dead-end function is 14677 // added to prevent errors 14678 } ); 14679 14680 14681 // jQuery access 14682 $.fn.dataTable = DataTable; 14683 14684 // Legacy aliases 14685 $.fn.dataTableSettings = DataTable.settings; 14686 $.fn.dataTableExt = DataTable.ext; 14687 14688 // With a capital `D` we return a DataTables API instance rather than a 14689 // jQuery object 14690 $.fn.DataTable = function ( opts ) { 14691 return $(this).dataTable( opts ).api(); 14692 }; 14693 14694 // All properties that are available to $.fn.dataTable should also be 14695 // available on $.fn.DataTable 14696 $.each( DataTable, function ( prop, val ) { 14697 $.fn.DataTable[ prop ] = val; 14698 } ); 14699 14700 14701 // Information about events fired by DataTables - for documentation. 14702 /** 14703 * Draw event, fired whenever the table is redrawn on the page, at the same 14704 * point as fnDrawCallback. This may be useful for binding events or 14705 * performing calculations when the table is altered at all. 14706 * @name DataTable#draw.dt 14707 * @event 14708 * @param {event} e jQuery event object 14709 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14710 */ 14711 14712 /** 14713 * Search event, fired when the searching applied to the table (using the 14714 * built-in global search, or column filters) is altered. 14715 * @name DataTable#search.dt 14716 * @event 14717 * @param {event} e jQuery event object 14718 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14719 */ 14720 14721 /** 14722 * Page change event, fired when the paging of the table is altered. 14723 * @name DataTable#page.dt 14724 * @event 14725 * @param {event} e jQuery event object 14726 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14727 */ 14728 14729 /** 14730 * Order event, fired when the ordering applied to the table is altered. 14731 * @name DataTable#order.dt 14732 * @event 14733 * @param {event} e jQuery event object 14734 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14735 */ 14736 14737 /** 14738 * DataTables initialisation complete event, fired when the table is fully 14739 * drawn, including Ajax data loaded, if Ajax data is required. 14740 * @name DataTable#init.dt 14741 * @event 14742 * @param {event} e jQuery event object 14743 * @param {object} oSettings DataTables settings object 14744 * @param {object} json The JSON object request from the server - only 14745 * present if client-side Ajax sourced data is used</li></ol> 14746 */ 14747 14748 /** 14749 * State save event, fired when the table has changed state a new state save 14750 * is required. This event allows modification of the state saving object 14751 * prior to actually doing the save, including addition or other state 14752 * properties (for plug-ins) or modification of a DataTables core property. 14753 * @name DataTable#stateSaveParams.dt 14754 * @event 14755 * @param {event} e jQuery event object 14756 * @param {object} oSettings DataTables settings object 14757 * @param {object} json The state information to be saved 14758 */ 14759 14760 /** 14761 * State load event, fired when the table is loading state from the stored 14762 * data, but prior to the settings object being modified by the saved state 14763 * - allowing modification of the saved state is required or loading of 14764 * state for a plug-in. 14765 * @name DataTable#stateLoadParams.dt 14766 * @event 14767 * @param {event} e jQuery event object 14768 * @param {object} oSettings DataTables settings object 14769 * @param {object} json The saved state information 14770 */ 14771 14772 /** 14773 * State loaded event, fired when state has been loaded from stored data and 14774 * the settings object has been modified by the loaded data. 14775 * @name DataTable#stateLoaded.dt 14776 * @event 14777 * @param {event} e jQuery event object 14778 * @param {object} oSettings DataTables settings object 14779 * @param {object} json The saved state information 14780 */ 14781 14782 /** 14783 * Processing event, fired when DataTables is doing some kind of processing 14784 * (be it, order, searcg or anything else). It can be used to indicate to 14785 * the end user that there is something happening, or that something has 14786 * finished. 14787 * @name DataTable#processing.dt 14788 * @event 14789 * @param {event} e jQuery event object 14790 * @param {object} oSettings DataTables settings object 14791 * @param {boolean} bShow Flag for if DataTables is doing processing or not 14792 */ 14793 14794 /** 14795 * Ajax (XHR) event, fired whenever an Ajax request is completed from a 14796 * request to made to the server for new data. This event is called before 14797 * DataTables processed the returned data, so it can also be used to pre- 14798 * process the data returned from the server, if needed. 14799 *
14800 * Note that this trigger is called in `fnServerData`, if you override 14801 * `fnServerData` and which to use this event, you need to trigger it in you 14802 * success function. 14803 * @name DataTable#xhr.dt 14804 * @event 14805 * @param {event} e jQuery event object 14806 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14807 * @param {object} json JSON returned from the server 14808 * 14809 * @example 14810 * // Use a custom property returned from the server in another DOM element 14811 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 14812 * $('#status').html( json.status ); 14813 * } ); 14814 * 14815 * @example 14816 * // Pre-process the data returned from the server 14817 * $('#table').dataTable().on('xhr.dt', function (e, settings, json) { 14818 * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) { 14819 * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two; 14820 * } 14821 * // Note no return - manipulate the data directly in the JSON object. 14822 * } ); 14823 */ 14824 14825 /** 14826 * Destroy event, fired when the DataTable is destroyed by calling fnDestroy 14827 * or passing the bDestroy:true parameter in the initialisation object. This 14828 * can be used to remove bound events, added DOM nodes, etc. 14829 * @name DataTable#destroy.dt 14830 * @event 14831 * @param {event} e jQuery event object 14832 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14833 */ 14834 14835 /** 14836 * Page length change event, fired when number of records to show on each 14837 * page (the length) is changed. 14838 * @name DataTable#length.dt 14839 * @event 14840 * @param {event} e jQuery event object 14841 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14842 * @param {integer} len New length 14843 */ 14844 14845 /** 14846 * Column sizing has changed. 14847 * @name DataTable#column-sizing.dt 14848 * @event 14849 * @param {event} e jQuery event object 14850 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14851 */ 14852 14853 /** 14854 * Column visibility has changed. 14855 * @name DataTable#column-visibility.dt 14856 * @event 14857 * @param {event} e jQuery event object 14858 * @param {object} o DataTables settings object {@link DataTable.models.oSettings} 14859 * @param {int} column Column index 14860 * @param {bool} vis `false` if column now hidden, or `true` if visible 14861 */ 14862 14863 return $.fn.dataTable; 14864})); 14865 14866}(window, document)); 14867
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.